--- /dev/null
+Changes for 1.8.3
+-----------------
+
+- Fixed rehash bug with specific conf changes that caused memory
+ corruption and crashes
+- Fixed a possible buffer overflow issue in oper hostmasking
+- Fixed solaris devpoll socket engine logic problems.
+- Fixed class reference counting errors.
+- Fixed a bug with cmode +j propagation on resync
+- Added a second set of join counters to send warning notices
+ to +d opers when the default thresholds are met. Still sends
+ a throttle notice when cmode +j thresholds are met.
+- Changed ERR_BANLISTFULL to respond depending on which list
+ (+b/+I/+e) is full. From Unim4trix0 (Unim4trix0@gmail.com).
+- Readded clone limiting (now better!), see doc/clones.txt
+- Range limiting for cmode +j args (static 4:2 - 60:60, rate 1/8 - 2/1).
+- Fixed spamming redudant cmode changes.
+- Fixed bad handling of bogus oper messages (from Zeke Gomez).
+- Fixed rehash issue with module blocks.
+- Fixed samode with no mode arguments choosing one at random for you :)
+- Increased throughput on data sent to clients.
+- Changed ERR_CHANNELISFULL to respond depending on which limit
+ (+l/+j) is reached. From Unim4trix0 (Unim4trix0@gmail.com),
+ discovered by Watchminister (watchminister@gmail.com).
+- Changed cmode +O join rejection to use ERR_INVITEONLY numeric.
+- Enabled umode +s (oper kills) for users, disabled +g (useless).
+- RWHO now sports clone and joined channel awareness.
+- Added flags token to allow blocks, see doc/reference.conf
+- Allow blocks with passwords are now hidden from nonopers in /stats I
+
+
+Changes for 1.8.2
+-----------------
+
+- fixed entropy generation on OpenBSD and cleaned up status messages
+ (from Mark19960)
+- fixed cosmetic error in /stats C reply
+- fixed autoconnect blast when connect->port was specified but not
+ class->connfreq (from Mark19960)
+- fixed crash on /stats request from a server (from Mark19960)
+- fixed invite exceptions not working at all (from wshs)
+- fixed ban exemptions not affecting bquiet (from wshs)
+- fixed -e/-I sync failure during netbursts of older channels
+- tweaked reference.conf
+- corrected new find_port() check
+- now removing simbans (restrict blocks) on rehash (from Ballsy)
+- fixed cosmetic errors in nick collision kills (from Goplat)
+- Converted old "X line" messages to "X block"
+- Changed stray free() to MyFree()
+- Corrected a tolower() reference I missed the first time around
+- Removed ancient prototype causing compile failures with gcc 3.4
+- Fixed 005 WATCH token (was using incorrect number)
+- Removed temporary debug code causing compile failure when !USE_SYSLOG
+- Finished correcting same port, multiple IP binds
+- stats L shows user IPs again (but still hides opers)
+- Numerics 477 and 487 no longer hardcoded dal.net
+- Fixed numeric responses for certain PRIVMSG/NOTICE targets
+- Updated reference.conf and template.conf with additional bits and better
+ documentation of Allow block quirks
+- Tweaked handling and display of removed-but-not-yet-deleted conf entries
+ after a rehash (Oper, Connect, Class)
+- Oper block host entries are now matched against the user@host that would
+ appear on IRC (previously what they matched was a bit convoluted)
+- Corrected class maxusers handling -- applies to the class, not the allow
+ block
+- Updated 004 and 005 numerics
+- trace now shows the class list again
+- bquiet is now using deferred cache concept from ratbox to deal with ban
+ exemptions correctly
+- Ban exemptions are now marked with type and checked during nick_is_banned()
+- Begin unbreaking redundant ban check -- will take at least one more release
+ to complete
+- Cleaned up related channel ban code
+- CHOOK_10SEC is now called when it should be (from wshs)
+- Unbroke modules command handling (from wshs)
+- Fixed modules load crash when there was no Modules block in ircd.conf
+ (from wshs)
+- Fixed SVSKILL crash on no parameters (from Zeke Gomez)
+- Compile fixes for DNS_DEBUG and DEBUGMODE (but don't use DEBUGMODE)
+- Compile fix for missing LINE_MAX
+- Spellcheck: virii -> viruses (from The List)
+- HIDE_LINKS functionality inverted and attached to show_links token in
+ Options block
+- NO_CHANOPS_WHEN_SPLIT functionality inverted and attached to allow_split_ops
+ token in Options block
+- Merging duplicate Allow blocks during rehash to avoid admin confusion
+- Boolean Options block items can now be disabled by rehash
+- Fixed "servtype hub" causing certain previously specified options to reset
+ to defaults
+- Fixed a loop error report that was broken when it was introduced 11 years ago
+- Ignoring SVSMODE +o/O attempts (not handled correctly)
+- Repaired showing of +s channels in LIST to +A users
+- Fixed and document DENY_SERVICES_MSGS (from wshs)
+- Corrected structfunc.h prototypes for modules (from wshs)
+- Added SVSMODE -e/-I support for channels
+- Fixed .maxclients not being read on startup
+- Rewrote m_invite(), behaves logically now
+- Enabled cmode +j (joins:secs rate limit)
+- Fixed resolver cache corruption (and crash), mostly affected newer RedHat
+ thanks huni and Sarcast for patience, analysis, and cores
+- More conf documentation clarity
+- Unresolved class reference in conf now reports class name
+- Updated RPL_VERSION, RPL_ISUPPORT; now running from a cache in s_debug.c
+- Removed sockhost data from RPL_YOURHOST, since it was always zeroed
+- Squished more memory corruption bugs
+ thanks Glitch and dev0 for more patience and cores
+- Module support is now unconditionally disabled under OS X
+- Build system now handles FD_SETSIZE properly when using the select engine
+- Internal maxconnections and SET MAX handling is rational again
+ ircd can run with as few as 20 FDs and support 10 clients
+- Ripped out obsolete sendto_match_servs()
+- Added support for non-noquit servers in #define NOQUIT
+- Updated zlib to version 1.2.1
+- Restricted stats q/Q/g to opers
+- Show IPs in stats C to services and local +A
+- Added RWHO, see /rwho ? and doc/pcrepattern.html for info
+- Set +k and +s umodes to opers only.
+- Fixed a bug in m_trace that caused cores when issuing a /trace when
+ connecting to a server.
+- ERR_WHOSYNTAX reply changed to ERR_NOPRIVILEGES for non opers trying oper
+ restricted who, but using correct syntax
+ fixed by Unim4trix0 (Unim4trix0@gmail.com)
+
+
+Changes for 1.8.0
+-----------------
+
+- Removed backwards compatibility for:
+ - NOQUIT
+ - UNCONNECT
+ - TSMODE
+ - NICKIP
+ All of these modes are now REQUIRED.
+- Removed Code and defines for outdated stuff:
+ - FOLLOW_IDENT_RFC
+ - NO_IDENT_SYSTYPE_OTHER
+ - NO_MIXED_CASE
+ - OLD_Y_LIMIT
+ - USE_REJECT_HOLD
+ This code is no longer used.
+- Removed define options for:
+ - CLIENT_COUNT
+ This code is now manditory.
+- Completely rewrote configuration structures.
+- Rewrote methods for connecting to servers.
+- Outdated Link structure config linking, now linking directly from
+ aClient(user/serv) structures to appropriate conf strucutures.
+- Backported lucas's aListener structure and routines from defunct
+ bahamut-devel tree.
+- Implemented +I/+e channel lists - thanks seddy.
+- Ports now can be opened and closed on /rehash
+- config file format changed to bind-style
+- klinefile outdated
+- replaced dbufs with sbufs - shared buffers.
+- removed old High Traffic Mode (HTM) code
+- config option block added to outdate use of ./config script
+- fixes for solaris and OSX compatibility
+- Added support for /dev/poll and epoll socket engines - thanks seddy.
+- Moved m_server and m_dkey into m_server.c
+- Moved m_stats into m_stats.c
+- Fixed memory counting routines. Thanks Quension!
+- Outdated modules.ini and all inifile uses - now a modules {} conf block
+- Updated m_module to allow non-admin viewing of hooks and loaded modules
+- Added module hooks for user and channel targetted privmsgs
--- /dev/null
+HOW TO BUILD:
+-------------
+1. Run the configure script. It will setup include/setup.h and the
+ Makefiles to match your system:
+ ./configure
+
+ Type ./configure --help to see different options. Most people will not
+ need to alter these.
+
+2. [DISCOURAGED] Edit the the "include/config.h" file. This allows you to
+ change various options of how the ircd will operate. Usually the defaults
+ are OK.
+
+3. "make" should build ircd.
+
+4. "make install" will install the ircd, config converter, and documents
+ to the directory set by ./configure
+
+5. Edit example.conf in your install directory, and move it to "ircd.conf".
+
+6. Run the binary! ircd will look in the directory you are executing from
+ for an ircd.conf first, then it will look to the directory local to itself.
+ You may override these options by specifying a config file using:
+ ./ircd -f path/to/ircd.conf
+
+Best of luck!
+-The Bahamut Team
+
+$Id: INSTALL,v 1.1 2005/01/12 07:44:55 mmondor Exp $
--- /dev/null
+PCRE LICENCE
+------------
+
+PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+Written by: Philip Hazel <ph10@cam.ac.uk>
+
+University of Cambridge Computing Service,
+Cambridge, England. Phone: +44 1223 334714.
+
+Copyright (c) 1997-2003 University of Cambridge
+
+Permission is granted to anyone to use this software for any purpose on any
+computer system, and to redistribute it freely, subject to the following
+restrictions:
+
+1. This software 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.
+
+2. The origin of this software must not be misrepresented, either by
+ explicit claim or by omission. In practice, this means that if you use
+ PCRE in software that you distribute to others, commercially or
+ otherwise, you must put a sentence like this
+
+ Regular expression support is provided by the PCRE library package,
+ which is open source software, written by Philip Hazel, and copyright
+ by the University of Cambridge, England.
+
+ somewhere reasonably visible in your documentation and in any relevant
+ files or online help data or similar. A reference to the ftp site for
+ the source, that is, to
+
+ ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/
+
+ should also be given in the documentation. However, this condition is not
+ intended to apply to whole chains of software. If package A includes PCRE,
+ it must acknowledge it, but if package B is software that includes package
+ A, the condition is not imposed on package B (unless it uses PCRE
+ independently).
+
+3. Altered versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+
+4. If PCRE is embedded in any software that is released under the GNU
+ General Purpose Licence (GPL), or Lesser General Purpose Licence (LGPL),
+ then the terms of that licence shall supersede any condition above with
+ which it is incompatible.
+
+The documentation for PCRE, supplied in the "doc" directory, is distributed
+under the same terms as the software itself.
+
+End
--- /dev/null
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 1, February 1989
+
+ Copyright (C) 1989 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 license agreements of most software companies try to keep users
+at the mercy of those companies. By contrast, our 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. The
+General Public License applies to the Free Software Foundation's
+software and to any other program whose authors commit to using it.
+You can use it for your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Specifically, the General Public License is designed to make
+sure that you have the freedom to give away or sell copies of free
+software, 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 a 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 tell them 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.
+
+ 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 Agreement 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 work containing the
+Program or a portion of it, either verbatim or with modifications. Each
+licensee is addressed as "you".
+
+ 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
+General Public License and to the absence of any warranty; and give any
+other recipients of the Program a copy of this General Public License
+along with the Program. You may charge a fee for the physical act of
+transferring a copy.
+
+ 2. You may modify your copy or copies of the Program or any portion of
+it, and copy and distribute such modifications under the terms of Paragraph
+1 above, provided that you also do the following:
+
+ a) cause the modified files to carry prominent notices stating that
+ you changed the files and the date of any change; and
+
+ b) cause the whole of any work that you distribute or publish, that
+ in whole or in part contains the Program or any part thereof, either
+ with or without modifications, to be licensed at no charge to all
+ third parties under the terms of this General Public License (except
+ that you may choose to grant warranty protection to some or all
+ third parties, at your option).
+
+ c) If the modified program normally reads commands interactively when
+ run, you must cause it, when started running for such interactive use
+ in the simplest and most usual 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 General
+ Public License.
+
+ d) 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.
+
+Mere aggregation of another independent work with the Program (or its
+derivative) on a volume of a storage or distribution medium does not bring
+the other work under the scope of these terms.
+\f
+ 3. You may copy and distribute the Program (or a portion or derivative of
+it, under Paragraph 2) in object code or executable form under the terms of
+Paragraphs 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
+ Paragraphs 1 and 2 above; or,
+
+ b) accompany it with a written offer, valid for at least three
+ years, to give any third party free (except for a nominal charge
+ for the cost of distribution) a complete machine-readable copy of the
+ corresponding source code, to be distributed under the terms of
+ Paragraphs 1 and 2 above; or,
+
+ c) accompany it with the information you received as to where the
+ corresponding source code may be obtained. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form alone.)
+
+Source code for a work means the preferred form of the work for making
+modifications to it. For an executable file, complete source code means
+all the source code for all modules it contains; but, as a special
+exception, it need not include source code for modules which are standard
+libraries that accompany the operating system on which the executable
+file runs, or for standard header files or definitions files that
+accompany that operating system.
+
+ 4. You may not copy, modify, sublicense, distribute or transfer the
+Program except as expressly provided under this General Public License.
+Any attempt otherwise to copy, modify, sublicense, distribute or transfer
+the Program is void, and will automatically terminate your rights to use
+the Program under this License. However, parties who have received
+copies, or rights to use copies, from you under this General Public
+License will not have their licenses terminated so long as such parties
+remain in full compliance.
+
+ 5. By copying, distributing or modifying 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.
+
+ 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.
+\f
+ 7. 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 the 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
+the license, you may choose any version ever published by the Free Software
+Foundation.
+
+ 8. 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
+
+ 9. 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.
+
+ 10. 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 humanity, 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 1, 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) 19xx 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 a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ program `Gnomovision' (a program to direct compilers to make passes
+ at assemblers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+# IRC - Internet Relay Chat, Makefile
+# Copyright (C) 1990, Jarkko Oikarinen
+#
+# 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 1, 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.
+#
+# $Id: Makefile.in,v 1.1 2005/01/12 07:44:55 mmondor Exp $
+
+RM=@RM@
+MV=@MV@
+
+ENGINE=@SENGINE@
+
+SHELL=/bin/sh
+SUBDIRS=zlib src doc tools
+INSTDIRS=src doc tools
+CLEANSUBDIRS=src tools
+
+CC=@CC@
+CFLAGS=@CFLAGS@
+LIBS=@LIBS@
+
+INSTALL_DIR=@INSTALL_DIR@
+
+all: build
+
+build:
+ -@if [ ! -f include/setup.h ] ; then \
+ echo "Hmm...doesn't look like you've run configure..."; \
+ echo "Doing so now."; \
+ sh configure; \
+ fi
+ @for i in $(SUBDIRS); do \
+ echo "Building $$i";\
+ cd $$i;\
+ ${MAKE} build; cd ..;\
+ done
+ @echo "******************************************************************************"
+ @echo "* For help with bahamut, please refer to http://bahamut.dal.net/ *"
+ @echo "* If you encouter serious security related bugs, please mail coders@dal.net *"
+ @echo "* For other bug reports and inquiries, please mail dalnet-src@dal.net *"
+ @echo "* Thank you for choosing Bahamut! - The DALnet coding team *"
+ @echo "******************************************************************************"
+
+profile:
+ @for i in $(SUBDIRS); do \
+ echo "Building $$i [profile]";\
+ cd $$i;\
+ ${MAKE} profile; cd ..;\
+ done
+
+clean:
+ ${RM} -f *~ core
+ @for i in $(CLEANSUBDIRS); do \
+ echo "Cleaning $$i";\
+ cd $$i;\
+ ${MAKE} clean; cd ..;\
+ done
+ -@if [ -f include/setup.h ] ; then \
+ echo "To really restart installation, make distclean" ; \
+ fi
+
+fullclean:
+ ${RM} -f *~ core
+ @for i in $(SUBDIRS); do \
+ echo "Cleaning $$i";\
+ cd $$i;\
+ ${MAKE} clean; cd ..;\
+ done
+ -@if [ -f include/setup.h ] ; then \
+ echo "To really restart installation, make distclean" ; \
+ fi
+
+distclean:
+ ${RM} -f Makefile *~ *.rej *.orig core ircd.core *.tmp
+ ${RM} -f config.status config.cache config.log
+ cd include; ${RM} -f setup.h *~ *.rej *.orig options.h; cd ..
+ @for i in $(SUBDIRS); do \
+ echo "Cleaning $$i";\
+ cd $$i;\
+ ${MAKE} distclean; cd ..;\
+ done
+
+depend:
+ @for i in $(SUBDIRS); do \
+ echo "Making dependencies in $$i";\
+ cd $$i;\
+ ${MAKE} depend; cd ..;\
+ done
+
+install: all
+ @if test ! -d $(INSTALL_DIR); then \
+ echo "Creating directory $(INSTALL_DIR)"; \
+ mkdir $(INSTALL_DIR); \
+ fi
+ @for i in $(INSTDIRS); do \
+ cd $$i; \
+ $(MAKE) install; \
+ cd ..; \
+ done
+ @echo ""
+ @echo "Now edit $(INSTALL_DIR)/template.conf"
+ @echo "and move it to ircd.conf - and you'll be all set."
+ @echo "See the doc/ directory and the INSTALL file for more assistance"
+ @echo "Thank you for choosing Bahamut!"
+ @echo ""
--- /dev/null
+Welcome to Bahamut 1.8
+----------------------
+
+Please refer to the INSTALL file for help instructions on building and
+installing ircd. The doc/ directory may also be of interest.
+
+Please refer to the CHANGES file to see what has changed in the 1.8
+revision of Bahamut.
+
+*** IMPORTANT ***
+Please send any SECURITY RELATED bugs to coders@dal.net - any
+non-critical bugs can be sent to dalnet-src@dal.net - a public list
+for code discussion.
+
+Thanks!
+-Bahamut Team
+
+$Id: README,v 1.1 2005/01/12 07:44:55 mmondor Exp $
--- /dev/null
+Future TODO List
+----------------
+
+- Split up aClient into separate structures for local and remote users
+- Backport message tokenization from 1.6
+- Carve off throttling into its own hook module
+- Revamp hashing to use a generic hashing model (like throttling).
+- Implement IPV6
+
+List to Ponder
+--------------
+
+- Add support for multiple language sets via flatfile configuration
+- Switch encryption to RSA
+- Backport IDENTITY from 1.6
--- /dev/null
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+timestamp='2003-02-22'
+
+# This file 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit 0 ;;
+ --version | -v )
+ echo "$version" ; exit 0 ;;
+ --help | --h* | -h )
+ echo "$usage"; exit 0 ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit 0 ;;
+ amiga:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hp300:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ macppc:OpenBSD:*:*)
+ echo powerpc-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme88k:OpenBSD:*:*)
+ echo m88k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvmeppc:OpenBSD:*:*)
+ echo powerpc-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ pmax:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sgi:OpenBSD:*:*)
+ echo mipseb-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ wgrisc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ *:OpenBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ alpha:OSF1:*:*)
+ if test $UNAME_RELEASE = "V4.0"; then
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ fi
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit 0 ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit 0 ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit 0 ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit 0;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit 0 ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit 0 ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit 0 ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit 0;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit 0;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit 0 ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit 0 ;;
+ DRS?6000:UNIX_SV:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7 && exit 0 ;;
+ esac ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit 0 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit 0 ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit 0 ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit 0 ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit 0 ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit 0 ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit 0 ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c \
+ && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+ && exit 0
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit 0 ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit 0 ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit 0 ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit 0 ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit 0 ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit 0 ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit 0 ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit 0 ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit 0 ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit 0 ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit 0 ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit 0 ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
+ echo rs6000-ibm-aix3.2.5
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit 0 ;;
+ *:AIX:*:[45])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit 0 ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit 0 ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit 0 ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit 0 ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit 0 ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit 0 ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit 0 ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ # avoid double evaluation of $set_cc_for_build
+ test -n "$CC_FOR_BUILD" || eval $set_cc_for_build
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
+ echo unknown-hitachi-hiuxwe2
+ exit 0 ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit 0 ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit 0 ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit 0 ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit 0 ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit 0 ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit 0 ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit 0 ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ *:UNICOS/mp:*:*)
+ echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit 0 ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:FreeBSD:*:*)
+ # Determine whether the default compiler uses glibc.
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #if __GLIBC__ >= 2
+ LIBC=gnu
+ #else
+ LIBC=
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC}
+ exit 0 ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit 0 ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit 0 ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit 0 ;;
+ x86:Interix*:3*)
+ echo i586-pc-interix3
+ exit 0 ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit 0 ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit 0 ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit 0 ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit 0 ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ *:GNU:*:*)
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit 0 ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit 0 ;;
+ arm*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ mips:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips
+ #undef mipsel
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mipsel
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+ ;;
+ mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips64
+ #undef mips64el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mips64el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips64
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+ ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit 0 ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit 0 ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit 0 ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit 0 ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit 0 ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit 0 ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit 0 ;;
+ i*86:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ # Set LC_ALL=C to ensure ld outputs messages in English.
+ ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported targets: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ ;;
+ a.out-i386-linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit 0 ;;
+ coff-i386)
+ echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+ exit 0 ;;
+ "")
+ # Either a pre-BFD a.out linker (linux-gnuoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+ exit 0 ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #ifdef __ELF__
+ # ifdef __GLIBC__
+ # if __GLIBC__ >= 2
+ LIBC=gnu
+ # else
+ LIBC=gnulibc1
+ # endif
+ # else
+ LIBC=gnulibc1
+ # endif
+ #else
+ #ifdef __INTEL_COMPILER
+ LIBC=gnu
+ #else
+ LIBC=gnuaout
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+ test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0
+ test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+ ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit 0 ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit 0 ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit 0 ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit 0 ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit 0 ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit 0 ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit 0 ;;
+ i*86:*:5:[78]*)
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit 0 ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit 0 ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit 0 ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit 0 ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit 0 ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit 0 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit 0 ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit 0 ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit 0 ;;
+ M68*:*:R3V[567]*:*)
+ test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+ 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4 && exit 0 ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit 0 ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit 0 ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit 0 ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit 0 ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit 0 ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit 0 ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit 0 ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit 0 ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit 0 ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit 0 ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit 0 ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit 0 ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Darwin:*:*)
+ case `uname -p` in
+ *86) UNAME_PROCESSOR=i686 ;;
+ powerpc) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit 0 ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit 0 ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit 0 ;;
+ NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit 0 ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit 0 ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit 0 ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit 0 ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit 0 ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit 0 ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit 0 ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit 0 ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit 0 ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit 0 ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ c34*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ c38*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ c4*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
--- /dev/null
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+timestamp='2003-02-22'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file 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., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit 0 ;;
+ --version | -v )
+ echo "$version" ; exit 0 ;;
+ --help | --h* | -h )
+ echo "$usage"; exit 0 ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit 0;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis)
+ os=
+ basic_machine=$1
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+ | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k \
+ | m32r | m68000 | m68k | m88k | mcore \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64vr | mips64vrel \
+ | mips64orion | mips64orionel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | msp430 \
+ | ns16k | ns32k \
+ | openrisc | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
+ | strongarm \
+ | tahoe | thumb | tic80 | tron \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xscale | xstormy16 | xtensa \
+ | z8k)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* \
+ | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+ | clipper-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* \
+ | m32r-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | mcore-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | msp430-* \
+ | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* \
+ | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
+ | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tron-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \
+ | xtensa-* \
+ | ymp-* \
+ | z8k-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ mmix*)
+ basic_machine=mmix-knuth
+ os=-mmixware
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nv1)
+ basic_machine=nv1-cray
+ os=-unicosmp
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ or32 | or32-*)
+ basic_machine=or32-unknown
+ os=-coff
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2)
+ basic_machine=i686-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tic4x | c4x*)
+ basic_machine=tic4x-unknown
+ os=-coff
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tic55x | c55x*)
+ basic_machine=tic55x-unknown
+ os=-coff
+ ;;
+ tic6x | c6x*)
+ basic_machine=tic6x-unknown
+ os=-coff
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparc | sparcv9 | sparcv9b)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
--- /dev/null
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.57.
+#
+# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
+# Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+exec 6>&1
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_config_libobj_dir=.
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete. It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS PACKAGE VERSION CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os SET_MAKE RM CP MV INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CPP EGREP ENCRYPT_SRC SSL_INCLUDES SSL_LIBS SENGINE INSTALL_DIR LIBOBJS LTLIBOBJS'
+ac_subst_files=''
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+ac_prev=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_option in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ eval "enable_$ac_feature=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_$ac_feature='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_$ac_package='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/-/_/g'`
+ eval "with_$ac_package=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ eval "$ac_envvar='$ac_optarg'"
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ { echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+ localstatedir libdir includedir oldincludedir infodir mandir
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_confdir=`(dirname "$0") 2>/dev/null ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$0" : 'X\(//\)[^/]' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$0" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
+ { (exit 1); exit 1; }; }
+ else
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+ fi
+fi
+(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+ { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
+ { (exit 1); exit 1; }; }
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+ac_env_CPP_set=${CPP+set}
+ac_env_CPP_value=$CPP
+ac_cv_env_CPP_set=${CPP+set}
+ac_cv_env_CPP_value=$CPP
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+_ACEOF
+
+ cat <<_ACEOF
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --infodir=DIR info documentation [PREFIX/info]
+ --mandir=DIR man documentation [PREFIX/man]
+_ACEOF
+
+ cat <<\_ACEOF
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+ --target=TARGET configure for building compilers for TARGET [HOST]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --disable-hookmodules disable support for loadable hook modules
+ --enable-openssl=DIR Enable OpenSSL support (DIR optional).
+ --disable-openssl Disable OpenSSL support.
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-socketengine=TYPE Set the socketengine type. Choices are:
+ kqueue poll select
+ --with-maxconnections=NUMBER Set the maximum number of sockets.
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have
+ headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_ACEOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ ac_popdir=`pwd`
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d $ac_dir || continue
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be
+# absolute.
+ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd`
+ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd`
+ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd`
+ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd`
+
+ cd $ac_dir
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f $ac_srcdir/configure.gnu; then
+ echo
+ $SHELL $ac_srcdir/configure.gnu --help=recursive
+ elif test -f $ac_srcdir/configure; then
+ echo
+ $SHELL $ac_srcdir/configure --help=recursive
+ elif test -f $ac_srcdir/configure.ac ||
+ test -f $ac_srcdir/configure.in; then
+ echo
+ $ac_configure --help
+ else
+ echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi
+ cd $ac_popdir
+ done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+ cat <<\_ACEOF
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
+Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit 0
+fi
+exec 5>config.log
+cat >&5 <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.57. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+hostinfo = `(hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ echo "PATH: $as_dir"
+done
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_sep=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+ 2)
+ ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+ # Get rid of the leading space.
+ ac_sep=" "
+ ;;
+ esac
+ done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Be sure not to use single quotes in there, as some shells,
+# such as our DU 5.0 friend, will then `close' the trap.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+{
+ (set) 2>&1 |
+ case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ sed -n \
+ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+ ;;
+ *)
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+}
+ echo
+
+ cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ cat <<\_ASBOX
+## ------------- ##
+## Output files. ##
+## ------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+ echo
+ sed "/^$/d" confdefs.h | sort
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ echo "$as_me: caught signal $ac_signal"
+ echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core core.* *.core &&
+ rm -rf conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+ ' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special
+ # files actually), so we avoid doing that.
+ if test -f "$cache_file"; then
+ { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . $cache_file;;
+ *) . ./$cache_file;;
+ esac
+ fi
+else
+ { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in `(set) 2>&1 |
+ sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val="\$ac_cv_env_${ac_var}_value"
+ eval ac_new_val="\$ac_env_${ac_var}_value"
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { echo "$as_me:$LINENO: former value: $ac_old_val" >&5
+echo "$as_me: former value: $ac_old_val" >&2;}
+ { echo "$as_me:$LINENO: current value: $ac_new_val" >&5
+echo "$as_me: current value: $ac_new_val" >&2;}
+ ac_cache_corrupted=:
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ac_config_headers="$ac_config_headers include/setup.h"
+
+
+PACKAGE=bahamut-release
+VERSION=1.8
+
+
+
+# autoheader templates
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --enable-hookmodules or --disable-hookmodules was given.
+if test "${enable_hookmodules+set}" = set; then
+ enableval="$enable_hookmodules"
+
+else
+ check_hmodules="yes"
+fi;
+
+# Check whether --enable-openssl or --disable-openssl was given.
+if test "${enable_openssl+set}" = set; then
+ enableval="$enable_openssl"
+ cf_enable_openssl=$enableval
+else
+ cf_enable_openssl="auto"
+fi;
+
+
+# Check whether --with-socketengine or --without-socketengine was given.
+if test "${with_socketengine+set}" = set; then
+ withval="$with_socketengine"
+ check_sengine=$withval
+else
+ check_sengine="yes"
+fi;
+
+# Check whether --with-maxconnections or --without-maxconnections was given.
+if test "${with_maxconnections+set}" = set; then
+ withval="$with_maxconnections"
+ check_maxconnections=$withval
+else
+ check_maxconnections="auto"
+fi;
+
+
+
+
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_CC" && break
+done
+
+ CC=$ac_ct_CC
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+ "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+echo "$as_me:$LINENO: checking for C compiler default output" >&5
+echo $ECHO_N "checking for C compiler default output... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5
+ (eval $ac_link_default) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Find the output, starting from the most likely. This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+
+# Be careful to initialize this variable, since it used to be cached.
+# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile.
+ac_cv_exeext=
+# b.out is created by i960 compilers.
+for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj )
+ ;;
+ conftest.$ac_ext )
+ # This is the source file.
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ # FIXME: I believe we export ac_cv_exeext for Libtool,
+ # but it would be cool to find out if it's true. Does anybody
+ # maintain Libtool? --akim.
+ export ac_cv_exeext
+ break;;
+ * )
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+ { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ fi
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX 10.20 and later -Ae
+# HP-UX older versions -Aa -D_HPUX_SOURCE
+# SVR4 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+case "x$ac_cv_prog_cc_stdc" in
+ x|xno)
+ echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+ *)
+ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+ CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+# Some people use a C++ compiler to compile C. Since we use `exit',
+# in C++ we need to declare it. In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+ choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ for ac_declaration in \
+ ''\
+ '#include <stdlib.h>' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
+do
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+echo "$as_me:$LINENO: checking CFLAGS for maximum warnings" >&5
+echo $ECHO_N "checking CFLAGS for maximum warnings... $ECHO_C" >&6
+if test "${ac_cv_cflags_warn_all+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_cflags_warn_all="no, unknown"
+
+
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ ac_save_CFLAGS="$CFLAGS"
+for ac_arg in "-pedantic % -Wall" "-xstrconst % -v" "-std1 % -verbose -w0 -warnprotos" "-qlanglvl=ansi % -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" "-ansi -ansiE % -fullwarn" "+ESlit % +w1" "-Xc % -pvctl,fullmsg" "-h conform % -h msglevel 2" #
+do CFLAGS="$ac_save_CFLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_cflags_warn_all=`echo $ac_arg | sed -e 's,.*% *,,'` ; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+done
+ CFLAGS="$ac_save_CFLAGS"
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_cflags_warn_all" >&5
+echo "${ECHO_T}$ac_cv_cflags_warn_all" >&6
+case ".$ac_cv_cflags_warn_all" in
+ .ok|.ok,*) ;;
+ .|.no|.no,*)
+ ;;
+ *)
+ if echo " $CFLAGS " | grep " $ac_cv_cflags_warn_all " 2>&1 >/dev/null
+ then { (echo "$as_me:$LINENO: : CFLAGS does contain \$ac_cv_cflags_warn_all") >&5
+ (: CFLAGS does contain $ac_cv_cflags_warn_all) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ else { (echo "$as_me:$LINENO: : CFLAGS=\"\$CFLAGS \$ac_cv_cflags_warn_all\"") >&5
+ (: CFLAGS="$CFLAGS $ac_cv_cflags_warn_all") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ CFLAGS="$CFLAGS $ac_cv_cflags_warn_all"
+ fi
+ ;;
+esac
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f $ac_dir/shtool; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5
+echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
+
+# Make sure we can run config.sub.
+$ac_config_sub sun4 >/dev/null 2>&1 ||
+ { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5
+echo "$as_me: error: cannot run $ac_config_sub" >&2;}
+ { (exit 1); exit 1; }; }
+
+echo "$as_me:$LINENO: checking build system type" >&5
+echo $ECHO_N "checking build system type... $ECHO_C" >&6
+if test "${ac_cv_build+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_build_alias=$build_alias
+test -z "$ac_cv_build_alias" &&
+ ac_cv_build_alias=`$ac_config_guess`
+test -z "$ac_cv_build_alias" &&
+ { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+ { (exit 1); exit 1; }; }
+ac_cv_build=`$ac_config_sub $ac_cv_build_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+echo "${ECHO_T}$ac_cv_build" >&6
+build=$ac_cv_build
+build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+echo "$as_me:$LINENO: checking host system type" >&5
+echo $ECHO_N "checking host system type... $ECHO_C" >&6
+if test "${ac_cv_host+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_host_alias=$host_alias
+test -z "$ac_cv_host_alias" &&
+ ac_cv_host_alias=$ac_cv_build_alias
+ac_cv_host=`$ac_config_sub $ac_cv_host_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+echo "${ECHO_T}$ac_cv_host" >&6
+host=$ac_cv_host
+host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+echo "$as_me:$LINENO: checking target system type" >&5
+echo $ECHO_N "checking target system type... $ECHO_C" >&6
+if test "${ac_cv_target+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_target_alias=$target_alias
+test "x$ac_cv_target_alias" = "x" &&
+ ac_cv_target_alias=$ac_cv_host_alias
+ac_cv_target=`$ac_config_sub $ac_cv_target_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_target_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_target_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_target" >&5
+echo "${ECHO_T}$ac_cv_target" >&6
+target=$ac_cv_target
+target_cpu=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+target_vendor=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+target_os=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+test -n "$target_alias" &&
+ test "$program_prefix$program_suffix$program_transform_name" = \
+ NONENONEs,x,x, &&
+ program_prefix=${target_alias}-
+echo "$as_me:$LINENO: checking for library containing strerror" >&5
+echo $ECHO_N "checking for library containing strerror... $ECHO_C" >&6
+if test "${ac_cv_search_strerror+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_strerror=no
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char strerror ();
+int
+main ()
+{
+strerror ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_strerror="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_strerror" = no; then
+ for ac_lib in cposix; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char strerror ();
+int
+main ()
+{
+strerror ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_strerror="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_strerror" >&5
+echo "${ECHO_T}$ac_cv_search_strerror" >&6
+if test "$ac_cv_search_strerror" != no; then
+ test "$ac_cv_search_strerror" = "none required" || LIBS="$ac_cv_search_strerror $LIBS"
+
+fi
+
+echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,./+-,__p_,'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.make <<\_ACEOF
+all:
+ @echo 'ac_maketemp="$(MAKE)"'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftest.make
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ SET_MAKE=
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+# Extract the first word of "rm", so it can be a program name with args.
+set dummy rm; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_RM+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $RM in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_RM="$RM" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_RM="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ ;;
+esac
+fi
+RM=$ac_cv_path_RM
+
+if test -n "$RM"; then
+ echo "$as_me:$LINENO: result: $RM" >&5
+echo "${ECHO_T}$RM" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+# Extract the first word of "cp", so it can be a program name with args.
+set dummy cp; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_CP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $CP in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_CP="$CP" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_CP="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ ;;
+esac
+fi
+CP=$ac_cv_path_CP
+
+if test -n "$CP"; then
+ echo "$as_me:$LINENO: result: $CP" >&5
+echo "${ECHO_T}$CP" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+# Extract the first word of "mv", so it can be a program name with args.
+set dummy mv; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_MV+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $MV in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_MV="$MV" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_MV="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ ;;
+esac
+fi
+MV=$ac_cv_path_MV
+
+if test -n "$MV"; then
+ echo "$as_me:$LINENO: result: $MV" >&5
+echo "${ECHO_T}$MV" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+ ./ | .// | /cC/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+done
+
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL=$ac_install_sh
+ fi
+fi
+echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo "$as_me:$LINENO: checking for inline" >&5
+echo $ECHO_N "checking for inline... $ECHO_C" >&6
+if test "${ac_cv_c_inline+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_inline=$ac_kw; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+done
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5
+echo "${ECHO_T}$ac_cv_c_inline" >&6
+case $ac_cv_c_inline in
+ inline | yes) ;;
+ no)
+cat >>confdefs.h <<\_ACEOF
+#define inline
+_ACEOF
+ ;;
+ *) cat >>confdefs.h <<_ACEOF
+#define inline $ac_cv_c_inline
+_ACEOF
+ ;;
+esac
+
+
+
+echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5
+echo $ECHO_N "checking for gethostbyname in -lnsl... $ECHO_C" >&6
+if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname ();
+int
+main ()
+{
+gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_nsl_gethostbyname=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_nsl_gethostbyname=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_lib_nsl_gethostbyname" >&6
+if test $ac_cv_lib_nsl_gethostbyname = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBNSL 1
+_ACEOF
+
+ LIBS="-lnsl $LIBS"
+
+fi
+
+echo "$as_me:$LINENO: checking for res_mkquery" >&5
+echo $ECHO_N "checking for res_mkquery... $ECHO_C" >&6
+if test "${ac_cv_func_res_mkquery+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char res_mkquery (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char res_mkquery ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_res_mkquery) || defined (__stub___res_mkquery)
+choke me
+#else
+char (*f) () = res_mkquery;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != res_mkquery;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_res_mkquery=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_res_mkquery=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_res_mkquery" >&5
+echo "${ECHO_T}$ac_cv_func_res_mkquery" >&6
+if test $ac_cv_func_res_mkquery = yes; then
+ :
+else
+
+echo "$as_me:$LINENO: checking for res_mkquery in -lresolv" >&5
+echo $ECHO_N "checking for res_mkquery in -lresolv... $ECHO_C" >&6
+if test "${ac_cv_lib_resolv_res_mkquery+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lresolv $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char res_mkquery ();
+int
+main ()
+{
+res_mkquery ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_resolv_res_mkquery=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_resolv_res_mkquery=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_resolv_res_mkquery" >&5
+echo "${ECHO_T}$ac_cv_lib_resolv_res_mkquery" >&6
+if test $ac_cv_lib_resolv_res_mkquery = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBRESOLV 1
+_ACEOF
+
+ LIBS="-lresolv $LIBS"
+
+fi
+
+fi
+
+echo "$as_me:$LINENO: checking for __res_mkquery" >&5
+echo $ECHO_N "checking for __res_mkquery... $ECHO_C" >&6
+if test "${ac_cv_func___res_mkquery+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char __res_mkquery (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char __res_mkquery ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub___res_mkquery) || defined (__stub_____res_mkquery)
+choke me
+#else
+char (*f) () = __res_mkquery;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != __res_mkquery;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func___res_mkquery=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func___res_mkquery=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func___res_mkquery" >&5
+echo "${ECHO_T}$ac_cv_func___res_mkquery" >&6
+if test $ac_cv_func___res_mkquery = yes; then
+ :
+else
+
+echo "$as_me:$LINENO: checking for __res_mkquery in -lresolv" >&5
+echo $ECHO_N "checking for __res_mkquery in -lresolv... $ECHO_C" >&6
+if test "${ac_cv_lib_resolv___res_mkquery+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lresolv $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char __res_mkquery ();
+int
+main ()
+{
+__res_mkquery ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_resolv___res_mkquery=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_resolv___res_mkquery=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_resolv___res_mkquery" >&5
+echo "${ECHO_T}$ac_cv_lib_resolv___res_mkquery" >&6
+if test $ac_cv_lib_resolv___res_mkquery = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBRESOLV 1
+_ACEOF
+
+ LIBS="-lresolv $LIBS"
+
+fi
+
+fi
+
+
+echo "$as_me:$LINENO: checking for socket in -lsocket" >&5
+echo $ECHO_N "checking for socket in -lsocket... $ECHO_C" >&6
+if test "${ac_cv_lib_socket_socket+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char socket ();
+int
+main ()
+{
+socket ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_socket_socket=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_socket_socket=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_socket_socket" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_socket" >&6
+if test $ac_cv_lib_socket_socket = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSOCKET 1
+_ACEOF
+
+ LIBS="-lsocket $LIBS"
+
+fi
+
+echo "$as_me:$LINENO: checking for crypt" >&5
+echo $ECHO_N "checking for crypt... $ECHO_C" >&6
+if test "${ac_cv_func_crypt+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char crypt (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char crypt ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_crypt) || defined (__stub___crypt)
+choke me
+#else
+char (*f) () = crypt;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != crypt;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_crypt=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_crypt=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_crypt" >&5
+echo "${ECHO_T}$ac_cv_func_crypt" >&6
+if test $ac_cv_func_crypt = yes; then
+ :
+else
+
+echo "$as_me:$LINENO: checking for crypt in -ldescrypt" >&5
+echo $ECHO_N "checking for crypt in -ldescrypt... $ECHO_C" >&6
+if test "${ac_cv_lib_descrypt_crypt+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldescrypt $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char crypt ();
+int
+main ()
+{
+crypt ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_descrypt_crypt=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_descrypt_crypt=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_descrypt_crypt" >&5
+echo "${ECHO_T}$ac_cv_lib_descrypt_crypt" >&6
+if test $ac_cv_lib_descrypt_crypt = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBDESCRYPT 1
+_ACEOF
+
+ LIBS="-ldescrypt $LIBS"
+
+else
+
+echo "$as_me:$LINENO: checking for crypt in -lcrypt" >&5
+echo $ECHO_N "checking for crypt in -lcrypt... $ECHO_C" >&6
+if test "${ac_cv_lib_crypt_crypt+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypt $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char crypt ();
+int
+main ()
+{
+crypt ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_crypt_crypt=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_crypt_crypt=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_crypt_crypt" >&5
+echo "${ECHO_T}$ac_cv_lib_crypt_crypt" >&6
+if test $ac_cv_lib_crypt_crypt = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBCRYPT 1
+_ACEOF
+
+ LIBS="-lcrypt $LIBS"
+
+fi
+
+fi
+
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if test "${ac_cv_prog_CPP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
+else
+ { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6
+if test "${ac_cv_prog_egrep+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+ then ac_cv_prog_egrep='grep -E'
+ else ac_cv_prog_egrep='egrep'
+ fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5
+echo "${ECHO_T}$ac_cv_prog_egrep" >&6
+ EGREP=$ac_cv_prog_egrep
+
+
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ exit(2);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+
+
+
+for ac_header in fcntl.h limits.h malloc.h netdb.h netinet/in.h stddef.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+
+for ac_header in stdlib.h string.h strings.h sys/file.h sys/ioctl.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+
+for ac_header in sys/param.h sys/socket.h sys/time.h syslog.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in utmp.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+
+
+for ac_header in inttypes.h sys/resource.h errno.h stdlib.h stddef.h getopt.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+echo "$as_me:$LINENO: checking MIN and MAX definition" >&5
+echo $ECHO_N "checking MIN and MAX definition... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#if defined( HAVE_SYS_PARAM_H )
+#include <sys/param.h>
+#ifdef MIN
+ yes
+#endif
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "yes" >/dev/null 2>&1; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_MINMAX 1
+_ACEOF
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest*
+
+
+
+if test $ac_cv_c_compiler_gnu = yes; then
+ echo "$as_me:$LINENO: checking whether $CC needs -traditional" >&5
+echo $ECHO_N "checking whether $CC needs -traditional... $ECHO_C" >&6
+if test "${ac_cv_prog_gcc_traditional+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_pattern="Autoconf.*'x'"
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sgtty.h>
+Autoconf TIOCGETP
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "$ac_pattern" >/dev/null 2>&1; then
+ ac_cv_prog_gcc_traditional=yes
+else
+ ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+ if test $ac_cv_prog_gcc_traditional = no; then
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <termio.h>
+Autoconf TCGETA
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "$ac_pattern" >/dev/null 2>&1; then
+ ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+ fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_gcc_traditional" >&5
+echo "${ECHO_T}$ac_cv_prog_gcc_traditional" >&6
+ if test $ac_cv_prog_gcc_traditional = yes; then
+ CC="$CC -traditional"
+ fi
+fi
+
+
+
+
+
+
+
+for ac_func in alarm dup2 gethostbyname gethostname getpass gettimeofday
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+
+
+
+
+
+for ac_func in inet_ntoa isascii memmove memset munmap setenv socket
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+
+
+
+
+
+for ac_func in strcasecmp strchr strdup strerror strncasecmp strrchr strtol
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+
+
+
+
+
+for ac_func in strtoul index strerror strtoken strtok inet_addr inet_netof
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+
+
+
+
+
+for ac_func in inet_aton gettimeofday lrand48 sigaction bzero bcmp bcopy
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+
+
+
+for ac_func in dn_skipname __dn_skipname getrusage times break
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+case "$target" in
+ *-solaris2*)
+ solaris2="yes"
+ cat >>confdefs.h <<\_ACEOF
+#define OS_SOLARIS2 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define OS_SOLARIS 1
+_ACEOF
+
+ cat >>confdefs.h <<_ACEOF
+#define WRITEV_IOV 16
+_ACEOF
+
+ ;;
+ *-freebsd*)
+ freebsd="yes"
+ cat >>confdefs.h <<_ACEOF
+#define WRITEV_IOV 32
+_ACEOF
+
+ ;;
+ *-netbsd*)
+ cat >>confdefs.h <<_ACEOF
+#define WRITEV_IOV 32
+_ACEOF
+
+ ;;
+ *-openbsd*)
+ cat >>confdefs.h <<_ACEOF
+#define WRITEV_IOV 32
+_ACEOF
+
+ ;;
+ *-linux*)
+ linux="yes"
+ cat >>confdefs.h <<_ACEOF
+#define WRITEV_IOV 32
+_ACEOF
+
+ ;;
+ *aix*)
+ aix="yes"
+ cat >>confdefs.h <<\_ACEOF
+#define AIX 1
+_ACEOF
+
+ ;;
+ *-darwin*)
+ check_hmodules="no"
+ cat >>confdefs.h <<_ACEOF
+#define WRITEV_IOV 32
+_ACEOF
+
+ ;;
+esac
+
+
+set_hmodules="disabled"
+
+if test "$check_hmodules" = "yes"; then
+
+echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBDL 1
+_ACEOF
+
+ LIBS="-ldl $LIBS"
+
+fi
+
+ if test "${ac_cv_header_dlfcn_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for dlfcn.h" >&5
+echo $ECHO_N "checking for dlfcn.h... $ECHO_C" >&6
+if test "${ac_cv_header_dlfcn_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_dlfcn_h" >&5
+echo "${ECHO_T}$ac_cv_header_dlfcn_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking dlfcn.h usability" >&5
+echo $ECHO_N "checking dlfcn.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <dlfcn.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking dlfcn.h presence" >&5
+echo $ECHO_N "checking dlfcn.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <dlfcn.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: dlfcn.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: dlfcn.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: dlfcn.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: dlfcn.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: dlfcn.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: dlfcn.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: dlfcn.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: dlfcn.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: dlfcn.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: dlfcn.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for dlfcn.h" >&5
+echo $ECHO_N "checking for dlfcn.h... $ECHO_C" >&6
+if test "${ac_cv_header_dlfcn_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_dlfcn_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_dlfcn_h" >&5
+echo "${ECHO_T}$ac_cv_header_dlfcn_h" >&6
+
+fi
+
+
+
+
+for ac_func in dlopen dlsym
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+ set_hmodules="enabled"
+fi
+done
+
+ if test "$set_hmodules" = "enabled"; then
+ cat >>confdefs.h <<\_ACEOF
+#define USE_HOOKMODULES 1
+_ACEOF
+
+ MOD_LIBS="-Wl,-export-dynamic"
+ fi
+fi
+
+echo "$as_me:$LINENO: checking for sys_errlist declaration" >&5
+echo $ECHO_N "checking for sys_errlist declaration... $ECHO_C" >&6
+if test "$cross_compiling" = yes; then
+ echo "$as_me:$LINENO: result: cross compiling" >&5
+echo "${ECHO_T}cross compiling" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <errno.h>
+main()
+{
+ char *s = sys_errlist[0];
+ exit(0);
+}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define SYS_ERRLIST_DECLARED 1
+_ACEOF
+
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+save_LIBS="$LIBS"
+
+echo "$as_me:$LINENO: checking for OpenSSL" >&5
+echo $ECHO_N "checking for OpenSSL... $ECHO_C" >&6
+
+if test "X$cf_enable_openssl" != "Xno" ; then
+ cf_openssl_basedir=""
+ if test "X$cf_enable_openssl" != "Xauto" &&
+ test "X$cf_enable_openssl" != "Xyes"; then
+ cf_openssl_basedir="${cf_enable_openssl}"
+ else
+ for dirs in /usr/local/ssl /usr/pkg /usr/local /usr/lib /usr/lib/ssl\
+ /opt /opt/openssl /usr/local/openssl ; do
+ if test -f "${dirs}/include/openssl/opensslv.h" ; then
+ cf_openssl_basedir="${dirs}"
+ break
+ fi
+ done
+ unset dirs
+ fi
+ if test "X$cf_openssl_basedir" != "X" ; then
+ if test -f "${cf_openssl_basedir}/include/openssl/opensslv.h" ; then
+ SSL_INCLUDES="-I${cf_openssl_basedir}/include"
+ SSL_LIBS="-L${cf_openssl_basedir}/lib"
+ else
+ cf_openssl_basedir=""
+ fi
+ else
+ if test -f "/usr/include/openssl/opensslv.h" ; then
+ cf_openssl_basedir="/usr"
+ fi
+ fi
+ if test "X$cf_openssl_basedir" != "X" ; then
+ LIBS="$save_LIBS $SSL_LIBS -lcrypto"
+ echo "$as_me:$LINENO: result: $cf_openssl_basedir" >&5
+echo "${ECHO_T}$cf_openssl_basedir" >&6
+ cf_enable_openssl="yes"
+ encryption="enabled"
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_ENCRYPTION_ON 1
+_ACEOF
+
+ ENCRYPT_SRC="rc4.c dh.c"
+
+ else
+ echo "$as_me:$LINENO: result: not found. Please check your path." >&5
+echo "${ECHO_T}not found. Please check your path." >&6
+ cf_enable_openssl="no"
+ encryption="disabled"
+ fi
+ unset cf_openssl_basedir
+else
+ encryption="disabled"
+ echo "$as_me:$LINENO: result: disabled" >&5
+echo "${ECHO_T}disabled" >&6
+fi
+
+unset save_LIBS
+
+
+
+if test "$check_sengine" = "yes"; then
+ engine="select"
+ if test "$freebsd" = "yes"; then
+ echo "$as_me:$LINENO: checking for kevent" >&5
+echo $ECHO_N "checking for kevent... $ECHO_C" >&6
+if test "${ac_cv_func_kevent+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char kevent (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char kevent ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_kevent) || defined (__stub___kevent)
+choke me
+#else
+char (*f) () = kevent;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != kevent;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_kevent=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_kevent=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_kevent" >&5
+echo "${ECHO_T}$ac_cv_func_kevent" >&6
+if test $ac_cv_func_kevent = yes; then
+ engine="kqueue"
+fi
+
+ elif test "$solaris2" = "yes"; then
+ engine="poll"
+ if test "${ac_cv_header_sys_devpoll_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for sys/devpoll.h" >&5
+echo $ECHO_N "checking for sys/devpoll.h... $ECHO_C" >&6
+if test "${ac_cv_header_sys_devpoll_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_sys_devpoll_h" >&5
+echo "${ECHO_T}$ac_cv_header_sys_devpoll_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking sys/devpoll.h usability" >&5
+echo $ECHO_N "checking sys/devpoll.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <sys/devpoll.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking sys/devpoll.h presence" >&5
+echo $ECHO_N "checking sys/devpoll.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/devpoll.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: sys/devpoll.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: sys/devpoll.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/devpoll.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: sys/devpoll.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: sys/devpoll.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: sys/devpoll.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/devpoll.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: sys/devpoll.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/devpoll.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: sys/devpoll.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for sys/devpoll.h" >&5
+echo $ECHO_N "checking for sys/devpoll.h... $ECHO_C" >&6
+if test "${ac_cv_header_sys_devpoll_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_sys_devpoll_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_sys_devpoll_h" >&5
+echo "${ECHO_T}$ac_cv_header_sys_devpoll_h" >&6
+
+fi
+if test $ac_cv_header_sys_devpoll_h = yes; then
+ engine="devpoll"
+fi
+
+
+ elif test "$linux" = "yes"; then
+ echo "$as_me:$LINENO: checking for poll" >&5
+echo $ECHO_N "checking for poll... $ECHO_C" >&6
+if test "${ac_cv_func_poll+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char poll (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char poll ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_poll) || defined (__stub___poll)
+choke me
+#else
+char (*f) () = poll;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != poll;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_poll=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_poll=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_poll" >&5
+echo "${ECHO_T}$ac_cv_func_poll" >&6
+if test $ac_cv_func_poll = yes; then
+ engine="poll"
+fi
+
+ if test "${ac_cv_header_sys_epoll_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for sys/epoll.h" >&5
+echo $ECHO_N "checking for sys/epoll.h... $ECHO_C" >&6
+if test "${ac_cv_header_sys_epoll_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_sys_epoll_h" >&5
+echo "${ECHO_T}$ac_cv_header_sys_epoll_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking sys/epoll.h usability" >&5
+echo $ECHO_N "checking sys/epoll.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <sys/epoll.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking sys/epoll.h presence" >&5
+echo $ECHO_N "checking sys/epoll.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/epoll.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: sys/epoll.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: sys/epoll.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/epoll.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: sys/epoll.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: sys/epoll.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: sys/epoll.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/epoll.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: sys/epoll.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/epoll.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: sys/epoll.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for sys/epoll.h" >&5
+echo $ECHO_N "checking for sys/epoll.h... $ECHO_C" >&6
+if test "${ac_cv_header_sys_epoll_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_sys_epoll_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_sys_epoll_h" >&5
+echo "${ECHO_T}$ac_cv_header_sys_epoll_h" >&6
+
+fi
+if test $ac_cv_header_sys_epoll_h = yes; then
+ HAVE_EPOLL_H=yes
+else
+ HAVE_EPOLL_H=no
+fi
+
+
+ echo "$as_me:$LINENO: checking for epoll_create in -lepoll" >&5
+echo $ECHO_N "checking for epoll_create in -lepoll... $ECHO_C" >&6
+if test "${ac_cv_lib_epoll_epoll_create+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lepoll $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char epoll_create ();
+int
+main ()
+{
+epoll_create ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_epoll_epoll_create=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_epoll_epoll_create=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_epoll_epoll_create" >&5
+echo "${ECHO_T}$ac_cv_lib_epoll_epoll_create" >&6
+if test $ac_cv_lib_epoll_epoll_create = yes; then
+ LIBS="$LIBS -lepoll"; have_epoll_lib="yes"; engine="epoll"
+else
+ have_epoll_lib="no"
+fi
+
+ if test "$HAVE_EPOLL_H $have_epoll_lib" = "yes no"; then
+ echo "$as_me:$LINENO: checking for epoll_create without -lepoll" >&5
+echo $ECHO_N "checking for epoll_create without -lepoll... $ECHO_C" >&6
+ if test "$cross_compiling" = yes; then
+ { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+ #include <stdint.h>
+ #include <sys/epoll.h>
+ #include <errno.h>
+
+ #include <asm/unistd.h>
+
+ _syscall1(int, epoll_create, int, size)
+
+ int main(int argc, char **argv) { return epoll_create(5) < 1; }
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ have_epoll_lib="yes"
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+have_epoll_lib="no"
+fi
+rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+ echo "$as_me:$LINENO: result: $have_epoll_lib" >&5
+echo "${ECHO_T}$have_epoll_lib" >&6
+ if test "$have_epoll_lib" = "yes"; then
+ cat >>confdefs.h <<\_ACEOF
+#define NEED_EPOLL_DEFS 1
+_ACEOF
+
+ fi
+ fi
+ if test "$HAVE_EPOLL_H $have_epoll_lib" = "yes yes"; then
+ engine="epoll";
+ fi
+ else
+ echo "$as_me:$LINENO: checking for poll" >&5
+echo $ECHO_N "checking for poll... $ECHO_C" >&6
+if test "${ac_cv_func_poll+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char poll (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char poll ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_poll) || defined (__stub___poll)
+choke me
+#else
+char (*f) () = poll;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != poll;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_poll=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_poll=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_poll" >&5
+echo "${ECHO_T}$ac_cv_func_poll" >&6
+if test $ac_cv_func_poll = yes; then
+ engine="poll"
+fi
+
+ fi
+elif test "$check_sengine" = "kqueue"; then
+ echo "$as_me:$LINENO: checking for kevent" >&5
+echo $ECHO_N "checking for kevent... $ECHO_C" >&6
+if test "${ac_cv_func_kevent+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char kevent (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char kevent ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_kevent) || defined (__stub___kevent)
+choke me
+#else
+char (*f) () = kevent;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != kevent;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_kevent=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_kevent=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_kevent" >&5
+echo "${ECHO_T}$ac_cv_func_kevent" >&6
+if test $ac_cv_func_kevent = yes; then
+ engine="kqueue"
+fi
+
+ if test "X$engine" = "X"; then
+ { echo "$as_me:$LINENO: " >&5
+echo "$as_me: " >&6;}
+ { echo "$as_me:$LINENO: kqueue not supported on this platform!" >&5
+echo "$as_me: kqueue not supported on this platform!" >&6;}
+ { { echo "$as_me:$LINENO: error: " >&5
+echo "$as_me: error: " >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ { echo "$as_me:$LINENO: setting socketengine type to kqueue" >&5
+echo "$as_me: setting socketengine type to kqueue" >&6;}
+elif test "$check_sengine" = "poll"; then
+ echo "$as_me:$LINENO: checking for poll" >&5
+echo $ECHO_N "checking for poll... $ECHO_C" >&6
+if test "${ac_cv_func_poll+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char poll (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char poll ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_poll) || defined (__stub___poll)
+choke me
+#else
+char (*f) () = poll;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != poll;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_poll=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_poll=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_poll" >&5
+echo "${ECHO_T}$ac_cv_func_poll" >&6
+if test $ac_cv_func_poll = yes; then
+ engine="poll"
+fi
+
+ if test "X$engine" = "X"; then
+ { echo "$as_me:$LINENO: " >&5
+echo "$as_me: " >&6;}
+ { echo "$as_me:$LINENO: poll not supported on this platform!" >&5
+echo "$as_me: poll not supported on this platform!" >&6;}
+ { { echo "$as_me:$LINENO: error: " >&5
+echo "$as_me: error: " >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ { echo "$as_me:$LINENO: setting socketengine type to poll" >&5
+echo "$as_me: setting socketengine type to poll" >&6;}
+elif test "$check_sengine" = "devpoll"; then
+ if test "${ac_cv_header_sys_devpoll_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for sys/devpoll.h" >&5
+echo $ECHO_N "checking for sys/devpoll.h... $ECHO_C" >&6
+if test "${ac_cv_header_sys_devpoll_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_sys_devpoll_h" >&5
+echo "${ECHO_T}$ac_cv_header_sys_devpoll_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking sys/devpoll.h usability" >&5
+echo $ECHO_N "checking sys/devpoll.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <sys/devpoll.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking sys/devpoll.h presence" >&5
+echo $ECHO_N "checking sys/devpoll.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/devpoll.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: sys/devpoll.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: sys/devpoll.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/devpoll.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: sys/devpoll.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: sys/devpoll.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: sys/devpoll.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/devpoll.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: sys/devpoll.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/devpoll.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: sys/devpoll.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for sys/devpoll.h" >&5
+echo $ECHO_N "checking for sys/devpoll.h... $ECHO_C" >&6
+if test "${ac_cv_header_sys_devpoll_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_sys_devpoll_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_sys_devpoll_h" >&5
+echo "${ECHO_T}$ac_cv_header_sys_devpoll_h" >&6
+
+fi
+if test $ac_cv_header_sys_devpoll_h = yes; then
+ engine="devpoll"
+fi
+
+
+ if test "X$engine" = "X"; then
+ { echo "$as_me:$LINENO: " >&5
+echo "$as_me: " >&6;}
+ { echo "$as_me:$LINENO: /dev/poll not supported on this system" >&5
+echo "$as_me: /dev/poll not supported on this system" >&6;}
+ { { echo "$as_me:$LINENO: error: " >&5
+echo "$as_me: error: " >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ { echo "$as_me:$LINENO: setting socketengine to devpoll" >&5
+echo "$as_me: setting socketengine to devpoll" >&6;}
+elif test "$check_sengine" = "epoll"; then
+ if test "${ac_cv_header_sys_epoll_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for sys/epoll.h" >&5
+echo $ECHO_N "checking for sys/epoll.h... $ECHO_C" >&6
+if test "${ac_cv_header_sys_epoll_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_sys_epoll_h" >&5
+echo "${ECHO_T}$ac_cv_header_sys_epoll_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking sys/epoll.h usability" >&5
+echo $ECHO_N "checking sys/epoll.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <sys/epoll.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking sys/epoll.h presence" >&5
+echo $ECHO_N "checking sys/epoll.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/epoll.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: sys/epoll.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: sys/epoll.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/epoll.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: sys/epoll.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: sys/epoll.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: sys/epoll.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/epoll.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: sys/epoll.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/epoll.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: sys/epoll.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for sys/epoll.h" >&5
+echo $ECHO_N "checking for sys/epoll.h... $ECHO_C" >&6
+if test "${ac_cv_header_sys_epoll_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_sys_epoll_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_sys_epoll_h" >&5
+echo "${ECHO_T}$ac_cv_header_sys_epoll_h" >&6
+
+fi
+if test $ac_cv_header_sys_epoll_h = yes; then
+ HAVE_EPOLL_H=yes
+else
+ HAVE_EPOLL_H=no
+fi
+
+
+ echo "$as_me:$LINENO: checking for epoll_create in -lepoll" >&5
+echo $ECHO_N "checking for epoll_create in -lepoll... $ECHO_C" >&6
+if test "${ac_cv_lib_epoll_epoll_create+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lepoll $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char epoll_create ();
+int
+main ()
+{
+epoll_create ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_epoll_epoll_create=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_epoll_epoll_create=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_epoll_epoll_create" >&5
+echo "${ECHO_T}$ac_cv_lib_epoll_epoll_create" >&6
+if test $ac_cv_lib_epoll_epoll_create = yes; then
+ LIBS="$LIBS -lepoll"; have_epoll_lib="yes"; engine="epoll"
+else
+ have_epoll_lib="no"
+fi
+
+ if test "$HAVE_EPOLL_H $have_epoll_lib" = "yes no"; then
+ echo "$as_me:$LINENO: checking for epoll_create without -lepoll" >&5
+echo $ECHO_N "checking for epoll_create without -lepoll... $ECHO_C" >&6
+ if test "$cross_compiling" = yes; then
+ { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+ #include <stdint.h>
+ #include <sys/epoll.h>
+ #include <errno.h>
+
+ #include <asm/unistd.h>
+
+ _syscall1(int, epoll_create, int, size)
+
+ int main(int argc, char **argv) { return epoll_create(5) < 1; }
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ have_epoll_lib="yes"
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+have_epoll_lib="no"
+fi
+rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+ echo "$as_me:$LINENO: result: $have_epoll_lib" >&5
+echo "${ECHO_T}$have_epoll_lib" >&6
+ if test "$have_epoll_lib" = "yes"; then
+ cat >>confdefs.h <<\_ACEOF
+#define NEED_EPOLL_DEFS 1
+_ACEOF
+
+ fi
+ fi
+ if test "$HAVE_EPOLL_H $have_epoll_lib" != "yes yes"; then
+ { echo "$as_me:$LINENO: " >&5
+echo "$as_me: " >&6;}
+ { { echo "$as_me:$LINENO: error: epoll is not supported on this machine" >&5
+echo "$as_me: error: epoll is not supported on this machine" >&2;}
+ { (exit 1); exit 1; }; }
+ { { echo "$as_me:$LINENO: error: " >&5
+echo "$as_me: error: " >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ { echo "$as_me:$LINENO: setting socketengine type to epoll" >&5
+echo "$as_me: setting socketengine type to epoll" >&6;}
+ engine="epoll";
+elif test "$check_sengine" = "select"; then
+ { echo "$as_me:$LINENO: setting socketengine type to select.. for some stupid reason" >&5
+echo "$as_me: setting socketengine type to select.. for some stupid reason" >&6;}
+ engine="select"
+else
+ { echo "$as_me:$LINENO: " >&5
+echo "$as_me: " >&6;}
+ { echo "$as_me:$LINENO: socket engine type incorrect!" >&5
+echo "$as_me: socket engine type incorrect!" >&6;}
+ { { echo "$as_me:$LINENO: error: " >&5
+echo "$as_me: error: " >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+SENGINE="socketengine_$engine.c"
+
+if test $engine = "select"; then
+ echo "$as_me:$LINENO: checking to see if FD_SETSIZE is broken" >&5
+echo $ECHO_N "checking to see if FD_SETSIZE is broken... $ECHO_C" >&6
+ if test "$cross_compiling" = yes; then
+ echo "$as_me:$LINENO: result: can't tell" >&5
+echo "${ECHO_T}can't tell" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+ #define FD_SETSIZE 666
+ #include <sys/types.h>
+ #include <sys/time.h>
+
+ int main()
+ {
+ if(FD_SETSIZE != 666)
+ exit(1);
+ exit(0);
+ }
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+
+ echo "$as_me:$LINENO: result: YES" >&5
+echo "${ECHO_T}YES" >&6
+ { echo "$as_me:$LINENO: WARNING: FD_SETSIZE is hard set by your operating system" >&5
+echo "$as_me: WARNING: FD_SETSIZE is hard set by your operating system" >&2;}
+ { echo "$as_me:$LINENO: WARNING: MAXCONNECTIONS must be no higher than the hardwired FD_SETSIZE" >&5
+echo "$as_me: WARNING: MAXCONNECTIONS must be no higher than the hardwired FD_SETSIZE" >&2;}
+ cat >>confdefs.h <<\_ACEOF
+#define BROKEN_FD_SETSIZE 1
+_ACEOF
+
+ broken_fd_setsize="yes"
+
+fi
+rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+
+if test "$solaris2" != "yes" && test "$aix" != "yes" &&
+ test "$set_hmodules" = "enabled"; then
+ LIBS="$LIBS $MOD_LIBS"
+fi
+
+if test "$check_maxconnections" = "auto"; then
+
+ echo "$as_me:$LINENO: checking Maximum file descriptors" >&5
+echo $ECHO_N "checking Maximum file descriptors... $ECHO_C" >&6;
+ if test "${maxconnections+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+ #include <sys/types.h>
+ #include <sys/time.h>
+ #include <sys/resource.h>
+ #include <stdio.h>
+ #ifdef RLIMIT_FDMAX
+ #define RLIMIT_FD_MAX RLIMIT_FDMAX
+ #else
+ #ifdef RLIMIT_NOFILE
+ #define RLIMIT_FD_MAX RLIMIT_NOFILE
+ #else
+ #ifdef RLIMIT_OPEN_MAX
+ #define RLIMIT_FD_MAX RLIMIT_OPEN_MAX
+ #else
+ #undef RLIMIT_FD_MAX
+ #endif
+ #endif
+ #endif
+
+
+ int main()
+ {
+ #ifndef BROKEN_FD_SETSIZE
+
+ #ifdef RLIMIT_FD_MAX
+ struct rlimit limit;
+
+ if(!getrlimit(RLIMIT_FD_MAX, &limit))
+ {
+ if(limit.rlim_max > 32768)
+ printf("32768");
+ else
+ printf("%ld", (long) limit.rlim_max);
+ }
+ else
+ #endif
+ printf("256");
+
+ #else
+ printf("%d", FD_SETSIZE);
+ #endif
+ return 0;
+ }
+
+
+_ACEOF
+
+ $CC -o conftest conftest.c >/dev/null 2>&1
+ maxconnections=`./conftest`
+ echo "$as_me:$LINENO: result: $maxconnections" >&5
+echo "${ECHO_T}$maxconnections" >&6
+ $RM -f conftest conftest.c
+
+fi
+
+ cat >>confdefs.h <<_ACEOF
+#define MAXCONNECTIONS ${maxconnections}
+_ACEOF
+
+
+else
+ maxconnections=$check_maxconnections
+ cat >>confdefs.h <<_ACEOF
+#define MAXCONNECTIONS ${maxconnections}
+_ACEOF
+
+fi
+
+if test "$engine" = "select" && test "$broken_fd_setsize" != "yes"; then
+ CFLAGS="$CFLAGS -DFD_SETSIZE=$maxconnections"
+fi
+
+if test $prefix = NONE; then
+ prefix=${HOME}/ircd
+fi
+
+INSTALL_DIR="${prefix}"
+
+
+
+
+
+
+
+ ac_config_files="$ac_config_files Makefile src/Makefile tools/Makefile doc/Makefile"
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+{
+ (set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+} |
+ sed '
+ t clear
+ : clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ : end' >>confcache
+if diff $cache_file confcache >/dev/null 2>&1; then :; else
+ if test -w $cache_file; then
+ test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
+ cat confcache >$cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[ ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[ ]*$//;
+}'
+fi
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_i=`echo "$ac_i" |
+ sed 's/\$U\././;s/\.o$//;s/\.obj$//'`
+ # 2. Add them.
+ ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext"
+ ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
+echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
+echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+exec 6>&1
+
+# Open the log real soon, to keep \$[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling. Logging --version etc. is OK.
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+} >&5
+cat >&5 <<_CSEOF
+
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.57. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+_CSEOF
+echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
+echo >&5
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+ echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+ echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+ echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+ echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to <bug-autoconf@gnu.org>."
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.57,
+ with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+srcdir=$srcdir
+INSTALL="$INSTALL"
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value. By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=*)
+ ac_option=`expr "x$1" : 'x\([^=]*\)='`
+ ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ -*)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ *) # This is not an option, so the user has probably given explicit
+ # arguments.
+ ac_option=$1
+ ac_need_defaults=false;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --vers* | -V )
+ echo "$ac_cs_version"; exit 0 ;;
+ --he | --h)
+ # Conflict between --help and --header
+ { { echo "$as_me:$LINENO: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ echo "$ac_cs_usage"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+ ac_need_defaults=false;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; } ;;
+
+ *) ac_config_targets="$ac_config_targets $1" ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+ echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+ exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+
+
+
+
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_config_target in $ac_config_targets
+do
+ case "$ac_config_target" in
+ # Handling of arguments.
+ "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "src/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
+ "tools/Makefile" ) CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
+ "doc/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+ "include/setup.h" ) CONFIG_HEADERS="$CONFIG_HEADERS include/setup.h" ;;
+ *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason to put it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+ trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+ trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=./confstat$$-$RANDOM
+ (umask 077 && mkdir $tmp)
+} ||
+{
+ echo "$me: cannot create a temporary directory in ." >&2
+ { (exit 1); exit 1; }
+}
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+
+#
+# CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "\$CONFIG_FILES"; then
+ # Protect against being on the right side of a sed subst in config.status.
+ sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+ s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s,@SHELL@,$SHELL,;t t
+s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s,@exec_prefix@,$exec_prefix,;t t
+s,@prefix@,$prefix,;t t
+s,@program_transform_name@,$program_transform_name,;t t
+s,@bindir@,$bindir,;t t
+s,@sbindir@,$sbindir,;t t
+s,@libexecdir@,$libexecdir,;t t
+s,@datadir@,$datadir,;t t
+s,@sysconfdir@,$sysconfdir,;t t
+s,@sharedstatedir@,$sharedstatedir,;t t
+s,@localstatedir@,$localstatedir,;t t
+s,@libdir@,$libdir,;t t
+s,@includedir@,$includedir,;t t
+s,@oldincludedir@,$oldincludedir,;t t
+s,@infodir@,$infodir,;t t
+s,@mandir@,$mandir,;t t
+s,@build_alias@,$build_alias,;t t
+s,@host_alias@,$host_alias,;t t
+s,@target_alias@,$target_alias,;t t
+s,@DEFS@,$DEFS,;t t
+s,@ECHO_C@,$ECHO_C,;t t
+s,@ECHO_N@,$ECHO_N,;t t
+s,@ECHO_T@,$ECHO_T,;t t
+s,@LIBS@,$LIBS,;t t
+s,@PACKAGE@,$PACKAGE,;t t
+s,@VERSION@,$VERSION,;t t
+s,@CC@,$CC,;t t
+s,@CFLAGS@,$CFLAGS,;t t
+s,@LDFLAGS@,$LDFLAGS,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
+s,@ac_ct_CC@,$ac_ct_CC,;t t
+s,@EXEEXT@,$EXEEXT,;t t
+s,@OBJEXT@,$OBJEXT,;t t
+s,@build@,$build,;t t
+s,@build_cpu@,$build_cpu,;t t
+s,@build_vendor@,$build_vendor,;t t
+s,@build_os@,$build_os,;t t
+s,@host@,$host,;t t
+s,@host_cpu@,$host_cpu,;t t
+s,@host_vendor@,$host_vendor,;t t
+s,@host_os@,$host_os,;t t
+s,@target@,$target,;t t
+s,@target_cpu@,$target_cpu,;t t
+s,@target_vendor@,$target_vendor,;t t
+s,@target_os@,$target_os,;t t
+s,@SET_MAKE@,$SET_MAKE,;t t
+s,@RM@,$RM,;t t
+s,@CP@,$CP,;t t
+s,@MV@,$MV,;t t
+s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
+s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
+s,@INSTALL_DATA@,$INSTALL_DATA,;t t
+s,@CPP@,$CPP,;t t
+s,@EGREP@,$EGREP,;t t
+s,@ENCRYPT_SRC@,$ENCRYPT_SRC,;t t
+s,@SSL_INCLUDES@,$SSL_INCLUDES,;t t
+s,@SSL_LIBS@,$SSL_LIBS,;t t
+s,@SENGINE@,$SENGINE,;t t
+s,@INSTALL_DIR@,$INSTALL_DIR,;t t
+s,@LIBOBJS@,$LIBOBJS,;t t
+s,@LTLIBOBJS@,$LTLIBOBJS,;t t
+CEOF
+
+_ACEOF
+
+ cat >>$CONFIG_STATUS <<\_ACEOF
+ # Split the substitutions into bite-sized pieces for seds with
+ # small command number limits, like on Digital OSF/1 and HP-UX.
+ ac_max_sed_lines=48
+ ac_sed_frag=1 # Number of current file.
+ ac_beg=1 # First line for current file.
+ ac_end=$ac_max_sed_lines # Line after last line for current file.
+ ac_more_lines=:
+ ac_sed_cmds=
+ while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ else
+ sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ fi
+ if test ! -s $tmp/subs.frag; then
+ ac_more_lines=false
+ else
+ # The purpose of the label and of the branching condition is to
+ # speed up the sed processing (if there are no `@' at all, there
+ # is no need to browse any of the substitutions).
+ # These are the two extra sed commands mentioned above.
+ (echo ':t
+ /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+ fi
+ ac_sed_frag=`expr $ac_sed_frag + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_lines`
+ fi
+ done
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+ fi
+fi # test -n "$CONFIG_FILES"
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be
+# absolute.
+ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd`
+ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd`
+ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd`
+ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd`
+
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_builddir$INSTALL ;;
+ esac
+
+ if test x"$ac_file" != x-; then
+ { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+ rm -f "$ac_file"
+ fi
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ configure_input=
+ else
+ configure_input="$ac_file. "
+ fi
+ configure_input=$configure_input"Generated from `echo $ac_file_in |
+ sed 's,.*/,,'` by configure."
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo $f;;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo $f
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo $srcdir/$f
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s,@configure_input@,$configure_input,;t t
+s,@srcdir@,$ac_srcdir,;t t
+s,@abs_srcdir@,$ac_abs_srcdir,;t t
+s,@top_srcdir@,$ac_top_srcdir,;t t
+s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t
+s,@builddir@,$ac_builddir,;t t
+s,@abs_builddir@,$ac_abs_builddir,;t t
+s,@top_builddir@,$ac_top_builddir,;t t
+s,@abs_top_builddir@,$ac_abs_top_builddir,;t t
+s,@INSTALL@,$ac_INSTALL,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+ rm -f $tmp/stdin
+ if test x"$ac_file" != x-; then
+ mv $tmp/out $ac_file
+ else
+ cat $tmp/out
+ rm -f $tmp/out
+ fi
+
+done
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+#
+# CONFIG_HEADER section.
+#
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='[ ].*$,\1#\2'
+ac_dC=' '
+ac_dD=',;t'
+# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='$,\1#\2define\3'
+ac_uC=' '
+ac_uD=',;t'
+
+for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo $f;;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo $f
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo $srcdir/$f
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+ # Remove the trailing spaces.
+ sed 's/[ ]*$//' $ac_file_inputs >$tmp/in
+
+_ACEOF
+
+# Transform confdefs.h into two sed scripts, `conftest.defines' and
+# `conftest.undefs', that substitutes the proper values into
+# config.h.in to produce config.h. The first handles `#define'
+# templates, and the second `#undef' templates.
+# And first: Protect against being on the right side of a sed subst in
+# config.status. Protect against being in an unquoted here document
+# in config.status.
+rm -f conftest.defines conftest.undefs
+# Using a here document instead of a string reduces the quoting nightmare.
+# Putting comments in sed scripts is not portable.
+#
+# `end' is used to avoid that the second main sed command (meant for
+# 0-ary CPP macros) applies to n-ary macro definitions.
+# See the Autoconf documentation for `clear'.
+cat >confdef2sed.sed <<\_ACEOF
+s/[\\&,]/\\&/g
+s,[\\$`],\\&,g
+t clear
+: clear
+s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp
+t end
+s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp
+: end
+_ACEOF
+# If some macros were called several times there might be several times
+# the same #defines, which is useless. Nevertheless, we may not want to
+# sort them, since we want the *last* AC-DEFINE to be honored.
+uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines
+sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs
+rm -f confdef2sed.sed
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >>conftest.undefs <<\_ACEOF
+s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */,
+_ACEOF
+
+# Break up conftest.defines because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS
+echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS
+echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS
+echo ' :' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.defines >/dev/null
+do
+ # Write a limited-size here document to $tmp/defines.sed.
+ echo ' cat >$tmp/defines.sed <<CEOF' >>$CONFIG_STATUS
+ # Speed up: don't consider the non `#define' lines.
+ echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS
+ # Work around the forget-to-reset-the-flag bug.
+ echo 't clr' >>$CONFIG_STATUS
+ echo ': clr' >>$CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS
+ echo 'CEOF
+ sed -f $tmp/defines.sed $tmp/in >$tmp/out
+ rm -f $tmp/in
+ mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail
+ rm -f conftest.defines
+ mv conftest.tail conftest.defines
+done
+rm -f conftest.defines
+echo ' fi # grep' >>$CONFIG_STATUS
+echo >>$CONFIG_STATUS
+
+# Break up conftest.undefs because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo ' # Handle all the #undef templates' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.undefs >/dev/null
+do
+ # Write a limited-size here document to $tmp/undefs.sed.
+ echo ' cat >$tmp/undefs.sed <<CEOF' >>$CONFIG_STATUS
+ # Speed up: don't consider the non `#undef'
+ echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS
+ # Work around the forget-to-reset-the-flag bug.
+ echo 't clr' >>$CONFIG_STATUS
+ echo ': clr' >>$CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS
+ echo 'CEOF
+ sed -f $tmp/undefs.sed $tmp/in >$tmp/out
+ rm -f $tmp/in
+ mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail
+ rm -f conftest.undefs
+ mv conftest.tail conftest.undefs
+done
+rm -f conftest.undefs
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ echo "/* Generated by configure. */" >$tmp/config.h
+ else
+ echo "/* $ac_file. Generated by configure. */" >$tmp/config.h
+ fi
+ cat $tmp/in >>$tmp/config.h
+ rm -f $tmp/in
+ if test x"$ac_file" != x-; then
+ if diff $ac_file $tmp/config.h >/dev/null 2>&1; then
+ { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ rm -f $ac_file
+ mv $tmp/config.h $ac_file
+ fi
+ else
+ cat $tmp/config.h
+ rm -f $tmp/config.h
+ fi
+done
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || { (exit 1); exit 1; }
+fi
+
+
+echo configuring zlib...
+(
+ cd zlib
+ ./configure
+ cd ..
+)
+
+echo ""
+echo " ******* Bahamut Configuration Settings *******"
+echo " System Build Type: $target"
+echo " Socket Engine Type: $engine"
+echo " Encryption: $encryption"
+echo " Loadable Modules: $set_hmodules"
+echo " Maximum Connections: $maxconnections"
+echo " Install Directory: $prefix"
+echo ""
--- /dev/null
+dnl Process this file with autoconf to produce a configure script.
+dnl rewritten for my own personal sanity, and for more extensive
+dnl checks - feb04 -epi
+
+AC_INIT
+
+AC_CONFIG_HEADER(include/setup.h)
+
+PACKAGE=bahamut-release
+VERSION=1.8
+AC_SUBST(PACKAGE)
+AC_SUBST(VERSION)
+
+# autoheader templates
+
+AH_TEMPLATE([BROKEN_FD_SETSIZE],[If on a system with a broken FD_SETSIZE])
+AH_TEMPLATE([HAVE_ENCRYPTION_ON],[If we support encryption])
+AH_TEMPLATE([HAVE_MINMAX],[If we have the MIN and MAX macros])
+AH_TEMPLATE([OS_SOLARIS2],[If we're running on Solaris])
+AH_TEMPLATE([OS_SOLARIS],[Not quite sure why we have two of these])
+AH_TEMPLATE([SYS_ERRLIST_DECLARED],[If the sys_errlist array is defined])
+AH_TEMPLATE([USE_HOOKMODULES],[Do we support loadable modules])
+AH_TEMPLATE([MAXCONNECTIONS],[Maximum Connections we allow])
+AH_TEMPLATE([NEED_EPOLL_DEFS],[epoll behavior])
+AH_TEMPLATE([AIX],[AIX support])
+AH_TEMPLATE([WRITEV_IOV],[Maxmimum number of iovecs supported by writev()])
+
+dnl Put our options of here for ease of reading.
+
+AC_ARG_ENABLE(hookmodules,
+[ --disable-hookmodules disable support for loadable hook modules],,
+[ check_hmodules="yes" ])
+
+AC_ARG_ENABLE(openssl,
+[ --enable-openssl[=DIR] Enable OpenSSL support (DIR optional).
+ --disable-openssl Disable OpenSSL support. ],
+[ cf_enable_openssl=$enableval ],
+[ cf_enable_openssl="auto" ])
+
+AC_ARG_WITH(socketengine,
+[ --with-socketengine=TYPE Set the socketengine type. Choices are:
+ kqueue poll select ],
+[ check_sengine=$withval ],
+[ check_sengine="yes" ])
+AC_ARG_WITH(maxconnections,
+[ --with-maxconnections=NUMBER Set the maximum number of sockets.],
+[ check_maxconnections=$withval ],
+[ check_maxconnections="auto" ])
+
+dnl -----------------------------------------------------------------
+dnl this adds our check for proper warnings checks
+dnl http://ac-archive.sourceforge.net/guidod/ax_cflags_warn_all.html
+dnl handy.
+
+AC_DEFUN([AX_CFLAGS_WARN_ALL],[dnl
+AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl
+AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_warn_all])dnl
+AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum warnings],
+VAR,[VAR="no, unknown"
+ AC_LANG_SAVE
+ AC_LANG_C
+ ac_save_[]FLAGS="$[]FLAGS"
+for ac_arg dnl
+in "-pedantic % -Wall" dnl GCC
+ "-xstrconst % -v" dnl Solaris C
+ "-std1 % -verbose -w0 -warnprotos" dnl Digital Unix
+ "-qlanglvl=ansi % -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX
+ "-ansi -ansiE % -fullwarn" dnl IRIX
+ "+ESlit % +w1" dnl HP-UX C
+ "-Xc % -pvctl[,]fullmsg" dnl NEC SX-5 (Super-UX 10)
+ "-h conform % -h msglevel 2" dnl Cray C (Unicos)
+ #
+do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
+ AC_TRY_COMPILE([],[return 0;],
+ [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
+done
+ FLAGS="$ac_save_[]FLAGS"
+ AC_LANG_RESTORE
+])
+case ".$VAR" in
+ .ok|.ok,*) m4_ifvaln($3,$3) ;;
+ .|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[
+ AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])
+ m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;;
+ *) m4_ifvaln($3,$3,[
+ if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null
+ then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR])
+ else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"])
+ m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"
+ fi ]) ;;
+esac
+AS_VAR_POPDEF([VAR])dnl
+AS_VAR_POPDEF([FLAGS])dnl
+])
+
+dnl the only difference - the LANG selection... and the default FLAGS
+
+AC_DEFUN([AX_CXXFLAGS_WARN_ALL],[dnl
+AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl
+AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_warn_all])dnl
+AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum warnings],
+VAR,[VAR="no, unknown"
+ AC_LANG_SAVE
+ AC_LANG_CXX
+ ac_save_[]FLAGS="$[]FLAGS"
+for ac_arg dnl
+in "-pedantic % -Wall" dnl GCC
+ "-xstrconst % -v" dnl Solaris C
+ "-std1 % -verbose -w0 -warnprotos" dnl Digital Unix
+ "-qlanglvl=ansi % -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX
+ "-ansi -ansiE % -fullwarn" dnl IRIX
+ "+ESlit % +w1" dnl HP-UX C
+ "-Xc % -pvctl[,]fullmsg" dnl NEC SX-5 (Super-UX 10)
+ "-h conform % -h msglevel 2" dnl Cray C (Unicos)
+ #
+do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
+ AC_TRY_COMPILE([],[return 0;],
+ [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
+done
+ FLAGS="$ac_save_[]FLAGS"
+ AC_LANG_RESTORE
+])
+case ".$VAR" in
+ .ok|.ok,*) m4_ifvaln($3,$3) ;;
+ .|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[
+ AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])
+ m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;;
+ *) m4_ifvaln($3,$3,[
+ if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null
+ then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR])
+ else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"])
+ m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"
+ fi ]) ;;
+esac
+AS_VAR_POPDEF([VAR])dnl
+AS_VAR_POPDEF([FLAGS])dnl
+])
+
+dnl implementation tactics:
+dnl the for-argument contains a list of options. The first part of
+dnl these does only exist to detect the compiler - usually it is
+dnl a global option to enable -ansi or -extrawarnings. All other
+dnl compilers will fail about it. That was needed since a lot of
+dnl compilers will give false positives for some option-syntax
+dnl like -Woption or -Xoption as they think of it is a pass-through
+dnl to later compile stages or something. The "%" is used as a
+dnl delimimiter. A non-option comment can be given after "%%" marks.
+
+dnl -------------------------------------------------------------------
+
+dnl Checks for programs.
+AC_PROG_CC
+AX_CFLAGS_WARN_ALL
+AC_CANONICAL_SYSTEM
+AC_ISC_POSIX
+AC_PROG_MAKE_SET
+AC_PATH_PROG(RM, rm)
+AC_PATH_PROG(CP, cp)
+AC_PATH_PROG(MV, mv)
+AC_PROG_INSTALL
+AC_C_INLINE
+
+dnl Checks for libraries.
+dnl Replace `main' with a function in -lnsl:
+AC_CHECK_LIB(nsl, gethostbyname)
+AC_CHECK_FUNC(res_mkquery,, AC_CHECK_LIB(resolv, res_mkquery))
+AC_CHECK_FUNC(__res_mkquery,, AC_CHECK_LIB(resolv, __res_mkquery))
+AC_CHECK_LIB(socket, socket)
+AC_CHECK_FUNC(crypt,, AC_CHECK_LIB(descrypt, crypt,,AC_CHECK_LIB(crypt, crypt,,)))
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS([fcntl.h limits.h malloc.h netdb.h netinet/in.h stddef.h])
+AC_CHECK_HEADERS([stdlib.h string.h strings.h sys/file.h sys/ioctl.h])
+AC_CHECK_HEADERS([sys/param.h sys/socket.h sys/time.h syslog.h unistd.h])
+AC_CHECK_HEADERS([utmp.h])
+AC_CHECK_HEADERS(inttypes.h sys/resource.h errno.h stdlib.h stddef.h getopt.h)
+AC_MSG_CHECKING(MIN and MAX definition)
+AC_EGREP_CPP(yes,
+[
+#if defined( HAVE_SYS_PARAM_H )
+#include <sys/param.h>
+#ifdef MIN
+ yes
+#endif
+#endif
+], AC_DEFINE(HAVE_MINMAX) AC_MSG_RESULT(yes), AC_MSG_RESULT(no))
+
+
+dnl Checks for library functions.
+AC_PROG_GCC_TRADITIONAL
+AC_CHECK_FUNCS([alarm dup2 gethostbyname gethostname getpass gettimeofday])
+AC_CHECK_FUNCS([inet_ntoa isascii memmove memset munmap setenv socket])
+AC_CHECK_FUNCS([strcasecmp strchr strdup strerror strncasecmp strrchr strtol])
+AC_CHECK_FUNCS([strtoul index strerror strtoken strtok inet_addr inet_netof])
+AC_CHECK_FUNCS([inet_aton gettimeofday lrand48 sigaction bzero bcmp bcopy])
+AC_CHECK_FUNCS([dn_skipname __dn_skipname getrusage times break])
+
+dnl check for various OSes
+
+case "$target" in
+ *-solaris2*)
+ solaris2="yes"
+ AC_DEFINE(OS_SOLARIS2)
+ AC_DEFINE(OS_SOLARIS)
+ AC_DEFINE_UNQUOTED(WRITEV_IOV, 16)
+ ;;
+ *-freebsd*)
+ freebsd="yes"
+ AC_DEFINE_UNQUOTED(WRITEV_IOV, 32)
+ ;;
+ *-netbsd*)
+ AC_DEFINE_UNQUOTED(WRITEV_IOV, 32)
+ ;;
+ *-openbsd*)
+ AC_DEFINE_UNQUOTED(WRITEV_IOV, 32)
+ ;;
+ *-linux*)
+ linux="yes"
+ AC_DEFINE_UNQUOTED(WRITEV_IOV, 32)
+ ;;
+ *aix*)
+ aix="yes"
+ AC_DEFINE(AIX)
+ ;;
+ *-darwin*)
+ check_hmodules="no"
+ AC_DEFINE_UNQUOTED(WRITEV_IOV, 32)
+ ;;
+esac
+
+dnl Checks for loadable hook module support
+
+set_hmodules="disabled"
+
+if test "$check_hmodules" = "yes"; then
+ AC_CHECK_LIB(dl, dlopen)
+ AC_CHECK_HEADER(dlfcn.h)
+ AC_CHECK_FUNCS(dlopen dlsym, [set_hmodules="enabled"])
+ if test "$set_hmodules" = "enabled"; then
+ AC_DEFINE(USE_HOOKMODULES)
+ MOD_LIBS="-Wl,-export-dynamic"
+ fi
+fi
+
+dnl Check for sys_errlist
+dnl Stolen from BitchX
+AC_MSG_CHECKING(for sys_errlist declaration)
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <stdio.h>
+#include <errno.h>
+main()
+{
+ char *s = sys_errlist[0];
+ exit(0);
+}
+],
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(SYS_ERRLIST_DECLARED),
+ AC_MSG_RESULT(no), AC_MSG_RESULT(cross compiling))
+
+dnl Openssl checks - combination of our old way and the hybrid7 method
+
+save_LIBS="$LIBS"
+
+AC_MSG_CHECKING(for OpenSSL)
+
+if test "X$cf_enable_openssl" != "Xno" ; then
+ cf_openssl_basedir=""
+ if test "X$cf_enable_openssl" != "Xauto" &&
+ test "X$cf_enable_openssl" != "Xyes"; then
+ dnl Support for --enable-openssl=/some/place
+ cf_openssl_basedir="${cf_enable_openssl}"
+ else
+ dnl Do the auto-probe here. Check some common directory paths.
+ for dirs in /usr/local/ssl /usr/pkg /usr/local /usr/lib /usr/lib/ssl\
+ /opt /opt/openssl /usr/local/openssl ; do
+ if test -f "${dirs}/include/openssl/opensslv.h" ; then
+ cf_openssl_basedir="${dirs}"
+ break
+ fi
+ done
+ unset dirs
+ fi
+ dnl Now check cf_openssl_found to see if we found anything.
+ if test "X$cf_openssl_basedir" != "X" ; then
+ if test -f "${cf_openssl_basedir}/include/openssl/opensslv.h" ; then
+ SSL_INCLUDES="-I${cf_openssl_basedir}/include"
+ SSL_LIBS="-L${cf_openssl_basedir}/lib"
+ else
+ dnl OpenSSL wasn't found in the directory specified. Naughty
+ dnl administrator...
+ cf_openssl_basedir=""
+ fi
+ else
+ dnl Check for stock FreeBSD 4.x and 5.x systems, since their files
+ dnl are in /usr/include and /usr/lib. In this case, we don't want to
+ dnl change INCLUDES or LIBS, but still want to enable OpenSSL.
+ dnl We can't do this check above, because some people want two versions
+ dnl of OpenSSL installed (stock FreeBSD 4.x/5.x and /usr/local/ssl)
+ dnl and they want /usr/local/ssl to have preference.
+ if test -f "/usr/include/openssl/opensslv.h" ; then
+ cf_openssl_basedir="/usr"
+ fi
+ fi
+ dnl If we have a basedir defined, then everything is okay. Otherwise,
+ dnl we have a problem.
+ if test "X$cf_openssl_basedir" != "X" ; then
+ LIBS="$save_LIBS $SSL_LIBS -lcrypto"
+ AC_MSG_RESULT($cf_openssl_basedir)
+ cf_enable_openssl="yes"
+ encryption="enabled"
+ AC_DEFINE(HAVE_ENCRYPTION_ON)
+ ENCRYPT_SRC="rc4.c dh.c"
+ AC_SUBST(ENCRYPT_SRC)
+ else
+ AC_MSG_RESULT(not found. Please check your path.)
+ cf_enable_openssl="no"
+ encryption="disabled"
+ fi
+ unset cf_openssl_basedir
+else
+ dnl If --disable-openssl was specified
+ encryption="disabled"
+ AC_MSG_RESULT(disabled)
+fi
+
+unset save_LIBS
+
+dnl end of openssl library test
+
+dnl once we add epoll and /dev/poll support, these will be
+dnl updated with the appropriate checks
+
+if test "$check_sengine" = "yes"; then
+ engine="select"
+ if test "$freebsd" = "yes"; then
+ AC_CHECK_FUNC(kevent, [ engine="kqueue" ], )
+ elif test "$solaris2" = "yes"; then
+ engine="poll"
+ AC_CHECK_HEADER(sys/devpoll.h, engine="devpoll", )
+ elif test "$linux" = "yes"; then
+ AC_CHECK_FUNC(poll, [ engine="poll" ], )
+ AC_CHECK_HEADER(sys/epoll.h, HAVE_EPOLL_H=yes, HAVE_EPOLL_H=no)
+ AC_CHECK_LIB(epoll, epoll_create,
+ [LIBS="$LIBS -lepoll"; have_epoll_lib="yes"; engine="epoll"],
+ have_epoll_lib="no")
+ if test "$HAVE_EPOLL_H $have_epoll_lib" = "yes no"; then
+ AC_MSG_CHECKING(for epoll_create [without -lepoll])
+ AC_TRY_RUN([
+ #include <stdint.h>
+ #include <sys/epoll.h>
+ #include <errno.h>
+
+ #include <asm/unistd.h>
+
+ _syscall1(int, epoll_create, int, size)
+
+ int main(int argc, char **argv) { return epoll_create(5) < 1; }
+ ],
+ have_epoll_lib="yes", have_epoll_lib="no")
+ AC_MSG_RESULT($have_epoll_lib)
+ if test "$have_epoll_lib" = "yes"; then
+ AC_DEFINE(NEED_EPOLL_DEFS)
+ fi
+ fi
+ if test "$HAVE_EPOLL_H $have_epoll_lib" = "yes yes"; then
+ engine="epoll";
+ fi
+ else
+ AC_CHECK_FUNC(poll, [ engine="poll"], )
+ fi
+elif test "$check_sengine" = "kqueue"; then
+ AC_CHECK_FUNC(kevent, [ engine="kqueue" ], )
+ if test "X$engine" = "X"; then
+ AC_MSG_NOTICE()
+ AC_MSG_NOTICE(kqueue not supported on this platform!)
+ AC_MSG_ERROR()
+ fi
+ AC_MSG_NOTICE(setting socketengine type to kqueue)
+elif test "$check_sengine" = "poll"; then
+ AC_CHECK_FUNC(poll, [ engine="poll" ], )
+ if test "X$engine" = "X"; then
+ AC_MSG_NOTICE()
+ AC_MSG_NOTICE(poll not supported on this platform!)
+ AC_MSG_ERROR()
+ fi
+ AC_MSG_NOTICE(setting socketengine type to poll)
+elif test "$check_sengine" = "devpoll"; then
+ AC_CHECK_HEADER(sys/devpoll.h, engine="devpoll", )
+ if test "X$engine" = "X"; then
+ AC_MSG_NOTICE()
+ AC_MSG_NOTICE(/dev/poll not supported on this system)
+ AC_MSG_ERROR()
+ fi
+ AC_MSG_NOTICE(setting socketengine to devpoll)
+elif test "$check_sengine" = "epoll"; then
+ AC_CHECK_HEADER(sys/epoll.h, HAVE_EPOLL_H=yes, HAVE_EPOLL_H=no)
+ AC_CHECK_LIB(epoll, epoll_create,
+ [LIBS="$LIBS -lepoll"; have_epoll_lib="yes"; engine="epoll"],
+ have_epoll_lib="no")
+ if test "$HAVE_EPOLL_H $have_epoll_lib" = "yes no"; then
+ AC_MSG_CHECKING(for epoll_create [without -lepoll])
+ AC_TRY_RUN([
+ #include <stdint.h>
+ #include <sys/epoll.h>
+ #include <errno.h>
+
+ #include <asm/unistd.h>
+
+ _syscall1(int, epoll_create, int, size)
+
+ int main(int argc, char **argv) { return epoll_create(5) < 1; }
+ ],
+ have_epoll_lib="yes", have_epoll_lib="no")
+ AC_MSG_RESULT($have_epoll_lib)
+ if test "$have_epoll_lib" = "yes"; then
+ AC_DEFINE(NEED_EPOLL_DEFS)
+ fi
+ fi
+ if test "$HAVE_EPOLL_H $have_epoll_lib" != "yes yes"; then
+ AC_MSG_NOTICE()
+ AC_MSG_ERROR(epoll is not supported on this machine)
+ AC_MSG_ERROR()
+ fi
+ AC_MSG_NOTICE(setting socketengine type to epoll)
+ engine="epoll";
+elif test "$check_sengine" = "select"; then
+ AC_MSG_NOTICE(setting socketengine type to select.. for some stupid reason)
+ engine="select"
+else
+ AC_MSG_NOTICE()
+ AC_MSG_NOTICE(socket engine type incorrect!)
+ AC_MSG_ERROR()
+fi
+
+SENGINE="socketengine_$engine.c"
+
+dnl Check to see if we have a broken FD_SETSIZE
+if test $engine = "select"; then
+ AC_MSG_CHECKING(to see if FD_SETSIZE is broken)
+ AC_TRY_RUN([
+ #define FD_SETSIZE 666
+ #include <sys/types.h>
+ #include <sys/time.h>
+
+ int main()
+ {
+ if(FD_SETSIZE != 666)
+ exit(1);
+ exit(0);
+ }
+ ],
+ AC_MSG_RESULT(no),
+ [
+ AC_MSG_RESULT(YES)
+ AC_MSG_WARN(FD_SETSIZE is hard set by your operating system)
+ AC_MSG_WARN(MAXCONNECTIONS must be no higher than the hardwired FD_SETSIZE)
+ AC_DEFINE(BROKEN_FD_SETSIZE)
+ broken_fd_setsize="yes"
+ ],
+ AC_MSG_RESULT(can't tell))
+fi
+
+if test "$solaris2" != "yes" && test "$aix" != "yes" &&
+ test "$set_hmodules" = "enabled"; then
+ LIBS="$LIBS $MOD_LIBS"
+fi
+
+if test "$check_maxconnections" = "auto"; then
+
+ AC_MSG_CHECKING(Maximum file descriptors);
+ AC_CACHE_VAL(maxconnections,
+[
+
+AC_LANG_CONFTEST(
+ [AC_LANG_SOURCE([[
+ #include <sys/types.h>
+ #include <sys/time.h>
+ #include <sys/resource.h>
+ #include <stdio.h>
+ #ifdef RLIMIT_FDMAX
+ #define RLIMIT_FD_MAX RLIMIT_FDMAX
+ #else
+ #ifdef RLIMIT_NOFILE
+ #define RLIMIT_FD_MAX RLIMIT_NOFILE
+ #else
+ #ifdef RLIMIT_OPEN_MAX
+ #define RLIMIT_FD_MAX RLIMIT_OPEN_MAX
+ #else
+ #undef RLIMIT_FD_MAX
+ #endif
+ #endif
+ #endif
+
+
+ int main()
+ {
+ #ifndef BROKEN_FD_SETSIZE
+
+ #ifdef RLIMIT_FD_MAX
+ struct rlimit limit;
+
+ if(!getrlimit(RLIMIT_FD_MAX, &limit))
+ {
+ if(limit.rlim_max > 32768)
+ printf("32768");
+ else
+ printf("%ld", (long) limit.rlim_max);
+ }
+ else
+ #endif
+ printf("256");
+
+ #else
+ printf("%d", FD_SETSIZE);
+ #endif
+ return 0;
+ }
+ ]])
+])
+
+ $CC -o conftest conftest.c >/dev/null 2>&1
+ maxconnections=`./conftest`
+ AC_MSG_RESULT($maxconnections)
+ $RM -f conftest conftest.c
+])
+ AC_DEFINE_UNQUOTED(MAXCONNECTIONS, ${maxconnections})
+
+else
+ maxconnections=$check_maxconnections
+ AC_DEFINE_UNQUOTED(MAXCONNECTIONS, ${maxconnections})
+fi
+
+if test "$engine" = "select" && test "$broken_fd_setsize" != "yes"; then
+ CFLAGS="$CFLAGS -DFD_SETSIZE=$maxconnections"
+fi
+
+if test $prefix = NONE; then
+ prefix=${HOME}/ircd
+fi
+
+INSTALL_DIR="${prefix}"
+
+AC_SUBST(SSL_INCLUDES)
+AC_SUBST(SSL_LIBS)
+AC_SUBST(LIBS)
+AC_SUBST(SENGINE)
+AC_SUBST(INSTALL_DIR)
+
+AC_OUTPUT(Makefile src/Makefile tools/Makefile doc/Makefile)
+
+echo configuring zlib...
+(
+ cd zlib
+ ./configure
+ cd ..
+)
+
+echo ""
+echo " ******* Bahamut Configuration Settings *******"
+echo " System Build Type: $target"
+echo " Socket Engine Type: $engine"
+echo " Encryption: $encryption"
+echo " Loadable Modules: $set_hmodules"
+echo " Maximum Connections: $maxconnections"
+echo " Install Directory: $prefix"
+echo ""
--- /dev/null
+Bahamut was taken on by a group of loosely knit coders that decided that
+Dreamforge just was eating up too much CPU to handle DALnet's growing user
+base. Originally starting out as the DFhybrid project, it slowly grew
+into the Bahamut project as the peices started falling together.
+
+Bahamut is based upon the hybrid IRCd, developed for EFnet, and we most
+surely wouldn't be where we are today without the dedication of the coders
+that developed that IRCd. The Hybrid team is outlined in the file
+included with this distribution, in doc/Hybrid-team. Please look over
+that file, those people are as much to credit for this as the people
+listed here.
+
+People who have supported the Bahamut project with code, support, or
+testing are, in alphabetical order:
+
+Aaron Wiebe epiphani@dal.net
+Chip Norkus wd@dal.net
+David Friedman driz@dal.net
+David Knepper dakal@dal.net
+David Parton sedition@dal.net
+Diane Bruce db@koruna.varner.com
+Ian Westcott rakarra@dal.net
+Jason Slagle raistlin@bahamut.net
+Karthik Arumugham karthik@karthik.com
+Kevin Turner kevin@dal.net
+Lucas Madar lucas@dal.net
+Mark Salerno msofty@dal.net
+Peter Wood doc_z@dal.net
+Ryan Smith xpsycho@dal.net
+Sven Nielsen dalvenjah@dal.net
+
+Thanks goes out to all those not listed here, your help is much
+appreciated.
+
+Feel free to contact the Bahamut team with any bugs, bug fixes, and the
+like at: coders@dal.net
+
+Also, there is a public mailing list for bahamut: dalnet-src@dal.net.
+This list would be the place to send suggestions and comments regarding
+Bahamut.
+
+And, last but not least, the Bahamut website is at http://bahamut.dal.net.
+
+Thanks for the Support,
+The Bahamut Coding Team
--- /dev/null
+Changes for 1.4.36
+- Fix bug that caused bans to be expired ~1 million times on startup
+- Remove opers from fdlists that are set -o via SVSMODE
+- Only show IPs of unknowns or clients to opers in /trace
+- Use OpenSSL instead of GMP for encryption (much cleaner! :)
+- Remove non-SSJOIN support
+- Allow for a server to detect it is out of synch, and request a
+ channel resynch from an upstream hub
+- Fix remote /stats k/K/a bug (it works now :)
+- Optimize some sendto() things that are used a lot
+- Add usermode +I (server hiding)
+ - Fix /whois, /admin, /who, etc to not allow a user to discover which
+ server a +I user is on
+- Don't let *MY* opers /kill U: lined things (but pass on kills destined for them already)
+- Chatops don't require you to be +gb (now, just +b)
+- Various typos fixed
+- No longer complain if a user is already on a +i channel, and they /join it
+- Use hash tables for very common res functions, which were taking up
+ as much as 80% of CPU time in a pooled server
+- add a command, /userip, for opers. Works just like /userhost.
+- Allow /who +c @#channel +#channel @+#channel for more refined /who listings
+- Add a /who flag for opers, +/-t, clients who have been on for more/less than <param> seconds
+- Don't let opers get stuck in weird anti-flooding bugs (oper recvq lock bug)
+- When an oper deopers, they are returned to the appropriate client class
+- Allow opers to /who +l <class> for local clients (class = Y: class)
+- Send optimizations for high-volume server connections
+- Remove fdlists for lists of clients and instead use linked lists for things:
+ - recvq clients, instead of searching through *all* clients
+ - listing clients, ditto
+- Remove certain things which actually caused poor server operation:
+ - HTM - relax sending out when we have high incoming traffic.
+ This actually causes a nasty bursty cycle.
+ - busy clients
+ This was taking up a great deal of CPU time to save CPU time. Hmm.
+- Rewrite the entire base socket engine; now supports kqueue on freebsd.
+ - Poll() and select() use persistant states, so these should be twice as fast as well.
+ - Stop remapping fds. What's the point?
+- /stats w reports fd map (don't use this on a large server! :)
+- /stats z is more informative
+- Hide the source servers of numerics (mask them with me.name)
+- Hide /kill sources in quit messages (still in +s, though) and in messages
+ sent to killed client
+- Hide split sources in quit messages
+- Add a LINKSCONTROL command which allows a services-controlled /links list
+- Better server traffic accounting in /stats ? (uses a moving average instead of a plain average)
+- Fix a bug in which connecting servers will always remove a key if the channel exists (argh!)
+- Correctly propogate cmode +O
+- Show more squelched info in /whois to opers
+- Be smarter about broken FD_SETSIZE implementations
+- Crash if we try to free something twice in the block allocator, produces a useful coredump
+ instead of confused opers and an unrelated crash hours later.
+- ability to lock /lusers output via services for a dynamic amount of time
+- Fix 'ghost channels' where I create a channel but none of the users in it exist to me
+- Allow /who +i ip/cidr and /who +I (show IPs only) for opers
+- SAJOIN, like SAMODE for joining channels. Joins through all modes, sends a globop.
+- Local servers notify the channel of an invite, not the server the invitee is on
+- Remove the drone module, replace it with a powerful and generic module system that
+ has event-based hooks.
+- Streamline some privmsg stuff, fix a few bugs.
+- Fix a bug in which an IP ban on 1.2.3.4* wouldn't work.
+- Dehybridize some things.
+- SVSMODE +T, which sets a "client type" that can be seen in a /who +T <clienttype>
+- Don't allow ',' in channel keys
+- Fix umode +r/-r notification to clients
+- Pretty print some things in /stats ?
+- Remove support for non-NOQUIT servers
+- Modes sent from servers come from the local server now
+- Complain about /who +<flag>, where <flag> isn't valid, instead of sending the entire client list
+- Move SQLINES and SGLINES into another hash-based structure for fast lookups
+- Add SVSHOLD, which adds a local temp qline for a nick for N seconds, intended to replace
+ enforcers in services.
+- Make HTM work on outgoing traffic (the part of HTM that limits sending lots of expensive
+ things like /list)
+- Don't complain about servers relinking that look 'juped'
+ (don't complain if the server that already exists is U: lined, unless I actually have a
+ .conf U: line for it!)
+- Compile with GCC3!
+- Nicer umode separation, ie what used to come in as *** Notice -- comes in as:
+ +d : *** Debug --
+ +y : *** Spy --
+ +c : *** Client --
+- Channel join throttling (cmode +j, but disabled for user changes by default to be compatible with
+ pre-1.4.36), defaults to 8 network non-split joins in 4 seconds before saying channel is full.
+- Fix the DEBUGMODE pattern string exploit
+
+Changes for 1.4.35
+- Source address support on /connect problem fixed
+- Squelching added, umode +x or +X (+X is silent squelch), this
+ prevents the user from doing certain online tasks such as privmsg.
+ Meant to be set by a U: lined server or client using SVSMODE.
+- Complete rewrite of the kline/akill/zline system. (s)zlines no longer
+ exist. K: lines set on IP addresses without username portions (or *)
+ are treated as Z: lines used to be. CIDR banning is now supported
+ in all K: line/akill bans (ie, 204.127.54.112/28).
+- +F usermode bypasses ircd's recvq throttling for opers
+- Improved handling under high load situations
+- Ban munching bug introduced in 1.4.34 is fixed
+- /rehash GC now works
+- lots of sendto_ops_lev changed to sendto_realops_lev for speed
+- Fix a bug where we'd try to target limit messages by a server and
+ write to locations of memory that weren't ours :)
+- Fix O: flags that just didn't work as advertised
+- Moved rejection notices to umode +j (re_j_ection)
+- Moved KILL messages from U: lined clients to umode +K (oper only)
+- Support for a loadable drone module, compile with --enable-dronemodule,
+ ircd tries to load drone.so from DPATH on startup or on /rehash drones,
+ read src/drone.c to view the interface
+- /stats t shows more information
+- Various code cleanup and readability fixes
+- Users and opers will now recieve a different output to '/who ?'.
+- When 'HELP_FORWARD_HS' is defined, non-opers /quote help requests
+ will be forwarded to HelpServ.
+
+Changes for 1.4.34
+- Don't use FD_SETSIZE at all if USE_POLL is defined
+- Fixed a server negotiation bug that could break apart the network
+ when autoconnects and user connects were done at the same instant
+- Fix a bug where PART messages were not sent to 'userB' when 'userA's
+ QUIT message was squelched on more than 1 channel
+- Fixed split riding ability left over from hybrid (where a channel
+ with a newer TS could 'take over' if it had ops and the older TS channel
+ did not)
+- Fixed 'topic riding' ability that allowed topics from newer TS'd channels
+ to propogate.
+- Fixed channel ban desync on netjoin
+- all channel modes are now sent with a TS
+- Target limiting anti-spam measure installed
+- Reject acebot-style drones by default
+- Minor fixes to prevent annoying auth error messages
+- Minor configuration/installation fixes
+
+-- WARNING --
+1.4.34 may cause desynch in net joins if used on a network with newer servers!
+This is because the algorithm for determining which channel modes to keep
+when servers rejoin has changed. You should upgrade your entire network
+to 1.4.34.
+-- WARNING --
+
+Changes for 1.4.33
+- Only ops can invite on channels
+- Various desync-causing memory-corrupting bugs fixed
+- Fixed a problem with perm klines where they werent removing the user
+- Moved to zlib 1.1.4, as 1.1.3 was vulnerable (but not directly in ircd)
+- Fixed minor SVSKILL wrong direction issue.
+- Fixed a wierd desync issue with sqlined channels
+- Fixed /stats l's sendM statistic - it wasnt working properly with crypt
+
+Changes for 1.4.32
+- Throttling modified to be more friendly and punish repeat offenders
+- Major bug causing memory corruption (coredumps as well as
+ duplicate or missing messages) fixed
+- Lag on signon fixed (where a user connects, but the server chooses
+ to ignore the user until something is sent to them)
+- Fixed a netsplit detection bug when a leaf server splits from its hub
+ (for no_chanops_when_split)
+- Fix for .conf based K: lines (that just didn't work)
+
+Changes for 1.4.31
+- Connection Throttling Patch from Chip Norkus
+
+Changes for 1.4.30
+- Updated 'make profile'; now on glibc2 systems, you can kill -USR1 the
+ process and get a current profile dump, and restart profiling
+- Kline/akill/zline matching has been revamped, which should help greatly with
+ lag under heavy user loads with many klines/akills/zlines
+- Deny sending .zip files and . files (with a null extension) to prevent
+ the spreading of exploits
+
+Changes for 1.4.29
+- Umode +R to not allow msgs from non registered nicks
+- chanmode +R extended to deny msgs for -r clients in channel
+- +c/+R extended to squelch quit messages with color/from non reg'd nicks
+- wrapped HTM detection code in #ifndef HUB
+- Added channel qline reason display
+- Removed LITTLE_I_LINES as with services they are dumb
+- Massive code reformatting
+- Moved some oper notices around to reduce unnecessary traffic
+- klines match IP field too now, for NICKIP akills.
+- Changed default mask to @DALnet so it's known it's a fake address
+
+- This is the last 1.4 release planned. For real this time.
+
+Changes for 1.4.28
+- Minor bug fixes
+
+Changes for 1.4.27
+- Fixed key bug
+- Fixed showstopper remoteclientsonlygetpiecesofaClient bug
+
+Changes for 1.4.25
+- Hide Nick Collisions (Revealing services location)
+- Make 005 show more info
+- Add who +i to search by IP
+- Hide stats L for non opers
+- Add NICKIP CAPAB for services to get nicks
+- Channel QLINES from Ryan
+- Removed * from valid key char
+
+Changes for 1.4.23
+- Some error message changes/fixes
+- Fixed a cloaking bug
+- Added support to source from a different local IP address when /connecting
+ out to another server; useful for servers which don't want to use the main
+ IP in the M: line as the server<->server IP
+ - To use: Add :<local IP> to the end of a C: line
+ - E.g.: C:192.168.0.1:pass:server.dal.net:7325:10:192.168.10.200
+- Block DCCs of .htm/.html files due to script viruses being spread in this
+ way
+- Prompt for max channels per user and oper pw encryption in the config
+ script
+- Example.conf brought up to date
+- Display proper error messages when you can't join a channel
+- Fixed the +a (away) who flag; its behavior was reversed from what it should
+ have been
+
+Changes for 1.4.22
+- Fixed a bug where a server with a bad name trying to connect or trying
+ to be used in /links could crash Bahamut
+
+Changes for 1.4.21
+- rate-squelch zipinbuf complain messages
+- turn off yet more DNS debug messages (forward<>reverse query error)
+- oper hostmasking no longer pollutes IPHASH (ouch)
+- configure script reworked to search better for libgmp.a
+- configure script bugs fixed
+
+Changes for 1.4.20
+- /whois works correctly for hostmasked opers. growl.
+- configure gives more information about gmp errors.
+
+Changes for 1.4.19 (released, but not an advised upgrade)
+- Fixed a crashing bug with /whois
+- Fixed a crashing bug with /oper (I need to remember how to handle nulls correctly :)
+- Imported res fixes from bahamut-stable
+- made configure work for solaris to find gmp
+
+Changes for 1.4.18 (never officially released)
+- Changed level of some debug messages to not go to all opers
+
+Changes for 1.4.17 (never officially released)
+- Oper hostmasking:
+ Your I: line password is oper<.password> where password is optional.
+ You then /server <yourserver> <yourport> <portpass:>opernick:operpass
+ Anyone +A can see your real username, host, and IP.
+
+Changes for 1.4.16
+- deal with long-time buffer overflow when more than MAXADDR
+ A DNS answers are received.
+
+Changes for 1.4.15 (never officially released)
+- Crash in res.c fixed (due to wrong question received under heavy load)
+- name resolution prevents ircd dns cache pollution
+
+Changes for 1.4.14 (previous release was 1.4.12)
+- RC4 streaming encryption added, diffie hellman key exchange
+ - Requires GMP library
+ - Vulnerable to man-in-the-middle attacks
+ - Requires 'E' flag in the N: line on both servers.
+- zlib-compressed links added
+ - Requires 'Z' flag in the N: line of a server
+ that wishes to zip outgoing links to that link.
+
+Changes for 1.4.12 (previous release was 1.4.8):
+- /stats ?, v fixed to hide u-lined servers
+- /lusers fixed to hide u-lined servers
+- name resolution is more strict
--- /dev/null
+The following are the Coding Standards for Bahamut.
+
+1) No C++ style comments are allowed in the code tree.
+2) All indentations shall be 4 characters long - no tab characters '\t'
+3) All variable names shall begin with a lowercase letter.
+4) All variables defined as macros shall be in all Upper Case
+5) All preprocessor directive shall be at char posistion 0 with no
+ spaces after the #.
+6) all conditional/loop statements shall have the brace on a line
+ by themselves
--- /dev/null
+#************************************************************************
+#* IRC - Internet Relay Chat, Makefile
+#* Copyright (C) 1990, Jarkko Oikarinen
+#*
+#* 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 1, 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.
+#*/
+
+RM=@RM@
+MV=@MV@
+
+INSTALL=@INSTALL@
+INSTALL_DATA=@INSTALL_DATA@
+INSTALL_DIR=@INSTALL_DIR@
+
+FILES=opers.txt reference.conf template.conf
+
+all:
+
+build:
+
+clean:
+
+install: all
+ @for i in $(FILES); do \
+ if test -f $(INSTALL_DIR)/$$i; then \
+ echo $(MV) $(INSTALL_DIR)/$$i $(INSTALL_DIR)/$$i.old; \
+ $(MV) $(INSTALL_DIR)/$$i $(INSTALL_DIR)/$$i.old; \
+ fi; \
+ echo $(INSTALL_DATA) $$i $(INSTALL_DIR); \
+ $(INSTALL_DATA) $$i $(INSTALL_DIR); \
+ done
+
+ -@if [ ! -f $(INSTALL_DIR)/ircd.motd ] ; then \
+ echo "ircd.motd does not exist, creating..."; \
+ touch $(INSTALL_DIR)/ircd.motd; \
+ echo "This is the default Bahamut MOTD" >> $(INSTALL_DIR)/ircd.motd; \
+ fi
+
+distclean: clean
+ $(RM) -f Makefile
--- /dev/null
+$Id: clones.txt,v 1.1 2005/01/12 07:44:56 mmondor Exp $
+Originally written by Trevor Talbot (Quension) in October 2004.
+
+
+Clone Limiting
+==============
+Bahamut supports limiting the number of connections from a single place,
+and this file describes the configuration for that feature. There are two
+kinds of places: a "host" is a single IP (10.0.0.1); a "site" is a single
+/24 block of IPs (10.0.0.*). Clones are the number of connections from a
+given place.
+
+Two types of clone limits are supported: local clones are the number of
+connections from a place on this server only; global clones refer to
+connections on the entire network. When a clone limit is reached, the
+server denies further connections from that place.
+
+
+Local clone limiting
+--------------------
+The default local clone limits are set using the local_clones token in the
+Options block in ircd.conf; see doc/reference.conf for details. In the
+absence of more specific limits, the defaults will regulate all connections
+to the server.
+
+Local limits set using the maxclones token in a Class block override the
+defaults; this is typically used with Allow blocks to provide exemptions
+for specific hosts. When a Class block defines a host limit, clients in
+that class are implicitly exempt from the default site limit.
+
+Example:
+
+ options { local_clones 1:10; };
+ class { name special; maxclones 5; };
+ allow { host *@10.0.0.1; class special; };
+
+ Suppose there is one client each connected from 10.0.0.2 - 9 (8 clients
+ from 10.0.0.*). If another client from 10.0.0.2 tries to connect, it
+ will be rejected because the default limit of 1 connection per host was
+ reached. Five more clients from 10.0.0.1 will be allowed to connect,
+ because the "special" class allows up to 5 connections from a single
+ host.
+
+ Note that because the class did not provide a site limit, five clients
+ from 10.0.0.1 will always be allowed to connect, despite the default
+ limit of 10 per site. To maintain a site limit for these clients,
+ specify one in the class maxclones statement:
+
+ class { name special; maxclones 5:10; };
+
+The default limits can be changed online using the SET DEFLCLONES command.
+Note that this setting is not saved and will be lost when the server is
+restarted; it is useful for testing or setting temporary limits.
+
+ SET DEFLCLONES - to display both limits
+ SET DEFLCLONES <host limit> - to set the host limit
+ SET DEFLCLONES <host limit>:<site limit> - to set both limits
+
+ Supplying a limit of 0 will revert to the internal default.
+
+Specific local limits can be set online using the SET LCLONES command;
+these are called "soft" limits and override all other local limits.
+A soft host limit also provides an implicit exemption from class and
+default site limits. Like DEFLCLONES, these are temporary.
+
+ SET LCLONES <host/site> - to display the limit
+ SET LCLONES <host/site> <limit> - to set the limit
+
+ Use a specific host or site mask, e.g. "10.0.0.1". Supplying a limit
+ of 0 will remove the soft limit; class and default limits will be used
+ instead.
+
+Note that it is possible to create some interesting configurations using
+the class setting. For example, this would effectively allow 5 clones from
+a specific ident@host, since only clients matching the allow block would get
+the increased per-host limit:
+
+ options { local_clones 1; };
+ class { name special; maxclones 5; };
+ allow { host ident@host; class special; };
+
+
+Global clone limiting
+---------------------
+This works in basically the same way as local clone limiting, except that
+it considers connections on the entire network, and is intended to be
+managed by network services.
+
+The default global clone limits are set using the global_clones token in
+the Options block in ircd.conf; see doc/reference.conf for details. In the
+absence of more specific limits, the defaults will regulate all connections
+to the server. Note that to be effective, all servers must share the same
+global limits. A server can only reject new connections to itself; it
+cannot tell other servers to do so.
+
+Example:
+
+ options { global_clones 2:6; };
+
+ If there are six clients on other servers on the network, from various
+ addresses in the 10.0.0.* block, this server will not allow another
+ connection from 10.0.0.1, because the global site limit has already
+ been reached. However, if the remote servers have a higher default,
+ they will still allow more clients to connect.
+
+Network services can set specific limits using the SVSCLONE command; these
+are referred to as "hard" global clone limits. A hard host limit provides
+an implicit exemption from the default site limit. The command syntax is
+provided here for services authors to reference; it is not accessible to
+clients.
+
+ SVSCLONE <host/site> <limit> - to set the limit
+
+ Use a specific host or site mask, e.g. "10.0.0.*". Supplying a limit
+ of 0 will remove the hard limit. This setting is stored by all servers
+ and propagated on netburst, in a manner similar to SQLINES.
+
+The default limits can be changed online using the SET DEFGCLONES command.
+Note that this setting is not saved and will be lost when the server is
+restarted; it is useful for testing or setting temporary limits.
+
+ SET DEFGCLONES - to display both limits
+ SET DEFGCLONES <host limit> - to set the host limit
+ SET DEFGCLONES <host limit>:<site limit> - to set both limits
+
+ Supplying a limit of 0 will revert to the internal default.
+
+Specific global limits can be set online using the SET GCLONES command;
+these are called "soft" global clone limits and override the defaults.
+A lower soft limit will also override a service-set hard limit, but it is
+not possible to set a soft limit higher than a hard one. Like DEFGCLONES,
+these are temporary.
+
+ SET GCLONES <host/site> - to display the limits
+ SET GCLONES <host/site> <limit> - to set the soft limit
+
+ Use a specific host or site mask, e.g. "10.0.0.1". Supplying a limit
+ of 0 will remove the soft limit; hard and default limits will be used
+ instead.
+
+
+Monitoring
+----------
+Rejection notices for clone connections are sent to usermode +j, in the
+following format:
+
+ clone <nick!user@host> (<place> <online>/<limit> <type> <from>)
+
+ <nick!user@host> is the rejected client
+ <place> is the host or site mask, e.g. "10.0.0.*"
+ <online> is the number of clients currently online from that place
+ <limit> is the limit for that place
+ <type> is "local" or "global"
+ <from> is where the limit was set:
+ "default", "soft", "hard", "class <name>"
+
+General statistics about the clones system are available on STATS d.
+
+A list of specific limits is available on STATS D, returned on numeric 225:
+
+ D <host/site> <soft local limit> <soft global> <hard global>
+
+
+Notes
+-----
+When local and global limits differ, the lowest limit applies. This means
+you should carefully choose the defaults and how you want to manage the
+specific limits, as working with both types of limits at once can be
+difficult.
+
+When a client is rejected, its exit reason is one of:
+
+ Too many connections from your host
+ Too many connections from your site
+
+It is not told which specific limit was reached.
+
+Very little host/site mask validation is done for the online commands; it
+is possible to query and set limits for completely bogus masks. Such
+limits will be retained but never used.
--- /dev/null
+Bahamut Hook Module System [2003-10-13]
+
+First released in Bahamut 1.4.36, the hook module system permits outside modules
+to be 'hooked' into bahamut without having to modify the core source tree.
+This is to allow other groups to write code to benefit IRCD that serve
+specific functions. As an example, some groups write modules to block
+common trojan / drone patterns.
+
+Once a module has been built, hooking it into the system is fairly simple.
+The components that are used, are:
+
+1. A modules/ directory where the shared modules themselves are stored
+
+To enable the hook module system, you must issue --enable-hook-modules
+at configuration time. Example:
+
+./configure --enable-hook-modules
+
+(As of bahamut 1.8, this is implicitely assumed.)
+
+---
+
+1. modules/ directory
+
+This directory stores the shared modules that you wish to hook into bahamut.
+The modules/ directory is found in the same directory as your server
+configuration files (eg: bahamut-release/modules)
+
+---
+
+USER COMMANDS TO CONTROL MODULES
+
+There are a few new commands to control modules. They are all accessed
+by using /quote module <command>.
+
+ /quote module LIST List all modules loaded in memory
+ /quote module HOOKS List where modules are hooked into ircd
+ /quote module LOAD <name> Load a module into memory
+ /quote module UNLOAD <name> Unload a module from memory
+
+To use the above commands, you must be an IRC Operator at the time
+of issuing the command (umode +o). To issue LOAD/UNLOAD commands, you must be
+a Server Adminstrator (umode +A)
+
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, doc/AUTHORS
+ * Copyright (C) 1990
+ *
+ * AUTHORS FILE:
+ * This file attempts to remember all contributors to the IRC
+ * developement. Names can be only added this file, no name
+ * should never be removed. This file must be included into all
+ * distributions of IRC and derived works.
+ *
+ * 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 1, 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.
+ */
+
+IRC was conceived of and written by Jarkko Oikarinen <jto@tolsun.oulu.fi>.
+IRC was originally written in University of Oulu, Computing Center.
+Jan 1991 - IRC 2.6 jto@tolsun.oulu.fi
+ - Multiple Channels and protocol changes
+
+Contributions were made by a cast of dozens, including the following:
+
+Markku Jarvinen <mta@tut.fi>: Emacs-like editing facility for the client
+
+Kimmo Suominen <kim@kannel.lut.fi>: HP-UX port
+
+Jeff Trim <jtrim@orion.cair.du.edu>: enhancements and advice
+
+Vijay Subramaniam <vijay@lll-winken.llnl.gov>: advice and ruthless publicity
+
+Karl Kleinpaste <karl@cis.ohio-state.edu>: user's manual
+
+Greg Lindahl <gl8f@virginia.edu>: AUTOMATON code, the Wumpus GM automaton,
+myriad bug fixes
+
+Bill Wisner <wisner@hayes.fai.alaska.edu>: numerous bug fixes and code
+enhancements
+
+Tom Davis <conslt16@zeus.unl.edu> and Tim Russell <russell@zeus.unl.edu>:
+VMS modifications
+
+Markku Savela <msa@tel4.tel.vtt.fi>: advice, support, and being the
+incentive to do some of our *own* coding. :)
+
+Tom Hopkins <hoppie@buengf.bu.edu>: bug fixes, quarantine lines,
+consolidation of various patches.
+
+Christopher Davis <ckd@cs.bu.edu>: EFnet/Anet gateway coding,
+many automata ;), documentation fixing.
+
+Helen Rose <hrose@cs.bu.edu>: documentation updating, and fixing.
+
+Tom Hinds <rocker@bucsf.bu.edu>: emacs client updating.
+
+Tim Miller <cerebus@bu-pub.bu.edu>: various server and client-breaking
+features.
+
+Darren Reed <avalon@coombs.anu.edu.au>: various bug fixes and enhancements.
+Introduced nickname and channelname hash tables into the server.
+
+The version 2.2 release was coordinated by Mike Bolotski
+<mikeb@salmon.ee.ubc.ca>.
+
+The version 2.4 release was coordinated by Markku Savela and
+Chelsea Ashley Dyerman
+
+The version 2.5.2 release was coordinated by Christopher Davis, Helen Rose,
+and Tom Hopkins.
+
+The versions 2.6.2, 2.7 and 2.8 releases were coordinated by Darren Reed.
+
+Contributions for the 2.8 release from the following people:
+Matthew Green <phone@coombs.anu.edu.au>
+Chuck Kane <ckane@ece.uiuc.edu>
+Matt Lyle <matt@oc.com>
+Vesa Ruokonen <ruokonen@lut.fi>
+
+Markku Savela <Markku.Savela@vtt.fi> / April 1990
+Fixed various bugs in 2.2PL1 release server (2.2msa.4) and changed
+sockets to use non-blocking mode (2.2msa.9). [I have absolutely
+nothing to do with clients :-]
+
+Chelsea Ashley Dyerman <chelsea@earth.cchem.berkeley.edu> / April 1990
+Rewrote the Makefiles, restructuring of source tree. Added libIrcd.a to
+the Makefile macros, numerous reformatting of server text messages, and
+added mkversion.sh to keep track of compilation statistics. Numerous
+bug fixes and enhancements, and co-coordinator of the 2.4 release.
+
+jarlek@ifi.uio.no added mail functions to irc.
+
+Armin Gruner <gruner@informatik.tu-muenchen.de> / May, June 1990:
+* Patched KILL-line feature for ircd.conf, works now.
+ Enhancement: Time intervals can be specified in passwd-field.
+ Result: KILL-Line is only active during these intervals
+* Patched PRIVMSG handling, now OPER can specify masks for sending
+ private messages, advantage: msg to all at a specified server or host.
+* Little tests on irc 2.5 alpha, fixed some little typos in client code.
+ Change: common/debug.c has been moved to ircd/s_debug.c, and a
+ irc/c_debug.c has been created, for the benefit that wrong server msg
+ are displayed if client does not recognize them. (strange, if a server
+ sends an 'unknown command', isn't it?)
+
+Tom Hopkins <hoppie@buengf.bu.edu> / September, October 1990:
+* Patched msa's K lines for servers (Q lines).
+* Consolidated several patches, including Stealth's logging patch.
+* Fixed several minor bugs.
+* Has done lots of other stuff that I can't seem to remember, but he
+ always works on code, so he has to have done alot more than three
+ lines worth. :)
+
+Thanks go to those persons not mentioned here who have added their advice,
+opinions, and code to IRC.
+
+Various modifications, bugreports, cleanups and testing by:
+
+Hugo Calendar <hugo@ucscb.ucsc.edu>
+Bo Adler <adler@csvax.cs.caltech.edu>
+Michael Sandrof <ms5n+@andrew.cmu.edu>
+Jon Solomon <jsol@cs.bu.edu>
+Jan Peterson <jlp@hamblin.math.byu.edu>
+Nathan Glasser <nathan@brokaw.lcs.mit.edu>
+Helen Rose <hrose@eff.org>
+Mike Pelletier <stealth@caen.engin.umich.edu>
+Basalat Ali Raja <gwydion@tavi.rice.edu>
+Eric P. Scott <eps@toaster.sfsu.edu>
+Dan Goodwin <fornax@wpi.wpi.edu>
+Noah Friedman <friedman@ai.mit.edu>
--- /dev/null
+These are the two most frequently asked questions about IRC server
+compliation:
+
+* I compile and everything seems fine during the compiling, but when it
+comes time for the program to link, I get errors complaining about dns and
+res things. What causes this?
+
+You need to make sure IRCDLIBS in the toplevel Makefile includes -lresolv
+
+
+* I start the ircd program and I get an error about chdir, no such file or
+directory. What causes this?
+
+Make sure IRCDDIR in the toplevel Makefile is set to the same as DPATH in
+include/config.h
+
+(send suggestions to this FAQ to hrose@cs.bu.edu)
--- /dev/null
+
+The hybrid team is a group of ircd coders who were frustrated
+with the instability and all-out "dirtiness" of the efnet ircd's
+available. "hybrid" is the name for the collective efforts of a group
+of people, all of us.
+
+Anyone is welcome to contribute to this effort..
+
+We have run the code through "purify", a commercial program designed
+to find memory leaks. The code has been mostly prototyped. Profiling has also
+been done to catch slow portions of the code. Portions of "crufty" code have
+been re-written. We have also looked at making the code as easy to setup
+up and run as possible using configure, checking header files etc.
+Finally speed enhancements and other enhancements have been made to this ircd.
+
+That is not to say that there are still not bugs, There are always bugs.
+But we have reviewed each others work on this project, and are open
+to bug reports.
+
+The following people have contributed blood, sweat, and/or code to
+this release of hybrid, in nick alphabetical order.
+
+cbongo, Chris A. Bongaarts (cab@tc.umn.edu)
+comstud, Chris Behrens (cbehrens@concentric.net)
+Dianora, Diane Bruce (db@db.net)
+johan, Johannes Erdfelt (jerdfelt@eng.mindspring.net)
+orabidoo, Roger Espel LLima (espel@unix.bigots.org)
+Rodder, Jon Lusky (lusky@vol.com)
+Shadowfax, Michael Pearce (mpearce@varner.com)
+ThemBones, Brian Kraemer (kraemer@u.washington.edu)
+Wohali, Joan Touzet (joant@cadence.com)
+
+Others are welcome.
+
+email bug fixes/complaints/rotten tomatoes to ircd-hybrid@vol.com
--- /dev/null
+Internet Relay Chat Operator Etiquette Guide
+
+May, 1992
+
+Welcome! You've either been selected to be an IRC Operator or you have set
+up your server and thus have taken on the dual task of IRC Server
+Administrator and IRC Operator. Your future days will be filled with hours
+of fun chatting on IRC, and then wondering why everyone you talked to went
+away, because the links had apparently broken.
+
+Linking:
+========
+
+You will be assigned links from the IRC Routing Coordinators. Please
+use these links and these links ONLY. The links have been designed to
+maximize efficiency and make delays in chatting minimal. You will
+usually be given two links, one to each regional backbone site.
+Connect to the primary site first and then to the secondary site. You
+should not need to connect to any other sites. You will be informed if
+this policy changes.
+
+Kills
+=====
+
+/kill is a special operator command. You should use it with
+care, and only if absolutely needed. The format is as follows:
+/kill NICKNAME comment. Comment can be a phrase of almost any length
+(within reason) and should be used for specifying the reason of the kill.
+Example: /kill Trillian She's a Ghost
+IRC Ghosts are created after a net split has occured and the net has yet to
+relink.
+
+/wallops PHRASE This is used to talk to those users who have their
+user mode set to +w. /wallops used to be a way for operators to talk
+about important matters in linking etc., but it has little use
+nowadays.
+
+/TRACE command /TRACE is useful to know what servers are connected to
+what. Sometimes /trace can be confusing, especially if you are using
+it for the first time. Here is an example of a trace from
+stekt1.oulu.fi to cdc835.cdc.polimi.it.
+
+/TRACE cdc835.cdc.polimi.it
+
+*** Link stekt1.oulu.fi<2.7.2> ==> cdc835.cdc.polimi.it
+*** Link rieska.oulu.fi<2.7.1>e ==> cdc835.cdc.polimi.it
+*** Link nic.funet.fi<2.7.1>e ==> cdc835.cdc.polimi.it
+*** Link ircserver.et.tudelft.nl<2.7.1>e ==> cdc835.cdc.polimi.it
+*** Link vesuv.unisg.ch<2.7.1>e ==> cdc835.cdc.polimi.it
+*** Link apollo.di.unipi.it<2.7.1>e ==> cdc835.cdc.polimi.it
+*** Oper Class[10] ==> Allanon[cdc835.cdc.polimi.it]
+*** User Class[11] ==> Lupandy[plus2.usr.dsi.unimi.it]
+*** Serv Class[3] ==> apollo.di.unipi.it[131.114.4.36] 132S 445C
+*** User Class[11] ==> Punk[pluto.sm.dsi.unimi.it]
+*** User Class[11] ==> TheEdge[pluto.sm.dsi.unimi.it]
+*** User Class[10] ==> Mork[cdc835.cdc.polimi.it]
+*** User Class[11] ==> Lollo[c700-2.sm.dsi.unimi.it]
+*** User Class[11] ==> Attila[hp2.sm.dsi.unimi.it]
+*** Class 0 Entries linked 1
+*** Class 11 Entries linked 5
+*** Class 10 Entries linked 2
+*** Class 3 Entries linked 1
+
+From this output you can see that the route goes first to
+rieska.oulu.fi (running version 2.7.1e), then nic.funet.fi,
+ircserver.et.tudelft.nl, vesuv.unisg.ch, and apollo.di.unipi.it, after
+which cdc835 is the next server. Then we see the connections on
+cdc835: One operator (Allanon) and 6 users are on line. The class of
+each connection is given. There is only one server connected to cdc835
+at the moment, and that server is apollo.di.unipi.it (cdc835 is said
+to be a "leaf" server at the moment). The numbers 132S 445C in the end
+of line tell us, that there are 132 servers and 445 clients connected
+to the servers from apollo onwards. Finally we see a grand total of
+connections in each connection class.
+
+
+/SQUIT server {comment}
+ /squit isolates a specified server from the next closest server, when
+you look at it along the trace path starting from your server.
+This is usually used in conjunction with CONNECT (explained later) to
+reroute traffic. This will be described in detail in the section
+"routing", preceding CONNECT.
+
+ Usage (and examples):
+
+ /squit E
+
+ If the network looks like this initially (and you are on server A)
+
+
+ A <---> B <---> C <---> D
+ ^
+ |
+ v
+ G <---> E <---> F <---> ... (rest of the net)
+
+
+ Then after issuing the previous /squit the network would look like this:
+
+ A <---> B <---> C <---> D
+
+
+ G <---> E <---> F <---> ...
+
+
+ /squit E {comment}
+
+ It usually helps to give a reason why you are sending a
+ SQUIT for a server. This can be accomplished by sending
+ the command "/squit server This link is making the US route
+ through Finland". The SQUIT will then be sent out, and the
+ server sending the squit will WALLOP sending the comment
+ so all operators can see it.
+
+/CONNECT server {portnum server2}
+ /connect is used to establish a link between two servers. These
+connections must be authorized by each server's ircd.conf file, but
+any operator can issue a CONNECT between authorized servers. This
+command is most often used in conjunction with SQUIT to reroute
+traffic.
+ If only one argument is given, this command causes the server you
+are on to attempt to connect to the server specified. For example,
+"/connect B" (in the previous example) would cause your server (A) to
+connect to B.
+ Suppose you wanted to reconnect server F to server E? You cannot
+contact server F since it is no longer part of your network. However,
+you can tell server E to connect to it. A remote CONNECT can be issued
+to server E.
+
+ Examples (assume you are on server A):
+
+ /connect B
+
+ If the network initially looks like this:
+
+ A B <---> ... (rest of network)
+
+ Then afterwards (if the connection succeeds) the network will look
+ like this:
+
+ A <---> B <---> ...
+
+
+ In the example where you wanted to reconnect server E to F, the
+ following syntax would be appropriate (note: we are assuming that
+ F's irc socket port is 6667, which is the default)
+
+ /connect F 6667 E
+
+ If the network initially looks like this:
+
+ A <---> B <---> C <---> D
+ ^
+ |
+ v
+ G <---> E F <---> ...
+
+ Then after your CONNECT request the network topology will look like this:
+
+ A <---> B <---> C <---> D
+ ^
+ |
+ v
+ G <---> E <---> F <---> ...
+
+ Be careful when connecting servers that you know which command to
+ use! If you simply issued "/connect F" from your server, the
+ network would look like this:
+
+
+ ... <---> F <---> A <---> B <---> C <---> D
+ ^
+ |
+ v
+ G <---> E
+
+ which for various reasons (discussed below) might be very
+ undesirable.
+
+Routing
+=======
+
+ When and how should you do rerouting? This depends on where your
+server is topologically located and whether you route traffic. If you
+are a leaf node (i.e. only connect to one server at a time) then
+chances are you won't need to do any routing at all. Your ircd.conf
+file should be written to connect to the best possible servers first
+before trying alternates. At the most, you may decide to squit an
+alternate server and connect to your primary if/when it goes back up.
+This only involves local squits, however.
+
+ If you are operating a backbone site, you may find yourself
+rerouting things quite often. If the servers badger.ugcs.caltech.edu
+(Pasadena, CA), irc.mit.edu (Boston, MA), minnie.cc.utexas.edu
+(Austin, TX) and ucsu.colorado.edu (Boulder, CO) were routing traffic
+in the following way:
+
+ ... <---> minnie <---> badger <---> bucsd <---> ucsu <---> ...
+
+It would make sense to either squit ucsu and reconnect it to minnie,
+or disconnect minnie from badger and connect to ucsu, because
+topologically (and geographically) ucsu and minnie are rather close.
+There are occasions when US traffic for some reasons winds up being
+routed through Australia. This is another case where traffic should
+definitely be rerouted. However, there are sometimes occasions when
+routing is going through "backdoor" methods. If you see something
+totally outrageous (like the east coast and the west coast being
+connected by eff.org) please ask for example on channel #twilight_zone
+before you send any squits, because chances are, it's like that for a
+reason.
+
+ Of course, any operator can remotely squit or connect servers, so
+if you see a problem and you're sure you know how to fix it, it's a
+good idea to do so. If the operator of a server which is is being
+routed poorly is online, it's probably best to contact him/her first,
+though.
+
+ Chances are that hub operators will be more familiar with the
+general topology of the network and which servers connect to which
+(which is why most of the manual routing is left to them), so if you
+have any problems, talk to the other operators on operator channels
+(#twilight_zone, #eu-opers etc.) That's what they are there for!
+ Also, be aware that servers will notify all the operators online of
+remote SQUITs and CONNECTs via WALLOPS.
+
+Please let us know if there should be any additions to this guide. Again,
+this is not MANDATORY, this is just a GUIDE. Please conduct yourself as
+an IRC Operator would...you are looked upon for assistance, both emotional
+and mental.
+
+Helen Rose Christopher Davis Noah Friedman
+<hrose@cs.bu.edu> <ckd@cs.bu.edu> <friedman@ai.mit.edu>
+
+January, 1991
+
+
+Updated by
+
+Mauri Haikola
+<mjh@stekt.oulu.fi>
+
+May, 1992
--- /dev/null
+This stuff is so ancient it's not even funny anymore. Take it with
+a grain of salt when you read it. --JRL
+
+The Bill Wisner example.conf has been updated, I have also included
+Helen Roses example.conf as example.conf.trillian (taken from
+the CSR tree ) as it is superiour in some respects to Bill's version.
+Updated as well to reflect hybrid . --Dianora
+
--- /dev/null
++hybrid-5.2p1 (5/12/98)
+removed uneeded variable in aClient (Dianora)
+added missing #ifdef's for USE_SYSLOG (Dianora)
+reverted to old check_pings() to fix high cpu usage (Rodder)
+fixed DEBUGMODE (Dianora)
+
++hybrid-5.2 (4/21/98) - The inevitable bug fix release
+-fixes
+* changed many of the defaults in config.h
+* removed ident_fdlist it was never used anyway (comstud)
+* fixed quote kline for 10 character user names (Dianora)
+* obscure bug with KICK message in a desync channel situation (Dianora)
+* bug with max channel name fixed (comstud/Dianora)
+* stop spam from links command i.e. beeps (Dianora)
+* bug with default +i not showing MODE to user initially (Rodder)
+* ANTI_IP_SPOOF moved to "broken" section of conf (Rodder)
+* ident lookups now work properly for all interfaces of
+ multihomed (or "VIF"'d) machines, including Solaris 2.6 (Rodder)
+* stats l/L no longer shows -i clients to non-opers (Rodder)
+* exorcised evil timedelta variable
+* Fixed oper wallops broadcasting instead of routing (Dianora)
+* Covered up bogus "Got Ident" messages in read_authports() (Rodder)
+* Fixed missing RPL_ENDOFTRACE for non-opered clients (Dianora)
+* #undef IDLE_FROM_MSG fixed, ping/pong/ison do not reset idle time (Dianora)
+
+-feature adds
+* bumped HTM code to not kick in until 40K/s by default
+* stop people from laming up the kline conf file with # in comment (Dianora)
+* added comstuds SEPARATE_QUOTE_KLINES_BY_DATE
+* use block allocator in FLUD code (Shadowfax)
+* added HTM quiet or HTM noisy option -- see NOISY_HTM in config.h
+ for initial setting (Dianora)
+* added LOCOPS, each type of wallops/operwall/locops is now flagged (Dianora)
+* added signon time to RPL_WHOISIDLE (Dianora)
+* allow local opers to see kills requested by riss (Dianora)
+* added ANTI_SPAMBOT code, read config.h (Dianora)
+* added fixklines to tools dir, use it to check kline.conf for #'s inside
+ of K-line comments (Dianora)
+* added OLD_Y_LIMIT in config.h.dist to go back to old Y/I line behaviour
+ (Dianora)
+* M: line passwd field now used to specify address to bind to on
+ machines with multiple interfaces. (Rodder)
+* P: line passwd field now used to specify address to bind to on
+ machines with multiple interfaces. (Rodder)
+* added /quote set SPAMNUM SPAMTIME to control ANTI_SPAMBOT behaviour (Dianora)
+* hybrid option flags removed from m_version and replaced
+ by (for opers) full listing of server defines in m_info (Rodder)
+* poll() code mods ported from CSr30 (comstud) by cbongo
+* m_whois() rewritten to use hash table when possible (Dianora)
+* spambot sign on code added (ThemBones)
+* i line (LITTLE_I_LINE) support, restricted i lines (Dianora)
+* NO_CHANOPS_WHEN_SPLIT delays channel hacking until rejoin (Dianora)
+* ANTI_SPAMBOT on sign on code (ThemBones)
+* only allow 4 kicked nicks per kick (Dianora)
+* sped up kline processing, redid check_pings in ircd.c (Dianora)
+* Server now checks for sane TS when connecting to other server,
+ see TS_MAX_DELTA and TS_WARN_DELTA in config.h (Rodder)
+* Server checks for backwards spinning clock and complains if
+ found (Rodder)
+* Check for error when timeofday is set (Shadowfax)
+* Announce TS changes after TS induced deops (Shadowfax)
+* stop redistributing away information to other servers
+* Prepared for TS4 mixed net by checking validity of channel mode changes
+ only at the local server (orabidoo)
+
++hybrid-5 (9/26/97)
+* LOTS AND LOTS OF CHANGES IN CONFIG.H
+* reorganized source tree, eliminating common subdir
+* reworked hash.c (Dianora)
+* reworked parse.c, tree prefix command lookups (Dianora/orabidoo)
+* all code is now function prototyped (Dianora)
+* improved bad host/nick handling, i.e. dns spoofers (ThemBones)
+* sped up send_umode_out in s_user.c (ThemBones)
+* sped up whowas processing, removed away from whowas (Dianora)
+* redid m_kline/cluster in s_serv.c (Dianora)
+* redid dline/kline handling (Dianora/Rodder/ThemBones)
+* removed lame #ifdefs in poll() (Dianora)
+* always defined D_LINES/E_LINES/F_LINES (Dianora)
+* TS_ONLY server now (Dianora)
+* cleaned up s_auth.c (Dianora/ThemBones)
+* changed BAN_INFO handling (Dianora)
+* sanity testing in res.c (Dianora)
+* added orabidoo's scache code (orabidoo/Dianora)
+* added KLINE_WITH_REASON kline reason on klines/connects (Dianora)
+* added NON_REDUNDANT_KLINE code (Dianora)
+* added ANTI_IP_SPOOF code (Dianora)
+* added temporary kline code (Dianora)
+* added Jolo's block allocator into list.c (Jolo/Dianora)
+* added ANTI_NICK_FLOOD code (Dianora)
+* removed UNIXPORT code (Dianora)
+* removed lame unused code in match.c (Jolo)
+* corrected many type errors, ran through purify (Jolo)
+* removed unused variables (Dianora)
+* folded in Shadowfax's FLUD code (Shadowfax/Dianora)
+* folded in Shadowfax's LOCKFILE code (Shadowfax/Dianora/Rodder/ThemBones)
+* added optional GLINE code (Dianora)
+* stats K now works for normal users (Dianora)
+* quote UNKLINE code as a option added (Dianora/common)
+* Reworked ACKPATCH, removed ONE kludge and use confeq field of Y instead,
+ used hash table of ip's (Dianora)
+* removed UNIXPORT support (Dianora)
+* added support for oper WALLOPS back in. Use /quote OPERWALL to send operwalls.
+* reworked version.c.SH to track build number (Rodder)
+* make clean removes more junk (Rodder)
+* added check for adequate FD_SETSIZE
+* created tools subdir (Rodder)
+* added "Unauthorized connection" back in, under umode +c (Dianora/Rodder)
+* modified autoconf for Solaris 2.6 (Rodder)
+* modified LUSERS to ignore masks (Rodder)
+* fixed mysterious exit() in fdlist.c from fd leak in s_auth.c (Dianorans)
+* fixed overrun bugs in res.c (Dianora/Johan/Shadowfax)
+
+-----------------------------------------------------------------------------
++hybrid-4.3 (8/19/97) - more bug fixes
+* typo that caused immediate crash on HPUX fixed
+* IP/hostname mismatch code fixed, warns the user instead of opers
+* typo fixed in missing klinefile error message
+
++hybrid-4.2 (8/4/97) - minor bug fix, one new feature
+* rcs version string was clobbering server version string
+* Bans can now match by IP for hosts that resolv (db)
+ IP_BAN_ALL define added to config.h
+
++hybrid-4 (7/28/97)
+* LOTS OF NEW STUFF IN CONFIG.H, GO READ IT!! THE WHOLE THING!!
+ EVEN IF YOU ARE UPGRADING TO THIS FROM A HYBRID-4 BETA!!
+* patch for yet another NICK bug
+* patch for m_server() bug
+* patch for TS3 bug
+* switched to GNU autoconf (thanks ns!)
+* WALLOPS now only go to real opers
+* ircsprintf() mod to check for NULL args (db)
+* fixed possible overflow res.c (db)
+# seperate klines file - see config.h (db)
+* quote_dline support - see config.h (db)
+* fixed timezone snafu in date()
+* added RFC1035_ANAL define reject _ and / in hostnames
+* removed old DELAY_NICK define.. broken and unneeded
+* modified s_err.c and created s_err.h. See CUSTOM_ERR in include/config.h
+* m_server() now quietly ignores clients that try to use SERVER
+* removed NOTE code, removed SUMMON code, gutted USERS
+* added automatic timestamps to comments of quote KLINE and DLINE
+* changed failure notice for clients bouncing off ACKPATCH
+ to "Only one connection at a time allowed from your hostname"
+* cleanup to channel.c
+* format() mod to check for NULL args (di)
+* removed more useless crap (UPHOST, VMS, etc) from config.h
+* #undef F_LINES fixed
+* oper WALLOPS changed to OPERWALL (code taken from csr30)
+* BSDI 3.0 FD_ALLOC support (db)
+# changed output of STATS D
+* Removed Q: line support
+* cleaned up find_conf_ip (db)
+* fixed crypt() usage to work on systems with longer salts
+ (ie FreeBSD without DES libs)
+* various spelling fixes (db)
+* N: line checking in m_server() (db)
+* WARN_NO_NLINE define added to config.h
+
+-----------------------------------------------------------------------------
++hybrid-3 (6/17/97):
+* Added USRIP command. This command returns user@ip in a USERHOST
+ reply for local clients only. Requests for remote nicks are treated
+ as though the nick doesn't exist.
+* Switched to Dianora's faster dich_conf.c
+* Check for invalid characters (see RFC1035) in hostnames
+* Fixed problem with coring due to invalid hostnames on non-local users
+* TSora version 3
+* Turned D_LINE support back on
+* Numerous changes to Config script, may actually work now
+* Additional OS defs in Makefile
+* Minor cleanup in include/config.h
+# created new INSTALL document
+
+-----------------------------------------------------------------------------
++hybrid-2 (4/12/97):
+This is ircd2.8/th.v5a.3 with the WHO, WHOWAS, and IsMember() code
+from Comstud's irc2.8.21CSr29. Please send email to Jon Lusky
+<irc@vol.com> if you find problems with it.
+
+Relevant excerpt from irc2.8.21+CSr29/README.CS:
+3) /whowas code totally rewritten. This code is better than Avalon's
+ ever was. You can now raise NICKNAMEHISTORYLENGTH in config.h to
+ a value that makes sense with today's number of clients. Without
+ rewriting, you could expect server lockup, mostly during splits.
+ These changes should lower CPU usage quite a bit, especially during
+ splits.
+4) /who code tweaked. IsMember() = CPU hog...IsMember() has been changed
+ and m_who does less find_user_link()s now...much less. This is
+ a big reducer of CPU usage. Also another "bug" was removed from
+ m_who that can possibly cause server lockups. The possibility still
+ remains, though...not sure how to improve it further without totally
+ breaking /who.
+5) This goes with #4, but...
+ /who nickname was optimized tremendously. However, this breaks /who
+ if you do /who username and username happens to match a nickname.
+ Oh well...too bad.
+
+-----------------------------------------------------------------------------
++hybrid-1 never really existed
+
--- /dev/null
+The following outlines the features and commands
+that Bahamut has for operators of the server.
+- 11/13/02 - srd (srd@dal.net)
+- 10/02/04 - Quension (quension@dal.net)
+
+Based upon opers.txt for ircd-hybrid by:
+ThemBones (kraemer@u.washington.edu)
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+Usermodes: (* designates that the umode is oper only)
+
+ USERMODE DESCRIPTION
+-----------------------------------------------------------------
+ +i - Is 'invisible'.
+ +w - Can see wallops messages.
+ +r - Is registered/identified to services.
+ +s - Can see oper kill messages.
+ +R - Will not receive messages from -r clients.
+ *+a - Designates the user as being a services administrator.
+ *+b - Can see chatops messages.
+ *+c - Can see client connections and exits.
+ *+d - Can see debug messages.
+ *+e - Can see dccallow failure notices.
+ *+f - Can see flood messages.
+ *+g - Can recieve globops messages.
+ *+h - Is available for help, being listed in /stats P
+ *+j - Can see rejected connection notices
+ *+k - Can see server kill messages.
+ *+m - Can see spambot notices.
+ *+n - Can see routing notices.
+ *+o - Is a global IRC Operator.
+ *+y - Can see certain information requests. (e.g. /stats)
+ *+A - Is a server administrator.
+ *+F - Can bypass the ircd's recvq throttling
+ *+K - Can see U:lined kill messages
+ *+O - Is a local IRC Operator.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+Oper Commands: (+ indicates that /quote must be used with ircII)
+
+COMMAND - USAGE and DESCRIPTION
+-------------------------------------------------------------------
+ SQUIT - SQUIT <server> [reason]
+ Splits <server> away from your side of the net with
+ [reason].
+
+ KILL - KILL <nick> <reason>
+ Disconnects user <nick> from the IRC server he/she
+ is connected to with reason <reason>.
+ Local Opers can only kill clients on their servers.
+ Global Opers can kill clients on any server on the
+ IRC network.
+
+ STATS - STATS <letter> [server|nick]
+ Queries server [server] (or your own server if no
+ server parameter is given) for info corresponing to
+ <letter>.
+ LETTER (* = Oper only.)
+ ------ (^ = Can be configured to be oper only.)
+ * a - Shows akills
+ * c - Shows connect blocks
+ * D - Shows special clone limits
+ * d - Shows clone limit statistics
+ * G - Shows local gcos restrictions
+ * g - Shows network gcos restrictions (sglines)
+ i - Shows allow blocks
+ * K - Shows permanent K lines
+ * k - Shows temporary K lines
+ l - Shows hostname and generic info about [nick]
+ * m - Shows commands and their usage
+ ^ o - Shows oper bocks
+ p - Shows opers connected and their idle times
+ * Q - Shows local nick/chan restrictions
+ * q - Shows network nick/chan restrictions (sqlines)
+ r - Shows resource usage by ircd (only in DEBUGMODE)
+ * s - Shows server name cache
+ * T - Shows throttle stats
+ * t - Shows generic server stats
+ * U - Shows super (U-Lined) servers.
+ u - Shows server uptime
+ v - Shows connected servers and their idle times
+ * w - Shows fd list (only in DEBUGMODE)
+ y - Shows class blocks
+ * z - Shows memory stats
+ ? - Shows network traffic statistics bdefgjnx
+
+ CONNECT - CONNECT <server_A> [port [server_B]]
+ When [server_B] is used, CONNECT asks [server_B] to
+ connect to <server_A>. Global Opers only.
+
+ When [server_B] is not used, CONNECT trys to connect
+ your server to <server_A>. Local and Global Opers.
+
+ When [port] is used, the connection will be attempted
+ to [port]. When [port] is not used, a default will be
+ chosen from the conf.
+
++ WALLOPS - WALLOPS :<message>
+ Sends a WALLOPS message of <message> to all users
+ who are umode +w (this includes non-opers).
+
++ LOCOPS - LOCOPS :<message>
+ Sends an LOCOPS message of <message> to all
+ opers on local server who are umode +g
+
++ GLOBOPS - GLOBOPS :<message>
+ Sends an GLOBOPS message of <message> to all
+ opers on the network who are umode +g
+
++ CHATOPS - CHATOPS :<message>
+ Sends an CHATOPS message of <message> to all
+ opers on the network who are umode +b
+
+ TRACE - TRACE [server|nick]
+ TRACE shows client info about [server|nick] or about
+ the server you are on if no [server|nick] is given.
+
+ All users that use TRACE can see the path to
+ [server|nick] if given and all servers and opers
+ connected, as well as the connection class they
+ fall into.
+
+ Opers can see unregistered connections on a server
+ with TRACE as well as connection class counts.
+
+ REHASH - REHASH [option]
+ When no [option] is given, ircd will re-read the
+ ircd.conf file.
+
+ [option] can be one of the following:
+ DNS - Re-read the /etc/resolv.conf file
+ TKLINES - Clears temporary klines
+ GC - Performs garbage collecting of excess
+ memory.
+ MOTD - Re-reads MOTD files
+ THROTTLES - Clears connection throttles
+ AKILLS - Clears akills
+ SQLINES - Clears sqlines
+ SGLINES - Clears sglines
+ TSQGLINES - Clears temporary nick/channel/gcos blocks
+
+ RESTART - RESTART
+ Restarts the IRC server.
+
+ CLOSE - CLOSE
+ Close any connections from clients who have not fully
+ registered yet.
+
+ DIE - DIE
+ Terminates the IRC server.
+
++ DNS - DNS
+ Shows some stats about ircd's asynchronous resolving
+ code
+
++ KLINE - KLINE [minutes] <nick|user@host> :[reason]
+ Adds a KLINE to the ircd.conf or klines.conf file which
+ will ban the specified user from using that server.
+ The banned client will receive a message saying he/she
+ is banned with reason [reason]
+
+ For a temporary KLINE, length of kline is given in
+ minutes as the first parameter i.e.
+ KLINE 10 <nick|user@host> :cool off for 10 minutes
+
++ UNKLINE - UNKLINE <user@host>
+ -- If compiled with UNKLINE --
+ Will attempt to unkline the given <user@host>
+
++ SET - SET <option> <value>
+ <option> can be one of the following:
+ MAX - Sets the number of max connections
+ to <value>.
+
+ -- The following three are if compiled with FLUD --
+ FLUDNUM - Sets the number of flud messages to
+ trip flud alarm to <value>
+ FLUDTIME - Sets the number of seconds in which
+ FLUDNUM msgs must occur to <value>
+ FLUDBLOCK - Sets the number of seconds to block
+ fluds to <value>
+
+ -- The following are if compiled with THROTTLE_ENABLE --
+ THROTTLE ENABLE - Enables/disables connection
+ throttling
+ THROTTLE COUNT - Sets connection count to <value>
+ THROTTLE TIME - Sets time window to <value> seconds
+ THROTTLE RECORDTIME - Sets host record time to <value>
+ seconds
+ THROTTLE HASH - Resizes throttle hashtable to
+ <value> buckets
+ LCLONES <ip> - Displays or sets soft local clone
+ limit for <ip> (1.2.3.4/1.2.3.*)
+ to <value> (0 to reset to default)
+ GCLONES <ip> - Displays or sets soft global clone
+ limit for <ip> to <value>
+ DEFLCLONES - Same as local_clones in conf
+ DEFGCLONES - Same as global_clones in conf
--- /dev/null
+<html>
+<head>
+<title>pcrepattern specification</title>
+</head>
+<body bgcolor="#FFFFFF" text="#00005A" link="#0066FF" alink="#3399FF" vlink="#2222BB">
+This HTML document has been generated automatically from the original man page.
+If there is any nonsense in it, please consult the man page, in case the
+conversion went wrong.<br>
+<ul>
+<li><a name="TOC1" href="#SEC1">PCRE REGULAR EXPRESSION DETAILS</a>
+<li><a name="TOC2" href="#SEC2">BACKSLASH</a>
+<li><a name="TOC3" href="#SEC3">CIRCUMFLEX AND DOLLAR</a>
+<li><a name="TOC4" href="#SEC4">FULL STOP (PERIOD, DOT)</a>
+<li><a name="TOC5" href="#SEC5">MATCHING A SINGLE BYTE</a>
+<li><a name="TOC6" href="#SEC6">SQUARE BRACKETS</a>
+<li><a name="TOC7" href="#SEC7">POSIX CHARACTER CLASSES</a>
+<li><a name="TOC8" href="#SEC8">VERTICAL BAR</a>
+<li><a name="TOC9" href="#SEC9">INTERNAL OPTION SETTING</a>
+<li><a name="TOC10" href="#SEC10">SUBPATTERNS</a>
+<li><a name="TOC11" href="#SEC11">NAMED SUBPATTERNS</a>
+<li><a name="TOC12" href="#SEC12">REPETITION</a>
+<li><a name="TOC13" href="#SEC13">ATOMIC GROUPING AND POSSESSIVE QUANTIFIERS</a>
+<li><a name="TOC14" href="#SEC14">BACK REFERENCES</a>
+<li><a name="TOC15" href="#SEC15">ASSERTIONS</a>
+<li><a name="TOC16" href="#SEC16">CONDITIONAL SUBPATTERNS</a>
+<li><a name="TOC17" href="#SEC17">COMMENTS</a>
+<li><a name="TOC18" href="#SEC18">RECURSIVE PATTERNS</a>
+<li><a name="TOC19" href="#SEC19">SUBPATTERNS AS SUBROUTINES</a>
+<li><a name="TOC20" href="#SEC20">CALLOUTS</a>
+</ul>
+<br><a name="SEC1" href="#TOC1">PCRE REGULAR EXPRESSION DETAILS</a><br>
+<P>
+The syntax and semantics of the regular expressions supported by PCRE are
+described below. Regular expressions are also described in the Perl
+documentation and in a number of other books, some of which have copious
+examples. Jeffrey Friedl's "Mastering Regular Expressions", published by
+O'Reilly, covers them in great detail. The description here is intended as
+reference documentation.
+</P>
+<P>
+The basic operation of PCRE is on strings of bytes. However, there is also
+support for UTF-8 character strings. To use this support you must build PCRE to
+include UTF-8 support, and then call <b>pcre_compile()</b> with the PCRE_UTF8
+option. How this affects the pattern matching is mentioned in several places
+below. There is also a summary of UTF-8 features in the
+<a href="pcre.html#utf8support">section on UTF-8 support</a>
+in the main
+<a href="pcre.html"><b>pcre</b></a>
+page.
+</P>
+<P>
+A regular expression is a pattern that is matched against a subject string from
+left to right. Most characters stand for themselves in a pattern, and match the
+corresponding characters in the subject. As a trivial example, the pattern
+</P>
+<P>
+<pre>
+ The quick brown fox
+</PRE>
+</P>
+<P>
+matches a portion of a subject string that is identical to itself. The power of
+regular expressions comes from the ability to include alternatives and
+repetitions in the pattern. These are encoded in the pattern by the use of
+<i>meta-characters</i>, which do not stand for themselves but instead are
+interpreted in some special way.
+</P>
+<P>
+There are two different sets of meta-characters: those that are recognized
+anywhere in the pattern except within square brackets, and those that are
+recognized in square brackets. Outside square brackets, the meta-characters are
+as follows:
+</P>
+<P>
+<pre>
+ \ general escape character with several uses
+ ^ assert start of string (or line, in multiline mode)
+ $ assert end of string (or line, in multiline mode)
+ . match any character except newline (by default)
+ [ start character class definition
+ | start of alternative branch
+ ( start subpattern
+ ) end subpattern
+ ? extends the meaning of (
+ also 0 or 1 quantifier
+ also quantifier minimizer
+ * 0 or more quantifier
+ + 1 or more quantifier
+ also "possessive quantifier"
+ { start min/max quantifier
+</PRE>
+</P>
+<P>
+Part of a pattern that is in square brackets is called a "character class". In
+a character class the only meta-characters are:
+</P>
+<P>
+<pre>
+ \ general escape character
+ ^ negate the class, but only if the first character
+ - indicates character range
+ [ POSIX character class (only if followed by POSIX
+ syntax)
+ ] terminates the character class
+</PRE>
+</P>
+<P>
+The following sections describe the use of each of the meta-characters.
+</P>
+<br><a name="SEC2" href="#TOC1">BACKSLASH</a><br>
+<P>
+The backslash character has several uses. Firstly, if it is followed by a
+non-alphameric character, it takes away any special meaning that character may
+have. This use of backslash as an escape character applies both inside and
+outside character classes.
+</P>
+<P>
+For example, if you want to match a * character, you write \* in the pattern.
+This escaping action applies whether or not the following character would
+otherwise be interpreted as a meta-character, so it is always safe to precede a
+non-alphameric with backslash to specify that it stands for itself. In
+particular, if you want to match a backslash, you write \\.
+</P>
+<P>
+If a pattern is compiled with the PCRE_EXTENDED option, whitespace in the
+pattern (other than in a character class) and characters between a # outside
+a character class and the next newline character are ignored. An escaping
+backslash can be used to include a whitespace or # character as part of the
+pattern.
+</P>
+<P>
+If you want to remove the special meaning from a sequence of characters, you
+can do so by putting them between \Q and \E. This is different from Perl in
+that $ and @ are handled as literals in \Q...\E sequences in PCRE, whereas in
+Perl, $ and @ cause variable interpolation. Note the following examples:
+</P>
+<P>
+<pre>
+ Pattern PCRE matches Perl matches
+</PRE>
+</P>
+<P>
+<pre>
+ \Qabc$xyz\E abc$xyz abc followed by the
+ contents of $xyz
+ \Qabc\$xyz\E abc\$xyz abc\$xyz
+ \Qabc\E\$\Qxyz\E abc$xyz abc$xyz
+</PRE>
+</P>
+<P>
+The \Q...\E sequence is recognized both inside and outside character classes.
+</P>
+<P>
+A second use of backslash provides a way of encoding non-printing characters
+in patterns in a visible manner. There is no restriction on the appearance of
+non-printing characters, apart from the binary zero that terminates a pattern,
+but when a pattern is being prepared by text editing, it is usually easier to
+use one of the following escape sequences than the binary character it
+represents:
+</P>
+<P>
+<pre>
+ \a alarm, that is, the BEL character (hex 07)
+ \cx "control-x", where x is any character
+ \e escape (hex 1B)
+ \f formfeed (hex 0C)
+ \n newline (hex 0A)
+ \r carriage return (hex 0D)
+ \t tab (hex 09)
+ \ddd character with octal code ddd, or backreference
+ \xhh character with hex code hh
+ \x{hhh..} character with hex code hhh... (UTF-8 mode only)
+</PRE>
+</P>
+<P>
+The precise effect of \cx is as follows: if x is a lower case letter, it
+is converted to upper case. Then bit 6 of the character (hex 40) is inverted.
+Thus \cz becomes hex 1A, but \c{ becomes hex 3B, while \c; becomes hex
+7B.
+</P>
+<P>
+After \x, from zero to two hexadecimal digits are read (letters can be in
+upper or lower case). In UTF-8 mode, any number of hexadecimal digits may
+appear between \x{ and }, but the value of the character code must be less
+than 2**31 (that is, the maximum hexadecimal value is 7FFFFFFF). If characters
+other than hexadecimal digits appear between \x{ and }, or if there is no
+terminating }, this form of escape is not recognized. Instead, the initial
+\x will be interpreted as a basic hexadecimal escape, with no following
+digits, giving a byte whose value is zero.
+</P>
+<P>
+Characters whose value is less than 256 can be defined by either of the two
+syntaxes for \x when PCRE is in UTF-8 mode. There is no difference in the
+way they are handled. For example, \xdc is exactly the same as \x{dc}.
+</P>
+<P>
+After \0 up to two further octal digits are read. In both cases, if there
+are fewer than two digits, just those that are present are used. Thus the
+sequence \0\x\07 specifies two binary zeros followed by a BEL character
+(code value 7). Make sure you supply two digits after the initial zero if the
+character that follows is itself an octal digit.
+</P>
+<P>
+The handling of a backslash followed by a digit other than 0 is complicated.
+Outside a character class, PCRE reads it and any following digits as a decimal
+number. If the number is less than 10, or if there have been at least that many
+previous capturing left parentheses in the expression, the entire sequence is
+taken as a <i>back reference</i>. A description of how this works is given
+later, following the discussion of parenthesized subpatterns.
+</P>
+<P>
+Inside a character class, or if the decimal number is greater than 9 and there
+have not been that many capturing subpatterns, PCRE re-reads up to three octal
+digits following the backslash, and generates a single byte from the least
+significant 8 bits of the value. Any subsequent digits stand for themselves.
+For example:
+</P>
+<P>
+<pre>
+ \040 is another way of writing a space
+ \40 is the same, provided there are fewer than 40
+ previous capturing subpatterns
+ \7 is always a back reference
+ \11 might be a back reference, or another way of
+ writing a tab
+ \011 is always a tab
+ \0113 is a tab followed by the character "3"
+ \113 might be a back reference, otherwise the
+ character with octal code 113
+ \377 might be a back reference, otherwise
+ the byte consisting entirely of 1 bits
+ \81 is either a back reference, or a binary zero
+ followed by the two characters "8" and "1"
+</PRE>
+</P>
+<P>
+Note that octal values of 100 or greater must not be introduced by a leading
+zero, because no more than three octal digits are ever read.
+</P>
+<P>
+All the sequences that define a single byte value or a single UTF-8 character
+(in UTF-8 mode) can be used both inside and outside character classes. In
+addition, inside a character class, the sequence \b is interpreted as the
+backspace character (hex 08). Outside a character class it has a different
+meaning (see below).
+</P>
+<P>
+The third use of backslash is for specifying generic character types:
+</P>
+<P>
+<pre>
+ \d any decimal digit
+ \D any character that is not a decimal digit
+ \s any whitespace character
+ \S any character that is not a whitespace character
+ \w any "word" character
+ \W any "non-word" character
+</PRE>
+</P>
+<P>
+Each pair of escape sequences partitions the complete set of characters into
+two disjoint sets. Any given character matches one, and only one, of each pair.
+</P>
+<P>
+In UTF-8 mode, characters with values greater than 255 never match \d, \s, or
+\w, and always match \D, \S, and \W.
+</P>
+<P>
+For compatibility with Perl, \s does not match the VT character (code 11).
+This makes it different from the the POSIX "space" class. The \s characters
+are HT (9), LF (10), FF (12), CR (13), and space (32).
+</P>
+<P>
+A "word" character is any letter or digit or the underscore character, that is,
+any character which can be part of a Perl "word". The definition of letters and
+digits is controlled by PCRE's character tables, and may vary if locale-
+specific matching is taking place (see
+<a href="pcreapi.html#localesupport">"Locale support"</a>
+in the
+<a href="pcreapi.html"><b>pcreapi</b></a>
+page). For example, in the "fr" (French) locale, some character codes greater
+than 128 are used for accented letters, and these are matched by \w.
+</P>
+<P>
+These character type sequences can appear both inside and outside character
+classes. They each match one character of the appropriate type. If the current
+matching point is at the end of the subject string, all of them fail, since
+there is no character to match.
+</P>
+<P>
+The fourth use of backslash is for certain simple assertions. An assertion
+specifies a condition that has to be met at a particular point in a match,
+without consuming any characters from the subject string. The use of
+subpatterns for more complicated assertions is described below. The backslashed
+assertions are
+</P>
+<P>
+<pre>
+ \b matches at a word boundary
+ \B matches when not at a word boundary
+ \A matches at start of subject
+ \Z matches at end of subject or before newline at end
+ \z matches at end of subject
+ \G matches at first matching position in subject
+</PRE>
+</P>
+<P>
+These assertions may not appear in character classes (but note that \b has a
+different meaning, namely the backspace character, inside a character class).
+</P>
+<P>
+A word boundary is a position in the subject string where the current character
+and the previous character do not both match \w or \W (i.e. one matches
+\w and the other matches \W), or the start or end of the string if the
+first or last character matches \w, respectively.
+</P>
+<P>
+The \A, \Z, and \z assertions differ from the traditional circumflex and
+dollar (described below) in that they only ever match at the very start and end
+of the subject string, whatever options are set. Thus, they are independent of
+multiline mode.
+</P>
+<P>
+They are not affected by the PCRE_NOTBOL or PCRE_NOTEOL options. If the
+<i>startoffset</i> argument of <b>pcre_exec()</b> is non-zero, indicating that
+matching is to start at a point other than the beginning of the subject, \A
+can never match. The difference between \Z and \z is that \Z matches before
+a newline that is the last character of the string as well as at the end of the
+string, whereas \z matches only at the end.
+</P>
+<P>
+The \G assertion is true only when the current matching position is at the
+start point of the match, as specified by the <i>startoffset</i> argument of
+<b>pcre_exec()</b>. It differs from \A when the value of <i>startoffset</i> is
+non-zero. By calling <b>pcre_exec()</b> multiple times with appropriate
+arguments, you can mimic Perl's /g option, and it is in this kind of
+implementation where \G can be useful.
+</P>
+<P>
+Note, however, that PCRE's interpretation of \G, as the start of the current
+match, is subtly different from Perl's, which defines it as the end of the
+previous match. In Perl, these can be different when the previously matched
+string was empty. Because PCRE does just one match at a time, it cannot
+reproduce this behaviour.
+</P>
+<P>
+If all the alternatives of a pattern begin with \G, the expression is anchored
+to the starting match position, and the "anchored" flag is set in the compiled
+regular expression.
+</P>
+<br><a name="SEC3" href="#TOC1">CIRCUMFLEX AND DOLLAR</a><br>
+<P>
+Outside a character class, in the default matching mode, the circumflex
+character is an assertion which is true only if the current matching point is
+at the start of the subject string. If the <i>startoffset</i> argument of
+<b>pcre_exec()</b> is non-zero, circumflex can never match if the PCRE_MULTILINE
+option is unset. Inside a character class, circumflex has an entirely different
+meaning (see below).
+</P>
+<P>
+Circumflex need not be the first character of the pattern if a number of
+alternatives are involved, but it should be the first thing in each alternative
+in which it appears if the pattern is ever to match that branch. If all
+possible alternatives start with a circumflex, that is, if the pattern is
+constrained to match only at the start of the subject, it is said to be an
+"anchored" pattern. (There are also other constructs that can cause a pattern
+to be anchored.)
+</P>
+<P>
+A dollar character is an assertion which is true only if the current matching
+point is at the end of the subject string, or immediately before a newline
+character that is the last character in the string (by default). Dollar need
+not be the last character of the pattern if a number of alternatives are
+involved, but it should be the last item in any branch in which it appears.
+Dollar has no special meaning in a character class.
+</P>
+<P>
+The meaning of dollar can be changed so that it matches only at the very end of
+the string, by setting the PCRE_DOLLAR_ENDONLY option at compile time. This
+does not affect the \Z assertion.
+</P>
+<P>
+The meanings of the circumflex and dollar characters are changed if the
+PCRE_MULTILINE option is set. When this is the case, they match immediately
+after and immediately before an internal newline character, respectively, in
+addition to matching at the start and end of the subject string. For example,
+the pattern /^abc$/ matches the subject string "def\nabc" in multiline mode,
+but not otherwise. Consequently, patterns that are anchored in single line mode
+because all branches start with ^ are not anchored in multiline mode, and a
+match for circumflex is possible when the <i>startoffset</i> argument of
+<b>pcre_exec()</b> is non-zero. The PCRE_DOLLAR_ENDONLY option is ignored if
+PCRE_MULTILINE is set.
+</P>
+<P>
+Note that the sequences \A, \Z, and \z can be used to match the start and
+end of the subject in both modes, and if all branches of a pattern start with
+\A it is always anchored, whether PCRE_MULTILINE is set or not.
+</P>
+<br><a name="SEC4" href="#TOC1">FULL STOP (PERIOD, DOT)</a><br>
+<P>
+Outside a character class, a dot in the pattern matches any one character in
+the subject, including a non-printing character, but not (by default) newline.
+In UTF-8 mode, a dot matches any UTF-8 character, which might be more than one
+byte long, except (by default) for newline. If the PCRE_DOTALL option is set,
+dots match newlines as well. The handling of dot is entirely independent of the
+handling of circumflex and dollar, the only relationship being that they both
+involve newline characters. Dot has no special meaning in a character class.
+</P>
+<br><a name="SEC5" href="#TOC1">MATCHING A SINGLE BYTE</a><br>
+<P>
+Outside a character class, the escape sequence \C matches any one byte, both
+in and out of UTF-8 mode. Unlike a dot, it always matches a newline. The
+feature is provided in Perl in order to match individual bytes in UTF-8 mode.
+Because it breaks up UTF-8 characters into individual bytes, what remains in
+the string may be a malformed UTF-8 string. For this reason it is best avoided.
+</P>
+<P>
+PCRE does not allow \C to appear in lookbehind assertions (see below), because
+in UTF-8 mode it makes it impossible to calculate the length of the lookbehind.
+</P>
+<br><a name="SEC6" href="#TOC1">SQUARE BRACKETS</a><br>
+<P>
+An opening square bracket introduces a character class, terminated by a closing
+square bracket. A closing square bracket on its own is not special. If a
+closing square bracket is required as a member of the class, it should be the
+first data character in the class (after an initial circumflex, if present) or
+escaped with a backslash.
+</P>
+<P>
+A character class matches a single character in the subject. In UTF-8 mode, the
+character may occupy more than one byte. A matched character must be in the set
+of characters defined by the class, unless the first character in the class
+definition is a circumflex, in which case the subject character must not be in
+the set defined by the class. If a circumflex is actually required as a member
+of the class, ensure it is not the first character, or escape it with a
+backslash.
+</P>
+<P>
+For example, the character class [aeiou] matches any lower case vowel, while
+[^aeiou] matches any character that is not a lower case vowel. Note that a
+circumflex is just a convenient notation for specifying the characters which
+are in the class by enumerating those that are not. It is not an assertion: it
+still consumes a character from the subject string, and fails if the current
+pointer is at the end of the string.
+</P>
+<P>
+In UTF-8 mode, characters with values greater than 255 can be included in a
+class as a literal string of bytes, or by using the \x{ escaping mechanism.
+</P>
+<P>
+When caseless matching is set, any letters in a class represent both their
+upper case and lower case versions, so for example, a caseless [aeiou] matches
+"A" as well as "a", and a caseless [^aeiou] does not match "A", whereas a
+caseful version would. PCRE does not support the concept of case for characters
+with values greater than 255.
+</P>
+<P>
+The newline character is never treated in any special way in character classes,
+whatever the setting of the PCRE_DOTALL or PCRE_MULTILINE options is. A class
+such as [^a] will always match a newline.
+</P>
+<P>
+The minus (hyphen) character can be used to specify a range of characters in a
+character class. For example, [d-m] matches any letter between d and m,
+inclusive. If a minus character is required in a class, it must be escaped with
+a backslash or appear in a position where it cannot be interpreted as
+indicating a range, typically as the first or last character in the class.
+</P>
+<P>
+It is not possible to have the literal character "]" as the end character of a
+range. A pattern such as [W-]46] is interpreted as a class of two characters
+("W" and "-") followed by a literal string "46]", so it would match "W46]" or
+"-46]". However, if the "]" is escaped with a backslash it is interpreted as
+the end of range, so [W-\]46] is interpreted as a single class containing a
+range followed by two separate characters. The octal or hexadecimal
+representation of "]" can also be used to end a range.
+</P>
+<P>
+Ranges operate in the collating sequence of character values. They can also be
+used for characters specified numerically, for example [\000-\037]. In UTF-8
+mode, ranges can include characters whose values are greater than 255, for
+example [\x{100}-\x{2ff}].
+</P>
+<P>
+If a range that includes letters is used when caseless matching is set, it
+matches the letters in either case. For example, [W-c] is equivalent to
+[][\^_`wxyzabc], matched caselessly, and if character tables for the "fr"
+locale are in use, [\xc8-\xcb] matches accented E characters in both cases.
+</P>
+<P>
+The character types \d, \D, \s, \S, \w, and \W may also appear in a
+character class, and add the characters that they match to the class. For
+example, [\dABCDEF] matches any hexadecimal digit. A circumflex can
+conveniently be used with the upper case character types to specify a more
+restricted set of characters than the matching lower case type. For example,
+the class [^\W_] matches any letter or digit, but not underscore.
+</P>
+<P>
+All non-alphameric characters other than \, -, ^ (at the start) and the
+terminating ] are non-special in character classes, but it does no harm if they
+are escaped.
+</P>
+<br><a name="SEC7" href="#TOC1">POSIX CHARACTER CLASSES</a><br>
+<P>
+Perl supports the POSIX notation for character classes, which uses names
+enclosed by [: and :] within the enclosing square brackets. PCRE also supports
+this notation. For example,
+</P>
+<P>
+<pre>
+ [01[:alpha:]%]
+</PRE>
+</P>
+<P>
+matches "0", "1", any alphabetic character, or "%". The supported class names
+are
+</P>
+<P>
+<pre>
+ alnum letters and digits
+ alpha letters
+ ascii character codes 0 - 127
+ blank space or tab only
+ cntrl control characters
+ digit decimal digits (same as \d)
+ graph printing characters, excluding space
+ lower lower case letters
+ print printing characters, including space
+ punct printing characters, excluding letters and digits
+ space white space (not quite the same as \s)
+ upper upper case letters
+ word "word" characters (same as \w)
+ xdigit hexadecimal digits
+</PRE>
+</P>
+<P>
+The "space" characters are HT (9), LF (10), VT (11), FF (12), CR (13), and
+space (32). Notice that this list includes the VT character (code 11). This
+makes "space" different to \s, which does not include VT (for Perl
+compatibility).
+</P>
+<P>
+The name "word" is a Perl extension, and "blank" is a GNU extension from Perl
+5.8. Another Perl extension is negation, which is indicated by a ^ character
+after the colon. For example,
+</P>
+<P>
+<pre>
+ [12[:^digit:]]
+</PRE>
+</P>
+<P>
+matches "1", "2", or any non-digit. PCRE (and Perl) also recognize the POSIX
+syntax [.ch.] and [=ch=] where "ch" is a "collating element", but these are not
+supported, and an error is given if they are encountered.
+</P>
+<P>
+In UTF-8 mode, characters with values greater than 255 do not match any of
+the POSIX character classes.
+</P>
+<br><a name="SEC8" href="#TOC1">VERTICAL BAR</a><br>
+<P>
+Vertical bar characters are used to separate alternative patterns. For example,
+the pattern
+</P>
+<P>
+<pre>
+ gilbert|sullivan
+</PRE>
+</P>
+<P>
+matches either "gilbert" or "sullivan". Any number of alternatives may appear,
+and an empty alternative is permitted (matching the empty string).
+The matching process tries each alternative in turn, from left to right,
+and the first one that succeeds is used. If the alternatives are within a
+subpattern (defined below), "succeeds" means matching the rest of the main
+pattern as well as the alternative in the subpattern.
+</P>
+<br><a name="SEC9" href="#TOC1">INTERNAL OPTION SETTING</a><br>
+<P>
+The settings of the PCRE_CASELESS, PCRE_MULTILINE, PCRE_DOTALL, and
+PCRE_EXTENDED options can be changed from within the pattern by a sequence of
+Perl option letters enclosed between "(?" and ")". The option letters are
+</P>
+<P>
+<pre>
+ i for PCRE_CASELESS
+ m for PCRE_MULTILINE
+ s for PCRE_DOTALL
+ x for PCRE_EXTENDED
+</PRE>
+</P>
+<P>
+For example, (?im) sets caseless, multiline matching. It is also possible to
+unset these options by preceding the letter with a hyphen, and a combined
+setting and unsetting such as (?im-sx), which sets PCRE_CASELESS and
+PCRE_MULTILINE while unsetting PCRE_DOTALL and PCRE_EXTENDED, is also
+permitted. If a letter appears both before and after the hyphen, the option is
+unset.
+</P>
+<P>
+When an option change occurs at top level (that is, not inside subpattern
+parentheses), the change applies to the remainder of the pattern that follows.
+If the change is placed right at the start of a pattern, PCRE extracts it into
+the global options (and it will therefore show up in data extracted by the
+<b>pcre_fullinfo()</b> function).
+</P>
+<P>
+An option change within a subpattern affects only that part of the current
+pattern that follows it, so
+</P>
+<P>
+<pre>
+ (a(?i)b)c
+</PRE>
+</P>
+<P>
+matches abc and aBc and no other strings (assuming PCRE_CASELESS is not used).
+By this means, options can be made to have different settings in different
+parts of the pattern. Any changes made in one alternative do carry on
+into subsequent branches within the same subpattern. For example,
+</P>
+<P>
+<pre>
+ (a(?i)b|c)
+</PRE>
+</P>
+<P>
+matches "ab", "aB", "c", and "C", even though when matching "C" the first
+branch is abandoned before the option setting. This is because the effects of
+option settings happen at compile time. There would be some very weird
+behaviour otherwise.
+</P>
+<P>
+The PCRE-specific options PCRE_UNGREEDY and PCRE_EXTRA can be changed in the
+same way as the Perl-compatible options by using the characters U and X
+respectively. The (?X) flag setting is special in that it must always occur
+earlier in the pattern than any of the additional features it turns on, even
+when it is at top level. It is best put at the start.
+</P>
+<br><a name="SEC10" href="#TOC1">SUBPATTERNS</a><br>
+<P>
+Subpatterns are delimited by parentheses (round brackets), which can be nested.
+Marking part of a pattern as a subpattern does two things:
+</P>
+<P>
+1. It localizes a set of alternatives. For example, the pattern
+</P>
+<P>
+<pre>
+ cat(aract|erpillar|)
+</PRE>
+</P>
+<P>
+matches one of the words "cat", "cataract", or "caterpillar". Without the
+parentheses, it would match "cataract", "erpillar" or the empty string.
+</P>
+<P>
+2. It sets up the subpattern as a capturing subpattern (as defined above).
+When the whole pattern matches, that portion of the subject string that matched
+the subpattern is passed back to the caller via the <i>ovector</i> argument of
+<b>pcre_exec()</b>. Opening parentheses are counted from left to right (starting
+from 1) to obtain the numbers of the capturing subpatterns.
+</P>
+<P>
+For example, if the string "the red king" is matched against the pattern
+</P>
+<P>
+<pre>
+ the ((red|white) (king|queen))
+</PRE>
+</P>
+<P>
+the captured substrings are "red king", "red", and "king", and are numbered 1,
+2, and 3, respectively.
+</P>
+<P>
+The fact that plain parentheses fulfil two functions is not always helpful.
+There are often times when a grouping subpattern is required without a
+capturing requirement. If an opening parenthesis is followed by a question mark
+and a colon, the subpattern does not do any capturing, and is not counted when
+computing the number of any subsequent capturing subpatterns. For example, if
+the string "the white queen" is matched against the pattern
+</P>
+<P>
+<pre>
+ the ((?:red|white) (king|queen))
+</PRE>
+</P>
+<P>
+the captured substrings are "white queen" and "queen", and are numbered 1 and
+2. The maximum number of capturing subpatterns is 65535, and the maximum depth
+of nesting of all subpatterns, both capturing and non-capturing, is 200.
+</P>
+<P>
+As a convenient shorthand, if any option settings are required at the start of
+a non-capturing subpattern, the option letters may appear between the "?" and
+the ":". Thus the two patterns
+</P>
+<P>
+<pre>
+ (?i:saturday|sunday)
+ (?:(?i)saturday|sunday)
+</PRE>
+</P>
+<P>
+match exactly the same set of strings. Because alternative branches are tried
+from left to right, and options are not reset until the end of the subpattern
+is reached, an option setting in one branch does affect subsequent branches, so
+the above patterns match "SUNDAY" as well as "Saturday".
+</P>
+<br><a name="SEC11" href="#TOC1">NAMED SUBPATTERNS</a><br>
+<P>
+Identifying capturing parentheses by number is simple, but it can be very hard
+to keep track of the numbers in complicated regular expressions. Furthermore,
+if an expression is modified, the numbers may change. To help with the
+difficulty, PCRE supports the naming of subpatterns, something that Perl does
+not provide. The Python syntax (?P<name>...) is used. Names consist of
+alphanumeric characters and underscores, and must be unique within a pattern.
+</P>
+<P>
+Named capturing parentheses are still allocated numbers as well as names. The
+PCRE API provides function calls for extracting the name-to-number translation
+table from a compiled pattern. For further details see the
+<a href="pcreapi.html"><b>pcreapi</b></a>
+documentation.
+</P>
+<br><a name="SEC12" href="#TOC1">REPETITION</a><br>
+<P>
+Repetition is specified by quantifiers, which can follow any of the following
+items:
+</P>
+<P>
+<pre>
+ a literal data character
+ the . metacharacter
+ the \C escape sequence
+ escapes such as \d that match single characters
+ a character class
+ a back reference (see next section)
+ a parenthesized subpattern (unless it is an assertion)
+</PRE>
+</P>
+<P>
+The general repetition quantifier specifies a minimum and maximum number of
+permitted matches, by giving the two numbers in curly brackets (braces),
+separated by a comma. The numbers must be less than 65536, and the first must
+be less than or equal to the second. For example:
+</P>
+<P>
+<pre>
+ z{2,4}
+</PRE>
+</P>
+<P>
+matches "zz", "zzz", or "zzzz". A closing brace on its own is not a special
+character. If the second number is omitted, but the comma is present, there is
+no upper limit; if the second number and the comma are both omitted, the
+quantifier specifies an exact number of required matches. Thus
+</P>
+<P>
+<pre>
+ [aeiou]{3,}
+</PRE>
+</P>
+<P>
+matches at least 3 successive vowels, but may match many more, while
+</P>
+<P>
+<pre>
+ \d{8}
+</PRE>
+</P>
+<P>
+matches exactly 8 digits. An opening curly bracket that appears in a position
+where a quantifier is not allowed, or one that does not match the syntax of a
+quantifier, is taken as a literal character. For example, {,6} is not a
+quantifier, but a literal string of four characters.
+</P>
+<P>
+In UTF-8 mode, quantifiers apply to UTF-8 characters rather than to individual
+bytes. Thus, for example, \x{100}{2} matches two UTF-8 characters, each of
+which is represented by a two-byte sequence.
+</P>
+<P>
+The quantifier {0} is permitted, causing the expression to behave as if the
+previous item and the quantifier were not present.
+</P>
+<P>
+For convenience (and historical compatibility) the three most common
+quantifiers have single-character abbreviations:
+</P>
+<P>
+<pre>
+ * is equivalent to {0,}
+ + is equivalent to {1,}
+ ? is equivalent to {0,1}
+</PRE>
+</P>
+<P>
+It is possible to construct infinite loops by following a subpattern that can
+match no characters with a quantifier that has no upper limit, for example:
+</P>
+<P>
+<pre>
+ (a?)*
+</PRE>
+</P>
+<P>
+Earlier versions of Perl and PCRE used to give an error at compile time for
+such patterns. However, because there are cases where this can be useful, such
+patterns are now accepted, but if any repetition of the subpattern does in fact
+match no characters, the loop is forcibly broken.
+</P>
+<P>
+By default, the quantifiers are "greedy", that is, they match as much as
+possible (up to the maximum number of permitted times), without causing the
+rest of the pattern to fail. The classic example of where this gives problems
+is in trying to match comments in C programs. These appear between the
+sequences /* and */ and within the sequence, individual * and / characters may
+appear. An attempt to match C comments by applying the pattern
+</P>
+<P>
+<pre>
+ /\*.*\*/
+</PRE>
+</P>
+<P>
+to the string
+</P>
+<P>
+<pre>
+ /* first command */ not comment /* second comment */
+</PRE>
+</P>
+<P>
+fails, because it matches the entire string owing to the greediness of the .*
+item.
+</P>
+<P>
+However, if a quantifier is followed by a question mark, it ceases to be
+greedy, and instead matches the minimum number of times possible, so the
+pattern
+</P>
+<P>
+<pre>
+ /\*.*?\*/
+</PRE>
+</P>
+<P>
+does the right thing with the C comments. The meaning of the various
+quantifiers is not otherwise changed, just the preferred number of matches.
+Do not confuse this use of question mark with its use as a quantifier in its
+own right. Because it has two uses, it can sometimes appear doubled, as in
+</P>
+<P>
+<pre>
+ \d??\d
+</PRE>
+</P>
+<P>
+which matches one digit by preference, but can match two if that is the only
+way the rest of the pattern matches.
+</P>
+<P>
+If the PCRE_UNGREEDY option is set (an option which is not available in Perl),
+the quantifiers are not greedy by default, but individual ones can be made
+greedy by following them with a question mark. In other words, it inverts the
+default behaviour.
+</P>
+<P>
+When a parenthesized subpattern is quantified with a minimum repeat count that
+is greater than 1 or with a limited maximum, more store is required for the
+compiled pattern, in proportion to the size of the minimum or maximum.
+</P>
+<P>
+If a pattern starts with .* or .{0,} and the PCRE_DOTALL option (equivalent
+to Perl's /s) is set, thus allowing the . to match newlines, the pattern is
+implicitly anchored, because whatever follows will be tried against every
+character position in the subject string, so there is no point in retrying the
+overall match at any position after the first. PCRE normally treats such a
+pattern as though it were preceded by \A.
+</P>
+<P>
+In cases where it is known that the subject string contains no newlines, it is
+worth setting PCRE_DOTALL in order to obtain this optimization, or
+alternatively using ^ to indicate anchoring explicitly.
+</P>
+<P>
+However, there is one situation where the optimization cannot be used. When .*
+is inside capturing parentheses that are the subject of a backreference
+elsewhere in the pattern, a match at the start may fail, and a later one
+succeed. Consider, for example:
+</P>
+<P>
+<pre>
+ (.*)abc\1
+</PRE>
+</P>
+<P>
+If the subject is "xyz123abc123" the match point is the fourth character. For
+this reason, such a pattern is not implicitly anchored.
+</P>
+<P>
+When a capturing subpattern is repeated, the value captured is the substring
+that matched the final iteration. For example, after
+</P>
+<P>
+<pre>
+ (tweedle[dume]{3}\s*)+
+</PRE>
+</P>
+<P>
+has matched "tweedledum tweedledee" the value of the captured substring is
+"tweedledee". However, if there are nested capturing subpatterns, the
+corresponding captured values may have been set in previous iterations. For
+example, after
+</P>
+<P>
+<pre>
+ /(a|(b))+/
+</PRE>
+</P>
+<P>
+matches "aba" the value of the second captured substring is "b".
+</P>
+<br><a name="SEC13" href="#TOC1">ATOMIC GROUPING AND POSSESSIVE QUANTIFIERS</a><br>
+<P>
+With both maximizing and minimizing repetition, failure of what follows
+normally causes the repeated item to be re-evaluated to see if a different
+number of repeats allows the rest of the pattern to match. Sometimes it is
+useful to prevent this, either to change the nature of the match, or to cause
+it fail earlier than it otherwise might, when the author of the pattern knows
+there is no point in carrying on.
+</P>
+<P>
+Consider, for example, the pattern \d+foo when applied to the subject line
+</P>
+<P>
+<pre>
+ 123456bar
+</PRE>
+</P>
+<P>
+After matching all 6 digits and then failing to match "foo", the normal
+action of the matcher is to try again with only 5 digits matching the \d+
+item, and then with 4, and so on, before ultimately failing. "Atomic grouping"
+(a term taken from Jeffrey Friedl's book) provides the means for specifying
+that once a subpattern has matched, it is not to be re-evaluated in this way.
+</P>
+<P>
+If we use atomic grouping for the previous example, the matcher would give up
+immediately on failing to match "foo" the first time. The notation is a kind of
+special parenthesis, starting with (?> as in this example:
+</P>
+<P>
+<pre>
+ (?>\d+)foo
+</PRE>
+</P>
+<P>
+This kind of parenthesis "locks up" the part of the pattern it contains once
+it has matched, and a failure further into the pattern is prevented from
+backtracking into it. Backtracking past it to previous items, however, works as
+normal.
+</P>
+<P>
+An alternative description is that a subpattern of this type matches the string
+of characters that an identical standalone pattern would match, if anchored at
+the current point in the subject string.
+</P>
+<P>
+Atomic grouping subpatterns are not capturing subpatterns. Simple cases such as
+the above example can be thought of as a maximizing repeat that must swallow
+everything it can. So, while both \d+ and \d+? are prepared to adjust the
+number of digits they match in order to make the rest of the pattern match,
+(?>\d+) can only match an entire sequence of digits.
+</P>
+<P>
+Atomic groups in general can of course contain arbitrarily complicated
+subpatterns, and can be nested. However, when the subpattern for an atomic
+group is just a single repeated item, as in the example above, a simpler
+notation, called a "possessive quantifier" can be used. This consists of an
+additional + character following a quantifier. Using this notation, the
+previous example can be rewritten as
+</P>
+<P>
+<pre>
+ \d++bar
+</PRE>
+</P>
+<P>
+Possessive quantifiers are always greedy; the setting of the PCRE_UNGREEDY
+option is ignored. They are a convenient notation for the simpler forms of
+atomic group. However, there is no difference in the meaning or processing of a
+possessive quantifier and the equivalent atomic group.
+</P>
+<P>
+The possessive quantifier syntax is an extension to the Perl syntax. It
+originates in Sun's Java package.
+</P>
+<P>
+When a pattern contains an unlimited repeat inside a subpattern that can itself
+be repeated an unlimited number of times, the use of an atomic group is the
+only way to avoid some failing matches taking a very long time indeed. The
+pattern
+</P>
+<P>
+<pre>
+ (\D+|<\d+>)*[!?]
+</PRE>
+</P>
+<P>
+matches an unlimited number of substrings that either consist of non-digits, or
+digits enclosed in <>, followed by either ! or ?. When it matches, it runs
+quickly. However, if it is applied to
+</P>
+<P>
+<pre>
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+</PRE>
+</P>
+<P>
+it takes a long time before reporting failure. This is because the string can
+be divided between the two repeats in a large number of ways, and all have to
+be tried. (The example used [!?] rather than a single character at the end,
+because both PCRE and Perl have an optimization that allows for fast failure
+when a single character is used. They remember the last single character that
+is required for a match, and fail early if it is not present in the string.)
+If the pattern is changed to
+</P>
+<P>
+<pre>
+ ((?>\D+)|<\d+>)*[!?]
+</PRE>
+</P>
+<P>
+sequences of non-digits cannot be broken, and failure happens quickly.
+</P>
+<br><a name="SEC14" href="#TOC1">BACK REFERENCES</a><br>
+<P>
+Outside a character class, a backslash followed by a digit greater than 0 (and
+possibly further digits) is a back reference to a capturing subpattern earlier
+(that is, to its left) in the pattern, provided there have been that many
+previous capturing left parentheses.
+</P>
+<P>
+However, if the decimal number following the backslash is less than 10, it is
+always taken as a back reference, and causes an error only if there are not
+that many capturing left parentheses in the entire pattern. In other words, the
+parentheses that are referenced need not be to the left of the reference for
+numbers less than 10. See the section entitled "Backslash" above for further
+details of the handling of digits following a backslash.
+</P>
+<P>
+A back reference matches whatever actually matched the capturing subpattern in
+the current subject string, rather than anything matching the subpattern
+itself (see
+<a href="#subpatternsassubroutines">"Subpatterns as subroutines"</a>
+below for a way of doing that). So the pattern
+</P>
+<P>
+<pre>
+ (sens|respons)e and \1ibility
+</PRE>
+</P>
+<P>
+matches "sense and sensibility" and "response and responsibility", but not
+"sense and responsibility". If caseful matching is in force at the time of the
+back reference, the case of letters is relevant. For example,
+</P>
+<P>
+<pre>
+ ((?i)rah)\s+\1
+</PRE>
+</P>
+<P>
+matches "rah rah" and "RAH RAH", but not "RAH rah", even though the original
+capturing subpattern is matched caselessly.
+</P>
+<P>
+Back references to named subpatterns use the Python syntax (?P=name). We could
+rewrite the above example as follows:
+</P>
+<P>
+<pre>
+ (?<p1>(?i)rah)\s+(?P=p1)
+</PRE>
+</P>
+<P>
+There may be more than one back reference to the same subpattern. If a
+subpattern has not actually been used in a particular match, any back
+references to it always fail. For example, the pattern
+</P>
+<P>
+<pre>
+ (a|(bc))\2
+</PRE>
+</P>
+<P>
+always fails if it starts to match "a" rather than "bc". Because there may be
+many capturing parentheses in a pattern, all digits following the backslash are
+taken as part of a potential back reference number. If the pattern continues
+with a digit character, some delimiter must be used to terminate the back
+reference. If the PCRE_EXTENDED option is set, this can be whitespace.
+Otherwise an empty comment can be used.
+</P>
+<P>
+A back reference that occurs inside the parentheses to which it refers fails
+when the subpattern is first used, so, for example, (a\1) never matches.
+However, such references can be useful inside repeated subpatterns. For
+example, the pattern
+</P>
+<P>
+<pre>
+ (a|b\1)+
+</PRE>
+</P>
+<P>
+matches any number of "a"s and also "aba", "ababbaa" etc. At each iteration of
+the subpattern, the back reference matches the character string corresponding
+to the previous iteration. In order for this to work, the pattern must be such
+that the first iteration does not need to match the back reference. This can be
+done using alternation, as in the example above, or by a quantifier with a
+minimum of zero.
+</P>
+<br><a name="SEC15" href="#TOC1">ASSERTIONS</a><br>
+<P>
+An assertion is a test on the characters following or preceding the current
+matching point that does not actually consume any characters. The simple
+assertions coded as \b, \B, \A, \G, \Z, \z, ^ and $ are described above.
+More complicated assertions are coded as subpatterns. There are two kinds:
+those that look ahead of the current position in the subject string, and those
+that look behind it.
+</P>
+<P>
+An assertion subpattern is matched in the normal way, except that it does not
+cause the current matching position to be changed. Lookahead assertions start
+with (?= for positive assertions and (?! for negative assertions. For example,
+</P>
+<P>
+<pre>
+ \w+(?=;)
+</PRE>
+</P>
+<P>
+matches a word followed by a semicolon, but does not include the semicolon in
+the match, and
+</P>
+<P>
+<pre>
+ foo(?!bar)
+</PRE>
+</P>
+<P>
+matches any occurrence of "foo" that is not followed by "bar". Note that the
+apparently similar pattern
+</P>
+<P>
+<pre>
+ (?!foo)bar
+</PRE>
+</P>
+<P>
+does not find an occurrence of "bar" that is preceded by something other than
+"foo"; it finds any occurrence of "bar" whatsoever, because the assertion
+(?!foo) is always true when the next three characters are "bar". A
+lookbehind assertion is needed to achieve this effect.
+</P>
+<P>
+If you want to force a matching failure at some point in a pattern, the most
+convenient way to do it is with (?!) because an empty string always matches, so
+an assertion that requires there not to be an empty string must always fail.
+</P>
+<P>
+Lookbehind assertions start with (?<= for positive assertions and (?<! for
+negative assertions. For example,
+</P>
+<P>
+<pre>
+ (?<!foo)bar
+</PRE>
+</P>
+<P>
+does find an occurrence of "bar" that is not preceded by "foo". The contents of
+a lookbehind assertion are restricted such that all the strings it matches must
+have a fixed length. However, if there are several alternatives, they do not
+all have to have the same fixed length. Thus
+</P>
+<P>
+<pre>
+ (?<=bullock|donkey)
+</PRE>
+</P>
+<P>
+is permitted, but
+</P>
+<P>
+<pre>
+ (?<!dogs?|cats?)
+</PRE>
+</P>
+<P>
+causes an error at compile time. Branches that match different length strings
+are permitted only at the top level of a lookbehind assertion. This is an
+extension compared with Perl (at least for 5.8), which requires all branches to
+match the same length of string. An assertion such as
+</P>
+<P>
+<pre>
+ (?<=ab(c|de))
+</PRE>
+</P>
+<P>
+is not permitted, because its single top-level branch can match two different
+lengths, but it is acceptable if rewritten to use two top-level branches:
+</P>
+<P>
+<pre>
+ (?<=abc|abde)
+</PRE>
+</P>
+<P>
+The implementation of lookbehind assertions is, for each alternative, to
+temporarily move the current position back by the fixed width and then try to
+match. If there are insufficient characters before the current position, the
+match is deemed to fail.
+</P>
+<P>
+PCRE does not allow the \C escape (which matches a single byte in UTF-8 mode)
+to appear in lookbehind assertions, because it makes it impossible to calculate
+the length of the lookbehind.
+</P>
+<P>
+Atomic groups can be used in conjunction with lookbehind assertions to specify
+efficient matching at the end of the subject string. Consider a simple pattern
+such as
+</P>
+<P>
+<pre>
+ abcd$
+</PRE>
+</P>
+<P>
+when applied to a long string that does not match. Because matching proceeds
+from left to right, PCRE will look for each "a" in the subject and then see if
+what follows matches the rest of the pattern. If the pattern is specified as
+</P>
+<P>
+<pre>
+ ^.*abcd$
+</PRE>
+</P>
+<P>
+the initial .* matches the entire string at first, but when this fails (because
+there is no following "a"), it backtracks to match all but the last character,
+then all but the last two characters, and so on. Once again the search for "a"
+covers the entire string, from right to left, so we are no better off. However,
+if the pattern is written as
+</P>
+<P>
+<pre>
+ ^(?>.*)(?<=abcd)
+</PRE>
+</P>
+<P>
+or, equivalently,
+</P>
+<P>
+<pre>
+ ^.*+(?<=abcd)
+</PRE>
+</P>
+<P>
+there can be no backtracking for the .* item; it can match only the entire
+string. The subsequent lookbehind assertion does a single test on the last four
+characters. If it fails, the match fails immediately. For long strings, this
+approach makes a significant difference to the processing time.
+</P>
+<P>
+Several assertions (of any sort) may occur in succession. For example,
+</P>
+<P>
+<pre>
+ (?<=\d{3})(?<!999)foo
+</PRE>
+</P>
+<P>
+matches "foo" preceded by three digits that are not "999". Notice that each of
+the assertions is applied independently at the same point in the subject
+string. First there is a check that the previous three characters are all
+digits, and then there is a check that the same three characters are not "999".
+This pattern does <i>not</i> match "foo" preceded by six characters, the first
+of which are digits and the last three of which are not "999". For example, it
+doesn't match "123abcfoo". A pattern to do that is
+</P>
+<P>
+<pre>
+ (?<=\d{3}...)(?<!999)foo
+</PRE>
+</P>
+<P>
+This time the first assertion looks at the preceding six characters, checking
+that the first three are digits, and then the second assertion checks that the
+preceding three characters are not "999".
+</P>
+<P>
+Assertions can be nested in any combination. For example,
+</P>
+<P>
+<pre>
+ (?<=(?<!foo)bar)baz
+</PRE>
+</P>
+<P>
+matches an occurrence of "baz" that is preceded by "bar" which in turn is not
+preceded by "foo", while
+</P>
+<P>
+<pre>
+ (?<=\d{3}(?!999)...)foo
+</PRE>
+</P>
+<P>
+is another pattern which matches "foo" preceded by three digits and any three
+characters that are not "999".
+</P>
+<P>
+Assertion subpatterns are not capturing subpatterns, and may not be repeated,
+because it makes no sense to assert the same thing several times. If any kind
+of assertion contains capturing subpatterns within it, these are counted for
+the purposes of numbering the capturing subpatterns in the whole pattern.
+However, substring capturing is carried out only for positive assertions,
+because it does not make sense for negative assertions.
+</P>
+<br><a name="SEC16" href="#TOC1">CONDITIONAL SUBPATTERNS</a><br>
+<P>
+It is possible to cause the matching process to obey a subpattern
+conditionally or to choose between two alternative subpatterns, depending on
+the result of an assertion, or whether a previous capturing subpattern matched
+or not. The two possible forms of conditional subpattern are
+</P>
+<P>
+<pre>
+ (?(condition)yes-pattern)
+ (?(condition)yes-pattern|no-pattern)
+</PRE>
+</P>
+<P>
+If the condition is satisfied, the yes-pattern is used; otherwise the
+no-pattern (if present) is used. If there are more than two alternatives in the
+subpattern, a compile-time error occurs.
+</P>
+<P>
+There are three kinds of condition. If the text between the parentheses
+consists of a sequence of digits, the condition is satisfied if the capturing
+subpattern of that number has previously matched. The number must be greater
+than zero. Consider the following pattern, which contains non-significant white
+space to make it more readable (assume the PCRE_EXTENDED option) and to divide
+it into three parts for ease of discussion:
+</P>
+<P>
+<pre>
+ ( \( )? [^()]+ (?(1) \) )
+</PRE>
+</P>
+<P>
+The first part matches an optional opening parenthesis, and if that
+character is present, sets it as the first captured substring. The second part
+matches one or more characters that are not parentheses. The third part is a
+conditional subpattern that tests whether the first set of parentheses matched
+or not. If they did, that is, if subject started with an opening parenthesis,
+the condition is true, and so the yes-pattern is executed and a closing
+parenthesis is required. Otherwise, since no-pattern is not present, the
+subpattern matches nothing. In other words, this pattern matches a sequence of
+non-parentheses, optionally enclosed in parentheses.
+</P>
+<P>
+If the condition is the string (R), it is satisfied if a recursive call to the
+pattern or subpattern has been made. At "top level", the condition is false.
+This is a PCRE extension. Recursive patterns are described in the next section.
+</P>
+<P>
+If the condition is not a sequence of digits or (R), it must be an assertion.
+This may be a positive or negative lookahead or lookbehind assertion. Consider
+this pattern, again containing non-significant white space, and with the two
+alternatives on the second line:
+</P>
+<P>
+<pre>
+ (?(?=[^a-z]*[a-z])
+ \d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} )
+</PRE>
+</P>
+<P>
+The condition is a positive lookahead assertion that matches an optional
+sequence of non-letters followed by a letter. In other words, it tests for the
+presence of at least one letter in the subject. If a letter is found, the
+subject is matched against the first alternative; otherwise it is matched
+against the second. This pattern matches strings in one of the two forms
+dd-aaa-dd or dd-dd-dd, where aaa are letters and dd are digits.
+</P>
+<br><a name="SEC17" href="#TOC1">COMMENTS</a><br>
+<P>
+The sequence (?# marks the start of a comment which continues up to the next
+closing parenthesis. Nested parentheses are not permitted. The characters
+that make up a comment play no part in the pattern matching at all.
+</P>
+<P>
+If the PCRE_EXTENDED option is set, an unescaped # character outside a
+character class introduces a comment that continues up to the next newline
+character in the pattern.
+</P>
+<br><a name="SEC18" href="#TOC1">RECURSIVE PATTERNS</a><br>
+<P>
+Consider the problem of matching a string in parentheses, allowing for
+unlimited nested parentheses. Without the use of recursion, the best that can
+be done is to use a pattern that matches up to some fixed depth of nesting. It
+is not possible to handle an arbitrary nesting depth. Perl has provided an
+experimental facility that allows regular expressions to recurse (amongst other
+things). It does this by interpolating Perl code in the expression at run time,
+and the code can refer to the expression itself. A Perl pattern to solve the
+parentheses problem can be created like this:
+</P>
+<P>
+<pre>
+ $re = qr{\( (?: (?>[^()]+) | (?p{$re}) )* \)}x;
+</PRE>
+</P>
+<P>
+The (?p{...}) item interpolates Perl code at run time, and in this case refers
+recursively to the pattern in which it appears. Obviously, PCRE cannot support
+the interpolation of Perl code. Instead, it supports some special syntax for
+recursion of the entire pattern, and also for individual subpattern recursion.
+</P>
+<P>
+The special item that consists of (? followed by a number greater than zero and
+a closing parenthesis is a recursive call of the subpattern of the given
+number, provided that it occurs inside that subpattern. (If not, it is a
+"subroutine" call, which is described in the next section.) The special item
+(?R) is a recursive call of the entire regular expression.
+</P>
+<P>
+For example, this PCRE pattern solves the nested parentheses problem (assume
+the PCRE_EXTENDED option is set so that white space is ignored):
+</P>
+<P>
+<pre>
+ \( ( (?>[^()]+) | (?R) )* \)
+</PRE>
+</P>
+<P>
+First it matches an opening parenthesis. Then it matches any number of
+substrings which can either be a sequence of non-parentheses, or a recursive
+match of the pattern itself (that is a correctly parenthesized substring).
+Finally there is a closing parenthesis.
+</P>
+<P>
+If this were part of a larger pattern, you would not want to recurse the entire
+pattern, so instead you could use this:
+</P>
+<P>
+<pre>
+ ( \( ( (?>[^()]+) | (?1) )* \) )
+</PRE>
+</P>
+<P>
+We have put the pattern into parentheses, and caused the recursion to refer to
+them instead of the whole pattern. In a larger pattern, keeping track of
+parenthesis numbers can be tricky. It may be more convenient to use named
+parentheses instead. For this, PCRE uses (?P>name), which is an extension to
+the Python syntax that PCRE uses for named parentheses (Perl does not provide
+named parentheses). We could rewrite the above example as follows:
+</P>
+<P>
+<pre>
+ (?P<pn> \( ( (?>[^()]+) | (?P>pn) )* \) )
+</PRE>
+</P>
+<P>
+This particular example pattern contains nested unlimited repeats, and so the
+use of atomic grouping for matching strings of non-parentheses is important
+when applying the pattern to strings that do not match. For example, when this
+pattern is applied to
+</P>
+<P>
+<pre>
+ (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa()
+</PRE>
+</P>
+<P>
+it yields "no match" quickly. However, if atomic grouping is not used,
+the match runs for a very long time indeed because there are so many different
+ways the + and * repeats can carve up the subject, and all have to be tested
+before failure can be reported.
+</P>
+<P>
+At the end of a match, the values set for any capturing subpatterns are those
+from the outermost level of the recursion at which the subpattern value is set.
+If you want to obtain intermediate values, a callout function can be used (see
+below and the
+<a href="pcrecallout.html"><b>pcrecallout</b></a>
+documentation). If the pattern above is matched against
+</P>
+<P>
+<pre>
+ (ab(cd)ef)
+</PRE>
+</P>
+<P>
+the value for the capturing parentheses is "ef", which is the last value taken
+on at the top level. If additional parentheses are added, giving
+</P>
+<P>
+<pre>
+ \( ( ( (?>[^()]+) | (?R) )* ) \)
+ ^ ^
+ ^ ^
+</PRE>
+</P>
+<P>
+the string they capture is "ab(cd)ef", the contents of the top level
+parentheses. If there are more than 15 capturing parentheses in a pattern, PCRE
+has to obtain extra memory to store data during a recursion, which it does by
+using <b>pcre_malloc</b>, freeing it via <b>pcre_free</b> afterwards. If no
+memory can be obtained, the match fails with the PCRE_ERROR_NOMEMORY error.
+</P>
+<P>
+Do not confuse the (?R) item with the condition (R), which tests for recursion.
+Consider this pattern, which matches text in angle brackets, allowing for
+arbitrary nesting. Only digits are allowed in nested brackets (that is, when
+recursing), whereas any characters are permitted at the outer level.
+</P>
+<P>
+<pre>
+ < (?: (?(R) \d++ | [^<>]*+) | (?R)) * >
+</PRE>
+</P>
+<P>
+In this pattern, (?(R) is the start of a conditional subpattern, with two
+different alternatives for the recursive and non-recursive cases. The (?R) item
+is the actual recursive call.
+</P>
+<a name="subpatternsassubroutines"></a><br><a name="SEC19" href="#TOC1">SUBPATTERNS AS SUBROUTINES</a><br>
+<P>
+If the syntax for a recursive subpattern reference (either by number or by
+name) is used outside the parentheses to which it refers, it operates like a
+subroutine in a programming language. An earlier example pointed out that the
+pattern
+</P>
+<P>
+<pre>
+ (sens|respons)e and \1ibility
+</PRE>
+</P>
+<P>
+matches "sense and sensibility" and "response and responsibility", but not
+"sense and responsibility". If instead the pattern
+</P>
+<P>
+<pre>
+ (sens|respons)e and (?1)ibility
+</PRE>
+</P>
+<P>
+is used, it does match "sense and responsibility" as well as the other two
+strings. Such references must, however, follow the subpattern to which they
+refer.
+</P>
+<br><a name="SEC20" href="#TOC1">CALLOUTS</a><br>
+<P>
+Perl has a feature whereby using the sequence (?{...}) causes arbitrary Perl
+code to be obeyed in the middle of matching a regular expression. This makes it
+possible, amongst other things, to extract different substrings that match the
+same pair of parentheses when there is a repetition.
+</P>
+<P>
+PCRE provides a similar feature, but of course it cannot obey arbitrary Perl
+code. The feature is called "callout". The caller of PCRE provides an external
+function by putting its entry point in the global variable <i>pcre_callout</i>.
+By default, this variable contains NULL, which disables all calling out.
+</P>
+<P>
+Within a regular expression, (?C) indicates the points at which the external
+function is to be called. If you want to identify different callout points, you
+can put a number less than 256 after the letter C. The default value is zero.
+For example, this pattern has two callout points:
+</P>
+<P>
+<pre>
+ (?C1)\dabc(?C2)def
+</PRE>
+</P>
+<P>
+During matching, when PCRE reaches a callout point (and <i>pcre_callout</i> is
+set), the external function is called. It is provided with the number of the
+callout, and, optionally, one item of data originally supplied by the caller of
+<b>pcre_exec()</b>. The callout function may cause matching to backtrack, or to
+fail altogether. A complete description of the interface to the callout
+function is given in the
+<a href="pcrecallout.html"><b>pcrecallout</b></a>
+documentation.
+</P>
+<P>
+Last updated: 03 February 2003
+<br>
+Copyright © 1997-2003 University of Cambridge.
--- /dev/null
+/*
+ * Bahamut IRCd, doc/reference.conf
+ *
+ * Originally written by Trevor Talbot (Quension) in April 2004.
+ * $Id: reference.conf,v 1.1 2005/01/12 07:44:56 mmondor Exp $
+ *
+ * The configuration format consists of blocks, each containing name-value
+ * pairs, tags, or string data. It is designed to be easily readable by
+ * both human and ircd.
+ *
+ * A block consists of a block name, an opening '{' brace, statements, a
+ * closing '}' brace, and a ';' semicolon. A statement consists of a
+ * name, possibly followed by a value, and ending with a semicolon.
+ * Strings that contain special characters or whitespace can be surrounded
+ * by '"' double quotes. All elements of the configuration are separated
+ * by whitespace, and can be packed on one line, or broken up over several
+ * lines.
+ *
+ */
+
+# Comments are supported in three forms:
+ /* C style
+ multi-line */
+ # shell style single-line
+ // C++ style single-line
+
+/*
+ * A sample block:
+ *
+ * block {
+ * name value; # A statement with a name value
+ * name 123; # A statement with a number value
+ * name "hello world"; # A statement with a string value
+ * tag; # A simple tag
+ * "will code for food"; # A simple string
+ * };
+ *
+ * The parser also understands a special include directive outside of a
+ * block context:
+ *
+ * include path/to/file.conf;
+ */
+
+
+###########################################################################
+# Global [REQUIRED]
+# The Global block defines information about the server itself.
+# This block is required for the server to start.
+#
+# Old conf format equivalents:
+# M:name::info
+# X:dpass:rpass
+
+global {
+ // required tokens
+ name not.configured; # The IRC name of the server
+ info "located on earth"; # A short info line
+
+ // optional tokens
+ dpass secret; # Password for DIE command
+ rpass secret; # Password for RESTART command
+
+ // the optional Admin block may also be specified here
+};
+
+# The DIE and RESTART commands can optionally require passwords to be
+# supplied, to help prevent accidents. If the dpass and rpass tokens are
+# not specified, no passwords are needed.
+#
+# The Admin block may be nested here. (This is currently a purely
+# organizational/astetic option. This will probably change in future
+# releases. -epi)
+#
+# The server name may only be changed by a server restart. The info line
+# can be changed on rehash, but will not propagate to other linked servers.
+#
+# There must be exactly one Global block.
+###########################################################################
+
+
+###########################################################################
+# Admin [SUGGESTED]
+# The Admin block defines up to 3 information lines for the ADMIN command.
+# It may also exist inside the Global block.
+#
+# Old conf format equivalents:
+# A:line 1:line 2:line 3
+
+admin {
+ // optional tokens
+ "An unconfigured server"; # Info line #1
+ "An unknown administrator"; # Info line #2
+ "email@somewhere.earth"; # Info line #3
+};
+
+# Not all lines are required. There may be only one Admin block.
+###########################################################################
+
+
+###########################################################################
+# Options [OPTIONAL]
+# The Options block configures various options for the server itself.
+# This block is recommended for networks other than DALnet.
+#
+# Old conf format equivalents:
+# T:wgmonhost:wgmonurl
+
+options {
+ // optional tokens
+ network_name unconfigured; # Name of the network
+ services_name services.name; # IRC name of services server
+ stats_name stats.name; # IRC name of stats server
+ staff_address staff.net; # Opermask hostname
+ nshelpurl "http://foo"; # URL for nick registration help
+ wgmonhost wgmon.host; # Wingate monitor scan host
+ wgmonurl "http://foo"; # URL for wingate monitor info
+ network_kline "kline@net"; # Contact email for network bans
+ local_kline "kline@server"; # Contact email for server bans
+ servtype client; # Set server type:
+ # CLIENT, HUB, SERVICESHUB
+ maxchannels 10; # Max chans user can join
+ ts_max_delta 300; # Maximum timestamp delta
+ ts_warn_delta 30; # Warn for TS deltas larger than this
+ local_clones 1:15; # Default maximum local IP:site clones
+ global_clones 3:30; # Default maximum global IP:site clones
+ crypt_oper_pass; # Encrypted passwords in Oper blocks
+ short_motd; # Use ircd.smotd
+ show_links; # Show real LINKS output
+ allow_split_ops; # Op in empty channels while unlinked
+};
+
+# The services and stats IRC server names are used for the shortform
+# commands, which are transformed into targeted name@server messages for
+# security. The services server name is used by SERVICES, IDENTIFY,
+# NICKSERV, CHANSERV, MEMOSERV, ROOTSERV, NS, CS, MS, and RS. The stats
+# server name is used by OPERSERV, STATSERV, HELPSERV, OS, SS, and HS.
+# >> defaults: services.dal.net, stats.dal.net
+#
+# The staff_address token is used for operator hostmasking, as described
+# in the Allow block documentation.
+# >> default: staff.dalnet
+#
+# The nshelpurl token is used to supply a URL for nick registration help.
+# It is sent to clients in the rejection numeric when they encounter a +R
+# channel and are not registered.
+# >> default: http://docs.dal.net/docs/nsemail.html
+#
+# The maxchannels token limits the number of channels a user may join at
+# one time. This limit does not apply to server operators.
+# >> default: 10
+#
+# The server type changes some behavior to be appropriate to the role.
+# CLIENT servers can only link to one other server (their uplink hub).
+# HUB servers link several servers together, but are not intended to hold
+# general users. The SERVICESHUB type enables some optimizations for
+# directly-connected services; it requires special services support and
+# should not be used in other cases.
+# >> default: CLIENT
+#
+# The server is capable of sending a set of notices to users on connect,
+# providing some information about a proxy bot that scans them. The
+# wgmonhost token is the host the bot will be connecting from (for users
+# with firewalls or other connection monitoring), and wgmonurl is a web
+# page containing additional information about the bot. If neither token
+# is specified, the notices will not be sent.
+#
+# Proper clock synchronization is required among connected servers. This
+# requirement can be relaxed by using the ts_warn_delta and ts_max_delta
+# tokens. The TS delta is the difference (in seconds) between the clocks
+# of this server and the one it is linked to. These options should only
+# be used as a last resort; the correct fix for TS delta problems is to
+# synchronize the clocks on both server computers, such as with the ntpdate
+# tool. Unsynchronized clocks may cause unpredictable network problems.
+# >> defaults: 15, 120
+#
+# The local_clones and global_clones tokens control the maximum number of
+# connections the server will allow from the same place by default. The
+# first number refers connections from the same IP (10.0.0.5). This number
+# may optionally be followed by a colon ':' and a second number, which
+# refers to connections from the same site (10.0.0.*). The local_clones
+# token sets the default limits for connections on this server only, and
+# may be overridden by the maxclones token in a Class block. The
+# global_clones token sets the default limits for connections as seen on
+# the entire network, and may be overridden by network services.
+# >> defaults: 10:60, 25:150
+#
+# The crypt_oper_pass token configures the server to use hashed passwords
+# in the Oper blocks, to avoid password discovery by someone reading the
+# conf file. If this token is specified, passwords in the Oper blocks
+# must be generated by the tools/mkpasswd utility.
+#
+# The short_motd token enables use of the ircd.smotd file, which is sent
+# to clients on connect instead of ircd.motd. The MOTD command still sends
+# the contents of ircd.motd as normal. This option is intended to reduce
+# traffic on connect, but still convince users to read the full motd when
+# appropriate.
+#
+# The show_links token causes the LINKS command to display real server
+# links (though Super servers are still hidden). If this token is not
+# specified, LINKS will display the list given to it by services.
+#
+# The allow_split_ops token causes the server to always give chanop status
+# to users who join empty channels, even when no other servers are linked.
+# Normally op status will not be given when this server is alone, to help
+# prevent channel abuse during netsplits. This token should be used if
+# your server is not part of a network. Opers are always given op status
+# in empty channels regardless of this setting.
+#
+# All of these tokens are optional, and can be specified at different times
+# in multiple Options blocks. If a token is specified twice, the second
+# value overrides the first.
+###########################################################################
+
+
+###########################################################################
+# Port [REQUIRED]
+# The Port blocks define where the server will accept connections. At
+# least one Port block is required to start.
+#
+# Old conf format equivalents:
+# M::bind::port
+# P:ipmask:bind::port
+
+port {
+ // required tokens
+ port 6667; # Port to listen on
+
+ // optional tokens
+ bind 127.0.0.1; # IP address to listen on
+ ipmask 127.0.*.*; # Mask to accept connections from
+};
+
+# If a bind address is not specified, the server listens on all available
+# interfaces.
+#
+# The ipmask token is used to limit the port to connections from the
+# specified IP mask. Only a simple mask is supported, consisting of a *
+# where one component of the address is (e.g. "192.168.*.*").
+#
+# There may be multiple Port blocks.
+###########################################################################
+
+
+###########################################################################
+# Class [RECOMMENDED]
+# The Class blocks define the connection classes used by the Allow, Oper,
+# and Connect blocks. While the server will start without a Class block,
+# it will not be usable.
+#
+# Old conf format equivalents:
+# Y:name:pingfreq::maxusers:maxsendq (for clients)
+# Y:name:pingfreq:connfreq:maxlinks:maxsendq (for servers)
+
+class {
+ // required tokens
+ name users; # Name of the class
+ pingfreq 90; # PING idle connection every N seconds
+ maxsendq 100000; # Send buffer limit
+
+ // optional, for Allow classes only:
+ maxusers 100; # Maximum number of clients
+ maxclones 2:20; # Maximum IP:site clones
+
+ // optional, for Connect classes only:
+ connfreq 300; # Try autoconnect every N seconds
+ maxlinks 1; # Autoconnect if less than N links in class
+};
+
+# Idle connections are polled with the PING command every pingfreq seconds.
+#
+# The maxsendq token controls the size of the internal send buffer, used
+# when a connection cannot accept large amounts of data at once. Certain
+# server commands emit such large amounts of data. As an example metric,
+# a 100KB user send queue can support a WHO <channel> query for a channel
+# with approximately 700 users. Large amounts of data are also generated
+# when two servers link and synchronize network state. If the send queue
+# limit is exceeded, the connection is terminated.
+#
+# For classes used in the Allow blocks, the maxusers token limits the
+# number of clients that may exist in this class. This is the most common
+# general user limit for the server. If this limit is reached, additional
+# clients will be rejected with a "server busy" message. This token must
+# not be specified for classes used in the Connect blocks.
+#
+# For classes used in the Allow blocks, the maxclones token limits the
+# number of clients that may connect from the same place in this class.
+# The first number refers to connections from the same IP (10.0.0.5); it
+# may be optionally followed by a colon ':' and a second number, which
+# refers to connections from the same site (10.0.0.*). If this limit is
+# reached, clients will be rejected with a "too many connections from your
+# host/site" message. Limits defined here override the defaults as
+# configured in the Options block. If a site limit is not supplied here,
+# clients in this class will effectively have no site limit; the default
+# limit will not be used. This token must not be specified for classes
+# used in the Connect blocks.
+#
+# For classes used in the Connect blocks, the connfreq token specifies the
+# frequency at which autoconnections are tried. This token works together
+# with maxlinks, which specifies the maximum number of servers in this
+# class to autoconnect to. For an autoconnection to take place, the
+# Connect block must have a valid port token, and there must be less than
+# maxlinks connected servers in this class. The connfreq and maxlinks
+# tokens must not be specified for classes used in the Allow or Oper
+# blocks.
+#
+# A "default" class is created internally using definitions in config.h.
+# This class is used when no other class is specified, but its settings are
+# not useful for most situations. Custom classes are strongly suggested.
+#
+# There may be multiple Class blocks; at least one is recommended.
+###########################################################################
+
+
+###########################################################################
+# Allow [RECOMMENDED]
+# The Allow blocks define the hosts connections are allowed from, and
+# places them into classes. While the server will start without an Allow
+# block, it will not be usable.
+#
+# Old conf format equivalents:
+# I:ipmask:passwd:host:port:class
+
+allow {
+ // required tokens
+ host *; # Resolved host mask (optional if using ipmask)
+ ipmask *; # Unresolved IP mask (optional if using host)
+
+ // optional tokens
+ port 6667; # Apply block to this port only
+ passwd secret; # Require password for connection
+ flags mCFT; # Special flags for this connection
+ class users; # Place connections in this class
+};
+
+# The server uses a default-deny policy for incoming connections; at least
+# one Allow block must be supplied if you wish to use your server.
+#
+# The host and ipmask tokens specify which connections this block matches.
+# The server always performs DNS and ident lookups for connections. If DNS
+# cannot find a hostname, the IP is used instead. If ident cannot get a
+# valid response, "unknown" is used during this stage. The client's
+# resolved hostname, IP address, ident reply, and username (from the USER
+# line) are used according to the results of the matches described below.
+#
+# The host token attempts to match first against the resolved hostname if
+# available, then against the IP address. To include the connection's
+# ident response in the match, use a mask in the form "ident@host". If a
+# client matches this token, it appears on IRC using its resolved hostname.
+#
+# The ipmask token attempts to match against the IP address only. To
+# include the connection's ident response in the match, use a mask in the
+# form "ident@host". If a client matches this token, it appears on IRC
+# using its IP address, even if its hostname was resolved.
+#
+# If the matching mask used ident ("ident@host" instead of "host"), and no
+# ident response was received from the client, it appears on IRC with its
+# username prefixed with '~'. If the matching mask used only the "host"
+# form, the client's username is not prefixed. If a valid ident response
+# was received, it is always used (without prefix), regardless of the mask
+# form.
+#
+# Only one of the host and ipmask tokens is needed; if both are used, host
+# is matched first. For typical configurations, using only the host token
+# with a "*@host" or "ident@host" mask is recommended.
+#
+# Examples:
+# // client with username "user", ident "ident", hostname "name"
+# host ident@*; # appears as ident@name
+# ipmask *; # appears as ident@10.0.0.1
+#
+# // same client without ident response
+# host *; # appears as user@name
+# host *@*; # appears as ~user@name
+# ipmask unknown@*; # appears as ~user@10.0.0.1
+#
+# The port token limits this block to match connections to the specified
+# port only.
+#
+# The passwd token requires that matching connections supply a password to
+# use the server. Clients can send a password string in multiple forms,
+# depending on which passwords need to be used. The basic format is:
+#
+# [passwd][:][opername:operpass][:][nickpass]
+#
+# If the Allow block requires a password, it must be supplied at the front
+# of the string. If operator hostmasking is enabled (via the flags token
+# described below), the client can mask itself by supplying a "name:passwd"
+# string as defined in an Oper block. When masked, a client appears on IRC
+# using the Oper block name for its ident, and the Options block
+# staff_address for its hostname. Any remaining passwords are sent to
+# NickServ in an SIDENTIFY command. All password components must be
+# separated from each other by a ':' colon.
+#
+# Using the examples in this file, a client could connect with the password
+# string "secret:johndoe:secret" and be masked as johndoe@staff.net.
+#
+# The flags token allows special behavior to be assigned to this
+# connection, using a set of single-letter options. The available flags
+# are:
+#
+# m Enable operator hostmasking
+# C Bypass clone limiting
+# F Force umode +F to bypass message flood checks
+# T Disable rapid (re)connection throttling
+#
+# When operator hostmasking is enabled, a matching client can connect using
+# a special password to be masked, as described for the passwd token above.
+#
+# Normally all clients are subjected to a clone limit check when they
+# connect, as configured in the Options and Class blocks. The C flag skips
+# this check for matching clients, allowing them to have an unrestricted
+# number of connections.
+#
+# The F flag forces matching clients to always have usermode +F, to avoid
+# various message flood checks. This flag is intended for special bots and
+# should not be used for server operators; opers can make use of the F
+# access flag as described in the Oper block documentation.
+#
+# By default, the server throttles rapid (re)connections from a single IP
+# address, to help reduce abuse and load. The T flag disables this
+# mechanism for matching clients. To qualify, a client must send valid
+# NICK and USER messages to register the connection, and stay connected
+# long enough to complete the ident and DNS lookups. However, a correct
+# password is not required.
+#
+# The class token specifies the connection Class to place matching
+# connections in. If not specified, the default class is used; see the
+# Class block description for details.
+#
+# There may be multiple Allow blocks; they are matched in the order they
+# appear.
+###########################################################################
+
+
+###########################################################################
+# Oper [SUGGESTED]
+# The Oper blocks define server operators. One or more of these blocks
+# is recommended if you intend to maintain your server.
+#
+# Old conf format equivalents:
+# O:host:passwd:name:access:class
+
+oper {
+ // required tokens
+ name johndoe; # Account name
+ passwd secret; # Account password (optionally encrypted)
+ host ident@hostmask; # Restrict access to this mask
+ host *@172.16.4.2; # Up to 32 masks can be specified here
+ access *Aa; # Access flags
+
+ // optional tokens
+ class opers; # Place authenticated client in this class
+};
+
+# The name and passwd tokens match the parameters of the OPER command. If
+# the crypt_oper_pass token is specified in the Options block, the passwd
+# string must be generated by the tools/mkpasswd utility. The plaintext
+# password is still used in the OPER command.
+#
+# To authenticate as an operator, a client must match one of the host
+# tokens specified in "user@host" mask form. There can be up to 32 host
+# tokens. The host part is matched against both resolved hostname and IP
+# address.
+#
+# The access token specifies what access an operator has, using a set of
+# single-letter flags. The available flags are:
+#
+# r Can use REHASH
+# h Can use GLOBOPS
+# w Can use WALLOPS
+# l Can use LOCOPS
+# b Can use KLINE
+# B Can use UNKLINE
+# c Can route this server
+# k Can kill clients on this server
+# n Can send server notices
+# u Can use umode +c (see client connection notices)
+# f Can use umode +f (see flood notices)
+# o Server operator: includes all of above, plus umodes
+# +y (spy), +d (debug), +b (CHATOPS)
+#
+# C Can route other servers
+# K Can kill clients on other servers
+# N Can send global notices
+# O Network operator: includes all of above
+#
+# D Can use DIE
+# R Can use RESTART
+# F Can use umode +F (no flood limits)
+# * all of the above
+#
+# A Can use umode +A (server administrator)
+# a Can use umode +a (services administrator)
+#
+# The class token specifies the connection class the operator will be
+# placed in. If not specified, the default class is used; see the Class
+# block description for details.
+#
+# There may be multiple Oper blocks.
+###########################################################################
+
+
+###########################################################################
+# Connect [OPTIONAL]
+# The Connect blocks define links to other servers.
+#
+# Old conf format equivalents:
+# C:host:cpasswd:name:port:class:bind
+# N:host:apasswd:name:flags:class
+# H:*::name
+
+connect {
+ // required tokens
+ name server.name; # Other server's name
+ host server.host; # Other server's host
+ apasswd secret; # Password to accept from other server
+ cpasswd secret; # Password to send to other server
+
+ // optional tokens
+ port 7000; # Port to autoconnect to other server on
+ bind 127.0.0.1; # IP to connect from
+ flags ZEH; # Flags for this link
+ class servers; # Connection class to use for this link
+};
+
+# The name token specifies the IRC name of the other server, and the host
+# token specifies its hostname or IP address. Using an IP address is
+# recommended.
+#
+# The apasswd token defines the password this server will accept from the
+# other one, and cpasswd defines the password to be sent.
+#
+# The port token is used to enable autoconnection. See the Class block
+# description for details.
+#
+# The bind token specifies the local IP to use when connecting to the
+# other server.
+#
+# The flags token defines various options for the connection:
+#
+# H other server is a hub (allowed to link other servers)
+# Z compress the link traffic
+# E encrypt the link using RC4 with DH key exchange
+#
+# The class token specifies the connection class to use for the server
+# link. If not specified, the default class is used; see the Class block
+# description for details.
+#
+# There may be multiple Connect blocks.
+###########################################################################
+
+
+###########################################################################
+# Super [OPTIONAL]
+# The Super block defines up to 24 super ("U-lined") servers, allowed to
+# to do special network things. Used for network services.
+#
+# Old conf format equivalents:
+# U:name:*:*
+
+super {
+ "server1.name"; # Super server #1
+ "server2.name"; # Super server #2
+ # ...
+};
+
+# Super servers are permitted to do things typical network services would
+# want to do, such as apply network bans, manage channel modes, etc; the
+# details are too numerous and complex to provide here. This block is a
+# simple list of up to 24 such servers, using their IRC names.
+#
+# Super servers may be changed by a rehash, but will not take effect until
+# all existing server links have been broken and reconnected.
+#
+# There may be multiple Super blocks; all blocks are combined into one
+# list. There is a global limit of 24 super servers.
+###########################################################################
+
+
+###########################################################################
+# Restrict [OPTIONAL]
+# The Restrict blocks disallow nicknames, channelnames, or clients with
+# specific GCOS (real name) fields.
+#
+# Old conf format equivalents:
+# Q::reason:mask (NICK, CHAN)
+# G::reason:mask (GCOS)
+
+restrict {
+ // required tokens
+ type chan; # Type of restriction: NICK, CHAN, GCOS
+ mask "#botworld"; # Disallowed mask
+
+ // optional tokens
+ reason "evil bots"; # Reason for restriction
+};
+
+# Setting the type token to "nick" will create a nickname restriction,
+# using the specified wildcard mask. Restricted nicknames cannot be used
+# by normal clients, but network operators may use them.
+#
+# Setting the type token to "chan" will create a channel restriction,
+# using the specified wildcard mask. Restricted channels cannot be used
+# by normal clients, but network operators may join them.
+#
+# Setting the type token to "gcos" will create a real name field ban,
+# using the specified wildcard mask. Clients with a matching real name
+# field will not be permitted to connect.
+#
+# The reason token provides a single-line reason for the restriction, and
+# is sent to clients along with the rejection notice.
+#
+# There may be multiple Restrict blocks.
+###########################################################################
+
+
+###########################################################################
+# Kill [OPTIONAL]
+# The Kill blocks disallow connections from clients based on specific
+# ident and host masks.
+#
+# Old conf format equivalents:
+# K:host:reason:username (mask was split)
+
+kill {
+ // required tokens
+ mask "*@192.168.0.0/24"; # Disallowed mask (wildcard or CIDR)
+
+ // optional tokens
+ reason "tourists only!"; # Reason for ban
+};
+
+# Kill blocks are a flexible general client ban mechanism. The mask token
+# can be specified in several formats:
+#
+# mask *.bot.world; # Wildcard hostname
+# mask user@*.isp; # Wildcard user@hostname
+# mask 192.168.0.0/16; # CIDR IP (all 4 parts needed)
+# mask user@10.4.2.2/30; # CIDR user@IP
+#
+# CIDR format is the most efficient, and should be used when possible. The
+# server will attempt to convert wildcard IP masks to CIDR form internally.
+#
+# Clients that match a Kill block will be rejected from the server.
+# Existing clients will be scanned for possible matches when new blocks are
+# loaded during rehash.
+#
+# There may be multiple Kill blocks.
+###########################################################################
+
+
+###########################################################################
+# Modules [OPTIONAL]
+# The Modules block configures dynamic module loading.
+#
+# Old conf format equivalents:
+# modules.ini
+
+modules {
+ // optional tokens
+ path mods; # Directory to look for modules in
+ autoload mod1; # Module to load at startup
+ autoload mod2; # Up to 128 modules can be specified here
+};
+
+# The path token specifies the directory to search for modules in, relative
+# to the ircd directory. There can only be one path, and the default is
+# "modules".
+#
+# The autoload token specifies the name of a module (without file
+# extension) to load automatically at startup. There can be up to 128
+# autoload tokens.
+#
+# There may be only one Modules block.
+###########################################################################
--- /dev/null
+When you type /version you will often see something like this:
+bahamut-1.8(02). server aABCdFhistTY/HoS TS5ow-r[RELEASE] RPL1 NP[U]
+
+Ever wondered what those funny chars mean after the version number? Well
+here they are:
+
+The first set before the '/' are compile-time flags:
+'a' config.h ANTI_SPAMBOT
+'A' config.h ALWAYS_SEND_DURING_SPLIT
+'B' config.h MAXBUFFERS
+'C' config.h CMDLINE_CONFIG
+'d' config.h DO_IDENTD
+'D' config.h DEBUGMODE
+'E' configure encryption support enabled
+'F' config.h FLUD
+'h' config.h SHOW_HEADERS
+'i' config.h SHOW_INVISIBLE_LUSERS
+'I' config.h NO_DEFAULT_INVISIBLE
+'J' config.h NO_DEFAULT_JOINRATE
+'M' configure module support enabled
+'N' config.h DNS_DEBUG
+'r' config.h DENY_SERVICES_MSGS
+'s' config.h SUPER_TARGETS_ONLY
+'t' config.h MSG_TARGET_LIMIT
+'T' config.h THROTTLE_ENABLE
+'u' config.h IRCII_KLUDGE
+'Y' config.h USE_SYSLOG
+
+The first set after the '/' are runtime flags:
+'H' ircd.conf servtype = hub
+'m' ircd.conf short_motd
+'o' ircd.conf allow_split_ops
+'p' ircd.conf crypt_oper_pass
+'S' ircd.conf servtype = serviceshub
+'w' ircd.conf wgmonhost/wgmonurl
+
+The next part, 'TS5ow', is mostly historical. The release tag is provided
+after it.
+
+If 'RPL#' shows up, oper hostmasking is enabled. The number is the level:
+ 1 All +A users can see real IP
+ 2 Local +A users can see real IP
+ 3 Noone can see real IP (but it's still logged)
+
+The last part, 'NP[]', contains network information hiding flags:
+'A' config.h FORCE_EVERYONE_HIDDEN
+'I' config.h ALLOW_HIDDEN_OPERS
+'K' config.h HIDE_KILL_ORIGINS
+'L' ircd.conf no show_links (hiding LINKS)
+'M' config.h HIDE_SERVERMODE_ORIGINS
+'N' config.h HIDE_NUMERIC_SOURCE
+'O' config.h NO_USER_OPERTARGETED_COMMANDS
+'P' config.h HIDE_SPLIT_SERVERS
+'S' config.h NO_USER_STATS
+'T' config.h NO_USER_TRACE
+'U' config.h HIDEULINEDSERVS
+'W' config.h NO_USER_SERVERNOTICES
--- /dev/null
+# =========================================================================
+# QUICKSTART: server configuration (see reference.conf for details)
+# =========================================================================
+
+/* server name and administration info */
+global {
+ name not.configured; # IRC name of the server
+ info "located on earth"; # A short info line
+ admin {
+ "An unconfigured server"; # Three information lines sent
+ "An unknown administrator"; # in reply to ADMIN command
+ "email@somewhere.earth";
+ };
+};
+
+/* server options */
+options {
+ network_name unconfigured; # A name is needed even if not linked
+ local_kline admin@server; # Contact email for server bans
+ show_links; # Show servers in LINKS
+ allow_split_ops; # Give ops in empty channels
+
+ // use these options when services is on the network
+ services_name services.name; # Name of services (NS/CS/MS/RS) server
+ stats_name stats.name; # Name of stats (OS/SS/HS) server
+ network_kline admin@net; # Contact email for network bans
+ nshelpurl "http://help"; # Nick registration help page
+
+ // if you need to link more than 1 server, uncomment the following line
+ # servtype hub;
+};
+
+/* where to listen for connections */
+port {
+ port 6667; # Port to listen on
+ bind 127.0.0.1; # IP address to listen on
+};
+
+/* more listening ports */
+port { port 6668; bind 127.0.0.1; };
+port { port 6669; bind 127.0.0.1; };
+port { port 7000; bind 127.0.0.1; };
+
+/* allow clients to connect */
+allow {
+ host *@*; # Allow anyone
+ class users; # Place them in the users class
+};
+
+/* connection class for users */
+class {
+ name users; # Class name
+ maxusers 100; # Maximum connections
+ pingfreq 90; # Check idle connections every N seconds
+ maxsendq 100000; # 100KB send buffer limit
+};
+
+/* connection class for server operators */
+class {
+ name opers;
+ pingfreq 90;
+ maxsendq 500000; # 500KB limit for opers
+};
+
+/* the server administrator */
+oper {
+ name admin; # Username
+ passwd secret; # Password
+ access OARD; # Server Administrator
+ host *@192.168.0.*; # Must be connecting from here
+ host *@10.64.64.*; # Or from here
+ // insert other other hostmasks here
+ class opers; # Belongs in the opers class
+};
+
+/* for services */
+super {
+ "services.name";
+ "stats.name";
+ // insert any other special servers here
+};
+
+/* reserved nicknames */
+restrict { type nick; mask "NickServ"; reason "reserved for services"; };
+restrict { type nick; mask "ChanServ"; reason "reserved for services"; };
+restrict { type nick; mask "MemoServ"; reason "reserved for services"; };
+restrict { type nick; mask "RootServ"; reason "reserved for services"; };
+restrict { type nick; mask "OperServ"; reason "reserved for services"; };
+restrict { type nick; mask "StatServ"; reason "reserved for services"; };
+restrict { type nick; mask "HelpServ"; reason "reserved for services"; };
+restrict { type nick; mask "services"; reason "reserved for services"; };
+
+
+/* === these next two blocks are for linking to a hub === */
+
+/* class for uplink hub */
+class {
+ name hub;
+ pingfreq 120; # Idle check every 2 minutes
+ connfreq 300; # Try autoconnect every 5 minutes
+ maxsendq 1000000; # 1MB send queue
+ maxlinks 1; # Autoconnect to only 1 hub at a time
+};
+
+/* our uplink hub */
+connect {
+ name hub.name; # Hub's IRC name
+ host 172.16.4.2; # Hub's IP address
+ port 7325; # Autoconnect to hub's port 7325
+ bind 127.0.0.1; # We connect from this IP
+ apasswd secret; # We accept this password from hub
+ cpasswd secret; # We send this password to hub
+ flags H; # It is a hub
+ class hub; # Use hub class
+};
+
+
+/* === these next two blocks are for linking to services === */
+
+/* class for services */
+class {
+ name services;
+ pingfreq 60; # Idle check every minute
+ maxsendq 5000000; # 5MB backlog buffer
+};
+
+/* our services */
+connect {
+ name services.name; # Services' IRC name
+ host 127.0.0.1; # IP address services connects from
+ apasswd secret; # Password services sends
+ cpasswd secret; # Same password
+ class services;
+};
--- /dev/null
+-bad
+-bap
+-nbc
+-br
+-cdb
+-nce
+-ci3
+-cli3
+-di12
+-dj
+-ei
+-fc1
+-i3
+-l72
+-lp
+-npcs
+-psl
+-sc
+-sob
+-TBlock -TBlockHeap -TClass -Tdbuf -Tdbufbuf -TaConfList -TaConfEntry
+-Tfdstruct -Thashentry -Treslist -Tcache -Tcachetable -TaConfItem
+-TaClient -TaChannel -TanUser -TaServer -TLink -TMode -Tts_val
+-TaMotd -TWhowas -Tmsg_tree -TBan -Tu_char -Tu_short -Tu_long
+-Tu_int -Taname -THEADER -Tip_entry -Tgline_pending -Tscache_entry
+-TNumeric
--- /dev/null
+/*************************************************************************
+ * File: blalloc.h
+ * Owner: jolo
+ *************************************************************************/
+
+/* $Id: blalloc.h,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#ifndef BLALLOC_H
+#define BLALLOC_H
+/* INCLUDES */
+#include <stddef.h>
+
+/* DEFINES */
+#define BlockHeapALLOC(bh, type) ((type *) BlockHeapAlloc(bh))
+
+/* TYPEDEFS */
+
+/* Block contains status information for an allocated block in our heap. */
+
+typedef struct Block
+{
+ void *elems; /* Points to allocated memory */
+ void *endElem; /* Points to last elem for boundck */
+ int freeElems; /* Number of available elems */
+ struct Block *next; /* Next in our chain of blocks */
+ unsigned long *allocMap; /* Bitmap of allocated blocks */
+} Block;
+
+/* BlockHeap contains the information for the root node of the memory heap. */
+
+typedef struct BlockHeap
+{
+ size_t elemSize; /* Size of each element to be stored */
+ int elemsPerBlock; /* Number of elements per block */
+ int numlongs; /* Size of Block's allocMap array */
+ int blocksAllocated; /* Number of blocks allocated */
+ int freeElems; /* Number of free elements */
+ Block *base; /* Pointer to first block */
+} BlockHeap;
+
+/* FUNCTION PROTOTYPES */
+
+BlockHeap *BlockHeapCreate(size_t elemsize, int elemsperblock);
+int BlockHeapDestroy(BlockHeap *bh);
+void *BlockHeapAlloc(BlockHeap *bh);
+int BlockHeapFree(BlockHeap *bh, void *ptr);
+
+#endif
--- /dev/null
+/*
+ * ++Copyright++ 1991, 1993 - Copyright (c) 1991, 1993 The Regents of
+ * the University of California. 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. All advertising materials mentioning features
+ * or use of this software must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors. 4. Neither the name of
+ * the University 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 REGENTS 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 REGENTS 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. - Portions Copyright (c) 1993 by Digital Equipment
+ * Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies, and that the name of Digital Equipment Corporation not be
+ * used in advertising or publicity pertaining to distribution of the
+ * document or software without specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -
+ * --Copyright--
+ */
+/* @(#)cdefs.h 8.1 (Berkeley) 6/2/93 $Id: cdefs.h,v 1.1.1.1 1998/07/01
+ * 14:33:57 wd Exp $
+ */
+
+/* $Id: cdefs.h,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#ifndef _CDEFS_H_
+#define _CDEFS_H_
+
+#if defined(__cplusplus)
+#define __BEGIN_DECLS extern "C" {
+#define __END_DECLS };
+#else
+#define __BEGIN_DECLS
+#define __END_DECLS
+#endif
+/*
+ * The __CONCAT macro is used to concatenate parts of symbol names,
+ * e.g. with "#define OLD(foo) __CONCAT(old,foo)", OLD(foo) produces
+ * oldfoo. The __CONCAT macro is a bit tricky -- make sure you don't
+ * put spaces in between its arguments. __CONCAT can also concatenate
+ * double-quoted strings produced by the __STRING macro, but this only
+ * works with ANSI C.
+ */
+#if defined(__STDC__) || defined(__cplusplus)
+#define __P(protos) protos /* full-blown ANSI C */
+#define __CONCAT(x,y) x ## y
+#define __STRING(x) #x
+#else /* !(__STDC__ || __cplusplus) */
+#define __P(protos) () /* traditional C preprocessor */
+#define __CONCAT(x,y) x/**/y
+#define __STRING(x) "x"
+#ifdef __GNUC__
+#define const __const /* GCC: ANSI C with -traditional */
+#define inline __inline
+#define signed __signed
+#define volatile __volatile
+#else /* !__GNUC__ */
+#define const /* delete ANSI C keywords */
+#define inline
+#define signed
+#define volatile
+#endif /* !__GNUC__ */
+#endif /* !(__STDC__ || __cplusplus) */
+/*
+ * GCC has extensions for declaring functions as `pure' (always returns
+ * the same value given the same inputs, i.e., has no external state
+ * and no side effects) and `dead' (nonreturning). These mainly affect
+ * optimization and warnings. Unfortunately, GCC complains if these
+ * are used under strict ANSI mode (`gcc -ansi -pedantic'), hence we
+ * need to define them only if compiling without this.
+ */
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+#define __dead __volatile
+#define __pure __const
+#else
+#define __dead
+#define __pure
+#endif
+#endif /* !_CDEFS_H_ */
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/channel.h
+ * Copyright (C) 1990 Jarkko Oikarinen
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: channel.h,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#ifndef __channel_include__
+#define __channel_include__
+#define find_channel(chname, chptr) (hash_find_channel(chname, chptr))
+#define CREATE 1 /* whether a channel should be created or just
+ * tested for existance */
+#define MODEBUFLEN 200 /* max modebuf we consider from users */
+#define REALMODEBUFLEN 512 /* max actual modebuf */
+#define NullChn ((aChannel *) NULL)
+#define ChannelExists(n) (find_channel(n, NullChn) != NullChn)
+#include "msg.h"
+#define MAXMODEPARAMS (MAXPARA-4) /* parv[0] .. parv[3] */
+#define MAXTSMODEPARAMS (MAXPARA-5) /* parv[0] .. parv[4] */
+#define MAXMODEPARAMSUSER 6
+#endif
--- /dev/null
+#ifndef CLONES_H
+#define CLONES_H
+/*
+ * clones.h - Clone detection and limiting
+ * Copyright (C) 2004 Trevor Talbot and
+ * the DALnet coding team
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: clones.h,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+
+
+#define CLIM_HARD_GLOBAL 1
+#define CLIM_SOFT_LOCAL 2
+#define CLIM_SOFT_GLOBAL 3
+
+typedef struct SCloneEnt CloneEnt;
+typedef struct SCloneStat CloneStat;
+
+struct SCloneEnt
+{
+ CloneEnt *prev; /* master list */
+ CloneEnt *next; /* master list */
+ aClient *clients; /* online clients, IP/32 only */
+ int lcount; /* local clones */
+ int gcount; /* global clones */
+ int limit; /* global limit (from services) */
+ int sllimit; /* soft local limit (from SET) */
+ int sglimit; /* soft global limit (from SET) */
+ char ent[HOSTIPLEN+1]; /* IP entity */
+};
+
+struct SCloneStat {
+ unsigned long rlh; /* rejected local hosts */
+ unsigned long rls; /* rejected local sites */
+ unsigned long rgh; /* rejected global hosts */
+ unsigned long rgs; /* rejected global sites */
+};
+
+extern CloneEnt *clones_list;
+extern CloneStat clones_stat;
+
+void clones_init(void);
+int clones_set(char *, int, int);
+void clones_get(char *, int *, int *, int *);
+void clones_send(aClient *);
+
+#ifdef THROTTLE_ENABLE
+
+int clones_check(aClient *);
+void clones_add(aClient *);
+void clones_remove(aClient *);
+
+#else /* THROTTLE_ENABLE */
+
+#define clones_check(x) (0)
+#define clones_add(x) ((void)0)
+#define clones_remove(x) ((void)0)
+
+#endif
+
+#endif /* CLONES_H */
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, include/common.h
+ * Copyright (C) 1990 Armin Gruner
+ *
+ * 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 1, 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.
+ *
+ */
+
+/* $Id: common.h,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#ifndef __common_include__
+#define __common_include__
+#define IRCD_MIN(a, b) ((a) < (b) ? (a) : (b))
+#if defined( HAVE_PARAM_H )
+#include <sys/param.h>
+#endif
+#ifndef NULL
+#define NULL 0
+#endif
+#ifdef TRUE
+#undef TRUE
+#endif
+#ifdef FALSE
+#undef FALSE
+#endif
+#define FALSE (0)
+#define TRUE (!FALSE)
+#define HIDEME 2
+/* Blah. I use these a lot. -Dianora */
+#ifdef YES
+#undef YES
+#endif
+#define YES 1
+#ifdef NO
+#undef NO
+#endif
+#define NO 0
+#ifdef FOREVER
+#undef FOREVER
+#endif
+#define FOREVER for(;;)
+/* -Dianora */
+#if !defined(STDC_HEADERS)
+char *malloc(), *calloc();
+void free();
+#endif
+extern void flush_fdlist_connections();
+extern int match(char *, char *);
+extern int mycmp(char *, char *);
+extern int mycmp_diff(char *, char *);
+extern int myncmp(char *, char *, int);
+#if !defined( HAVE_STRTOK )
+extern char *strtok(char *, char *);
+#endif
+#if !defined( HAVE_STRTOKEN )
+extern char *strtoken(char **, char *, char *);
+#endif
+#if !defined( HAVE_INET_ADDR )
+extern unsigned long inet_addr(char *);
+#endif
+#if !defined(HAVE_INET_NTOA) || !defined(HAVE_INET_NETOF)
+#include <netinet/in.h>
+#endif
+#if !defined( HAVE_INET_NTOA )
+extern char *inet_ntoa(struct in_addr);
+#endif
+#if !defined( HAVE_INET_NETOF )
+extern int inet_netof(struct in_addr);
+#endif
+extern char *myctime(time_t);
+extern char *strtoken(char **, char *, char *);
+#if !defined(HAVE_MINMAX)
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+#endif /* !HAVE_MINMAX */
+#define DupString(x,y) do{x=MyMalloc(strlen(y)+1);(void)strcpy(x,y);}while(0)
+extern unsigned char tolowertab[];
+#define ToLower(c) (tolowertab[(u_char)(c)])
+extern unsigned char touppertab[];
+#define ToUpper(c) (touppertab[(u_char)(c)])
+extern unsigned char char_atribs[];
+#define PRINT 1
+#define CNTRL 2
+#define ALPHA 4
+#define PUNCT 8
+#define DIGIT 16
+#define SPACE 32
+#define IsCntrl(c) (char_atribs[(u_char)(c)]&CNTRL)
+#define IsAlpha(c) (char_atribs[(u_char)(c)]&ALPHA)
+#define IsSpace(c) (char_atribs[(u_char)(c)]&SPACE)
+#define IsLower(c) ((char_atribs[(u_char)(c)]&ALPHA) && ((u_char)(c) > 0x5f))
+#define IsUpper(c) ((char_atribs[(u_char)(c)]&ALPHA) && ((u_char)(c) < 0x60))
+#define IsDigit(c) (char_atribs[(u_char)(c)]&DIGIT)
+#define IsXDigit(c) (isdigit(c) || 'a' <= (c) && (c) <= 'f' || \
+ 'A' <= (c) && (c) <= 'F')
+#define IsAlnum(c) (char_atribs[(u_char)(c)]&(DIGIT|ALPHA))
+#define IsPrint(c) (char_atribs[(u_char)(c)]&PRINT)
+#define IsAscii(c) ((u_char)(c) >= 0 && (u_char)(c) <= 0x7f)
+#define IsGraph(c) ((char_atribs[(u_char)(c)]&PRINT) && ((u_char)(c) != 0x32))
+#define IsPunct(c) (!(char_atribs[(u_char)(c)]&(CNTRL|ALPHA|DIGIT)))
+extern struct SLink *find_user_link();
+#endif /* common_include */
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, include/config.h
+ * Copyright (C) 1990 Jarkko Oikarinen
+ *
+ * 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 1, 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.
+ *
+ */
+
+/* $Id: config.h,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#ifndef __config_include__
+#define __config_include__
+
+#include "setup.h"
+#include "defs.h"
+
+
+/* READ THIS FIRST BEFORE EDITING!!!
+ *
+ * Most people will have no real reason to edit config.h, with the
+ * exception of perhaps turning off certain things such as throttling
+ * or flood protection options. Most of the stuff you will have to edit
+ * can be found in the ircd.conf - see doc/reference.conf for information
+ * on that.
+ */
+
+/*
+ * NO_DEFAULT_INVISIBLE - clients not +i by default When defined, your
+ * users will not automatically be attributed with user mode "i" (i ==
+ * invisible). Invisibility means people dont showup in WHO or NAMES
+ * unless they are on the same channel as you.
+ */
+#undef NO_DEFAULT_INVISIBLE
+
+/*
+ * USE_SYSLOG - log errors and such to syslog() If you wish to have the
+ * server send 'vital' messages about server through syslog, define
+ * USE_SYSLOG. Only system errors and events critical to the server are
+ * logged although if this is defined with FNAME_USERLOG, syslog() is
+ * used instead of the above file. It is not recommended that this
+ * option is used unless you tell the system administrator beforehand
+ * and obtain their permission to send messages to the system log
+ * files.
+ *
+ * IT IS STRONGLY RECOMMENDED THAT YOU *DO* USE SYSLOG. Many fatal ircd
+ * errors are only logged to syslog.
+ */
+#ifdef HAVE_SYSLOG_H
+#define USE_SYSLOG
+/*
+ * SYSLOG_KILL SYSLOG_SQUIT SYSLOG_CONNECT SYSLOG_USERS SYSLOG_OPER If
+ * you use syslog above, you may want to turn some (none) of the
+ * spurious log messages for KILL,SQUIT,etc off.
+ */
+#undef SYSLOG_KILL /* log all operator kills */
+#undef SYSLOG_SQUIT /* log all remote squits */
+#undef SYSLOG_CONNECT /* log remote connect messages */
+#undef SYSLOG_USERS /* send userlog stuff to syslog */
+#undef SYSLOG_OPER /* log all users who successfully oper */
+#undef SYSLOG_BLOCK_ALLOCATOR /* debug block allocator */
+
+/*
+ * LOG_FACILITY - facility to use for syslog() Define the facility you
+ * want to use for syslog(). Ask your sysadmin which one you should
+ * use.
+ */
+#define LOG_FACILITY LOG_LOCAL4
+#endif /* HAVE_SYSLOG_H */
+
+/* Defaults for things in option block of ircd.conf */
+
+/* WGMON notices are sent to users to warn them about the proxy scans. */
+#define DEFAULT_WGMON_URL "http://kline.dal.net/proxy/"
+#define DEFAULT_WGMON_HOST "some.bot.host"
+
+/* Hostmasking address */
+#define DEFAULT_STAFF_ADDRESS "staff.dalnet"
+
+/* Sent to users in 001 and 005 numerics */
+#define DEFAULT_NETWORK "DALnet"
+
+/* used for services aliases */
+#define DEFAULT_SERVICES_NAME "services.dal.net"
+#define DEFAULT_STATS_NAME "stats.dal.net"
+
+/* sent to users when they have been klined from the server */
+#define DEFAULT_NKLINE_ADDY "admin@badly.configured.server"
+#define DEFAULT_LKLINE_ADDY "admin@badly.configured.server"
+
+/* Sent to users when they encounter mode +R */
+#define DEFAULT_NS_REGISTER_URL "http://docs.dal.net/docs/nsemail.html"
+
+/* self explanitory */
+#define DEFAULT_MAXCHANNELSPERUSER 10
+
+/* Default difference in time sync between servers before we complain */
+#define DEFAULT_TSMAXDELTA 120
+#define DEFAULT_TSWARNDELTA 15
+
+/* default clone limits */
+#define DEFAULT_LOCAL_IP_CLONES 10
+#define DEFAULT_LOCAL_IP24_CLONES 60
+#define DEFAULT_GLOBAL_IP_CLONES 25
+#define DEFAULT_GLOBAL_IP24_CLONES 150
+
+/*
+ * HIDEULINEDSERVS
+ * Define this if you want to hide the location of U:lined servers (and
+ * then clients on them) from nonopers. With this defined, no non-oper
+ * should be able to find out which server the U:lined server is connected
+ * to. If you are connected to the main DALnet network, you MUST have this
+ * enabled.
+ */
+#define HIDEULINEDSERVS 1
+
+#define THROTTLE_ENABLE /* enable throttling, see below */
+
+/* File names
+ * the server will look for these files
+ */
+#define MPATH "ircd.motd"
+#define SMPATH "ircd.smotd"
+#define LPATH "ircd.log"
+#define PPATH "ircd.pid"
+#define HPATH "opers.txt"
+
+
+/* Services Definitions */
+#define CHANSERV "ChanServ"
+#define NICKSERV "NickServ"
+#define MEMOSERV "MemoServ"
+#define ROOTSERV "RootServ"
+#define OPERSERV "OperServ"
+#define STATSERV "StatServ"
+#define HELPSERV "HelpServ"
+
+/*
+ * DENY_SERVICES_MSGS
+ * Define this to cause PRIVMSG <service> to be rejected with numeric 487,
+ * explaining that "/msg <service>" is no longer supported, and to use
+ * "/msg <service>@<services_name>" or "/<service>" instead.
+ */
+#undef DENY_SERVICES_MSGS
+
+/*
+ * FNAME_USERLOG and FNAME_OPERLOG - logs of local USERS and OPERS
+ * Define this filename to maintain a list of persons who log into this
+ * server. Logging will stop when the file does not exist. Logging will
+ * be disable also if you do not define this. FNAME_USERLOG just logs
+ * user connections, FNAME_OPERLOG logs every successful use of /oper.
+ * These are either full paths or files within DPATH.
+ *
+ */
+
+#undef FNAME_USERLOG
+#undef FNAME_OPERLOG
+
+/*
+#define FNAME_USERLOG "/usr/local/ircd/users"
+#define FNAME_OPERLOG "/usr/local/ircd/opers"
+*/
+
+/* define this if you want to support non-noquit servers. handy for
+ * services that are not noquit compliant.
+ */
+#undef NOQUIT
+
+/*
+ * DEFAULT_KLINE_TIME
+ *
+ * Define this to the default time for a kline (in minutes) for klines with
+ * unspecified times. undefine this for all klines with unspecified times
+ * to be perm. (if defined, a kline with zero time will be perm). -- lucas
+ */
+#define DEFAULT_KLINE_TIME 30
+
+/*
+ * Pretty self explanatory: These are shown in server notices and to the
+ * recipient of a "you are banned" message.
+ */
+#define LOCAL_BAN_NAME "k-line"
+#define NETWORK_BAN_NAME "autokill"
+#define LOCAL_BANNED_NAME "k-lined"
+#define NETWORK_BANNED_NAME "autokilled"
+
+/*
+ * LOCKFILE - Exclusive use of ircd.conf and kline.conf during writes
+ *
+ * This creates a lockfile prior to writes to ircd.conf or kline.conf, and
+ * can be used in conjunction with viconf (included in the tools
+ * directory). This prevents loss of data when klines are added while
+ * someone is manually editting the file. File writes will be retried
+ * at the next KLINE, ZLINE, REHASH, or after CHECK_PENDING_KLINES
+ * minutes have elapsed.
+ *
+ * If you do not wish to use this feature, leave LOCKFILE #undef
+ */
+#define LOCKFILE "/tmp/ircd.conf.lock"
+#define CHECK_PENDING_KLINES 10 /* in minutes */
+
+/*
+ * RFC1035_ANAL Defining this causes ircd to reject hostnames with
+ * non-compliant chars. undef'ing it will allow hostnames with _ or /
+ * to connect
+ */
+#define RFC1035_ANAL
+
+/*
+ * IGNORE_FIRST_CHAR - define this for NO_MIXED_CASE if you wish to
+ * ignore the first character
+ */
+#define IGNORE_FIRST_CHAR
+
+/*
+ * USERNAMES_IN_TRACE - show usernames in trace Define this if you want
+ * to see usernames in /trace.
+ */
+#define USERNAMES_IN_TRACE
+
+/*
+ * DO_IDENTD - check identd if you undefine this, ircd will never check
+ * identd regardless of @'s in I:lines. You must still use @'s in your
+ * I: lines to get ircd to do ident lookup even if you define this.
+ */
+#define DO_IDENTD
+
+/* IDENTD_COMPLAIN - yell at users that don't have identd installed */
+#undef IDENTD_COMPLAIN
+
+/*
+ * MOTD_WAIT - minimum seconds between use of MOTD, INFO, HELP, LINKS *
+ * before max use count is reset * -Dianora
+ */
+#define MOTD_WAIT 10
+
+/* MOTD_MAX * max use count before delay above comes into effect */
+#define MOTD_MAX 3
+
+/* SHOW_HEADERS - Shows messages like "looking up hostname" */
+#define SHOW_HEADERS
+
+/*
+ * NO_OPER_FLOOD - disable flood control for opers define this to
+ * remove flood control for opers
+ */
+#define NO_OPER_FLOOD
+
+/* SHOW_UH - show the user@host everywhere */
+#define SHOW_UH
+#ifdef SHOW_UH
+#define USERNAMES_IN_TRACE
+#endif
+
+/*
+ * SHOW_INVISIBLE_LUSERS - show invisible clients in LUSERS As defined
+ * this will show the correct invisible count for anyone who does
+ * LUSERS on your server. On a large net this doesnt mean much, but on
+ * a small net it might be an advantage to undefine it.
+ */
+#define SHOW_INVISIBLE_LUSERS
+
+/*
+ * DEFAULT_HELP_MODE - default your opers to +h helper mode. This
+ * is strongly recommended
+ */
+#define DEFAULT_HELP_MODE
+
+/*
+ * NICER_UMODENOTICE_SEPARATION
+ * By default, all usermode notices (+d, for instance) come as
+ * :servername NOTICE nick :*** Notice -- blah blah
+ * This makes them come as *** Debug, or *** Spy, etc.
+ */
+#define NICER_UMODENOTICE_SEPARATION
+
+/*
+ * MAXIMUM LINKS - max links for class 0 if no Y: line configured
+ *
+ * This define is useful for leaf nodes and gateways. It keeps you from
+ * connecting to too many places. It works by keeping you from
+ * connecting to more than "n" nodes which you have C:blah::blah:6667
+ * lines for.
+ *
+ * Note that any number of nodes can still connect to you. This only
+ * limits the number that you actively reach out to connect to.
+ *
+ * Leaf nodes are nodes which are on the edge of the tree. If you want to
+ * have a backup link, then sometimes you end up connected to both your
+ * primary and backup, routing traffic between them. To prevent this,
+ * #define MAXIMUM_LINKS 1 and set up both primary and secondary with
+ * C:blah::blah:6667 lines. THEY SHOULD NOT TRY TO CONNECT TO YOU, YOU
+ * SHOULD CONNECT TO THEM.
+ *
+ * Gateways such as the server which connects Australia to the US can do a
+ * similar thing. Put the American nodes you want to connect to in with
+ * C:blah::blah:6667 lines, and the Australian nodes with C:blah::blah
+ * lines. Have the Americans put you in with C:blah::blah lines. Then
+ * you will only connect to one of the Americans.
+ *
+ * This value is only used if you don't have server classes defined, and a
+ * server is in class 0 (the default class if none is set).
+ *
+ */
+#define MAXIMUM_LINKS 1
+
+/*
+ * IRCII_KLUDGE - leave it defined Define this if you want the server
+ * to accomplish ircII standard Sends an extra NOTICE in the beginning
+ * of client connection
+ */
+#undef IRCII_KLUDGE
+
+/*
+ * CLIENT_FLOOD - client excess flood threshold this controls the
+ * number of bytes the server will allow a client to send to the server
+ * without processing before disconnecting the client for flooding it.
+ * Values greater than 8000 make no difference to the server.
+ */
+#define CLIENT_FLOOD 2560
+
+/*
+ * CMDLINE_CONFIG - allow conf-file to be specified on command line
+ * NOTE: defining CMDLINE_CONFIG and installing ircd SUID or SGID is a
+ * MAJOR security problem - they can use the "-f" option to read any
+ * files that the 'new' access lets them.
+ */
+#define CMDLINE_CONFIG
+
+/*
+ * FAILED_OPER_NOTICE - send a notice to all opers when someone tries
+ * to /oper and uses an incorrect password.
+ */
+#define FAILED_OPER_NOTICE
+
+/*
+ * ANTI_NICK_FLOOD - prevents nick flooding define if you want to block
+ * local clients from nickflooding
+ */
+#define ANTI_NICK_FLOOD
+
+/*
+ * defaults allow 4 nick changes in 20 seconds
+ */
+#define MAX_NICK_TIME 20
+#define MAX_NICK_CHANGES 4
+
+/* NO_AWAY_FLUD
+ * reallow propregation of AWAY messages, but do not allow AWAY flooding
+ * I reccomend a max of 5 AWAY's in 3 Minutes
+ */
+#define NO_AWAY_FLUD
+
+#ifdef NO_AWAY_FLUD
+# define MAX_AWAY_TIME 180 /* time in seconds */
+# define MAX_AWAY_COUNT 5
+#endif
+
+/*
+ * UNKLINE - /quote unkline - remove klines on the fly if you choose to
+ * support this, an oper can do a /quote UNKLINE of an exact matching
+ * KLINE to remove the kline
+ */
+#define UNKLINE
+
+/*
+ * WARN_NO_NLINE Define this if you want ops to get noticed about
+ * "things" trying to connect as servers that don't have N: lines.
+ * Twits with misconfigured servers can get really annoying with
+ * enabled.
+ */
+#define WARN_NO_NLINE
+
+/*
+ * RIDICULOUS_PARANOIA_LEVEL
+ *
+ * This indicates the level of ridiculous paranoia the admin has.
+ * The settings are as follows:
+ *
+ * 0 - No hostmasking is available.
+ * 1 - All +A users can see the real IP.
+ * 2 - Local +A can see the real IP.
+ * 3 - Noone can see the real IP. It is still logged.
+ *
+ * WARNING:
+ * Running levels above 1 on DALnet will result in your server being juped
+ * from the network if a security breech is suspected.
+ *
+ * If level 3 is selected, USE_SYSLOG must be defined.
+ */
+#define RIDICULOUS_PARANOIA_LEVEL 1
+#if (RIDICULOUS_PARANOIA_LEVEL==3)
+#ifndef USE_SYSLOG
+#error "USE_SYSLOG MUST BE DEFINED FOR LEVEL 3"
+#endif
+#endif
+
+/*
+ * Forward /quote help to HelpServ
+ *
+ * If defined, any /quote help requests from users sent to the ircd
+ * will forward the help message over to HelpServ if defined, as
+ * well as the default HelpServ topic request command. -srd
+ */
+#define HELP_FORWARD_HS
+#ifdef HELP_FORWARD_HS
+# define DEF_HELP_CMD "?"
+#endif
+
+/*
+ * For all of these options below, #define NETWORK_PARANOIA
+ * and leave the individual ones alone.
+ */
+#undef NETWORK_PARANOIA
+
+/*
+ * NO_USER_SERVERKILLS
+ * Users can't set mode +k
+ *
+ * NO_USER_OPERKILLS
+ * Users can't set mode +s
+ *
+ * NO_USER_STATS
+ * Users can't get /stats from anything
+ *
+ * NO_LOCAL_USER_STATS
+ * Local users can't get /stats from anything, each server does its own
+ * checking (not recommended)
+ * No effect if NO_USER_STATS is defined
+ *
+ * NO_USER_TRACE
+ * Users can't use TRACE
+ *
+ * NO_USER_OPERTARGETED_COMMANDS
+ * Users can't do /motd oper, /admin oper, /whois oper oper,
+ * /whois server.* oper on any oper that is set +I
+ * (see oper hiding section)
+ *
+ * HIDE_NUMERIC_SOURCE
+ * All numerics going out to local clients come from the local server
+ * Necessary for numerics from remote servers not giving information away
+ *
+ * HIDE_KILL_ORIGINS
+ * All /kills appear, from a user standpoint, to come from HIDDEN_SERVER_NAME
+ * Note that NO_USER_OPERKILLS and NO_USER_SERVERKILLS must be defined for
+ * this to actually provide any security.
+ *
+ * HIDE_SPLIT_SERVERS
+ * Hide the names of servers during netsplits
+ *
+ * HIDE_SERVERMODE_ORIGINS
+ * Hide the origins of server modes (ie, in netjoins).
+ * (They will all come from me.name)
+ */
+#define NO_USER_SERVERKILLS
+/* #undef NO_USER_OPERKILLS */
+/* #undef NO_USER_STATS */
+/* #undef NO_LOCAL_USER_STATS */
+/* #undef NO_USER_TRACE */
+/* #undef NO_USER_OPERTARGETED_COMMANDS */
+/* #undef HIDE_NUMERIC_SOURCE */
+/* #undef HIDE_KILL_ORIGINS */
+/* #undef HIDE_SPLIT_SERVERS */
+/* #undef HIDE_SERVERMODE_ORIGINS */
+
+/***********************/
+/* OPER HIDING SECTION */
+/***********************/
+
+/*
+ * ALLOW_HIDDEN_OPERS
+ *
+ * Allow your opers to be set +I (hidden) -- required for the commands below
+ * If not defined, everything below in the oper hiding section must be
+ * undefined.
+ */
+#undef ALLOW_HIDDEN_OPERS
+
+/*
+ * DEFAULT_MASKED_HIDDEN
+ *
+ * Makes all your opers that hostmasked +I (hidden) by default
+ * ALLOW_HIDDEN_OPERS must be defined with this enabled.
+ */
+#undef DEFAULT_MASKED_HIDDEN
+
+/*
+ * ALL_OPERS_HIDDEN
+ *
+ * Makes all your opers on a 'hidden' server by default (sets +I at /oper)
+ * ALLOW_HIDDEN_OPERS must be defined with this enabled.
+ * DEFAULT_MASKED_HIDDEN is reccommended with this enabled.
+ */
+#undef ALL_OPERS_HIDDEN
+
+/*
+ * FORCE_OPERS_HIDDEN
+ *
+ * Makes it so that all opers can't set -I (not hidden)
+ *
+ * Define ALL_OPERS_HIDDEN, DEFAULT_MASKED_HIDDEN, ALLOW_HIDDEN_OPERS
+ * with this as well, or things will not work properly
+ */
+#undef FORCE_OPERS_HIDDEN
+
+/*
+ * FORCE_EVERYONE_HIDDEN
+ *
+ * Makes it so that everyone on your server is set +I and can't set -I
+ *
+ * Every other hidden option in the oper hiding section must be
+ * defined as well.
+ */
+#undef FORCE_EVERYONE_HIDDEN
+
+/*
+ * Show these for hidden opers, self explanatory
+ * DO NOT CHANGE ON A SERVER TO SERVER BASIS
+ * THESE ARE NETWORK-WIDE!
+ */
+#define HIDDEN_SERVER_NAME "*.dal.net"
+#define HIDDEN_SERVER_DESC "DALnet IRC Network"
+
+/***************************/
+/* END OPER HIDING SECTION */
+/***************************/
+
+#ifdef NETWORK_PARANOIA
+# define NO_USER_SERVERKILLS
+# define NO_USER_OPERKILLS
+# define NO_USER_STATS
+# define NO_USER_TRACE
+# define NO_USER_OPERTARGETED_COMMANDS
+# define HIDE_NUMERIC_SOURCE
+# define HIDE_KILL_ORIGINS
+# define HIDE_SPLIT_SERVERS
+# define HIDE_SERVERMODE_ORIGINS
+#endif
+
+/* EXEMPT_LISTS and INVITE_LISTS
+ * Written by Sedition, Feb.04
+ */
+#define EXEMPT_LISTS
+#define INVITE_LISTS
+
+/******************************************************************
+ * STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP
+ *
+ * You shouldn't change anything below this line, unless absolutely
+ * needed.
+ */
+
+/*
+ * PING_NAZI
+ *
+ * be nazi-ish about pings (re-check every client connect,
+ * user registration, etc)
+ */
+#undef PING_NAZI
+
+/*
+ * ALWAYS_SEND_DURING_SPLIT
+ * on a large network, if your server is carrying large amounts of clients,
+ * and your server splits from the main network, the amount of allocated
+ * dbufs will skyrocket as buffers fill up with QUIT messages. This code
+ * attempts to combat this by sending out data whenever possible during a
+ * split. - lucas
+ */
+#define ALWAYS_SEND_DURING_SPLIT
+
+/* INITIAL_DBUFS - how many dbufs to preallocate */
+#define INITIAL_DBUFS 1024 /* preallocate 2 megs of dbufs */
+
+
+/* INITIAL_SBUFS_X - how many bytes of sbufs to preallocate */
+#define INITIAL_SBUFS_SMALL 2 * (1 << 20) /* 2 meg */
+#define INITIAL_SBUFS_LARGE 2 * (1 << 20) /* 2 meg */
+#define INITIAL_SBUFS_USERS 256 /* number of sbuf user structs to pool */
+
+/*
+ * MAXBUFFERS - increase socket buffers
+ *
+ * Increase send & receive socket buffer up to 64k, keeps clients at 8K
+ * and only raises servers to 64K
+ */
+#define MAXBUFFERS
+
+/*
+ * PORTNUM - default port where ircd resides Port where ircd resides.
+ * NOTE: This *MUST* be greater than 1024 if you plan to run ircd under
+ * any other uid than root.
+ */
+#define PORTNUM 7000 /* 7000 for DALnet */
+
+/*
+ * NICKNAMEHISTORYLENGTH - size of WHOWAS array this defines the length
+ * of the nickname history. each time a user changes nickname or signs
+ * off, their old nickname is added to the top of the list. NOTE: this
+ * is directly related to the amount of memory ircd will use whilst
+ * resident and running - it hardly ever gets swapped to disk! Memory
+ * will be preallocated for the entire whowas array when ircd is
+ * started.
+ */
+#define NICKNAMEHISTORYLENGTH 2048
+
+/*
+ * TIMESEC - Time interval to wait and if no messages have been
+ * received, then check for PINGFREQUENCY and CONNECTFREQUENCY
+ */
+#define TIMESEC 5 /* Recommended value: 5 */
+
+/*
+ * MAXSENDQLENGTH - Max amount of internal send buffering Max amount of
+ * internal send buffering when socket is stuck (bytes)
+ */
+#define MAXSENDQLENGTH 5050000
+
+/*
+ * PINGFREQUENCY - ping frequency for idle connections If daemon
+ * doesn't receive anything from any of its links within PINGFREQUENCY
+ * seconds, then the server will attempt to check for an active link
+ * with a PING message. If no reply is received within (PINGFREQUENCY *
+ * 2) seconds, then the connection will be closed.
+ */
+#define PINGFREQUENCY 120 /* Recommended value: 120 */
+
+/*
+ * CONNECTFREQUENCY - time to wait before auto-reconencting If the
+ * connection to to uphost is down, then attempt to reconnect every
+ * CONNECTFREQUENCY seconds.
+ */
+#define CONNECTFREQUENCY 600 /* Recommended value: 600 */
+
+/*
+ * HANGONGOODLINK and HANGONGOODLINK Often net breaks for a short time
+ * and it's useful to try to establishing the same connection again
+ * faster than CONNECTFREQUENCY would allow. But, to keep trying on bad
+ * connection, we require that connection has been open for certain
+ * minimum time (HANGONGOODLINK) and we give the net few seconds to
+ * steady (HANGONRETRYDELAY). This latter has to be long enough that
+ * the other end of the connection has time to notice it broke too.
+ * 1997/09/18 recommended values by ThemBones for modern Efnet
+ */
+
+#define HANGONRETRYDELAY 60 /* Recommended value: 30-60 seconds */
+#define HANGONGOODLINK 3600 /* Recommended value: 30-60 minutes */
+
+/*
+ * WRITEWAITDELAY - Number of seconds to wait for write to complete if
+ * stuck.
+ */
+#define WRITEWAITDELAY 10 /* Recommended value: 15 */
+
+/*
+ * CONNECTTIMEOUT - Number of seconds to wait for a connect(2) call to
+ * complete. NOTE: this must be at *LEAST* 10. When a client connects,
+ * it has CONNECTTIMEOUT - 10 seconds for its host to respond to an
+ * ident lookup query and for a DNS answer to be retrieved.
+ */
+#define CONNECTTIMEOUT 30 /* Recommended value: 30 */
+
+/*
+ * KILLCHASETIMELIMIT - Max time from the nickname change that still
+ * causes KILL automaticly to switch for the current nick of that user.
+ * (seconds)
+ */
+#define KILLCHASETIMELIMIT 90 /* Recommended value: 90 */
+
+/*
+ * FLUD - CTCP Flood Detection and Protection
+ *
+ * This enables server CTCP flood detection and protection for local
+ * clients. It works well against fludnets and flood clones. The
+ * effect of this code on server CPU and memory usage is minimal,
+ * however you may not wish to take the risk, or be fundamentally
+ * opposed to checking the contents of PRIVMSG's (though no privacy is
+ * breached). This code is not useful for routing only servers (ie,
+ * HUB's with little or no local client base), and the hybrid team
+ * strongly recommends that you do not use FLUD with HUB. The following
+ * default thresholds may be tweaked, but these seem to work well.
+ */
+#define FLUD
+
+/*
+ * ANTI_SPAMBOT if ANTI_SPAMBOT is defined try to discourage spambots
+ * The defaults =should= be fine for the timers/counters etc. but you
+ * can play with them. -Dianora
+ *
+ * Defining this also does a quick check whether the client sends us a
+ * "user foo x x :foo" where x is just a single char. More often than
+ * not, it's a bot if it did. -ThemBones
+ */
+#define ANTI_SPAMBOT
+
+/*
+ * ANTI_SPAMBOT parameters, don't touch these if you don't understand
+ * what is going on.
+ *
+ * if a client joins MAX_JOIN_LEAVE_COUNT channels in a row, but spends
+ * less than MIN_JOIN_LEAVE_TIME seconds on each one, flag it as a
+ * possible spambot. disable JOIN for it and PRIVMSG but give no
+ * indication to the client that this is happening. every time it tries
+ * to JOIN OPER_SPAM_COUNTDOWN times, flag all opers on local server.
+ * If a client doesn't LEAVE a channel for at least 2 minutes the
+ * join/leave counter is decremented each time a LEAVE is done
+ *
+ */
+#define MIN_JOIN_LEAVE_TIME 60
+#define MAX_JOIN_LEAVE_COUNT 25
+#define OPER_SPAM_COUNTDOWN 5
+#define JOIN_LEAVE_COUNT_EXPIRE_TIME 120
+
+/*
+ * If ANTI_SPAMBOT_WARN_ONLY is #define'd Warn opers about possible
+ * spambots only, do not disable JOIN and PRIVMSG if possible spambot
+ * is noticed Depends on your policies.
+ */
+#undef ANTI_SPAMBOT_WARN_ONLY
+
+#ifdef FLUD
+# define FLUD_NUM 4 /* Number of flud messages to trip alarm */
+# define FLUD_TIME 3 /* Seconds in which FLUD_NUM msgs must occur */
+# define FLUD_BLOCK 15 /* Seconds to block fluds */
+#endif
+
+/*
+ * If the OS has SOMAXCONN use that value, otherwise Use the value in
+ * HYBRID_SOMAXCONN for the listen(); backlog try 5 or 25. 5 for AIX
+ * and SUNOS, 25 should work better for other OS's
+ */
+#define HYBRID_SOMAXCONN 25
+
+/*
+ * Throttling support:
+ * THROTTLE_ENABLE - enable throttling code, if undefined, the functions
+ * will be empty. runtime settable.
+ * THROTTLE_TRIGCOUNT - number of connections to triggle throttle action
+ * THROTTLE_TRIGTIME - number of seconds in which THROTTLE_TRIGCOUNT must
+ * happen
+ * THROTTLE_RECORDTIME- length to keep records for each ip (since last connect
+ from this ip)
+ * THROTTLE_HASHSIZE - size of the throttle hashtable, also tuneable
+ *
+ * Recommended values: 3, 15, 1800. 3+ connections in 15 or less seconds will
+ * result in a connection throttle z:line. These are also
+ * z: line time grows, pseudo-exponentially
+ * first zline : 2 minutes
+ * second zline: 5 minutes
+ * third zline : 15 minutes
+ * fourth zline: 30 minutes
+ * anything more is an hour
+ * tuneable at runtime. -wd */
+/* part of options.h now #define THROTTLE_ENABLE */
+#define THROTTLE_TRIGCOUNT 3
+#define THROTTLE_TRIGTIME 15
+#define THROTTLE_RECORDTIME 1800
+#define THROTTLE_HASHSIZE 25147
+
+/*
+ * Message-throttling support.
+ * MSG_TARGET_LIMIT: if defined, imposes limits on message targets
+ * MSG_TARGET_MIN: initial number of message targets allowed (recommend 5 or less)
+ * MSG_TARGET_MAX: maximum number of message targets stored (recommend 5 or
+ * less)
+ * MSG_TARGET_MINTOMAXTIME: number of seconds a user must be online
+ * before given MSG_TARGET_MAX targets
+ * MSG_TARGET_TIME: time before message targets expire (this is what you should
+ * tweak)
+ */
+
+#define MSG_TARGET_LIMIT
+#define MSG_TARGET_MIN 5
+#define MSG_TARGET_MAX 8 /* MUST BE >= MSG_TARGET_MIN!!! */
+#define MSG_TARGET_MINTOMAXTIME 300
+#define MSG_TARGET_TIME 45
+
+/*
+ * Channel joining rate-throttling support
+ *
+ * DEFAULT_JOIN_NUM: number of joins to allow, network-wide, in a period of
+ * DEFAULT_JOIN_TIME seconds.
+ * DEFAULT_JOIN_TIME: time to collect joins.
+ * JOINRATE_SERVER_ONLY: Only let servers/U: lined things set +j.
+ * KEEP THIS IF USING A NETWORK WITH PRE-1.4.36 SERVERS!
+ */
+/* defaults are very forgiving. */
+#define DEFAULT_JOIN_NUM 8
+#define DEFAULT_JOIN_TIME 4
+#undef JOINRATE_SERVER_ONLY
+
+/* Debugging configs */
+
+#undef DNS_DEBUG
+
+/*
+ * DEBUGMODE is used mostly for internal development, it is likely to
+ * make your client server very sluggish. You usually shouldn't need
+ * this. -Dianora
+ *
+ * Currently, DEBUGMODE is pretty much useless.
+ * Don't use it. - lucas
+ */
+#undef DEBUGMODE /* define DEBUGMODE to enable */
+#undef DUMP_DEBUG
+
+/* DONT_CHECK_QLINE_REMOTE
+ * Don't check for Q:lines on remote clients. We can't do anything
+ * if a remote client is using a nick q:lined locally, so
+ * why check? If you don't care about the wasted CPU, and you're
+ * curious, feel free to #define this. I recommend you don't
+ * on a client server unless it's got a lot of power.
+ * -wd */
+#define DONT_CHECK_QLINE_REMOTE
+
+/* ------------------------- END CONFIGURATION SECTION -------------------- */
+#ifdef APOLLO
+#define RESTARTING_SYSTEMCALLS
+#endif /*
+ * read/write are restarted after signals
+ * defining this 1, gets siginterrupt call
+ * compiled, which attempts to remove this
+ * behaviour (apollo sr10.1/bsd4.3 needs this)
+ */
+
+#define HELPFILE HPATH
+#define MOTD MPATH
+#define SHORTMOTD SMPATH
+#define IRCD_PIDFILE PPATH
+
+/* enforce a minimum, even though it'll probably break at runtime */
+#if (MAXCONNECTIONS < 20)
+# undef MAXCONNECTIONS
+# define MAXCONNECTIONS 20
+#endif
+
+#if (MAXCONNECTIONS > 1000)
+# define MAX_BUFFER (MAXCONNECTIONS / 100)
+#else
+# define MAX_BUFFER 10
+#endif
+
+#define MAX_ACTIVECONN (MAXCONNECTIONS - MAX_BUFFER)
+
+#if defined(CLIENT_FLOOD) && ((CLIENT_FLOOD > 8000) || (CLIENT_FLOOD < 512))
+#error CLIENT_FLOOD needs redefining.
+#endif
+
+#if !defined(CLIENT_FLOOD)
+#error CLIENT_FLOOD undefined.
+#endif
+
+#if defined(DEBUGMODE) || defined(DNS_DEBUG)
+extern void debug(int level, char *pattern, ...);
+#define Debug(x) debug x
+#define LOGFILE LPATH
+#else
+#define Debug(x) ;
+#define LOGFILE "/dev/null"
+#endif
+
+#define CONFIG_H_LEVEL_183
+#endif /* __config_include__ */
--- /dev/null
+/* Bahamut IRCd - include/confparse.h
+ * Copyright (c) 2004, Aaron Wiebe
+ *
+ * Apply the GPL here.
+ */
+
+/* $Id: confparse.h,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+/* our structures */
+
+typedef struct TopConf tConf;
+typedef struct SubConf sConf;
+typedef struct ConfVar cVar;
+
+/* our top level conf options */
+struct TopConf
+{
+ char *tok; /* our token string */
+ unsigned int flag; /* our token flag */
+ unsigned int nest; /* tokens we allow to nest here */
+ sConf *subtok; /* sub-tokens allowed in here */
+ int (*func) (); /* function to call to add this */
+};
+
+/* sub-token options */
+struct SubConf
+{
+ char *tok; /* our token string */
+ unsigned long flag; /* our token flag */
+ unsigned int var; /* our variable type */
+};
+
+struct ConfVar
+{
+ sConf *type;
+ char *value;
+ int loaded; /* 1 - identified.
+ * 2 - variable loaded
+ * 3 - delimited cleared */
+};
+
+/* tokens allowing subtokens */
+
+#define CONFT_GLOBAL "GLOBAL"
+#define CONFF_GLOBAL 0x000001
+#define CONFT_OPTIONS "OPTIONS"
+#define CONFF_OPTIONS 0x000002
+#define CONFT_CLASS "CLASS"
+#define CONFF_CLASS 0x000004
+#define CONFT_ALLOW "ALLOW"
+#define CONFF_ALLOW 0x000008
+#define CONFT_OPER "OPER"
+#define CONFF_OPER 0x000010
+#define CONFT_CONNECT "CONNECT"
+#define CONFF_CONNECT 0x000020
+#define CONFT_RESTRICT "RESTRICT"
+#define CONFF_RESTRICT 0x000040
+#define CONFT_SUPER "SUPER"
+#define CONFF_SUPER 0x000080
+#define CONFT_KILL "KILL"
+#define CONFF_KILL 0x000100
+#define CONFT_ADMIN "ADMIN"
+#define CONFF_ADMIN 0x000200
+#define CONFT_PORT "PORT"
+#define CONFF_PORT 0x000400
+#define CONFT_MODULES "MODULES"
+#define CONFF_MODULES 0x000800
+
+/* subtokens */
+
+#define SCONFT_NAME "NAME"
+#define SCONFF_NAME 0x000001
+#define SCONFT_INFO "INFO"
+#define SCONFF_INFO 0x000002
+#define SCONFT_DPASS "DPASS"
+#define SCONFF_DPASS 0x000004
+#define SCONFT_RPASS "RPASS"
+#define SCONFF_RPASS 0x000008
+#define SCONFT_PINGFREQ "PINGFREQ"
+#define SCONFF_PINGFREQ 0x000010
+#define SCONFT_CONNFREQ "CONNFREQ"
+#define SCONFF_CONNFREQ 0x000020
+#define SCONFT_MAXUSERS "MAXUSERS"
+#define SCONFF_MAXUSERS 0x000040
+#define SCONFT_MAXSENDQ "MAXSENDQ"
+#define SCONFF_MAXSENDQ 0x000080
+#define SCONFT_CLASS "CLASS"
+#define SCONFF_CLASS 0x000100
+#define SCONFT_HOST "HOST"
+#define SCONFF_HOST 0x000200
+#define SCONFT_PORT "PORT"
+#define SCONFF_PORT 0x000800
+#define SCONFT_PASSWD "PASSWD"
+#define SCONFF_PASSWD 0x001000
+#define SCONFT_ACCESS "ACCESS"
+#define SCONFF_ACCESS 0x002000
+#define SCONFT_BIND "BIND"
+#define SCONFF_BIND 0x004000
+#define SCONFT_APASSWD "APASSWD"
+#define SCONFF_APASSWD 0x008000
+#define SCONFT_CPASSWD "CPASSWD"
+#define SCONFF_CPASSWD 0x010000
+#define SCONFT_FLAGS "FLAGS"
+#define SCONFF_FLAGS 0x020000
+#define SCONFT_REASON "REASON"
+#define SCONFF_REASON 0x040000
+#define SCONFT_TYPE "TYPE"
+#define SCONFF_TYPE 0x080000
+#define SCONFT_MASK "MASK"
+#define SCONFF_MASK 0x100000
+#define SCONFT_IPMASK "IPMASK"
+#define SCONFF_IPMASK 0x200000
+
+#define SCONFF_STRING 0x800000 /* allow freeform strings */
+
+/* subtoken aliases */
+
+#define SCONFT_MAXCLONE "MAXCLONES"
+#define SCONFT_MAXLINKS "MAXLINKS"
+
+/* these are the strings for options ONLY */
+
+#define OPTT_NETNAME "NETWORK_NAME"
+#define OPTF_NETNAME 0x000002
+#define OPTT_STAFFADDY "STAFF_ADDRESS"
+#define OPTF_STAFFADDY 0x000004
+#define OPTT_SERVNAME "SERVICES_NAME"
+#define OPTF_SERVNAME 0x000010
+#define OPTT_MAXCHAN "MAXCHANNELS"
+#define OPTF_MAXCHAN 0x000020
+#define OPTT_WGMONHOST "WGMONHOST"
+#define OPTF_WGMONHOST 0x000040
+#define OPTT_WGMONURL "WGMONURL"
+#define OPTF_WGMONURL 0x000080
+#define OPTT_NKLINEADDY "NETWORK_KLINE"
+#define OPTF_NKLINEADDY 0x000100
+#define OPTT_LKLINEADDY "LOCAL_KLINE"
+#define OPTF_LKLINEADDY 0x000200
+#define OPTT_CRYPTPASS "CRYPT_OPER_PASS"
+#define OPTF_CRYPTPASS 0x000400
+#define OPTT_SMOTD "SHORT_MOTD"
+#define OPTF_SMOTD 0x000800
+#define OPTT_SERVTYPE "SERVTYPE"
+#define OPTF_SERVTYPE 0x001000
+#define OPTT_STATSNAME "STATS_NAME"
+#define OPTF_STATSNAME 0x002000
+#define OPTT_TSMAXDELTA "TS_MAX_DELTA"
+#define OPTF_TSMAXDELTA 0x004000
+#define OPTT_TSWARNDELTA "TS_WARN_DELTA"
+#define OPTF_TSWARNDELTA 0x008000
+#define OPTT_NSREGURL "NSHELPURL"
+#define OPTF_NSREGURL 0x010000
+#define OPTT_SHOWLINKS "SHOW_LINKS"
+#define OPTF_SHOWLINKS 0x020000
+#define OPTT_SPLITOPOK "ALLOW_SPLIT_OPS"
+#define OPTF_SPLITOPOK 0x040000
+#define OPTT_LCLONES "LOCAL_CLONES"
+#define OPTF_LCLONES 0x080000
+#define OPTT_GCLONES "GLOBAL_CLONES"
+#define OPTF_GCLONES 0x100000
+
+/* module block definitions */
+
+#define MBTT_PATH "PATH"
+#define MBTF_PATH 0x0001
+#define MBTT_AUTOLOAD "AUTOLOAD"
+#define MBTF_AUTOLOAD 0x0002
+#define MBTT_OPTLOAD "OPTLOAD"
+#define MBTF_OPTLOAD 0x0004
+
+/* our variable types */
+
+#define VARTYPE_INT 0x0001 /* integers */
+#define VARTYPE_STRING 0x0002 /* freeform strings */
+#define VARTYPE_NAME 0x0004 /* non-free name */
+#define VARTYPE_NONE 0x0008 /* doesnt take any var */
+
+/* functions for parsing variables into appropriate variables */
+
+#ifdef CONF_TABS
+
+sConf confglobtab[] =
+{
+ {SCONFT_NAME, SCONFF_NAME, VARTYPE_NAME},
+ {SCONFT_INFO, SCONFF_INFO, VARTYPE_STRING},
+ {SCONFT_DPASS, SCONFF_DPASS, VARTYPE_NAME},
+ {SCONFT_RPASS, SCONFF_RPASS, VARTYPE_NAME},
+ {(char *) 0, 0, 0}
+};
+
+sConf confopttab[] =
+{
+ {OPTT_NETNAME, OPTF_NETNAME, VARTYPE_NAME},
+ {OPTT_SERVNAME, OPTF_SERVNAME, VARTYPE_NAME},
+ {OPTT_STATSNAME, OPTF_STATSNAME, VARTYPE_NAME},
+ {OPTT_MAXCHAN, OPTF_MAXCHAN, VARTYPE_INT},
+ {OPTT_WGMONHOST, OPTF_WGMONHOST, VARTYPE_NAME},
+ {OPTT_WGMONURL, OPTF_WGMONURL, VARTYPE_NAME},
+ {OPTT_NKLINEADDY, OPTF_NKLINEADDY, VARTYPE_NAME},
+ {OPTT_LKLINEADDY, OPTF_LKLINEADDY, VARTYPE_NAME},
+ {OPTT_CRYPTPASS, OPTF_CRYPTPASS, VARTYPE_NONE},
+ {OPTT_SMOTD, OPTF_SMOTD, VARTYPE_NONE},
+ {OPTT_SERVTYPE, OPTF_SERVTYPE, VARTYPE_NAME},
+ {OPTT_TSMAXDELTA, OPTF_TSMAXDELTA, VARTYPE_INT},
+ {OPTT_TSWARNDELTA, OPTF_TSWARNDELTA, VARTYPE_INT},
+ {OPTT_STAFFADDY, OPTF_STAFFADDY, VARTYPE_NAME},
+ {OPTT_NSREGURL, OPTF_NSREGURL, VARTYPE_NAME},
+ {OPTT_SHOWLINKS, OPTF_SHOWLINKS, VARTYPE_NONE},
+ {OPTT_SPLITOPOK, OPTF_SPLITOPOK, VARTYPE_NONE},
+ {OPTT_LCLONES, OPTF_LCLONES, VARTYPE_NAME},
+ {OPTT_GCLONES, OPTF_GCLONES, VARTYPE_NAME},
+ {(char *) 0, 0, 0}
+};
+
+sConf confmoduletab[] =
+{
+ {MBTT_PATH, MBTF_PATH, VARTYPE_NAME},
+ {MBTT_AUTOLOAD, MBTF_AUTOLOAD, VARTYPE_NAME},
+ {MBTT_OPTLOAD, MBTF_OPTLOAD, VARTYPE_NAME},
+ {(char *) 0, 0, 0}
+};
+
+sConf confclasstab[] =
+{
+ {SCONFT_NAME, SCONFF_NAME, VARTYPE_NAME},
+ {SCONFT_PINGFREQ, SCONFF_PINGFREQ, VARTYPE_INT},
+ {SCONFT_CONNFREQ, SCONFF_CONNFREQ, VARTYPE_INT},
+ {SCONFT_MAXCLONE, SCONFF_CONNFREQ, VARTYPE_NAME},
+ {SCONFT_MAXUSERS, SCONFF_MAXUSERS, VARTYPE_INT},
+ {SCONFT_MAXLINKS, SCONFF_MAXUSERS, VARTYPE_INT},
+ {SCONFT_MAXSENDQ, SCONFF_MAXSENDQ, VARTYPE_INT},
+ {(char *) 0, 0, 0}
+};
+
+sConf confallowtab[] =
+{
+ {SCONFT_HOST, SCONFF_HOST, VARTYPE_NAME},
+ {SCONFT_IPMASK, SCONFF_IPMASK, VARTYPE_NAME},
+ {SCONFT_PORT, SCONFF_PORT, VARTYPE_INT},
+ {SCONFT_PASSWD, SCONFF_PASSWD, VARTYPE_NAME},
+ {SCONFT_CLASS, SCONFF_CLASS, VARTYPE_NAME},
+ {SCONFT_FLAGS, SCONFF_FLAGS, VARTYPE_NAME},
+ {(char *) 0, 0, 0}
+};
+
+sConf confopertab[] =
+{
+ {SCONFT_NAME, SCONFF_NAME, VARTYPE_NAME},
+ {SCONFT_HOST, SCONFF_HOST, VARTYPE_NAME},
+ {SCONFT_PASSWD, SCONFF_PASSWD, VARTYPE_NAME},
+ {SCONFT_ACCESS, SCONFF_ACCESS, VARTYPE_NAME},
+ {SCONFT_CLASS, SCONFF_CLASS, VARTYPE_NAME},
+ {(char *) 0, 0, 0}
+};
+
+sConf confconnecttab[] =
+{
+ {SCONFT_NAME, SCONFF_NAME, VARTYPE_NAME},
+ {SCONFT_HOST, SCONFF_HOST, VARTYPE_NAME},
+ {SCONFT_BIND, SCONFF_BIND, VARTYPE_NAME},
+ {SCONFT_APASSWD, SCONFF_APASSWD, VARTYPE_NAME},
+ {SCONFT_CPASSWD, SCONFF_CPASSWD, VARTYPE_NAME},
+ {SCONFT_FLAGS, SCONFF_FLAGS, VARTYPE_NAME},
+ {SCONFT_PORT, SCONFF_PORT, VARTYPE_INT},
+ {SCONFT_CLASS, SCONFF_CLASS, VARTYPE_NAME},
+ {(char *) 0, 0, 0}
+};
+
+sConf confrestricttab[] =
+{
+ {SCONFT_REASON, SCONFF_REASON, VARTYPE_STRING},
+ {SCONFT_TYPE, SCONFF_TYPE, VARTYPE_NAME},
+ {SCONFT_MASK, SCONFF_MASK, VARTYPE_NAME},
+ {(char *) 0, 0, 0}
+};
+
+sConf confkilltab[] =
+{
+ {SCONFT_REASON, SCONFF_REASON, VARTYPE_STRING},
+ {SCONFT_MASK, SCONFF_MASK, VARTYPE_NAME},
+ {(char *) 0, 0, 0}
+};
+
+sConf confporttab[] =
+{
+ {SCONFT_PORT, SCONFF_PORT, VARTYPE_INT},
+ {SCONFT_BIND, SCONFF_BIND, VARTYPE_NAME},
+ {SCONFT_IPMASK, SCONFF_IPMASK, VARTYPE_NAME},
+ {(char *) 0, 0, 0}
+};
+
+
+sConf confopentab[] =
+{
+ {0,SCONFF_STRING,0},
+ {(char *) 0, 0, 0}
+};
+
+extern int confadd_global(cVar **, int);
+extern int confadd_options(cVar **, int);
+extern int confadd_class(cVar **, int);
+extern int confadd_allow(cVar **, int);
+extern int confadd_oper(cVar **, int);
+extern int confadd_connect(cVar **, int);
+extern int confadd_restrict(cVar **, int);
+extern int confadd_super(cVar **, int);
+extern int confadd_kill(cVar **, int);
+extern int confadd_admin(cVar **, int);
+extern int confadd_port(cVar **, int);
+extern int confadd_modules(cVar **, int);
+
+struct TopConf tconftab[] =
+{
+ {CONFT_GLOBAL, CONFF_GLOBAL, CONFF_ADMIN, confglobtab, confadd_global},
+ {CONFT_OPTIONS, CONFF_OPTIONS, 0, confopttab, confadd_options},
+ {CONFT_CLASS, CONFF_CLASS, 0, confclasstab, confadd_class},
+ {CONFT_ALLOW, CONFF_ALLOW, 0, confallowtab, confadd_allow},
+ {CONFT_OPER, CONFF_OPER, 0, confopertab, confadd_oper},
+ {CONFT_CONNECT, CONFF_CONNECT, 0, confconnecttab, confadd_connect},
+ {CONFT_RESTRICT, CONFF_RESTRICT, 0, confrestricttab, confadd_restrict},
+ {CONFT_KILL, CONFF_KILL, 0, confkilltab, confadd_kill},
+ {CONFT_ADMIN, CONFF_ADMIN, 0, confopentab, confadd_admin},
+ {CONFT_SUPER, CONFF_SUPER, 0, confopentab, confadd_super},
+ {CONFT_PORT, CONFF_PORT, 0, confporttab, confadd_port},
+ {CONFT_MODULES, CONFF_MODULES, 0, confmoduletab, confadd_modules},
+ {(char *) 0, 0, 0, 0}
+};
+
+
+#endif
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, include/dbuf.h
+ * Copyright (C) 1990 Markku Savela
+ *
+ * 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 1, 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.
+ */
+/* $Id: dbuf.h,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+#ifndef INCLUDED_dbuf_h
+#define INCLUDED_dbuf_h
+#ifndef INCLUDED_config_h
+#include "config.h"
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+
+#define IsEol(c) (c==10||c==13)
+/*
+** dbuf is a collection of functions which can be used to
+** maintain a dynamic buffering of a byte stream.
+** Functions allocate and release memory dynamically as
+** required [Actually, there is nothing that prevents
+** this package maintaining the buffer on disk, either]
+*/
+struct DBufBuffer;
+
+/*
+** These structure definitions are only here to be used
+** as a whole, *DO NOT EVER REFER TO THESE FIELDS INSIDE
+** THE STRUCTURES*! It must be possible to change the internal
+** implementation of this package without changing the
+** interface.
+*/
+struct DBuf
+{
+ struct DBufBuffer* head; /* First data buffer, if length > 0 */
+ struct DBufBuffer* tail; /* last data buffer, if length > 0 */
+ size_t length; /* Current number of bytes stored */
+};
+
+extern int DBufCount;
+extern int DBufUsedCount;
+
+/*
+** dbuf_put
+** Append the number of bytes to the buffer, allocating more
+** memory as needed. Bytes are copied into internal buffers
+** from users buffer.
+**
+** returns > 0, if operation successfull
+** < 0, if failed (due memory allocation problem)
+*/
+extern int dbuf_put(struct DBuf* dyn, const char* buf, size_t len);
+
+/*
+** dbuf_get
+** Remove number of bytes from the buffer, releasing dynamic
+** memory, if applicaple. Bytes are copied from internal buffers
+** to users buffer.
+**
+** returns the number of bytes actually copied to users buffer,
+** if >= 0, any value less than the size of the users
+** buffer indicates the dbuf became empty by this operation.
+**
+** Return 0 indicates that buffer was already empty.
+**
+** Negative return values indicate some unspecified
+** error condition, rather fatal...
+*/
+extern size_t dbuf_get(struct DBuf* dbuf, char* buf, size_t len);
+
+/*
+** dbuf_map, dbuf_delete
+** These functions are meant to be used in pairs and offer
+** a more efficient way of emptying the buffer than the
+** normal 'dbuf_get' would allow--less copying needed.
+**
+** map returns a pointer to a largest contiguous section
+** of bytes in front of the buffer, the length of the
+** section is placed into the indicated "long int"
+** variable. Returns NULL *and* zero length, if the
+** buffer is empty.
+**
+** delete removes the specified number of bytes from the
+** front of the buffer releasing any memory used for them.
+**
+** Example use (ignoring empty condition here ;)
+**
+** buf = dbuf_map(&dyn, &count);
+** <process N bytes (N <= count) of data pointed by 'buf'>
+** dbuf_delete(&dyn, N);
+**
+** Note: delete can be used alone, there is no real binding
+** between map and delete functions...
+*/
+/*
+ * dyn - Dynamic buffer header
+ * len - Return number of bytes accessible
+ */
+extern char* dbuf_map(struct DBuf* dyn, size_t* len);
+extern void dbuf_delete(struct DBuf* dyn, size_t len);
+
+/*
+** DBufLength
+** Return the current number of bytes stored into the buffer.
+** (One should use this instead of referencing the internal
+** length field explicitly...)
+*/
+#define DBufLength(dyn) ((dyn)->length)
+
+/*
+** DBufClear
+** Scratch the current content of the buffer. Release all
+** allocated buffers and make it empty.
+*/
+#define DBufClear(dyn) dbuf_delete((dyn), DBufLength(dyn))
+
+extern int dbuf_getmsg(struct DBuf* dyn, char* buf, size_t len);
+extern void dbuf_init(void);
+extern void count_dbuf_memory(size_t* allocated, size_t* used);
+
+#endif /* INCLUDED_dbuf_h */
--- /dev/null
+#if !defined( DEFS_H_INCLUDED )
+# define DEFS_H_INCLUDED 1
+
+/*
+ * None of the following should need to be changed by hand.
+ */
+
+/* $Id: defs.h,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+# if !defined( HAVE_BCOPY )
+# define bcopy(a,b,c) memcpy(b,a,c)
+# endif
+# if !defined( HAVE_BCMP )
+# define bcmp memcmp
+# endif
+# if !defined( HAVE_BZERO )
+# define bzero(a,b) memset(a,0,b)
+# endif
+
+# if defined( __osf__ )
+# define OSF
+# undef BSD
+# include <sys/param.h>
+# if !defined( BSD )
+# define BSD
+# endif
+# endif
+
+# if !defined(HAVE_DN_SKIPNAME)
+# if defined(HAVE___DN_SKIPNAME)
+# define dn_skipname __dn_skipname
+# else
+# error Could not find dn_skipname() or __dn_skipname()
+# endif
+#endif
+/*
+ * The following OS specific stuff is a compatibility kludge it would
+ * be nice to get rid of all of this eventually.
+ */
+#if defined(OS_SOLARIS2) && !defined( SOL20 )
+# define SOL20 1
+#endif
+
+#if defined( aix ) || defined( OS_AIX )
+# include <sys/machine.h>
+# if BYTE_ORDER == BIG_ENDIAN
+# define BIT_ZERO_ON_LEFT
+# elif BYTE_ORDER == LOTTLE_ENDIAN
+# define BIT_ZERO_ON_RIGHT
+# endif
+# define BSD_INCLUDES
+# if !defined( AIX )
+# define AIX 1
+# endif
+# define USE_POLL 1 /* KLUGE - only define on AIX 4.x!! -cab */
+#endif
+
+#if defined( OS_MIPS )
+# undef SYSV
+# undef BSD
+# define BSD 1 /* mips only works in a bsd43 environment */
+# if !defined( MIPS )
+# define MIPS 1
+# endif
+#endif
+
+/* This code contributed by Rossi 'vejeta' Marcello <vjt@users.sourceforge.net>
+ * Originally in va_copy.h, however there wasnt much there, so i stuck it in
+ * here. Thanks Rossi! -epi
+ */
+
+/* va_copy hooks for IRCd */
+
+#if defined(__powerpc__)
+# if defined(__NetBSD__)
+# define VA_COPY va_copy
+# elif defined(__FreeBSD__) || defined(__linux__)
+# define VA_COPY __va_copy
+# endif
+#elif defined (__x86_64)
+# define VA_COPY __va_copy
+#else
+# define VA_COPY(x, y) x = y
+#endif
+
+
+#endif /* DEFS_H_INCLUDED */
--- /dev/null
+#ifndef DH_HEADER
+extern int dh_init();
+extern void dh_end_session(void *);
+extern void *dh_start_session();
+extern char *dh_get_s_public(char *, int, void *);
+extern int dh_get_s_shared(char *, int *, void *);
+extern int dh_generate_shared(void *, char *);
+
+extern int dh_hexstr_to_raw(char *string, unsigned char *hexout, int *hexlen);
+
+extern void rc4_process_stream_to_buf(void *rc4_context, const unsigned char *istring,
+ unsigned char *ostring, unsigned int stringlen);
+extern void rc4_process_stream(void *rc4_context, unsigned char *istring, unsigned int stringlen);
+extern void *rc4_initstate(unsigned char *key, int keylen);
+extern void rc4_destroystate(void *a);
+
+#else
+
+/* this stuff is only included for dh.c .. this is a kludge,
+ * but our header files are fucking disgusting anyway.
+ */
+
+struct session_info
+{
+ DH *dh;
+ char *session_shared;
+ int session_shared_length;
+};
+
+/*
+ * Do not change these unless
+ * you also change the prime below
+ */
+
+#define KEY_BITS 512
+
+#define RAND_BITS KEY_BITS
+#define RAND_BYTES (RAND_BITS / 8)
+#define RAND_BYTES_HEX ((RAND_BYTES * 2) + 1)
+
+#define PRIME_BITS 1024
+#define PRIME_BYTES (PRIME_BITS / 8)
+#define PRIME_BYTES_HEX ((PRIME_BYTES * 2) + 1)
+
+static BIGNUM *ircd_prime;
+static BIGNUM *ircd_generator;
+
+static char *hex_to_string[256] =
+{
+ "00", "01", "02", "03", "04", "05", "06", "07",
+ "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
+ "10", "11", "12", "13", "14", "15", "16", "17",
+ "18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
+ "20", "21", "22", "23", "24", "25", "26", "27",
+ "28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
+ "30", "31", "32", "33", "34", "35", "36", "37",
+ "38", "39", "3a", "3b", "3c", "3d", "3e", "3f",
+ "40", "41", "42", "43", "44", "45", "46", "47",
+ "48", "49", "4a", "4b", "4c", "4d", "4e", "4f",
+ "50", "51", "52", "53", "54", "55", "56", "57",
+ "58", "59", "5a", "5b", "5c", "5d", "5e", "5f",
+ "60", "61", "62", "63", "64", "65", "66", "67",
+ "68", "69", "6a", "6b", "6c", "6d", "6e", "6f",
+ "70", "71", "72", "73", "74", "75", "76", "77",
+ "78", "79", "7a", "7b", "7c", "7d", "7e", "7f",
+ "80", "81", "82", "83", "84", "85", "86", "87",
+ "88", "89", "8a", "8b", "8c", "8d", "8e", "8f",
+ "90", "91", "92", "93", "94", "95", "96", "97",
+ "98", "99", "9a", "9b", "9c", "9d", "9e", "9f",
+ "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
+ "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af",
+ "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7",
+ "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf",
+ "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7",
+ "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf",
+ "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+ "d8", "d9", "da", "db", "dc", "dd", "de", "df",
+ "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7",
+ "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef",
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff"
+};
+
+/* This prime is taken from IPsec */
+
+static unsigned int dh_gen_1024 = 2;
+static unsigned char dh_prime_1024[] =
+{
+ 0xF4, 0x88, 0xFD, 0x58, 0x4E, 0x49, 0xDB, 0xCD,
+ 0x20, 0xB4, 0x9D, 0xE4, 0x91, 0x07, 0x36, 0x6B,
+ 0x33, 0x6C, 0x38, 0x0D, 0x45, 0x1D, 0x0F, 0x7C,
+ 0x88, 0xB3, 0x1C, 0x7C, 0x5B, 0x2D, 0x8E, 0xF6,
+ 0xF3, 0xC9, 0x23, 0xC0, 0x43, 0xF0, 0xA5, 0x5B,
+ 0x18, 0x8D, 0x8E, 0xBB, 0x55, 0x8C, 0xB8, 0x5D,
+ 0x38, 0xD3, 0x34, 0xFD, 0x7C, 0x17, 0x57, 0x43,
+ 0xA3, 0x1D, 0x18, 0x6C, 0xDE, 0x33, 0x21, 0x2C,
+ 0xB5, 0x2A, 0xFF, 0x3C, 0xE1, 0xB1, 0x29, 0x40,
+ 0x18, 0x11, 0x8D, 0x7C, 0x84, 0xA7, 0x0A, 0x72,
+ 0xD6, 0x86, 0xC4, 0x03, 0x19, 0xC8, 0x07, 0x29,
+ 0x7A, 0xCA, 0x95, 0x0C, 0xD9, 0x96, 0x9F, 0xAB,
+ 0xD0, 0x0A, 0x50, 0x9B, 0x02, 0x46, 0xD3, 0x08,
+ 0x3D, 0x66, 0xA4, 0x5D, 0x41, 0x9F, 0x9C, 0x7C,
+ 0xBD, 0x89, 0x4B, 0x22, 0x19, 0x26, 0xBA, 0xAB,
+ 0xA2, 0x5E, 0xC3, 0x55, 0xE9, 0x2F, 0x78, 0xC7
+};
+
+/*
+ * These are too big for ircd. :\
+static unsigned int dh_gen_2048 = 2;
+static unsigned char dh_prime_2048[] = {
+ 0xF6, 0x42, 0x57, 0xB7, 0x08, 0x7F, 0x08, 0x17,
+ 0x72, 0xA2, 0xBA, 0xD6, 0xA9, 0x42, 0xF3, 0x05,
+ 0xE8, 0xF9, 0x53, 0x11, 0x39, 0x4F, 0xB6, 0xF1,
+ 0x6E, 0xB9, 0x4B, 0x38, 0x20, 0xDA, 0x01, 0xA7,
+ 0x56, 0xA3, 0x14, 0xE9, 0x8F, 0x40, 0x55, 0xF3,
+ 0xD0, 0x07, 0xC6, 0xCB, 0x43, 0xA9, 0x94, 0xAD,
+ 0xF7, 0x4C, 0x64, 0x86, 0x49, 0xF8, 0x0C, 0x83,
+ 0xBD, 0x65, 0xE9, 0x17, 0xD4, 0xA1, 0xD3, 0x50,
+ 0xF8, 0xF5, 0x59, 0x5F, 0xDC, 0x76, 0x52, 0x4F,
+ 0x3D, 0x3D, 0x8D, 0xDB, 0xCE, 0x99, 0xE1, 0x57,
+ 0x92, 0x59, 0xCD, 0xFD, 0xB8, 0xAE, 0x74, 0x4F,
+ 0xC5, 0xFC, 0x76, 0xBC, 0x83, 0xC5, 0x47, 0x30,
+ 0x61, 0xCE, 0x7C, 0xC9, 0x66, 0xFF, 0x15, 0xF9,
+ 0xBB, 0xFD, 0x91, 0x5E, 0xC7, 0x01, 0xAA, 0xD3,
+ 0x5B, 0x9E, 0x8D, 0xA0, 0xA5, 0x72, 0x3A, 0xD4,
+ 0x1A, 0xF0, 0xBF, 0x46, 0x00, 0x58, 0x2B, 0xE5,
+ 0xF4, 0x88, 0xFD, 0x58, 0x4E, 0x49, 0xDB, 0xCD,
+ 0x20, 0xB4, 0x9D, 0xE4, 0x91, 0x07, 0x36, 0x6B,
+ 0x33, 0x6C, 0x38, 0x0D, 0x45, 0x1D, 0x0F, 0x7C,
+ 0x88, 0xB3, 0x1C, 0x7C, 0x5B, 0x2D, 0x8E, 0xF6,
+ 0xF3, 0xC9, 0x23, 0xC0, 0x43, 0xF0, 0xA5, 0x5B,
+ 0x18, 0x8D, 0x8E, 0xBB, 0x55, 0x8C, 0xB8, 0x5D,
+ 0x38, 0xD3, 0x34, 0xFD, 0x7C, 0x17, 0x57, 0x43,
+ 0xA3, 0x1D, 0x18, 0x6C, 0xDE, 0x33, 0x21, 0x2C,
+ 0xB5, 0x2A, 0xFF, 0x3C, 0xE1, 0xB1, 0x29, 0x40,
+ 0x18, 0x11, 0x8D, 0x7C, 0x84, 0xA7, 0x0A, 0x72,
+ 0xD6, 0x86, 0xC4, 0x03, 0x19, 0xC8, 0x07, 0x29,
+ 0x7A, 0xCA, 0x95, 0x0C, 0xD9, 0x96, 0x9F, 0xAB,
+ 0xD0, 0x0A, 0x50, 0x9B, 0x02, 0x46, 0xD3, 0x08,
+ 0x3D, 0x66, 0xA4, 0x5D, 0x41, 0x9F, 0x9C, 0x7C,
+ 0xBD, 0x89, 0x4B, 0x22, 0x19, 0x26, 0xBA, 0xAB,
+ 0xA2, 0x5E, 0xC3, 0x55, 0xE9, 0x32, 0x0B, 0x3B
+};
+ */
+
+#endif
--- /dev/null
+#ifndef _IRCD_DOG3_FDLIST
+#define _IRCD_DOG3_FDLIST
+
+/* $Id: fdlist.h,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+typedef struct fdstruct
+{
+ int entry[MAXCONNECTIONS + 2];
+ int last_entry;
+#ifdef USE_KQUEUE
+ int kqueue_fd;
+#endif
+} fdlist;
+
+void addto_fdlist(int a, fdlist * b);
+void delfrom_fdlist(int a, fdlist * b);
+void init_fdlist(fdlist * b);
+
+#endif /* _IRCD_DOG3_FDLIST */
--- /dev/null
+/* we recommend to not print,
+ * but if you want to, just switch undef and define
+#define FDSDEBUG
+ */
+#undef FDSDEBUG
+#ifdef FDSDEBUG
+#define fdfprintf(x, y, ...) if(isatty(2)) fprintf(x, y);
+#else
+#define fdfprintf(x, y, ...)
+#endif
+
+struct fd_callbackp {
+ void (*callback)(struct fd_callbackp *);
+ void *param;
+ int fd; /* fd number */
+ int rdf; /* fd is set for reading */
+ int wrf; /* fd is set for writing */
+};
+
+#define FDT_NONE 0
+#define FDT_AUTH 1
+#define FDT_RESOLVER 2
+#define FDT_CLIENT 3
+#define FDT_LISTENER 4
+#define FDT_CALLBACKP 5
+
+#define FDF_WANTREAD 0x01
+#define FDF_WANTWRITE 0x02
+
+void init_fds();
+
+void add_fd(int fd, int type, void *value);
+void del_fd(int fd);
+#define add_callback_fd(fds) add_fd((fds)->fd, FDT_CALLBACKP, (fds))
+#define del_callback_fd(fds) del_fd((fds)->fd)
+
+void get_fd_info(int fd, int *type, unsigned int *flags, void **value);
+void set_fd_flags(int fd, unsigned int flags);
+void unset_fd_flags(int fd, unsigned int flags);
+
+void set_fd_internal(int fd, void *ptr);
+void *get_fd_internal(int fd);
+
+void check_client_fd(aClient *cptr);
+
+void report_fds(aClient *cptr);
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, include/find.h
+ * Copyright (C) 2000
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: find.h,v 1.1 2005/01/12 07:44:58 mmondor Exp $ */
+
+#ifndef __find_include__
+#define __find_include__
+
+#define find_nickserver(a, b) hash_find_nickserver(a, b)
+#define find_server(a, b) hash_find_server(a, b)
+#define find_name(a, b) hash_find_server(a, b)
+#define find_client(a, b) hash_find_client(a, b)
+
+static inline aClient *find_person(char *name, aClient *cptr)
+{
+ aClient *acptr = find_client(name, cptr);
+
+ return acptr ? (IsClient(acptr) ? acptr : cptr) : cptr;
+}
+
+#endif /* __find_include__ */
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, include/h.h
+ * Copyright (C) 1992 Darren Reed
+ *
+ * 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 1, 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.
+ */
+/*
+ * "h.h". - Headers file.
+ *
+ * Most of the externs and prototypes thrown in here to 'cleanup' things.
+ * -avalon
+ *
+ *
+ */
+
+/* $Id: h.h,v 1.1 2005/01/12 07:44:58 mmondor Exp $ */
+
+#include "send.h"
+#include "ircsprintf.h"
+
+extern int R_do_dns, R_fin_dns, R_fin_dnsc, R_fail_dns, R_do_id,
+ R_fin_id, R_fail_id;
+
+extern aMotd *motd;
+extern struct tm *motd_tm;
+
+extern aMotd *shortmotd;
+extern aMotd *helpfile; /* oper helpfile is a link list of aMotd */
+
+extern DLink *server_list;
+extern DLink *oper_list;
+extern DLink *listing_clients;
+extern DLink *recvq_clients;
+
+extern aConnect *connects;
+extern aAllow *allows;
+extern aPort *ports;
+extern Conf_Me *MeLine;
+extern aOper *opers;
+extern char *uservers[];
+extern aClass *classes;
+
+extern char ProxyMonURL[TOPICLEN+1];
+extern char ProxyMonHost[HOSTLEN+1];
+extern char Network_Name[HOSTLEN+1];
+extern char Services_Name[HOSTLEN+1];
+extern char NS_Services_Name[HOSTLEN+9];
+extern char CS_Services_Name[HOSTLEN+9];
+extern char MS_Services_Name[HOSTLEN+9];
+extern char RS_Services_Name[HOSTLEN+9];
+extern char Stats_Name[HOSTLEN+1];
+extern char OS_Stats_Name[HOSTLEN+9];
+extern char SS_Stats_Name[HOSTLEN+9];
+extern char HS_Stats_Name[HOSTLEN+9];
+extern char Staff_Address[HOSTLEN+1];
+extern char NS_Register_URL[TOPICLEN+1];
+extern char Network_Kline_Address[HOSTLEN+1];
+extern char Local_Kline_Address[HOSTLEN+1];
+extern int maxchannelsperuser, tsmaxdelta, tswarndelta;
+extern int confopts, new_confopts;
+extern int local_ip_limit, local_ip24_limit, global_ip_limit,
+ global_ip24_limit;
+
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+extern char dpath[PATH_MAX], spath[PATH_MAX];
+
+#include "fdlist.h"
+extern fdlist serv_fdlist;
+extern fdlist busycli_fdlist;
+extern fdlist default_fdlist;
+extern fdlist oper_fdlist;
+extern int MAXCLIENTS;
+extern struct Counter Count;
+
+extern time_t NOW;
+extern time_t last_stat_save;
+extern time_t nextconnect, nextdnscheck, nextping, timeofday;
+extern aClient *client, me, *local[];
+extern aChannel *channel;
+extern struct stats *ircstp;
+extern int bootopt;
+
+extern char *canonize(char *);
+extern void check_fdlists();
+extern aChannel *find_channel(char *, aChannel *);
+extern aBan *nick_is_banned(aChannel *, char *, aClient *);
+extern void remove_matching_bans(aChannel *, aClient *, aClient *);
+#ifdef EXEMPT_LISTS
+extern void remove_matching_exempts(aChannel *, aClient *, aClient *);
+#endif
+#ifdef INVITE_LISTS
+extern void remove_matching_invites(aChannel *, aClient *, aClient *);
+#endif
+extern void remove_user_from_channel(aClient *, aChannel *);
+extern void del_invite(aClient *, aChannel *);
+extern void send_user_joins(aClient *, aClient *);
+extern int can_send(aClient *, aChannel *, char *);
+extern int is_chan_op(aClient *, aChannel *);
+extern int has_voice(aClient *, aChannel *);
+extern int count_channels(aClient *);
+extern char *pretty_mask(char *);
+
+
+extern aClient *find_chasing(aClient *, char *, int *);
+
+extern int find_restrict(aClient *);
+extern int rehash(aClient *, aClient *, int);
+extern int initconf(char *);
+extern inline char *finishconf(void);
+extern void merge_confs();
+extern int lock_kline_file();
+
+extern void clear_scache_hash_table(void);
+extern char *find_or_add(char *);
+extern void count_scache(int *, u_long *);
+extern void list_scache(aClient *, aClient *, int, char **);
+
+extern void *MyMalloc(size_t);
+extern void *MyRealloc(void *, size_t);
+
+/* MyFree is defined as a macro in sys.h
+ * extern void MyFree (void *);
+ */
+
+extern char *debugmode, configfile[], *sbrk0;
+extern char *klinefile;
+extern char *zlinefile;
+extern char *getfield(char *);
+extern void get_sockhost(aClient *, char *);
+extern char *rpl_str(int);
+extern char *err_str(int);
+extern char *getreply(int);
+extern char *strerror(int);
+extern int dgets(int, char *, int);
+extern char *inetntoa(char *);
+extern int dbufalloc, dbufblocks, debuglevel, errno;
+extern int highest_fd, debuglevel, portnum,
+ debugtty, maxusersperchannel;
+extern int readcalls, udpfd, resfd;
+extern aClient *add_connection(aListener *, int);
+extern int add_listener(aPort *);
+extern void add_local_domain(char *, int);
+extern int check_client(aClient *);
+extern int check_server_init(aClient *);
+extern void close_connection(aClient *);
+extern void close_listeners();
+extern void open_listeners();
+extern int connect_server(aConnect *, aClient *, struct hostent *);
+extern void get_my_name(aClient *, char *, int);
+extern int get_sockerr(aClient *);
+extern int inetport(aClient *, char *, int, u_long);
+extern void init_sys();
+extern int read_message(time_t, fdlist *);
+extern void report_error(char *, aClient *);
+extern void set_non_blocking(int, aClient *);
+extern int setup_ping(void);
+extern void summon(aClient *, char *, char *, char *);
+extern int unixport(aClient *, char *, int);
+extern int utmp_open(void);
+extern int utmp_read(int, char *, char *, char *, int);
+extern int utmp_close(int);
+
+extern void do_dns_async(void);
+extern int completed_connection(aClient *);
+extern void accept_connection(aListener *);
+extern char * irc_get_sockerr(aClient *);
+extern int read_packet(aClient *);
+extern int do_client_queue(aClient *);
+extern void read_error_exit(aClient *, int, int);
+extern int readwrite_client(aClient *, int, int);
+
+extern inline char *get_listener_name(aListener *);
+extern int attach_Iline(aClient *, struct hostent *, char *);
+extern aConnect *find_aConnect(char *);
+extern aOper *find_oper(char *, char *, char *, char *);
+extern aConnect *find_aConnect_match(char *, char *, char *);
+extern int find_aUserver(char *);
+extern void clear_conflinks(aClient *);
+
+extern void start_auth(aClient *);
+extern void read_authports(aClient *);
+extern void send_authports(aClient *);
+
+extern void restart(char *);
+extern void send_channel_modes(aClient *, aChannel *);
+extern void server_reboot(void);
+extern void terminate(void), write_pidfile(void);
+
+extern int match(char *, char *);
+extern char *collapse(char *);
+
+extern int writecalls, writeb[];
+#ifdef WRITEV_IOV
+extern int deliver_it(aClient *, struct iovec *, int);
+#else
+extern int deliver_it(aClient *, char *, int);
+#endif
+
+extern inline int check_registered(aClient *);
+extern inline int check_registered_user(aClient *);
+extern char *get_client_name(aClient *, int);
+extern char *get_client_host(aClient *);
+extern char *my_name_for_link(char *, aConnect *);
+extern char *myctime(time_t), *date(time_t);
+extern int exit_client(aClient *, aClient *, aClient *, char *);
+extern void initstats(void);
+extern char *make_parv_copy(char *, int, char **);
+
+extern int parse(aClient *, char *, char *);
+extern void init_tree_parse(struct Message *);
+
+extern int do_numeric(int, aClient *, aClient *, int, char **);
+extern int hunt_server(aClient *, aClient *, char *, int, int, char **);
+extern aClient *next_client(aClient *, char *);
+extern aClient *next_client_double(aClient *, char *);
+
+extern int m_umode(aClient *, aClient *, int, char **);
+extern int m_names(aClient *, aClient *, int, char **);
+extern void send_umode(aClient *, aClient *, int, int, char *);
+extern int del_silence(aClient *, char *);
+
+
+extern void free_client(aClient *);
+extern void free_link(Link *);
+extern void free_dlink(DLink *);
+extern void free_chanmember(chanMember *);
+extern void free_class(aClass *);
+extern void free_user(anUser *, aClient *);
+extern void free_channel(aChannel *);
+extern aChannel *make_channel();
+extern Link *make_link(void);
+extern DLink *make_dlink(void);
+extern chanMember *make_chanmember(void);
+extern anUser *make_user(aClient *);
+extern aClass *make_class(void);
+extern aServer *make_server(aClient *);
+extern aClient *make_client(aClient *, aClient *);
+extern chanMember *find_user_member(chanMember *, aClient *);
+extern Link *find_str_link(Link *, char *);
+extern void add_client_to_list(aClient *);
+extern void checklist(void);
+extern void remove_client_from_list(aClient *);
+extern void initlists(void);
+extern void block_garbage_collect(void); /* list.c */
+extern void block_destroy(void); /* list.c */
+
+extern void set_effective_class(aClient *);
+extern void initclass();
+
+extern struct hostent *get_res(char *);
+extern struct hostent *gethost_byaddr(char *, Link *);
+extern struct hostent *gethost_byname(char *, Link *);
+extern void flush_cache(void);
+extern int init_resolver(int);
+extern time_t timeout_query_list(time_t);
+extern time_t expire_cache(time_t);
+extern void del_queries(char *);
+
+extern void clear_channel_hash_table(void);
+extern void clear_client_hash_table(void);
+extern int add_to_client_hash_table(char *, aClient *);
+extern int del_from_client_hash_table(char *, aClient *);
+extern int add_to_channel_hash_table(char *, aChannel *);
+extern int del_from_channel_hash_table(char *, aChannel *);
+extern aChannel *hash_find_channel(char *, aChannel *);
+extern aClient *hash_find_client(char *, aClient *);
+extern aClient *hash_find_nickserver(char *, aClient *);
+extern aClient *hash_find_server(char *, aClient *);
+
+extern void add_history(aClient *, int);
+extern aClient *get_history(char *, time_t);
+extern void initwhowas(void);
+extern void off_history(aClient *);
+
+extern int dopacket(aClient *, char *, int);
+extern int client_dopacket(aClient *, char *, int);
+
+/* VARARGS2 */
+
+extern void send_rplversion(aClient *);
+extern void send_rplisupport(aClient *);
+extern void build_rplcache(void);
+
+extern void debug(int level, char *pattern, ...);
+
+#ifdef DEBUGMODE
+extern void send_listinfo(aClient *, char *);
+#endif
+
+extern void send_list(aClient *, int);
+extern aChannel *hash_get_chan_bucket(int);
+
+#ifdef DUMP_DEBUG
+extern FILE *dumpfp;
+#endif
+
+#ifdef FLUD
+int check_for_flood();
+void free_fluders();
+void free_fludees();
+#define MyFludConnect(x) (((x)->fd >= 0) || ((x)->fd == -2))
+
+#endif /* FLUD */
+
+#ifdef ANTI_SPAMBOT
+#define MIN_SPAM_NUM 5
+#define MIN_SPAM_TIME 60
+#endif
+
+#define MAXKILLS 20
+extern void count_watch_memory(int *, u_long *);
+extern void clear_watch_hash_table(void);
+extern int add_to_watch_hash_table(char *, aClient *);
+extern int del_from_watch_hash_table(char *, aClient *);
+extern int hash_check_watch(aClient *, int);
+extern int hash_del_watch_list(aClient *);
+extern aWatch *hash_get_watch(char *);
+#define MAXWATCH 128
+
+DLink *add_to_list(DLink **, void *);
+void remove_from_list(DLink **, void *, DLink *);
+void print_list_memory(aClient *);
+
+#include "find.h"
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, include/hash.h
+ * Copyright (C) 1991 Darren Reed
+ *
+ * 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 1, 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.
+ */
+/*
+ * This is all DOUGH_HASH now - Dianora
+ */
+
+/* $Id: hash.h,v 1.1 2005/01/12 07:44:58 mmondor Exp $ */
+
+#ifndef __hash_include__
+#define __hash_include__
+
+typedef struct hashentry
+{
+ int hits;
+ int links;
+ void *list;
+} aHashEntry;
+
+/* Taner had BITS_PER_COL 4 BITS_PER_COL_MASK 0xF - Dianora */
+
+#define BITS_PER_COL 3
+#define BITS_PER_COL_MASK 0x7
+#define MAX_SUB (1<<BITS_PER_COL)
+
+/* Client hash table
+ * used in hash.c
+ */
+
+#define U_MAX_INITIAL 8192
+#define U_MAX_INITIAL_MASK (U_MAX_INITIAL-1)
+#define U_MAX (U_MAX_INITIAL*MAX_SUB)
+
+/* Channel hash table
+ * used in hash.c
+ */
+
+#define CH_MAX_INITIAL 2048
+#define CH_MAX_INITIAL_MASK (CH_MAX_INITIAL-1)
+#define CH_MAX (CH_MAX_INITIAL*MAX_SUB)
+
+/* Who was hash table
+ * used in whowas.c
+ */
+
+#define WW_MAX_INITIAL 16
+#define WW_MAX_INITIAL_MASK (WW_MAX_INITIAL-1)
+#define WW_MAX (WW_MAX_INITIAL*MAX_SUB)
+
+#define WATCHHASHSIZE 10007
+
+#endif /* __hash_include__ */
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, include/hooks.h
+ * Copyright (C) 2003 Lucas Madar
+ *
+ */
+
+enum c_hooktype {
+ CHOOK_10SEC, /* Called every 10 seconds or so --
+ * not guaranteed to be 10 seconds *
+ * Params: None
+ * Returns void
+ */
+ CHOOK_PREACCESS, /* Called before any access checks (dns, ident)
+ * are done, acptr->ip is valid,
+ * acptr->hostip is not "*"
+ * Params: 1: (aClient *)
+ * Returns int
+ */
+ CHOOK_POSTACCESS, /* called after access checks are done
+ * (right before client is put on network)
+ * Params: 1: (aClient *)
+ * Returns int
+ */
+ CHOOK_POSTMOTD, /* called after MOTD is shown to the client
+ * Params: 1: (aClient *)
+ * Returns int
+ */
+
+ CHOOK_MSG, /* called for every privmsg or notice
+ * Params: 3: (aClient *, int isnotice, char *msgtext),
+ * Returns int
+ */
+ CHOOK_CHANMSG, /* called for every privmsg or notice to a channel
+ * Params: 4: (aClient *source, aChannel *destination,
+\ * int isnotice, char *msgtxt)
+ * Returns int
+ */
+ CHOOK_USERMSG, /* called for every privmsg or notice to a user
+ * Params: 4: (aClient *source, aClient *destination,
+ * int isnotice, char *msgtxt)
+ * Returns int
+ */
+ CHOOK_MYMSG, /* called for every privmsg or notice to 'me.name'
+ * Params: 3: (aClient *, int isnotice, char *msgtext)
+ * Returns int
+ */
+ CHOOK_SIGNOFF, /* called on client exit (exit_client)
+ * Params: 1: (aClient *)
+ * Returns void */
+ MHOOK_LOAD, /* Called for modules loading and unloading */
+ MHOOK_UNLOAD /* Params: 2: (char *modulename, void *moduleopaque) */
+};
+
+extern int call_hooks(enum c_hooktype hooktype, ...);
+extern int init_modules();
+
+#define MODULE_INTERFACE_VERSION 1006 /* the interface version (hooks, modules.c commands, etc) */
+
+#ifdef BIRCMODULE
+extern void *bircmodule_add_hook(enum c_hooktype, void *, void *);
+extern void bircmodule_del_hook();
+extern int bircmodule_malloc(int);
+extern int bircmodule_free(void *);
+#endif
--- /dev/null
+/*
+ * Copyright (c) 1983 Regents of the University of California. All
+ * rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement: ``This product includes software
+ * developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with
+ * the distribution and in all advertising materials mentioning
+ * features or use of this software. Neither the name of the University
+ * 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 ``AS IS'' AND WITHOUT ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ *
+ * @(#)inet.h 5.4 (Berkeley) 6/1/90
+ */
+
+/* $Id: inet.h,v 1.1 2005/01/12 07:44:58 mmondor Exp $ */
+
+/* External definitions for functions in inet(3) */
+#include "config.h" /* for system definitions */
+
+#ifdef __alpha
+#define __u_l unsigned int
+#else
+#define __u_l unsigned long
+#endif
+
+#ifdef __STDC__
+extern __u_l inet_addr(char *);
+extern char *inet_ntoa(char *);
+extern __u_l inet_makeaddr(int, int);
+extern __u_l inet_network(char *);
+extern __u_l inet_lnaof(struct in_addr);
+extern __u_l inet_netof(struct in_addr);
+
+#else
+extern __u_l inet_addr();
+extern char *inet_ntoa();
+
+extern __u_l inet_makeaddr();
+
+#endif
+extern __u_l inet_network();
+extern __u_l inet_lnaof();
+extern __u_l inet_netof();
+
+#undef __u_l
--- /dev/null
+#ifndef IRCSPRINTF_H
+#define IRCSPRINTF_H
+#include <stdarg.h>
+#include <stdio.h>
+#include "setup.h"
+
+/* define this if you intend to use ircsnprintf or ircvsnprintf */
+/* It's not used, and sNprintf functions are not in all libraries */
+#define WANT_SNPRINTF
+
+int ircsprintf(char *str, const char *format, ...);
+int ircvsprintf(char *str, const char *format, va_list ap);
+#ifdef WANT_SNPRINTF
+int ircvsnprintf(char *str, size_t size, const char *format, va_list ap);
+int ircsnprintf(char *str, size_t size, const char *format, ...);
+#endif
+/* This code contributed by Rossi 'vejeta' Marcello <vjt@users.sourceforge.net>
+ * Originally in va_copy.h, however there wasnt much there, so i stuck it in
+ * here. Thanks Rossi! -epi
+ */
+
+/* va_copy hooks for IRCd */
+
+#if defined(__powerpc__)
+# if defined(__NetBSD__)
+# define VA_COPY va_copy
+# elif defined(__FreeBSD__) || defined(__linux__)
+# define VA_COPY __va_copy
+# endif
+#elif defined (__x86_64)
+# define VA_COPY __va_copy
+#else
+# define VA_COPY(x, y) x = y
+#endif
+
+#endif
+
+
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, include/msg.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * 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 1, 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.
+ *
+ */
+
+/* $Id: msg.h,v 1.1 2005/01/12 07:44:58 mmondor Exp $ */
+
+#ifndef __msg_include__
+#define __msg_include__
+
+#define MSG_PRIVATE "PRIVMSG" /* PRIV */
+#define MSG_WHO "WHO" /* WHO -> WHOC */
+#define MSG_WHOIS "WHOIS" /* WHOI */
+#define MSG_WHOWAS "WHOWAS" /* WHOW */
+#define MSG_USER "USER" /* USER */
+#define MSG_NICK "NICK" /* NICK */
+#define MSG_SERVER "SERVER" /* SERV */
+#define MSG_LIST "LIST" /* LIST */
+#define MSG_TOPIC "TOPIC" /* TOPI */
+#define MSG_INVITE "INVITE" /* INVI */
+#define MSG_VERSION "VERSION" /* VERS */
+#define MSG_QUIT "QUIT" /* QUIT */
+#define MSG_SQUIT "SQUIT" /* SQUI */
+#define MSG_KILL "KILL" /* KILL */
+#define MSG_INFO "INFO" /* INFO */
+#define MSG_LINKS "LINKS" /* LINK */
+#define MSG_STATS "STATS" /* STAT */
+#define MSG_USERS "USERS" /* USER -> USRS */
+#define MSG_HELP "HELP" /* HELP */
+#define MSG_ERROR "ERROR" /* ERRO */
+#define MSG_AWAY "AWAY" /* AWAY */
+#define MSG_CONNECT "CONNECT" /* CONN */
+#define MSG_PING "PING" /* PING */
+#define MSG_PONG "PONG" /* PONG */
+#define MSG_OPER "OPER" /* OPER */
+#define MSG_PASS "PASS" /* PASS */
+#define MSG_WALLOPS "WALLOPS" /* WALL */
+#define MSG_TIME "TIME" /* TIME */
+#define MSG_NAMES "NAMES" /* NAME */
+#define MSG_ADMIN "ADMIN" /* ADMI */
+#define MSG_TRACE "TRACE" /* TRAC */
+#define MSG_NOTICE "NOTICE" /* NOTI */
+#define MSG_JOIN "JOIN" /* JOIN */
+#define MSG_PART "PART" /* PART */
+#define MSG_LUSERS "LUSERS" /* LUSE */
+#define MSG_MOTD "MOTD" /* MOTD */
+#define MSG_MODE "MODE" /* MODE */
+#define MSG_KICK "KICK" /* KICK */
+#define MSG_USERHOST "USERHOST" /* USER -> USRH */
+#define MSG_USERIP "USERIP" /* USER -> USRH */
+#define MSG_ISON "ISON" /* ISON */
+#define MSG_REHASH "REHASH" /* REHA */
+#define MSG_RESTART "RESTART" /* REST */
+#define MSG_CLOSE "CLOSE" /* CLOS */
+#define MSG_SVINFO "SVINFO" /* SVINFO */
+#define MSG_SJOIN "SJOIN" /* SJOIN */
+#define MSG_DIE "DIE" /* DIE */
+#define MSG_HASH "HASH" /* HASH */
+#define MSG_DNS "DNS" /* DNS -> DNSS */
+#define MSG_OPERWALL "OPERWALL" /* OPERWALL */
+#define MSG_GLOBOPS "GLOBOPS" /* GLOBOPS */
+#define MSG_CHATOPS "CHATOPS" /* CHATOPS */
+#define MSG_GOPER "GOPER" /* GOPER */
+#define MSG_GNOTICE "GNOTICE" /* GNOTICE */
+#define MSG_KLINE "KLINE" /* KLINE */
+#ifdef UNKLINE
+#define MSG_UNKLINE "UNKLINE" /* UNKLINE */
+#endif
+#define MSG_SET "SET" /* SET */
+#define MSG_SAMODE "SAMODE" /* SAMODE */
+#define MSG_SAJOIN "SAJOIN" /* SAJOIN */
+#define MSG_CHANSERV "CHANSERV" /* CHANSERV */
+#define MSG_NICKSERV "NICKSERV" /* NICKSERV */
+#define MSG_MEMOSERV "MEMOSERV" /* MEMOSERV */
+#define MSG_ROOTSERV "ROOTSERV" /* MEMOSERV */
+#define MSG_OPERSERV "OPERSERV" /* OPERSERV */
+#define MSG_STATSERV "STATSERV" /* STATSERV */
+#define MSG_HELPSERV "HELPSERV" /* HELPSERV */
+#define MSG_SERVICES "SERVICES" /* SERVICES */
+#define MSG_IDENTIFY "IDENTIFY" /* IDENTIFY */
+#define MSG_CAPAB "CAPAB" /* CAPAB */
+#define MSG_LOCOPS "LOCOPS" /* LOCOPS */
+#define MSG_SVSNICK "SVSNICK" /* SVSNICK */
+#define MSG_SVSNOOP "SVSNOOP" /* SVSNOOP */
+#define MSG_SVSKILL "SVSKILL" /* SVSKILL */
+#define MSG_SVSMODE "SVSMODE" /* SVSMODE */
+#define MSG_SVSHOLD "SVSHOLD" /* SVSHOLD */
+#define MSG_AKILL "AKILL" /* AKILL */
+#define MSG_RAKILL "RAKILL" /* RAKILL */
+#define MSG_SILENCE "SILENCE" /* SILENCE */
+#define MSG_WATCH "WATCH" /* WATCH */
+#define MSG_SQLINE "SQLINE" /* SQLINE */
+#define MSG_UNSQLINE "UNSQLINE" /* UNSQLINE */
+#define MSG_BURST "BURST" /* BURST */
+#define MSG_DCCALLOW "DCCALLOW" /* dccallow */
+#define MSG_SGLINE "SGLINE" /* sgline */
+#define MSG_UNSGLINE "UNSGLINE" /* unsgline */
+#define MSG_DKEY "DKEY" /* diffie-hellman negotiation */
+#define MSG_NS "NS" /* NickServ commands */
+#define MSG_CS "CS" /* ChanServ commands */
+#define MSG_MS "MS" /* MemoServ commands */
+#define MSG_RS "RS" /* RootServ commands */
+#define MSG_OS "OS" /* OperServ commands */
+#define MSG_SS "SS" /* StatServ commands */
+#define MSG_HS "HS" /* StatServ commands */
+#define MSG_RESYNCH "RESYNCH" /* RESYNCH */
+#define MSG_LUSERSLOCK "LUSERSLOCK" /* Lusers LOCK */
+#define MSG_LINKSCONTROL "LINKSCONTROL" /* LINKSCONTROL */
+#define MSG_MODULE "MODULE" /* MODULE */
+#define MSG_RWHO "RWHO" /* RWHO */
+#define MSG_SVSCLONE "SVSCLONE" /* SVSCLONE */
+
+#define MAXPARA 15
+
+extern int m_kline(aClient *, aClient *, int, char **);
+extern int m_unkline(aClient *, aClient *, int, char **);
+extern int m_akill(aClient *, aClient *, int, char **);
+extern int m_rakill(aClient *, aClient *, int, char **);
+extern int m_locops(aClient *, aClient *, int, char **);
+extern int m_private(aClient *, aClient *, int, char **);
+extern int m_topic(aClient *, aClient *, int, char **);
+extern int m_join(aClient *, aClient *, int, char **);
+extern int m_part(aClient *, aClient *, int, char **);
+extern int m_mode(aClient *, aClient *, int, char **);
+extern int m_ping(aClient *, aClient *, int, char **);
+extern int m_pong(aClient *, aClient *, int, char **);
+extern int m_wallops(aClient *, aClient *, int, char **);
+extern int m_kick(aClient *, aClient *, int, char **);
+extern int m_nick(aClient *, aClient *, int, char **);
+extern int m_error(aClient *, aClient *, int, char **);
+extern int m_notice(aClient *, aClient *, int, char **);
+extern int m_invite(aClient *, aClient *, int, char **);
+extern int m_quit(aClient *, aClient *, int, char **);
+extern int m_kill(aClient *, aClient *, int, char **);
+extern int m_motd(aClient *, aClient *, int, char **);
+extern int m_who(aClient *, aClient *, int, char **);
+extern int m_whois(aClient *, aClient *, int, char **);
+extern int m_user(aClient *, aClient *, int, char **);
+extern int m_list(aClient *, aClient *, int, char **);
+extern int m_server(aClient *, aClient *, int, char **);
+extern int m_info(aClient *, aClient *, int, char **);
+extern int m_links(aClient *, aClient *, int, char **);
+extern int m_summon(aClient *, aClient *, int, char **);
+extern int m_stats(aClient *, aClient *, int, char **);
+extern int m_users(aClient *, aClient *, int, char **);
+extern int m_services(aClient *, aClient *, int, char **);
+extern int m_identify(aClient *, aClient *, int, char **);
+extern int m_ns(aClient *, aClient *, int, char **);
+extern int m_cs(aClient *, aClient *, int, char **);
+extern int m_ms(aClient *, aClient *, int, char **);
+extern int m_rs(aClient *, aClient *, int, char **);
+extern int m_os(aClient *, aClient *, int, char **);
+extern int m_ss(aClient *, aClient *, int, char **);
+extern int m_hs(aClient *, aClient *, int, char **);
+extern int m_svsnick(aClient *, aClient *, int, char **);
+extern int m_svskill(aClient *, aClient *, int, char **);
+extern int m_svsmode(aClient *, aClient *, int, char **);
+extern int m_svshold(aClient *, aClient *, int, char **);
+extern int m_version(aClient *, aClient *, int, char **);
+extern int m_help(aClient *, aClient *, int, char **);
+extern int m_squit(aClient *, aClient *, int, char **);
+extern int m_away(aClient *, aClient *, int, char **);
+extern int m_connect(aClient *, aClient *, int, char **);
+extern int m_oper(aClient *, aClient *, int, char **);
+extern int m_pass(aClient *, aClient *, int, char **);
+extern int m_trace(aClient *, aClient *, int, char **);
+extern int m_time(aClient *, aClient *, int, char **);
+extern int m_names(aClient *, aClient *, int, char **);
+extern int m_admin(aClient *, aClient *, int, char **);
+extern int m_lusers(aClient *, aClient *, int, char **);
+extern int m_umode(aClient *, aClient *, int, char **);
+extern int m_close(aClient *, aClient *, int, char **);
+extern int m_motd(aClient *, aClient *, int, char **);
+extern int m_whowas(aClient *, aClient *, int, char **);
+extern int m_userhost(aClient *, aClient *, int, char **);
+extern int m_userip(aClient *, aClient *, int, char **);
+extern int m_ison(aClient *, aClient *, int, char **);
+extern int m_svinfo(aClient *, aClient *, int, char **);
+extern int m_sjoin(aClient *, aClient *, int, char **);
+extern int m_samode(aClient *, aClient *, int, char **);
+extern int m_sajoin(aClient *, aClient *, int, char **);
+extern int m_globops(aClient *, aClient *, int, char **);
+extern int m_chatops(aClient *, aClient *, int, char **);
+extern int m_goper(aClient *, aClient *, int, char **);
+extern int m_gnotice(aClient *, aClient *, int, char **);
+extern int m_rehash(aClient *, aClient *, int, char **);
+extern int m_restart(aClient *, aClient *, int, char **);
+extern int m_die(aClient *, aClient *, int, char **);
+extern int m_hash(aClient *, aClient *, int, char **);
+extern int m_dns(aClient *, aClient *, int, char **);
+extern int m_set(aClient *, aClient *, int, char **);
+extern int m_capab(aClient *, aClient *, int, char **);
+extern int m_silence(aClient *, aClient *, int, char **);
+extern int m_watch(aClient *, aClient *, int, char **);
+extern int m_sqline(aClient *, aClient *, int, char **);
+extern int m_unsqline(aClient *, aClient *, int, char **);
+extern int m_burst(aClient *, aClient *, int, char **);
+extern int m_dccallow(aClient *, aClient *, int, char **);
+extern int m_sgline(aClient *, aClient *, int, char **);
+extern int m_unsgline(aClient *, aClient *, int, char **);
+extern int m_dkey(aClient *, aClient *, int, char **);
+extern int m_resynch(aClient *, aClient *, int, char **);
+extern int m_luserslock(aClient *, aClient *, int, char **);
+extern int m_linkscontrol(aClient *, aClient *, int, char **);
+extern int m_module(aClient *, aClient *, int, char **);
+extern int m_rwho(aClient *, aClient *, int, char **);
+extern int m_svsclone(aClient *, aClient *, int, char **);
+
+#ifdef MSGTAB
+struct Message msgtab[] =
+{
+ {MSG_PRIVATE, m_private, 0, MAXPARA, 1, 0, 1, 0L},
+ {MSG_NICK, m_nick, 0, MAXPARA, 1, 1, 0, 0L},
+ {MSG_NOTICE, m_notice, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_JOIN, m_join, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_MODE, m_mode, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_SAMODE, m_samode, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_SAJOIN, m_sajoin, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_QUIT, m_quit, 0, MAXPARA, 1, 1, 0, 0L},
+ {MSG_PART, m_part, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_TOPIC, m_topic, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_INVITE, m_invite, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_KICK, m_kick, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_WALLOPS, m_wallops, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_LOCOPS, m_locops, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_PONG, m_pong, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_PING, m_ping, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_ERROR, m_error, 0, MAXPARA, 1, 1, 0, 0L},
+ {MSG_KILL, m_kill, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_USER, m_user, 0, MAXPARA, 1, 1, 0, 0L},
+ {MSG_AWAY, m_away, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_ISON, m_ison, 0, 1, 1, 0, 0, 0L},
+ {MSG_SERVER, m_server, 0, MAXPARA, 1, 1, 0, 0L},
+ {MSG_SQUIT, m_squit, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_WHOIS, m_whois, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_WHO, m_who, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_WHOWAS, m_whowas, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_LIST, m_list, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_NAMES, m_names, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_USERHOST, m_userhost, 0, 1, 1, 0, 0, 0L},
+ {MSG_USERIP, m_userip, 0, 1, 1, 0, 0, 0L},
+ {MSG_TRACE, m_trace, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_PASS, m_pass, 0, MAXPARA, 1, 1, 0, 0L},
+ {MSG_LUSERS, m_lusers, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_TIME, m_time, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_OPER, m_oper, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_CONNECT, m_connect, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_VERSION, m_version, 0, MAXPARA, 1, 1, 0, 0L},
+ {MSG_STATS, m_stats, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_LINKS, m_links, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_ADMIN, m_admin, 0, MAXPARA, 1, 1, 0, 0L},
+ {MSG_USERS, m_users, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_HELP, m_help, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_INFO, m_info, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_MOTD, m_motd, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_SVINFO, m_svinfo, 0, MAXPARA, 1, 1, 0, 0L},
+ {MSG_SJOIN, m_sjoin, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_GLOBOPS, m_globops, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_CHATOPS, m_chatops, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_GOPER, m_goper, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_GNOTICE, m_gnotice, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_CLOSE, m_close, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_KLINE, m_kline, 0, MAXPARA, 1, 0, 0, 0L},
+#ifdef UNKLINE
+ {MSG_UNKLINE, m_unkline, 0, MAXPARA, 1, 0, 0, 0L},
+#endif
+ {MSG_HASH, m_hash, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_DNS, m_dns, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_REHASH, m_rehash, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_RESTART, m_restart, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_DIE, m_die, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_SET, m_set, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_CHANSERV, m_cs, 0, 1, 1, 0, 0, 0L},
+ {MSG_NICKSERV, m_ns, 0, 1, 1, 0, 0, 0L},
+ {MSG_MEMOSERV, m_ms, 0, 1, 1, 0, 0, 0L},
+ {MSG_ROOTSERV, m_rs, 0, 1, 1, 0, 0, 0L},
+ {MSG_OPERSERV, m_os, 0, 1, 1, 0, 0, 0L},
+ {MSG_STATSERV, m_ss, 0, 1, 1, 0, 0, 0L},
+ {MSG_HELPSERV, m_hs, 0, 1, 1, 0, 0, 0L},
+ {MSG_SERVICES, m_services, 0, 1, 1, 0, 0, 0L},
+ {MSG_IDENTIFY, m_identify, 0, 1, 1, 0, 0, 0L},
+ {MSG_SVSNICK, m_svsnick, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_SVSKILL, m_svskill, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_SVSMODE, m_svsmode, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_SVSHOLD, m_svshold, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_AKILL, m_akill, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_RAKILL, m_rakill, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_SILENCE, m_silence, 0, MAXPARA, 1, 0, 0, 0L },
+ {MSG_WATCH, m_watch, 0, 1, 1, 0, 0, 0L },
+ {MSG_DCCALLOW, m_dccallow, 0, 1, 1, 0, 0, 0L },
+ {MSG_SQLINE, m_sqline, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_UNSQLINE, m_unsqline, 0, MAXPARA, 1, 0, 0, 0L },
+ {MSG_CAPAB, m_capab, 0, MAXPARA, 1, 1, 0, 0L},
+ {MSG_BURST, m_burst, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_SGLINE, m_sgline, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_UNSGLINE, m_unsgline, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_DKEY, m_dkey, 0, MAXPARA, 1, 1, 0, 0L},
+ {MSG_NS, m_ns, 0, 1, 1, 1, 0, 0L},
+ {MSG_CS, m_cs, 0, 1, 1, 1, 0, 0L},
+ {MSG_MS, m_ms, 0, 1, 1, 1, 0, 0L},
+ {MSG_RS, m_rs, 0, 1, 1, 1, 0, 0L},
+ {MSG_OS, m_os, 0, 1, 1, 1, 0, 0L},
+ {MSG_SS, m_ss, 0, 1, 1, 1, 0, 0L},
+ {MSG_HS, m_hs, 0, 1, 1, 1, 0, 0L},
+ {MSG_RESYNCH, m_resynch, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_LUSERSLOCK, m_luserslock, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_LINKSCONTROL, m_linkscontrol, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_MODULE, m_module, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_RWHO, m_rwho, 0, MAXPARA, 1, 0, 0, 0L},
+ {MSG_SVSCLONE, m_svsclone, 0, MAXPARA, 1, 0 ,0, 0L},
+ {(char *) 0, (int (*)()) 0, 0, 0, 0, 0, 0, 0L}
+};
+
+MESSAGE_TREE *msg_tree_root;
+#else
+extern struct Message msgtab[];
+extern MESSAGE_TREE *msg_tree_root;
+#endif
+#endif /* __msg_include__ */
--- /dev/null
+/*
+ * Copyright (c) 1983, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement: ``This product includes software
+ * developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with
+ * the distribution and in all advertising materials mentioning
+ * features or use of this software. Neither the name of the University
+ * 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 ``AS IS'' AND WITHOUT ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ *
+ * @(#)nameser.h 5.24 (Berkeley) 6/1/90
+ */
+
+/* $Id: nameser.h,v 1.1 2005/01/12 07:44:58 mmondor Exp $ */
+
+/* Define constants based on rfc883 */
+
+#define PACKETSZ 512 /* maximum packet size */
+#define MAXDNAME 256 /* maximum domain name */
+#define MAXCDNAME 255 /* maximum compressed domain name */
+#define MAXLABEL 63 /* maximum length of domain label */
+
+#define QFIXEDSZ 4 /* Number of bytes of fixed size
+ * data in query structure */
+#define RRFIXEDSZ 10 /* number of bytes of fixed size data
+ * in resource record */
+#define NAMESERVER_PORT 53 /* Internet nameserver port number */
+
+/* Currently defined opcodes */
+
+#define QUERY 0x0 /* standard query */
+#define IQUERY 0x1 /* inverse query */
+#define STATUS 0x2 /* nameserver status query */
+
+/* non standard */
+
+#define UPDATEA 0x9 /* add resource record */
+#define UPDATED 0xa /* delete a specific resource record */
+#define UPDATEDA 0xb /* delete all nemed resource record */
+#define UPDATEM 0xc /* modify a specific resource record */
+#define UPDATEMA 0xd /* modify all named resource record */
+#define ZONEINIT 0xe /* initial zone transfer */
+#define ZONEREF 0xf /* incremental zone referesh */
+
+/* Currently defined response codes */
+
+#ifdef NOERROR /* defined by solaris2 in
+#undef NOERROR * <sys/stream.h> to be -1 */
+#endif
+
+#define NOERROR 0 /* no error */
+#define FORMERR 1 /* format error */
+#define SERVFAIL 2 /* server failure */
+#define NXDOMAIN 3 /* non existent domain */
+#define NOTIMP 4 /* not implemented */
+#define REFUSED 5 /* query refused */
+
+/* non standard */
+
+#define NOCHANGE 0xf /* update failed to change db */
+
+/* Type values for resources and queries */
+
+#define T_A 1 /* host address */
+#define T_NS 2 /* authoritative server */
+#define T_MD 3 /* mail destination */
+#define T_MF 4 /* mail forwarder */
+#define T_CNAME 5 /* connonical name */
+#define T_SOA 6 /* start of authority zone */
+#define T_MB 7 /* mailbox domain name */
+#define T_MG 8 /* mail group member */
+#define T_MR 9 /* mail rename name */
+#define T_NULL 10 /* null resource record */
+#define T_WKS 11 /* well known service */
+#define T_PTR 12 /* domain name pointer */
+#define T_HINFO 13 /* host information */
+#define T_MINFO 14 /* mailbox information */
+#define T_MX 15 /* mail routing information */
+#define T_TXT 16 /* text strings */
+
+/* non standard */
+
+#define T_UINFO 100 /* user (finger) information */
+#define T_UID 101 /* user ID */
+#define T_GID 102 /* group ID */
+#define T_UNSPEC 103 /* Unspecified format (binary data) */
+
+/* Query type values which do not appear in resource records */
+
+#define T_AXFR 252 /* transfer zone of authority */
+#define T_MAILB 253 /* transfer mailbox records */
+#define T_MAILA 254 /* transfer mail agent records */
+#define T_ANY 255 /* wildcard match */
+
+/* Values for class field */
+
+#define C_IN 1 /* the arpa internet */
+#define C_CHAOS 3 /* for chaos net at MIT */
+#define C_HS 4 /* for Hesiod name server at MIT */
+
+/* Query class values which do not appear in resource records */
+
+#define C_ANY 255 /* wildcard match */
+
+/* Status return codes for T_UNSPEC conversion routines */
+
+#define CONV_SUCCESS 0
+#define CONV_OVERFLOW -1
+#define CONV_BADFMT -2
+#define CONV_BADCKSUM -3
+#define CONV_BADBUFLEN -4
+
+#ifndef BYTE_ORDER
+#define LITTLE_ENDIAN 1234 /* least-significant byte first (vax) */
+#define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */
+#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp) */
+
+#if defined(vax) || defined(ns32000) || defined(sun386) || defined(MIPSEL) || \
+ defined(BIT_ZERO_ON_RIGHT) || defined(i386) ||\
+ defined(___vax__) || defined(__ns32000__) || defined(__sun386__) ||\
+ defined(__alpha)
+
+#define BYTE_ORDER LITTLE_ENDIAN
+
+#endif
+
+#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \
+ defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \
+ defined(MIPSEB) || defined(__hpux) || defined(__convex__) || \
+ defined(__pyr__) || defined(__mc68000__) || defined(__sparc__) ||\
+ defined(_IBMR2) || defined (BIT_ZERO_ON_LEFT)
+
+#define BYTE_ORDER BIG_ENDIAN
+
+#endif
+
+#endif /* BYTE_ORDER */
+
+#ifndef BYTE_ORDER
+/* you must determine what the correct bit order is for your compiler */
+
+UNDEFINED_BIT_ORDER;
+
+#endif
+
+/*
+ * Structure for query header, the order of the fields is machine and
+ * compiler dependent, in our case, the bits within a byte are assignd
+ * least significant first, while the order of transmition is most
+ * significant first. This requires a somewhat confusing
+ * rearrangement.
+ */
+
+typedef struct
+{
+ u_short id; /* query identification number */
+#if BYTE_ORDER == BIG_ENDIAN
+
+ /* fields in third byte */
+
+ u_char qr:1; /* response flag */
+ u_char opcode:4; /* purpose of message */
+ u_char aa:1; /* authoritive answer */
+ u_char tc:1; /* truncated message */
+ u_char rd:1; /* recursion desired */
+
+ /* fields in fourth byte */
+
+ u_char ra:1; /* recursion available */
+ u_char pr:1; /* primary server required (non standard) */
+ u_char unused:2; /* unused bits */
+ u_char rcode:4; /* response code */
+
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
+
+ /* fields in third byte */
+
+ u_char rd:1; /* recursion desired */
+ u_char tc:1; /* truncated message */
+ u_char aa:1; /* authoritive answer */
+ u_char opcode:4; /* purpose of message */
+ u_char qr:1; /* response flag */
+
+ /* fields in fourth byte */
+
+ u_char rcode:4; /* response code */
+ u_char unused:2; /* unused bits */
+ u_char pr:1; /* primary server required (non standard) */
+ u_char ra:1; /* recursion available */
+
+#endif
+
+ /* remaining bytes */
+
+ u_short qdcount; /* number of question entries */
+ u_short ancount; /* number of answer entries */
+ u_short nscount; /* number of authority entries */
+ u_short arcount; /* number of resource entries */
+} HEADER;
+
+/* Defines for handling compressed domain names */
+
+#define INDIR_MASK 0xc0
+
+/* Structure for passing resource records around. */
+
+struct rrec
+{
+ short r_zone; /* zone number */
+ short r_class; /* class number */
+ short r_type; /* type number */
+#ifdef __alpha
+ u_int r_ttl; /* time to live */
+#else
+ u_long r_ttl; /* time to live */
+#endif
+ int r_size; /* size of data area */
+ char *r_data; /* pointer to data */
+};
+
+extern u_short _getshort();
+
+#ifdef __alpha
+extern u_int _getlong();
+#else
+extern u_long _getlong();
+#endif
+
+/*
+ * Inline versions of get/put short/long. Pointer is advanced; we
+ * assume that both arguments are lvalues and will already be in
+ * registers. cp MUST be u_char *.
+ */
+
+#define GETSHORT(s, cp) { \
+ (s) = *(cp)++ << 8; \
+ (s) |= *(cp)++; \
+}
+
+#define GETLONG(l, cp) { \
+ (l) = *(cp)++ << 8; \
+ (l) |= *(cp)++; (l) <<= 8; \
+ (l) |= *(cp)++; (l) <<= 8; \
+ (l) |= *(cp)++; \
+}
+
+#define PUTSHORT(s, cp) { \
+ *(cp)++ = (s) >> 8; \
+ *(cp)++ = (s); \
+}
+
+/* Warning: PUTLONG destroys its first argument.*/
+
+#define PUTLONG(l, cp) { \
+ (cp)[3] = l; \
+ (cp)[2] = (l >>= 8); \
+ (cp)[1] = (l >>= 8); \
+ (cp)[0] = l >> 8; \
+ (cp) += sizeof(u_long); \
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, include/numeric.h
+ * Copyright (C) 1990 Jarkko Oikarinen
+ *
+ * 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 1, 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.
+ *
+ */
+
+/* $Id: numeric.h,v 1.1 2005/01/12 07:44:58 mmondor Exp $ */
+
+
+#define RPL_WELCOME 001
+#define RPL_YOURHOST 002
+#define RPL_CREATED 003
+#define RPL_MYINFO 004
+#define RPL_ISUPPORT 005
+
+#define RPL_TRACELINK 200
+#define RPL_TRACECONNECTING 201
+#define RPL_TRACEHANDSHAKE 202
+#define RPL_TRACEUNKNOWN 203
+#define RPL_TRACEOPERATOR 204
+#define RPL_TRACEUSER 205
+#define RPL_TRACESERVER 206
+
+#define RPL_TRACENEWTYPE 208
+#define RPL_TRACECLASS 209
+
+#define RPL_STATSLINKINFO 211
+#define RPL_STATSCOMMANDS 212
+#define RPL_STATSCLINE 213
+#define RPL_STATSNLINE 214
+#define RPL_STATSILINE 215
+#define RPL_STATSKLINE 216
+#define RPL_STATSQLINE 217
+#define RPL_STATSYLINE 218
+#define RPL_ENDOFSTATS 219
+
+#define RPL_UMODEIS 221
+#define RPL_STATSBLINE 222
+#define RPL_STATSELINE 223
+
+#define RPL_STATSCLONE 225
+#define RPL_STATSCOUNT 226
+#define RPL_STATSGLINE 227
+
+#define RPL_SERVLIST 234
+#define RPL_SERVLISTEND 235
+
+#define RPL_STATSLLINE 241
+#define RPL_STATSUPTIME 242
+#define RPL_STATSOLINE 243
+#define RPL_STATSHLINE 244
+#define RPL_STATSSLINE 245
+#define RPL_STATSULINE 246
+
+#define RPL_STATSDEBUG 249
+
+#define RPL_LUSERCLIENT 251
+#define RPL_LUSEROP 252
+#define RPL_LUSERUNKNOWN 253
+#define RPL_LUSERCHANNELS 254
+#define RPL_LUSERME 255
+#define RPL_ADMINME 256
+#define RPL_ADMINLOC1 257
+#define RPL_ADMINLOC2 258
+#define RPL_ADMINEMAIL 259
+
+#define RPL_TRACELOG 261
+#define RPL_ENDOFTRACE 262
+#define RPL_LOAD2HI 263
+
+#define RPL_LOCALUSERS 265
+#define RPL_GLOBALUSERS 266
+
+#define RPL_SILELIST 271
+#define RPL_ENDOFSILELIST 272
+
+#define RPL_NONE 300
+#define RPL_AWAY 301
+#define RPL_USERHOST 302
+#define RPL_ISON 303
+#define RPL_TEXT 304
+#define RPL_UNAWAY 305
+#define RPL_NOWAWAY 306
+#define RPL_WHOISREGNICK 307
+#define RPL_WHOISADMIN 308
+#define RPL_WHOISSADMIN 309
+#define RPL_WHOISSVCMSG 310
+#define RPL_WHOISUSER 311
+#define RPL_WHOISSERVER 312
+#define RPL_WHOISOPERATOR 313
+#define RPL_WHOWASUSER 314
+#define RPL_ENDOFWHO 315
+#define RPL_WHOISCHANOP 316
+#define RPL_WHOISIDLE 317
+#define RPL_ENDOFWHOIS 318
+#define RPL_WHOISCHANNELS 319
+
+#define RPL_LISTSTART 321
+#define RPL_LIST 322
+#define RPL_LISTEND 323
+#define RPL_CHANNELMODEIS 324
+
+#define RPL_CREATIONTIME 329
+
+#define RPL_NOTOPIC 331
+#define RPL_TOPIC 332
+#define RPL_TOPICWHOTIME 333
+#define RPL_COMMANDSYNTAX 334
+
+#define RPL_WHOISTEXT 337
+#define RPL_WHOISACTUALLY 338
+
+#define RPL_INVITING 341
+#define RPL_SUMMONING 342
+
+#define RPL_INVITELIST 346
+#define RPL_ENDOFINVITELIST 347
+#define RPL_EXEMPTLIST 348
+#define RPL_ENDOFEXEMPTLIST 349
+
+#define RPL_VERSION 351
+#define RPL_WHOREPLY 352
+#define RPL_NAMREPLY 353
+#define RPL_RWHOREPLY 354
+
+#define RPL_KILLDONE 361
+#define RPL_CLOSING 362
+#define RPL_CLOSEEND 363
+#define RPL_LINKS 364
+#define RPL_ENDOFLINKS 365
+#define RPL_ENDOFNAMES 366
+#define RPL_BANLIST 367
+#define RPL_ENDOFBANLIST 368
+#define RPL_ENDOFWHOWAS 369
+
+#define RPL_INFO 371
+#define RPL_MOTD 372
+#define RPL_INFOSTART 373
+#define RPL_ENDOFINFO 374
+#define RPL_MOTDSTART 375
+#define RPL_ENDOFMOTD 376
+
+#define RPL_YOUREOPER 381
+#define RPL_REHASHING 382
+
+#define RPL_MYPORTIS 384
+#define RPL_NOTOPERANYMORE 385
+
+#define RPL_TIME 391
+#define RPL_USERSSTART 392
+#define RPL_USERS 393
+#define RPL_ENDOFUSERS 394
+#define RPL_NOUSERS 395
+
+#define ERR_NOSUCHNICK 401
+#define ERR_NOSUCHSERVER 402
+#define ERR_NOSUCHCHANNEL 403
+#define ERR_CANNOTSENDTOCHAN 404
+#define ERR_TOOMANYCHANNELS 405
+#define ERR_WASNOSUCHNICK 406
+#define ERR_TOOMANYTARGETS 407
+#define ERR_NOCOLORSONCHAN 408
+#define ERR_NOORIGIN 409
+
+#define ERR_NORECIPIENT 411
+#define ERR_NOTEXTTOSEND 412
+#define ERR_NOTOPLEVEL 413
+#define ERR_WILDTOPLEVEL 414
+
+#define ERR_UNKNOWNCOMMAND 421
+#define ERR_NOMOTD 422
+#define ERR_NOADMININFO 423
+#define ERR_FILEERROR 424
+
+#define ERR_TOOMANYAWAY 429
+
+#define ERR_NONICKNAMEGIVEN 431
+#define ERR_ERRONEUSNICKNAME 432
+#define ERR_NICKNAMEINUSE 433
+
+#define ERR_BANONCHAN 435
+#define ERR_NICKCOLLISION 436
+#define ERR_BANNICKCHANGE 437
+
+#define ERR_TARGETTOFAST 439
+
+#define ERR_SERVICESDOWN 440
+#define ERR_USERNOTINCHANNEL 441
+#define ERR_NOTONCHANNEL 442
+#define ERR_USERONCHANNEL 443
+#define ERR_NOLOGIN 444
+#define ERR_SUMMONDISABLED 445
+#define ERR_USERSDISABLED 446
+
+#define ERR_NOTREGISTERED 451
+
+#define ERR_NEEDMOREPARAMS 461
+#define ERR_ALREADYREGISTRED 462
+#define ERR_NOPERMFORHOST 463
+#define ERR_PASSWDMISMATCH 464
+#define ERR_YOUREBANNEDCREEP 465
+#define ERR_YOUWILLBEBANNED 466
+#define ERR_KEYSET 467
+#define ERR_ONLYSERVERSCANCHANGE 468
+
+#define ERR_CHANNELISFULL 471
+#define ERR_UNKNOWNMODE 472
+#define ERR_INVITEONLYCHAN 473
+#define ERR_BANNEDFROMCHAN 474
+#define ERR_BADCHANNELKEY 475
+#define ERR_BADCHANMASK 476
+#define ERR_NEEDREGGEDNICK 477
+#define ERR_BANLISTFULL 478
+#define ERR_BADCHANNAME 479
+
+#define ERR_NOPRIVILEGES 481
+#define ERR_CHANOPRIVSNEEDED 482
+#define ERR_CANTKILLSERVER 483
+#define ERR_DESYNC 484
+#define ERR_CHANBANREASON 485
+#define ERR_NONONREG 486
+#define ERR_MSGSERVICES 487
+
+#define ERR_NOOPERHOST 491
+
+#define ERR_UMODEUNKNOWNFLAG 501
+#define ERR_USERSDONTMATCH 502
+
+#define ERR_GHOSTEDCLIENT 503
+#define ERR_LAST_ERR_MSG 504
+
+#define ERR_SILELISTFULL 511
+#define ERR_TOOMANYWATCH 512
+
+#define ERR_TOOMANYDCC 514
+
+#define ERR_LISTSYNTAX 521
+#define ERR_WHOSYNTAX 522
+#define ERR_WHOLIMEXCEED 523
+
+#define RPL_LOGON 600
+#define RPL_LOGOFF 601
+#define RPL_WATCHOFF 602
+#define RPL_WATCHSTAT 603
+#define RPL_NOWON 604
+#define RPL_NOWOFF 605
+#define RPL_WATCHLIST 606
+#define RPL_ENDOFWATCHLIST 607
+
+#define RPL_DCCSTATUS 617
+#define RPL_DCCLIST 618
+#define RPL_ENDOFDCCLIST 619
+#define RPL_DCCINFO 620
+
+#define ERR_NUMERIC_ERR 999
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, include/patchlevel.h
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: patchlevel.h,v 1.1 2005/01/12 07:44:58 mmondor Exp $ */
+
+#ifndef __patchlevel_header__
+#define __patchlevel_header__
+
+/* these don't go in the version itself, but they're importany anyways */
+#define RELEASE 1
+#define BETA 2
+#define CURRENT 3
+
+#define BRANCHSTATUS RELEASE
+
+#define BASENAME "bahamut"
+#define MAJOR 1
+#define MINOR 8
+#define PATCH 3
+
+#define PATCHES ""
+
+void build_version(void);
+
+#endif
+
--- /dev/null
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* Copyright (c) 1997-2003 University of Cambridge */
+
+#ifndef _PCRE_H
+#define _PCRE_H
+
+/* The file pcre.h is build by "configure". Do not edit it; instead
+make changes to pcre.in. */
+
+#define PCRE_MAJOR 4
+#define PCRE_MINOR 5
+#define PCRE_DATE 01-December-2003
+
+/* Win32 uses DLL by default */
+
+#ifdef _WIN32
+# ifdef PCRE_DEFINITION
+# ifdef DLL_EXPORT
+# define PCRE_DATA_SCOPE __declspec(dllexport)
+# endif
+# else
+# ifndef PCRE_STATIC
+# define PCRE_DATA_SCOPE extern __declspec(dllimport)
+# endif
+# endif
+#endif
+#ifndef PCRE_DATA_SCOPE
+# define PCRE_DATA_SCOPE extern
+#endif
+
+/* Have to include stdlib.h in order to ensure that size_t is defined;
+it is needed here for malloc. */
+
+#include <stdlib.h>
+
+/* Allow for C++ users */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Options */
+
+#define PCRE_CASELESS 0x0001
+#define PCRE_MULTILINE 0x0002
+#define PCRE_DOTALL 0x0004
+#define PCRE_EXTENDED 0x0008
+#define PCRE_ANCHORED 0x0010
+#define PCRE_DOLLAR_ENDONLY 0x0020
+#define PCRE_EXTRA 0x0040
+#define PCRE_NOTBOL 0x0080
+#define PCRE_NOTEOL 0x0100
+#define PCRE_UNGREEDY 0x0200
+#define PCRE_NOTEMPTY 0x0400
+#define PCRE_UTF8 0x0800
+#define PCRE_NO_AUTO_CAPTURE 0x1000
+#define PCRE_NO_UTF8_CHECK 0x2000
+
+/* Exec-time and get/set-time error codes */
+
+#define PCRE_ERROR_NOMATCH (-1)
+#define PCRE_ERROR_NULL (-2)
+#define PCRE_ERROR_BADOPTION (-3)
+#define PCRE_ERROR_BADMAGIC (-4)
+#define PCRE_ERROR_UNKNOWN_NODE (-5)
+#define PCRE_ERROR_NOMEMORY (-6)
+#define PCRE_ERROR_NOSUBSTRING (-7)
+#define PCRE_ERROR_MATCHLIMIT (-8)
+#define PCRE_ERROR_CALLOUT (-9) /* Never used by PCRE itself */
+#define PCRE_ERROR_BADUTF8 (-10)
+#define PCRE_ERROR_BADUTF8_OFFSET (-11)
+
+/* Request types for pcre_fullinfo() */
+
+#define PCRE_INFO_OPTIONS 0
+#define PCRE_INFO_SIZE 1
+#define PCRE_INFO_CAPTURECOUNT 2
+#define PCRE_INFO_BACKREFMAX 3
+#define PCRE_INFO_FIRSTBYTE 4
+#define PCRE_INFO_FIRSTCHAR 4 /* For backwards compatibility */
+#define PCRE_INFO_FIRSTTABLE 5
+#define PCRE_INFO_LASTLITERAL 6
+#define PCRE_INFO_NAMEENTRYSIZE 7
+#define PCRE_INFO_NAMECOUNT 8
+#define PCRE_INFO_NAMETABLE 9
+#define PCRE_INFO_STUDYSIZE 10
+
+/* Request types for pcre_config() */
+
+#define PCRE_CONFIG_UTF8 0
+#define PCRE_CONFIG_NEWLINE 1
+#define PCRE_CONFIG_LINK_SIZE 2
+#define PCRE_CONFIG_POSIX_MALLOC_THRESHOLD 3
+#define PCRE_CONFIG_MATCH_LIMIT 4
+#define PCRE_CONFIG_STACKRECURSE 5
+
+/* Bit flags for the pcre_extra structure */
+
+#define PCRE_EXTRA_STUDY_DATA 0x0001
+#define PCRE_EXTRA_MATCH_LIMIT 0x0002
+#define PCRE_EXTRA_CALLOUT_DATA 0x0004
+
+/* Types */
+
+struct real_pcre; /* declaration; the definition is private */
+typedef struct real_pcre pcre;
+
+/* The structure for passing additional data to pcre_exec(). This is defined in
+such as way as to be extensible. */
+
+typedef struct pcre_extra {
+ unsigned long int flags; /* Bits for which fields are set */
+ void *study_data; /* Opaque data from pcre_study() */
+ unsigned long int match_limit; /* Maximum number of calls to match() */
+ void *callout_data; /* Data passed back in callouts */
+} pcre_extra;
+
+/* The structure for passing out data via the pcre_callout_function. We use a
+structure so that new fields can be added on the end in future versions,
+without changing the API of the function, thereby allowing old clients to work
+without modification. */
+
+typedef struct pcre_callout_block {
+ int version; /* Identifies version of block */
+ /* ------------------------ Version 0 ------------------------------- */
+ int callout_number; /* Number compiled into pattern */
+ int *offset_vector; /* The offset vector */
+ const char *subject; /* The subject being matched */
+ int subject_length; /* The length of the subject */
+ int start_match; /* Offset to start of this match attempt */
+ int current_position; /* Where we currently are */
+ int capture_top; /* Max current capture */
+ int capture_last; /* Most recently closed capture */
+ void *callout_data; /* Data passed in with the call */
+ /* ------------------------------------------------------------------ */
+} pcre_callout_block;
+
+/* Indirection for store get and free functions. These can be set to
+alternative malloc/free functions if required. Special ones are used in the
+non-recursive case for "frames". There is also an optional callout function
+that is triggered by the (?) regex item. Some magic is required for Win32 DLL;
+it is null on other OS. For Virtual Pascal, these have to be different again.
+*/
+
+#ifndef VPCOMPAT
+PCRE_DATA_SCOPE void *(*pcre_malloc)(size_t);
+PCRE_DATA_SCOPE void (*pcre_free)(void *);
+PCRE_DATA_SCOPE void *(*pcre_stack_malloc)(size_t);
+PCRE_DATA_SCOPE void (*pcre_stack_free)(void *);
+PCRE_DATA_SCOPE int (*pcre_callout)(pcre_callout_block *);
+#else /* VPCOMPAT */
+extern void *pcre_malloc(size_t);
+extern void pcre_free(void *);
+extern void *pcre_stack_malloc(size_t);
+extern void pcre_stack_free(void *);
+extern int pcre_callout(pcre_callout_block *);
+#endif /* VPCOMPAT */
+
+/* Exported PCRE functions */
+
+extern pcre *pcre_compile(const char *, int, const char **,
+ int *, const unsigned char *);
+extern int pcre_config(int, void *);
+extern int pcre_copy_named_substring(const pcre *, const char *,
+ int *, int, const char *, char *, int);
+extern int pcre_copy_substring(const char *, int *, int, int,
+ char *, int);
+extern int pcre_exec(const pcre *, const pcre_extra *,
+ const char *, int, int, int, int *, int);
+extern void pcre_free_substring(const char *);
+extern void pcre_free_substring_list(const char **);
+extern int pcre_fullinfo(const pcre *, const pcre_extra *, int,
+ void *);
+extern int pcre_get_named_substring(const pcre *, const char *,
+ int *, int, const char *, const char **);
+extern int pcre_get_stringnumber(const pcre *, const char *);
+extern int pcre_get_substring(const char *, int *, int, int,
+ const char **);
+extern int pcre_get_substring_list(const char *, int *, int,
+ const char ***);
+extern int pcre_info(const pcre *, int *, int *);
+extern const unsigned char *pcre_maketables(void);
+extern pcre_extra *pcre_study(const pcre *, int, const char **);
+extern const char *pcre_version(void);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* End of pcre.h */
--- /dev/null
+/* pcre_config.h, created to embed PCRE in bahamut */
+
+#include "setup.h"
+
+#define EBCDIC 0
+#define EXPORT
+#define NEWLINE '\n'
+#define LINK_SIZE 2
+#define POSIX_MALLOC_THRESHOLD 10
+#define MATCH_LIMIT 1000
+
--- /dev/null
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+
+/* This is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language. See
+the file Tech.Notes for some information on the internals.
+
+Written by: Philip Hazel <ph10@cam.ac.uk>
+
+ Copyright (c) 1997-2003 University of Cambridge
+
+-----------------------------------------------------------------------------
+Permission is granted to anyone to use this software for any purpose on any
+computer system, and to redistribute it freely, subject to the following
+restrictions:
+
+1. This software 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.
+
+2. The origin of this software must not be misrepresented, either by
+ explicit claim or by omission.
+
+3. Altered versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+
+4. If PCRE is embedded in any software that is released under the GNU
+ General Purpose Licence (GPL), then the terms of that licence shall
+ supersede any condition above with which it is incompatible.
+-----------------------------------------------------------------------------
+*/
+
+/* This header contains definitions that are shared between the different
+modules, but which are not relevant to the outside. */
+
+/* Get the definitions provided by running "configure" */
+
+#include "pcre_config.h"
+
+/* Standard C headers plus the external interface definition. The only time
+setjmp and stdarg are used is when NO_RECURSE is set. */
+
+#include <ctype.h>
+#include <limits.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef PCRE_SPY
+#define PCRE_DEFINITION /* Win32 __declspec(export) trigger for .dll */
+#endif
+
+#include "pcre.h"
+
+/* When compiling for use with the Virtual Pascal compiler, these functions
+need to have their names changed. PCRE must be compiled with the -DVPCOMPAT
+option on the command line. */
+
+#ifdef VPCOMPAT
+#define strncmp(s1,s2,m) _strncmp(s1,s2,m)
+#define memcpy(d,s,n) _memcpy(d,s,n)
+#define memmove(d,s,n) _memmove(d,s,n)
+#define memset(s,c,n) _memset(s,c,n)
+#else /* VPCOMPAT */
+
+/* To cope with SunOS4 and other systems that lack memmove() but have bcopy(),
+define a macro for memmove() if HAVE_MEMMOVE is false, provided that HAVE_BCOPY
+is set. Otherwise, include an emulating function for those systems that have
+neither (there some non-Unix environments where this is the case). This assumes
+that all calls to memmove are moving strings upwards in store, which is the
+case in PCRE. */
+
+#if ! HAVE_MEMMOVE
+#undef memmove /* some systems may have a macro */
+#if HAVE_BCOPY
+#define memmove(a, b, c) bcopy(b, a, c)
+#else /* HAVE_BCOPY */
+void *
+pcre_memmove(unsigned char *dest, const unsigned char *src, size_t n)
+{
+int i;
+dest += n;
+src += n;
+for (i = 0; i < n; ++i) *(--dest) = *(--src);
+}
+#define memmove(a, b, c) pcre_memmove(a, b, c)
+#endif /* not HAVE_BCOPY */
+#endif /* not HAVE_MEMMOVE */
+#endif /* not VPCOMPAT */
+
+
+/* PCRE keeps offsets in its compiled code as 2-byte quantities by default.
+These are used, for example, to link from the start of a subpattern to its
+alternatives and its end. The use of 2 bytes per offset limits the size of the
+compiled regex to around 64K, which is big enough for almost everybody.
+However, I received a request for an even bigger limit. For this reason, and
+also to make the code easier to maintain, the storing and loading of offsets
+from the byte string is now handled by the macros that are defined here.
+
+The macros are controlled by the value of LINK_SIZE. This defaults to 2 in
+the config.h file, but can be overridden by using -D on the command line. This
+is automated on Unix systems via the "configure" command. */
+
+#if LINK_SIZE == 2
+
+#define PUT(a,n,d) \
+ (a[n] = (d) >> 8), \
+ (a[(n)+1] = (d) & 255)
+
+#define GET(a,n) \
+ (((a)[n] << 8) | (a)[(n)+1])
+
+#define MAX_PATTERN_SIZE (1 << 16)
+
+
+#elif LINK_SIZE == 3
+
+#define PUT(a,n,d) \
+ (a[n] = (d) >> 16), \
+ (a[(n)+1] = (d) >> 8), \
+ (a[(n)+2] = (d) & 255)
+
+#define GET(a,n) \
+ (((a)[n] << 16) | ((a)[(n)+1] << 8) | (a)[(n)+2])
+
+#define MAX_PATTERN_SIZE (1 << 24)
+
+
+#elif LINK_SIZE == 4
+
+#define PUT(a,n,d) \
+ (a[n] = (d) >> 24), \
+ (a[(n)+1] = (d) >> 16), \
+ (a[(n)+2] = (d) >> 8), \
+ (a[(n)+3] = (d) & 255)
+
+#define GET(a,n) \
+ (((a)[n] << 24) | ((a)[(n)+1] << 16) | ((a)[(n)+2] << 8) | (a)[(n)+3])
+
+#define MAX_PATTERN_SIZE (1 << 30) /* Keep it positive */
+
+
+#else
+#error LINK_SIZE must be either 2, 3, or 4
+#endif
+
+
+/* Convenience macro defined in terms of the others */
+
+#define PUTINC(a,n,d) PUT(a,n,d), a += LINK_SIZE
+
+
+/* PCRE uses some other 2-byte quantities that do not change when the size of
+offsets changes. There are used for repeat counts and for other things such as
+capturing parenthesis numbers in back references. */
+
+#define PUT2(a,n,d) \
+ a[n] = (d) >> 8; \
+ a[(n)+1] = (d) & 255
+
+#define GET2(a,n) \
+ (((a)[n] << 8) | (a)[(n)+1])
+
+#define PUT2INC(a,n,d) PUT2(a,n,d), a += 2
+
+
+/* In case there is no definition of offsetof() provided - though any proper
+Standard C system should have one. */
+
+#ifndef offsetof
+#define offsetof(p_type,field) ((size_t)&(((p_type *)0)->field))
+#endif
+
+/* These are the public options that can change during matching. */
+
+#define PCRE_IMS (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL)
+
+/* Private options flags start at the most significant end of the four bytes,
+but skip the top bit so we can use ints for convenience without getting tangled
+with negative values. The public options defined in pcre.h start at the least
+significant end. Make sure they don't overlap, though now that we have expanded
+to four bytes there is plenty of space. */
+
+#define PCRE_FIRSTSET 0x40000000 /* first_byte is set */
+#define PCRE_REQCHSET 0x20000000 /* req_byte is set */
+#define PCRE_STARTLINE 0x10000000 /* start after \n for multiline */
+#define PCRE_ICHANGED 0x08000000 /* i option changes within regex */
+
+/* Options for the "extra" block produced by pcre_study(). */
+
+#define PCRE_STUDY_MAPPED 0x01 /* a map of starting chars exists */
+
+/* Masks for identifying the public options which are permitted at compile
+time, run time or study time, respectively. */
+
+#define PUBLIC_OPTIONS \
+ (PCRE_CASELESS|PCRE_EXTENDED|PCRE_ANCHORED|PCRE_MULTILINE| \
+ PCRE_DOTALL|PCRE_DOLLAR_ENDONLY|PCRE_EXTRA|PCRE_UNGREEDY|PCRE_UTF8| \
+ PCRE_NO_AUTO_CAPTURE|PCRE_NO_UTF8_CHECK)
+
+#define PUBLIC_EXEC_OPTIONS \
+ (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|PCRE_NO_UTF8_CHECK)
+
+#define PUBLIC_STUDY_OPTIONS 0 /* None defined */
+
+/* Magic number to provide a small check against being handed junk. */
+
+#define MAGIC_NUMBER 0x50435245UL /* 'PCRE' */
+
+/* Negative values for the firstchar and reqchar variables */
+
+#define REQ_UNSET (-2)
+#define REQ_NONE (-1)
+
+/* Flags added to firstbyte or reqbyte; a "non-literal" item is either a
+variable-length repeat, or a anything other than literal characters. */
+
+#define REQ_CASELESS 0x0100 /* indicates caselessness */
+#define REQ_VARY 0x0200 /* reqbyte followed non-literal item */
+
+/* Miscellaneous definitions */
+
+typedef int BOOL;
+
+#define FALSE 0
+#define TRUE 1
+
+/* Escape items that are just an encoding of a particular data value. Note that
+ESC_n is defined as yet another macro, which is set in config.h to either \n
+(the default) or \r (which some people want). */
+
+#ifndef ESC_e
+#define ESC_e 27
+#endif
+
+#ifndef ESC_f
+#define ESC_f '\f'
+#endif
+
+#ifndef ESC_n
+#define ESC_n NEWLINE
+#endif
+
+#ifndef ESC_r
+#define ESC_r '\r'
+#endif
+
+/* We can't officially use ESC_t because it is a POSIX reserved identifier
+(presumably because of all the others like size_t). */
+
+#ifndef ESC_tee
+#define ESC_tee '\t'
+#endif
+
+/* These are escaped items that aren't just an encoding of a particular data
+value such as \n. They must have non-zero values, as check_escape() returns
+their negation. Also, they must appear in the same order as in the opcode
+definitions below, up to ESC_z. There's a dummy for OP_ANY because it
+corresponds to "." rather than an escape sequence. The final one must be
+ESC_REF as subsequent values are used for \1, \2, \3, etc. There is are two
+tests in the code for an escape greater than ESC_b and less than ESC_Z to
+detect the types that may be repeated. These are the types that consume a
+character. If any new escapes are put in between that don't consume a
+character, that code will have to change. */
+
+enum { ESC_A = 1, ESC_G, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W,
+ ESC_w, ESC_dum1, ESC_C, ESC_Z, ESC_z, ESC_E, ESC_Q, ESC_REF };
+
+/* Flag bits and data types for the extended class (OP_XCLASS) for classes that
+contain UTF-8 characters with values greater than 255. */
+
+#define XCL_NOT 0x01 /* Flag: this is a negative class */
+#define XCL_MAP 0x02 /* Flag: a 32-byte map is present */
+
+#define XCL_END 0 /* Marks end of individual items */
+#define XCL_SINGLE 1 /* Single item (one multibyte char) follows */
+#define XCL_RANGE 2 /* A range (two multibyte chars) follows */
+
+
+/* Opcode table: OP_BRA must be last, as all values >= it are used for brackets
+that extract substrings. Starting from 1 (i.e. after OP_END), the values up to
+OP_EOD must correspond in order to the list of escapes immediately above.
+Note that whenever this list is updated, the two macro definitions that follow
+must also be updated to match. */
+
+enum {
+ OP_END, /* 0 End of pattern */
+
+ /* Values corresponding to backslashed metacharacters */
+
+ OP_SOD, /* 1 Start of data: \A */
+ OP_SOM, /* 2 Start of match (subject + offset): \G */
+ OP_NOT_WORD_BOUNDARY, /* 3 \B */
+ OP_WORD_BOUNDARY, /* 4 \b */
+ OP_NOT_DIGIT, /* 5 \D */
+ OP_DIGIT, /* 6 \d */
+ OP_NOT_WHITESPACE, /* 7 \S */
+ OP_WHITESPACE, /* 8 \s */
+ OP_NOT_WORDCHAR, /* 9 \W */
+ OP_WORDCHAR, /* 10 \w */
+ OP_ANY, /* 11 Match any character */
+ OP_ANYBYTE, /* 12 Match any byte (\C); different to OP_ANY for UTF-8 */
+ OP_EODN, /* 13 End of data or \n at end of data: \Z. */
+ OP_EOD, /* 14 End of data: \z */
+
+ OP_OPT, /* 15 Set runtime options */
+ OP_CIRC, /* 16 Start of line - varies with multiline switch */
+ OP_DOLL, /* 17 End of line - varies with multiline switch */
+ OP_CHARS, /* 18 Match string of characters */
+ OP_NOT, /* 19 Match anything but the following char */
+
+ OP_STAR, /* 20 The maximizing and minimizing versions of */
+ OP_MINSTAR, /* 21 all these opcodes must come in pairs, with */
+ OP_PLUS, /* 22 the minimizing one second. */
+ OP_MINPLUS, /* 23 This first set applies to single characters */
+ OP_QUERY, /* 24 */
+ OP_MINQUERY, /* 25 */
+ OP_UPTO, /* 26 From 0 to n matches */
+ OP_MINUPTO, /* 27 */
+ OP_EXACT, /* 28 Exactly n matches */
+
+ OP_NOTSTAR, /* 29 The maximizing and minimizing versions of */
+ OP_NOTMINSTAR, /* 30 all these opcodes must come in pairs, with */
+ OP_NOTPLUS, /* 31 the minimizing one second. */
+ OP_NOTMINPLUS, /* 32 This set applies to "not" single characters */
+ OP_NOTQUERY, /* 33 */
+ OP_NOTMINQUERY, /* 34 */
+ OP_NOTUPTO, /* 35 From 0 to n matches */
+ OP_NOTMINUPTO, /* 36 */
+ OP_NOTEXACT, /* 37 Exactly n matches */
+
+ OP_TYPESTAR, /* 38 The maximizing and minimizing versions of */
+ OP_TYPEMINSTAR, /* 39 all these opcodes must come in pairs, with */
+ OP_TYPEPLUS, /* 40 the minimizing one second. These codes must */
+ OP_TYPEMINPLUS, /* 41 be in exactly the same order as those above. */
+ OP_TYPEQUERY, /* 42 This set applies to character types such as \d */
+ OP_TYPEMINQUERY, /* 43 */
+ OP_TYPEUPTO, /* 44 From 0 to n matches */
+ OP_TYPEMINUPTO, /* 45 */
+ OP_TYPEEXACT, /* 46 Exactly n matches */
+
+ OP_CRSTAR, /* 47 The maximizing and minimizing versions of */
+ OP_CRMINSTAR, /* 48 all these opcodes must come in pairs, with */
+ OP_CRPLUS, /* 49 the minimizing one second. These codes must */
+ OP_CRMINPLUS, /* 50 be in exactly the same order as those above. */
+ OP_CRQUERY, /* 51 These are for character classes and back refs */
+ OP_CRMINQUERY, /* 52 */
+ OP_CRRANGE, /* 53 These are different to the three seta above. */
+ OP_CRMINRANGE, /* 54 */
+
+ OP_CLASS, /* 55 Match a character class, chars < 256 only */
+ OP_NCLASS, /* 56 Same, but the bitmap was created from a negative
+ class - the difference is relevant only when a UTF-8
+ character > 255 is encountered. */
+
+ OP_XCLASS, /* 57 Extended class for handling UTF-8 chars within the
+ class. This does both positive and negative. */
+
+ OP_REF, /* 58 Match a back reference */
+ OP_RECURSE, /* 59 Match a numbered subpattern (possibly recursive) */
+ OP_CALLOUT, /* 60 Call out to external function if provided */
+
+ OP_ALT, /* 61 Start of alternation */
+ OP_KET, /* 62 End of group that doesn't have an unbounded repeat */
+ OP_KETRMAX, /* 63 These two must remain together and in this */
+ OP_KETRMIN, /* 64 order. They are for groups the repeat for ever. */
+
+ /* The assertions must come before ONCE and COND */
+
+ OP_ASSERT, /* 65 Positive lookahead */
+ OP_ASSERT_NOT, /* 66 Negative lookahead */
+ OP_ASSERTBACK, /* 67 Positive lookbehind */
+ OP_ASSERTBACK_NOT, /* 68 Negative lookbehind */
+ OP_REVERSE, /* 69 Move pointer back - used in lookbehind assertions */
+
+ /* ONCE and COND must come after the assertions, with ONCE first, as there's
+ a test for >= ONCE for a subpattern that isn't an assertion. */
+
+ OP_ONCE, /* 70 Once matched, don't back up into the subpattern */
+ OP_COND, /* 71 Conditional group */
+ OP_CREF, /* 72 Used to hold an extraction string number (cond ref) */
+
+ OP_BRAZERO, /* 73 These two must remain together and in this */
+ OP_BRAMINZERO, /* 74 order. */
+
+ OP_BRANUMBER, /* 75 Used for extracting brackets whose number is greater
+ than can fit into an opcode. */
+
+ OP_BRA /* 76 This and greater values are used for brackets that
+ extract substrings up to a basic limit. After that,
+ use is made of OP_BRANUMBER. */
+};
+
+/* WARNING: There is an implicit assumption in study.c that all opcodes are
+less than 128 in value. This makes handling UTF-8 character sequences easier.
+*/
+
+
+/* This macro defines textual names for all the opcodes. There are used only
+for debugging, in pcre.c when DEBUG is defined, and also in pcretest.c. The
+macro is referenced only in printint.c. */
+
+#define OP_NAME_LIST \
+ "End", "\\A", "\\G", "\\B", "\\b", "\\D", "\\d", \
+ "\\S", "\\s", "\\W", "\\w", "Any", "Anybyte", "\\Z", "\\z", \
+ "Opt", "^", "$", "chars", "not", \
+ "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \
+ "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \
+ "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \
+ "*", "*?", "+", "+?", "?", "??", "{", "{", \
+ "class", "nclass", "xclass", "Ref", "Recurse", "Callout", \
+ "Alt", "Ket", "KetRmax", "KetRmin", "Assert", "Assert not", \
+ "AssertB", "AssertB not", "Reverse", "Once", "Cond", "Cond ref",\
+ "Brazero", "Braminzero", "Branumber", "Bra"
+
+
+/* This macro defines the length of fixed length operations in the compiled
+regex. The lengths are used when searching for specific things, and also in the
+debugging printing of a compiled regex. We use a macro so that it can be
+incorporated both into pcre.c and pcretest.c without being publicly exposed.
+
+As things have been extended, some of these are no longer fixed lenths, but are
+minima instead. For example, the length of a single-character repeat may vary
+in UTF-8 mode. The code that uses this table must know about such things. */
+
+#define OP_LENGTHS \
+ 1, /* End */ \
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* \A, \G, \B, \B, \D, \d, \S, \s, \W, \w */ \
+ 1, 1, 1, 1, 2, 1, 1, /* Any, Anybyte, \Z, \z, Opt, ^, $ */ \
+ 2, /* Chars - the minimum length */ \
+ 2, /* not */ \
+ /* Positive single-char repeats ** These are */ \
+ 2, 2, 2, 2, 2, 2, /* *, *?, +, +?, ?, ?? ** minima in */ \
+ 4, 4, 4, /* upto, minupto, exact ** UTF-8 mode */ \
+ /* Negative single-char repeats - only for chars < 256 */ \
+ 2, 2, 2, 2, 2, 2, /* NOT *, *?, +, +?, ?, ?? */ \
+ 4, 4, 4, /* NOT upto, minupto, exact */ \
+ /* Positive type repeats */ \
+ 2, 2, 2, 2, 2, 2, /* Type *, *?, +, +?, ?, ?? */ \
+ 4, 4, 4, /* Type upto, minupto, exact */ \
+ /* Character class & ref repeats */ \
+ 1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */ \
+ 5, 5, /* CRRANGE, CRMINRANGE */ \
+ 33, /* CLASS */ \
+ 33, /* NCLASS */ \
+ 0, /* XCLASS - variable length */ \
+ 3, /* REF */ \
+ 1+LINK_SIZE, /* RECURSE */ \
+ 2, /* CALLOUT */ \
+ 1+LINK_SIZE, /* Alt */ \
+ 1+LINK_SIZE, /* Ket */ \
+ 1+LINK_SIZE, /* KetRmax */ \
+ 1+LINK_SIZE, /* KetRmin */ \
+ 1+LINK_SIZE, /* Assert */ \
+ 1+LINK_SIZE, /* Assert not */ \
+ 1+LINK_SIZE, /* Assert behind */ \
+ 1+LINK_SIZE, /* Assert behind not */ \
+ 1+LINK_SIZE, /* Reverse */ \
+ 1+LINK_SIZE, /* Once */ \
+ 1+LINK_SIZE, /* COND */ \
+ 3, /* CREF */ \
+ 1, 1, /* BRAZERO, BRAMINZERO */ \
+ 3, /* BRANUMBER */ \
+ 1+LINK_SIZE /* BRA */ \
+
+
+/* The highest extraction number before we have to start using additional
+bytes. (Originally PCRE didn't have support for extraction counts highter than
+this number.) The value is limited by the number of opcodes left after OP_BRA,
+i.e. 255 - OP_BRA. We actually set it a bit lower to leave room for additional
+opcodes. */
+
+#define EXTRACT_BASIC_MAX 150
+
+/* A magic value for OP_CREF to indicate the "in recursion" condition. */
+
+#define CREF_RECURSE 0xffff
+
+/* The texts of compile-time error messages are defined as macros here so that
+they can be accessed by the POSIX wrapper and converted into error codes. Yes,
+I could have used error codes in the first place, but didn't feel like changing
+just to accommodate the POSIX wrapper. */
+
+#define ERR1 "\\ at end of pattern"
+#define ERR2 "\\c at end of pattern"
+#define ERR3 "unrecognized character follows \\"
+#define ERR4 "numbers out of order in {} quantifier"
+#define ERR5 "number too big in {} quantifier"
+#define ERR6 "missing terminating ] for character class"
+#define ERR7 "invalid escape sequence in character class"
+#define ERR8 "range out of order in character class"
+#define ERR9 "nothing to repeat"
+#define ERR10 "operand of unlimited repeat could match the empty string"
+#define ERR11 "internal error: unexpected repeat"
+#define ERR12 "unrecognized character after (?"
+#define ERR13 "POSIX named classes are supported only within a class"
+#define ERR14 "missing )"
+#define ERR15 "reference to non-existent subpattern"
+#define ERR16 "erroffset passed as NULL"
+#define ERR17 "unknown option bit(s) set"
+#define ERR18 "missing ) after comment"
+#define ERR19 "parentheses nested too deeply"
+#define ERR20 "regular expression too large"
+#define ERR21 "failed to get memory"
+#define ERR22 "unmatched parentheses"
+#define ERR23 "internal error: code overflow"
+#define ERR24 "unrecognized character after (?<"
+#define ERR25 "lookbehind assertion is not fixed length"
+#define ERR26 "malformed number after (?("
+#define ERR27 "conditional group contains more than two branches"
+#define ERR28 "assertion expected after (?("
+#define ERR29 "(?R or (?digits must be followed by )"
+#define ERR30 "unknown POSIX class name"
+#define ERR31 "POSIX collating elements are not supported"
+#define ERR32 "this version of PCRE is not compiled with PCRE_UTF8 support"
+#define ERR33 "spare error"
+#define ERR34 "character value in \\x{...} sequence is too large"
+#define ERR35 "invalid condition (?(0)"
+#define ERR36 "\\C not allowed in lookbehind assertion"
+#define ERR37 "PCRE does not support \\L, \\l, \\N, \\P, \\p, \\U, \\u, or \\X"
+#define ERR38 "number after (?C is > 255"
+#define ERR39 "closing ) for (?C expected"
+#define ERR40 "recursive call could loop indefinitely"
+#define ERR41 "unrecognized character after (?P"
+#define ERR42 "syntax error after (?P"
+#define ERR43 "two named groups have the same name"
+#define ERR44 "invalid UTF-8 string"
+
+/* All character handling must be done as unsigned characters. Otherwise there
+are problems with top-bit-set characters and functions such as isspace().
+However, we leave the interface to the outside world as char *, because that
+should make things easier for callers. We define a short type for unsigned char
+to save lots of typing. I tried "uchar", but it causes problems on Digital
+Unix, where it is defined in sys/types, so use "uschar" instead. */
+
+typedef unsigned char uschar;
+
+/* The real format of the start of the pcre block; the index of names and the
+code vector run on as long as necessary after the end. */
+
+typedef struct real_pcre {
+ unsigned long int magic_number;
+ size_t size; /* Total that was malloced */
+ const unsigned char *tables; /* Pointer to tables */
+ unsigned long int options;
+ unsigned short int top_bracket;
+ unsigned short int top_backref;
+ unsigned short int first_byte;
+ unsigned short int req_byte;
+ unsigned short int name_entry_size; /* Size of any name items; 0 => none */
+ unsigned short int name_count; /* Number of name items */
+} real_pcre;
+
+/* The format of the block used to store data from pcre_study(). */
+
+typedef struct pcre_study_data {
+ size_t size; /* Total that was malloced */
+ uschar options;
+ uschar start_bits[32];
+} pcre_study_data;
+
+/* Structure for passing "static" information around between the functions
+doing the compiling, so that they are thread-safe. */
+
+typedef struct compile_data {
+ const uschar *lcc; /* Points to lower casing table */
+ const uschar *fcc; /* Points to case-flipping table */
+ const uschar *cbits; /* Points to character type table */
+ const uschar *ctypes; /* Points to table of type maps */
+ const uschar *start_code; /* The start of the compiled code */
+ uschar *name_table; /* The name/number table */
+ int names_found; /* Number of entries so far */
+ int name_entry_size; /* Size of each entry */
+ int top_backref; /* Maximum back reference */
+ unsigned int backref_map; /* Bitmap of low back refs */
+ int req_varyopt; /* "After variable item" flag for reqbyte */
+} compile_data;
+
+/* Structure for maintaining a chain of pointers to the currently incomplete
+branches, for testing for left recursion. */
+
+typedef struct branch_chain {
+ struct branch_chain *outer;
+ uschar *current;
+} branch_chain;
+
+/* Structure for items in a linked list that represents an explicit recursive
+call within the pattern. */
+
+typedef struct recursion_info {
+ struct recursion_info *prevrec; /* Previous recursion record (or NULL) */
+ int group_num; /* Number of group that was called */
+ const uschar *after_call; /* "Return value": points after the call in the expr */
+ const uschar *save_start; /* Old value of md->start_match */
+ int *offset_save; /* Pointer to start of saved offsets */
+ int saved_max; /* Number of saved offsets */
+} recursion_info;
+
+/* When compiling in a mode that doesn't use recursive calls to match(),
+a structure is used to remember local variables on the heap. It is defined in
+pcre.c, close to the match() function, so that it is easy to keep it in step
+with any changes of local variable. However, the pointer to the current frame
+must be saved in some "static" place over a longjmp(). We declare the
+structure here so that we can put a pointer in the match_data structure.
+NOTE: This isn't used for a "normal" compilation of pcre. */
+
+struct heapframe;
+
+/* Structure for passing "static" information around between the functions
+doing the matching, so that they are thread-safe. */
+
+typedef struct match_data {
+ unsigned long int match_call_count; /* As it says */
+ unsigned long int match_limit;/* As it says */
+ int *offset_vector; /* Offset vector */
+ int offset_end; /* One past the end */
+ int offset_max; /* The maximum usable for return data */
+ const uschar *lcc; /* Points to lower casing table */
+ const uschar *ctypes; /* Points to table of type maps */
+ BOOL offset_overflow; /* Set if too many extractions */
+ BOOL notbol; /* NOTBOL flag */
+ BOOL noteol; /* NOTEOL flag */
+ BOOL utf8; /* UTF8 flag */
+ BOOL endonly; /* Dollar not before final \n */
+ BOOL notempty; /* Empty string match not wanted */
+ const uschar *start_code; /* For use when recursing */
+ const uschar *start_subject; /* Start of the subject string */
+ const uschar *end_subject; /* End of the subject string */
+ const uschar *start_match; /* Start of this match attempt */
+ const uschar *end_match_ptr; /* Subject position at end match */
+ int end_offset_top; /* Highwater mark at end of match */
+ int capture_last; /* Most recent capture number */
+ int start_offset; /* The start offset value */
+ recursion_info *recursive; /* Linked list of recursion data */
+ void *callout_data; /* To pass back to callouts */
+ struct heapframe *thisframe; /* Used only when compiling for no recursion */
+} match_data;
+
+/* Bit definitions for entries in the pcre_ctypes table. */
+
+#define ctype_space 0x01
+#define ctype_letter 0x02
+#define ctype_digit 0x04
+#define ctype_xdigit 0x08
+#define ctype_word 0x10 /* alphameric or '_' */
+#define ctype_meta 0x80 /* regexp meta char or zero (end pattern) */
+
+/* Offsets for the bitmap tables in pcre_cbits. Each table contains a set
+of bits for a class map. Some classes are built by combining these tables. */
+
+#define cbit_space 0 /* [:space:] or \s */
+#define cbit_xdigit 32 /* [:xdigit:] */
+#define cbit_digit 64 /* [:digit:] or \d */
+#define cbit_upper 96 /* [:upper:] */
+#define cbit_lower 128 /* [:lower:] */
+#define cbit_word 160 /* [:word:] or \w */
+#define cbit_graph 192 /* [:graph:] */
+#define cbit_print 224 /* [:print:] */
+#define cbit_punct 256 /* [:punct:] */
+#define cbit_cntrl 288 /* [:cntrl:] */
+#define cbit_length 320 /* Length of the cbits table */
+
+/* Offsets of the various tables from the base tables pointer, and
+total length. */
+
+#define lcc_offset 0
+#define fcc_offset 256
+#define cbits_offset 512
+#define ctypes_offset (cbits_offset + cbit_length)
+#define tables_length (ctypes_offset + 256)
+
+/* End of internal.h */
--- /dev/null
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ * $FreeBSD: src/sys/sys/queue.h,v 1.40 2000/08/03 17:31:56 hsu Exp $
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define _SYS_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * singly-linked tail queues, lists, tail queues, and circular queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction. Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A singly-linked tail queue is headed by a pair of pointers, one to the
+ * head of the list and the other to the tail of the list. The elements are
+ * singly linked for minimum space and pointer manipulation overhead at the
+ * expense of O(n) removal for arbitrary elements. New elements can be added
+ * to the list after an existing element, at the head of the list, or at the
+ * end of the list. Elements being removed from the head of the tail queue
+ * should use the explicit macro for this purpose for optimum efficiency.
+ * A singly-linked tail queue may only be traversed in the forward direction.
+ * Singly-linked tail queues are ideal for applications with large datasets
+ * and few or no removals or for implementing a FIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ *
+ *
+ * SLIST LIST STAILQ TAILQ CIRCLEQ
+ * _HEAD + + + + +
+ * _HEAD_INITIALIZER + + + + +
+ * _ENTRY + + + + +
+ * _INIT + + + + +
+ * _EMPTY + + + + +
+ * _FIRST + + + + +
+ * _NEXT + + + + +
+ * _PREV - - - + +
+ * _LAST - - + + +
+ * _FOREACH + + + + +
+ * _FOREACH_REVERSE - - - + +
+ * _INSERT_HEAD + + + + +
+ * _INSERT_BEFORE - + - + +
+ * _INSERT_AFTER + + + + +
+ * _INSERT_TAIL - - + + +
+ * _REMOVE_HEAD + - + - -
+ * _REMOVE + + + + +
+ *
+ */
+
+/*
+ * Singly-linked List declarations.
+ */
+#define SLIST_HEAD(name, type) \
+struct name { \
+ struct type *slh_first; /* first element */ \
+}
+
+#define SLIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define SLIST_ENTRY(type) \
+struct { \
+ struct type *sle_next; /* next element */ \
+}
+
+/*
+ * Singly-linked List functions.
+ */
+#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
+
+#define SLIST_FIRST(head) ((head)->slh_first)
+
+#define SLIST_FOREACH(var, head, field) \
+ for ((var) = SLIST_FIRST((head)); \
+ (var); \
+ (var) = SLIST_NEXT((var), field))
+
+#define SLIST_INIT(head) do { \
+ SLIST_FIRST((head)) = NULL; \
+} while (0)
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
+ SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
+ SLIST_NEXT((slistelm), field) = (elm); \
+} while (0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) do { \
+ SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
+ SLIST_FIRST((head)) = (elm); \
+} while (0)
+
+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define SLIST_REMOVE(head, elm, type, field) do { \
+ if (SLIST_FIRST((head)) == (elm)) { \
+ SLIST_REMOVE_HEAD((head), field); \
+ } \
+ else { \
+ struct type *curelm = SLIST_FIRST((head)); \
+ while (SLIST_NEXT(curelm, field) != (elm)) \
+ curelm = SLIST_NEXT(curelm, field); \
+ SLIST_NEXT(curelm, field) = \
+ SLIST_NEXT(SLIST_NEXT(curelm, field), field); \
+ } \
+} while (0)
+
+#define SLIST_REMOVE_HEAD(head, field) do { \
+ SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
+} while (0)
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define STAILQ_HEAD(name, type) \
+struct name { \
+ struct type *stqh_first;/* first element */ \
+ struct type **stqh_last;/* addr of last next element */ \
+}
+
+#define STAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).stqh_first }
+
+#define STAILQ_ENTRY(type) \
+struct { \
+ struct type *stqe_next; /* next element */ \
+}
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
+
+#define STAILQ_FIRST(head) ((head)->stqh_first)
+
+#define STAILQ_FOREACH(var, head, field) \
+ for((var) = STAILQ_FIRST((head)); \
+ (var); \
+ (var) = STAILQ_NEXT((var), field))
+
+#define STAILQ_INIT(head) do { \
+ STAILQ_FIRST((head)) = NULL; \
+ (head)->stqh_last = &STAILQ_FIRST((head)); \
+} while (0)
+
+#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \
+ if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+ STAILQ_NEXT((tqelm), field) = (elm); \
+} while (0)
+
+#define STAILQ_INSERT_HEAD(head, elm, field) do { \
+ if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+ STAILQ_FIRST((head)) = (elm); \
+} while (0)
+
+#define STAILQ_INSERT_TAIL(head, elm, field) do { \
+ STAILQ_NEXT((elm), field) = NULL; \
+ *(head)->stqh_last = (elm); \
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+} while (0)
+
+#define STAILQ_LAST(head, type, field) \
+ (STAILQ_EMPTY(head) ? \
+ NULL : \
+ strbase(type, (head)->stqh_last, field))
+
+#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
+
+#define STAILQ_REMOVE(head, elm, type, field) do { \
+ if (STAILQ_FIRST((head)) == (elm)) { \
+ STAILQ_REMOVE_HEAD(head, field); \
+ } \
+ else { \
+ struct type *curelm = STAILQ_FIRST((head)); \
+ while (STAILQ_NEXT(curelm, field) != (elm)) \
+ curelm = STAILQ_NEXT(curelm, field); \
+ if ((STAILQ_NEXT(curelm, field) = \
+ STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\
+ (head)->stqh_last = &STAILQ_NEXT((curelm), field);\
+ } \
+} while (0)
+
+#define STAILQ_REMOVE_HEAD(head, field) do { \
+ if ((STAILQ_FIRST((head)) = \
+ STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
+ (head)->stqh_last = &STAILQ_FIRST((head)); \
+} while (0)
+
+#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \
+ if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \
+ (head)->stqh_last = &STAILQ_FIRST((head)); \
+} while (0)
+
+/*
+ * List declarations.
+ */
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List functions.
+ */
+
+#define LIST_EMPTY(head) ((head)->lh_first == NULL)
+
+#define LIST_FIRST(head) ((head)->lh_first)
+
+#define LIST_FOREACH(var, head, field) \
+ for ((var) = LIST_FIRST((head)); \
+ (var); \
+ (var) = LIST_NEXT((var), field))
+
+#define LIST_INIT(head) do { \
+ LIST_FIRST((head)) = NULL; \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
+ if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
+ LIST_NEXT((listelm), field)->field.le_prev = \
+ &LIST_NEXT((elm), field); \
+ LIST_NEXT((listelm), field) = (elm); \
+ (elm)->field.le_prev = &LIST_NEXT((listelm), field); \
+} while (0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ LIST_NEXT((elm), field) = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &LIST_NEXT((elm), field); \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do { \
+ if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
+ LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
+ LIST_FIRST((head)) = (elm); \
+ (elm)->field.le_prev = &LIST_FIRST((head)); \
+} while (0)
+
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+#define LIST_REMOVE(elm, field) do { \
+ if (LIST_NEXT((elm), field) != NULL) \
+ LIST_NEXT((elm), field)->field.le_prev = \
+ (elm)->field.le_prev; \
+ *(elm)->field.le_prev = LIST_NEXT((elm), field); \
+} while (0)
+
+/*
+ * Tail queue declarations.
+ */
+#define TAILQ_HEAD(name, type) \
+struct name { \
+ struct type *tqh_first; /* first element */ \
+ struct type **tqh_last; /* addr of last next element */ \
+}
+
+#define TAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+}
+
+/*
+ * Tail queue functions.
+ */
+#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
+
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+
+#define TAILQ_FOREACH(var, head, field) \
+ for ((var) = TAILQ_FIRST((head)); \
+ (var); \
+ (var) = TAILQ_NEXT((var), field))
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
+ for ((var) = TAILQ_LAST((head), headname); \
+ (var); \
+ (var) = TAILQ_PREV((var), headname, field))
+
+#define TAILQ_INIT(head) do { \
+ TAILQ_FIRST((head)) = NULL; \
+ (head)->tqh_last = &TAILQ_FIRST((head)); \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
+ TAILQ_NEXT((elm), field)->field.tqe_prev = \
+ &TAILQ_NEXT((elm), field); \
+ else \
+ (head)->tqh_last = &TAILQ_NEXT((elm), field); \
+ TAILQ_NEXT((listelm), field) = (elm); \
+ (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
+} while (0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ TAILQ_NEXT((elm), field) = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
+ if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
+ TAILQ_FIRST((head))->field.tqe_prev = \
+ &TAILQ_NEXT((elm), field); \
+ else \
+ (head)->tqh_last = &TAILQ_NEXT((elm), field); \
+ TAILQ_FIRST((head)) = (elm); \
+ (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
+ TAILQ_NEXT((elm), field) = NULL; \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &TAILQ_NEXT((elm), field); \
+} while (0)
+
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+#define TAILQ_REMOVE(head, elm, field) do { \
+ if ((TAILQ_NEXT((elm), field)) != NULL) \
+ TAILQ_NEXT((elm), field)->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
+} while (0)
+
+/*
+ * Circular queue declarations.
+ */
+#define CIRCLEQ_HEAD(name, type) \
+struct name { \
+ struct type *cqh_first; /* first element */ \
+ struct type *cqh_last; /* last element */ \
+}
+
+#define CIRCLEQ_HEAD_INITIALIZER(head) \
+ { (void *)&(head), (void *)&(head) }
+
+#define CIRCLEQ_ENTRY(type) \
+struct { \
+ struct type *cqe_next; /* next element */ \
+ struct type *cqe_prev; /* previous element */ \
+}
+
+/*
+ * Circular queue functions.
+ */
+#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head))
+
+#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
+
+#define CIRCLEQ_FOREACH(var, head, field) \
+ for ((var) = CIRCLEQ_FIRST((head)); \
+ (var) != (void *)(head); \
+ (var) = CIRCLEQ_NEXT((var), field))
+
+#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
+ for ((var) = CIRCLEQ_LAST((head)); \
+ (var) != (void *)(head); \
+ (var) = CIRCLEQ_PREV((var), field))
+
+#define CIRCLEQ_INIT(head) do { \
+ CIRCLEQ_FIRST((head)) = (void *)(head); \
+ CIRCLEQ_LAST((head)) = (void *)(head); \
+} while (0)
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ CIRCLEQ_NEXT((elm), field) = CIRCLEQ_NEXT((listelm), field); \
+ CIRCLEQ_PREV((elm), field) = (listelm); \
+ if (CIRCLEQ_NEXT((listelm), field) == (void *)(head)) \
+ CIRCLEQ_LAST((head)) = (elm); \
+ else \
+ CIRCLEQ_PREV(CIRCLEQ_NEXT((listelm), field), field) = (elm);\
+ CIRCLEQ_NEXT((listelm), field) = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
+ CIRCLEQ_NEXT((elm), field) = (listelm); \
+ CIRCLEQ_PREV((elm), field) = CIRCLEQ_PREV((listelm), field); \
+ if (CIRCLEQ_PREV((listelm), field) == (void *)(head)) \
+ CIRCLEQ_FIRST((head)) = (elm); \
+ else \
+ CIRCLEQ_NEXT(CIRCLEQ_PREV((listelm), field), field) = (elm);\
+ CIRCLEQ_PREV((listelm), field) = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
+ CIRCLEQ_NEXT((elm), field) = CIRCLEQ_FIRST((head)); \
+ CIRCLEQ_PREV((elm), field) = (void *)(head); \
+ if (CIRCLEQ_LAST((head)) == (void *)(head)) \
+ CIRCLEQ_LAST((head)) = (elm); \
+ else \
+ CIRCLEQ_PREV(CIRCLEQ_FIRST((head)), field) = (elm); \
+ CIRCLEQ_FIRST((head)) = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
+ CIRCLEQ_NEXT((elm), field) = (void *)(head); \
+ CIRCLEQ_PREV((elm), field) = CIRCLEQ_LAST((head)); \
+ if (CIRCLEQ_FIRST((head)) == (void *)(head)) \
+ CIRCLEQ_FIRST((head)) = (elm); \
+ else \
+ CIRCLEQ_NEXT(CIRCLEQ_LAST((head)), field) = (elm); \
+ CIRCLEQ_LAST((head)) = (elm); \
+} while (0)
+
+#define CIRCLEQ_LAST(head) ((head)->cqh_last)
+
+#define CIRCLEQ_NEXT(elm,field) ((elm)->field.cqe_next)
+
+#define CIRCLEQ_PREV(elm,field) ((elm)->field.cqe_prev)
+
+#define CIRCLEQ_REMOVE(head, elm, field) do { \
+ if (CIRCLEQ_NEXT((elm), field) == (void *)(head)) \
+ CIRCLEQ_LAST((head)) = CIRCLEQ_PREV((elm), field); \
+ else \
+ CIRCLEQ_PREV(CIRCLEQ_NEXT((elm), field), field) = \
+ CIRCLEQ_PREV((elm), field); \
+ if (CIRCLEQ_PREV((elm), field) == (void *)(head)) \
+ CIRCLEQ_FIRST((head)) = CIRCLEQ_NEXT((elm), field); \
+ else \
+ CIRCLEQ_NEXT(CIRCLEQ_PREV((elm), field), field) = \
+ CIRCLEQ_NEXT((elm), field); \
+} while (0)
+
+#endif /* !_SYS_QUEUE_H */
+/* vi:set ts=8 sts=4 sw=4 tw=79: */
--- /dev/null
+/*
+ * irc2.7.2/ircd/res.h (C)opyright 1992 Darren Reed.
+ */
+
+/* $Id: res.h,v 1.1 2005/01/12 07:44:58 mmondor Exp $ */
+
+#ifndef __res_include__
+#define __res_include__
+
+#define RES_INITLIST 1
+#define RES_CALLINIT 2
+#define RES_INITSOCK 4
+#define RES_INITDEBG 8
+#define RES_INITCACH 16
+
+#define MAXPACKET 1024
+#define IRC_MAXALIASES 10
+#define IRC_MAXADDRS 10
+
+#define AR_TTL 600 /* TTL in seconds for dns cache entries */
+
+struct hent
+{
+ char *h_name; /* official name of host */
+ char *h_aliases[IRC_MAXALIASES]; /* alias list */
+ int h_addrtype; /* host address type */
+ int h_length; /* length of address */
+
+ /* list of addresses from name server */
+ struct in_addr h_addr_list[IRC_MAXADDRS];
+
+#define h_addr h_addr_list[0] /* address, for backward compatiblity */
+};
+
+typedef struct reslist
+{
+ int id;
+ int sent; /* number of requests sent */
+ int srch;
+ time_t ttl;
+ char type;
+ char retries; /* retry counter */
+ char sends; /* number of sends (>1 means resent) */
+ char resend; /* send flag. 0 == dont resend */
+ time_t sentat;
+ time_t timeout;
+ struct in_addr addr;
+ char *name;
+ Link cinfo;
+ struct hent he;
+ int has_rev; /* is he_rev valid? */
+ struct hent he_rev;
+
+ struct reslist *next;
+ struct reslist *id_hashnext;
+ struct reslist *cp_hashnext;
+} ResRQ;
+
+typedef struct cache
+{
+ time_t expireat;
+ time_t ttl;
+ struct hostent he;
+ struct cache *hname_next, *hnum_next, *list_next;
+} aCache;
+
+typedef struct cachetable
+{
+ aCache *num_list;
+ aCache *name_list;
+} CacheTable;
+
+typedef struct reshash
+{
+ ResRQ *id_list;
+ ResRQ *cp_list;
+} ResHash;
+
+#define ARES_CACSIZE 307
+#define ARES_IDCACSIZE 2099
+
+#define IRC_MAXCACHED 281
+
+#endif /* __res_include__ */
--- /dev/null
+#ifndef LOCAL_RESOLV_H
+#define LOCAL_RESOLV_H 1
+
+/*
+ * Copyright (c) 1983, 1987, 1989 The Regents of the University of
+ * California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement: ``This product includes software
+ * developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with
+ * the distribution and in all advertising materials mentioning
+ * features or use of this software. Neither the name of the University
+ * 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 ``AS IS'' AND WITHOUT ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ *
+ * @(#)resolv.h 5.10.1 (Berkeley) 6/1/90
+ */
+/*
+ * Resolver configuration file. Normally not present, but may contain
+ * the address of the inital name server(s) to query and the domain
+ * search list.
+ */
+
+/* $Id: resolv.h,v 1.1 2005/01/12 07:44:58 mmondor Exp $ */
+
+#ifndef _PATH_RESCONF
+#define _PATH_RESCONF "/etc/resolv.conf"
+#endif
+/* Global defines and variables for resolver stub. */
+#define MAXNS 3 /* max # name servers we'll track */
+#define MAXDFLSRCH 3 /* # default domain levels to try */
+#define MAXDNSRCH 6 /* max # domains in search path */
+#define LOCALDOMAINPARTS 2 /* min levels in name that is "local" */
+#define MAXSERVICES 2 /* max # of services to search */
+
+#define RES_TIMEOUT 5 /* min. seconds between retries */
+
+#define RES_SERVICE_NONE 0
+#define RES_SERVICE_BIND 1
+#define RES_SERVICE_LOCAL 2
+/* Resolver options */
+#define RES_INIT 0x0001 /* address initialized */
+#define RES_DEBUG 0x0002 /* print debug messages */
+#define RES_AAONLY 0x0004 /* authoritative answers only */
+#define RES_USEVC 0x0008 /* use virtual circuit */
+#define RES_PRIMARY 0x0010 /* query primary server only */
+#define RES_IGNTC 0x0020 /* ignore trucation errors */
+#define RES_RECURSE 0x0040 /* recursion desired */
+#define RES_DEFNAMES 0x0080 /* use default domain name */
+#define RES_STAYOPEN 0x0100 /* Keep TCP socket open */
+#define RES_DNSRCH 0x0200 /* search up local domain tree */
+
+#define RES_DEFAULT (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH)
+
+#if ((__GNU_LIBRARY__ == 6) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 3))
+# define MAXRESOLVSORT 10 /* number of net to sort on */
+
+struct __res_state {
+ int retrans; /* retransmition time interval */
+ int retry; /* number of times to retransmit */
+ u_long options; /* option flags - see below. */
+ int nscount; /* number of name servers */
+ struct sockaddr_in
+ nsaddr_list[MAXNS]; /* address of name server */
+# define nsaddr nsaddr_list[0] /* for backward compatibility */
+ u_short id; /* current message id */
+ char *dnsrch[MAXDNSRCH+1]; /* components of domain to search */
+ char defdname[256]; /* default domain (deprecated) */
+ u_long pfcode; /* RES_PRF_ flags - see below. */
+ unsigned ndots:4; /* threshold for initial abs. query */
+ unsigned nsort:4; /* number of elements in sort_list[] */
+ char unused[3];
+ struct {
+ struct in_addr addr;
+ u_int32_t mask;
+ } sort_list[MAXRESOLVSORT];
+};
+
+typedef struct __res_state *res_state;
+
+extern struct __res_state *__res_state(void) __attribute__ ((__const__));
+#define _res (*__res_state())
+
+#else
+
+struct state {
+ int retrans; /* retransmition time interval */
+ int retry; /* number of times to retransmit */
+ long options; /* option flags - see below. */
+ int nscount; /* number of name servers */
+ struct sockaddr_in nsaddr_list[MAXNS]; /* address of name server */
+#define nsaddr nsaddr_list[0] /* for backward compatibility */
+ unsigned short id; /* current packet id */
+ char defdname[MAXDNAME]; /* default domain */
+ char *dnsrch[MAXDNSRCH + 1]; /* components of domain to search */
+ unsigned short order[MAXSERVICES + 1]; /* search service order */
+};
+
+extern struct state _res;
+#endif
+
+extern char *p_cdname(), *p_rr(), *p_type(), *p_class(), *p_time();
+
+#if ((__GNU_LIBRARY__ == 6) && (__GLIBC__ >=2) && (__GLIBC_MINOR__ >= 2))
+#define res_init __res_init
+#define res_mkquery __res_mkquery
+#define dn_expand __dn_expand
+#endif
+
+extern int res_mkquery ();
+extern int dn_expand ();
+extern int res_init();
+#endif
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, include/sbuf.h
+ * Copyright (C) 2004 David Parton
+ *
+ * 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 1, 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.
+ */
+/* $Id: sbuf.h,v 1.1 2005/01/12 07:44:58 mmondor Exp $ */
+
+#ifndef SBUF_H
+#define SBUF_H
+
+/* Definitions */
+#define SBUF_LARGE_BUFFER 512
+#define SBUF_SMALL_BUFFER 256
+
+/* Macros */
+#define IsEol(c) ((c) == '\r' || (c) == '\n')
+#define SBufLength(s) ((s)->length)
+#define SBufClear(s) sbuf_delete((s), (s)->length)
+
+/* forward declaration */
+struct _SBufUser;
+struct _SBuf;
+
+
+typedef struct _SBuf
+{
+ int length;
+ struct _SBufUser *head, *tail;
+} SBuf;
+
+/* function protoypes */
+
+extern int sbuf_init();
+extern int sbuf_begin_share(const char* theData, int theLength, void** thePtr);
+extern int sbuf_end_share(void** thePtr, int theNum);
+extern int sbuf_put_share(SBuf* theBuf, void *theSBuffer);
+extern int sbuf_put(SBuf* theBuf, const char* theData, int theLength);
+extern int sbuf_delete(SBuf* theBuf, int theLength);
+extern char* sbuf_map(SBuf* theBuf, int* theLength);
+extern int sbuf_flush(SBuf* theBuf);
+extern int sbuf_getmsg(SBuf* theBuf, char* theData, int theLength);
+extern int sbuf_get(SBuf* theBuf, char* theData, int theLength);
+extern void sbuf_count(int* userUsed, int* userTotal, int* userSize,
+ int* smallUsed, int* smallTotal, int* smallSize,
+ int* largeUsed, int* largeTotal, int* largeSize,
+ int* blockUsed, int* blockSize, int* userblockUsed, int* userblockSize);
+
+#ifdef WRITEV_IOV
+extern int sbuf_mapiov(SBuf *, struct iovec *);
+#endif
+
+#endif /* #ifndef SBUF_H */
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, include/h.h
+ * Copyright (C) 1992 Darren Reed
+ *
+ * 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 1, 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.
+ */
+/*
+ * "send.h". - Headers file.
+ *
+ * all the send* functions are declared here.
+ */
+
+/* $Id: send.h,v 1.1 2005/01/12 07:44:58 mmondor Exp $ */
+
+#ifndef SEND_H
+#define SEND_H
+
+/* send all queued crap to aClient */
+extern int send_queued(aClient *);
+
+#include <stdarg.h>
+#include "fdlist.h"
+
+extern void init_send();
+
+extern void send_chatops(char *pattern, ...);
+extern void send_globops(char *pattern, ...);
+extern void send_operwall(aClient *, char *, char *);
+
+extern void sendto_all_butone(aClient *one, aClient *from, char *pattern, ...);
+extern void sendto_channel_butone(aClient *one, aClient *from,
+ aChannel *chptr, char *pattern, ...);
+extern void sendto_channel_remote_butone(aClient *one, aClient *from,
+ aChannel *chptr, char *pattern, ...);
+extern void sendto_channel_butserv(aChannel *chptr, aClient *from,
+ char *pattern, ...);
+extern void sendto_channel_butserv_me(aChannel *chptr, aClient *from,
+ char *pattern, ...);
+extern void sendto_channelops_butserv(aChannel *chptr, aClient *from,
+ char *pattern, ...);
+extern void sendto_channelops_butone(aClient *one, aClient *from,
+ aChannel *chptr,char *pattern, ...);
+extern void sendto_channelvoice_butone(aClient *one, aClient *from,
+ aChannel *chptr, char *pattern, ...);
+extern void sendto_channelvoiceops_butone(aClient *one, aClient *from,
+ aChannel *chptr, char *patern, ...);
+extern void sendto_common_channels(aClient *user, char *pattern, ...);
+extern void send_quit_to_common_channels(aClient *from, char *reason);
+extern void send_part_to_common_channels(aClient *from, char *reason);
+extern void sendto_fdlist(fdlist *listp, char *pattern, ...);
+extern void sendto_locops(char *pattern, ...);
+extern void sendto_match_butone(aClient *one, aClient *from, char *mask,
+ int what, char *pattern, ...);
+extern void sendto_one(aClient *to, char *pattern, ...);
+extern void sendto_one_services(aClient *to, char *pattern, ...);
+extern void sendto_ops(char *pattern, ...);
+extern void sendto_ops_butone(aClient *one, aClient *from, char *pattern, ...);
+extern void sendto_ops_lev(int lev, char *pattern, ...);
+extern void sendto_prefix_one(aClient *to, aClient *from, char *pattern, ...);
+
+extern void sendto_realops_lev(int lev, char *pattern, ...);
+extern void sendto_realops(char *pattern, ...);
+extern void sendto_serv_butone(aClient *one, char *pattern, ...);
+extern void sendto_serv_butone_services(aClient *one, char *pattern, ...);
+extern void sendto_wallops_butone(aClient *one, aClient *from,
+ char *pattern, ...);
+extern void sendto_gnotice(char *pattern, ...);
+
+extern void ts_warn(char *pattern, ...);
+
+extern void vsendto_fdlist(fdlist *listp, char *pattern, va_list vl);
+extern void vsendto_one(aClient *to, char *pattern, va_list vl);
+extern void vsendto_prefix_one(aClient *to, aClient *from,
+ char *pattern, va_list vl);
+extern void vsendto_realops(char *pattern, va_list vl);
+
+extern void flush_connections();
+extern void dump_connections();
+#endif
--- /dev/null
+/* include/setup.h.in. Generated from configure.in by autoheader. */
+
+/* AIX support */
+#undef AIX
+
+/* If on a system with a broken FD_SETSIZE */
+#undef BROKEN_FD_SETSIZE
+
+/* Define to 1 if you have the `alarm' function. */
+#undef HAVE_ALARM
+
+/* Define to 1 if you have the `bcmp' function. */
+#undef HAVE_BCMP
+
+/* Define to 1 if you have the `bcopy' function. */
+#undef HAVE_BCOPY
+
+/* Define to 1 if you have the `break' function. */
+#undef HAVE_BREAK
+
+/* Define to 1 if you have the `bzero' function. */
+#undef HAVE_BZERO
+
+/* Define to 1 if you have the `dlopen' function. */
+#undef HAVE_DLOPEN
+
+/* Define to 1 if you have the `dlsym' function. */
+#undef HAVE_DLSYM
+
+/* Define to 1 if you have the `dn_skipname' function. */
+#undef HAVE_DN_SKIPNAME
+
+/* Define to 1 if you have the `dup2' function. */
+#undef HAVE_DUP2
+
+/* If we support encryption */
+#undef HAVE_ENCRYPTION_ON
+
+/* Define to 1 if you have the <errno.h> header file. */
+#undef HAVE_ERRNO_H
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the `gethostbyname' function. */
+#undef HAVE_GETHOSTBYNAME
+
+/* Define to 1 if you have the `gethostname' function. */
+#undef HAVE_GETHOSTNAME
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#undef HAVE_GETOPT_H
+
+/* Define to 1 if you have the `getpass' function. */
+#undef HAVE_GETPASS
+
+/* Define to 1 if you have the `getrusage' function. */
+#undef HAVE_GETRUSAGE
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the `index' function. */
+#undef HAVE_INDEX
+
+/* Define to 1 if you have the `inet_addr' function. */
+#undef HAVE_INET_ADDR
+
+/* Define to 1 if you have the `inet_aton' function. */
+#undef HAVE_INET_ATON
+
+/* Define to 1 if you have the `inet_netof' function. */
+#undef HAVE_INET_NETOF
+
+/* Define to 1 if you have the `inet_ntoa' function. */
+#undef HAVE_INET_NTOA
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `isascii' function. */
+#undef HAVE_ISASCII
+
+/* Define to 1 if you have the `crypt' library (-lcrypt). */
+#undef HAVE_LIBCRYPT
+
+/* Define to 1 if you have the `descrypt' library (-ldescrypt). */
+#undef HAVE_LIBDESCRYPT
+
+/* Define to 1 if you have the `dl' library (-ldl). */
+#undef HAVE_LIBDL
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#undef HAVE_LIBRESOLV
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define to 1 if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define to 1 if you have the `lrand48' function. */
+#undef HAVE_LRAND48
+
+/* Define to 1 if you have the <malloc.h> header file. */
+#undef HAVE_MALLOC_H
+
+/* Define to 1 if you have the `memmove' function. */
+#undef HAVE_MEMMOVE
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `memset' function. */
+#undef HAVE_MEMSET
+
+/* If we have the MIN and MAX macros */
+#undef HAVE_MINMAX
+
+/* Define to 1 if you have the `munmap' function. */
+#undef HAVE_MUNMAP
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the `setenv' function. */
+#undef HAVE_SETENV
+
+/* Define to 1 if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the `socket' function. */
+#undef HAVE_SOCKET
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#undef HAVE_STDDEF_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strcasecmp' function. */
+#undef HAVE_STRCASECMP
+
+/* Define to 1 if you have the `strchr' function. */
+#undef HAVE_STRCHR
+
+/* Define to 1 if you have the `strdup' function. */
+#undef HAVE_STRDUP
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strncasecmp' function. */
+#undef HAVE_STRNCASECMP
+
+/* Define to 1 if you have the `strrchr' function. */
+#undef HAVE_STRRCHR
+
+/* Define to 1 if you have the `strtok' function. */
+#undef HAVE_STRTOK
+
+/* Define to 1 if you have the `strtoken' function. */
+#undef HAVE_STRTOKEN
+
+/* Define to 1 if you have the `strtol' function. */
+#undef HAVE_STRTOL
+
+/* Define to 1 if you have the `strtoul' function. */
+#undef HAVE_STRTOUL
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#undef HAVE_SYSLOG_H
+
+/* Define to 1 if you have the <sys/file.h> header file. */
+#undef HAVE_SYS_FILE_H
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the `times' function. */
+#undef HAVE_TIMES
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the <utmp.h> header file. */
+#undef HAVE_UTMP_H
+
+/* Define to 1 if you have the `__dn_skipname' function. */
+#undef HAVE___DN_SKIPNAME
+
+/* Maximum Connections we allow */
+#undef MAXCONNECTIONS
+
+/* epoll behavior */
+#undef NEED_EPOLL_DEFS
+
+/* Not quite sure why we have two of these */
+#undef OS_SOLARIS
+
+/* If we're running on Solaris */
+#undef OS_SOLARIS2
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* If the sys_errlist array is defined */
+#undef SYS_ERRLIST_DECLARED
+
+/* Do we support loadable modules */
+#undef USE_HOOKMODULES
+
+/* Maxmimum number of iovecs supported by writev() */
+#undef WRITEV_IOV
+
+/* Define as `__inline' if that's what the C compiler calls it, or to nothing
+ if it is not supported. */
+#undef inline
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, include/sock.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: sock.h,v 1.1 2005/01/12 07:44:58 mmondor Exp $ */
+
+#ifndef FD_ZERO
+#define FD_ZERO(set) (((set)->fds_bits[0]) = 0)
+#define FD_SET(s1, set) (((set)->fds_bits[0]) |= 1 << (s1))
+#define FD_ISSET(s1, set) (((set)->fds_bits[0]) & (1 << (s1)))
+#define FD_SETSIZE 30
+#endif
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, include/struct.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * 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 1, 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.
+ *
+ *
+ */
+
+/* $Id: struct.h,v 1.1 2005/01/12 07:44:58 mmondor Exp $ */
+
+#ifndef __struct_include__
+#define __struct_include__
+
+#include "config.h"
+#if !defined(CONFIG_H_LEVEL_183)
+#error Incorrect config.h for this revision of ircd.
+#endif
+
+#include "sys.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#if defined( HAVE_STDDEF_H )
+#include <stddef.h>
+#endif
+#ifdef ORATIMING
+#include <sys/time.h>
+#endif
+
+#ifdef USE_SYSLOG
+#include <syslog.h>
+#if defined( HAVE_SYS_SYSLOG_H )
+#include <sys/syslog.h>
+#endif
+#endif
+
+#define REPORT_DO_DNS_ ":%s NOTICE AUTH :*** Looking up your hostname..."
+#define REPORT_FIN_DNS_ ":%s NOTICE AUTH :*** Found your hostname"
+#define REPORT_FIN_DNSC_ ":%s NOTICE AUTH :*** Found your hostname, cached"
+#define REPORT_FAIL_DNS_ ":%s NOTICE AUTH :*** Couldn't look up your "\
+ "hostname"
+#define REPORT_DO_ID_ ":%s NOTICE AUTH :*** Checking Ident"
+#define REPORT_FIN_ID_ ":%s NOTICE AUTH :*** Got Ident response"
+#define REPORT_FAIL_ID_ ":%s NOTICE AUTH :*** No Ident response"
+
+extern char REPORT_DO_DNS[256], REPORT_FIN_DNS[256], REPORT_FIN_DNSC[256],
+ REPORT_FAIL_DNS[256], REPORT_DO_ID[256], REPORT_FIN_ID[256],
+ REPORT_FAIL_ID[256];
+
+#include "hash.h"
+
+#include "sbuf.h"
+
+typedef struct Client aClient;
+typedef struct Channel aChannel;
+typedef struct User anUser;
+typedef struct Server aServer;
+typedef struct SLink Link;
+typedef struct SLinkD DLink;
+typedef struct ChanLink chanMember;
+typedef struct SMode Mode;
+typedef struct Watch aWatch;
+typedef struct Ban aBan;
+#ifdef INVITE_LISTS
+typedef struct LInvite anInvite;
+#endif
+#ifdef EXEMPT_LISTS
+typedef struct Exempt aBanExempt;
+#endif
+typedef struct ListOptions LOpts;
+typedef struct Listener aListener;
+typedef struct Conf_Connect aConnect;
+typedef struct Conf_Allow aAllow;
+typedef struct Conf_Oper aOper;
+typedef struct Conf_Me Conf_Me;
+typedef struct Conf_Port aPort;
+typedef struct Conf_Class aClass;
+typedef struct Conf_Modules Conf_Modules;
+typedef long ts_val;
+
+typedef struct MotdItem aMotd;
+
+
+
+#define HOSTLEN 63 /* Length of hostname. Updated to */
+
+/* comply with RFC1123 */
+
+#define HOSTIPLEN 15 /* Length of dotted quad form of IP */
+
+#define NICKLEN 30
+
+/* Necessary to put 9 here instead of 10 if
+ * s_msg.c/m_nick has been corrected. This
+ * preserves compatibility with old * servers --msa
+ */
+
+#define MAX_DATE_STRING 32 /* maximum string length for a date string */
+
+#define USERLEN 10
+#define REALLEN 50
+#define TOPICLEN 307
+#define KILLLEN 400
+#define CHANNELLEN 32
+#define PASSWDLEN 63
+#define KEYLEN 23
+#define BUFSIZE 512 /* WARNING: *DONT* CHANGE THIS!!!! */
+#define MAXRECIPIENTS 20
+#define MAXBANS 100
+#define MAXINVITELIST 45
+#define MAXEXEMPTLIST 45
+
+#define MOTDLINELEN 90
+
+#define MAXSILES 10
+#define MAXSILELENGTH 128
+
+#define MAXDCCALLOW 5
+#define DCC_LINK_ME 0x01 /* This is my dcc allow */
+#define DCC_LINK_REMOTE 0x02 /* I need to remove these dcc allows from
+ * these clients when I die
+ */
+
+#define USERHOST_REPLYLEN (NICKLEN+HOSTLEN+USERLEN+5)
+
+/*
+ * 'offsetof' is defined in ANSI-C. The following definition * is not
+ * absolutely portable (I have been told), but so far * it has worked
+ * on all machines I have needed it. The type * should be size_t but...
+ * --msa
+ */
+
+#ifndef offsetof
+#define offsetof(t,m) (int)((&((t *)0L)->m))
+#endif
+
+#define elementsof(x) (sizeof(x)/sizeof(x[0]))
+
+/* flags for bootup options (command line flags) */
+
+#define BOOT_CONSOLE 1
+#define BOOT_QUICK 2
+#define BOOT_DEBUG 4
+#define BOOT_TTY 8
+#define BOOT_OPER 16
+#define BOOT_STDERR 64
+#define STAT_LOG -6 /* logfile for -x */
+#define STAT_MASTER -5 /* Local ircd master before identification */
+#define STAT_CONNECTING -4
+#define STAT_HANDSHAKE -3
+#define STAT_ME -2
+#define STAT_UNKNOWN -1
+/* the line of truth lies here (truth == registeredness) */
+#define STAT_SERVER 0
+#define STAT_CLIENT 1
+
+/* status macros. */
+
+#define IsRegisteredUser(x) ((x)->status == STAT_CLIENT)
+#define IsRegistered(x) ((x)->status >= STAT_SERVER)
+#define IsConnecting(x) ((x)->status == STAT_CONNECTING)
+#define IsHandshake(x) ((x)->status == STAT_HANDSHAKE)
+#define IsMe(x) ((x)->status == STAT_ME)
+#define IsUnknown(x) ((x)->status == STAT_UNKNOWN || \
+ (x)->status == STAT_MASTER)
+#define IsServer(x) ((x)->status == STAT_SERVER)
+#define IsClient(x) ((x)->status == STAT_CLIENT)
+#define IsLog(x) ((x)->status == STAT_LOG)
+
+#define SetMaster(x) ((x)->status = STAT_MASTER)
+#define SetConnecting(x) ((x)->status = STAT_CONNECTING)
+#define SetHandshake(x) ((x)->status = STAT_HANDSHAKE)
+#define SetMe(x) ((x)->status = STAT_ME)
+#define SetUnknown(x) ((x)->status = STAT_UNKNOWN)
+#define SetServer(x) ((x)->status = STAT_SERVER)
+#define SetClient(x) ((x)->status = STAT_CLIENT)
+#define SetLog(x) ((x)->status = STAT_LOG)
+
+#define FLAGS_PINGSENT 0x000001 /* Unreplied ping sent */
+#define FLAGS_DEADSOCKET 0x000002 /* Local socket is dead--Exiting soon */
+#define FLAGS_KILLED 0x000004 /* Prevents "QUIT" from being sent for
+ * this */
+#define FLAGS_BLOCKED 0x000008 /* socket is in a blocked condition */
+#define FLAGS_CLOSING 0x000010 /* set when closing to suppress errors */
+#define FLAGS_LISTEN 0x000020 /* used to mark clients which we listen()
+ * on */
+#define FLAGS_HAVERECVQ 0x000040 /* Client has full commands in their recvq */
+#define FLAGS_DOINGDNS 0x000080 /* client is waiting for a DNS
+ * response */
+#define FLAGS_AUTH 0x000100 /* client is waiting on rfc931
+ * response */
+#define FLAGS_WRAUTH 0x000200 /* set if we havent writen to ident
+ * server */
+#define FLAGS_LOCAL 0x000400 /* set for local clients */
+#define FLAGS_GOTID 0x000800 /* successful ident lookup achieved */
+#define FLAGS_DOID 0x001000 /* I-lines say must use ident return */
+#define FLAGS_NONL 0x002000 /* No \n in buffer */
+#define FLAGS_NORMALEX 0x004000 /* Client exited normally */
+#define FLAGS_SENDQEX 0x008000 /* Sendq exceeded */
+#define FLAGS_ULINE 0x020000 /* client is U-lined */
+#define FLAGS_USERBURST 0x040000 /* server in nick/channel netburst */
+#define FLAGS_TOPICBURST 0x080000 /* server in topic netburst */
+#define FLAGS_BURST (FLAGS_USERBURST | FLAGS_TOPICBURST)
+#define FLAGS_SOBSENT 0x100000 /* we've sent an SOB, just have to
+ * send an EOB */
+#define FLAGS_EOBRECV 0x200000 /* we're waiting on an EOB */
+#define FLAGS_BAD_DNS 0x400000 /* spoofer-guy */
+#define FLAGS_SERV_NEGO 0x800000 /* This is a server that has passed
+ * connection tests, but is a stat < 0
+ * for handshake purposes */
+#define FLAGS_RC4IN 0x1000000 /* This link is rc4 encrypted. */
+#define FLAGS_RC4OUT 0x2000000 /* This link is rc4 encrypted. */
+#define FLAGS_ZIPPED_IN 0x4000000 /* This link is gzipped. */
+#define FLAGS_ZIPPED_OUT 0x8000000 /* This link is gzipped. */
+
+/* Capabilities of the ircd or clients */
+
+#define CAPAB_DKEY 0x0001 /* server supports dh-key exchange */
+#define CAPAB_ZIP 0x0002 /* server supports gz'd links */
+#define CAPAB_DOZIP 0x0004 /* output to this link shall be gzipped */
+#define CAPAB_DODKEY 0x0008 /* do I do dkey with this link? */
+#define CAPAB_BURST 0x0010 /* server supports BURST command */
+#define CAPAB_UNCONN 0x0020 /* server supports UNCONNECT */
+#ifdef NOQUIT
+#define CAPAB_NOQUIT 0x0040 /* noquit support */
+#endif
+
+
+#define SetDKEY(x) ((x)->capabilities |= CAPAB_DKEY)
+#define CanDoDKEY(x) ((x)->capabilities & CAPAB_DKEY)
+/* N: line, flag E */
+#define SetWantDKEY(x) ((x)->capabilities |= CAPAB_DODKEY)
+#define WantDKEY(x) ((x)->capabilities & CAPAB_DODKEY)
+
+#define SetZipCapable(x) ((x)->capabilities |= CAPAB_ZIP)
+#define IsZipCapable(x) ((x)->capabilities & CAPAB_ZIP)
+/* this is set in N: line, flag Z */
+#define DoZipThis(x) ((x)->capabilities & CAPAB_DOZIP)
+
+#define SetBurst(x) ((x)->capabilities |= CAPAB_BURST)
+#define IsBurst(x) ((x)->capabilities & CAPAB_BURST)
+
+#define SetUnconnect(x) ((x)->capabilities |= CAPAB_UNCONN)
+#define IsUnconnect(x) ((x)->capabilities & CAPAB_UNCONN)
+
+#ifdef NOQUIT
+#define SetNoquit(x) ((x)->capabilities |= CAPAB_NOQUIT)
+#define IsNoquit(x) ((x)->capabilities & CAPAB_NOQUIT)
+#endif
+
+
+/* flag macros. */
+#define IsULine(x) ((x)->flags & FLAGS_ULINE)
+
+
+/* User Modes */
+#define UMODE_o 0x00001 /* umode +o - Oper */
+#define UMODE_O 0x00002 /* umode +O - Local Oper */
+#define UMODE_i 0x00004 /* umode +i - Invisible */
+#define UMODE_w 0x00008 /* umode +w - Get wallops */
+#define UMODE_s 0x00010 /* umode +s - Server notices */
+#define UMODE_c 0x00020 /* umode +c - Client connections/exits */
+#define UMODE_r 0x00040 /* umode +r - registered nick */
+#define UMODE_k 0x00080 /* umode +k - Server kill messages */
+#define UMODE_f 0x00100 /* umode +f - Server flood messages */
+#define UMODE_y 0x00200 /* umode +y - Stats/links */
+#define UMODE_d 0x00400 /* umode +d - Debug info */
+#define UMODE_g 0x01000 /* umode +g - Globops */
+#define UMODE_b 0x02000 /* umode +b - Chatops */
+#define UMODE_a 0x04000 /* umode +a - Services Admin */
+#define UMODE_A 0x08000 /* umode +A - Server Admin */
+#define UMODE_n 0x10000 /* umode +n - Routing Notices */
+#define UMODE_h 0x20000 /* umode +h - Helper */
+#define UMODE_m 0x40000 /* umode +m - spambot notices */
+#define UMODE_R 0x80000 /* unmode +R - No non registered msgs */
+#define UMODE_e 0x100000 /* umode +e - oper notices for the above +D */
+#define UMODE_x 0x200000 /* umode +x - Squelch with notice */
+#define UMODE_X 0x400000 /* umode +X - Squelch without notice */
+#define UMODE_D 0x800000 /* umode +D - Hidden dccallow umode */
+#define UMODE_F 0x1000000 /* umode +F - no cptr->since message rate throttle */
+#define UMODE_j 0x2000000 /* umode +j - client rejection notices */
+#define UMODE_K 0x4000000 /* umode +K - U: lined server kill messages */
+#define UMODE_I 0x8000000 /* umode +I - invisible oper (masked) */
+
+/* for sendto_ops_lev */
+
+#define CCONN_LEV 1
+#define REJ_LEV 2
+#define SKILL_LEV 3
+#define SPY_LEV 4
+#define DEBUG_LEV 5
+#define FLOOD_LEV 6
+#define SPAM_LEV 7
+#define DCCSEND_LEV 8
+#define USKILL_LEV 9
+
+/* SEND_UMODES:
+ * we send these to remote servers.
+ * ALL_UMODES
+ * we send these to our clients.
+ * if you don't put something in ALL_UMODES,
+ * that mode will be 'silent.'
+ */
+
+#define SEND_UMODES (UMODE_a|UMODE_i|UMODE_o|UMODE_r|UMODE_A|UMODE_I|UMODE_R)
+#define ALL_UMODES (SEND_UMODES|UMODE_b|UMODE_c|UMODE_d|UMODE_e|UMODE_f|\
+ UMODE_g|UMODE_h|UMODE_j|UMODE_k|UMODE_m|UMODE_n|UMODE_s|\
+ UMODE_w|UMODE_y|UMODE_F|UMODE_K|UMODE_O)
+
+/* modes users can set themselves */
+#define USER_UMODES (UMODE_i|UMODE_k|UMODE_w|UMODE_s|UMODE_R)
+
+/* modes only opers can have */
+#define OPER_UMODES (UMODE_a|UMODE_b|UMODE_c|UMODE_d|UMODE_e|UMODE_f|UMODE_g|\
+ UMODE_h|UMODE_j|UMODE_m|UMODE_n|UMODE_y|UMODE_A|UMODE_F|\
+ UMODE_K)
+
+#define FLAGS_ID (FLAGS_DOID|FLAGS_GOTID)
+
+#define IsOper(x) ((x)->umode & UMODE_o)
+#define IsLocOp(x) ((x)->umode & UMODE_O)
+#define IsInvisible(x) ((x)->umode & UMODE_i)
+#define IsAnOper(x) ((x)->umode & (UMODE_o|UMODE_O))
+#define CanBeOper(x) ((x)->umode & (UMODE_o|UMODE_O|UMODE_I))
+#define IsARegNick(x) ((x)->umode & (UMODE_r))
+#define IsRegNick(x) ((x)->umode & UMODE_r)
+#define IsSAdmin(x) ((x)->umode & UMODE_a)
+#define IsAdmin(x) ((x)->umode & UMODE_A)
+#define IsUmodef(x) ((x)->umode & UMODE_f)
+#define IsUmodec(x) ((x)->umode & UMODE_c)
+#define IsUmodey(x) ((x)->umode & UMODE_y)
+#define IsUmoded(x) ((x)->umode & UMODE_d)
+#define IsUmodeb(x) ((x)->umode & UMODE_b)
+#define IsUmoden(x) ((x)->umode & UMODE_n)
+#define IsUmodem(x) ((x)->umode & UMODE_m)
+#define IsUmodeh(x) ((x)->umode & UMODE_h)
+#define IsUmodee(x) ((x)->umode & UMODE_e)
+#define IsUmodej(x) ((x)->umode & UMODE_j)
+#define IsUmodeK(x) ((x)->umode & UMODE_K)
+#define IsUmodek(x) ((x)->umode & UMODE_k)
+#define IsUmodes(x) ((x)->umode & UMODE_s)
+#define IsUmodeI(x) ((x)->umode & UMODE_I)
+#define IsNoNonReg(x) ((x)->umode & UMODE_R)
+#define IsWSquelch(x) ((x)->umode & UMODE_x)
+#define IsSSquelch(x) ((x)->umode & UMODE_X)
+#define IsSquelch(x) (IsSSquelch(x) || IsWSquelch(x))
+#define IsPerson(x) ((x)->user && IsClient(x))
+#define IsPrivileged(x) (IsAnOper(x) || IsServer(x))
+#define SendWallops(x) ((x)->umode & UMODE_w)
+#define SendServNotice(x) ((x)->umode & UMODE_s)
+#define SendCConnNotice(x) ((x)->umode & UMODE_c)
+#define SendRejNotice(x) ((x)->umode & UMODE_j)
+#define SendSkillNotice(x) ((x)->umode & UMODE_k)
+#define SendSUkillNotice(x) ((x)->umode & UMODE_K)
+#define SendSpyNotice(x) ((x)->umode & UMODE_y)
+#define SendDCCNotice(x) ((x)->umode & UMODE_e)
+#define SendFloodNotice(x) ((x)->umode & UMODE_f)
+#define SendSpamNotice(x) ((x)->umode & UMODE_m)
+#define SendDebugNotice(x) ((x)->umode & UMODE_d)
+#define SendGlobops(x) ((x)->umode & UMODE_g)
+#define SendChatops(x) ((x)->umode & UMODE_b)
+#define SendRnotice(x) ((x)->umode & UMODE_n)
+#define NoMsgThrottle(x) ((x)->umode & UMODE_F)
+#define IsListening(x) ((x)->flags & FLAGS_LISTEN)
+#define IsLocal(x) ((x)->flags & FLAGS_LOCAL)
+#define IsDead(x) ((x)->flags & FLAGS_DEADSOCKET)
+#define SetOper(x) ((x)->umode |= UMODE_o)
+#define SetRegNick(x) ((x)->umode |= UMODE_r)
+#define SetNoNonReg(x) ((x)->umode |= UMODE_R)
+#define SetSAdmin(x) ((x)->umode |= UMODE_a)
+#define SetLocOp(x) ((x)->umode |= UMODE_O)
+#define SetInvisible(x) ((x)->umode |= UMODE_i)
+#define SetWallops(x) ((x)->umode |= UMODE_w)
+#define SetWSquelch(x) ((x)->umode |= UMODE_x)
+#define SetSSquelch(x) ((x)->umode |= UMODE_X)
+#define SetNoMsgThrottle(x) ((x)->umode |= UMODE_F)
+#define SetDNS(x) ((x)->flags |= FLAGS_DOINGDNS)
+#define DoingDNS(x) ((x)->flags & FLAGS_DOINGDNS)
+#define DoingAuth(x) ((x)->flags & FLAGS_AUTH)
+#define NoNewLine(x) ((x)->flags & FLAGS_NONL)
+#define SeenDCCNotice(x) ((x)->umode & UMODE_D)
+#define SetDCCNotice(x) ((x)->umode |= UMODE_D)
+
+#define SetNegoServer(x) ((x)->flags |= FLAGS_SERV_NEGO)
+#define IsNegoServer(x) ((x)->flags & FLAGS_SERV_NEGO)
+#define ClearNegoServer(x) ((x)->flags &= ~FLAGS_SERV_NEGO)
+#define IsRC4OUT(x) ((x)->flags & FLAGS_RC4OUT)
+#define SetRC4OUT(x) ((x)->flags |= FLAGS_RC4OUT)
+#define IsRC4IN(x) ((x)->flags & FLAGS_RC4IN)
+#define SetRC4IN(x) ((x)->flags |= FLAGS_RC4IN)
+#define RC4EncLink(x) (((x)->flags & (FLAGS_RC4IN|FLAGS_RC4OUT)) ==\
+ (FLAGS_RC4IN|FLAGS_RC4OUT))
+
+#define ZipIn(x) ((x)->flags & FLAGS_ZIPPED_IN)
+#define SetZipIn(x) ((x)->flags |= FLAGS_ZIPPED_IN)
+#define ZipOut(x) ((x)->flags & FLAGS_ZIPPED_OUT)
+#define SetZipOut(x) ((x)->flags |= FLAGS_ZIPPED_OUT)
+
+#define ClearSAdmin(x) ((x)->umode &= ~UMODE_a)
+#define ClearAdmin(x) ((x)->umode &= ~UMODE_A)
+#define ClearUmodef(x) ((x)->umode &= ~UMODE_f)
+#define ClearUmodem(x) ((x)->umode &= ~UMODE_m)
+#define ClearUmodec(x) ((x)->umode &= ~UMODE_c)
+#define ClearUmodey(x) ((x)->umode &= ~UMODE_y)
+#define ClearUmoded(x) ((x)->umode &= ~UMODE_d)
+#define ClearUmodeb(x) ((x)->umode &= ~UMODE_b)
+#define ClearUmoden(x) ((x)->umode &= ~UMODE_n)
+#define ClearUmodeh(x) ((x)->umode &= ~UMODE_h)
+#define ClearUmodee(x) ((x)->umode &= ~UMODE_e)
+#define ClearUmodej(x) ((x)->umode &= ~UMODE_j)
+#define ClearUmodeK(x) ((x)->umode &= ~UMODE_K)
+#define ClearUmodek(x) ((x)->umode &= ~UMODE_k)
+#define ClearUmodes(x) ((x)->umode &= ~UMODE_s)
+#define ClearUmodeI(x) ((x)->umode &= ~UMODE_I)
+#define ClearNoNonReg(x) ((x)->umode &= ~UMODE_R)
+#define ClearWSquelch(x) ((x)->umode &= ~UMODE_x)
+#define ClearSSquelch(x) ((x)->umode &= ~UMODE_X)
+#define ClearOper(x) ((x)->umode &= ~UMODE_o)
+#define ClearLocOp(x) ((x)->umode &= ~UMODE_O)
+#define ClearInvisible(x) ((x)->umode &= ~UMODE_i)
+#define ClearWallops(x) ((x)->umode &= ~UMODE_w)
+#define ClearNoMsgThrottle(x) ((x)->umode &= ~UMODE_F)
+#define ClearDNS(x) ((x)->flags &= ~FLAGS_DOINGDNS)
+#define ClearAuth(x) ((x)->flags &= ~FLAGS_AUTH)
+
+/* Oper flags */
+
+/* defined operator access levels */
+#define OFLAG_REHASH 0x00000001 /* Oper can /rehash server */
+#define OFLAG_DIE 0x00000002 /* Oper can /die the server */
+#define OFLAG_RESTART 0x00000004 /* Oper can /restart the server */
+#define OFLAG_HELPOP 0x00000010 /* Oper can send /HelpOps */
+#define OFLAG_GLOBOP 0x00000020 /* Oper can send /GlobOps */
+#define OFLAG_WALLOP 0x00000040 /* Oper can send /WallOps */
+#define OFLAG_LOCOP 0x00000080 /* Oper can send /LocOps */
+#define OFLAG_LROUTE 0x00000100 /* Oper can do local routing */
+#define OFLAG_GROUTE 0x00000200 /* Oper can do global routing */
+#define OFLAG_LKILL 0x00000400 /* Oper can do local kills */
+#define OFLAG_GKILL 0x00000800 /* Oper can do global kills */
+#define OFLAG_KLINE 0x00001000 /* Oper can /kline users */
+#define OFLAG_UNKLINE 0x00002000 /* Oper can /unkline users */
+#define OFLAG_LNOTICE 0x00004000 /* Oper can send local serv notices */
+#define OFLAG_GNOTICE 0x00008000 /* Oper can send global notices */
+#define OFLAG_ADMIN 0x00010000 /* Admin */
+#define OFLAG_UMODEc 0x00020000 /* Oper can set umode +c : client connect */
+#define OFLAG_UMODEf 0x00040000 /* Oper can set umode +f : flood notices */
+#define OFLAG_SADMIN 0x00080000 /* Oper can be a services admin */
+#define OFLAG_ZLINE 0x00100000 /* Oper can use /zline and /unzline */
+#define OFLAG_UMODEy 0x00200000 /* Oper can set umode +y : spy */
+#define OFLAG_UMODEd 0x00400000 /* Oper can set umode +d : debug */
+#define OFLAG_UMODEb 0x00800000 /* Oper can set umode +b : chatops */
+#define OFLAG_UMODEF 0x01000000 /* Oper can set umode +F : no flood throttling */
+#define OFLAG_LOCAL (OFLAG_REHASH|OFLAG_HELPOP|OFLAG_GLOBOP|OFLAG_WALLOP|\
+ OFLAG_LOCOP|OFLAG_LROUTE|OFLAG_LKILL|OFLAG_KLINE|\
+ OFLAG_UNKLINE|OFLAG_LNOTICE|OFLAG_UMODEc|OFLAG_UMODEf|OFLAG_UMODEd|\
+ OFLAG_UMODEb|OFLAG_UMODEy)
+#define OFLAG_GLOBAL (OFLAG_LOCAL|OFLAG_GROUTE|OFLAG_GKILL|OFLAG_GNOTICE)
+#define OFLAG_ISGLOBAL (OFLAG_GROUTE|OFLAG_GKILL|OFLAG_GNOTICE)
+#define OPCanZline(x) ((x)->oflag & OFLAG_SADMIN)
+#define OPCanRehash(x) ((x)->oflag & OFLAG_REHASH)
+#define OPCanDie(x) ((x)->oflag & OFLAG_DIE)
+#define OPCanRestart(x) ((x)->oflag & OFLAG_RESTART)
+#define OPCanHelpOp(x) ((x)->oflag & OFLAG_HELPOP)
+#define OPCanGlobOps(x) ((x)->oflag & OFLAG_GLOBOP)
+#define OPCanWallOps(x) ((x)->oflag & OFLAG_WALLOP)
+#define OPCanLocOps(x) ((x)->oflag & OFLAG_LOCOP)
+#define OPCanLRoute(x) ((x)->oflag & OFLAG_LROUTE)
+#define OPCanGRoute(x) ((x)->oflag & OFLAG_GROUTE)
+#define OPCanLKill(x) ((x)->oflag & OFLAG_LKILL)
+#define OPCanGKill(x) ((x)->oflag & OFLAG_GKILL)
+#define OPCanKline(x) ((x)->oflag & OFLAG_KLINE)
+#define OPCanUnKline(x) ((x)->oflag & OFLAG_UNKLINE)
+#define OPCanLNotice(x) ((x)->oflag & OFLAG_LNOTICE)
+#define OPCanGNotice(x) ((x)->oflag & OFLAG_GNOTICE)
+#define OPIsAdmin(x) ((x)->oflag & OFLAG_ADMIN)
+#define OPIsSAdmin(x) ((x)->oflag & OFLAG_SADMIN)
+#define OPCanUModec(x) ((x)->oflag & OFLAG_UMODEc)
+#define OPCanUModef(x) ((x)->oflag & OFLAG_UMODEf)
+#define OPCanUModey(x) ((x)->oflag & OFLAG_UMODEy)
+#define OPCanUModed(x) ((x)->oflag & OFLAG_UMODEd)
+#define OPCanUModeb(x) ((x)->oflag & OFLAG_UMODEb)
+#define OPCanUModeF(x) ((x)->oflag & OFLAG_UMODEF)
+#define OPClearRehash(x) ((x)->oflag &= ~OFLAG_REHASH)
+#define OPClearDie(x) ((x)->oflag &= ~OFLAG_DIE)
+#define OPClearRestart(x) ((x)->oflag &= ~OFLAG_RESTART)
+#define OPClearHelpOp(x) ((x)->oflag &= ~OFLAG_HELPOP)
+#define OPClearGlobOps(x) ((x)->oflag &= ~OFLAG_GLOBOP)
+#define OPClearWallOps(x) ((x)->oflag &= ~OFLAG_WALLOP)
+#define OPClearLocOps(x) ((x)->oflag &= ~OFLAG_LOCOP)
+#define OPClearLRoute(x) ((x)->oflag &= ~OFLAG_LROUTE)
+#define OPClearGRoute(x) ((x)->oflag &= ~OFLAG_GROUTE)
+#define OPClearLKill(x) ((x)->oflag &= ~OFLAG_LKILL)
+#define OPClearGKill(x) ((x)->oflag &= ~OFLAG_GKILL)
+#define OPClearKline(x) ((x)->oflag &= ~OFLAG_KLINE)
+#define OPClearUnKline(x) ((x)->oflag &= ~OFLAG_UNKLINE)
+#define OPClearLNotice(x) ((x)->oflag &= ~OFLAG_LNOTICE)
+#define OPClearGNotice(x) ((x)->oflag &= ~OFLAG_GNOTICE)
+#define OPClearAdmin(x) ((x)->oflag &= ~OFLAG_ADMIN)
+#define OPClearSAdmin(x) ((x)->oflag &= ~OFLAG_SADMIN)
+#define OPClearUModec(x) ((x)->oflag &= ~OFLAG_UMODEc)
+#define OPClearUModef(x) ((x)->oflag &= ~OFLAG_UMODEf)
+#define OPClearUModey(x) ((x)->oflag &= ~OFLAG_UMODEy)
+#define OPClearUModed(x) ((x)->oflag &= ~OFLAG_UMODEd)
+#define OPClearUModeb(x) ((x)->oflag &= ~OFLAG_UMODEb)
+#define OPClearZLine(x) ((x)->oflag &= ~OFLAG_ZLINE)
+#define OPClearUModeF(x) ((x)->oflag &= ~OFLAG_UMODEF)
+
+/* defined debugging levels */
+#define DEBUG_FATAL 0
+#define DEBUG_ERROR 1 /* report_error() and other errors that are found */
+#define DEBUG_NOTICE 3
+#define DEBUG_DNS 4 /* used by all DNS related routines - a *lot* */
+#define DEBUG_INFO 5 /* general usful info */
+#define DEBUG_NUM 6 /* numerics */
+#define DEBUG_SEND 7 /* everything that is sent out */
+#define DEBUG_DEBUG 8 /* anything to do with debugging, ie unimportant :) */
+#define DEBUG_MALLOC 9 /* malloc/free calls */
+#define DEBUG_LIST 10 /* debug list use */
+/* defines for curses in client */
+#define DUMMY_TERM 0
+#define CURSES_TERM 1
+#define TERMCAP_TERM 2
+
+struct Counter
+{
+ int server; /* servers */
+ int myserver; /* my servers */
+ int myulined; /* my ulined servers */
+ int oper; /* Opers */
+ int chan; /* Channels */
+ int local; /* Local Clients */
+ int total; /* total clients */
+ int invisi; /* invisible clients */
+ int unknown; /* unknown connections */
+ int max_loc; /* MAX local clients */
+ int max_tot; /* MAX global clients */
+ ts_val start; /* when we started collecting info */
+ u_long today; /* Client Connections today */
+ ts_val day; /* when today started */
+ u_long weekly; /* connections this week */
+ ts_val week; /* when this week started */
+ u_long monthly; /* connections this month */
+ ts_val month; /* when this month started */
+ u_long yearly; /* this is gonna be big */
+ ts_val year; /* when this year started (HEH!) */
+};
+
+struct MotdItem
+{
+ char line[MOTDLINELEN];
+ struct MotdItem *next;
+};
+
+/* lets speed this up... also removed away information. *tough* Dianora */
+typedef struct Whowas
+{
+ int hashv;
+ char name[NICKLEN + 1];
+ char username[USERLEN + 1];
+ char hostname[HOSTLEN + 1];
+ char *servername;
+ char realname[REALLEN + 1];
+ time_t logoff;
+ unsigned int umode;
+ struct Client *online; /* Pointer to new nickname for chasing or NULL */
+
+ struct Whowas *next; /* for hash table... */
+
+ struct Whowas *prev; /* for hash table... */
+ struct Whowas *cnext; /* for client struct linked list */
+ struct Whowas *cprev; /* for client struct linked list */
+} aWhowas;
+
+/* configuration structures */
+
+#define CONF_ILLEGAL 0x80000000
+#define CONF_MATCH 0x40000000
+
+#define CONF_CLIENT 0x0002
+#define CONF_CONNECT_SERVER 0x0004
+#define CONF_NOCONNECT_SERVER 0x0008
+#define CONF_LOCOP 0x0010
+#define CONF_OPERATOR 0x0020
+#define CONF_ME 0x0040
+#define CONF_KILL 0x0080
+#define CONF_ADMIN 0x0100
+#define CONF_CLASS 0x0200
+#define CONF_SERVICE 0x0400
+#define CONF_LISTEN_PORT 0x1000
+#define CONF_HUB 0x2000
+#define CONF_ELINE 0x4000
+#define CONF_FLINE 0x8000
+#define CONF_QUARANTINE 0x40000
+#define CONF_ULINE 0x80000
+#define CONF_DRPASS 0x100000 /* die/restart pass, from df465 */
+#define CONF_GCOS 0x200000
+#define CONF_SQLINE 0x400000
+#define CONF_MONINFO 0x800000 /* proxy monitor info */
+#define CONF_OPS (CONF_OPERATOR | CONF_LOCOP)
+#define CONF_SERVER_MASK (CONF_CONNECT_SERVER | CONF_NOCONNECT_SERVER)
+#define CONF_CLIENT_MASK (CONF_CLIENT | CONF_SERVICE | CONF_OPS | \
+ CONF_SERVER_MASK)
+#define IsIllegal(x) ((x)->status & CONF_ILLEGAL)
+
+/* did the password field specify OPER? */
+#define CONF_FLAGS_I_OPERPORT 0x0002
+/* does NAME in I:HOST::NAME have an @? */
+#define CONF_FLAGS_I_NAME_HAS_AT 0x0004
+/* does HOST in I:HOST::NAME have an @? */
+#define CONF_FLAGS_I_HOST_HAS_AT 0x0008
+/* do we match allow:hostmask? */
+#define CONF_FLAGS_I_MATCH_NAME 0x0010
+/* do we match allow:ipmask? */
+#define CONF_FLAGS_I_MATCH_HOST 0x0020
+/* remove throttle on match? */
+#define CONF_FLAGS_NOTHROTTLE 0x0040
+/* force umode +F? */
+#define CONF_FLAGS_FORCEFLOOD 0x0080
+/* skip clone checks? */
+#define CONF_FLAGS_SKIPCLONES 0x0100
+
+/* global configuration flags */
+
+#define FLAGS_HUB 0x0001
+#define FLAGS_SERVHUB 0x0002
+#define FLAGS_SMOTD 0x0004
+#define FLAGS_CRYPTPASS 0x0008
+#define FLAGS_WGMONURL 0x0010
+#define FLAGS_WGMONHOST 0x0020
+#define FLAGS_WGMON (FLAGS_WGMONURL|FLAGS_WGMONHOST)
+#define FLAGS_SHOWLINKS 0x0040
+#define FLAGS_SPLITOPOK 0x0080
+
+/* flags for connects */
+
+#define CONN_ZIP 0x001 /* zippable */
+#define CONN_DKEY 0x010 /* cryptable */
+#define CONN_HUB 0x100 /* hubbable! */
+
+struct Conf_Connect
+{
+ /* this is currently BOTH C:lines and N:lines */
+ char *host;
+ char *apasswd; /* nline password - to accept connection */
+ char *cpasswd; /* cline password - to connect out with */
+ char *name;
+ char *source; /* when connecting, use this IP address */
+ struct in_addr ipnum; /* ip address host field */
+ int port;
+ int flags;
+ int legal;
+ aClient *acpt; /* whos using this! */
+ time_t hold; /* used for autoconnections */
+ char *class_name; /* the accual name of our class */
+ aClass *class; /* pointer to the class */
+ aConnect *next;
+};
+
+struct Conf_Allow
+{
+ /* this is an I:line */
+ char *ipmask;
+ char *passwd;
+ char *hostmask;
+ int port;
+ int flags;
+ int clients;
+ int legal;
+ char *class_name;
+ aClass *class;
+ aAllow *next;
+};
+
+struct Conf_Me
+{
+ /* combined A, X and M lines */
+ char *servername;
+ char *info;
+ char *diepass;
+ char *restartpass;
+ char *admin[3]; /* our three admin lines */
+};
+
+#define MAXHOSTS 32
+
+struct Conf_Oper
+{
+ /* this is an O:line */
+ char *hosts[MAXHOSTS+1];
+ char *passwd;
+ char *nick;
+ int flags;
+ int legal;
+ int opers; /* number of opers currently using this */
+ char *class_name;
+ aClass *class;
+ aOper *next;
+};
+
+struct Conf_Modules
+{
+ char *module_path;
+ char *autoload[128];
+ char *optload[128];
+};
+
+struct Conf_Port
+{
+ char *allow;
+ char *address;
+ int port;
+ aListener *lstn;
+ int legal;
+ aPort *next;
+};
+
+struct Conf_Class
+{
+ char *name;
+ int connfreq;
+ int pingfreq;
+ int maxlinks;
+ long maxsendq;
+ int ip24clones;
+ int links;
+ int refs;
+ aClass *next;
+};
+
+struct Listener {
+ struct Listener *next; /* next listener */
+ int fd; /* fd of this listener */
+ u_short port;
+ char allow_string[32]; /* allow from */
+ char vhost_string[32]; /* bind to */
+ struct in_addr allow_ip; /* allow from */
+ struct in_addr vhost_ip; /* bind to */
+ time_t lasttime; /* last time I accepted */
+ long sendK; /* counters, see below */
+ u_short sendB;
+ long sendM;
+ long receiveK;
+ u_short receiveB;
+ long receiveM;
+ u_long ccount; /* total number of clients to connect here */
+ int clients; /* number of clients currently on this */
+ aPort *aport; /* link to the P: line I came from */
+};
+
+
+/* Client structures */
+struct User
+{
+ Link *channel; /* chain of channel pointer blocks */
+ Link *invited; /* chain of invite pointer blocks */
+ char *away; /* pointer to away message */
+ time_t last;
+ int joined; /* number of channels joined */
+ char username[USERLEN + 1];
+ char host[HOSTLEN + 1];
+ char *server; /* pointer to scached server name */
+ unsigned int servicetype; /* set by SVSMODE +T */
+ unsigned int servicestamp; /* set by SVSMODE +d */
+ /*
+ * In a perfect world the 'server' name should not be needed, a
+ * pointer to the client describing the server is enough.
+ * Unfortunately, in reality, server may not yet be in links while
+ * USER is introduced... --msa
+ */
+ Link *silence; /* chain of silenced users */
+ LOpts *lopt; /* Saved /list options */
+ Link *dccallow; /* chain of dcc send allowed users */
+#if (RIDICULOUS_PARANOIA_LEVEL>=1)
+ char *real_oper_host;
+ char *real_oper_username;
+ char *real_oper_ip;
+#endif
+ aOper *oper;
+ aAllow *allow;
+};
+
+struct Server
+{
+ char *up; /* Pointer to scache name */
+ char bynick[NICKLEN + 1];
+ char byuser[USERLEN + 1];
+ char byhost[HOSTLEN + 1];
+ aConnect *aconn; /* N-line pointer for this server */
+ int dkey_flags; /* dkey flags */
+#ifdef HAVE_ENCRYPTION_ON
+ void *sessioninfo_in; /* pointer to opaque sessioninfo structure */
+ void *sessioninfo_out; /* pointer to opaque sessioninfo structure */
+ void *rc4_in; /* etc */
+ void *rc4_out; /* etc */
+#endif
+ void *zip_out;
+ void *zip_in;
+};
+
+struct Client
+{
+ struct Client *next, *prev, *hnext;
+ anUser *user; /* ...defined, if this is a User */
+ aServer *serv; /* ...defined, if this is a server */
+ aWhowas *whowas; /* Pointers to whowas structs */
+ time_t lasttime; /* ...should be only LOCAL clients? --msa */
+ time_t firsttime; /* time client was created */
+ time_t since; /* last time we parsed something */
+ ts_val tsinfo; /* TS on the nick, SVINFO on servers */
+ long flags; /* client flags */
+ long umode; /* We can illeviate overflow this way */
+ aClient *from; /* == self, if Local Client, *NEVER* NULL! */
+ aClient *uplink; /* this client's uplink to the network */
+ int fd; /* >= 0, for local clients */
+ int hopcount; /* number of servers to this 0 = local */
+ short status; /* Client type */
+ char nicksent;
+ char name[HOSTLEN + 1]; /* Unique name of the client, nick or
+ * host */
+ char info[REALLEN + 1]; /* Free form additional client
+ * information */
+#ifdef FLUD
+ Link *fludees;
+#endif
+
+ struct in_addr ip; /* keep real ip# too */
+ char hostip[HOSTIPLEN + 1]; /* Keep real ip as string
+ * too - Dianora */
+
+ Link *watch; /* user's watch list */
+ int watches; /* how many watches this user has set */
+
+#ifdef THROTTLE_ENABLE
+ struct { /* clone tracking */
+ aClient *prev;
+ aClient *next;
+ } clone;
+#endif
+
+/*
+####### # # ### # # ##### #####
+ # # # # ## # # # # #
+ # # # # # # # # #
+ # ####### # # # # # #### #####
+ # # # # # # # # # #
+ # # # # # ## # # # #
+ # # # ### # # ##### #####
+
+###### ####### # ####### # #
+# # # # # # # # #
+# # # # # # # # #
+###### ##### # # # # # #
+# # # # # # # # #
+# # # # # # # # #
+###### ####### ####### ####### ## ##
+
+ ##### ####### # # # # #######
+# # # # # # ## # #
+# # # # # # # # #
+# # # # # # # # #
+# # # # # # # # #
+# # # # # # # ## #
+ ##### ####### ##### # # #
+
+ # ###### ####### # ####### ##### # #
+ # # # # # # # # # # # # #
+ # # # # # # # # # # # #
+# # ###### ##### # # # # # # #
+####### # # # # # # # ####### #
+# # # # # # # # # # # # #
+# # # # ####### ####### ####### ##### # # #######
+
+####### # # # # # ### ### ###
+# # ## # # # # ### ### ###
+# # # # # # # # ### ### ###
+# # # # # # # # # #
+# # # # # # #
+# # # ## # # ### ### ###
+####### # # ####### # ### ### ###
+
+*/
+ /*
+ * The following fields are allocated only for local clients
+ * (directly connected to this server with a socket. The first
+ * of them MUST be the "count"--it is the field to which the
+ * allocation is tied to! Never refer to these fields, if (from != self).
+ */
+
+ int count; /* Amount of data in buffer */
+#ifdef FLUD
+ time_t fludblock;
+ struct fludbot *fluders;
+#endif
+#ifdef ANTI_SPAMBOT
+ time_t last_join_time; /* when this client last joined a channel */
+ time_t last_leave_time; /* when this client last left a channel */
+ int join_leave_count; /* count of JOIN/LEAVE in less
+ * than MIN_JOIN_LEAVE_TIME seconds */
+ int oper_warn_count_down; /* warn opers of this possible spambot
+ * every time this gets to 0 */
+#endif
+ char buffer[BUFSIZE]; /* Incoming message buffer */
+ short lastsq; /* # of 2k blocks when sendqueued called
+ * last */
+ SBuf sendQ; /* Outgoing message queue--if socket full */
+ SBuf recvQ; /* Hold for data incoming yet to be parsed */
+ long sendM; /* Statistics: protocol messages send */
+ long sendK; /* Statistics: total k-bytes send */
+ long receiveM; /* Statistics: protocol messages received */
+ long receiveK; /* Statistics: total k-bytes received */
+ u_short sendB; /* counters to count upto 1-k lots of bytes */
+ u_short receiveB; /* sent and received. */
+ long lastrecvM; /* to check for activity --Mika */
+ int priority;
+ aListener *lstn; /* listener which we accepted from */
+ int authfd; /* fd for rfc931 authentication */
+ char username[USERLEN + 1]; /* username here now for auth stuff */
+ unsigned short port; /* and the remote port# too :-) */
+ struct hostent *hostp;
+#ifdef ANTI_NICK_FLOOD
+ time_t last_nick_change;
+ int number_of_nick_changes;
+#endif
+#ifdef NO_AWAY_FLUD
+ time_t alas; /* last time of away set */
+ int acount; /* count of away settings */
+#endif
+
+ char sockhost[HOSTLEN + 1]; /* This is the host name from
+ * the socket and after which the
+ * connection was accepted. */
+ char passwd[PASSWDLEN + 1];
+ /* try moving this down here to prevent weird problems... ? */
+ int oflag; /* Operator Flags */
+ int sockerr; /* what was the last error returned for
+ * this socket? */
+ int capabilities; /* what this server/client supports */
+ aClass *class; /* our current effective class */
+
+#ifdef MSG_TARGET_LIMIT
+ struct {
+ struct Client *cli;
+ time_t sent;
+ } targets[MSG_TARGET_MAX]; /* structure for target rate limiting */
+ time_t last_target_complain;
+ unsigned int num_target_errors;
+#endif
+
+};
+
+#define CLIENT_LOCAL_SIZE sizeof(aClient)
+#define CLIENT_REMOTE_SIZE offsetof(aClient,count)
+/* statistics structures */
+struct stats
+{
+ unsigned int is_cl; /* number of client connections */
+ unsigned int is_sv; /* number of server connections */
+ unsigned int is_ni; /* connection but no idea who it was */
+ unsigned short is_cbs; /* bytes sent to clients */
+ unsigned short is_cbr; /* bytes received to clients */
+ unsigned short is_sbs; /* bytes sent to servers */
+ unsigned short is_sbr; /* bytes received to servers */
+ unsigned long is_cks; /* k-bytes sent to clients */
+ unsigned long is_ckr; /* k-bytes received to clients */
+ unsigned long is_sks; /* k-bytes sent to servers */
+ unsigned long is_skr; /* k-bytes received to servers */
+ time_t is_cti; /* time spent connected by clients */
+ time_t is_sti; /* time spent connected by servers */
+ unsigned int is_ac; /* connections accepted */
+ unsigned int is_ref; /* accepts refused */
+ unsigned int is_throt; /* accepts throttled */
+ unsigned int is_drone; /* refused drones */
+ unsigned int is_unco; /* unknown commands */
+ unsigned int is_wrdi; /* command going in wrong direction */
+ unsigned int is_unpf; /* unknown prefix */
+ unsigned int is_empt; /* empty message */
+ unsigned int is_num; /* numeric message */
+ unsigned int is_kill; /* number of kills generated on collisions */
+ unsigned int is_fake; /* MODE 'fakes' */
+ unsigned int is_asuc; /* successful auth requests */
+ unsigned int is_abad; /* bad auth requests */
+ unsigned int is_udp; /* packets recv'd on udp port */
+ unsigned int is_loc; /* local connections made */
+ unsigned int is_ref_1; /* refused at kline stage 1 */
+ unsigned int is_ref_2; /* refused at kline stage 2 */
+#ifdef FLUD
+ unsigned int is_flud; /* users/channels flood protected */
+#endif /* FLUD */
+};
+
+/* mode structure for channels */
+
+struct SMode
+{
+ unsigned int mode;
+ int limit;
+ char key[KEYLEN + 1];
+ int join_num;
+ int join_time;
+};
+
+/* Message table structure */
+
+struct Message
+{
+ char *cmd;
+ int (*func) ();
+ unsigned int count; /* number of times command used */
+ int parameters;
+ char flags;
+
+ /* bit 0 set means that this command is allowed to be used only on
+ * the average of once per 2 seconds -SRB */
+
+ /* I could have defined other bit maps to above instead of the next
+ * two flags that I added. so sue me. -Dianora */
+
+ char allow_unregistered_use; /* flag if this command can be used
+ * if unregistered */
+
+ char reset_idle; /* flag if this command causes idle time to be
+ * reset */
+ unsigned long bytes;
+};
+
+typedef struct msg_tree
+{
+ char *final;
+ struct Message *msg;
+ struct msg_tree *pointers[26];
+} MESSAGE_TREE;
+
+/*
+ * Move BAN_INFO information out of the SLink struct its _only_ used
+ * for bans, no use wasting the memory for it in any other type of
+ * link. Keep in mind, doing this that it makes it slower as more
+ * Malloc's/Free's have to be done, on the plus side bans are a smaller
+ * percentage of SLink usage. Over all, the th+hybrid coding team came
+ * to the conclusion it was worth the effort.
+ *
+ * - Dianora
+ */
+
+struct Ban
+{
+ char *banstr;
+ char *who;
+ time_t when;
+ u_char type;
+ aBan *next;
+};
+
+#ifdef INVITE_LISTS
+/* channel invite list structure */
+
+struct LInvite
+{
+ char* invstr;
+ char* who;
+ time_t when;
+ anInvite* next;
+};
+#endif
+
+#ifdef EXEMPT_LISTS
+/* channel ban exempt list structure */
+
+struct Exempt
+{
+ char* banstr;
+ char* who;
+ time_t when;
+ u_char type;
+ aBanExempt* next;
+};
+#endif
+
+/* channel member link structure, used for chanmember chains */
+struct ChanLink
+{
+ struct ChanLink *next;
+ aClient *cptr;
+ int flags;
+ unsigned int banserial; /* used for bquiet cache */
+};
+
+/* general link structure used for chains */
+
+struct SLink
+{
+ struct SLink *next;
+ union
+ {
+ aClient *cptr;
+ aChannel *chptr;
+ aConnect *aconn; /* here for resolver purposes */
+ aBan *banptr;
+ aWatch *wptr;
+ char *cp;
+ } value;
+ int flags;
+};
+
+struct SLinkD
+{
+ struct SLinkD *next;
+ struct SLinkD *prev;
+ union
+ {
+ aClient *cptr;
+ aChannel *chptr;
+ aBan *banptr;
+ aWatch *wptr;
+ char *cp;
+ } value;
+ int flags;
+};
+
+/* channel structure */
+
+struct Channel
+{
+ struct Channel *nextch, *prevch, *hnextch;
+ int hashv; /* raw hash value */
+ Mode mode;
+ char topic[TOPICLEN + 1];
+ char topic_nick[NICKLEN + 1];
+ time_t topic_time;
+ int users;
+ chanMember* members;
+ Link* invites; /* users invited to the channel */
+ aBan* banlist;
+#ifdef INVITE_LISTS
+ anInvite* invite_list; /* +I list */
+#endif
+#ifdef EXEMPT_LISTS
+ aBanExempt* banexempt_list;
+#endif
+ ts_val channelts;
+#ifdef FLUD
+ time_t fludblock;
+ struct fludbot *fluders;
+#endif
+ char chname[CHANNELLEN+1];
+ int join_start; /* these two are for +j watching */
+ int join_count;
+ int default_join_start; /* these two handle the default joinrate handling */
+ int default_join_count;
+ unsigned int banserial; /* used for bquiet cache */
+};
+
+#define TS_CURRENT 5 /* current TS protocol version */
+#define TS_MIN 3 /* minimum supported TS protocol version */
+#define TS_DOESTS 0x20000000
+#define DoesTS(x) ((x)->tsinfo == TS_DOESTS)
+/* Channel Related macros follow */
+
+/* Channel related flags */
+
+#define CHFL_CHANOP 0x0001 /* Channel operator */
+#define CHFL_VOICE 0x0002 /* the power to speak */
+#define CHFL_DEOPPED 0x0004 /* deopped by us, modes need to be bounced */
+#define CHFL_BANNED 0x0008 /* is banned */
+
+/* ban mask types */
+
+#define MTYP_FULL 0x01 /* mask is nick!user@host */
+#define MTYP_USERHOST 0x02 /* mask is user@host */
+#define MTYP_HOST 0x04 /* mask is host only */
+
+/* Channel Visibility macros */
+
+#define MODE_CHANOP CHFL_CHANOP
+#define MODE_VOICE CHFL_VOICE
+#define MODE_DEOPPED CHFL_DEOPPED
+#define MODE_PRIVATE 0x00008
+#define MODE_SECRET 0x00010
+#define MODE_MODERATED 0x00020
+#define MODE_TOPICLIMIT 0x00040
+#define MODE_INVITEONLY 0x00080
+#define MODE_NOPRIVMSGS 0x00100
+#define MODE_KEY 0x00200
+#define MODE_BAN 0x00400
+#define MODE_LIMIT 0x00800
+#define MODE_REGISTERED 0x01000
+#define MODE_REGONLY 0x02000
+#define MODE_NOCOLOR 0x04000
+#define MODE_OPERONLY 0x08000
+#define MODE_MODREG 0x10000
+#define MODE_LISTED 0x20000
+#define MODE_JOINRATE 0x40000
+
+/* mode flags which take another parameter (With PARAmeterS) */
+
+#define MODE_WPARAS (MODE_CHANOP|MODE_VOICE|MODE_BAN|MODE_KEY|MODE_LIMIT)
+
+/*
+ * Undefined here, these are used in conjunction with the above modes
+ * in the source. #define MODE_DEL 0x40000000 #define
+ * MODE_ADD 0x80000000
+ */
+
+#define HoldChannel(x) (!(x))
+
+/*name invisible */
+
+#define SecretChannel(x) ((x) && ((x)->mode.mode & MODE_SECRET))
+
+/* channel not shown but names are */
+
+#define HiddenChannel(x) ((x) && ((x)->mode.mode & MODE_PRIVATE))
+
+/* channel visible */
+
+#define ShowChannel(v,c) (PubChannel(c) || IsMember((v),(c)))
+#define PubChannel(x) ((!x) || ((x)->mode.mode &\
+ (MODE_PRIVATE | MODE_SECRET)) == 0)
+
+#define IsMember(blah,chan) ((blah && blah->user && \
+ find_channel_link((blah->user)->channel, chan)) ? 1 : 0)
+
+#define IsChannelName(name) ((name) && (*(name) == '#'))
+
+/* Misc macros */
+
+#define BadPtr(x) (!(x) || (*(x) == '\0'))
+
+#define isvalid(c) (((c) >= 'A' && (c) < '~') || IsDigit(c) || (c) == '-')
+
+#define MyConnect(x) ((x)->fd >= 0)
+#define MyClient(x) (MyConnect(x) && IsClient(x))
+#define MyOper(x) (MyConnect(x) && IsOper(x))
+
+/* String manipulation macros */
+
+/* strncopynt --> strncpyzt to avoid confusion, sematics changed N must
+ * be now the number of bytes in the array --msa */
+
+#define strncpyzt(x, y, N) do{(void)strncpy(x,y,N);x[N-1]='\0';}while(0)
+#define StrEq(x,y) (!strcmp((x),(y)))
+
+/* used in SetMode() in channel.c and m_umode() in s_msg.c */
+
+#define MODE_NULL 0
+#define MODE_ADD 0x40000000
+#define MODE_DEL 0x20000000
+
+/* return values for hunt_server() */
+
+#define HUNTED_NOSUCH (-1) /* if the hunted server is not found */
+#define HUNTED_ISME 0 /* if this server should execute the command */
+#define HUNTED_PASS 1 /* if message passed onwards successfully */
+
+/* used when sending to #mask or $mask */
+
+#define MATCH_SERVER 1
+#define MATCH_HOST 2
+
+/* used for async dns values */
+
+#define ASYNC_NONE (-1)
+#define ASYNC_CLIENT 0
+#define ASYNC_CONNECT 1
+#define ASYNC_CONF 2
+#define ASYNC_SERVER 3
+
+/* misc variable externs */
+
+extern char version[128], *infotext[];
+extern char *generation, *creation;
+
+/* misc defines */
+
+#define ZIP_NEXT_BUFFER -4
+#define RC4_NEXT_BUFFER -3
+#define FLUSH_BUFFER -2
+#define UTMP "/etc/utmp"
+#define COMMA ","
+
+#ifdef ORATIMING
+/*
+ * Timing stuff (for performance measurements): compile with
+ * -DORATIMING and put a TMRESET where you want the counter of time
+ * spent set to 0, a TMPRINT where you want the accumulated results,
+ * and TMYES/TMNO pairs around the parts you want timed -orabidoo
+ */
+
+extern struct timeval tsdnow, tsdthen;
+extern unsigned long tsdms;
+
+#define TMRESET tsdms=0;
+#define TMYES gettimeofday(&tsdthen, NULL);
+#define TMNO gettimeofday(&tsdnow, NULL);\
+ if (tsdnow.tv_sec!=tsdthen.tv_sec) \
+ tsdms+=1000000*(tsdnow.tv_sec-tsdthen.tv_sec);\
+ tsdms+=tsdnow.tv_usec; tsdms-=tsdthen.tv_usec;
+#define TMPRINT sendto_ops("Time spent: %ld ms", tsdms);
+#else
+#define TMRESET
+#define TMYES
+#define TMNO
+#define TMPRINT
+#endif
+
+/* allow 5 minutes after server rejoins the network before allowing
+ * chanops new channel */
+
+#ifdef FLUD
+struct fludbot
+{
+ struct Client *fluder;
+ int count;
+ time_t first_msg, last_msg;
+ struct fludbot *next;
+};
+
+#endif /* FLUD */
+
+struct Watch
+{
+ aWatch *hnext;
+ time_t lasttime;
+ Link *watch;
+ char nick[1];
+};
+
+struct ListOptions
+{
+ LOpts *next;
+ Link *yeslist, *nolist;
+ int starthash;
+ short int showall, only_listed;
+ unsigned short usermin;
+ int usermax;
+ time_t currenttime;
+ time_t chantimemin;
+ time_t chantimemax;
+ time_t topictimemin;
+ time_t topictimemax;
+};
+
+typedef struct SearchOptions
+{
+ int umodes;
+ char *nick;
+ char *user;
+ char *host;
+ char *gcos;
+ char *ip;
+ int class;
+ int class_value;
+ unsigned int cidr4_ip;
+ unsigned int cidr4_mask;
+ int ts;
+ int ts_value;
+ aChannel *channel;
+ aClient *server;
+ unsigned int channelflags;
+ unsigned int client_type;
+#ifdef AIX
+ unsigned umode_plus:1;
+ unsigned nick_plus:1;
+ unsigned user_plus:1;
+ unsigned host_plus:1;
+ unsigned gcos_plus:1;
+ unsigned ip_plus:1;
+ unsigned cidr4_plus:1;
+ unsigned chan_plus:1;
+ unsigned serv_plus:1;
+ unsigned away_plus:1;
+ unsigned check_away:1;
+ unsigned check_umode:1;
+ unsigned show_chan:1;
+ unsigned search_chan:1;
+ unsigned ip_show:1;
+ unsigned client_type_plus:1;
+ /* unsigned spare:0; spare space for more stuff(?) */
+#else
+ char umode_plus:1;
+ char nick_plus:1;
+ char user_plus:1;
+ char host_plus:1;
+ char gcos_plus:1;
+ char ip_plus:1;
+ char cidr4_plus:1;
+ char chan_plus:1;
+ char serv_plus:1;
+ char away_plus:1;
+ char check_away:1;
+ char check_umode:1;
+ char show_chan:1;
+ char search_chan:1;
+ char ip_show:1;
+ char client_type_plus:1;
+ /* char spare:0; spare space for more stuff(?) */
+#endif
+} SOpts;
+
+/*
+ * Send /LIST as long as their output isn't blocking
+ * and we haven't used 2/3rds of their sendQ
+ */
+#define IsSendable(x) (!((x)->flags & FLAGS_BLOCKED) && \
+ SBufLength(&(x)->sendQ) < (int) \
+ ((float) (x)->class->maxsendq / 1.5))
+#define DoList(x) (((x)->user) && ((x)->user->lopt))
+
+/* internal defines for cptr->sockerr */
+#define IRCERR_BUFALLOC -11
+#define IRCERR_ZIP -12
+
+#endif /* __struct_include__ */
+
--- /dev/null
+/* include/structfunc.h
+ * Copyright(c) 2003, Aaron Wiebe
+ * Bahamut Development Team
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: structfunc.h,v 1.1 2005/01/12 07:44:58 mmondor Exp $ */
+
+/* This file includes external function defines for aClient (and possibly
+ * other) structure references. */
+
+extern aClient *ac_next(aClient *);
+extern aClient *ac_prev(aClient *);
+extern anUser *ac_user(aClient *);
+extern aServer *ac_server(aClient *);
+extern aWhowas *ac_whowas(aClient *);
+extern aClient *ac_from(aClient *);
+extern aClient *ac_uplink(aClient *);
+extern time_t ac_lasttime(aClient *);
+extern time_t ac_firsttime(aClient *);
+extern time_t ac_since(aClient *);
+extern ts_val ac_tsinfo(aClient *);
+extern int ac_fd(aClient *);
+extern int ac_hopcount(aClient *);
+extern short ac_status(aClient *);
+extern char ac_nicksent(aClient *);
+extern char *ac_name(aClient *);
+extern char *ac_info(aClient *);
+#ifdef FLUD
+extern Link *ac_fludees(aClient *);
+#endif
+extern struct in_addr ac_ip(aClient *);
+extern char *ac_hostip(aClient *);
+extern Link *ac_watch(aClient *);
+extern int ac_watches(aClient *);
+/******************************************
+ * These are the local functions...
+ ******************************************/
+extern int ac_count(aClient *);
+#ifdef FLUD
+extern time_t ac_fludblock(aClient *);
+extern struct fludbot *ac_fluders(aClient *);
+#endif
+#ifdef ANTI_SPAMBOT
+extern time_t ac_last_join_time(aClient *);
+extern time_t ac_last_leave_time(aClient *);
+extern int ac_join_leave_count(aClient *);
+extern int ac_oper_warn_count_down(aClient *);
+#endif
+extern char *ac_buffer(aClient *);
+extern short ac_lastsq(aClient *);
+extern SBuf *ac_sendQ(aClient *);
+extern SBuf *ac_recvQ(aClient *);
+extern long ac_sendM(aClient *);
+extern long ac_sendK(aClient *);
+extern long ac_recieveM(aClient *);
+extern long ac_recieveK(aClient *);
+extern u_short ac_sendB(aClient *);
+extern u_short ac_recieveB(aClient *);
+extern long ac_lastrecvM(aClient *);
+extern int ac_priority(aClient *);
+extern aListener *ac_lstn(aClient *);
+extern Link *ac_confs(aClient *);
+extern int ac_authfd(aClient *);
+extern char *ac_username(aClient *);
+extern unsigned short ac_port(aClient *);
+extern struct hostent *ac_hostp(aClient *);
+#ifdef ANTI_NICK_FLOOD
+extern time_t ac_last_nick_change(aClient *);
+extern int ac_number_of_nick_changes(aClient *);
+#endif
+#ifdef NO_AWAY_FLUD
+extern time_t ac_alas(aClient *);
+extern int ac_acount(aClient *);
+#endif
+extern char *ac_sockhost(aClient *);
+extern char *ac_passwd(aClient *);
+extern int ac_oflag(aClient *);
+extern int ac_sockerr(aClient *);
+extern int ac_capabilities(aClient *);
+extern int ac_pingval(aClient *);
+extern int ac_sendqlen(aClient *);
+/********************************
+ * These are channel access functions
+ ********************************/
+extern aChannel *ch_next(aChannel *);
+extern aChannel *ch_prev(aChannel *);
+extern aChannel *ch_hnext(aChannel *);
+extern int ch_hashv(aChannel *);
+extern Mode ch_mode(aChannel *);
+extern char *ch_topic(aChannel *);
+extern char *ch_topic_nick(aChannel *);
+extern time_t ch_topic_time(aChannel *);
+extern int ch_users(aChannel *);
+extern chanMember *ch_members(aChannel *);
+extern Link *ch_invites(aChannel *);
+extern aBan *ch_banlist(aChannel *);
+#ifdef INVITE_LISTS
+extern anInvite *ch_invite_list(aChannel *);
+#endif
+#ifdef EXEMPT_LISTS
+extern aBanExempt *ch_banexempt_list(aChannel *);
+#endif
+extern ts_val ch_channelts(aChannel *);
+#ifdef FLUD
+extern time_t ch_fludblock(aChannel *);
+extern struct fludbot *ch_fluders(aChannel *);
+#endif
+extern char *ch_chname(aChannel *);
+extern int ch_join_start(aChannel *);
+extern int ch_join_count(aChannel *);
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, include/sys.h
+ * Copyright (C) 1990 University of Oulu, Computing Center
+ *
+ * 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 1, 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.
+ *
+ */
+
+/* $Id: sys.h,v 1.1 2005/01/12 07:44:58 mmondor Exp $ */
+
+#ifndef __sys_include__
+#define __sys_include__
+#ifdef ISC202
+#include <net/errno.h>
+#else
+#include <sys/errno.h>
+#endif
+#include "setup.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+
+#if defined( HAVE_UNISTD_H )
+#include <unistd.h>
+#endif
+
+#if defined( HAVE_STDLIB_H )
+#include <stdlib.h>
+#endif
+
+#if defined( HAVE_STRINGS_H )
+#include <strings.h>
+#endif
+
+#if defined( HAVE_STRING_H )
+#include <string.h>
+#endif
+
+#if defined( HAVE_LIMITS_H )
+#include <limits.h>
+#endif
+
+#define strcasecmp mycmp
+#define strncasecmp myncmp
+
+#if !defined( HAVE_INDEX )
+#define index strchr
+#define rindex strrchr
+#endif
+
+#ifdef AIX
+#include <sys/select.h>
+#include <time.h>
+#endif
+
+#include <sys/time.h>
+
+#if ((__GNU_LIBRARY__ == 6) && (__GLIBC__ >=2) && (__GLIBC_MINOR__ >= 2))
+#include <time.h>
+#endif
+
+#ifdef WRITEV_IOV
+#include <sys/uio.h>
+#endif
+
+#define MyFree(x) do { if (x) free(x); (x) = NULL; } while(0)
+
+extern void dummy();
+
+#ifdef NO_U_TYPES
+
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+typedef unsigned long u_long;
+typedef unsigned int u_int;
+
+#endif
+
+#endif /* __sys_include__ */
--- /dev/null
+#ifndef THROTTLE_H
+#define THROTTLE_H
+/*
+ * Copyright 2000, 2001 Chip Norkus
+ *
+ * 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.
+ *
+ * 2a. 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.
+ * 2b. Redistribution in binary form requires specific prior written
+ * authorization of the maintainer.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Chip Norkus.
+ *
+ * 4. The names of the maintainer, developers and contributors may not be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MAINTAINER, DEVELOPERS 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 DEVELOPERS 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.
+ */
+
+/* define functions with throttling enabled, then add other definitions later
+ * in case throttling was removed at compile time to speed along the system ;)
+ * the functions are pretty simple, externally. throttle_check is given
+ * an IP in string dotted quad form, and returns 1 if it should be allowed,
+ * or 0 if it is to be throttled and dropped. this should be done at the same
+ * time as the z:line check. throttle_timer() should be called once per i/o
+ * loop to expire throttles and Z:lines. All other structures and functions
+ * can be found in src/throttle.c as they should not be accessed outside of it.
+ *
+ * additionally, throttle_init() should be called once at initialization stage
+ * to setup hash tables and what-have-you
+ */
+
+/* setting bits */
+extern int throttle_enable, throttle_tcount, throttle_ttime, throttle_rtime;
+void throttle_force(char *host);
+
+
+#ifdef THROTTLE_ENABLE
+int throttle_check(char *ip, int fd, time_t sotime);
+void throttle_remove(char *host);
+void throttle_timer(time_t now);
+
+void throttle_init(void);
+void throttle_rehash(void);
+void throttle_resize(int size);
+void throttle_stats(aClient *cptr, char *name);
+
+#else
+
+#define throttle_check(x,y,z) ((int)1)
+#define throttle_remove(x) ((void)0)
+#define throttle_timer(x) ((void)0)
+
+#define throttle_init() ((void)0)
+#define throttle_rehash() ((void)0)
+#define throttle_resize(x) ((void)0)
+#define throttle_stats(x,y) ((void)0)
+#endif
+
+
+#include "queue.h"
+
+SLIST_HEAD(hashent_list_t, hashent_t);
+typedef struct hashent_list_t hashent_list;
+
+typedef struct hashent_t
+{
+ void *ent;
+ SLIST_ENTRY(hashent_t) lp;
+} hashent;
+
+typedef struct hash_table_t
+{
+ int size; /* this should probably always be prime :) */
+ hashent_list *table; /* our table */
+ size_t keyoffset; /* this stores the offset of the key from the
+ given structure */
+ size_t keylen; /* the length of the key. if 0, assume key
+ is a NULL terminated string */
+
+#define HASH_FL_NOCASE 0x1 /* ignore case (ToLower before hash) */
+#define HASH_FL_STRING 0x2 /* key is a nul-terminated string, treat len
+ as a maximum length to hash */
+ int flags;
+ /* our comparison function, used in hash_find_ent(). this behaves much
+ * like the the compare function is used in qsort(). This means that a
+ * return of 0 (ZERO) means success! (this lets you use stuff like
+ * strncmp easily) */
+ int (*cmpfunc)(void *, void *);
+} hash_table;
+
+/* this function creates a hashtable with 'elems' buckets (elems should be
+* prime for best efficiency). 'offset' is the offset of the key from
+* structures being added (this should be obtained with the 'offsetof()'
+ * function). len is the length of the key, and flags are any flags for the
+* table (see above). cmpfunc is the function which should be used for
+* comparison when calling 'hash_find' */
+hash_table *create_hash_table(int elems, size_t offset, size_t len, int flags,
+ int (*cmpfunc)(void *, void *));
+/* this function destroys a previously created hashtable */
+void destroy_hash_table(hash_table *table);
+/* this function resizes a hash-table to the new size given with 'elems'.
+* this is not in any way inexpensive, and should really not be done very
+* often. */
+void resize_hash_table(hash_table *table, int elems);
+/* this function gets the hash value of a given key, relative to the size of
+* the hashtable */
+unsigned int hash_get_key_hash(hash_table *table, void *key, size_t offset);
+/* these functions do what you would expect, adding/deleting/finding items
+* in a hash table */
+int hash_insert(hash_table *table, void *ent);
+int hash_delete(hash_table *table, void *ent);
+void *hash_find(hash_table *table, void *key);
+
+#endif /* THROTTLE_H */
+/* vi:set ts=8 sts=4 sw=4 tw=79: */
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, include/userban.h
+ * Copyright (C) 2002 Lucas Madar
+ * and the DALnet coding team
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: userban.h,v 1.1 2005/01/12 07:44:58 mmondor Exp $ */
+
+#define UBAN_LOCAL 0x001 /* formerly known as a K: or Z: line */
+#define UBAN_NETWORK 0x002 /* formerly known as an autokill or an SZline */
+
+#define UBAN_GECOS 0x004 /* formerly known as an SGLINE */
+#define UBAN_NICK 0x008 /* formerly known as an SQLINE */
+
+#define UBAN_HOST 0x010 /* this ban matches against the user's resolved host */
+#define UBAN_IP 0x020 /* this ban matches against the user's IP address */
+
+#define UBAN_WILD 0x040 /* this ban has wildcards */
+
+#define UBAN_CIDR4 0x080 /* this ban is an IPv4 CIDR ban */
+#define UBAN_CIDR4BIG 0x100 /* this ban is an IPv4 CIDR ban for something greater than a /16 */
+
+#define UBAN_WILDUSER 0x200 /* Username is just '*' */
+#define UBAN_WILDHOST 0x400 /* Hostname is just '*.*' or '*' -- this ban is a user@* ban */
+
+#define UBAN_TEMPORARY 0x800 /* userban is temporary */
+
+#define SBAN_LOCAL 0x001
+#define SBAN_NETWORK 0x002
+#define SBAN_NICK 0x004 /* sban on the nick field */
+#define SBAN_GCOS 0x008 /* sban on the gcos field */
+#define SBAN_CHAN 0x010 /* sban on the chname field */
+#define SBAN_WILD 0x020 /* sban mask contains wildcards */
+#define SBAN_TEMPORARY 0x040 /* sban is temporary */
+
+struct userBan {
+ unsigned int flags;
+ char *u; /* username */
+ char *h; /* host or IP or GECOS or NICK */
+
+ unsigned int cidr4ip; /* cidr4 IP */
+ unsigned int cidr4mask; /* cidr4 mask */
+
+ char *reason;
+ time_t timeset; /* time this ban was set */
+ time_t duration; /* length of this ban, in seconds, or 0xFFFFFFFF for permanent */
+
+ void *internal_ent; /* internal -- pointer to banlist entry tag */
+};
+
+struct simBan {
+ unsigned int flags;
+ char *mask;
+
+ char *reason;
+ time_t timeset;
+ time_t duration;
+
+ void *internal_ent; /* internal -- pointer to banlist entry tag */
+};
+
+
+void init_userban();
+
+struct userBan *make_hostbased_ban(char *, char *);
+
+void add_hostbased_userban(struct userBan *);
+void remove_userban(struct userBan *);
+void userban_free(struct userBan *);
+
+struct userBan *check_userbanned(aClient *, unsigned int, unsigned int);
+struct userBan *find_userban_exact(struct userBan *, unsigned int);
+
+void expire_userbans();
+void remove_userbans_match_flags(unsigned int, unsigned int);
+void report_userbans_match_flags(aClient *cptr, unsigned int, unsigned int);
+
+int user_match_ban(aClient *, struct userBan *);
+char *get_userban_host(struct userBan *, char *, int);
+
+int count_userbans(aClient *cptr);
+
+/* Simban Calls */
+
+struct simBan *make_simpleban(unsigned int, char *);
+void add_simban(struct simBan *);
+void remove_simban(struct simBan *);
+struct simBan *find_simban_exact(struct simBan *);
+int user_match_simban(aClient *, struct simBan *);
+struct simBan *check_mask_simbanned(char *, unsigned int);
+void simban_free(struct simBan *);
+void remove_simban(struct simBan *);
+void remove_simbans_match_flags(unsigned int, unsigned int);
+void remove_simbans_match_mask(unsigned int, char *, int);
+void report_simbans_match_flags(aClient *, unsigned int, unsigned int);
+void expire_simbans();
+void send_simbans(aClient *, unsigned int);
+int count_simbans(aClient *);
+void remove_simban(struct simBan *);
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, include/whowas.h
+ * Copyright (C) 1990 Markku Savela
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: whowas.h,v 1.1 2005/01/12 07:44:58 mmondor Exp $ */
+
+#ifndef __whowas_include__
+#define __whowas_include__
+
+/* WHOWAS structure moved here from whowas.c */
+
+typedef struct aname
+{
+ anUser *ww_user;
+ aClient *ww_online;
+ time_t ww_logout;
+ char ww_nick[NICKLEN + 1];
+ char ww_info[REALLEN + 1];
+} aName;
+
+/*
+ * * add_history
+ * Add the currently defined name of the client to history.
+ * usually called before changing to a new name (nick).
+ * Client must be a fully registered user (specifically,
+ * the user structure must have been allocated).
+ */
+void add_history(aClient *, int);
+
+/*
+ * * off_history
+ * This must be called when the client structure is about to
+ * be released. History mechanism keeps pointers to client
+ * structures and it must know when they cease to exist. This
+ * also implicitly calls AddHistory.
+ */
+void off_history(aClient *);
+
+/*
+ * * get_history
+ * Return the current client that was using the given
+ * nickname within the timelimit. Returns NULL, if no
+ * one found...
+ */
+aClient *get_history(char *, time_t);
+
+int m_whowas(aClient *, aClient *, int, char *[]);
+
+#endif /* __whowas_include__ */
--- /dev/null
+extern void *zip_create_input_session();
+extern void *zip_create_output_session();
+extern char *zip_input(void *session, char *buffer, int *len, int *err,
+ char **nbuf, int *nlen);
+/* largedata is err return */
+extern char *zip_output(void *session, char *buffer, int *len,
+ int forceflush, int *largedata);
+extern int zip_is_data_out(void *session);
+extern void zip_out_get_stats(void *session, unsigned long *insiz,
+ unsigned long *outsiz, double *ratio);
+extern void zip_in_get_stats(void *session, unsigned long *insiz,
+ unsigned long *outsiz, double *ratio);
+extern void zip_destroy_input_session(void *session);
+extern void zip_destroy_output_session(void *session);
+
--- /dev/null
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
--- /dev/null
+CC=@CC@
+RM=@RM@
+MV=@MV@
+IRCDLIBS=@LIBS@ ../zlib/libz.a
+INCLUDEDIR=-I../include
+OPENSSLINC=@SSL_INCLUDES@
+ENGINE=@SENGINE@
+CRYPTO=@ENCRYPT_SRC@
+INSTALL=@INSTALL@
+INSTALL_BIN=@INSTALL_PROGRAM@
+INSTALL_DIR=@INSTALL_DIR@
+CFLAGS=@CFLAGS@
+
+RES_SRC =
+
+#This is only for very old systems that NEED this
+#RES_SRC = res_mkquery.c res_init.c res_comp.c
+
+SOURCES = blalloc.c bsd.c channel.c clientlist.c clones.c confparse.c \
+ fdlist.c fds.c hash.c hide.c inet_addr.c ircd.c ircsprintf.c list.c \
+ m_nick.c m_rwho.c m_server.c m_services.c m_stats.c m_who.c match.c \
+ modules.c packet.c parse.c pcre.c res.c s_auth.c s_bsd.c s_conf.c \
+ s_debug.c s_err.c s_misc.c s_numeric.c s_serv.c s_user.c sbuf.c \
+ scache.c send.c struct.c support.c throttle.c userban.c whowas.c \
+ zlink.c \
+ $(ENGINE) $(CRYPTO)
+
+OBJECTS = $(SOURCES:.c=.o) version.o
+
+all:
+ @echo ""
+ @echo "You're in the wrong directory. Make in ..!"
+ @echo ""
+
+build: ircd
+
+# Yuck - don't use this.
+depend:
+ makedepend $(INCLUDE) $(SOURCES)
+
+clean:
+ $(RM) -f $(OBJECTS) *~ ircd.core core ircd
+
+distclean: clean
+ $(RM) -f Makefile version.c.last
+
+.c.o:
+ $(CC) $(CFLAGS) $(INCLUDEDIR) -c $<
+
+ircd: $(OBJECTS)
+ $(CC) ${LDFLAGS} -o ircd $(OBJECTS) $(IRCDLIBS)
+ mv version.c version.c.last
+
+install:
+ @if test -f $(INSTALL_DIR)/ircd; then \
+ echo $(MV) $(INSTALL_DIR)/ircd $(INSTALL_DIR)/ircd.old; \
+ $(MV) $(INSTALL_DIR)/ircd $(INSTALL_DIR)/ircd.old; \
+ fi
+ @echo $(INSTALL_BIN) ircd $(INSTALL_DIR);
+ $(INSTALL_BIN) ircd $(INSTALL_DIR)
+
+version.c: version.c.SH
+ /bin/sh ./version.c.SH
+
+blalloc.o: blalloc.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h ../include/h.h \
+ ../include/send.h ../include/fdlist.h ../include/ircsprintf.h \
+ ../include/find.h ../include/numeric.h ../include/blalloc.h
+bsd.o: bsd.c ../include/struct.h ../include/config.h ../include/setup.h \
+ ../include/defs.h ../include/hash.h ../include/sbuf.h \
+ ../include/common.h ../include/sys.h ../include/h.h ../include/send.h \
+ ../include/fdlist.h ../include/ircsprintf.h ../include/find.h \
+ ../include/fds.h
+channel.o: channel.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h \
+ ../include/numeric.h ../include/channel.h ../include/msg.h \
+ ../include/h.h ../include/send.h ../include/fdlist.h \
+ ../include/ircsprintf.h ../include/find.h ../include/userban.h
+clientlist.o: clientlist.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h ../include/h.h \
+ ../include/send.h ../include/fdlist.h ../include/ircsprintf.h \
+ ../include/find.h ../include/numeric.h ../include/blalloc.h
+clones.o: clones.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h ../include/h.h \
+ ../include/send.h ../include/fdlist.h ../include/ircsprintf.h \
+ ../include/find.h ../include/blalloc.h ../include/numeric.h \
+ ../include/channel.h ../include/msg.h ../include/throttle.h \
+ ../include/queue.h ../include/clones.h
+confparse.o: confparse.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h ../include/h.h \
+ ../include/send.h ../include/fdlist.h ../include/ircsprintf.h \
+ ../include/find.h ../include/userban.h ../include/confparse.h
+fdlist.o: fdlist.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h ../include/h.h \
+ ../include/send.h ../include/fdlist.h ../include/ircsprintf.h \
+ ../include/find.h
+fds.o: fds.c ../include/struct.h ../include/config.h ../include/setup.h \
+ ../include/defs.h ../include/hash.h ../include/sbuf.h \
+ ../include/common.h ../include/sys.h ../include/h.h ../include/send.h \
+ ../include/fdlist.h ../include/ircsprintf.h ../include/find.h \
+ ../include/fds.h ../include/numeric.h
+hash.o: hash.c ../include/struct.h ../include/config.h ../include/setup.h \
+ ../include/defs.h ../include/hash.h ../include/sbuf.h \
+ ../include/common.h ../include/sys.h ../include/h.h ../include/send.h \
+ ../include/fdlist.h ../include/ircsprintf.h ../include/find.h
+hide.o: hide.c ../include/struct.h ../include/config.h ../include/setup.h \
+ ../include/defs.h ../include/hash.h ../include/sbuf.h \
+ ../include/common.h ../include/sys.h ../include/h.h ../include/send.h \
+ ../include/fdlist.h ../include/ircsprintf.h ../include/find.h \
+ ../include/fds.h ../include/numeric.h
+inet_addr.o: inet_addr.c ../include/setup.h ../include/struct.h \
+ ../include/config.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h \
+ ../include/nameser.h ../include/resolv.h
+ircd.o: ircd.c ../include/struct.h ../include/config.h ../include/setup.h \
+ ../include/defs.h ../include/hash.h ../include/sbuf.h \
+ ../include/common.h ../include/sys.h ../include/numeric.h \
+ ../include/msg.h ../include/inet.h ../include/h.h ../include/send.h \
+ ../include/fdlist.h ../include/ircsprintf.h ../include/find.h \
+ ../include/patchlevel.h ../include/dh.h ../include/throttle.h \
+ ../include/queue.h ../include/userban.h ../include/clones.h \
+ ../include/hooks.h ../include/fds.h
+ircsprintf.o: ircsprintf.c ../include/ircsprintf.h ../include/setup.h
+list.o: list.c ../include/struct.h ../include/config.h ../include/setup.h \
+ ../include/defs.h ../include/hash.h ../include/sbuf.h \
+ ../include/common.h ../include/sys.h ../include/h.h ../include/send.h \
+ ../include/fdlist.h ../include/ircsprintf.h ../include/find.h \
+ ../include/numeric.h ../include/blalloc.h ../include/dh.h \
+ ../include/zlink.h
+m_nick.o: m_nick.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h \
+ ../include/numeric.h ../include/msg.h ../include/channel.h \
+ ../include/h.h ../include/send.h ../include/fdlist.h \
+ ../include/ircsprintf.h ../include/find.h ../include/userban.h
+m_rwho.o: m_rwho.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h ../include/h.h \
+ ../include/send.h ../include/fdlist.h ../include/ircsprintf.h \
+ ../include/find.h ../include/numeric.h ../include/channel.h \
+ ../include/msg.h ../include/inet.h ../include/pcre.h
+m_server.o: m_server.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h \
+ ../include/numeric.h ../include/h.h ../include/send.h \
+ ../include/fdlist.h ../include/ircsprintf.h ../include/find.h \
+ ../include/dh.h ../include/userban.h ../include/zlink.h \
+ ../include/throttle.h ../include/queue.h ../include/clones.h
+m_services.o: m_services.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h \
+ ../include/numeric.h ../include/msg.h ../include/channel.h \
+ ../include/h.h ../include/send.h ../include/fdlist.h \
+ ../include/ircsprintf.h ../include/find.h ../include/userban.h \
+ ../include/clones.h
+m_stats.o: m_stats.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h \
+ ../include/numeric.h ../include/msg.h ../include/channel.h \
+ ../include/h.h ../include/send.h ../include/fdlist.h \
+ ../include/ircsprintf.h ../include/find.h ../include/zlink.h \
+ ../include/userban.h ../include/blalloc.h ../include/throttle.h \
+ ../include/queue.h ../include/whowas.h ../include/res.h
+m_who.o: m_who.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h \
+ ../include/numeric.h ../include/inet.h ../include/msg.h \
+ ../include/channel.h ../include/h.h ../include/send.h \
+ ../include/fdlist.h ../include/ircsprintf.h ../include/find.h
+match.o: match.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h
+modules.o: modules.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h \
+ ../include/numeric.h ../include/msg.h ../include/channel.h \
+ ../include/throttle.h ../include/queue.h ../include/h.h \
+ ../include/send.h ../include/fdlist.h ../include/ircsprintf.h \
+ ../include/find.h ../include/hooks.h
+packet.o: packet.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h ../include/msg.h \
+ ../include/h.h ../include/send.h ../include/fdlist.h \
+ ../include/ircsprintf.h ../include/find.h ../include/dh.h \
+ ../include/zlink.h
+parse.o: parse.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/msg.h ../include/sys.h \
+ ../include/numeric.h ../include/h.h ../include/send.h \
+ ../include/fdlist.h ../include/ircsprintf.h ../include/find.h
+pcre.o: pcre.c ../include/pcre_internal.h ../include/pcre_config.h \
+ ../include/setup.h ../include/pcre.h pcre_chartables.c
+res.o: res.c ../include/struct.h ../include/config.h ../include/setup.h \
+ ../include/defs.h ../include/hash.h ../include/sbuf.h \
+ ../include/common.h ../include/sys.h ../include/res.h \
+ ../include/numeric.h ../include/h.h ../include/send.h \
+ ../include/fdlist.h ../include/ircsprintf.h ../include/find.h \
+ ../include/fds.h ../include/nameser.h ../include/resolv.h \
+ ../include/inet.h
+s_auth.o: s_auth.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h ../include/res.h \
+ ../include/numeric.h ../include/patchlevel.h ../include/sock.h \
+ ../include/h.h ../include/send.h ../include/fdlist.h \
+ ../include/ircsprintf.h ../include/find.h ../include/fds.h
+s_bsd.o: s_bsd.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h ../include/res.h \
+ ../include/numeric.h ../include/patchlevel.h ../include/zlink.h \
+ ../include/throttle.h ../include/queue.h ../include/userban.h \
+ ../include/clones.h ../include/h.h ../include/send.h \
+ ../include/fdlist.h ../include/ircsprintf.h ../include/find.h \
+ ../include/inet.h ../include/hooks.h ../include/nameser.h \
+ ../include/resolv.h ../include/fds.h
+s_conf.o: s_conf.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h \
+ ../include/numeric.h ../include/inet.h ../include/h.h ../include/send.h \
+ ../include/fdlist.h ../include/ircsprintf.h ../include/find.h \
+ ../include/userban.h ../include/confparse.h
+s_debug.o: s_debug.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h ../include/h.h \
+ ../include/send.h ../include/fdlist.h ../include/ircsprintf.h \
+ ../include/find.h ../include/patchlevel.h ../include/numeric.h \
+ ../include/channel.h ../include/msg.h
+s_err.o: s_err.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/numeric.h ../include/h.h ../include/send.h \
+ ../include/fdlist.h ../include/ircsprintf.h ../include/find.h
+s_misc.o: s_misc.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h \
+ ../include/numeric.h ../include/zlink.h ../include/hooks.h \
+ ../include/clones.h ../include/h.h ../include/send.h \
+ ../include/fdlist.h ../include/ircsprintf.h ../include/find.h
+s_numeric.o: s_numeric.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h \
+ ../include/numeric.h ../include/channel.h ../include/msg.h \
+ ../include/h.h ../include/send.h ../include/fdlist.h \
+ ../include/ircsprintf.h ../include/find.h
+s_serv.o: s_serv.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h \
+ ../include/numeric.h ../include/msg.h ../include/channel.h \
+ ../include/nameser.h ../include/resolv.h ../include/dh.h \
+ ../include/zlink.h ../include/userban.h ../include/h.h \
+ ../include/send.h ../include/fdlist.h ../include/ircsprintf.h \
+ ../include/find.h ../include/throttle.h ../include/queue.h
+s_user.o: s_user.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h \
+ ../include/numeric.h ../include/msg.h ../include/channel.h \
+ ../include/throttle.h ../include/queue.h ../include/clones.h \
+ ../include/h.h ../include/send.h ../include/fdlist.h \
+ ../include/ircsprintf.h ../include/find.h ../include/blalloc.h \
+ ../include/userban.h ../include/hooks.h
+sbuf.o: sbuf.c ../include/sbuf.h ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/common.h ../include/sys.h ../include/h.h ../include/send.h \
+ ../include/fdlist.h ../include/ircsprintf.h ../include/find.h
+scache.o: scache.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h \
+ ../include/numeric.h ../include/h.h ../include/send.h \
+ ../include/fdlist.h ../include/ircsprintf.h ../include/find.h
+send.o: send.c ../include/struct.h ../include/config.h ../include/setup.h \
+ ../include/defs.h ../include/hash.h ../include/sbuf.h \
+ ../include/common.h ../include/sys.h ../include/h.h ../include/send.h \
+ ../include/fdlist.h ../include/ircsprintf.h ../include/find.h \
+ ../include/numeric.h ../include/dh.h ../include/zlink.h \
+ ../include/fds.h
+struct.o: struct.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h \
+ ../include/numeric.h ../include/msg.h ../include/channel.h \
+ ../include/throttle.h ../include/queue.h ../include/structfunc.h
+support.o: support.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h ../include/h.h \
+ ../include/send.h ../include/fdlist.h ../include/ircsprintf.h \
+ ../include/find.h
+throttle.o: throttle.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h ../include/res.h \
+ ../include/h.h ../include/send.h ../include/fdlist.h \
+ ../include/ircsprintf.h ../include/find.h ../include/numeric.h \
+ ../include/blalloc.h ../include/queue.h ../include/throttle.h
+userban.o: userban.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h \
+ ../include/numeric.h ../include/inet.h ../include/h.h ../include/send.h \
+ ../include/fdlist.h ../include/ircsprintf.h ../include/find.h \
+ ../include/userban.h ../include/queue.h
+version.o: version.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/patchlevel.h
+whowas.o: whowas.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/defs.h ../include/hash.h \
+ ../include/sbuf.h ../include/common.h ../include/sys.h \
+ ../include/numeric.h ../include/h.h ../include/send.h \
+ ../include/fdlist.h ../include/ircsprintf.h ../include/find.h
+
+dh.o: dh.c \
+ ../include/patchlevel.h
+ $(CC) $(CFLAGS) $(OPENSSLINC) $(INCLUDEDIR) -c $<
+rc4.o: rc4.c \
+ ../include/patchlevel.h
+zlink.o: zlink.c ../zlib/zlib.h ../zlib/zconf.h
+ $(CC) $(CFLAGS) $(INCLUDEDIR) -I../zlib -c $<
+socketengine_poll.o: ../include/config.h ../include/h.h
+socketengine_select.o: ../include/config.h ../include/h.h
+socketengine_kqueue.o: ../include/config.h ../include/h.h
+socketengine_epoll.o: ../include/config.h ../include/h.h
--- /dev/null
+/************************************************************************
+ *
+ * File: blalloc.c
+ * Owner: Wohali (Joan Touzet)
+ * Hacked up for use in ircd by Dianora
+ *************************************************************************/
+
+/* $Id: blalloc.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+/* INCLUDES */
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include "numeric.h"
+#include "blalloc.h"
+
+/* FUNCTION PROTOTYPES (LOCAL FUNCTIONS ONLY) */
+static int newblock(BlockHeap *bh);
+
+/* FUNCTION PROTOTYPES (EXTERN FUNCTIONS ONLY) */
+extern void outofmemory(); /* defined in list.c */
+
+/* FUNCTION DOCUMENTATION:
+ *
+ * newblock
+ * Description:
+ * mallocs a new block for addition to a blockheap
+ * Parameters:
+ * bh (IN): Pointer to parent blockheap.
+ * Returns:
+ * 0 if successful, 1 if not
+ */
+static int newblock(BlockHeap *bh)
+{
+ Block *b;
+ int i;
+ /* Setup the initial data structure. */
+ b = (Block *) MyMalloc(sizeof(Block));
+ if (b == NULL)
+ return 1;
+ b->freeElems = bh->elemsPerBlock;
+ b->next = bh->base;
+ b->allocMap = (unsigned long *) MyMalloc(sizeof(unsigned long) * (bh->numlongs + 1));
+ memset((void *) b->allocMap, '\0', (bh->numlongs + 1) * sizeof(unsigned long));
+ if (b->allocMap == NULL)
+ {
+ MyFree(b);
+ return 1;
+ }
+ /* Now allocate the memory for the elems themselves. */
+ b->elems = (void *) MyMalloc((bh->elemsPerBlock + 1) * bh->elemSize);
+ if (b->elems == NULL)
+ {
+ MyFree(b->allocMap);
+ MyFree(b);
+ return 1;
+ }
+ b->endElem = (void *) ((unsigned long) b->elems +
+ (unsigned long) ((bh->elemsPerBlock - 1) *
+ bh->elemSize));
+ /* Mark all blocks as free */
+ for (i = 0; i < bh->numlongs; i++)
+ b->allocMap[i] = 0L;
+ /* Finally, link it in to the heap. */
+ ++bh->blocksAllocated;
+ bh->freeElems += bh->elemsPerBlock;
+ bh->base = b;
+ return 0;
+}
+
+/* FUNCTION DOCUMENTATION:
+ *
+ * BlockHeapCreate
+ *
+ * Description:
+ * Creates a new blockheap from which smaller blocks can be allocated.
+ * Intended to be used instead of multiple calls to malloc() when
+ * performance is an issue.
+ * Parameters:
+ * elemsize (IN): Size of the basic element to be stored
+ * elemsperblock (IN): Number of elements to be stored in a single
+ * block of memory. When the blockheap runs out of free memory, it will
+ * allocate elemsize * elemsperblock more.
+ * Returns:
+ * Pointer to new BlockHeap, or NULL if unsuccessful
+ */
+BlockHeap *BlockHeapCreate(size_t elemsize, int elemsperblock)
+{
+ BlockHeap *bh;
+ /* Catch idiotic requests up front */
+ if ((elemsize <= 0) || (elemsperblock <= 0))
+ {
+ outofmemory(); /* die.. out of memory */
+ }
+ /* Allocate our new BlockHeap */
+ bh = (BlockHeap *) MyMalloc(sizeof(BlockHeap));
+ if (bh == NULL)
+ {
+ outofmemory(); /* die.. out of memory */
+ }
+ elemsize = elemsize + (elemsize & (sizeof(void *) - 1));
+ bh->elemSize = elemsize;
+ bh->elemsPerBlock = elemsperblock;
+ bh->blocksAllocated = 0;
+ bh->freeElems = 0;
+ bh->numlongs = (bh->elemsPerBlock / (sizeof(unsigned long) * 8)) + 1;
+ if ((bh->elemsPerBlock % (sizeof(unsigned long) * 8)) == 0)
+ bh->numlongs--;
+ bh->base = NULL;
+
+ /* Be sure our malloc was successful */
+ if (newblock(bh))
+ {
+ MyFree(bh);
+ outofmemory(); /* die.. out of memory */
+ }
+ /* DEBUG */
+ if (bh == NULL)
+ {
+ outofmemory(); /* die.. out of memory */
+ }
+ return bh;
+}
+
+/* FUNCTION DOCUMENTATION:
+ *
+ * BlockHeapAlloc
+ *
+ * Description:
+ * Returns a pointer to a struct within our BlockHeap that's free for
+ * the taking.
+ * Parameters:
+ * bh (IN): Pointer to the Blockheap.
+ * Returns:
+ * Pointer to a structure (void *), or NULL if unsuccessful.
+ */
+
+void *BlockHeapAlloc(BlockHeap *bh)
+{
+ Block *walker;
+ int unit;
+ unsigned long mask;
+ unsigned long ctr;
+ if (bh == NULL) return ((void *) NULL);
+ if (bh->freeElems == 0) /* Allocate new block and assign */
+ {
+ /* newblock returns 1 if unsuccessful, 0 if not */
+ if (newblock(bh))
+ {
+ return ((void *) NULL);
+ }
+ else
+ {
+ walker = bh->base;
+ walker->allocMap[0] = 0x1L;
+ walker->freeElems--;
+ bh->freeElems--;
+ if (bh->base->elems == NULL)
+ return ((void *) NULL);
+ }
+ return ((bh->base)->elems); /* ...and take the first elem. */
+ }
+ for (walker = bh->base; walker != NULL; walker = walker->next)
+ {
+ if (walker->freeElems > 0)
+ {
+ mask = 0x1L;
+ ctr = 0;
+ unit = 0;
+ while (unit < bh->numlongs)
+ {
+ if ((mask == 0x1L) && (walker->allocMap[unit] == ~0))
+ {
+ /* Entire subunit is used, skip to next one. */
+ unit++;
+ ctr = 0;
+ continue;
+ }
+ /* Check the current element, if free allocate block */
+ if (!(mask & walker->allocMap[unit]))
+ {
+ walker->allocMap[unit] |= mask; /* Mark block as used */
+ walker->freeElems--;
+ bh->freeElems--;
+ /* And return the pointer
+ *
+ * Address arithemtic is always ca-ca have to make sure
+ * the the bit pattern for the base address is converted
+ * into the same number of bits in an integer type, that
+ * has at least sizeof(unsigned long) at least ==
+ * sizeof(void *) -Dianora
+ */
+
+ return ((void *) ((unsigned long) walker->elems +
+ ((unit * sizeof(unsigned long) *
+ 8 + ctr) *
+ (unsigned long) bh->elemSize)));
+ }
+ /* Step up to the next unit */
+ mask <<= 1;
+ ctr++;
+ if (!mask)
+ {
+ mask = 0x1L;
+ unit++;
+ ctr = 0;
+ }
+ } /* while */
+ } /* if */
+ } /* for */
+
+ return ((void *) NULL); /* If you get here, something bad happened ! */
+}
+
+/* FUNCTION DOCUMENTATION:
+ *
+ * BlockHeapFree
+ *
+ * Description:
+ * Returns an element to the free pool, does not free()
+ * Parameters:
+ * bh (IN): Pointer to BlockHeap containing element
+ * ptr (in): Pointer to element to be "freed"
+ * Returns:
+ * 0 if successful, 1 if element not contained within BlockHeap.
+ */
+
+int BlockHeapFree(BlockHeap *bh, void *ptr)
+{
+ Block *walker;
+ unsigned long ctr;
+ unsigned long bitmask;
+ if (bh == NULL)
+ {
+#if defined(USE_SYSLOG) && defined(SYSLOG_BLOCK_ALLOCATOR)
+ syslog(LOG_DEBUG, "blalloc.c bh == NULL");
+#endif
+ return 1;
+ }
+ for (walker = bh->base; walker != NULL; walker = walker->next)
+ {
+ if ((ptr >= walker->elems) && (ptr <= walker->endElem))
+ {
+ ctr = ((unsigned long) ptr - (unsigned long) (walker->elems)) /
+ (unsigned long) bh->elemSize;
+ bitmask = 1L << (ctr % (sizeof(unsigned long) * 8));
+ ctr = ctr / (sizeof(unsigned long) * 8);
+ /* Flip the right allocation bit
+ *
+ * Complain if the bit is already clear, something is wrong
+ * (typically, someone freed the same block twice)
+ */
+ if ((walker->allocMap[ctr] & bitmask) == 0)
+ {
+ abort(); /* This is more useful than some random complaining */
+#if defined(USE_SYSLOG) && defined(SYSLOG_BLOCK_ALLOCATOR)
+ syslog(LOG_DEBUG, "blalloc.c bit already clear in map!");
+#endif
+ sendto_ops("blalloc.c bit already clear in map!");
+ sendto_ops("Please report to the bahamut team!"
+ "bahamut-bugs@bahamut.net");
+ }
+ else
+ {
+ walker->allocMap[ctr] = walker->allocMap[ctr] & ~bitmask;
+ walker->freeElems++;
+ bh->freeElems++;
+ }
+ return 0;
+ }
+ }
+ return 1;
+}
+/* FUNCTION DOCUMENTATION:
+ *
+ * BlockHeapGarbageCollect
+ *
+ * Description:
+ * Performs garbage colletion on the block heap. Any blocks that are
+ * completely unallocated are removed from the heap. Garbage
+ * collection will never remove the root node of the heap.
+ * Parameters:
+ * bh (IN): Pointer to the BlockHeap to be cleaned up
+ * Returns:
+ * 0 if successful, 1 if bh == NULL
+ */
+int BlockHeapGarbageCollect(BlockHeap *bh)
+{
+ Block *walker, *last;
+
+ if (bh == NULL) return 1;
+
+ if (bh->freeElems < bh->elemsPerBlock)
+ {
+ /* There couldn't possibly be an entire free block. Return. */
+ return 0;
+ }
+
+ last = NULL;
+ walker = bh->base;
+ while (walker)
+ {
+ /* This section rewritten Dec 10 1998 - Dianora */
+ int i;
+ for (i = 0; i < bh->numlongs; i++)
+ {
+ if (walker->allocMap[i])
+ break;
+ }
+ if (i == bh->numlongs)
+ {
+ /* This entire block is free. Remove it. */
+ MyFree(walker->elems);
+ MyFree(walker->allocMap);
+ if (last)
+ {
+ last->next = walker->next;
+ MyFree(walker);
+ walker = last->next;
+ }
+ else
+ {
+ bh->base = walker->next;
+ MyFree(walker);
+ walker = bh->base;
+ }
+ bh->blocksAllocated--;
+ bh->freeElems -= bh->elemsPerBlock;
+ }
+ else
+ {
+ last = walker;
+ walker = walker->next;
+ }
+ }
+ return 0;
+}
+
+/* FUNCTION DOCUMENTATION:
+ *
+ * BlockHeapDestroy
+ *
+ * Description:
+ * Completely free()s a BlockHeap. Use for cleanup.
+ * Parameters:
+ * bh (IN): Pointer to the BlockHeap to be destroyed.
+ * Returns:
+ * 0 if successful, 1 if bh == NULL
+ */
+int BlockHeapDestroy(BlockHeap *bh)
+{
+ Block *walker, *next;
+ if (bh == NULL) return 1;
+ for (walker = bh->base; walker != NULL; walker = next)
+ {
+ next = walker->next;
+ MyFree(walker->elems);
+ MyFree(walker->allocMap);
+ MyFree(walker);
+ }
+ MyFree(bh);
+ return 0;
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/bsd.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: bsd.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include "fds.h"
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+extern int errno; /* ...seems that errno.h doesn't define this everywhere */
+#ifndef SYS_ERRLIST_DECLARED
+extern char *sys_errlist[];
+#endif
+
+#if defined(DEBUGMODE) || defined (DNS_DEBUG)
+int writecalls = 0, writeb[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+int readcalls = 0;
+#endif
+void dummy()
+{
+ struct sigaction act;
+
+ act.sa_handler = dummy;
+ act.sa_flags = 0;
+ (void) sigemptyset(&act.sa_mask);
+ (void) sigaddset(&act.sa_mask, SIGALRM);
+ (void) sigaddset(&act.sa_mask, SIGPIPE);
+#ifdef SIGWINCH
+ (void) sigaddset(&act.sa_mask, SIGWINCH);
+#endif
+ (void) sigaction(SIGALRM, &act, (struct sigaction *) NULL);
+ (void) sigaction(SIGPIPE, &act, (struct sigaction *) NULL);
+#ifdef SIGWINCH
+ (void) sigaction(SIGWINCH, &act, (struct sigaction *) NULL);
+#endif
+}
+
+/*
+ * deliver_it
+ *
+ * Attempt to send a sequence of bytes to the connection.
+ * Returns
+ * < 0 Some fatal error occurred, (but not EWOULDBLOCK).
+ * his return is a request to close the socket and clean up the link.
+ * >= 0 No real error occurred, returns the number of bytes actually
+ * transferred. EWOULDBLOCK and other similar conditions should be mapped
+ * to zero return.
+ * Upper level routine will have to decide what to do with
+ * those unwritten bytes...
+ * *NOTE* alarm calls have been preserved, so this should work equally
+ * well whether blocking or non-blocking mode is used...
+ */
+#ifdef WRITEV_IOV
+int deliver_it(aClient *cptr, struct iovec *iov, int len)
+#else
+int deliver_it(aClient *cptr, char *str, int len)
+#endif
+{
+ int retval;
+ aListener *lptr = cptr->lstn;
+#ifdef DEBUGMODE
+ writecalls++;
+#endif
+#ifdef WRITEV_IOV
+ retval = writev(cptr->fd, iov, len);
+#else
+ retval = send(cptr->fd, str, len, 0);
+#endif
+ /*
+ * Convert WOULDBLOCK to a return of "0 bytes moved". This
+ * should occur only if socket was non-blocking. Note, that all is
+ * Ok, if the 'write' just returns '0' instead of an error and
+ * errno=EWOULDBLOCK.
+ */
+ if (retval < 0 && (errno == EWOULDBLOCK || errno == EAGAIN ||
+ errno == ENOBUFS))
+ {
+ retval = 0;
+ cptr->flags |= FLAGS_BLOCKED;
+ set_fd_flags(cptr->fd, FDF_WANTWRITE);
+ return (retval); /* Just get out now... */
+ }
+ else if (retval > 0)
+ {
+ if(cptr->flags & FLAGS_BLOCKED)
+ {
+ cptr->flags &= ~FLAGS_BLOCKED;
+ unset_fd_flags(cptr->fd, FDF_WANTWRITE);
+ }
+ }
+
+#ifdef DEBUGMODE
+ if (retval < 0)
+ {
+ writeb[0]++;
+ Debug((DEBUG_ERROR, "write error (%s) to %s",
+ sys_errlist[errno], cptr->name));
+ }
+ else if (retval == 0)
+ writeb[1]++;
+ else if (retval < 16)
+ writeb[2]++;
+ else if (retval < 32)
+ writeb[3]++;
+ else if (retval < 64)
+ writeb[4]++;
+ else if (retval < 128)
+ writeb[5]++;
+ else if (retval < 256)
+ writeb[6]++;
+ else if (retval < 512)
+ writeb[7]++;
+ else if (retval < 1024)
+ writeb[8]++;
+ else
+ writeb[9]++;
+#endif
+ if (retval > 0)
+ {
+ cptr->sendB += retval;
+ if (cptr->sendB & 0x0400)
+ {
+ cptr->sendK += (cptr->sendB >> 10);
+ cptr->sendB &= 0x03ff; /* 2^10 = 1024, 3ff = 1023 */
+ }
+ me.sendB += retval;
+ if (me.sendB & 0x0400)
+ {
+ me.sendK += (me.sendB >> 10);
+ me.sendB &= 0x03ff;
+ }
+
+ if (lptr)
+ {
+ lptr->sendB += retval;
+ if (lptr->sendB & 0x0400)
+ {
+ lptr->sendK += (lptr->sendB >> 10);
+ lptr->sendB &= 0x03ff;
+ }
+ }
+ }
+ return (retval);
+}
--- /dev/null
+/*
+ * IRC - Internet Relay Chat, src/channel.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Co Center
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: channel.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "channel.h"
+#include "h.h"
+#include "userban.h"
+
+int server_was_split = YES;
+
+aChannel *channel = NullChn;
+
+#ifdef INVITE_LISTS
+/* +I list functions */
+int add_invite_id(aClient*, aChannel*, char*);
+int del_invite_id(aChannel*, char*);
+anInvite* is_invited(aClient*, aChannel*);
+#endif
+
+#ifdef EXEMPT_LISTS
+/* +e list functions */
+int add_exempt_id(aClient*, aChannel*, char*);
+int del_exempt_id(aChannel*, char*);
+#endif
+
+static int add_banid(aClient *, aChannel *, char *);
+static int can_join(aClient *, aChannel *, char *);
+static void channel_modes(aClient *, char *, char *, aChannel *);
+static int del_banid(aChannel *, char *);
+static int is_banned(aClient *, aChannel *, chanMember *);
+static int set_mode(aClient *, aClient *, aChannel *, int,
+ int, char **, char *, char *);
+static void sub1_from_channel(aChannel *);
+
+int check_channelname(aClient *, unsigned char *);
+void clean_channelname(unsigned char *);
+static void add_invite(aClient *, aChannel *);
+void del_invite(aClient *, aChannel *);
+
+#ifdef ORATIMING
+struct timeval tsdnow, tsdthen;
+unsigned long tsdms;
+#endif
+
+/* number of seconds to add to all readings of time() when making TS's */
+
+static char *PartFmt = ":%s PART %s";
+static char *PartFmt2 = ":%s PART %s :%s";
+
+/* server <-> server SJOIN format */
+static char *SJOINFmt = ":%s SJOIN %ld %s %s %s :%s";
+/* NP means no paramaters, don't send the extra space there */
+static char *SJOINFmtNP = ":%s SJOIN %ld %s %s :%s";
+/* client SJOIN format, for no channel creation */
+static char *CliSJOINFmt = ":%s SJOIN %ld %s";
+
+/* some buffers for rebuilding channel/nick lists with ,'s */
+static char nickbuf[BUFSIZE], buf[BUFSIZE];
+static char modebuf[REALMODEBUFLEN], parabuf[REALMODEBUFLEN];
+
+/* externally defined function */
+extern Link *find_channel_link(Link *, aChannel *); /* defined in list.c */
+#ifdef ANTI_SPAMBOT
+extern int spam_num; /* defined in s_serv.c */
+extern int spam_time; /* defined in s_serv.c */
+#endif
+
+/* return the length (>=0) of a chain of links. */
+static int list_length(Link *lp)
+{
+ int count = 0;
+
+ for (; lp; lp = lp->next)
+ count++;
+ return count;
+}
+
+/* check to see if the message has any color chars in it. */
+static int
+msg_has_colors(char *msg)
+{
+
+ char *c;
+ if (msg == NULL)
+ return 0;
+ c = msg;
+ while(*c)
+ {
+ if(*c == '\003' || *c == '\033')
+ break;
+ else
+ c++;
+ }
+ if(*c)
+ return 1;
+ return 0;
+}
+
+/*
+ * find_chasing
+ * Find the client structure for a nick name (user) using history
+ * mechanism if necessary. If the client is not found, an error message
+ * (NO SUCH NICK) is generated. If the client was found through the
+ * history, chasing will be 1 and otherwise 0.
+ */
+aClient *find_chasing(aClient *sptr, char *user, int *chasing)
+{
+ aClient *who = find_client(user, (aClient *) NULL);
+
+ if (chasing)
+ *chasing = 0;
+ if (who)
+ return who;
+ if (!(who = get_history(user, (long) KILLCHASETIMELIMIT)))
+ {
+ sendto_one(sptr, err_str(ERR_NOSUCHNICK),
+ me.name, sptr->name, user);
+ return ((aClient *) NULL);
+ }
+ if (chasing)
+ *chasing = 1;
+ return who;
+}
+
+/*
+ * Fixes a string so that the first white space found becomes an end of
+ * string marker (`\-`). returns the 'fixed' string or "*" if the
+ * string was NULL length or a NULL pointer.
+ */
+static char * check_string(char *s)
+{
+ static char star[2] = "*";
+ char *str = s;
+
+ if (BadPtr(s))
+ return star;
+
+ for (; *s; s++)
+ if (IsSpace(*s))
+ {
+ *s = '\0';
+ break;
+ }
+
+ return (BadPtr(str)) ? star : str;
+}
+/*
+ * create a string of form "foo!bar@fubar" given foo, bar and fubar as
+ * the parameters. If NULL, they become "*".
+ */
+static char *make_nick_user_host(char *nick, char *name, char *host)
+{
+ static char namebuf[NICKLEN + USERLEN + HOSTLEN + 6];
+ int n;
+ char *ptr1, *ptr2;
+
+ ptr1 = namebuf;
+ for (ptr2 = check_string(nick), n = NICKLEN; *ptr2 && n--;)
+ *ptr1++ = *ptr2++;
+ *ptr1++ = '!';
+ for (ptr2 = check_string(name), n = USERLEN; *ptr2 && n--;)
+ *ptr1++ = *ptr2++;
+ *ptr1++ = '@';
+ for (ptr2 = check_string(host), n = HOSTLEN; *ptr2 && n--;)
+ *ptr1++ = *ptr2++;
+ *ptr1 = '\0';
+ return (namebuf);
+}
+
+#ifdef EXEMPT_LISTS
+/* Exempt list functions (+e) */
+
+int add_exempt_id(aClient* cptr, aChannel* chptr, char* exempt_id)
+{
+ aBanExempt* exempt = NULL;
+ int cnt = 0;
+
+ for (exempt = chptr->banexempt_list; exempt; exempt = exempt->next)
+ {
+ if (MyClient(cptr))
+ {
+ if (++cnt >= MAXEXEMPTLIST)
+ {
+ sendto_one(cptr, getreply(ERR_BANLISTFULL), me.name, cptr->name,
+ chptr->chname, exempt_id, "exempt");
+ return -1;
+ }
+ if (!match(exempt->banstr, exempt_id))
+ return -1;
+ }
+ else if (!mycmp(exempt->banstr, exempt_id))
+ return -1;
+ }
+ exempt = (aBanExempt*)MyMalloc(sizeof(aBanExempt));
+ exempt->banstr = (char*)MyMalloc(strlen(exempt_id)+1);
+ strcpy(exempt->banstr, exempt_id);
+ exempt->when = timeofday;
+ exempt->next = chptr->banexempt_list;
+ chptr->banexempt_list = exempt;
+ chptr->banserial++;
+
+ if (IsPerson(cptr))
+ {
+ exempt->who = (char *) MyMalloc(strlen(cptr->name) +
+ strlen(cptr->user->username) +
+ strlen(cptr->user->host) + 3);
+ (void) ircsprintf(exempt->who, "%s!%s@%s",
+ cptr->name, cptr->user->username, cptr->user->host);
+ }
+ else
+ {
+ exempt->who = (char *) MyMalloc(strlen(cptr->name) + 1);
+ (void) strcpy(exempt->who, cptr->name);
+ }
+
+ /* determine type for less matching later */
+ if(exempt_id[0] == '*' && exempt_id[1] == '!')
+ {
+ if(exempt_id[2] == '*' && exempt_id[3] == '@')
+ exempt->type = MTYP_HOST;
+ else
+ exempt->type = MTYP_USERHOST;
+ }
+ else
+ exempt->type = MTYP_FULL;
+
+ return 0;
+}
+
+int del_exempt_id(aChannel* chptr, char* exempt_id)
+{
+ aBanExempt** exempt;
+ aBanExempt* tmp;
+
+ if (!exempt_id)
+ return -1;
+ for (exempt = &chptr->banexempt_list; *exempt; exempt = &((*exempt)->next))
+ {
+ if (mycmp(exempt_id, (*exempt)->banstr) == 0)
+ {
+ tmp = *exempt;
+ *exempt = tmp->next;
+
+ chptr->banserial++;
+
+ MyFree(tmp->banstr);
+ MyFree(tmp->who);
+ MyFree(tmp);
+
+ break;
+ }
+ }
+ return 0;
+}
+
+#endif
+
+#ifdef INVITE_LISTS
+/* Invite list functions (+I) */
+
+int add_invite_id(aClient* cptr, aChannel* chptr, char* invite_id)
+{
+ anInvite* invite;
+ int cnt = 0;
+
+ for (invite = chptr->invite_list; invite; invite = invite->next)
+ {
+ if (MyClient(cptr))
+ {
+ if (++cnt >= MAXINVITELIST)
+ {
+ sendto_one(cptr, getreply(ERR_BANLISTFULL), me.name, cptr->name,
+ chptr->chname, invite_id, "invite");
+ return -1;
+ }
+ if (!match(invite->invstr, invite_id))
+ return -1;
+ }
+ else if (!mycmp(invite->invstr, invite_id))
+ return -1;
+ }
+
+ invite = (anInvite*)MyMalloc(sizeof(anInvite));
+ invite->invstr = (char*)MyMalloc(strlen(invite_id)+1);
+ strcpy(invite->invstr, invite_id);
+ invite->when = timeofday;
+ invite->next = chptr->invite_list;
+ chptr->invite_list = invite;
+
+ if (IsPerson(cptr))
+ {
+ invite->who = (char *) MyMalloc(strlen(cptr->name) +
+ strlen(cptr->user->username) +
+ strlen(cptr->user->host) + 3);
+ (void) ircsprintf(invite->who, "%s!%s@%s",
+ cptr->name, cptr->user->username, cptr->user->host);
+ }
+ else
+ {
+ invite->who = (char *) MyMalloc(strlen(cptr->name) + 1);
+ (void) strcpy(invite->who, cptr->name);
+ }
+ return 0;
+}
+
+int del_invite_id(aChannel* chptr, char* invite_id)
+{
+ anInvite** invite;
+ anInvite* tmp;
+
+ if (!invite_id)
+ return -1;
+ for (invite = &chptr->invite_list; *invite; invite = &((*invite)->next))
+ {
+ if (mycmp(invite_id, (*invite)->invstr) == 0)
+ {
+ tmp = *invite;
+ *invite = tmp->next;
+
+ MyFree(tmp->invstr);
+ MyFree(tmp->who);
+ MyFree(tmp);
+
+ break;
+ }
+ }
+ return 0;
+}
+
+anInvite* is_invited(aClient* cptr, aChannel* chptr)
+{
+ char s[NICKLEN + USERLEN + HOSTLEN + 6];
+ char *s2;
+ anInvite* invite;
+
+ strcpy(s, make_nick_user_host(cptr->name, cptr->user->username,
+ cptr->user->host));
+ s2 = make_nick_user_host(cptr->name, cptr->user->username,
+ cptr->hostip);
+
+ for (invite = chptr->invite_list; invite; invite = invite->next)
+ {
+ if (!match(invite->invstr, s) || !match(invite->invstr, s2))
+ break;
+ }
+ return invite;
+}
+
+#endif
+
+/* Ban functions to work with mode +b */
+/* add_banid - add an id to be banned to the channel (belongs to cptr) */
+
+static int add_banid(aClient *cptr, aChannel *chptr, char *banid)
+{
+ aBan *ban;
+ int cnt = 0;
+
+ for (ban = chptr->banlist; ban; ban = ban->next)
+ {
+ /* Begin unbreaking redundant ban checking. First step is to allow
+ * ALL non-duplicates from remote servers. Local clients are still
+ * subject to the flawed redundancy check for compatibility with
+ * older servers. This check can be corrected later. -Quension */
+ if (MyClient(cptr))
+ {
+ if (++cnt >= MAXBANS)
+ {
+ sendto_one(cptr, getreply(ERR_BANLISTFULL), me.name, cptr->name,
+ chptr->chname, banid, "ban");
+ return -1;
+ }
+ if (!match(ban->banstr, banid))
+ return -1;
+ }
+ else if (!mycmp(ban->banstr, banid))
+ return -1;
+ }
+
+ ban = (aBan *) MyMalloc(sizeof(aBan));
+ ban->banstr = (char *) MyMalloc(strlen(banid) + 1);
+ (void) strcpy(ban->banstr, banid);
+ ban->next = chptr->banlist;
+
+ if (IsPerson(cptr))
+ {
+ ban->who = (char *) MyMalloc(strlen(cptr->name) +
+ strlen(cptr->user->username) +
+ strlen(cptr->user->host) + 3);
+ (void) ircsprintf(ban->who, "%s!%s@%s",
+ cptr->name, cptr->user->username, cptr->user->host);
+ }
+ else
+ {
+ ban->who = (char *) MyMalloc(strlen(cptr->name) + 1);
+ (void) strcpy(ban->who, cptr->name);
+ }
+
+ /* determine what 'type' of mask this is, for less matching later */
+
+ if(banid[0] == '*' && banid[1] == '!')
+ {
+ if(banid[2] == '*' && banid[3] == '@')
+ ban->type = MTYP_HOST;
+ else
+ ban->type = MTYP_USERHOST;
+ }
+ else
+ ban->type = MTYP_FULL;
+
+ ban->when = timeofday;
+ chptr->banlist = ban;
+ chptr->banserial++;
+
+ return 0;
+}
+
+/*
+ * del_banid - delete an id belonging to cptr if banid is null,
+ * deleteall banids belonging to cptr.
+ */
+static int del_banid(aChannel *chptr, char *banid)
+{
+ aBan **ban;
+ aBan *tmp;
+
+ if (!banid)
+ return -1;
+ for (ban = &(chptr->banlist); *ban; ban = &((*ban)->next))
+ if (mycmp(banid, (*ban)->banstr) == 0)
+ {
+ tmp = *ban;
+ *ban = tmp->next;
+
+ chptr->banserial++;
+
+ MyFree(tmp->banstr);
+ MyFree(tmp->who);
+ MyFree(tmp);
+
+ break;
+ }
+ return 0;
+}
+
+/*
+ * is_banned - returns CHFL_BANNED if banned else 0
+ *
+ * caches banned status in chanMember for can_send()
+ * -Quension [Jun 2004]
+ */
+
+static int is_banned(aClient *cptr, aChannel *chptr, chanMember *cm)
+{
+ aBan *ban;
+#ifdef EXEMPT_LISTS
+ aBanExempt *exempt;
+#endif
+ char s[NICKLEN + USERLEN + HOSTLEN + 6];
+ char *s2;
+
+ if (!IsPerson(cptr))
+ return 0;
+
+ /* if cache is valid, use it */
+ if (cm)
+ {
+ if (cm->banserial == chptr->banserial)
+ return (cm->flags & CHFL_BANNED);
+ cm->banserial = chptr->banserial;
+ cm->flags &= ~CHFL_BANNED;
+ }
+
+ strcpy(s, make_nick_user_host(cptr->name, cptr->user->username,
+ cptr->user->host));
+ s2 = make_nick_user_host(cptr->name, cptr->user->username,
+ cptr->hostip);
+
+#ifdef EXEMPT_LISTS
+ for (exempt = chptr->banexempt_list; exempt; exempt = exempt->next)
+ if (!match(exempt->banstr, s) || !match(exempt->banstr, s2))
+ return 0;
+#endif
+
+ for (ban = chptr->banlist; ban; ban = ban->next)
+ if ((match(ban->banstr, s) == 0) ||
+ (match(ban->banstr, s2) == 0))
+ break;
+
+ if (ban)
+ {
+ if (cm)
+ cm->flags |= CHFL_BANNED;
+ return CHFL_BANNED;
+ }
+
+ return 0;
+}
+
+aBan *nick_is_banned(aChannel *chptr, char *nick, aClient *cptr)
+{
+ aBan *ban;
+#ifdef EXEMPT_LISTS
+ aBanExempt *exempt;
+#endif
+ char *s, s2[NICKLEN+USERLEN+HOSTLEN+6];
+
+ if (!IsPerson(cptr)) return NULL;
+
+ strcpy(s2, make_nick_user_host(nick, cptr->user->username,
+ cptr->user->host));
+ s = make_nick_user_host(nick, cptr->user->username, cptr->hostip);
+
+#ifdef EXEMPT_LISTS
+ for (exempt = chptr->banexempt_list; exempt; exempt = exempt->next)
+ if (exempt->type == MTYP_FULL &&
+ ((match(exempt->banstr, s2) == 0) ||
+ (match(exempt->banstr, s) == 0)))
+ return NULL;
+#endif
+
+ for (ban = chptr->banlist; ban; ban = ban->next)
+ if (ban->type == MTYP_FULL && /* only check applicable bans */
+ ((match(ban->banstr, s2) == 0) || /* check host before IP */
+ (match(ban->banstr, s) == 0)))
+ break;
+ return (ban);
+}
+
+void remove_matching_bans(aChannel *chptr, aClient *cptr, aClient *from)
+{
+ aBan *ban, *bnext;
+ char targhost[NICKLEN+USERLEN+HOSTLEN+6];
+ char targip[NICKLEN+USERLEN+HOSTLEN+6];
+ char *m;
+ int count = 0, send = 0;
+
+ if (!IsPerson(cptr)) return;
+
+ strcpy(targhost, make_nick_user_host(cptr->name, cptr->user->username,
+ cptr->user->host));
+ strcpy(targip, make_nick_user_host(cptr->name, cptr->user->username,
+ cptr->hostip));
+
+ m = modebuf;
+ *m++ = '-';
+ *m = '\0';
+
+ *parabuf = '\0';
+
+ ban = chptr->banlist;
+
+ while(ban)
+ {
+ bnext = ban->next;
+ if((match(ban->banstr, targhost) == 0) ||
+ (match(ban->banstr, targip) == 0))
+ {
+ if (strlen(parabuf) + strlen(ban->banstr) + 10 < (size_t) MODEBUFLEN)
+ {
+ if(*parabuf)
+ strcat(parabuf, " ");
+ strcat(parabuf, ban->banstr);
+ count++;
+ *m++ = 'b';
+ *m = '\0';
+ }
+ else
+ if(*parabuf)
+ send = 1;
+
+ if(count == MAXTSMODEPARAMS)
+ send = 1;
+
+ if(send)
+ {
+ sendto_channel_butserv_me(chptr, from, ":%s MODE %s %s %s",
+ from->name, chptr->chname, modebuf,
+ parabuf);
+ sendto_serv_butone(from, ":%s MODE %s %ld %s %s", from->name,
+ chptr->chname, chptr->channelts, modebuf,
+ parabuf);
+ send = 0;
+ *parabuf = '\0';
+ m = modebuf;
+ *m++ = '-';
+ if(count != MAXTSMODEPARAMS)
+ {
+ strcpy(parabuf, ban->banstr);
+ *m++ = 'b';
+ count = 1;
+ }
+ else
+ count = 0;
+ *m = '\0';
+ }
+
+ del_banid(chptr, ban->banstr);
+ }
+ ban = bnext;
+ }
+
+ if(*parabuf)
+ {
+ sendto_channel_butserv_me(chptr, from, ":%s MODE %s %s %s", from->name,
+ chptr->chname, modebuf, parabuf);
+ sendto_serv_butone(from, ":%s MODE %s %ld %s %s", from->name,
+ chptr->chname, chptr->channelts, modebuf, parabuf);
+ }
+
+ return;
+}
+
+#ifdef EXEMPT_LISTS
+void remove_matching_exempts(aChannel *chptr, aClient *cptr, aClient *from)
+{
+ aBanExempt *ex, *enext;
+ char targhost[NICKLEN+USERLEN+HOSTLEN+6];
+ char targip[NICKLEN+USERLEN+HOSTLEN+6];
+ char *m;
+ int count = 0, send = 0;
+
+ if (!IsPerson(cptr)) return;
+
+ strcpy(targhost, make_nick_user_host(cptr->name, cptr->user->username,
+ cptr->user->host));
+ strcpy(targip, make_nick_user_host(cptr->name, cptr->user->username,
+ cptr->hostip));
+
+ m = modebuf;
+ *m++ = '-';
+ *m = '\0';
+
+ *parabuf = '\0';
+
+ ex = chptr->banexempt_list;
+
+ while(ex)
+ {
+ enext = ex->next;
+ if((match(ex->banstr, targhost) == 0) ||
+ (match(ex->banstr, targip) == 0))
+ {
+ if (strlen(parabuf) + strlen(ex->banstr) + 10 < (size_t) MODEBUFLEN)
+ {
+ if(*parabuf)
+ strcat(parabuf, " ");
+ strcat(parabuf, ex->banstr);
+ count++;
+ *m++ = 'e';
+ *m = '\0';
+ }
+ else
+ if(*parabuf)
+ send = 1;
+
+ if(count == MAXTSMODEPARAMS)
+ send = 1;
+
+ if(send)
+ {
+ sendto_channel_butserv_me(chptr, from, ":%s MODE %s %s %s",
+ from->name, chptr->chname, modebuf,
+ parabuf);
+ sendto_serv_butone(from, ":%s MODE %s %ld %s %s", from->name,
+ chptr->chname, chptr->channelts, modebuf,
+ parabuf);
+ send = 0;
+ *parabuf = '\0';
+ m = modebuf;
+ *m++ = '-';
+ if(count != MAXTSMODEPARAMS)
+ {
+ strcpy(parabuf, ex->banstr);
+ *m++ = 'e';
+ count = 1;
+ }
+ else
+ count = 0;
+ *m = '\0';
+ }
+
+ del_exempt_id(chptr, ex->banstr);
+ }
+ ex = enext;
+ }
+
+ if(*parabuf)
+ {
+ sendto_channel_butserv_me(chptr, from, ":%s MODE %s %s %s", from->name,
+ chptr->chname, modebuf, parabuf);
+ sendto_serv_butone(from, ":%s MODE %s %ld %s %s", from->name,
+ chptr->chname, chptr->channelts, modebuf, parabuf);
+ }
+
+ return;
+}
+#endif
+
+#ifdef INVITE_LISTS
+void remove_matching_invites(aChannel *chptr, aClient *cptr, aClient *from)
+{
+ anInvite *inv, *inext;
+ char targhost[NICKLEN+USERLEN+HOSTLEN+6];
+ char targip[NICKLEN+USERLEN+HOSTLEN+6];
+ char *m;
+ int count = 0, send = 0;
+
+ if (!IsPerson(cptr)) return;
+
+ strcpy(targhost, make_nick_user_host(cptr->name, cptr->user->username,
+ cptr->user->host));
+ strcpy(targip, make_nick_user_host(cptr->name, cptr->user->username,
+ cptr->hostip));
+
+ m = modebuf;
+ *m++ = '-';
+ *m = '\0';
+
+ *parabuf = '\0';
+
+ inv = chptr->invite_list;
+
+ while(inv)
+ {
+ inext = inv->next;
+ if((match(inv->invstr, targhost) == 0) ||
+ (match(inv->invstr, targip) == 0))
+ {
+ if (strlen(parabuf) + strlen(inv->invstr) + 10 < (size_t) MODEBUFLEN)
+ {
+ if(*parabuf)
+ strcat(parabuf, " ");
+ strcat(parabuf, inv->invstr);
+ count++;
+ *m++ = 'I';
+ *m = '\0';
+ }
+ else
+ if(*parabuf)
+ send = 1;
+
+ if(count == MAXTSMODEPARAMS)
+ send = 1;
+
+ if(send)
+ {
+ sendto_channel_butserv_me(chptr, from, ":%s MODE %s %s %s",
+ from->name, chptr->chname, modebuf,
+ parabuf);
+ sendto_serv_butone(from, ":%s MODE %s %ld %s %s", from->name,
+ chptr->chname, chptr->channelts, modebuf,
+ parabuf);
+ send = 0;
+ *parabuf = '\0';
+ m = modebuf;
+ *m++ = '-';
+ if(count != MAXTSMODEPARAMS)
+ {
+ strcpy(parabuf, inv->invstr);
+ *m++ = 'I';
+ count = 1;
+ }
+ else
+ count = 0;
+ *m = '\0';
+ }
+
+ del_invite_id(chptr, inv->invstr);
+ }
+ inv = inext;
+ }
+
+ if(*parabuf)
+ {
+ sendto_channel_butserv_me(chptr, from, ":%s MODE %s %s %s", from->name,
+ chptr->chname, modebuf, parabuf);
+ sendto_serv_butone(from, ":%s MODE %s %ld %s %s", from->name,
+ chptr->chname, chptr->channelts, modebuf, parabuf);
+ }
+
+ return;
+}
+#endif
+
+int check_joinrate(aChannel *chptr, time_t ts, int local, aClient *cptr)
+{
+ int join_num = DEFAULT_JOIN_NUM;
+ int join_time = DEFAULT_JOIN_TIME;
+
+ if(!local && (NOW - ts) > 60)
+ return 1; /* attempt to compensate for lag */
+
+ /* This first section checks the defaults, the second
+ * checks the channels +j settings */
+ /* Has the join_time period elapsed? */
+ if((NOW - chptr->default_join_start) > join_time)
+ {
+ chptr->default_join_start = NOW;
+ chptr->default_join_count = 0;
+ }
+ /* If it's local and we've filled the join count, complain
+ * to ops so they can take the appropriate measures */
+ if(local && chptr->default_join_count >= join_num)
+ sendto_realops_lev(DEBUG_LEV, "Join rate warning on %s"
+ " for %s!%s@%s (%d/%d in %d) (No action taken)",
+ chptr->chname, cptr->name, cptr->user->username,
+ cptr->user->host, chptr->default_join_count, join_num,
+ NOW - chptr->default_join_start);
+ /* update the count here for attempts, in case a lower throttle blocks */
+ chptr->default_join_count++;
+
+ /* Has the channel set their own custom settings? */
+ if(chptr->mode.mode & MODE_JOINRATE)
+ {
+ if(chptr->mode.join_num == 0 || chptr->mode.join_time == 0)
+ return 1; /* channel has turned this off */
+
+ join_time = chptr->mode.join_time;
+ join_num = chptr->mode.join_num;
+ }
+ /* Has the join_time period elapsed? */
+ if((NOW - chptr->join_start) > join_time)
+ {
+ chptr->join_start = NOW;
+ chptr->join_count = 0;
+ return 1;
+ }
+
+ /* If it's local and we've filled the join count, say no */
+ if(local && chptr->join_count >= join_num)
+ {
+ sendto_realops_lev(DEBUG_LEV, "Join rate throttling on %s"
+ " for %s!%s@%s (%d/%d in %d)",
+ chptr->chname, cptr->name, cptr->user->username,
+ cptr->user->host, chptr->join_count, join_num,
+ NOW - chptr->join_start);
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * adds a user to a channel by adding another link to the channels
+ * member chain.
+ */
+static void add_user_to_channel(aChannel *chptr, aClient *who, int flags)
+{
+ Link *ptr;
+ chanMember *cm;
+
+#ifdef DUMP_DEBUG
+ fprintf(dumpfp,"Add to channel %s: %p:%s\n",chptr->chname,who,who->name);
+#endif
+
+ if (who->user)
+ {
+ cm = make_chanmember();
+ cm->flags = flags;
+ cm->cptr = who;
+ cm->next = chptr->members;
+ cm->banserial = chptr->banserial;
+
+ chptr->members = cm;
+ chptr->users++;
+
+ ptr = make_link();
+ ptr->value.chptr = chptr;
+ ptr->next = who->user->channel;
+ who->user->channel = ptr;
+ who->user->joined++;
+ }
+}
+
+void remove_user_from_channel(aClient *sptr, aChannel *chptr)
+{
+ chanMember **curr, *tmp;
+ Link **lcurr, *ltmp;
+
+ for (curr = &chptr->members; (tmp = *curr); curr = &tmp->next)
+ if (tmp->cptr == sptr)
+ {
+ *curr = tmp->next;
+ free_chanmember(tmp);
+ break;
+ }
+
+ for (lcurr = &sptr->user->channel; (ltmp = *lcurr); lcurr = <mp->next)
+ if (ltmp->value.chptr == chptr)
+ {
+ *lcurr = ltmp->next;
+ free_link(ltmp);
+ break;
+ }
+ sptr->user->joined--;
+ sub1_from_channel(chptr);
+}
+
+int is_chan_op(aClient *cptr, aChannel *chptr)
+{
+ chanMember *cm;
+
+ if (chptr)
+ if ((cm = find_user_member(chptr->members, cptr)))
+ return (cm->flags & CHFL_CHANOP);
+
+ return 0;
+}
+
+int is_deopped(aClient *cptr, aChannel *chptr)
+{
+ chanMember *cm;
+
+ if (chptr)
+ if ((cm = find_user_member(chptr->members, cptr)))
+ return (cm->flags & CHFL_DEOPPED);
+
+ return 0;
+}
+
+int has_voice(aClient *cptr, aChannel *chptr)
+{
+ chanMember *cm;
+
+ if (chptr)
+ if ((cm = find_user_member(chptr->members, cptr)))
+ return (cm->flags & CHFL_VOICE);
+
+ return 0;
+}
+
+int can_send(aClient *cptr, aChannel *chptr, char *msg)
+{
+ chanMember *cm;
+
+ if (IsServer(cptr) || IsULine(cptr))
+ return 0;
+
+ cm = find_user_member(chptr->members, cptr);
+
+ if(!cm)
+ {
+ if (chptr->mode.mode & MODE_MODERATED)
+ return (MODE_MODERATED);
+ if(chptr->mode.mode & MODE_NOPRIVMSGS)
+ return (MODE_NOPRIVMSGS);
+ if ((chptr->mode.mode & MODE_MODREG) && !IsRegNick(cptr))
+ return (ERR_NEEDREGGEDNICK);
+ if ((chptr->mode.mode & MODE_NOCOLOR) && msg_has_colors(msg))
+ return (ERR_NOCOLORSONCHAN);
+ if (MyClient(cptr) && is_banned(cptr, chptr, NULL))
+ return (MODE_BAN); /*
+ * channel is -n and user is not there;
+ * we need to bquiet them if we can
+ */
+ }
+ else
+ {
+ /* ops and voices can talk through everything except NOCOLOR */
+ if (!(cm->flags & (CHFL_CHANOP | CHFL_VOICE)))
+ {
+ if (chptr->mode.mode & MODE_MODERATED)
+ return (MODE_MODERATED);
+ if (is_banned(cptr, chptr, cm))
+ return (MODE_BAN);
+ if ((chptr->mode.mode & MODE_MODREG) && !IsRegNick(cptr))
+ return (ERR_NEEDREGGEDNICK);
+ }
+ if ((chptr->mode.mode & MODE_NOCOLOR) && msg_has_colors(msg))
+ return (ERR_NOCOLORSONCHAN);
+ }
+
+ return 0;
+}
+
+/*
+ * write the "simple" list of channel modes for channel chptr onto
+ * buffer mbuf with the parameters in pbuf.
+ */
+static void channel_modes(aClient *cptr, char *mbuf, char *pbuf,
+ aChannel *chptr)
+{
+ pbuf[0] = '\0';
+ *mbuf++ = '+';
+ if (chptr->mode.mode & MODE_SECRET)
+ *mbuf++ = 's';
+ else if (chptr->mode.mode & MODE_PRIVATE)
+ *mbuf++ = 'p';
+ if (chptr->mode.mode & MODE_MODERATED)
+ *mbuf++ = 'm';
+ if (chptr->mode.mode & MODE_TOPICLIMIT)
+ *mbuf++ = 't';
+ if (chptr->mode.mode & MODE_INVITEONLY)
+ *mbuf++ = 'i';
+ if (chptr->mode.mode & MODE_NOPRIVMSGS)
+ *mbuf++ = 'n';
+ if (chptr->mode.mode & MODE_REGISTERED)
+ *mbuf++ = 'r';
+ if (chptr->mode.mode & MODE_REGONLY)
+ *mbuf++ = 'R';
+ if (chptr->mode.mode & MODE_NOCOLOR)
+ *mbuf++ = 'c';
+ if (chptr->mode.mode & MODE_OPERONLY)
+ *mbuf++ = 'O';
+ if (chptr->mode.mode & MODE_MODREG)
+ *mbuf++ = 'M';
+#ifdef USE_CHANMODE_L
+ if (chptr->mode.mode & MODE_LISTED)
+ *mbuf++ = 'L';
+#endif
+ if (chptr->mode.limit)
+ {
+ *mbuf++ = 'l';
+ if (IsMember(cptr, chptr) || IsServer(cptr) || IsULine(cptr))
+ ircsprintf(pbuf, "%d", chptr->mode.limit);
+ }
+ if (*chptr->mode.key)
+ {
+ *mbuf++ = 'k';
+ if (IsMember(cptr, chptr) || IsServer(cptr) || IsULine(cptr))
+ {
+ if(pbuf[0] != '\0')
+ strcat(pbuf, " ");
+ strcat(pbuf, chptr->mode.key);
+ }
+ }
+ if (chptr->mode.mode & MODE_JOINRATE)
+ {
+ *mbuf++ = 'j';
+
+ if (IsMember(cptr, chptr) || IsServer(cptr) || IsULine(cptr))
+ {
+ char tmp[128];
+ if(pbuf[0] != '\0')
+ strcat(pbuf, " ");
+
+ if(chptr->mode.join_num == 0 || chptr->mode.join_time == 0)
+ ircsprintf(tmp, "0");
+ else
+ ircsprintf(tmp, "%d:%d", chptr->mode.join_num,
+ chptr->mode.join_time);
+
+ strcat(pbuf, tmp);
+ }
+ }
+ *mbuf++ = '\0';
+ return;
+}
+
+static void send_channel_lists(aClient *cptr, aChannel *chptr)
+{
+ aBan *bp;
+#ifdef EXEMPT_LISTS
+ aBanExempt *exempt;
+#endif
+#ifdef INVITE_LISTS
+ anInvite *inv;
+#endif
+ char *cp;
+ int count = 0, send = 0;
+
+ cp = modebuf + strlen(modebuf);
+
+ if (*parabuf) /* mode +l or +k xx */
+ count = 1;
+
+ for (bp = chptr->banlist; bp; bp = bp->next)
+ {
+ if (strlen(parabuf) + strlen(bp->banstr) + 20 < (size_t) MODEBUFLEN)
+ {
+ if(*parabuf)
+ strcat(parabuf, " ");
+ strcat(parabuf, bp->banstr);
+ count++;
+ *cp++ = 'b';
+ *cp = '\0';
+ }
+ else if (*parabuf)
+ send = 1;
+
+ if (count == MAXTSMODEPARAMS)
+ send = 1;
+
+ if (send)
+ {
+ sendto_one(cptr, ":%s MODE %s %ld %s %s", me.name, chptr->chname,
+ chptr->channelts, modebuf, parabuf);
+ send = 0;
+ *parabuf = '\0';
+ cp = modebuf;
+ *cp++ = '+';
+ if (count != MAXTSMODEPARAMS)
+ {
+ strcpy(parabuf, bp->banstr);
+ *cp++ = 'b';
+ count = 1;
+ }
+ else
+ count = 0;
+ *cp = '\0';
+ }
+ }
+#ifdef EXEMPT_LISTS
+ for (exempt = chptr->banexempt_list; exempt; exempt = exempt->next)
+ {
+ if (strlen(parabuf) + strlen(exempt->banstr) + 20 < (size_t)MODEBUFLEN)
+ {
+ if (*parabuf) strcat(parabuf, " ");
+ strcat(parabuf, exempt->banstr);
+ count++;
+ *cp++ = 'e';
+ *cp = 0;
+ }
+ else if (*parabuf)
+ send = 1;
+
+
+ if (count == MAXTSMODEPARAMS)
+ send = 1;
+
+ if (send)
+ {
+ sendto_one(cptr, ":%s MODE %s %ld %s %s", me.name, chptr->chname,
+ chptr->channelts, modebuf, parabuf);
+ send = 0;
+ *parabuf = 0;
+ cp = modebuf;
+ *cp++ = '+';
+ if (count != MAXTSMODEPARAMS)
+ {
+ strcpy(parabuf, exempt->banstr);
+ *cp++ = 'e';
+ count = 1;
+ }
+ else count = 0;
+ *cp = 0;
+ }
+ }
+#endif
+#ifdef INVITE_LISTS
+ for (inv = chptr->invite_list; inv; inv = inv->next)
+ {
+ if (strlen(parabuf) + strlen(inv->invstr) + 20 < (size_t)MODEBUFLEN)
+ {
+ if (*parabuf) strcat(parabuf, " ");
+ strcat(parabuf, inv->invstr);
+ count++;
+ *cp++ = 'I';
+ *cp = 0;
+ }
+ else if (*parabuf)
+ send = 1;
+
+
+ if (count == MAXTSMODEPARAMS)
+ send = 1;
+
+ if (send)
+ {
+ sendto_one(cptr, ":%s MODE %s %ld %s %s", me.name, chptr->chname,
+ chptr->channelts, modebuf, parabuf);
+ send = 0;
+ *parabuf = 0;
+ cp = modebuf;
+ *cp++ = '+';
+ if (count != MAXTSMODEPARAMS)
+ {
+ strcpy(parabuf, inv->invstr);
+ *cp++ = 'I';
+ count = 1;
+ }
+ else count = 0;
+ *cp = 0;
+ }
+ }
+#endif
+
+}
+
+/* send "cptr" a full list of the modes for channel chptr. */
+void send_channel_modes(aClient *cptr, aChannel *chptr)
+{
+ chanMember *l, *anop = NULL, *skip = NULL;
+ int n = 0;
+ char *t;
+
+ if (*chptr->chname != '#')
+ return;
+
+ *modebuf = *parabuf = '\0';
+ channel_modes(cptr, modebuf, parabuf, chptr);
+
+ ircsprintf(buf, ":%s SJOIN %ld %s %s %s :", me.name,
+ chptr->channelts, chptr->chname, modebuf, parabuf);
+ t = buf + strlen(buf);
+ for (l = chptr->members; l; l = l->next)
+ if (l->flags & MODE_CHANOP)
+ {
+ anop = l;
+ break;
+ }
+ /*
+ * follow the channel, but doing anop first if it's defined *
+ * -orabidoo
+ */
+ l = NULL;
+ for (;;)
+ {
+ if (anop)
+ {
+ l = skip = anop;
+ anop = NULL;
+ }
+ else
+ {
+ if (l == NULL || l == skip)
+ l = chptr->members;
+ else
+ l = l->next;
+ if (l && l == skip)
+ l = l->next;
+ if (l == NULL)
+ break;
+ }
+ if (l->flags & MODE_CHANOP)
+ *t++ = '@';
+ if (l->flags & MODE_VOICE)
+ *t++ = '+';
+ strcpy(t, l->cptr->name);
+ t += strlen(t);
+ *t++ = ' ';
+ n++;
+ if (t - buf > BUFSIZE - 80)
+ {
+ *t++ = '\0';
+ if (t[-1] == ' ')
+ t[-1] = '\0';
+ sendto_one(cptr, "%s", buf);
+ sprintf(buf, ":%s SJOIN %ld %s 0 :", me.name,
+ chptr->channelts, chptr->chname);
+ t = buf + strlen(buf);
+ n = 0;
+ }
+ }
+
+ if (n)
+ {
+ *t++ = '\0';
+ if (t[-1] == ' ')
+ t[-1] = '\0';
+ sendto_one(cptr, "%s", buf);
+ }
+ *parabuf = '\0';
+ *modebuf = '+';
+ modebuf[1] = '\0';
+ send_channel_lists(cptr, chptr);
+ if (modebuf[1] || *parabuf)
+ sendto_one(cptr, ":%s MODE %s %ld %s %s",
+ me.name, chptr->chname, chptr->channelts, modebuf, parabuf);
+}
+
+/* m_mode parv[0] - sender parv[1] - channel */
+
+int m_mode(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ int mcount = 0, chanop=0;
+ aChannel *chptr;
+ int subparc = 2;
+
+ /* Now, try to find the channel in question */
+ if (parc > 1)
+ {
+ chptr = find_channel(parv[1], NullChn);
+ if (chptr == NullChn)
+ return m_umode(cptr, sptr, parc, parv);
+ }
+ else
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "MODE");
+ return 0;
+ }
+
+ if (!check_channelname(sptr, (unsigned char *) parv[1]))
+ return 0;
+
+ if (MyClient(sptr))
+ {
+ if (is_chan_op(sptr, chptr))
+ chanop = 1;
+ }
+ else
+ chanop = 2;
+
+ if (parc < 3)
+ {
+ *modebuf = *parabuf = '\0';
+ modebuf[1] = '\0';
+ channel_modes(sptr, modebuf, parabuf, chptr);
+ sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS), me.name, parv[0],
+ chptr->chname, modebuf, parabuf);
+ sendto_one(sptr, rpl_str(RPL_CREATIONTIME), me.name, parv[0],
+ chptr->chname, chptr->channelts);
+ return 0;
+ }
+
+ if(IsServer(cptr) && IsDigit(parv[2][0]))
+ {
+ ts_val modets = atol(parv[2]);
+ if(modets != 0 && (modets > chptr->channelts))
+ return 0;
+ subparc++;
+ }
+
+ mcount = set_mode(cptr, sptr, chptr, chanop, parc - subparc, parv + subparc,
+ modebuf, parabuf);
+
+ if (strlen(modebuf) > (size_t) 1)
+ switch (mcount)
+ {
+ case 0:
+ break;
+ case -1:
+ if (MyClient(sptr))
+ sendto_one(sptr,
+ err_str(ERR_CHANOPRIVSNEEDED),
+ me.name, parv[0], chptr->chname);
+ else
+ ircstp->is_fake++;
+ break;
+ default:
+ sendto_channel_butserv_me(chptr, sptr,
+ ":%s MODE %s %s %s", parv[0],
+ chptr->chname, modebuf,
+ parabuf);
+ sendto_serv_butone(cptr, ":%s MODE %s %ld %s %s", parv[0],
+ chptr->chname, chptr->channelts, modebuf,
+ parabuf);
+ }
+ return 0;
+}
+
+/* the old set_mode was pissing me off with it's disgusting
+ * hackery, so I rewrote it. Hope this works. }:> --wd
+ * Corrected a 4-year-old mistake: the max modes limit applies to
+ * the number of parameters, not mode changes. -Quension [Apr 2004]
+ */
+static int set_mode(aClient *cptr, aClient *sptr, aChannel *chptr,
+ int level, int parc, char *parv[], char *mbuf, char *pbuf)
+{
+#define SM_ERR_NOPRIVS 0x0001 /* is not an op */
+#define SM_ERR_MOREPARMS 0x0002 /* needs more parameters */
+#define SM_ERR_RESTRICTED 0x0004 /* not allowed to op others or be op'd */
+#define SM_ERR_NOTOPER 0x0008 /* not an irc op */
+#define SM_MAXMODES MAXMODEPARAMSUSER
+
+/* this macro appends to pbuf */
+#define ADD_PARA(p) pptr = p; if(pidx) pbuf[pidx++] = ' '; while(*pptr) \
+ pbuf[pidx++] = *pptr++;
+
+ static int flags[] =
+ {
+ MODE_PRIVATE, 'p', MODE_SECRET, 's',
+ MODE_MODERATED, 'm', MODE_NOPRIVMSGS, 'n',
+ MODE_TOPICLIMIT, 't', MODE_REGONLY, 'R',
+ MODE_INVITEONLY, 'i', MODE_NOCOLOR, 'c', MODE_OPERONLY, 'O',
+ MODE_MODREG, 'M',
+#ifdef USE_CHANMODE_L
+ MODE_LISTED, 'L',
+#endif
+ 0x0, 0x0
+ };
+
+ Link *lp; /* for walking lists */
+ chanMember *cm; /* for walking channel member lists */
+ aBan *bp; /* for walking banlists */
+ char *modes=parv[0]; /* user's idea of mode changes */
+ int args; /* counter for what argument we're on */
+ int anylistsent = IsServer(sptr) ? 1 : 0; /* Only send 1 list and not to servers */
+ char change='+'; /* by default we + things... */
+ int errors=0; /*
+ * errors returned, set with bitflags
+ * so we only return them once
+ */
+ /* from remote servers, ungodly numbers of modes can be sent, but
+ * from local users only SM_MAXMODES are allowed */
+ int maxparams=((IsServer(sptr) || IsULine(sptr)) ? 512 : SM_MAXMODES);
+ int nmodes=0; /* how many modes we've set so far */
+ int nparams=0; /* how many modes with parameters we've set so far */
+ aClient *who = NULL; /* who we're doing a mode for */
+ int chasing = 0;
+ int i=0;
+ char moreparmsstr[]="MODE ";
+ char nuhbuf[NICKLEN + USERLEN + HOSTLEN + 6]; /* for bans */
+ char tmp[128]; /* temporary buffer */
+ int pidx = 0; /* index into pbuf */
+ char *pptr; /* temporary paramater pointer */
+ char *morig = mbuf; /* beginning of mbuf */
+ /* :cptr-name MODE chptr->chname [MBUF] [PBUF] (buflen - 3 max and NULL) */
+ /* added another 11 bytes to this, for TSMODE -epi */
+ int prelen = strlen(cptr->name) + strlen(chptr->chname) + 27;
+ /* drop duplicates in the same mode change -- yeah, this is cheap, but real
+ duplicate checking will have to wait for a protocol change to kill
+ desyncs */
+ int seenalready = 0;
+
+
+ args=1;
+
+ if(parc<1)
+ return 0;
+
+ *mbuf++='+'; /* add the plus, even if they don't */
+ /* go through once to clean the user's mode string so we can
+ * have a simple parser run through it...*/
+
+ while(*modes)
+ {
+ switch(*modes)
+ {
+ case '+':
+ if(*(mbuf-1)=='-')
+ {
+ *(mbuf-1)='+'; /* change it around now */
+ change='+';
+ break;
+ }
+ else if(change=='+') /* we're still doing a +, we don't care */
+ break;
+ change=*modes;
+ *mbuf++='+';
+ break;
+
+ case '-':
+ if(*(mbuf-1)=='+')
+ {
+ *(mbuf-1)='-'; /* change it around now */
+ change='-';
+ break;
+ }
+ else if(change=='-')
+ break; /* we're still doing a -, we don't care */
+ change=*modes;
+ *mbuf++='-';
+ break;
+
+ case 'O':
+ if (level<1 || (MyClient(sptr) && !IsOper(sptr)))
+ {
+ errors |= SM_ERR_NOTOPER;
+ break;
+ }
+ else
+ {
+ if (change=='+')
+ chptr->mode.mode|=MODE_OPERONLY;
+ else
+ chptr->mode.mode&=~MODE_OPERONLY;
+ *mbuf++ = *modes;
+ nmodes++;
+ }
+ break;
+ case 'o':
+ case 'v':
+ if(level<1)
+ {
+ errors |= SM_ERR_NOPRIVS;
+ break;
+ }
+ if(parv[args]==NULL)
+ {
+ /* silently drop the spare +o/v's */
+ break;
+ }
+ if(++nparams > maxparams)
+ {
+ /* too many modes with params, eat this one */
+ args++;
+ break;
+ }
+
+ who = find_chasing(sptr, parv[args], &chasing);
+ cm = find_user_member(chptr->members, who);
+ if(cm == NULL)
+ {
+ sendto_one(sptr, err_str(ERR_USERNOTINCHANNEL),
+ me.name, cptr->name, parv[args], chptr->chname);
+ /* swallow the arg */
+ args++;
+ break;
+ }
+ /* if we're going to overflow our mode buffer,
+ * drop the change instead */
+ if((prelen + (mbuf - morig) + pidx + NICKLEN + 1) >
+ REALMODEBUFLEN)
+ {
+ args++;
+ break;
+ }
+
+ /* if we have the user, set them +/-[vo] */
+ if(change=='+')
+ cm->flags|=(*modes=='o' ? CHFL_CHANOP : CHFL_VOICE);
+ else
+ cm->flags&=~((*modes=='o' ? CHFL_CHANOP : CHFL_VOICE));
+
+ /* we've decided their mode was okay, cool */
+ *mbuf++ = *modes;
+ ADD_PARA(cm->cptr->name)
+ args++;
+ nmodes++;
+ if (IsServer(sptr) && *modes == 'o' && change=='+')
+ {
+ chptr->channelts = 0;
+ sendto_ops("Server %s setting +o and blasting TS on %s",
+ sptr->name, chptr->chname);
+ }
+ break;
+
+#ifdef INVITE_LISTS
+ case 'I':
+ if (level < 1 && parv[args] != NULL)
+ {
+ errors |= SM_ERR_NOPRIVS;
+ break;
+ }
+ else if (parv[args] == NULL)
+ {
+ anInvite *invite;
+
+ if (anylistsent) /* don't send the list if they have received one */
+ break;
+
+ for (invite = chptr->invite_list; invite; invite = invite->next)
+ sendto_one(sptr, rpl_str(RPL_INVITELIST), me.name, cptr->name,
+ chptr->chname, invite->invstr, invite->who, invite->when);
+ sendto_one(cptr, rpl_str(RPL_ENDOFINVITELIST), me.name,
+ cptr->name, chptr->chname);
+ anylistsent = 1;
+ break;
+ }
+ if(++nparams > maxparams)
+ {
+ /* too many modes with params, eat this one */
+ args++;
+ break;
+ }
+
+ if (*parv[args] == ':' || *parv[args] == '\0')
+ {
+ args++;
+ break;
+ }
+
+ strcpy(nuhbuf, collapse(pretty_mask(parv[args])));
+ parv[args] = nuhbuf;
+ /* if we're going to overflow our mode buffer,
+ * drop the change instead */
+ if((prelen + (mbuf - morig) + pidx + strlen(nuhbuf) + 1) >
+ REALMODEBUFLEN)
+ {
+ args++;
+ break;
+ }
+ /* if we can't add or delete (depending) the ban, change is
+ * worthless anyhow */
+
+ if(!(change=='+' && !add_invite_id(sptr, chptr, parv[args])) &&
+ !(change=='-' && !del_invite_id(chptr, parv[args])))
+ {
+ args++;
+ break;
+ }
+
+ *mbuf++ = 'I';
+ ADD_PARA(parv[args])
+ args++;
+ nmodes++;
+ break;
+#endif
+
+#ifdef EXEMPT_LISTS
+ case 'e':
+ if (level < 1 && parv[args] != NULL)
+ {
+ errors |= SM_ERR_NOPRIVS;
+ break;
+ }
+ else if (parv[args] == NULL)
+ {
+ aBanExempt* exempt;
+
+ if (anylistsent) /* don't send the list if they have received one */
+ break;
+ for (exempt = chptr->banexempt_list; exempt; exempt = exempt->next)
+ sendto_one(sptr, rpl_str(RPL_EXEMPTLIST), me.name, cptr->name,
+ chptr->chname, exempt->banstr, exempt->who, exempt->when);
+ sendto_one(cptr, rpl_str(RPL_ENDOFEXEMPTLIST), me.name,
+ cptr->name, chptr->chname);
+ anylistsent = 1;
+ break;
+ }
+ if(++nparams > maxparams)
+ {
+ /* too many modes with params, eat this one */
+ args++;
+ break;
+ }
+
+ if (*parv[args] == ':' || *parv[args] == '\0')
+ {
+ args++;
+ break;
+ }
+
+ strcpy(nuhbuf, collapse(pretty_mask(parv[args])));
+ parv[args] = nuhbuf;
+ /* if we're going to overflow our mode buffer,
+ * drop the change instead */
+ if((prelen + (mbuf - morig) + pidx + strlen(nuhbuf) + 1) >
+ REALMODEBUFLEN)
+ {
+ args++;
+ break;
+ }
+ /* if we can't add or delete (depending) the exempt, change is
+ * worthless anyhow */
+
+ if(!(change=='+' && !add_exempt_id(sptr, chptr, parv[args])) &&
+ !(change=='-' && !del_exempt_id(chptr, parv[args])))
+ {
+ args++;
+ break;
+ }
+
+ *mbuf++ = 'e';
+ ADD_PARA(parv[args])
+ args++;
+ nmodes++;
+ break;
+#endif
+
+ case 'b':
+ /* if the user has no more arguments, then they just want
+ * to see the bans, okay, cool. */
+ if(level < 1 && parv[args] != NULL)
+ {
+ errors |= SM_ERR_NOPRIVS;
+ break;
+ }
+ /* show them the bans, woowoo */
+ if(parv[args]==NULL)
+ {
+ if (anylistsent)
+ break;
+ for(bp=chptr->banlist;bp;bp=bp->next)
+ sendto_one(sptr, rpl_str(RPL_BANLIST), me.name, cptr->name,
+ chptr->chname, bp->banstr, bp->who, bp->when);
+ sendto_one(cptr, rpl_str(RPL_ENDOFBANLIST), me.name,
+ cptr->name, chptr->chname);
+ anylistsent = 1;
+ break; /* we don't pass this along, either.. */
+ }
+ if(++nparams > maxparams)
+ {
+ /* too many modes with params, eat this one */
+ args++;
+ break;
+ }
+
+ /* do not allow : in bans, or a null ban */
+ if(*parv[args]==':' || *parv[args] == '\0')
+ {
+ args++;
+ break;
+ }
+
+ /* make a 'pretty' ban mask here, then try and set it */
+ /* okay kids, let's do this again.
+ * the buffer returned by pretty_mask is from
+ * make_nick_user_host. This buffer is eaten by add/del banid.
+ * Thus, some poor schmuck gets himself on the banlist.
+ * Fixed. - lucas */
+ strcpy(nuhbuf, collapse(pretty_mask(parv[args])));
+ parv[args] = nuhbuf;
+ /* if we're going to overflow our mode buffer,
+ * drop the change instead */
+ if((prelen + (mbuf - morig) + pidx + strlen(nuhbuf) + 1) >
+ REALMODEBUFLEN)
+ {
+ args++;
+ break;
+ }
+ /* if we can't add or delete (depending) the ban, change is
+ * worthless anyhow */
+
+ if(!(change=='+' && !add_banid(sptr, chptr, parv[args])) &&
+ !(change=='-' && !del_banid(chptr, parv[args])))
+ {
+ args++;
+ break;
+ }
+
+ *mbuf++ = 'b';
+ ADD_PARA(parv[args])
+ args++;
+ nmodes++;
+ break;
+
+ case 'j':
+#ifdef JOINRATE_SERVER_ONLY
+ if (MyClient(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_ONLYSERVERSCANCHANGE),
+ me.name, cptr->name, chptr->chname);
+ break;
+ }
+#endif
+
+ if(level<1)
+ {
+ errors |= SM_ERR_NOPRIVS;
+ break;
+ }
+
+ /* if it's a -, just change the flag, we have no arguments */
+ if(change=='-')
+ {
+ if (MyClient(sptr) && (seenalready & MODE_JOINRATE))
+ break;
+ seenalready |= MODE_JOINRATE;
+
+ if((prelen + (mbuf - morig) + pidx + 1) > REALMODEBUFLEN)
+ break;
+ *mbuf++ = 'j';
+ chptr->mode.mode &= ~MODE_JOINRATE;
+ chptr->mode.join_num = 0;
+ chptr->mode.join_time = 0;
+ chptr->join_start = 0;
+ chptr->join_count = 0;
+ nmodes++;
+ break;
+ }
+ else
+ {
+ char *tmpa, *tmperr;
+ int j_num, j_time, tval;
+
+ if(parv[args] == NULL)
+ {
+ errors|=SM_ERR_MOREPARMS;
+ break;
+ }
+ if(++nparams > maxparams)
+ {
+ /* too many modes with params, eat this one */
+ args++;
+ break;
+ }
+ if (MyClient(sptr) && (seenalready & MODE_JOINRATE))
+ {
+ args++;
+ break;
+ }
+ seenalready |= MODE_JOINRATE;
+
+ tmpa = strchr(parv[args], ':');
+ if(tmpa)
+ {
+ *tmpa = '\0';
+ tmpa++;
+ j_time = strtol(tmpa, &tmperr, 10);
+ if(*tmperr != '\0' || j_time < 0)
+ {
+ /* error, user specified something
+ * invalid, just bail. */
+ args++;
+ break;
+ }
+ }
+ else
+ j_time = 0;
+
+ j_num = strtol(parv[args], &tmperr, 10);
+ if(*tmperr != '\0' || j_num < 0)
+ {
+ args++;
+ break;
+ }
+
+ /* range limit for local non-samodes */
+ if (MyClient(sptr) && level < 2)
+ {
+ /* static limits: time <= 60, 4 <= num <= 60 */
+ if (j_time > 60)
+ j_time = 60;
+ if (j_num > 60)
+ j_num = 60;
+ if (j_num < 4)
+ j_num = 4;
+
+ /* adjust number to time using min rate 1/8 */
+ tval = (j_time-1)/8+1;
+ if (j_num < tval)
+ j_num = tval;
+
+ /* adjust time to number using max rate 2/1 */
+ tval = j_num/2;
+ if (j_time < tval)
+ j_time = tval;
+ }
+
+ if(j_num == 0 || j_time == 0)
+ {
+ j_num = j_time = 0;
+ ircsprintf(tmp, "0");
+ }
+ else
+ ircsprintf(tmp, "%d:%d", j_num, j_time);
+
+ /* if we're going to overflow our mode buffer,
+ * drop the change instead */
+ if((prelen + (mbuf - morig) + pidx + strlen(tmp)) > REALMODEBUFLEN)
+ {
+ args++;
+ break;
+ }
+
+ chptr->mode.mode |= MODE_JOINRATE;
+ chptr->mode.join_num = j_num;
+ chptr->mode.join_time = j_time;
+ chptr->join_start = 0;
+ chptr->join_count = 0;
+ *mbuf++ = 'j';
+ ADD_PARA(tmp);
+ args++;
+ nmodes++;
+ break;
+ }
+
+ case 'l':
+ if(level<1)
+ {
+ errors |= SM_ERR_NOPRIVS;
+ break;
+ }
+
+ /* if it's a -, just change the flag, we have no arguments */
+ if(change=='-')
+ {
+ if (MyClient(sptr) && (seenalready & MODE_LIMIT))
+ break;
+ seenalready |= MODE_LIMIT;
+
+ if((prelen + (mbuf - morig) + pidx + 1) > REALMODEBUFLEN)
+ break;
+ *mbuf++ = 'l';
+ chptr->mode.mode &= ~MODE_LIMIT;
+ chptr->mode.limit = 0;
+ nmodes++;
+ break;
+ }
+ else
+ {
+ if(parv[args] == NULL)
+ {
+ errors|=SM_ERR_MOREPARMS;
+ break;
+ }
+ if(++nparams > maxparams)
+ {
+ /* too many modes with params, eat this one */
+ args++;
+ break;
+ }
+ if (MyClient(sptr) && (seenalready & MODE_LIMIT))
+ {
+ args++;
+ break;
+ }
+ seenalready |= MODE_LIMIT;
+
+ /* if we're going to overflow our mode buffer,
+ * drop the change instead */
+ if((prelen + (mbuf - morig) + pidx + 16) > REALMODEBUFLEN)
+ {
+ args++;
+ break;
+ }
+
+ i = atoi(parv[args]);
+
+ /* toss out invalid modes */
+ if(i < 1)
+ {
+ args++;
+ break;
+ }
+ ircsprintf(tmp, "%d", i);
+ chptr->mode.limit = i;
+ chptr->mode.mode |= MODE_LIMIT;
+ *mbuf++ = 'l';
+ ADD_PARA(tmp);
+ args++;
+ nmodes++;
+ break;
+ }
+
+ case 'k':
+ if(level<1)
+ {
+ errors |= SM_ERR_NOPRIVS;
+ break;
+ }
+ if(parv[args]==NULL)
+ break;
+ if(++nparams > maxparams)
+ {
+ /* too many modes with params, eat this one */
+ args++;
+ break;
+ }
+ if (MyClient(sptr) && (seenalready & MODE_KEY))
+ {
+ args++;
+ break;
+ }
+ seenalready |= MODE_KEY;
+
+ /* do not allow keys to start with :! ack! - lucas */
+ /* another ack: don't let people set null keys! */
+ /* and yet a third ack: no spaces in keys -epi */
+ if(*parv[args]==':' || *parv[args] == '\0' ||
+ strchr(parv[args], ' '))
+ {
+ args++;
+ break;
+ }
+
+ /* Do not let *'s in keys in preperation for key hiding - Raist
+ * Also take out ",", which makes a channel unjoinable - lucas
+ */
+
+ if (strchr(parv[args], '*') != NULL ||
+ strchr(parv[args], ',') != NULL)
+ {
+ args++;
+ break;
+ }
+
+ /* if we're going to overflow our mode buffer,
+ * drop the change instead */
+ if((prelen + (mbuf - morig) + pidx + KEYLEN+2) > REALMODEBUFLEN)
+ {
+ args++;
+ break;
+ }
+
+ /* if they're an op, they can futz with the key in
+ * any manner they like, we're not picky */
+ if(change=='+')
+ {
+ strncpy(chptr->mode.key,parv[args],KEYLEN);
+ ADD_PARA(chptr->mode.key)
+ }
+ else
+ {
+ char *sendkey = chptr->mode.key;
+ if (!*sendkey)
+ sendkey = parv[args];
+ ADD_PARA(sendkey)
+ *chptr->mode.key = '\0';
+ }
+ *mbuf++='k';
+ args++;
+ nmodes++;
+ break;
+
+ case 'r':
+ if (MyClient(sptr) && (seenalready & MODE_REGISTERED))
+ break;
+ seenalready |= MODE_REGISTERED;
+ if (!IsServer(sptr) && !IsULine(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_ONLYSERVERSCANCHANGE),
+ me.name, cptr->name, chptr->chname);
+ break;
+ }
+ else
+ {
+ if((prelen + (mbuf - morig) + pidx + 1) > REALMODEBUFLEN)
+ break;
+
+ if(change=='+')
+ chptr->mode.mode|=MODE_REGISTERED;
+ else
+ chptr->mode.mode&=~MODE_REGISTERED;
+ }
+ *mbuf++='r';
+ nmodes++;
+ break;
+
+ case 'L':
+ if (MyClient(sptr) && (seenalready & MODE_LISTED))
+ break;
+ seenalready |= MODE_LISTED;
+ if (MyClient(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_ONLYSERVERSCANCHANGE),
+ me.name, cptr->name, chptr->chname);
+ break;
+ }
+ else
+ {
+ if((prelen + (mbuf - morig) + pidx + 1) > REALMODEBUFLEN)
+ break;
+
+ if(change=='+')
+ chptr->mode.mode|=MODE_LISTED;
+ else
+ chptr->mode.mode&=~MODE_LISTED;
+ }
+ *mbuf++='L';
+ nmodes++;
+ break;
+
+ case 'i':
+ if(level < 1)
+ {
+ errors |= SM_ERR_NOPRIVS;
+ break;
+ }
+ if(change=='-')
+ while ((lp=chptr->invites))
+ del_invite(lp->value.cptr, chptr);
+ /* fall through to default case */
+
+ default:
+ /* phew, no more tough modes. }:>, the rest are all
+ * covered in one step
+ * with the above array */
+ if(level<1)
+ {
+ errors |= SM_ERR_NOPRIVS;
+ break;
+ }
+ for(i=1;flags[i]!=0x0;i+=2)
+ {
+ if((prelen + (mbuf - morig) + pidx + 1) > REALMODEBUFLEN)
+ break;
+
+ if(*modes==(char)flags[i])
+ {
+ if (MyClient(sptr) && (seenalready & flags[i-1]))
+ break;
+ seenalready |= flags[i-1];
+
+ if(change=='+')
+ chptr->mode.mode |= flags[i-1];
+ else
+ chptr->mode.mode &= ~flags[i-1];
+ *mbuf++=*modes;
+ nmodes++;
+ break;
+ }
+ }
+ /* unknown mode.. */
+ if(flags[i]==0x0)
+ {
+ /* we still spew lots of unknown mode bits...*/
+ /* but only to our own clients, silently ignore bogosity
+ * from other servers... */
+ if(MyClient(sptr))
+ sendto_one(sptr, err_str(ERR_UNKNOWNMODE), me.name,
+ sptr->name, *modes);
+
+ }
+ break;
+ }
+
+ /* spit out more parameters error here */
+ if(errors & SM_ERR_MOREPARMS && MyClient(sptr))
+ {
+ moreparmsstr[5]=change;
+ moreparmsstr[6]=*modes;
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name,
+ sptr->name, moreparmsstr);
+ errors &= ~SM_ERR_MOREPARMS; /* oops, kill it in this case */
+ }
+ modes++;
+ }
+ /* clean up the end of the string... */
+ if(*(mbuf-1) == '+' || *(mbuf-1) == '-')
+ *(mbuf-1) = '\0';
+ else
+ *mbuf = '\0';
+ pbuf[pidx] = '\0';
+ if(MyClient(sptr))
+ {
+ if(errors & SM_ERR_NOPRIVS)
+ sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name,
+ sptr->name, chptr->chname);
+ if(errors & SM_ERR_NOTOPER)
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, sptr->name);
+ if(errors & SM_ERR_RESTRICTED)
+ sendto_one(sptr,":%s NOTICE %s :*** Notice -- You are "
+ "restricted and cannot chanop others",
+ me.name, sptr->name);
+ }
+ /* all done! */
+ return nmodes;
+#undef ADD_PARA
+}
+
+static int can_join(aClient *sptr, aChannel *chptr, char *key)
+{
+ Link *lp;
+ int invited = 0;
+ int error = 0;
+ char *r = NULL;
+
+ for(lp = sptr->user->invited; lp; lp = lp->next)
+ {
+ if(lp->value.chptr == chptr)
+ {
+ invited = 1;
+ break;
+ }
+ }
+
+ if (invited || IsULine(sptr))
+ return 1;
+
+ if (check_joinrate(chptr, NOW, 1, sptr) == 0)
+ {
+ r = "+j";
+ error = ERR_CHANNELISFULL;
+ }
+ else if (chptr->mode.mode & MODE_INVITEONLY)
+ {
+ r = "+i";
+ error = ERR_INVITEONLYCHAN;
+ }
+ else if (chptr->mode.mode & MODE_OPERONLY && !IsOper(sptr))
+ {
+ r = "+O";
+ error = ERR_INVITEONLYCHAN;
+ }
+ else if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
+ {
+ r = "+l";
+ error = ERR_CHANNELISFULL;
+ }
+ else if (chptr->mode.mode & MODE_REGONLY && !IsRegNick(sptr))
+ error = ERR_NEEDREGGEDNICK;
+ else if (*chptr->mode.key && (BadPtr(key) || mycmp(chptr->mode.key, key)))
+ error = ERR_BADCHANNELKEY;
+
+#ifdef INVITE_LISTS
+ if (error && is_invited(sptr, chptr))
+ error = 0;
+#endif
+
+ if (!error && is_banned(sptr, chptr, NULL))
+ error = ERR_BANNEDFROMCHAN;
+
+ if (error)
+ {
+ if (error==ERR_NEEDREGGEDNICK)
+ sendto_one(sptr, getreply(ERR_NEEDREGGEDNICK), me.name, sptr->name,
+ chptr->chname, "join", NS_Services_Name,
+ NS_Register_URL);
+ else
+ sendto_one(sptr, getreply(error), me.name, sptr->name,
+ chptr->chname, r);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * can_join_whynot:
+ * puts a list of the modes preventing us from joining in reasonbuf
+ * ret is number of matched modes
+ */
+static int
+can_join_whynot(aClient *sptr, aChannel *chptr, char *key, char *reasonbuf)
+{
+ Link *lp;
+ int invited = 0;
+ int rbufpos = 0;
+
+ for(lp = sptr->user->invited; lp; lp = lp->next)
+ {
+ if(lp->value.chptr == chptr)
+ {
+ invited = 1;
+ break;
+ }
+ }
+
+ if (invited || IsULine(sptr))
+ return 0;
+
+ if (chptr->mode.mode & MODE_INVITEONLY)
+ reasonbuf[rbufpos++] = 'i';
+ if (chptr->mode.mode & MODE_REGONLY && !IsRegNick(sptr))
+ reasonbuf[rbufpos++] = 'R';
+ if (chptr->mode.mode & MODE_OPERONLY && !IsOper(sptr))
+ reasonbuf[rbufpos++] = 'O';
+ if (*chptr->mode.key && (BadPtr(key) || mycmp(chptr->mode.key, key)))
+ reasonbuf[rbufpos++] = 'k';
+ if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
+ reasonbuf[rbufpos++] = 'l';
+ if (check_joinrate(chptr, NOW, 1, sptr) == 0)
+ reasonbuf[rbufpos++] = 'j';
+
+#ifdef INVITE_LISTS
+ if (rbufpos && is_invited(sptr, chptr))
+ rbufpos = 0;
+#endif
+
+ if (is_banned(sptr, chptr, NULL))
+ reasonbuf[rbufpos++] = 'b';
+
+ reasonbuf[rbufpos] = '\0';
+ return rbufpos;
+}
+
+/*
+ * Remove bells and commas from channel name
+ */
+void clean_channelname(unsigned char *cn)
+{
+ for (; *cn; cn++)
+ /*
+ * All characters >33 are allowed, except commas, and the weird
+ * fake-space character mIRCers whine about -wd
+ */
+ if (*cn < 33 || *cn == ',' || (*cn == 160))
+ {
+ *cn = '\0';
+ return;
+ }
+ return;
+}
+
+/* we also tell the client if the channel is invalid. */
+int check_channelname(aClient *cptr, unsigned char *cn)
+{
+ if(!MyClient(cptr))
+ return 1;
+ for(;*cn;cn++)
+ {
+ if(*cn<33 || *cn == ',' || *cn==160)
+ {
+ sendto_one(cptr, getreply(ERR_BADCHANNAME), me.name, cptr->name,
+ cn);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * * Get Channel block for chname (and allocate a new channel *
+ * block, if it didn't exist before).
+ */
+static aChannel *
+get_channel(aClient *cptr, char *chname, int flag, int *created)
+{
+ aChannel *chptr;
+ int len;
+
+ if(created)
+ *created = 0;
+
+ if (BadPtr(chname))
+ return NULL;
+
+ len = strlen(chname);
+ if (MyClient(cptr) && len > CHANNELLEN)
+ {
+ len = CHANNELLEN;
+ *(chname + CHANNELLEN) = '\0';
+ }
+ if ((chptr = find_channel(chname, (aChannel *) NULL)))
+ return (chptr);
+ if (flag == CREATE)
+ {
+ chptr = make_channel();
+
+ if(created)
+ *created = 1;
+
+ strncpyzt(chptr->chname, chname, len + 1);
+ if (channel)
+ channel->prevch = chptr;
+ chptr->prevch = NULL;
+ chptr->nextch = channel;
+ channel = chptr;
+ chptr->channelts = timeofday;
+ (void) add_to_channel_hash_table(chname, chptr);
+ Count.chan++;
+ }
+ return chptr;
+}
+
+static void add_invite(aClient *cptr, aChannel *chptr)
+{
+ Link *inv, **tmp;
+
+ del_invite(cptr, chptr);
+ /*
+ * delete last link in chain if the list is max length
+ */
+ if (list_length(cptr->user->invited) >= maxchannelsperuser)
+ {
+ /*
+ * This forgets the channel side of invitation -Vesa inv =
+ * cptr->user->invited; cptr->user->invited = inv->next;
+ * free_link(inv);
+ */
+ del_invite(cptr, cptr->user->invited->value.chptr);
+
+ }
+
+ /*
+ * add client to channel invite list
+ */
+ inv = make_link();
+ inv->value.cptr = cptr;
+ inv->next = chptr->invites;
+ chptr->invites = inv;
+ /*
+ * add channel to the end of the client invite list
+ */
+ for (tmp = &(cptr->user->invited); *tmp; tmp = &((*tmp)->next));
+ inv = make_link();
+ inv->value.chptr = chptr;
+ inv->next = NULL;
+ (*tmp) = inv;
+}
+
+/*
+ * Delete Invite block from channel invite list and client invite list
+ */
+void del_invite(aClient *cptr, aChannel *chptr)
+{
+ Link **inv, *tmp;
+
+ for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
+ if (tmp->value.cptr == cptr)
+ {
+ *inv = tmp->next;
+ free_link(tmp);
+ break;
+ }
+
+ for (inv = &(cptr->user->invited); (tmp = *inv); inv = &tmp->next)
+ if (tmp->value.chptr == chptr)
+ {
+ *inv = tmp->next;
+ free_link(tmp);
+ break;
+ }
+}
+
+/*
+ * * Subtract one user from channel i (and free channel * block, if
+ * channel became empty).
+ */
+static void sub1_from_channel(aChannel *chptr)
+{
+ Link *tmp;
+ aBan *bp, *bprem;
+#ifdef INVITE_LISTS
+ anInvite *invite, *invrem;
+#endif
+#ifdef EXEMPT_LISTS
+ aBanExempt *exempt, *exrem;
+#endif
+
+ if (--chptr->users <= 0)
+ {
+ /*
+ * Now, find all invite links from channel structure
+ */
+ while ((tmp = chptr->invites))
+ del_invite(tmp->value.cptr, chptr);
+
+ bp = chptr->banlist;
+ while (bp)
+ {
+ bprem = bp;
+ bp = bp->next;
+ MyFree(bprem->banstr);
+ MyFree(bprem->who);
+ MyFree(bprem);
+ }
+#ifdef INVITE_LISTS
+ invite = chptr->invite_list;
+ while (invite)
+ {
+ invrem = invite;
+ invite = invite->next;
+ MyFree(invrem->invstr);
+ MyFree(invrem->who);
+ MyFree(invrem);
+ }
+#endif
+#ifdef EXEMPT_LISTS
+ exempt = chptr->banexempt_list;
+ while (exempt)
+ {
+ exrem = exempt;
+ exempt = exempt->next;
+ MyFree(exrem->banstr);
+ MyFree(exrem->who);
+ MyFree(exrem);
+ }
+#endif
+
+ if (chptr->prevch)
+ chptr->prevch->nextch = chptr->nextch;
+ else
+ channel = chptr->nextch;
+ if (chptr->nextch)
+ chptr->nextch->prevch = chptr->prevch;
+ (void) del_from_channel_hash_table(chptr->chname, chptr);
+#ifdef FLUD
+ free_fluders(NULL, chptr);
+#endif
+ free_channel(chptr);
+ Count.chan--;
+ }
+}
+
+/*
+ * m_join
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ * parv[2] = channel password (key)
+ */
+int m_join(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ static char jbuf[BUFSIZE];
+ Link *lp;
+ struct simBan *ban;
+ aChannel *chptr;
+ char *name, *key = NULL;
+ int i, flags = 0, chanlen=0;
+ int allow_op = YES;
+ char *p = NULL, *p2 = NULL;
+
+#ifdef ANTI_SPAMBOT
+ int successful_join_count = 0;
+ /* Number of channels successfully joined */
+#endif
+
+ if (!(sptr->user))
+ {
+ /* something is *fucked* - bail */
+ return 0;
+ }
+
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "JOIN");
+ return 0;
+ }
+
+ if (MyClient(sptr))
+ parv[1] = canonize(parv[1]);
+
+ *jbuf = '\0';
+ /*
+ * * Rebuild list of channels joined to be the actual result of the *
+ * JOIN. Note that "JOIN 0" is the destructive problem.
+ */
+ for (i = 0, name = strtoken(&p, parv[1], ","); name;
+ name = strtoken(&p, (char *) NULL, ","))
+ {
+ /*
+ * pathological case only on longest channel name. * If not dealt
+ * with here, causes desynced channel ops * since ChannelExists()
+ * doesn't see the same channel * as one being joined. cute bug.
+ * Oct 11 1997, Dianora/comstud
+ */
+ if(!check_channelname(sptr, (unsigned char *) name))
+ continue;
+
+ chanlen=strlen(name);
+
+ if (chanlen > CHANNELLEN) /* same thing is done in get_channel() */
+ {
+ name[CHANNELLEN] = '\0';
+ chanlen=CHANNELLEN;
+ }
+ if (*name == '0' && !atoi(name))
+ *jbuf = '\0';
+ else if (!IsChannelName(name))
+ {
+ if (MyClient(sptr))
+ sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL),
+ me.name, parv[0], name);
+ continue;
+ }
+ if (*jbuf)
+ (void) strcat(jbuf, ",");
+ (void) strncat(jbuf, name, sizeof(jbuf) - i - 1);
+ i += chanlen + 1;
+ }
+
+ p = NULL;
+ if (parv[2])
+ key = strtoken(&p2, parv[2], ",");
+ parv[2] = NULL; /*
+ * for m_names call later, parv[parc]
+ * * must == NULL
+ */
+ for (name = strtoken(&p, jbuf, ","); name;
+ key = (key) ? strtoken(&p2, NULL, ",") : NULL,
+ name = strtoken(&p, NULL, ","))
+ {
+ /*
+ * JOIN 0 sends out a part for all channels a user * has
+ * joined.
+ */
+ if (*name == '0' && !atoi(name))
+ {
+ if (sptr->user->channel == NULL)
+ continue;
+ while ((lp = sptr->user->channel))
+ {
+ chptr = lp->value.chptr;
+ sendto_channel_butserv(chptr, sptr, PartFmt,
+ parv[0], chptr->chname);
+ remove_user_from_channel(sptr, chptr);
+ }
+ /*
+ * Added /quote set for SPAMBOT
+ *
+ * int spam_time = MIN_JOIN_LEAVE_TIME; int spam_num =
+ * MAX_JOIN_LEAVE_COUNT;
+ */
+#ifdef ANTI_SPAMBOT /* Dianora */
+
+ if (MyConnect(sptr) && !IsAnOper(sptr))
+ {
+ if (sptr->join_leave_count >= spam_num)
+ {
+ sendto_realops_lev(SPAM_LEV, "User %s (%s@%s) is a "
+ "possible spambot", sptr->name,
+ sptr->user->username, sptr->user->host);
+ sptr->oper_warn_count_down = OPER_SPAM_COUNTDOWN;
+ }
+ else
+ {
+ int t_delta;
+
+ if ((t_delta = (NOW - sptr->last_leave_time)) >
+ JOIN_LEAVE_COUNT_EXPIRE_TIME)
+ {
+ int decrement_count;
+
+ decrement_count = (t_delta /
+ JOIN_LEAVE_COUNT_EXPIRE_TIME);
+
+ if (decrement_count > sptr->join_leave_count)
+ sptr->join_leave_count = 0;
+ else
+ sptr->join_leave_count -= decrement_count;
+ }
+ else
+ {
+ if ((NOW - (sptr->last_join_time)) < spam_time)
+ {
+ /* oh, its a possible spambot */
+ sptr->join_leave_count++;
+ }
+ }
+ sptr->last_leave_time = NOW;
+ }
+ }
+#endif
+ sendto_serv_butone(cptr, ":%s JOIN 0", parv[0]);
+ continue;
+ }
+
+ if (MyConnect(sptr))
+ {
+ /* have we quarantined this channel? */
+ if(!IsOper(sptr) && (ban = check_mask_simbanned(name, SBAN_CHAN)))
+ {
+ sendto_one(sptr, getreply(ERR_CHANBANREASON), me.name, parv[0], name,
+ BadPtr(ban->reason) ? "Reserved channel" :
+ ban->reason);
+ continue;
+ }
+
+ /*
+ * local client is first to enter previously nonexistent *
+ * channel so make them (rightfully) the Channel * Operator.
+ */
+ flags = (ChannelExists(name)) ? 0 : CHFL_CHANOP;
+
+ if (!IsAnOper(sptr) && server_was_split
+ && !(confopts & FLAGS_SPLITOPOK))
+ allow_op = NO;
+
+ if ((sptr->user->joined >= maxchannelsperuser) &&
+ (!IsAnOper(sptr) || (sptr->user->joined >=
+ maxchannelsperuser * 3)))
+ {
+ sendto_one(sptr, err_str(ERR_TOOMANYCHANNELS),
+ me.name, parv[0], name);
+#ifdef ANTI_SPAMBOT
+ if (successful_join_count)
+ sptr->last_join_time = NOW;
+#endif
+ return 0;
+ }
+#ifdef ANTI_SPAMBOT /*
+ * Dianora
+ */
+ if (flags == 0) /* if channel doesn't exist, don't penalize */
+ successful_join_count++;
+ if (sptr->join_leave_count >= spam_num)
+ {
+ /* Its already known as a possible spambot */
+
+ if (sptr->oper_warn_count_down > 0) /* my general paranoia */
+ sptr->oper_warn_count_down--;
+ else
+ sptr->oper_warn_count_down = 0;
+
+ if (sptr->oper_warn_count_down == 0)
+ {
+ sendto_realops_lev(SPAM_LEV, "User %s (%s@%s) trying to "
+ "join %s is a possible spambot",
+ sptr->name,
+ sptr->user->username,
+ sptr->user->host,
+ name);
+ sptr->oper_warn_count_down = OPER_SPAM_COUNTDOWN;
+ }
+# ifndef ANTI_SPAMBOT_WARN_ONLY
+ return 0; /* Don't actually JOIN anything, but
+ * don't let spambot know that */
+# endif
+ }
+#endif
+ }
+ else
+ {
+ /*
+ * complain for remote JOINs to existing channels * (they
+ * should be SJOINs) -orabidoo
+ */
+ if (!ChannelExists(name))
+ ts_warn("User on %s remotely JOINing new channel",
+ sptr->user->server);
+ }
+
+ chptr = get_channel(sptr, name, CREATE, NULL);
+
+ if (chptr && IsMember(sptr, chptr))
+ continue;
+
+ if (!chptr || (MyConnect(sptr) && !can_join(sptr, chptr, key)))
+ {
+#ifdef ANTI_SPAMBOT
+ if (successful_join_count > 0)
+ successful_join_count--;
+#endif
+ continue;
+ }
+
+/* only complain when the user can join the channel, the channel is
+ * being created by this user, and this user is not allowed to be an op.
+ * - lucas
+ */
+
+ if (flags && !allow_op)
+ sendto_one(sptr, ":%s NOTICE %s :*** Notice -- Due to a network "
+ "split, you can not obtain channel operator status in "
+ "a new channel at this time.", me.name, sptr->name);
+
+ /* Complete user entry to the new channel (if any) */
+ if (allow_op)
+ add_user_to_channel(chptr, sptr, flags);
+ else
+ add_user_to_channel(chptr, sptr, 0);
+ chptr->join_count++;
+ /* Set timestamp if appropriate, and propagate */
+ if (MyClient(sptr) && flags == CHFL_CHANOP)
+ {
+ chptr->channelts = timeofday;
+
+ /* we keep channel "creations" to the server sjoin format,
+ so we can bounce modes and stuff if our ts is older. */
+
+ if (allow_op)
+ sendto_serv_butone(cptr, ":%s SJOIN %ld %s + :@%s", me.name,
+ chptr->channelts, name, parv[0]);
+ else
+ sendto_serv_butone(cptr, ":%s SJOIN %ld %s + :%s", me.name,
+ chptr->channelts, name, parv[0]);
+ }
+ else if (MyClient(sptr))
+ sendto_serv_butone(cptr, CliSJOINFmt, parv[0], chptr->channelts,
+ name);
+ else
+ sendto_serv_butone(cptr, ":%s JOIN :%s", parv[0], name);
+
+ /* notify all other users on the new channel */
+ sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
+
+ if (MyClient(sptr))
+ {
+ del_invite(sptr, chptr);
+ if (chptr->topic[0] != '\0')
+ {
+ sendto_one(sptr, rpl_str(RPL_TOPIC), me.name,
+ parv[0], name, chptr->topic);
+ sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME),
+ me.name, parv[0], name,
+ chptr->topic_nick,
+ chptr->topic_time);
+ }
+ parv[1] = name;
+ (void) m_names(cptr, sptr, 2, parv);
+ }
+ }
+
+#ifdef ANTI_SPAMBOT
+ if (MyConnect(sptr) && successful_join_count)
+ sptr->last_join_time = NOW;
+#endif
+ return 0;
+}
+
+/* m_sajoin
+ * join a channel regardless of modes.
+ */
+
+int m_sajoin(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aChannel *chptr;
+ char *name;
+ int i;
+ char errmodebuf[128];
+
+ /* Remote sajoin? nope. */
+ if(!MyClient(sptr))
+ return 0;
+
+ if(!IsSAdmin(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "SAJOIN");
+ return 0;
+ }
+
+ name = parv[1];
+
+ chptr = find_channel(name, NULL);
+ if(!chptr)
+ {
+ sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL),
+ me.name, parv[0], name);
+ return 0;
+ }
+
+ /* bail if they're already in the channel */
+ if(IsMember(sptr, chptr))
+ return 0;
+
+ if((i = can_join_whynot(sptr, chptr, NULL, errmodebuf)))
+ {
+ send_globops("from %s: %s used SAJOIN (%s +%s)",
+ me.name, sptr->name, chptr->chname, errmodebuf);
+ sendto_serv_butone(NULL, ":%s GLOBOPS :%s used SAJOIN (%s +%s)",
+ me.name, sptr->name, chptr->chname, errmodebuf);
+ }
+ else
+ sendto_one(sptr, ":%s NOTICE %s :You didn't need to use"
+ " /SAJOIN for %s", me.name, parv[0], chptr->chname);
+
+ add_user_to_channel(chptr, sptr, 0);
+ sendto_serv_butone(cptr, CliSJOINFmt, parv[0], chptr->channelts, name);
+ sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
+ if(MyClient(sptr))
+ {
+ if(chptr->topic[0] != '\0')
+ {
+ sendto_one(sptr, rpl_str(RPL_TOPIC), me.name, parv[0],
+ name, chptr->topic);
+ sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME), me.name, parv[0],
+ name, chptr->topic_nick, chptr->topic_time);
+ }
+ parv[1] = name;
+ parv[2] = NULL;
+ m_names(cptr, sptr, 2, parv);
+ }
+ return 0;
+}
+
+/*
+ * m_part
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ * parv[2] = Optional part reason
+ */
+int m_part(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aChannel *chptr;
+ char *p, *name;
+ char *reason = (parc > 2 && parv[2]) ? parv[2] : NULL;
+
+ if (parc < 2 || parv[1][0] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "PART");
+ return 0;
+ }
+
+ name = strtoken(&p, parv[1], ",");
+
+#ifdef ANTI_SPAMBOT /* Dianora */
+ /* if its my client, and isn't an oper */
+
+ if (name && MyConnect(sptr) && !IsAnOper(sptr))
+ {
+ if (sptr->join_leave_count >= spam_num)
+ {
+ sendto_realops_lev(SPAM_LEV, "User %s (%s@%s) is a possible"
+ " spambot", sptr->name, sptr->user->username,
+ sptr->user->host);
+ sptr->oper_warn_count_down = OPER_SPAM_COUNTDOWN;
+ }
+ else
+ {
+ int t_delta;
+
+ if ((t_delta = (NOW - sptr->last_leave_time)) >
+ JOIN_LEAVE_COUNT_EXPIRE_TIME)
+ {
+ int decrement_count;
+
+ decrement_count = (t_delta / JOIN_LEAVE_COUNT_EXPIRE_TIME);
+
+ if (decrement_count > sptr->join_leave_count)
+ sptr->join_leave_count = 0;
+ else
+ sptr->join_leave_count -= decrement_count;
+ }
+ else
+ {
+ if ((NOW - (sptr->last_join_time)) < spam_time)
+ {
+ /* oh, its a possible spambot */
+ sptr->join_leave_count++;
+ }
+ }
+ sptr->last_leave_time = NOW;
+ }
+ }
+#endif
+
+ while (name)
+ {
+ chptr = get_channel(sptr, name, 0, NULL);
+ if (!chptr)
+ {
+ sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL),
+ me.name, parv[0], name);
+ name = strtoken(&p, (char *) NULL, ",");
+ continue;
+ }
+
+ if (!IsMember(sptr, chptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOTONCHANNEL),
+ me.name, parv[0], name);
+ name = strtoken(&p, (char *) NULL, ",");
+ continue;
+ }
+ /* Remove user from the old channel (if any) */
+
+ if (parc < 3 || can_send(sptr,chptr,reason))
+ sendto_serv_butone(cptr, PartFmt, parv[0], name);
+ else
+ sendto_serv_butone(cptr, PartFmt2, parv[0], name, reason);
+ if (parc < 3 || can_send(sptr,chptr,reason))
+ sendto_channel_butserv(chptr, sptr, PartFmt, parv[0], name);
+ else
+ sendto_channel_butserv(chptr, sptr, PartFmt2, parv[0], name,
+ reason);
+ remove_user_from_channel(sptr, chptr);
+ name = strtoken(&p, (char *) NULL, ",");
+ }
+ return 0;
+}
+
+/*
+ * m_kick
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ * parv[2] = client to kick
+ * parv[3] = kick comment
+ */
+int m_kick(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aClient *who;
+ aChannel *chptr;
+ int chasing = 0;
+ int user_count; /* count nicks being kicked, only allow 4 */
+ char *comment, *name, *p = NULL, *user, *p2 = NULL;
+
+ if (parc < 3 || *parv[1] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "KICK");
+ return 0;
+ }
+ if (IsServer(sptr) && !IsULine(sptr))
+ sendto_ops("KICK from %s for %s %s",
+ parv[0], parv[1], parv[2]);
+ comment = (BadPtr(parv[3])) ? parv[0] : parv[3];
+ if (strlen(comment) > (size_t) TOPICLEN)
+ comment[TOPICLEN] = '\0';
+
+ *nickbuf = *buf = '\0';
+ name = strtoken(&p, parv[1], ",");
+
+ while (name)
+ {
+ chptr = get_channel(sptr, name, !CREATE, NULL);
+ if (!chptr)
+ {
+ sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL),
+ me.name, parv[0], name);
+ name = strtoken(&p, (char *) NULL, ",");
+ continue;
+ }
+
+ /*
+ * You either have chan op privs, or you don't -Dianora
+ *
+ * orabidoo and I discussed this one for a while... I hope he
+ * approves of this code, users can get quite confused...
+ * -Dianora
+ */
+
+ if (!IsServer(sptr) && !is_chan_op(sptr, chptr) && !IsULine(sptr))
+ {
+ /* was a user, not a server and user isn't seen as a chanop here */
+
+ if (MyConnect(sptr))
+ {
+ /* user on _my_ server, with no chanops.. so go away */
+
+ sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
+ me.name, parv[0], chptr->chname);
+ name = strtoken(&p, (char *) NULL, ",");
+ continue;
+ }
+
+ if (chptr->channelts == 0)
+ {
+ /* If its a TS 0 channel, do it the old way */
+
+ sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
+ me.name, parv[0], chptr->chname);
+ name = strtoken(&p, (char *) NULL, ",");
+ continue;
+ }
+ /*
+ * Its a user doing a kick, but is not showing as chanop
+ * locally its also not a user ON -my- server, and the channel
+ * has a TS. There are two cases we can get to this point
+ * then...
+ *
+ * 1) connect burst is happening, and for some reason a legit op
+ * has sent a KICK, but the SJOIN hasn't happened yet or been
+ * seen. (who knows.. due to lag...)
+ *
+ * 2) The channel is desynced. That can STILL happen with TS
+ *
+ * Now, the old code roger wrote, would allow the KICK to go
+ * through. Thats quite legit, but lets weird things like
+ * KICKS by users who appear not to be chanopped happen, or
+ * even neater, they appear not to be on the channel. This
+ * fits every definition of a desync, doesn't it? ;-) So I
+ * will allow the KICK, otherwise, things are MUCH worse. But
+ * I will warn it as a possible desync.
+ *
+ * -Dianora
+ *
+ * sendto_one(sptr, err_str(ERR_DESYNC), me.name, parv[0],
+ * chptr->chname);
+ *
+ * After more discussion with orabidoo...
+ *
+ * The code was sound, however, what happens if we have +h (TS4)
+ * and some servers don't understand it yet? we will be seeing
+ * servers with users who appear to have no chanops at all,
+ * merrily kicking users.... -Dianora
+ *
+ */
+ }
+
+ user = strtoken(&p2, parv[2], ",");
+ user_count = 4;
+ while (user && user_count)
+ {
+ user_count--;
+ if (!(who = find_chasing(sptr, user, &chasing)))
+ {
+ user = strtoken(&p2, (char *) NULL, ",");
+ continue; /* No such user left! */
+ }
+
+ if (IsMember(who, chptr))
+ {
+ sendto_channel_butserv(chptr, sptr,
+ ":%s KICK %s %s :%s", parv[0],
+ name, who->name, comment);
+ sendto_serv_butone(cptr, ":%s KICK %s %s :%s", parv[0], name,
+ who->name, comment);
+ remove_user_from_channel(who, chptr);
+ }
+ else
+ sendto_one(sptr, err_str(ERR_USERNOTINCHANNEL),
+ me.name, parv[0], user, name);
+ user = strtoken(&p2, (char *) NULL, ",");
+ } /* loop on parv[2] */
+
+ name = strtoken(&p, (char *) NULL, ",");
+ } /* loop on parv[1] */
+
+ return (0);
+}
+
+int count_channels(aClient *sptr)
+{
+ aChannel *chptr;
+ int count = 0;
+
+ for (chptr = channel; chptr; chptr = chptr->nextch)
+ count++;
+ return (count);
+}
+
+void send_topic_burst(aClient *cptr)
+{
+ aChannel *chptr;
+ aClient *acptr;
+ for (chptr = channel; chptr; chptr = chptr->nextch)
+ {
+ if(chptr->topic[0] != '\0')
+ sendto_one(cptr, ":%s TOPIC %s %s %ld :%s", me.name, chptr->chname,
+ chptr->topic_nick, chptr->topic_time, chptr->topic);
+ }
+ for (acptr = client; acptr; acptr = acptr->next)
+ {
+ if(!IsPerson(acptr) || acptr->from == cptr)
+ continue;
+ if(acptr->user->away)
+ sendto_one(cptr, ":%s AWAY :%s", acptr->name, acptr->user->away);
+ }
+}
+
+/*
+ * m_topic
+ * parv[0] = sender prefix
+ * parv[1] = topic text
+ */
+int m_topic(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aChannel *chptr = NullChn;
+ char *topic = NULL, *name, *tnick = sptr->name;
+ time_t ts = timeofday;
+ int member;
+
+ if (parc < 2)
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0],
+ "TOPIC");
+ return 0;
+ }
+
+ name = parv[1];
+ chptr = find_channel(name, NullChn);
+ if(!chptr)
+ {
+ sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
+ return 0;
+ }
+
+ member = IsMember(sptr, chptr);
+
+ if (parc == 2) /* user is requesting a topic */
+ {
+ char *namep = chptr->chname;
+ char tempchname[CHANNELLEN + 2];
+
+ if(!member && !(ShowChannel(sptr, chptr)))
+ {
+ if(IsAdmin(sptr))
+ {
+ tempchname[0] = '%';
+ strcpy(&tempchname[1], chptr->chname);
+ namep = tempchname;
+ }
+ else
+ {
+ sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0],
+ name);
+ return 0;
+ }
+ }
+
+ if (chptr->topic[0] == '\0')
+ sendto_one(sptr, rpl_str(RPL_NOTOPIC), me.name, parv[0], namep);
+ else
+ {
+ sendto_one(sptr, rpl_str(RPL_TOPIC), me.name, parv[0], namep,
+ chptr->topic);
+ sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME), me.name, parv[0],
+ namep, chptr->topic_nick, chptr->topic_time);
+ }
+ return 0;
+ }
+
+ topic = parv[2];
+
+ if (MyClient(sptr))
+ {
+ if (!member)
+ {
+ sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0],name);
+ return 0;
+ }
+
+ if ((chptr->mode.mode & MODE_TOPICLIMIT) && !is_chan_op(sptr, chptr))
+ {
+ sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0],
+ chptr->chname);
+ return 0;
+ }
+ }
+ else
+ {
+ /* extended info */
+ if (parc > 3)
+ {
+ topic = (parc > 4 ? parv[4] : "");
+ tnick = parv[2];
+ ts = atoi(parv[3]);
+ }
+
+ /* ignore old topics during burst/race */
+ if (!IsULine(sptr) && chptr->topic[0] && chptr->topic_time >= ts)
+ return 0;
+ }
+
+ strncpyzt(chptr->topic, topic, TOPICLEN + 1);
+ strcpy(chptr->topic_nick, tnick);
+ chptr->topic_time = ts;
+
+ /* in this case I think it's better that we send all the info that df
+ * sends with the topic, so I changed everything to work like that.
+ * -wd */
+
+ sendto_serv_butone(cptr, ":%s TOPIC %s %s %lu :%s", parv[0],
+ chptr->chname, chptr->topic_nick, chptr->topic_time,
+ chptr->topic);
+ sendto_channel_butserv_me(chptr, sptr, ":%s TOPIC %s :%s", parv[0],
+ chptr->chname, chptr->topic);
+
+ return 0;
+}
+
+/*
+ * m_invite
+ * parv[0] - sender prefix
+ * parv[1] - user to invite
+ * parv[2] - channel name
+ */
+int m_invite(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aClient *acptr;
+ aChannel *chptr = NULL;
+
+ if (parc < 3 || *parv[1] == 0)
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0],
+ "INVITE");
+ return -1;
+ }
+
+ if (!(acptr = find_person(parv[1], NULL)))
+ {
+ sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], parv[1]);
+ return 0;
+ }
+
+ if (MyClient(sptr))
+ {
+ if (!(chptr = find_channel(parv[2], NULL)))
+ {
+ sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0],
+ parv[2]);
+ return 0;
+ }
+
+ if (!IsMember(sptr, chptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0],
+ parv[2]);
+ return 0;
+ }
+
+ if (IsMember(acptr, chptr))
+ {
+ sendto_one(sptr, err_str(ERR_USERONCHANNEL), me.name, parv[0],
+ parv[1], chptr->chname);
+ return 0;
+ }
+
+ if (!is_chan_op(sptr, chptr))
+ {
+ sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0],
+ chptr->chname);
+ return 0;
+ }
+
+ sendto_one(sptr, rpl_str(RPL_INVITING), me.name, parv[0], acptr->name,
+ chptr->chname);
+
+ if (acptr->user->away)
+ sendto_one(sptr, rpl_str(RPL_AWAY), me.name, parv[0], acptr->name,
+ acptr->user->away);
+ }
+
+ if (MyClient(acptr))
+ {
+ /* stuff already done above */
+ if (!MyClient(sptr))
+ {
+ if (!(chptr = find_channel(parv[2], NullChn)))
+ return 0;
+
+ if (IsMember(acptr, chptr))
+ return 0;
+ }
+
+ add_invite(acptr, chptr);
+
+ sendto_prefix_one(acptr, sptr, ":%s INVITE %s :%s", parv[0],
+ acptr->name, chptr->chname);
+ sendto_channelops_butone(NULL, &me, chptr, ":%s NOTICE @%s :%s invited"
+ " %s into channel %s", me.name, chptr->chname,
+ parv[0], acptr->name, chptr->chname);
+
+ return 0;
+ }
+
+ sendto_one(acptr, ":%s INVITE %s :%s", parv[0], parv[1], parv[2]);
+
+ return 0;
+}
+
+
+/*
+ * The function which sends the actual channel list back to the user.
+ * Operates by stepping through the hashtable, sending the entries back if
+ * they match the criteria.
+ * cptr = Local client to send the output back to.
+ * numsend = Number (roughly) of lines to send back. Once this number has
+ * been exceeded, send_list will finish with the current hash bucket,
+ * and record that number as the number to start next time send_list
+ * is called for this user. So, this function will almost always send
+ * back more lines than specified by numsend (though not by much,
+ * assuming CH_MAX is was well picked). So be conservative in your choice
+ * of numsend. -Rak
+ */
+
+void send_list(aClient *cptr, int numsend)
+{
+ aChannel *chptr;
+ LOpts *lopt = cptr->user->lopt;
+ int hashnum;
+
+ for (hashnum = lopt->starthash; hashnum < CH_MAX; hashnum++)
+ {
+ if (numsend > 0)
+ {
+ for (chptr = (aChannel *)hash_get_chan_bucket(hashnum);
+ chptr; chptr = chptr->hnextch)
+ {
+ if (SecretChannel(chptr) && !IsAdmin(cptr)
+ && !IsMember(cptr, chptr))
+ continue;
+#ifdef USE_CHANMODE_L
+ if (lopt->only_listed && !(chptr->mode.mode & MODE_LISTED))
+ continue;
+#endif
+ if ((!lopt->showall) && ((chptr->users < lopt->usermin) ||
+ ((lopt->usermax >= 0) &&
+ (chptr->users > lopt->usermax)) ||
+ ((chptr->channelts||1) <
+ lopt->chantimemin) ||
+ (chptr->topic_time <
+ lopt->topictimemin) ||
+ (chptr->channelts >
+ lopt->chantimemax) ||
+ (chptr->topic_time >
+ lopt->topictimemax) ||
+ (lopt->nolist &&
+ find_str_link(lopt->nolist,
+ chptr->chname)) ||
+ (lopt->yeslist &&
+ !find_str_link(lopt->yeslist,
+ chptr->chname))))
+ continue;
+
+ /* Seem'd more efficent to seperate into two commands
+ * then adding an or to the inline. -- Doc.
+ */
+ if (IsAdmin(cptr))
+ {
+ char tempchname[CHANNELLEN + 2], *altchname;
+
+ if (SecretChannel(chptr))
+ {
+ tempchname[0] = '%';
+ strcpy(&tempchname[1], chptr->chname);
+ altchname = &tempchname[0];
+ }
+ else
+ altchname = chptr->chname;
+
+ sendto_one(cptr, rpl_str(RPL_LIST), me.name, cptr->name,
+ altchname, chptr->users, chptr->topic);
+ }
+ else
+ {
+ sendto_one(cptr, rpl_str(RPL_LIST), me.name, cptr->name,
+ ShowChannel(cptr, chptr) ? chptr->chname : "*",
+ chptr->users,
+ ShowChannel(cptr, chptr) ? chptr->topic : "");
+ }
+ numsend--;
+ }
+ }
+ else
+ break;
+ }
+
+ /* All done */
+ if (hashnum == CH_MAX)
+ {
+ Link *lp, *next;
+ sendto_one(cptr, rpl_str(RPL_LISTEND), me.name, cptr->name);
+ for (lp = lopt->yeslist; lp; lp = next)
+ {
+ next = lp->next;
+ free_link(lp);
+ }
+ for (lp = lopt->nolist; lp; lp = next)
+ {
+ next = lp->next;
+ free_link(lp);
+ }
+
+ MyFree(cptr->user->lopt);
+ cptr->user->lopt = NULL;
+ remove_from_list(&listing_clients, cptr, NULL);
+ return;
+ }
+
+ /*
+ * We've exceeded the limit on the number of channels to send back
+ * at once.
+ */
+ lopt->starthash = hashnum;
+ return;
+}
+
+
+/*
+ * m_list
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ */
+int m_list(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aChannel *chptr;
+ time_t currenttime = time(NULL);
+ char *name, *p = NULL;
+ LOpts *lopt = NULL;
+ Link *lp, *next;
+ int usermax, usermin, error = 0, doall = 0, only_listed = 1;
+ int x;
+ time_t chantimemin, chantimemax;
+ ts_val topictimemin, topictimemax;
+ Link *yeslist = NULL, *nolist = NULL;
+
+ static char *usage[] = {
+ " Usage: /raw LIST options (on mirc) or /quote LIST options (ircII)",
+ "",
+ "If you don't include any options, the default is to send you the",
+ "entire unfiltered list of channels. Below are the options you can",
+ "use, and what channels LIST will return when you use them.",
+ ">number List channels with more than <number> people.",
+ "<number List channels with less than <number> people.",
+ "C>number List channels created between now and <number> minutes ago.",
+ "C<number List channels created earlier than <number> minutes ago.",
+ "T>number List channels whose topics are older than <number> minutes",
+ " (Ie, they have not changed in the last <number> minutes.",
+ "T<number List channels whose topics are not older than <number> "
+ "minutes.",
+ "*mask* List channels that match *mask*",
+ "!*mask* List channels that do not match *mask*",
+ NULL
+ };
+
+ /* Some starting san checks -- No interserver lists allowed. */
+ if (cptr != sptr || !sptr->user) return 0;
+
+ if (IsSquelch(sptr))
+ {
+ sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]);
+ return 0;
+ }
+
+ /* If a /list is in progress, then another one will cancel it */
+ if ((lopt = sptr->user->lopt)!=NULL)
+ {
+ sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]);
+ for (lp = lopt->yeslist; lp; lp = next)
+ {
+ next = lp->next;
+ free_link(lp);
+ }
+ for (lp = lopt->nolist; lp; lp = next)
+ {
+ next = lp->next;
+ free_link(lp);
+ }
+ MyFree(sptr->user->lopt);
+ sptr->user->lopt = NULL;
+ remove_from_list(&listing_clients, sptr, NULL);
+ return 0;
+ }
+
+ if (parc < 2 || BadPtr(parv[1]))
+ {
+
+ sendto_one(sptr, rpl_str(RPL_LISTSTART), me.name, parv[0]);
+ lopt = sptr->user->lopt = (LOpts *) MyMalloc(sizeof(LOpts));
+ memset(lopt, '\0', sizeof(LOpts));
+
+ lopt->showall = 1;
+#ifdef USE_CHANMODE_L
+ lopt->only_listed = 1;
+#endif
+
+ add_to_list(&listing_clients, sptr);
+
+ if (SBufLength(&cptr->sendQ) < 2048)
+ send_list(cptr, 64);
+
+ return 0;
+ }
+
+ if ((parc == 2) && (parv[1][0] == '?') && (parv[1][1] == '\0'))
+ {
+ char **ptr = usage;
+ for (; *ptr; ptr++)
+ sendto_one(sptr, rpl_str(RPL_COMMANDSYNTAX), me.name,
+ cptr->name, *ptr);
+ return 0;
+ }
+
+ sendto_one(sptr, rpl_str(RPL_LISTSTART), me.name, parv[0]);
+
+ chantimemax = topictimemax = currenttime + 86400;
+ chantimemin = topictimemin = 0;
+ usermin = 2; /* By default, set the minimum to 2 users */
+ usermax = -1; /* No maximum */
+
+ for (name = strtoken(&p, parv[1], ","); name && !error;
+ name = strtoken(&p, (char *) NULL, ","))
+ {
+
+ switch (*name)
+ {
+ case '<':
+ usermax = atoi(name+1) - 1;
+ doall = 1;
+ break;
+ case '>':
+ usermin = atoi(name+1) + 1;
+ doall = 1;
+ break;
+#ifdef USE_CHANMODE_L
+ case '-':
+ if(!strcasecmp(++name,"all"))
+ {
+ only_listed = 0;
+ doall = 1;
+ }
+ break;
+#endif
+ case 'C':
+ case 'c': /* Channel TS time -- creation time? */
+ ++name;
+ switch (*name++)
+ {
+ case '<':
+ chantimemax = currenttime - 60 * atoi(name);
+ doall = 1;
+ break;
+ case '>':
+ chantimemin = currenttime - 60 * atoi(name);
+ doall = 1;
+ break;
+ default:
+ sendto_one(sptr, err_str(ERR_LISTSYNTAX), me.name,
+ cptr->name);
+ error = 1;
+ }
+ break;
+ case 'T':
+ case 't':
+ ++name;
+ switch (*name++)
+ {
+ case '<':
+ topictimemax = currenttime - 60 * atoi(name);
+ doall = 1;
+ break;
+ case '>':
+ topictimemin = currenttime - 60 * atoi(name);
+ doall = 1;
+ break;
+ default:
+ sendto_one(sptr, err_str(ERR_LISTSYNTAX), me.name,
+ cptr->name);
+ error = 1;
+ }
+ break;
+ default: /* A channel, possibly with wildcards.
+ * Thought for the future: Consider turning wildcard
+ * processing on the fly.
+ * new syntax: !channelmask will tell ircd to ignore
+ * any channels matching that mask, and then
+ * channelmask will tell ircd to send us a list of
+ * channels only masking channelmask. Note: Specifying
+ * a channel without wildcards will return that
+ * channel even if any of the !channelmask masks
+ * matches it.
+ */
+ if (*name == '!')
+ {
+ doall = 1;
+ lp = make_link();
+ lp->next = nolist;
+ nolist = lp;
+ DupString(lp->value.cp, name+1);
+ }
+ else if (strchr(name, '*') || strchr(name, '*'))
+ {
+ doall = 1;
+ lp = make_link();
+ lp->next = yeslist;
+ yeslist = lp;
+ DupString(lp->value.cp, name);
+ }
+ else /* Just a normal channel */
+ {
+ chptr = find_channel(name, NullChn);
+ if (chptr && ((x = ShowChannel(sptr, chptr)) ||
+ IsAdmin(sptr)))
+ {
+ char *nameptr = name;
+ char channame[CHANNELLEN + 2];
+
+ if(!x && IsAdmin(sptr))
+ {
+ channame[0] = '%';
+ strcpy(&channame[1], chptr->chname);
+ nameptr = channame;
+ }
+
+ sendto_one(sptr, rpl_str(RPL_LIST), me.name, parv[0],
+ nameptr, chptr->users, chptr->topic);
+ }
+ }
+ } /* switch */
+ } /* while */
+
+ if (doall)
+ {
+ lopt = sptr->user->lopt = (LOpts *) MyMalloc(sizeof(LOpts));
+ memset(lopt, '\0', sizeof(LOpts));
+ lopt->usermin = usermin;
+ lopt->usermax = usermax;
+ lopt->topictimemax = topictimemax;
+ lopt->topictimemin = topictimemin;
+ lopt->chantimemax = chantimemax;
+ lopt->chantimemin = chantimemin;
+ lopt->nolist = nolist;
+ lopt->yeslist = yeslist;
+ lopt->only_listed = only_listed;
+
+ add_to_list(&listing_clients, sptr);
+
+ if (SBufLength(&cptr->sendQ) < 2048)
+ send_list(cptr, 64);
+ return 0;
+ }
+
+ sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]);
+
+ return 0;
+}
+
+
+
+/************************************************************************
+ * m_names() - Added by Jto 27 Apr 1989
+ * 12 Feb 2000 - geesh, time for a rewrite -lucas
+ ************************************************************************/
+/*
+ * m_names
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ */
+
+/* maximum names para to show to opers when abuse occurs */
+#define TRUNCATED_NAMES 64
+
+int m_names(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ int mlen = strlen(me.name) + NICKLEN + 7;
+ aChannel *chptr;
+ aClient *acptr;
+ int member;
+ chanMember *cm;
+ int idx, flag = 1, spos;
+ char *s, *para = parv[1];
+
+ if (parc < 2 || !MyConnect(sptr))
+ {
+ sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0], "*");
+ return 0;
+ }
+
+ for(s = para; *s; s++)
+ {
+ if(*s == ',')
+ {
+ if(strlen(para) > TRUNCATED_NAMES)
+ para[TRUNCATED_NAMES] = '\0';
+ sendto_realops("names abuser %s %s", get_client_name(sptr, FALSE),
+ para);
+ sendto_one(sptr, err_str(ERR_TOOMANYTARGETS), me.name, sptr->name,
+ "NAMES");
+ return 0;
+ }
+ }
+
+ if(!check_channelname(sptr, (unsigned char *)para))
+ return 0;
+
+ chptr = find_channel(para, (aChannel *) NULL);
+
+ if (!chptr || !ShowChannel(sptr, chptr))
+ {
+ sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0], para);
+ return 0;
+ }
+
+ /* cache whether this user is a member of this channel or not */
+ member = IsMember(sptr, chptr);
+
+ if(PubChannel(chptr))
+ buf[0] = '=';
+ else if(SecretChannel(chptr))
+ buf[0] = '@';
+ else
+ buf[0] = '*';
+
+ idx = 1;
+ buf[idx++] = ' ';
+ for(s = chptr->chname; *s; s++)
+ buf[idx++] = *s;
+ buf[idx++] = ' ';
+ buf[idx++] = ':';
+
+ /* If we go through the following loop and never add anything,
+ we need this to be empty, otherwise spurious things from the
+ LAST /names call get stuck in there.. - lucas */
+ buf[idx] = '\0';
+
+ spos = idx; /* starting point in buffer for names!*/
+
+ for (cm = chptr->members; cm; cm = cm->next)
+ {
+ acptr = cm->cptr;
+ if(IsInvisible(acptr) && !member)
+ continue;
+ if(cm->flags & CHFL_CHANOP)
+ buf[idx++] = '@';
+ else if(cm->flags & CHFL_VOICE)
+ buf[idx++] = '+';
+ for(s = acptr->name; *s; s++)
+ buf[idx++] = *s;
+ buf[idx++] = ' ';
+ buf[idx] = '\0';
+ flag = 1;
+ if(mlen + idx + NICKLEN > BUFSIZE - 3)
+ {
+ sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
+ idx = spos;
+ flag = 0;
+ }
+ }
+
+ if (flag)
+ sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
+
+ sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0], para);
+
+ return 0;
+}
+
+void send_user_joins(aClient *cptr, aClient *user)
+{
+ Link *lp;
+ aChannel *chptr;
+ int cnt = 0, len = 0, clen;
+ char *mask;
+
+ *buf = ':';
+ (void) strcpy(buf + 1, user->name);
+ (void) strcat(buf, " JOIN ");
+ len = strlen(user->name) + 7;
+
+ for (lp = user->user->channel; lp; lp = lp->next)
+ {
+ chptr = lp->value.chptr;
+ if (*chptr->chname == '&')
+ continue;
+ if ((mask = strchr(chptr->chname, ':')))
+ if (match(++mask, cptr->name))
+ continue;
+ clen = strlen(chptr->chname);
+ if (clen > (size_t) BUFSIZE - 7 - len)
+ {
+ if (cnt)
+ sendto_one(cptr, "%s", buf);
+ *buf = ':';
+ (void) strcpy(buf + 1, user->name);
+ (void) strcat(buf, " JOIN ");
+ len = strlen(user->name) + 7;
+ cnt = 0;
+ }
+ (void) strcpy(buf + len, chptr->chname);
+ cnt++;
+ len += clen;
+ if (lp->next)
+ {
+ len++;
+ (void) strcat(buf, ",");
+ }
+ }
+ if (*buf && cnt)
+ sendto_one(cptr, "%s", buf);
+
+ return;
+}
+
+void kill_ban_list(aClient *cptr, aChannel *chptr)
+{
+ void *pnx;
+ aBan *bp;
+#ifdef EXEMPT_LISTS
+ aBanExempt *ep;
+#endif
+#ifdef INVITE_LISTS
+ anInvite *ip;
+#endif
+ char *cp;
+ int count = 0, send = 0;
+
+ cp = modebuf;
+ *cp++ = '-';
+ *cp = '\0';
+
+ *parabuf = '\0';
+
+ for (bp = chptr->banlist; bp; bp = bp->next)
+ {
+ if (strlen(parabuf) + strlen(bp->banstr) + 10 < (size_t) MODEBUFLEN)
+ {
+ if(*parabuf)
+ strcat(parabuf, " ");
+ strcat(parabuf, bp->banstr);
+ count++;
+ *cp++ = 'b';
+ *cp = '\0';
+ }
+ else if (*parabuf)
+ send = 1;
+
+ if (count == MAXMODEPARAMS)
+ send = 1;
+
+ if (send) {
+ sendto_channel_butserv_me(chptr, cptr, ":%s MODE %s %s %s",
+ cptr->name, chptr->chname, modebuf, parabuf);
+ send = 0;
+ *parabuf = '\0';
+ cp = modebuf;
+ *cp++ = '-';
+ if (count != MAXMODEPARAMS)
+ {
+ strcpy(parabuf, bp->banstr);
+ *cp++ = 'b';
+ count = 1;
+ }
+ else
+ count = 0;
+ *cp = '\0';
+ }
+ }
+
+#ifdef EXEMPT_LISTS
+ for (ep = chptr->banexempt_list; ep; ep = ep->next)
+ {
+ if (strlen(parabuf) + strlen(ep->banstr) + 10 < (size_t) MODEBUFLEN)
+ {
+ if(*parabuf)
+ strcat(parabuf, " ");
+ strcat(parabuf, ep->banstr);
+ count++;
+ *cp++ = 'e';
+ *cp = '\0';
+ }
+ else if (*parabuf)
+ send = 1;
+
+ if (count == MAXMODEPARAMS)
+ send = 1;
+
+ if (send) {
+ sendto_channel_butserv_me(chptr, cptr, ":%s MODE %s %s %s",
+ cptr->name, chptr->chname, modebuf, parabuf);
+ send = 0;
+ *parabuf = '\0';
+ cp = modebuf;
+ *cp++ = '-';
+ if (count != MAXMODEPARAMS)
+ {
+ strcpy(parabuf, ep->banstr);
+ *cp++ = 'e';
+ count = 1;
+ }
+ else
+ count = 0;
+ *cp = '\0';
+ }
+ }
+#endif
+
+#ifdef INVITE_LISTS
+ for (ip = chptr->invite_list; ip; ip = ip->next)
+ {
+ if (strlen(parabuf) + strlen(ip->invstr) + 10 < (size_t) MODEBUFLEN)
+ {
+ if(*parabuf)
+ strcat(parabuf, " ");
+ strcat(parabuf, ip->invstr);
+ count++;
+ *cp++ = 'I';
+ *cp = '\0';
+ }
+ else if (*parabuf)
+ send = 1;
+
+ if (count == MAXMODEPARAMS)
+ send = 1;
+
+ if (send) {
+ sendto_channel_butserv_me(chptr, cptr, ":%s MODE %s %s %s",
+ cptr->name, chptr->chname, modebuf, parabuf);
+ send = 0;
+ *parabuf = '\0';
+ cp = modebuf;
+ *cp++ = '-';
+ if (count != MAXMODEPARAMS)
+ {
+ strcpy(parabuf, ip->invstr);
+ *cp++ = 'I';
+ count = 1;
+ }
+ else
+ count = 0;
+ *cp = '\0';
+ }
+ }
+#endif
+
+ if(*parabuf)
+ {
+ sendto_channel_butserv_me(chptr, cptr, ":%s MODE %s %s %s", cptr->name,
+ chptr->chname, modebuf, parabuf);
+ }
+
+ /* physically destroy channel ban list */
+
+ bp = chptr->banlist;
+ while(bp)
+ {
+ pnx = bp->next;
+ MyFree(bp->banstr);
+ MyFree(bp->who);
+ MyFree(bp);
+ bp = pnx;
+ }
+ chptr->banlist = NULL;
+
+#ifdef EXEMPT_LISTS
+ ep = chptr->banexempt_list;
+ while(ep)
+ {
+ pnx = ep->next;
+ MyFree(ep->banstr);
+ MyFree(ep->who);
+ MyFree(ep);
+ ep = pnx;
+ }
+ chptr->banexempt_list = NULL;
+#endif
+
+#ifdef INVITE_LISTS
+ ip = chptr->invite_list;
+ while(ip)
+ {
+ pnx = ip->next;
+ MyFree(ip->invstr);
+ MyFree(ip->who);
+ MyFree(ip);
+ ip = pnx;
+ }
+ chptr->invite_list = NULL;
+#endif
+
+ /* reset bquiet cache */
+ chptr->banserial++;
+}
+
+static inline void sjoin_sendit(aClient *cptr, aClient *sptr,
+ aChannel *chptr, char *from)
+{
+ sendto_channel_butserv_me(chptr, sptr, ":%s MODE %s %s %s", from,
+ chptr->chname, modebuf, parabuf);
+}
+
+/* m_resynch
+ *
+ * parv[0] = sender
+ * parv[1] = #channel
+ *
+ * Sent from a server I am directly connected to that is requesting I resend
+ * EVERYTHING I know about #channel.
+ */
+int m_resynch(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aChannel *chptr;
+
+ if(!MyConnect(sptr) || !IsServer(sptr) || parc < 2)
+ return 0;
+
+ chptr = find_channel(parv[1], NullChn);
+
+ sendto_realops_lev(DEBUG_LEV, "%s is requesting a resynch of %s%s",
+ parv[0], parv[1], (chptr == NullChn) ? " [failed]" : "");
+
+ if (chptr != NullChn)
+ send_channel_modes(sptr, chptr);
+ return 0;
+}
+
+/*
+ * m_sjoin
+ * parv[0] - sender
+ * parv[1] - TS
+ * parv[2] - channel
+ * parv[3] - modes + n arguments (key and/or limit)
+ * parv[4+n] - flags+nick list (all in one parameter)
+ *
+ * process a SJOIN, taking the TS's into account to either ignore the
+ * incoming modes or undo the existing ones or merge them, and JOIN all
+ * the specified users while sending JOIN/MODEs to non-TS servers and
+ * to clients
+ */
+
+#define INSERTSIGN(x,y) \
+if (what != x) { \
+*mbuf++=y; \
+what = x; \
+}
+
+#define SJ_MODEPLUS(x, y) \
+ if(((y) & mode.mode) && !((y) & oldmode->mode)) \
+ { \
+ INSERTSIGN(1, '+') \
+ *mbuf++ = (x); \
+ }
+
+#define SJ_MODEMINUS(x, y) \
+ if(((y) & oldmode->mode) && !((y) & mode.mode)) \
+ { \
+ INSERTSIGN(-1, '-') \
+ *mbuf++ = (x); \
+ }
+
+#define SJ_MODEADD(x, y) case (x): mode.mode |= (y); break
+
+#define ADD_PARA(p) para = p; if(pbpos) parabuf[pbpos++] = ' '; \
+ while(*para) parabuf[pbpos++] = *para++;
+#define ADD_SJBUF(p) para = p; if(sjbufpos) sjbuf[sjbufpos++] = ' '; \
+ while(*para) sjbuf[sjbufpos++] = *para++;
+
+int m_sjoin(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aChannel *chptr;
+ aClient *acptr;
+ ts_val newts, oldts, tstosend;
+ static Mode mode, *oldmode;
+ chanMember *cm;
+ int args = 0, haveops = 0, keepourmodes = 1, keepnewmodes = 1,
+ doesop = 0, what = 0, pargs = 0, fl, people = 0,
+ isnew, clientjoin = 0, pbpos, sjbufpos, created = 0;
+ char *s, *s0, *para;
+ static char numeric[16], sjbuf[BUFSIZE];
+ char keep_modebuf[REALMODEBUFLEN], keep_parabuf[REALMODEBUFLEN];
+ char *mbuf = modebuf, *p;
+
+ /* if my client is SJOINing, it's just a local user being a dufus.
+ * Ignore him.
+ * parc >= 5 (new serv<->serv SJOIN format)
+ * parc >= 6 (old serv<->serv SJOIN format)
+ * parc == 3 (new serv<->serv cliSJOIN format)
+ */
+
+ if (MyClient(sptr) || (parc < 5 && IsServer(sptr)) ||
+ (parc < 3 && IsPerson(sptr)))
+ return 0;
+
+ if(parc == 3 && IsPerson(sptr))
+ clientjoin = 1;
+ else
+ if(IsDigit(parv[2][0]))
+ {
+ int i;
+
+ if(parc < 6)
+ return 0;
+
+ for(i = 2; i < (parc - 1); i++)
+ parv[i] = parv[i+1];
+
+ parc--;
+ }
+
+ if (!IsChannelName(parv[2]))
+ return 0;
+
+ newts = atol(parv[1]);
+
+ isnew = ChannelExists(parv[2]) ? 0 : 1;
+ chptr = get_channel(sptr, parv[2], CREATE, &created);
+ oldts = chptr->channelts;
+
+ for (cm = chptr->members; cm; cm = cm->next)
+ if (cm->flags & MODE_CHANOP)
+ {
+ haveops++;
+ break;
+ }
+
+ if(clientjoin) /* we have a good old client sjoin, with timestamp */
+ {
+ if (isnew)
+ chptr->channelts = tstosend = newts;
+ else if (newts == 0 || oldts == 0)
+ chptr->channelts = tstosend = 0;
+ else if (newts == oldts)
+ tstosend = oldts;
+ else if (newts < oldts)
+ {
+#ifdef OLD_WEIRD_CHANOP_NEGOTIATION
+ if (haveops)
+ tstosend = oldts;
+ else
+ chptr->channelts = tstosend = newts;
+#else
+ chptr->channelts = tstosend = newts;
+ sendto_realops_lev(DEBUG_LEV, "Changing TS for %s from %d to %d on"
+ " client SJOIN", chptr->chname, oldts, newts);
+#endif
+ }
+ else
+ tstosend = oldts;
+
+ /* parv[0] is the client that is joining. parv[0] == sptr->name */
+
+ if (!IsMember(sptr, chptr))
+ {
+ add_user_to_channel(chptr, sptr, 0);
+ chptr->join_count++;
+ chptr->default_join_count++;
+ sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0],
+ parv[2]);
+ }
+
+ sendto_serv_butone(cptr, CliSJOINFmt, parv[0], tstosend, parv[2]);
+
+ /* if the channel is created in client sjoin,
+ * we lost some channel modes. */
+ if(created)
+ {
+ sendto_realops_lev(DEBUG_LEV, "Requesting resynch of %s from "
+ "%s (%s!%s@%s[%s] created)", chptr->chname,
+ cptr->name, sptr->name, sptr->user->username,
+ sptr->user->host, sptr->hostip);
+ sendto_one(cptr, "RESYNCH %s", chptr->chname);
+ }
+
+ return 0;
+ }
+
+ memset((char *) &mode, '\0', sizeof(mode));
+
+ s = parv[3];
+ while (*s)
+ {
+ switch (*(s++))
+ {
+ SJ_MODEADD('i', MODE_INVITEONLY);
+ SJ_MODEADD('n', MODE_NOPRIVMSGS);
+ SJ_MODEADD('p', MODE_PRIVATE);
+ SJ_MODEADD('s', MODE_SECRET);
+ SJ_MODEADD('m', MODE_MODERATED);
+ SJ_MODEADD('t', MODE_TOPICLIMIT);
+ SJ_MODEADD('r', MODE_REGISTERED);
+ SJ_MODEADD('R', MODE_REGONLY);
+ SJ_MODEADD('M', MODE_MODREG);
+ SJ_MODEADD('c', MODE_NOCOLOR);
+ SJ_MODEADD('O', MODE_OPERONLY);
+#ifdef USE_CHANMODE_L
+ SJ_MODEADD('L', MODE_LISTED);
+#endif
+ case 'k':
+ strncpyzt(mode.key, parv[4 + args], KEYLEN + 1);
+ args++;
+ if (parc < 5 + args)
+ return 0;
+ break;
+
+ case 'j':
+ {
+ char *tmpa, *tmpb;
+
+ mode.mode |= MODE_JOINRATE;
+ tmpa = parv[4 + args];
+
+ tmpb = strchr(tmpa, ':');
+ if(tmpb)
+ {
+ *tmpb = '\0';
+ tmpb++;
+ mode.join_time = atoi(tmpb);
+ }
+ else
+ mode.join_time = 0;
+
+ mode.join_num = atoi(tmpa);
+
+ args++;
+ if (parc < 5 + args)
+ return 0;
+ }
+ break;
+
+ case 'l':
+ mode.limit = atoi(parv[4 + args]);
+ args++;
+ if (parc < 5 + args)
+ return 0;
+ break;
+ }
+ }
+
+ doesop = (parv[4 + args][0] == '@' || parv[4 + args][1] == '@');
+
+ oldmode = &chptr->mode;
+
+ /* newts is the ts the remote server is providing */
+ /* oldts is our channel TS */
+ /* whichever TS is smaller wins. */
+
+ if (isnew)
+ chptr->channelts = tstosend = newts;
+ else if (newts == 0 || oldts == 0)
+ chptr->channelts = tstosend = 0;
+ else if (newts == oldts)
+ tstosend = oldts;
+#ifdef OLD_WEIRD_CHANOP_NEGOTIATION
+ else if (newts < oldts)
+ {
+ /* if remote ts is older, and they have ops, don't keep our modes. */
+ if (doesop)
+ {
+ kill_ban_list(sptr, chptr);
+ keepourmodes = 0;
+ }
+ if (haveops && !doesop)
+ tstosend = oldts;
+ else
+ chptr->channelts = tstosend = newts;
+ }
+ else /* if our TS is older, and we have ops, don't keep their modes */
+ {
+ if (haveops)
+ keepnewmodes = 0;
+ if (doesop && !haveops)
+ {
+ chptr->channelts = tstosend = newts;
+ if (MyConnect(sptr) && !IsULine(sptr))
+ ts_warn("Hacked ops on opless channel: %s", chptr->chname);
+ }
+ else
+ tstosend = oldts;
+ }
+#else
+ else if (newts < oldts)
+ {
+ /* if remote ts is older, don't keep our modes. */
+ kill_ban_list(sptr, chptr);
+ keepourmodes = 0;
+ chptr->channelts = tstosend = newts;
+ }
+ else /* if our TS is older, don't keep their modes */
+ {
+ keepnewmodes = 0;
+ tstosend = oldts;
+ }
+#endif
+
+ if (!keepnewmodes)
+ mode = *oldmode;
+ else if (keepourmodes)
+ {
+ mode.mode |= oldmode->mode;
+ if (oldmode->limit > mode.limit)
+ mode.limit = oldmode->limit;
+ if(*oldmode->key && *mode.key && strcmp(mode.key, oldmode->key) > 0)
+ strcpy(mode.key, oldmode->key);
+ else if(*oldmode->key && *mode.key == '\0')
+ strcpy(mode.key, oldmode->key);
+ if ((oldmode->mode & MODE_JOINRATE) && mode.join_num)
+ {
+ /* 0 wins */
+ if (!oldmode->join_num)
+ {
+ mode.join_num = oldmode->join_num;
+ mode.join_time = oldmode->join_time;
+ }
+ /* more joins or same joins in less time wins */
+ else if (oldmode->join_num > mode.join_num ||
+ (oldmode->join_num == mode.join_num &&
+ oldmode->join_time < mode.join_time))
+ {
+ mode.join_num = oldmode->join_num;
+ mode.join_time = oldmode->join_time;
+ }
+ }
+ }
+
+ pbpos = 0;
+
+ /*
+ * since the most common case is that the modes are exactly the same,
+ * this if will skip over the most common case... :)
+ *
+ * this would look prettier in a for loop, but it's unrolled here
+ * so it's a bit faster. - lucas
+ *
+ * pass +: go through and add new modes that are in mode and not oldmode
+ * pass -: go through and delete old modes that are in oldmode and not mode
+ */
+
+ if(mode.mode != oldmode->mode)
+ {
+ SJ_MODEPLUS('p', MODE_PRIVATE);
+ SJ_MODEPLUS('s', MODE_SECRET);
+ SJ_MODEPLUS('m', MODE_MODERATED);
+ SJ_MODEPLUS('n', MODE_NOPRIVMSGS);
+ SJ_MODEPLUS('t', MODE_TOPICLIMIT);
+ SJ_MODEPLUS('i', MODE_INVITEONLY);
+ SJ_MODEPLUS('r', MODE_REGISTERED);
+ SJ_MODEPLUS('R', MODE_REGONLY);
+ SJ_MODEPLUS('M', MODE_MODREG);
+ SJ_MODEPLUS('c', MODE_NOCOLOR);
+ SJ_MODEPLUS('O', MODE_OPERONLY);
+#ifdef USE_CHANMODE_L
+ SJ_MODEPLUS('L', MODE_LISTED);
+#endif
+
+ SJ_MODEMINUS('p', MODE_PRIVATE);
+ SJ_MODEMINUS('s', MODE_SECRET);
+ SJ_MODEMINUS('m', MODE_MODERATED);
+ SJ_MODEMINUS('n', MODE_NOPRIVMSGS);
+ SJ_MODEMINUS('t', MODE_TOPICLIMIT);
+ SJ_MODEMINUS('i', MODE_INVITEONLY);
+ SJ_MODEMINUS('r', MODE_REGISTERED);
+ SJ_MODEMINUS('R', MODE_REGONLY);
+ SJ_MODEMINUS('M', MODE_MODREG);
+ SJ_MODEMINUS('c', MODE_NOCOLOR);
+ SJ_MODEMINUS('O', MODE_OPERONLY);
+#ifdef USE_CHANMODE_L
+ SJ_MODEMINUS('L', MODE_LISTED);
+#endif
+
+ }
+
+ if ((oldmode->mode & MODE_JOINRATE) && !(mode.mode & MODE_JOINRATE))
+ {
+ INSERTSIGN(-1,'-')
+ *mbuf++ = 'j';
+ }
+
+ if ((mode.mode & MODE_JOINRATE) && (!(oldmode->mode & MODE_JOINRATE) ||
+ (oldmode->join_num != mode.join_num ||
+ oldmode->join_time != mode.join_time)))
+ {
+ char tmp[128];
+
+ INSERTSIGN(1,'+')
+ *mbuf++ = 'j';
+
+ if(mode.join_num == 0 || mode.join_time == 0)
+ ircsprintf(tmp, "0");
+ else
+ ircsprintf(tmp, "%d:%d", mode.join_num, mode.join_time);
+ ADD_PARA(tmp)
+ pargs++;
+ }
+
+ if (oldmode->limit && !mode.limit)
+ {
+ INSERTSIGN(-1,'-')
+ *mbuf++ = 'l';
+ }
+
+ if (mode.limit && oldmode->limit != mode.limit)
+ {
+ INSERTSIGN(1,'+')
+ *mbuf++ = 'l';
+ sprintf(numeric, "%-15d", mode.limit);
+ if ((s = strchr(numeric, ' ')))
+ *s = '\0';
+ ADD_PARA(numeric);
+ pargs++;
+ }
+
+ if (oldmode->key[0] && !mode.key[0])
+ {
+ INSERTSIGN(-1,'-')
+ *mbuf++ = 'k';
+ ADD_PARA(oldmode->key)
+ pargs++;
+ }
+
+ if (mode.key[0] && strcmp(oldmode->key, mode.key))
+ {
+ INSERTSIGN(1,'+')
+ *mbuf++ = 'k';
+ ADD_PARA(mode.key)
+ pargs++;
+ }
+
+ chptr->mode = mode;
+
+ if (!keepourmodes) /* deop and devoice everyone! */
+ {
+ what = 0;
+ for (cm = chptr->members; cm; cm = cm->next)
+ {
+ if (cm->flags & MODE_CHANOP)
+ {
+ INSERTSIGN(-1,'-')
+ *mbuf++ = 'o';
+ ADD_PARA(cm->cptr->name)
+ pargs++;
+ if (pargs >= MAXMODEPARAMS)
+ {
+ *mbuf = '\0';
+ parabuf[pbpos] = '\0';
+ sjoin_sendit(cptr, sptr, chptr, parv[0]);
+ mbuf = modebuf;
+ *mbuf = '\0';
+ pargs = pbpos = what = 0;
+ }
+ cm->flags &= ~MODE_CHANOP;
+ }
+
+ if (cm->flags & MODE_VOICE)
+ {
+ INSERTSIGN(-1,'-')
+ *mbuf++ = 'v';
+ ADD_PARA(cm->cptr->name)
+ pargs++;
+ if (pargs >= MAXMODEPARAMS)
+ {
+ *mbuf = '\0';
+ parabuf[pbpos] = '\0';
+ sjoin_sendit(cptr, sptr, chptr, parv[0]);
+ mbuf = modebuf;
+ *mbuf = '\0';
+ pargs = pbpos = what = 0;
+ }
+ cm->flags &= ~MODE_VOICE;
+ }
+ }
+ /*
+ * We know if we get here, and we're in a sync, we haven't sent our topic
+ * to sptr yet. (since topic burst is sent after sjoin burst finishes)
+ */
+ if(chptr->topic[0])
+ {
+ chptr->topic[0] = '\0';
+ sendto_channel_butserv_me(chptr, sptr, ":%s TOPIC %s :%s",
+ sptr->name, chptr->chname, chptr->topic);
+ }
+ sendto_channel_butserv(chptr, &me,
+ ":%s NOTICE %s :*** Notice -- TS for %s "
+ "changed from %ld to %ld",
+ me.name, chptr->chname, chptr->chname,
+ oldts, newts);
+ }
+
+ if (mbuf != modebuf)
+ {
+ *mbuf = '\0';
+ parabuf[pbpos] = '\0';
+ sjoin_sendit(cptr, sptr, chptr, parv[0]);
+ }
+
+ *modebuf = '\0';
+ parabuf[0] = '\0';
+ if (parv[3][0] != '0' && keepnewmodes)
+ channel_modes(sptr, modebuf, parabuf, chptr);
+ else
+ {
+ modebuf[0] = '0';
+ modebuf[1] = '\0';
+ }
+
+ /* We do this down below now, so we can send out for two sjoin formats.
+ * sprintf(t, ":%s SJOIN %ld %ld %s %s %s :", parv[0], tstosend, tstosend,
+ * parv[2], modebuf, parabuf);
+ * t += strlen(t);
+ * the pointer "t" has been removed and is now replaced with an
+ * index into sjbuf for faster appending
+ */
+
+ strcpy(keep_modebuf, modebuf);
+ strcpy(keep_parabuf, parabuf);
+
+ sjbufpos = 0;
+ mbuf = modebuf;
+ pbpos = 0;
+ pargs = 0;
+ *mbuf++ = '+';
+
+ for (s = s0 = strtoken(&p, parv[args + 4], " "); s;
+ s = s0 = strtoken(&p, (char *) NULL, " "))
+ {
+ fl = 0;
+ if (*s == '@' || s[1] == '@')
+ fl |= MODE_CHANOP;
+ if (*s == '+' || s[1] == '+')
+ fl |= MODE_VOICE;
+ if (!keepnewmodes)
+ {
+ if (fl & MODE_CHANOP)
+ fl = MODE_DEOPPED;
+ else
+ fl = 0;
+ }
+ while (*s == '@' || *s == '+')
+ s++;
+ if (!(acptr = find_chasing(sptr, s, NULL)))
+ continue;
+ if (acptr->from != cptr)
+ continue;
+ people++;
+ if (!IsMember(acptr, chptr))
+ {
+ add_user_to_channel(chptr, acptr, fl);
+ sendto_channel_butserv(chptr, acptr, ":%s JOIN :%s", s, parv[2]);
+ }
+ if (keepnewmodes)
+ {
+ ADD_SJBUF(s0)
+ }
+ else
+ {
+ ADD_SJBUF(s)
+ }
+ if (fl & MODE_CHANOP)
+ {
+ *mbuf++ = 'o';
+ ADD_PARA(s)
+ pargs++;
+ if (pargs >= MAXMODEPARAMS)
+ {
+ *mbuf = '\0';
+ parabuf[pbpos] = '\0';
+ sjoin_sendit(cptr, sptr, chptr, parv[0]);
+ mbuf = modebuf;
+ *mbuf++ = '+';
+ pargs = pbpos = 0;
+ }
+ }
+ if (fl & MODE_VOICE)
+ {
+ *mbuf++ = 'v';
+ ADD_PARA(s)
+ pargs++;
+ if (pargs >= MAXMODEPARAMS)
+ {
+ *mbuf = '\0';
+ parabuf[pbpos] = '\0';
+ sjoin_sendit(cptr, sptr, chptr, parv[0]);
+ mbuf = modebuf;
+ *mbuf++ = '+';
+ pargs = pbpos = 0;
+ }
+ }
+ }
+
+ parabuf[pbpos] = '\0';
+
+ *mbuf = '\0';
+ if (pargs)
+ sjoin_sendit(cptr, sptr, chptr, parv[0]);
+ if (people)
+ {
+ sjbuf[sjbufpos] = '\0';
+
+ if(keep_parabuf[0] != '\0')
+ sendto_serv_butone(cptr, SJOINFmt, parv[0], tstosend, parv[2],
+ keep_modebuf, keep_parabuf, sjbuf);
+ else
+ sendto_serv_butone(cptr, SJOINFmtNP, parv[0], tstosend, parv[2],
+ keep_modebuf, sjbuf);
+ }
+ else if(created && chptr->users == 0)
+ sub1_from_channel(chptr);
+ return 0;
+}
+#undef INSERTSIGN
+#undef ADD_PARA
+#undef ADD_SJBUF
+
+/* m_samode - Just bout the same as df
+ * - Raistlin
+ * parv[0] = sender
+ * parv[1] = channel
+ * parv[2] = modes
+ */
+int m_samode(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aChannel *chptr;
+
+ if (!MyClient(sptr))
+ return 0;
+
+ if (!IsAnOper(sptr) || !IsSAdmin(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+
+ if(parc < 3)
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "SAMODE");
+ return 0;
+ }
+
+ if((chptr = find_channel(parv[1], NullChn)) == NullChn)
+ return 0;
+
+ if(!check_channelname(sptr, (unsigned char *)parv[1]))
+ return 0;
+
+ set_mode(cptr, sptr, chptr, 2, parc - 2, parv + 2, modebuf, parabuf);
+
+ if (strlen(modebuf) > (size_t)1)
+ {
+ sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s %s",
+ parv[0], chptr->chname, modebuf, parabuf);
+ sendto_serv_butone(cptr, ":%s MODE %s 0 %s %s", parv[0], chptr->chname,
+ modebuf, parabuf);
+ if(MyClient(sptr))
+ {
+ sendto_serv_butone(NULL, ":%s GLOBOPS :%s used SAMODE (%s %s%s%s)",
+ me.name, sptr->name, chptr->chname, modebuf,
+ (*parabuf!=0 ? " " : ""), parabuf);
+ send_globops("from %s: %s used SAMODE (%s %s%s%s)",
+ me.name, sptr->name, chptr->chname, modebuf,
+ (*parabuf!=0 ? " " : ""), parabuf);
+ }
+ }
+ return 0;
+}
+
+char *pretty_mask(char *mask)
+{
+ char *cp, *user, *host;
+
+ if ((user = strchr((cp = mask), '!')))
+ *user++ = '\0';
+ if ((host = strrchr(user ? user : cp, '@')))
+ {
+ *host++ = '\0';
+ if (!user)
+ return make_nick_user_host(NULL, cp, host);
+ }
+ else if (!user && strchr(cp, '.'))
+ return make_nick_user_host(NULL, NULL, cp);
+ return make_nick_user_host(cp, user, host);
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/clientlist.c
+ * Copyright (C) 2003 Lucas Madar
+ */
+
+/* $Id: clientlist.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include "numeric.h"
+#include "blalloc.h"
+
+DLink *server_list = NULL;
+DLink *oper_list = NULL;
+
+/* Clients currently doing a /list */
+DLink *listing_clients = NULL;
+DLink *recvq_clients = NULL;
+
+int get_list_memory(DLink *list)
+{
+ DLink *lp;
+ int count = 0;
+
+ for(lp = list; lp; lp = lp->next)
+ count++;
+
+ return count;
+}
+
+void print_list_memory(aClient *cptr)
+{
+ int lc;
+
+ lc = get_list_memory(server_list);
+ sendto_one(cptr, ":%s %d %s : server_list %d(%d)",
+ me.name, RPL_STATSDEBUG, cptr->name, lc, lc * sizeof(DLink));
+
+ lc = get_list_memory(oper_list);
+ sendto_one(cptr, ":%s %d %s : oper_list %d(%d)",
+ me.name, RPL_STATSDEBUG, cptr->name, lc, lc * sizeof(DLink));
+
+ lc = get_list_memory(listing_clients);
+ sendto_one(cptr, ":%s %d %s : listing_clients %d(%d)",
+ me.name, RPL_STATSDEBUG, cptr->name, lc, lc * sizeof(DLink));
+
+ lc = get_list_memory(recvq_clients);
+ sendto_one(cptr, ":%s %d %s : recvq_clients %d(%d)",
+ me.name, RPL_STATSDEBUG, cptr->name, lc, lc * sizeof(DLink));
+}
+
+DLink *add_to_list(DLink **list, void *ptr)
+{
+ DLink *lp = make_dlink();
+
+ lp->value.cp = (char *) ptr;
+ lp->next = *list;
+ lp->prev = NULL;
+ if(lp->next)
+ lp->next->prev = lp;
+ *list = lp;
+
+ return lp;
+}
+
+static inline void remove_dlink_list(DLink **list, DLink *link)
+{
+ if(link->next)
+ link->next->prev = link->prev;
+
+ if(link->prev)
+ link->prev->next = link->next;
+ else
+ {
+ *list = link->next;
+ if(*list)
+ (*list)->prev = NULL;
+ }
+
+ free_dlink(link);
+}
+
+void remove_from_list(DLink **list, void *ptr, DLink *link)
+{
+ DLink *lp;
+
+ if(link)
+ {
+ remove_dlink_list(list, link);
+ return;
+ }
+
+ for(lp = *list; lp; lp = lp->next)
+ {
+ if(lp->value.cp == (char *) ptr)
+ {
+ remove_dlink_list(list, lp);
+ return;
+ }
+ }
+
+ sendto_realops("remove_from_list(%x, %x) failed!!", (int) list, (int) ptr);
+}
--- /dev/null
+/*
+ * clones.c - Clone detection and limiting
+ * Copyright (C) 2004 Trevor Talbot and
+ * the DALnet coding team
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: clones.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+/*
+ * WARNING: code is chummy with throttle.c
+ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include "blalloc.h"
+#include "numeric.h"
+#include "channel.h"
+
+#include "throttle.h"
+#include "clones.h"
+
+
+#ifndef THROTTLE_ENABLE
+extern BlockHeap *hashent_freelist;
+#endif
+
+
+static void *clones_hashtable;
+
+BlockHeap *free_cloneents;
+CloneEnt *clones_list;
+CloneStat clones_stat;
+
+
+static CloneEnt *
+get_clone(char *key, int create)
+{
+ CloneEnt *ce;
+
+ if (!(ce = hash_find(clones_hashtable, key)) && create)
+ {
+ ce = BlockHeapALLOC(free_cloneents, CloneEnt);
+ memset(ce, 0, sizeof(*ce));
+ strcpy(ce->ent, key);
+ hash_insert(clones_hashtable, ce);
+ ce->next = clones_list;
+ if (clones_list)
+ clones_list->prev = ce;
+ clones_list = ce;
+ }
+
+ return ce;
+}
+
+static void
+expire_clone(CloneEnt *ce)
+{
+ if (ce->gcount || ce->limit || ce->sllimit || ce->sglimit)
+ return;
+
+ if (ce->next)
+ ce->next->prev = ce->prev;
+ if (ce->prev)
+ ce->prev->next = ce->next;
+ else
+ clones_list = ce->next;
+ hash_delete(clones_hashtable, ce);
+ BlockHeapFree(free_cloneents, ce);
+}
+
+
+#ifdef THROTTLE_ENABLE
+static void
+get_clones(aClient *cptr, CloneEnt **ceip, CloneEnt **ce24, int create)
+{
+ char ip24[HOSTIPLEN+1];
+ char *s;
+
+ strcpy(ip24, cptr->hostip);
+ /* deliberate core if strrchr fails -- we need a valid IP string */
+ s = strrchr(ip24, '.');
+ *++s = '*';
+ *++s = 0;
+
+ *ceip = get_clone(cptr->hostip, create);
+ *ce24 = get_clone(ip24, create);
+}
+
+static int
+report_lclone(aClient *cptr, CloneEnt *ce, int l, int is24, char *t, char *n)
+{
+ if (n)
+ sendto_realops_lev(REJ_LEV, "clone %s!%s@%s (%s %d/%d local %s %s)",
+ cptr->name, cptr->user->username, cptr->user->host,
+ ce->ent, ce->lcount, l, t, n);
+ else
+ sendto_realops_lev(REJ_LEV, "clone %s!%s@%s (%s %d/%d local %s)",
+ cptr->name, cptr->user->username, cptr->user->host,
+ ce->ent, ce->lcount, l, t);
+
+ if (is24)
+ clones_stat.rls++;
+ else
+ clones_stat.rlh++;
+
+ throttle_force(cptr->hostip);
+
+ return (is24 ? 2 : 1);
+}
+
+static int
+report_gclone(aClient *cptr, CloneEnt *ce, int l, int is24, char *t)
+{
+ sendto_realops_lev(REJ_LEV, "clone %s!%s@%s (%s %d/%d global %s)",
+ cptr->name, cptr->user->username, cptr->user->host,
+ ce->ent, ce->gcount, l, t);
+
+ if (is24)
+ clones_stat.rgs++;
+ else
+ clones_stat.rgh++;
+
+ throttle_force(cptr->hostip);
+
+ return (is24 ? 2 : 1);
+}
+
+/*
+ * Checks a local client against the clone limits.
+ * Returns 1 if IP/32 limit hit, 2 if IP/24 limit hit, 0 otherwise.
+ */
+int
+clones_check(aClient *cptr)
+{
+ CloneEnt *ceip;
+ CloneEnt *ce24;
+ int limit;
+ int lpri = 0;
+ int gpri = 0;
+
+ get_clones(cptr, &ceip, &ce24, 0);
+
+ if (ceip)
+ {
+ /* local limit priority stack: soft set, class, default */
+ if ((limit = ceip->sllimit))
+ {
+ lpri = 3;
+ if (ceip->lcount >= limit)
+ return report_lclone(cptr, ceip, limit, 0, "soft", NULL);
+ }
+ else if ((limit = cptr->user->allow->class->connfreq))
+ {
+ lpri = 2;
+ if (ceip->lcount >= limit)
+ return report_lclone(cptr, ceip, limit, 0, "class",
+ cptr->user->allow->class->name);
+ }
+ else
+ {
+ lpri = 1;
+ limit = local_ip_limit;
+ if (ceip->lcount >= limit)
+ return report_lclone(cptr, ceip, limit, 0, "default", NULL);
+ }
+
+ /* global limit priority stack: soft set, services, default */
+ if ((limit = ceip->sglimit))
+ {
+ gpri = 3;
+ if (ceip->gcount >= limit)
+ return report_gclone(cptr, ceip, limit, 0, "soft");
+ }
+ else if ((limit = ceip->limit))
+ {
+ gpri = 2;
+ if (ceip->gcount >= limit)
+ return report_gclone(cptr, ceip, limit, 0, "hard");
+ }
+ else
+ {
+ gpri = 1;
+ limit = global_ip_limit;
+ if (ceip->gcount >= limit)
+ return report_gclone(cptr, ceip, limit, 0, "default");
+ }
+ }
+
+ if (ce24)
+ {
+ /* For local limits, a specific host limit provides an implicit
+ * exemption from site limits of a lower priority. */
+ if ((limit = ce24->sllimit))
+ {
+ if (ce24->lcount >= limit)
+ return report_lclone(cptr, ce24, limit, 1, "soft", NULL);
+ }
+ else if (lpri <= 2 && (limit = cptr->user->allow->class->ip24clones))
+ {
+ if (ce24->lcount >= limit)
+ return report_lclone(cptr, ce24, limit, 1, "class",
+ cptr->user->allow->class->name);
+ }
+ else if (lpri <= 1)
+ {
+ limit = local_ip24_limit;
+ if (ce24->lcount >= limit)
+ return report_lclone(cptr, ce24, limit, 1, "default", NULL);
+ }
+
+ /* For global limits, the implicit exemption is for the default only;
+ * the soft limit can only be lower, not higher, so the service-set
+ * hard limit wins if it's not present. */
+ if ((limit = ce24->sglimit))
+ {
+ if (ce24->gcount >= limit)
+ return report_gclone(cptr, ce24, limit, 1, "soft");
+ }
+ else if ((limit = ce24->limit))
+ {
+ if (ce24->gcount >= limit)
+ return report_gclone(cptr, ce24, limit, 1, "hard");
+ }
+ else if (gpri <= 1)
+ {
+ limit = global_ip24_limit;
+ if (ce24->gcount >= limit)
+ return report_gclone(cptr, ce24, limit, 1, "default");
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Adds a client to the clone list.
+ */
+void
+clones_add(aClient *cptr)
+{
+ CloneEnt *ceip;
+ CloneEnt *ce24;
+
+ get_clones(cptr, &ceip, &ce24, 1);
+
+ cptr->clone.prev = NULL;
+ cptr->clone.next = ceip->clients;
+ if (ceip->clients)
+ ceip->clients->clone.prev = cptr;
+ ceip->clients = cptr;
+
+ ceip->gcount++;
+ ce24->gcount++;
+
+ if (MyConnect(cptr))
+ {
+ ceip->lcount++;
+ ce24->lcount++;
+ }
+}
+
+/*
+ * Removes a client from the clone list.
+ */
+void
+clones_remove(aClient *cptr)
+{
+ CloneEnt *ceip;
+ CloneEnt *ce24;
+
+ get_clones(cptr, &ceip, &ce24, 0);
+
+ if (cptr->clone.next)
+ cptr->clone.next->clone.prev = cptr->clone.prev;
+ if (cptr->clone.prev)
+ cptr->clone.prev->clone.next = cptr->clone.next;
+ else
+ ceip->clients = cptr->clone.next;
+
+ ceip->gcount--;
+ ce24->gcount--;
+
+ /* !$%#&*%@ user state handling! */
+ if (cptr->uplink == &me)
+ {
+ ceip->lcount--;
+ ce24->lcount--;
+ }
+
+ expire_clone(ceip);
+ expire_clone(ce24);
+}
+#endif /* THROTTLE_ENABLE */
+
+/*
+ * Sets a global clone limit. A limit of 0 reverts to default settings.
+ * Returns -1 on invalid parameters, old value otherwise.
+ */
+int
+clones_set(char *ent, int type, int limit)
+{
+ CloneEnt *ce;
+ int rval = 0;
+
+ if (strlen(ent) > HOSTIPLEN)
+ return -1;
+
+ if (limit < 0)
+ return -1;
+
+ ce = get_clone(ent, 1);
+
+ switch (type)
+ {
+ case CLIM_HARD_GLOBAL:
+ rval = ce->limit;
+ ce->limit = limit;
+ if (limit && ce->sglimit > limit)
+ ce->sglimit = 0;
+ break;
+
+ case CLIM_SOFT_GLOBAL:
+ rval = ce->sglimit;
+ ce->sglimit = limit;
+ break;
+
+ case CLIM_SOFT_LOCAL:
+ rval = ce->sllimit;
+ ce->sllimit = limit;
+ break;
+ }
+
+ expire_clone(ce);
+
+ return rval;
+}
+
+/*
+ * Gets the current clone limits. 0 means using default.
+ */
+void clones_get(char *ent, int *hglimit, int *sglimit, int *sllimit)
+{
+ CloneEnt *ce;
+
+ ce = get_clone(ent, 0);
+
+ if (ce)
+ {
+ *hglimit = ce->limit;
+ *sglimit = ce->sglimit;
+ *sllimit = ce->sllimit;
+ }
+ else
+ {
+ *hglimit = 0;
+ *sglimit = 0;
+ *sllimit = 0;
+ }
+}
+
+/*
+ * Propagate global clone limits.
+ */
+void
+clones_send(aClient *cptr)
+{
+ CloneEnt *ce;
+
+ for (ce = clones_list; ce; ce = ce->next)
+ {
+ if (!ce->limit)
+ continue;
+ sendto_one(cptr, ":%s SVSCLONE %s %d", me.name, ce->ent, ce->limit);
+ }
+}
+
+/*
+ * Must be called AFTER throttle_init()
+ */
+void
+clones_init(void)
+{
+#ifndef THROTTLE_ENABLE
+ hashent_freelist = BlockHeapCreate(sizeof(hashent), 1024);
+#endif
+ free_cloneents = BlockHeapCreate(sizeof(CloneEnt), 1024);
+ clones_hashtable = create_hash_table(THROTTLE_HASHSIZE,
+ offsetof(CloneEnt, ent), HOSTIPLEN,
+ 2, (void *)strcmp);
+}
+
--- /dev/null
+/************************************************************************
+ * Bahamut IRCd, src/confparse.c
+ * Copyright (C) 2004, Aaron Wiebe
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: confparse.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include "userban.h"
+#define CONF_TABS
+#include "confparse.h"
+
+#ifndef LINE_MAX
+#define LINE_MAX 256
+#endif
+
+/* notes on confparse.c
+ * While this initial revision requires a fair bit of trimming down,
+ * my primary goal right now was to build an extendable system that will
+ * allow for fairly easy changes to the config file.
+ * Heres a few notes on how to go about that.
+ *
+ * The parser works on two primary depths - blocks and tokens:
+ *
+ * block {
+ * token value;
+ * token "string value";
+ * token 123; # int value
+ * token; # nonvar token
+ * };
+ *
+ * It can also parse non-token blocks:
+ *
+ * block (
+ * "string string string";
+ * "string blah";
+ * };
+ *
+ * Blocks are defined by tconftab (in confparse.h)
+ * Tokens are defined by sconftab (^^^^^^^^^^^^^^)
+ *
+ * Each block must have a function that takes the values collected
+ * and checks them against the requirements. These functions are also
+ * handy for getting variables out of the array that they are stored in.
+ *
+ * The array variables are placed in (an array of cVar structs) contains
+ * all values for the the block, and the corrisponding sconftab item.
+ *
+ * I feel the need to rewrite large sections of this still, but I'll just
+ * be happy to have it working for now.
+ *
+ * Feb 24/04
+ * -epi
+ */
+
+extern int forked;
+extern char *set_classes(void);
+extern aPort *new_ports;
+extern Conf_Me *new_MeLine;
+
+/* free_vars()
+ * clear our temp variable array used by parse_block and children
+ */
+
+static void
+free_vars(cVar *vars[])
+{
+ int i = 0;
+
+ while(vars[i])
+ {
+ MyFree(vars[i]->value);
+ MyFree(vars[i]);
+ i++;
+ }
+}
+
+/* error handler */
+
+static char *current_file = "unknown";
+
+void
+confparse_error(char *problem, int line)
+{
+ if(!forked)
+ printf("ERROR: %s near line %d of %s\n", problem, line, current_file);
+ else
+ sendto_realops("Conf Error: %s near line %d of %s", problem, line,
+ current_file);
+ return;
+}
+
+/* check_quote
+ * this routine skips over any ignored items inside our file
+ */
+
+static int quote = 0;
+
+static char *
+check_quote(char *cur)
+{
+ if(quote)
+ {
+ while((cur = strchr(cur, '*')))
+ if((*(++cur) == '/'))
+ {
+ cur++;
+ quote = 0;
+ break;
+ }
+ if(!cur)
+ return cur;
+ }
+ while((*cur == ' ') || (*cur == '\t'))
+ cur++;
+ /* now we've hit something .. check for single line quotes */
+ if (!*cur || *cur == '#' || *cur == '\n' ||
+ (*cur == '/' && *(cur+1) == '/'))
+ return NULL;
+ /* check for multiple line quotes */
+ if((*cur == '/') && (*(cur+1) == '*'))
+ {
+ cur += 2;
+ quote = 1;
+ while((cur = strchr(cur, '*')))
+ if((*(++cur) == '/'))
+ {
+ cur++;
+ quote = 0;
+ break;
+ }
+ if(!cur)
+ return cur;
+ else
+ return check_quote(cur);
+ }
+ return cur;
+}
+
+#define MAX_VALUES 128 /* maximum values per block */
+
+static char *
+parse_block(tConf *block, char *cur, FILE *file, int *lnum)
+{
+ char *tok, *var, *var2;
+ char line[LINE_MAX];
+ tConf *b2 = NULL;
+ sConf *item = NULL;
+ sConf *sconftab = block->subtok;
+ cVar *vars[MAX_VALUES] = { 0 };
+ int vnum = 0, tlnum = 0, clear = 0, done = 0, skip = 0;
+
+ if((sconftab) && (sconftab->flag == SCONFF_STRING))
+ {
+ /* this subtype only takes freeform variables
+ * dont bother looking for tokens
+ */
+ int i = 0;
+ while(!BadPtr(cur) || ((fgets(line, LINE_MAX, file) != NULL) &&
+ (*lnum)++ && (cur = line)))
+ {
+ cur = check_quote(cur);
+ if(BadPtr(cur))
+ continue;
+ if(clear)
+ {
+ if(*cur != ';')
+ {
+ confparse_error("Missing semicolon", *lnum);
+ free_vars(vars);
+ return NULL;
+ }
+ else
+ cur++;
+ clear = 0;
+ cur = check_quote(cur);
+ if(BadPtr(cur))
+ continue;
+ }
+ if(done)
+ {
+ if(*cur != ';')
+ {
+ confparse_error("Missing block end semicolon", *lnum);
+ free_vars(vars);
+ return NULL;
+ }
+ else
+ cur++;
+ if(((*block->func) (vars, *lnum)) == -1)
+ {
+ free_vars(vars);
+ return NULL;
+ }
+ if(BadPtr(cur))
+ *cur = '#'; /* we cant return a bad pointer because
+ * that will pull us out of the conf read
+ * so this will just get ignored
+ * kludgy, but effective */
+ free_vars(vars);
+ return cur;
+ }
+ cur = check_quote(cur);
+ if(BadPtr(cur))
+ continue;
+ if(*cur == '}')
+ {
+ done = 1;
+ cur++;
+ cur = check_quote(cur);
+ if(BadPtr(cur))
+ continue;
+ if(*cur != ';')
+ {
+ confparse_error("Missing block end semicolon", *lnum);
+ free_vars(vars);
+ return NULL;
+ }
+ else
+ cur++;
+ if(((*block->func) (vars, *lnum)) == -1)
+ {
+ free_vars(vars);
+ return NULL;
+ }
+ if(BadPtr(cur))
+ *cur = '#'; /* we cant return a bad pointer because
+ * that will pull us out of the conf read
+ * so this will just get ignored
+ * kludgy, but effective */
+ free_vars(vars);
+ return cur;
+ }
+ vars[vnum] = (cVar *) MyMalloc(sizeof(cVar));
+ memset((char *) vars[vnum], '\0', sizeof(cVar));
+ vars[vnum]->loaded = 1;
+ vars[vnum]->type = NULL;
+ tok = cur;
+ if(*cur == '"')
+ {
+ i = 1;
+ cur++;
+ }
+ var = cur;
+ if(i == 1)
+ {
+ while(!BadPtr(cur) && (*cur != '"'))
+ cur++;
+ if(BadPtr(cur))
+ {
+ confparse_error("Cant find closequote", *lnum);
+ free_vars(vars);
+ return NULL;
+ }
+ *cur = '\0';
+ cur++;
+ while(!BadPtr(cur) && (*cur != ';'))
+ cur++;
+ }
+ else
+ {
+ while(!BadPtr(cur) && (*cur != ';'))
+ {
+ if((*cur == ' '))
+ {
+ *cur = '\0';
+ if(vars[vnum]->loaded == 1)
+ {
+ DupString(vars[vnum]->value, var);
+ vars[vnum]->loaded = 2;
+ }
+ }
+ else if(vars[vnum]->loaded == 2)
+ {
+ confparse_error("Junk after value", *lnum);
+ free_vars(vars);
+ return NULL;
+ }
+ cur++;
+ }
+ }
+ tlnum = *lnum;
+ if(BadPtr(cur))
+ {
+ clear = 1;
+ continue;
+ }
+ *cur = '\0';
+ cur++;
+ if(vars[vnum]->loaded == 1)
+ DupString(vars[vnum]->value, var);
+ vars[vnum]->loaded = 3;
+ vnum++;
+ }
+ confparse_error("Unexpected EOF: Syntax Error", tlnum);
+ free_vars(vars);
+ return NULL;
+ }
+
+ while(!BadPtr(cur) || ((fgets(line, LINE_MAX, file) != NULL) && (*lnum)++
+ && (cur = line)))
+ {
+ cur = check_quote(cur);
+ if(BadPtr(cur))
+ continue;
+ if(clear)
+ {
+ /* if we're looking for a closing semicolon, check for it first
+ * if we cant find it, ignore it and hope for the best
+ */
+ if(*cur != ';')
+ {
+ confparse_error("Missing semicolon ", *lnum);
+ free_vars(vars);
+ return NULL;
+ }
+ else
+ cur++;
+ clear = 0;
+ if(vars[vnum])
+ {
+ vars[vnum]->loaded = 3;
+ vnum++;
+ }
+ item = NULL;
+ cur = check_quote(cur);
+ if(BadPtr(cur))
+ continue;
+ }
+ if(done)
+ {
+ /* we've found the end of our block, now we're looking for the
+ * closing semicolon. if we cant find it, ignore it and
+ * hope for the best
+ */
+ if(*cur != ';')
+ {
+ confparse_error("Missing block end semicolon", *lnum);
+ free_vars(vars);
+ return NULL;
+ }
+ else
+ cur++;
+ if(((*block->func) (vars, *lnum)) == -1)
+ {
+ free_vars(vars);
+ return NULL;
+ }
+ if(BadPtr(cur))
+ *cur = '#'; /* we cant return a bad pointer because
+ * that will pull us out of the conf read
+ * so this will just get ignored
+ * kludgy, but effective */
+ free_vars(vars);
+ return cur;
+ }
+ if(b2 && b2->tok)
+ {
+ /* we've identified a nested block in a previous loop.
+ * we didnt get an openquote yet, so look for that.
+ * we must find this. keep looking til we do.
+ */
+ if(*cur != '{')
+ {
+ confparse_error("Junk after nested block token", *lnum);
+ free_vars(vars);
+ return NULL;
+ }
+ cur++;
+ cur = check_quote(cur);
+ cur = parse_block(b2, cur, file, lnum);
+ b2 = NULL;
+ continue;
+ }
+ if(!item || !item->tok)
+ {
+ /* if we dont already have a specific token we're working on
+ * find one here.
+ */
+ cur = check_quote(cur);
+ if(BadPtr(cur))
+ continue;
+ tok = cur;
+ tlnum = *lnum;
+ if(*cur == '}')
+ {
+ /* if we've got a closebracket, then we've hit the end
+ * of our block.
+ */
+ done = 1;
+ cur++;
+ cur = check_quote(cur);
+ if(BadPtr(cur))
+ continue;
+ if(*cur != ';')
+ {
+ confparse_error("Missing block end semicolon", *lnum);
+ free_vars(vars);
+ return NULL;
+ }
+ else
+ cur++;
+ if(((*block->func) (vars, *lnum)) == -1)
+ {
+ free_vars(vars);
+ return NULL;
+ }
+ if(BadPtr(cur))
+ *cur = '#'; /* we cant return a bad pointer because
+ * that will pull us out of the conf read
+ * so this will just get ignored
+ * kludgy, but effective */
+ free_vars(vars);
+ return cur;
+
+ }
+ /* our token ends where whitespace or a semicolon begins */
+ while(!BadPtr(cur) && ((*cur != ' ') && (*cur != ';') &&
+ (*cur != '\t') && (*cur != '\n')))
+ cur++;
+ if(BadPtr(cur))
+ {
+ confparse_error("Unterminated token", *lnum);
+ free_vars(vars);
+ return NULL;
+ }
+ else
+ {
+ if(*cur == ';')
+ skip = 1;
+ *cur = '\0';
+ }
+ cur++;
+ if(block->nest)
+ {
+ /* we allow nested stuff inside here, so check for it. */
+ for(b2 = tconftab; b2->tok; b2++)
+ if(!mycmp(b2->tok, tok))
+ break;
+ if(b2 && b2->tok)
+ if(!(block->nest & b2->flag))
+ b2 = NULL;
+ if(b2 && b2->tok)
+ {
+ /* recurse through the block we found */
+ tlnum = *lnum;
+ if((cur = strchr(cur, '{')))
+ {
+ cur++;
+ cur = check_quote(cur);
+ cur = parse_block(b2, cur, file, lnum);
+ b2 = NULL;
+ continue;
+ }
+ if(BadPtr(cur))
+ continue;
+ }
+ }
+ /* find our token */
+ for(item = sconftab; item && item->tok; item++)
+ if(!mycmp(item->tok, tok))
+ break;
+ if(!item->tok)
+ {
+ confparse_error("Unknown token", *lnum);
+ free_vars(vars);
+ return NULL;
+ }
+ /* create our variable */
+ vars[vnum] = (cVar *) MyMalloc(sizeof(cVar));
+ memset((char *) vars[vnum], '\0', sizeof(cVar));
+ vars[vnum]->type = item;
+ vars[vnum]->loaded = 1;
+ }
+ if(item->var & VARTYPE_NONE)
+ {
+ /* we dont need to grab a variable for this type
+ * just look for the closing semicolon, and move on */
+ vars[vnum]->loaded = 2;
+ if(!skip)
+ {
+ /* we've already gotten our semicolon back
+ * at the end of our token. dont look for it. */
+ cur = check_quote(cur);
+ while(!BadPtr(cur) && (*cur != ';'))
+ cur++;
+ if(BadPtr(cur))
+ {
+ clear = 1;
+ continue;
+ }
+ cur++;
+ }
+ skip = 0;
+ vars[vnum]->loaded = 3;
+ vnum++;
+ item = NULL;
+ continue;
+ }
+ if(item->var & VARTYPE_STRING)
+ {
+ /* we're looking for a string here, so we require
+ * quotes around the string...
+ */
+ cur = check_quote(cur);
+ while(!BadPtr(cur) && (*cur != '"'))
+ cur++;
+ if(BadPtr(cur))
+ continue;
+ cur++;
+ var = cur;
+ while(!BadPtr(cur) && (*cur != '"'))
+ cur++;
+ if(BadPtr(cur))
+ {
+ confparse_error("Unterminated quote", *lnum);
+ free_vars(vars);
+ return NULL;
+ }
+ *cur = '\0';
+ cur++;
+ DupString(vars[vnum]->value, var);
+ vars[vnum]->loaded = 2;
+ while(!BadPtr(cur) && (*cur != ';'))
+ cur++;
+ if(BadPtr(cur))
+ {
+ clear = 1;
+ continue;
+ }
+ cur++;
+ vars[vnum]->loaded = 3;
+ vnum++;
+ item = NULL;
+ continue;
+ }
+ if(item->var & VARTYPE_INT)
+ {
+ cur = check_quote(cur);
+ var = cur;
+ while(!BadPtr(cur) && ((*cur != ';') && (*cur != '\t') &&
+ (*cur != '\n') && (*cur != ' ')))
+ cur++;
+ if(BadPtr(cur))
+ {
+ clear = 1;
+ continue;
+ }
+ if(*cur != ';')
+ clear = 1;
+ *cur = '\0';
+ cur++;
+ var2 = var;
+ while(*var)
+ {
+ if(IsDigit(*var))
+ var++;
+ else
+ {
+ confparse_error("Expecting integer value", *lnum);
+ free_vars(vars);
+ return NULL;
+ }
+ }
+ if(!item)
+ continue;
+ var = var2;
+ DupString(vars[vnum]->value, var);
+ vars[vnum]->loaded = 3;
+ vnum++;
+ item = NULL;
+ continue;
+ }
+ if(item->var & VARTYPE_NAME)
+ {
+ cur = check_quote(cur);
+ if(!BadPtr(cur) && (*cur == '"'))
+ cur++;
+ var = cur;
+ while(!BadPtr(cur) && (*cur != ';'))
+ {
+ if((*cur == ' ') || (*cur == '"') || (*cur == '\t'))
+ {
+ *cur = '\0';
+ if(vars[vnum]->loaded == 1)
+ {
+ DupString(vars[vnum]->value, var);
+ vars[vnum]->loaded = 2;
+ }
+ }
+ cur++;
+ }
+ if(BadPtr(cur))
+ {
+ clear = 1;
+ continue;
+ }
+ *cur = '\0';
+ cur++;
+ if(vars[vnum]->loaded == 1)
+ DupString(vars[vnum]->value, var);
+ vars[vnum]->loaded = 3;
+ vnum++;
+ item = NULL;
+ continue;
+ }
+ confparse_error("Unexpected EOF: Syntax Error", tlnum);
+ free_vars(vars);
+ return NULL;
+ }
+ confparse_error("Unexpected EOF: Syntax Error", tlnum);
+ free_vars(vars);
+ return NULL;
+}
+
+int
+initconf(char *filename)
+{
+ int lnum = 0, blnum = 0, clear = 0;
+ char line[LINE_MAX];
+ char *cur = NULL;
+ char *tok;
+ tConf *block = NULL;
+ FILE *file;
+
+ current_file = filename;
+
+ if(!(file = fopen(filename, "r")))
+ {
+ if(forked)
+ sendto_realops("Unable to open config file %s%s", file, "\n");
+ else
+ printf("Unable to open config file %s\n", filename);
+ return -1;
+ }
+
+ while(!BadPtr(cur) || ((fgets(line, LINE_MAX, file) != NULL) && ++lnum
+ && (cur = line)))
+ {
+ cur = check_quote(cur);
+ if(BadPtr(cur))
+ continue;
+ /* now, we should be ok to get that token.. */
+ if(!block)
+ {
+ tok = cur;
+ while((*cur != ' ') && (*cur != '\n') && (*cur != '{'))
+ cur++; /* find the whitespace following the token */
+ if(*cur == '{')
+ clear = 1;
+ *cur = '\0';
+ cur++;
+ if(!mycmp("INCLUDE", tok))
+ {
+ /* this is an include - find pull out the file name
+ * and parse this file now
+ */
+ char *var;
+ cur = check_quote(cur);
+ if((*cur == '"') || *cur == '<')
+ cur++;
+ var = cur;
+ while((*cur != ' ') && (*cur != '"') && (*cur != '>') &&
+ (*cur != '\n') && (*cur != '\t'))
+ cur++;
+ if(BadPtr(cur))
+ {
+ confparse_error("Bad include line", lnum);
+ return -1;
+ }
+ *cur = '\0';
+ cur++;
+ if(initconf(var) == -1)
+ return -1;
+ current_file = filename; /* reset */
+ continue;
+ }
+ for(block = tconftab; block->tok; block++)
+ if(!mycmp(block->tok, tok))
+ break;
+ if(!block->tok)
+ {
+ confparse_error("Unknown block type", lnum);
+ return -1;
+ }
+ blnum = lnum;
+ }
+ cur = check_quote(cur);
+ if(BadPtr(cur))
+ continue;
+ if((*cur == '{') || clear)
+ cur++;
+ else
+ {
+ confparse_error("Junk after block name", lnum);
+ return -1;
+ }
+ if((cur = parse_block(block, cur, file, &lnum)) == NULL)
+ {
+ return -1;
+ }
+ clear = 0;
+ block = NULL;
+ continue;
+ }
+ if(clear)
+ {
+ confparse_error("Unexpected EOF: Syntax error", blnum);
+ return -1;
+ }
+ return 1;
+}
+
+inline char *
+finishconf(void)
+{
+ static char buf[256];
+ char *ret;
+
+ if (!new_MeLine || !new_MeLine->servername)
+ return "Missing global block";
+ if ((ret = set_classes()))
+ {
+ ircsnprintf(buf, sizeof(buf), "Missing class block for referenced "
+ "class '%s'", ret);
+ return buf;
+ }
+ if (!new_ports)
+ return "No ports defined";
+ return NULL;
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/dh.c
+ * Copyright (C) 2000 Lucas Madar
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: dh.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+/*
+ * Diffie-Hellman key exchange for bahamut ircd.
+ * Lucas Madar <lucas@dal.net> -- 2000
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#include <openssl/bn.h>
+#include <openssl/dh.h>
+
+#define DH_HEADER
+#include "dh.h"
+
+
+#ifdef __OpenBSD__
+#define RAND_SRC "/dev/arandom"
+#else
+#define RAND_SRC "/dev/random"
+#endif
+
+
+static int verify_is_hex(char *string)
+{
+ int l = strlen(string);
+ char tmp[4] = {'\0', '\0', '\0', '\0'};
+ int tmpidx = 0;
+
+ if(l & 0x01) /* check if it's odd length */
+ {
+ l++;
+ tmp[tmpidx++] = '0'; /* pad with zero */
+ }
+
+ while(*string)
+ {
+ tmp[tmpidx++] = *string++;
+ if(tmpidx == 2)
+ {
+ char *eptr;
+ unsigned char x;
+
+ tmpidx = 0;
+
+ x = strtol(tmp, &eptr, 16);
+ if(*eptr != '\0')
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int dh_hexstr_to_raw(char *string, unsigned char *hexout, int *hexlen)
+{
+ int l = strlen(string);
+ char tmp[3] = {'\0', '\0', '\0'};
+ int tmpidx = 0;
+ int hexidx = 0;
+
+ if(l & 0x01) /* check if it's odd length */
+ {
+ l++;
+ tmp[tmpidx++] = '0'; /* pad with zero */
+ }
+
+ while(*string)
+ {
+ tmp[tmpidx++] = *string++;
+ if(tmpidx == 2)
+ {
+ char *eptr;
+ unsigned char x;
+
+ tmpidx = 0;
+
+ x = strtol(tmp, &eptr, 16);
+ if(*eptr != '\0')
+ return 0;
+ hexout[hexidx++] = (unsigned char) x;
+ }
+ }
+ *hexlen = hexidx;
+ return 1;
+}
+
+static inline void entropy_error(void)
+{
+ printf("\nCould not generate entropy from %s:\n%s\n\n",
+ RAND_SRC, strerror(errno));
+ printf("ircd needs a %d byte random seed.\n", RAND_BYTES);
+ printf("You can place a file containing random data called"
+ " .ircd.entropy\nin the directory with your ircd.conf."
+ " This file must be at least %d bytes\n", RAND_BYTES);
+ printf("long and should be suitably random.\n");
+}
+
+static int make_entropy()
+{
+ char randbuf[RAND_BYTES * 4];
+ FILE *fp;
+ int i;
+
+ printf("\nNo random state found, generating entropy from %s...\n",
+ RAND_SRC);
+ printf("On some systems this may take a while, and can be helped by"
+ " keeping the\nsystem busy, such as pounding on the keyboard.\n");
+
+ fp = fopen(RAND_SRC, "r");
+ if(!fp)
+ {
+ entropy_error();
+ return 0;
+ }
+
+ for(i = 0; i < (RAND_BYTES * 4); i++)
+ {
+ int cv;
+
+ cv = fgetc(fp);
+
+ if(cv == EOF)
+ {
+ if(ferror(fp))
+ {
+ entropy_error();
+ fclose(fp);
+ return 0;
+ }
+ clearerr(fp);
+ usleep(100);
+ i--;
+ continue;
+ }
+
+ randbuf[i] = cv;
+ if(i && (i % 64 == 0))
+ {
+ printf(" %d%% .. ", (int)(((float) i / (float) (RAND_BYTES * 4))
+ * 100.0));
+ fflush(stdout);
+ }
+ }
+ printf("Done.\n");
+ fclose(fp);
+
+ fp = fopen(".ircd.entropy", "w");
+ if(!fp)
+ {
+ printf("Could not open .ircd.entropy for writing: %s\n",
+ strerror(errno));
+ return 0;
+ }
+
+ fwrite(randbuf, RAND_BYTES * 4, 1, fp);
+ fclose(fp);
+
+ RAND_load_file(".ircd.entropy", -1);
+
+ return 1;
+}
+
+static int init_random()
+{
+ int ret;
+ time_t now;
+
+ ret = RAND_load_file(".ircd.entropy", -1);
+ if(ret <= 0)
+ {
+ if(!make_entropy())
+ return -1;
+ }
+ else
+ printf("%d bytes of entropy loaded.\n", ret);
+
+ now = time(NULL);
+
+ /* this is probably not too good, but it saves just writing
+ the whole state back to disk with no changes. */
+ RAND_seed(&now, 4);
+ RAND_write_file(".ircd.entropy");
+
+ return 0;
+}
+
+static void create_prime()
+{
+ char buf[PRIME_BYTES_HEX];
+ int i;
+ int bufpos = 0;
+
+ for(i = 0; i < PRIME_BYTES; i++)
+ {
+ char *x = hex_to_string[dh_prime_1024[i]];
+ while(*x)
+ buf[bufpos++] = *x++;
+ }
+ buf[bufpos] = '\0';
+
+ ircd_prime = NULL;
+ BN_hex2bn(&ircd_prime, buf);
+ ircd_generator = BN_new();
+ BN_set_word(ircd_generator, dh_gen_1024);
+}
+
+int dh_init()
+{
+ ERR_load_crypto_strings();
+
+ create_prime();
+ if(init_random() == -1)
+ return -1;
+ return 0;
+}
+
+int dh_generate_shared(void *session, char *public_key)
+{
+ BIGNUM *tmp;
+ int len;
+ struct session_info *si = (struct session_info *) session;
+
+ if(verify_is_hex(public_key) == 0 || !si || si->session_shared)
+ return 0;
+
+ tmp = NULL;
+ BN_hex2bn(&tmp, public_key);
+ if(!tmp)
+ return 0;
+
+ si->session_shared_length = DH_size(si->dh);
+ si->session_shared = (char *) malloc(DH_size(si->dh));
+ len = DH_compute_key(si->session_shared, tmp, si->dh);
+ BN_free(tmp);
+
+ if(len < 0)
+ return 0;
+
+ si->session_shared_length = len;
+
+ return 1;
+}
+
+void *dh_start_session()
+{
+ struct session_info *si;
+
+ si = (struct session_info *) malloc(sizeof(struct session_info));
+ if(!si)
+ abort();
+
+ memset(si, 0, sizeof(struct session_info));
+
+ si->dh = DH_new();
+ si->dh->p = BN_dup(ircd_prime);
+ si->dh->g = BN_dup(ircd_generator);
+
+ if(!DH_generate_key(si->dh))
+ {
+ DH_free(si->dh);
+ free(si);
+ return NULL;
+ }
+
+ return (void *) si;
+}
+
+void dh_end_session(void *session)
+{
+ struct session_info *si = (struct session_info *) session;
+
+ if(si->dh)
+ {
+ DH_free(si->dh);
+ si->dh = NULL;
+ }
+
+ if(si->session_shared)
+ {
+ memset(si->session_shared, 0, si->session_shared_length);
+ free(si->session_shared);
+ si->session_shared = NULL;
+ }
+
+ free(si);
+}
+
+char *dh_get_s_public(char *buf, int maxlen, void *session)
+{
+ struct session_info *si = (struct session_info *) session;
+ char *tmp;
+
+ if(!si || !si->dh || !si->dh->pub_key)
+ return NULL;
+
+ tmp = BN_bn2hex(si->dh->pub_key);
+ if(!tmp)
+ return NULL;
+
+ if(strlen(tmp) + 1 > maxlen)
+ {
+ OPENSSL_free(tmp);
+ return NULL;
+ }
+ strcpy(buf, tmp);
+ OPENSSL_free(tmp);
+
+ return buf;
+}
+
+int dh_get_s_shared(char *buf, int *maxlen, void *session)
+{
+ struct session_info *si = (struct session_info *) session;
+
+ if(!si || !si->session_shared || *maxlen < si->session_shared_length)
+ return 0;
+
+ *maxlen = si->session_shared_length;
+ memcpy(buf, si->session_shared, *maxlen);
+
+ return 1;
+}
--- /dev/null
+/*
+ * fdlist.c maintain lists of certain important fds
+ */
+
+/* $Id: fdlist.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include "config.h"
+#include "fdlist.h"
+
+#ifdef USE_KQUEUE
+#include <sys/event.h>
+#endif
+
+void addto_fdlist(int fd, fdlist * listp)
+{
+ int index;
+
+ if ((index = ++listp->last_entry) >= MAXCONNECTIONS) {
+ /* list too big.. must exit */
+ --listp->last_entry;
+
+#ifdef USE_SYSLOG
+ (void) syslog(LOG_CRIT, "fdlist.c list too big.. must exit");
+#endif
+ abort();
+ }
+ else
+ listp->entry[index] = fd;
+ return;
+}
+
+void delfrom_fdlist(int fd, fdlist * listp)
+{
+ int i;
+
+ for (i = listp->last_entry; i; i--)
+ {
+ if (listp->entry[i] == fd)
+ break;
+ }
+ if (!i)
+ return; /* could not find it! */
+ /* swap with last_entry */
+ if (i == listp->last_entry)
+ {
+ listp->entry[i] = 0;
+ listp->last_entry--;
+ return;
+ }
+ else
+ {
+ listp->entry[i] = listp->entry[listp->last_entry];
+ listp->entry[listp->last_entry] = 0;
+ listp->last_entry--;
+ return;
+ }
+}
+
+void init_fdlist(fdlist * listp)
+{
+ listp->last_entry = 0;
+ memset((char *) listp->entry, '\0', sizeof(listp->entry));
+#ifdef USE_KQUEUE
+ listp->kqueue_fd = kqueue();
+#endif
+ return;
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/fds.c
+ * Copyright (C) 2003 Lucas Madar
+ *
+ * fds.c -- file descriptor list management routines
+ *
+ */
+
+/* $Id: fds.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include "fds.h"
+#include "numeric.h"
+
+void engine_add_fd(int);
+void engine_del_fd(int);
+void engine_change_fd_state(int, unsigned int);
+
+struct afd_entry {
+ int type;
+ void *value;
+ unsigned int flags;
+ void *internal;
+};
+
+struct afd_entry fd_list[MAXCONNECTIONS];
+
+#ifdef DEBUGMODE
+static char *type_string(int type)
+{
+ switch(type)
+ {
+ case FDT_NONE:
+ return "NONE";
+
+ case FDT_CLIENT:
+ return "client";
+
+ case FDT_AUTH:
+ return "auth";
+
+ case FDT_RESOLVER:
+ return "resolver";
+
+ case FDT_LISTENER:
+ return "listener";
+
+ case FDT_CALLBACKP:
+ return "callback";
+ }
+
+ return "???";
+}
+
+static char *flags_string(unsigned int flags)
+{
+ static char fbuf[512];
+
+ fbuf[0] = '\0';
+
+ if(flags & FDF_WANTREAD)
+ {
+ if(fbuf[0])
+ strcat(fbuf, ", ");
+ strcat(fbuf, "read");
+ }
+
+ if(flags & FDF_WANTWRITE)
+ {
+ if(fbuf[0])
+ strcat(fbuf, ", ");
+ strcat(fbuf, "write");
+ }
+
+ return fbuf;
+}
+
+void report_fds(aClient *cptr)
+{
+ int i;
+ char *name, *blocking;
+
+ for(i = 0; i < MAXCONNECTIONS; i++)
+ {
+ if(fd_list[i].type == FDT_NONE)
+ continue;
+
+ if(fd_list[i].type == FDT_CLIENT ||
+ fd_list[i].type == FDT_AUTH)
+ {
+ aClient *cptr = (aClient *) fd_list[i].value;
+ int hide = (IsConnecting(cptr) || IsHandshake(cptr) || IsServer(cptr)) ? HIDEME : 0;
+
+ name = get_client_name(cptr, hide);
+ blocking = (cptr->flags & FLAGS_BLOCKED) ?
+ "BLOCKED" : "_";
+ }
+ else
+ {
+ name = "-";
+ blocking = "-";
+ }
+
+ sendto_one(cptr, ":%s %d %s :%d - %s [%s] %s %s",
+ me.name, RPL_STATSDEBUG, cptr->name,
+ i, type_string(fd_list[i].type),
+ flags_string(fd_list[i].flags),
+ name, blocking);
+
+ }
+}
+#endif
+
+static inline void fd_range_assert(int fd)
+{
+ if(fd < 0 || fd >= MAXCONNECTIONS)
+ abort();
+}
+
+static inline void fd_notused_assert(int fd)
+{
+ if(fd_list[fd].type != FDT_NONE)
+ abort();
+}
+
+static inline void fd_used_assert(int fd)
+{
+ if(fd_list[fd].type == FDT_NONE)
+ abort();
+}
+
+void add_fd(int fd, int type, void *value)
+{
+ fdfprintf(stderr, "add_fd: %d %d %x\n", fd, type, (int) value);
+
+ fd_range_assert(fd);
+ fd_notused_assert(fd);
+
+ fd_list[fd].type = type;
+ fd_list[fd].value = value;
+ fd_list[fd].flags = 0;
+ engine_add_fd(fd);
+}
+
+void del_fd(int fd)
+{
+ fdfprintf(stderr, "del_fd: %d\n", fd);
+
+ fd_range_assert(fd);
+ fd_used_assert(fd);
+
+ engine_del_fd(fd);
+
+ fd_list[fd].type = FDT_NONE;
+ fd_list[fd].value = NULL;
+ fd_list[fd].internal = NULL;
+}
+
+void set_fd_flags(int fd, unsigned int flags)
+{
+ int oldflags;
+ fd_range_assert(fd);
+ fd_used_assert(fd);
+
+ oldflags = fd_list[fd].flags;
+
+ fd_list[fd].flags |= flags;
+
+ fdfprintf(stderr, "set_fd_flags: %d %x [%x -> %x]\n", fd, flags, oldflags, fd_list[fd].flags);
+
+ if(oldflags != fd_list[fd].flags)
+ engine_change_fd_state(fd, fd_list[fd].flags);
+}
+
+void unset_fd_flags(int fd, unsigned int flags)
+{
+ int oldflags;
+ fd_range_assert(fd);
+ fd_used_assert(fd);
+
+ oldflags = fd_list[fd].flags;
+
+ fd_list[fd].flags &= ~(flags);
+
+ fdfprintf(stderr, "unset_fd_flags: %d %x [%x -> %x]\n", fd, flags, oldflags, fd_list[fd].flags);
+ if(oldflags != fd_list[fd].flags)
+ engine_change_fd_state(fd, fd_list[fd].flags);
+}
+
+void get_fd_info(int fd, int *type, unsigned int *flags, void **value)
+{
+ fd_range_assert(fd);
+
+ *type = fd_list[fd].type;
+ *flags = fd_list[fd].flags;
+ *value = fd_list[fd].value;
+}
+
+unsigned int get_fd_flags(int fd)
+{
+ fd_range_assert(fd);
+ fd_used_assert(fd);
+
+ return fd_list[fd].flags;
+}
+
+void init_fds()
+{
+ memset(fd_list, 0, sizeof(struct afd_entry) * MAXCONNECTIONS);
+}
+
+void set_fd_internal(int fd, void *ptr)
+{
+ fd_list[fd].internal = ptr;
+}
+
+void *get_fd_internal(int fd)
+{
+ return fd_list[fd].internal;
+}
+
+/*
+ * check_client_fd
+ *
+ * called whenever a state change is necessary on a client
+ * ie, when ident and dns are finished
+ */
+
+void check_client_fd(aClient *cptr)
+{
+ if (DoingAuth(cptr))
+ {
+ unsigned int fdflags = get_fd_flags(cptr->authfd);
+
+ if(!(fdflags & FDF_WANTREAD))
+ set_fd_flags(cptr->authfd, FDF_WANTREAD);
+
+ if((cptr->flags & FLAGS_WRAUTH) && !(fdflags & FDF_WANTWRITE))
+ set_fd_flags(cptr->authfd, FDF_WANTWRITE);
+ else if(!(cptr->flags & FLAGS_WRAUTH) && (fdflags & FDF_WANTWRITE))
+ unset_fd_flags(cptr->authfd, FDF_WANTWRITE);
+
+ return;
+ }
+
+ if (DoingDNS(cptr))
+ return;
+
+ set_fd_flags(cptr->fd, FDF_WANTREAD);
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/hash.c
+ * Copyright (C) 1991 Darren Reed
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: hash.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "hash.h"
+#include "h.h"
+
+static aHashEntry clientTable[U_MAX];
+static aHashEntry channelTable[CH_MAX];
+
+/*
+ * look in whowas.c for the missing ...[WW_MAX]; entry - Dianora
+ *
+ * Hashing.
+ *
+ * The server uses a chained hash table to provide quick and efficient
+ * hash table mantainence (providing the hash function works evenly
+ * over the input range). The hash table is thus not susceptible to
+ * problems of filling all the buckets or the need to rehash. It is
+ * expected that the hash table would look somehting like this during
+ * use: +-----+ +-----+ +-----+ +-----+
+ * ---| 224 |----| 225 |----| 226 |---| 227 |---
+ * +-----+ +-----+ +-----+ +-----+
+ * | | |
+ * +-----+ +-----+ +-----+
+ * | A | | C | | D |
+ * +-----+ +-----+ +-----+
+ * |
+ * +-----+
+ * | B |
+ * +-----+
+ *
+ * A - GOPbot, B - chang, C - hanuaway, D - *.mu.OZ.AU
+ *
+ * The order shown above is just one instant of the server. Each time a
+ * lookup is made on an entry in the hash table and it is found, the
+ * entry is moved to the top of the chain.
+ *
+ * ^^^^^^^^^^^^^^^^ **** Not anymore - Dianora
+ *
+ */
+
+unsigned hash_nick_name(char *nname)
+{
+ unsigned hash = 0;
+ int hash2 = 0;
+ int ret;
+ char lower;
+
+ while (*nname)
+ {
+ lower = ToLower(*nname);
+ hash = (hash << 1) + lower;
+ hash2 = (hash2 >> 1) + lower;
+ nname++;
+ }
+ ret = ((hash & U_MAX_INITIAL_MASK) << BITS_PER_COL) +
+ (hash2 & BITS_PER_COL_MASK);
+ return ret;
+}
+
+/*
+ * hash_channel_name
+ *
+ * calculate a hash value on at most the first 30 characters of the
+ * channel name. Most names are short than this or dissimilar in this
+ * range. There is little or no point hashing on a full channel name
+ * which maybe 255 chars long.
+ */
+int hash_channel_name(char *name)
+{
+ unsigned char *hname = (unsigned char *) name;
+ unsigned int hash = 0;
+ int hash2 = 0;
+ char lower;
+ int i = 30;
+
+ while (*hname && --i)
+ {
+ lower = ToLower(*hname);
+ hash = (hash << 1) + lower;
+ hash2 = (hash2 >> 1) + lower;
+ hname++;
+ }
+ return ((hash & CH_MAX_INITIAL_MASK) << BITS_PER_COL) +
+ (hash2 & BITS_PER_COL_MASK);
+}
+
+unsigned int hash_whowas_name(char *name)
+{
+ unsigned char *nname = (unsigned char *) name;
+ unsigned int hash = 0;
+ int hash2 = 0;
+ int ret;
+ char lower;
+
+ while (*nname)
+ {
+ lower = ToLower(*nname);
+ hash = (hash << 1) + lower;
+ hash2 = (hash2 >> 1) + lower;
+ nname++;
+ }
+ ret = ((hash & WW_MAX_INITIAL_MASK) << BITS_PER_COL) +
+ (hash2 & BITS_PER_COL_MASK);
+ return ret;
+}
+
+/*
+ * clear_*_hash_table
+ *
+ * Nullify the hashtable and its contents so it is completely empty.
+ */
+
+void clear_client_hash_table()
+{
+ memset((char *) clientTable, '\0', sizeof(aHashEntry) * U_MAX);
+}
+
+void clear_channel_hash_table()
+{
+ memset((char *) channelTable, '\0', sizeof(aHashEntry) * CH_MAX);
+}
+
+/* add_to_client_hash_table */
+int add_to_client_hash_table(char *name, aClient *cptr)
+{
+ int hashv;
+
+ hashv = hash_nick_name(name);
+ cptr->hnext = (aClient *) clientTable[hashv].list;
+ clientTable[hashv].list = (void *) cptr;
+ clientTable[hashv].links++;
+ clientTable[hashv].hits++;
+ return 0;
+}
+
+/* add_to_channel_hash_table */
+int add_to_channel_hash_table(char *name, aChannel *chptr)
+{
+ int hashv;
+
+ hashv = hash_channel_name(name);
+ chptr->hnextch = (aChannel *) channelTable[hashv].list;
+ channelTable[hashv].list = (void *) chptr;
+ channelTable[hashv].links++;
+ channelTable[hashv].hits++;
+ return 0;
+}
+
+/* del_from_client_hash_table */
+int
+del_from_client_hash_table(char *name, aClient *cptr)
+{
+ aClient *tmp, *prev = NULL;
+ int hashv;
+
+ hashv = hash_nick_name(name);
+ for (tmp = (aClient *) clientTable[hashv].list; tmp; tmp = tmp->hnext)
+ {
+ if (tmp == cptr)
+ {
+ if (prev)
+ prev->hnext = tmp->hnext;
+ else
+ clientTable[hashv].list = (void *) tmp->hnext;
+ tmp->hnext = NULL;
+ if (clientTable[hashv].links > 0)
+ {
+ clientTable[hashv].links--;
+ return 1;
+ }
+ else
+ /*
+ * Should never actually return from here and if we do it
+ * is an error/inconsistency in the hash table.
+ */
+ return -1;
+ }
+ prev = tmp;
+ }
+ return 0;
+}
+
+/* del_from_channel_hash_table */
+int del_from_channel_hash_table(char *name, aChannel *chptr)
+{
+ aChannel *tmp, *prev = NULL;
+ int hashv;
+
+ hashv = hash_channel_name(name);
+ for (tmp = (aChannel *) channelTable[hashv].list; tmp;
+ tmp = tmp->hnextch)
+ {
+ if (tmp == chptr)
+ {
+ if (prev)
+ prev->hnextch = tmp->hnextch;
+ else
+ channelTable[hashv].list = (void *) tmp->hnextch;
+ tmp->hnextch = NULL;
+ if (channelTable[hashv].links > 0)
+ {
+ channelTable[hashv].links--;
+ return 1;
+ }
+ else
+ return -1;
+ }
+ prev = tmp;
+ }
+ return 0;
+}
+
+/* hash_find_client */
+aClient *hash_find_client(char *name, aClient *cptr)
+{
+ aClient *tmp;
+ aHashEntry *tmp3;
+ int hashv;
+
+ hashv = hash_nick_name(name);
+ tmp3 = &clientTable[hashv];
+ /* Got the bucket, now search the chain. */
+ for (tmp = (aClient *) tmp3->list; tmp; tmp = tmp->hnext)
+ if (mycmp(name, tmp->name) == 0)
+ {
+ return (tmp);
+ }
+ return (cptr);
+ /*
+ * If the member of the hashtable we found isnt at the top of its
+ * chain, put it there. This builds a most-frequently used order
+ * into the chains of the hash table, giving speedier lookups on
+ * those nicks which are being used currently. This same block of
+ * code is also used for channels and servers for the same
+ * performance reasons.
+ *
+ * I don't believe it does.. it only wastes CPU, lets try it and
+ * see....
+ *
+ * - Dianora
+ */
+}
+
+/*
+ * hash_find_nickserver
+ */
+aClient *hash_find_nickserver(char *name, aClient *cptr)
+{
+ aClient *tmp;
+ aHashEntry *tmp3;
+ int hashv;
+ char *serv;
+
+ serv = strchr(name, '@');
+ *serv++ = '\0';
+ hashv = hash_nick_name(name);
+ tmp3 = &clientTable[hashv];
+ /* Got the bucket, now search the chain. */
+ for (tmp = (aClient *) tmp3->list; tmp; tmp = tmp->hnext)
+ if (mycmp(name, tmp->name) == 0 && tmp->user &&
+ mycmp(serv, tmp->user->server) == 0)
+ {
+ *--serv = '\0';
+ return (tmp);
+ }
+
+ *--serv = '\0';
+ return (cptr);
+}
+
+/* hash_find_server*/
+aClient *hash_find_server(char *server, aClient *cptr)
+{
+ aClient *tmp;
+ aHashEntry *tmp3;
+
+ int hashv;
+
+ hashv = hash_nick_name(server);
+ tmp3 = &clientTable[hashv];
+
+ for (tmp = (aClient *) tmp3->list; tmp; tmp = tmp->hnext)
+ {
+ if (!IsServer(tmp) && !IsMe(tmp))
+ continue;
+ if (mycmp(server, tmp->name) == 0)
+ {
+ return (tmp);
+ }
+ }
+
+ /*
+ * Whats happening in this next loop ? Well, it takes a name like
+ * foo.bar.edu and proceeds to earch for *.edu and then *.bar.edu.
+ * This is for checking full server names against masks although it
+ * isnt often done this way in lieu of using matches().
+ */
+ return (cptr);
+}
+
+/* hash_find_channel */
+aChannel *hash_find_channel(char *name, aChannel *chptr)
+{
+ int hashv;
+ aChannel *tmp;
+ aHashEntry *tmp3;
+
+ hashv = hash_channel_name(name);
+ tmp3 = &channelTable[hashv];
+
+ for (tmp = (aChannel *) tmp3->list; tmp; tmp = tmp->hnextch)
+ if (mycmp(name, tmp->chname) == 0)
+ {
+ return (tmp);
+ }
+ return chptr;
+}
+
+/*
+ * NOTE: this command is not supposed to be an offical part of the ircd
+ * protocol. It is simply here to help debug and to monitor the
+ * performance of the hash functions and table, enabling a better
+ * algorithm to be sought if this one becomes troublesome. -avalon
+ *
+ * Needs rewriting for DOUGH_HASH, consider this a place holder until
+ * thats done. Hopefully for hybrid-5, if not. tough. - Dianora
+ *
+ */
+
+int m_hash(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ return 0;
+}
+
+/*
+ * Rough figure of the datastructures for notify:
+ *
+ * NOTIFY HASH cptr1
+ * | |- nick1
+ * nick1-|- cptr1 |- nick2
+ * | |- cptr2 cptr3
+ * | |- cptr3 cptr2 |- nick1
+ * | |- nick1
+ * nick2-|- cptr2 |- nick2
+ * |- cptr1
+ *
+ * add-to-notify-hash-table:
+ * del-from-notify-hash-table:
+ * hash-del-notify-list:
+ * hash-check-notify:
+ * hash-get-notify:
+ */
+
+static aWatch *watchTable[WATCHHASHSIZE];
+
+void count_watch_memory(int *count, u_long *memory)
+{
+ int i = WATCHHASHSIZE;
+ aWatch *anptr;
+
+
+ while (i--)
+ {
+ anptr = watchTable[i];
+ while (anptr)
+ {
+ (*count)++;
+ (*memory) += sizeof(aWatch)+strlen(anptr->nick);
+ anptr = anptr->hnext;
+ }
+ }
+}
+
+void clear_watch_hash_table(void)
+{
+ memset((char *)watchTable, '\0', sizeof(watchTable));
+}
+
+
+/* add_to_watch_hash_table */
+int add_to_watch_hash_table(char *nick, aClient *cptr)
+{
+ int hashv;
+ aWatch *anptr;
+ Link *lp;
+
+
+ /* Get the right bucket... */
+ hashv = hash_nick_name(nick)%WATCHHASHSIZE;
+
+ /* Find the right nick (header) in the bucket, or NULL... */
+ if ((anptr = (aWatch *)watchTable[hashv]))
+ while (anptr && mycmp(anptr->nick, nick))
+ anptr = anptr->hnext;
+
+ /* If found NULL (no header for this nick), make one... */
+ if (!anptr)
+ {
+ anptr = (aWatch *)MyMalloc(sizeof(aWatch)+strlen(nick));
+ anptr->lasttime = timeofday;
+ strcpy(anptr->nick, nick);
+
+ anptr->watch = NULL;
+
+ anptr->hnext = watchTable[hashv];
+ watchTable[hashv] = anptr;
+ }
+ /* Is this client already on the watch-list? */
+ if ((lp = anptr->watch))
+ while (lp && (lp->value.cptr != cptr))
+ lp = lp->next;
+
+ /* No it isn't, so add it in the bucket and client addint it */
+ if (!lp)
+ {
+ lp = anptr->watch;
+ anptr->watch = make_link();
+ anptr->watch->value.cptr = cptr;
+ anptr->watch->next = lp;
+
+ lp = make_link();
+ lp->next = cptr->watch;
+ lp->value.wptr = anptr;
+ cptr->watch = lp;
+ cptr->watches++;
+ }
+
+ return 0;
+}
+
+/* hash_check_watch */
+int hash_check_watch(aClient *cptr, int reply)
+{
+ int hashv;
+ aWatch *anptr;
+ Link *lp;
+
+
+ /* Get us the right bucket */
+ hashv = hash_nick_name(cptr->name)%WATCHHASHSIZE;
+
+ /* Find the right header in this bucket */
+ if ((anptr = (aWatch *)watchTable[hashv]))
+ while (anptr && mycmp(anptr->nick, cptr->name))
+ anptr = anptr->hnext;
+ if (!anptr)
+ return 0; /* This nick isn't on watch */
+
+ /* Update the time of last change to item */
+ anptr->lasttime = NOW;
+
+ /* Send notifies out to everybody on the list in header */
+ for (lp = anptr->watch; lp; lp = lp->next)
+ sendto_one(lp->value.cptr, rpl_str(reply), me.name,
+ lp->value.cptr->name, cptr->name,
+ (IsPerson(cptr)?cptr->user->username:"<N/A>"),
+ (IsPerson(cptr)?cptr->user->host:"<N/A>"),
+ anptr->lasttime, cptr->info);
+
+ return 0;
+}
+
+/* hash_get_watch */
+aWatch *hash_get_watch(char *name)
+{
+ int hashv;
+ aWatch *anptr;
+
+
+ hashv = hash_nick_name(name)%WATCHHASHSIZE;
+
+ if ((anptr = (aWatch *)watchTable[hashv]))
+ while (anptr && mycmp(anptr->nick, name))
+ anptr = anptr->hnext;
+
+ return anptr;
+}
+
+/* del_from_watch_hash_table */
+int del_from_watch_hash_table(char *nick, aClient *cptr)
+{
+ int hashv;
+ aWatch *anptr, *nlast = NULL;
+ Link *lp, *last = NULL;
+
+
+ /* Get the bucket for this nick... */
+ hashv = hash_nick_name(nick)%WATCHHASHSIZE;
+
+ /* Find the right header, maintaining last-link pointer... */
+ if ((anptr = (aWatch *)watchTable[hashv]))
+ while (anptr && mycmp(anptr->nick, nick))
+ {
+ nlast = anptr;
+ anptr = anptr->hnext;
+ }
+ if (!anptr)
+ return 0; /* No such watch */
+
+ /* Find this client from the list of notifies... with last-ptr. */
+ if ((lp = anptr->watch))
+ while (lp && (lp->value.cptr != cptr))
+ {
+ last = lp;
+ lp = lp->next;
+ }
+ if (!lp)
+ return 0; /* No such client to watch */
+
+ /* Fix the linked list under header, then remove the watch entry */
+ if (!last)
+ anptr->watch = lp->next;
+ else
+ last->next = lp->next;
+ free_link(lp);
+
+ /* Do the same regarding the links in client-record... */
+ last = NULL;
+ if ((lp = cptr->watch))
+ while (lp && (lp->value.wptr != anptr))
+ {
+ last = lp;
+ lp = lp->next;
+ }
+
+ /*
+ * Give error on the odd case... probobly not even neccessary
+ * No error checking in ircd is unneccessary ;) -Cabal95
+ */
+ if (!lp)
+ sendto_ops("WATCH debug error: del_from_watch_hash_table "
+ "found a watch entry with no client "
+ "counterpoint processing nick %s on client %s!",
+ nick, cptr->user);
+ else
+ {
+ if (!last) /* First one matched */
+ cptr->watch = lp->next;
+ else
+ last->next = lp->next;
+ free_link(lp);
+ }
+ /* In case this header is now empty of notices, remove it */
+ if (!anptr->watch)
+ {
+ if (!nlast)
+ watchTable[hashv] = anptr->hnext;
+ else
+ nlast->hnext = anptr->hnext;
+ MyFree(anptr);
+ }
+
+ /* Update count of notifies on nick */
+ cptr->watches--;
+
+ return 0;
+}
+
+/* hash_del_watch_list */
+int hash_del_watch_list(aClient *cptr)
+{
+ int hashv;
+ aWatch *anptr;
+ Link *np, *lp, *last;
+
+
+ if (!(np = cptr->watch))
+ return 0; /* Nothing to do */
+
+ cptr->watch = NULL; /* Break the watch-list for client */
+ while (np)
+ {
+ /* Find the watch-record from hash-table... */
+ anptr = np->value.wptr;
+ last = NULL;
+ for (lp = anptr->watch; lp && (lp->value.cptr != cptr);
+ lp = lp->next)
+ last = lp;
+
+ /* Not found, another "worst case" debug error */
+ if (!lp)
+ sendto_ops("WATCH Debug error: hash_del_watch_list "
+ "found a WATCH entry with no table "
+ "counterpoint processing client %s!",
+ cptr->name);
+ else
+ {
+ /* Fix the watch-list and remove entry */
+ if (!last)
+ anptr->watch = lp->next;
+ else
+ last->next = lp->next;
+ free_link(lp);
+
+ /*
+ * If this leaves a header without notifies,
+ * remove it. Need to find the last-pointer!
+ */
+ if (!anptr->watch)
+ {
+ aWatch *np2, *nl;
+
+ hashv = hash_nick_name(anptr->nick)%WATCHHASHSIZE;
+
+ nl = NULL;
+ np2 = watchTable[hashv];
+ while (np2 != anptr)
+ {
+ nl = np2;
+ np2 = np2->hnext;
+ }
+
+ if (nl)
+ nl->hnext = anptr->hnext;
+ else
+ watchTable[hashv] = anptr->hnext;
+ MyFree(anptr);
+ }
+ }
+
+ lp = np; /* Save last pointer processed */
+ np = np->next; /* Jump to the next pointer */
+ free_link(lp); /* Free the previous */
+ }
+
+ cptr->watches = 0;
+
+ return 0;
+}
+
+aChannel *hash_get_chan_bucket(int hashv)
+{
+ if (hashv > CH_MAX)
+ return NULL;
+ return (aChannel *)channelTable[hashv].list;
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/hide.c
+ * Copyright (C) 2003 Lucas Madar
+ *
+ * hide.c - code for hiding information
+ *
+ */
+
+/* $Id: hide.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include "fds.h"
+#include "numeric.h"
+
+/* This is how we maintain a 'fake' list of servers */
+
+struct fakelinkserver {
+ char *name;
+ char *description;
+};
+
+/* lserver_list is a linked list of Link structures,
+ each with the 'cp' member pointing to a struct fakelinkserver */
+
+static Link *lserver_list = NULL;
+
+static struct fakelinkserver *fakelinkserver_find(char *name)
+{
+ Link *lp;
+ struct fakelinkserver *ls;
+
+ for(lp = lserver_list; lp; lp = lp->next)
+ {
+ ls = (struct fakelinkserver *) lp->value.cp;
+ if(mycmp(name, ls->name) == 0)
+ return ls;
+ }
+ return NULL;
+}
+
+/*
+ * Delete the entire list
+ */
+void fakelinkserver_reset()
+{
+ Link *lp;
+ struct fakelinkserver *ls;
+
+ while((lp = lserver_list))
+ {
+ lserver_list = lp->next;
+
+ ls = (struct fakelinkserver *) lp->value.cp;
+ MyFree(ls->name);
+ MyFree(ls->description);
+ MyFree(ls);
+ free_link(lp);
+ }
+}
+
+static void fakelinkserver_delete(char *name)
+{
+ Link *lp, *lpprev, *lpn;
+ struct fakelinkserver *ls;
+
+ for(lp = lserver_list, lpprev = NULL; lp; lpprev = lp, lp = lpn)
+ {
+ lpn = lp->next;
+ ls = (struct fakelinkserver *) lp->value.cp;
+ if(mycmp(name, ls->name) == 0)
+ {
+ if(lpprev)
+ lpprev->next = lp->next;
+ else
+ lserver_list = lp->next;
+
+ MyFree(ls->name);
+ MyFree(ls->description);
+ MyFree(ls);
+ free_link(lp);
+ return;
+ }
+ }
+}
+
+static void fakelinkserver_add(char *name, char *desc)
+{
+ struct fakelinkserver *ls;
+ Link *lp;
+
+ if(fakelinkserver_find(name))
+ return;
+
+ ls = (struct fakelinkserver *) MyMalloc(sizeof(struct fakelinkserver));
+ ls->name = (char *) MyMalloc(strlen(name) + 1);
+ strcpy(ls->name, name);
+ ls->description = (char *) MyMalloc(strlen(desc) + 1);
+ strcpy(ls->description, desc);
+
+ lp = make_link();
+ lp->value.cp = (char *) ls;
+ lp->next = lserver_list;
+ lserver_list = lp;
+}
+
+/*
+ * update the server's description
+ */
+void fakelinkserver_update(char *name, char *desc)
+{
+ struct fakelinkserver *ls;
+
+ if(!(ls = fakelinkserver_find(name)))
+ return;
+
+ MyFree(ls->description);
+ ls->description = (char *) MyMalloc(strlen(desc) + 1);
+ strcpy(ls->description, desc);
+}
+
+int m_linkscontrol(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ if (!(parc > 1 && (IsServer(sptr) || IsULine(sptr))))
+ return 0;
+ else
+ {
+ char pbuf[512];
+
+ make_parv_copy(pbuf, parc, parv);
+ sendto_serv_butone(cptr, ":%s LINKSCONTROL %s", parv[0], pbuf);
+ }
+
+ if(mycmp(parv[1], "RESET") == 0)
+ {
+ fakelinkserver_reset();
+ return 0;
+ }
+ else if(parc > 2 && mycmp(parv[1], "+") == 0)
+ {
+ char *servername = parv[2];
+ aClient *acptr = find_server(servername, NULL);
+ char *desc = (parc > 3) ? parv[3] : HIDDEN_SERVER_DESC;
+
+ if(strchr(servername, '.') == NULL)
+ return 0;
+
+ if(strchr(servername, ' ') != NULL)
+ return 0;
+
+ fakelinkserver_add(servername, acptr ? acptr->info : desc);
+ }
+ else if(parc > 2 && mycmp(parv[1], "-") == 0)
+ {
+ char *servername = parv[2];
+
+ fakelinkserver_delete(servername);
+ }
+
+ return 0;
+}
+
+/* send the list to a client doing /links */
+void fakeserver_list(aClient *sptr)
+{
+ Link *lp;
+
+ for (lp = lserver_list; lp; lp = lp->next)
+ {
+ struct fakelinkserver *ls = (struct fakelinkserver *) lp->value.cp;
+
+ sendto_one(sptr, rpl_str(RPL_LINKS), me.name, sptr->name,
+ ls->name, ls->name, 0, ls->description);
+ }
+}
+
+/* send the list to a client server (we are a hub server) */
+void fakeserver_sendserver(aClient *sptr)
+{
+ Link *lp;
+
+#if 0 /* Don't do this. */
+ /* tell them to reset their list */
+ sendto_one(sptr, ":%s LINKSCONTROL RESET", me.name);
+#endif
+
+ for (lp = lserver_list; lp; lp = lp->next)
+ {
+ struct fakelinkserver *ls = (struct fakelinkserver *) lp->value.cp;
+
+ sendto_one(sptr, ":%s LINKSCONTROL + %s :%s",
+ me.name, ls->name, ls->description);
+ }
+}
+
+/* -1 if lusers isn't locked */
+static time_t luserslock_expiretime = -1;
+
+int is_luserslocked()
+{
+ if(luserslock_expiretime == -1)
+ return 0;
+
+ if(luserslock_expiretime <= NOW)
+ {
+ luserslock_expiretime = -1;
+ sendto_realops("LUSERS lock has expired");
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct fakelusers_struct {
+ int m_server;
+ int m_ulined;
+ int m_client;
+ int m_clientmax;
+ int i_count;
+ int c_count;
+ int s_count;
+ int o_count;
+ int chan_count;
+ int m_total;
+ int m_totalmax;
+} fakelusers = {0};
+
+static void dolocklusers()
+{
+ fakelusers.m_server = Count.myserver;
+ fakelusers.m_ulined = Count.myulined;
+ fakelusers.m_client = Count.local;
+ fakelusers.m_clientmax = Count.max_loc;
+ fakelusers.i_count = Count.invisi;
+ fakelusers.c_count = Count.total - Count.invisi;
+ fakelusers.s_count = Count.server;
+ fakelusers.o_count = Count.oper;
+ fakelusers.chan_count = Count.chan;
+ fakelusers.m_total = Count.total;
+ fakelusers.m_totalmax = Count.max_tot;
+}
+
+void send_fake_users(aClient *sptr)
+{
+ sendto_one(sptr, rpl_str(RPL_LOCALUSERS), me.name, sptr->name,
+ fakelusers.m_client, fakelusers.m_clientmax);
+ sendto_one(sptr, rpl_str(RPL_GLOBALUSERS), me.name, sptr->name,
+ fakelusers.m_total, fakelusers.m_totalmax);
+}
+
+void send_fake_lusers(aClient *sptr)
+{
+#ifdef SHOW_INVISIBLE_LUSERS
+ sendto_one(sptr, rpl_str(RPL_LUSERCLIENT), me.name, sptr->name,
+ fakelusers.c_count, fakelusers.i_count, fakelusers.s_count);
+#else
+ sendto_one(sptr,
+ ":%s %d %s :There are %d users on %d servers", me.name,
+ RPL_LUSERCLIENT, sptr->name, fakelusers.c_count,
+ fakelusers.s_count);
+#endif
+
+ if (fakelusers.o_count)
+ sendto_one(sptr, rpl_str(RPL_LUSEROP),
+ me.name, sptr->name, fakelusers.o_count);
+
+ if(fakelusers.chan_count)
+ sendto_one(sptr, rpl_str(RPL_LUSERCHANNELS),
+ me.name, sptr->name, fakelusers.chan_count);
+
+ sendto_one(sptr, rpl_str(RPL_LUSERME), me.name, sptr->name,
+#ifdef HIDEULINEDSERVS
+ fakelusers.m_server - fakelusers.m_ulined);
+#else
+ fakelusers.m_server);
+#endif
+
+ sendto_one(sptr, rpl_str(RPL_LOCALUSERS), me.name, sptr->name,
+ fakelusers.m_client, fakelusers.m_clientmax);
+ sendto_one(sptr, rpl_str(RPL_GLOBALUSERS), me.name, sptr->name,
+ fakelusers.m_total, fakelusers.m_totalmax);
+}
+
+int m_luserslock(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ char pbuf[512];
+
+ if(!(IsULine(sptr) || IsServer(sptr)))
+ return 0;
+
+ /* LUSERSLOCK UNTIL <time> */
+ if(parc > 2 && mycmp(parv[1], "UNTIL") == 0)
+ {
+ time_t until = strtol(parv[2], NULL, 0);
+
+ if(until < NOW)
+ return 0;
+
+ if(luserslock_expiretime != -1 && luserslock_expiretime < until)
+ {
+ sendto_realops("LUSERS lock extended by %s (%d minute duration from now)",
+ sptr->name, 1 + (until - NOW) / 60);
+
+ luserslock_expiretime = until;
+ }
+ else if(luserslock_expiretime == -1)
+ {
+ sendto_realops("LUSERS lock activated by %s (%d minute duration)",
+ sptr->name, 1 + (until - NOW) / 60);
+
+ luserslock_expiretime = until;
+ dolocklusers();
+ }
+ }
+ /* LUSERSLOCK CANCEL */
+ else if(parc > 1 && mycmp(parv[1], "CANCEL") == 0)
+ {
+ if(confopts & FLAGS_HUB)
+ /* If I'm a hub, toss out anyone but services telling me to cancel. */
+ if(!IsULine(sptr))
+ return 0;
+
+ if(luserslock_expiretime != -1)
+ {
+ luserslock_expiretime = -1;
+ sendto_realops("LUSERS lock cancelled by %s", sptr->name);
+ }
+ }
+
+ make_parv_copy(pbuf, parc, parv);
+ sendto_serv_butone(cptr, ":%s LUSERSLOCK %s", parv[0], pbuf);
+
+ return 0;
+}
+
+void fakelusers_sendlock(aClient *sptr)
+{
+ if(luserslock_expiretime == -1)
+ sendto_one(sptr, ":%s LUSERSLOCK CANCEL", me.name);
+ else
+ sendto_one(sptr, ":%s LUSERSLOCK UNTIL %d", (int) luserslock_expiretime);
+}
--- /dev/null
+/*
+ * ++Copyright++ 1983, 1990, 1993 - Copyright (c) 1983, 1990, 1993 The
+ * Regents of the University of California. 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. All advertising materials mentioning features
+ * or use of this software must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors. 4. Neither the name of
+ * the University 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 REGENTS 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 REGENTS 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. - Portions Copyright (c) 1993 by Digital Equipment
+ * Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies, and that the name of Digital Equipment Corporation not be
+ * used in advertising or publicity pertaining to distribution of the
+ * document or software without specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -
+ * --Copyright--
+ */
+
+/* $Id: inet_addr.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+#include "setup.h"
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include <netinet/in.h>
+#include "nameser.h"
+#include "resolv.h"
+
+#ifndef INADDR_NONE
+#define INADDR_NONE ((u_long)0xffffffff)
+#endif
+
+/* this is a compatibility routine, not needed on recent BSD releases */
+#if !defined( HAVE_INET_ADDR )
+/*
+ * Ascii internet address interpretation routine. The value returned is
+ * in network order.
+ */
+u_long inet_addr(const char *cp)
+{
+ struct in_addr val;
+
+ if (inet_aton(cp, &val))
+ return (val.s_addr);
+ return (INADDR_NONE);
+}
+#endif
+
+/*
+ * Check whether "cp" is a valid ascii representation of an Internet
+ * address and convert to a binary address. Returns 1 if the address is
+ * valid, 0 if not. This replaces inet_addr, the return value from
+ * which cannot distinguish between failure and a local broadcast
+ * address.
+ */
+#if !defined( HAVE_INET_ATON )
+int inet_aton(const u_char *cp, struct in_addr *addr)
+{
+ u_long val;
+ int base, n;
+ u_char c;
+ u_int parts[4];
+ u_int *pp = parts;
+
+ for (;;)
+ {
+ /*
+ * Collect number up to ``.''. Values are specified as for C:
+ * 0x=hex, 0=octal, other=decimal.
+ */
+ val = 0;
+ base = 10;
+ if (*cp == '0')
+ {
+ if (*++cp == 'x' || *cp == 'X')
+ base = 16, cp++;
+ else
+ base = 8;
+ }
+ while ((c = *cp) != '\0')
+ {
+ if (IsAscii(c) && IsDigit(c))
+ {
+ val = (val * base) + (c - '0');
+ cp++;
+ continue;
+ }
+ if (base == 16 && IsAscii(c) && IsXDigit(c))
+ {
+ val = (val << 4) +
+ (c + 10 - (IsLower(c) ? 'a' : 'A'));
+ cp++;
+ continue;
+ }
+ break;
+ }
+ if (*cp == '.')
+ {
+ /*
+ * Internet format: a.b.c.d a.b.c (with c treated as
+ * 16-bits) a.b (with b treated as 24 bits)
+ */
+ if (pp >= parts + 3 || val > 0xff)
+ return (0);
+ *pp++ = val, cp++;
+ }
+ else
+ break;
+ }
+ /* Check for trailing characters. */
+ if (*cp && (!IsAscii(*cp) || !IsSpace(*cp)))
+ return (0);
+ /* Concoct the address according to the number of parts specified. */
+ n = pp - parts + 1;
+ switch (n)
+ {
+ case 1: /* a -- 32 bits */
+ break;
+
+ case 2: /* a.b -- 8.24 bits */
+ if (val > 0xffffff)
+ return (0);
+ val |= parts[0] << 24;
+ break;
+
+ case 3: /* a.b.c -- 8.8.16 bits */
+ if (val > 0xffff)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16);
+ break;
+
+ case 4: /* a.b.c.d -- 8.8.8.8 bits */
+ if (val > 0xff)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+ break;
+ }
+ if (addr)
+ addr->s_addr = htonl(val);
+ return (1);
+}
+#endif
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/ircd.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: ircd.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "msg.h"
+#include "sbuf.h"
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <pwd.h>
+#include <signal.h>
+#include <fcntl.h>
+#if defined PROFILING && defined __GLIBC__ && (__GLIBC__ >= 2)
+#include <sys/gmon.h>
+#define monstartup __monstartup
+#endif
+#include "inet.h"
+#include "h.h"
+#include "patchlevel.h"
+#include "dh.h"
+
+#include "throttle.h"
+#include "userban.h"
+#include "clones.h"
+#include "hooks.h"
+#include "fds.h"
+
+aMotd *motd;
+aMotd *helpfile; /* misnomer, aMotd could be generalized */
+aMotd *shortmotd; /* short motd */
+
+struct tm *motd_tm;
+
+/* global conf options (from option block) */
+char ProxyMonURL[TOPICLEN+1];
+char ProxyMonHost[HOSTLEN+1];
+char Network_Name[HOSTLEN+1];
+char Services_Name[HOSTLEN+1];
+char NS_Services_Name[HOSTLEN+9];
+char CS_Services_Name[HOSTLEN+9];
+char MS_Services_Name[HOSTLEN+9];
+char RS_Services_Name[HOSTLEN+9];
+char Stats_Name[HOSTLEN+1];
+char OS_Stats_Name[HOSTLEN+9];
+char SS_Stats_Name[HOSTLEN+9];
+char HS_Stats_Name[HOSTLEN+9];
+char NS_Register_URL[TOPICLEN+1];
+char Network_Kline_Address[HOSTLEN+1];
+char Local_Kline_Address[HOSTLEN+1];
+char Staff_Address[HOSTLEN+1];
+int maxchannelsperuser, tsmaxdelta, tswarndelta;
+int confopts, new_confopts;
+int local_ip_limit, local_ip24_limit, global_ip_limit, global_ip24_limit;
+
+/* this stuff by mnystrom@mit.edu */
+#include "fdlist.h"
+
+fdlist default_fdlist; /* just the number of the entry */
+
+int MAXCLIENTS = MAX_ACTIVECONN; /* runtime configurable by m_set */
+
+struct Counter Count;
+int R_do_dns, R_fin_dns, R_fin_dnsc, R_fail_dns, R_do_id,
+ R_fin_id, R_fail_id;
+
+time_t NOW;
+time_t last_stat_save;
+aClient me; /* That's me */
+aClient *client = &me; /* Pointer to beginning of Client list */
+
+int forked = 0;
+
+float curSendK = 0, curRecvK = 0;
+
+#ifdef LOCKFILE
+extern time_t pending_kline_time;
+extern struct pkl *pending_klines;
+extern void do_pending_klines(void);
+#endif
+extern void engine_read_message(int);
+
+void server_reboot();
+void restart(char *);
+static void open_debugfile(), setup_signals();
+static void io_loop();
+
+/* externally needed functions */
+
+extern void init_fdlist(fdlist *); /* defined in fdlist.c */
+extern void read_motd(char *); /* defined in s_serv.c */
+extern void read_shortmotd(char *); /* defined in s_serv.c */
+extern void read_help(char *); /* defined in s_serv.c */
+extern void init_globals();
+
+char **myargv;
+char configfile[PATH_MAX] = {0}; /* Server configuration file */
+
+int debuglevel = -1; /* Server debug level */
+int bootopt = 0; /* Server boot option flags */
+char *debugmode = ""; /* -"- -"- -"- */
+char *sbrk0; /* initial sbrk(0) */
+static int dorehash = 0;
+char dpath[PATH_MAX] = {0}; /* our configure files live in here */
+char spath[PATH_MAX] = {0}; /* the path to our binary */
+int rehashed = 1;
+int zline_in_progress = 0; /* killing off matching D lines */
+time_t nextconnect = 1; /* time for next try_connections call */
+time_t nextping = 1; /* same as above for check_pings() */
+time_t nextdnscheck = 0; /* next time to poll dns to force timeout */
+time_t nextexpire = 1; /* next expire run on the dns cache */
+time_t nextbanexpire = 1; /* next time to expire the throttles/userbans */
+
+#ifdef PROFILING
+extern void _start, etext;
+
+static int profiling_state = 1;
+static int profiling_newmsg = 0;
+static char profiling_msg[512];
+
+void s_dumpprof()
+{
+ char buf[32];
+
+ sprintf(buf, "gmon.%d", (int)time(NULL));
+ setenv("GMON_OUT_PREFIX", buf, 1);
+ _mcleanup();
+ monstartup ((u_long) &_start, (u_long) &etext);
+ setenv("GMON_OUT_PREFIX", "gmon.auto", 1);
+ sprintf(profiling_msg, "Reset profile, saved past profile data to %s", buf);
+ profiling_newmsg = 1;
+}
+
+void s_toggleprof()
+{
+ char buf[32];
+
+ if(profiling_state == 1)
+ {
+ sprintf(buf, "gmon.%d", (int)time(NULL));
+ setenv("GMON_OUT_PREFIX", buf, 1);
+ _mcleanup();
+ sprintf(profiling_msg, "Turned profiling OFF, saved profile data to %s", buf);
+ profiling_state = 0;
+ }
+ else
+ {
+ monstartup ((u_long) &_start, (u_long) &etext);
+ setenv("GMON_OUT_PREFIX", "gmon.auto", 1);
+ profiling_state = 1;
+ sprintf(profiling_msg, "Turned profiling ON");
+ }
+ profiling_newmsg = 1;
+}
+
+#endif
+
+void s_die()
+{
+ FILE *fp;
+ char tmp[PATH_MAX];
+ dump_connections(me.fd);
+#ifdef USE_SYSLOG
+ (void) syslog(LOG_CRIT, "Server killed By SIGTERM");
+#endif
+ ircsprintf(tmp, "%s/.maxclients", dpath);
+ fp=fopen(tmp, "w");
+ if(fp!=NULL)
+ {
+ fprintf(fp, "%d %d %li %li %li %ld %ld %ld %ld", Count.max_loc,
+ Count.max_tot, Count.weekly, Count.monthly,
+ Count.yearly, Count.start, Count.week, Count.month,
+ Count.year);
+ fclose(fp);
+ }
+ exit(0);
+}
+
+static void s_rehash()
+{
+ struct sigaction act;
+ dorehash = 1;
+ act.sa_handler = s_rehash;
+ act.sa_flags = 0;
+ (void) sigemptyset(&act.sa_mask);
+ (void) sigaddset(&act.sa_mask, SIGHUP);
+ (void) sigaction(SIGHUP, &act, NULL);
+}
+
+void restart(char *mesg)
+{
+ static int was_here = NO; /* redundant due to restarting flag below */
+ if (was_here)
+ abort();
+ was_here = YES;
+
+#ifdef USE_SYSLOG
+ (void) syslog(LOG_WARNING, "Restarting Server because: %s, sbrk(0)-etext: %d",
+ mesg, (u_int) sbrk((size_t) 0) - (u_int) sbrk0);
+#endif
+ server_reboot();
+}
+
+void s_restart()
+{
+ static int restarting = 0;
+
+#ifdef USE_SYSLOG
+ (void) syslog(LOG_WARNING, "Server Restarting on SIGINT");
+#endif
+ if (restarting == 0)
+ {
+ /* Send (or attempt to) a dying scream to oper if present */
+ restarting = 1;
+ server_reboot();
+ }
+}
+
+void server_reboot()
+{
+ int i;
+ sendto_ops("Aieeeee!!! Restarting server... sbrk(0)-etext: %d",
+ (u_int) sbrk((size_t) 0) - (u_int) sbrk0);
+
+ Debug((DEBUG_NOTICE, "Restarting server..."));
+ dump_connections(me.fd);
+ /*
+ * fd 0 must be 'preserved' if either the -d or -i options have
+ * been passed to us before restarting.
+ */
+#ifdef USE_SYSLOG
+ (void) closelog();
+#endif
+ for (i = 3; i < MAXCONNECTIONS; i++)
+ (void) close(i);
+
+ if (!(bootopt & (BOOT_TTY | BOOT_DEBUG)))
+ (void) close(2);
+
+ (void) close(1);
+
+ if (!(bootopt & BOOT_OPER))
+ (void) execv(spath, myargv);
+
+#ifdef USE_SYSLOG
+ /* Have to reopen since it has been closed above */
+ openlog(myargv[0], LOG_PID | LOG_NDELAY, LOG_FACILITY);
+ syslog(LOG_CRIT, "execv(%s,%s) failed: %m\n", spath, myargv[0]);
+ closelog();
+#endif
+
+ Debug((DEBUG_FATAL, "Couldn't restart server: %s", strerror(errno)));
+ exit(-1);
+}
+
+/*
+ * try_connections
+ *
+ * Scan through configuration and try new connections.
+ * Returns the calendar time when the next call to this
+ * function should be made latest. (No harm done if this
+ * is called earlier or later...)
+ */
+static time_t try_connections(time_t currenttime)
+{
+ aConnect *aconn, **pconn, *con_conn = (aConnect *) NULL;
+ aClient *cptr;
+ aClass *cltmp;
+ int connecting, confrq;
+ time_t next = 0;
+
+ connecting = FALSE;
+
+ Debug((DEBUG_NOTICE, "Connection check at : %s",
+ myctime(currenttime)));
+
+ for (aconn = connects; aconn; aconn = aconn->next)
+ {
+ /* Also when already connecting! (update holdtimes) --SRB */
+ if (aconn->port <= 0 || aconn->class->connfreq == 0)
+ continue;
+ cltmp = aconn->class;
+
+ /*
+ * * Skip this entry if the use of it is still on hold until
+ * future. Otherwise handle this entry (and set it on hold
+ * until next time). Will reset only hold times, if already
+ * made one successfull connection... [this algorithm is a bit
+ * fuzzy... -- msa >;) ]
+ */
+
+ if ((aconn->hold > currenttime))
+ {
+ if ((next > aconn->hold) || (next == 0))
+ next = aconn->hold;
+ continue;
+ }
+
+ confrq = cltmp->connfreq;
+ aconn->hold = currenttime + confrq;
+
+ /* Found a CONNECT config with port specified, scan clients
+ * and see if this server is already connected?
+ */
+
+ cptr = find_name(aconn->name, (aClient *) NULL);
+
+ if (!cptr && (cltmp->links < cltmp->maxlinks) && !connecting)
+ {
+ con_conn = aconn;
+ /* We connect only one at time... */
+ connecting = TRUE;
+ }
+
+ if ((next > aconn->hold) || (next == 0))
+ next = aconn->hold;
+ }
+
+ if (connecting)
+ {
+ if (con_conn->next) /* are we already last? */
+ {
+ for (pconn = &connects; (aconn = *pconn);
+ pconn = &(aconn->next))
+ /*
+ * put the current one at the end and make sure we try all
+ * connections
+ */
+ if (aconn == con_conn)
+ *pconn = aconn->next;
+ (*pconn = con_conn)->next = 0;
+ }
+ if (connect_server(con_conn, (aClient *) NULL,
+ (struct hostent *) NULL) == 0)
+ sendto_gnotice("from %s: Connection to %s activated.", me.name,
+ con_conn->name);
+ }
+ Debug((DEBUG_NOTICE, "Next connection check : %s", myctime(next)));
+ return (next);
+}
+
+/* dianora's code in the new checkpings is slightly wasteful.
+ * however, upon inspection (thanks seddy), when we close a connection,
+ * the ordering of local[i] is NOT reordered; simply local[highest_fd] becomes
+ * local[i], so we can just i--; - lucas
+ */
+
+static time_t check_pings(time_t currenttime)
+{
+ aClient *cptr;
+ int ping = 0, i;
+ time_t oldest = 0; /* timeout removed, see EXPLANATION below */
+ char fbuf[512], *errtxt = "No response from %s, closing link";
+
+
+ for (i = 0; i <= highest_fd; i++)
+ {
+ if (!(cptr = local[i]) || IsMe(cptr) || IsLog(cptr))
+ continue;
+
+ /* Note: No need to notify opers here. It's
+ * already done when "FLAGS_DEADSOCKET" is set.
+ */
+
+ if (cptr->flags & FLAGS_DEADSOCKET)
+ {
+ exit_client(cptr, cptr, &me, (cptr->flags & FLAGS_SENDQEX) ?
+ "SendQ exceeded" : "Dead socket");
+ continue;
+ }
+
+ if (IsRegistered(cptr))
+ ping = cptr->class->pingfreq;
+ else
+ ping = CONNECTTIMEOUT;
+
+ /*
+ * Ok, so goto's are ugly and can be avoided here but this code
+ * is already indented enough so I think its justified. -avalon
+ *
+ * justified by what? laziness? <g>
+ * If the client pingtime is fine (ie, not larger than the client ping)
+ * skip over all the checks below. - lucas
+ */
+
+ if (ping < (currenttime - cptr->lasttime))
+ {
+ /*
+ * If the server hasnt talked to us in 2*ping seconds and it has
+ * a ping time, then close its connection. If the client is a
+ * user and a KILL line was found to be active, close this
+ * connection too.
+ */
+ if (((cptr->flags & FLAGS_PINGSENT) &&
+ ((currenttime - cptr->lasttime) >= (2 * ping))) ||
+ ((!IsRegistered(cptr) &&
+ (currenttime - cptr->since) >= ping)))
+ {
+ if (!IsRegistered(cptr) && (DoingDNS(cptr) ||
+ DoingAuth(cptr)))
+ {
+ if (cptr->authfd >= 0)
+ {
+ del_fd(cptr->authfd);
+ close(cptr->authfd);
+ cptr->authfd = -1;
+ cptr->count = 0;
+ *cptr->buffer = '\0';
+ }
+#ifdef SHOW_HEADERS
+ if (DoingDNS(cptr))
+ sendto_one(cptr, REPORT_FAIL_DNS);
+ if (DoingAuth(cptr))
+ sendto_one(cptr, REPORT_FAIL_ID);
+#endif
+ Debug((DEBUG_NOTICE, "DNS/AUTH timeout %s",
+ get_client_name(cptr, TRUE)));
+ del_queries((char *) cptr);
+ ClearAuth(cptr);
+ ClearDNS(cptr);
+ cptr->since = currenttime;
+ check_client_fd(cptr);
+ continue;
+ }
+
+ if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr))
+ {
+ ircsprintf(fbuf, "from %s: %s", me.name, errtxt);
+ sendto_gnotice(fbuf, get_client_name(cptr, HIDEME));
+ ircsprintf(fbuf, ":%s GNOTICE :%s", me.name, errtxt);
+ sendto_serv_butone(cptr, fbuf,
+ get_client_name(cptr, HIDEME));
+ }
+
+ exit_client(cptr, cptr, &me, "Ping timeout");
+ continue;
+ } /* don't send pings during a burst, as we send them already. */
+ else if (!(cptr->flags & (FLAGS_PINGSENT|FLAGS_BURST)) &&
+ !(IsConnecting(cptr) || IsHandshake(cptr)))
+ {
+ /*
+ * if we havent PINGed the connection and we havent heard from
+ * it in a while, PING it to make sure it is still alive.
+ */
+ cptr->flags |= FLAGS_PINGSENT;
+ /* not nice but does the job */
+ cptr->lasttime = currenttime - ping;
+ sendto_one(cptr, "PING :%s", me.name);
+ }
+ }
+
+ /* see EXPLANATION below
+ *
+ * timeout = cptr->lasttime + ping;
+ * while (timeout <= currenttime)
+ * timeout += ping;
+ * if (timeout < oldest || !oldest)
+ * oldest = timeout;
+ */
+
+ /*
+ * Check UNKNOWN connections - if they have been in this state
+ * for > 100s, close them.
+ */
+ if (IsUnknown(cptr))
+ if (cptr->firsttime ? ((timeofday - cptr->firsttime) > 100) : 0)
+ (void) exit_client(cptr, cptr, &me, "Connection Timed Out");
+ }
+
+ rehashed = 0;
+ zline_in_progress = 0;
+
+ /* EXPLANATION
+ * on a server with a large volume of clients, at any given point
+ * there may be a client which needs to be pinged the next second,
+ * or even right away (a second may have passed while running
+ * check_pings). Preserving CPU time is more important than
+ * pinging clients out at exact times, IMO. Therefore, I am going to make
+ * check_pings always return currenttime + 9. This means that it may take
+ * a user up to 9 seconds more than pingfreq to timeout. Oh well.
+ * Plus, the number is 9 to 'stagger' our check_pings calls out over
+ * time, to avoid doing it and the other tasks ircd does at the same time
+ * all the time (which are usually done on intervals of 5 seconds or so).
+ * - lucas
+ *
+ * if (!oldest || oldest < currenttime)
+ * oldest = currenttime + PINGFREQUENCY;
+ */
+
+ oldest = currenttime + 9;
+
+ Debug((DEBUG_NOTICE, "Next check_ping() call at: %s, %d %d %d",
+ myctime(oldest), ping, oldest, currenttime));
+
+ return oldest;
+}
+
+/* get_paths()
+ * setup our file paths
+ */
+
+void get_paths(char *argv)
+{
+ char t_dpath[PATH_MAX], t_d2path[PATH_MAX], tmp[PATH_MAX],
+ tmp2[PATH_MAX];
+ int len, fd;
+
+ *t_dpath = 0;
+ *t_d2path = 0;
+ *tmp = 0;
+ *tmp2 = 0;
+
+ if(!*configfile)
+ {
+ getcwd(t_dpath, PATH_MAX); /* directory we're called from */
+ if(argv[0] == '/') /* absolute filename used to call */
+ strcat(spath, argv);
+ else
+ {
+ strcat(spath, t_dpath);
+ strcat(spath, "/");
+ strcat(spath, argv);
+ }
+ strcat(tmp, t_dpath);
+ strcat(tmp, "/ircd.conf");
+ if((fd = open(tmp, O_RDONLY)) > 0)
+ {
+ /* found our ircd.conf in the directory
+ * where we were called from */
+ strcpy(configfile, tmp);
+ close(fd);
+ strcpy(dpath, t_dpath);
+ return;
+ }
+ len = strlen(spath);
+ while(spath[len] != '/')
+ len--;
+ strncat(t_d2path, spath, len);
+ strcat(tmp2, t_d2path);
+ strcat(tmp2, "/ircd.conf");
+ if((fd = open(tmp2, O_RDONLY)) > 0)
+ {
+ /* found the ircd.conf in the directory local
+ * to our binary itself */
+ strcpy(configfile, tmp);
+ close(fd);
+ strcpy(dpath, t_d2path);
+ return;
+ }
+ }
+ else
+ {
+ getcwd(t_dpath, PATH_MAX); /* directory we're called from */
+ if(argv[0] == '/') /* absolute filename used to call */
+ strcat(spath, argv);
+ else
+ {
+ strcat(spath, t_dpath);
+ strcat(spath, "/");
+ strcat(spath, argv);
+ }
+ if(configfile[0] == '/') /* absolute filename in configfile */
+ {
+ len = strlen(configfile);
+ while(configfile[len] != '/')
+ len--;
+ strncat(dpath, configfile, len);
+ }
+ else
+ {
+ strcat(dpath, t_dpath);
+ strcat(dpath, "/");
+ if(strchr(configfile, '/'))
+ {
+ len = strlen(configfile);
+ while(configfile[len] != '/')
+ len--;
+ strncat(dpath, configfile, len);
+ }
+ }
+ }
+ printf("CONFIGFILE: %s\n", configfile);
+}
+
+
+/*
+ * bad_command
+ * This is called when the commandline is not acceptable.
+ * Give error message and exit without starting anything.
+ */
+static int bad_command()
+{
+ printf("Usage: ircd ");
+#ifdef CMDLINE_CONFIG
+ printf("[-f configfile] ");
+#endif
+ printf("[-t] [-v]\n");
+ printf("-t will cause ircd not to fork (mostly for debugging)\n");
+ printf("-v will cause ircd to print its version and quit\n");
+ printf("Server Not Started\n");
+ return (-1);
+}
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+/* ripped this out of hybrid7 out of lazyness. */
+static void
+setup_corefile()
+{
+#ifdef HAVE_SYS_RESOURCE_H
+ struct rlimit rlim; /* resource limits */
+
+ /* Set corefilesize to maximum */
+ if (!getrlimit(RLIMIT_CORE, &rlim))
+ {
+ rlim.rlim_cur = rlim.rlim_max;
+ setrlimit(RLIMIT_CORE, &rlim);
+ }
+#endif
+}
+
+char REPORT_DO_DNS[256], REPORT_FIN_DNS[256], REPORT_FIN_DNSC[256],
+ REPORT_FAIL_DNS[256], REPORT_DO_ID[256], REPORT_FIN_ID[256],
+ REPORT_FAIL_ID[256];
+
+FILE *dumpfp=NULL;
+
+int
+main(int argc, char *argv[])
+{
+ uid_t uid, euid;
+ char tmp[PATH_MAX];
+ FILE *mcsfp;
+ char *conferr;
+
+ if ((timeofday = time(NULL)) == -1)
+ {
+ (void) fprintf(stderr, "ERROR: Clock Failure (%d)\n", errno);
+ exit(errno);
+ }
+
+ build_version();
+
+ printf("\n%s booting...\n", version);
+ printf("Security related issues should be sent to coders@dal.net\n");
+ printf("All other issues should be sent to dalnet-src@dal.net\n\n");
+
+ setup_corefile();
+
+ Count.server = 1; /* us */
+ Count.oper = 0;
+ Count.chan = 0;
+ Count.local = 0;
+ Count.total = 0;
+ Count.invisi = 0;
+ Count.unknown = 0;
+ Count.max_loc = 0;
+ Count.max_tot = 0;
+ Count.today = 0;
+ Count.weekly = 0;
+ Count.monthly = 0;
+ Count.yearly = 0;
+ Count.start = NOW;
+ Count.day = NOW;
+ Count.week = NOW;
+ Count.month = NOW;
+ Count.year = NOW;
+
+ /*
+ * this code by mika@cs.caltech.edu
+ * it is intended to keep the ircd from being swapped out. BSD
+ * swapping criteria do not match the requirements of ircd
+ */
+
+#if defined(INITIAL_SBUFS_LARGE) && defined(INITIAL_SBUFS_SMALL)
+ sbuf_init();
+#endif
+
+ sbrk0 = (char *) sbrk((size_t) 0);
+ uid = getuid();
+ euid = geteuid();
+
+#ifdef PROFILING
+ setenv("GMON_OUT_PREFIX", "gmon.out", 1);
+ (void) signal(SIGUSR1, s_dumpprof);
+ (void) signal(SIGUSR2, s_toggleprof);
+#endif
+
+ myargv = argv;
+ (void) umask(077); /* better safe than sorry --SRB */
+ memset((char *) &me, '\0', sizeof(me));
+
+ setup_signals();
+ /*
+ * * All command line parameters have the syntax "-fstring" or "-f
+ * string" (e.g. the space is optional). String may be empty. Flag
+ * characters cannot be concatenated (like "-fxyz"), it would
+ * conflict with the form "-fstring".
+ */
+ while (--argc > 0 && (*++argv)[0] == '-')
+ {
+ char *p = argv[0] + 1;
+ int flag = *p++;
+
+ if (flag == '\0' || *p == '\0')
+ {
+ if (argc > 1 && argv[1][0] != '-')
+ {
+ p = *++argv;
+ argc -= 1;
+ }
+ else
+ p = "";
+ }
+
+ switch (flag)
+ {
+#ifdef CMDLINE_CONFIG
+ case 'f':
+ (void) setuid((uid_t) uid);
+ strcpy(configfile, p);
+ break;
+#endif
+ case 's':
+ bootopt |= BOOT_STDERR;
+ break;
+ case 't':
+ (void) setuid((uid_t) uid);
+ bootopt |= BOOT_TTY;
+ break;
+ case 'v':
+ (void) printf("%s\n", version);
+ exit(0);
+ case 'x':
+#ifdef DEBUGMODE
+ (void) setuid((uid_t) uid);
+ debuglevel = atoi(p);
+ debugmode = *p ? p : "0";
+ bootopt |= BOOT_DEBUG;
+ break;
+#else
+ bad_command();
+ break;
+#endif
+ default:
+ bad_command();
+ break;
+ }
+ }
+
+ get_paths(myargv[0]);
+
+ if(chdir(dpath))
+ {
+ printf("Error changing directory to ircd.conf location\n");
+ printf("Server not started\n");
+ exit(0);
+ }
+
+ ircsprintf(tmp, "%s/.maxclients", dpath);
+ mcsfp = fopen(tmp, "r");
+ if(mcsfp != NULL)
+ {
+ fscanf(mcsfp, "%d %d %li %li %li %ld %ld %ld %ld", &Count.max_loc,
+ &Count.max_tot, &Count.weekly, &Count.monthly, &Count.yearly,
+ &Count.start, &Count.week, &Count.month, &Count.year);
+ fclose(mcsfp);
+ }
+
+ if ((uid != euid) && !euid)
+ {
+ printf("Do not run ircd as root.\nAborting...\n");
+ exit(-1);
+ }
+
+ if (argc > 0)
+ return bad_command(); /* This should exit out */
+
+ init_globals();
+
+#ifdef HAVE_ENCRYPTION_ON
+ printf("Initializing Encryption...");
+ if(dh_init() == -1)
+ {
+ printf("\n\nEncryption Init failed!\n\n");
+ return 0;
+ }
+#endif
+
+ motd = (aMotd *) NULL;
+ helpfile = (aMotd *) NULL;
+ motd_tm = NULL;
+ shortmotd = NULL;
+
+ clear_client_hash_table();
+ clear_channel_hash_table();
+ clear_scache_hash_table(); /* server cache name table */
+
+ /* init the throttle system -wd */
+ throttle_init();
+
+ /* clone tracking and limiting */
+ clones_init();
+
+ /* init the file descriptor tracking system */
+ init_fds();
+
+ /* init the kline/akill system */
+ init_userban();
+
+ initlists();
+ initwhowas();
+ initstats();
+ init_tree_parse(msgtab);
+ init_send();
+ open_debugfile();
+ NOW = time(NULL);
+
+ initclass();
+
+ if(initconf(configfile) == -1)
+ {
+ printf("Server not started\n");
+ exit(-1);
+ }
+ conferr = finishconf();
+ if (conferr)
+ {
+ printf("ERROR: %s in config file\nServer not started\n", conferr);
+ exit(-1);
+ }
+ merge_confs();
+ build_rplcache();
+ read_motd(MOTD);
+ read_help(HELPFILE);
+ if(confopts & FLAGS_SMOTD)
+ read_shortmotd(SHORTMOTD);
+ printf("Configuration Loaded.\n");
+
+ init_fdlist(&default_fdlist);
+ {
+ int i;
+
+ for (i = MAXCONNECTIONS + 1; i > 0; i--)
+ {
+ default_fdlist.entry[i] = i - 1;
+ }
+ }
+
+ /* init the modules, load default modules! */
+ init_modules();
+
+ me.flags = FLAGS_LISTEN;
+ me.fd = -1;
+
+ /* We don't want to calculate these every time they are used :) */
+
+ sprintf(REPORT_DO_DNS, REPORT_DO_DNS_, me.name);
+ sprintf(REPORT_FIN_DNS, REPORT_FIN_DNS_, me.name);
+ sprintf(REPORT_FIN_DNSC, REPORT_FIN_DNSC_, me.name);
+ sprintf(REPORT_FAIL_DNS, REPORT_FAIL_DNS_, me.name);
+ sprintf(REPORT_DO_ID, REPORT_DO_ID_, me.name);
+ sprintf(REPORT_FIN_ID, REPORT_FIN_ID_, me.name);
+ sprintf(REPORT_FAIL_ID, REPORT_FAIL_ID_, me.name);
+ R_do_dns = strlen(REPORT_DO_DNS);
+ R_fin_dns = strlen(REPORT_FIN_DNS);
+ R_fin_dnsc = strlen(REPORT_FIN_DNSC);
+ R_fail_dns = strlen(REPORT_FAIL_DNS);
+ R_do_id = strlen(REPORT_DO_ID);
+ R_fin_id = strlen(REPORT_FIN_ID);
+ R_fail_id = strlen(REPORT_FAIL_ID);
+
+ NOW = time(NULL);
+
+ init_sys();
+ forked = 1;
+
+#ifdef USE_SYSLOG
+# define SYSLOG_ME "ircd"
+ openlog(SYSLOG_ME, LOG_PID | LOG_NDELAY, LOG_FACILITY);
+#endif
+
+ /* the pid file must be written *AFTER* the fork */
+ write_pidfile();
+
+
+ /* moved this to here such that we allow more verbose error
+ * checking on startup. -epi
+ */
+ open_listeners();
+
+ get_my_name(&me, me.sockhost, sizeof(me.sockhost) - 1);
+ if (me.name[0] == '\0')
+ strncpyzt(me.name, me.sockhost, sizeof(me.name));
+ me.hopcount = 0;
+ me.authfd = -1;
+ me.next = NULL;
+ me.user = NULL;
+ me.from = &me;
+ SetMe(&me);
+ make_server(&me);
+ me.serv->up = me.name;
+ me.lasttime = me.since = me.firsttime = NOW;
+ (void) add_to_client_hash_table(me.name, &me);
+
+
+#ifdef DUMP_DEBUG
+ dumpfp=fopen("dump.log", "w");
+#endif
+#ifdef USE_SYSLOG
+ syslog(LOG_NOTICE, "Server Ready");
+#endif
+
+ io_loop();
+ return 0;
+}
+
+void do_recvqs()
+{
+ DLink *lp, *lpn;
+ aClient *cptr;
+
+ for(lp = recvq_clients; lp; lp = lpn)
+ {
+ lpn = lp->next;
+ cptr = lp->value.cptr;
+
+ if(SBufLength(&cptr->recvQ) && !NoNewLine(cptr))
+ {
+ if(do_client_queue(cptr) == FLUSH_BUFFER)
+ continue;
+ }
+
+ if(!(SBufLength(&cptr->recvQ) && !NoNewLine(cptr)))
+ {
+ remove_from_list(&recvq_clients, cptr, lp);
+ cptr->flags &= ~(FLAGS_HAVERECVQ);
+ }
+ }
+}
+
+void send_safelists()
+{
+ DLink *lp, *lpn;
+ aClient *cptr;
+
+ for(lp = listing_clients; lp; lp = lpn)
+ {
+ lpn = lp->next;
+
+ cptr = lp->value.cptr;
+ while(DoList(cptr) && IsSendable(cptr))
+ send_list(cptr, 64);
+ }
+}
+
+void io_loop()
+{
+ char to_send[200];
+ int lastexp=0;
+
+ time_t next10sec = 0; /* For events we do every 10 seconds */
+
+ time_t lastbwcalc = 0;
+ long lastbwSK = 0, lastbwRK = 0;
+ time_t lasttimeofday;
+ int delay = 0;
+
+ while(1)
+ {
+ lasttimeofday = timeofday;
+
+ if ((timeofday = time(NULL)) == -1)
+ {
+#ifdef USE_SYSLOG
+ syslog(LOG_WARNING, "Clock Failure (%d), TS can be corrupted",
+ errno);
+#endif
+ sendto_ops("Clock Failure (%d), TS can be corrupted", errno);
+ }
+
+ if (timeofday < lasttimeofday)
+ {
+ ircsprintf(to_send, "System clock running backwards - (%d < %d)",
+ timeofday, lasttimeofday);
+ report_error(to_send, &me);
+ }
+
+ NOW = timeofday;
+
+ /*
+ * Calculate a moving average of our total traffic.
+ * Traffic is a 4 second average, 'sampled' every 2 seconds.
+ */
+
+ if((timeofday - lastbwcalc) >= 2)
+ {
+ long ilength = timeofday - lastbwcalc;
+
+ curSendK += (float) (me.sendK - lastbwSK) / (float) ilength;
+ curRecvK += (float) (me.receiveK - lastbwRK) / (float) ilength;
+ curSendK /= 2;
+ curRecvK /= 2;
+
+ lastbwSK = me.sendK;
+ lastbwRK = me.receiveK;
+ lastbwcalc = timeofday;
+ }
+
+ /*
+ * We only want to connect if a connection is due, not every
+ * time through. Note, if there are no active C lines, this call
+ * to Tryconnections is made once only; it will return 0. - avalon
+ */
+
+ if (nextconnect && timeofday >= nextconnect)
+ nextconnect = try_connections(timeofday);
+
+ /* DNS checks. One to timeout queries, one for cache expiries.*/
+
+ if (timeofday >= nextdnscheck)
+ nextdnscheck = timeout_query_list(timeofday);
+ if (timeofday >= nextexpire)
+ nextexpire = expire_cache(timeofday);
+
+ if (timeofday >= nextbanexpire)
+ {
+ /*
+ * magic number: 13 seconds
+ * space out these heavy tasks at semi-random intervals, so as not to coincide
+ * with anything else ircd does regularly
+ */
+ nextbanexpire = NOW + 13;
+
+ if(lastexp == 0)
+ {
+ expire_userbans();
+ lastexp++;
+ }
+ else if(lastexp == 1)
+ {
+ expire_simbans();
+ lastexp++;
+ }
+ else
+ {
+ throttle_timer(NOW);
+ lastexp = 0;
+ }
+ }
+
+ if (timeofday >= next10sec)
+ {
+ next10sec = timeofday + 10;
+ call_hooks(CHOOK_10SEC);
+ }
+
+ /*
+ * take the smaller of the two 'timed' event times as the time
+ * of next event (stops us being late :) - avalon WARNING -
+ * nextconnect can return 0!
+ */
+
+ if (nextconnect)
+ delay = MIN(nextping, nextconnect);
+ else
+ delay = nextping;
+ delay = MIN(nextdnscheck, delay);
+ delay = MIN(nextexpire, delay);
+ delay -= timeofday;
+
+ /*
+ * Parse people who have blocked recvqs
+ */
+ do_recvqs();
+
+ /*
+ * Send people their /list replies, being careful
+ * not to fill their sendQ
+ */
+ send_safelists();
+
+ /*
+ * Adjust delay to something reasonable [ad hoc values] (one
+ * might think something more clever here... --msa)
+ * We don't really need to check that often and as long
+ * as we don't delay too long, everything should be ok.
+ * waiting too long can cause things to timeout...
+ * i.e. PINGS -> a disconnection :(
+ * - avalon
+ */
+ if (delay < 1)
+ delay = 1;
+ else
+ {
+ /* We need to get back here to do that recvq thing */
+ if(recvq_clients != NULL)
+ delay = 1;
+ else
+ delay = MIN(delay, TIMESEC);
+ }
+
+ engine_read_message(delay); /* check everything! */
+
+ /*
+ * * ...perhaps should not do these loops every time, but only if
+ * there is some chance of something happening (but, note that
+ * conf->hold times may be changed elsewhere--so precomputed next
+ * event time might be too far away... (similarly with ping
+ * times) --msa
+ */
+
+ if ((timeofday >= nextping))
+ nextping = check_pings(timeofday);
+
+#ifdef PROFILING
+ if (profiling_newmsg)
+ {
+ sendto_realops("PROFILING: %s", profiling_msg);
+ profiling_newmsg = 0;
+ }
+#endif
+
+ if (dorehash)
+ {
+ (void) rehash(&me, &me, 1);
+ (void) read_motd(MOTD);
+ dorehash = 0;
+ }
+ /*
+ *
+ * Flush output buffers on all connections now if they
+ * have data in them (or at least try to flush) -avalon
+ *
+ * flush_connections(me.fd);
+ *
+ * avalon, what kind of crack have you been smoking? why
+ * on earth would we flush_connections blindly when
+ * we already check to see if we can write (and do)
+ * in read_message? There is no point, as this causes
+ * lots and lots of unnecessary sendto's which
+ * 99% of the time will fail because if we couldn't
+ * empty them in read_message we can't empty them here.
+ * one effect: during htm, output to normal lusers
+ * will lag.
+ * htm doesnt exist anymore, but this comment was funny, so i
+ * left it in. -epi
+ */
+
+ /* Now we've made this call a bit smarter. */
+ /* Only flush non-blocked sockets. */
+
+ flush_connections(me.fd);
+
+#ifdef LOCKFILE
+ /*
+ * * If we have pending klines and CHECK_PENDING_KLINES minutes
+ * have passed, try writing them out. -ThemBones
+ */
+
+ if ((pending_klines) && ((timeofday - pending_kline_time)
+ >= (CHECK_PENDING_KLINES * 60)))
+ do_pending_klines();
+#endif
+ }
+}
+
+/*
+ * open_debugfile
+ *
+ * If the -t option is not given on the command line when the server is
+ * started, all debugging output is sent to the file set by LPATH in
+ * config.h Here we just open that file and make sure it is opened to
+ * fd 2 so that any fprintf's to stderr also goto the logfile. If the
+ * debuglevel is not set from the command line by -x, use /dev/null as
+ * the dummy logfile as long as DEBUGMODE has been defined, else dont
+ * waste the fd.
+ */
+static void open_debugfile()
+{
+#ifdef DEBUGMODE
+ int fd;
+ aClient *cptr;
+
+ if (debuglevel >= 0)
+ {
+ cptr = make_client(NULL, NULL);
+ cptr->fd = 2;
+ SetLog(cptr);
+ cptr->port = debuglevel;
+ cptr->flags = 0;
+ /*XXX cptr->acpt = cptr; */
+ local[2] = cptr;
+ (void) strcpy(cptr->sockhost, me.sockhost);
+
+ (void) printf("isatty = %d ttyname = %#x\n",
+ isatty(2), (u_int) ttyname(2));
+ if (!(bootopt & BOOT_TTY)) /* leave debugging output on fd */
+ {
+ (void) truncate(LOGFILE, 0);
+ if ((fd = open(LOGFILE, O_WRONLY | O_CREAT, 0600)) < 0)
+ if ((fd = open("/dev/null", O_WRONLY)) < 0)
+ exit(-1);
+ if (fd != 2)
+ {
+ (void) dup2(fd, 2);
+ (void) close(fd);
+ }
+ strncpyzt(cptr->name, LOGFILE, sizeof(cptr->name));
+ }
+ else if (isatty(2) && ttyname(2))
+ strncpyzt(cptr->name, ttyname(2), sizeof(cptr->name));
+ else
+ (void) strcpy(cptr->name, "FD2-Pipe");
+ Debug((DEBUG_FATAL, "Debug: File <%s> Level: %d at %s",
+ cptr->name, cptr->port, myctime(time(NULL))));
+ }
+ else
+ local[2] = NULL;
+#endif
+ return;
+}
+
+static void setup_signals()
+{
+ struct sigaction act;
+
+ act.sa_handler = SIG_IGN;
+ act.sa_flags = 0;
+ (void) sigemptyset(&act.sa_mask);
+ (void) sigaddset(&act.sa_mask, SIGPIPE);
+ (void) sigaddset(&act.sa_mask, SIGALRM);
+# ifdef SIGWINCH
+ (void) sigaddset(&act.sa_mask, SIGWINCH);
+ (void) sigaction(SIGWINCH, &act, NULL);
+# endif
+ (void) sigaction(SIGPIPE, &act, NULL);
+ act.sa_handler = dummy;
+ (void) sigaction(SIGALRM, &act, NULL);
+ act.sa_handler = s_rehash;
+ (void) sigemptyset(&act.sa_mask);
+ (void) sigaddset(&act.sa_mask, SIGHUP);
+ (void) sigaction(SIGHUP, &act, NULL);
+ act.sa_handler = s_restart;
+ (void) sigaddset(&act.sa_mask, SIGINT);
+ (void) sigaction(SIGINT, &act, NULL);
+ act.sa_handler = s_die;
+ (void) sigaddset(&act.sa_mask, SIGTERM);
+ (void) sigaction(SIGTERM, &act, NULL);
+
+#ifdef RESTARTING_SYSTEMCALLS
+ /*
+ * * At least on Apollo sr10.1 it seems continuing system calls
+ * after signal is the default. The following 'siginterrupt'
+ * should change that default to interrupting calls.
+ */
+ (void) siginterrupt(SIGALRM, 1);
+#endif
+}
+
+void build_version(void)
+{
+ char *s=PATCHES;
+ ircsprintf(version, "%s-%.1d.%.1d(%.2d)%s", BASENAME,
+ MAJOR, MINOR, PATCH, (*s != 0 ? PATCHES : ""));
+}
--- /dev/null
+#include "ircsprintf.h"
+
+char num[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+char itoa_tab[10] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
+char xtoa_tab[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f' };
+char nullstring[]="(null)";
+
+#ifdef WANT_SNPRINTF
+inline int irc_printf(char *str, size_t size, const char *pattern, va_list vl)
+#else
+inline int irc_printf(char *str, const char *pattern, va_list vl)
+#endif
+{
+ char *s;
+ char *buf=str;
+ const char *format=pattern;
+ unsigned long i, u;
+ int len=0;
+ va_list ap;
+ VA_COPY(ap, vl);
+
+#ifdef WANT_SNPRINTF
+ if(!size)
+ {
+#endif
+ while(*format)
+ {
+ u = 0;
+ switch(*format)
+ {
+ case '%':
+ format++;
+ switch(*format)
+ {
+ case 's': /* most popular ;) */
+ s=va_arg(ap, char *);
+ while(*s)
+ buf[len++]=*s++;
+ format++;
+ break;
+ case 'u':
+ format--; /* falls through and is caught below */
+ case 'l':
+ if (*(format+1) == 'u')
+ {
+ u=1;
+ format++;
+ }
+ else if (*(format+1) == 'd')
+ {
+ u=0;
+ format++;
+ }
+ else
+ u=0;
+ /* fallthrough */
+ case 'd':
+ case 'i':
+ i=va_arg(ap, unsigned long);
+ if(!u)
+ if(i&0x80000000)
+ {
+ buf[len++]='-'; /* it's negative.. */
+ i = 0x80000000 - (i & ~0x80000000);
+ }
+ s=&num[11];
+ do
+ {
+ *--s=itoa_tab[i%10];
+ i/=10;
+ } while(i!=0);
+ while(*s)
+ buf[len++]=*s++;
+ format++;
+ break;
+ case 'n':
+ /* oo, sneaky...it really is just a long, though! */
+ case 'x':
+ case 'X':
+ i=va_arg(ap, long);
+ buf[len++]='0';
+ buf[len++]='x';
+ s=&num[11];
+ do
+ {
+ *--s=xtoa_tab[i%16];
+ i/=16;
+ } while(i!=0);
+ while(*s)
+ buf[len++]=*s++;
+ format++;
+ break;
+ case 'c':
+ buf[len++]= (char) va_arg(ap, int);
+ format++;
+ break;
+ default:
+ /* yick, unknown type...default to returning what our
+ s[n]printf friend would */
+ return vsprintf(str, pattern, vl);
+ break;
+ }
+ break;
+ default:
+ buf[len++]=*format++;
+ break;
+ }
+ }
+ buf[len]=0;
+ return len;
+#ifdef WANT_SNPRINTF
+ }
+ else
+ {
+ while(*format && len<size)
+ {
+ u = 0;
+ switch(*format)
+ {
+ case '%':
+ format++;
+ switch(*format)
+ {
+ case 's': /* most popular ;) */
+ s=va_arg(ap, char *);
+ if(s==NULL)
+ s=nullstring;
+ while(*s && len<size)
+ buf[len++]=*s++;
+ format++;
+ break;
+ case 'u':
+ format--; /* now fall through and it's caught, cool */
+ case 'l':
+ if (*(format+1) == 'u')
+ {
+ u=1;
+ format++;
+ }
+ else if (*(format+1) == 'd')
+ {
+ u=0;
+ format++;
+ }
+ else
+ u=0;
+ /* fallthrough */
+ case 'd':
+ case 'i':
+ i=va_arg(ap, unsigned long);
+ if(!u)
+ if(i&0x80000000)
+ {
+ buf[len++]='-'; /* it's negative.. */
+ i = 0x80000000 - (i & ~0x80000000);
+ }
+ s=&num[11];
+ do
+ {
+ *--s=itoa_tab[i%10];
+ i/=10;
+ } while(i!=0);
+ while(*s && len<size)
+ buf[len++]=*s++;
+ format++;
+ break;
+ case 'n':
+ /* oo, sneaky...it really is just a long, though! */
+ case 'x':
+ case 'X':
+ i=va_arg(ap, long);
+ buf[len++]='0';
+ if(len<size)
+ buf[len++]='x';
+ else
+ break;
+ s=&num[11];
+ do
+ {
+ *--s=xtoa_tab[i%16];
+ i/=16;
+ } while(i!=0);
+ while(*s && len<size)
+ buf[len++]=*s++;
+ format++;
+ break;
+ case 'c':
+ buf[len++]= (char) va_arg(ap, int);
+ format++;
+ break;
+ default:
+ /* yick, unknown type...default to returning what our
+ s[n]printf friend would */
+ return vsnprintf(str, size, pattern, vl);
+ break;
+ }
+ break;
+ default:
+ buf[len++]=*format++;
+ break;
+ }
+ }
+ buf[len]=0;
+ return len;
+ }
+#endif /* WANT_SNPRINTF */
+}
+
+int ircsprintf(char *str, const char *format, ...)
+{
+ int ret;
+ va_list vl;
+ va_start(vl, format);
+#ifdef WANT_SNPRINTF
+ ret=irc_printf(str, 0, format, vl);
+#else
+ ret=irc_printf(str, format, vl);
+#endif
+ va_end(vl);
+ return ret;
+}
+
+#ifdef WANT_SNPRINTF
+int ircsnprintf(char *str, size_t size, const char *format, ...)
+{
+ int ret;
+ va_list vl;
+ va_start(vl, format);
+ ret=irc_printf(str, size, format, vl);
+ va_end(vl);
+ return ret;
+}
+#endif
+
+int ircvsprintf(char *str, const char *format, va_list ap)
+{
+ int ret;
+#ifdef WANT_SNPRINTF
+ ret=irc_printf(str, 0, format, ap);
+#else
+ ret=irc_printf(str, format, ap);
+#endif
+ return ret;
+}
+
+#ifdef WANT_SNPRINTF
+int ircvsnprintf(char *str, size_t size, const char *format, va_list ap)
+{
+ int ret;
+ ret=irc_printf(str, size, format, ap);
+ return ret;
+}
+#endif
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/list.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Finland
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: list.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include "numeric.h"
+#include "blalloc.h"
+#include "dh.h"
+#include "zlink.h"
+
+extern int BlockHeapGarbageCollect(BlockHeap *);
+
+/* locally defined functions */
+
+/*
+ * re-written to use Wohali (joant@cadence.com) block allocator
+ * routines. very nicely done Wohali
+ *
+ * -Dianora
+ *
+ * Number of Link's to pre-allocate at a time for Efnet 1000 seems
+ * reasonable, for smaller nets who knows? -Dianora
+ */
+
+#define LINK_PREALLOCATE 1024
+#define DLINK_PREALLOCATE 128
+#define CHANMEMBER_PREALLOCATE 1024
+/*
+ * Number of aClient structures to preallocate at a time for Efnet 1024
+ * is reasonable for smaller nets who knows? -Dianora
+ * This means you call MyMalloc 30 some odd times, rather than 30k
+ * times -Dianora
+ */
+
+#define CLIENTS_PREALLOCATE 1024
+#if CLIENTS_PREALLOCATE > MAXCONNECTIONS
+#undef CLIENTS_PREALLOCATE
+#define CLIENTS_PREALLOCATE MAXCONNECTIONS
+#endif
+
+/* Number of channels to allocate per block, 1024 sounds nice. */
+
+#define CHANNELS_PREALLOCATE 1024
+
+void outofmemory();
+
+int numclients = 0;
+
+/* for jolo's block allocator */
+BlockHeap *free_local_aClients;
+BlockHeap *free_Links;
+BlockHeap *free_DLinks;
+BlockHeap *free_chanMembers;
+BlockHeap *free_remote_aClients;
+BlockHeap *free_anUsers;
+BlockHeap *free_channels;
+
+#ifdef FLUD
+BlockHeap *free_fludbots;
+
+#endif /* FLUD */
+
+void initlists()
+{
+ /* Might want to bump up LINK_PREALLOCATE if FLUD is defined */
+ free_Links = BlockHeapCreate((size_t) sizeof(Link), LINK_PREALLOCATE);
+ free_DLinks = BlockHeapCreate((size_t) sizeof(DLink), DLINK_PREALLOCATE);
+ free_chanMembers = BlockHeapCreate((size_t) sizeof(chanMember),
+ CHANMEMBER_PREALLOCATE);
+
+ /*
+ * start off with CLIENTS_PREALLOCATE for now... on typical efnet
+ * these days, it can get up to 35k allocated
+ */
+
+ free_remote_aClients =
+ BlockHeapCreate((size_t) CLIENT_REMOTE_SIZE, CLIENTS_PREALLOCATE);
+
+ /* Can't EVER have more than MAXCONNECTIONS number of local aClients
+ * And that was stupid, because an idle server built for 32k would use
+ * 50 megs of ram.
+ */
+
+ free_local_aClients = BlockHeapCreate((size_t) CLIENT_LOCAL_SIZE,
+ CLIENTS_PREALLOCATE);
+ /* anUser structs are used by both local aClients, and remote aClients */
+
+ free_anUsers = BlockHeapCreate((size_t) sizeof(anUser),
+ CLIENTS_PREALLOCATE * 2);
+
+ /* channels are a very frequent thing in ircd. :) */
+
+ free_channels = BlockHeapCreate((size_t) sizeof(aChannel),
+ CHANNELS_PREALLOCATE);
+
+
+#ifdef FLUD
+ /* fludbot structs are used to track CTCP Flooders */
+ free_fludbots = BlockHeapCreate((size_t) sizeof(struct fludbot),
+ CLIENTS_PREALLOCATE);
+
+#endif /* FLUD */
+}
+
+/*
+ * outofmemory()
+ *
+ * input - NONE output - NONE side effects -
+ * simply try to report there is a problem I free all the memory in the
+ * kline lists hoping to free enough memory so that a proper report can
+ * be made. If I was already here (was_here) then I got called twice,
+ * and more drastic measures are in order. I'll try to just abort() at
+ * least. -Dianora
+ */
+
+void outofmemory()
+{
+ static int was_here = 0;
+
+ if (was_here)
+ abort();
+
+ was_here = YES;
+
+ Debug((DEBUG_FATAL, "Out of memory: restarting server..."));
+ restart("Out of Memory");
+}
+
+/*
+ * Create a new aClient structure and set it to initial state. *
+ *
+ * from == NULL, create local client (a client connected *
+ * o a socket). *
+ *
+ * from, create remote client (behind a socket *
+ * ssociated with the client defined by *
+ * ('from' is a local client!!).
+ *
+ * uplink is this client's uplink connection to the network. - lucas
+ */
+aClient *make_client(aClient *from, aClient *uplink)
+{
+ aClient *cptr = NULL;
+
+ if (!from) /* from is NULL */
+ {
+
+ cptr = BlockHeapALLOC(free_local_aClients, aClient);
+
+ if (cptr == (aClient *) NULL)
+ outofmemory();
+
+ memset((char *) cptr, '\0' ,CLIENT_LOCAL_SIZE);
+
+ /* Note: structure is zero (calloc) */
+ cptr->from = cptr; /* 'from' of local client is self! */
+
+ cptr->status = STAT_UNKNOWN;
+ cptr->fd = -2;
+ cptr->uplink = uplink;
+ strcpy(cptr->username, "unknown");
+ cptr->since = cptr->lasttime = cptr->firsttime = timeofday;
+ cptr->sockerr = -1;
+ cptr->authfd = -1;
+ return (cptr);
+ }
+ else /* from is not NULL */
+ {
+ cptr = BlockHeapALLOC(free_remote_aClients, aClient);
+
+ if (cptr == (aClient *) NULL)
+ outofmemory();
+
+ memset((char *) cptr, '\0', CLIENT_REMOTE_SIZE);
+
+ /* Note: structure is zero (calloc) */
+ cptr->from = from;
+ cptr->status = STAT_UNKNOWN;
+ cptr->fd = -1;
+ cptr->uplink = uplink;
+ return (cptr);
+ }
+}
+
+void free_client(aClient *cptr)
+{
+ int retval = 0;
+
+ if (cptr->fd == -2)
+ {
+ retval = BlockHeapFree(free_local_aClients, cptr);
+ }
+ else
+ {
+ retval = BlockHeapFree(free_remote_aClients, cptr);
+ }
+ if (retval)
+ {
+ /*
+ * Looks unprofessional maybe, but I am going to leave this
+ * sendto_ops in it should never happen, and if it does, the
+ * hybrid team wants to hear about it
+ */
+ sendto_ops("list.c couldn't BlockHeapFree(free_remote_aClients,cptr) "
+ "cptr = %lX", cptr);
+ sendto_ops("Please report to the bahamut team! "
+ "coders@dal.net");
+ abort();
+#if defined(USE_SYSLOG) && defined(SYSLOG_BLOCK_ALLOCATOR)
+ syslog(LOG_DEBUG, "list.c couldn't "
+ "BlockHeapFree(free_remote_aClients,cptr) cptr = %lX", cptr);
+#endif
+ }
+}
+
+/*
+ * make_channel() free_channel()
+ * functions to maintain blockheap of channels.
+ */
+
+aChannel *make_channel()
+{
+ aChannel *chan;
+
+ chan = BlockHeapALLOC(free_channels, aChannel);
+
+ if(chan == NULL)
+ outofmemory();
+
+ memset((char *)chan, '\0', sizeof(aChannel));
+
+ return chan;
+}
+
+void free_channel(aChannel *chan)
+{
+ if (BlockHeapFree(free_channels, chan)) {
+ sendto_ops("list.c couldn't BlockHeapFree(free_channels,chan) "
+ "chan = %lX", chan);
+ sendto_ops("Please report to the bahamut team!");
+ }
+}
+
+/*
+ * * 'make_user' add's an User information block to a client * if it
+ * was not previously allocated.
+ */
+anUser *make_user(aClient *cptr)
+{
+ anUser *user;
+
+ user = cptr->user;
+ if (!user)
+ {
+ user = BlockHeapALLOC(free_anUsers, anUser);
+
+ if (user == (anUser *) NULL)
+ outofmemory();
+
+ memset(user, 0, sizeof(anUser));
+ cptr->user = user;
+ }
+ return user;
+}
+
+aServer *make_server(aClient *cptr)
+{
+ aServer *serv = cptr->serv;
+
+ if (!serv)
+ {
+ serv = (aServer *) MyMalloc(sizeof(aServer));
+
+ memset(serv, 0, sizeof(aServer));
+ cptr->serv = serv;
+ }
+ return cptr->serv;
+}
+
+/*
+ * free_user
+ * Decrease user reference count by one and release block,
+ * if count reaches 0
+ */
+void free_user(anUser *user, aClient *cptr)
+{
+ if (user->away)
+ MyFree(user->away);
+#if (RIDICULOUS_PARANOIA_LEVEL>=1)
+ if (user->real_oper_host)
+ MyFree(user->real_oper_host);
+ if (user->real_oper_username)
+ MyFree(user->real_oper_username);
+ if (user->real_oper_ip)
+ MyFree(user->real_oper_ip);
+#endif
+ /* sanity check */
+ if (user->joined || user->invited || user->channel)
+ sendto_ops("* %#x user (%s!%s@%s) %#x %#x %#x %d *",
+ cptr, cptr ? cptr->name : "<noname>",
+ user->username, user->host, user,
+ user->invited, user->channel, user->joined);
+
+ if (BlockHeapFree(free_anUsers, user))
+ {
+ sendto_ops("list.c couldn't BlockHeapFree(free_anUsers,user) "
+ "user = %lX", user);
+ sendto_ops("Please report to the bahamut team! "
+ "bahamut-bugs@bahamut.net");
+#if defined(USE_SYSLOG) && defined(SYSLOG_BLOCK_ALLOCATOR)
+ syslog(LOG_DEBUG, "list.c couldn't BlockHeapFree(free_anUsers,user) "
+ "user = %lX", user);
+#endif
+ }
+}
+
+/* taken the code from ExitOneClient() for this and placed it here. - avalon */
+void remove_client_from_list(aClient *cptr)
+{
+ if (IsServer(cptr))
+ Count.server--;
+ else if (IsClient(cptr))
+ {
+ Count.total--;
+ if (IsAnOper(cptr))
+ Count.oper--;
+ if (IsInvisible(cptr))
+ Count.invisi--;
+ }
+ if (cptr->prev)
+ cptr->prev->next = cptr->next;
+ else
+ {
+ client = cptr->next;
+ client->prev = NULL;
+ }
+ if (cptr->next)
+ cptr->next->prev = cptr->prev;
+
+ if (IsPerson(cptr) && cptr->user)
+ {
+ add_history(cptr, 0);
+ off_history(cptr);
+ }
+
+#ifdef FLUD
+ if (MyFludConnect(cptr))
+ free_fluders(cptr, NULL);
+ free_fludees(cptr);
+#endif
+
+ if (cptr->user)
+ free_user(cptr->user, cptr); /* try this here */
+ if (cptr->serv)
+ {
+#ifdef HAVE_ENCRYPTION_ON
+ if(cptr->serv->sessioninfo_in)
+ dh_end_session(cptr->serv->sessioninfo_in);
+ if(cptr->serv->sessioninfo_out)
+ dh_end_session(cptr->serv->sessioninfo_out);
+ if(cptr->serv->rc4_in)
+ rc4_destroystate(cptr->serv->rc4_in);
+ if(cptr->serv->rc4_out)
+ rc4_destroystate(cptr->serv->rc4_out);
+#endif
+ if(cptr->serv->zip_in)
+ zip_destroy_input_session(cptr->serv->zip_in);
+ if(cptr->serv->zip_out)
+ zip_destroy_output_session(cptr->serv->zip_out);
+ MyFree(cptr->serv);
+ }
+
+ free_client(cptr);
+ return;
+}
+
+/*
+ * although only a small routine, it appears in a number of places as a
+ * collection of a few lines...functions like this *should* be in this
+ * file, shouldnt they ? after all, this is list.c, isnt it ? -avalon
+ */
+void add_client_to_list(aClient *cptr)
+{
+ /*
+ * since we always insert new clients to the top of the list, this
+ * should mean the "me" is the bottom most item in the list.
+ */
+ cptr->next = client;
+ client = cptr;
+ if (cptr->next)
+ cptr->next->prev = cptr;
+ return;
+}
+
+/* Look for ptr in the linked listed pointed to by link. */
+chanMember *find_user_member(chanMember *cm, aClient *ptr)
+{
+ if (ptr)
+ while (cm)
+ {
+ if (cm->cptr == ptr)
+ return (cm);
+ cm = cm->next;
+ }
+ return ((chanMember *) NULL);
+}
+
+Link *find_channel_link(Link *lp, aChannel *chptr)
+{
+ if (chptr)
+ for (; lp; lp = lp->next)
+ if (lp->value.chptr == chptr)
+ return lp;
+ return ((Link *) NULL);
+}
+
+/*
+ * Look for a match in a list of strings. Go through the list, and run
+ * match() on it. Side effect: if found, this link is moved to the top of
+ * the list.
+ */
+Link *find_str_link(Link *lp, char *charptr)
+{
+ if (!charptr)
+ return ((Link *)NULL);
+ while(lp!=NULL)
+ {
+ if(!match(lp->value.cp, charptr))
+ return lp;
+ lp=lp->next;
+ }
+ return ((Link *)NULL);
+}
+
+Link *make_link()
+{
+ Link *lp;
+ lp = BlockHeapALLOC(free_Links, Link);
+
+ if (lp == (Link *) NULL)
+ outofmemory();
+
+ lp->next = (Link *) NULL; /* just to be paranoid... */
+
+ return lp;
+}
+
+void free_link(Link *lp)
+{
+ if (BlockHeapFree(free_Links, lp)) {
+ sendto_ops("list.c couldn't BlockHeapFree(free_Links,lp) lp = %lX",
+ lp);
+ sendto_ops("Please report to the bahamut team!");
+ }
+}
+
+DLink *make_dlink()
+{
+ DLink *lp;
+ lp = BlockHeapALLOC(free_DLinks, DLink);
+
+ if (lp == (DLink *) NULL)
+ outofmemory();
+
+ lp->next = (DLink *) NULL; /* just to be paranoid... */
+ lp->prev = (DLink *) NULL; /* just to be paranoid... */
+
+ return lp;
+}
+
+void free_dlink(DLink *lp)
+{
+ if (BlockHeapFree(free_DLinks, lp)) {
+ sendto_ops("list.c couldn't BlockHeapFree(free_DLinks,lp) lp = %lX",
+ lp);
+ sendto_ops("Please report to the bahamut team!");
+ }
+}
+
+chanMember *make_chanmember() {
+ chanMember *mp;
+ mp = BlockHeapALLOC(free_chanMembers, chanMember);
+
+ if (mp == (chanMember *) NULL)
+ outofmemory();
+
+ return mp;
+}
+
+void free_chanmember(chanMember *mp)
+{
+ if (BlockHeapFree(free_chanMembers, mp)) {
+ sendto_ops("list.c couldn't BlockHeapFree(free_chanMembers,mp) "
+ "mp = %lX", mp);
+ sendto_ops("Please report to the bahamut team!");
+ }
+}
+
+aClass *make_class()
+{
+ aClass *tmp;
+
+ tmp = (aClass *) MyMalloc(sizeof(aClass));
+ memset((char *) tmp, '\0', sizeof(aClass));
+ return tmp;
+}
+
+aOper *make_oper()
+{
+ aOper *i;
+ i = (struct Conf_Oper *) MyMalloc(sizeof(aOper));
+ memset((char *) i, '\0', sizeof(aOper));
+ return i;
+}
+
+aConnect *make_connect()
+{
+ aConnect *i;
+ i = (struct Conf_Connect *) MyMalloc(sizeof(aConnect));
+ memset((char *) i, '\0', sizeof(aConnect));
+ return i;
+}
+
+aAllow *make_allow()
+{
+ aAllow *i;
+ i = (struct Conf_Allow *) MyMalloc(sizeof(aAllow));
+ memset((char *) i, '\0', sizeof(aAllow));
+ return i;
+}
+
+aPort *make_port()
+{
+ aPort *i;
+ i = (struct Conf_Port *) MyMalloc(sizeof(aPort));
+ memset((char *) i, '\0', sizeof(aPort));
+ return i;
+}
+
+Conf_Me *make_me()
+{
+ Conf_Me *i;
+ i = (struct Conf_Me *) MyMalloc(sizeof(Conf_Me));
+ memset((char *) i, '\0', sizeof(Conf_Me));
+ return i;
+}
+
+/*
+ * Attempt to free up some block memory
+ *
+ * list_garbage_collect
+ *
+ * inputs - NONE output - NONE side effects -
+ * memory is possibly freed up
+ */
+
+void block_garbage_collect()
+{
+ BlockHeapGarbageCollect(free_Links);
+ BlockHeapGarbageCollect(free_chanMembers);
+ BlockHeapGarbageCollect(free_local_aClients);
+ BlockHeapGarbageCollect(free_remote_aClients);
+ BlockHeapGarbageCollect(free_anUsers);
+ BlockHeapGarbageCollect(free_channels);
+#ifdef FLUD
+ BlockHeapGarbageCollect(free_fludbots);
+#endif
+}
--- /dev/null
+/* m_nick.c - Because s_user.c was just crazy.
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free softwmare; 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 1, 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.
+ */
+
+/* $Id: m_nick.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "msg.h"
+#include "channel.h"
+#include <sys/stat.h>
+#include <utmp.h>
+#include <fcntl.h>
+#include "h.h"
+#include "userban.h"
+
+extern int do_user(char *, aClient *, aClient *, char *, char *, char *,
+ unsigned long, unsigned int, char *);
+
+extern int register_user(aClient *, aClient *, char *, char *);
+
+
+extern int user_modes[];
+
+/*
+ * * 'do_nick_name' ensures that the given parameter (nick) is * really
+ * a proper string for a nickname (note, the 'nick' * may be modified
+ * in the process...) *
+ *
+ * RETURNS the length of the final NICKNAME (0, if *
+ * nickname is illegal) *
+ *
+ * Nickname characters are in range * 'A'..'}', '_', '-', '0'..'9' *
+ * anything outside the above set will terminate nickname. * In
+ * addition, the first character cannot be '-' * or a Digit. *
+ *
+ * Note: * '~'-character should be allowed, but * a change should
+ * be global, some confusion would * result if only few servers
+ * allowed it...
+ */
+
+static int do_nick_name(char *nick) {
+ char *ch;
+
+ if (*nick == '-' || IsDigit(*nick)) /* first character is [0..9-] */
+ return 0;
+
+ for (ch = nick; *ch && (ch - nick) < NICKLEN; ch++)
+ if (!isvalid(*ch) || IsSpace(*ch))
+ break;
+
+ *ch = '\0';
+
+ return (ch - nick);
+}
+
+/*
+ * m_nick
+ * parv[0] = sender prefix
+ * parv[1] = nickname
+ * parv[2] = hopcount when new user; TS when nick change
+ * parv[3] = TS
+ * ---- new user only below ----
+ * parv[4] = umode
+ * parv[5] = username
+ * parv[6] = hostname
+ * parv[7] = server
+ * parv[8] = serviceid
+ * parv[9] = IP
+ * parv[10] = ircname
+ * -- endif
+ */
+int m_nick(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ struct simBan *ban;
+ aClient *acptr, *uplink;
+ Link *lp;
+ char nick[NICKLEN + 2];
+ ts_val newts = 0;
+ int sameuser = 0, samenick = 0;
+
+ if (parc < 2)
+ {
+ sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN),
+ me.name, parv[0]);
+ return 0;
+ }
+
+ if (!IsServer(sptr) && IsServer(cptr) && parc > 2)
+ newts = atol(parv[2]);
+ else if (IsServer(sptr) && parc > 3)
+ newts = atol(parv[3]);
+ else
+ parc = 2;
+ /*
+ * parc == 2 on a normal client sign on (local) and a normal client
+ * nick change
+ * parc == 4 on a normal server-to-server client nick change
+ * parc == 11 on a normal TS style server-to-server NICK introduction
+ */
+ if ((IsServer(sptr) || (parc > 4)) && (parc < 11))
+ {
+ /*
+ * We got the wrong number of params. Someone is trying to trick
+ * us. Kill it. -ThemBones As discussed with ThemBones, not much
+ * point to this code now sending a whack of global kills would
+ * also be more annoying then its worth, just note the problem,
+ * and continue -Dianora
+ */
+ sendto_realops("IGNORING BAD NICK: %s[%s@%s] on %s (from %s)", parv[1],
+ (parc >= 6) ? parv[5] : "-",
+ (parc >= 7) ? parv[6] : "-",
+ (parc >= 8) ? parv[7] : "-", parv[0]);
+ return 0;
+
+ }
+
+ strncpyzt(nick, parv[1], NICKLEN + 1);
+ /*
+ * if do_nick_name() returns a null name OR if the server sent a
+ * nick name and do_nick_name() changed it in some way (due to rules
+ * of nick creation) then reject it. If from a server and we reject
+ * it, and KILL it. -avalon 4/4/92
+ */
+ if (do_nick_name(nick) == 0 || (IsServer(cptr) && strcmp(nick, parv[1])))
+ {
+ sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME),
+ me.name, parv[0], parv[1], "Erroneous Nickname");
+
+ if (IsServer(cptr))
+ {
+ ircstp->is_kill++;
+ sendto_realops_lev(DEBUG_LEV, "Bad Nick: %s From: %s %s",
+ parv[1], parv[0],
+ get_client_name(cptr, FALSE));
+ sendto_one(cptr, ":%s KILL %s :%s (Bad Nick)",
+ me.name, parv[1], me.name);
+ if (sptr != cptr) { /* bad nick change */
+ sendto_serv_butone(cptr, ":%s KILL %s :%s (Bad Nick)", me.name,
+ parv[0], me.name);
+ sptr->flags |= FLAGS_KILLED;
+ return exit_client(cptr, sptr, &me, "BadNick");
+ }
+ }
+ return 0;
+ }
+ /*
+ * Check against nick name collisions.
+ *
+ * Put this 'if' here so that the nesting goes nicely on the screen
+ * :) We check against server name list before determining if the
+ * nickname is present in the nicklist (due to the way the below
+ * for loop is constructed). -avalon
+ */
+ do
+ {
+ if ((acptr = find_server(nick, NULL)))
+ if (MyConnect(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name,
+ BadPtr(parv[0]) ? "*" : parv[0], nick);
+ return 0;
+ }
+
+ /*
+ * acptr already has result from find_server
+ * Well. unless we have a capricious server on the net, a nick can
+ * never be the same as a server name - Dianora
+ * That's not the only case; maybe someone broke do_nick_name
+ * or changed it so they could use "." in nicks on their network
+ * - sedition
+ */
+
+ if (acptr)
+ {
+ /*
+ * We have a nickname trying to use the same name as a
+ * server. Send out a nick collision KILL to remove the
+ * nickname. As long as only a KILL is sent out, there is no
+ * danger of the server being disconnected. Ultimate way to
+ * jupiter a nick ? >;-). -avalon
+ */
+ sendto_realops_lev(SKILL_LEV, "Nick collision on %s", sptr->name);
+ ircstp->is_kill++;
+ sendto_one(cptr, ":%s KILL %s :%s (Nick Collision)", me.name,
+ sptr->name, me.name);
+ sptr->flags |= FLAGS_KILLED;
+ return exit_client(cptr, sptr, &me, "Nick/Server collision");
+ }
+
+ if (!(acptr = find_client(nick, NULL)))
+ break;
+
+ /*
+ * If acptr == sptr, then we have a client doing a nick change
+ * between *equivalent* nicknames as far as server is concerned
+ * (user is changing the case of his/her nickname or somesuch)
+ */
+ if (acptr == sptr)
+ {
+ if (strcmp(acptr->name, nick) == 0)
+ return 0;
+ else
+ break;
+ } /* If user is changing nick to itself no point in propogating */
+
+ /*
+ * Note: From this point forward it can be assumed that acptr !=
+ * sptr (point to different client structures).
+ *
+ * If the older one is "non-person", the new entry is just
+ * allowed to overwrite it. Just silently drop non-person, and
+ * proceed with the nick. This should take care of the "dormant
+ * nick" way of generating collisions...
+ */
+ if (IsUnknown(acptr))
+ {
+ if (MyConnect(acptr))
+ {
+ exit_client(NULL, acptr, &me, "Overridden");
+ break;
+ }
+ else if (!(acptr->user))
+ {
+ sendto_realops_lev(SKILL_LEV, "Nick Collision on %s", parv[1]);
+ sendto_serv_butone(NULL, ":%s KILL %s :%s (Nick Collision)",
+ me.name, acptr->name, me.name);
+ acptr->flags |= FLAGS_KILLED;
+ /* Having no USER struct should be ok... */
+ return exit_client(cptr, acptr, &me,
+ "Got TS NICK before Non-TS USER");
+ }
+ }
+
+ if (!IsServer(cptr))
+ {
+ /*
+ * NICK is coming from local client connection. Just send
+ * error reply and ignore the command.
+ * parv[0] is empty on connecting clients
+ */
+ sendto_one(sptr, err_str(ERR_NICKNAMEINUSE),
+ me.name, BadPtr(parv[0]) ? "*" : parv[0], nick);
+ return 0;
+ }
+ /*
+ * NICK was coming from a server connection. Means that the same
+ * nick is registered for different users by different server.
+ * This is either a race condition (two users coming online about
+ * same time, or net reconnecting) or just two net fragments
+ * becoming joined and having same nicks in use. We cannot have
+ * TWO users with same nick--purge this NICK from the system with
+ * a KILL... >;)
+ *
+ * Changed to something reasonable like IsServer(sptr) (true if
+ * "NICK new", false if ":old NICK new") -orabidoo
+ */
+
+ if (IsServer(sptr))
+ {
+ /*
+ * A new NICK being introduced by a neighbouring server (e.g.
+ * message type "NICK new" received)
+ */
+ if (!newts || !acptr->tsinfo || (newts == acptr->tsinfo))
+ {
+ sendto_realops_lev(SKILL_LEV, "Nick collision on %s", parv[1]);
+ ircstp->is_kill++;
+ sendto_one(acptr, err_str(ERR_NICKCOLLISION),
+ me.name, acptr->name, acptr->name);
+ sendto_serv_butone(NULL, ":%s KILL %s :%s (Nick Collision)",
+ me.name, acptr->name, me.name);
+ acptr->flags |= FLAGS_KILLED;
+ return exit_client(cptr, acptr, &me, "Nick collision");
+ }
+ else
+ {
+ /* XXX This looks messed up to me XXX - Raist */
+ sameuser = (acptr->user) &&
+ mycmp(acptr->user->username, parv[5]) == 0 &&
+ mycmp(acptr->user->host, parv[6]) == 0;
+ if ((sameuser && newts < acptr->tsinfo) ||
+ (!sameuser && newts > acptr->tsinfo))
+ {
+ return 0;
+ }
+ else
+ {
+ sendto_realops_lev(SKILL_LEV, "Nick collision on %s",parv[1]);
+ ircstp->is_kill++;
+ sendto_one(acptr, err_str(ERR_NICKCOLLISION),
+ me.name, acptr->name, acptr->name);
+ sendto_serv_butone(sptr, ":%s KILL %s :%s (Nick Collision)",
+ me.name, acptr->name, me.name);
+ acptr->flags |= FLAGS_KILLED;
+ (void) exit_client(cptr, acptr, &me, "Nick collision");
+ break;
+ }
+ }
+ }
+ /*
+ * * A NICK change has collided (e.g. message type * ":old NICK
+ * new". This requires more complex cleanout. * Both clients must be
+ * purged from this server, the "new" * must be killed from the
+ * incoming connection, and "old" must * be purged from all outgoing
+ * connections.
+ */
+ if (!newts || !acptr->tsinfo || (newts == acptr->tsinfo) ||
+ !sptr->user)
+ {
+ sendto_realops_lev(SKILL_LEV, "Nick change collision: %s", parv[1]);
+ ircstp->is_kill++;
+ sendto_one(acptr, err_str(ERR_NICKCOLLISION),
+ me.name, acptr->name, acptr->name);
+ sendto_serv_butone(NULL, ":%s KILL %s :%s (Nick Collision)",me.name,
+ sptr->name, me.name);
+ ircstp->is_kill++;
+ sendto_serv_butone(NULL, ":%s KILL %s :%s (Nick Collision)",me.name,
+ acptr->name, me.name);
+ acptr->flags |= FLAGS_KILLED;
+ (void) exit_client(NULL, acptr, &me, "Nick collision(new)");
+ sptr->flags |= FLAGS_KILLED;
+ return exit_client(cptr, sptr, &me, "Nick collision(old)");
+ }
+ else
+ {
+ /* XXX This looks messed up XXX */
+ sameuser = mycmp(acptr->user->username, sptr->user->username) == 0
+ && mycmp(acptr->user->host, sptr->user->host) == 0;
+ if ((sameuser && newts < acptr->tsinfo) ||
+ (!sameuser && newts > acptr->tsinfo)) {
+ if (sameuser)
+ sendto_realops_lev(SKILL_LEV,
+ "Nick change collision from %s to %s",
+ sptr->name, acptr->name);
+ ircstp->is_kill++;
+ sendto_serv_butone(cptr, ":%s KILL %s : %s (Nick Collision)",me.name,
+ sptr->name, me.name);
+ sptr->flags |= FLAGS_KILLED;
+ if (sameuser)
+ return exit_client(cptr, sptr, &me, "Nick collision(old)");
+ else
+ return exit_client(cptr, sptr, &me, "Nick collision(new)");
+ }
+ else
+ {
+ sendto_realops_lev(SKILL_LEV, "Nick collision on %s", acptr->name);
+
+ ircstp->is_kill++;
+ sendto_one(acptr, err_str(ERR_NICKCOLLISION),
+ me.name, acptr->name, acptr->name);
+ sendto_serv_butone(sptr, ":%s KILL %s :%s (Nick Collision)",me.name,
+ acptr->name, me.name);
+ acptr->flags |= FLAGS_KILLED;
+ (void) exit_client(cptr, acptr, &me, "Nick collision");
+ }
+ }
+ } while (0);
+
+ if (IsServer(sptr))
+ {
+ uplink = find_server(parv[7], NULL);
+ if(!uplink)
+ {
+ /* if we can't find the server this nick is on,
+ * complain loudly and ignore it. - lucas */
+ sendto_realops("Remote nick %s on UNKNOWN server %s\n",
+ nick, parv[7]);
+ return 0;
+ }
+ sptr = make_client(cptr, uplink);
+
+ /* If this is on a U: lined server, it's a U: lined client. */
+ if(IsULine(uplink))
+ sptr->flags|=FLAGS_ULINE;
+
+ add_client_to_list(sptr);
+ if (parc > 2)
+ sptr->hopcount = atoi(parv[2]);
+ if (newts)
+ {
+ sptr->tsinfo = newts;
+ }
+ else
+ {
+ newts = sptr->tsinfo = (ts_val) timeofday;
+ ts_warn("Remote nick %s introduced without a TS", nick);
+ }
+ /* copy the nick in place */
+ (void) strcpy(sptr->name, nick);
+ (void) add_to_client_hash_table(nick, sptr);
+ if (parc >= 10)
+ {
+ int *s, flag;
+ char *m;
+
+ /* parse the usermodes -orabidoo */
+ m = &parv[4][1];
+ while (*m)
+ {
+ for (s = user_modes; (flag = *s); s += 2)
+ if (*m == *(s + 1))
+ {
+ if ((flag == UMODE_o) || (flag == UMODE_O))
+ Count.oper++;
+ sptr->umode |= flag & SEND_UMODES;
+ break;
+ }
+ m++;
+ }
+ if (parc==10)
+ {
+ return do_user(nick, cptr, sptr, parv[5], parv[6],
+ parv[7], strtoul(parv[8], NULL, 0), 0, parv[9]);
+ } else if (parc==11)
+ {
+ return do_user(nick, cptr, sptr, parv[5], parv[6], parv[7],
+ strtoul(parv[8], NULL, 0),
+ strtoul(parv[9], NULL, 0), parv[10]);
+ }
+ }
+ }
+ else if (sptr->name[0])
+ {
+ /*
+ * Client just changing his/her nick. If he/she is on a
+ * channel, send note of change to all clients on that channel.
+ * Propagate notice to other servers.
+ */
+ /* if the nickname is different, set the TS */
+ if (mycmp(parv[0], nick))
+ {
+ sptr->tsinfo = newts ? newts : (ts_val) timeofday;
+ }
+#ifdef DONT_CHECK_QLINE_REMOTE
+ if (MyConnect(sptr))
+ {
+#endif
+ if ((ban = check_mask_simbanned(nick, SBAN_NICK)))
+ {
+#ifndef DONT_CHECK_QLINE_REMOTE
+ if (!MyConnect(sptr))
+ sendto_realops("Restricted nick %s from %s on %s", nick,
+ (*sptr->name != 0 && !IsServer(sptr)) ?
+ sptr->name : "<unregistered>",
+ (sptr->user == NULL) ? ((IsServer(sptr)) ?
+ parv[6] : me.name) :
+ sptr->user->server);
+#endif
+
+ if (MyConnect(sptr) && (!IsServer(cptr)) && (!IsOper(cptr))
+ && (!IsULine(sptr)))
+ {
+ sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name,
+ BadPtr(parv[0]) ? "*" : parv[0], nick,
+ BadPtr(ban->reason) ? "Erroneous Nickname" :
+ ban->reason);
+ sendto_realops_lev(REJ_LEV,
+ "Forbidding restricted nick %s from %s.",
+ nick, get_client_name(cptr, FALSE));
+ return 0;
+ }
+ }
+#ifdef DONT_CHECK_QLINE_REMOTE
+ }
+#endif
+ if (MyConnect(sptr))
+ {
+ if (IsRegisteredUser(sptr))
+ {
+
+ /* before we change their nick, make sure they're not banned
+ * on any channels, and!! make sure they're not changing to
+ * a banned nick -sed */
+ /* a little cleaner - lucas */
+
+ for (lp = sptr->user->channel; lp; lp = lp->next)
+ {
+ if (can_send(sptr, lp->value.chptr, NULL))
+ {
+ sendto_one(sptr, err_str(ERR_BANNICKCHANGE), me.name,
+ sptr->name, lp->value.chptr->chname);
+ return 0;
+ }
+ if (nick_is_banned(lp->value.chptr, nick, sptr) != NULL)
+ {
+ sendto_one(sptr, err_str(ERR_BANONCHAN), me.name,
+ sptr->name, nick, lp->value.chptr->chname);
+ return 0;
+ }
+ }
+#ifdef ANTI_NICK_FLOOD
+ if ((sptr->last_nick_change + MAX_NICK_TIME) < NOW)
+ sptr->number_of_nick_changes = 0;
+ sptr->last_nick_change = NOW;
+ sptr->number_of_nick_changes++;
+
+ if (sptr->number_of_nick_changes > MAX_NICK_CHANGES &&
+ !IsAnOper(sptr))
+ {
+ sendto_one(sptr,
+ ":%s NOTICE %s :*** Notice -- Too many nick "
+ "changes. Wait %d seconds before trying again.",
+ me.name, sptr->name, MAX_NICK_TIME);
+ return 0;
+ }
+#endif
+ /* If it changed nicks, -r it */
+ if ((sptr->umode & UMODE_r) && (mycmp(parv[0], nick) != 0))
+ {
+ unsigned int oldumode;
+ char mbuf[BUFSIZE];
+
+ oldumode = sptr->umode;
+ sptr->umode &= ~UMODE_r;
+ send_umode(sptr, sptr, oldumode, ALL_UMODES, mbuf);
+ }
+
+ sendto_common_channels(sptr, ":%s NICK :%s", parv[0],
+ nick);
+ if (sptr->user)
+ {
+ add_history(sptr, 1);
+
+ sendto_serv_butone(cptr, ":%s NICK %s :%ld",
+ parv[0], nick, sptr->tsinfo);
+ }
+ }
+ }
+ else
+ {
+ sendto_common_channels(sptr, ":%s NICK :%s", parv[0], nick);
+ if (sptr->user)
+ {
+ add_history(sptr, 1);
+
+ sendto_serv_butone(cptr, ":%s NICK %s :%ld",
+ parv[0], nick, sptr->tsinfo);
+ }
+
+ /* If it changed nicks, -r it */
+ if (mycmp(parv[0], nick))
+ sptr->umode &= ~UMODE_r;
+ }
+ }
+ else
+ {
+ /* Client setting NICK the first time */
+ if (MyConnect(sptr))
+ {
+ if ((ban = check_mask_simbanned(nick, SBAN_NICK)))
+ {
+ if (MyConnect(sptr) && (!IsServer(cptr)) && (!IsOper(cptr))
+ && (!IsULine(sptr)))
+ {
+ sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name,
+ BadPtr(parv[0]) ? "*" : parv[0], nick,
+ BadPtr(ban->reason) ? "Erroneous Nickname" :
+ ban->reason);
+ sendto_realops_lev(REJ_LEV,
+ "Forbidding restricted nick %s from "
+ "<unregistered>%s.", nick,
+ get_client_name(cptr, FALSE));
+ return 0;
+ }
+ }
+ }
+
+ strcpy(sptr->name, nick);
+ sptr->tsinfo = timeofday;
+ if (sptr->user)
+ {
+ /* USER already received, now we have NICK */
+
+ if (register_user(cptr, sptr, nick, sptr->user->username)
+ == FLUSH_BUFFER)
+ return FLUSH_BUFFER;
+ }
+ }
+ /* Finally set new nick name. */
+
+ if (sptr->name[0])
+ {
+ del_from_client_hash_table(sptr->name, sptr);
+ samenick = mycmp(sptr->name, nick) ? 0 : 1;
+ if (IsPerson(sptr) && !samenick)
+ hash_check_watch(sptr, RPL_LOGOFF);
+ }
+ strcpy(sptr->name, nick);
+ add_to_client_hash_table(nick, sptr);
+ if (IsPerson(sptr) && !samenick)
+ hash_check_watch(sptr, RPL_LOGON);
+ return 0;
+}
--- /dev/null
+/*
+ * m_rwho.c - Regular expression enabled WHO
+ * Copyright (C) 2004 Trevor Talbot and
+ * the DALnet coding team
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: m_rwho.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include "numeric.h"
+#include "channel.h"
+#include "inet.h"
+#include "clones.h"
+
+#include "pcre.h"
+
+extern int user_modes[];
+extern unsigned int cidr_to_netmask(unsigned int);
+extern Link *find_channel_link(Link *, aChannel *);
+
+/* max capturing submatches to allow in all fields combined */
+#define MAX_SUBMATCHES 9
+
+/* for pcre_exec(), don't touch */
+#define NVEC ((MAX_SUBMATCHES+1)*3)
+
+/* PCRE matched fields */
+#define RWHO_NICK 1
+#define RWHO_USER 2
+#define RWHO_GCOS 3
+#define RWHO_AWAY 4
+#define RWHO_COUNT 5
+
+/* other matched fields */
+#define RWM_AWAY 0x0001
+#define RWM_HOST 0x0002
+#define RWM_IP 0x0004
+#define RWM_MODES 0x0008
+#define RWM_SERVER 0x0010
+#define RWM_TS 0x0020
+#define RWM_STYPE 0x0040
+#define RWM_JOINS 0x0080
+#define RWM_CLONES 0x0100
+#define RWM_MATCHES 0x0200
+#define RWM_CHANNEL 0x0400
+
+/* whois compatibility */
+#define RWC_SHOWIP 0x0001
+#define RWC_CHANNEL 0x0002
+
+/* output options */
+#define RWO_NICK 0x0001
+#define RWO_USER 0x0002
+#define RWO_HOST 0x0004
+#define RWO_IP 0x0008
+#define RWO_MODES 0x0010
+#define RWO_FLAGS 0x0020
+#define RWO_SERVER 0x0040
+#define RWO_TS 0x0080
+#define RWO_STYPE 0x0100
+#define RWO_GCOS 0x0200
+#define RWO_AWAY 0x0400
+#define RWO_JOINS 0x0800
+#define RWO_CLONES 0x1000
+#define RWO_MATCHES 0x2000
+#define RWO_CHANNEL 0x4000
+
+
+static const char *rwho_help[] = {
+ "RWHO <[+|-]matchflags>[/<outputflags>[:<cookie>]] <args>",
+ "Match flags are specified like channel modes,",
+ "'+' being a positive match and '-' being a negative one:",
+ " a - user is (not) away",
+ " c <channel> - user is on channel <channel> (+ only)",
+ " d <clones> - there are N or more (less) users per host",
+ " D <matches> - there are N or more (less) matching users per host",
+ " h <host> - user's host does (not) match wildcard mask",
+ " i <ip> - user's IP does (not) match CIDR <ip>",
+ " j <channels> - user is in N or more (less) channels",
+ " m <usermodes> - user is (not) using modes <usermodes>",
+ " s <server> - user is (not) on server <server>",
+ " t <seconds> - user has been online N or more (less) seconds",
+ " T <type> - user is (not) type <type> as set by services",
+ " C - for compatibility with WHO, use discouraged",
+ " I - for compatibility with WHO, use discouraged",
+ "The following match flags are compiled into a single regular expression",
+ "in the order you specify, so later flags can use backreferences to",
+ "submatches in the flags prior:",
+ " A <away> - user's away reason matches regexp pattern (implies +a)",
+ " g <gcos/name> - user's real name matches regexp pattern",
+ " n <nick> - user's nick matches regexp pattern",
+ " u <username> - user's username matches regexp pattern",
+ "The regular expression flags do not support negative matches.",
+ "The optional output flags cause replies to be sent using numeric 354 and",
+ "contain only the fields associated with the flags in the order below:",
+ " :<cookie> - supplied cookie (useful for scripts)",
+ " n - user's nick",
+ " u - user's username",
+ " h - user's host",
+ " i - user's IP",
+ " s - user's server",
+ " f - standard WHO flags (GH*%@+)",
+ " c - user's most recently joined channel",
+ " j - number of joined channels",
+ " d - number of clones on user's IP",
+ " D - number of matches on user's IP (see below)",
+ " t - user's signon timestamp",
+ " T - user's type (set by services)",
+ " m - user's modes",
+ " g - user's gcos/real name (mutually exclusive with 'a')",
+ " a - user's away reason (mutually exclusive with 'g')",
+ "There are three special output flags:",
+ " L<count> - limit to N results (no space between L and <count>)",
+ " C - no results, just supply match count in RPL_ENDOFWHO",
+ " D - returns only one matching result per host (summarize)",
+ NULL
+};
+
+static struct {
+ unsigned check[2]; /* things to try match */
+ unsigned rplfields; /* fields to include in the response */
+ unsigned compat; /* WHO compatibility flags */
+ char *rplcookie; /* response cookie */
+ int countonly; /* counting only, no results */
+ int limit; /* max number of results */
+ int spat[RWHO_COUNT]; /* match string build pattern */
+ pcre *re; /* regex pattern */
+ aClient *server; /* server */
+ aChannel *chptr; /* search in channel */
+ char *host_pat[2]; /* wildcard host pattern */
+ int (*host_func[2])(); /* host match function */
+ int umodes[2]; /* usermodes */
+ unsigned stype; /* services type */
+ unsigned ip_mask[2]; /* IP netmask */
+ unsigned ip_addr[2]; /* IP address */
+ char *ip_str[2]; /* IP string if CIDR is invalid */
+ ts_val ts[2]; /* signon timestamp */
+ int joined[2]; /* min/max joined chans */
+ int clones[2]; /* min/max clones */
+ int matches[2]; /* min/max clone matches */
+ int thisclones; /* number of clones on this host */
+ int thismatches; /* number of matches on this host */
+} rwho_opts;
+
+static char rwhobuf[1024];
+static char scratch[1024];
+
+
+/*
+ * Send a syntax error message.
+ */
+static void rwho_synerr(aClient *sptr, char *msg)
+{
+ sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name, sptr->name, "RWHO",
+ "rwho");
+ if (msg)
+ sendto_one(sptr, getreply(RPL_COMMANDSYNTAX), me.name, sptr->name,msg);
+}
+
+/*
+ * Build the regular expression to use for nick/user/gcos/away matching.
+ * Returns 1 on success, 0 on failure.
+ */
+static int rwho_compile(aClient *cptr, char *remap[])
+{
+ const char *es;
+ int ei;
+ char *s;
+ int i, j;
+ char arg = 0;
+
+ s = rwhobuf;
+ for (i = 0; rwho_opts.spat[i]; i++)
+ s += ircsprintf(s, "(?>(?:%s)\\x00)", remap[rwho_opts.spat[i]]);
+
+ rwho_opts.re = pcre_compile(rwhobuf,
+ PCRE_EXTRA|PCRE_ANCHORED|PCRE_UNGREEDY,
+ &es, &ei, NULL);
+
+ if (!rwho_opts.re)
+ {
+ rwho_synerr(cptr, NULL);
+
+ /* the things we do for error messages... */
+ for (i = 0; rwho_opts.spat[i]; i++)
+ {
+ rwho_opts.re = pcre_compile(remap[rwho_opts.spat[i]],
+ PCRE_EXTRA|PCRE_ANCHORED|PCRE_UNGREEDY,
+ &es, &ei, NULL);
+ if (rwho_opts.re)
+ {
+ free(rwho_opts.re);
+ continue;
+ }
+
+ if (es)
+ {
+ j = 0;
+ s = remap[rwho_opts.spat[i]];
+
+ switch (rwho_opts.spat[i])
+ {
+ case RWHO_AWAY: arg = 'A'; break;
+ case RWHO_GCOS: arg = 'g'; break;
+ case RWHO_NICK: arg = 'n'; break;
+ case RWHO_USER: arg = 'u'; break;
+ }
+
+ while (*s)
+ {
+ if (ei == j)
+ {
+ scratch[j++] = 037;
+ scratch[j++] = *s++;
+ scratch[j++] = 037;
+ }
+ else
+ scratch[j++] = *s++;
+ }
+ scratch[j] = 0;
+
+ ircsprintf(rwhobuf, "Invalid flag %c expression %s", arg,
+ scratch);
+ sendto_one(cptr, getreply(RPL_COMMANDSYNTAX), me.name,
+ cptr->name, rwhobuf);
+ sendto_one(cptr, getreply(RPL_COMMANDSYNTAX), me.name,
+ cptr->name, es);
+ break;
+ }
+ }
+
+ return 0;
+ }
+
+ pcre_fullinfo(rwho_opts.re, NULL, PCRE_INFO_CAPTURECOUNT, &ei);
+ if (ei > MAX_SUBMATCHES)
+ {
+ rwho_synerr(cptr, "too many capturing submatches, use (?:)");
+ free(rwho_opts.re);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Parse the options to the RWHO command.
+ * Returns 1 on success, 0 on failure.
+ */
+static int rwho_parseopts(aClient *sptr, int parc, char *parv[])
+{
+ char *remap[RWHO_COUNT] = {0};
+ char *sfl;
+ char *s;
+ int spatidx = 0;
+ int neg = 0;
+ int arg = 2;
+ int i;
+ ts_val ts;
+ unsigned ui;
+
+ memset(&rwho_opts, 0, sizeof(rwho_opts));
+
+ if (parc < 2)
+ {
+ sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name, sptr->name, "RWHO",
+ "rwho");
+ return 0;
+ }
+
+ if (*parv[1] == '?')
+ {
+ const char **ptr;
+ for (ptr = rwho_help; *ptr; ptr++)
+ sendto_one(sptr, getreply(RPL_COMMANDSYNTAX), me.name,
+ parv[0], *ptr);
+ sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, parv[0], "?","RWHO");
+ return 0;
+ }
+
+ /* parse match options */
+ for (sfl = parv[1]; *sfl; sfl++)
+ {
+ if (*sfl == '/')
+ {
+ sfl++;
+ break;
+ }
+
+ switch (*sfl)
+ {
+ case '+':
+ neg = 0;
+ break;
+
+ case '-':
+ neg = 1;
+ break;
+
+ case 'a':
+ if (rwho_opts.check[!neg] & RWM_AWAY)
+ {
+ rwho_synerr(sptr, "cannot use both +a and -a in match");
+ return 0;
+ }
+ rwho_opts.check[neg] |= RWM_AWAY;
+ break;
+
+ case 'c':
+ if (!parv[arg])
+ {
+ rwho_synerr(sptr, "missing argument for match flag c");
+ return 0;
+ }
+ if (neg)
+ {
+ rwho_synerr(sptr, "negative match not supported for match"
+ " flag c");
+ return 0;
+ }
+ rwho_opts.chptr = find_channel(parv[arg], NULL);
+ if (!rwho_opts.chptr)
+ {
+ sendto_one(sptr, getreply(ERR_NOSUCHCHANNEL), me.name,
+ parv[0], parv[arg]);
+ return 0;
+ }
+ rwho_opts.check[neg] |= RWM_CHANNEL;
+ arg++;
+ break;
+
+ case 'C':
+ rwho_opts.compat |= RWC_CHANNEL;
+ break;
+
+ case 'd':
+ if (!parv[arg])
+ {
+ rwho_synerr(sptr, "missing argument for match flag d");
+ return 0;
+ }
+ i = strtol(parv[arg], &s, 0);
+ if (*s != 0 || i < 1)
+ {
+ rwho_synerr(sptr, "invalid number of clones for match"
+ " flag d");
+ return 0;
+ }
+ rwho_opts.clones[neg] = i;
+ rwho_opts.check[neg] |= RWM_CLONES;
+ arg++;
+ break;
+
+ case 'D':
+ if (!parv[arg])
+ {
+ rwho_synerr(sptr, "missing argument for match flag D");
+ return 0;
+ }
+ i = strtol(parv[arg], &s, 0);
+ if (*s != 0 || i < 1)
+ {
+ rwho_synerr(sptr, "invalid number of matches for match"
+ " flag D");
+ return 0;
+ }
+ rwho_opts.matches[neg] = i;
+ rwho_opts.check[neg] |= RWM_MATCHES;
+ arg++;
+ break;
+
+ case 'h':
+ if (!parv[arg])
+ {
+ rwho_synerr(sptr, "missing argument for match flag h");
+ return 0;
+ }
+ if (strchr(parv[arg], '*') || strchr(parv[arg], '?'))
+ rwho_opts.host_func[neg] = match;
+ else
+ rwho_opts.host_func[neg] = mycmp;
+ rwho_opts.host_pat[neg] = parv[arg];
+ rwho_opts.check[neg] |= RWM_HOST;
+ arg++;
+ break;
+
+ case 'i':
+ if (!parv[arg])
+ {
+ rwho_synerr(sptr, "missing argument for match flag i");
+ return 0;
+ }
+ if ((s = strchr(parv[arg], '/')))
+ {
+ *s++ = 0;
+ i = strtol(s, &s, 10);
+ if (*s == 0 && 1 < i && i < 32)
+ rwho_opts.ip_mask[neg] = htonl(cidr_to_netmask(i));
+ }
+ else
+ rwho_opts.ip_mask[neg] = ~0;
+ rwho_opts.ip_addr[neg] = inet_addr(parv[arg]);
+ if (!rwho_opts.ip_mask[neg] ||
+ (rwho_opts.ip_mask[neg] != ~0 &&
+ rwho_opts.ip_addr[neg] == 0xFFFFFFFF))
+ {
+ rwho_synerr(sptr, "invalid CIDR IP for match flag i");
+ return 0;
+ }
+ if (rwho_opts.ip_addr[neg] == 0xFFFFFFFF)
+ rwho_opts.ip_str[neg] = parv[arg];
+ else
+ rwho_opts.ip_addr[neg] &= rwho_opts.ip_mask[neg];
+ rwho_opts.check[neg] |= RWM_IP;
+ arg++;
+ break;
+
+ case 'I':
+ rwho_opts.compat |= RWC_SHOWIP;
+ break;
+
+ case 'j':
+ if (!parv[arg])
+ {
+ rwho_synerr(sptr, "missing argument for match flag s");
+ return 0;
+ }
+ i = strtol(parv[arg], &s, 0);
+ if (*s != 0 || i < 0)
+ {
+ rwho_synerr(sptr, "invalid number of channels for match"
+ " flag j");
+ return 0;
+ }
+ rwho_opts.joined[neg] = i;
+ rwho_opts.check[neg] |= RWM_JOINS;
+ arg++;
+ break;
+
+ case 'm':
+ if (!parv[arg])
+ {
+ rwho_synerr(sptr, "missing argument for match flag m");
+ return 0;
+ }
+ for (s = parv[arg]; *s; s++)
+ for (i = 1; user_modes[i]; i+=2)
+ if (*s == user_modes[i])
+ {
+ rwho_opts.umodes[neg] |= user_modes[i-1];
+ break;
+ }
+ rwho_opts.check[neg] |= RWM_MODES;
+ arg++;
+ break;
+
+ case 's':
+ if (!parv[arg])
+ {
+ rwho_synerr(sptr, "missing argument for match flag s");
+ return 0;
+ }
+ if (rwho_opts.check[!neg] & RWM_SERVER)
+ {
+ rwho_synerr(sptr, "cannot use both +s and -s in match");
+ return 0;
+ }
+ rwho_opts.server = find_server(parv[arg], NULL);
+ if (!rwho_opts.server)
+ {
+ sendto_one(sptr, getreply(ERR_NOSUCHSERVER), me.name,
+ sptr->name, parv[arg]);
+ return 0;
+ }
+ rwho_opts.check[neg] |= RWM_SERVER;
+ arg++;
+ break;
+
+ case 't':
+ if (!parv[arg])
+ {
+ rwho_synerr(sptr, "missing argument for match flag t");
+ return 0;
+ }
+ ts = strtol(parv[arg], &s, 0);
+ if (*s != 0 || ts <= 0)
+ {
+ rwho_synerr(sptr, "invalid number of seconds for match"
+ " flag t");
+ return 0;
+ }
+ rwho_opts.ts[neg] = NOW - ts;
+ rwho_opts.check[neg] |= RWM_TS;
+ arg++;
+ break;
+
+ case 'T':
+ if (!parv[arg])
+ {
+ rwho_synerr(sptr, "missing argument for match flag T");
+ return 0;
+ }
+ if (rwho_opts.check[!neg] & RWM_STYPE)
+ {
+ rwho_synerr(sptr, "cannot use both +T and -T in match");
+ return 0;
+ }
+ ui = strtoul(parv[arg], &s, 0);
+ if (*s != 0)
+ {
+ rwho_synerr(sptr, "invalid type for match flag T");
+ return 0;
+ }
+ rwho_opts.stype = ui;
+ rwho_opts.check[neg] |= RWM_STYPE;
+ arg++;
+ break;
+
+ case 'A':
+ if (!parv[arg])
+ {
+ rwho_synerr(sptr, "missing argument for match flag A");
+ return 0;
+ }
+ if (remap[RWHO_AWAY])
+ {
+ rwho_synerr(sptr, "flags may not be used more than once");
+ return 0;
+ }
+ if (neg)
+ {
+ rwho_synerr(sptr, "negative match not supported for match"
+ " flag A");
+ return 0;
+ }
+ if (rwho_opts.check[!neg] & RWM_AWAY)
+ {
+ rwho_synerr(sptr, "cannot use both +A and -a in match");
+ return 0;
+ }
+ remap[RWHO_AWAY] = parv[arg];
+ rwho_opts.spat[spatidx++] = RWHO_AWAY;
+ rwho_opts.check[neg] |= RWM_AWAY; /* implicit +a */
+ arg++;
+ break;
+
+ case 'g':
+ if (!parv[arg])
+ {
+ rwho_synerr(sptr, "missing argument for match flag g");
+ return 0;
+ }
+ if (remap[RWHO_GCOS])
+ {
+ rwho_synerr(sptr, "flags may not be used more than once");
+ return 0;
+ }
+ if (neg)
+ {
+ rwho_synerr(sptr, "negative match not supported for match"
+ " flag g");
+ return 0;
+ }
+ remap[RWHO_GCOS] = parv[arg];
+ rwho_opts.spat[spatidx++] = RWHO_GCOS;
+ arg++;
+ break;
+
+ case 'n':
+ if (!parv[arg])
+ {
+ rwho_synerr(sptr, "missing argument for match flag n");
+ return 0;
+ }
+ if (remap[RWHO_NICK])
+ {
+ rwho_synerr(sptr, "flags may not be used more than once");
+ return 0;
+ }
+ if (neg)
+ {
+ rwho_synerr(sptr, "negative match not supported for match"
+ " flag n");
+ return 0;
+ }
+ remap[RWHO_NICK] = parv[arg];
+ rwho_opts.spat[spatidx++] = RWHO_NICK;
+ arg++;
+ break;
+
+ case 'u':
+ if (!parv[arg])
+ {
+ rwho_synerr(sptr, "missing argument for match flag u");
+ return 0;
+ }
+ if (remap[RWHO_USER])
+ {
+ rwho_synerr(sptr, "flags may not be used more than once");
+ return 0;
+ }
+ if (neg)
+ {
+ rwho_synerr(sptr, "negative match not supported for match"
+ " flag u");
+ return 0;
+ }
+ remap[RWHO_USER] = parv[arg];
+ rwho_opts.spat[spatidx++] = RWHO_USER;
+ arg++;
+ break;
+
+ default:
+ ircsprintf(scratch, "unknown match flag %c", *sfl);
+ rwho_synerr(sptr, scratch);
+ return 0;
+ }
+ }
+
+ /* parse output options */
+ while (*sfl)
+ {
+ if (*sfl == ':')
+ {
+ if (!*++sfl)
+ {
+ rwho_synerr(sptr, NULL);
+ return 0;
+ }
+ rwho_opts.rplcookie = sfl;
+ break;
+ }
+
+ switch (*sfl)
+ {
+ case 'n': rwho_opts.rplfields |= RWO_NICK; sfl++; break;
+ case 'u': rwho_opts.rplfields |= RWO_USER; sfl++; break;
+ case 'h': rwho_opts.rplfields |= RWO_HOST; sfl++; break;
+ case 'i': rwho_opts.rplfields |= RWO_IP; sfl++; break;
+ case 's': rwho_opts.rplfields |= RWO_SERVER; sfl++; break;
+ case 'f': rwho_opts.rplfields |= RWO_FLAGS; sfl++; break;
+ case 'c': rwho_opts.rplfields |= RWO_CHANNEL; sfl++; break;
+ case 'j': rwho_opts.rplfields |= RWO_JOINS; sfl++; break;
+ case 'd': rwho_opts.rplfields |= RWO_CLONES; sfl++; break;
+ case 'D': rwho_opts.rplfields |= RWO_MATCHES; sfl++; break;
+ case 't': rwho_opts.rplfields |= RWO_TS; sfl++; break;
+ case 'T': rwho_opts.rplfields |= RWO_STYPE; sfl++; break;
+ case 'm': rwho_opts.rplfields |= RWO_MODES; sfl++; break;
+ case 'g': rwho_opts.rplfields |= RWO_GCOS; sfl++; break;
+ case 'a': rwho_opts.rplfields |= RWO_AWAY; sfl++; break;
+
+ case 'C': rwho_opts.countonly = 1; sfl++; break;
+
+ case 'L':
+ rwho_opts.limit = strtol(sfl+1, &sfl, 10);
+ if (rwho_opts.limit < 1)
+ {
+ rwho_synerr(sptr, "invalid limit for output flag L");
+ return 0;
+ }
+ break;
+
+ default:
+ ircsprintf(scratch, "unknown output flag %c", *sfl);
+ rwho_synerr(sptr, scratch);
+ return 0;
+ }
+ }
+
+ if ((rwho_opts.rplfields & (RWO_GCOS|RWO_AWAY)) == (RWO_GCOS|RWO_AWAY))
+ {
+ rwho_synerr(sptr, "output flags g and a may not be used together");
+ return 0;
+ }
+
+ if ((rwho_opts.check[0] & rwho_opts.check[1] & RWM_CLONES)
+ && (rwho_opts.clones[0] > rwho_opts.clones[1]))
+ {
+ rwho_synerr(sptr, "values for match flags +d and -d will never match");
+ return 0;
+ }
+
+ if ((rwho_opts.check[0] & rwho_opts.check[1] & RWM_MATCHES)
+ && (rwho_opts.matches[0] > rwho_opts.matches[1]))
+ {
+ rwho_synerr(sptr, "values for match flags +D and -D will never match");
+ return 0;
+ }
+
+ if ((rwho_opts.check[0] & rwho_opts.check[1] & RWM_JOINS)
+ && (rwho_opts.joined[0] > rwho_opts.joined[1]))
+ {
+ rwho_synerr(sptr, "values for match flags +j and -j will never match");
+ return 0;
+ }
+
+ if ((rwho_opts.check[0] & rwho_opts.check[1] & RWM_TS)
+ && (rwho_opts.ts[0] < rwho_opts.ts[1]))
+ {
+ rwho_synerr(sptr, "values for match flags +t and -t will never match");
+ return 0;
+ }
+
+ if (spatidx && !rwho_compile(sptr, remap))
+ return 0;
+
+ return 1;
+}
+
+/*
+ * See if a client matches the search parameters.
+ * Returns 1 on match, 0 on no match.
+ * Fills in failcode and failclient upon unexpected PCRE error.
+ */
+static int rwho_match(aClient *cptr, int *failcode, aClient **failclient)
+{
+ char *s;
+ char *b;
+ int i;
+ int ovec[NVEC];
+
+ if ((rwho_opts.check[0] & RWM_SERVER) &&
+ (cptr->uplink != rwho_opts.server))
+ return 0;
+ else if ((rwho_opts.check[1] & RWM_SERVER) &&
+ (cptr->uplink == rwho_opts.server))
+ return 0;
+
+ if ((rwho_opts.check[0] & RWM_TS) && (cptr->tsinfo > rwho_opts.ts[0]))
+ return 0;
+
+ if ((rwho_opts.check[1] & RWM_TS) && (cptr->tsinfo < rwho_opts.ts[1]))
+ return 0;
+
+ if ((rwho_opts.check[0] & RWM_AWAY) && !cptr->user->away)
+ return 0;
+ else if ((rwho_opts.check[1] & RWM_AWAY) && cptr->user->away)
+ return 0;
+
+ if ((rwho_opts.check[0] & RWM_STYPE) &&
+ (cptr->user->servicetype != rwho_opts.stype))
+ return 0;
+ else if ((rwho_opts.check[1] & RWM_STYPE) &&
+ (cptr->user->servicetype == rwho_opts.stype))
+ return 0;
+
+ if ((rwho_opts.check[0] & RWM_JOINS) &&
+ (cptr->user->joined < rwho_opts.joined[0]))
+ return 0;
+
+ if ((rwho_opts.check[1] & RWM_JOINS) &&
+ (cptr->user->joined > rwho_opts.joined[1]))
+ return 0;
+
+ if ((rwho_opts.check[0] & RWM_MODES) &&
+ ((cptr->umode & rwho_opts.umodes[0]) != rwho_opts.umodes[0]))
+ return 0;
+
+ if ((rwho_opts.check[1] & RWM_MODES) &&
+ (cptr->umode & rwho_opts.umodes[1]))
+ return 0;
+
+ if ((rwho_opts.check[0] & RWM_CHANNEL) && !IsMember(cptr, rwho_opts.chptr))
+ return 0;
+
+ if (rwho_opts.check[0] & RWM_IP)
+ {
+ if (rwho_opts.ip_str[0])
+ {
+ if (match(rwho_opts.ip_str[0], cptr->hostip))
+ return 0;
+ }
+ else if ((cptr->ip.s_addr & rwho_opts.ip_mask[0])
+ != rwho_opts.ip_addr[0])
+ return 0;
+ }
+
+ if (rwho_opts.check[1] & RWM_IP)
+ {
+ if (rwho_opts.ip_str[1])
+ {
+ if (!match(rwho_opts.ip_str[1], cptr->hostip))
+ return 0;
+ }
+ else if ((cptr->ip.s_addr & rwho_opts.ip_mask[1])
+ == rwho_opts.ip_addr[1])
+ return 0;
+ }
+
+ if ((rwho_opts.check[0] & RWM_HOST) &&
+ rwho_opts.host_func[0](rwho_opts.host_pat[0], cptr->user->host))
+ return 0;
+
+ if ((rwho_opts.check[1] & RWM_HOST) &&
+ !rwho_opts.host_func[1](rwho_opts.host_pat[1], cptr->user->host))
+ return 0;
+
+ if (rwho_opts.re)
+ {
+ s = scratch;
+ for (i = 0; rwho_opts.spat[i]; i++)
+ {
+ switch (rwho_opts.spat[i])
+ {
+ case RWHO_NICK:
+ b = cptr->name;
+ while ((*s++ = *b++));
+ /* note: deliberately using zero terminator */
+ break;
+
+ case RWHO_USER:
+ b = cptr->user->username;
+ while ((*s++ = *b++));
+ break;
+
+ case RWHO_GCOS:
+ b = cptr->info;
+ while ((*s++ = *b++));
+ break;
+
+ /* will core if RWM_AWAY wasn't implicitly set */
+ case RWHO_AWAY:
+ b = cptr->user->away;
+ while ((*s++ = *b++));
+ break;
+ }
+ }
+
+ i = pcre_exec(rwho_opts.re, NULL, scratch, s - scratch, 0, 0, ovec,
+ NVEC);
+
+ if (i < 0)
+ {
+ if (i == PCRE_ERROR_NOMATCH)
+ return 0;
+
+ *failcode = i;
+ *failclient = cptr;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * Prepare rwhobuf for response text.
+ * Returns a pointer to space for rwho_reply().
+ */
+static char *rwho_prepbuf(aClient *cptr)
+{
+ char *s = rwhobuf;
+
+ if (!rwho_opts.rplfields)
+ return s;
+
+ s += ircsprintf(s, getreply(RPL_RWHOREPLY), me.name, cptr->name);
+
+ if (rwho_opts.rplcookie)
+ s += ircsprintf(s, " %s", rwho_opts.rplcookie);
+
+ return s;
+}
+
+/*
+ * Build response text in supplied buffer.
+ */
+static void rwho_reply(aClient *cptr, aClient *ac, char *buf, chanMember *cm)
+{
+ char *src;
+ char *dst;
+ aChannel *chptr = NULL;
+
+ dst = buf;
+
+ if (ac->user->channel)
+ chptr = ac->user->channel->value.chptr;
+
+ /* use standard RPL_WHOREPLY if no output flags */
+ if (!rwho_opts.rplfields)
+ {
+ char status[5];
+ char chname[CHANNELLEN+2] = "*";
+
+ if (!cm && (rwho_opts.compat & RWC_CHANNEL) && chptr)
+ {
+ for (cm = chptr->members; cm; cm = cm->next)
+ if (cm->cptr == ac)
+ break;
+ }
+
+ dst = status;
+ if (ac->user->away)
+ *dst++ = 'G';
+ else
+ *dst++ = 'H';
+ if (IsAnOper(ac))
+ *dst++ = '*';
+ else if (IsInvisible(ac))
+ *dst++ = '%';
+ if (cm)
+ {
+ if (cm->flags & CHFL_CHANOP)
+ *dst++ = '@';
+ else if (cm->flags & CHFL_VOICE)
+ *dst++ = '+';
+ }
+ *dst = 0;
+
+ if (!rwho_opts.chptr && (rwho_opts.compat & RWC_CHANNEL) && chptr)
+ {
+ dst = chname;
+ if (!PubChannel(chptr))
+ *dst++ = '%';
+ if (PubChannel(chptr) || IsAdmin(cptr))
+ strcpy(dst, chptr->chname);
+ }
+
+ if (rwho_opts.compat & RWC_SHOWIP)
+ src = ac->hostip;
+ else
+ src = ac->user->host;
+
+ ircsprintf(buf, getreply(RPL_WHOREPLY), me.name, cptr->name,
+ rwho_opts.chptr ? rwho_opts.chptr->chname : chname,
+ ac->user->username, src, ac->user->server,
+ ac->name, status, ac->hopcount, ac->info);
+ return;
+ }
+
+ if (rwho_opts.rplfields & RWO_NICK)
+ {
+ src = ac->name;
+ *dst++ = ' ';
+ while (*src)
+ *dst++ = *src++;
+ }
+
+ if (rwho_opts.rplfields & RWO_USER)
+ {
+ src = ac->user->username;
+ *dst++ = ' ';
+ while (*src)
+ *dst++ = *src++;
+ }
+
+ if (rwho_opts.rplfields & RWO_HOST)
+ {
+ src = ac->user->host;
+ *dst++ = ' ';
+ while (*src)
+ *dst++ = *src++;
+ }
+
+ if (rwho_opts.rplfields & RWO_IP)
+ {
+ src = ac->hostip;
+ *dst++ = ' ';
+ while (*src)
+ *dst++ = *src++;
+ }
+
+ if (rwho_opts.rplfields & RWO_SERVER)
+ {
+ src = ac->user->server;
+ *dst++ = ' ';
+ while (*src)
+ *dst++ = *src++;
+ }
+
+ if (rwho_opts.rplfields & RWO_FLAGS)
+ {
+ *dst++ = ' ';
+ if (ac->user->away)
+ *dst++ = 'G';
+ else
+ *dst++ = 'H';
+ if (IsAnOper(ac))
+ *dst++ = '*';
+ if (IsInvisible(ac))
+ *dst++ = '%';
+
+ if (!cm && (rwho_opts.rplfields & RWO_CHANNEL) && chptr)
+ {
+ for (cm = chptr->members; cm; cm = cm->next)
+ if (cm->cptr == cptr)
+ break;
+ }
+
+ if (cm)
+ {
+ if (cm->flags & CHFL_CHANOP)
+ *dst++ = '@';
+ if (cm->flags & CHFL_VOICE)
+ *dst++ = '+';
+ }
+ }
+
+ if (rwho_opts.rplfields & RWO_CHANNEL)
+ {
+ *dst++ = ' ';
+
+ if (!chptr)
+ *dst++ = '*';
+ else
+ {
+ if (!PubChannel(chptr))
+ *dst++ = '%';
+ if (PubChannel(chptr) || IsAdmin(cptr))
+ {
+ src = chptr->chname;
+ while (*src)
+ *dst++ = *src++;
+ }
+ }
+ }
+
+ if (rwho_opts.rplfields & RWO_JOINS)
+ dst += ircsprintf(dst, " %d", ac->user->joined);
+
+ if (rwho_opts.rplfields & RWO_CLONES)
+ dst += ircsprintf(dst, " %d", rwho_opts.thisclones);
+
+ if (rwho_opts.rplfields & RWO_MATCHES)
+ dst += ircsprintf(dst, " %d", rwho_opts.thismatches);
+
+ if (rwho_opts.rplfields & RWO_TS)
+ dst += ircsprintf(dst, " %d", ac->tsinfo);
+
+ if (rwho_opts.rplfields & RWO_STYPE)
+ dst += ircsprintf(dst, " %d", ac->user->servicetype);
+
+ if (rwho_opts.rplfields & RWO_MODES)
+ {
+ int i;
+
+ *dst++ = ' ';
+ *dst++ = '+';
+ for (i = 0; user_modes[i]; i += 2)
+ {
+ if (ac->umode & user_modes[i])
+ *dst++ = user_modes[i+1];
+ }
+ }
+
+ if (rwho_opts.rplfields & RWO_GCOS)
+ {
+ src = ac->info;
+ *dst++ = ' ';
+ *dst++ = ':';
+ while (*src)
+ *dst++ = *src++;
+ }
+ else if (rwho_opts.rplfields & RWO_AWAY)
+ {
+ src = ac->user->away;
+ *dst++ = ' ';
+ *dst++ = ':';
+ if (src)
+ while (*src)
+ *dst++ = *src++;
+ }
+
+ *dst = 0;
+}
+
+/*
+ * m_rwho - flexible client search with regular expression support
+ * parv[0] - sender
+ * parv[1] - flags
+ * parv[2] - arguments
+ */
+int m_rwho(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ chanMember *cm;
+ aClient *ac;
+ aClient *failclient = NULL;
+ int failcode = 0;
+ int results = 0;
+ int left;
+ char *fill;
+
+ if (!IsAnOper(sptr))
+ {
+ sendto_one(sptr, getreply(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+
+ if (!rwho_parseopts(sptr, parc, parv))
+ return 0;
+
+ left = rwho_opts.limit ? rwho_opts.limit : INT_MAX;
+
+ fill = rwho_prepbuf(sptr);
+
+ if (rwho_opts.chptr && !IsAdmin(sptr) && !ShowChannel(sptr, rwho_opts.chptr))
+ rwho_opts.countonly = 1;
+
+ if (((rwho_opts.check[0] | rwho_opts.check[1]) & (RWM_CLONES|RWM_MATCHES))
+ || (rwho_opts.rplfields & (RWO_CLONES|RWO_MATCHES)))
+ {
+ CloneEnt *ce;
+ aClient *fm;
+
+ for (ce = clones_list; ce; ce = ce->next)
+ {
+ if (!ce->clients)
+ continue;
+
+ if ((rwho_opts.check[0] & RWM_CLONES) &&
+ (ce->gcount < rwho_opts.clones[0]))
+ continue;
+
+ if ((rwho_opts.check[1] & RWM_CLONES) &&
+ (ce->gcount > rwho_opts.clones[1]))
+ continue;
+
+ fm = NULL;
+ rwho_opts.thismatches = 0;
+ rwho_opts.thisclones = ce->gcount;
+
+ /* if using match flag D or summarizing, we need the match count */
+ if (((rwho_opts.check[0] | rwho_opts.check[1]) & RWM_MATCHES)
+ || (rwho_opts.rplfields & RWO_MATCHES))
+ {
+ for (ac = ce->clients; ac; ac = ac->clone.next)
+ {
+ if (!rwho_match(ac, &failcode, &failclient))
+ continue;
+
+ if (!fm)
+ fm = ac;
+
+ rwho_opts.thismatches++;
+ }
+
+ /* we know no matches, so no need to process further */
+ if (!rwho_opts.thismatches)
+ continue;
+
+ if ((rwho_opts.check[0] & RWM_MATCHES) &&
+ (rwho_opts.thismatches < rwho_opts.matches[0]))
+ continue;
+
+ if ((rwho_opts.check[1] & RWM_MATCHES) &&
+ (rwho_opts.thismatches > rwho_opts.matches[1]))
+ continue;
+ }
+
+ /* if summarizing, we cached from the sweep above */
+ if (rwho_opts.rplfields & RWO_MATCHES)
+ {
+ if (!left)
+ {
+ sendto_one(sptr, getreply(ERR_WHOLIMEXCEED), me.name,
+ parv[0], rwho_opts.limit, "RWHO");
+ break;
+ }
+
+ if (!rwho_opts.countonly)
+ {
+ rwho_reply(sptr, fm, fill, NULL);
+ sendto_one(sptr, "%s", rwhobuf);
+ }
+
+ results++;
+ left--;
+ continue;
+ }
+
+ /* not summarizing, so send each match */
+ for (ac = ce->clients; ac; ac = ac->clone.next)
+ {
+ if (!rwho_match(ac, &failcode, &failclient))
+ continue;
+
+ if (!left)
+ {
+ sendto_one(sptr, getreply(ERR_WHOLIMEXCEED), me.name,
+ parv[0], rwho_opts.limit, "RWHO");
+ break;
+ }
+
+ if (!rwho_opts.countonly)
+ {
+ rwho_reply(sptr, ac, fill, NULL);
+ sendto_one(sptr, "%s", rwhobuf);
+ }
+
+ results++;
+ left--;
+ }
+ }
+ }
+ else if (rwho_opts.chptr)
+ {
+ rwho_opts.check[0] &= ~RWM_CHANNEL;
+
+ for (cm = rwho_opts.chptr->members; cm; cm = cm->next)
+ {
+ ac = cm->cptr;
+
+ if (!rwho_match(ac, &failcode, &failclient))
+ continue;
+
+ if (!left)
+ {
+ sendto_one(sptr, getreply(ERR_WHOLIMEXCEED), me.name, parv[0],
+ rwho_opts.limit, "RWHO");
+ break;
+ }
+
+ if (!rwho_opts.countonly)
+ {
+ rwho_reply(sptr, ac, fill, cm);
+ sendto_one(sptr, "%s", rwhobuf);
+ }
+
+ results++;
+ left--;
+ }
+ }
+ else
+ {
+ for (ac = client; ac; ac = ac->next)
+ {
+ if (!IsClient(ac))
+ continue;
+
+ if (!rwho_match(ac, &failcode, &failclient))
+ continue;
+
+ if (!left)
+ {
+ sendto_one(sptr, getreply(ERR_WHOLIMEXCEED), me.name, parv[0],
+ rwho_opts.limit, "RWHO");
+ break;
+ }
+
+ if (!rwho_opts.countonly)
+ {
+ rwho_reply(sptr, ac, fill, NULL);
+ sendto_one(sptr, "%s", rwhobuf);
+ }
+
+ results++;
+ left--;
+ }
+ }
+
+ if (rwho_opts.compat)
+ sendto_one(sptr, getreply(RPL_COMMANDSYNTAX), me.name, sptr->name,
+ "NOTE: match flags C and I are deprecated");
+
+ ircsprintf(rwhobuf, "%d", results);
+ sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, parv[0], rwhobuf,"RWHO");
+
+ if (failcode)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :RWHO: Internal error %d during "
+ "match, notify coders!", me.name, parv[0], failcode);
+ sendto_one(sptr, ":%s NOTICE %s :RWHO: Match target was: %s %s "
+ "[%s] [%s]", me.name, parv[0], failclient->name,
+ failclient->user->username, failclient->info,
+ failclient->user->away ? failclient->user->away : "");
+ }
+
+ free(rwho_opts.re);
+
+ return 0;
+}
+
--- /dev/null
+/* Bahamut IRCd, src/m_server.c
+ * Copyright (c) 2004, Aaron Wiebe and the Bahamut Team
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: m_server.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "h.h"
+#include "dh.h"
+#include "userban.h"
+#include "zlink.h"
+#include "throttle.h"
+#include "clones.h"
+
+/* externally defined functions */
+
+extern void fakelinkserver_update(char *, char *);
+extern void fakeserver_sendserver(aClient *);
+extern void fakelusers_sendlock(aClient *);
+extern void reset_sock_opts(int, int);
+
+/* internal functions */
+
+static void sendnick_TS(aClient *cptr, aClient *acptr)
+{
+ static char ubuf[12];
+
+ if (IsPerson(acptr))
+ {
+ send_umode(NULL, acptr, 0, SEND_UMODES, ubuf);
+ if (!*ubuf) /* trivial optimization - Dianora */
+ {
+ ubuf[0] = '+';
+ ubuf[1] = '\0';
+ }
+ sendto_one(cptr, "NICK %s %d %ld %s %s %s %s %lu %lu :%s",
+ acptr->name, acptr->hopcount + 1, acptr->tsinfo, ubuf,
+ acptr->user->username, acptr->user->host,
+ acptr->user->server, acptr->user->servicestamp,
+ htonl(acptr->ip.s_addr), acptr->info);
+ }
+}
+
+static int
+do_server_estab(aClient *cptr)
+{
+ aClient *acptr;
+ aConnect *aconn;
+ aChannel *chptr;
+ int i;
+ /* "refresh" inpath with host */
+ char *inpath = get_client_name(cptr, HIDEME);
+
+ SetServer(cptr);
+
+ Count.server++;
+ Count.myserver++;
+
+ if(IsZipCapable(cptr) && DoZipThis(cptr))
+ {
+ sendto_one(cptr, "SVINFO ZIP");
+ SetZipOut(cptr);
+ cptr->serv->zip_out = zip_create_output_session();
+ }
+
+#ifdef MAXBUFFERS
+ /* let's try to bump up server sock_opts... -Taner */
+ reset_sock_opts(cptr->fd, 1);
+#endif
+
+ /* adds to server list */
+ add_to_list(&server_list, cptr);
+
+ set_effective_class(cptr);
+
+ /* Check one more time for good measure... is it there? */
+ if ((acptr = find_name(cptr->name, NULL)))
+ {
+ char nbuf[HOSTLEN * 2 + USERLEN + 5];
+ aClient *bcptr;
+
+ /*
+ * While negotiating stuff, another copy of this server appeared.
+ *
+ * Rather than KILL the link which introduced it, KILL the
+ * youngest of the two links. -avalon
+ */
+
+ bcptr = (cptr->firsttime > acptr->from->firsttime) ? cptr :
+ acptr->from;
+ sendto_one(bcptr, "ERROR :Server %s already exists", cptr->name);
+ if (bcptr == cptr)
+ {
+ sendto_gnotice("from %s: Link %s cancelled, server %s already "
+ "exists (final phase)", me.name,
+ get_client_name(bcptr, HIDEME), cptr->name);
+ sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, "
+ "server %s already exists (final phase)",
+ me.name, get_client_name(bcptr, HIDEME),
+ cptr->name);
+ return exit_client(bcptr, bcptr, &me,
+ "Server Exists (final phase)");
+ }
+ /* inform all those who care (set +n) -epi */
+
+ strcpy(nbuf, get_client_name(bcptr, HIDEME));
+ sendto_gnotice("from %s: Link %s cancelled, server %s reintroduced "
+ "by %s (final phase)", me.name, nbuf, cptr->name,
+ get_client_name(cptr, HIDEME));
+ sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, server %s "
+ "reintroduced by %s (final phase)", me.name, nbuf,
+ cptr->name, get_client_name(cptr, HIDEME));
+ exit_client(bcptr, bcptr, &me, "Server Exists (final phase)");
+ }
+
+ /* error, error, error! if a server is U:'d, and it connects to us,
+ * we need to figure that out! So, do it here. - lucas
+ */
+
+ if (find_aUserver(cptr->name))
+ {
+ Count.myulined++;
+ cptr->flags |= FLAGS_ULINE;
+ }
+
+ fakelinkserver_update(cptr->name, cptr->info);
+
+ sendto_gnotice("from %s: Link with %s established, states:%s%s%s%s",
+ me.name, inpath, ZipOut(cptr) ? " Output-compressed" : "",
+ RC4EncLink(cptr) ? " encrypted" : "",
+ IsULine(cptr) ? " ULined" : "",
+ DoesTS(cptr) ? " TS" : " Non-TS");
+
+ /*
+ * Notify everyone of the fact that this has just linked: the entire
+ * network should get two of these, one explaining the link between
+ * me->serv and the other between serv->me
+ */
+
+ sendto_serv_butone(NULL, ":%s GNOTICE :Link with %s established: %s",
+ me.name, inpath,
+ DoesTS(cptr) ? "TS link" : "Non-TS link!");
+
+ add_to_client_hash_table(cptr->name, cptr);
+
+ /* add it to scache */
+
+ find_or_add(cptr->name);
+
+ /*
+ * Old sendto_serv_but_one() call removed because we now need to
+ * send different names to different servers (domain name
+ * matching) Send new server to other servers.
+ */
+ for (i = 0; i <= highest_fd; i++)
+ {
+ if (!(acptr = local[i]) || !IsServer(acptr) || acptr == cptr ||
+ IsMe(acptr))
+ continue;
+ if ((aconn = acptr->serv->aconn) &&
+ !match(my_name_for_link(me.name, aconn), cptr->name))
+ continue;
+ sendto_one(acptr, ":%s SERVER %s 2 :%s", me.name, cptr->name,
+ cptr->info);
+ }
+
+ /*
+ * Pass on my client information to the new server
+ *
+ * First, pass only servers (idea is that if the link gets
+ * cancelled beacause the server was already there, there are no
+ * NICK's to be cancelled...). Of course, if cancellation occurs,
+ * all this info is sent anyway, and I guess the link dies when a
+ * read is attempted...? --msa
+ *
+ * Note: Link cancellation to occur at this point means that at
+ * least two servers from my fragment are building up connection
+ * this other fragment at the same time, it's a race condition,
+ * not the normal way of operation...
+ *
+ * ALSO NOTE: using the get_client_name for server names-- see
+ * previous *WARNING*!!! (Also, original inpath is
+ * destroyed...)
+ */
+
+ aconn = cptr->serv->aconn;
+ for (acptr = &me; acptr; acptr = acptr->prev)
+ {
+ if (acptr->from == cptr)
+ continue;
+ if (IsServer(acptr))
+ {
+ if (match(my_name_for_link(me.name, aconn), acptr->name) == 0)
+ continue;
+ sendto_one(cptr, ":%s SERVER %s %d :%s",
+ acptr->serv->up, acptr->name,
+ acptr->hopcount + 1, acptr->info);
+ }
+ }
+
+ /* send out our SQLINES and SGLINES too */
+ send_simbans(cptr, SBAN_CHAN|SBAN_NETWORK);
+ send_simbans(cptr, SBAN_NICK|SBAN_NETWORK);
+ send_simbans(cptr, SBAN_GCOS|SBAN_NETWORK);
+
+ /* Send out fake server list and other 'fake' stuff */
+ fakeserver_sendserver(cptr);
+
+ /* send clone list */
+ clones_send(cptr);
+
+ /* Bursts are about to start.. send a BURST */
+ if (IsBurst(cptr))
+ sendto_one(cptr, "BURST");
+
+ /*
+ * * Send it in the shortened format with the TS, if it's a TS
+ * server; walk the list of channels, sending all the nicks that
+ * haven't been sent yet for each channel, then send the channel
+ * itself -- it's less obvious than sending all nicks first, but
+ * on the receiving side memory will be allocated more nicely
+ * saving a few seconds in the handling of a split -orabidoo
+ */
+ {
+ chanMember *cm;
+ static char nickissent = 1;
+
+ nickissent = 3 - nickissent;
+ /*
+ * flag used for each nick to check if we've sent it yet - must
+ * be different each time and !=0, so we alternate between 1 and
+ * 2 -orabidoo
+ */
+ for (chptr = channel; chptr; chptr = chptr->nextch)
+ {
+ for (cm = chptr->members; cm; cm = cm->next)
+ {
+ acptr = cm->cptr;
+ if (acptr->nicksent != nickissent)
+ {
+ acptr->nicksent = nickissent;
+ if (acptr->from != cptr)
+ sendnick_TS(cptr, acptr);
+ }
+ }
+ send_channel_modes(cptr, chptr);
+ }
+ /* also send out those that are not on any channel */
+ for (acptr = &me; acptr; acptr = acptr->prev)
+ if (acptr->nicksent != nickissent)
+ {
+ acptr->nicksent = nickissent;
+ if (acptr->from != cptr)
+ sendnick_TS(cptr, acptr);
+ }
+ }
+
+ if(confopts & FLAGS_HUB)
+ fakelusers_sendlock(cptr);
+
+ if(ZipOut(cptr))
+ {
+ unsigned long inb, outb;
+ double rat;
+
+ zip_out_get_stats(cptr->serv->zip_out, &inb, &outb, &rat);
+
+ if(inb)
+ {
+ sendto_gnotice("from %s: Connect burst to %s: %lu bytes normal, "
+ "%lu compressed (%3.2f%%)", me.name,
+ get_client_name(cptr, HIDEME), inb, outb, rat);
+ sendto_serv_butone(cptr, ":%s GNOTICE :Connect burst to %s: %lu "
+ "bytes normal, %lu compressed (%3.2f%%)",
+ me.name, get_client_name(cptr, HIDEME), inb,
+ outb, rat);
+ }
+ }
+
+ /* stuff a PING at the end of this burst so we can figure out when
+ the other side has finished processing it. */
+ cptr->flags |= FLAGS_BURST|FLAGS_PINGSENT;
+ if (IsBurst(cptr)) cptr->flags |= FLAGS_SOBSENT;
+ sendto_one(cptr, "PING :%s", me.name);
+
+ return 0;
+}
+
+static int
+m_server_estab(aClient *cptr)
+{
+ aConnect *aconn;
+
+ char *inpath, *host, *s, *encr;
+ int split;
+
+ inpath = get_client_name(cptr, HIDEME); /* "refresh" inpath with host */
+ split = mycmp(cptr->name, cptr->sockhost);
+ host = cptr->name;
+
+ if (!(aconn = cptr->serv->aconn))
+ {
+ ircstp->is_ref++;
+ sendto_one(cptr, "ERROR :Access denied. No Connect block for server %s",
+ inpath);
+ sendto_ops("Access denied. No Connect block for server %s", inpath);
+ return exit_client(cptr, cptr, cptr, "No Connect block for server");
+ }
+
+ encr = cptr->passwd;
+ if (*aconn->apasswd && !StrEq(aconn->apasswd, encr))
+ {
+ ircstp->is_ref++;
+ sendto_one(cptr, "ERROR :No Access (passwd mismatch) %s", inpath);
+ sendto_ops("Access denied (passwd mismatch) %s", inpath);
+ return exit_client(cptr, cptr, cptr, "Bad Password");
+ }
+ memset(cptr->passwd, '\0', sizeof(cptr->passwd));
+
+ if(!(confopts & FLAGS_HUB))
+ {
+ int i;
+ for (i = 0; i <= highest_fd; i++)
+ if (local[i] && IsServer(local[i]))
+ {
+ ircstp->is_ref++;
+ sendto_one(cptr, "ERROR :I'm a leaf not a hub");
+ return exit_client(cptr, cptr, cptr, "I'm a leaf");
+ }
+ }
+
+ /* aconf->port is a CAPAB field, kind-of. kludge. mm, mm. */
+ /* no longer! this should still get better though */
+ if((aconn->flags & CONN_ZIP))
+ SetZipCapable(cptr);
+ if((aconn->flags & CONN_DKEY))
+ SetWantDKEY(cptr);
+ if (IsUnknown(cptr))
+ {
+ if (aconn->cpasswd[0])
+ sendto_one(cptr, "PASS %s :TS", aconn->cpasswd);
+
+ /* Pass my info to the new server */
+
+#ifdef HAVE_ENCRYPTION_ON
+ if(!WantDKEY(cptr))
+ sendto_one(cptr, "CAPAB SSJOIN NOQUIT BURST UNCONNECT ZIP "
+ "NICKIP TSMODE");
+ else
+ sendto_one(cptr, "CAPAB SSJOIN NOQUIT BURST UNCONNECT DKEY "
+ "ZIP NICKIP TSMODE");
+#else
+ sendto_one(cptr, "CAPAB SSJOIN NOQUIT BURST UNCONNECT ZIP NICKIP TSMODE");
+#endif
+
+ sendto_one(cptr, "SERVER %s 1 :%s",
+ my_name_for_link(me.name, aconn),
+ (me.info[0]) ? (me.info) : "IRCers United");
+ }
+ else
+ {
+ s = (char *) strchr(aconn->host, '@');
+ *s = '\0'; /* should never be NULL -- wanna bet? -Dianora */
+
+ Debug((DEBUG_INFO, "Check Usernames [%s]vs[%s]", aconn->host,
+ cptr->username));
+ if (match(aconn->host, cptr->username))
+ {
+ *s = '@';
+ ircstp->is_ref++;
+ sendto_ops("Username mismatch [%s]v[%s] : %s",
+ aconn->host, cptr->username,
+ get_client_name(cptr, HIDEME));
+ sendto_one(cptr, "ERROR :No Username Match");
+ return exit_client(cptr, cptr, cptr, "Bad User");
+ }
+ *s = '@';
+ }
+
+ /* send routing notice, this should never happen anymore */
+ if (!DoesTS(cptr))
+ {
+ sendto_gnotice("from %s: Warning: %s linked, non-TS server",
+ me.name, get_client_name(cptr, TRUE));
+ sendto_serv_butone(cptr,
+ ":%s GNOTICE :Warning: %s linked, non-TS server",
+ me.name, get_client_name(cptr, TRUE));
+ }
+
+ sendto_one(cptr, "SVINFO %d %d 0 :%ld", TS_CURRENT, TS_MIN,
+ (ts_val) timeofday);
+
+ /* sendto one(cptr, "CAPAB ...."); moved to after PASS but before SERVER
+ * now in two places.. up above and in s_bsd.c. - lucas
+ * This is to make sure we pass on our capabilities before we establish
+ * a server connection
+ */
+
+ /*
+ * *WARNING*
+ * In the following code in place of plain
+ * server's name we send what is returned by
+ * get_client_name which may add the "sockhost" after the name.
+ * It's *very* *important* that there is a SPACE between
+ * the name and sockhost (if present). The receiving server
+ * will start the information field from this first blank and
+ * thus puts the sockhost into info. ...a bit tricky, but
+ * you have been warned, besides code is more neat this way...
+ * --msa
+ */
+
+ cptr->serv->up = me.name;
+ cptr->serv->aconn = aconn;
+
+ throttle_remove(inetntoa((char *)&cptr->ip));
+
+ /* now fill out the servers info so nobody knows dink about it. */
+ memset((char *)&cptr->ip, '\0', sizeof(struct in_addr));
+ strcpy(cptr->hostip, "127.0.0.1");
+ strcpy(cptr->sockhost, "localhost");
+
+#ifdef HAVE_ENCRYPTION_ON
+ if(!CanDoDKEY(cptr) || !WantDKEY(cptr))
+ return do_server_estab(cptr);
+ else
+ {
+ SetNegoServer(cptr); /* VERY IMPORTANT THAT THIS IS HERE */
+ sendto_one(cptr, "DKEY START");
+ }
+#else
+ return do_server_estab(cptr);
+#endif
+
+ return 0;
+}
+
+/*
+ * m_server
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ * parv[2] = serverinfo/hopcount
+ * parv[3] = serverinfo
+ */
+int m_server(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ int i;
+ char info[REALLEN + 1], *inpath, *host;
+ aClient *acptr, *bcptr;
+ aConnect *aconn;
+ int hop;
+ char nbuf[HOSTLEN * 2 + USERLEN + 5]; /* same size as in s_misc.c */
+
+ info[0] = '\0';
+ inpath = get_client_name(cptr, HIDEME);
+
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ sendto_one(cptr, "ERROR :No servername");
+ return 0;
+ }
+
+ hop = 0;
+ host = parv[1];
+ if (parc > 3 && atoi(parv[2]))
+ {
+ hop = atoi(parv[2]);
+ strncpyzt(info, parv[3], REALLEN);
+ }
+ else if (parc > 2)
+ {
+ strncpyzt(info, parv[2], REALLEN);
+ if ((parc > 3) && ((i = strlen(info)) < (REALLEN - 2)))
+ {
+ strcat(info, " ");
+ strncat(info, parv[3], REALLEN - i - 2);
+ info[REALLEN] = '\0';
+ }
+ }
+ /*
+ * July 5, 1997
+ * Rewritten to throw away server cruft from users,
+ * combined the hostname validity test with cleanup of host name,
+ * so a cleaned up hostname can be returned as an error if
+ * necessary. - Dianora
+ */
+
+ /* yes, the if(strlen) below is really needed!! */
+ if (strlen(host) > HOSTLEN)
+ host[HOSTLEN] = '\0';
+
+ if (IsPerson(cptr))
+ {
+ /* A local link that has been identified as a USER tries
+ * something fishy... ;-)
+ */
+ sendto_one(cptr, err_str(ERR_UNKNOWNCOMMAND),
+ me.name, parv[0], "SERVER");
+
+ return 0;
+ }
+ else
+ /* hostile servername check */
+ {
+ /*
+ * Lets check for bogus names and clean them up we don't bother
+ * cleaning up ones from users, becasuse we will never see them
+ * any more - Dianora
+ */
+
+ int bogus_server = 0;
+ int found_dot = 0;
+ char clean_host[(2 * HOSTLEN) + 1];
+ char *s;
+ char *d;
+ int n;
+
+ s = host;
+ d = clean_host;
+ n = (2 * HOSTLEN) - 2;
+
+ while (*s && n > 0)
+ {
+ if ((unsigned char) *s < (unsigned char) ' ')
+ /* Is it a control character? */
+ {
+ bogus_server = 1;
+ *d++ = '^';
+ *d++ = (char) ((unsigned char) *s + 0x40);
+ /* turn it into a printable */
+ n -= 2;
+ }
+ else if ((unsigned char) *s > (unsigned char) '~')
+ {
+ bogus_server = 1;
+ *d++ = '.';
+ n--;
+ }
+ else
+ {
+ if (*s == '.')
+ found_dot = 1;
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ if ((!found_dot) || bogus_server)
+ {
+ sendto_one(sptr, "ERROR :Bogus server name (%s)",
+ clean_host);
+ return exit_client(cptr, cptr, cptr, "Bogus server name");
+ }
+ }
+
+ /*
+ * check to see this host even has an N line before bothering
+ * anyone about it. Its only a quick sanity test to stop the
+ * conference room and win95 ircd dorks. Sure, it will be
+ * redundantly checked again in m_server_estab() *sigh* yes there
+ * will be wasted CPU as the conf list will be scanned twice. But
+ * how often will this happen? - Dianora
+ *
+ * This should (will be) be recoded to check the IP is valid as well,
+ * with a pointer to the valid N line conf kept for later, saving an
+ * extra lookup.. *sigh* - Dianora
+ */
+ if (!IsServer(cptr))
+ {
+ if (!find_aConnect(host))
+ {
+
+#ifdef WARN_NO_NLINE
+ sendto_realops("Link %s dropped, no Connect block",
+ get_client_name(cptr, TRUE));
+#endif
+
+ return exit_client(cptr, cptr, cptr, "No Connect block");
+ }
+ }
+
+ if ((acptr = find_name(host, NULL)))
+ {
+ /*
+ * * This link is trying feed me a server that I already have
+ * access through another path -- multiple paths not accepted
+ * currently, kill this link immediately!!
+ *
+ * Rather than KILL the link which introduced it, KILL the
+ * youngest of the two links. -avalon
+ */
+
+ bcptr = (cptr->firsttime > acptr->from->firsttime) ? cptr :
+ acptr->from;
+ sendto_one(bcptr, "ERROR :Server %s already exists", host);
+ if (bcptr == cptr)
+ {
+ /* Don't complain for servers that are juped */
+ /* (don't complain if the server that already exists is U: lined,
+ unless I actually have a .conf U: line for it */
+ if(!IsULine(acptr) || !find_aUserver(acptr->name))
+ {
+ sendto_gnotice("from %s: Link %s cancelled, server %s already "
+ "exists", me.name, get_client_name(bcptr, HIDEME),
+ host);
+ sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, "
+ "server %s already exists", me.name,
+ get_client_name(bcptr, HIDEME), host);
+ }
+ return exit_client(bcptr, bcptr, &me, "Server Exists");
+ }
+ /* inform all those who care (set +n) -epi */
+ strcpy(nbuf, get_client_name(bcptr, HIDEME));
+ sendto_gnotice("from %s: Link %s cancelled, server %s reintroduced "
+ "by %s", me.name, nbuf, host,
+ get_client_name(cptr, HIDEME));
+ sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, server %s "
+ "reintroduced by %s", me.name, nbuf, host,
+ get_client_name(cptr, HIDEME));
+ exit_client(bcptr, bcptr, &me, "Server Exists");
+ }
+ /*
+ * The following if statement would be nice to remove since user
+ * nicks never have '.' in them and servers must always have '.' in
+ * them. There should never be a server/nick name collision, but it
+ * is possible a capricious server admin could deliberately do
+ * something strange.
+ *
+ * -Dianora
+ */
+
+ if ((acptr = find_client(host, NULL)) && acptr != cptr)
+ {
+ /*
+ * * Server trying to use the same name as a person. Would
+ * cause a fair bit of confusion. Enough to make it hellish for
+ * a while and servers to send stuff to the wrong place.
+ */
+ sendto_one(cptr, "ERROR :Nickname %s already exists!", host);
+ strcpy(nbuf, get_client_name(cptr, HIDEME));
+ sendto_gnotice("from %s: Link %s cancelled, servername/nick collision",
+ me.name, nbuf);
+ sendto_serv_butone(cptr, ":%s GNOTICE :Link %s cancelled, "
+ "servername/nick collision", me.name, nbuf);
+ return exit_client(cptr, cptr, cptr, "Nick as Server");
+ }
+
+ if (IsServer(cptr))
+ {
+ /*
+ * * Server is informing about a new server behind this link.
+ * Create REMOTE server structure, add it to list and propagate
+ * word to my other server links...
+ */
+ if (parc == 1 || info[0] == '\0')
+ {
+ sendto_one(cptr, "ERROR :No server info specified for %s", host);
+ return 0;
+ }
+ /*
+ * * See if the newly found server is behind a guaranteed leaf
+ * (L-line). If so, close the link.
+ *
+ * Depreciated. Kinda redundant with Hlines. -epi
+ */
+ if (!(cptr->serv->aconn->flags & CONN_HUB))
+ {
+ aconn = cptr->serv->aconn;
+ sendto_gnotice("from %s: Non-Hub link %s introduced %s(%s).",
+ me.name, get_client_name(cptr, HIDEME), host,
+ aconn ? (aconn->host ? aconn->host : "*") : "!");
+ sendto_serv_butone(cptr,":%s GNOTICE :Non-Hub link %s introduced "
+ "%s(%s).", me.name,
+ get_client_name(cptr, HIDEME), host,
+ aconn ? (aconn->host ? aconn->host : "*") :
+ "!");
+ sendto_one(cptr, "ERROR :You're not a hub (introducing %s)",
+ host);
+ return exit_client(cptr, cptr, cptr, "Too many servers");
+ }
+
+ acptr = make_client(cptr, sptr);
+ make_server(acptr);
+ acptr->hopcount = hop;
+ strncpyzt(acptr->name, host, sizeof(acptr->name));
+ strncpyzt(acptr->info, info, REALLEN);
+ acptr->serv->up = find_or_add(parv[0]);
+
+ fakelinkserver_update(acptr->name, acptr->info);
+ SetServer(acptr);
+
+ /*
+ * if this server is behind a U-lined server, make it U-lined as
+ * well. - lucas
+ */
+
+ if (IsULine(sptr) || find_aUserver(acptr->name))
+ {
+ acptr->flags |= FLAGS_ULINE;
+ sendto_realops_lev(DEBUG_LEV, "%s introducing super server %s",
+ cptr->name, acptr->name);
+ }
+
+ Count.server++;
+
+ add_client_to_list(acptr);
+ add_to_client_hash_table(acptr->name, acptr);
+ /*
+ * Old sendto_serv_but_one() call removed because we now need
+ * to send different names to different servers (domain name matching)
+ */
+ for (i = 0; i <= highest_fd; i++)
+ {
+ if (!(bcptr = local[i]) || !IsServer(bcptr) || bcptr == cptr ||
+ IsMe(bcptr))
+ continue;
+ if (!(aconn = bcptr->serv->aconn))
+ {
+ sendto_gnotice("from %s: Lost Connect block for %s on %s."
+ " Closing", me.name,
+ get_client_name(cptr, HIDEME), host);
+ sendto_serv_butone(cptr, ":%s GNOTICE :Lost Connect block for"
+ " %s on %s. Closing", me.name,
+ get_client_name(cptr, HIDEME), host);
+ return exit_client(cptr, cptr, cptr, "Lost Connect block");
+ }
+ if (match(my_name_for_link(me.name, aconn), acptr->name) == 0)
+ continue;
+ sendto_one(bcptr, ":%s SERVER %s %d :%s",
+ parv[0], acptr->name, hop + 1, acptr->info);
+ }
+ return 0;
+ }
+
+ if (!IsUnknown(cptr) && !IsHandshake(cptr))
+ return 0;
+
+ /*
+ * * A local link that is still in undefined state wants to be a
+ * SERVER. Check if this is allowed and change status
+ * accordingly...
+ */
+ /*
+ * * Reject a direct nonTS server connection if we're TS_ONLY
+ * -orabidoo
+ */
+
+ strncpyzt(cptr->name, host, sizeof(cptr->name));
+ strncpyzt(cptr->info, info[0] ? info : me.name, REALLEN);
+ cptr->hopcount = hop;
+
+ switch (check_server_init(cptr))
+ {
+ case 0:
+ return m_server_estab(cptr);
+ case 1:
+ sendto_ops("Access check for %s in progress",
+ get_client_name(cptr, HIDEME));
+ return 1;
+ default:
+ ircstp->is_ref++;
+ sendto_ops("Received unauthorized connection from %s.",
+ get_client_host(cptr));
+ return exit_client(cptr, cptr, cptr, "No Connect block");
+ }
+}
+
+/* m_dkey
+ * lucas's code, i assume.
+ * moved here from s_serv.c due to its integration in the encrypted
+ * server negotiation stuffs. -epi
+ */
+
+#define DKEY_GOTIN 0x01
+#define DKEY_GOTOUT 0x02
+
+#define DKEY_DONE(x) (((x) & (DKEY_GOTIN|DKEY_GOTOUT)) == \
+ (DKEY_GOTIN|DKEY_GOTOUT))
+
+int m_dkey(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ if(!(IsNegoServer(sptr) && parc > 1))
+ {
+ if(IsPerson(sptr))
+ return 0;
+ return exit_client(sptr, sptr, sptr, "Not negotiating now");
+ }
+#ifdef HAVE_ENCRYPTION_ON
+ if(mycmp(parv[1], "START") == 0)
+ {
+ char keybuf[1024];
+
+ if(parc != 2)
+ return exit_client(sptr, sptr, sptr, "DKEY START failure");
+
+ if(sptr->serv->sessioninfo_in != NULL &&
+ sptr->serv->sessioninfo_out != NULL)
+ return exit_client(sptr, sptr, sptr, "DKEY START duplicate?!");
+
+ sptr->serv->sessioninfo_in = dh_start_session();
+ sptr->serv->sessioninfo_out = dh_start_session();
+
+ sendto_realops("Initiating diffie-hellman key exchange with %s",
+ sptr->name);
+
+ dh_get_s_public(keybuf, 1024, sptr->serv->sessioninfo_in);
+ sendto_one(sptr, "DKEY PUB I %s", keybuf);
+
+ dh_get_s_public(keybuf, 1024, sptr->serv->sessioninfo_out);
+ sendto_one(sptr, "DKEY PUB O %s", keybuf);
+ return 0;
+ }
+
+ if(mycmp(parv[1], "PUB") == 0)
+ {
+ char keybuf[1024];
+ int keylen;
+
+ if(parc != 4 || !sptr->serv->sessioninfo_in ||
+ !sptr->serv->sessioninfo_out)
+ return exit_client(sptr, sptr, sptr, "DKEY PUB failure");
+
+ if(mycmp(parv[2], "O") == 0) /* their out is my in! */
+ {
+ if(!dh_generate_shared(sptr->serv->sessioninfo_in, parv[3]))
+ return exit_client(sptr, sptr, sptr, "DKEY PUB O invalid");
+ sptr->serv->dkey_flags |= DKEY_GOTOUT;
+ }
+ else if(mycmp(parv[2], "I") == 0) /* their out is my in! */
+ {
+ if(!dh_generate_shared(sptr->serv->sessioninfo_out, parv[3]))
+ return exit_client(sptr, sptr, sptr, "DKEY PUB I invalid");
+ sptr->serv->dkey_flags |= DKEY_GOTIN;
+ }
+ else
+ return exit_client(sptr, sptr, sptr, "DKEY PUB bad option");
+
+ if(DKEY_DONE(sptr->serv->dkey_flags))
+ {
+ sendto_one(sptr, "DKEY DONE");
+ SetRC4OUT(sptr);
+
+ keylen = 1024;
+ if(!dh_get_s_shared(keybuf, &keylen, sptr->serv->sessioninfo_in))
+ return exit_client(sptr, sptr, sptr,
+ "Could not setup encrypted session");
+ sptr->serv->rc4_in = rc4_initstate(keybuf, keylen);
+
+ keylen = 1024;
+ if(!dh_get_s_shared(keybuf, &keylen, sptr->serv->sessioninfo_out))
+ return exit_client(sptr, sptr, sptr,
+ "Could not setup encrypted session");
+ sptr->serv->rc4_out = rc4_initstate(keybuf, keylen);
+
+ dh_end_session(sptr->serv->sessioninfo_in);
+ dh_end_session(sptr->serv->sessioninfo_out);
+
+ sptr->serv->sessioninfo_in = sptr->serv->sessioninfo_out = NULL;
+ return 0;
+ }
+
+ return 0;
+ }
+
+
+ if(mycmp(parv[1], "DONE") == 0)
+ {
+ if(!((sptr->serv->sessioninfo_in == NULL &&
+ sptr->serv->sessioninfo_out == NULL) &&
+ (sptr->serv->rc4_in != NULL && sptr->serv->rc4_out != NULL)))
+ return exit_client(sptr, sptr, sptr, "DKEY DONE when not done!");
+ SetRC4IN(sptr);
+ sendto_realops("Diffie-Hellman exchange with %s complete, connection "
+ "encrypted.", sptr->name);
+ sendto_one(sptr, "DKEY EXIT");
+ return RC4_NEXT_BUFFER;
+ }
+
+ if(mycmp(parv[1], "EXIT") == 0)
+ {
+ if(!(IsRC4IN(sptr) && IsRC4OUT(sptr)))
+ return exit_client(sptr, sptr, sptr, "DKEY EXIT when not in "
+ "proper stage");
+ ClearNegoServer(sptr);
+ return do_server_estab(sptr);
+ }
+#endif
+ return 0;
+}
+
--- /dev/null
+/* m_services.c - Because s_user.c was just crazy.
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free softwmare; 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 1, 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.
+ */
+
+/* $Id: m_services.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "msg.h"
+#include "channel.h"
+#include <sys/stat.h>
+#include <utmp.h>
+#include <fcntl.h>
+#include "h.h"
+#include "userban.h"
+#include "clones.h"
+
+/* Externally defined stuffs */
+extern int user_modes[];
+
+/*
+ * the services aliases. *
+ *
+ * NICKSERV - /nickserv * CHANSERV - /chanserv * OPERSERV -
+ * /operserv * MEMOSERV - /memoserv * SERVICES - /services *
+ * IDENTIFY - /identify * taz's code -mjs
+ */
+
+/* Code provided by orabidoo */
+/*
+ * a random number generator loosely based on RC5; assumes ints are at
+ * least 32 bit
+ */
+
+static unsigned long
+my_rand()
+{
+ static unsigned long s = 0, t = 0, k = 12345678;
+ int i;
+
+ if (s == 0 && t == 0)
+ {
+ s = (unsigned long) getpid();
+ t = (unsigned long) time(NULL);
+ }
+ for (i = 0; i < 12; i++)
+ {
+ s = (((s ^ t) << (t & 31)) | ((s ^ t) >> (31 - (t & 31)))) + k;
+ k += s + t;
+ t = (((t ^ s) << (s & 31)) | ((t ^ s) >> (31 - (s & 31)))) + k;
+ k += s + t;
+ }
+ return s;
+}
+
+/* m_ns */
+int m_ns(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aClient *acptr;
+
+ if (check_registered_user(sptr))
+ return 0;
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ if(MyClient(sptr))
+ sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
+ return -1;
+ }
+ if ((acptr = find_server(Services_Name, NULL)))
+ {
+ if(confopts & FLAGS_SERVHUB)
+ sendto_one(acptr, ":%s NS :%s", parv[0], parv[1]);
+ else
+ sendto_one(acptr, ":%s PRIVMSG %s@%s :%s",
+ parv[0], NICKSERV, Services_Name, parv[1]);
+ }
+ else
+ sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name,
+ parv[0], NICKSERV);
+ return 0;
+}
+
+/* m_cs */
+int m_cs(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aClient *acptr;
+
+ if (check_registered_user(sptr))
+ return 0;
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ if(MyClient(sptr))
+ sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
+ return -1;
+ }
+ if ((acptr = find_server(Services_Name, NULL)))
+ {
+ if(confopts & FLAGS_SERVHUB)
+
+ sendto_one(acptr, ":%s CS :%s", parv[0], parv[1]);
+ else
+ sendto_one(acptr, ":%s PRIVMSG %s@%s :%s",
+ parv[0], CHANSERV, Services_Name, parv[1]);
+ }
+ else
+ sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name,
+ parv[0], CHANSERV);
+ return 0;
+}
+
+/* m_ms */
+int m_ms(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aClient *acptr;
+
+ if (check_registered_user(sptr))
+ return 0;
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ if(MyClient(sptr))
+ sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
+ return -1;
+ }
+ if ((acptr = find_server(Services_Name, NULL)))
+ {
+ if(confopts & FLAGS_SERVHUB)
+ sendto_one(acptr, ":%s MS :%s", parv[0], parv[1]);
+ else
+ sendto_one(acptr, ":%s PRIVMSG %s@%s :%s",
+ parv[0], MEMOSERV, Services_Name, parv[1]);
+ }
+ else
+ sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name,
+ parv[0], MEMOSERV);
+ return 0;
+}
+
+/* m_rs */
+int m_rs(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aClient *acptr;
+
+ if (check_registered_user(sptr))
+ return 0;
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ if(MyClient(sptr))
+ sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
+ return -1;
+ }
+ if ((acptr = find_server(Services_Name, NULL)))
+ {
+ if(confopts & FLAGS_SERVHUB)
+ sendto_one(acptr, ":%s RS :%s", parv[0], parv[1]);
+ else
+ sendto_one(acptr, ":%s PRIVMSG %s@%s :%s",
+ parv[0], ROOTSERV, Services_Name, parv[1]);
+ }
+ else
+ sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name,
+ parv[0], ROOTSERV);
+ return 0;
+}
+
+/* m_os */
+int m_os(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aClient *acptr;
+
+ if (check_registered_user(sptr))
+ return 0;
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ if(MyClient(sptr))
+ sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
+ return -1;
+ }
+ if ((acptr = find_server(Stats_Name, NULL)))
+ {
+ if(confopts & FLAGS_SERVHUB)
+ sendto_one(acptr, ":%s OS :%s", parv[0], parv[1]);
+ else
+ sendto_one(acptr, ":%s PRIVMSG %s@%s :%s",
+ parv[0], OPERSERV, Stats_Name, parv[1]);
+ }
+ else
+ sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name,
+ parv[0], OPERSERV);
+ return 0;
+}
+
+/* m_ss */
+int m_ss(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aClient *acptr;
+
+ if (check_registered_user(sptr))
+ return 0;
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ if(MyClient(sptr))
+ sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
+ return -1;
+ }
+ if ((acptr = find_server(Stats_Name, NULL)))
+ {
+ if(confopts & FLAGS_SERVHUB)
+ sendto_one(acptr, ":%s SS :%s", parv[0], parv[1]);
+ else
+ sendto_one(acptr, ":%s PRIVMSG %s@%s :%s",
+ parv[0], STATSERV, Stats_Name, parv[1]);
+ }
+ else
+ sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name,
+ parv[0], STATSERV);
+ return 0;
+}
+
+/* m_hs */
+int m_hs(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aClient *acptr;
+
+ if (check_registered_user(sptr))
+ return 0;
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ if(MyClient(sptr))
+ sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
+ return -1;
+ }
+ if ((acptr = find_server(Stats_Name, NULL)))
+ {
+ if(confopts & FLAGS_SERVHUB)
+ sendto_one(acptr, ":%s HS :%s", parv[0], parv[1]);
+ else
+ sendto_one(acptr, ":%s PRIVMSG %s@%s :%s",
+ parv[0], HELPSERV, Stats_Name, parv[1]);
+ }
+ else
+ sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name,
+ parv[0], HELPSERV);
+ return 0;
+}
+
+/* m_services -- see df465+taz */
+int m_services(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ char *tmps;
+
+ if (check_registered_user(sptr))
+ return 0;
+
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
+ return -1;
+ }
+ if ((strlen(parv[1]) >= 4) && (!myncmp(parv[1], "help", 4)))
+ {
+ sendto_one(sptr, ":services!service@%s NOTICE %s :For ChanServ "
+ "help use: /chanserv help", Services_Name,
+ sptr->name);
+ sendto_one(sptr, ":services!service@%s NOTICE %s :For NickServ "
+ "help use: /nickserv help", Services_Name,
+ sptr->name);
+ sendto_one(sptr, ":services!service@%s NOTICE %s :For MemoServ "
+ "help use: /memoserv help", Services_Name,
+ sptr->name);
+ return 0;
+ }
+ if ((tmps = (char *) strchr(parv[1], ' ')))
+ {
+ for(; *tmps == ' '; tmps++); /* er.. before this for loop, the next
+ * comparison would always compare '#'
+ * with ' '.. oops. - lucas
+ */
+ if (*tmps == '#')
+ return m_cs(cptr, sptr, parc, parv);
+ else
+ return m_ns(cptr, sptr, parc, parv);
+ }
+ return m_ns(cptr, sptr, parc, parv);
+}
+
+/* m_identify df465+taz */
+int m_identify(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ char buf[BUFSIZE+1];
+ char *myparv[MAXPARA + 1];
+
+ if (check_registered_user(sptr))
+ return 0;
+
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
+ return -1;
+ }
+ (void) ircsnprintf(buf, BUFSIZE, "IDENTIFY %s", parv[1]);
+
+ myparv[0]=parv[0];
+ myparv[1]=buf;
+
+ if (*parv[1] == '#')
+ return m_cs(cptr, sptr, parc, myparv);
+ else
+ return m_ns(cptr, sptr, parc, myparv);
+
+ return 0;
+}
+
+/* s_svsnick - Pretty straight forward. Mostly straight outta df
+ * - Raistlin
+ * parv[0] = sender
+ * parv[1] = old nickname
+ * parv[2] = new nickname
+ * parv[3] = timestamp
+ */
+int m_svsnick(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aClient *acptr, *ocptr;
+ char newnick[NICKLEN + 1];
+
+ if (!IsULine(sptr)||parc < 4||(strlen(parv[2]) > NICKLEN))
+ return 0;
+
+ if(hunt_server(cptr, sptr, ":%s SVSNICK %s %s :%s", 1, parc, parv) != HUNTED_ISME)
+ return 0;
+
+ /* can't find them? oh well. */
+ if ((acptr = find_person(parv[1], NULL)) == NULL)
+ return 0;
+
+ strncpyzt(newnick, parv[2], NICKLEN+1);
+
+ /* does the nick we're changing them to already exist? */
+ /* Try to make a unique nickname */
+ if((ocptr = find_client(newnick, NULL)) != NULL)
+ {
+ int tries = 0, nprefix;
+
+ do
+ {
+ nprefix = my_rand() % 99999;
+ ircsnprintf(newnick, NICKLEN, "%s-%d", parv[2], nprefix);
+ tries++;
+ } while (((ocptr = find_client(newnick, NULL)) != NULL) && (tries < 10));
+
+ /* well, we tried.. */
+ if(ocptr)
+ {
+ if(IsUnknown(ocptr))
+ return exit_client(ocptr, ocptr, &me, "SVSNICK Override");
+ else
+ return exit_client(acptr, acptr, &me, "SVSNICK Collide");
+ }
+ }
+
+ if(acptr->umode & UMODE_r)
+ {
+ unsigned int oldumode;
+ char mbuf[BUFSIZE];
+
+ oldumode = acptr->umode;
+ acptr->umode &= ~UMODE_r;
+
+ send_umode(acptr, acptr, oldumode, ALL_UMODES, mbuf);
+ }
+
+ acptr->tsinfo = atoi(parv[3]);
+#ifdef ANTI_NICK_FLOOD
+ acptr->last_nick_change = atoi(parv[3]);
+#endif
+ sendto_common_channels(acptr, ":%s NICK :%s", parv[1], newnick);
+ add_history(acptr, 1);
+ sendto_serv_butone(NULL, ":%s NICK %s :%d", parv[1], newnick,
+ acptr->tsinfo);
+ if(acptr->name[0])
+ del_from_client_hash_table(acptr->name, acptr);
+ strcpy(acptr->name, newnick);
+ add_to_client_hash_table(acptr->name, acptr);
+
+ return 0;
+}
+
+/* channel_svsmode:
+ * parv[0] sender
+ * parv[1] channel
+ * parv[2] modes
+ * parv[3] nick
+ * parv[4] nickts
+ * currently, only a mode of -b is supported.
+ * services should use MODE for regular channel modes.
+ * 2/5/00 lucas
+ * preconditions: parc >= 3, sptr is ulined
+ */
+int channel_svsmode(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aChannel *chptr;
+ aClient *acptr = NULL;
+ char *m, *nick = NULL;
+ char change = '+';
+ ts_val nickts = 0;
+ int sendmsg = 1;
+
+ if(!(chptr = find_channel(parv[1], NULL)))
+ return 0;
+
+ if(parc >= 4)
+ {
+ nick = parv[3];
+ if(parc > 4)
+ nickts = atol(parv[4]);
+ }
+
+ if(nick)
+ {
+ acptr = find_person(nick, NULL);
+ if(!acptr || (nickts && acptr->tsinfo != nickts))
+ return 0;
+ }
+
+ for(m = parv[2]; *m; m++)
+ switch(*m)
+ {
+ case '+':
+ case '-':
+ change = *m;
+ break;
+
+ case 'b':
+ if(nick && MyClient(acptr) && change == '-')
+ {
+ remove_matching_bans(chptr, acptr, &me);
+ sendmsg--;
+ }
+ break;
+
+#ifdef EXEMPT_LISTS
+ case 'e':
+ if (nick && MyClient(acptr) && change == '-')
+ {
+ remove_matching_exempts(chptr, acptr, &me);
+ sendmsg--;
+ }
+ break;
+#endif
+
+#ifdef INVITE_LISTS
+ case 'I':
+ if (nick && MyClient(acptr) && change == '-')
+ {
+ remove_matching_invites(chptr, acptr, &me);
+ sendmsg--;
+ }
+ break;
+#endif
+
+ default:
+ sendmsg++;
+ break;
+ }
+
+ if(!sendmsg) return 0;
+
+ if(nick)
+ sendto_serv_butone(cptr, ":%s SVSMODE %s %s %s %ld", parv[0], parv[1],
+ parv[2], nick, acptr->tsinfo);
+ else
+ sendto_serv_butone(cptr, ":%s SVSMODE %s %s", parv[0], parv[1],
+ parv[2]);
+
+ return 0;
+}
+
+/* m_svsmode - df function integrated
+ * - Raistlin
+ * -- Behaviour changed - Epi (11/30/99)
+ * parv[0] - sender
+ * parv[1] - nick
+ * parv[2] - TS (or mode, depending on svs version)
+ * parv[3] - mode (or services id if old svs version)
+ * parv[4] - optional arguement (services id)
+ */
+int m_svsmode(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ int flag, *s, what, oldumode;
+ char *m, *modes, *optarg;
+ aClient *acptr;
+ ts_val ts = 0;
+
+ if (!IsULine(sptr) || (parc < 3))
+ return 0;
+
+ if (parv[1][0] == '#')
+ return channel_svsmode(cptr, sptr, parc, parv);
+
+ if ((parc >= 4) && ((parv[3][0] == '+') || (parv[3][0] == '-')))
+ {
+ ts = atol(parv[2]);
+ modes = parv[3];
+ optarg = (parc > 4) ? parv[4] : NULL;
+ }
+ else
+ {
+ modes = parv[2];
+ optarg = (parc > 3) ? parv[3] : NULL;
+ }
+
+ if (!(acptr = find_person(parv[1], NULL)))
+ return 0;
+
+ if (ts && (ts != acptr->tsinfo))
+ return 0;
+
+ what = MODE_ADD;
+ oldumode = acptr->umode;
+ for (m = modes; *m; m++)
+ switch(*m)
+ {
+ case '+':
+ what = MODE_ADD;
+ break;
+ case '-':
+ what = MODE_DEL;
+ break;
+ case ' ':
+ case '\n':
+ case '\r':
+ case '\t':
+ break;
+ case 'd':
+ if (optarg && IsDigit(*optarg))
+ acptr->user->servicestamp = strtoul(optarg, NULL, 0);
+ break;
+ case 'T':
+ if (optarg && IsDigit(*optarg))
+ acptr->user->servicetype = strtoul(optarg, NULL, 0);
+ break;
+ default:
+ for (s = user_modes; (flag = *s); s += 2)
+ {
+ if (*m == (char)(*(s+1)))
+ {
+ if (what == MODE_ADD)
+ {
+ /* no opering this way */
+ if (flag & (UMODE_o|UMODE_O))
+ break;
+ acptr->umode |= flag;
+ }
+ else if (acptr->umode & flag)
+ {
+ acptr->umode &= ~flag;
+
+ /* deopering ok */
+ if (MyConnect(acptr) && (flag & (UMODE_o|UMODE_O))
+ && !IsAnOper(acptr))
+ {
+ acptr->oflag = 0;
+ remove_from_list(&oper_list, acptr, NULL);
+ }
+ }
+
+ break;
+ }
+ }
+ break;
+ }
+
+ if (optarg)
+ sendto_serv_butone(cptr, ":%s SVSMODE %s %ld %s %s",
+ parv[0], parv[1], acptr->tsinfo, modes, optarg);
+ else
+ sendto_serv_butone(cptr, ":%s SVSMODE %s %ld %s",
+ parv[0], parv[1], acptr->tsinfo, modes);
+
+ if (MyClient(acptr) && (oldumode != acptr->umode))
+ {
+ char buf[BUFSIZE];
+ send_umode(acptr, acptr, oldumode, ALL_UMODES, buf);
+ }
+
+ return 0;
+}
+
+/* m_svshold
+ * Adds a temporary local nick ban.
+ * parv[0] - sender
+ * parv[1] - nick
+ * parv[2] - duration (0 to remove existing ban)
+ * parv[3] - optional reason
+ */
+int m_svshold(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ struct simBan *ban, *oban;
+ char *reason, *mask;
+ int length;
+
+ if(!IsULine(sptr) || parc < 3)
+ return 0;
+
+ mask = parv[1];
+ length = strtol(parv[2], NULL, 0);
+ reason = (parc < 4) ? "Nickname is reserved, try again later" : parv[3];
+
+ /* marked local so netbursts don't propagate it */
+ ban = make_simpleban(SBAN_LOCAL|SBAN_NICK|SBAN_TEMPORARY, parv[1]);
+ if(!ban)
+ {
+ sendto_realops_lev(DEBUG_LEV, "make_simpleban(%s) failed on svshold", mask);
+ return 0;
+ }
+ ban->reason = NULL;
+
+ if((oban = find_simban_exact(ban)) != NULL)
+ {
+ simban_free(ban);
+ ban = NULL;
+
+ if(length <= 0)
+ {
+ remove_simban(oban);
+ }
+ else
+ {
+ if(oban->reason)
+ MyFree(oban->reason);
+ oban->reason = (char *) MyMalloc(strlen(reason) + 1);
+ strcpy(oban->reason, reason);
+ oban->timeset = NOW;
+ oban->duration = length;
+ }
+ }
+ else if(length > 0)
+ {
+ ban->reason = (char *) MyMalloc(strlen(reason) + 1);
+ strcpy(ban->reason, reason);
+ ban->timeset = NOW;
+ ban->duration = length;
+ add_simban(ban);
+ }
+ else
+ simban_free(ban);
+
+ if(parc < 4)
+ sendto_serv_butone(cptr, ":%s SVSHOLD %s %s", sptr->name, parv[1], parv[2]);
+ else
+ sendto_serv_butone(cptr, ":%s SVSHOLD %s %s :%s", sptr->name, parv[1], parv[2], parv[3]);
+
+ return 0;
+}
+
+
+/* m_svsclone
+* Sets a clone limit for an IP mask (1.2.3.4 or 1.2.3.*).
+* parv[0] - sender
+* parv[1] - mask
+* parv[2] - duration (0 to revert to default limit)
+*/
+int
+m_svsclone(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ int d;
+
+ if (parc != 3)
+ return 0;
+
+ if (!(IsServer(sptr) || IsULine(sptr)))
+ return 0;
+
+ d = atoi(parv[2]);
+ clones_set(parv[1], CLIM_HARD_GLOBAL, d);
+ sendto_serv_butone(cptr, ":%s SVSCLONE %s %s", parv[0], parv[1], parv[2]);
+
+ return 0;
+}
+
--- /dev/null
+/* m_stats.c
+ * Copyright (c) 2004, The Bahamut Development Team and Aaron Wiebe
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free softwmare; 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 1, 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.
+ */
+
+/* $Id: m_stats.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "msg.h"
+#include "channel.h"
+#include <sys/stat.h>
+#include <utmp.h>
+#include <fcntl.h>
+#include "h.h"
+#include "zlink.h"
+#include "userban.h"
+#include "blalloc.h"
+#include "throttle.h"
+#include "whowas.h"
+#include "res.h"
+#include "sbuf.h"
+#include "clones.h"
+
+#if defined(DEBUGMODE) && defined(HAVE_GETRUSAGE)
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+
+extern float curSendK, curRecvK;
+extern aWhowas WHOWAS[];
+extern aCache *cachetop;
+#ifdef DEBUGMODE
+extern void report_fds(aClient *);
+#endif
+
+/* internal function defines */
+
+static void show_opers(aClient *, char *);
+static void show_servers(aClient *, char *);
+static void count_memory(aClient *, char *);
+#ifdef DEBUGMODE
+static void send_usage(aClient *, char *);
+#endif
+static void count_whowas_memory(int *, u_long *);
+static void serv_info(aClient *, char *);
+static void tstats(aClient *, char *);
+static u_long cres_mem(aClient *);
+static u_long count_conf_memory(aClient *);
+
+/* support functions */
+/* show_opers
+ * replies to stats p requests
+ */
+
+static u_long
+cres_mem(aClient *sptr)
+{
+ aCache *c = cachetop;
+ struct hostent *h;
+ int i;
+ u_long nm = 0, im = 0, sm = 0, ts = 0;
+
+ for (; c; c = c->list_next)
+ {
+ sm += sizeof(*c);
+ h = &c->he;
+ for (i = 0; h->h_addr_list[i]; i++)
+ {
+ im += sizeof(char *);
+ im += sizeof(struct in_addr);
+ }
+ im += sizeof(char *);
+
+ for (i = 0; h->h_aliases[i]; i++)
+ {
+ nm += sizeof(char *);
+
+ nm += strlen(h->h_aliases[i]);
+ }
+ nm += i - 1;
+ nm += sizeof(char *);
+
+ if (h->h_name)
+ nm += strlen(h->h_name);
+ }
+ ts = ARES_CACSIZE * sizeof(CacheTable);
+ sendto_one(sptr, ":%s %d %s :RES table sz %d",
+ me.name, RPL_STATSDEBUG, sptr->name, ts);
+ sendto_one(sptr, ":%s %d %s :RES Structs sz %d IP storage sz %d "
+ "Name storage sz %d", me.name, RPL_STATSDEBUG, sptr->name, sm,
+ im, nm);
+ return ts + sm + im + nm;
+}
+
+static void
+count_whowas_memory(int *wwu, u_long *wwum)
+{
+ aWhowas *tmp;
+ int i;
+ int u = 0;
+ u_long um = 0;
+
+ /* count the number of used whowas structs in 'u' */
+ /* count up the memory used of whowas structs in um */
+
+ for (i = 0, tmp = &WHOWAS[0]; i < NICKNAMEHISTORYLENGTH; i++, tmp++)
+ if (tmp->hashv != -1)
+ {
+ u++;
+ um += sizeof(aWhowas);
+ }
+ *wwu = u;
+ *wwum = um;
+ return;
+}
+
+#define MAXUSERVS 24
+
+/*
+ * Send conf memory usage to a client, and return the total bytes in use.
+ */
+static u_long
+count_conf_memory(aClient *cptr)
+{
+ int cnc = 0; u_long cnm = 0; /* aConnects */
+ int alc = 0; u_long alm = 0; /* aAllows */
+ int opc = 0; u_long opm = 0; /* aOpers */
+ int ptc = 0; u_long ptm = 0; /* aPorts */
+ int clc = 0; u_long clm = 0; /* aClasses */
+ int usc = 0; u_long usm = 0; /* U:lined */
+ int tc = 0; u_long tm = 0; /* totals */
+
+ int i;
+ aConnect *cnptr;
+ aAllow *alptr;
+ aOper *opptr;
+ aPort *ptptr;
+ aClass *clptr;
+
+ for (cnptr = connects; cnptr; cnptr = cnptr->next)
+ {
+ cnc++;
+ cnm += sizeof(*cnptr);
+ if (!BadPtr(cnptr->host))
+ cnm += strlen(cnptr->host) + 1;
+ if (!BadPtr(cnptr->apasswd))
+ cnm += strlen(cnptr->apasswd) + 1;
+ if (!BadPtr(cnptr->cpasswd))
+ cnm += strlen(cnptr->cpasswd) + 1;
+ if (!BadPtr(cnptr->name))
+ cnm += strlen(cnptr->name) + 1;
+ if (!BadPtr(cnptr->source))
+ cnm += strlen(cnptr->source) + 1;
+ if (!BadPtr(cnptr->class_name))
+ cnm += strlen(cnptr->class_name) + 1;
+ }
+
+ for (alptr = allows; alptr; alptr = alptr->next)
+ {
+ alc++;
+ alm += sizeof(*alptr);
+ if (!BadPtr(alptr->ipmask))
+ alm += strlen(alptr->ipmask) + 1;
+ if (!BadPtr(alptr->passwd))
+ alm += strlen(alptr->passwd) + 1;
+ if (!BadPtr(alptr->hostmask))
+ alm += strlen(alptr->hostmask) + 1;
+ if (!BadPtr(alptr->class_name))
+ alm += strlen(alptr->class_name) + 1;
+ }
+
+ for (opptr = opers; opptr; opptr = opptr->next)
+ {
+ opc++;
+ opm += sizeof(*opptr);
+ if (!BadPtr(opptr->passwd))
+ opm += strlen(opptr->passwd) + 1;
+ if (!BadPtr(opptr->nick))
+ opm += strlen(opptr->nick) + 1;
+ if (!BadPtr(opptr->class_name))
+ opm += strlen(opptr->class_name) + 1;
+ for (i = 0; i < sizeof(opptr->hosts)/sizeof(opptr->hosts[0]); i++)
+ if (!BadPtr(opptr->hosts[i]))
+ opm += strlen(opptr->hosts[i]) + 1;
+ }
+
+ for (ptptr = ports; ptptr; ptptr = ptptr->next)
+ {
+ ptc++;
+ ptm += sizeof(*ptptr);
+ if (!BadPtr(ptptr->allow))
+ ptm += strlen(ptptr->allow) + 1;
+ if (!BadPtr(ptptr->address))
+ ptm += strlen(ptptr->address) + 1;
+ }
+
+ for (clptr = classes; clptr; clptr = clptr->next)
+ {
+ clc++;
+ clm += sizeof(*clptr);
+ if (!BadPtr(clptr->name))
+ clm += strlen(clptr->name) + 1;
+ }
+
+ for (i = 0; i < MAXUSERVS; i++)
+ {
+ if (!BadPtr(uservers[i]))
+ {
+ usc++;
+ usm += strlen(uservers[i]) + 1;
+ }
+ }
+
+ tc = cnc + alc + opc + ptc + clc + usc;
+ tm = cnm + alm + opm + ptm + clm + usm;
+
+ sendto_one(cptr, ":%s %d %s :Conf entries %d(%lu):",
+ me.name, RPL_STATSDEBUG, cptr->name, tc, tm);
+ sendto_one(cptr, ":%s %d %s : aConnect %d(%lu)",
+ me.name, RPL_STATSDEBUG, cptr->name, cnc, cnm);
+ sendto_one(cptr, ":%s %d %s : aAllow %d(%lu)",
+ me.name, RPL_STATSDEBUG, cptr->name, alc, alm);
+ sendto_one(cptr, ":%s %d %s : aOper %d(%lu)",
+ me.name, RPL_STATSDEBUG, cptr->name, opc, opm);
+ sendto_one(cptr, ":%s %d %s : aPort %d(%lu)",
+ me.name, RPL_STATSDEBUG, cptr->name, ptc, ptm);
+ sendto_one(cptr, ":%s %d %s : aClass %d(%lu)",
+ me.name, RPL_STATSDEBUG, cptr->name, clc, clm);
+ sendto_one(cptr, ":%s %d %s : U-servers %d(%lu)",
+ me.name, RPL_STATSDEBUG, cptr->name, usc, usm);
+
+ return tm;
+}
+
+
+
+#ifdef DEBUGMODE
+static void
+send_usage(aClient *cptr, char *nick)
+{
+
+#if defined( HAVE_GETRUSAGE )
+ struct rusage rus;
+ time_t secs, rup;
+
+#ifdef hz
+#define hzz hz
+#else
+#ifdef HZ
+#define hzz HZ
+#else
+ int hzz = 1;
+
+#endif
+#endif
+
+ if (getrusage(RUSAGE_SELF, &rus) == -1) {
+ sendto_one(cptr, ":%s NOTICE %s :Getruseage error: %s.",
+ me.name, nick, sys_errlist[errno]);
+ return;
+ }
+ secs = rus.ru_utime.tv_sec + rus.ru_stime.tv_sec;
+ rup = timeofday - me.since;
+ if (secs == 0)
+ secs = 1;
+
+ sendto_one(cptr,
+ ":%s %d %s :CPU Secs %d:%d User %d:%d System %d:%d",
+ me.name, RPL_STATSDEBUG, nick, secs / 60, secs % 60,
+ rus.ru_utime.tv_sec / 60, rus.ru_utime.tv_sec % 60,
+ rus.ru_stime.tv_sec / 60, rus.ru_stime.tv_sec % 60);
+ sendto_one(cptr, ":%s %d %s :RSS %d ShMem %d Data %d Stack %d",
+ me.name, RPL_STATSDEBUG, nick, rus.ru_maxrss,
+ rus.ru_ixrss / (rup * hzz), rus.ru_idrss / (rup * hzz),
+ rus.ru_isrss / (rup * hzz));
+ sendto_one(cptr, ":%s %d %s :Swaps %d Reclaims %d Faults %d",
+ me.name, RPL_STATSDEBUG, nick, rus.ru_nswap,
+ rus.ru_minflt, rus.ru_majflt);
+ sendto_one(cptr, ":%s %d %s :Block in %d out %d",
+ me.name, RPL_STATSDEBUG, nick, rus.ru_inblock,
+ rus.ru_oublock);
+ sendto_one(cptr, ":%s %d %s :Msg Rcv %d Send %d",
+ me.name, RPL_STATSDEBUG, nick, rus.ru_msgrcv, rus.ru_msgsnd);
+ sendto_one(cptr, ":%s %d %s :Signals %d Context Vol. %d Invol %d",
+ me.name, RPL_STATSDEBUG, nick, rus.ru_nsignals,
+ rus.ru_nvcsw, rus.ru_nivcsw);
+#else
+#if defined( HAVE_TIMES )
+ struct tms tmsbuf;
+ time_t secs, mins;
+ int hzz = 1, ticpermin;
+ int umin, smin, usec, ssec;
+
+ ticpermin = hzz * 60;
+
+ umin = tmsbuf.tms_utime / ticpermin;
+ usec = (tmsbuf.tms_utime % ticpermin) / (float) hzz;
+ smin = tmsbuf.tms_stime / ticpermin;
+ ssec = (tmsbuf.tms_stime % ticpermin) / (float) hzz;
+ secs = usec + ssec;
+ mins = (secs / 60) + umin + smin;
+ secs %= hzz;
+ if (times(&tmsbuf) == -1) {
+ sendto_one(cptr, ":%s %d %s :times(2) error: %s.",
+ me.name, RPL_STATSDEBUG, nick, strerror(errno));
+ return;
+ }
+ secs = tmsbuf.tms_utime + tmsbuf.tms_stime;
+
+ sendto_one(cptr,
+ ":%s %d %s :CPU Secs %d:%d User %d:%d System %d:%d",
+ me.name, RPL_STATSDEBUG, nick, mins, secs, umin, usec,
+ smin, ssec);
+#endif /* HAVE_TIMES */
+#endif /* HAVE_GETRUSAGE */
+ sendto_one(cptr, ":%s %d %s :Reads %d Writes %d",
+ me.name, RPL_STATSDEBUG, nick, readcalls, writecalls);
+/* sendto_one(cptr, ":%s %d %s :DBUF alloc %d used %d",
+ me.name, RPL_STATSDEBUG, nick, DBufCount, DBufUsedCount);
+ */
+ sendto_one(cptr,
+ ":%s %d %s :Writes: <0 %d 0 %d <16 %d <32 %d <64 %d",
+ me.name, RPL_STATSDEBUG, nick,
+ writeb[0], writeb[1], writeb[2], writeb[3], writeb[4]);
+ sendto_one(cptr,
+ ":%s %d %s :<128 %d <256 %d <512 %d <1024 %d >1024 %d",
+ me.name, RPL_STATSDEBUG, nick,
+ writeb[5], writeb[6], writeb[7], writeb[8], writeb[9]);
+ return;
+}
+#endif /* DEBUGMODE */
+
+
+static void
+count_memory(aClient *cptr, char *nick)
+{
+ extern aChannel *channel;
+
+ extern BlockHeap *free_local_aClients;
+ extern BlockHeap *free_Links;
+ extern BlockHeap *free_DLinks;
+ extern BlockHeap *free_remote_aClients;
+ extern BlockHeap *free_anUsers;
+ extern BlockHeap *free_channels;
+ extern BlockHeap *free_chanMembers;
+#ifdef FLUD
+ extern BlockHeap *free_fludbots;
+#endif
+ extern BlockHeap *free_cloneents;
+
+ extern aMotd *motd;
+ extern aMotd *shortmotd;
+ extern aMotd *helpfile;
+
+ extern int num_msg_trees;
+
+ aClient *acptr;
+ Link *link;
+ chanMember *cm;
+ aBan *bp;
+ aChannel *chptr;
+ aMotd *amo;
+ CloneEnt *ce;
+
+ int lc = 0; /* local clients */
+ int lcc = 0; /* local client conf links */
+ int rc = 0; /* remote clients */
+ int us = 0; /* user structs */
+ int chu = 0; /* channel users */
+ int chi = 0; /* channel invites */
+ int chb = 0; /* channel bans */
+ int wwu = 0; /* whowas users */
+ int ch = 0;
+ int usi = 0; /* users invited */
+ int usc = 0; /* users in channels */
+ int usdm = 0; /* dccallow local */
+ int usdr = 0; /* dccallow remote */
+ int uss = 0; /* silenced users */
+ int aw = 0; /* aways set */
+ int number_servers_cached; /* number of servers cached by
+ * scache
+ */
+ u_long chbm = 0; /* memory used by channel bans */
+ u_long lcm = 0; /* memory used by local clients */
+ u_long rcm = 0; /* memory used by remote clients */
+ u_long awm = 0; /* memory used by aways */
+ u_long wwm = 0; /* whowas array memory used */
+ u_long rm = 0; /* res memory used */
+ u_long mem_servers_cached; /* memory used by scache */
+
+ u_long totco = 0;
+ u_long totcl = 0;
+ u_long totch = 0;
+ u_long totww = 0;
+ u_long totmisc = 0;
+ u_long tothash = 0;
+ u_long totuban = 0;
+ u_long tot = 0;
+
+ int wlh=0, wle=0; /* watch headers/entries */
+ u_long wlhm=0; /* memory used by watch */
+
+ int lcalloc = 0; /* local clients allocated */
+ int rcalloc = 0; /* remote clients allocated */
+ int useralloc = 0; /* allocated users */
+ int linkalloc = 0; /* allocated links */
+ int dlinkalloc = 0; /* allocated dlinks */
+ int totallinks = 0; /* total links used */
+ int chanalloc = 0; /* total channels alloc'd */
+ int cmemballoc = 0;
+ int clonealloc = 0;
+ u_long lcallocsz = 0, rcallocsz = 0; /* size for stuff above */
+ u_long userallocsz = 0, linkallocsz = 0, dlinkallocsz = 0, chanallocsz = 0;
+ u_long cmemballocsz = 0, cloneallocsz = 0;
+
+ int fludalloc = 0;
+ u_long fludallocsz = 0;
+ int fludlink = 0;
+
+ int cloneent = 0;
+ u_long cloneentsz = 0;
+
+ int motdlen = 0;
+
+ int servn = 0;
+
+ /* sbuf counts -- 0 = used, 1 = total, 2 = size */
+ int sbuf_user[3], sbuf_small[3], sbuf_large[3];
+ /* block counts -- 0 = total, 1 = size */
+ int sbuf_blocks[2], sbuf_userblocks[2];
+
+
+ count_whowas_memory(&wwu, &wwm); /* no more away memory to count */
+
+ count_watch_memory(&wlh, &wlhm);
+
+ for(acptr = client; acptr; acptr = acptr->next)
+ {
+ if(MyConnect(acptr))
+ {
+ lc++;
+ wle += acptr->watches;
+ }
+ else
+ rc++;
+
+
+#ifdef FLUD
+ for (link = acptr->fludees; link;
+ link = link->next)
+ fludlink++;
+#endif
+ if (acptr->serv)
+ servn++;
+
+ if (acptr->user)
+ {
+ us++;
+ for (link = acptr->user->invited; link;
+ link = link->next)
+ usi++;
+ for (link = acptr->user->channel; link;
+ link = link->next)
+ usc++;
+ for (link = acptr->user->dccallow; link;
+ link = link->next)
+ {
+ if(link->flags == DCC_LINK_ME)
+ usdm++;
+ else
+ usdr++;
+ }
+ for (link = acptr->user->silence; link;
+ link = link->next)
+ uss++;
+ if (acptr->user->away)
+ {
+ aw++;
+ awm += (strlen(acptr->user->away) + 1);
+ }
+ }
+ }
+
+ lcm = lc * CLIENT_LOCAL_SIZE;
+ rcm = rc * CLIENT_REMOTE_SIZE;
+
+ for (chptr = channel; chptr; chptr = chptr->nextch)
+ {
+ ch++;
+
+ for (cm = chptr->members; cm; cm = cm->next)
+ chu++;
+ for (link = chptr->invites; link; link = link->next)
+ chi++;
+ for (bp = chptr->banlist; bp; bp = bp->next)
+ {
+ chb++;
+ chbm += (strlen(bp->who) + strlen(bp->banstr) + 2 + sizeof(aBan));
+ }
+ }
+
+ for (amo = motd; amo; amo = amo->next)
+ motdlen++;
+ for (amo = shortmotd; amo; amo = amo->next)
+ motdlen++;
+ for (amo = helpfile; amo; amo = amo->next)
+ motdlen++;
+
+ for (ce = clones_list; ce; ce = ce->next)
+ cloneent++;
+ cloneentsz = cloneent * sizeof(*ce);
+
+ lcalloc = free_local_aClients->blocksAllocated *
+ free_local_aClients->elemsPerBlock;
+ lcallocsz = lcalloc * free_local_aClients->elemSize;
+
+ rcalloc = free_remote_aClients->blocksAllocated *
+ free_remote_aClients->elemsPerBlock;
+ rcallocsz = rcalloc * free_remote_aClients->elemSize;
+
+ useralloc = free_anUsers->blocksAllocated * free_anUsers->elemsPerBlock;
+ userallocsz = useralloc * free_anUsers->elemSize;
+
+ linkalloc = free_Links->blocksAllocated * free_Links->elemsPerBlock;
+ linkallocsz = linkalloc * free_Links->elemSize;
+
+ dlinkalloc = free_DLinks->blocksAllocated * free_DLinks->elemsPerBlock;
+ dlinkallocsz = dlinkalloc * free_DLinks->elemSize;
+
+ chanalloc = free_channels->blocksAllocated * free_channels->elemsPerBlock;
+ chanallocsz = chanalloc * free_channels->elemSize;
+
+ cmemballoc = free_chanMembers->blocksAllocated *
+ free_chanMembers->elemsPerBlock;
+ cmemballocsz = cmemballoc * free_chanMembers->elemSize;
+
+#ifdef FLUD
+ fludalloc = free_fludbots->blocksAllocated * free_fludbots->elemsPerBlock;
+ fludallocsz = fludalloc * free_fludbots->elemSize;
+#endif
+
+ clonealloc = free_cloneents->blocksAllocated
+ * free_cloneents->elemsPerBlock;
+ cloneallocsz = clonealloc * free_cloneents->elemSize;
+
+ totallinks = lcc + usi + uss + usc + chi + wle + fludlink + usdm + usdr;
+
+ sendto_one(cptr, ":%s %d %s :Memory Use Summary",
+ me.name, RPL_STATSDEBUG, nick);
+ sendto_one(cptr, ":%s %d %s :Client usage %d(%d) ALLOC %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, lc + rc, lcm + rcm,
+ lcalloc + rcalloc, lcallocsz + rcallocsz);
+ sendto_one(cptr, ":%s %d %s : Local %d(%d) ALLOC %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, lc, lcm, lcalloc, lcallocsz);
+ sendto_one(cptr, ":%s %d %s : Remote %d(%d) ALLOC %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, rc, rcm, rcalloc, rcallocsz);
+ sendto_one(cptr, ":%s %d %s :Users %d(%d) ALLOC %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, us, us * sizeof(anUser),
+ useralloc, userallocsz);
+
+ totcl = lcallocsz + rcallocsz + userallocsz;
+
+ sendto_one(cptr, ":%s %d %s :Links %d(%d) ALLOC %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, totallinks,
+ totallinks * sizeof(Link), linkalloc, linkallocsz);
+ sendto_one(cptr, ":%s %d %s : UserInvites %d(%d) ChanInvites %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, usi, usi * sizeof(Link), chi,
+ chi * sizeof(Link));
+ sendto_one(cptr, ":%s %d %s : UserChannels %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, usc, usc * sizeof(Link));
+ sendto_one(cptr, ":%s %d %s : DCCAllow Local %d(%d) Remote %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, usdm, usdm * sizeof(Link),
+ usdr, usdr * sizeof(Link));
+ sendto_one(cptr, ":%s %d %s : WATCH entries %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, wle, wle*sizeof(Link));
+ sendto_one(cptr, ":%s %d %s : Fludees %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, fludlink, fludlink*sizeof(Link));
+
+ sendto_one(cptr, ":%s %d %s :DLinks ALLOC %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, dlinkalloc, dlinkallocsz);
+ /* Print summary of DLINKs used in clientlist.c */
+ print_list_memory(cptr);
+
+ /* Count (and print) conf memory used in s_conf.c */
+ totco = count_conf_memory(cptr);
+
+ sendto_one(cptr, ":%s %d %s :WATCH headers %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, wlh, wlhm);
+ sendto_one(cptr, ":%s %d %s :Away Messages %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, aw, awm);
+ sendto_one(cptr, ":%s %d %s :MOTD structs %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, motdlen,
+ motdlen * sizeof(aMotd));
+ sendto_one(cptr, ":%s %d %s :Servers %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, servn, servn * sizeof(aServer));
+ sendto_one(cptr, ":%s %d %s :Message Trees %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, num_msg_trees,
+ num_msg_trees * sizeof(MESSAGE_TREE));
+
+ totmisc = wlhm + awm + (motdlen * sizeof(aMotd)) + totco +
+ (servn * sizeof(aServer)) +
+ (num_msg_trees * sizeof(MESSAGE_TREE));
+
+ sendto_one(cptr, ":%s %d %s :Fludbots ALLOC %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, fludalloc, fludallocsz);
+
+ sendto_one(cptr, ":%s %d %s :Clones %d(%d) ALLOC %d(%d)", me.name,
+ RPL_STATSDEBUG, nick, cloneent, cloneentsz, clonealloc,
+ cloneallocsz);
+
+ sendto_one(cptr, ":%s %d %s :Channels %d(%d) ALLOC %d(%d) Bans %d(%d) "
+ "Members %d(%d) ALLOC %d(%d)", me.name, RPL_STATSDEBUG, nick,
+ ch, ch * sizeof(aChannel), chanalloc, chanallocsz, chb, chbm,
+ chu, chu * sizeof(chanMember), cmemballoc, cmemballocsz);
+
+ totch = chanallocsz + cmemballocsz + chbm;
+
+ /* print userban summary, get userban total usage */
+ totuban = count_userbans(cptr);
+ totuban += count_simbans(cptr);
+
+ sendto_one(cptr, ":%s %d %s :Whowas users %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, wwu, wwu * sizeof(anUser));
+ sendto_one(cptr, ":%s %d %s :Whowas array %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, NICKNAMEHISTORYLENGTH, wwm);
+
+ totww = wwu * sizeof(anUser) + wwm;
+
+ sendto_one(cptr, ":%s %d %s :Hash: client %d(%d) chan %d(%d) whowas "
+ "%d(%d) watch %d(%d)", me.name, RPL_STATSDEBUG, nick,
+ U_MAX, sizeof(aHashEntry) * U_MAX,
+ CH_MAX, sizeof(aHashEntry) * CH_MAX,
+ WW_MAX, sizeof(aWhowas *) * WW_MAX,
+ WATCHHASHSIZE, sizeof(aWatch *) * WATCHHASHSIZE);
+
+/* count_dbuf_memory(&db, &db2);
+ sendto_one(cptr, ":%s %d %s :Dbuf blocks %d(%d) MAX %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, DBufUsedCount, db2,
+ DBufCount, db);
+*/
+ sbuf_count(&sbuf_user[0], &sbuf_user[1], &sbuf_user[2],
+ &sbuf_small[0], &sbuf_small[1], &sbuf_small[2],
+ &sbuf_large[0], &sbuf_large[1], &sbuf_large[2],
+ &sbuf_blocks[0], &sbuf_blocks[1], &sbuf_userblocks[0], &sbuf_userblocks[1]);
+ sendto_one(cptr, ":%s %d %s :SBUF ALLOC(%d)", me.name, RPL_STATSDEBUG, nick,
+ sbuf_user[1]*sbuf_user[2] + sbuf_small[1]*sbuf_small[2] + sbuf_large[1]*sbuf_large[2] +
+ sbuf_blocks[0]*sbuf_blocks[1] + sbuf_userblocks[0]*sbuf_userblocks[1]);
+ sendto_one(cptr, ":%s %d %s : BLOCKS %d(%d) USERBLOCKS %d(%d)", me.name, RPL_STATSDEBUG, nick,
+ sbuf_blocks[0], sbuf_blocks[0]*sbuf_blocks[1], sbuf_userblocks[0], sbuf_userblocks[0]*sbuf_userblocks[1]);
+ sendto_one(cptr, ":%s %d %s : USERS %d MAX(%d) ALLOC(%d)", me.name, RPL_STATSDEBUG, nick,
+ sbuf_user[0], sbuf_user[1], sbuf_user[1]*sbuf_user[2]);
+ sendto_one(cptr, ":%s %d %s : SMALL %d MAX(%d) ALLOC(%d)", me.name, RPL_STATSDEBUG, nick,
+ sbuf_small[0], sbuf_small[1], sbuf_small[1]*sbuf_small[2]);
+ sendto_one(cptr, ":%s %d %s : LARGE %d MAX(%d) ALLOC(%d)", me.name, RPL_STATSDEBUG, nick,
+ sbuf_large[0], sbuf_large[1], sbuf_large[1]*sbuf_large[2]);
+
+
+
+ rm = cres_mem(cptr);
+
+ count_scache(&number_servers_cached, &mem_servers_cached);
+
+ sendto_one(cptr, ":%s %d %s :scache %d(%d)",
+ me.name, RPL_STATSDEBUG, nick,
+ number_servers_cached,
+ mem_servers_cached);
+
+ tothash = (sizeof(aHashEntry)*U_MAX)+(sizeof(aHashEntry)*CH_MAX) +
+ (sizeof(aWatch *)*WATCHHASHSIZE) + (sizeof(aWhowas *)*WW_MAX);
+
+ tot = totww + totch + totcl + totmisc + /*db +*/ rm + tothash + linkallocsz +
+ dlinkallocsz + fludallocsz + totuban;
+
+ sendto_one(cptr, ":%s %d %s :whowas %d chan %d client/user %d misc %d "
+ /*dbuf %d*/ "hash %d res %d link %d flud %d simuserban %d",
+ me.name, RPL_STATSDEBUG, nick, totww, totch, totcl, totmisc,
+ /*db,*/ tothash, rm, linkallocsz, fludallocsz, totuban);
+
+ sendto_one(cptr, ":%s %d %s :TOTAL: %d sbrk(0)-etext: %u",
+ me.name, RPL_STATSDEBUG, nick, tot,
+ (u_int) sbrk((size_t) 0) - (u_int) sbrk0);
+ return;
+}
+
+
+static void
+show_opers(aClient *cptr, char *name)
+{
+ aClient *cptr2;
+ DLink *lp;
+ int j = 0;
+
+ for (lp = oper_list; lp; lp = lp->next)
+ {
+ cptr2 = lp->value.cptr;
+
+ if (!IsAnOper(cptr))
+ {
+ if (cptr2->umode & UMODE_h)
+ {
+ sendto_one(cptr, ":%s %d %s :%s (%s@%s) Idle: %d",
+ me.name, RPL_STATSDEBUG, name, cptr2->name,
+ cptr2->user->username, cptr2->user->host,
+ timeofday - cptr2->user->last);
+ j++;
+ }
+ }
+ else
+ {
+ sendto_one(cptr, ":%s %d %s :%s (%s@%s) Idle: %d",
+ me.name, RPL_STATSDEBUG, name, cptr2->name,
+ cptr2->user->username, cptr2->user->host,
+ timeofday - cptr2->user->last);
+ j++;
+ }
+ }
+ sendto_one(cptr, ":%s %d %s :%d OPER%s", me.name, RPL_STATSDEBUG,
+ name, j, (j == 1) ? "" : "s");
+}
+
+/* show_servers
+ * replies to stats v requests
+ */
+static void
+show_servers(aClient *cptr, char *name)
+{
+ aClient *cptr2;
+ DLink *lp;
+ int j = 0;
+
+ for (lp = server_list; lp; lp = lp->next)
+ {
+ cptr2 = lp->value.cptr;
+
+#ifdef HIDEULINEDSERVS
+ if(IsULine(cptr2) && !IsAnOper(cptr))
+ continue;
+#endif
+ j++;
+ sendto_one(cptr, ":%s %d %s :%s (%s!%s@%s) Idle: %d",
+ me.name, RPL_STATSDEBUG, name, cptr2->name,
+ (cptr2->serv->bynick[0] ? cptr2->serv->bynick : "Remote."),
+ (cptr2->serv->byuser[0] ? cptr2->serv->byuser : "*"),
+ (cptr2->serv->byhost[0] ? cptr2->serv->byhost : "*"),
+ timeofday - cptr2->lasttime);
+ }
+ sendto_one(cptr, ":%s %d %s :%d Server%s", me.name, RPL_STATSDEBUG,
+ name, j, (j == 1) ? "" : "s");
+}
+
+/* serv_info
+ * replies to stats ? requests
+ */
+
+#define _1MEG (1024.0)
+#define _1GIG (1024.0*1024.0)
+#define _1TER (1024.0*1024.0*1024.0)
+#define _GMKs(x) ((x > _1TER) ? "Terabytes" : ((x > _1GIG) ? \
+ "Gigabytes" : \
+ ((x > _1MEG) ? "Megabytes" : "Kilobytes")))
+#define _GMKv(x) ( (x > _1TER) ? (float)(x/_1TER) : ((x > _1GIG) ? \
+ (float)(x/_1GIG) : ((x > _1MEG) ? (float)(x/_1MEG) :\
+ (float)x)))
+
+static void
+serv_info(aClient *cptr, char *name)
+{
+ static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :%u %u %s";
+ long sendK, receiveK, uptime;
+ aClient *acptr;
+ DLink *lp;
+ int i = 0;
+
+ sendK = receiveK = 0;
+
+ for (lp = server_list; lp; lp = lp->next)
+ {
+ acptr = lp->value.cptr;
+
+#ifdef HIDEULINEDSERVS
+ if (IsULine(acptr) && !IsAnOper(cptr))
+ continue;
+#endif
+ sendK += acptr->sendK;
+ receiveK += acptr->receiveK;
+ sendto_one(cptr, Lformat, me.name, RPL_STATSLINKINFO,
+ name, ( IsAnOper(cptr) ? get_client_name(acptr, HIDEME)
+ : acptr->name ),
+ (int) SBufLength(&acptr->sendQ),
+ (int) acptr->sendM, (int) acptr->sendK,
+ (int) acptr->receiveM, (int) acptr->receiveK,
+ timeofday - acptr->firsttime, timeofday - acptr->since,
+ IsServer(acptr) ? (DoesTS(acptr) ? "TS" : "NoTS") : "-");
+
+
+ if(RC4EncLink(acptr))
+ sendto_one(cptr, ":%s %d %s : - RC4 encrypted", me.name,
+ RPL_STATSDEBUG, name);
+
+ if(ZipOut(acptr))
+ {
+ unsigned long ib, ob;
+ double rat;
+
+ zip_out_get_stats(acptr->serv->zip_out, &ib, &ob, &rat);
+ if(ib)
+ {
+ sendto_one(cptr, ":%s %d %s : - [O] Zip inbytes %d, "
+ "outbytes %d (%3.2f%%)", me.name, RPL_STATSDEBUG,
+ name, ib, ob, rat);
+ }
+ }
+
+ if(ZipIn(acptr))
+ {
+ unsigned long ib, ob;
+ double rat;
+
+ zip_in_get_stats(acptr->serv->zip_in, &ib, &ob, &rat);
+ if(ob)
+ {
+ sendto_one(cptr, ":%s %d %s : - [I] Zip inbytes %d, "
+ "outbytes %d (%3.2f%%)", me.name, RPL_STATSDEBUG,
+ name, ib, ob, rat);
+ }
+ }
+ i++;
+ }
+ sendto_one(cptr, ":%s %d %s :%u total server%s",
+ me.name, RPL_STATSDEBUG, name, i, (i == 1) ? "" : "s");
+ sendto_one(cptr, ":%s %d %s :Sent total : %7.2f %s",
+ me.name, RPL_STATSDEBUG, name, _GMKv(sendK), _GMKs(sendK));
+ sendto_one(cptr, ":%s %d %s :Recv total : %7.2f %s",
+ me.name, RPL_STATSDEBUG, name, _GMKv(receiveK),
+ _GMKs(receiveK));
+
+ uptime = (timeofday - me.since);
+ sendto_one(cptr, ":%s %d %s :Server send: %7.2f %s (%4.1f K/s total,"
+ " %4.1f K/s current)", me.name, RPL_STATSDEBUG, name,
+ _GMKv(me.sendK), _GMKs(me.sendK),
+ (float) ((float) me.sendK / (float) uptime), curSendK);
+ sendto_one(cptr, ":%s %d %s :Server recv: %7.2f %s (%4.1f K/s total,"
+ " %4.1f K/s current)", me.name, RPL_STATSDEBUG, name,
+ _GMKv(me.receiveK), _GMKs(me.receiveK),
+ (float) ((float) me.receiveK / (float) uptime), curRecvK);
+}
+
+/* tstats
+ * responced to stats t requests (oddly enough)
+ */
+
+static void
+tstats(aClient *cptr, char *name)
+{
+ aClient *acptr;
+ int i;
+ struct stats *sp;
+ struct stats tmp;
+
+ sp = &tmp;
+ memcpy((char *) sp, (char *) ircstp, sizeof(*sp));
+ for (i = 0; i < highest_fd; i++)
+ {
+ if (!(acptr = local[i]))
+ continue;
+ if (IsServer(acptr))
+ {
+ sp->is_sbs += acptr->sendB;
+ sp->is_sbr += acptr->receiveB;
+ sp->is_sks += acptr->sendK;
+ sp->is_skr += acptr->receiveK;
+ sp->is_sti += timeofday - acptr->firsttime;
+ sp->is_sv++;
+ if (sp->is_sbs > 1023)
+ {
+ sp->is_sks += (sp->is_sbs >> 10);
+ sp->is_sbs &= 0x3ff;
+ }
+ if (sp->is_sbr > 1023)
+ {
+ sp->is_skr += (sp->is_sbr >> 10);
+ sp->is_sbr &= 0x3ff;
+ }
+
+ }
+ else if (IsClient(acptr))
+ {
+ sp->is_cbs += acptr->sendB;
+ sp->is_cbr += acptr->receiveB;
+ sp->is_cks += acptr->sendK;
+ sp->is_ckr += acptr->receiveK;
+ sp->is_cti += timeofday - acptr->firsttime;
+ sp->is_cl++;
+ if (sp->is_cbs > 1023)
+ {
+ sp->is_cks += (sp->is_cbs >> 10);
+ sp->is_cbs &= 0x3ff;
+ }
+ if (sp->is_cbr > 1023)
+ {
+ sp->is_ckr += (sp->is_cbr >> 10);
+ sp->is_cbr &= 0x3ff;
+ }
+
+ }
+ else if (IsUnknown(acptr))
+ sp->is_ni++;
+ }
+
+ sendto_one(cptr, ":%s %d %s :accepts %u refused %u",
+ me.name, RPL_STATSDEBUG, name, sp->is_ac, sp->is_ref);
+ sendto_one(cptr, ":%s %d %s :unknown commands %u prefixes %u",
+ me.name, RPL_STATSDEBUG, name, sp->is_unco, sp->is_unpf);
+ sendto_one(cptr, ":%s %d %s :nick collisions %u unknown closes %u",
+ me.name, RPL_STATSDEBUG, name, sp->is_kill, sp->is_ni);
+ sendto_one(cptr, ":%s %d %s :wrong direction %u empty %u",
+ me.name, RPL_STATSDEBUG, name, sp->is_wrdi, sp->is_empt);
+ sendto_one(cptr, ":%s %d %s :numerics seen %u mode fakes %u",
+ me.name, RPL_STATSDEBUG, name, sp->is_num, sp->is_fake);
+ sendto_one(cptr, ":%s %d %s :auth successes %u fails %u",
+ me.name, RPL_STATSDEBUG, name, sp->is_asuc, sp->is_abad);
+ sendto_one(cptr, ":%s %d %s :local connections %u udp packets %u",
+ me.name, RPL_STATSDEBUG, name, sp->is_loc, sp->is_udp);
+ sendto_one(cptr, ":%s %d %s :drones refused %u throttled rejections %u",
+ me.name, RPL_STATSDEBUG, name, sp->is_drone, sp->is_throt);
+ sendto_one(cptr, ":%s %d %s :banned users refused before ident/dns"
+ " %u after ident/dns %u", me.name, RPL_STATSDEBUG,
+ name, sp->is_ref_1, sp->is_ref_2);
+ sendto_one(cptr, ":%s %d %s :Client Server",
+ me.name, RPL_STATSDEBUG, name);
+ sendto_one(cptr, ":%s %d %s :connected %u %u",
+ me.name, RPL_STATSDEBUG, name, sp->is_cl, sp->is_sv);
+ sendto_one(cptr, ":%s %d %s :bytes sent %u.%uK %u.%uK",
+ me.name, RPL_STATSDEBUG, name,
+ sp->is_cks, sp->is_cbs, sp->is_sks, sp->is_sbs);
+ sendto_one(cptr, ":%s %d %s :bytes recv %u.%uK %u.%uK",
+ me.name, RPL_STATSDEBUG, name,
+ sp->is_ckr, sp->is_cbr, sp->is_skr, sp->is_sbr);
+ sendto_one(cptr, ":%s %d %s :time connected %u %u",
+ me.name, RPL_STATSDEBUG, name, sp->is_cti, sp->is_sti);
+#ifdef FLUD
+ sendto_one(cptr, ":%s %d %s :CTCP Floods Blocked %u",
+ me.name, RPL_STATSDEBUG, name, sp->is_flud);
+#endif /* FLUD */
+}
+
+
+/* m_stats and friends
+ * Carved off from s_serv.c in Feb04 by epiphani
+ * This mess of routines seemed to go better by themselves, seeing
+ * as how s_serv.c is getting massive.
+ *
+ * m_stats
+ * parv[0] = sender prefix
+ * parv[1] = statistics selector (defaults to Message frequency)
+ * parv[2] = server name (current server defaulted, if omitted)
+ */
+
+int m_stats(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :%u %u %s";
+ static char Sformat[] = ":%s %d %s Name SendQ SendM SendBytes RcveM "
+ "RcveBytes :Open_since Idle TS";
+
+ struct Message *mptr;
+ aClient *acptr;
+ char stat = parc > 1 ? parv[1][0] : '\0';
+ int i, doall = 0, wilds = 0;
+ char *name;
+ time_t sincetime;
+ static time_t last_used = 0L;
+
+#ifdef NO_USER_STATS
+ if (!IsAnOper(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+#else
+#ifdef NO_LOCAL_USER_STATS
+ if (!IsAnOper(sptr) && !MyConnect(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+#endif
+#endif
+
+ if (hunt_server(cptr, sptr, ":%s STATS %s :%s", 2, parc, parv) !=
+ HUNTED_ISME)
+ return 0;
+
+ if (IsSquelch(sptr))
+ return 0;
+
+ if (!IsAnOper(sptr) && !IsULine(sptr))
+ {
+ /* allow remote stats p l ? u */
+ if (!((stat == 'p') || (stat == 'P') || (stat=='?') || (stat=='u') ||
+ (stat=='l') || (stat=='L')) && !MyConnect(sptr))
+ return 0;
+
+ /* if they're my user, penalize them. */
+ if (MyConnect(sptr))
+ sptr->since += 5;
+
+ if ((last_used + MOTD_WAIT) > NOW)
+ return 0;
+ else
+ last_used = NOW;
+ }
+
+ if (parc > 2)
+ {
+ name = parv[2];
+ if (!mycmp(name, me.name))
+ doall = 2;
+ else if (match(name, me.name) == 0)
+ doall = 1;
+ if (strchr(name, '*') || strchr(name, '?'))
+ wilds = 1;
+ }
+ else
+ name = me.name;
+
+ if (stat != (char) 0 && !IsULine(sptr) && !IsServer(sptr))
+ sendto_realops_lev(SPY_LEV, "STATS %c requested by %s (%s@%s) [%s]",
+ stat, sptr->name, sptr->user->username,
+ sptr->user->host, sptr->user->server);
+ switch (stat)
+ {
+ case 'L':
+ case 'l':
+ /* changed behavior totally. This is what we do now:
+ * #1: if the user is not opered, never return ips for anything
+ * #2: we DON'T deny /stats l for opers. Ever heard of /sping?
+ * it's easy to see if you're lagging a server, why restrict
+ * something used 99% of the time for good when you're not
+ * doing any harm?
+ * #3: NEVER return all users on a server, UGH, just like
+ * /trace, this was fiercely obnoxious. If you don't
+ * add an argument, you get all SERVER links.
+ */
+ sendto_one(sptr, Sformat, me.name, RPL_STATSLINKINFO, parv[0]);
+ if ((parc > 2) && !(doall || wilds))
+ { /* Single client lookup */
+ if (!(acptr = find_person(name, NULL)))
+ break;
+ /*
+ * sincetime might be greater than timeofday,
+ * store a new value here to avoid sending
+ * negative since-times. -Rak
+ */
+ sincetime = (acptr->since > timeofday) ? 0 :
+ timeofday - acptr->since;
+ sendto_one(sptr, Lformat, me.name, RPL_STATSLINKINFO, parv[0],
+ ( (IsAnOper(sptr) || !IsAnOper(acptr))
+ ? get_client_name(acptr, TRUE)
+ : get_client_name(acptr, HIDEME) ),
+ (int) SBufLength(&acptr->sendQ),
+ (int) acptr->sendM, (int) acptr->sendK,
+ (int) acptr->receiveM, (int) acptr->receiveK,
+ timeofday - acptr->firsttime, sincetime,
+ IsServer(acptr) ? (DoesTS(acptr) ?
+ "TS" : "NoTS") : "-");
+ }
+ else
+ {
+ for (i = 0; i <= highest_fd; i++)
+ {
+ if (!(acptr = local[i]))
+ continue;
+ if(!IsServer(acptr))
+ continue; /* nothing but servers */
+#ifdef HIDEULINEDSERVS
+ if(IsULine(acptr) && !IsAnOper(sptr))
+ continue;
+#endif
+ sincetime = (acptr->since > timeofday) ? 0 :
+ timeofday - acptr->since;
+ sendto_one(sptr, Lformat, me.name, RPL_STATSLINKINFO, parv[0],
+ ( IsAnOper(sptr) ? get_client_name(acptr, HIDEME)
+ : acptr->name ),
+ (int) SBufLength(&acptr->sendQ),
+ (int) acptr->sendM, (int) acptr->sendK,
+ (int) acptr->receiveM, (int) acptr->receiveK,
+ timeofday - acptr->firsttime, sincetime,
+ IsServer(acptr) ? (DoesTS(acptr) ?
+ "TS" : "NoTS") : "-");
+ }
+ }
+ break;
+ case 'C':
+ case 'c':
+ /* this should be fixed and combined into a more reasonable
+ * single responce. Will work on this later -epi
+ */
+#ifdef HIDEULINEDSERVS
+ if (!IsAnOper(sptr))
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ else
+#endif
+ {
+ aConnect *tmp;
+ if(!connects)
+ break;
+ for(tmp = connects; tmp; tmp = tmp->next)
+ {
+ if (tmp->legal == -1)
+ continue;
+
+ if(IsULine(sptr) || (MyClient(sptr) && IsAdmin(sptr)))
+ {
+ sendto_one(sptr, rpl_str(RPL_STATSCLINE), me.name,
+ sptr->name, "C", tmp->host, tmp->name, tmp->port,
+ tmp->class->name);
+ sendto_one(sptr, rpl_str(RPL_STATSNLINE), me.name,
+ sptr->name, "N", tmp->host, tmp->name, tmp->flags,
+ tmp->class->name);
+ }
+ else
+ {
+ sendto_one(sptr, rpl_str(RPL_STATSCLINE), me.name,
+ sptr->name, "C", "*", tmp->name, tmp->port,
+ tmp->class->name);
+ sendto_one(sptr, rpl_str(RPL_STATSNLINE), me.name,
+ sptr->name, "N", "*", tmp->name, tmp->flags,
+ tmp->class->name);
+ }
+ }
+ }
+ break;
+
+ case 'D':
+ if (!IsAnOper(sptr))
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ else
+ {
+ CloneEnt *ce;
+
+ for (ce = clones_list; ce; ce = ce->next)
+ if (ce->limit || ce->sllimit || ce->sglimit)
+ sendto_one(sptr, rpl_str(RPL_STATSCLONE), me.name,
+ parv[0], ce->ent, ce->sllimit, ce->sglimit,
+ ce->limit);
+ }
+ break;
+
+ case 'd':
+ if (!IsAnOper(sptr))
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ else
+ {
+ CloneEnt *ce;
+ int entries = 0;
+#ifdef THROTTLE_ENABLE
+ int sllimits = 0;
+ int sglimits = 0;
+ int hlimits = 0;
+ int active = 0;
+ int sites = 0;
+ unsigned long rtot;
+#endif
+
+ for (ce = clones_list; ce; ce = ce->next)
+ {
+ entries++;
+#ifdef THROTTLE_ENABLE
+ if (ce->sllimit)
+ sllimits++;
+ if (ce->sglimit)
+ sglimits++;
+ if (ce->limit)
+ hlimits++;
+ if (ce->gcount)
+ {
+ active++;
+ /* blah, but not important enough for its own flag */
+ if (!ce->clients)
+ sites++;
+ }
+#endif
+ }
+
+#ifdef THROTTLE_ENABLE
+ rtot = clones_stat.rlh + clones_stat.rls
+ + clones_stat.rgh + clones_stat.rgs;
+
+ sendto_one(sptr, ":%s %d %s :Default local host limit: %d"
+ " site: %d", me.name, RPL_STATSDEBUG, parv[0],
+ local_ip_limit, local_ip24_limit);
+ sendto_one(sptr, ":%s %d %s :Default global host limit: %d"
+ " site: %d", me.name, RPL_STATSDEBUG, parv[0],
+ global_ip_limit, global_ip24_limit);
+#endif
+ sendto_one(sptr, ":%s %d %s :Clone entries: %d", me.name,
+ RPL_STATSDEBUG, parv[0], entries);
+#ifdef THROTTLE_ENABLE
+ sendto_one(sptr, ":%s %d %s : Active hosts: %d sites: %d",
+ me.name, RPL_STATSDEBUG, parv[0], active-sites,
+ sites);
+ sendto_one(sptr, ":%s %d %s : Soft local limits: %d"
+ " global: %d", me.name, RPL_STATSDEBUG, parv[0],
+ sllimits, sglimits);
+ sendto_one(sptr, ":%s %d %s : Hard global limits: %d",
+ me.name, RPL_STATSDEBUG, parv[0], hlimits);
+ sendto_one(sptr, ":%s %d %s :Rejected connections: %lu",
+ me.name, RPL_STATSDEBUG, parv[0], rtot);
+ sendto_one(sptr, ":%s %d %s : Local hosts: %lu sites: %lu",
+ me.name, RPL_STATSDEBUG, parv[0],
+ clones_stat.rlh, clones_stat.rls);
+ sendto_one(sptr, ":%s %d %s : Global hosts: %lu sites: %lu",
+ me.name, RPL_STATSDEBUG, parv[0],
+ clones_stat.rgh, clones_stat.rgs);
+#endif
+ }
+ break;
+
+ case 'G':
+ if(IsAnOper(sptr))
+ report_simbans_match_flags(sptr, SBAN_GCOS|SBAN_LOCAL, 0);
+ else
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ break;
+ case 'g':
+ if(IsAnOper(sptr))
+ report_simbans_match_flags(sptr, SBAN_GCOS|SBAN_NETWORK, 0);
+ else
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ break;
+
+ case 'I':
+ case 'i':
+ {
+ aAllow *tmp;
+ if(!allows)
+ break;
+ for(tmp = allows; tmp; tmp = tmp->next)
+ {
+ if (tmp->passwd && !(IsAnOper(sptr) || IsULine(sptr)))
+ continue;
+ sendto_one(sptr, rpl_str(RPL_STATSILINE), me.name,
+ sptr->name, (tmp->legal == -1 ? "Ix" : "I"),
+ tmp->ipmask, tmp->flags, tmp->hostmask, tmp->port,
+ tmp->class->name);
+ }
+ break;
+ }
+ case 'k':
+ if(IsAnOper(sptr))
+ report_userbans_match_flags(sptr, UBAN_TEMPORARY|UBAN_LOCAL, 0);
+ else
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ break;
+
+ case 'K':
+ if (IsAnOper(sptr))
+ report_userbans_match_flags(sptr, UBAN_LOCAL, UBAN_TEMPORARY);
+ else
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ break;
+
+ case 'A':
+ case 'a':
+ if(IsAnOper(sptr))
+ report_userbans_match_flags(sptr, UBAN_NETWORK, 0);
+ else
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ break;
+
+ case 'M':
+ case 'm':
+ /*
+ * original behaviour was not to report the command, if
+ * the command hadn't been used. I'm going to always
+ * report the command instead -Dianora
+ * Why would users want to see this? Made Oper only.
+ */
+ if(IsAnOper(sptr))
+ for (mptr = msgtab; mptr->cmd; mptr++)
+ sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS), me.name,
+ parv[0], mptr->cmd, mptr->count, mptr->bytes);
+ break;
+
+ case 'N':
+ case 'n':
+ sendto_one(sptr, rpl_str(RPL_STATSCOUNT), me.name, parv[0],
+ "User Connects Today: ", Count.today);
+ sendto_one(sptr, rpl_str(RPL_STATSCOUNT), me.name, parv[0],
+ "User Connects past week: ", Count.weekly);
+ sendto_one(sptr, rpl_str(RPL_STATSCOUNT), me.name, parv[0],
+ "User Connects past month: ", Count.monthly);
+ sendto_one(sptr, rpl_str(RPL_STATSCOUNT), me.name, parv[0],
+ "User Connects past year: ", Count.yearly);
+ break;
+ case 'o':
+ case 'O':
+ {
+ aOper *tmp;
+ int i = 0;
+ if(!opers)
+ break;
+ if (IsAnOper(sptr) || IsULine(sptr))
+ {
+ for(tmp = opers; tmp; tmp = tmp->next)
+ for(i = 0; tmp->hosts[i]; i++)
+ sendto_one(sptr, rpl_str(RPL_STATSOLINE), me.name,
+ sptr->name, (tmp->legal == -1 ? "Ox" : "O"),
+ tmp->hosts[i], tmp->nick, tmp->flags,
+ tmp->class->name);
+ }
+ else
+ {
+ for(tmp = opers; tmp; tmp = tmp->next)
+ {
+ if (tmp->legal == -1)
+ continue;
+ sendto_one(sptr, rpl_str(RPL_STATSOLINE), me.name,
+ sptr->name, "O", "*", tmp->nick, tmp->flags,
+ tmp->class->name);
+ }
+ }
+ break;
+ }
+
+ case 'p':
+ case 'P':
+ show_opers(sptr, parv[0]);
+ break;
+
+ case 'Q':
+ if(IsAnOper(sptr))
+ {
+ report_simbans_match_flags(sptr, SBAN_NICK|SBAN_LOCAL, 0);
+ report_simbans_match_flags(sptr, SBAN_CHAN|SBAN_LOCAL, 0);
+ }
+ else
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ break;
+ case 'q':
+ if(IsAnOper(sptr))
+ {
+ report_simbans_match_flags(sptr, SBAN_NICK|SBAN_NETWORK, 0);
+ report_simbans_match_flags(sptr, SBAN_CHAN|SBAN_NETWORK, 0);
+ }
+ else
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ break;
+
+ case 'R':
+ case 'r':
+#ifdef DEBUGMODE
+ send_usage(sptr, parv[0]);
+#endif
+ break;
+
+ case 'S':
+ case 's':
+ if (IsAnOper(sptr))
+ list_scache(cptr, sptr, parc, parv);
+ else
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ break;
+
+ case 'T':
+ if (IsAnOper(sptr))
+ throttle_stats(sptr, parv[0]);
+ else
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ break;
+
+ case 't':
+ if (IsAnOper(sptr))
+ tstats(sptr, parv[0]);
+ else
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ break;
+
+ case 'U':
+#ifdef HIDEULINEDSERVS
+ if (!IsOper(sptr))
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ else
+#endif
+ {
+ int i;
+ for(i = 0; uservers[i]; i++)
+ sendto_one(sptr, rpl_str(RPL_STATSULINE), me.name,
+ sptr->name, "U", "*", uservers[i], 0, 0);
+ }
+ break;
+
+ case 'u':
+ {
+ time_t now;
+
+ now = timeofday - me.since;
+ sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0],
+ now / 86400, (now / 3600) % 24, (now / 60) % 60, now % 60);
+ break;
+ }
+
+ case 'v':
+ case 'V':
+ show_servers(sptr, parv[0]);
+ break;
+
+#ifdef DEBUGMODE
+ case 'w':
+ case 'W':
+ if(IsAnOper(sptr))
+ report_fds(sptr);
+ else
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ break;
+#endif
+
+ case 'Y':
+ case 'y':
+ {
+ aClass *tmp;
+ if(!classes)
+ break;
+ for(tmp = classes; tmp; tmp = tmp->next)
+ sendto_one(sptr, rpl_str(RPL_STATSYLINE), me.name,
+ sptr->name, 'Y', tmp->name, tmp->pingfreq,
+ tmp->connfreq, tmp->ip24clones, tmp->maxlinks,
+ tmp->maxsendq);
+ break;
+ }
+
+ case 'Z':
+ case 'z':
+ if (IsAnOper(sptr))
+ count_memory(sptr, parv[0]);
+ else
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ break;
+
+ case '?':
+ serv_info(sptr, parv[0]);
+ break;
+
+ default:
+ stat = '*';
+ break;
+ }
+ sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat);
+ return 0;
+}
+
--- /dev/null
+/* m_who.c - Because s_user.c was just crazy.
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free softwmare; 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 1, 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.
+ */
+
+/* $Id: m_who.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "inet.h"
+#include "msg.h"
+#include "channel.h"
+#include <sys/stat.h>
+#include <utmp.h>
+#include <fcntl.h>
+#include "h.h"
+
+/* Internally defined stuffs */
+SOpts wsopts;
+int build_searchopts(aClient *, int, char **);
+int chk_who(aClient *, int);
+
+/* Externally defined stuffs */
+extern int user_modes[];
+
+extern Link *find_channel_link(Link *, aChannel *);
+extern unsigned int cidr_to_netmask(unsigned int);
+
+int build_searchopts(aClient *sptr, int parc, char *parv[])
+{
+ static char *who_oper_help[] =
+ {
+ "/WHO [+|-][acghilmnstuCM] [args]",
+ "Flags are specified like channel modes,",
+ "The flags cghimnsu all have arguments",
+ "Flags are set to a positive check by +, a negative check by -",
+ "The flags work as follows:",
+ "Flag a: user is away",
+ "Flag c <channel>: user is on <channel>,",
+ " no wildcards accepted",
+ "Flag g <gcos/realname>: user has string <gcos> in their GCOS,",
+ " wildcards accepted, oper only",
+ "Flag h <host>: user has string <host> in their hostname,",
+ " wildcards accepted",
+ "Flag i <ip>: user is from <ip>, wildcards and cidr accepted,",
+ "Flag m <usermodes>: user has <usermodes> set on them",
+ "Flag n <nick>: user has string <nick> in their nickname,",
+ " wildcards accepted",
+ "Flag s <server>: user is on server <server>,",
+ " wildcards not accepted",
+ "Flag t <seconds>: (+t) show users on for more than or equal to <seconds> seconds",
+ " (-t) show users on for less than <seconds> seconds",
+ "Flag u <user>: user has string <user> in their username,",
+ " wildcards accepted",
+ "Flag T <type>: user is of type <type>, where type is assigned",
+ " by services.",
+ "Behavior flags:",
+ "Flag C: show first visible channel user is in",
+ "Flag M: check for user in channels I am a member of",
+ "Flag I: always show IPs instead of hosts",
+ NULL
+ };
+
+ static char *who_user_help[] =
+ {
+ "/WHO [+|-][achmnsuCM] [args]",
+ "Flags are specified like channel modes,",
+ "The flags cghimnsu all have arguments",
+ "Flags are set to a positive check by +, a negative check by -",
+ "The flags work as follows:",
+ "Flag a: user is away",
+ "Flag c <channel>: user is on <channel>,",
+ " no wildcards accepted",
+ "Flag h <host>: user has string <host> in their hostname,",
+ " wildcards accepted",
+ "Flag m <usermodes>: user has <usermodes> set on them,",
+ " only usermodes o/O/a/A will return a result",
+ "Flag n <nick>: user has string <nick> in their nickname,",
+ " wildcards accepted",
+ "Flag s <server>: user is on server <server>,",
+ " wildcards not accepted",
+ "Flag u <user>: user has string <user> in their username,",
+ " wildcards accepted",
+ "Behavior flags:",
+ "Flag C: show first visible channel user is in",
+ "Flag M: check for user in channels I am a member of",
+ NULL
+ };
+
+ char *flags, change=1, *s, *err;
+ int args=1, i, rval;
+
+ memset((char *)&wsopts, '\0', sizeof(SOpts));
+ /* if we got no extra arguments, send them the help. yeech. */
+ /* if it's /who ?, send them the help */
+ if(parc < 1 || parv[0][0]=='?')
+ {
+ /* So we don't confuse users with flags they cannot use,
+ a different /who ? output will be given to users and
+ opers -srd */
+
+ char **ptr = NULL;
+
+ if (!IsAnOper(sptr))
+ ptr = who_user_help;
+ else
+ ptr = who_oper_help;
+
+ for (; *ptr; ptr++)
+ sendto_one(sptr, getreply(RPL_COMMANDSYNTAX), me.name,
+ sptr->name, *ptr);
+ sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name, "?","WHO");
+ return 0;
+ }
+ /* backwards compatibility */
+ else if(parv[0][0]=='0' && parv[0][1]==0)
+ {
+ if(parc>1 && *parv[1]=='o')
+ {
+ wsopts.check_umode=1;
+ wsopts.umode_plus=1;
+ wsopts.umodes=UMODE_o;
+ }
+ wsopts.host_plus=1;
+ wsopts.host="*";
+ return 1;
+ }
+ /* if the first argument isn't a list of stuff */
+ else if(parv[0][0]!='+' && parv[0][0]!='-')
+ {
+ if(parv[0][0]=='#' || parv[0][0]=='&')
+ {
+ wsopts.channel=find_channel(parv[0],NullChn);
+ if(wsopts.channel==NULL)
+ {
+ sendto_one(sptr, getreply(ERR_NOSUCHCHANNEL), me.name,
+ sptr->name, parv[0]);
+ return 0;
+ }
+ }
+ else
+ {
+ /* If the arguement has a . in it, treat it as an
+ * address. Otherwise treat it as a nick. -Rak */
+ if (strchr(parv[0], '.'))
+ {
+ wsopts.host_plus=1;
+ wsopts.host=parv[0];
+ }
+ else
+ {
+ wsopts.nick_plus=1;
+ wsopts.nick=parv[0];
+ }
+ }
+ return 1;
+ }
+ /* now walk the list (a lot like set_mode) and set arguments
+ * as appropriate. */
+ flags=parv[0];
+ while(*flags)
+ {
+ switch(*flags)
+ {
+ case '+':
+ case '-':
+ change=(*flags=='+' ? 1 : 0);
+ break;
+ case 'a':
+ if(change)
+ wsopts.away_plus=1; /* they want here people */
+ else
+ wsopts.away_plus=0;
+ wsopts.check_away=1;
+ break;
+ case 'C':
+ wsopts.show_chan = change;
+ break;
+ case 'M':
+ wsopts.search_chan = change;
+ break;
+ case 'c':
+ if(parv[args]==NULL || !change)
+ {
+ sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
+ sptr->name, "WHO", "who");
+ return 0;
+ }
+ if(*parv[args] == '@' || *parv[args] == '+')
+ {
+ char *cname = parv[args] + 1;
+
+ if(*parv[args] == '@')
+ {
+ wsopts.channelflags = CHFL_CHANOP;
+ if(*cname == '+')
+ {
+ wsopts.channelflags |= CHFL_VOICE;
+ cname++;
+ }
+ }
+ else
+ wsopts.channelflags = CHFL_VOICE;
+
+ wsopts.channel=find_channel(cname, NullChn);
+ }
+ else
+ {
+ wsopts.channelflags = 0;
+ wsopts.channel=find_channel(parv[args],NullChn);
+ }
+
+ if(wsopts.channel==NULL)
+ {
+ sendto_one(sptr, getreply(ERR_NOSUCHCHANNEL), me.name,
+ sptr->name, parv[args]);
+ return 0;
+ }
+ wsopts.chan_plus=change;
+ args++;
+ break;
+ case 'g':
+ if(parv[args]==NULL)
+ {
+ sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
+ sptr->name, "WHO", "who");
+ return 0;
+ }
+ else if(!IsAnOper(sptr))
+ {
+ sendto_one(sptr, getreply(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+ wsopts.gcos=parv[args];
+ wsopts.gcos_plus=change;
+ args++;
+ break;
+ case 'h':
+ if(parv[args]==NULL)
+ {
+ sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
+ sptr->name, "WHO", "who");
+ return 0;
+ }
+ wsopts.host=parv[args];
+ wsopts.host_plus=change;
+ args++;
+ break;
+ case 't':
+ if(parv[args]==NULL || (rval = strtol(parv[args], &err, 0)) == 0 || *err != '\0')
+ {
+ sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
+ sptr->name, "WHO", "who");
+ return 0;
+ }
+ else if(!IsAnOper(sptr))
+ {
+ sendto_one(sptr, getreply(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+ wsopts.ts = rval;
+ wsopts.ts_value = change ? 2 : 1;
+ args++;
+ break;
+ case 'T':
+ if(parv[args]==NULL || (rval = strtol(parv[args], &err, 0)) == 0 || *err != '\0')
+ {
+ sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
+ sptr->name, "WHO", "who");
+ return 0;
+ }
+ else if(!IsAnOper(sptr))
+ {
+ sendto_one(sptr, getreply(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+ wsopts.client_type = rval;
+ wsopts.client_type_plus = change ? 1 : 0;
+ args++;
+ break;
+ case 'I':
+ if(!IsAnOper(sptr))
+ {
+ sendto_one(sptr, getreply(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+ wsopts.ip_show = change;
+ break;
+ case 'i':
+ if(parv[args]==NULL)
+ {
+ sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
+ sptr->name, "WHO", "who");
+ return 0;
+ }
+ else if(!IsAnOper(sptr))
+ {
+ sendto_one(sptr, getreply(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+ else
+ {
+ char *cpos;
+
+ if((cpos = strchr(parv[args], '/')))
+ {
+ char *err;
+ unsigned int maskval, ipval;
+
+ *(cpos++) = '\0';
+
+ ipval = inet_addr(parv[args]);
+ maskval = strtol(cpos, &err, 10);
+ if(ipval == 0xFFFFFFFF || *err != '\0' ||
+ maskval < 1 || maskval > 32)
+ {
+ sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name, sptr->name,
+ "WHO", "who");
+ return 0;
+ }
+
+ maskval = htonl(cidr_to_netmask(maskval));
+ ipval &= maskval;
+
+ wsopts.cidr4_plus = change;
+ wsopts.cidr4_mask = maskval;
+ wsopts.cidr4_ip = ipval;
+ args++;
+ }
+ else
+ {
+ wsopts.ip=parv[args];
+ wsopts.ip_plus=change;
+ args++;
+ }
+ }
+ break;
+ case 'm':
+ if(parv[args]==NULL)
+ {
+ sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
+ sptr->name, "WHO", "who");
+ return 0;
+ }
+ s=parv[args];
+ while(*s)
+ {
+ for(i=1;user_modes[i]!=0x0;i+=2)
+ {
+ if(*s==(char)user_modes[i])
+ {
+ wsopts.umodes|=user_modes[i-1];
+ break;
+ }
+ }
+ s++;
+ }
+ if(!IsAnOper(sptr)) /* only let users search for +/-oOaA */
+ wsopts.umodes=(wsopts.umodes&(UMODE_o|UMODE_O|UMODE_a|UMODE_A));
+ wsopts.umode_plus=change;
+ if(wsopts.umodes)
+ wsopts.check_umode=1;
+ args++;
+ break;
+ case 'n':
+ if(parv[args]==NULL)
+ {
+ sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
+ sptr->name, "WHO", "who");
+ return 0;
+ }
+ wsopts.nick=parv[args];
+ wsopts.nick_plus=change;
+ args++;
+ break;
+ case 's':
+ if(parv[args]==NULL || !change)
+ {
+ sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
+ sptr->name, "WHO", "who");
+ return 0;
+ }
+ wsopts.server=find_server(parv[args],NULL);
+ if(wsopts.server==NULL)
+ {
+ sendto_one(sptr, getreply(ERR_NOSUCHSERVER), me.name,
+ sptr->name, parv[args]);
+ return 0;
+ }
+ wsopts.serv_plus=change;
+ args++;
+ break;
+ case 'u':
+ if(parv[args]==NULL)
+ {
+ sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
+ sptr->name, "WHO", "who");
+ return 0;
+ }
+ wsopts.user=parv[args];
+ wsopts.user_plus=change;
+ args++;
+ break;
+ default:
+ sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
+ sptr->name, "WHO", "who");
+ return 0;
+
+ }
+ flags++;
+ }
+
+ /* if we specified search_chan, we _must_ specify something useful
+ * to go with it. Specifying a channel makes no sense, and no params make no
+ * sense either, as does specifying a nick.
+ */
+
+ if(wsopts.search_chan && !(wsopts.check_away || wsopts.gcos_plus ||
+ wsopts.host_plus || wsopts.check_umode ||
+ wsopts.serv_plus || wsopts.nick_plus ||
+ wsopts.user_plus || wsopts.ts_value ||
+ wsopts.client_type_plus || wsopts.ip_plus))
+ {
+ if(parv[args]==NULL || wsopts.channel || wsopts.nick ||
+ parv[args][0] == '#' || parv[args][0] == '&')
+ {
+ sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name, sptr->name, "WHO",
+ "who");
+ return 0;
+ }
+
+ if (strchr(parv[args], '.'))
+ {
+ wsopts.host_plus=1;
+ wsopts.host=parv[args];
+ }
+ else
+ {
+ sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name, sptr->name, "WHO",
+ "who");
+ return 0;
+ }
+ }
+ else /* can't show_chan if nothing else is set! */
+ if(wsopts.show_chan && !(wsopts.check_away || wsopts.gcos_plus ||
+ wsopts.host_plus || wsopts.check_umode ||
+ wsopts.serv_plus || wsopts.nick_plus ||
+ wsopts.user_plus || wsopts.ts_value ||
+ wsopts.client_type_plus || wsopts.ip_plus ||
+ wsopts.chan_plus))
+ {
+ if(parv[args]==NULL)
+ {
+ sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name, sptr->name, "WHO",
+ "who");
+ return 0;
+ }
+
+ if (strchr(parv[args], '.'))
+ {
+ wsopts.host_plus=1;
+ wsopts.host=parv[args];
+ }
+ else
+ {
+ wsopts.nick_plus=1;
+ wsopts.nick=parv[args];
+ }
+ }
+
+ /* hey cool, it all worked! */
+ return 1;
+}
+
+/* these four are used by chk_who to check gcos/nick/user/host
+ * respectively
+ * as well as ip -srd */
+
+int (*gchkfn)(char *, char *);
+int (*nchkfn)(char *, char *);
+int (*uchkfn)(char *, char *);
+int (*hchkfn)(char *, char *);
+int (*ichkfn)(char *, char *);
+
+int chk_who(aClient *ac, int showall)
+{
+ if(!IsClient(ac))
+ return 0;
+ if(IsInvisible(ac) && !showall)
+ return 0;
+
+ if(wsopts.client_type_plus &&
+ wsopts.client_type != ac->user->servicetype)
+ return 0;
+
+ if(wsopts.check_umode)
+ if((wsopts.umode_plus &&
+ !((ac->umode&wsopts.umodes)==wsopts.umodes)) ||
+ (!wsopts.umode_plus && ((ac->umode&wsopts.umodes)==wsopts.umodes)))
+ return 0;
+
+ if(wsopts.check_away)
+ if((wsopts.away_plus && ac->user->away==NULL) ||
+ (!wsopts.away_plus && ac->user->away!=NULL))
+ return 0;
+
+ /* while this is wasteful now, in the future
+ * when clients contain pointers to their servers
+ * of origin, this'll become a 4 byte check instead of a mycmp
+ * -wd */
+ /* welcome to the future... :) - lucas */
+ if(wsopts.serv_plus)
+ {
+ if(wsopts.server != ac->uplink)
+ return 0;
+ /* don't let people find hidden opers via /who +s server */
+ if(IsUmodeI(ac) && !showall)
+ return 0;
+ }
+ /* we only call match once, since if the first condition
+ * isn't true, most (all?) compilers will never try the
+ * second...phew :) */
+ if(wsopts.user!=NULL)
+ if((wsopts.user_plus && uchkfn(wsopts.user, ac->user->username)) ||
+ (!wsopts.user_plus && !uchkfn(wsopts.user, ac->user->username)))
+ return 0;
+
+ if(wsopts.nick!=NULL)
+ if((wsopts.nick_plus && nchkfn(wsopts.nick, ac->name)) ||
+ (!wsopts.nick_plus && !nchkfn(wsopts.nick, ac->name)))
+ return 0;
+
+ if(wsopts.host!=NULL)
+ if((wsopts.host_plus && hchkfn(wsopts.host, ac->user->host)) ||
+ (!wsopts.host_plus && !hchkfn(wsopts.host, ac->user->host)))
+ return 0;
+
+ if(wsopts.cidr4_plus)
+ if((ac->ip.s_addr & wsopts.cidr4_mask) != wsopts.cidr4_ip)
+ return 0;
+
+ if(wsopts.ip_plus)
+ if(ichkfn(wsopts.ip, ac->hostip))
+ return 0;
+
+ if(wsopts.gcos!=NULL)
+ if((wsopts.gcos_plus && gchkfn(wsopts.gcos, ac->info)) ||
+ (!wsopts.gcos_plus && !gchkfn(wsopts.gcos, ac->info)))
+ return 0;
+
+ /*
+ * For the below options, a value of two means '+',
+ * a value of 1 means '-', and a value of 0 means
+ * not speficied.
+ */
+
+ if(wsopts.ts_value == 2 && /* +t */
+ NOW - ac->tsinfo < wsopts.ts)
+ return 0;
+ else if(wsopts.ts_value == 1 && /* -t */
+ NOW - ac->tsinfo >= wsopts.ts)
+ return 0;
+
+ return 1;
+}
+
+inline char *first_visible_channel(aClient *cptr, aClient *sptr)
+{
+ Link *lp;
+ int secret = 0;
+ aChannel *chptr = NULL;
+ static char chnbuf[CHANNELLEN + 2];
+
+ if(cptr->user->channel)
+ {
+ if(IsAdmin(sptr))
+ {
+ chptr = cptr->user->channel->value.chptr;
+ if(!(ShowChannel(sptr, chptr)))
+ secret = 1;
+ }
+ else
+ {
+ for(lp = cptr->user->channel; lp; lp = lp->next)
+ {
+ if(ShowChannel(sptr, lp->value.chptr))
+ break;
+ }
+ if(lp)
+ chptr = lp->value.chptr;
+ }
+
+ if(chptr)
+ {
+ if(!secret)
+ return chptr->chname;
+ ircsprintf(chnbuf, "%%%s", chptr->chname);
+ return chnbuf;
+ }
+ }
+ return "*";
+}
+
+/* allow lusers only 200 replies from /who */
+#define MAXWHOREPLIES 200
+#define WHO_HOPCOUNT(s, a) ( ( (IsULine((a)) || IsUmodeI((a))) && !IsAnOper((s)) ) ? 0 : a->hopcount)
+#define WHO_SERVER(s ,a) ((IsUmodeI((a)) && !IsAnOper((s))) ? HIDDEN_SERVER_NAME : a->user->server)
+#define WHO_HOST(a) ((wsopts.ip_show) ? (a)->hostip : (a)->user->host)
+int m_who(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aClient *ac;
+ chanMember *cm;
+ Link *lp;
+ int shown=0, i=0, showall=IsAnOper(sptr);
+ char status[4];
+
+ /* drop nonlocal clients */
+ if(!MyClient(sptr))
+ return 0;
+
+ if(!build_searchopts(sptr, parc-1, parv+1))
+ return 0; /* /who was no good */
+
+ if(wsopts.gcos!=NULL && (strchr(wsopts.gcos, '?'))==NULL &&
+ (strchr(wsopts.gcos, '*'))==NULL)
+ gchkfn=mycmp;
+ else
+ gchkfn=match;
+ if(wsopts.nick!=NULL && (strchr(wsopts.nick, '?'))==NULL &&
+ (strchr(wsopts.nick, '*'))==NULL)
+ nchkfn=mycmp;
+ else
+ nchkfn=match;
+ if(wsopts.user!=NULL && (strchr(wsopts.user, '?'))==NULL &&
+ (strchr(wsopts.user, '*'))==NULL)
+ uchkfn=mycmp;
+ else
+ uchkfn=match;
+ if(wsopts.host!=NULL && (strchr(wsopts.host, '?'))==NULL &&
+ (strchr(wsopts.host, '*'))==NULL)
+ hchkfn=mycmp;
+ else
+ hchkfn=match;
+
+ if(wsopts.ip!=NULL && (strchr(wsopts.ip, '?'))==NULL &&
+ (strchr(wsopts.ip, '*'))==NULL)
+ ichkfn=mycmp;
+ else
+ ichkfn=match;
+
+ if(wsopts.channel!=NULL)
+ {
+ if(IsMember(sptr,wsopts.channel))
+ showall=1;
+ else if(SecretChannel(wsopts.channel) && IsAdmin(sptr))
+ showall=1;
+ else if(!SecretChannel(wsopts.channel) && IsAnOper(sptr))
+ showall=1;
+ else
+ showall=0;
+ if(showall || !SecretChannel(wsopts.channel))
+ {
+ for(cm=wsopts.channel->members; cm; cm=cm->next)
+ {
+ ac=cm->cptr;
+ i=0;
+ if(!chk_who(ac,showall))
+ continue;
+ /* If we have channel flags set, verify they match */
+ if(wsopts.channelflags && ((cm->flags & wsopts.channelflags) == 0))
+ continue;
+ /* get rid of the pidly stuff first */
+ /* wow, they passed it all, give them the reply...
+ * IF they haven't reached the max, or they're an oper */
+ status[i++]=(ac->user->away==NULL ? 'H' : 'G');
+ status[i]=(IsAnOper(ac) ? '*' : ((IsInvisible(ac) &&
+ IsOper(sptr)) ? '%' : 0));
+ status[((status[i]) ? ++i : i)]=((cm->flags&CHFL_CHANOP) ? '@'
+ : ((cm->flags&CHFL_VOICE) ?
+ '+' : 0));
+ status[++i]=0;
+ sendto_one(sptr, getreply(RPL_WHOREPLY), me.name, sptr->name,
+ wsopts.channel->chname, ac->user->username,
+ WHO_HOST(ac), WHO_SERVER(sptr, ac), ac->name, status,
+ WHO_HOPCOUNT(sptr, ac),
+ ac->info);
+ }
+ }
+ sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name,
+ wsopts.channel->chname, "WHO");
+ return 0;
+ }
+ /* if (for whatever reason) they gave us a nick with no
+ * wildcards, just do a find_person, bewm! */
+ else if(nchkfn==mycmp)
+ {
+ ac=find_person(wsopts.nick,NULL);
+ if(ac!=NULL)
+ {
+ if(!chk_who(ac,1))
+ {
+ sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name,
+ wsopts.host!=NULL ? wsopts.host : wsopts.nick, "WHO");
+ return 0;
+ }
+ else
+ {
+ status[0]=(ac->user->away==NULL ? 'H' : 'G');
+ status[1]=(IsAnOper(ac) ? '*' : (IsInvisible(ac) &&
+ IsAnOper(sptr) ? '%' : 0));
+ status[2]=0;
+ sendto_one(sptr, getreply(RPL_WHOREPLY), me.name, sptr->name,
+ wsopts.show_chan ? first_visible_channel(ac, sptr)
+ : "*", ac->user->username, WHO_HOST(ac),
+ WHO_SERVER(sptr, ac), ac->name, status,
+ WHO_HOPCOUNT(sptr, ac),
+ ac->info);
+ sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name,
+ wsopts.host!=NULL ? wsopts.host : wsopts.nick, "WHO");
+ return 0;
+ }
+ }
+ sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name,
+ wsopts.host!=NULL ? wsopts.host : wsopts.nick, "WHO");
+ return 0;
+ }
+
+ if(wsopts.search_chan)
+ {
+ for(lp = sptr->user->channel; lp; lp = lp->next)
+ {
+ for(cm = lp->value.chptr->members; cm; cm = cm->next)
+ {
+ ac = cm->cptr;
+ if(!chk_who(ac, 1))
+ continue;
+
+ if(shown==MAXWHOREPLIES && !IsAnOper(sptr))
+ {
+ sendto_one(sptr, getreply(ERR_WHOLIMEXCEED), me.name,
+ sptr->name, MAXWHOREPLIES, "WHO");
+ break;
+ }
+
+ i = 0;
+ status[i++]=(ac->user->away==NULL ? 'H' : 'G');
+ status[i]=(IsAnOper(ac) ? '*' : ((IsInvisible(ac) &&
+ IsOper(sptr)) ? '%' : 0));
+ status[((status[i]) ? ++i : i)]=((cm->flags&CHFL_CHANOP) ?
+ '@' : ((cm->flags&CHFL_VOICE)
+ ? '+' : 0));
+ status[++i]=0;
+ sendto_one(sptr, getreply(RPL_WHOREPLY), me.name, sptr->name,
+ lp->value.chptr->chname, ac->user->username,
+ WHO_HOST(ac),WHO_SERVER(sptr, ac), ac->name,
+ status, WHO_HOPCOUNT(sptr, ac), ac->info);
+ shown++;
+ }
+ }
+ }
+ else
+ {
+ for(ac=client;ac;ac=ac->next)
+ {
+ if(!chk_who(ac,showall))
+ continue;
+ /* wow, they passed it all, give them the reply...
+ * IF they haven't reached the max, or they're an oper */
+ if(shown==MAXWHOREPLIES && !IsAnOper(sptr))
+ {
+ sendto_one(sptr, getreply(ERR_WHOLIMEXCEED), me.name,
+ sptr->name, MAXWHOREPLIES, "WHO");
+ break; /* break out of loop so we can send end of who */
+ }
+ status[0]=(ac->user->away==NULL ? 'H' : 'G');
+ status[1]=(IsAnOper(ac) ? '*' : (IsInvisible(ac) &&
+ IsAnOper(sptr) ? '%' : 0));
+ status[2]=0;
+ sendto_one(sptr, getreply(RPL_WHOREPLY), me.name, sptr->name,
+ wsopts.show_chan ? first_visible_channel(ac, sptr) :
+ "*", ac->user->username, WHO_HOST(ac),
+ WHO_SERVER(sptr, ac), ac->name, status,
+ WHO_HOPCOUNT(sptr, ac), ac->info);
+ shown++;
+ }
+ }
+ sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name,
+ (wsopts.host!=NULL ? wsopts.host :
+ (wsopts.nick!=NULL ? wsopts.nick :
+ (wsopts.user!=NULL ? wsopts.user :
+ (wsopts.gcos!=NULL ? wsopts.gcos :
+ (wsopts.server!=NULL ? wsopts.server->name :
+ "*"))))), "WHO");
+ return 0;
+}
--- /dev/null
+
+/************************************************************************
+ * IRC - Internet Relay Chat, src/match.c
+ * Copyright (C) 1990 Jarkko Oikarinen
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: match.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+
+#if 0 /* this code is depricated, however it may still prove useful
+ in the long run to 'show' it here */
+
+#define MAX_CALLS 512
+static int calls = 0;
+
+/*
+ * * Compare if a given string (name) matches the given * mask (which
+ * can contain wild cards: '*' - match any * number of chars, '?' -
+ * match any single character. *
+ *
+ * return 0, if match * 1, if no match
+ */
+/*
+ * * _match() * Iterative matching function, rather than recursive. *
+ * Written by Douglas A Lewis (dalewis@acsu.buffalo.edu)
+ */
+
+static int wdmatch(const char *string, const char *wild);
+
+static int _match(char *mask, char *name)
+{
+ u_char *m = (u_char *) mask, *n = (u_char *) name;
+ char *ma = mask, *na = name;
+ int wild = 0, q = 0;
+
+ while (1)
+ {
+ if (calls++ > MAX_CALLS)
+ return 1;
+ if (*m == '*')
+ {
+ while (*m == '*')
+ m++;
+ wild = 1;
+ ma = (char *) m;
+ na = (char *) n;
+ }
+
+ if (!*m)
+ {
+ if (!*n)
+ return 0;
+ for (m--; (m > (u_char *) mask) && (*m == '?'); m--);
+ if ((*m == '*') && (m > (u_char *) mask) &&
+ (m[-1] != '\\'))
+ return 0;
+ if (!wild)
+ return 1;
+ m = (u_char *) ma;
+ n = (u_char *) ++na;
+ }
+ else if (!*n)
+ {
+ while (*m == '*')
+ m++;
+ return (*m != 0);
+ }
+ if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
+ {
+ m++;
+ q = 1;
+ }
+ else
+ q = 0;
+
+ if ((ToLower(*m) != ToLower(*n)) && ((*m != '?') || q))
+ {
+ if (!wild)
+ return 1;
+ m = (u_char *) ma;
+ n = (u_char *) ++na;
+ }
+ else
+ {
+ if (*m)
+ m++;
+ if (*n)
+ n++;
+ }
+ }
+}
+
+int match(char *n, char *m)
+{
+ calls=0;
+ return wdmatch(n,m);
+}
+#endif
+
+/*
+ * * collapse a pattern string into minimal components. * This
+ * particular version is "in place", so that it changes the pattern *
+ * which is to be reduced to a "minimal" size.
+ */
+char *collapse(char *pattern)
+{
+ char *s = pattern, *s1, *t;
+
+ if (BadPtr(pattern))
+ return pattern;
+ /* Collapse all \** into \*, \*[?]+\** into \*[?]+ */
+ for (; *s; s++)
+ if (*s == '\\')
+ {
+ if (!*(s + 1))
+ break;
+ else
+ s++;
+ }
+ else if (*s == '*')
+ {
+ if (*(t = s1 = s + 1) == '*')
+ while (*t == '*')
+ t++;
+ else if (*t == '?')
+ for (t++, s1++; *t == '*' || *t == '?'; t++)
+ if (*t == '?')
+ *s1++ = *t;
+ while ((*s1++ = *t++));
+ }
+ return pattern;
+}
+
+unsigned char tolowertab[] =
+{0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
+ 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+ 0x1e, 0x1f,
+ ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
+ '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ ':', ';', '<', '=', '>', '?',
+ '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
+ 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
+ 't', 'u', 'v', 'w', 'x', 'y', 'z', '[', '\\', ']', '^', '_',
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
+ 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
+ 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
+ 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+ 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
+ 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
+ 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
+ 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
+ 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
+ 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff};
+
+unsigned char touppertab[] =
+{0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
+ 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+ 0x1e, 0x1f,
+ ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
+ '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
+ 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
+ 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', 0x5f,
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
+ 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
+ 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~',
+ 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+ 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
+ 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
+ 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
+ 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
+ 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
+ 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff};
+
+unsigned char char_atribs[] =
+{
+ /* 0-7 */
+ CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL,
+ /* 8-12*/
+ CNTRL, CNTRL | SPACE, CNTRL | SPACE, CNTRL | SPACE, CNTRL | SPACE,
+ /* 13-15 */
+ CNTRL | SPACE, CNTRL, CNTRL,
+ /* 16-23 */
+ CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL,
+ /* 24-31 */
+ CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL,
+ /* space */
+ PRINT | SPACE,
+ /* !"#$%&'( */
+ PRINT, PRINT, PRINT, PRINT, PRINT, PRINT, PRINT, PRINT,
+ /* )*+,-./ */
+ PRINT, PRINT, PRINT, PRINT, PRINT, PRINT, PRINT,
+ /* 0123 */
+ PRINT | DIGIT, PRINT | DIGIT, PRINT | DIGIT, PRINT | DIGIT,
+ /* 4567 */
+ PRINT | DIGIT, PRINT | DIGIT, PRINT | DIGIT, PRINT | DIGIT,
+ /* 89:; */
+ PRINT | DIGIT, PRINT | DIGIT, PRINT, PRINT,
+ /* <=>? */
+ PRINT, PRINT, PRINT, PRINT,
+ /* @ */
+ PRINT,
+ /* ABC */
+ PRINT | ALPHA, PRINT | ALPHA, PRINT | ALPHA,
+ /* DEF */
+ PRINT | ALPHA, PRINT | ALPHA, PRINT | ALPHA,
+ /* GHI */
+ PRINT | ALPHA, PRINT | ALPHA, PRINT | ALPHA,
+ /* JKL */
+ PRINT | ALPHA, PRINT | ALPHA, PRINT | ALPHA,
+ /* MNO */
+ PRINT | ALPHA, PRINT | ALPHA, PRINT | ALPHA,
+ /* PQR */
+ PRINT | ALPHA, PRINT | ALPHA, PRINT | ALPHA,
+ /* STU */
+ PRINT | ALPHA, PRINT | ALPHA, PRINT | ALPHA,
+ /* VWX */
+ PRINT | ALPHA, PRINT | ALPHA, PRINT | ALPHA,
+ /* YZ[ */
+ PRINT | ALPHA, PRINT | ALPHA, PRINT | ALPHA,
+ /* \]^ */
+ PRINT | ALPHA, PRINT | ALPHA, PRINT | ALPHA,
+ /* _` */
+ PRINT, PRINT,
+ /* abc */
+ PRINT | ALPHA, PRINT | ALPHA, PRINT | ALPHA,
+ /* def */
+ PRINT | ALPHA, PRINT | ALPHA, PRINT | ALPHA,
+ /* ghi */
+ PRINT | ALPHA, PRINT | ALPHA, PRINT | ALPHA,
+ /* jkl */
+ PRINT | ALPHA, PRINT | ALPHA, PRINT | ALPHA,
+ /* mno */
+ PRINT | ALPHA, PRINT | ALPHA, PRINT | ALPHA,
+ /* pqr */
+ PRINT | ALPHA, PRINT | ALPHA, PRINT | ALPHA,
+ /* stu */
+ PRINT | ALPHA, PRINT | ALPHA, PRINT | ALPHA,
+ /* vwx */
+ PRINT | ALPHA, PRINT | ALPHA, PRINT | ALPHA,
+ /* yz{ */
+ PRINT | ALPHA, PRINT | ALPHA, PRINT | ALPHA,
+ /* \}~ */
+ PRINT | ALPHA, PRINT | ALPHA, PRINT | ALPHA,
+ /* del */
+ 0,
+ /* 80-8f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 90-9f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* a0-af */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* b0-bf */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* c0-cf */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* d0-df */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* e0-ef */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* f0-ff */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* screw that lexocographic crap, nothing in ircd ever cares */
+int mycmp(char *s1, char *s2)
+{
+ unsigned char *str1 = (unsigned char *) s1;
+ unsigned char *str2 = (unsigned char *) s2;
+ while (touppertab[*str1] == touppertab[*str2])
+ {
+ if (*str1 == '\0')
+ return 0;
+ str1++;str2++;
+ }
+ return (-1);
+}
+
+int mycmp_diff(char *s1, char *s2)
+{
+ int ret;
+ unsigned char *str1 = (unsigned char *) s1;
+ unsigned char *str2 = (unsigned char *) s2;
+ while ((ret = touppertab[*str1] - touppertab[*str2]) == 0)
+ {
+ if (*str1 == '\0')
+ return 0;
+ str1++;str2++;
+ }
+ return ret;
+}
+
+int myncmp(char *str1, char *str2, int n)
+{
+ unsigned char *s1 = (unsigned char *) str1;
+ unsigned char *s2 = (unsigned char *) str2;
+ while (touppertab[*s1] == touppertab[*s2])
+ {
+ s1++;
+ s2++;
+ n--;
+ if (n == 0 || (*s1 == '\0' && *s2 == '\0'))
+ return 0;
+ }
+ return (-1);
+}
+
+#define MAX_CALLS 512
+static int calls = 0;
+
+static inline int _match(char *wild, char *string);
+
+int match(char *n, char *m)
+{
+ calls=0;
+ return _match(n,m);
+}
+
+static inline int _match(char *wild, char *string)
+{
+ if (calls++ > MAX_CALLS)
+ return 1;
+
+ /* the *! in a match is such a common case that we optimize
+ * for it inherently */
+
+ if(wild[0]=='*' && wild[1]=='!')
+ {
+ wild+=2;
+ while(*string!='!' && *string)
+ string++;
+ if(!*string)
+ return 1;
+ string++;
+ }
+ /* we also optimize further for *!*@...which is also very
+ * common...*/
+ if(wild[0]=='*' && wild[1]=='@')
+ {
+ wild+=2;
+ while(*string!='@' && *string)
+ string++;
+ if(!*string)
+ return 1;
+ string++;
+ }
+ while(1)
+ {
+ /*
+ * Logic: Match * in a string, this is confusing, sort of
+ * if * is the last thing in the wildcard, the match is
+ * definite if we've gotten this far.
+ * otherwise we try and find every occurance of the
+ * the next character in the wildcard within the string
+ * and match from there, calling the function recursively
+ * until some level below us returns positive, in which
+ * case we too return positive. For strings with lots
+ * of wildcards this gets disgustingly recursive.
+ */
+ if(!*wild)
+ return ((!*string) ? 0 : 1);
+ if(*wild=='*')
+ {
+ /* if ret==2 then we know it's a problem un-solvable
+ * by match, so we totally give up instead of trying
+ * a bunch of other recursions to check through */
+ wild++;
+ /* swallow all extraneous '*'s after. */
+ while(*wild=='*')
+ wild++;
+ while(*wild=='?' && *string)
+ {
+ wild++;string++;
+ }
+ if(!*wild)
+ return 0;
+ if(*wild=='*')
+ continue;
+ while(*string)
+ {
+ if(touppertab[(u_char)*string]
+ == touppertab[(u_char)*wild]
+ && !_match((wild+1), (string+1)))
+ return 0;
+ string++;
+ }
+ }
+ if(!*string)
+ return 1;
+ if(*wild!='?' && touppertab[(u_char)*string]!=
+ touppertab[(u_char)*wild])
+ return 1;
+ string++;
+ wild++;
+ }
+ return 1;
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/modules.c
+ * Copyright (C) 2003, Lucas Madar
+ */
+
+/* $Id: modules.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "msg.h"
+#include "channel.h"
+#include "throttle.h"
+#include "h.h"
+#include "hooks.h"
+
+extern Conf_Modules *modules;
+
+#ifndef USE_HOOKMODULES
+int
+m_module(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ if(MyClient(sptr) && !IsAnOper(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+
+ if (parc > 2)
+ {
+ if (!mycmp(parv[1], "LIST") || !mycmp(parv[1], "HOOKS"))
+ {
+ if (hunt_server(cptr, sptr, "%s MODULE %s %s", 2, parc, parv)
+ != HUNTED_ISME)
+ return 0;
+ }
+ else if (!mycmp(parv[1], "CGLOBAL"))
+ {
+ char pbuf[512];
+
+ if(!(IsServer(sptr) || IsULine(sptr)))
+ return 0;
+
+ /* Pass this on to all servers! */
+ make_parv_copy(pbuf, parc, parv);
+ sendto_serv_butone(cptr, ":%s MODULE %s", parv[0], pbuf);
+
+ return 0;
+ }
+ }
+
+ if (IsPerson(sptr))
+ sendto_one(sptr, "%s NOTICE %s :I don't have module support.",
+ me.name, sptr->name);
+
+ return 0;
+}
+
+int
+call_hooks(enum c_hooktype hooktype, ...)
+{
+ return 0;
+}
+
+int
+init_modules()
+{
+ return 0;
+}
+
+#else
+
+#include <dlfcn.h>
+
+/* XXX hack. check on RTLD_NOW later. */
+#ifndef RTLD_NOW
+#define RTLD_NOW 0
+#endif
+
+DLink *module_list = NULL;
+
+typedef struct loaded_module
+{
+ char *name;
+
+ char *version;
+ char *description;
+
+ void *handle;
+
+ void (*module_check) (int *);
+ int (*module_init) (void *);
+ void (*module_shutdown) (void);
+ void (*module_getinfo) (char **, char **);
+ int (*module_command) (aClient *, int, char **);
+ int (*module_globalcommand) (aClient *, aClient *, int, char **);
+} aModule;
+
+/* Forward decls */
+char *bircmodule_strdup(char *);
+void *bircmodule_malloc(int);
+void bircmodule_free(void *);
+void drop_all_hooks(aModule *owner);
+void list_hooks(aClient *sptr);
+
+aModule *
+find_module(char *name)
+{
+ DLink *lp;
+
+ for(lp = module_list; lp; lp = lp->next)
+ {
+ aModule *mod = (aModule *) lp->value.cp;
+
+ if(strcmp(mod->name, name) == 0)
+ return mod;
+ }
+ return NULL;
+}
+
+aModule *
+find_module_opaque(void *opaque)
+{
+ DLink *lp;
+
+ for(lp = module_list; lp; lp = lp->next)
+ {
+ aModule *mod = (aModule *) lp->value.cp;
+
+ if(opaque == (void *) mod)
+ return mod;
+ }
+ return NULL;
+}
+
+int
+modsym_load(aClient *sptr, char *modname, char *symbol, void *modulehandle,
+ void **retfunc)
+{
+ void *ret;
+ const char *error;
+
+ ret = dlsym(modulehandle, symbol);
+
+ if((error = dlerror()) != NULL)
+ {
+ if(sptr)
+ sendto_one(sptr, ":%s NOTICE %s :Module symbol error for %s/%s: %s",
+ me.name, sptr->name, modname, symbol, error);
+ else
+ fprintf(stderr, " - Module symbol error for %s/%s: %s\n",
+ modname, symbol, error);
+
+ dlclose(modulehandle);
+ return 0;
+ }
+
+ *retfunc = ret;
+ return 1;
+}
+
+void
+list_modules(aClient *sptr)
+{
+ DLink *lp;
+
+ for(lp = module_list; lp; lp = lp->next)
+ {
+ aModule *mod = (aModule *) lp->value.cp;
+ sendto_one(sptr, ":%s NOTICE %s :Module: %s Version: %s",
+ me.name, sptr->name, mod->name, mod->version);
+
+ sendto_one(sptr, ":%s NOTICE %s : - %s", me.name, sptr->name,
+ mod->description);
+ }
+}
+
+void
+destroy_module(aModule *themod)
+{
+ (*themod->module_shutdown)();
+ dlclose(themod->handle);
+ bircmodule_free(themod->name);
+ bircmodule_free(themod->version);
+ bircmodule_free(themod->description);
+ remove_from_list(&module_list, themod, NULL);
+ bircmodule_free(themod);
+}
+
+int
+load_module(aClient *sptr, char *modname)
+{
+ aModule tmpmod, *themod;
+ char mnamebuf[512], *ver, *desc;
+ int acsz = -1, ret;
+
+ if((themod = find_module(modname)))
+ {
+ if(sptr)
+ sendto_one(sptr, ":%s NOTICE %s :Module %s is already loaded"
+ " [version: %s]", me.name, sptr->name, modname,
+ themod->version);
+ else
+ fprintf(stderr, " - Module %s is already loaded [version: %s]\n",
+ modname, themod->version);
+ return 0;
+ }
+
+ if(modules && modules->module_path)
+ ircsnprintf(mnamebuf, 512, "%s/%s.so", modules->module_path, modname);
+ else
+ ircsnprintf(mnamebuf, 512, "%s/modules/%s.so", dpath, modname);
+
+ tmpmod.handle = dlopen(mnamebuf, RTLD_NOW);
+ if(tmpmod.handle == NULL)
+ {
+ if(sptr)
+ sendto_one(sptr, ":%s NOTICE %s :Module load error for %s: %s",
+ me.name, sptr->name, modname, dlerror());
+ else
+ fprintf(stderr, " - Module load error for %s: %s\n",
+ modname, dlerror());
+ return -1;
+ }
+
+ if(!modsym_load(sptr, modname, "bircmodule_check", tmpmod.handle,
+ (void **) &tmpmod.module_check))
+ return -1;
+ if(!modsym_load(sptr, modname, "bircmodule_init", tmpmod.handle,
+ (void **) &tmpmod.module_init))
+ return -1;
+ if(!modsym_load(sptr, modname, "bircmodule_shutdown", tmpmod.handle,
+ (void **) &tmpmod.module_shutdown))
+ return -1;
+ if(!modsym_load(sptr, modname, "bircmodule_getinfo", tmpmod.handle,
+ (void **) &tmpmod.module_getinfo))
+ return -1;
+ if(!modsym_load(sptr, modname, "bircmodule_command", tmpmod.handle,
+ (void **) &tmpmod.module_command))
+ return -1;
+ if(!modsym_load(sptr, modname, "bircmodule_globalcommand", tmpmod.handle,
+ (void **) &tmpmod.module_globalcommand))
+ return -1;
+
+ (*tmpmod.module_check)(&acsz);
+ if(acsz != MODULE_INTERFACE_VERSION)
+ {
+ if(sptr)
+ sendto_one(sptr, ":%s NOTICE %s :Module load error for %s:"
+ " Incompatible module (My interface version: %d Module"
+ " version: %d)", me.name, sptr->name, modname,
+ MODULE_INTERFACE_VERSION, acsz);
+ else
+ fprintf(stderr, " - Module load error for %s: Incompatible module ("
+ "My interface version: %d Module version: %d)\n",
+ modname, MODULE_INTERFACE_VERSION, acsz);
+ dlclose(tmpmod.handle);
+ return -1;
+ }
+
+ tmpmod.name = bircmodule_strdup(modname);
+
+ ver = desc = NULL;
+ (*tmpmod.module_getinfo)(&ver, &desc);
+ tmpmod.version = bircmodule_strdup((ver != NULL) ? ver : "<no version>");
+ tmpmod.description = bircmodule_strdup((desc != NULL) ? desc :
+ "<no description>");
+ themod = (aModule *) bircmodule_malloc(sizeof(aModule));
+ memcpy(themod, &tmpmod, sizeof(aModule));
+ add_to_list(&module_list, themod);
+
+ ret = (*themod->module_init)((void *) themod);
+
+ if(ret == 0)
+ {
+ if(sptr)
+ sendto_one(sptr, ":%s NOTICE %s :Module %s successfully loaded"
+ " [version: %s]", me.name, sptr->name, modname,
+ themod->version);
+ else
+ fprintf(stderr, " - Module %s successfully loaded [version: %s]\n",
+ modname, themod->version);
+
+ call_hooks(MHOOK_LOAD, modname, (void *) themod);
+ }
+ else
+ {
+ drop_all_hooks(themod);
+ destroy_module(themod);
+
+ if(sptr)
+ sendto_one(sptr, ":%s NOTICE %s :Module %s load failed (module"
+ " requested unload)", me.name, sptr->name, modname);
+ else
+ fprintf(stderr, " - Module %s load failed (module requested"
+ " unload)\n", modname);
+ }
+ return 0;
+}
+
+int
+unload_module(aClient *sptr, char *modname)
+{
+ aModule *themod = find_module(modname);
+
+ if(!themod)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :Module %s is not loaded",
+ me.name, sptr->name, modname);
+ return 0;
+ }
+
+ drop_all_hooks(themod);
+ call_hooks(MHOOK_UNLOAD, themod->name, (void *) themod);
+ destroy_module(themod);
+
+ sendto_one(sptr, ":%s NOTICE %s :Module %s successfully unloaded",
+ me.name, sptr->name, modname);
+
+ return 0;
+}
+
+int
+m_module(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ if(!IsAnOper(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+
+ if(parc < 2)
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name,
+ parv[0], "MODULE");
+ return 0;
+ }
+
+ /* this should technically never happen anyway, but.. */
+ if(!MyClient(sptr) && !(IsAnOper(sptr) || IsULine(sptr) || IsServer(sptr)))
+ return 0;
+
+ if(mycmp(parv[1], "LOAD") == 0)
+ {
+ if(!(MyClient(sptr) && IsAdmin(sptr)))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+ if(!BadPtr(parv[2]))
+ load_module(sptr, parv[2]);
+ else
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name,
+ parv[0], "MODULE");
+ return 0;
+ }
+
+ }
+ else if(mycmp(parv[1], "UNLOAD") == 0)
+ {
+ if(!(MyClient(sptr) && IsAdmin(sptr)))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+ if(!BadPtr(parv[2]))
+ unload_module(sptr, parv[2]);
+ else
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name,
+ parv[0], "MODULE");
+ return 0;
+ }
+ }
+ else if(mycmp(parv[1], "LIST") == 0)
+ {
+ if(parc > 2 && hunt_server(cptr, sptr, ":%s MODULE %s %s", 2,
+ parc, parv) != HUNTED_ISME)
+ return 0;
+
+ list_modules(sptr);
+ sendto_one(sptr, ":%s NOTICE %s :--- End of module list ---",
+ me.name, sptr->name);
+ }
+ else if(mycmp(parv[1], "HOOKS") == 0)
+ {
+ if(parc > 2 && hunt_server(cptr, sptr, ":%s MODULE %s %s", 2,
+ parc, parv) != HUNTED_ISME)
+ return 0;
+
+ list_hooks(sptr);
+ sendto_one(sptr, ":%s NOTICE %s :--- End of hook list ---",
+ me.name, sptr->name);
+ }
+ else if(mycmp(parv[1], "CMD") == 0)
+ {
+ aModule *themod;
+ if(!(MyClient(sptr) && IsAdmin(sptr)))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+ if(BadPtr(parv[2]))
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name,
+ parv[0], "MODULE");
+ return 0;
+ }
+ themod = find_module(parv[2]);
+ if(!themod)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :Module %s not found for cmd",
+ me.name, sptr->name, parv[2]);
+ return 0;
+ }
+ return (*themod->module_command) (sptr, parc - 2, parv + 2);
+ }
+ else if(parc > 2 && mycmp(parv[1], "CGLOBAL") == 0)
+ {
+ char pbuf[512];
+ aModule *themod;
+
+ if(!(IsServer(sptr) || IsULine(sptr)))
+ return 0;
+
+ themod = find_module(parv[2]);
+
+ /* Pass this on to all servers! */
+ make_parv_copy(pbuf, parc, parv);
+ sendto_serv_butone(cptr, ":%s MODULE %s", parv[0], pbuf);
+
+ if(themod)
+ return (*themod->module_globalcommand)
+ (cptr, sptr, parc - 2, parv + 2);
+ }
+ return 0;
+}
+
+
+/* module memory functions */
+
+char *
+bircmodule_strdup(char *string)
+{
+ char *ret = MyMalloc(strlen(string) + 1);
+ strcpy(ret, string);
+ return ret;
+}
+
+void *
+bircmodule_malloc(int size)
+{
+ return MyMalloc(size);
+}
+
+void
+bircmodule_free(void *p)
+{
+ MyFree(p);
+}
+
+/* hook functions */
+
+typedef struct module_hook
+{
+ aModule *owner;
+ void *funcptr;
+ int hooktype;
+} aHook;
+
+static DLink *preaccess_hooks = NULL;
+static DLink *postaccess_hooks = NULL;
+static DLink *postmotd_hooks = NULL;
+static DLink *msg_hooks = NULL;
+static DLink *chanmsg_hooks = NULL;
+static DLink *usermsg_hooks = NULL;
+static DLink *mymsg_hooks = NULL;
+static DLink *every10_hooks = NULL;
+static DLink *signoff_hooks = NULL;
+static DLink *mload_hooks = NULL;
+static DLink *munload_hooks = NULL;
+
+static DLink *all_hooks = NULL;
+
+char *
+get_texthooktype(enum c_hooktype hooktype)
+{
+ static char ubuf[32];
+
+ switch(hooktype)
+ {
+ case CHOOK_10SEC:
+ return "10 seconds";
+
+ case CHOOK_PREACCESS:
+ return "Pre-access";
+
+ case CHOOK_POSTACCESS:
+ return "Post-access";
+
+ case CHOOK_POSTMOTD:
+ return "Post-MOTD";
+
+ case CHOOK_MSG:
+ return "Message";
+
+ case CHOOK_CHANMSG:
+ return "Channel Message";
+
+ case CHOOK_USERMSG:
+ return "User targeted Message";
+
+ case CHOOK_MYMSG:
+ return "Message to me";
+
+ case CHOOK_SIGNOFF:
+ return "Signoff";
+
+ case MHOOK_LOAD:
+ return "Module load";
+
+ case MHOOK_UNLOAD:
+ return "Module unload";
+
+ default:
+ ircsnprintf(ubuf, 32, "Unknown (%d)", hooktype);
+ return ubuf;
+ }
+}
+
+DLink **
+get_hooklist(enum c_hooktype hooktype)
+{
+ DLink **hooklist;
+
+ switch(hooktype)
+ {
+ case CHOOK_10SEC:
+ hooklist = &every10_hooks;
+ break;
+
+ case CHOOK_PREACCESS:
+ hooklist = &preaccess_hooks;
+ break;
+
+ case CHOOK_POSTACCESS:
+ hooklist = &postaccess_hooks;
+ break;
+
+ case CHOOK_POSTMOTD:
+ hooklist = &postmotd_hooks;
+ break;
+
+ case CHOOK_MSG:
+ hooklist = &msg_hooks;
+ break;
+
+ case CHOOK_CHANMSG:
+ hooklist = &chanmsg_hooks;
+ break;
+
+ case CHOOK_USERMSG:
+ hooklist = &usermsg_hooks;
+ break;
+
+ case CHOOK_MYMSG:
+ hooklist = &mymsg_hooks;
+ break;
+
+ case CHOOK_SIGNOFF:
+ hooklist = &signoff_hooks;
+ break;
+
+ case MHOOK_LOAD:
+ hooklist = &mload_hooks;
+ break;
+
+ case MHOOK_UNLOAD:
+ hooklist = &munload_hooks;
+ break;
+
+ default:
+ return NULL;
+ }
+ return hooklist;
+}
+
+void
+drop_all_hooks(aModule *owner)
+{
+ DLink *lp, *lpn, **hooklist;
+
+ for(lp = all_hooks; lp; lp = lpn)
+ {
+ aHook *hk = (aHook *) lp->value.cp;
+
+ lpn = lp->next;
+
+ if(hk->owner == owner)
+ {
+ sendto_realops_lev(DEBUG_LEV, "Module cleanup: removing hook [%s]"
+ " for opaque %d", get_texthooktype(hk->hooktype),
+ (int) owner);
+
+ hooklist = get_hooklist((enum c_hooktype) hk->hooktype);
+
+ remove_from_list(hooklist, hk, NULL);
+ remove_from_list(&all_hooks, hk, NULL);
+ bircmodule_free(hk);
+ }
+ }
+}
+
+void *
+bircmodule_add_hook(enum c_hooktype hooktype, void *opaque, void *funcptr)
+{
+ DLink **hooklist;
+ aHook *hk;
+ aModule *owner;
+
+ if(!(owner = find_module_opaque(opaque)))
+ {
+ sendto_realops_lev(DEBUG_LEV, "Module tried to add hooktype %d with"
+ " unknown opaque 0x%x", (int) hooktype, (int) opaque);
+ return NULL;
+ }
+
+ if((hooklist = get_hooklist(hooktype)) == NULL)
+ return NULL;
+
+ hk = (aHook *) bircmodule_malloc(sizeof(aHook));
+ hk->owner = owner;
+ hk->funcptr = funcptr;
+ hk->hooktype = (int) hooktype;
+
+ add_to_list(&all_hooks, hk);
+ add_to_list(hooklist, hk);
+
+ return (void *) hk;
+}
+
+void
+bircmodule_del_hook(void *opaque)
+{
+ DLink *lp, *lpn, **hooklist;
+
+ for(lp = all_hooks; lp; lp = lpn)
+ {
+ aHook *hk = (aHook *) lp->value.cp;
+
+ lpn = lp->next;
+
+ if((void *) hk == opaque)
+ {
+ hooklist = get_hooklist((enum c_hooktype) hk->hooktype);
+
+ remove_from_list(hooklist, hk, NULL);
+ remove_from_list(&all_hooks, hk, NULL);
+ bircmodule_free(hk);
+ }
+ }
+}
+
+int
+call_hooks(enum c_hooktype hooktype, ...)
+{
+ va_list vl;
+ int ret = 0;
+ DLink *lp;
+
+ va_start(vl, hooktype);
+
+ switch(hooktype)
+ {
+ case CHOOK_10SEC:
+ for(lp = every10_hooks; lp; lp = lp->next)
+ {
+ void (*rfunc) () = ((aHook *)lp->value.cp)->funcptr;
+ (*rfunc)();
+ }
+ break;
+
+ case CHOOK_PREACCESS:
+ {
+ aClient *acptr = va_arg(vl, aClient *);
+
+ for(lp = preaccess_hooks; lp; lp = lp->next)
+ {
+ int (*rfunc) (aClient *) = ((aHook *)lp->value.cp)->funcptr;
+ if((ret = (*rfunc)(acptr)) == FLUSH_BUFFER)
+ break;
+ }
+ break;
+ }
+
+ case CHOOK_POSTACCESS:
+ {
+ aClient *acptr = va_arg(vl, aClient *);
+
+ for(lp = postaccess_hooks; lp; lp = lp->next)
+ {
+ int (*rfunc) (aClient *) = ((aHook *)lp->value.cp)->funcptr;
+ if((ret = (*rfunc)(acptr)) == FLUSH_BUFFER)
+ break;
+ }
+ break;
+ }
+
+ case CHOOK_POSTMOTD:
+ {
+ aClient *acptr = va_arg(vl, aClient *);
+
+ for(lp = postmotd_hooks; lp; lp = lp->next)
+ {
+ int (*rfunc) (aClient *) = ((aHook *)lp->value.cp)->funcptr;
+ if((ret = (*rfunc)(acptr)) == FLUSH_BUFFER)
+ break;
+ }
+ break;
+ }
+
+ case CHOOK_MSG:
+ {
+ aClient *acptr = va_arg(vl, aClient *);
+ int aint = va_arg(vl, int);
+ char *txtptr = va_arg(vl, char *);
+
+ for(lp = msg_hooks; lp; lp = lp->next)
+ {
+ int (*rfunc) (aClient *, int, char *) =
+ ((aHook *)lp->value.cp)->funcptr;
+ if((ret = (*rfunc)(acptr, aint, txtptr)) == FLUSH_BUFFER)
+ break;
+ }
+ break;
+ }
+
+ case CHOOK_CHANMSG:
+ {
+ aClient *acptr = va_arg(vl, aClient *);
+ aChannel *chptr = va_arg(vl, aChannel *);
+ int aint = va_arg(vl, int);
+ char *txtptr = va_arg(vl, char *);
+
+ for(lp = chanmsg_hooks; lp; lp = lp->next)
+ {
+ int (*rfunc) (aClient *, aChannel *, int, char *) =
+ ((aHook *)lp->value.cp)->funcptr;
+ if((ret = (*rfunc)(acptr, chptr, aint, txtptr))
+ == FLUSH_BUFFER)
+ break;
+ }
+ break;
+ }
+
+ case CHOOK_USERMSG:
+ {
+ aClient *acptr = va_arg(vl, aClient *);
+ aClient *dcptr = va_arg(vl, aClient *);
+ int aint = va_arg(vl, int);
+ char *txtptr = va_arg(vl, char *);
+
+ for(lp = usermsg_hooks; lp; lp = lp->next)
+ {
+ int (*rfunc) (aClient *, aClient *, int, char *) =
+ ((aHook *)lp->value.cp)->funcptr;
+ if((ret = (*rfunc)(acptr, dcptr, aint, txtptr))
+ == FLUSH_BUFFER)
+ break;
+ }
+ break;
+ }
+
+ case CHOOK_MYMSG:
+ {
+ aClient *acptr = va_arg(vl, aClient *);
+ int aint = va_arg(vl, int);
+ char *txtptr = va_arg(vl, char *);
+
+ for(lp = mymsg_hooks; lp; lp = lp->next)
+ {
+ int (*rfunc) (aClient *, int, char *) =
+ ((aHook *)lp->value.cp)->funcptr;
+ if((ret = (*rfunc)(acptr, aint, txtptr)) == FLUSH_BUFFER)
+ break;
+ }
+ break;
+ }
+
+ case CHOOK_SIGNOFF:
+ {
+ aClient *acptr = va_arg(vl, aClient *);
+ for(lp = signoff_hooks; lp; lp = lp->next)
+ {
+ void (*rfunc) (aClient *) =
+ ((aHook *)lp->value.cp)->funcptr;
+ (*rfunc)(acptr);
+ }
+ break;
+ }
+
+ case MHOOK_LOAD:
+ {
+ char *txtptr = va_arg(vl, char *);
+ void *avoid = va_arg(vl, void *);
+
+ for(lp = mload_hooks; lp; lp = lp->next)
+ {
+ int (*rfunc) (char *, void *) =
+ ((aHook *)lp->value.cp)->funcptr;
+ (*rfunc)(txtptr, avoid);
+ }
+ break;
+ }
+
+ case MHOOK_UNLOAD:
+ {
+ char *txtptr = va_arg(vl, char *);
+ void *avoid = va_arg(vl, void *);
+ for(lp = munload_hooks; lp; lp = lp->next)
+ {
+ int (*rfunc) (char *, void *) =
+ ((aHook *)lp->value.cp)->funcptr;
+ (*rfunc)(txtptr, avoid);
+ }
+ break;
+ }
+
+ default:
+ sendto_realops_lev(DEBUG_LEV, "Call for unknown hook type %d",
+ hooktype);
+ break;
+ }
+ va_end(vl);
+ return ret;
+}
+
+void
+list_hooks(aClient *sptr)
+{
+ DLink *lp;
+
+ for(lp = all_hooks; lp; lp = lp->next)
+ {
+ aHook *hook = (aHook *) lp->value.cp;
+ aModule *mod = hook->owner;
+
+ sendto_one(sptr, ":%s NOTICE %s :Module: %s Type: %s",
+ me.name, sptr->name, mod->name,
+ get_texthooktype(hook->hooktype));
+ }
+}
+
+int init_modules()
+{
+ int i;
+
+ if(!modules)
+ return 0;
+
+ for(i = 0; modules->autoload[i]; i++)
+ {
+ load_module(NULL, modules->autoload[i]);
+ printf("Module %s Loaded Successfully.\n", modules->autoload[i]);
+ }
+ return 0;
+}
+#endif
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/packet.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: packet.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "msg.h"
+#include "h.h"
+#include "dh.h"
+#include "zlink.h"
+
+/*
+ * * dopacket
+ * cptr - pointer to client structure for which the buffer
+ * data applies.
+ * buffer - pointr to the buffer containing the newly read data
+ * length - number of valid bytes of data in the buffer
+ *
+ * Note:
+ * It is implicitly assumed that dopacket is called only
+ * with cptr of "local" variation, which contains all the
+ * necessary fields (buffer etc..)
+ */
+int dopacket(aClient *cptr, char *buffer, int length)
+{
+ char *ch1;
+ char *ch2;
+ char *cptrbuf = cptr->buffer;
+ aListener *lptr = cptr->lstn;
+ char *nbuf = NULL;
+ int nlen;
+
+#ifdef HAVE_ENCRYPTION_ON
+ if(IsRC4IN(cptr))
+ rc4_process_stream(cptr->serv->rc4_in, buffer, length);
+#endif
+
+ me.receiveB += length; /* Update bytes received */
+ cptr->receiveB += length;
+
+ if (cptr->receiveB & 0x0400)
+ {
+ cptr->receiveK += (cptr->receiveB >> 10);
+ cptr->receiveB &= 0x03ff; /* 2^10 = 1024, 3ff = 1023 */
+ }
+
+ if (lptr)
+ {
+ lptr->receiveB += length;
+ if (lptr->receiveB & 0x0400)
+ {
+ lptr->receiveK += (lptr->receiveB >> 10);
+ lptr->receiveB &= 0x03ff;
+ }
+ }
+ else if (me.receiveB & 0x0400)
+ {
+ me.receiveK += (me.receiveB >> 10);
+ me.receiveB &= 0x03ff;
+ }
+
+zcontinue:
+ ch1 = cptrbuf + cptr->count;
+ ch2 = buffer;
+
+ if(ZipIn(cptr))
+ {
+ int err;
+ ch2 = zip_input(cptr->serv->zip_in, ch2, &length, &err, &nbuf, &nlen);
+
+ if(length == -1)
+ {
+ sendto_realops("Zipin error for %s: (%d) %s\n", cptr->name,
+ err, ch2);
+ return exit_client(cptr, cptr, &me, "fatal error in zip_input!");
+ }
+ }
+
+ while (--length >= 0)
+ {
+ char g;
+
+ g = (*ch1 = *ch2++);
+ /*
+ * Yuck. Stuck. To make sure we stay backward compatible, we
+ * must assume that either CR or LF terminates the message and
+ * not CR-LF. By allowing CR or LF (alone) into the body of
+ * messages, backward compatibility is lost and major problems
+ * will arise. - Avalon
+ */
+ if (g < '\16' && (g == '\n' || g == '\r')) {
+ if (ch1 == cptrbuf)
+ continue; /* Skip extra LF/CR's */
+ *ch1 = '\0';
+ me.receiveM += 1; /* Update messages received */
+ cptr->receiveM += 1;
+ if (lptr)
+ lptr->receiveM += 1;
+ cptr->count = 0; /*
+ * ...just in case parse returns with
+ * FLUSH_BUFFER without removing the
+ * structure pointed by cptr... --msa
+ */
+ switch (parse(cptr, cptr->buffer, ch1))
+ {
+ case FLUSH_BUFFER:
+ return FLUSH_BUFFER;
+
+ case ZIP_NEXT_BUFFER:
+ if(length)
+ {
+ int err;
+ ch2 = zip_input(cptr->serv->zip_in, ch2, &length,
+ &err, &nbuf, &nlen);
+
+ if(length == -1)
+ {
+ sendto_realops("Zipin error for %s: (%d) %s\n",
+ cptr->name, err, ch2);
+ return exit_client(cptr, cptr, &me,
+ "fatal error in zip_input!");
+ }
+ }
+ break;
+
+#ifdef HAVE_ENCRYPTION_ON
+ case RC4_NEXT_BUFFER:
+ if(length)
+ rc4_process_stream(cptr->serv->rc4_in, ch2, length);
+ break;
+#endif
+
+ default:
+ break;
+ }
+
+ /*
+ * Socket is dead so exit (which always returns with *
+ * FLUSH_BUFFER here). - avalon
+ */
+ if (cptr->flags & FLAGS_DEADSOCKET)
+ return exit_client(cptr, cptr, &me,
+ (cptr->flags & FLAGS_SENDQEX) ?
+ "SendQ exceeded" : "Dead socket");
+ ch1 = cptrbuf;
+ }
+ else if (ch1 < cptrbuf + (sizeof(cptr->buffer) - 1))
+ ch1++; /* There is always room for the null */
+ }
+ cptr->count = ch1 - cptrbuf;
+
+ if(nbuf)
+ {
+#if 0 /* this message is annoying and not quite that useful */
+ static time_t last_complain = 0;
+ static int numrepeat = 0;
+
+ numrepeat++;
+
+ if(NOW > (last_complain + 300)) /* if more than 5 mins have elapsed */
+ {
+ if(last_complain == 0)
+ {
+ sendto_realops("Overflowed zipInBuf! "
+ "If you see this a lot, you should increase "
+ "zipInBufSize in src/zlink.c.");
+ }
+ else
+ {
+ sendto_realops("Overflowed zipInBuf %d time%s in the "
+ "last %d minutes. If you see this a lot, you "
+ "should increase zipInBufSize in src/zlink.c.",
+ numrepeat, numrepeat == 1 ? "" : "s",
+ (NOW - last_complain) / 60);
+ }
+ last_complain = NOW;
+ numrepeat = 0;
+ }
+#endif
+
+ buffer = nbuf;
+ length = nlen;
+ nbuf = NULL;
+ goto zcontinue; /* gross, but it should work.. */
+ }
+
+ return 0;
+}
+
+int client_dopacket(aClient *cptr, char *buffer, int length)
+{
+
+ strncpy(cptr->buffer, buffer, BUFSIZE);
+ length = strlen(cptr->buffer);
+
+ /* Update messages received */
+ ++me.receiveM;
+ ++cptr->receiveM;
+
+ /* Update bytes received */
+ cptr->receiveB += length;
+
+ if (cptr->receiveB > 1023)
+ {
+ cptr->receiveK += (cptr->receiveB >> 10);
+ cptr->receiveB &= 0x03ff; /* 2^10 = 1024, 3ff = 1023 */
+ }
+ me.receiveB += length;
+
+ if (me.receiveB > 1023)
+ {
+ me.receiveK += (me.receiveB >> 10);
+ me.receiveB &= 0x03ff;
+ }
+
+ cptr->count = 0; /* ...just in case parse returns with */
+ if (FLUSH_BUFFER == parse(cptr, cptr->buffer, cptr->buffer + length))
+ {
+ /*
+ * CLIENT_EXITED means actually that cptr
+ * structure *does* not exist anymore!!! --msa
+ */
+ return FLUSH_BUFFER;
+ }
+ else if (cptr->flags & FLAGS_DEADSOCKET)
+ {
+ /*
+ * Socket is dead so exit (which always returns with
+ * CLIENT_EXITED here). - avalon
+ */
+ return exit_client(cptr, cptr, &me,
+ (cptr->flags & FLAGS_SENDQEX) ?
+ "SendQ exceeded" : "Dead socket");
+ }
+ return 1;
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/parse.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: parse.c,v 1.1 2005/01/12 07:44:56 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#define MSGTAB
+#include "msg.h"
+#undef MSGTAB
+#include "sys.h"
+#include "numeric.h"
+#include "h.h"
+
+#if defined( HAVE_STRING_H )
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/* NOTE: parse() should not be called recursively by other functions! */
+static char *para[MAXPARA + 1];
+static int cancel_clients(aClient *, aClient *, char *);
+static void remove_unknown(aClient *, char *, char *);
+
+static char sender[HOSTLEN + 1];
+static int cancel_clients(aClient *, aClient *, char *);
+static void remove_unknown(aClient *, char *, char *);
+
+static struct Message *do_msg_tree(MESSAGE_TREE *, char *, struct Message *);
+static struct Message *tree_parse(char *);
+
+int num_msg_trees = 0;
+
+/*
+ * parse a buffer.
+ *
+ * NOTE: parse() should not be called recusively by any other functions!
+ */
+
+int parse(aClient *cptr, char *buffer, char *bufend)
+{
+ aClient *from = cptr;
+ char *ch, *s;
+ int i, numeric = 0, paramcount;
+ struct Message *mptr;
+
+#ifdef DUMP_DEBUG
+ if(dumpfp!=NULL)
+ {
+ fprintf(dumpfp, "<- %s: %s\n", (cptr->name ? cptr->name : "*"),
+ buffer);
+ fflush(dumpfp);
+ }
+#endif
+ Debug((DEBUG_DEBUG, "Parsing %s: %s", get_client_name(cptr, TRUE),
+ buffer));
+
+ if (IsDead(cptr))
+ return -1;
+
+ s = sender;
+ *s = '\0';
+
+ for (ch = buffer; *ch == ' '; ch++); /* skip spaces */
+
+ para[0] = from->name;
+ if (*ch == ':')
+ {
+ /*
+ * Copy the prefix to 'sender' assuming it terminates with
+ * SPACE (or NULL, which is an error, though).
+ */
+
+ for (++ch; *ch && *ch != ' '; ++ch)
+ if (s < (sender + HOSTLEN))
+ *s++ = *ch;
+ *s = '\0';
+
+ /*
+ * Actually, only messages coming from servers can have the
+ * prefix--prefix silently ignored, if coming from a user
+ * client...
+ *
+ * ...sigh, the current release "v2.2PL1" generates also null
+ * prefixes, at least to NOTIFY messages (e.g. it puts
+ * "sptr->nickname" as prefix from server structures where it's
+ * null--the following will handle this case as "no prefix" at
+ * all --msa (": NOTICE nick ...")
+ */
+
+ if (*sender && IsServer(cptr))
+ {
+ from = find_client(sender, (aClient *) NULL);
+
+ /*
+ * okay, this doesn't seem to do much here.
+ * from->name _MUST_ be equal to sender.
+ * That's what find_client does.
+ * find_client will find servers too, and since we don't use server
+ * masking, the find server call is useless (and very wasteful).
+ * now, there HAS to be a from and from->name and
+ * sender have to be the same
+ * for us to get to the next if. but the next if
+ * starts out with if(!from)
+ * so this is UNREACHABLE CODE! AGH! - lucas
+ *
+ * if (!from || mycmp(from->name, sender))
+ * from = find_server(sender, (aClient *) NULL);
+ * else if (!from && strchr(sender, '@'))
+ * from = find_nickserv(sender, (aClient *) NULL);
+ */
+
+ para[0] = sender;
+ /*
+ * Hmm! If the client corresponding to the prefix is not
+ * found--what is the correct action??? Now, I will ignore the
+ * message (old IRC just let it through as if the prefix just
+ * wasn't there...) --msa
+ */
+ if (!from)
+ {
+ Debug((DEBUG_ERROR, "Unknown prefix (%s)(%s) from (%s)",
+ sender, buffer, cptr->name));
+
+ ircstp->is_unpf++;
+ remove_unknown(cptr, sender, buffer);
+
+ return -1;
+ }
+
+ if (from->from != cptr)
+ {
+ ircstp->is_wrdi++;
+ Debug((DEBUG_ERROR, "Message (%s) coming from (%s)",
+ buffer, cptr->name));
+
+ return cancel_clients(cptr, from, buffer);
+ }
+ }
+ while (*ch == ' ')
+ ch++;
+ }
+
+ if (*ch == '\0')
+ {
+ ircstp->is_empt++;
+ Debug((DEBUG_NOTICE, "Empty message from host %s:%s",
+ cptr->name, from->name));
+ return (-1);
+ }
+ /*
+ * Extract the command code from the packet. Point s to the end
+ * of the command code and calculate the length using pointer
+ * arithmetic. Note: only need length for numerics and *all*
+ * numerics must have parameters and thus a space after the command
+ * code. -avalon
+ *
+ * ummm???? - Dianora
+ */
+
+ /* check for numeric */
+ if (*(ch + 3) == ' ' && IsDigit(*ch) && IsDigit(*(ch + 1)) &&
+ IsDigit(*(ch + 2)))
+ {
+ mptr = (struct Message *) NULL;
+ numeric = (*ch - '0') * 100 + (*(ch + 1) - '0') *
+ 10 + (*(ch + 2) - '0');
+ paramcount = MAXPARA;
+ ircstp->is_num++;
+ s = ch + 3;
+ *s++ = '\0';
+ }
+ else
+ {
+ s = strchr(ch, ' ');
+
+ if (s)
+ *s++ = '\0';
+
+ mptr = tree_parse(ch);
+
+ if (!mptr || !mptr->cmd)
+ {
+ /*
+ * only send error messages to things that actually sent
+ * buffers to us and only people, too.
+ */
+ if (buffer[0] != '\0')
+ {
+ if (IsPerson(from))
+ sendto_one(from, ":%s %d %s %s :Unknown command",
+ me.name, ERR_UNKNOWNCOMMAND, from->name, ch);
+ Debug((DEBUG_ERROR, "Unknown (%s) from %s",
+ ch, get_client_name(cptr, TRUE)));
+ }
+ ircstp->is_unco++;
+ return -1;
+ }
+
+ paramcount = mptr->parameters;
+ i = bufend - ((s) ? s : ch);
+ mptr->bytes += i;
+ /*
+ * Allow only 1 msg per 2 seconds (on average) to prevent
+ * dumping. to keep the response rate up, bursts of up to 5 msgs
+ * are allowed -SRB Opers can send 1 msg per second, burst of ~20
+ * -Taner
+ */
+ if ((mptr->flags & 1) && !(IsServer(cptr)))
+ {
+ if (!NoMsgThrottle(cptr))
+ {
+#ifdef NO_OPER_FLOOD
+ if (IsAnOper(cptr))
+ /* "randomly" (weighted) increase the since */
+ cptr->since += (cptr->receiveM % 10) ? 1 : 0;
+ else
+#endif
+ cptr->since += (2 + i / 120);
+ }
+ }
+ }
+ /*
+ * Must the following loop really be so devious? On surface it
+ * splits the message to parameters from blank spaces. But, if
+ * paramcount has been reached, the rest of the message goes into
+ * this last parameter (about same effect as ":" has...) --msa
+ */
+
+ /* Note initially true: s==NULL || *(s-1) == '\0' !! */
+
+ i = 1;
+ if (s)
+ {
+ if (paramcount > MAXPARA)
+ paramcount = MAXPARA;
+ for (;;)
+ {
+ while (*s == ' ')
+ *s++ = '\0';
+
+ if (*s == '\0')
+ break;
+ if (*s == ':')
+ {
+ /* The rest is a single parameter */
+ para[i++] = s + 1;
+ break;
+ }
+ para[i++] = s;
+ if (i >= paramcount)
+ {
+ if(paramcount == MAXPARA && strchr(s, ' '))
+ {
+ sendto_realops_lev(DEBUG_LEV, "Overflowed MAXPARA on %s from %s",
+ mptr ? mptr->cmd : "numeric",
+ get_client_name(cptr, (IsServer(cptr) ? HIDEME : TRUE)));
+ }
+ break;
+ }
+
+ while(*s && *s != ' ')
+ s++;
+ }
+ }
+
+ para[i] = NULL;
+ if (mptr == (struct Message *) NULL)
+ return (do_numeric(numeric, cptr, from, i, para));
+
+ mptr->count++;
+
+ /* patch to avoid server flooding from unregistered connects */
+ /*
+ * check allow_unregistered_use flag I've set up instead of function
+ * comparing *yech* - Dianora
+ */
+
+ if (!IsRegistered(cptr) && !mptr->allow_unregistered_use) {
+ sendto_one(from, ":%s %d %s %s :Register first.",
+ me.name, ERR_NOTREGISTERED, from->name, ch);
+ return -1;
+ }
+
+ if (IsRegisteredUser(cptr) && mptr->reset_idle)
+ from->user->last = timeofday;
+
+ return (*mptr->func) (cptr, from, i, para);
+}
+
+/*
+ * init_tree_parse()
+ *
+ * inputs - pointer to msg_table defined in msg.h output
+ * NONE side effects - MUST MUST be called at startup ONCE before
+ * any other keyword hash routine is used.
+ *
+ * -Dianora, orabidoo
+ */
+
+/* for qsort'ing the msgtab in place -orabidoo */
+static int mcmp(struct Message *m1, struct Message *m2)
+{
+ return strcmp(m1->cmd, m2->cmd);
+}
+
+/* Initialize the msgtab parsing tree -orabidoo */
+void init_tree_parse(struct Message *mptr)
+{
+ int i;
+ struct Message *mpt = mptr;
+
+ for (i = 0; mpt->cmd; mpt++)
+ i++;
+ qsort((void *) mptr, i, sizeof(struct Message),
+ (int (*)(const void *, const void *)) mcmp);
+
+ msg_tree_root = (MESSAGE_TREE *) MyMalloc(sizeof(MESSAGE_TREE));
+ num_msg_trees++;
+ mpt = do_msg_tree(msg_tree_root, "", mptr);
+ /*
+ * this happens if one of the msgtab entries included characters
+ * other than capital letters -orabidoo
+ */
+ if (mpt->cmd)
+ {
+ fprintf(stderr, "bad msgtab entry: ``%s''\n", mpt->cmd);
+ exit(1);
+ }
+}
+
+/* Recursively make a prefix tree out of the msgtab -orabidoo */
+static struct Message *do_msg_tree(MESSAGE_TREE * mtree, char *prefix,
+ struct Message *mptr)
+{
+ char newpref[64]; /* must be longer than any command */
+ int c, c2, lp;
+ MESSAGE_TREE *mtree1;
+
+ lp = strlen(prefix);
+ if (!lp || !strncmp(mptr->cmd, prefix, lp))
+ {
+ if (!mptr[1].cmd || (lp && strncmp(mptr[1].cmd, prefix, lp)))
+ {
+ /* non ambiguous, make a final case */
+ mtree->final = mptr->cmd + lp;
+ mtree->msg = mptr;
+ for (c = 0; c <= 25; c++)
+ mtree->pointers[c] = NULL;
+ return mptr + 1;
+ }
+ else
+ {
+ /* ambigous, make new entries for each of the letters that match */
+ if (!mycmp(mptr->cmd, prefix))
+ {
+ mtree->final = (void *) 1;
+ mtree->msg = mptr;
+ mptr++;
+ }
+ else
+ mtree->final = NULL;
+
+ for (c = 'A'; c <= 'Z'; c++)
+ {
+ if (mptr->cmd[lp] == c)
+ {
+ mtree1 = (MESSAGE_TREE *) MyMalloc(sizeof(MESSAGE_TREE));
+ num_msg_trees++;
+ mtree1->final = NULL;
+ mtree->pointers[c - 'A'] = mtree1;
+ strcpy(newpref, prefix);
+ newpref[lp] = c;
+ newpref[lp + 1] = '\0';
+ mptr = do_msg_tree(mtree1, newpref, mptr);
+ if (!mptr->cmd || strncmp(mptr->cmd, prefix, lp))
+ {
+ for (c2 = c + 1 - 'A'; c2 <= 25; c2++)
+ mtree->pointers[c2] = NULL;
+ return mptr;
+ }
+ }
+ else
+ {
+ mtree->pointers[c - 'A'] = NULL;
+ }
+ }
+ return mptr;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "do_msg_tree: this should never happen!\n");
+ exit(1);
+ }
+}
+
+/*
+ * tree_parse()
+ *
+ * inputs
+ * - pointer to command in upper case output NULL pointer if not found
+ * struct Message pointer to command entry if found
+ * side effects - NONE
+ *
+ * -Dianora, orabidoo
+ */
+static struct Message *tree_parse(char *cmd)
+{
+ char r;
+ MESSAGE_TREE *mtree = msg_tree_root;
+
+ while ((r = *cmd++))
+ {
+ r &= 0xdf; /*
+ * some touppers have trouble w/
+ * lowercase, says Dianora
+ */
+ if (r < 'A' || r > 'Z')
+ return NULL;
+ mtree = mtree->pointers[r - 'A'];
+ if (!mtree)
+ return NULL;
+ if (mtree->final == (void *) 1)
+ {
+ if (!*cmd)
+ return mtree->msg;
+ }
+ else if (mtree->final && !mycmp(mtree->final, cmd))
+ return mtree->msg;
+ }
+ return ((struct Message *) NULL);
+}
+
+/* field breakup for ircd.conf file. */
+char *getfield(char *newline)
+{
+ static char *line = (char *) NULL;
+ char *end, *field;
+
+ if (newline)
+ line = newline;
+
+ if (line == (char *) NULL)
+ return ((char *) NULL);
+
+ field = line;
+ if ((end = strchr(line, ':')) == NULL)
+ {
+ line = (char *) NULL;
+ if ((end = strchr(field, '\n')) == (char *) NULL)
+ end = field + strlen(field);
+ }
+ else
+ line = end + 1;
+ *end = '\0';
+ return (field);
+}
+
+static int cancel_clients(aClient *cptr, aClient *sptr, char *cmd)
+{
+ /*
+ * kill all possible points that are causing confusion here, I'm not
+ * sure I've got this all right... - avalon
+ *
+ * knowing avalon, probably not.
+ */
+ /*
+ * with TS, fake prefixes are a common thing, during the connect
+ * burst when there's a nick collision, and they must be ignored
+ * rather than killed because one of the two is surviving.. so we
+ * don't bother sending them to all ops everytime, as this could
+ * send 'private' stuff from lagged clients. we do send the ones
+ * that cause servers to be dropped though, as well as the ones
+ * from * non-TS servers -orabidoo
+ */
+ /*
+ * Incorrect prefix for a server from some connection. If it is a
+ * client trying to be annoying, just QUIT them, if it is a server
+ * then the same deal.
+ */
+ if (IsServer(sptr) || IsMe(sptr))
+ {
+ /* Sorry, but at the moment this is just too much for even opers
+ to see. -Rak */
+ /* or we could just take out the message. <EG> -wd */
+ sendto_realops_lev(DEBUG_LEV, "Message for %s[%s] from %s",
+ sptr->name, sptr->from->name,
+ get_client_name(cptr,
+ (IsServer(cptr) ? HIDEME : TRUE)));
+ if (IsServer(cptr))
+ {
+ sendto_realops_lev(DEBUG_LEV,
+ "Not dropping server %s (%s) for "
+ "Fake Direction", cptr->name, sptr->name);
+ return -1;
+ }
+
+ if (IsClient(cptr))
+ sendto_realops_lev(DEBUG_LEV,
+ "Would have dropped client %s (%s@%s) "
+ "[%s from %s]", cptr->name,
+ cptr->user->username, cptr->user->host,
+ cptr->user->server, cptr->from->name);
+ return -1;
+ }
+ /*
+ * Ok, someone is trying to impose as a client and things are
+ * confused. If we got the wrong prefix from a server, send out a
+ * kill, else just exit the lame client.
+ */
+ if (IsServer(cptr))
+ {
+ /*
+ * If the fake prefix is coming from a TS server, discard it
+ * silently -orabidoo
+ * also drop it if we're gonna kill services by not doing so }:/
+ */
+ if (DoesTS(cptr))
+ {
+ if (sptr->user)
+ sendto_realops_lev(DEBUG_LEV,
+ "Message for %s[%s@%s!%s] from %s "
+ "(TS, ignored)", sptr->name,
+ sptr->user->username, sptr->user->host,
+ sptr->from->name,
+ get_client_name(cptr, TRUE));
+ return 0;
+ }
+ else
+ {
+ if (sptr->user)
+ sendto_realops_lev(DEBUG_LEV,
+ "Message for %s[%s@%s!%s] from %s",
+ sptr->name, sptr->user->username,
+ sptr->user->host,
+ sptr->from->name,
+ get_client_name(cptr, (IsServer(cptr) ?
+ HIDEME : TRUE)));
+ if(IsULine(sptr))
+ {
+ sendto_realops_lev(DEBUG_LEV,
+ "Would have killed U:lined client %s "
+ "for fake direction", sptr->name);
+ return 0;
+ }
+ sendto_serv_butone(NULL,
+ ":%s KILL %s :%s (%s[%s] != %s, Fake Prefix)",
+ me.name, sptr->name, me.name,
+ sptr->name, sptr->from->name,
+ get_client_name(cptr, (IsServer(cptr) ?
+ HIDEME : TRUE)));
+ sptr->flags |= FLAGS_KILLED;
+ return exit_client(cptr, sptr, &me, "Fake Prefix");
+ }
+ }
+ return exit_client(cptr, cptr, &me, "Fake prefix");
+}
+
+static void remove_unknown(aClient *cptr, char *sender, char *buffer)
+{
+ if (!IsRegistered(cptr))
+ return;
+
+ if (IsClient(cptr))
+ {
+ sendto_realops_lev(DEBUG_LEV,
+ "Weirdness: Unknown client prefix (%s) from %s, "
+ "Ignoring %s", buffer,
+ get_client_name(cptr, FALSE), sender);
+ return;
+ }
+ /* Not from a server so don't need to worry about it. */
+ if (!IsServer(cptr))
+ return;
+ /*
+ * Do kill if it came from a server because it means there is a
+ * ghost user on the other server which needs to be removed. -avalon
+ * Tell opers about this. -Taner
+ */
+ if (!strchr(sender, '.'))
+ sendto_one(cptr, ":%s KILL %s :%s (%s(?) <- %s)",
+ me.name, sender, me.name, sender,
+ get_client_name(cptr, FALSE));
+ else
+ {
+ sendto_realops_lev(DEBUG_LEV,
+ "Unknown prefix (%s) from %s, Squitting %s",
+ buffer, get_client_name(cptr, HIDEME), sender);
+ sendto_one(cptr, ":%s SQUIT %s :(Unknown prefix (%s) from %s)",
+ me.name, sender, buffer, get_client_name(cptr, HIDEME));
+ }
+}
--- /dev/null
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/*
+This is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language. See
+the file Tech.Notes for some information on the internals.
+
+Written by: Philip Hazel <ph10@cam.ac.uk>
+
+ Copyright (c) 1997-2003 University of Cambridge
+
+-----------------------------------------------------------------------------
+Permission is granted to anyone to use this software for any purpose on any
+computer system, and to redistribute it freely, subject to the following
+restrictions:
+
+1. This software 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.
+
+2. The origin of this software must not be misrepresented, either by
+ explicit claim or by omission.
+
+3. Altered versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+
+4. If PCRE is embedded in any software that is released under the GNU
+ General Purpose Licence (GPL), then the terms of that licence shall
+ supersede any condition above with which it is incompatible.
+-----------------------------------------------------------------------------
+*/
+
+
+/* Define DEBUG to get debugging output on stdout. */
+/* #define DEBUG */
+
+/* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef
+inline, and there are *still* stupid compilers about that don't like indented
+pre-processor statements. I suppose it's only been 10 years... */
+
+#ifdef DEBUG
+#define DPRINTF(p) printf p
+#else
+#define DPRINTF(p) /*nothing*/
+#endif
+
+/* Include the internals header, which itself includes "config.h", the Standard
+C headers, and the external pcre header. */
+
+#include "pcre_internal.h"
+
+
+/* Allow compilation as C++ source code, should anybody want to do that. */
+
+#ifdef __cplusplus
+#define class pcre_class
+#endif
+
+
+/* Maximum number of items on the nested bracket stacks at compile time. This
+applies to the nesting of all kinds of parentheses. It does not limit
+un-nested, non-capturing parentheses. This number can be made bigger if
+necessary - it is used to dimension one int and one unsigned char vector at
+compile time. */
+
+#define BRASTACK_SIZE 200
+
+
+/* Maximum number of ints of offset to save on the stack for recursive calls.
+If the offset vector is bigger, malloc is used. This should be a multiple of 3,
+because the offset vector is always a multiple of 3 long. */
+
+#define REC_STACK_SAVE_MAX 30
+
+
+/* The number of bytes in a literal character string above which we can't add
+any more is set at 250 in order to allow for UTF-8 characters. (In theory it
+could be 255 when UTF-8 support is excluded, but that means that some of the
+test output would be different, which just complicates things.) */
+
+#define MAXLIT 250
+
+
+/* The maximum remaining length of subject we are prepared to search for a
+req_byte match. */
+
+#define REQ_BYTE_MAX 1000
+
+
+/* Table of sizes for the fixed-length opcodes. It's defined in a macro so that
+the definition is next to the definition of the opcodes in internal.h. */
+
+static const uschar OP_lengths[] = { OP_LENGTHS };
+
+/* Min and max values for the common repeats; for the maxima, 0 => infinity */
+
+static const char rep_min[] = { 0, 0, 1, 1, 0, 0 };
+static const char rep_max[] = { 0, 0, 0, 0, 1, 1 };
+
+/* Table for handling escaped characters in the range '0'-'z'. Positive returns
+are simple data values; negative values are for special things like \d and so
+on. Zero means further processing is needed (for things like \x), or the escape
+is invalid. */
+
+#if !EBCDIC /* This is the "normal" table for ASCII systems */
+static const short int escapes[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 7 */
+ 0, 0, ':', ';', '<', '=', '>', '?', /* 8 - ? */
+ '@', -ESC_A, -ESC_B, -ESC_C, -ESC_D, -ESC_E, 0, -ESC_G, /* @ - G */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */
+ 0, -ESC_Q, 0, -ESC_S, 0, 0, 0, -ESC_W, /* P - W */
+ 0, 0, -ESC_Z, '[', '\\', ']', '^', '_', /* X - _ */
+ '`', 7, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0, /* ` - g */
+ 0, 0, 0, 0, 0, 0, ESC_n, 0, /* h - o */
+ 0, 0, ESC_r, -ESC_s, ESC_tee, 0, 0, -ESC_w, /* p - w */
+ 0, 0, -ESC_z /* x - z */
+};
+
+#else /* This is the "abnormal" table for EBCDIC systems */
+static const short int escapes[] = {
+/* 48 */ 0, 0, 0, '.', '<', '(', '+', '|',
+/* 50 */ '&', 0, 0, 0, 0, 0, 0, 0,
+/* 58 */ 0, 0, '!', '$', '*', ')', ';', '~',
+/* 60 */ '-', '/', 0, 0, 0, 0, 0, 0,
+/* 68 */ 0, 0, '|', ',', '%', '_', '>', '?',
+/* 70 */ 0, 0, 0, 0, 0, 0, 0, 0,
+/* 78 */ 0, '`', ':', '#', '@', '\'', '=', '"',
+/* 80 */ 0, 7, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0,
+/* 88 */ 0, 0, 0, '{', 0, 0, 0, 0,
+/* 90 */ 0, 0, 0, 'l', 0, ESC_n, 0, 0,
+/* 98 */ 0, ESC_r, 0, '}', 0, 0, 0, 0,
+/* A0 */ 0, '~', -ESC_s, ESC_tee, 0, 0, -ESC_w, 0,
+/* A8 */ 0,-ESC_z, 0, 0, 0, '[', 0, 0,
+/* B0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+/* B8 */ 0, 0, 0, 0, 0, ']', '=', '-',
+/* C0 */ '{',-ESC_A, -ESC_B, -ESC_C, -ESC_D,-ESC_E, 0, -ESC_G,
+/* C8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+/* D0 */ '}', 0, 0, 0, 0, 0, 0, 0,
+/* D8 */-ESC_Q, 0, 0, 0, 0, 0, 0, 0,
+/* E0 */ '\\', 0, -ESC_S, 0, 0, 0, -ESC_W, 0,
+/* E8 */ 0,-ESC_Z, 0, 0, 0, 0, 0, 0,
+/* F0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+/* F8 */ 0, 0, 0, 0, 0, 0, 0, 0
+};
+#endif
+
+
+/* Tables of names of POSIX character classes and their lengths. The list is
+terminated by a zero length entry. The first three must be alpha, upper, lower,
+as this is assumed for handling case independence. */
+
+static const char *const posix_names[] = {
+ "alpha", "lower", "upper",
+ "alnum", "ascii", "blank", "cntrl", "digit", "graph",
+ "print", "punct", "space", "word", "xdigit" };
+
+static const uschar posix_name_lengths[] = {
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 };
+
+/* Table of class bit maps for each POSIX class; up to three may be combined
+to form the class. The table for [:blank:] is dynamically modified to remove
+the vertical space characters. */
+
+static const int posix_class_maps[] = {
+ cbit_lower, cbit_upper, -1, /* alpha */
+ cbit_lower, -1, -1, /* lower */
+ cbit_upper, -1, -1, /* upper */
+ cbit_digit, cbit_lower, cbit_upper, /* alnum */
+ cbit_print, cbit_cntrl, -1, /* ascii */
+ cbit_space, -1, -1, /* blank - a GNU extension */
+ cbit_cntrl, -1, -1, /* cntrl */
+ cbit_digit, -1, -1, /* digit */
+ cbit_graph, -1, -1, /* graph */
+ cbit_print, -1, -1, /* print */
+ cbit_punct, -1, -1, /* punct */
+ cbit_space, -1, -1, /* space */
+ cbit_word, -1, -1, /* word - a Perl extension */
+ cbit_xdigit,-1, -1 /* xdigit */
+};
+
+/* Table to identify digits and hex digits. This is used when compiling
+patterns. Note that the tables in chartables are dependent on the locale, and
+may mark arbitrary characters as digits - but the PCRE compiling code expects
+to handle only 0-9, a-z, and A-Z as digits when compiling. That is why we have
+a private table here. It costs 256 bytes, but it is a lot faster than doing
+character value tests (at least in some simple cases I timed), and in some
+applications one wants PCRE to compile efficiently as well as match
+efficiently.
+
+For convenience, we use the same bit definitions as in chartables:
+
+ 0x04 decimal digit
+ 0x08 hexadecimal digit
+
+Then we can use ctype_digit and ctype_xdigit in the code. */
+
+#if !EBCDIC /* This is the "normal" case, for ASCII systems */
+static const unsigned char digitab[] =
+ {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8- 15 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - ' */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ( - / */
+ 0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, /* 0 - 7 */
+ 0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00, /* 8 - ? */
+ 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* @ - G */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* H - O */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* P - W */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* X - _ */
+ 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* ` - g */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* h - o */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p - w */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* x -127 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */
+
+#else /* This is the "abnormal" case, for EBCDIC systems */
+static const unsigned char digitab[] =
+ {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 0 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8- 15 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 10 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 32- 39 20 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 40- 47 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 48- 55 30 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 56- 63 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - 71 40 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 72- | */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* & - 87 50 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 88- ¬ */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - -103 60 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 104- ? */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 112-119 70 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 120- " */
+ 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* 128- g 80 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* h -143 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144- p 90 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* q -159 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160- x A0 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* y -175 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ^ -183 B0 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */
+ 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* { - G C0 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* H -207 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* } - P D0 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Q -223 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* \ - X E0 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Y -239 */
+ 0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, /* 0 - 7 F0 */
+ 0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00};/* 8 -255 */
+
+static const unsigned char ebcdic_chartab[] = { /* chartable partial dup */
+ 0x80,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /* 0- 7 */
+ 0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x00, /* 8- 15 */
+ 0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /* 16- 23 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */
+ 0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /* 32- 39 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 40- 47 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 48- 55 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 56- 63 */
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - 71 */
+ 0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80, /* 72- | */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* & - 87 */
+ 0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00, /* 88- ¬ */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - -103 */
+ 0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x80, /* 104- ? */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 112-119 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 120- " */
+ 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* 128- g */
+ 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* h -143 */
+ 0x00,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* 144- p */
+ 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* q -159 */
+ 0x00,0x00,0x12,0x12,0x12,0x12,0x12,0x12, /* 160- x */
+ 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* y -175 */
+ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ^ -183 */
+ 0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00, /* 184-191 */
+ 0x80,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* { - G */
+ 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* H -207 */
+ 0x00,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* } - P */
+ 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* Q -223 */
+ 0x00,0x00,0x12,0x12,0x12,0x12,0x12,0x12, /* \ - X */
+ 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* Y -239 */
+ 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /* 0 - 7 */
+ 0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x00};/* 8 -255 */
+#endif
+
+
+/* Definition to allow mutual recursion */
+
+static BOOL
+ compile_regex(int, int, int *, uschar **, const uschar **, const char **,
+ BOOL, int, int *, int *, branch_chain *, compile_data *);
+
+/* Structure for building a chain of data that actually lives on the
+stack, for holding the values of the subject pointer at the start of each
+subpattern, so as to detect when an empty string has been matched by a
+subpattern - to break infinite loops. When NO_RECURSE is set, these blocks
+are on the heap, not on the stack. */
+
+typedef struct eptrblock {
+ struct eptrblock *epb_prev;
+ const uschar *epb_saved_eptr;
+} eptrblock;
+
+/* Flag bits for the match() function */
+
+#define match_condassert 0x01 /* Called to check a condition assertion */
+#define match_isgroup 0x02 /* Set if start of bracketed group */
+
+/* Non-error returns from the match() function. Error returns are externally
+defined PCRE_ERROR_xxx codes, which are all negative. */
+
+#define MATCH_MATCH 1
+#define MATCH_NOMATCH 0
+
+
+
+/*************************************************
+* Global variables *
+*************************************************/
+
+/* PCRE is thread-clean and doesn't use any global variables in the normal
+sense. However, it calls memory allocation and free functions via the four
+indirections below, and it can optionally do callouts. These values can be
+changed by the caller, but are shared between all threads. However, when
+compiling for Virtual Pascal, things are done differently (see pcre.in). */
+
+#ifndef VPCOMPAT
+#ifdef __cplusplus
+extern "C" void *(*pcre_malloc)(size_t) = malloc;
+extern "C" void (*pcre_free)(void *) = free;
+extern "C" void *(*pcre_stack_malloc)(size_t) = malloc;
+extern "C" void (*pcre_stack_free)(void *) = free;
+extern "C" int (*pcre_callout)(pcre_callout_block *) = NULL;
+#else
+void *(*pcre_malloc)(size_t) = malloc;
+void (*pcre_free)(void *) = free;
+void *(*pcre_stack_malloc)(size_t) = malloc;
+void (*pcre_stack_free)(void *) = free;
+int (*pcre_callout)(pcre_callout_block *) = NULL;
+#endif
+#endif
+
+
+/*************************************************
+* Macros and tables for character handling *
+*************************************************/
+
+/* When UTF-8 encoding is being used, a character is no longer just a single
+byte. The macros for character handling generate simple sequences when used in
+byte-mode, and more complicated ones for UTF-8 characters. */
+
+#ifndef SUPPORT_UTF8
+#define GETCHAR(c, eptr) c = *eptr;
+#define GETCHARINC(c, eptr) c = *eptr++;
+#define GETCHARINCTEST(c, eptr) c = *eptr++;
+#define GETCHARLEN(c, eptr, len) c = *eptr;
+#define BACKCHAR(eptr)
+
+#else /* SUPPORT_UTF8 */
+
+/* Get the next UTF-8 character, not advancing the pointer. This is called when
+we know we are in UTF-8 mode. */
+
+#define GETCHAR(c, eptr) \
+ c = *eptr; \
+ if ((c & 0xc0) == 0xc0) \
+ { \
+ int gcii; \
+ int gcaa = utf8_table4[c & 0x3f]; /* Number of additional bytes */ \
+ int gcss = 6*gcaa; \
+ c = (c & utf8_table3[gcaa]) << gcss; \
+ for (gcii = 1; gcii <= gcaa; gcii++) \
+ { \
+ gcss -= 6; \
+ c |= (eptr[gcii] & 0x3f) << gcss; \
+ } \
+ }
+
+/* Get the next UTF-8 character, advancing the pointer. This is called when we
+know we are in UTF-8 mode. */
+
+#define GETCHARINC(c, eptr) \
+ c = *eptr++; \
+ if ((c & 0xc0) == 0xc0) \
+ { \
+ int gcaa = utf8_table4[c & 0x3f]; /* Number of additional bytes */ \
+ int gcss = 6*gcaa; \
+ c = (c & utf8_table3[gcaa]) << gcss; \
+ while (gcaa-- > 0) \
+ { \
+ gcss -= 6; \
+ c |= (*eptr++ & 0x3f) << gcss; \
+ } \
+ }
+
+/* Get the next character, testing for UTF-8 mode, and advancing the pointer */
+
+#define GETCHARINCTEST(c, eptr) \
+ c = *eptr++; \
+ if (md->utf8 && (c & 0xc0) == 0xc0) \
+ { \
+ int gcaa = utf8_table4[c & 0x3f]; /* Number of additional bytes */ \
+ int gcss = 6*gcaa; \
+ c = (c & utf8_table3[gcaa]) << gcss; \
+ while (gcaa-- > 0) \
+ { \
+ gcss -= 6; \
+ c |= (*eptr++ & 0x3f) << gcss; \
+ } \
+ }
+
+/* Get the next UTF-8 character, not advancing the pointer, incrementing length
+if there are extra bytes. This is called when we know we are in UTF-8 mode. */
+
+#define GETCHARLEN(c, eptr, len) \
+ c = *eptr; \
+ if ((c & 0xc0) == 0xc0) \
+ { \
+ int gcii; \
+ int gcaa = utf8_table4[c & 0x3f]; /* Number of additional bytes */ \
+ int gcss = 6*gcaa; \
+ c = (c & utf8_table3[gcaa]) << gcss; \
+ for (gcii = 1; gcii <= gcaa; gcii++) \
+ { \
+ gcss -= 6; \
+ c |= (eptr[gcii] & 0x3f) << gcss; \
+ } \
+ len += gcaa; \
+ }
+
+/* If the pointer is not at the start of a character, move it back until
+it is. Called only in UTF-8 mode. */
+
+#define BACKCHAR(eptr) while((*eptr & 0xc0) == 0x80) eptr--;
+
+#endif
+
+
+
+/*************************************************
+* Default character tables *
+*************************************************/
+
+/* A default set of character tables is included in the PCRE binary. Its source
+is built by the maketables auxiliary program, which uses the default C ctypes
+functions, and put in the file chartables.c. These tables are used by PCRE
+whenever the caller of pcre_compile() does not provide an alternate set of
+tables. */
+
+#include "pcre_chartables.c"
+
+
+
+#ifdef SUPPORT_UTF8
+/*************************************************
+* Tables for UTF-8 support *
+*************************************************/
+
+/* These are the breakpoints for different numbers of bytes in a UTF-8
+character. */
+
+static const int utf8_table1[] =
+ { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff};
+
+/* These are the indicator bits and the mask for the data bits to set in the
+first byte of a character, indexed by the number of additional bytes. */
+
+static const int utf8_table2[] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc};
+static const int utf8_table3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};
+
+/* Table of the number of extra characters, indexed by the first character
+masked with 0x3f. The highest number for a valid UTF-8 character is in fact
+0x3d. */
+
+static const uschar utf8_table4[] = {
+ 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,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 };
+
+
+/*************************************************
+* Convert character value to UTF-8 *
+*************************************************/
+
+/* This function takes an integer value in the range 0 - 0x7fffffff
+and encodes it as a UTF-8 character in 0 to 6 bytes.
+
+Arguments:
+ cvalue the character value
+ buffer pointer to buffer for result - at least 6 bytes long
+
+Returns: number of characters placed in the buffer
+*/
+
+static int
+ord2utf8(int cvalue, uschar *buffer)
+{
+register int i, j;
+for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++)
+ if (cvalue <= utf8_table1[i]) break;
+buffer += i;
+for (j = i; j > 0; j--)
+ {
+ *buffer-- = 0x80 | (cvalue & 0x3f);
+ cvalue >>= 6;
+ }
+*buffer = utf8_table2[i] | cvalue;
+return i + 1;
+}
+#endif
+
+
+
+/*************************************************
+* Print compiled regex *
+*************************************************/
+
+/* The code for doing this is held in a separate file that is also included in
+pcretest.c. It defines a function called print_internals(). */
+
+#ifdef DEBUG
+#include "printint.c"
+#endif
+
+
+
+/*************************************************
+* Return version string *
+*************************************************/
+
+#define STRING(a) # a
+#define XSTRING(s) STRING(s)
+
+EXPORT const char *
+pcre_version(void)
+{
+return XSTRING(PCRE_MAJOR) "." XSTRING(PCRE_MINOR) " " XSTRING(PCRE_DATE);
+}
+
+
+
+
+/*************************************************
+* (Obsolete) Return info about compiled pattern *
+*************************************************/
+
+/* This is the original "info" function. It picks potentially useful data out
+of the private structure, but its interface was too rigid. It remains for
+backwards compatibility. The public options are passed back in an int - though
+the re->options field has been expanded to a long int, all the public options
+at the low end of it, and so even on 16-bit systems this will still be OK.
+Therefore, I haven't changed the API for pcre_info().
+
+Arguments:
+ external_re points to compiled code
+ optptr where to pass back the options
+ first_byte where to pass back the first character,
+ or -1 if multiline and all branches start ^,
+ or -2 otherwise
+
+Returns: number of capturing subpatterns
+ or negative values on error
+*/
+
+EXPORT int
+pcre_info(const pcre *external_re, int *optptr, int *first_byte)
+{
+const real_pcre *re = (const real_pcre *)external_re;
+if (re == NULL) return PCRE_ERROR_NULL;
+if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC;
+if (optptr != NULL) *optptr = (int)(re->options & PUBLIC_OPTIONS);
+if (first_byte != NULL)
+ *first_byte = ((re->options & PCRE_FIRSTSET) != 0)? re->first_byte :
+ ((re->options & PCRE_STARTLINE) != 0)? -1 : -2;
+return re->top_bracket;
+}
+
+
+
+/*************************************************
+* Return info about compiled pattern *
+*************************************************/
+
+/* This is a newer "info" function which has an extensible interface so
+that additional items can be added compatibly.
+
+Arguments:
+ external_re points to compiled code
+ extra_data points extra data, or NULL
+ what what information is required
+ where where to put the information
+
+Returns: 0 if data returned, negative on error
+*/
+
+EXPORT int
+pcre_fullinfo(const pcre *external_re, const pcre_extra *extra_data, int what,
+ void *where)
+{
+const real_pcre *re = (const real_pcre *)external_re;
+const pcre_study_data *study = NULL;
+
+if (re == NULL || where == NULL) return PCRE_ERROR_NULL;
+if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC;
+
+if (extra_data != NULL && (extra_data->flags & PCRE_EXTRA_STUDY_DATA) != 0)
+ study = (const pcre_study_data *)extra_data->study_data;
+
+switch (what)
+ {
+ case PCRE_INFO_OPTIONS:
+ *((unsigned long int *)where) = re->options & PUBLIC_OPTIONS;
+ break;
+
+ case PCRE_INFO_SIZE:
+ *((size_t *)where) = re->size;
+ break;
+
+ case PCRE_INFO_STUDYSIZE:
+ *((size_t *)where) = (study == NULL)? 0 : study->size;
+ break;
+
+ case PCRE_INFO_CAPTURECOUNT:
+ *((int *)where) = re->top_bracket;
+ break;
+
+ case PCRE_INFO_BACKREFMAX:
+ *((int *)where) = re->top_backref;
+ break;
+
+ case PCRE_INFO_FIRSTBYTE:
+ *((int *)where) =
+ ((re->options & PCRE_FIRSTSET) != 0)? re->first_byte :
+ ((re->options & PCRE_STARTLINE) != 0)? -1 : -2;
+ break;
+
+ case PCRE_INFO_FIRSTTABLE:
+ *((const uschar **)where) =
+ (study != NULL && (study->options & PCRE_STUDY_MAPPED) != 0)?
+ study->start_bits : NULL;
+ break;
+
+ case PCRE_INFO_LASTLITERAL:
+ *((int *)where) =
+ ((re->options & PCRE_REQCHSET) != 0)? re->req_byte : -1;
+ break;
+
+ case PCRE_INFO_NAMEENTRYSIZE:
+ *((int *)where) = re->name_entry_size;
+ break;
+
+ case PCRE_INFO_NAMECOUNT:
+ *((int *)where) = re->name_count;
+ break;
+
+ case PCRE_INFO_NAMETABLE:
+ *((const uschar **)where) = (const uschar *)re + sizeof(real_pcre);
+ break;
+
+ default: return PCRE_ERROR_BADOPTION;
+ }
+
+return 0;
+}
+
+
+
+/*************************************************
+* Return info about what features are configured *
+*************************************************/
+
+/* This is function which has an extensible interface so that additional items
+can be added compatibly.
+
+Arguments:
+ what what information is required
+ where where to put the information
+
+Returns: 0 if data returned, negative on error
+*/
+
+EXPORT int
+pcre_config(int what, void *where)
+{
+switch (what)
+ {
+ case PCRE_CONFIG_UTF8:
+#ifdef SUPPORT_UTF8
+ *((int *)where) = 1;
+#else
+ *((int *)where) = 0;
+#endif
+ break;
+
+ case PCRE_CONFIG_NEWLINE:
+ *((int *)where) = NEWLINE;
+ break;
+
+ case PCRE_CONFIG_LINK_SIZE:
+ *((int *)where) = LINK_SIZE;
+ break;
+
+ case PCRE_CONFIG_POSIX_MALLOC_THRESHOLD:
+ *((int *)where) = POSIX_MALLOC_THRESHOLD;
+ break;
+
+ case PCRE_CONFIG_MATCH_LIMIT:
+ *((unsigned int *)where) = MATCH_LIMIT;
+ break;
+
+ case PCRE_CONFIG_STACKRECURSE:
+#ifdef NO_RECURSE
+ *((int *)where) = 0;
+#else
+ *((int *)where) = 1;
+#endif
+ break;
+
+ default: return PCRE_ERROR_BADOPTION;
+ }
+
+return 0;
+}
+
+
+
+#ifdef DEBUG
+/*************************************************
+* Debugging function to print chars *
+*************************************************/
+
+/* Print a sequence of chars in printable format, stopping at the end of the
+subject if the requested.
+
+Arguments:
+ p points to characters
+ length number to print
+ is_subject TRUE if printing from within md->start_subject
+ md pointer to matching data block, if is_subject is TRUE
+
+Returns: nothing
+*/
+
+static void
+pchars(const uschar *p, int length, BOOL is_subject, match_data *md)
+{
+int c;
+if (is_subject && length > md->end_subject - p) length = md->end_subject - p;
+while (length-- > 0)
+ if (isprint(c = *(p++))) printf("%c", c); else printf("\\x%02x", c);
+}
+#endif
+
+
+
+
+/*************************************************
+* Handle escapes *
+*************************************************/
+
+/* This function is called when a \ has been encountered. It either returns a
+positive value for a simple escape such as \n, or a negative value which
+encodes one of the more complicated things such as \d. When UTF-8 is enabled,
+a positive value greater than 255 may be returned. On entry, ptr is pointing at
+the \. On exit, it is on the final character of the escape sequence.
+
+Arguments:
+ ptrptr points to the pattern position pointer
+ errorptr points to the pointer to the error message
+ bracount number of previous extracting brackets
+ options the options bits
+ isclass TRUE if inside a character class
+
+Returns: zero or positive => a data character
+ negative => a special escape sequence
+ on error, errorptr is set
+*/
+
+static int
+check_escape(const uschar **ptrptr, const char **errorptr, int bracount,
+ int options, BOOL isclass)
+{
+const uschar *ptr = *ptrptr;
+int c, i;
+
+/* If backslash is at the end of the pattern, it's an error. */
+
+c = *(++ptr);
+if (c == 0) *errorptr = ERR1;
+
+/* Non-alphamerics are literals. For digits or letters, do an initial lookup in
+a table. A non-zero result is something that can be returned immediately.
+Otherwise further processing may be required. */
+
+#if !EBCDIC /* ASCII coding */
+else if (c < '0' || c > 'z') {} /* Not alphameric */
+else if ((i = escapes[c - '0']) != 0) c = i;
+
+#else /* EBCDIC coding */
+else if (c < 'a' || (ebcdic_chartab[c] & 0x0E) == 0) {} /* Not alphameric */
+else if ((i = escapes[c - 0x48]) != 0) c = i;
+#endif
+
+/* Escapes that need further processing, or are illegal. */
+
+else
+ {
+ const uschar *oldptr;
+ switch (c)
+ {
+ /* A number of Perl escapes are not handled by PCRE. We give an explicit
+ error. */
+
+ case 'l':
+ case 'L':
+ case 'N':
+ case 'p':
+ case 'P':
+ case 'u':
+ case 'U':
+ case 'X':
+ *errorptr = ERR37;
+ break;
+
+ /* The handling of escape sequences consisting of a string of digits
+ starting with one that is not zero is not straightforward. By experiment,
+ the way Perl works seems to be as follows:
+
+ Outside a character class, the digits are read as a decimal number. If the
+ number is less than 10, or if there are that many previous extracting
+ left brackets, then it is a back reference. Otherwise, up to three octal
+ digits are read to form an escaped byte. Thus \123 is likely to be octal
+ 123 (cf \0123, which is octal 012 followed by the literal 3). If the octal
+ value is greater than 377, the least significant 8 bits are taken. Inside a
+ character class, \ followed by a digit is always an octal number. */
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+
+ if (!isclass)
+ {
+ oldptr = ptr;
+ c -= '0';
+ while ((digitab[ptr[1]] & ctype_digit) != 0)
+ c = c * 10 + *(++ptr) - '0';
+ if (c < 10 || c <= bracount)
+ {
+ c = -(ESC_REF + c);
+ break;
+ }
+ ptr = oldptr; /* Put the pointer back and fall through */
+ }
+
+ /* Handle an octal number following \. If the first digit is 8 or 9, Perl
+ generates a binary zero byte and treats the digit as a following literal.
+ Thus we have to pull back the pointer by one. */
+
+ if ((c = *ptr) >= '8')
+ {
+ ptr--;
+ c = 0;
+ break;
+ }
+
+ /* \0 always starts an octal number, but we may drop through to here with a
+ larger first octal digit. */
+
+ case '0':
+ c -= '0';
+ while(i++ < 2 && ptr[1] >= '0' && ptr[1] <= '7')
+ c = c * 8 + *(++ptr) - '0';
+ c &= 255; /* Take least significant 8 bits */
+ break;
+
+ /* \x is complicated when UTF-8 is enabled. \x{ddd} is a character number
+ which can be greater than 0xff, but only if the ddd are hex digits. */
+
+ case 'x':
+#ifdef SUPPORT_UTF8
+ if (ptr[1] == '{' && (options & PCRE_UTF8) != 0)
+ {
+ const uschar *pt = ptr + 2;
+ register int count = 0;
+ c = 0;
+ while ((digitab[*pt] & ctype_xdigit) != 0)
+ {
+ int cc = *pt++;
+ count++;
+#if !EBCDIC /* ASCII coding */
+ if (cc >= 'a') cc -= 32; /* Convert to upper case */
+ c = c * 16 + cc - ((cc < 'A')? '0' : ('A' - 10));
+#else /* EBCDIC coding */
+ if (cc >= 'a' && cc <= 'z') cc += 64; /* Convert to upper case */
+ c = c * 16 + cc - ((cc >= '0')? '0' : ('A' - 10));
+#endif
+ }
+ if (*pt == '}')
+ {
+ if (c < 0 || count > 8) *errorptr = ERR34;
+ ptr = pt;
+ break;
+ }
+ /* If the sequence of hex digits does not end with '}', then we don't
+ recognize this construct; fall through to the normal \x handling. */
+ }
+#endif
+
+ /* Read just a single hex char */
+
+ c = 0;
+ while (i++ < 2 && (digitab[ptr[1]] & ctype_xdigit) != 0)
+ {
+ int cc; /* Some compilers don't like ++ */
+ cc = *(++ptr); /* in initializers */
+#if !EBCDIC /* ASCII coding */
+ if (cc >= 'a') cc -= 32; /* Convert to upper case */
+ c = c * 16 + cc - ((cc < 'A')? '0' : ('A' - 10));
+#else /* EBCDIC coding */
+ if (cc <= 'z') cc += 64; /* Convert to upper case */
+ c = c * 16 + cc - ((cc >= '0')? '0' : ('A' - 10));
+#endif
+ }
+ break;
+
+ /* Other special escapes not starting with a digit are straightforward */
+
+ case 'c':
+ c = *(++ptr);
+ if (c == 0)
+ {
+ *errorptr = ERR2;
+ return 0;
+ }
+
+ /* A letter is upper-cased; then the 0x40 bit is flipped. This coding
+ is ASCII-specific, but then the whole concept of \cx is ASCII-specific.
+ (However, an EBCDIC equivalent has now been added.) */
+
+#if !EBCDIC /* ASCII coding */
+ if (c >= 'a' && c <= 'z') c -= 32;
+ c ^= 0x40;
+#else /* EBCDIC coding */
+ if (c >= 'a' && c <= 'z') c += 64;
+ c ^= 0xC0;
+#endif
+ break;
+
+ /* PCRE_EXTRA enables extensions to Perl in the matter of escapes. Any
+ other alphameric following \ is an error if PCRE_EXTRA was set; otherwise,
+ for Perl compatibility, it is a literal. This code looks a bit odd, but
+ there used to be some cases other than the default, and there may be again
+ in future, so I haven't "optimized" it. */
+
+ default:
+ if ((options & PCRE_EXTRA) != 0) switch(c)
+ {
+ default:
+ *errorptr = ERR3;
+ break;
+ }
+ break;
+ }
+ }
+
+*ptrptr = ptr;
+return c;
+}
+
+
+
+/*************************************************
+* Check for counted repeat *
+*************************************************/
+
+/* This function is called when a '{' is encountered in a place where it might
+start a quantifier. It looks ahead to see if it really is a quantifier or not.
+It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd}
+where the ddds are digits.
+
+Arguments:
+ p pointer to the first char after '{'
+
+Returns: TRUE or FALSE
+*/
+
+static BOOL
+is_counted_repeat(const uschar *p)
+{
+if ((digitab[*p++] & ctype_digit) == 0) return FALSE;
+while ((digitab[*p] & ctype_digit) != 0) p++;
+if (*p == '}') return TRUE;
+
+if (*p++ != ',') return FALSE;
+if (*p == '}') return TRUE;
+
+if ((digitab[*p++] & ctype_digit) == 0) return FALSE;
+while ((digitab[*p] & ctype_digit) != 0) p++;
+
+return (*p == '}');
+}
+
+
+
+/*************************************************
+* Read repeat counts *
+*************************************************/
+
+/* Read an item of the form {n,m} and return the values. This is called only
+after is_counted_repeat() has confirmed that a repeat-count quantifier exists,
+so the syntax is guaranteed to be correct, but we need to check the values.
+
+Arguments:
+ p pointer to first char after '{'
+ minp pointer to int for min
+ maxp pointer to int for max
+ returned as -1 if no max
+ errorptr points to pointer to error message
+
+Returns: pointer to '}' on success;
+ current ptr on error, with errorptr set
+*/
+
+static const uschar *
+read_repeat_counts(const uschar *p, int *minp, int *maxp, const char **errorptr)
+{
+int min = 0;
+int max = -1;
+
+while ((digitab[*p] & ctype_digit) != 0) min = min * 10 + *p++ - '0';
+
+if (*p == '}') max = min; else
+ {
+ if (*(++p) != '}')
+ {
+ max = 0;
+ while((digitab[*p] & ctype_digit) != 0) max = max * 10 + *p++ - '0';
+ if (max < min)
+ {
+ *errorptr = ERR4;
+ return p;
+ }
+ }
+ }
+
+/* Do paranoid checks, then fill in the required variables, and pass back the
+pointer to the terminating '}'. */
+
+if (min > 65535 || max > 65535)
+ *errorptr = ERR5;
+else
+ {
+ *minp = min;
+ *maxp = max;
+ }
+return p;
+}
+
+
+
+/*************************************************
+* Find first significant op code *
+*************************************************/
+
+/* This is called by several functions that scan a compiled expression looking
+for a fixed first character, or an anchoring op code etc. It skips over things
+that do not influence this. For some calls, a change of option is important.
+
+Arguments:
+ code pointer to the start of the group
+ options pointer to external options
+ optbit the option bit whose changing is significant, or
+ zero if none are
+
+Returns: pointer to the first significant opcode
+*/
+
+static const uschar*
+first_significant_code(const uschar *code, int *options, int optbit)
+{
+for (;;)
+ {
+ switch ((int)*code)
+ {
+ case OP_OPT:
+ if (optbit > 0 && ((int)code[1] & optbit) != (*options & optbit))
+ *options = (int)code[1];
+ code += 2;
+ break;
+
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ do code += GET(code, 1); while (*code == OP_ALT);
+ /* Fall through */
+
+ case OP_CALLOUT:
+ case OP_CREF:
+ case OP_BRANUMBER:
+ case OP_WORD_BOUNDARY:
+ case OP_NOT_WORD_BOUNDARY:
+ code += OP_lengths[*code];
+ break;
+
+ default:
+ return code;
+ }
+ }
+/* Control never reaches here */
+}
+
+
+
+
+/*************************************************
+* Find the fixed length of a pattern *
+*************************************************/
+
+/* Scan a pattern and compute the fixed length of subject that will match it,
+if the length is fixed. This is needed for dealing with backward assertions.
+In UTF8 mode, the result is in characters rather than bytes.
+
+Arguments:
+ code points to the start of the pattern (the bracket)
+ options the compiling options
+
+Returns: the fixed length, or -1 if there is no fixed length,
+ or -2 if \C was encountered
+*/
+
+static int
+find_fixedlength(uschar *code, int options)
+{
+int length = -1;
+
+register int branchlength = 0;
+register uschar *cc = code + 1 + LINK_SIZE;
+
+/* Scan along the opcodes for this branch. If we get to the end of the
+branch, check the length against that of the other branches. */
+
+for (;;)
+ {
+ int d;
+ register int op = *cc;
+ if (op >= OP_BRA) op = OP_BRA;
+
+ switch (op)
+ {
+ case OP_BRA:
+ case OP_ONCE:
+ case OP_COND:
+ d = find_fixedlength(cc, options);
+ if (d < 0) return d;
+ branchlength += d;
+ do cc += GET(cc, 1); while (*cc == OP_ALT);
+ cc += 1 + LINK_SIZE;
+ break;
+
+ /* Reached end of a branch; if it's a ket it is the end of a nested
+ call. If it's ALT it is an alternation in a nested call. If it is
+ END it's the end of the outer call. All can be handled by the same code. */
+
+ case OP_ALT:
+ case OP_KET:
+ case OP_KETRMAX:
+ case OP_KETRMIN:
+ case OP_END:
+ if (length < 0) length = branchlength;
+ else if (length != branchlength) return -1;
+ if (*cc != OP_ALT) return length;
+ cc += 1 + LINK_SIZE;
+ branchlength = 0;
+ break;
+
+ /* Skip over assertive subpatterns */
+
+ case OP_ASSERT:
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ do cc += GET(cc, 1); while (*cc == OP_ALT);
+ /* Fall through */
+
+ /* Skip over things that don't match chars */
+
+ case OP_REVERSE:
+ case OP_BRANUMBER:
+ case OP_CREF:
+ case OP_OPT:
+ case OP_CALLOUT:
+ case OP_SOD:
+ case OP_SOM:
+ case OP_EOD:
+ case OP_EODN:
+ case OP_CIRC:
+ case OP_DOLL:
+ case OP_NOT_WORD_BOUNDARY:
+ case OP_WORD_BOUNDARY:
+ cc += OP_lengths[*cc];
+ break;
+
+ /* Handle char strings. In UTF-8 mode we must count characters, not bytes.
+ This requires a scan of the string, unfortunately. We assume valid UTF-8
+ strings, so all we do is reduce the length by one for every byte whose bits
+ are 10xxxxxx. */
+
+ case OP_CHARS:
+ branchlength += *(++cc);
+#ifdef SUPPORT_UTF8
+ if ((options & PCRE_UTF8) != 0)
+ for (d = 1; d <= *cc; d++)
+ if ((cc[d] & 0xc0) == 0x80) branchlength--;
+#endif
+ cc += *cc + 1;
+ break;
+
+ /* Handle exact repetitions. The count is already in characters, but we
+ need to skip over a multibyte character in UTF8 mode. */
+
+ case OP_EXACT:
+ branchlength += GET2(cc,1);
+ cc += 4;
+#ifdef SUPPORT_UTF8
+ if ((options & PCRE_UTF8) != 0)
+ {
+ while((*cc & 0x80) == 0x80) cc++;
+ }
+#endif
+ break;
+
+ case OP_TYPEEXACT:
+ branchlength += GET2(cc,1);
+ cc += 4;
+ break;
+
+ /* Handle single-char matchers */
+
+ case OP_NOT_DIGIT:
+ case OP_DIGIT:
+ case OP_NOT_WHITESPACE:
+ case OP_WHITESPACE:
+ case OP_NOT_WORDCHAR:
+ case OP_WORDCHAR:
+ case OP_ANY:
+ branchlength++;
+ cc++;
+ break;
+
+ /* The single-byte matcher isn't allowed */
+
+ case OP_ANYBYTE:
+ return -2;
+
+ /* Check a class for variable quantification */
+
+#ifdef SUPPORT_UTF8
+ case OP_XCLASS:
+ cc += GET(cc, 1) - 33;
+ /* Fall through */
+#endif
+
+ case OP_CLASS:
+ case OP_NCLASS:
+ cc += 33;
+
+ switch (*cc)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ return -1;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ if (GET2(cc,1) != GET2(cc,3)) return -1;
+ branchlength += GET2(cc,1);
+ cc += 5;
+ break;
+
+ default:
+ branchlength++;
+ }
+ break;
+
+ /* Anything else is variable length */
+
+ default:
+ return -1;
+ }
+ }
+/* Control never gets here */
+}
+
+
+
+
+/*************************************************
+* Scan compiled regex for numbered bracket *
+*************************************************/
+
+/* This little function scans through a compiled pattern until it finds a
+capturing bracket with the given number.
+
+Arguments:
+ code points to start of expression
+ utf8 TRUE in UTF-8 mode
+ number the required bracket number
+
+Returns: pointer to the opcode for the bracket, or NULL if not found
+*/
+
+static const uschar *
+find_bracket(const uschar *code, BOOL utf8, int number)
+{
+#ifndef SUPPORT_UTF8
+utf8 = utf8; /* Stop pedantic compilers complaining */
+#endif
+
+for (;;)
+ {
+ register int c = *code;
+ if (c == OP_END) return NULL;
+ else if (c == OP_CHARS) code += code[1] + OP_lengths[c];
+ else if (c > OP_BRA)
+ {
+ int n = c - OP_BRA;
+ if (n > EXTRACT_BASIC_MAX) n = GET2(code, 2+LINK_SIZE);
+ if (n == number) return (uschar *)code;
+ code += OP_lengths[OP_BRA];
+ }
+ else
+ {
+ code += OP_lengths[c];
+
+#ifdef SUPPORT_UTF8
+
+ /* In UTF-8 mode, opcodes that are followed by a character may be followed
+ by a multi-byte character. The length in the table is a minimum, so we have
+ to scan along to skip the extra characters. All opcodes are less than 128,
+ so we can use relatively efficient code. */
+
+ if (utf8) switch(c)
+ {
+ case OP_EXACT:
+ case OP_UPTO:
+ case OP_MINUPTO:
+ case OP_STAR:
+ case OP_MINSTAR:
+ case OP_PLUS:
+ case OP_MINPLUS:
+ case OP_QUERY:
+ case OP_MINQUERY:
+ while ((*code & 0xc0) == 0x80) code++;
+ break;
+
+ /* XCLASS is used for classes that cannot be represented just by a bit
+ map. This includes negated single high-valued characters. The length in
+ the table is zero; the actual length is stored in the compled code. */
+
+ case OP_XCLASS:
+ code += GET(code, 1) + 1;
+ break;
+ }
+#endif
+ }
+ }
+}
+
+
+
+/*************************************************
+* Scan compiled regex for recursion reference *
+*************************************************/
+
+/* This little function scans through a compiled pattern until it finds an
+instance of OP_RECURSE.
+
+Arguments:
+ code points to start of expression
+ utf8 TRUE in UTF-8 mode
+
+Returns: pointer to the opcode for OP_RECURSE, or NULL if not found
+*/
+
+static const uschar *
+find_recurse(const uschar *code, BOOL utf8)
+{
+#ifndef SUPPORT_UTF8
+utf8 = utf8; /* Stop pedantic compilers complaining */
+#endif
+
+for (;;)
+ {
+ register int c = *code;
+ if (c == OP_END) return NULL;
+ else if (c == OP_RECURSE) return code;
+ else if (c == OP_CHARS) code += code[1] + OP_lengths[c];
+ else if (c > OP_BRA)
+ {
+ code += OP_lengths[OP_BRA];
+ }
+ else
+ {
+ code += OP_lengths[c];
+
+#ifdef SUPPORT_UTF8
+
+ /* In UTF-8 mode, opcodes that are followed by a character may be followed
+ by a multi-byte character. The length in the table is a minimum, so we have
+ to scan along to skip the extra characters. All opcodes are less than 128,
+ so we can use relatively efficient code. */
+
+ if (utf8) switch(c)
+ {
+ case OP_EXACT:
+ case OP_UPTO:
+ case OP_MINUPTO:
+ case OP_STAR:
+ case OP_MINSTAR:
+ case OP_PLUS:
+ case OP_MINPLUS:
+ case OP_QUERY:
+ case OP_MINQUERY:
+ while ((*code & 0xc0) == 0x80) code++;
+ break;
+
+ /* XCLASS is used for classes that cannot be represented just by a bit
+ map. This includes negated single high-valued characters. The length in
+ the table is zero; the actual length is stored in the compled code. */
+
+ case OP_XCLASS:
+ code += GET(code, 1) + 1;
+ break;
+ }
+#endif
+ }
+ }
+}
+
+
+
+/*************************************************
+* Scan compiled branch for non-emptiness *
+*************************************************/
+
+/* This function scans through a branch of a compiled pattern to see whether it
+can match the empty string or not. It is called only from could_be_empty()
+below. Note that first_significant_code() skips over assertions. If we hit an
+unclosed bracket, we return "empty" - this means we've struck an inner bracket
+whose current branch will already have been scanned.
+
+Arguments:
+ code points to start of search
+ endcode points to where to stop
+ utf8 TRUE if in UTF8 mode
+
+Returns: TRUE if what is matched could be empty
+*/
+
+static BOOL
+could_be_empty_branch(const uschar *code, const uschar *endcode, BOOL utf8)
+{
+register int c;
+for (code = first_significant_code(code + 1 + LINK_SIZE, NULL, 0);
+ code < endcode;
+ code = first_significant_code(code + OP_lengths[c], NULL, 0))
+ {
+ const uschar *ccode;
+
+ c = *code;
+
+ if (c >= OP_BRA)
+ {
+ BOOL empty_branch;
+ if (GET(code, 1) == 0) return TRUE; /* Hit unclosed bracket */
+
+ /* Scan a closed bracket */
+
+ empty_branch = FALSE;
+ do
+ {
+ if (!empty_branch && could_be_empty_branch(code, endcode, utf8))
+ empty_branch = TRUE;
+ code += GET(code, 1);
+ }
+ while (*code == OP_ALT);
+ if (!empty_branch) return FALSE; /* All branches are non-empty */
+ code += 1 + LINK_SIZE;
+ c = *code;
+ }
+
+ else switch (c)
+ {
+ /* Check for quantifiers after a class */
+
+#ifdef SUPPORT_UTF8
+ case OP_XCLASS:
+ ccode = code + GET(code, 1);
+ goto CHECK_CLASS_REPEAT;
+#endif
+
+ case OP_CLASS:
+ case OP_NCLASS:
+ ccode = code + 33;
+
+#ifdef SUPPORT_UTF8
+ CHECK_CLASS_REPEAT:
+#endif
+
+ switch (*ccode)
+ {
+ case OP_CRSTAR: /* These could be empty; continue */
+ case OP_CRMINSTAR:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ break;
+
+ default: /* Non-repeat => class must match */
+ case OP_CRPLUS: /* These repeats aren't empty */
+ case OP_CRMINPLUS:
+ return FALSE;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ if (GET2(ccode, 1) > 0) return FALSE; /* Minimum > 0 */
+ break;
+ }
+ break;
+
+ /* Opcodes that must match a character */
+
+ case OP_NOT_DIGIT:
+ case OP_DIGIT:
+ case OP_NOT_WHITESPACE:
+ case OP_WHITESPACE:
+ case OP_NOT_WORDCHAR:
+ case OP_WORDCHAR:
+ case OP_ANY:
+ case OP_ANYBYTE:
+ case OP_CHARS:
+ case OP_NOT:
+ case OP_PLUS:
+ case OP_MINPLUS:
+ case OP_EXACT:
+ case OP_NOTPLUS:
+ case OP_NOTMINPLUS:
+ case OP_NOTEXACT:
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEEXACT:
+ return FALSE;
+
+ /* End of branch */
+
+ case OP_KET:
+ case OP_KETRMAX:
+ case OP_KETRMIN:
+ case OP_ALT:
+ return TRUE;
+
+ /* In UTF-8 mode, STAR, MINSTAR, QUERY, MINQUERY, UPTO, and MINUPTO may be
+ followed by a multibyte character */
+
+#ifdef SUPPORT_UTF8
+ case OP_STAR:
+ case OP_MINSTAR:
+ case OP_QUERY:
+ case OP_MINQUERY:
+ case OP_UPTO:
+ case OP_MINUPTO:
+ if (utf8) while ((code[2] & 0xc0) == 0x80) code++;
+ break;
+#endif
+ }
+ }
+
+return TRUE;
+}
+
+
+
+/*************************************************
+* Scan compiled regex for non-emptiness *
+*************************************************/
+
+/* This function is called to check for left recursive calls. We want to check
+the current branch of the current pattern to see if it could match the empty
+string. If it could, we must look outwards for branches at other levels,
+stopping when we pass beyond the bracket which is the subject of the recursion.
+
+Arguments:
+ code points to start of the recursion
+ endcode points to where to stop (current RECURSE item)
+ bcptr points to the chain of current (unclosed) branch starts
+ utf8 TRUE if in UTF-8 mode
+
+Returns: TRUE if what is matched could be empty
+*/
+
+static BOOL
+could_be_empty(const uschar *code, const uschar *endcode, branch_chain *bcptr,
+ BOOL utf8)
+{
+while (bcptr != NULL && bcptr->current >= code)
+ {
+ if (!could_be_empty_branch(bcptr->current, endcode, utf8)) return FALSE;
+ bcptr = bcptr->outer;
+ }
+return TRUE;
+}
+
+
+
+/*************************************************
+* Check for POSIX class syntax *
+*************************************************/
+
+/* This function is called when the sequence "[:" or "[." or "[=" is
+encountered in a character class. It checks whether this is followed by an
+optional ^ and then a sequence of letters, terminated by a matching ":]" or
+".]" or "=]".
+
+Argument:
+ ptr pointer to the initial [
+ endptr where to return the end pointer
+ cd pointer to compile data
+
+Returns: TRUE or FALSE
+*/
+
+static BOOL
+check_posix_syntax(const uschar *ptr, const uschar **endptr, compile_data *cd)
+{
+int terminator; /* Don't combine these lines; the Solaris cc */
+terminator = *(++ptr); /* compiler warns about "non-constant" initializer. */
+if (*(++ptr) == '^') ptr++;
+while ((cd->ctypes[*ptr] & ctype_letter) != 0) ptr++;
+if (*ptr == terminator && ptr[1] == ']')
+ {
+ *endptr = ptr;
+ return TRUE;
+ }
+return FALSE;
+}
+
+
+
+
+/*************************************************
+* Check POSIX class name *
+*************************************************/
+
+/* This function is called to check the name given in a POSIX-style class entry
+such as [:alnum:].
+
+Arguments:
+ ptr points to the first letter
+ len the length of the name
+
+Returns: a value representing the name, or -1 if unknown
+*/
+
+static int
+check_posix_name(const uschar *ptr, int len)
+{
+register int yield = 0;
+while (posix_name_lengths[yield] != 0)
+ {
+ if (len == posix_name_lengths[yield] &&
+ strncmp((const char *)ptr, posix_names[yield], len) == 0) return yield;
+ yield++;
+ }
+return -1;
+}
+
+
+/*************************************************
+* Adjust OP_RECURSE items in repeated group *
+*************************************************/
+
+/* OP_RECURSE items contain an offset from the start of the regex to the group
+that is referenced. This means that groups can be replicated for fixed
+repetition simply by copying (because the recursion is allowed to refer to
+earlier groups that are outside the current group). However, when a group is
+optional (i.e. the minimum quantifier is zero), OP_BRAZERO is inserted before
+it, after it has been compiled. This means that any OP_RECURSE items within it
+that refer to the group itself or any contained groups have to have their
+offsets adjusted. That is the job of this function. Before it is called, the
+partially compiled regex must be temporarily terminated with OP_END.
+
+Arguments:
+ group points to the start of the group
+ adjust the amount by which the group is to be moved
+ utf8 TRUE in UTF-8 mode
+ cd contains pointers to tables etc.
+
+Returns: nothing
+*/
+
+static void
+adjust_recurse(uschar *group, int adjust, BOOL utf8, compile_data *cd)
+{
+uschar *ptr = group;
+while ((ptr = (uschar *)find_recurse(ptr, utf8)) != NULL)
+ {
+ int offset = GET(ptr, 1);
+ if (cd->start_code + offset >= group) PUT(ptr, 1, offset + adjust);
+ ptr += 1 + LINK_SIZE;
+ }
+}
+
+
+
+/*************************************************
+* Compile one branch *
+*************************************************/
+
+/* Scan the pattern, compiling it into the code vector. If the options are
+changed during the branch, the pointer is used to change the external options
+bits.
+
+Arguments:
+ optionsptr pointer to the option bits
+ brackets points to number of extracting brackets used
+ code points to the pointer to the current code point
+ ptrptr points to the current pattern pointer
+ errorptr points to pointer to error message
+ firstbyteptr set to initial literal character, or < 0 (REQ_UNSET, REQ_NONE)
+ reqbyteptr set to the last literal character required, else < 0
+ bcptr points to current branch chain
+ cd contains pointers to tables etc.
+
+Returns: TRUE on success
+ FALSE, with *errorptr set on error
+*/
+
+static BOOL
+compile_branch(int *optionsptr, int *brackets, uschar **codeptr,
+ const uschar **ptrptr, const char **errorptr, int *firstbyteptr,
+ int *reqbyteptr, branch_chain *bcptr, compile_data *cd)
+{
+int repeat_type, op_type;
+int repeat_min = 0, repeat_max = 0; /* To please picky compilers */
+int bravalue = 0;
+int length;
+int greedy_default, greedy_non_default;
+int firstbyte, reqbyte;
+int zeroreqbyte, zerofirstbyte;
+int req_caseopt, reqvary, tempreqvary;
+int condcount = 0;
+int options = *optionsptr;
+register int c;
+register uschar *code = *codeptr;
+uschar *tempcode;
+BOOL inescq = FALSE;
+BOOL groupsetfirstbyte = FALSE;
+const uschar *ptr = *ptrptr;
+const uschar *tempptr;
+uschar *previous = NULL;
+uschar class[32];
+
+#ifdef SUPPORT_UTF8
+BOOL class_utf8;
+BOOL utf8 = (options & PCRE_UTF8) != 0;
+uschar *class_utf8data;
+uschar utf8_char[6];
+#else
+BOOL utf8 = FALSE;
+#endif
+
+/* Set up the default and non-default settings for greediness */
+
+greedy_default = ((options & PCRE_UNGREEDY) != 0);
+greedy_non_default = greedy_default ^ 1;
+
+/* Initialize no first char, no required char. REQ_UNSET means "no char
+matching encountered yet". It gets changed to REQ_NONE if we hit something that
+matches a non-fixed char first char; reqbyte just remains unset if we never
+find one.
+
+When we hit a repeat whose minimum is zero, we may have to adjust these values
+to take the zero repeat into account. This is implemented by setting them to
+zerofirstbyte and zeroreqbyte when such a repeat is encountered. The individual
+item types that can be repeated set these backoff variables appropriately. */
+
+firstbyte = reqbyte = zerofirstbyte = zeroreqbyte = REQ_UNSET;
+
+/* The variable req_caseopt contains either the REQ_CASELESS value or zero,
+according to the current setting of the caseless flag. REQ_CASELESS is a bit
+value > 255. It is added into the firstbyte or reqbyte variables to record the
+case status of the value. */
+
+req_caseopt = ((options & PCRE_CASELESS) != 0)? REQ_CASELESS : 0;
+
+/* Switch on next character until the end of the branch */
+
+for (;; ptr++)
+ {
+ BOOL negate_class;
+ BOOL possessive_quantifier;
+ int class_charcount;
+ int class_lastchar;
+ int newoptions;
+ int recno;
+ int skipbytes;
+ int subreqbyte;
+ int subfirstbyte;
+
+ c = *ptr;
+ if (inescq && c != 0) goto NORMAL_CHAR;
+
+ if ((options & PCRE_EXTENDED) != 0)
+ {
+ if ((cd->ctypes[c] & ctype_space) != 0) continue;
+ if (c == '#')
+ {
+ /* The space before the ; is to avoid a warning on a silly compiler
+ on the Macintosh. */
+ while ((c = *(++ptr)) != 0 && c != NEWLINE) ;
+ if (c != 0) continue; /* Else fall through to handle end of string */
+ }
+ }
+
+ switch(c)
+ {
+ /* The branch terminates at end of string, |, or ). */
+
+ case 0:
+ case '|':
+ case ')':
+ *firstbyteptr = firstbyte;
+ *reqbyteptr = reqbyte;
+ *codeptr = code;
+ *ptrptr = ptr;
+ return TRUE;
+
+ /* Handle single-character metacharacters. In multiline mode, ^ disables
+ the setting of any following char as a first character. */
+
+ case '^':
+ if ((options & PCRE_MULTILINE) != 0)
+ {
+ if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE;
+ }
+ previous = NULL;
+ *code++ = OP_CIRC;
+ break;
+
+ case '$':
+ previous = NULL;
+ *code++ = OP_DOLL;
+ break;
+
+ /* There can never be a first char if '.' is first, whatever happens about
+ repeats. The value of reqbyte doesn't change either. */
+
+ case '.':
+ if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE;
+ zerofirstbyte = firstbyte;
+ zeroreqbyte = reqbyte;
+ previous = code;
+ *code++ = OP_ANY;
+ break;
+
+ /* Character classes. If the included characters are all < 255 in value, we
+ build a 32-byte bitmap of the permitted characters, except in the special
+ case where there is only one such character. For negated classes, we build
+ the map as usual, then invert it at the end. However, we use a different
+ opcode so that data characters > 255 can be handled correctly.
+
+ If the class contains characters outside the 0-255 range, a different
+ opcode is compiled. It may optionally have a bit map for characters < 256,
+ but those above are are explicitly listed afterwards. A flag byte tells
+ whether the bitmap is present, and whether this is a negated class or not.
+ */
+
+ case '[':
+ previous = code;
+
+ /* PCRE supports POSIX class stuff inside a class. Perl gives an error if
+ they are encountered at the top level, so we'll do that too. */
+
+ if ((ptr[1] == ':' || ptr[1] == '.' || ptr[1] == '=') &&
+ check_posix_syntax(ptr, &tempptr, cd))
+ {
+ *errorptr = (ptr[1] == ':')? ERR13 : ERR31;
+ goto FAILED;
+ }
+
+ /* If the first character is '^', set the negation flag and skip it. */
+
+ if ((c = *(++ptr)) == '^')
+ {
+ negate_class = TRUE;
+ c = *(++ptr);
+ }
+ else
+ {
+ negate_class = FALSE;
+ }
+
+ /* Keep a count of chars with values < 256 so that we can optimize the case
+ of just a single character (as long as it's < 256). For higher valued UTF-8
+ characters, we don't yet do any optimization. */
+
+ class_charcount = 0;
+ class_lastchar = -1;
+
+#ifdef SUPPORT_UTF8
+ class_utf8 = FALSE; /* No chars >= 256 */
+ class_utf8data = code + LINK_SIZE + 34; /* For UTF-8 items */
+#endif
+
+ /* Initialize the 32-char bit map to all zeros. We have to build the
+ map in a temporary bit of store, in case the class contains only 1
+ character (< 256), because in that case the compiled code doesn't use the
+ bit map. */
+
+ memset(class, 0, 32 * sizeof(uschar));
+
+ /* Process characters until ] is reached. By writing this as a "do" it
+ means that an initial ] is taken as a data character. The first pass
+ through the regex checked the overall syntax, so we don't need to be very
+ strict here. At the start of the loop, c contains the first byte of the
+ character. */
+
+ do
+ {
+#ifdef SUPPORT_UTF8
+ if (utf8 && c > 127)
+ { /* Braces are required because the */
+ GETCHARLEN(c, ptr, ptr); /* macro generates multiple statements */
+ }
+#endif
+
+ /* Inside \Q...\E everything is literal except \E */
+
+ if (inescq)
+ {
+ if (c == '\\' && ptr[1] == 'E')
+ {
+ inescq = FALSE;
+ ptr++;
+ continue;
+ }
+ else goto LONE_SINGLE_CHARACTER;
+ }
+
+ /* Handle POSIX class names. Perl allows a negation extension of the
+ form [:^name:]. A square bracket that doesn't match the syntax is
+ treated as a literal. We also recognize the POSIX constructions
+ [.ch.] and [=ch=] ("collating elements") and fault them, as Perl
+ 5.6 and 5.8 do. */
+
+ if (c == '[' &&
+ (ptr[1] == ':' || ptr[1] == '.' || ptr[1] == '=') &&
+ check_posix_syntax(ptr, &tempptr, cd))
+ {
+ BOOL local_negate = FALSE;
+ int posix_class, i;
+ register const uschar *cbits = cd->cbits;
+
+ if (ptr[1] != ':')
+ {
+ *errorptr = ERR31;
+ goto FAILED;
+ }
+
+ ptr += 2;
+ if (*ptr == '^')
+ {
+ local_negate = TRUE;
+ ptr++;
+ }
+
+ posix_class = check_posix_name(ptr, tempptr - ptr);
+ if (posix_class < 0)
+ {
+ *errorptr = ERR30;
+ goto FAILED;
+ }
+
+ /* If matching is caseless, upper and lower are converted to
+ alpha. This relies on the fact that the class table starts with
+ alpha, lower, upper as the first 3 entries. */
+
+ if ((options & PCRE_CASELESS) != 0 && posix_class <= 2)
+ posix_class = 0;
+
+ /* Or into the map we are building up to 3 of the static class
+ tables, or their negations. The [:blank:] class sets up the same
+ chars as the [:space:] class (all white space). We remove the vertical
+ white space chars afterwards. */
+
+ posix_class *= 3;
+ for (i = 0; i < 3; i++)
+ {
+ BOOL blankclass = strncmp((char *)ptr, "blank", 5) == 0;
+ int taboffset = posix_class_maps[posix_class + i];
+ if (taboffset < 0) break;
+ if (local_negate)
+ {
+ for (c = 0; c < 32; c++) class[c] |= ~cbits[c+taboffset];
+ if (blankclass) class[1] |= 0x3c;
+ }
+ else
+ {
+ for (c = 0; c < 32; c++) class[c] |= cbits[c+taboffset];
+ if (blankclass) class[1] &= ~0x3c;
+ }
+ }
+
+ ptr = tempptr + 1;
+ class_charcount = 10; /* Set > 1; assumes more than 1 per class */
+ continue; /* End of POSIX syntax handling */
+ }
+
+ /* Backslash may introduce a single character, or it may introduce one
+ of the specials, which just set a flag. Escaped items are checked for
+ validity in the pre-compiling pass. The sequence \b is a special case.
+ Inside a class (and only there) it is treated as backspace. Elsewhere
+ it marks a word boundary. Other escapes have preset maps ready to
+ or into the one we are building. We assume they have more than one
+ character in them, so set class_charcount bigger than one. */
+
+ if (c == '\\')
+ {
+ c = check_escape(&ptr, errorptr, *brackets, options, TRUE);
+ if (-c == ESC_b) c = '\b'; /* \b is backslash in a class */
+
+ if (-c == ESC_Q) /* Handle start of quoted string */
+ {
+ if (ptr[1] == '\\' && ptr[2] == 'E')
+ {
+ ptr += 2; /* avoid empty string */
+ }
+ else inescq = TRUE;
+ continue;
+ }
+
+ else if (c < 0)
+ {
+ register const uschar *cbits = cd->cbits;
+ class_charcount = 10; /* Greater than 1 is what matters */
+ switch (-c)
+ {
+ case ESC_d:
+ for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_digit];
+ continue;
+
+ case ESC_D:
+ for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_digit];
+ continue;
+
+ case ESC_w:
+ for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_word];
+ continue;
+
+ case ESC_W:
+ for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_word];
+ continue;
+
+ case ESC_s:
+ for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_space];
+ class[1] &= ~0x08; /* Perl 5.004 onwards omits VT from \s */
+ continue;
+
+ case ESC_S:
+ for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_space];
+ class[1] |= 0x08; /* Perl 5.004 onwards omits VT from \s */
+ continue;
+
+ /* Unrecognized escapes are faulted if PCRE is running in its
+ strict mode. By default, for compatibility with Perl, they are
+ treated as literals. */
+
+ default:
+ if ((options & PCRE_EXTRA) != 0)
+ {
+ *errorptr = ERR7;
+ goto FAILED;
+ }
+ c = *ptr; /* The final character */
+ }
+ }
+
+ /* Fall through if we have a single character (c >= 0). This may be
+ > 256 in UTF-8 mode. */
+
+ } /* End of backslash handling */
+
+ /* A single character may be followed by '-' to form a range. However,
+ Perl does not permit ']' to be the end of the range. A '-' character
+ here is treated as a literal. */
+
+ if (ptr[1] == '-' && ptr[2] != ']')
+ {
+ int d;
+ ptr += 2;
+
+#ifdef SUPPORT_UTF8
+ if (utf8)
+ { /* Braces are required because the */
+ GETCHARLEN(d, ptr, ptr); /* macro generates multiple statements */
+ }
+ else
+#endif
+ d = *ptr;
+
+ /* The second part of a range can be a single-character escape, but
+ not any of the other escapes. Perl 5.6 treats a hyphen as a literal
+ in such circumstances. */
+
+ if (d == '\\')
+ {
+ const uschar *oldptr = ptr;
+ d = check_escape(&ptr, errorptr, *brackets, options, TRUE);
+
+ /* \b is backslash; any other special means the '-' was literal */
+
+ if (d < 0)
+ {
+ if (d == -ESC_b) d = '\b'; else
+ {
+ ptr = oldptr - 2;
+ goto LONE_SINGLE_CHARACTER; /* A few lines below */
+ }
+ }
+ }
+
+ /* Check that the two values are in the correct order */
+
+ if (d < c)
+ {
+ *errorptr = ERR8;
+ goto FAILED;
+ }
+
+ /* If d is greater than 255, we can't just use the bit map, so set up
+ for the UTF-8 supporting class type. If we are not caseless, we can
+ just set up a single range. If we are caseless, the characters < 256
+ are handled with a bitmap, in order to get the case-insensitive
+ handling. */
+
+#ifdef SUPPORT_UTF8
+ if (d > 255)
+ {
+ class_utf8 = TRUE;
+ *class_utf8data++ = XCL_RANGE;
+ if ((options & PCRE_CASELESS) == 0)
+ {
+ class_utf8data += ord2utf8(c, class_utf8data);
+ class_utf8data += ord2utf8(d, class_utf8data);
+ continue; /* Go get the next char in the class */
+ }
+ class_utf8data += ord2utf8(256, class_utf8data);
+ class_utf8data += ord2utf8(d, class_utf8data);
+ d = 255;
+ /* Fall through */
+ }
+#endif
+ /* We use the bit map if the range is entirely < 255, or if part of it
+ is < 255 and matching is caseless. */
+
+ for (; c <= d; c++)
+ {
+ class[c/8] |= (1 << (c&7));
+ if ((options & PCRE_CASELESS) != 0)
+ {
+ int uc = cd->fcc[c]; /* flip case */
+ class[uc/8] |= (1 << (uc&7));
+ }
+ class_charcount++; /* in case a one-char range */
+ class_lastchar = c;
+ }
+
+ continue; /* Go get the next char in the class */
+ }
+
+ /* Handle a lone single character - we can get here for a normal
+ non-escape char, or after \ that introduces a single character. */
+
+ LONE_SINGLE_CHARACTER:
+
+ /* Handle a multibyte character */
+
+#ifdef SUPPORT_UTF8
+ if (utf8 && c > 255)
+ {
+ class_utf8 = TRUE;
+ *class_utf8data++ = XCL_SINGLE;
+ class_utf8data += ord2utf8(c, class_utf8data);
+ }
+ else
+#endif
+ /* Handle a single-byte character */
+ {
+ class [c/8] |= (1 << (c&7));
+ if ((options & PCRE_CASELESS) != 0)
+ {
+ c = cd->fcc[c]; /* flip case */
+ class[c/8] |= (1 << (c&7));
+ }
+ class_charcount++;
+ class_lastchar = c;
+ }
+ }
+
+ /* Loop until ']' reached; the check for end of string happens inside the
+ loop. This "while" is the end of the "do" above. */
+
+ while ((c = *(++ptr)) != ']' || inescq);
+
+ /* If class_charcount is 1, we saw precisely one character with a value <
+ 256. In UTF-8 mode, we can optimize if there were no characters >= 256 and
+ the one character is < 128. In non-UTF-8 mode we can always optimize.
+
+ The optimization throws away the bit map. We turn the item into a
+ 1-character OP_CHARS if it's positive, or OP_NOT if it's negative. Note
+ that OP_NOT does not support multibyte characters. In the positive case, it
+ can cause firstbyte to be set. Otherwise, there can be no first char if
+ this item is first, whatever repeat count may follow. In the case of
+ reqbyte, save the previous value for reinstating. */
+
+#ifdef SUPPORT_UTF8
+ if (class_charcount == 1 &&
+ (!utf8 ||
+ (!class_utf8 && class_lastchar < 128)))
+#else
+ if (class_charcount == 1)
+#endif
+ {
+ zeroreqbyte = reqbyte;
+ if (negate_class)
+ {
+ if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE;
+ zerofirstbyte = firstbyte;
+ *code++ = OP_NOT;
+ }
+ else
+ {
+ if (firstbyte == REQ_UNSET)
+ {
+ zerofirstbyte = REQ_NONE;
+ firstbyte = class_lastchar | req_caseopt;
+ }
+ else
+ {
+ zerofirstbyte = firstbyte;
+ reqbyte = class_lastchar | req_caseopt | cd->req_varyopt;
+ }
+ *code++ = OP_CHARS;
+ *code++ = 1;
+ }
+ *code++ = class_lastchar;
+ break; /* End of class handling */
+ } /* End of 1-byte optimization */
+
+ /* Otherwise, if this is the first thing in the branch, there can be no
+ first char setting, whatever the repeat count. Any reqbyte setting must
+ remain unchanged after any kind of repeat. */
+
+ if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE;
+ zerofirstbyte = firstbyte;
+ zeroreqbyte = reqbyte;
+
+ /* If there are characters with values > 255, we have to compile an
+ extended class, with its own opcode. If there are no characters < 256,
+ we can omit the bitmap. */
+
+#ifdef SUPPORT_UTF8
+ if (class_utf8)
+ {
+ *class_utf8data++ = XCL_END; /* Marks the end of extra data */
+ *code++ = OP_XCLASS;
+ code += LINK_SIZE;
+ *code = negate_class? XCL_NOT : 0;
+
+ /* If the map is required, install it, and move on to the end of
+ the extra data */
+
+ if (class_charcount > 0)
+ {
+ *code++ |= XCL_MAP;
+ memcpy(code, class, 32);
+ code = class_utf8data;
+ }
+
+ /* If the map is not required, slide down the extra data. */
+
+ else
+ {
+ int len = class_utf8data - (code + 33);
+ memmove(code + 1, code + 33, len);
+ code += len + 1;
+ }
+
+ /* Now fill in the complete length of the item */
+
+ PUT(previous, 1, code - previous);
+ break; /* End of class handling */
+ }
+#endif
+
+ /* If there are no characters > 255, negate the 32-byte map if necessary,
+ and copy it into the code vector. If this is the first thing in the branch,
+ there can be no first char setting, whatever the repeat count. Any reqbyte
+ setting must remain unchanged after any kind of repeat. */
+
+ if (negate_class)
+ {
+ *code++ = OP_NCLASS;
+ for (c = 0; c < 32; c++) code[c] = ~class[c];
+ }
+ else
+ {
+ *code++ = OP_CLASS;
+ memcpy(code, class, 32);
+ }
+ code += 32;
+ break;
+
+ /* Various kinds of repeat */
+
+ case '{':
+ if (!is_counted_repeat(ptr+1)) goto NORMAL_CHAR;
+ ptr = read_repeat_counts(ptr+1, &repeat_min, &repeat_max, errorptr);
+ if (*errorptr != NULL) goto FAILED;
+ goto REPEAT;
+
+ case '*':
+ repeat_min = 0;
+ repeat_max = -1;
+ goto REPEAT;
+
+ case '+':
+ repeat_min = 1;
+ repeat_max = -1;
+ goto REPEAT;
+
+ case '?':
+ repeat_min = 0;
+ repeat_max = 1;
+
+ REPEAT:
+ if (previous == NULL)
+ {
+ *errorptr = ERR9;
+ goto FAILED;
+ }
+
+ if (repeat_min == 0)
+ {
+ firstbyte = zerofirstbyte; /* Adjust for zero repeat */
+ reqbyte = zeroreqbyte; /* Ditto */
+ }
+
+ /* Remember whether this is a variable length repeat */
+
+ reqvary = (repeat_min == repeat_max)? 0 : REQ_VARY;
+
+ op_type = 0; /* Default single-char op codes */
+ possessive_quantifier = FALSE; /* Default not possessive quantifier */
+
+ /* Save start of previous item, in case we have to move it up to make space
+ for an inserted OP_ONCE for the additional '+' extension. */
+
+ tempcode = previous;
+
+ /* If the next character is '+', we have a possessive quantifier. This
+ implies greediness, whatever the setting of the PCRE_UNGREEDY option.
+ If the next character is '?' this is a minimizing repeat, by default,
+ but if PCRE_UNGREEDY is set, it works the other way round. We change the
+ repeat type to the non-default. */
+
+ if (ptr[1] == '+')
+ {
+ repeat_type = 0; /* Force greedy */
+ possessive_quantifier = TRUE;
+ ptr++;
+ }
+ else if (ptr[1] == '?')
+ {
+ repeat_type = greedy_non_default;
+ ptr++;
+ }
+ else repeat_type = greedy_default;
+
+ /* If previous was a recursion, we need to wrap it inside brackets so that
+ it can be replicated if necessary. */
+
+ if (*previous == OP_RECURSE)
+ {
+ memmove(previous + 1 + LINK_SIZE, previous, 1 + LINK_SIZE);
+ code += 1 + LINK_SIZE;
+ *previous = OP_BRA;
+ PUT(previous, 1, code - previous);
+ *code = OP_KET;
+ PUT(code, 1, code - previous);
+ code += 1 + LINK_SIZE;
+ }
+
+ /* If previous was a string of characters, chop off the last one and use it
+ as the subject of the repeat. If there was only one character, we can
+ abolish the previous item altogether. If a one-char item has a minumum of
+ more than one, ensure that it is set in reqbyte - it might not be if a
+ sequence such as x{3} is the first thing in a branch because the x will
+ have gone into firstbyte instead. */
+
+ if (*previous == OP_CHARS)
+ {
+ /* Deal with UTF-8 characters that take up more than one byte. It's
+ easier to write this out separately than try to macrify it. Use c to
+ hold the length of the character in bytes, plus 0x80 to flag that it's a
+ length rather than a small character. */
+
+#ifdef SUPPORT_UTF8
+ if (utf8 && (code[-1] & 0x80) != 0)
+ {
+ uschar *lastchar = code - 1;
+ while((*lastchar & 0xc0) == 0x80) lastchar--;
+ c = code - lastchar; /* Length of UTF-8 character */
+ memcpy(utf8_char, lastchar, c); /* Save the char */
+ if (lastchar == previous + 2) /* There was only one character */
+ {
+ code = previous; /* Abolish the previous item */
+ }
+ else
+ {
+ previous[1] -= c; /* Adjust length of previous */
+ code = lastchar; /* Lost char off the end */
+ tempcode = code; /* Adjust position to be moved for '+' */
+ }
+ c |= 0x80; /* Flag c as a length */
+ }
+ else
+#endif
+
+ /* Handle the case of a single byte - either with no UTF8 support, or
+ with UTF-8 disabled, or for a UTF-8 character < 128. */
+
+ {
+ c = *(--code);
+ if (code == previous + 2) /* There was only one character */
+ {
+ code = previous; /* Abolish the previous item */
+ if (repeat_min > 1) reqbyte = c | req_caseopt | cd->req_varyopt;
+ }
+ else
+ {
+ previous[1]--; /* adjust length */
+ tempcode = code; /* Adjust position to be moved for '+' */
+ }
+ }
+
+ goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */
+ }
+
+ /* If previous was a single negated character ([^a] or similar), we use
+ one of the special opcodes, replacing it. The code is shared with single-
+ character repeats by setting opt_type to add a suitable offset into
+ repeat_type. OP_NOT is currently used only for single-byte chars. */
+
+ else if (*previous == OP_NOT)
+ {
+ op_type = OP_NOTSTAR - OP_STAR; /* Use "not" opcodes */
+ c = previous[1];
+ code = previous;
+ goto OUTPUT_SINGLE_REPEAT;
+ }
+
+ /* If previous was a character type match (\d or similar), abolish it and
+ create a suitable repeat item. The code is shared with single-character
+ repeats by setting op_type to add a suitable offset into repeat_type. */
+
+ else if (*previous < OP_EODN)
+ {
+ op_type = OP_TYPESTAR - OP_STAR; /* Use type opcodes */
+ c = *previous;
+ code = previous;
+
+ OUTPUT_SINGLE_REPEAT:
+
+ /* If the maximum is zero then the minimum must also be zero; Perl allows
+ this case, so we do too - by simply omitting the item altogether. */
+
+ if (repeat_max == 0) goto END_REPEAT;
+
+ /* Combine the op_type with the repeat_type */
+
+ repeat_type += op_type;
+
+ /* A minimum of zero is handled either as the special case * or ?, or as
+ an UPTO, with the maximum given. */
+
+ if (repeat_min == 0)
+ {
+ if (repeat_max == -1) *code++ = OP_STAR + repeat_type;
+ else if (repeat_max == 1) *code++ = OP_QUERY + repeat_type;
+ else
+ {
+ *code++ = OP_UPTO + repeat_type;
+ PUT2INC(code, 0, repeat_max);
+ }
+ }
+
+ /* The case {1,} is handled as the special case + */
+
+ else if (repeat_min == 1 && repeat_max == -1)
+ *code++ = OP_PLUS + repeat_type;
+
+ /* The case {n,n} is just an EXACT, while the general case {n,m} is
+ handled as an EXACT followed by an UPTO. An EXACT of 1 is optimized. */
+
+ else
+ {
+ if (repeat_min != 1)
+ {
+ *code++ = OP_EXACT + op_type; /* NB EXACT doesn't have repeat_type */
+ PUT2INC(code, 0, repeat_min);
+ }
+
+ /* If the mininum is 1 and the previous item was a character string,
+ we either have to put back the item that got cancelled if the string
+ length was 1, or add the character back onto the end of a longer
+ string. For a character type nothing need be done; it will just get
+ put back naturally. Note that the final character is always going to
+ get added below, so we leave code ready for its insertion. */
+
+ else if (*previous == OP_CHARS)
+ {
+ if (code == previous) code += 2; else
+
+ /* In UTF-8 mode, a multibyte char has its length in c, with the 0x80
+ bit set as a flag. The length will always be between 2 and 6. */
+
+#ifdef SUPPORT_UTF8
+ if (utf8 && c >= 128) previous[1] += c & 7; else
+#endif
+ previous[1]++;
+ }
+
+ /* For a single negated character we also have to put back the
+ item that got cancelled. At present this applies only to single byte
+ characters in any mode. */
+
+ else if (*previous == OP_NOT) code++;
+
+ /* If the maximum is unlimited, insert an OP_STAR. Before doing so,
+ we have to insert the character for the previous code. In UTF-8 mode,
+ long characters have their length in c, with the 0x80 bit as a flag. */
+
+ if (repeat_max < 0)
+ {
+#ifdef SUPPORT_UTF8
+ if (utf8 && c >= 128)
+ {
+ memcpy(code, utf8_char, c & 7);
+ code += c & 7;
+ }
+ else
+#endif
+ *code++ = c;
+ *code++ = OP_STAR + repeat_type;
+ }
+
+ /* Else insert an UPTO if the max is greater than the min, again
+ preceded by the character, for the previously inserted code. */
+
+ else if (repeat_max != repeat_min)
+ {
+#ifdef SUPPORT_UTF8
+ if (utf8 && c >= 128)
+ {
+ memcpy(code, utf8_char, c & 7);
+ code += c & 7;
+ }
+ else
+#endif
+ *code++ = c;
+ repeat_max -= repeat_min;
+ *code++ = OP_UPTO + repeat_type;
+ PUT2INC(code, 0, repeat_max);
+ }
+ }
+
+ /* The character or character type itself comes last in all cases. */
+
+#ifdef SUPPORT_UTF8
+ if (utf8 && c >= 128)
+ {
+ memcpy(code, utf8_char, c & 7);
+ code += c & 7;
+ }
+ else
+#endif
+
+ *code++ = c;
+ }
+
+ /* If previous was a character class or a back reference, we put the repeat
+ stuff after it, but just skip the item if the repeat was {0,0}. */
+
+ else if (*previous == OP_CLASS ||
+ *previous == OP_NCLASS ||
+#ifdef SUPPORT_UTF8
+ *previous == OP_XCLASS ||
+#endif
+ *previous == OP_REF)
+ {
+ if (repeat_max == 0)
+ {
+ code = previous;
+ goto END_REPEAT;
+ }
+ if (repeat_min == 0 && repeat_max == -1)
+ *code++ = OP_CRSTAR + repeat_type;
+ else if (repeat_min == 1 && repeat_max == -1)
+ *code++ = OP_CRPLUS + repeat_type;
+ else if (repeat_min == 0 && repeat_max == 1)
+ *code++ = OP_CRQUERY + repeat_type;
+ else
+ {
+ *code++ = OP_CRRANGE + repeat_type;
+ PUT2INC(code, 0, repeat_min);
+ if (repeat_max == -1) repeat_max = 0; /* 2-byte encoding for max */
+ PUT2INC(code, 0, repeat_max);
+ }
+ }
+
+ /* If previous was a bracket group, we may have to replicate it in certain
+ cases. */
+
+ else if (*previous >= OP_BRA || *previous == OP_ONCE ||
+ *previous == OP_COND)
+ {
+ register int i;
+ int ketoffset = 0;
+ int len = code - previous;
+ uschar *bralink = NULL;
+
+ /* If the maximum repeat count is unlimited, find the end of the bracket
+ by scanning through from the start, and compute the offset back to it
+ from the current code pointer. There may be an OP_OPT setting following
+ the final KET, so we can't find the end just by going back from the code
+ pointer. */
+
+ if (repeat_max == -1)
+ {
+ register uschar *ket = previous;
+ do ket += GET(ket, 1); while (*ket != OP_KET);
+ ketoffset = code - ket;
+ }
+
+ /* The case of a zero minimum is special because of the need to stick
+ OP_BRAZERO in front of it, and because the group appears once in the
+ data, whereas in other cases it appears the minimum number of times. For
+ this reason, it is simplest to treat this case separately, as otherwise
+ the code gets far too messy. There are several special subcases when the
+ minimum is zero. */
+
+ if (repeat_min == 0)
+ {
+ /* If the maximum is also zero, we just omit the group from the output
+ altogether. */
+
+ if (repeat_max == 0)
+ {
+ code = previous;
+ goto END_REPEAT;
+ }
+
+ /* If the maximum is 1 or unlimited, we just have to stick in the
+ BRAZERO and do no more at this point. However, we do need to adjust
+ any OP_RECURSE calls inside the group that refer to the group itself or
+ any internal group, because the offset is from the start of the whole
+ regex. Temporarily terminate the pattern while doing this. */
+
+ if (repeat_max <= 1)
+ {
+ *code = OP_END;
+ adjust_recurse(previous, 1, utf8, cd);
+ memmove(previous+1, previous, len);
+ code++;
+ *previous++ = OP_BRAZERO + repeat_type;
+ }
+
+ /* If the maximum is greater than 1 and limited, we have to replicate
+ in a nested fashion, sticking OP_BRAZERO before each set of brackets.
+ The first one has to be handled carefully because it's the original
+ copy, which has to be moved up. The remainder can be handled by code
+ that is common with the non-zero minimum case below. We have to
+ adjust the value or repeat_max, since one less copy is required. Once
+ again, we may have to adjust any OP_RECURSE calls inside the group. */
+
+ else
+ {
+ int offset;
+ *code = OP_END;
+ adjust_recurse(previous, 2 + LINK_SIZE, utf8, cd);
+ memmove(previous + 2 + LINK_SIZE, previous, len);
+ code += 2 + LINK_SIZE;
+ *previous++ = OP_BRAZERO + repeat_type;
+ *previous++ = OP_BRA;
+
+ /* We chain together the bracket offset fields that have to be
+ filled in later when the ends of the brackets are reached. */
+
+ offset = (bralink == NULL)? 0 : previous - bralink;
+ bralink = previous;
+ PUTINC(previous, 0, offset);
+ }
+
+ repeat_max--;
+ }
+
+ /* If the minimum is greater than zero, replicate the group as many
+ times as necessary, and adjust the maximum to the number of subsequent
+ copies that we need. If we set a first char from the group, and didn't
+ set a required char, copy the latter from the former. */
+
+ else
+ {
+ if (repeat_min > 1)
+ {
+ if (groupsetfirstbyte && reqbyte < 0) reqbyte = firstbyte;
+ for (i = 1; i < repeat_min; i++)
+ {
+ memcpy(code, previous, len);
+ code += len;
+ }
+ }
+ if (repeat_max > 0) repeat_max -= repeat_min;
+ }
+
+ /* This code is common to both the zero and non-zero minimum cases. If
+ the maximum is limited, it replicates the group in a nested fashion,
+ remembering the bracket starts on a stack. In the case of a zero minimum,
+ the first one was set up above. In all cases the repeat_max now specifies
+ the number of additional copies needed. */
+
+ if (repeat_max >= 0)
+ {
+ for (i = repeat_max - 1; i >= 0; i--)
+ {
+ *code++ = OP_BRAZERO + repeat_type;
+
+ /* All but the final copy start a new nesting, maintaining the
+ chain of brackets outstanding. */
+
+ if (i != 0)
+ {
+ int offset;
+ *code++ = OP_BRA;
+ offset = (bralink == NULL)? 0 : code - bralink;
+ bralink = code;
+ PUTINC(code, 0, offset);
+ }
+
+ memcpy(code, previous, len);
+ code += len;
+ }
+
+ /* Now chain through the pending brackets, and fill in their length
+ fields (which are holding the chain links pro tem). */
+
+ while (bralink != NULL)
+ {
+ int oldlinkoffset;
+ int offset = code - bralink + 1;
+ uschar *bra = code - offset;
+ oldlinkoffset = GET(bra, 1);
+ bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset;
+ *code++ = OP_KET;
+ PUTINC(code, 0, offset);
+ PUT(bra, 1, offset);
+ }
+ }
+
+ /* If the maximum is unlimited, set a repeater in the final copy. We
+ can't just offset backwards from the current code point, because we
+ don't know if there's been an options resetting after the ket. The
+ correct offset was computed above. */
+
+ else code[-ketoffset] = OP_KETRMAX + repeat_type;
+ }
+
+ /* Else there's some kind of shambles */
+
+ else
+ {
+ *errorptr = ERR11;
+ goto FAILED;
+ }
+
+ /* If the character following a repeat is '+', we wrap the entire repeated
+ item inside OP_ONCE brackets. This is just syntactic sugar, taken from
+ Sun's Java package. The repeated item starts at tempcode, not at previous,
+ which might be the first part of a string whose (former) last char we
+ repeated. However, we don't support '+' after a greediness '?'. */
+
+ if (possessive_quantifier)
+ {
+ int len = code - tempcode;
+ memmove(tempcode + 1+LINK_SIZE, tempcode, len);
+ code += 1 + LINK_SIZE;
+ len += 1 + LINK_SIZE;
+ tempcode[0] = OP_ONCE;
+ *code++ = OP_KET;
+ PUTINC(code, 0, len);
+ PUT(tempcode, 1, len);
+ }
+
+ /* In all case we no longer have a previous item. We also set the
+ "follows varying string" flag for subsequently encountered reqbytes if
+ it isn't already set and we have just passed a varying length item. */
+
+ END_REPEAT:
+ previous = NULL;
+ cd->req_varyopt |= reqvary;
+ break;
+
+
+ /* Start of nested bracket sub-expression, or comment or lookahead or
+ lookbehind or option setting or condition. First deal with special things
+ that can come after a bracket; all are introduced by ?, and the appearance
+ of any of them means that this is not a referencing group. They were
+ checked for validity in the first pass over the string, so we don't have to
+ check for syntax errors here. */
+
+ case '(':
+ newoptions = options;
+ skipbytes = 0;
+
+ if (*(++ptr) == '?')
+ {
+ int set, unset;
+ int *optset;
+
+ switch (*(++ptr))
+ {
+ case '#': /* Comment; skip to ket */
+ ptr++;
+ while (*ptr != ')') ptr++;
+ continue;
+
+ case ':': /* Non-extracting bracket */
+ bravalue = OP_BRA;
+ ptr++;
+ break;
+
+ case '(':
+ bravalue = OP_COND; /* Conditional group */
+
+ /* Condition to test for recursion */
+
+ if (ptr[1] == 'R')
+ {
+ code[1+LINK_SIZE] = OP_CREF;
+ PUT2(code, 2+LINK_SIZE, CREF_RECURSE);
+ skipbytes = 3;
+ ptr += 3;
+ }
+
+ /* Condition to test for a numbered subpattern match. We know that
+ if a digit follows ( then there will just be digits until ) because
+ the syntax was checked in the first pass. */
+
+ else if ((digitab[ptr[1]] && ctype_digit) != 0)
+ {
+ int condref; /* Don't amalgamate; some compilers */
+ condref = *(++ptr) - '0'; /* grumble at autoincrement in declaration */
+ while (*(++ptr) != ')') condref = condref*10 + *ptr - '0';
+ if (condref == 0)
+ {
+ *errorptr = ERR35;
+ goto FAILED;
+ }
+ ptr++;
+ code[1+LINK_SIZE] = OP_CREF;
+ PUT2(code, 2+LINK_SIZE, condref);
+ skipbytes = 3;
+ }
+ /* For conditions that are assertions, we just fall through, having
+ set bravalue above. */
+ break;
+
+ case '=': /* Positive lookahead */
+ bravalue = OP_ASSERT;
+ ptr++;
+ break;
+
+ case '!': /* Negative lookahead */
+ bravalue = OP_ASSERT_NOT;
+ ptr++;
+ break;
+
+ case '<': /* Lookbehinds */
+ switch (*(++ptr))
+ {
+ case '=': /* Positive lookbehind */
+ bravalue = OP_ASSERTBACK;
+ ptr++;
+ break;
+
+ case '!': /* Negative lookbehind */
+ bravalue = OP_ASSERTBACK_NOT;
+ ptr++;
+ break;
+ }
+ break;
+
+ case '>': /* One-time brackets */
+ bravalue = OP_ONCE;
+ ptr++;
+ break;
+
+ case 'C': /* Callout - may be followed by digits */
+ *code++ = OP_CALLOUT;
+ {
+ int n = 0;
+ while ((digitab[*(++ptr)] & ctype_digit) != 0)
+ n = n * 10 + *ptr - '0';
+ if (n > 255)
+ {
+ *errorptr = ERR38;
+ goto FAILED;
+ }
+ *code++ = n;
+ }
+ previous = NULL;
+ continue;
+
+ case 'P': /* Named subpattern handling */
+ if (*(++ptr) == '<') /* Definition */
+ {
+ int i, namelen;
+ uschar *slot = cd->name_table;
+ const uschar *name; /* Don't amalgamate; some compilers */
+ name = ++ptr; /* grumble at autoincrement in declaration */
+
+ while (*ptr++ != '>');
+ namelen = ptr - name - 1;
+
+ for (i = 0; i < cd->names_found; i++)
+ {
+ int crc = memcmp(name, slot+2, namelen);
+ if (crc == 0)
+ {
+ if (slot[2+namelen] == 0)
+ {
+ *errorptr = ERR43;
+ goto FAILED;
+ }
+ crc = -1; /* Current name is substring */
+ }
+ if (crc < 0)
+ {
+ memmove(slot + cd->name_entry_size, slot,
+ (cd->names_found - i) * cd->name_entry_size);
+ break;
+ }
+ slot += cd->name_entry_size;
+ }
+
+ PUT2(slot, 0, *brackets + 1);
+ memcpy(slot + 2, name, namelen);
+ slot[2+namelen] = 0;
+ cd->names_found++;
+ goto NUMBERED_GROUP;
+ }
+
+ if (*ptr == '=' || *ptr == '>') /* Reference or recursion */
+ {
+ int i, namelen;
+ int type = *ptr++;
+ const uschar *name = ptr;
+ uschar *slot = cd->name_table;
+
+ while (*ptr != ')') ptr++;
+ namelen = ptr - name;
+
+ for (i = 0; i < cd->names_found; i++)
+ {
+ if (strncmp((char *)name, (char *)slot+2, namelen) == 0) break;
+ slot += cd->name_entry_size;
+ }
+ if (i >= cd->names_found)
+ {
+ *errorptr = ERR15;
+ goto FAILED;
+ }
+
+ recno = GET2(slot, 0);
+
+ if (type == '>') goto HANDLE_RECURSION; /* A few lines below */
+
+ /* Back reference */
+
+ previous = code;
+ *code++ = OP_REF;
+ PUT2INC(code, 0, recno);
+ cd->backref_map |= (recno < 32)? (1 << recno) : 1;
+ if (recno > cd->top_backref) cd->top_backref = recno;
+ continue;
+ }
+
+ /* Should never happen */
+ break;
+
+ case 'R': /* Pattern recursion */
+ ptr++; /* Same as (?0) */
+ /* Fall through */
+
+ /* Recursion or "subroutine" call */
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ {
+ const uschar *called;
+ recno = 0;
+ while((digitab[*ptr] & ctype_digit) != 0)
+ recno = recno * 10 + *ptr++ - '0';
+
+ /* Come here from code above that handles a named recursion */
+
+ HANDLE_RECURSION:
+
+ previous = code;
+
+ /* Find the bracket that is being referenced. Temporarily end the
+ regex in case it doesn't exist. */
+
+ *code = OP_END;
+ called = (recno == 0)?
+ cd->start_code : find_bracket(cd->start_code, utf8, recno);
+
+ if (called == NULL)
+ {
+ *errorptr = ERR15;
+ goto FAILED;
+ }
+
+ /* If the subpattern is still open, this is a recursive call. We
+ check to see if this is a left recursion that could loop for ever,
+ and diagnose that case. */
+
+ if (GET(called, 1) == 0 && could_be_empty(called, code, bcptr, utf8))
+ {
+ *errorptr = ERR40;
+ goto FAILED;
+ }
+
+ /* Insert the recursion/subroutine item */
+
+ *code = OP_RECURSE;
+ PUT(code, 1, called - cd->start_code);
+ code += 1 + LINK_SIZE;
+ }
+ continue;
+
+ /* Character after (? not specially recognized */
+
+ default: /* Option setting */
+ set = unset = 0;
+ optset = &set;
+
+ while (*ptr != ')' && *ptr != ':')
+ {
+ switch (*ptr++)
+ {
+ case '-': optset = &unset; break;
+
+ case 'i': *optset |= PCRE_CASELESS; break;
+ case 'm': *optset |= PCRE_MULTILINE; break;
+ case 's': *optset |= PCRE_DOTALL; break;
+ case 'x': *optset |= PCRE_EXTENDED; break;
+ case 'U': *optset |= PCRE_UNGREEDY; break;
+ case 'X': *optset |= PCRE_EXTRA; break;
+ }
+ }
+
+ /* Set up the changed option bits, but don't change anything yet. */
+
+ newoptions = (options | set) & (~unset);
+
+ /* If the options ended with ')' this is not the start of a nested
+ group with option changes, so the options change at this level. Compile
+ code to change the ims options if this setting actually changes any of
+ them. We also pass the new setting back so that it can be put at the
+ start of any following branches, and when this group ends (if we are in
+ a group), a resetting item can be compiled.
+
+ Note that if this item is right at the start of the pattern, the
+ options will have been abstracted and made global, so there will be no
+ change to compile. */
+
+ if (*ptr == ')')
+ {
+ if ((options & PCRE_IMS) != (newoptions & PCRE_IMS))
+ {
+ *code++ = OP_OPT;
+ *code++ = newoptions & PCRE_IMS;
+ }
+
+ /* Change options at this level, and pass them back for use
+ in subsequent branches. Reset the greedy defaults and the case
+ value for firstbyte and reqbyte. */
+
+ *optionsptr = options = newoptions;
+ greedy_default = ((newoptions & PCRE_UNGREEDY) != 0);
+ greedy_non_default = greedy_default ^ 1;
+ req_caseopt = ((options & PCRE_CASELESS) != 0)? REQ_CASELESS : 0;
+
+ previous = NULL; /* This item can't be repeated */
+ continue; /* It is complete */
+ }
+
+ /* If the options ended with ':' we are heading into a nested group
+ with possible change of options. Such groups are non-capturing and are
+ not assertions of any kind. All we need to do is skip over the ':';
+ the newoptions value is handled below. */
+
+ bravalue = OP_BRA;
+ ptr++;
+ }
+ }
+
+ /* If PCRE_NO_AUTO_CAPTURE is set, all unadorned brackets become
+ non-capturing and behave like (?:...) brackets */
+
+ else if ((options & PCRE_NO_AUTO_CAPTURE) != 0)
+ {
+ bravalue = OP_BRA;
+ }
+
+ /* Else we have a referencing group; adjust the opcode. If the bracket
+ number is greater than EXTRACT_BASIC_MAX, we set the opcode one higher, and
+ arrange for the true number to follow later, in an OP_BRANUMBER item. */
+
+ else
+ {
+ NUMBERED_GROUP:
+ if (++(*brackets) > EXTRACT_BASIC_MAX)
+ {
+ bravalue = OP_BRA + EXTRACT_BASIC_MAX + 1;
+ code[1+LINK_SIZE] = OP_BRANUMBER;
+ PUT2(code, 2+LINK_SIZE, *brackets);
+ skipbytes = 3;
+ }
+ else bravalue = OP_BRA + *brackets;
+ }
+
+ /* Process nested bracketed re. Assertions may not be repeated, but other
+ kinds can be. We copy code into a non-register variable in order to be able
+ to pass its address because some compilers complain otherwise. Pass in a
+ new setting for the ims options if they have changed. */
+
+ previous = (bravalue >= OP_ONCE)? code : NULL;
+ *code = bravalue;
+ tempcode = code;
+ tempreqvary = cd->req_varyopt; /* Save value before bracket */
+
+ if (!compile_regex(
+ newoptions, /* The complete new option state */
+ options & PCRE_IMS, /* The previous ims option state */
+ brackets, /* Extracting bracket count */
+ &tempcode, /* Where to put code (updated) */
+ &ptr, /* Input pointer (updated) */
+ errorptr, /* Where to put an error message */
+ (bravalue == OP_ASSERTBACK ||
+ bravalue == OP_ASSERTBACK_NOT), /* TRUE if back assert */
+ skipbytes, /* Skip over OP_COND/OP_BRANUMBER */
+ &subfirstbyte, /* For possible first char */
+ &subreqbyte, /* For possible last char */
+ bcptr, /* Current branch chain */
+ cd)) /* Tables block */
+ goto FAILED;
+
+ /* At the end of compiling, code is still pointing to the start of the
+ group, while tempcode has been updated to point past the end of the group
+ and any option resetting that may follow it. The pattern pointer (ptr)
+ is on the bracket. */
+
+ /* If this is a conditional bracket, check that there are no more than
+ two branches in the group. */
+
+ else if (bravalue == OP_COND)
+ {
+ uschar *tc = code;
+ condcount = 0;
+
+ do {
+ condcount++;
+ tc += GET(tc,1);
+ }
+ while (*tc != OP_KET);
+
+ if (condcount > 2)
+ {
+ *errorptr = ERR27;
+ goto FAILED;
+ }
+
+ /* If there is just one branch, we must not make use of its firstbyte or
+ reqbyte, because this is equivalent to an empty second branch. */
+
+ if (condcount == 1) subfirstbyte = subreqbyte = REQ_NONE;
+ }
+
+ /* Handle updating of the required and first characters. Update for normal
+ brackets of all kinds, and conditions with two branches (see code above).
+ If the bracket is followed by a quantifier with zero repeat, we have to
+ back off. Hence the definition of zeroreqbyte and zerofirstbyte outside the
+ main loop so that they can be accessed for the back off. */
+
+ zeroreqbyte = reqbyte;
+ zerofirstbyte = firstbyte;
+ groupsetfirstbyte = FALSE;
+
+ if (bravalue >= OP_BRA || bravalue == OP_ONCE || bravalue == OP_COND)
+ {
+ /* If we have not yet set a firstbyte in this branch, take it from the
+ subpattern, remembering that it was set here so that a repeat of more
+ than one can replicate it as reqbyte if necessary. If the subpattern has
+ no firstbyte, set "none" for the whole branch. In both cases, a zero
+ repeat forces firstbyte to "none". */
+
+ if (firstbyte == REQ_UNSET)
+ {
+ if (subfirstbyte >= 0)
+ {
+ firstbyte = subfirstbyte;
+ groupsetfirstbyte = TRUE;
+ }
+ else firstbyte = REQ_NONE;
+ zerofirstbyte = REQ_NONE;
+ }
+
+ /* If firstbyte was previously set, convert the subpattern's firstbyte
+ into reqbyte if there wasn't one, using the vary flag that was in
+ existence beforehand. */
+
+ else if (subfirstbyte >= 0 && subreqbyte < 0)
+ subreqbyte = subfirstbyte | tempreqvary;
+
+ /* If the subpattern set a required byte (or set a first byte that isn't
+ really the first byte - see above), set it. */
+
+ if (subreqbyte >= 0) reqbyte = subreqbyte;
+ }
+
+ /* For a forward assertion, we take the reqbyte, if set. This can be
+ helpful if the pattern that follows the assertion doesn't set a different
+ char. For example, it's useful for /(?=abcde).+/. We can't set firstbyte
+ for an assertion, however because it leads to incorrect effect for patterns
+ such as /(?=a)a.+/ when the "real" "a" would then become a reqbyte instead
+ of a firstbyte. This is overcome by a scan at the end if there's no
+ firstbyte, looking for an asserted first char. */
+
+ else if (bravalue == OP_ASSERT && subreqbyte >= 0) reqbyte = subreqbyte;
+
+ /* Now update the main code pointer to the end of the group. */
+
+ code = tempcode;
+
+ /* Error if hit end of pattern */
+
+ if (*ptr != ')')
+ {
+ *errorptr = ERR14;
+ goto FAILED;
+ }
+ break;
+
+ /* Check \ for being a real metacharacter; if not, fall through and handle
+ it as a data character at the start of a string. Escape items are checked
+ for validity in the pre-compiling pass. */
+
+ case '\\':
+ tempptr = ptr;
+ c = check_escape(&ptr, errorptr, *brackets, options, FALSE);
+
+ /* Handle metacharacters introduced by \. For ones like \d, the ESC_ values
+ are arranged to be the negation of the corresponding OP_values. For the
+ back references, the values are ESC_REF plus the reference number. Only
+ back references and those types that consume a character may be repeated.
+ We can test for values between ESC_b and ESC_Z for the latter; this may
+ have to change if any new ones are ever created. */
+
+ if (c < 0)
+ {
+ if (-c == ESC_Q) /* Handle start of quoted string */
+ {
+ if (ptr[1] == '\\' && ptr[2] == 'E') ptr += 2; /* avoid empty string */
+ else inescq = TRUE;
+ continue;
+ }
+
+ /* For metasequences that actually match a character, we disable the
+ setting of a first character if it hasn't already been set. */
+
+ if (firstbyte == REQ_UNSET && -c > ESC_b && -c < ESC_Z)
+ firstbyte = REQ_NONE;
+
+ /* Set values to reset to if this is followed by a zero repeat. */
+
+ zerofirstbyte = firstbyte;
+ zeroreqbyte = reqbyte;
+
+ /* Back references are handled specially */
+
+ if (-c >= ESC_REF)
+ {
+ int number = -c - ESC_REF;
+ previous = code;
+ *code++ = OP_REF;
+ PUT2INC(code, 0, number);
+ }
+ else
+ {
+ previous = (-c > ESC_b && -c < ESC_Z)? code : NULL;
+ *code++ = -c;
+ }
+ continue;
+ }
+
+ /* Data character: reset and fall through */
+
+ ptr = tempptr;
+ c = '\\';
+
+ /* Handle a run of data characters until a metacharacter is encountered.
+ The first character is guaranteed not to be whitespace or # when the
+ extended flag is set. */
+
+ NORMAL_CHAR:
+ default:
+ previous = code;
+ *code = OP_CHARS;
+ code += 2;
+ length = 0;
+
+ do
+ {
+ /* If in \Q...\E, check for the end; if not, we always have a literal */
+
+ if (inescq)
+ {
+ if (c == '\\' && ptr[1] == 'E')
+ {
+ inescq = FALSE;
+ ptr++;
+ }
+ else
+ {
+ *code++ = c;
+ length++;
+ }
+ continue;
+ }
+
+ /* Skip white space and comments for /x patterns */
+
+ if ((options & PCRE_EXTENDED) != 0)
+ {
+ if ((cd->ctypes[c] & ctype_space) != 0) continue;
+ if (c == '#')
+ {
+ /* The space before the ; is to avoid a warning on a silly compiler
+ on the Macintosh. */
+ while ((c = *(++ptr)) != 0 && c != NEWLINE) ;
+ if (c == 0) break;
+ continue;
+ }
+ }
+
+ /* Backslash may introduce a data char or a metacharacter. Escaped items
+ are checked for validity in the pre-compiling pass. Stop the string
+ before a metaitem. */
+
+ if (c == '\\')
+ {
+ tempptr = ptr;
+ c = check_escape(&ptr, errorptr, *brackets, options, FALSE);
+ if (c < 0) { ptr = tempptr; break; }
+
+ /* If a character is > 127 in UTF-8 mode, we have to turn it into
+ two or more bytes in the UTF-8 encoding. */
+
+#ifdef SUPPORT_UTF8
+ if (utf8 && c > 127)
+ {
+ uschar buffer[8];
+ int len = ord2utf8(c, buffer);
+ for (c = 0; c < len; c++) *code++ = buffer[c];
+ length += len;
+ continue;
+ }
+#endif
+ }
+
+ /* Ordinary character or single-char escape */
+
+ *code++ = c;
+ length++;
+ }
+
+ /* This "while" is the end of the "do" above. */
+
+ while (length < MAXLIT && (cd->ctypes[c = *(++ptr)] & ctype_meta) == 0);
+
+ /* Update the first and last requirements. These are always bytes, even in
+ UTF-8 mode. However, there is a special case to be considered when there
+ are only one or two characters. Because this gets messy in UTF-8 mode, the
+ code is kept separate. When we get here "length" contains the number of
+ bytes. */
+
+#ifdef SUPPORT_UTF8
+ if (utf8 && length > 1)
+ {
+ uschar *t = previous + 3; /* After this code, t */
+ while (t < code && (*t & 0xc0) == 0x80) t++; /* follows the 1st char */
+
+ /* Handle the case when there is only one multibyte character. It must
+ have at least two bytes because of the "length > 1" test above. */
+
+ if (t == code)
+ {
+ /* If no previous first byte, set it from this character, but revert to
+ none on a zero repeat. */
+
+ if (firstbyte == REQ_UNSET)
+ {
+ zerofirstbyte = REQ_NONE;
+ firstbyte = previous[2];
+ }
+
+ /* Otherwise, leave the first byte value alone, and don't change it on
+ a zero repeat */
+
+ else zerofirstbyte = firstbyte;
+
+ /* In both cases, a zero repeat resets the previous required byte */
+
+ zeroreqbyte = reqbyte;
+ }
+
+ /* Handle the case when there is more than one character. These may be
+ single-byte or multibyte characters */
+
+ else
+ {
+ t = code - 1; /* After this code, t is at the */
+ while ((*t & 0xc0) == 0x80) t--; /* start of the last character */
+
+ /* If no previous first byte, set it from the first character, and
+ retain it on a zero repeat (of the last character). The required byte
+ is reset on a zero repeat, either to the byte before the last
+ character, unless this is the first byte of the string. In that case,
+ it reverts to its previous value. */
+
+ if (firstbyte == REQ_UNSET)
+ {
+ zerofirstbyte = firstbyte = previous[2] | req_caseopt;
+ zeroreqbyte = (t - 1 == previous + 2)?
+ reqbyte : t[-1] | req_caseopt | cd->req_varyopt;
+ }
+
+ /* If there was a previous first byte, leave it alone, and don't change
+ it on a zero repeat. The required byte is reset on a zero repeat to the
+ byte before the last character. */
+
+ else
+ {
+ zerofirstbyte = firstbyte;
+ zeroreqbyte = t[-1] | req_caseopt | cd->req_varyopt;
+ }
+ }
+
+ /* In all cases (we know length > 1), the new required byte is the last
+ byte of the string. */
+
+ reqbyte = code[-1] | req_caseopt | cd->req_varyopt;
+ }
+
+ else /* End of UTF-8 coding */
+#endif
+
+ /* This is the code for non-UTF-8 operation, either without UTF-8 support,
+ or when UTF-8 is not enabled. */
+
+ {
+ /* firstbyte was not previously set; take it from this string */
+
+ if (firstbyte == REQ_UNSET)
+ {
+ if (length == 1)
+ {
+ zerofirstbyte = REQ_NONE;
+ firstbyte = previous[2] | req_caseopt;
+ zeroreqbyte = reqbyte;
+ }
+ else
+ {
+ zerofirstbyte = firstbyte = previous[2] | req_caseopt;
+ zeroreqbyte = (length > 2)?
+ (code[-2] | req_caseopt | cd->req_varyopt) : reqbyte;
+ reqbyte = code[-1] | req_caseopt | cd->req_varyopt;
+ }
+ }
+
+ /* firstbyte was previously set */
+
+ else
+ {
+ zerofirstbyte = firstbyte;
+ zeroreqbyte = (length == 1)? reqbyte :
+ code[-2] | req_caseopt | cd->req_varyopt;
+ reqbyte = code[-1] | req_caseopt | cd->req_varyopt;
+ }
+ }
+
+ /* Set the length in the data vector, and advance to the next state. */
+
+ previous[1] = length;
+ if (length < MAXLIT) ptr--;
+ break;
+ }
+ } /* end of big loop */
+
+/* Control never reaches here by falling through, only by a goto for all the
+error states. Pass back the position in the pattern so that it can be displayed
+to the user for diagnosing the error. */
+
+FAILED:
+*ptrptr = ptr;
+return FALSE;
+}
+
+
+
+
+/*************************************************
+* Compile sequence of alternatives *
+*************************************************/
+
+/* On entry, ptr is pointing past the bracket character, but on return
+it points to the closing bracket, or vertical bar, or end of string.
+The code variable is pointing at the byte into which the BRA operator has been
+stored. If the ims options are changed at the start (for a (?ims: group) or
+during any branch, we need to insert an OP_OPT item at the start of every
+following branch to ensure they get set correctly at run time, and also pass
+the new options into every subsequent branch compile.
+
+Argument:
+ options option bits, including any changes for this subpattern
+ oldims previous settings of ims option bits
+ brackets -> int containing the number of extracting brackets used
+ codeptr -> the address of the current code pointer
+ ptrptr -> the address of the current pattern pointer
+ errorptr -> pointer to error message
+ lookbehind TRUE if this is a lookbehind assertion
+ skipbytes skip this many bytes at start (for OP_COND, OP_BRANUMBER)
+ firstbyteptr place to put the first required character, or a negative number
+ reqbyteptr place to put the last required character, or a negative number
+ bcptr pointer to the chain of currently open branches
+ cd points to the data block with tables pointers etc.
+
+Returns: TRUE on success
+*/
+
+static BOOL
+compile_regex(int options, int oldims, int *brackets, uschar **codeptr,
+ const uschar **ptrptr, const char **errorptr, BOOL lookbehind, int skipbytes,
+ int *firstbyteptr, int *reqbyteptr, branch_chain *bcptr, compile_data *cd)
+{
+const uschar *ptr = *ptrptr;
+uschar *code = *codeptr;
+uschar *last_branch = code;
+uschar *start_bracket = code;
+uschar *reverse_count = NULL;
+int firstbyte, reqbyte;
+int branchfirstbyte, branchreqbyte;
+branch_chain bc;
+
+bc.outer = bcptr;
+bc.current = code;
+
+firstbyte = reqbyte = REQ_UNSET;
+
+/* Offset is set zero to mark that this bracket is still open */
+
+PUT(code, 1, 0);
+code += 1 + LINK_SIZE + skipbytes;
+
+/* Loop for each alternative branch */
+
+for (;;)
+ {
+ /* Handle a change of ims options at the start of the branch */
+
+ if ((options & PCRE_IMS) != oldims)
+ {
+ *code++ = OP_OPT;
+ *code++ = options & PCRE_IMS;
+ }
+
+ /* Set up dummy OP_REVERSE if lookbehind assertion */
+
+ if (lookbehind)
+ {
+ *code++ = OP_REVERSE;
+ reverse_count = code;
+ PUTINC(code, 0, 0);
+ }
+
+ /* Now compile the branch */
+
+ if (!compile_branch(&options, brackets, &code, &ptr, errorptr,
+ &branchfirstbyte, &branchreqbyte, &bc, cd))
+ {
+ *ptrptr = ptr;
+ return FALSE;
+ }
+
+ /* If this is the first branch, the firstbyte and reqbyte values for the
+ branch become the values for the regex. */
+
+ if (*last_branch != OP_ALT)
+ {
+ firstbyte = branchfirstbyte;
+ reqbyte = branchreqbyte;
+ }
+
+ /* If this is not the first branch, the first char and reqbyte have to
+ match the values from all the previous branches, except that if the previous
+ value for reqbyte didn't have REQ_VARY set, it can still match, and we set
+ REQ_VARY for the regex. */
+
+ else
+ {
+ /* If we previously had a firstbyte, but it doesn't match the new branch,
+ we have to abandon the firstbyte for the regex, but if there was previously
+ no reqbyte, it takes on the value of the old firstbyte. */
+
+ if (firstbyte >= 0 && firstbyte != branchfirstbyte)
+ {
+ if (reqbyte < 0) reqbyte = firstbyte;
+ firstbyte = REQ_NONE;
+ }
+
+ /* If we (now or from before) have no firstbyte, a firstbyte from the
+ branch becomes a reqbyte if there isn't a branch reqbyte. */
+
+ if (firstbyte < 0 && branchfirstbyte >= 0 && branchreqbyte < 0)
+ branchreqbyte = branchfirstbyte;
+
+ /* Now ensure that the reqbytes match */
+
+ if ((reqbyte & ~REQ_VARY) != (branchreqbyte & ~REQ_VARY))
+ reqbyte = REQ_NONE;
+ else reqbyte |= branchreqbyte; /* To "or" REQ_VARY */
+ }
+
+ /* If lookbehind, check that this branch matches a fixed-length string,
+ and put the length into the OP_REVERSE item. Temporarily mark the end of
+ the branch with OP_END. */
+
+ if (lookbehind)
+ {
+ int length;
+ *code = OP_END;
+ length = find_fixedlength(last_branch, options);
+ DPRINTF(("fixed length = %d\n", length));
+ if (length < 0)
+ {
+ *errorptr = (length == -2)? ERR36 : ERR25;
+ *ptrptr = ptr;
+ return FALSE;
+ }
+ PUT(reverse_count, 0, length);
+ }
+
+ /* Reached end of expression, either ')' or end of pattern. Go back through
+ the alternative branches and reverse the chain of offsets, with the field in
+ the BRA item now becoming an offset to the first alternative. If there are
+ no alternatives, it points to the end of the group. The length in the
+ terminating ket is always the length of the whole bracketed item. If any of
+ the ims options were changed inside the group, compile a resetting op-code
+ following, except at the very end of the pattern. Return leaving the pointer
+ at the terminating char. */
+
+ if (*ptr != '|')
+ {
+ int length = code - last_branch;
+ do
+ {
+ int prev_length = GET(last_branch, 1);
+ PUT(last_branch, 1, length);
+ length = prev_length;
+ last_branch -= length;
+ }
+ while (length > 0);
+
+ /* Fill in the ket */
+
+ *code = OP_KET;
+ PUT(code, 1, code - start_bracket);
+ code += 1 + LINK_SIZE;
+
+ /* Resetting option if needed */
+
+ if ((options & PCRE_IMS) != oldims && *ptr == ')')
+ {
+ *code++ = OP_OPT;
+ *code++ = oldims;
+ }
+
+ /* Set values to pass back */
+
+ *codeptr = code;
+ *ptrptr = ptr;
+ *firstbyteptr = firstbyte;
+ *reqbyteptr = reqbyte;
+ return TRUE;
+ }
+
+ /* Another branch follows; insert an "or" node. Its length field points back
+ to the previous branch while the bracket remains open. At the end the chain
+ is reversed. It's done like this so that the start of the bracket has a
+ zero offset until it is closed, making it possible to detect recursion. */
+
+ *code = OP_ALT;
+ PUT(code, 1, code - last_branch);
+ bc.current = last_branch = code;
+ code += 1 + LINK_SIZE;
+ ptr++;
+ }
+/* Control never reaches here */
+}
+
+
+
+
+/*************************************************
+* Check for anchored expression *
+*************************************************/
+
+/* Try to find out if this is an anchored regular expression. Consider each
+alternative branch. If they all start with OP_SOD or OP_CIRC, or with a bracket
+all of whose alternatives start with OP_SOD or OP_CIRC (recurse ad lib), then
+it's anchored. However, if this is a multiline pattern, then only OP_SOD
+counts, since OP_CIRC can match in the middle.
+
+We can also consider a regex to be anchored if OP_SOM starts all its branches.
+This is the code for \G, which means "match at start of match position, taking
+into account the match offset".
+
+A branch is also implicitly anchored if it starts with .* and DOTALL is set,
+because that will try the rest of the pattern at all possible matching points,
+so there is no point trying again.... er ....
+
+.... except when the .* appears inside capturing parentheses, and there is a
+subsequent back reference to those parentheses. We haven't enough information
+to catch that case precisely.
+
+At first, the best we could do was to detect when .* was in capturing brackets
+and the highest back reference was greater than or equal to that level.
+However, by keeping a bitmap of the first 31 back references, we can catch some
+of the more common cases more precisely.
+
+Arguments:
+ code points to start of expression (the bracket)
+ options points to the options setting
+ bracket_map a bitmap of which brackets we are inside while testing; this
+ handles up to substring 31; after that we just have to take
+ the less precise approach
+ backref_map the back reference bitmap
+
+Returns: TRUE or FALSE
+*/
+
+static BOOL
+is_anchored(register const uschar *code, int *options, unsigned int bracket_map,
+ unsigned int backref_map)
+{
+do {
+ const uschar *scode =
+ first_significant_code(code + 1+LINK_SIZE, options, PCRE_MULTILINE);
+ register int op = *scode;
+
+ /* Capturing brackets */
+
+ if (op > OP_BRA)
+ {
+ int new_map;
+ op -= OP_BRA;
+ if (op > EXTRACT_BASIC_MAX) op = GET2(scode, 2+LINK_SIZE);
+ new_map = bracket_map | ((op < 32)? (1 << op) : 1);
+ if (!is_anchored(scode, options, new_map, backref_map)) return FALSE;
+ }
+
+ /* Other brackets */
+
+ else if (op == OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND)
+ {
+ if (!is_anchored(scode, options, bracket_map, backref_map)) return FALSE;
+ }
+
+ /* .* is not anchored unless DOTALL is set and it isn't in brackets that
+ are or may be referenced. */
+
+ else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR) &&
+ (*options & PCRE_DOTALL) != 0)
+ {
+ if (scode[1] != OP_ANY || (bracket_map & backref_map) != 0) return FALSE;
+ }
+
+ /* Check for explicit anchoring */
+
+ else if (op != OP_SOD && op != OP_SOM &&
+ ((*options & PCRE_MULTILINE) != 0 || op != OP_CIRC))
+ return FALSE;
+ code += GET(code, 1);
+ }
+while (*code == OP_ALT); /* Loop for each alternative */
+return TRUE;
+}
+
+
+
+/*************************************************
+* Check for starting with ^ or .* *
+*************************************************/
+
+/* This is called to find out if every branch starts with ^ or .* so that
+"first char" processing can be done to speed things up in multiline
+matching and for non-DOTALL patterns that start with .* (which must start at
+the beginning or after \n). As in the case of is_anchored() (see above), we
+have to take account of back references to capturing brackets that contain .*
+because in that case we can't make the assumption.
+
+Arguments:
+ code points to start of expression (the bracket)
+ bracket_map a bitmap of which brackets we are inside while testing; this
+ handles up to substring 31; after that we just have to take
+ the less precise approach
+ backref_map the back reference bitmap
+
+Returns: TRUE or FALSE
+*/
+
+static BOOL
+is_startline(const uschar *code, unsigned int bracket_map,
+ unsigned int backref_map)
+{
+do {
+ const uschar *scode = first_significant_code(code + 1+LINK_SIZE, NULL, 0);
+ register int op = *scode;
+
+ /* Capturing brackets */
+
+ if (op > OP_BRA)
+ {
+ int new_map;
+ op -= OP_BRA;
+ if (op > EXTRACT_BASIC_MAX) op = GET2(scode, 2+LINK_SIZE);
+ new_map = bracket_map | ((op < 32)? (1 << op) : 1);
+ if (!is_startline(scode, new_map, backref_map)) return FALSE;
+ }
+
+ /* Other brackets */
+
+ else if (op == OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND)
+ { if (!is_startline(scode, bracket_map, backref_map)) return FALSE; }
+
+ /* .* is not anchored unless DOTALL is set and it isn't in brackets that
+ may be referenced. */
+
+ else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR)
+ {
+ if (scode[1] != OP_ANY || (bracket_map & backref_map) != 0) return FALSE;
+ }
+
+ /* Check for explicit circumflex */
+
+ else if (op != OP_CIRC) return FALSE;
+ code += GET(code, 1);
+ }
+while (*code == OP_ALT); /* Loop for each alternative */
+return TRUE;
+}
+
+
+
+/*************************************************
+* Check for asserted fixed first char *
+*************************************************/
+
+/* During compilation, the "first char" settings from forward assertions are
+discarded, because they can cause conflicts with actual literals that follow.
+However, if we end up without a first char setting for an unanchored pattern,
+it is worth scanning the regex to see if there is an initial asserted first
+char. If all branches start with the same asserted char, or with a bracket all
+of whose alternatives start with the same asserted char (recurse ad lib), then
+we return that char, otherwise -1.
+
+Arguments:
+ code points to start of expression (the bracket)
+ options pointer to the options (used to check casing changes)
+ inassert TRUE if in an assertion
+
+Returns: -1 or the fixed first char
+*/
+
+static int
+find_firstassertedchar(const uschar *code, int *options, BOOL inassert)
+{
+register int c = -1;
+do {
+ int d;
+ const uschar *scode =
+ first_significant_code(code + 1+LINK_SIZE, options, PCRE_CASELESS);
+ register int op = *scode;
+
+ if (op >= OP_BRA) op = OP_BRA;
+
+ switch(op)
+ {
+ default:
+ return -1;
+
+ case OP_BRA:
+ case OP_ASSERT:
+ case OP_ONCE:
+ case OP_COND:
+ if ((d = find_firstassertedchar(scode, options, op == OP_ASSERT)) < 0)
+ return -1;
+ if (c < 0) c = d; else if (c != d) return -1;
+ break;
+
+ case OP_EXACT: /* Fall through */
+ scode++;
+
+ case OP_CHARS: /* Fall through */
+ scode++;
+
+ case OP_PLUS:
+ case OP_MINPLUS:
+ if (!inassert) return -1;
+ if (c < 0)
+ {
+ c = scode[1];
+ if ((*options & PCRE_CASELESS) != 0) c |= REQ_CASELESS;
+ }
+ else if (c != scode[1]) return -1;
+ break;
+ }
+
+ code += GET(code, 1);
+ }
+while (*code == OP_ALT);
+return c;
+}
+
+
+
+
+#ifdef SUPPORT_UTF8
+/*************************************************
+* Validate a UTF-8 string *
+*************************************************/
+
+/* This function is called (optionally) at the start of compile or match, to
+validate that a supposed UTF-8 string is actually valid. The early check means
+that subsequent code can assume it is dealing with a valid string. The check
+can be turned off for maximum performance, but then consequences of supplying
+an invalid string are then undefined.
+
+Arguments:
+ string points to the string
+ length length of string, or -1 if the string is zero-terminated
+
+Returns: < 0 if the string is a valid UTF-8 string
+ >= 0 otherwise; the value is the offset of the bad byte
+*/
+
+static int
+valid_utf8(const uschar *string, int length)
+{
+register const uschar *p;
+
+if (length < 0)
+ {
+ for (p = string; *p != 0; p++);
+ length = p - string;
+ }
+
+for (p = string; length-- > 0; p++)
+ {
+ register int ab;
+ register int c = *p;
+ if (c < 128) continue;
+ if ((c & 0xc0) != 0xc0) return p - string;
+ ab = utf8_table4[c & 0x3f]; /* Number of additional bytes */
+ if (length < ab) return p - string;
+ length -= ab;
+
+ /* Check top bits in the second byte */
+ if ((*(++p) & 0xc0) != 0x80) return p - string;
+
+ /* Check for overlong sequences for each different length */
+ switch (ab)
+ {
+ /* Check for xx00 000x */
+ case 1:
+ if ((c & 0x3e) == 0) return p - string;
+ continue; /* We know there aren't any more bytes to check */
+
+ /* Check for 1110 0000, xx0x xxxx */
+ case 2:
+ if (c == 0xe0 && (*p & 0x20) == 0) return p - string;
+ break;
+
+ /* Check for 1111 0000, xx00 xxxx */
+ case 3:
+ if (c == 0xf0 && (*p & 0x30) == 0) return p - string;
+ break;
+
+ /* Check for 1111 1000, xx00 0xxx */
+ case 4:
+ if (c == 0xf8 && (*p & 0x38) == 0) return p - string;
+ break;
+
+ /* Check for leading 0xfe or 0xff, and then for 1111 1100, xx00 00xx */
+ case 5:
+ if (c == 0xfe || c == 0xff ||
+ (c == 0xfc && (*p & 0x3c) == 0)) return p - string;
+ break;
+ }
+
+ /* Check for valid bytes after the 2nd, if any; all must start 10 */
+ while (--ab > 0)
+ {
+ if ((*(++p) & 0xc0) != 0x80) return p - string;
+ }
+ }
+
+return -1;
+}
+#endif
+
+
+
+/*************************************************
+* Compile a Regular Expression *
+*************************************************/
+
+/* This function takes a string and returns a pointer to a block of store
+holding a compiled version of the expression.
+
+Arguments:
+ pattern the regular expression
+ options various option bits
+ errorptr pointer to pointer to error text
+ erroroffset ptr offset in pattern where error was detected
+ tables pointer to character tables or NULL
+
+Returns: pointer to compiled data block, or NULL on error,
+ with errorptr and erroroffset set
+*/
+
+EXPORT pcre *
+pcre_compile(const char *pattern, int options, const char **errorptr,
+ int *erroroffset, const unsigned char *tables)
+{
+real_pcre *re;
+int length = 1 + LINK_SIZE; /* For initial BRA plus length */
+int runlength;
+int c, firstbyte, reqbyte;
+int bracount = 0;
+int branch_extra = 0;
+int branch_newextra;
+int item_count = -1;
+int name_count = 0;
+int max_name_size = 0;
+#ifdef SUPPORT_UTF8
+int lastcharlength = 0;
+BOOL utf8;
+BOOL class_utf8;
+#endif
+BOOL inescq = FALSE;
+unsigned int brastackptr = 0;
+size_t size;
+uschar *code;
+const uschar *codestart;
+const uschar *ptr;
+compile_data compile_block;
+int brastack[BRASTACK_SIZE];
+uschar bralenstack[BRASTACK_SIZE];
+
+/* We can't pass back an error message if errorptr is NULL; I guess the best we
+can do is just return NULL. */
+
+if (errorptr == NULL) return NULL;
+*errorptr = NULL;
+
+/* However, we can give a message for this error */
+
+if (erroroffset == NULL)
+ {
+ *errorptr = ERR16;
+ return NULL;
+ }
+*erroroffset = 0;
+
+/* Can't support UTF8 unless PCRE has been compiled to include the code. */
+
+#ifdef SUPPORT_UTF8
+utf8 = (options & PCRE_UTF8) != 0;
+if (utf8 && (options & PCRE_NO_UTF8_CHECK) == 0 &&
+ (*erroroffset = valid_utf8((uschar *)pattern, -1)) >= 0)
+ {
+ *errorptr = ERR44;
+ return NULL;
+ }
+#else
+if ((options & PCRE_UTF8) != 0)
+ {
+ *errorptr = ERR32;
+ return NULL;
+ }
+#endif
+
+if ((options & ~PUBLIC_OPTIONS) != 0)
+ {
+ *errorptr = ERR17;
+ return NULL;
+ }
+
+/* Set up pointers to the individual character tables */
+
+if (tables == NULL) tables = pcre_default_tables;
+compile_block.lcc = tables + lcc_offset;
+compile_block.fcc = tables + fcc_offset;
+compile_block.cbits = tables + cbits_offset;
+compile_block.ctypes = tables + ctypes_offset;
+
+/* Maximum back reference and backref bitmap. This is updated for numeric
+references during the first pass, but for named references during the actual
+compile pass. The bitmap records up to 31 back references to help in deciding
+whether (.*) can be treated as anchored or not. */
+
+compile_block.top_backref = 0;
+compile_block.backref_map = 0;
+
+/* Reflect pattern for debugging output */
+
+DPRINTF(("------------------------------------------------------------------\n"));
+DPRINTF(("%s\n", pattern));
+
+/* The first thing to do is to make a pass over the pattern to compute the
+amount of store required to hold the compiled code. This does not have to be
+perfect as long as errors are overestimates. At the same time we can detect any
+flag settings right at the start, and extract them. Make an attempt to correct
+for any counted white space if an "extended" flag setting appears late in the
+pattern. We can't be so clever for #-comments. */
+
+ptr = (const uschar *)(pattern - 1);
+while ((c = *(++ptr)) != 0)
+ {
+ int min, max;
+ int class_optcount;
+ int bracket_length;
+ int duplength;
+
+ /* If we are inside a \Q...\E sequence, all chars are literal */
+
+ if (inescq) goto NORMAL_CHAR;
+
+ /* Otherwise, first check for ignored whitespace and comments */
+
+ if ((options & PCRE_EXTENDED) != 0)
+ {
+ if ((compile_block.ctypes[c] & ctype_space) != 0) continue;
+ if (c == '#')
+ {
+ /* The space before the ; is to avoid a warning on a silly compiler
+ on the Macintosh. */
+ while ((c = *(++ptr)) != 0 && c != NEWLINE) ;
+ if (c == 0) break;
+ continue;
+ }
+ }
+
+ item_count++; /* Is zero for the first non-comment item */
+
+ switch(c)
+ {
+ /* A backslashed item may be an escaped "normal" character or a
+ character type. For a "normal" character, put the pointers and
+ character back so that tests for whitespace etc. in the input
+ are done correctly. */
+
+ case '\\':
+ {
+ const uschar *save_ptr = ptr;
+ c = check_escape(&ptr, errorptr, bracount, options, FALSE);
+ if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
+ if (c >= 0)
+ {
+ ptr = save_ptr;
+ c = '\\';
+ goto NORMAL_CHAR;
+ }
+ }
+
+ /* If \Q, enter "literal" mode */
+
+ if (-c == ESC_Q)
+ {
+ inescq = TRUE;
+ continue;
+ }
+
+ /* Other escapes need one byte, and are of length one for repeats */
+
+ length++;
+#ifdef SUPPORT_UTF8
+ lastcharlength = 1;
+#endif
+
+ /* A back reference needs an additional 2 bytes, plus either one or 5
+ bytes for a repeat. We also need to keep the value of the highest
+ back reference. */
+
+ if (c <= -ESC_REF)
+ {
+ int refnum = -c - ESC_REF;
+ compile_block.backref_map |= (refnum < 32)? (1 << refnum) : 1;
+ if (refnum > compile_block.top_backref)
+ compile_block.top_backref = refnum;
+ length += 2; /* For single back reference */
+ if (ptr[1] == '{' && is_counted_repeat(ptr+2))
+ {
+ ptr = read_repeat_counts(ptr+2, &min, &max, errorptr);
+ if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
+ if ((min == 0 && (max == 1 || max == -1)) ||
+ (min == 1 && max == -1))
+ length++;
+ else length += 5;
+ if (ptr[1] == '?') ptr++;
+ }
+ }
+ continue;
+
+ case '^': /* Single-byte metacharacters */
+ case '.':
+ case '$':
+ length++;
+#ifdef SUPPORT_UTF8
+ lastcharlength = 1;
+#endif
+ continue;
+
+ case '*': /* These repeats won't be after brackets; */
+ case '+': /* those are handled separately */
+ case '?':
+ length++;
+ goto POSESSIVE; /* A few lines below */
+
+ /* This covers the cases of braced repeats after a single char, metachar,
+ class, or back reference. */
+
+ case '{':
+ if (!is_counted_repeat(ptr+1)) goto NORMAL_CHAR;
+ ptr = read_repeat_counts(ptr+1, &min, &max, errorptr);
+ if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
+
+ /* These special cases just insert one extra opcode */
+
+ if ((min == 0 && (max == 1 || max == -1)) ||
+ (min == 1 && max == -1))
+ length++;
+
+ /* These cases might insert additional copies of a preceding character. */
+
+ else
+ {
+#ifdef SUPPORT_UTF8
+ /* In UTF-8 mode, we should find the length in lastcharlength */
+ if (utf8)
+ {
+ if (min != 1)
+ {
+ length -= lastcharlength; /* Uncount the original char or metachar */
+ if (min > 0) length += 3 + lastcharlength;
+ }
+ length += lastcharlength + ((max > 0)? 3 : 1);
+ }
+ else
+#endif
+
+ /* Not UTF-8 mode: all characters are one byte */
+ {
+ if (min != 1)
+ {
+ length--; /* Uncount the original char or metachar */
+ if (min > 0) length += 4;
+ }
+
+ length += (max > 0)? 4 : 2;
+ }
+ }
+
+ if (ptr[1] == '?') ptr++; /* Needs no extra length */
+
+ POSESSIVE: /* Test for possessive quantifier */
+ if (ptr[1] == '+')
+ {
+ ptr++;
+ length += 2 + 2*LINK_SIZE; /* Allow for atomic brackets */
+ }
+ continue;
+
+ /* An alternation contains an offset to the next branch or ket. If any ims
+ options changed in the previous branch(es), and/or if we are in a
+ lookbehind assertion, extra space will be needed at the start of the
+ branch. This is handled by branch_extra. */
+
+ case '|':
+ length += 1 + LINK_SIZE + branch_extra;
+ continue;
+
+ /* A character class uses 33 characters provided that all the character
+ values are less than 256. Otherwise, it uses a bit map for low valued
+ characters, and individual items for others. Don't worry about character
+ types that aren't allowed in classes - they'll get picked up during the
+ compile. A character class that contains only one single-byte character
+ uses 2 or 3 bytes, depending on whether it is negated or not. Notice this
+ where we can. (In UTF-8 mode we can do this only for chars < 128.) */
+
+ case '[':
+ class_optcount = 0;
+
+#ifdef SUPPORT_UTF8
+ class_utf8 = FALSE;
+#endif
+
+ if (*(++ptr) == '^') ptr++;
+
+ /* Written as a "do" so that an initial ']' is taken as data */
+
+ if (*ptr != 0) do
+ {
+ /* Inside \Q...\E everything is literal except \E */
+
+ if (inescq)
+ {
+ if (*ptr != '\\' || ptr[1] != 'E') goto NON_SPECIAL_CHARACTER;
+ inescq = FALSE;
+ ptr += 1;
+ continue;
+ }
+
+ /* Outside \Q...\E, check for escapes */
+
+ if (*ptr == '\\')
+ {
+#ifdef SUPPORT_UTF8
+ int prevchar = ptr[-1];
+#endif
+ int ch = check_escape(&ptr, errorptr, bracount, options, TRUE);
+ if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
+
+ /* \b is backspace inside a class */
+
+ if (-ch == ESC_b) ch = '\b';
+
+ /* \Q enters quoting mode */
+
+ if (-ch == ESC_Q)
+ {
+ inescq = TRUE;
+ continue;
+ }
+
+ /* Handle escapes that turn into characters */
+
+ if (ch >= 0)
+ {
+#ifdef SUPPORT_UTF8
+ if (utf8)
+ {
+ if (ch > 127) class_optcount = 10; /* Ensure > 1 */
+ if (ch > 255)
+ {
+ uschar buffer[6];
+ if (!class_utf8)
+ {
+ class_utf8 = TRUE;
+ length += LINK_SIZE + 1 + 1;
+ }
+ length += 1 + ord2utf8(ch, buffer);
+
+ /* If this wide character is preceded by '-', add an extra 2 to
+ the length in case the previous character was < 128, because in
+ this case the whole range will be put into the list. */
+
+ if (prevchar == '-') length += 2;
+ }
+ }
+#endif
+ class_optcount++; /* for possible optimization */
+ }
+ else class_optcount = 10; /* \d, \s etc; make sure > 1 */
+ }
+
+ /* Check the syntax for POSIX stuff. The bits we actually handle are
+ checked during the real compile phase. */
+
+ else if (*ptr == '[' && check_posix_syntax(ptr, &ptr, &compile_block))
+ {
+ ptr++;
+ class_optcount = 10; /* Make sure > 1 */
+ }
+
+ /* Anything else just increments the possible optimization count. If
+ there are wide characters, we are going to have to use an XCLASS. */
+
+ else
+ {
+ NON_SPECIAL_CHARACTER:
+ class_optcount++;
+
+#ifdef SUPPORT_UTF8
+ if (utf8)
+ {
+ int ch;
+ int extra = 0;
+ GETCHARLEN(ch, ptr, extra);
+ if (ch > 127) class_optcount = 10; /* No optimization possible */
+ if (ch > 255)
+ {
+ if (!class_utf8)
+ {
+ class_utf8 = TRUE;
+ length += LINK_SIZE + 1 + 1;
+ }
+ length += 2 + extra;
+
+ /* If this wide character is preceded by '-', add an extra 2 to
+ the length in case the previous character was < 128, because in
+ this case the whole range will be put into the list. */
+
+ if (ptr[-1] == '-') length += 2;
+
+ /* Advance to the end of this character */
+
+ ptr += extra;
+ }
+ }
+#endif
+ }
+ }
+ while (*(++ptr) != 0 && (inescq || *ptr != ']')); /* Concludes "do" above */
+
+ if (*ptr == 0) /* Missing terminating ']' */
+ {
+ *errorptr = ERR6;
+ goto PCRE_ERROR_RETURN;
+ }
+
+ /* We can optimize when there was only one optimizable character. Repeats
+ for positive and negated single one-byte chars are handled by the general
+ code. Here, we handle repeats for the class opcodes. */
+
+ if (class_optcount == 1) length += 3; else
+ {
+ length += 33;
+
+ /* A repeat needs either 1 or 5 bytes. If it is a possessive quantifier,
+ we also need extra for wrapping the whole thing in a sub-pattern. */
+
+ if (*ptr != 0 && ptr[1] == '{' && is_counted_repeat(ptr+2))
+ {
+ ptr = read_repeat_counts(ptr+2, &min, &max, errorptr);
+ if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
+ if ((min == 0 && (max == 1 || max == -1)) ||
+ (min == 1 && max == -1))
+ length++;
+ else length += 5;
+ if (ptr[1] == '+')
+ {
+ ptr++;
+ length += 2 + 2*LINK_SIZE;
+ }
+ else if (ptr[1] == '?') ptr++;
+ }
+ }
+ continue;
+
+ /* Brackets may be genuine groups or special things */
+
+ case '(':
+ branch_newextra = 0;
+ bracket_length = 1 + LINK_SIZE;
+
+ /* Handle special forms of bracket, which all start (? */
+
+ if (ptr[1] == '?')
+ {
+ int set, unset;
+ int *optset;
+
+ switch (c = ptr[2])
+ {
+ /* Skip over comments entirely */
+ case '#':
+ ptr += 3;
+ while (*ptr != 0 && *ptr != ')') ptr++;
+ if (*ptr == 0)
+ {
+ *errorptr = ERR18;
+ goto PCRE_ERROR_RETURN;
+ }
+ continue;
+
+ /* Non-referencing groups and lookaheads just move the pointer on, and
+ then behave like a non-special bracket, except that they don't increment
+ the count of extracting brackets. Ditto for the "once only" bracket,
+ which is in Perl from version 5.005. */
+
+ case ':':
+ case '=':
+ case '!':
+ case '>':
+ ptr += 2;
+ break;
+
+ /* (?R) specifies a recursive call to the regex, which is an extension
+ to provide the facility which can be obtained by (?p{perl-code}) in
+ Perl 5.6. In Perl 5.8 this has become (??{perl-code}).
+
+ From PCRE 4.00, items such as (?3) specify subroutine-like "calls" to
+ the appropriate numbered brackets. This includes both recursive and
+ non-recursive calls. (?R) is now synonymous with (?0). */
+
+ case 'R':
+ ptr++;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ ptr += 2;
+ if (c != 'R')
+ while ((digitab[*(++ptr)] & ctype_digit) != 0);
+ if (*ptr != ')')
+ {
+ *errorptr = ERR29;
+ goto PCRE_ERROR_RETURN;
+ }
+ length += 1 + LINK_SIZE;
+
+ /* If this item is quantified, it will get wrapped inside brackets so
+ as to use the code for quantified brackets. We jump down and use the
+ code that handles this for real brackets. */
+
+ if (ptr[1] == '+' || ptr[1] == '*' || ptr[1] == '?' || ptr[1] == '{')
+ {
+ length += 2 + 2 * LINK_SIZE; /* to make bracketed */
+ duplength = 5 + 3 * LINK_SIZE;
+ goto HANDLE_QUANTIFIED_BRACKETS;
+ }
+ continue;
+
+ /* (?C) is an extension which provides "callout" - to provide a bit of
+ the functionality of the Perl (?{...}) feature. An optional number may
+ follow (default is zero). */
+
+ case 'C':
+ ptr += 2;
+ while ((digitab[*(++ptr)] & ctype_digit) != 0);
+ if (*ptr != ')')
+ {
+ *errorptr = ERR39;
+ goto PCRE_ERROR_RETURN;
+ }
+ length += 2;
+ continue;
+
+ /* Named subpatterns are an extension copied from Python */
+
+ case 'P':
+ ptr += 3;
+ if (*ptr == '<')
+ {
+ const uschar *p; /* Don't amalgamate; some compilers */
+ p = ++ptr; /* grumble at autoincrement in declaration */
+ while ((compile_block.ctypes[*ptr] & ctype_word) != 0) ptr++;
+ if (*ptr != '>')
+ {
+ *errorptr = ERR42;
+ goto PCRE_ERROR_RETURN;
+ }
+ name_count++;
+ if (ptr - p > max_name_size) max_name_size = (ptr - p);
+ break;
+ }
+
+ if (*ptr == '=' || *ptr == '>')
+ {
+ while ((compile_block.ctypes[*(++ptr)] & ctype_word) != 0);
+ if (*ptr != ')')
+ {
+ *errorptr = ERR42;
+ goto PCRE_ERROR_RETURN;
+ }
+ break;
+ }
+
+ /* Unknown character after (?P */
+
+ *errorptr = ERR41;
+ goto PCRE_ERROR_RETURN;
+
+ /* Lookbehinds are in Perl from version 5.005 */
+
+ case '<':
+ ptr += 3;
+ if (*ptr == '=' || *ptr == '!')
+ {
+ branch_newextra = 1 + LINK_SIZE;
+ length += 1 + LINK_SIZE; /* For the first branch */
+ break;
+ }
+ *errorptr = ERR24;
+ goto PCRE_ERROR_RETURN;
+
+ /* Conditionals are in Perl from version 5.005. The bracket must either
+ be followed by a number (for bracket reference) or by an assertion
+ group, or (a PCRE extension) by 'R' for a recursion test. */
+
+ case '(':
+ if (ptr[3] == 'R' && ptr[4] == ')')
+ {
+ ptr += 4;
+ length += 3;
+ }
+ else if ((digitab[ptr[3]] & ctype_digit) != 0)
+ {
+ ptr += 4;
+ length += 3;
+ while ((digitab[*ptr] & ctype_digit) != 0) ptr++;
+ if (*ptr != ')')
+ {
+ *errorptr = ERR26;
+ goto PCRE_ERROR_RETURN;
+ }
+ }
+ else /* An assertion must follow */
+ {
+ ptr++; /* Can treat like ':' as far as spacing is concerned */
+ if (ptr[2] != '?' ||
+ (ptr[3] != '=' && ptr[3] != '!' && ptr[3] != '<') )
+ {
+ ptr += 2; /* To get right offset in message */
+ *errorptr = ERR28;
+ goto PCRE_ERROR_RETURN;
+ }
+ }
+ break;
+
+ /* Else loop checking valid options until ) is met. Anything else is an
+ error. If we are without any brackets, i.e. at top level, the settings
+ act as if specified in the options, so massage the options immediately.
+ This is for backward compatibility with Perl 5.004. */
+
+ default:
+ set = unset = 0;
+ optset = &set;
+ ptr += 2;
+
+ for (;; ptr++)
+ {
+ c = *ptr;
+ switch (c)
+ {
+ case 'i':
+ *optset |= PCRE_CASELESS;
+ continue;
+
+ case 'm':
+ *optset |= PCRE_MULTILINE;
+ continue;
+
+ case 's':
+ *optset |= PCRE_DOTALL;
+ continue;
+
+ case 'x':
+ *optset |= PCRE_EXTENDED;
+ continue;
+
+ case 'X':
+ *optset |= PCRE_EXTRA;
+ continue;
+
+ case 'U':
+ *optset |= PCRE_UNGREEDY;
+ continue;
+
+ case '-':
+ optset = &unset;
+ continue;
+
+ /* A termination by ')' indicates an options-setting-only item; if
+ this is at the very start of the pattern (indicated by item_count
+ being zero), we use it to set the global options. This is helpful
+ when analyzing the pattern for first characters, etc. Otherwise
+ nothing is done here and it is handled during the compiling
+ process.
+
+ [Historical note: Up to Perl 5.8, options settings at top level
+ were always global settings, wherever they appeared in the pattern.
+ That is, they were equivalent to an external setting. From 5.8
+ onwards, they apply only to what follows (which is what you might
+ expect).] */
+
+ case ')':
+ if (item_count == 0)
+ {
+ options = (options | set) & (~unset);
+ set = unset = 0; /* To save length */
+ item_count--; /* To allow for several */
+ }
+
+ /* Fall through */
+
+ /* A termination by ':' indicates the start of a nested group with
+ the given options set. This is again handled at compile time, but
+ we must allow for compiled space if any of the ims options are
+ set. We also have to allow for resetting space at the end of
+ the group, which is why 4 is added to the length and not just 2.
+ If there are several changes of options within the same group, this
+ will lead to an over-estimate on the length, but this shouldn't
+ matter very much. We also have to allow for resetting options at
+ the start of any alternations, which we do by setting
+ branch_newextra to 2. Finally, we record whether the case-dependent
+ flag ever changes within the regex. This is used by the "required
+ character" code. */
+
+ case ':':
+ if (((set|unset) & PCRE_IMS) != 0)
+ {
+ length += 4;
+ branch_newextra = 2;
+ if (((set|unset) & PCRE_CASELESS) != 0) options |= PCRE_ICHANGED;
+ }
+ goto END_OPTIONS;
+
+ /* Unrecognized option character */
+
+ default:
+ *errorptr = ERR12;
+ goto PCRE_ERROR_RETURN;
+ }
+ }
+
+ /* If we hit a closing bracket, that's it - this is a freestanding
+ option-setting. We need to ensure that branch_extra is updated if
+ necessary. The only values branch_newextra can have here are 0 or 2.
+ If the value is 2, then branch_extra must either be 2 or 5, depending
+ on whether this is a lookbehind group or not. */
+
+ END_OPTIONS:
+ if (c == ')')
+ {
+ if (branch_newextra == 2 &&
+ (branch_extra == 0 || branch_extra == 1+LINK_SIZE))
+ branch_extra += branch_newextra;
+ continue;
+ }
+
+ /* If options were terminated by ':' control comes here. Fall through
+ to handle the group below. */
+ }
+ }
+
+ /* Extracting brackets must be counted so we can process escapes in a
+ Perlish way. If the number exceeds EXTRACT_BASIC_MAX we are going to
+ need an additional 3 bytes of store per extracting bracket. However, if
+ PCRE_NO_AUTO)CAPTURE is set, unadorned brackets become non-capturing, so we
+ must leave the count alone (it will aways be zero). */
+
+ else if ((options & PCRE_NO_AUTO_CAPTURE) == 0)
+ {
+ bracount++;
+ if (bracount > EXTRACT_BASIC_MAX) bracket_length += 3;
+ }
+
+ /* Save length for computing whole length at end if there's a repeat that
+ requires duplication of the group. Also save the current value of
+ branch_extra, and start the new group with the new value. If non-zero, this
+ will either be 2 for a (?imsx: group, or 3 for a lookbehind assertion. */
+
+ if (brastackptr >= sizeof(brastack)/sizeof(int))
+ {
+ *errorptr = ERR19;
+ goto PCRE_ERROR_RETURN;
+ }
+
+ bralenstack[brastackptr] = branch_extra;
+ branch_extra = branch_newextra;
+
+ brastack[brastackptr++] = length;
+ length += bracket_length;
+ continue;
+
+ /* Handle ket. Look for subsequent max/min; for certain sets of values we
+ have to replicate this bracket up to that many times. If brastackptr is
+ 0 this is an unmatched bracket which will generate an error, but take care
+ not to try to access brastack[-1] when computing the length and restoring
+ the branch_extra value. */
+
+ case ')':
+ length += 1 + LINK_SIZE;
+ if (brastackptr > 0)
+ {
+ duplength = length - brastack[--brastackptr];
+ branch_extra = bralenstack[brastackptr];
+ }
+ else duplength = 0;
+
+ /* The following code is also used when a recursion such as (?3) is
+ followed by a quantifier, because in that case, it has to be wrapped inside
+ brackets so that the quantifier works. The value of duplength must be
+ set before arrival. */
+
+ HANDLE_QUANTIFIED_BRACKETS:
+
+ /* Leave ptr at the final char; for read_repeat_counts this happens
+ automatically; for the others we need an increment. */
+
+ if ((c = ptr[1]) == '{' && is_counted_repeat(ptr+2))
+ {
+ ptr = read_repeat_counts(ptr+2, &min, &max, errorptr);
+ if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
+ }
+ else if (c == '*') { min = 0; max = -1; ptr++; }
+ else if (c == '+') { min = 1; max = -1; ptr++; }
+ else if (c == '?') { min = 0; max = 1; ptr++; }
+ else { min = 1; max = 1; }
+
+ /* If the minimum is zero, we have to allow for an OP_BRAZERO before the
+ group, and if the maximum is greater than zero, we have to replicate
+ maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting
+ bracket set. */
+
+ if (min == 0)
+ {
+ length++;
+ if (max > 0) length += (max - 1) * (duplength + 3 + 2*LINK_SIZE);
+ }
+
+ /* When the minimum is greater than zero, we have to replicate up to
+ minval-1 times, with no additions required in the copies. Then, if there
+ is a limited maximum we have to replicate up to maxval-1 times allowing
+ for a BRAZERO item before each optional copy and nesting brackets for all
+ but one of the optional copies. */
+
+ else
+ {
+ length += (min - 1) * duplength;
+ if (max > min) /* Need this test as max=-1 means no limit */
+ length += (max - min) * (duplength + 3 + 2*LINK_SIZE)
+ - (2 + 2*LINK_SIZE);
+ }
+
+ /* Allow space for once brackets for "possessive quantifier" */
+
+ if (ptr[1] == '+')
+ {
+ ptr++;
+ length += 2 + 2*LINK_SIZE;
+ }
+ continue;
+
+ /* Non-special character. For a run of such characters the length required
+ is the number of characters + 2, except that the maximum run length is
+ MAXLIT. We won't get a skipped space or a non-data escape or the start of a
+ # comment as the first character, so the length can't be zero. */
+
+ NORMAL_CHAR:
+ default:
+ length += 2;
+ runlength = 0;
+ do
+ {
+#ifdef SUPPORT_UTF8
+ lastcharlength = 1; /* Need length of last char for UTF-8 repeats */
+#endif
+
+ /* If in a \Q...\E sequence, check for end; otherwise it's a literal */
+ if (inescq)
+ {
+ if (c == '\\' && ptr[1] == 'E')
+ {
+ inescq = FALSE;
+ ptr++;
+ }
+ else runlength++;
+ continue;
+ }
+
+ /* Skip whitespace and comments for /x */
+
+ if ((options & PCRE_EXTENDED) != 0)
+ {
+ if ((compile_block.ctypes[c] & ctype_space) != 0) continue;
+ if (c == '#')
+ {
+ /* The space before the ; is to avoid a warning on a silly compiler
+ on the Macintosh. */
+ while ((c = *(++ptr)) != 0 && c != NEWLINE) ;
+ continue;
+ }
+ }
+
+ /* Backslash may introduce a data char or a metacharacter; stop the
+ string before the latter. */
+
+ if (c == '\\')
+ {
+ const uschar *saveptr = ptr;
+ c = check_escape(&ptr, errorptr, bracount, options, FALSE);
+ if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
+ if (c < 0) { ptr = saveptr; break; }
+
+ /* In UTF-8 mode, add on the number of additional bytes needed to
+ encode this character, and save the total length in case this is a
+ final char that is repeated. */
+
+#ifdef SUPPORT_UTF8
+ if (utf8 && c > 127)
+ {
+ int i;
+ for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++)
+ if (c <= utf8_table1[i]) break;
+ runlength += i;
+ lastcharlength += i;
+ }
+#endif
+ }
+
+ /* Ordinary character or single-char escape */
+
+ runlength++;
+ }
+
+ /* This "while" is the end of the "do" above. */
+
+ while (runlength < MAXLIT &&
+ (compile_block.ctypes[c = *(++ptr)] & ctype_meta) == 0);
+
+ /* If we hit a meta-character, back off to point to it */
+
+ if (runlength < MAXLIT) ptr--;
+
+ /* If the last char in the string is a UTF-8 multibyte character, we must
+ set lastcharlength correctly. If it was specified as an escape, this will
+ already have been done above. However, we also have to support in-line
+ UTF-8 characters, so check backwards from where we are. */
+
+#ifdef SUPPORT_UTF8
+ if (utf8)
+ {
+ const uschar *lastptr = ptr - 1;
+ if ((*lastptr & 0x80) != 0)
+ {
+ while((*lastptr & 0xc0) == 0x80) lastptr--;
+ lastcharlength = ptr - lastptr;
+ }
+ }
+#endif
+
+ length += runlength;
+ continue;
+ }
+ }
+
+length += 2 + LINK_SIZE; /* For final KET and END */
+
+if (length > MAX_PATTERN_SIZE)
+ {
+ *errorptr = ERR20;
+ return NULL;
+ }
+
+/* Compute the size of data block needed and get it, either from malloc or
+externally provided function. */
+
+size = length + sizeof(real_pcre) + name_count * (max_name_size + 3);
+re = (real_pcre *)(pcre_malloc)(size);
+
+if (re == NULL)
+ {
+ *errorptr = ERR21;
+ return NULL;
+ }
+
+/* Put in the magic number, and save the size, options, and table pointer */
+
+re->magic_number = MAGIC_NUMBER;
+re->size = size;
+re->options = options;
+re->tables = tables;
+re->name_entry_size = max_name_size + 3;
+re->name_count = name_count;
+
+/* The starting points of the name/number translation table and of the code are
+passed around in the compile data block. */
+
+compile_block.names_found = 0;
+compile_block.name_entry_size = max_name_size + 3;
+compile_block.name_table = (uschar *)re + sizeof(real_pcre);
+codestart = compile_block.name_table + re->name_entry_size * re->name_count;
+compile_block.start_code = codestart;
+compile_block.req_varyopt = 0;
+
+/* Set up a starting, non-extracting bracket, then compile the expression. On
+error, *errorptr will be set non-NULL, so we don't need to look at the result
+of the function here. */
+
+ptr = (const uschar *)pattern;
+code = (uschar *)codestart;
+*code = OP_BRA;
+bracount = 0;
+(void)compile_regex(options, options & PCRE_IMS, &bracount, &code, &ptr,
+ errorptr, FALSE, 0, &firstbyte, &reqbyte, NULL, &compile_block);
+re->top_bracket = bracount;
+re->top_backref = compile_block.top_backref;
+
+/* If not reached end of pattern on success, there's an excess bracket. */
+
+if (*errorptr == NULL && *ptr != 0) *errorptr = ERR22;
+
+/* Fill in the terminating state and check for disastrous overflow, but
+if debugging, leave the test till after things are printed out. */
+
+*code++ = OP_END;
+
+#ifndef DEBUG
+if (code - codestart > length) *errorptr = ERR23;
+#endif
+
+/* Give an error if there's back reference to a non-existent capturing
+subpattern. */
+
+if (re->top_backref > re->top_bracket) *errorptr = ERR15;
+
+/* Failed to compile, or error while post-processing */
+
+if (*errorptr != NULL)
+ {
+ (pcre_free)(re);
+ PCRE_ERROR_RETURN:
+ *erroroffset = ptr - (const uschar *)pattern;
+ return NULL;
+ }
+
+/* If the anchored option was not passed, set the flag if we can determine that
+the pattern is anchored by virtue of ^ characters or \A or anything else (such
+as starting with .* when DOTALL is set).
+
+Otherwise, if we know what the first character has to be, save it, because that
+speeds up unanchored matches no end. If not, see if we can set the
+PCRE_STARTLINE flag. This is helpful for multiline matches when all branches
+start with ^. and also when all branches start with .* for non-DOTALL matches.
+*/
+
+if ((options & PCRE_ANCHORED) == 0)
+ {
+ int temp_options = options;
+ if (is_anchored(codestart, &temp_options, 0, compile_block.backref_map))
+ re->options |= PCRE_ANCHORED;
+ else
+ {
+ if (firstbyte < 0)
+ firstbyte = find_firstassertedchar(codestart, &temp_options, FALSE);
+ if (firstbyte >= 0) /* Remove caseless flag for non-caseable chars */
+ {
+ int ch = firstbyte & 255;
+ re->first_byte = ((firstbyte & REQ_CASELESS) != 0 &&
+ compile_block.fcc[ch] == ch)? ch : firstbyte;
+ re->options |= PCRE_FIRSTSET;
+ }
+ else if (is_startline(codestart, 0, compile_block.backref_map))
+ re->options |= PCRE_STARTLINE;
+ }
+ }
+
+/* For an anchored pattern, we use the "required byte" only if it follows a
+variable length item in the regex. Remove the caseless flag for non-caseable
+chars. */
+
+if (reqbyte >= 0 &&
+ ((re->options & PCRE_ANCHORED) == 0 || (reqbyte & REQ_VARY) != 0))
+ {
+ int ch = reqbyte & 255;
+ re->req_byte = ((reqbyte & REQ_CASELESS) != 0 &&
+ compile_block.fcc[ch] == ch)? (reqbyte & ~REQ_CASELESS) : reqbyte;
+ re->options |= PCRE_REQCHSET;
+ }
+
+/* Print out the compiled data for debugging */
+
+#ifdef DEBUG
+
+printf("Length = %d top_bracket = %d top_backref = %d\n",
+ length, re->top_bracket, re->top_backref);
+
+if (re->options != 0)
+ {
+ printf("%s%s%s%s%s%s%s%s%s\n",
+ ((re->options & PCRE_ANCHORED) != 0)? "anchored " : "",
+ ((re->options & PCRE_CASELESS) != 0)? "caseless " : "",
+ ((re->options & PCRE_ICHANGED) != 0)? "case state changed " : "",
+ ((re->options & PCRE_EXTENDED) != 0)? "extended " : "",
+ ((re->options & PCRE_MULTILINE) != 0)? "multiline " : "",
+ ((re->options & PCRE_DOTALL) != 0)? "dotall " : "",
+ ((re->options & PCRE_DOLLAR_ENDONLY) != 0)? "endonly " : "",
+ ((re->options & PCRE_EXTRA) != 0)? "extra " : "",
+ ((re->options & PCRE_UNGREEDY) != 0)? "ungreedy " : "");
+ }
+
+if ((re->options & PCRE_FIRSTSET) != 0)
+ {
+ int ch = re->first_byte & 255;
+ const char *caseless = ((re->first_byte & REQ_CASELESS) == 0)? "" : " (caseless)";
+ if (isprint(ch)) printf("First char = %c%s\n", ch, caseless);
+ else printf("First char = \\x%02x%s\n", ch, caseless);
+ }
+
+if ((re->options & PCRE_REQCHSET) != 0)
+ {
+ int ch = re->req_byte & 255;
+ const char *caseless = ((re->req_byte & REQ_CASELESS) == 0)? "" : " (caseless)";
+ if (isprint(ch)) printf("Req char = %c%s\n", ch, caseless);
+ else printf("Req char = \\x%02x%s\n", ch, caseless);
+ }
+
+print_internals(re, stdout);
+
+/* This check is done here in the debugging case so that the code that
+was compiled can be seen. */
+
+if (code - codestart > length)
+ {
+ *errorptr = ERR23;
+ (pcre_free)(re);
+ *erroroffset = ptr - (uschar *)pattern;
+ return NULL;
+ }
+#endif
+
+return (pcre *)re;
+}
+
+
+
+/*************************************************
+* Match a back-reference *
+*************************************************/
+
+/* If a back reference hasn't been set, the length that is passed is greater
+than the number of characters left in the string, so the match fails.
+
+Arguments:
+ offset index into the offset vector
+ eptr points into the subject
+ length length to be matched
+ md points to match data block
+ ims the ims flags
+
+Returns: TRUE if matched
+*/
+
+static BOOL
+match_ref(int offset, register const uschar *eptr, int length, match_data *md,
+ unsigned long int ims)
+{
+const uschar *p = md->start_subject + md->offset_vector[offset];
+
+#ifdef DEBUG
+if (eptr >= md->end_subject)
+ printf("matching subject <null>");
+else
+ {
+ printf("matching subject ");
+ pchars(eptr, length, TRUE, md);
+ }
+printf(" against backref ");
+pchars(p, length, FALSE, md);
+printf("\n");
+#endif
+
+/* Always fail if not enough characters left */
+
+if (length > md->end_subject - eptr) return FALSE;
+
+/* Separate the caselesss case for speed */
+
+if ((ims & PCRE_CASELESS) != 0)
+ {
+ while (length-- > 0)
+ if (md->lcc[*p++] != md->lcc[*eptr++]) return FALSE;
+ }
+else
+ { while (length-- > 0) if (*p++ != *eptr++) return FALSE; }
+
+return TRUE;
+}
+
+
+#ifdef SUPPORT_UTF8
+/*************************************************
+* Match character against an XCLASS *
+*************************************************/
+
+/* This function is called from within the XCLASS code below, to match a
+character against an extended class which might match values > 255.
+
+Arguments:
+ c the character
+ data points to the flag byte of the XCLASS data
+
+Returns: TRUE if character matches, else FALSE
+*/
+
+static BOOL
+match_xclass(int c, const uschar *data)
+{
+int t;
+BOOL negated = (*data & XCL_NOT) != 0;
+
+/* Character values < 256 are matched against a bitmap, if one is present. If
+not, we still carry on, because there may be ranges that start below 256 in the
+additional data. */
+
+if (c < 256)
+ {
+ if ((*data & XCL_MAP) != 0 && (data[1 + c/8] & (1 << (c&7))) != 0)
+ return !negated; /* char found */
+ }
+
+/* Now match against the list of large chars or ranges that end with a large
+char. First skip the bit map if present. */
+
+if ((*data++ & XCL_MAP) != 0) data += 32;
+
+while ((t = *data++) != XCL_END)
+ {
+ int x, y;
+ GETCHARINC(x, data);
+ if (t == XCL_SINGLE)
+ {
+ if (c == x) return !negated;
+ }
+ else
+ {
+ GETCHARINC(y, data);
+ if (c >= x && c <= y) return !negated;
+ }
+ }
+
+return negated; /* char was not found */
+}
+#endif
+
+
+/***************************************************************************
+****************************************************************************
+ RECURSION IN THE match() FUNCTION
+
+The match() function is highly recursive. Some regular expressions can cause
+it to recurse thousands of times. I was writing for Unix, so I just let it
+call itself recursively. This uses the stack for saving everything that has
+to be saved for a recursive call. On Unix, the stack can be large, and this
+works fine.
+
+It turns out that on non-Unix systems there are problems with programs that
+use a lot of stack. (This despite the fact that every last chip has oodles
+of memory these days, and techniques for extending the stack have been known
+for decades.) So....
+
+There is a fudge, triggered by defining NO_RECURSE, which avoids recursive
+calls by keeping local variables that need to be preserved in blocks of memory
+obtained from malloc instead instead of on the stack. Macros are used to
+achieve this so that the actual code doesn't look very different to what it
+always used to.
+****************************************************************************
+***************************************************************************/
+
+
+/* These versions of the macros use the stack, as normal */
+
+#ifndef NO_RECURSE
+#define REGISTER register
+#define RMATCH(rx,ra,rb,rc,rd,re,rf,rg) rx = match(ra,rb,rc,rd,re,rf,rg)
+#define RRETURN(ra) return ra
+#else
+
+
+/* These versions of the macros manage a private stack on the heap. Note
+that the rd argument of RMATCH isn't actually used. It's the md argument of
+match(), which never actually changes. */
+
+#define REGISTER
+
+#define RMATCH(rx,ra,rb,rc,rd,re,rf,rg)\
+ {\
+ heapframe *newframe = (pcre_stack_malloc)(sizeof(heapframe));\
+ if (setjmp(frame->Xwhere) == 0)\
+ {\
+ newframe->Xeptr = ra;\
+ newframe->Xecode = rb;\
+ newframe->Xoffset_top = rc;\
+ newframe->Xims = re;\
+ newframe->Xeptrb = rf;\
+ newframe->Xflags = rg;\
+ newframe->Xprevframe = frame;\
+ frame = newframe;\
+ DPRINTF(("restarting from line %d\n", __LINE__));\
+ goto HEAP_RECURSE;\
+ }\
+ else\
+ {\
+ DPRINTF(("longjumped back to line %d\n", __LINE__));\
+ frame = md->thisframe;\
+ rx = frame->Xresult;\
+ }\
+ }
+
+#define RRETURN(ra)\
+ {\
+ heapframe *newframe = frame;\
+ frame = newframe->Xprevframe;\
+ (pcre_stack_free)(newframe);\
+ if (frame != NULL)\
+ {\
+ frame->Xresult = ra;\
+ md->thisframe = frame;\
+ longjmp(frame->Xwhere, 1);\
+ }\
+ return ra;\
+ }
+
+
+/* Structure for remembering the local variables in a private frame */
+
+typedef struct heapframe {
+ struct heapframe *Xprevframe;
+
+ /* Function arguments that may change */
+
+ const uschar *Xeptr;
+ const uschar *Xecode;
+ int Xoffset_top;
+ long int Xims;
+ eptrblock *Xeptrb;
+ int Xflags;
+
+ /* Function local variables */
+
+ const uschar *Xcallpat;
+ const uschar *Xcharptr;
+ const uschar *Xdata;
+ const uschar *Xlastptr;
+ const uschar *Xnext;
+ const uschar *Xpp;
+ const uschar *Xprev;
+ const uschar *Xsaved_eptr;
+
+ recursion_info Xnew_recursive;
+
+ BOOL Xcur_is_word;
+ BOOL Xcondition;
+ BOOL Xminimize;
+ BOOL Xprev_is_word;
+
+ unsigned long int Xoriginal_ims;
+
+ int Xctype;
+ int Xfc;
+ int Xfi;
+ int Xlength;
+ int Xmax;
+ int Xmin;
+ int Xnumber;
+ int Xoffset;
+ int Xop;
+ int Xsave_capture_last;
+ int Xsave_offset1, Xsave_offset2, Xsave_offset3;
+ int Xstacksave[REC_STACK_SAVE_MAX];
+
+ eptrblock Xnewptrb;
+
+ /* Place to pass back result, and where to jump back to */
+
+ int Xresult;
+ jmp_buf Xwhere;
+
+} heapframe;
+
+#endif
+
+
+/***************************************************************************
+***************************************************************************/
+
+
+
+/*************************************************
+* Match from current position *
+*************************************************/
+
+/* On entry ecode points to the first opcode, and eptr to the first character
+in the subject string, while eptrb holds the value of eptr at the start of the
+last bracketed group - used for breaking infinite loops matching zero-length
+strings. This function is called recursively in many circumstances. Whenever it
+returns a negative (error) response, the outer incarnation must also return the
+same response.
+
+Performance note: It might be tempting to extract commonly used fields from the
+md structure (e.g. utf8, end_subject) into individual variables to improve
+performance. Tests using gcc on a SPARC disproved this; in the first case, it
+made performance worse.
+
+Arguments:
+ eptr pointer in subject
+ ecode position in code
+ offset_top current top pointer
+ md pointer to "static" info for the match
+ ims current /i, /m, and /s options
+ eptrb pointer to chain of blocks containing eptr at start of
+ brackets - for testing for empty matches
+ flags can contain
+ match_condassert - this is an assertion condition
+ match_isgroup - this is the start of a bracketed group
+
+Returns: MATCH_MATCH if matched ) these values are >= 0
+ MATCH_NOMATCH if failed to match )
+ a negative PCRE_ERROR_xxx value if aborted by an error condition
+ (e.g. stopped by recursion limit)
+*/
+
+static int
+match(REGISTER const uschar *eptr, REGISTER const uschar *ecode,
+ int offset_top, match_data *md, unsigned long int ims, eptrblock *eptrb,
+ int flags)
+{
+/* These variables do not need to be preserved over recursion in this function,
+so they can be ordinary variables in all cases. Mark them with "register"
+because they are used a lot in loops. */
+
+register int rrc; /* Returns from recursive calls */
+register int i; /* Used for loops not involving calls to RMATCH() */
+register int c; /* Character values not kept over RMATCH() calls */
+
+/* When recursion is not being used, all "local" variables that have to be
+preserved over calls to RMATCH() are part of a "frame" which is obtained from
+heap storage. Set up the top-level frame here; others are obtained from the
+heap whenever RMATCH() does a "recursion". See the macro definitions above. */
+
+#ifdef NO_RECURSE
+heapframe *frame = (pcre_stack_malloc)(sizeof(heapframe));
+frame->Xprevframe = NULL; /* Marks the top level */
+
+/* Copy in the original argument variables */
+
+frame->Xeptr = eptr;
+frame->Xecode = ecode;
+frame->Xoffset_top = offset_top;
+frame->Xims = ims;
+frame->Xeptrb = eptrb;
+frame->Xflags = flags;
+
+/* This is where control jumps back to to effect "recursion" */
+
+HEAP_RECURSE:
+
+/* Macros make the argument variables come from the current frame */
+
+#define eptr frame->Xeptr
+#define ecode frame->Xecode
+#define offset_top frame->Xoffset_top
+#define ims frame->Xims
+#define eptrb frame->Xeptrb
+#define flags frame->Xflags
+
+/* Ditto for the local variables */
+
+#define callpat frame->Xcallpat
+#define charptr frame->Xcharptr
+#define data frame->Xdata
+#define lastptr frame->Xlastptr
+#define next frame->Xnext
+#define pp frame->Xpp
+#define prev frame->Xprev
+#define saved_eptr frame->Xsaved_eptr
+
+#define new_recursive frame->Xnew_recursive
+
+#define cur_is_word frame->Xcur_is_word
+#define condition frame->Xcondition
+#define minimize frame->Xminimize
+#define prev_is_word frame->Xprev_is_word
+
+#define original_ims frame->Xoriginal_ims
+
+#define ctype frame->Xctype
+#define fc frame->Xfc
+#define fi frame->Xfi
+#define length frame->Xlength
+#define max frame->Xmax
+#define min frame->Xmin
+#define number frame->Xnumber
+#define offset frame->Xoffset
+#define op frame->Xop
+#define save_capture_last frame->Xsave_capture_last
+#define save_offset1 frame->Xsave_offset1
+#define save_offset2 frame->Xsave_offset2
+#define save_offset3 frame->Xsave_offset3
+#define stacksave frame->Xstacksave
+
+#define newptrb frame->Xnewptrb
+
+/* When recursion is being used, local variables are allocated on the stack and
+get preserved during recursion in the normal way. In this environment, fi and
+i, and fc and c, can be the same variables. */
+
+#else
+#define fi i
+#define fc c
+
+const uschar *callpat; /* Many of these variables are used ony */
+#if 0
+const uschar *charptr; /* small blocks of the code. My normal */
+#endif
+const uschar *data; /* style of coding would have declared */
+#if 0
+const uschar *lastptr; /* them within each of those blocks. */
+#endif
+const uschar *next; /* However, in order to accommodate the */
+const uschar *pp; /* version of this code that uses an */
+const uschar *prev; /* external "stack" implemented on the */
+const uschar *saved_eptr; /* heap, it is easier to declare them */
+ /* all here, so the declarations can */
+recursion_info new_recursive; /* be cut out in a block. The only */
+ /* declarations within blocks below are */
+BOOL cur_is_word; /* for variables that do not have to */
+BOOL condition; /* be preserved over a recursive call */
+BOOL minimize; /* to RMATCH(). */
+BOOL prev_is_word;
+
+unsigned long int original_ims;
+
+int ctype;
+int length;
+int max;
+int min;
+int number;
+int offset;
+int op;
+int save_capture_last;
+int save_offset1, save_offset2, save_offset3;
+int stacksave[REC_STACK_SAVE_MAX];
+
+eptrblock newptrb;
+#endif
+
+
+/* OK, now we can get on with the real code of the function. Recursion is
+specified by the macros RMATCH and RRETURN. When NO_RECURSE is *not* defined,
+these just turn into a recursive call to match() and a "return", respectively.
+However, RMATCH isn't like a function call because it's quite a complicated
+macro. It has to be used in one particular way. This shouldn't, however, impact
+performance when true recursion is being used. */
+
+if (md->match_call_count++ >= md->match_limit) RRETURN(PCRE_ERROR_MATCHLIMIT);
+
+original_ims = ims; /* Save for resetting on ')' */
+
+/* At the start of a bracketed group, add the current subject pointer to the
+stack of such pointers, to be re-instated at the end of the group when we hit
+the closing ket. When match() is called in other circumstances, we don't add to
+this stack. */
+
+if ((flags & match_isgroup) != 0)
+ {
+ newptrb.epb_prev = eptrb;
+ newptrb.epb_saved_eptr = eptr;
+ eptrb = &newptrb;
+ }
+
+/* Now start processing the operations. */
+
+for (;;)
+ {
+ op = *ecode;
+ minimize = FALSE;
+
+ /* Opening capturing bracket. If there is space in the offset vector, save
+ the current subject position in the working slot at the top of the vector. We
+ mustn't change the current values of the data slot, because they may be set
+ from a previous iteration of this group, and be referred to by a reference
+ inside the group.
+
+ If the bracket fails to match, we need to restore this value and also the
+ values of the final offsets, in case they were set by a previous iteration of
+ the same bracket.
+
+ If there isn't enough space in the offset vector, treat this as if it were a
+ non-capturing bracket. Don't worry about setting the flag for the error case
+ here; that is handled in the code for KET. */
+
+ if (op > OP_BRA)
+ {
+ number = op - OP_BRA;
+
+ /* For extended extraction brackets (large number), we have to fish out the
+ number from a dummy opcode at the start. */
+
+ if (number > EXTRACT_BASIC_MAX)
+ number = GET2(ecode, 2+LINK_SIZE);
+ offset = number << 1;
+
+#ifdef DEBUG
+ printf("start bracket %d subject=", number);
+ pchars(eptr, 16, TRUE, md);
+ printf("\n");
+#endif
+
+ if (offset < md->offset_max)
+ {
+ save_offset1 = md->offset_vector[offset];
+ save_offset2 = md->offset_vector[offset+1];
+ save_offset3 = md->offset_vector[md->offset_end - number];
+ save_capture_last = md->capture_last;
+
+ DPRINTF(("saving %d %d %d\n", save_offset1, save_offset2, save_offset3));
+ md->offset_vector[md->offset_end - number] = eptr - md->start_subject;
+
+ do
+ {
+ RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb,
+ match_isgroup);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ md->capture_last = save_capture_last;
+ ecode += GET(ecode, 1);
+ }
+ while (*ecode == OP_ALT);
+
+ DPRINTF(("bracket %d failed\n", number));
+
+ md->offset_vector[offset] = save_offset1;
+ md->offset_vector[offset+1] = save_offset2;
+ md->offset_vector[md->offset_end - number] = save_offset3;
+
+ RRETURN(MATCH_NOMATCH);
+ }
+
+ /* Insufficient room for saving captured contents */
+
+ else op = OP_BRA;
+ }
+
+ /* Other types of node can be handled by a switch */
+
+ switch(op)
+ {
+ case OP_BRA: /* Non-capturing bracket: optimized */
+ DPRINTF(("start bracket 0\n"));
+ do
+ {
+ RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb,
+ match_isgroup);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ ecode += GET(ecode, 1);
+ }
+ while (*ecode == OP_ALT);
+ DPRINTF(("bracket 0 failed\n"));
+ RRETURN(MATCH_NOMATCH);
+
+ /* Conditional group: compilation checked that there are no more than
+ two branches. If the condition is false, skipping the first branch takes us
+ past the end if there is only one branch, but that's OK because that is
+ exactly what going to the ket would do. */
+
+ case OP_COND:
+ if (ecode[LINK_SIZE+1] == OP_CREF) /* Condition extract or recurse test */
+ {
+ offset = GET2(ecode, LINK_SIZE+2) << 1; /* Doubled ref number */
+ condition = (offset == CREF_RECURSE * 2)?
+ (md->recursive != NULL) :
+ (offset < offset_top && md->offset_vector[offset] >= 0);
+ RMATCH(rrc, eptr, ecode + (condition?
+ (LINK_SIZE + 4) : (LINK_SIZE + 1 + GET(ecode, 1))),
+ offset_top, md, ims, eptrb, match_isgroup);
+ RRETURN(rrc);
+ }
+
+ /* The condition is an assertion. Call match() to evaluate it - setting
+ the final argument TRUE causes it to stop at the end of an assertion. */
+
+ else
+ {
+ RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL,
+ match_condassert | match_isgroup);
+ if (rrc == MATCH_MATCH)
+ {
+ ecode += 1 + LINK_SIZE + GET(ecode, LINK_SIZE+2);
+ while (*ecode == OP_ALT) ecode += GET(ecode, 1);
+ }
+ else if (rrc != MATCH_NOMATCH)
+ {
+ RRETURN(rrc); /* Need braces because of following else */
+ }
+ else ecode += GET(ecode, 1);
+ RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb,
+ match_isgroup);
+ RRETURN(rrc);
+ }
+ /* Control never reaches here */
+
+ /* Skip over conditional reference or large extraction number data if
+ encountered. */
+
+ case OP_CREF:
+ case OP_BRANUMBER:
+ ecode += 3;
+ break;
+
+ /* End of the pattern. If we are in a recursion, we should restore the
+ offsets appropriately and continue from after the call. */
+
+ case OP_END:
+ if (md->recursive != NULL && md->recursive->group_num == 0)
+ {
+ recursion_info *rec = md->recursive;
+ DPRINTF(("Hit the end in a (?0) recursion\n"));
+ md->recursive = rec->prevrec;
+ memmove(md->offset_vector, rec->offset_save,
+ rec->saved_max * sizeof(int));
+ md->start_match = rec->save_start;
+ ims = original_ims;
+ ecode = rec->after_call;
+ break;
+ }
+
+ /* Otherwise, if PCRE_NOTEMPTY is set, fail if we have matched an empty
+ string - backtracking will then try other alternatives, if any. */
+
+ if (md->notempty && eptr == md->start_match) RRETURN(MATCH_NOMATCH);
+ md->end_match_ptr = eptr; /* Record where we ended */
+ md->end_offset_top = offset_top; /* and how many extracts were taken */
+ RRETURN(MATCH_MATCH);
+
+ /* Change option settings */
+
+ case OP_OPT:
+ ims = ecode[1];
+ ecode += 2;
+ DPRINTF(("ims set to %02lx\n", ims));
+ break;
+
+ /* Assertion brackets. Check the alternative branches in turn - the
+ matching won't pass the KET for an assertion. If any one branch matches,
+ the assertion is true. Lookbehind assertions have an OP_REVERSE item at the
+ start of each branch to move the current point backwards, so the code at
+ this level is identical to the lookahead case. */
+
+ case OP_ASSERT:
+ case OP_ASSERTBACK:
+ do
+ {
+ RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL,
+ match_isgroup);
+ if (rrc == MATCH_MATCH) break;
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ ecode += GET(ecode, 1);
+ }
+ while (*ecode == OP_ALT);
+ if (*ecode == OP_KET) RRETURN(MATCH_NOMATCH);
+
+ /* If checking an assertion for a condition, return MATCH_MATCH. */
+
+ if ((flags & match_condassert) != 0) RRETURN(MATCH_MATCH);
+
+ /* Continue from after the assertion, updating the offsets high water
+ mark, since extracts may have been taken during the assertion. */
+
+ do ecode += GET(ecode,1); while (*ecode == OP_ALT);
+ ecode += 1 + LINK_SIZE;
+ offset_top = md->end_offset_top;
+ continue;
+
+ /* Negative assertion: all branches must fail to match */
+
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK_NOT:
+ do
+ {
+ RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL,
+ match_isgroup);
+ if (rrc == MATCH_MATCH) RRETURN(MATCH_NOMATCH);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ ecode += GET(ecode,1);
+ }
+ while (*ecode == OP_ALT);
+
+ if ((flags & match_condassert) != 0) RRETURN(MATCH_MATCH);
+
+ ecode += 1 + LINK_SIZE;
+ continue;
+
+ /* Move the subject pointer back. This occurs only at the start of
+ each branch of a lookbehind assertion. If we are too close to the start to
+ move back, this match function fails. When working with UTF-8 we move
+ back a number of characters, not bytes. */
+
+ case OP_REVERSE:
+#ifdef SUPPORT_UTF8
+ if (md->utf8)
+ {
+ c = GET(ecode,1);
+ for (i = 0; i < c; i++)
+ {
+ eptr--;
+ if (eptr < md->start_subject) RRETURN(MATCH_NOMATCH);
+ BACKCHAR(eptr)
+ }
+ }
+ else
+#endif
+
+ /* No UTF-8 support, or not in UTF-8 mode: count is byte count */
+
+ {
+ eptr -= GET(ecode,1);
+ if (eptr < md->start_subject) RRETURN(MATCH_NOMATCH);
+ }
+
+ /* Skip to next op code */
+
+ ecode += 1 + LINK_SIZE;
+ break;
+
+ /* The callout item calls an external function, if one is provided, passing
+ details of the match so far. This is mainly for debugging, though the
+ function is able to force a failure. */
+
+ case OP_CALLOUT:
+ if (pcre_callout != NULL)
+ {
+ pcre_callout_block cb;
+ cb.version = 0; /* Version 0 of the callout block */
+ cb.callout_number = ecode[1];
+ cb.offset_vector = md->offset_vector;
+ cb.subject = (const char *)md->start_subject;
+ cb.subject_length = md->end_subject - md->start_subject;
+ cb.start_match = md->start_match - md->start_subject;
+ cb.current_position = eptr - md->start_subject;
+ cb.capture_top = offset_top/2;
+ cb.capture_last = md->capture_last;
+ cb.callout_data = md->callout_data;
+ if ((rrc = (*pcre_callout)(&cb)) > 0) RRETURN(MATCH_NOMATCH);
+ if (rrc < 0) RRETURN(rrc);
+ }
+ ecode += 2;
+ break;
+
+ /* Recursion either matches the current regex, or some subexpression. The
+ offset data is the offset to the starting bracket from the start of the
+ whole pattern. (This is so that it works from duplicated subpatterns.)
+
+ If there are any capturing brackets started but not finished, we have to
+ save their starting points and reinstate them after the recursion. However,
+ we don't know how many such there are (offset_top records the completed
+ total) so we just have to save all the potential data. There may be up to
+ 65535 such values, which is too large to put on the stack, but using malloc
+ for small numbers seems expensive. As a compromise, the stack is used when
+ there are no more than REC_STACK_SAVE_MAX values to store; otherwise malloc
+ is used. A problem is what to do if the malloc fails ... there is no way of
+ returning to the top level with an error. Save the top REC_STACK_SAVE_MAX
+ values on the stack, and accept that the rest may be wrong.
+
+ There are also other values that have to be saved. We use a chained
+ sequence of blocks that actually live on the stack. Thanks to Robin Houston
+ for the original version of this logic. */
+
+ case OP_RECURSE:
+ {
+ callpat = md->start_code + GET(ecode, 1);
+ new_recursive.group_num = *callpat - OP_BRA;
+
+ /* For extended extraction brackets (large number), we have to fish out
+ the number from a dummy opcode at the start. */
+
+ if (new_recursive.group_num > EXTRACT_BASIC_MAX)
+ new_recursive.group_num = GET2(callpat, 2+LINK_SIZE);
+
+ /* Add to "recursing stack" */
+
+ new_recursive.prevrec = md->recursive;
+ md->recursive = &new_recursive;
+
+ /* Find where to continue from afterwards */
+
+ ecode += 1 + LINK_SIZE;
+ new_recursive.after_call = ecode;
+
+ /* Now save the offset data. */
+
+ new_recursive.saved_max = md->offset_end;
+ if (new_recursive.saved_max <= REC_STACK_SAVE_MAX)
+ new_recursive.offset_save = stacksave;
+ else
+ {
+ new_recursive.offset_save =
+ (int *)(pcre_malloc)(new_recursive.saved_max * sizeof(int));
+ if (new_recursive.offset_save == NULL) RRETURN(PCRE_ERROR_NOMEMORY);
+ }
+
+ memcpy(new_recursive.offset_save, md->offset_vector,
+ new_recursive.saved_max * sizeof(int));
+ new_recursive.save_start = md->start_match;
+ md->start_match = eptr;
+
+ /* OK, now we can do the recursion. For each top-level alternative we
+ restore the offset and recursion data. */
+
+ DPRINTF(("Recursing into group %d\n", new_recursive.group_num));
+ do
+ {
+ RMATCH(rrc, eptr, callpat + 1 + LINK_SIZE, offset_top, md, ims,
+ eptrb, match_isgroup);
+ if (rrc == MATCH_MATCH)
+ {
+ md->recursive = new_recursive.prevrec;
+ if (new_recursive.offset_save != stacksave)
+ (pcre_free)(new_recursive.offset_save);
+ RRETURN(MATCH_MATCH);
+ }
+ else if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+
+ md->recursive = &new_recursive;
+ memcpy(md->offset_vector, new_recursive.offset_save,
+ new_recursive.saved_max * sizeof(int));
+ callpat += GET(callpat, 1);
+ }
+ while (*callpat == OP_ALT);
+
+ DPRINTF(("Recursion didn't match\n"));
+ md->recursive = new_recursive.prevrec;
+ if (new_recursive.offset_save != stacksave)
+ (pcre_free)(new_recursive.offset_save);
+ RRETURN(MATCH_NOMATCH);
+ }
+ /* Control never reaches here */
+
+ /* "Once" brackets are like assertion brackets except that after a match,
+ the point in the subject string is not moved back. Thus there can never be
+ a move back into the brackets. Friedl calls these "atomic" subpatterns.
+ Check the alternative branches in turn - the matching won't pass the KET
+ for this kind of subpattern. If any one branch matches, we carry on as at
+ the end of a normal bracket, leaving the subject pointer. */
+
+ case OP_ONCE:
+ {
+ prev = ecode;
+ saved_eptr = eptr;
+
+ do
+ {
+ RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims,
+ eptrb, match_isgroup);
+ if (rrc == MATCH_MATCH) break;
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ ecode += GET(ecode,1);
+ }
+ while (*ecode == OP_ALT);
+
+ /* If hit the end of the group (which could be repeated), fail */
+
+ if (*ecode != OP_ONCE && *ecode != OP_ALT) RRETURN(MATCH_NOMATCH);
+
+ /* Continue as from after the assertion, updating the offsets high water
+ mark, since extracts may have been taken. */
+
+ do ecode += GET(ecode,1); while (*ecode == OP_ALT);
+
+ offset_top = md->end_offset_top;
+ eptr = md->end_match_ptr;
+
+ /* For a non-repeating ket, just continue at this level. This also
+ happens for a repeating ket if no characters were matched in the group.
+ This is the forcible breaking of infinite loops as implemented in Perl
+ 5.005. If there is an options reset, it will get obeyed in the normal
+ course of events. */
+
+ if (*ecode == OP_KET || eptr == saved_eptr)
+ {
+ ecode += 1+LINK_SIZE;
+ break;
+ }
+
+ /* The repeating kets try the rest of the pattern or restart from the
+ preceding bracket, in the appropriate order. We need to reset any options
+ that changed within the bracket before re-running it, so check the next
+ opcode. */
+
+ if (ecode[1+LINK_SIZE] == OP_OPT)
+ {
+ ims = (ims & ~PCRE_IMS) | ecode[4];
+ DPRINTF(("ims set to %02lx at group repeat\n", ims));
+ }
+
+ if (*ecode == OP_KETRMIN)
+ {
+ RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, match_isgroup);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ }
+ else /* OP_KETRMAX */
+ {
+ RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, match_isgroup);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ RMATCH(rrc, eptr, ecode + 1+LINK_SIZE, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ }
+ }
+ RRETURN(MATCH_NOMATCH);
+
+ /* An alternation is the end of a branch; scan along to find the end of the
+ bracketed group and go to there. */
+
+ case OP_ALT:
+ do ecode += GET(ecode,1); while (*ecode == OP_ALT);
+ break;
+
+ /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating
+ that it may occur zero times. It may repeat infinitely, or not at all -
+ i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper
+ repeat limits are compiled as a number of copies, with the optional ones
+ preceded by BRAZERO or BRAMINZERO. */
+
+ case OP_BRAZERO:
+ {
+ next = ecode+1;
+ RMATCH(rrc, eptr, next, offset_top, md, ims, eptrb, match_isgroup);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ do next += GET(next,1); while (*next == OP_ALT);
+ ecode = next + 1+LINK_SIZE;
+ }
+ break;
+
+ case OP_BRAMINZERO:
+ {
+ next = ecode+1;
+ do next += GET(next,1); while (*next == OP_ALT);
+ RMATCH(rrc, eptr, next + 1+LINK_SIZE, offset_top, md, ims, eptrb,
+ match_isgroup);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ ecode++;
+ }
+ break;
+
+ /* End of a group, repeated or non-repeating. If we are at the end of
+ an assertion "group", stop matching and return MATCH_MATCH, but record the
+ current high water mark for use by positive assertions. Do this also
+ for the "once" (not-backup up) groups. */
+
+ case OP_KET:
+ case OP_KETRMIN:
+ case OP_KETRMAX:
+ {
+ prev = ecode - GET(ecode, 1);
+ saved_eptr = eptrb->epb_saved_eptr;
+
+ /* Back up the stack of bracket start pointers. */
+
+ eptrb = eptrb->epb_prev;
+
+ if (*prev == OP_ASSERT || *prev == OP_ASSERT_NOT ||
+ *prev == OP_ASSERTBACK || *prev == OP_ASSERTBACK_NOT ||
+ *prev == OP_ONCE)
+ {
+ md->end_match_ptr = eptr; /* For ONCE */
+ md->end_offset_top = offset_top;
+ RRETURN(MATCH_MATCH);
+ }
+
+ /* In all other cases except a conditional group we have to check the
+ group number back at the start and if necessary complete handling an
+ extraction by setting the offsets and bumping the high water mark. */
+
+ if (*prev != OP_COND)
+ {
+ number = *prev - OP_BRA;
+
+ /* For extended extraction brackets (large number), we have to fish out
+ the number from a dummy opcode at the start. */
+
+ if (number > EXTRACT_BASIC_MAX) number = GET2(prev, 2+LINK_SIZE);
+ offset = number << 1;
+
+#ifdef DEBUG
+ printf("end bracket %d", number);
+ printf("\n");
+#endif
+
+ /* Test for a numbered group. This includes groups called as a result
+ of recursion. Note that whole-pattern recursion is coded as a recurse
+ into group 0, so it won't be picked up here. Instead, we catch it when
+ the OP_END is reached. */
+
+ if (number > 0)
+ {
+ md->capture_last = number;
+ if (offset >= md->offset_max) md->offset_overflow = TRUE; else
+ {
+ md->offset_vector[offset] =
+ md->offset_vector[md->offset_end - number];
+ md->offset_vector[offset+1] = eptr - md->start_subject;
+ if (offset_top <= offset) offset_top = offset + 2;
+ }
+
+ /* Handle a recursively called group. Restore the offsets
+ appropriately and continue from after the call. */
+
+ if (md->recursive != NULL && md->recursive->group_num == number)
+ {
+ recursion_info *rec = md->recursive;
+ DPRINTF(("Recursion (%d) succeeded - continuing\n", number));
+ md->recursive = rec->prevrec;
+ md->start_match = rec->save_start;
+ memcpy(md->offset_vector, rec->offset_save,
+ rec->saved_max * sizeof(int));
+ ecode = rec->after_call;
+ ims = original_ims;
+ break;
+ }
+ }
+ }
+
+ /* Reset the value of the ims flags, in case they got changed during
+ the group. */
+
+ ims = original_ims;
+ DPRINTF(("ims reset to %02lx\n", ims));
+
+ /* For a non-repeating ket, just continue at this level. This also
+ happens for a repeating ket if no characters were matched in the group.
+ This is the forcible breaking of infinite loops as implemented in Perl
+ 5.005. If there is an options reset, it will get obeyed in the normal
+ course of events. */
+
+ if (*ecode == OP_KET || eptr == saved_eptr)
+ {
+ ecode += 1 + LINK_SIZE;
+ break;
+ }
+
+ /* The repeating kets try the rest of the pattern or restart from the
+ preceding bracket, in the appropriate order. */
+
+ if (*ecode == OP_KETRMIN)
+ {
+ RMATCH(rrc, eptr, ecode + 1+LINK_SIZE, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, match_isgroup);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ }
+ else /* OP_KETRMAX */
+ {
+ RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, match_isgroup);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ RMATCH(rrc, eptr, ecode + 1+LINK_SIZE, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ }
+ }
+
+ RRETURN(MATCH_NOMATCH);
+
+ /* Start of subject unless notbol, or after internal newline if multiline */
+
+ case OP_CIRC:
+ if (md->notbol && eptr == md->start_subject) RRETURN(MATCH_NOMATCH);
+ if ((ims & PCRE_MULTILINE) != 0)
+ {
+ if (eptr != md->start_subject && eptr[-1] != NEWLINE)
+ RRETURN(MATCH_NOMATCH);
+ ecode++;
+ break;
+ }
+ /* ... else fall through */
+
+ /* Start of subject assertion */
+
+ case OP_SOD:
+ if (eptr != md->start_subject) RRETURN(MATCH_NOMATCH);
+ ecode++;
+ break;
+
+ /* Start of match assertion */
+
+ case OP_SOM:
+ if (eptr != md->start_subject + md->start_offset) RRETURN(MATCH_NOMATCH);
+ ecode++;
+ break;
+
+ /* Assert before internal newline if multiline, or before a terminating
+ newline unless endonly is set, else end of subject unless noteol is set. */
+
+ case OP_DOLL:
+ if ((ims & PCRE_MULTILINE) != 0)
+ {
+ if (eptr < md->end_subject)
+ { if (*eptr != NEWLINE) RRETURN(MATCH_NOMATCH); }
+ else
+ { if (md->noteol) RRETURN(MATCH_NOMATCH); }
+ ecode++;
+ break;
+ }
+ else
+ {
+ if (md->noteol) RRETURN(MATCH_NOMATCH);
+ if (!md->endonly)
+ {
+ if (eptr < md->end_subject - 1 ||
+ (eptr == md->end_subject - 1 && *eptr != NEWLINE))
+ RRETURN(MATCH_NOMATCH);
+ ecode++;
+ break;
+ }
+ }
+ /* ... else fall through */
+
+ /* End of subject assertion (\z) */
+
+ case OP_EOD:
+ if (eptr < md->end_subject) RRETURN(MATCH_NOMATCH);
+ ecode++;
+ break;
+
+ /* End of subject or ending \n assertion (\Z) */
+
+ case OP_EODN:
+ if (eptr < md->end_subject - 1 ||
+ (eptr == md->end_subject - 1 && *eptr != NEWLINE)) RRETURN(MATCH_NOMATCH);
+ ecode++;
+ break;
+
+ /* Word boundary assertions */
+
+ case OP_NOT_WORD_BOUNDARY:
+ case OP_WORD_BOUNDARY:
+ {
+
+ /* Find out if the previous and current characters are "word" characters.
+ It takes a bit more work in UTF-8 mode. Characters > 255 are assumed to
+ be "non-word" characters. */
+
+#ifdef SUPPORT_UTF8
+ if (md->utf8)
+ {
+ if (eptr == md->start_subject) prev_is_word = FALSE; else
+ {
+ lastptr = eptr - 1;
+ while((*lastptr & 0xc0) == 0x80) lastptr--;
+ GETCHAR(c, lastptr);
+ prev_is_word = c < 256 && (md->ctypes[c] & ctype_word) != 0;
+ }
+ if (eptr >= md->end_subject) cur_is_word = FALSE; else
+ {
+ GETCHAR(c, eptr);
+ cur_is_word = c < 256 && (md->ctypes[c] & ctype_word) != 0;
+ }
+ }
+ else
+#endif
+
+ /* More streamlined when not in UTF-8 mode */
+
+ {
+ prev_is_word = (eptr != md->start_subject) &&
+ ((md->ctypes[eptr[-1]] & ctype_word) != 0);
+ cur_is_word = (eptr < md->end_subject) &&
+ ((md->ctypes[*eptr] & ctype_word) != 0);
+ }
+
+ /* Now see if the situation is what we want */
+
+ if ((*ecode++ == OP_WORD_BOUNDARY)?
+ cur_is_word == prev_is_word : cur_is_word != prev_is_word)
+ RRETURN(MATCH_NOMATCH);
+ }
+ break;
+
+ /* Match a single character type; inline for speed */
+
+ case OP_ANY:
+ if ((ims & PCRE_DOTALL) == 0 && eptr < md->end_subject && *eptr == NEWLINE)
+ RRETURN(MATCH_NOMATCH);
+ if (eptr++ >= md->end_subject) RRETURN(MATCH_NOMATCH);
+#ifdef SUPPORT_UTF8
+ if (md->utf8)
+ while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
+#endif
+ ecode++;
+ break;
+
+ /* Match a single byte, even in UTF-8 mode. This opcode really does match
+ any byte, even newline, independent of the setting of PCRE_DOTALL. */
+
+ case OP_ANYBYTE:
+ if (eptr++ >= md->end_subject) RRETURN(MATCH_NOMATCH);
+ ecode++;
+ break;
+
+ case OP_NOT_DIGIT:
+ if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+ GETCHARINCTEST(c, eptr);
+ if (
+#ifdef SUPPORT_UTF8
+ c < 256 &&
+#endif
+ (md->ctypes[c] & ctype_digit) != 0
+ )
+ RRETURN(MATCH_NOMATCH);
+ ecode++;
+ break;
+
+ case OP_DIGIT:
+ if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+ GETCHARINCTEST(c, eptr);
+ if (
+#ifdef SUPPORT_UTF8
+ c >= 256 ||
+#endif
+ (md->ctypes[c] & ctype_digit) == 0
+ )
+ RRETURN(MATCH_NOMATCH);
+ ecode++;
+ break;
+
+ case OP_NOT_WHITESPACE:
+ if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+ GETCHARINCTEST(c, eptr);
+ if (
+#ifdef SUPPORT_UTF8
+ c < 256 &&
+#endif
+ (md->ctypes[c] & ctype_space) != 0
+ )
+ RRETURN(MATCH_NOMATCH);
+ ecode++;
+ break;
+
+ case OP_WHITESPACE:
+ if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+ GETCHARINCTEST(c, eptr);
+ if (
+#ifdef SUPPORT_UTF8
+ c >= 256 ||
+#endif
+ (md->ctypes[c] & ctype_space) == 0
+ )
+ RRETURN(MATCH_NOMATCH);
+ ecode++;
+ break;
+
+ case OP_NOT_WORDCHAR:
+ if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+ GETCHARINCTEST(c, eptr);
+ if (
+#ifdef SUPPORT_UTF8
+ c < 256 &&
+#endif
+ (md->ctypes[c] & ctype_word) != 0
+ )
+ RRETURN(MATCH_NOMATCH);
+ ecode++;
+ break;
+
+ case OP_WORDCHAR:
+ if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+ GETCHARINCTEST(c, eptr);
+ if (
+#ifdef SUPPORT_UTF8
+ c >= 256 ||
+#endif
+ (md->ctypes[c] & ctype_word) == 0
+ )
+ RRETURN(MATCH_NOMATCH);
+ ecode++;
+ break;
+
+ /* Match a back reference, possibly repeatedly. Look past the end of the
+ item to see if there is repeat information following. The code is similar
+ to that for character classes, but repeated for efficiency. Then obey
+ similar code to character type repeats - written out again for speed.
+ However, if the referenced string is the empty string, always treat
+ it as matched, any number of times (otherwise there could be infinite
+ loops). */
+
+ case OP_REF:
+ {
+ offset = GET2(ecode, 1) << 1; /* Doubled ref number */
+ ecode += 3; /* Advance past item */
+
+ /* If the reference is unset, set the length to be longer than the amount
+ of subject left; this ensures that every attempt at a match fails. We
+ can't just fail here, because of the possibility of quantifiers with zero
+ minima. */
+
+ length = (offset >= offset_top || md->offset_vector[offset] < 0)?
+ md->end_subject - eptr + 1 :
+ md->offset_vector[offset+1] - md->offset_vector[offset];
+
+ /* Set up for repetition, or handle the non-repeated case */
+
+ switch (*ecode)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ c = *ecode++ - OP_CRSTAR;
+ minimize = (c & 1) != 0;
+ min = rep_min[c]; /* Pick up values from tables; */
+ max = rep_max[c]; /* zero for max => infinity */
+ if (max == 0) max = INT_MAX;
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ minimize = (*ecode == OP_CRMINRANGE);
+ min = GET2(ecode, 1);
+ max = GET2(ecode, 3);
+ if (max == 0) max = INT_MAX;
+ ecode += 5;
+ break;
+
+ default: /* No repeat follows */
+ if (!match_ref(offset, eptr, length, md, ims)) RRETURN(MATCH_NOMATCH);
+ eptr += length;
+ continue; /* With the main loop */
+ }
+
+ /* If the length of the reference is zero, just continue with the
+ main loop. */
+
+ if (length == 0) continue;
+
+ /* First, ensure the minimum number of matches are present. We get back
+ the length of the reference string explicitly rather than passing the
+ address of eptr, so that eptr can be a register variable. */
+
+ for (i = 1; i <= min; i++)
+ {
+ if (!match_ref(offset, eptr, length, md, ims)) RRETURN(MATCH_NOMATCH);
+ eptr += length;
+ }
+
+ /* If min = max, continue at the same level without recursion.
+ They are not both allowed to be zero. */
+
+ if (min == max) continue;
+
+ /* If minimizing, keep trying and advancing the pointer */
+
+ if (minimize)
+ {
+ for (fi = min;; fi++)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (fi >= max || !match_ref(offset, eptr, length, md, ims))
+ RRETURN(MATCH_NOMATCH);
+ eptr += length;
+ }
+ /* Control never gets here */
+ }
+
+ /* If maximizing, find the longest string and work backwards */
+
+ else
+ {
+ pp = eptr;
+ for (i = min; i < max; i++)
+ {
+ if (!match_ref(offset, eptr, length, md, ims)) break;
+ eptr += length;
+ }
+ while (eptr >= pp)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ eptr -= length;
+ }
+ RRETURN(MATCH_NOMATCH);
+ }
+ }
+ /* Control never gets here */
+
+
+
+ /* Match a bit-mapped character class, possibly repeatedly. This op code is
+ used when all the characters in the class have values in the range 0-255.
+ The only difference between OP_CLASS and OP_NCLASS occurs when a data
+ character outside the range is encountered.
+
+ First, look past the end of the item to see if there is repeat information
+ following. Then obey similar code to character type repeats - written out
+ again for speed. */
+
+ case OP_NCLASS:
+ case OP_CLASS:
+ {
+ data = ecode + 1; /* Save for matching */
+ ecode += 33; /* Advance past the item */
+
+ switch (*ecode)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ c = *ecode++ - OP_CRSTAR;
+ minimize = (c & 1) != 0;
+ min = rep_min[c]; /* Pick up values from tables; */
+ max = rep_max[c]; /* zero for max => infinity */
+ if (max == 0) max = INT_MAX;
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ minimize = (*ecode == OP_CRMINRANGE);
+ min = GET2(ecode, 1);
+ max = GET2(ecode, 3);
+ if (max == 0) max = INT_MAX;
+ ecode += 5;
+ break;
+
+ default: /* No repeat follows */
+ min = max = 1;
+ break;
+ }
+
+ /* First, ensure the minimum number of matches are present. */
+
+#ifdef SUPPORT_UTF8
+ /* UTF-8 mode */
+ if (md->utf8)
+ {
+ for (i = 1; i <= min; i++)
+ {
+ if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+ GETCHARINC(c, eptr);
+ if (c > 255)
+ {
+ if (op == OP_CLASS) RRETURN(MATCH_NOMATCH);
+ }
+ else
+ {
+ if ((data[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH);
+ }
+ }
+ }
+ else
+#endif
+ /* Not UTF-8 mode */
+ {
+ for (i = 1; i <= min; i++)
+ {
+ if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+ c = *eptr++;
+ if ((data[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH);
+ }
+ }
+
+ /* If max == min we can continue with the main loop without the
+ need to recurse. */
+
+ if (min == max) continue;
+
+ /* If minimizing, keep testing the rest of the expression and advancing
+ the pointer while it matches the class. */
+
+ if (minimize)
+ {
+#ifdef SUPPORT_UTF8
+ /* UTF-8 mode */
+ if (md->utf8)
+ {
+ for (fi = min;; fi++)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+ GETCHARINC(c, eptr);
+ if (c > 255)
+ {
+ if (op == OP_CLASS) RRETURN(MATCH_NOMATCH);
+ }
+ else
+ {
+ if ((data[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH);
+ }
+ }
+ }
+ else
+#endif
+ /* Not UTF-8 mode */
+ {
+ for (fi = min;; fi++)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+ c = *eptr++;
+ if ((data[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH);
+ }
+ }
+ /* Control never gets here */
+ }
+
+ /* If maximizing, find the longest possible run, then work backwards. */
+
+ else
+ {
+ pp = eptr;
+
+#ifdef SUPPORT_UTF8
+ /* UTF-8 mode */
+ if (md->utf8)
+ {
+ for (i = min; i < max; i++)
+ {
+ int len = 1;
+ if (eptr >= md->end_subject) break;
+ GETCHARLEN(c, eptr, len);
+ if (c > 255)
+ {
+ if (op == OP_CLASS) break;
+ }
+ else
+ {
+ if ((data[c/8] & (1 << (c&7))) == 0) break;
+ }
+ eptr += len;
+ }
+ for (;;)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (eptr-- == pp) break; /* Stop if tried at original pos */
+ BACKCHAR(eptr);
+ }
+ }
+ else
+#endif
+ /* Not UTF-8 mode */
+ {
+ for (i = min; i < max; i++)
+ {
+ if (eptr >= md->end_subject) break;
+ c = *eptr;
+ if ((data[c/8] & (1 << (c&7))) == 0) break;
+ eptr++;
+ }
+ while (eptr >= pp)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ eptr--;
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ }
+ }
+
+ RRETURN(MATCH_NOMATCH);
+ }
+ }
+ /* Control never gets here */
+
+
+ /* Match an extended character class. This opcode is encountered only
+ in UTF-8 mode, because that's the only time it is compiled. */
+
+#ifdef SUPPORT_UTF8
+ case OP_XCLASS:
+ {
+ data = ecode + 1 + LINK_SIZE; /* Save for matching */
+ ecode += GET(ecode, 1); /* Advance past the item */
+
+ switch (*ecode)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ c = *ecode++ - OP_CRSTAR;
+ minimize = (c & 1) != 0;
+ min = rep_min[c]; /* Pick up values from tables; */
+ max = rep_max[c]; /* zero for max => infinity */
+ if (max == 0) max = INT_MAX;
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ minimize = (*ecode == OP_CRMINRANGE);
+ min = GET2(ecode, 1);
+ max = GET2(ecode, 3);
+ if (max == 0) max = INT_MAX;
+ ecode += 5;
+ break;
+
+ default: /* No repeat follows */
+ min = max = 1;
+ break;
+ }
+
+ /* First, ensure the minimum number of matches are present. */
+
+ for (i = 1; i <= min; i++)
+ {
+ if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+ GETCHARINC(c, eptr);
+ if (!match_xclass(c, data)) RRETURN(MATCH_NOMATCH);
+ }
+
+ /* If max == min we can continue with the main loop without the
+ need to recurse. */
+
+ if (min == max) continue;
+
+ /* If minimizing, keep testing the rest of the expression and advancing
+ the pointer while it matches the class. */
+
+ if (minimize)
+ {
+ for (fi = min;; fi++)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+ GETCHARINC(c, eptr);
+ if (!match_xclass(c, data)) RRETURN(MATCH_NOMATCH);
+ }
+ /* Control never gets here */
+ }
+
+ /* If maximizing, find the longest possible run, then work backwards. */
+
+ else
+ {
+ pp = eptr;
+ for (i = min; i < max; i++)
+ {
+ int len = 1;
+ if (eptr >= md->end_subject) break;
+ GETCHARLEN(c, eptr, len);
+ if (!match_xclass(c, data)) break;
+ eptr += len;
+ }
+ for(;;)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (eptr-- == pp) break; /* Stop if tried at original pos */
+ BACKCHAR(eptr)
+ }
+ RRETURN(MATCH_NOMATCH);
+ }
+
+ /* Control never gets here */
+ }
+#endif /* End of XCLASS */
+
+ /* Match a run of characters */
+
+ case OP_CHARS:
+ {
+ register int slen = ecode[1];
+ ecode += 2;
+
+#ifdef DEBUG /* Sigh. Some compilers never learn. */
+ if (eptr >= md->end_subject)
+ printf("matching subject <null> against pattern ");
+ else
+ {
+ printf("matching subject ");
+ pchars(eptr, slen, TRUE, md);
+ printf(" against pattern ");
+ }
+ pchars(ecode, slen, FALSE, md);
+ printf("\n");
+#endif
+
+ if (slen > md->end_subject - eptr) RRETURN(MATCH_NOMATCH);
+ if ((ims & PCRE_CASELESS) != 0)
+ {
+ while (slen-- > 0)
+ if (md->lcc[*ecode++] != md->lcc[*eptr++])
+ RRETURN(MATCH_NOMATCH);
+ }
+ else
+ {
+ while (slen-- > 0) if (*ecode++ != *eptr++) RRETURN(MATCH_NOMATCH);
+ }
+ }
+ break;
+
+ /* Match a single character repeatedly; different opcodes share code. */
+
+ case OP_EXACT:
+ min = max = GET2(ecode, 1);
+ ecode += 3;
+ goto REPEATCHAR;
+
+ case OP_UPTO:
+ case OP_MINUPTO:
+ min = 0;
+ max = GET2(ecode, 1);
+ minimize = *ecode == OP_MINUPTO;
+ ecode += 3;
+ goto REPEATCHAR;
+
+ case OP_STAR:
+ case OP_MINSTAR:
+ case OP_PLUS:
+ case OP_MINPLUS:
+ case OP_QUERY:
+ case OP_MINQUERY:
+ c = *ecode++ - OP_STAR;
+ minimize = (c & 1) != 0;
+ min = rep_min[c]; /* Pick up values from tables; */
+ max = rep_max[c]; /* zero for max => infinity */
+ if (max == 0) max = INT_MAX;
+
+ /* Common code for all repeated single-character matches. We can give
+ up quickly if there are fewer than the minimum number of characters left in
+ the subject. */
+
+ REPEATCHAR:
+#ifdef SUPPORT_UTF8
+ if (md->utf8)
+ {
+ length = 1;
+ charptr = ecode;
+ GETCHARLEN(fc, ecode, length);
+ if (min * length > md->end_subject - eptr) RRETURN(MATCH_NOMATCH);
+ ecode += length;
+
+ /* Handle multibyte character matching specially here. There is no
+ support for any kind of casing for multibyte characters. */
+
+ if (length > 1)
+ {
+ for (i = 1; i <= min; i++)
+ {
+ if (memcmp(eptr, charptr, length) != 0) RRETURN(MATCH_NOMATCH);
+ eptr += length;
+ }
+
+ if (min == max) continue;
+
+ if (minimize)
+ {
+ for (fi = min;; fi++)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (fi >= max ||
+ eptr >= md->end_subject ||
+ memcmp(eptr, charptr, length) != 0)
+ RRETURN(MATCH_NOMATCH);
+ eptr += length;
+ }
+ /* Control never gets here */
+ }
+ else
+ {
+ pp = eptr;
+ for (i = min; i < max; i++)
+ {
+ if (eptr > md->end_subject - length ||
+ memcmp(eptr, charptr, length) != 0)
+ break;
+ eptr += length;
+ }
+ while (eptr >= pp)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ eptr -= length;
+ }
+ RRETURN(MATCH_NOMATCH);
+ }
+ /* Control never gets here */
+ }
+
+ /* If the length of a UTF-8 character is 1, we fall through here, and
+ obey the code as for non-UTF-8 characters below, though in this case the
+ value of fc will always be < 128. */
+ }
+ else
+#endif
+
+ /* When not in UTF-8 mode, load a single-byte character. */
+ {
+ if (min > md->end_subject - eptr) RRETURN(MATCH_NOMATCH);
+ fc = *ecode++;
+ }
+
+ /* The value of fc at this point is always less than 256, though we may or
+ may not be in UTF-8 mode. The code is duplicated for the caseless and
+ caseful cases, for speed, since matching characters is likely to be quite
+ common. First, ensure the minimum number of matches are present. If min =
+ max, continue at the same level without recursing. Otherwise, if
+ minimizing, keep trying the rest of the expression and advancing one
+ matching character if failing, up to the maximum. Alternatively, if
+ maximizing, find the maximum number of characters and work backwards. */
+
+ DPRINTF(("matching %c{%d,%d} against subject %.*s\n", fc, min, max,
+ max, eptr));
+
+ if ((ims & PCRE_CASELESS) != 0)
+ {
+ fc = md->lcc[fc];
+ for (i = 1; i <= min; i++)
+ if (fc != md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH);
+ if (min == max) continue;
+ if (minimize)
+ {
+ for (fi = min;; fi++)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (fi >= max || eptr >= md->end_subject ||
+ fc != md->lcc[*eptr++])
+ RRETURN(MATCH_NOMATCH);
+ }
+ /* Control never gets here */
+ }
+ else
+ {
+ pp = eptr;
+ for (i = min; i < max; i++)
+ {
+ if (eptr >= md->end_subject || fc != md->lcc[*eptr]) break;
+ eptr++;
+ }
+ while (eptr >= pp)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ eptr--;
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ }
+ RRETURN(MATCH_NOMATCH);
+ }
+ /* Control never gets here */
+ }
+
+ /* Caseful comparisons (includes all multi-byte characters) */
+
+ else
+ {
+ for (i = 1; i <= min; i++) if (fc != *eptr++) RRETURN(MATCH_NOMATCH);
+ if (min == max) continue;
+ if (minimize)
+ {
+ for (fi = min;; fi++)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (fi >= max || eptr >= md->end_subject || fc != *eptr++)
+ RRETURN(MATCH_NOMATCH);
+ }
+ /* Control never gets here */
+ }
+ else
+ {
+ pp = eptr;
+ for (i = min; i < max; i++)
+ {
+ if (eptr >= md->end_subject || fc != *eptr) break;
+ eptr++;
+ }
+ while (eptr >= pp)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ eptr--;
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ }
+ RRETURN(MATCH_NOMATCH);
+ }
+ }
+ /* Control never gets here */
+
+ /* Match a negated single one-byte character. The character we are
+ checking can be multibyte. */
+
+ case OP_NOT:
+ if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+ ecode++;
+ GETCHARINCTEST(c, eptr);
+ if ((ims & PCRE_CASELESS) != 0)
+ {
+#ifdef SUPPORT_UTF8
+ if (c < 256)
+#endif
+ c = md->lcc[c];
+ if (md->lcc[*ecode++] == c) RRETURN(MATCH_NOMATCH);
+ }
+ else
+ {
+ if (*ecode++ == c) RRETURN(MATCH_NOMATCH);
+ }
+ break;
+
+ /* Match a negated single one-byte character repeatedly. This is almost a
+ repeat of the code for a repeated single character, but I haven't found a
+ nice way of commoning these up that doesn't require a test of the
+ positive/negative option for each character match. Maybe that wouldn't add
+ very much to the time taken, but character matching *is* what this is all
+ about... */
+
+ case OP_NOTEXACT:
+ min = max = GET2(ecode, 1);
+ ecode += 3;
+ goto REPEATNOTCHAR;
+
+ case OP_NOTUPTO:
+ case OP_NOTMINUPTO:
+ min = 0;
+ max = GET2(ecode, 1);
+ minimize = *ecode == OP_NOTMINUPTO;
+ ecode += 3;
+ goto REPEATNOTCHAR;
+
+ case OP_NOTSTAR:
+ case OP_NOTMINSTAR:
+ case OP_NOTPLUS:
+ case OP_NOTMINPLUS:
+ case OP_NOTQUERY:
+ case OP_NOTMINQUERY:
+ c = *ecode++ - OP_NOTSTAR;
+ minimize = (c & 1) != 0;
+ min = rep_min[c]; /* Pick up values from tables; */
+ max = rep_max[c]; /* zero for max => infinity */
+ if (max == 0) max = INT_MAX;
+
+ /* Common code for all repeated single-character (less than 255) matches.
+ We can give up quickly if there are fewer than the minimum number of
+ characters left in the subject. */
+
+ REPEATNOTCHAR:
+ if (min > md->end_subject - eptr) RRETURN(MATCH_NOMATCH);
+ fc = *ecode++;
+
+ /* The code is duplicated for the caseless and caseful cases, for speed,
+ since matching characters is likely to be quite common. First, ensure the
+ minimum number of matches are present. If min = max, continue at the same
+ level without recursing. Otherwise, if minimizing, keep trying the rest of
+ the expression and advancing one matching character if failing, up to the
+ maximum. Alternatively, if maximizing, find the maximum number of
+ characters and work backwards. */
+
+ DPRINTF(("negative matching %c{%d,%d} against subject %.*s\n", fc, min, max,
+ max, eptr));
+
+ if ((ims & PCRE_CASELESS) != 0)
+ {
+ fc = md->lcc[fc];
+
+#ifdef SUPPORT_UTF8
+ /* UTF-8 mode */
+ if (md->utf8)
+ {
+ register int d;
+ for (i = 1; i <= min; i++)
+ {
+ GETCHARINC(d, eptr);
+ if (d < 256) d = md->lcc[d];
+ if (fc == d) RRETURN(MATCH_NOMATCH);
+ }
+ }
+ else
+#endif
+
+ /* Not UTF-8 mode */
+ {
+ for (i = 1; i <= min; i++)
+ if (fc == md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH);
+ }
+
+ if (min == max) continue;
+
+ if (minimize)
+ {
+#ifdef SUPPORT_UTF8
+ /* UTF-8 mode */
+ if (md->utf8)
+ {
+ register int d;
+ for (fi = min;; fi++)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ GETCHARINC(d, eptr);
+ if (d < 256) d = md->lcc[d];
+ if (fi >= max || eptr >= md->end_subject || fc == d)
+ RRETURN(MATCH_NOMATCH);
+ }
+ }
+ else
+#endif
+ /* Not UTF-8 mode */
+ {
+ for (fi = min;; fi++)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (fi >= max || eptr >= md->end_subject || fc == md->lcc[*eptr++])
+ RRETURN(MATCH_NOMATCH);
+ }
+ }
+ /* Control never gets here */
+ }
+
+ /* Maximize case */
+
+ else
+ {
+ pp = eptr;
+
+#ifdef SUPPORT_UTF8
+ /* UTF-8 mode */
+ if (md->utf8)
+ {
+ register int d;
+ for (i = min; i < max; i++)
+ {
+ int len = 1;
+ if (eptr >= md->end_subject) break;
+ GETCHARLEN(d, eptr, len);
+ if (d < 256) d = md->lcc[d];
+ if (fc == d) break;
+ eptr += len;
+ }
+ for(;;)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (eptr-- == pp) break; /* Stop if tried at original pos */
+ BACKCHAR(eptr);
+ }
+ }
+ else
+#endif
+ /* Not UTF-8 mode */
+ {
+ for (i = min; i < max; i++)
+ {
+ if (eptr >= md->end_subject || fc == md->lcc[*eptr]) break;
+ eptr++;
+ }
+ while (eptr >= pp)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ eptr--;
+ }
+ }
+
+ RRETURN(MATCH_NOMATCH);
+ }
+ /* Control never gets here */
+ }
+
+ /* Caseful comparisons */
+
+ else
+ {
+#ifdef SUPPORT_UTF8
+ /* UTF-8 mode */
+ if (md->utf8)
+ {
+ register int d;
+ for (i = 1; i <= min; i++)
+ {
+ GETCHARINC(d, eptr);
+ if (fc == d) RRETURN(MATCH_NOMATCH);
+ }
+ }
+ else
+#endif
+ /* Not UTF-8 mode */
+ {
+ for (i = 1; i <= min; i++)
+ if (fc == *eptr++) RRETURN(MATCH_NOMATCH);
+ }
+
+ if (min == max) continue;
+
+ if (minimize)
+ {
+#ifdef SUPPORT_UTF8
+ /* UTF-8 mode */
+ if (md->utf8)
+ {
+ register int d;
+ for (fi = min;; fi++)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ GETCHARINC(d, eptr);
+ if (fi >= max || eptr >= md->end_subject || fc == d)
+ RRETURN(MATCH_NOMATCH);
+ }
+ }
+ else
+#endif
+ /* Not UTF-8 mode */
+ {
+ for (fi = min;; fi++)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (fi >= max || eptr >= md->end_subject || fc == *eptr++)
+ RRETURN(MATCH_NOMATCH);
+ }
+ }
+ /* Control never gets here */
+ }
+
+ /* Maximize case */
+
+ else
+ {
+ pp = eptr;
+
+#ifdef SUPPORT_UTF8
+ /* UTF-8 mode */
+ if (md->utf8)
+ {
+ register int d;
+ for (i = min; i < max; i++)
+ {
+ int len = 1;
+ if (eptr >= md->end_subject) break;
+ GETCHARLEN(d, eptr, len);
+ if (fc == d) break;
+ eptr += len;
+ }
+ for(;;)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (eptr-- == pp) break; /* Stop if tried at original pos */
+ BACKCHAR(eptr);
+ }
+ }
+ else
+#endif
+ /* Not UTF-8 mode */
+ {
+ for (i = min; i < max; i++)
+ {
+ if (eptr >= md->end_subject || fc == *eptr) break;
+ eptr++;
+ }
+ while (eptr >= pp)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ eptr--;
+ }
+ }
+
+ RRETURN(MATCH_NOMATCH);
+ }
+ }
+ /* Control never gets here */
+
+ /* Match a single character type repeatedly; several different opcodes
+ share code. This is very similar to the code for single characters, but we
+ repeat it in the interests of efficiency. */
+
+ case OP_TYPEEXACT:
+ min = max = GET2(ecode, 1);
+ minimize = TRUE;
+ ecode += 3;
+ goto REPEATTYPE;
+
+ case OP_TYPEUPTO:
+ case OP_TYPEMINUPTO:
+ min = 0;
+ max = GET2(ecode, 1);
+ minimize = *ecode == OP_TYPEMINUPTO;
+ ecode += 3;
+ goto REPEATTYPE;
+
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEQUERY:
+ case OP_TYPEMINQUERY:
+ c = *ecode++ - OP_TYPESTAR;
+ minimize = (c & 1) != 0;
+ min = rep_min[c]; /* Pick up values from tables; */
+ max = rep_max[c]; /* zero for max => infinity */
+ if (max == 0) max = INT_MAX;
+
+ /* Common code for all repeated single character type matches. Note that
+ in UTF-8 mode, '.' matches a character of any length, but for the other
+ character types, the valid characters are all one-byte long. */
+
+ REPEATTYPE:
+ ctype = *ecode++; /* Code for the character type */
+
+ /* First, ensure the minimum number of matches are present. Use inline
+ code for maximizing the speed, and do the type test once at the start
+ (i.e. keep it out of the loop). Also we can test that there are at least
+ the minimum number of bytes before we start. This isn't as effective in
+ UTF-8 mode, but it does no harm. Separate the UTF-8 code completely as that
+ is tidier. */
+
+ if (min > md->end_subject - eptr) RRETURN(MATCH_NOMATCH);
+ if (min > 0)
+ {
+#ifdef SUPPORT_UTF8
+ if (md->utf8) switch(ctype)
+ {
+ case OP_ANY:
+ for (i = 1; i <= min; i++)
+ {
+ if (eptr >= md->end_subject ||
+ (*eptr++ == NEWLINE && (ims & PCRE_DOTALL) == 0))
+ RRETURN(MATCH_NOMATCH);
+ while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
+ }
+ break;
+
+ case OP_ANYBYTE:
+ eptr += min;
+ break;
+
+ case OP_NOT_DIGIT:
+ for (i = 1; i <= min; i++)
+ {
+ if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+ GETCHARINC(c, eptr);
+ if (c < 256 && (md->ctypes[c] & ctype_digit) != 0)
+ RRETURN(MATCH_NOMATCH);
+ }
+ break;
+
+ case OP_DIGIT:
+ for (i = 1; i <= min; i++)
+ {
+ if (eptr >= md->end_subject ||
+ *eptr >= 128 || (md->ctypes[*eptr++] & ctype_digit) == 0)
+ RRETURN(MATCH_NOMATCH);
+ /* No need to skip more bytes - we know it's a 1-byte character */
+ }
+ break;
+
+ case OP_NOT_WHITESPACE:
+ for (i = 1; i <= min; i++)
+ {
+ if (eptr >= md->end_subject ||
+ (*eptr < 128 && (md->ctypes[*eptr++] & ctype_space) != 0))
+ RRETURN(MATCH_NOMATCH);
+ while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
+ }
+ break;
+
+ case OP_WHITESPACE:
+ for (i = 1; i <= min; i++)
+ {
+ if (eptr >= md->end_subject ||
+ *eptr >= 128 || (md->ctypes[*eptr++] & ctype_space) == 0)
+ RRETURN(MATCH_NOMATCH);
+ /* No need to skip more bytes - we know it's a 1-byte character */
+ }
+ break;
+
+ case OP_NOT_WORDCHAR:
+ for (i = 1; i <= min; i++)
+ {
+ if (eptr >= md->end_subject ||
+ (*eptr < 128 && (md->ctypes[*eptr++] & ctype_word) != 0))
+ RRETURN(MATCH_NOMATCH);
+ while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
+ }
+ break;
+
+ case OP_WORDCHAR:
+ for (i = 1; i <= min; i++)
+ {
+ if (eptr >= md->end_subject ||
+ *eptr >= 128 || (md->ctypes[*eptr++] & ctype_word) == 0)
+ RRETURN(MATCH_NOMATCH);
+ /* No need to skip more bytes - we know it's a 1-byte character */
+ }
+ break;
+ }
+ else
+#endif
+
+ /* Code for the non-UTF-8 case for minimum matching */
+
+ switch(ctype)
+ {
+ case OP_ANY:
+ if ((ims & PCRE_DOTALL) == 0)
+ {
+ for (i = 1; i <= min; i++)
+ if (*eptr++ == NEWLINE) RRETURN(MATCH_NOMATCH);
+ }
+ else eptr += min;
+ break;
+
+ case OP_ANYBYTE:
+ eptr += min;
+ break;
+
+ case OP_NOT_DIGIT:
+ for (i = 1; i <= min; i++)
+ if ((md->ctypes[*eptr++] & ctype_digit) != 0) RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_DIGIT:
+ for (i = 1; i <= min; i++)
+ if ((md->ctypes[*eptr++] & ctype_digit) == 0) RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_NOT_WHITESPACE:
+ for (i = 1; i <= min; i++)
+ if ((md->ctypes[*eptr++] & ctype_space) != 0) RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_WHITESPACE:
+ for (i = 1; i <= min; i++)
+ if ((md->ctypes[*eptr++] & ctype_space) == 0) RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_NOT_WORDCHAR:
+ for (i = 1; i <= min; i++)
+ if ((md->ctypes[*eptr++] & ctype_word) != 0)
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_WORDCHAR:
+ for (i = 1; i <= min; i++)
+ if ((md->ctypes[*eptr++] & ctype_word) == 0)
+ RRETURN(MATCH_NOMATCH);
+ break;
+ }
+ }
+
+ /* If min = max, continue at the same level without recursing */
+
+ if (min == max) continue;
+
+ /* If minimizing, we have to test the rest of the pattern before each
+ subsequent match. Again, separate the UTF-8 case for speed. */
+
+ if (minimize)
+ {
+#ifdef SUPPORT_UTF8
+ /* UTF-8 mode */
+ if (md->utf8)
+ {
+ for (fi = min;; fi++)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+
+ GETCHARINC(c, eptr);
+ switch(ctype)
+ {
+ case OP_ANY:
+ if ((ims & PCRE_DOTALL) == 0 && c == NEWLINE) RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_ANYBYTE:
+ break;
+
+ case OP_NOT_DIGIT:
+ if (c < 256 && (md->ctypes[c] & ctype_digit) != 0)
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_DIGIT:
+ if (c >= 256 || (md->ctypes[c] & ctype_digit) == 0)
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_NOT_WHITESPACE:
+ if (c < 256 && (md->ctypes[c] & ctype_space) != 0)
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_WHITESPACE:
+ if (c >= 256 || (md->ctypes[c] & ctype_space) == 0)
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_NOT_WORDCHAR:
+ if (c < 256 && (md->ctypes[c] & ctype_word) != 0)
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_WORDCHAR:
+ if (c >= 256 && (md->ctypes[c] & ctype_word) == 0)
+ RRETURN(MATCH_NOMATCH);
+ break;
+ }
+ }
+ }
+ else
+#endif
+ /* Not UTF-8 mode */
+ {
+ for (fi = min;; fi++)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+ c = *eptr++;
+ switch(ctype)
+ {
+ case OP_ANY:
+ if ((ims & PCRE_DOTALL) == 0 && c == NEWLINE) RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_ANYBYTE:
+ break;
+
+ case OP_NOT_DIGIT:
+ if ((md->ctypes[c] & ctype_digit) != 0) RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_DIGIT:
+ if ((md->ctypes[c] & ctype_digit) == 0) RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_NOT_WHITESPACE:
+ if ((md->ctypes[c] & ctype_space) != 0) RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_WHITESPACE:
+ if ((md->ctypes[c] & ctype_space) == 0) RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_NOT_WORDCHAR:
+ if ((md->ctypes[c] & ctype_word) != 0) RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_WORDCHAR:
+ if ((md->ctypes[c] & ctype_word) == 0) RRETURN(MATCH_NOMATCH);
+ break;
+ }
+ }
+ }
+ /* Control never gets here */
+ }
+
+ /* If maximizing it is worth using inline code for speed, doing the type
+ test once at the start (i.e. keep it out of the loop). Again, keep the
+ UTF-8 stuff separate. */
+
+ else
+ {
+ pp = eptr;
+
+#ifdef SUPPORT_UTF8
+ /* UTF-8 mode */
+
+ if (md->utf8)
+ {
+ switch(ctype)
+ {
+ case OP_ANY:
+
+ /* Special code is required for UTF8, but when the maximum is unlimited
+ we don't need it, so we repeat the non-UTF8 code. This is probably
+ worth it, because .* is quite a common idiom. */
+
+ if (max < INT_MAX)
+ {
+ if ((ims & PCRE_DOTALL) == 0)
+ {
+ for (i = min; i < max; i++)
+ {
+ if (eptr >= md->end_subject || *eptr == NEWLINE) break;
+ eptr++;
+ while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
+ }
+ }
+ else
+ {
+ for (i = min; i < max; i++)
+ {
+ eptr++;
+ while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
+ }
+ }
+ }
+
+ /* Handle unlimited UTF-8 repeat */
+
+ else
+ {
+ if ((ims & PCRE_DOTALL) == 0)
+ {
+ for (i = min; i < max; i++)
+ {
+ if (eptr >= md->end_subject || *eptr == NEWLINE) break;
+ eptr++;
+ }
+ break;
+ }
+ else
+ {
+ c = max - min;
+ if (c > md->end_subject - eptr) c = md->end_subject - eptr;
+ eptr += c;
+ }
+ }
+ break;
+
+ /* The byte case is the same as non-UTF8 */
+
+ case OP_ANYBYTE:
+ c = max - min;
+ if (c > md->end_subject - eptr) c = md->end_subject - eptr;
+ eptr += c;
+ break;
+
+ case OP_NOT_DIGIT:
+ for (i = min; i < max; i++)
+ {
+ int len = 1;
+ if (eptr >= md->end_subject) break;
+ GETCHARLEN(c, eptr, len);
+ if (c < 256 && (md->ctypes[c] & ctype_digit) != 0) break;
+ eptr+= len;
+ }
+ break;
+
+ case OP_DIGIT:
+ for (i = min; i < max; i++)
+ {
+ int len = 1;
+ if (eptr >= md->end_subject) break;
+ GETCHARLEN(c, eptr, len);
+ if (c >= 256 ||(md->ctypes[c] & ctype_digit) == 0) break;
+ eptr+= len;
+ }
+ break;
+
+ case OP_NOT_WHITESPACE:
+ for (i = min; i < max; i++)
+ {
+ int len = 1;
+ if (eptr >= md->end_subject) break;
+ GETCHARLEN(c, eptr, len);
+ if (c < 256 && (md->ctypes[c] & ctype_space) != 0) break;
+ eptr+= len;
+ }
+ break;
+
+ case OP_WHITESPACE:
+ for (i = min; i < max; i++)
+ {
+ int len = 1;
+ if (eptr >= md->end_subject) break;
+ GETCHARLEN(c, eptr, len);
+ if (c >= 256 ||(md->ctypes[c] & ctype_space) == 0) break;
+ eptr+= len;
+ }
+ break;
+
+ case OP_NOT_WORDCHAR:
+ for (i = min; i < max; i++)
+ {
+ int len = 1;
+ if (eptr >= md->end_subject) break;
+ GETCHARLEN(c, eptr, len);
+ if (c < 256 && (md->ctypes[c] & ctype_word) != 0) break;
+ eptr+= len;
+ }
+ break;
+
+ case OP_WORDCHAR:
+ for (i = min; i < max; i++)
+ {
+ int len = 1;
+ if (eptr >= md->end_subject) break;
+ GETCHARLEN(c, eptr, len);
+ if (c >= 256 || (md->ctypes[c] & ctype_word) == 0) break;
+ eptr+= len;
+ }
+ break;
+ }
+
+ /* eptr is now past the end of the maximum run */
+
+ for(;;)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (eptr-- == pp) break; /* Stop if tried at original pos */
+ BACKCHAR(eptr);
+ }
+ }
+ else
+#endif
+
+ /* Not UTF-8 mode */
+ {
+ switch(ctype)
+ {
+ case OP_ANY:
+ if ((ims & PCRE_DOTALL) == 0)
+ {
+ for (i = min; i < max; i++)
+ {
+ if (eptr >= md->end_subject || *eptr == NEWLINE) break;
+ eptr++;
+ }
+ break;
+ }
+ /* For DOTALL case, fall through and treat as \C */
+
+ case OP_ANYBYTE:
+ c = max - min;
+ if (c > md->end_subject - eptr) c = md->end_subject - eptr;
+ eptr += c;
+ break;
+
+ case OP_NOT_DIGIT:
+ for (i = min; i < max; i++)
+ {
+ if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) != 0)
+ break;
+ eptr++;
+ }
+ break;
+
+ case OP_DIGIT:
+ for (i = min; i < max; i++)
+ {
+ if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) == 0)
+ break;
+ eptr++;
+ }
+ break;
+
+ case OP_NOT_WHITESPACE:
+ for (i = min; i < max; i++)
+ {
+ if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) != 0)
+ break;
+ eptr++;
+ }
+ break;
+
+ case OP_WHITESPACE:
+ for (i = min; i < max; i++)
+ {
+ if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) == 0)
+ break;
+ eptr++;
+ }
+ break;
+
+ case OP_NOT_WORDCHAR:
+ for (i = min; i < max; i++)
+ {
+ if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) != 0)
+ break;
+ eptr++;
+ }
+ break;
+
+ case OP_WORDCHAR:
+ for (i = min; i < max; i++)
+ {
+ if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) == 0)
+ break;
+ eptr++;
+ }
+ break;
+ }
+
+ /* eptr is now past the end of the maximum run */
+
+ while (eptr >= pp)
+ {
+ RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+ eptr--;
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ }
+ }
+
+ /* Get here if we can't make it match with any permitted repetitions */
+
+ RRETURN(MATCH_NOMATCH);
+ }
+ /* Control never gets here */
+
+ /* There's been some horrible disaster. Since all codes > OP_BRA are
+ for capturing brackets, and there shouldn't be any gaps between 0 and
+ OP_BRA, arrival here can only mean there is something seriously wrong
+ in the code above or the OP_xxx definitions. */
+
+ default:
+ DPRINTF(("Unknown opcode %d\n", *ecode));
+ RRETURN(PCRE_ERROR_UNKNOWN_NODE);
+ }
+
+ /* Do not stick any code in here without much thought; it is assumed
+ that "continue" in the code above comes out to here to repeat the main
+ loop. */
+
+ } /* End of main loop */
+/* Control never reaches here */
+}
+
+
+/***************************************************************************
+****************************************************************************
+ RECURSION IN THE match() FUNCTION
+
+Undefine all the macros that were defined above to handle this. */
+
+#ifdef NO_RECURSE
+#undef eptr
+#undef ecode
+#undef offset_top
+#undef ims
+#undef eptrb
+#undef flags
+
+#undef callpat
+#undef charptr
+#undef data
+#undef lastptr
+#undef next
+#undef pp
+#undef prev
+#undef saved_eptr
+
+#undef new_recursive
+
+#undef cur_is_word
+#undef condition
+#undef minimize
+#undef prev_is_word
+
+#undef original_ims
+
+#undef ctype
+#undef length
+#undef max
+#undef min
+#undef number
+#undef offset
+#undef op
+#undef save_capture_last
+#undef save_offset1
+#undef save_offset2
+#undef save_offset3
+#undef stacksave
+
+#undef newptrb
+
+#endif
+
+/* These two are defined as macros in both cases */
+
+#undef fc
+#undef fi
+
+/***************************************************************************
+***************************************************************************/
+
+
+
+/*************************************************
+* Execute a Regular Expression *
+*************************************************/
+
+/* This function applies a compiled re to a subject string and picks out
+portions of the string if it matches. Two elements in the vector are set for
+each substring: the offsets to the start and end of the substring.
+
+Arguments:
+ external_re points to the compiled expression
+ extra_data points to extra data or is NULL
+ subject points to the subject string
+ length length of subject string (may contain binary zeros)
+ start_offset where to start in the subject string
+ options option bits
+ offsets points to a vector of ints to be filled in with offsets
+ offsetcount the number of elements in the vector
+
+Returns: > 0 => success; value is the number of elements filled in
+ = 0 => success, but offsets is not big enough
+ -1 => failed to match
+ < -1 => some kind of unexpected problem
+*/
+
+EXPORT int
+pcre_exec(const pcre *external_re, const pcre_extra *extra_data,
+ const char *subject, int length, int start_offset, int options, int *offsets,
+ int offsetcount)
+{
+int rc, resetcount, ocount;
+int first_byte = -1;
+int req_byte = -1;
+int req_byte2 = -1;
+unsigned long int ims = 0;
+BOOL using_temporary_offsets = FALSE;
+BOOL anchored;
+BOOL startline;
+BOOL first_byte_caseless = FALSE;
+BOOL req_byte_caseless = FALSE;
+match_data match_block;
+const uschar *start_bits = NULL;
+const uschar *start_match = (const uschar *)subject + start_offset;
+const uschar *end_subject;
+const uschar *req_byte_ptr = start_match - 1;
+const pcre_study_data *study;
+const real_pcre *re = (const real_pcre *)external_re;
+
+/* Plausibility checks */
+
+if ((options & ~PUBLIC_EXEC_OPTIONS) != 0) return PCRE_ERROR_BADOPTION;
+if (re == NULL || subject == NULL ||
+ (offsets == NULL && offsetcount > 0)) return PCRE_ERROR_NULL;
+
+/* Fish out the optional data from the extra_data structure, first setting
+the default values. */
+
+study = NULL;
+match_block.match_limit = MATCH_LIMIT;
+match_block.callout_data = NULL;
+
+if (extra_data != NULL)
+ {
+ register unsigned int flags = extra_data->flags;
+ if ((flags & PCRE_EXTRA_STUDY_DATA) != 0)
+ study = (const pcre_study_data *)extra_data->study_data;
+ if ((flags & PCRE_EXTRA_MATCH_LIMIT) != 0)
+ match_block.match_limit = extra_data->match_limit;
+ if ((flags & PCRE_EXTRA_CALLOUT_DATA) != 0)
+ match_block.callout_data = extra_data->callout_data;
+ }
+
+/* Now we have re supposedly pointing to the regex */
+
+if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC;
+
+anchored = ((re->options | options) & PCRE_ANCHORED) != 0;
+startline = (re->options & PCRE_STARTLINE) != 0;
+
+match_block.start_code =
+ (const uschar *)re + sizeof(real_pcre) + re->name_count * re->name_entry_size;
+match_block.start_subject = (const uschar *)subject;
+match_block.start_offset = start_offset;
+match_block.end_subject = match_block.start_subject + length;
+end_subject = match_block.end_subject;
+
+match_block.endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0;
+match_block.utf8 = (re->options & PCRE_UTF8) != 0;
+
+match_block.notbol = (options & PCRE_NOTBOL) != 0;
+match_block.noteol = (options & PCRE_NOTEOL) != 0;
+match_block.notempty = (options & PCRE_NOTEMPTY) != 0;
+
+match_block.recursive = NULL; /* No recursion at top level */
+
+match_block.lcc = re->tables + lcc_offset;
+match_block.ctypes = re->tables + ctypes_offset;
+
+/* Check a UTF-8 string if required. Unfortunately there's no way of passing
+back the character offset. */
+
+#ifdef SUPPORT_UTF8
+if (match_block.utf8 && (options & PCRE_NO_UTF8_CHECK) == 0)
+ {
+ if (valid_utf8((uschar *)subject, length) >= 0)
+ return PCRE_ERROR_BADUTF8;
+ if (start_offset > 0 && start_offset < length)
+ {
+ int tb = ((uschar *)subject)[start_offset];
+ if (tb > 127)
+ {
+ tb &= 0xc0;
+ if (tb != 0 && tb != 0xc0) return PCRE_ERROR_BADUTF8_OFFSET;
+ }
+ }
+ }
+#endif
+
+/* The ims options can vary during the matching as a result of the presence
+of (?ims) items in the pattern. They are kept in a local variable so that
+restoring at the exit of a group is easy. */
+
+ims = re->options & (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL);
+
+/* If the expression has got more back references than the offsets supplied can
+hold, we get a temporary bit of working store to use during the matching.
+Otherwise, we can use the vector supplied, rounding down its size to a multiple
+of 3. */
+
+ocount = offsetcount - (offsetcount % 3);
+
+if (re->top_backref > 0 && re->top_backref >= ocount/3)
+ {
+ ocount = re->top_backref * 3 + 3;
+ match_block.offset_vector = (int *)(pcre_malloc)(ocount * sizeof(int));
+ if (match_block.offset_vector == NULL) return PCRE_ERROR_NOMEMORY;
+ using_temporary_offsets = TRUE;
+ DPRINTF(("Got memory to hold back references\n"));
+ }
+else match_block.offset_vector = offsets;
+
+match_block.offset_end = ocount;
+match_block.offset_max = (2*ocount)/3;
+match_block.offset_overflow = FALSE;
+match_block.capture_last = -1;
+
+/* Compute the minimum number of offsets that we need to reset each time. Doing
+this makes a huge difference to execution time when there aren't many brackets
+in the pattern. */
+
+resetcount = 2 + re->top_bracket * 2;
+if (resetcount > offsetcount) resetcount = ocount;
+
+/* Reset the working variable associated with each extraction. These should
+never be used unless previously set, but they get saved and restored, and so we
+initialize them to avoid reading uninitialized locations. */
+
+if (match_block.offset_vector != NULL)
+ {
+ register int *iptr = match_block.offset_vector + ocount;
+ register int *iend = iptr - resetcount/2 + 1;
+ while (--iptr >= iend) *iptr = -1;
+ }
+
+/* Set up the first character to match, if available. The first_byte value is
+never set for an anchored regular expression, but the anchoring may be forced
+at run time, so we have to test for anchoring. The first char may be unset for
+an unanchored pattern, of course. If there's no first char and the pattern was
+studied, there may be a bitmap of possible first characters. */
+
+if (!anchored)
+ {
+ if ((re->options & PCRE_FIRSTSET) != 0)
+ {
+ first_byte = re->first_byte & 255;
+ if ((first_byte_caseless = ((re->first_byte & REQ_CASELESS) != 0)) == TRUE)
+ first_byte = match_block.lcc[first_byte];
+ }
+ else
+ if (!startline && study != NULL &&
+ (study->options & PCRE_STUDY_MAPPED) != 0)
+ start_bits = study->start_bits;
+ }
+
+/* For anchored or unanchored matches, there may be a "last known required
+character" set. */
+
+if ((re->options & PCRE_REQCHSET) != 0)
+ {
+ req_byte = re->req_byte & 255;
+ req_byte_caseless = (re->req_byte & REQ_CASELESS) != 0;
+ req_byte2 = (re->tables + fcc_offset)[req_byte]; /* case flipped */
+ }
+
+/* Loop for handling unanchored repeated matching attempts; for anchored regexs
+the loop runs just once. */
+
+do
+ {
+ register int *iptr = match_block.offset_vector;
+ register int *iend = iptr + resetcount;
+
+ /* Reset the maximum number of extractions we might see. */
+
+ while (iptr < iend) *iptr++ = -1;
+
+ /* Advance to a unique first char if possible */
+
+ if (first_byte >= 0)
+ {
+ if (first_byte_caseless)
+ while (start_match < end_subject &&
+ match_block.lcc[*start_match] != first_byte)
+ start_match++;
+ else
+ while (start_match < end_subject && *start_match != first_byte)
+ start_match++;
+ }
+
+ /* Or to just after \n for a multiline match if possible */
+
+ else if (startline)
+ {
+ if (start_match > match_block.start_subject + start_offset)
+ {
+ while (start_match < end_subject && start_match[-1] != NEWLINE)
+ start_match++;
+ }
+ }
+
+ /* Or to a non-unique first char after study */
+
+ else if (start_bits != NULL)
+ {
+ while (start_match < end_subject)
+ {
+ register int c = *start_match;
+ if ((start_bits[c/8] & (1 << (c&7))) == 0) start_match++; else break;
+ }
+ }
+
+#ifdef DEBUG /* Sigh. Some compilers never learn. */
+ printf(">>>> Match against: ");
+ pchars(start_match, end_subject - start_match, TRUE, &match_block);
+ printf("\n");
+#endif
+
+ /* If req_byte is set, we know that that character must appear in the subject
+ for the match to succeed. If the first character is set, req_byte must be
+ later in the subject; otherwise the test starts at the match point. This
+ optimization can save a huge amount of backtracking in patterns with nested
+ unlimited repeats that aren't going to match. Writing separate code for
+ cased/caseless versions makes it go faster, as does using an autoincrement
+ and backing off on a match.
+
+ HOWEVER: when the subject string is very, very long, searching to its end can
+ take a long time, and give bad performance on quite ordinary patterns. This
+ showed up when somebody was matching /^C/ on a 32-megabyte string... so we
+ don't do this when the string is sufficiently long. */
+
+ if (req_byte >= 0 && end_subject - start_match < REQ_BYTE_MAX)
+ {
+ register const uschar *p = start_match + ((first_byte >= 0)? 1 : 0);
+
+ /* We don't need to repeat the search if we haven't yet reached the
+ place we found it at last time. */
+
+ if (p > req_byte_ptr)
+ {
+ if (req_byte_caseless)
+ {
+ while (p < end_subject)
+ {
+ register int pp = *p++;
+ if (pp == req_byte || pp == req_byte2) { p--; break; }
+ }
+ }
+ else
+ {
+ while (p < end_subject)
+ {
+ if (*p++ == req_byte) { p--; break; }
+ }
+ }
+
+ /* If we can't find the required character, break the matching loop */
+
+ if (p >= end_subject) break;
+
+ /* If we have found the required character, save the point where we
+ found it, so that we don't search again next time round the loop if
+ the start hasn't passed this character yet. */
+
+ req_byte_ptr = p;
+ }
+ }
+
+ /* When a match occurs, substrings will be set for all internal extractions;
+ we just need to set up the whole thing as substring 0 before returning. If
+ there were too many extractions, set the return code to zero. In the case
+ where we had to get some local store to hold offsets for backreferences, copy
+ those back references that we can. In this case there need not be overflow
+ if certain parts of the pattern were not used. */
+
+ match_block.start_match = start_match;
+ match_block.match_call_count = 0;
+
+ rc = match(start_match, match_block.start_code, 2, &match_block, ims, NULL,
+ match_isgroup);
+
+ if (rc == MATCH_NOMATCH)
+ {
+ start_match++;
+#ifdef SUPPORT_UTF8
+ if (match_block.utf8)
+ while((*start_match & 0xc0) == 0x80) start_match++;
+#endif
+ continue;
+ }
+
+ if (rc != MATCH_MATCH)
+ {
+ DPRINTF((">>>> error: returning %d\n", rc));
+ return rc;
+ }
+
+ /* We have a match! Copy the offset information from temporary store if
+ necessary */
+
+ if (using_temporary_offsets)
+ {
+ if (offsetcount >= 4)
+ {
+ memcpy(offsets + 2, match_block.offset_vector + 2,
+ (offsetcount - 2) * sizeof(int));
+ DPRINTF(("Copied offsets from temporary memory\n"));
+ }
+ if (match_block.end_offset_top > offsetcount)
+ match_block.offset_overflow = TRUE;
+
+ DPRINTF(("Freeing temporary memory\n"));
+ (pcre_free)(match_block.offset_vector);
+ }
+
+ rc = match_block.offset_overflow? 0 : match_block.end_offset_top/2;
+
+ if (offsetcount < 2) rc = 0; else
+ {
+ offsets[0] = start_match - match_block.start_subject;
+ offsets[1] = match_block.end_match_ptr - match_block.start_subject;
+ }
+
+ DPRINTF((">>>> returning %d\n", rc));
+ return rc;
+ }
+
+/* This "while" is the end of the "do" above */
+
+while (!anchored && start_match <= end_subject);
+
+if (using_temporary_offsets)
+ {
+ DPRINTF(("Freeing temporary memory\n"));
+ (pcre_free)(match_block.offset_vector);
+ }
+
+DPRINTF((">>>> returning PCRE_ERROR_NOMATCH\n"));
+
+return PCRE_ERROR_NOMATCH;
+}
+
+/* End of pcre.c */
--- /dev/null
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* This file is automatically written by the dftables auxiliary
+program. If you edit it by hand, you might like to edit the Makefile to
+prevent its ever being regenerated.
+
+This file is #included in the compilation of pcre.c to build the default
+character tables which are used when no tables are passed to the compile
+function. */
+
+static unsigned char pcre_default_tables[] = {
+
+/* This table is a lower casing table. */
+
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 97, 98, 99,100,101,102,103,
+ 104,105,106,107,108,109,110,111,
+ 112,113,114,115,116,117,118,119,
+ 120,121,122, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99,100,101,102,103,
+ 104,105,106,107,108,109,110,111,
+ 112,113,114,115,116,117,118,119,
+ 120,121,122,123,124,125,126,127,
+ 128,129,130,131,132,133,134,135,
+ 136,137,138,139,140,141,142,143,
+ 144,145,146,147,148,149,150,151,
+ 152,153,154,155,156,157,158,159,
+ 160,161,162,163,164,165,166,167,
+ 168,169,170,171,172,173,174,175,
+ 176,177,178,179,180,181,182,183,
+ 184,185,186,187,188,189,190,191,
+ 192,193,194,195,196,197,198,199,
+ 200,201,202,203,204,205,206,207,
+ 208,209,210,211,212,213,214,215,
+ 216,217,218,219,220,221,222,223,
+ 224,225,226,227,228,229,230,231,
+ 232,233,234,235,236,237,238,239,
+ 240,241,242,243,244,245,246,247,
+ 248,249,250,251,252,253,254,255,
+
+/* This table is a case flipping table. */
+
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 97, 98, 99,100,101,102,103,
+ 104,105,106,107,108,109,110,111,
+ 112,113,114,115,116,117,118,119,
+ 120,121,122, 91, 92, 93, 94, 95,
+ 96, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90,123,124,125,126,127,
+ 128,129,130,131,132,133,134,135,
+ 136,137,138,139,140,141,142,143,
+ 144,145,146,147,148,149,150,151,
+ 152,153,154,155,156,157,158,159,
+ 160,161,162,163,164,165,166,167,
+ 168,169,170,171,172,173,174,175,
+ 176,177,178,179,180,181,182,183,
+ 184,185,186,187,188,189,190,191,
+ 192,193,194,195,196,197,198,199,
+ 200,201,202,203,204,205,206,207,
+ 208,209,210,211,212,213,214,215,
+ 216,217,218,219,220,221,222,223,
+ 224,225,226,227,228,229,230,231,
+ 232,233,234,235,236,237,238,239,
+ 240,241,242,243,244,245,246,247,
+ 248,249,250,251,252,253,254,255,
+
+/* This table contains bit maps for various character classes.
+Each map is 32 bytes long and the bits run from the least
+significant end of each byte. The classes that have their own
+maps are: space, xdigit, digit, upper, lower, word, graph
+print, punct, and cntrl. Other classes are built from combinations. */
+
+ 0x00,0x3e,0x00,0x00,0x01,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
+ 0x7e,0x00,0x00,0x00,0x7e,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xfe,0xff,0xff,0x07,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0x07,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
+ 0xfe,0xff,0xff,0x87,0xfe,0xff,0xff,0x07,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0xfe,0xff,0x00,0xfc,
+ 0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x78,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+/* This table identifies various classes of character by individual bits:
+ 0x01 white space character
+ 0x02 letter
+ 0x04 decimal digit
+ 0x08 hexadecimal digit
+ 0x10 alphanumeric or '_'
+ 0x80 regular expression metacharacter or binary zero
+*/
+
+ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */
+ 0x00,0x01,0x01,0x00,0x01,0x01,0x00,0x00, /* 8- 15 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */
+ 0x01,0x00,0x00,0x00,0x80,0x00,0x00,0x00, /* - ' */
+ 0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x00, /* ( - / */
+ 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /* 0 - 7 */
+ 0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x80, /* 8 - ? */
+ 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* @ - G */
+ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* H - O */
+ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* P - W */
+ 0x12,0x12,0x12,0x80,0x00,0x00,0x80,0x10, /* X - _ */
+ 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* ` - g */
+ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* h - o */
+ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* p - w */
+ 0x12,0x12,0x12,0x80,0x80,0x00,0x00,0x00, /* x -127 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */
+
+/* End of chartables.c */
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/rc4.c
+ * Copyright (C) 2000 Lucas Madar
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: rc4.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Transparent rc4 implementation
+ * Based upon sample in crypto++ library,
+ * which was based upon an anonymous usenet posting.
+ * Implemented by Lucas Madar <lucas@dal.net>
+ *
+ * Remember that it is IMPERITAVE to generate a new key
+ * for each state. DO NOT USE THE SAME KEY FOR ANY TWO STATES.
+ */
+
+typedef unsigned char RC4BYTE;
+typedef unsigned int RC4DWORD;
+
+struct rc4_state
+{
+ RC4BYTE mstate[256];
+ RC4BYTE x;
+ RC4BYTE y;
+};
+
+void *rc4_initstate(unsigned char *key, int keylen)
+{
+ RC4DWORD i;
+ RC4BYTE tmp, idx1, idx2;
+ struct rc4_state *rc4;
+
+ if(sizeof(RC4BYTE) != 1) abort(); /* MUST BE 1 BYTE! */
+ if(sizeof(RC4DWORD) != 4) abort(); /* MUST BE 4 BYTES! */
+
+ rc4 = (struct rc4_state *) malloc(sizeof(struct rc4_state));
+ memset(rc4, 0, sizeof(struct rc4_state));
+
+ for(i = 0; i < 256; i++) /* initialize our state array */
+ rc4->mstate[i] = (RC4BYTE) i;
+
+ for(i = 0, idx1 = idx2 = 0; i < 256; i++)
+ {
+ idx2 = (key[idx1++] + rc4->mstate[i] + idx2);
+
+ tmp = rc4->mstate[i];
+ rc4->mstate[i] = rc4->mstate[idx2];
+ rc4->mstate[idx2] = tmp;
+
+ if(idx1 >= keylen)
+ idx1 = 0;
+ }
+
+ return (void *) rc4;
+}
+
+void rc4_process_stream(void *rc4_context, unsigned char *istring,
+ unsigned int stringlen)
+{
+ struct rc4_state *rc4 = (struct rc4_state *) rc4_context;
+ RC4BYTE *s = rc4->mstate;
+ RC4DWORD x = rc4->x, y = rc4->y;
+
+ while(stringlen--)
+ {
+ RC4DWORD a, b;
+
+ x = (x+1) & 0xFF;
+ a = s[x];
+ y = (y+a) & 0xFF;
+ b = s[y];
+ s[x] = b;
+ s[y] = a;
+ *istring++ ^= s[(a + b) & 0xFF];
+ }
+
+ rc4->x = (RC4BYTE) x;
+ rc4->y = (RC4BYTE) y;
+}
+
+void rc4_process_stream_to_buf(void *rc4_context,
+ const unsigned char *istring,
+ unsigned char *ostring, unsigned int stringlen)
+{
+ struct rc4_state *rc4 = (struct rc4_state *) rc4_context;
+ RC4BYTE *s = rc4->mstate;
+ RC4DWORD x = rc4->x, y = rc4->y;
+
+ while(stringlen--)
+ {
+ RC4DWORD a, b;
+
+ x = (x+1) & 0xFF;
+ a = s[x];
+ y = (y+a) & 0xFF;
+ b = s[y];
+ s[x] = b;
+ s[y] = a;
+ *ostring++ = *istring++ ^ s[(a + b) & 0xFF];
+ }
+
+ rc4->x = (RC4BYTE) x;
+ rc4->y = (RC4BYTE) y;
+}
+
+void rc4_destroystate(void *a)
+{
+ memset(a, 0, sizeof(struct rc4_state));
+ free(a);
+}
--- /dev/null
+/*
+ * src/res.c (C)opyright 1992 Darren Reed. All rights reserved. This
+ * file may not be distributed without the author's permission in any
+ * shape or form. The author takes no responsibility for any damage or
+ * loss of property which results from the use of this software.
+ */
+
+/* $Id: res.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "res.h"
+#include "numeric.h"
+#include "h.h"
+#include "fds.h"
+
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include "nameser.h"
+#include "resolv.h"
+#include "inet.h"
+
+/* ALLOW_CACHE_NAMES
+ *
+ * If enabled, this allows our resolver code to keep a hash table
+ * of names, for which we find in gethost_byname calls.
+ * This presents a few problems with anti-spoofing code.
+ *
+ * Since the majority of our host lookups are reverse, having
+ * a cached record for reverse records (addresses) seems useful.
+ * If, for some reason, you want this on, you may define it.
+ */
+#undef ALLOW_CACHE_NAMES
+
+/* SEARCH_CACHE_ADDRESSES
+ *
+ * All of our records will probably only have one valid IP address.
+ * If you want to search for multiple addresses, define this.
+ * (In the current implementation, it should not really be possible
+ * to get multiple addresses.)
+ *
+ * If not, it saves CPU as a cache miss does not traverse the
+ * entire cache tree for a result.
+ */
+#undef SEARCH_CACHE_ADDRESSES
+
+#define PROCANSWER_STRANGE -2 /* invalid answer or query, try again */
+#define PROCANSWER_MALICIOUS -3 /* obviously malicious reply,
+ * don't do DNS on this ip. */
+
+#undef DEBUG /* because theres alot of debug code in here */
+
+extern int dn_expand(char *, char *, char *, char *, int);
+extern int dn_skipname(char *, char *);
+extern int
+res_mkquery(int, char *, int, int, char *, int,
+ struct rrec *, char *, int);
+
+#ifndef AIX
+extern int errno, h_errno;
+#endif
+extern int highest_fd;
+extern aClient *local[];
+
+static char hostbuf[HOSTLEN + 1];
+static int incache = 0;
+static CacheTable hashtable[ARES_CACSIZE];
+static ResHash idcphashtable[ARES_IDCACSIZE];
+aCache *cachetop = NULL;
+static ResRQ *last, *first;
+
+static void rem_cache(aCache *);
+static void rem_request(ResRQ *);
+static int do_query_name(Link *, char *, ResRQ *);
+static int do_query_number(Link *, struct in_addr *, ResRQ *);
+static void resend_query(ResRQ *);
+static int proc_answer(ResRQ *, HEADER *, char *, char *);
+static int query_name(char *, int, int, ResRQ *);
+static aCache *make_cache(ResRQ *);
+static aCache *find_cache_name(char *);
+static aCache *find_cache_number(ResRQ *, char *);
+static int add_request(ResRQ *);
+static ResRQ *make_request(Link *);
+static int send_res_msg(char *, int, int);
+static ResRQ *find_id(int);
+static int hash_number(unsigned char *);
+static unsigned int hash_id(unsigned int);
+static unsigned int hash_cp(char *);
+static void update_list(ResRQ *, aCache *);
+#ifdef ALLOW_CACHE_NAMES
+static int hash_name(char *);
+#endif
+static struct hostent *getres_err(ResRQ *, char *);
+
+static struct cacheinfo
+{
+ int ca_adds;
+ int ca_dels;
+ int ca_expires;
+ int ca_lookups;
+ int ca_na_hits;
+ int ca_nu_hits;
+ int ca_updates;
+} cainfo;
+
+static struct resinfo
+{
+ int re_errors;
+ int re_nu_look;
+ int re_na_look;
+ int re_replies;
+ int re_requests;
+ int re_resends;
+ int re_sent;
+ int re_timeouts;
+ int re_shortttl;
+ int re_unkrep;
+} reinfo;
+
+int init_resolver(int op)
+{
+ int ret = 0;
+
+#ifdef LRAND48
+ srand48(timeofday);
+#endif
+ if (op & RES_INITLIST)
+ {
+ memset((char *) &reinfo, '\0', sizeof(reinfo));
+ first = last = NULL;
+ }
+ if (op & RES_CALLINIT)
+ {
+ ret = res_init();
+ if (!_res.nscount)
+ {
+ _res.nscount = 1;
+ _res.nsaddr_list[0].sin_addr.s_addr = inet_addr("127.0.0.1");
+ }
+ }
+
+ if (op & RES_INITSOCK)
+ {
+ int on = 0;
+
+ ret = resfd = socket(AF_INET, SOCK_DGRAM, 0);
+ (void) setsockopt(ret, SOL_SOCKET, SO_BROADCAST,
+ (char *) &on, sizeof(on));
+ }
+#ifdef DEBUG
+ if (op & RES_INITDEBG);
+ _res.options |= RES_DEBUG;
+#endif
+ if (op & RES_INITCACH)
+ {
+ memset((char *) &cainfo, '\0', sizeof(cainfo));
+ memset((char *) hashtable, '\0', sizeof(hashtable));
+ memset((char *) idcphashtable, '\0', sizeof(idcphashtable));
+ }
+ if (op == 0)
+ ret = resfd;
+ return ret;
+}
+
+static int add_request(ResRQ * new)
+{
+ if (!new)
+ return -1;
+ if (!first)
+ first = last = new;
+ else {
+ last->next = new;
+ last = new;
+ }
+ new->next = NULL;
+ reinfo.re_requests++;
+ return 0;
+}
+
+static void rem_request_id(ResRQ *req)
+{
+ unsigned int hv = hash_id(req->id);
+ ResRQ *rptr, *r2ptr = NULL;
+
+ for(rptr = idcphashtable[hv].id_list; rptr; r2ptr = rptr, rptr = rptr->id_hashnext)
+ {
+ if(rptr != req)
+ continue;
+
+ if(r2ptr != NULL)
+ r2ptr->id_hashnext = req->id_hashnext;
+ else
+ idcphashtable[hv].id_list = req->id_hashnext;
+ break;
+ }
+}
+
+static void add_request_id(ResRQ *req)
+{
+ unsigned int hv = hash_id(req->id);
+
+ req->id_hashnext = idcphashtable[hv].id_list;
+ idcphashtable[hv].id_list = req;
+}
+
+static ResRQ *find_request_id(int id)
+{
+ unsigned int hv = hash_id(id);
+ ResRQ *res = idcphashtable[hv].id_list;
+
+ while(res)
+ {
+ if(res->id == id)
+ return res;
+ res = res->id_hashnext;
+ }
+ return NULL;
+}
+
+static void rem_request_cp(ResRQ *req)
+{
+ unsigned int hv = hash_cp(req->cinfo.value.cp);
+ ResRQ *rptr, *r2ptr = NULL;
+
+ for(rptr = idcphashtable[hv].cp_list; rptr; r2ptr = rptr, rptr = rptr->cp_hashnext)
+ {
+ if(rptr != req)
+ continue;
+
+ if(r2ptr != NULL)
+ r2ptr->cp_hashnext = req->cp_hashnext;
+ else
+ idcphashtable[hv].cp_list = req->cp_hashnext;
+ break;
+ }
+}
+
+static void add_request_cp(ResRQ *req)
+{
+ unsigned int hv = hash_cp(req->cinfo.value.cp);
+
+ req->cp_hashnext = idcphashtable[hv].cp_list;
+ idcphashtable[hv].cp_list = req;
+}
+
+static ResRQ *find_request_cp(char *cp)
+{
+ unsigned int hv = hash_cp(cp);
+ ResRQ *res = idcphashtable[hv].cp_list;
+
+ while(res)
+ {
+ if(res->cinfo.value.cp == cp)
+ return res;
+ res = res->cp_hashnext;
+ }
+ return NULL;
+}
+
+/*
+ * remove a request from the list. This must also free any memory that
+ * has been allocated for temporary storage of DNS results.
+ */
+static void rem_request(ResRQ * old)
+{
+ ResRQ **rptr, *r2ptr = NULL;
+ int i;
+ char *s;
+
+ if (!old)
+ return;
+
+ if(old->id != -1)
+ {
+ rem_request_id(old);
+ old->id = -1;
+ }
+
+ if(old->cinfo.value.cp != NULL)
+ rem_request_cp(old);
+
+ for (rptr = &first; *rptr; r2ptr = *rptr, rptr = &(*rptr)->next)
+ if (*rptr == old)
+ {
+ *rptr = old->next;
+ if (last == old)
+ last = r2ptr;
+ break;
+ }
+#ifdef DEBUG
+ Debug((DEBUG_INFO, "rem_request:Remove %#x at %#x %#x",
+ old, *rptr, r2ptr));
+#endif
+ r2ptr = old;
+
+ if (r2ptr->he.h_name)
+ MyFree(r2ptr->he.h_name);
+ for (i = 0; i < IRC_MAXALIASES; i++)
+ if ((s = r2ptr->he.h_aliases[i]))
+ MyFree(s);
+
+ if (r2ptr->he_rev.h_name)
+ MyFree(r2ptr->he_rev.h_name);
+ for (i = 0; i < IRC_MAXALIASES; i++)
+ if ((s = r2ptr->he_rev.h_aliases[i]))
+ MyFree(s);
+
+ if (r2ptr->name)
+ MyFree(r2ptr->name);
+ MyFree(r2ptr);
+
+ return;
+}
+
+/* Create a DNS request record for the server. */
+static ResRQ *make_request(Link *lp)
+{
+ ResRQ *nreq;
+
+ nreq = (ResRQ *) MyMalloc(sizeof(ResRQ));
+ memset((char *) nreq, '\0', sizeof(ResRQ));
+ nreq->next = NULL; /* where NULL is non-zero */
+ nreq->sentat = timeofday;
+ nreq->retries = 3;
+ nreq->resend = 1;
+ nreq->srch = -1;
+ nreq->id = -1;
+ if (lp)
+ {
+ memcpy((char *) &nreq->cinfo, (char *) lp, sizeof(Link));
+ add_request_cp(nreq);
+ }
+ else
+ memset((char *) &nreq->cinfo, '\0', sizeof(Link));
+
+ nreq->timeout = 4; /* start at 4 and exponential inc. */
+ nreq->he.h_addrtype = AF_INET;
+ nreq->he.h_name = NULL;
+ nreq->he.h_aliases[0] = NULL;
+ (void) add_request(nreq);
+ return nreq;
+}
+
+/*
+ * Remove queries from the list which have been there too long without
+ * being resolved.
+ */
+time_t timeout_query_list(time_t now)
+{
+ ResRQ *rptr, *r2ptr;
+ time_t next = 0, tout;
+ aClient *cptr;
+
+ Debug((DEBUG_DNS, "timeout_query_list at %s", myctime(now)));
+ for (rptr = first; rptr; rptr = r2ptr)
+ {
+ r2ptr = rptr->next;
+ tout = rptr->sentat + rptr->timeout;
+ if (now >= tout)
+ {
+ if (--rptr->retries <= 0)
+ {
+#ifdef DEBUG
+ Debug((DEBUG_ERROR, "timeout %x now %d cptr %x",
+ rptr, now, rptr->cinfo.value.cptr));
+#endif
+ reinfo.re_timeouts++;
+ cptr = rptr->cinfo.value.cptr;
+ switch (rptr->cinfo.flags)
+ {
+ case ASYNC_CLIENT:
+#ifdef SHOW_HEADERS
+ sendto_one(cptr, REPORT_FAIL_DNS);
+#endif
+ ClearDNS(cptr);
+ check_client_fd(cptr);
+ break;
+
+ case ASYNC_CONNECT:
+ sendto_ops("Host %s unknown",
+ rptr->name);
+ break;
+ }
+ rem_request(rptr);
+ continue;
+ }
+ else
+ {
+ rptr->sentat = now;
+ rptr->timeout += rptr->timeout;
+ resend_query(rptr);
+#ifdef DEBUG
+ Debug((DEBUG_INFO, "r %x now %d retry %d c %x",
+ rptr, now, rptr->retries,
+ rptr->cinfo.value.cptr));
+#endif
+ }
+ }
+ if (!next || tout < next)
+ next = tout;
+ }
+ return (next > now) ? next : (now + AR_TTL);
+}
+
+/*
+ * del_queries - called by the server to cleanup outstanding queries
+ * for which there no longer exist clients or conf lines.
+ */
+void del_queries(char *cp)
+{
+ ResRQ *ret = find_request_cp(cp);
+
+ if(ret)
+ rem_request(ret);
+}
+
+/*
+ * sends msg to all nameservers found in the "_res" structure. This
+ * should reflect /etc/resolv.conf. We will get responses which arent
+ * needed but is easier than checking to see if nameserver isnt
+ * present. Returns number of messages successfully sent to nameservers
+ * or -1 if no successful sends.
+ */
+static int send_res_msg(char *msg, int len, int rcount)
+{
+ int i;
+ int sent = 0, max;
+
+ if (!msg)
+ return -1;
+
+ max = MIN(_res.nscount, rcount);
+ if (_res.options & RES_PRIMARY)
+ max = 1;
+ if (!max)
+ max = 1;
+
+ for (i = 0; i < max; i++)
+ {
+ _res.nsaddr_list[i].sin_family = AF_INET;
+ if (sendto(resfd, msg, len, 0,
+ (struct sockaddr *) &(_res.nsaddr_list[i]),
+ sizeof(struct sockaddr)) == len)
+ {
+ reinfo.re_sent++;
+ sent++;
+ }
+ else
+ Debug((DEBUG_ERROR, "s_r_m:sendto: %d on %d",
+ errno, resfd));
+ }
+
+ return (sent) ? sent : -1;
+}
+
+/* find a dns request id (id is determined by dn_mkquery) */
+static ResRQ *find_id(int id)
+{
+ ResRQ *ret = find_request_id(id);
+
+ return ret;
+}
+
+struct hostent *gethost_byname(char *name, Link *lp)
+{
+ aCache *cp;
+
+ if (name == (char *) NULL)
+ return ((struct hostent *) NULL);
+
+ reinfo.re_na_look++;
+ if ((cp = find_cache_name(name)))
+ return (struct hostent *) &(cp->he);
+ if (!lp)
+ return NULL;
+ (void) do_query_name(lp, name, NULL);
+ return ((struct hostent *) NULL);
+}
+
+struct hostent *gethost_byaddr(char *addr, Link *lp)
+{
+ aCache *cp;
+
+ if (addr == (char *) NULL)
+ return ((struct hostent *) NULL);
+
+ reinfo.re_nu_look++;
+ if ((cp = find_cache_number(NULL, addr)))
+ return (struct hostent *) &(cp->he);
+ if (!lp)
+ return NULL;
+ (void) do_query_number(lp, (struct in_addr *) addr, NULL);
+ return ((struct hostent *) NULL);
+}
+
+static int do_query_name(Link *lp, char *name, ResRQ * rptr)
+{
+ char hname[HOSTLEN + 1];
+ int len;
+
+ strncpyzt(hname, name, HOSTLEN);
+ len = strlen(hname);
+
+ if (rptr && !strchr(hname, '.') && _res.options & RES_DEFNAMES)
+ {
+ if ((sizeof(hname) - len - 1) >= 2)
+ {
+ (void) strncat(hname, ".", sizeof(hname) - len - 1);
+ len++;
+ if ((sizeof(hname) - len - 1) >= 1)
+ (void) strncat(hname, _res.defdname, sizeof(hname) - len - 1);
+ }
+ }
+ /*
+ * Store the name passed as the one to lookup and generate other
+ * host names to pass onto the nameserver(s) for lookups.
+ */
+ if (!rptr)
+ {
+ rptr = make_request(lp);
+ rptr->type = T_A;
+ rptr->name = (char *) MyMalloc(strlen(name) + 1);
+ (void) strcpy(rptr->name, name);
+ }
+ return (query_name(hname, C_IN, T_A, rptr));
+}
+
+/* Use this to do reverse IP# lookups. */
+static int do_query_number(Link *lp, struct in_addr *numb, ResRQ * rptr)
+{
+ char ipbuf[32];
+ u_char *cp;
+
+ cp = (u_char *) &numb->s_addr;
+ (void) ircsprintf(ipbuf, "%u.%u.%u.%u.in-addr.arpa.",
+ (u_int) (cp[3]), (u_int) (cp[2]),
+ (u_int) (cp[1]), (u_int) (cp[0]));
+
+ if (!rptr)
+ {
+ rptr = make_request(lp);
+ rptr->type = T_PTR;
+ rptr->addr.s_addr = numb->s_addr;
+ memcpy((char *) &rptr->he.h_addr,
+ (char *) &numb->s_addr, sizeof(struct in_addr));
+ rptr->he.h_length = sizeof(struct in_addr);
+ }
+ return (query_name(ipbuf, C_IN, T_PTR, rptr));
+}
+
+/* generate a query based on class, type and name. */
+static int query_name(char *name, int class, int type, ResRQ * rptr)
+{
+ struct timeval tv;
+ char buf[MAXPACKET];
+ int r, s, k = 0;
+ HEADER *hptr;
+
+ memset(buf, '\0', sizeof(buf));
+ r = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
+ buf, sizeof(buf));
+ if (r <= 0)
+ {
+ h_errno = NO_RECOVERY;
+ return r;
+ }
+
+ if(rptr->id != -1)
+ rem_request_id(rptr);
+
+ hptr = (HEADER *) buf;
+#ifdef LRAND48
+ do
+ {
+ hptr->id = htons(ntohs(hptr->id) + k + lrand48() & 0xffff);
+#else
+ (void) gettimeofday(&tv, NULL);
+ do
+ {
+#if 0 /* emacs kludge */
+ }
+#endif
+ hptr->id = htons(ntohs(hptr->id) + k +
+ (u_short) (tv.tv_usec & 0xffff));
+#endif /* LRAND48 */
+ k++;
+ } while (find_id(ntohs(hptr->id)));
+ rptr->id = ntohs(hptr->id);
+ add_request_id(rptr);
+ rptr->sends++;
+ s = send_res_msg(buf, r, rptr->sends);
+ if (s == -1)
+ {
+ h_errno = TRY_AGAIN;
+ return -1;
+ }
+ else
+ rptr->sent += s;
+ return 0;
+}
+
+static void resend_query(ResRQ * rptr)
+{
+ if (rptr->resend == 0)
+ return;
+ reinfo.re_resends++;
+ switch (rptr->type)
+ {
+ case T_PTR:
+ (void) do_query_number(NULL, &rptr->addr, rptr);
+ break;
+ case T_A:
+ (void) do_query_name(NULL, rptr->name, rptr);
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
+/* returns 0 on failure, nonzero on success */
+int arpa_to_ip(char *arpastring, unsigned int *saddr)
+{
+ int idx = 0, onum = 0;
+ char ipbuf[HOSTLEN + 1];
+ char *fragptr[4];
+ u_char *ipptr;
+
+ strcpy(ipbuf, arpastring);
+
+ /* ipbuf should contain a string in the format of 4.3.2.1.in-addr.arpa */
+
+ fragptr[onum++] = ipbuf;
+
+ while(ipbuf[idx])
+ {
+ if(ipbuf[idx] == '.')
+ {
+ ipbuf[idx++] = '\0';
+ if(onum == 4)
+ break;
+ fragptr[onum++] = ipbuf + idx;
+ }
+ else
+ idx++;
+ }
+
+ if(onum != 4)
+ return 0;
+
+ if(mycmp(ipbuf + idx, "in-addr.arpa"))
+ return 0;
+
+ ipptr = (u_char *) saddr;
+
+ ipptr[0] = (u_char) atoi(fragptr[3]);
+ ipptr[1] = (u_char) atoi(fragptr[2]);
+ ipptr[2] = (u_char) atoi(fragptr[1]);
+ ipptr[3] = (u_char) atoi(fragptr[0]);
+ return 1;
+}
+
+#undef DNS_ANS_DEBUG_MAX
+#undef DNS_ANS_DEBUG
+
+#define MAX_ACCEPTABLE_ANS 10
+
+static char acceptable_answers[MAX_ACCEPTABLE_ANS][HOSTLEN + 1];
+static int num_acc_answers = 0;
+
+#define add_acceptable_answer(x) do { \
+ if(num_acc_answers < MAX_ACCEPTABLE_ANS) \
+ strcpy(acceptable_answers[num_acc_answers++], x); } while (0);
+
+static inline char *is_acceptable_answer(char *h)
+{
+ int i;
+
+ for (i = 0; i < num_acc_answers; i++)
+ {
+ if(mycmp(acceptable_answers[i], h) == 0)
+ return acceptable_answers[i];
+ }
+ return 0;
+}
+
+#ifdef DNS_ANS_DEBUG_MAX
+static char dhostbuf[HOSTLEN + 1];
+#endif
+
+/* process name server reply. */
+static int proc_answer(ResRQ * rptr, HEADER *hptr, char *buf, char *eob)
+{
+ char *cp, **alias, *acc;
+ struct hent *hp;
+ int class, type, dlen, len, ans = 0, n, origtype = rptr->type;
+ int adr = 0;
+ struct in_addr ptrrep, dr;
+
+ num_acc_answers = 0;
+
+ cp = buf + sizeof(HEADER);
+ hp = (struct hent *) &(rptr->he);
+
+ while ((hp->h_addr_list[adr].s_addr) && (adr < IRC_MAXADDRS))
+ adr++;
+
+ alias = hp->h_aliases;
+ while (*alias)
+ alias++;
+
+ if(hptr->qdcount != 1)
+ {
+ sendto_realops_lev(DEBUG_LEV,
+ "DNS packet with question count of %d ",
+ hptr->qdcount);
+ return -1;
+ }
+
+ /*
+ * ensure the question we're getting a reply for
+ * is a the right question.
+ */
+
+ if((n = dn_expand(buf, eob, cp, hostbuf, sizeof(hostbuf))) <= 0)
+ {
+ /* broken dns packet, toss it out */
+ return -1;
+ }
+ else
+ {
+ int strangeness = 0;
+ char tmphost[HOSTLEN];
+
+ hostbuf[HOSTLEN] = '\0';
+ cp += n;
+ type = (int) _getshort(cp);
+ cp += sizeof(short);
+ class = (int) _getshort(cp);
+ cp += sizeof(short);
+ if(class != C_IN)
+ {
+ sendto_realops_lev(DEBUG_LEV,
+ "Expected DNS packet class C_IN, got %d ",
+ class);
+ strangeness++;
+ }
+
+ if(type != rptr->type)
+ {
+ sendto_realops_lev(DEBUG_LEV,
+ "Expected DNS packet type %d, got %d ",
+ rptr->type, type);
+ strangeness++;
+ }
+
+ if(rptr->type == T_A && rptr->name)
+ {
+ strcpy(tmphost, rptr->name);
+ }
+ else if(rptr->type == T_PTR)
+ {
+ u_char *ipp;
+
+ ipp = (u_char *) &rptr->addr.s_addr;
+ ircsprintf(tmphost, "%u.%u.%u.%u.in-addr.arpa",
+ (u_int) (ipp[3]), (u_int) (ipp[2]),
+ (u_int) (ipp[1]), (u_int) (ipp[0]));
+ }
+ else
+ {
+ sendto_realops_lev(DEBUG_LEV,
+ "rptr->type is unknown type %d! "
+ "(rptr->name == %x)",
+ rptr->type, rptr->name);
+ return -1;
+ }
+
+ if(mycmp(tmphost, hostbuf) != 0)
+ {
+ sendto_realops_lev(DEBUG_LEV, "Asked question for %s, but got "
+ "reply about question %s (!!!)",
+ tmphost, hostbuf);
+ strangeness++;
+ }
+
+ if(strangeness)
+ return PROCANSWER_STRANGE;
+ }
+
+ /* proccess each answer sent to us blech. */
+ while (hptr->ancount-- > 0 && cp && cp < eob)
+ {
+ n = dn_expand(buf, eob, cp, hostbuf, sizeof(hostbuf));
+ hostbuf[HOSTLEN] = '\0';
+
+ if (n <= 0)
+ break;
+ cp += n;
+ type = (int) _getshort(cp);
+ cp += sizeof(short);
+
+ class = (int) _getshort(cp);
+ cp += sizeof(short);
+
+ rptr->ttl = _getlong(cp);
+ cp += sizeof(rptr->ttl);
+ dlen = (int) _getshort(cp);
+ cp += sizeof(short);
+
+ /* Wait to set rptr->type until we verify this structure */
+
+ len = strlen(hostbuf);
+ /* name server never returns with trailing '.' */
+ if (!strchr(hostbuf, '.') && (_res.options & RES_DEFNAMES))
+ {
+ (void) strcat(hostbuf, ".");
+ len++;
+ if ((len + 2) < sizeof(hostbuf))
+ {
+ strncpy(hostbuf, _res.defdname,
+ sizeof(hostbuf) - 1 - len);
+ hostbuf[HOSTLEN] = '\0';
+ len = MIN(len + strlen(_res.defdname),
+ sizeof(hostbuf)) - 1;
+ }
+ }
+
+#ifdef DNS_ANS_DEBUG_MAX
+ strcpy(dhostbuf, hostbuf);
+#endif
+
+ switch (type)
+ {
+ case T_A:
+ if(rptr->name == NULL)
+ {
+ sendto_realops_lev(DEBUG_LEV,"Received DNS_A answer, but null "
+ "rptr->name!");
+ return PROCANSWER_STRANGE;
+ }
+ if(mycmp(rptr->name, hostbuf) != 0)
+ {
+ if(!num_acc_answers || !(acc = is_acceptable_answer(hostbuf)))
+ {
+#ifdef DNS_ANS_DEBUG
+ sendto_realops_lev(DEBUG_LEV,
+ "Received DNS_A answer for %s, but "
+ "asked question for %s", hostbuf,
+ rptr->name);
+#endif
+ return PROCANSWER_STRANGE;
+ }
+#ifdef DNS_ANS_DEBUG
+ sendto_realops_lev(DEBUG_LEV,
+ "DNS_A answer from an acceptable (%s)",
+ acc);
+#endif
+ }
+ hp->h_length = dlen;
+ if (ans == 1)
+ hp->h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
+ /* from Christophe Kalt <kalt@stealth.net> */
+ if (dlen != sizeof(dr))
+ {
+ sendto_realops("Bad IP length (%d) returned for %s",
+ dlen, hostbuf);
+ Debug((DEBUG_DNS, "Bad IP length (%d) returned for %s",
+ dlen, hostbuf));
+ return PROCANSWER_MALICIOUS;
+ }
+
+ if(adr < IRC_MAXADDRS)
+ {
+ /* ensure we never go over the bounds of our adr array */
+ memcpy((char *)&dr, cp, sizeof(dr));
+ hp->h_addr_list[adr].s_addr = dr.s_addr;
+ Debug((DEBUG_INFO, "got ip # %s for %s",
+ inetntoa((char *) &hp->h_addr_list[adr]), hostbuf));
+
+#ifdef DNS_ANS_DEBUG_MAX
+ sendto_realops_lev(DEBUG_LEV, "%s A %s", dhostbuf,
+ inetntoa((char *) &hp->h_addr_list[adr]));
+#endif
+ adr++;
+ }
+
+ if (!hp->h_name)
+ {
+ hp->h_name = (char *) MyMalloc(len + 1);
+ strcpy(hp->h_name, hostbuf);
+ }
+ ans++;
+ cp += dlen;
+ rptr->type = type;
+ break;
+
+ case T_PTR:
+ acc = NULL;
+ if(!num_acc_answers || !(acc = is_acceptable_answer(hostbuf)))
+ {
+ if(!(arpa_to_ip(hostbuf, &ptrrep.s_addr)))
+ {
+#ifdef DNS_ANS_DEBUG
+ sendto_realops_lev(DEBUG_LEV,
+ "Received strangely formed PTR answer "
+ "for %s (asked for %s) -- ignoring",
+ hostbuf, inetntoa((char *)&rptr->addr));
+#endif
+ return PROCANSWER_STRANGE;
+ }
+
+ if(ptrrep.s_addr != rptr->addr.s_addr)
+ {
+#ifdef DNS_ANS_DEBUG
+ char ipbuf[16];
+
+ strcpy(ipbuf, inetntoa((char *)&ptrrep));
+ sendto_realops_lev(DEBUG_LEV,
+ "Received DNS_PTR answer for %s, "
+ "but asked question for %s",
+ ipbuf, inetntoa((char*)&rptr->addr));
+#endif
+ return PROCANSWER_STRANGE;
+ }
+ }
+
+#ifdef DNS_ANS_DEBUG
+ if(acc)
+ sendto_realops_lev(DEBUG_LEV,
+ "DNS_PTR from an acceptable (%s)", acc);
+#endif
+
+ if ((n = dn_expand(buf, eob, cp, hostbuf,
+ sizeof(hostbuf))) < 0)
+ {
+ cp = NULL;
+ break;
+ }
+
+ /*
+ * This comment is based on analysis by Shadowfax,
+ * Jolo and johan, not me. (Dianora) I am only
+ * commenting it.
+ *
+ * dn_expand is guaranteed to not return more than
+ * sizeof(hostbuf) but do all implementations of
+ * dn_expand also guarantee buffer is terminated with
+ * null byte? Lets not take chances. -Dianora
+ */
+ hostbuf[HOSTLEN] = '\0';
+ cp += n;
+ len = strlen(hostbuf);
+
+#ifdef DNS_ANS_DEBUG_MAX
+ sendto_realops_lev(DEBUG_LEV, "%s PTR %s", dhostbuf, hostbuf);
+#endif
+
+ Debug((DEBUG_INFO, "got host %s", hostbuf));
+ /*
+ * copy the returned hostname into the host name or
+ * alias field if there is a known hostname already.
+ */
+ if (hp->h_name)
+ {
+ /*
+ * This is really fishy. In fact, so fishy,
+ * that I say we just don't do this in this case.
+ *
+ * seems to happen with a whole host of .my addresses.
+ * interesting. - lucas
+ */
+
+ if (alias >= &(hp->h_aliases[IRC_MAXALIASES - 1]))
+ break;
+ *alias = (char *) MyMalloc(len + 1);
+ strcpy(*alias++, hostbuf);
+ *alias = NULL;
+ }
+ else
+ {
+ hp->h_name = (char *) MyMalloc(len + 1);
+ strcpy(hp->h_name, hostbuf);
+ }
+ ans++;
+ rptr->type = type;
+ break;
+
+ case T_CNAME:
+ acc = NULL;
+
+ if(origtype == T_PTR)
+ {
+ if(!num_acc_answers || !(acc = is_acceptable_answer(hostbuf)))
+ {
+ if(!(arpa_to_ip(hostbuf, &ptrrep.s_addr)))
+ {
+#ifdef DNS_ANS_DEBUG
+ sendto_realops_lev(DEBUG_LEV,
+ "Received strangely formed "
+ "CNAME(PTR) answer for %s (asked "
+ "for %s) -- ignoring",
+ hostbuf,
+ inetntoa((char *)&rptr->addr));
+#endif
+ return PROCANSWER_STRANGE;
+ }
+
+ if(ptrrep.s_addr != rptr->addr.s_addr)
+ {
+#ifdef DNS_ANS_DEBUG
+ char ipbuf[16];
+
+ strcpy(ipbuf, inetntoa((char *)&ptrrep));
+ sendto_realops_lev(DEBUG_LEV, "Received "
+ "DNS_CNAME(PTR) answer for %s, "
+ "but asked question for %s",
+ ipbuf,
+ inetntoa((char*)&rptr->addr));
+#endif
+ return PROCANSWER_STRANGE;
+ }
+ }
+#ifdef DNS_ANS_DEBUG
+ if(acc)
+ sendto_realops_lev(DEBUG_LEV, "DNS_CNAME (PTR) answer "
+ "from an acceptable (%s)", acc);
+#endif
+ }
+ else if(origtype == T_A)
+ {
+ if(mycmp(rptr->name, hostbuf) != 0)
+ {
+ if(!num_acc_answers || !(acc = is_acceptable_answer(hostbuf)))
+ {
+#ifdef DNS_ANS_DEBUG
+ sendto_realops_lev(DEBUG_LEV, "Received DNS_CNAME(A) "
+ "answer for %s, but asked "
+ "question for %s",
+ hostbuf, rptr->name);
+#endif
+ return PROCANSWER_STRANGE;
+ }
+#ifdef DNS_ANS_DEBUG
+ sendto_realops_lev(DEBUG_LEV, "DNS_CNAME (A) answer from "
+ "an acceptable (%s)", acc);
+#endif
+ }
+ }
+
+ Debug((DEBUG_INFO, "got cname %s", hostbuf));
+
+ if (alias >= &(hp->h_aliases[IRC_MAXALIASES - 1]))
+ break;
+ *alias = (char *) MyMalloc(len + 1);
+ strcpy(*alias++, hostbuf);
+ *alias = NULL;
+ ans++;
+ rptr->type = type;
+
+ if ((n = dn_expand(buf, eob, cp, hostbuf, sizeof(hostbuf))) < 0)
+ {
+ cp = NULL;
+ break;
+ }
+
+ hostbuf[HOSTLEN] = '\0';
+ cp += n;
+
+ add_acceptable_answer(hostbuf);
+
+#ifdef DNS_ANS_DEBUG_MAX
+ sendto_realops_lev(DEBUG_LEV, "%s CNAME %s", dhostbuf, hostbuf);
+#endif
+
+ break;
+
+ default:
+#ifdef DEBUG
+ Debug((DEBUG_INFO, "proc_answer: type:%d for:%s",
+ type, hostbuf));
+#endif
+ break;
+ }
+ }
+ return ans;
+}
+
+/*
+ * read a dns reply from the nameserver and process it.
+ */
+struct hostent *get_res(char *lp)
+{
+ static char buf[sizeof(HEADER) + MAXPACKET];
+ HEADER *hptr;
+ ResRQ *rptr = NULL;
+ aCache *cp = (aCache *) NULL;
+ struct sockaddr_in sin;
+ int rc, a, len = sizeof(sin), max;
+
+ rc = recvfrom(resfd, buf, sizeof(buf), 0, (struct sockaddr *) &sin, &len);
+ if (rc <= sizeof(HEADER))
+ return getres_err(rptr, lp);
+
+ /*
+ * convert DNS reply reader from Network byte order to CPU byte
+ * order.
+ */
+ hptr = (HEADER *) buf;
+ hptr->id = ntohs(hptr->id);
+ hptr->ancount = ntohs(hptr->ancount);
+ hptr->qdcount = ntohs(hptr->qdcount);
+ hptr->nscount = ntohs(hptr->nscount);
+ hptr->arcount = ntohs(hptr->arcount);
+#ifdef DEBUG
+ Debug((DEBUG_NOTICE, "get_res:id = %d rcode = %d ancount = %d",
+ hptr->id, hptr->rcode, hptr->ancount));
+#endif
+ reinfo.re_replies++;
+ /*
+ * response for an id which we have already received an answer for
+ * just ignore this response.
+ */
+ rptr = find_id(hptr->id);
+ if (!rptr)
+ return getres_err(rptr, lp);
+ /*
+ * check against possibly fake replies
+ */
+ max = MIN(_res.nscount, rptr->sends);
+ if (!max)
+ max = 1;
+
+ for (a = 0; a < max; a++)
+ if (!_res.nsaddr_list[a].sin_addr.s_addr ||
+ !memcmp((char *) &sin.sin_addr,
+ (char *) &_res.nsaddr_list[a].sin_addr,
+ sizeof(struct in_addr)))
+ break;
+
+ if (a == max)
+ {
+ reinfo.re_unkrep++;
+ return getres_err(rptr, lp);
+ }
+
+ if ((hptr->rcode != NOERROR) || (hptr->ancount == 0))
+ {
+ switch (hptr->rcode)
+ {
+ case NXDOMAIN:
+ h_errno = TRY_AGAIN;
+ break;
+ case SERVFAIL:
+ h_errno = TRY_AGAIN;
+ break;
+ case NOERROR:
+ h_errno = NO_DATA;
+ break;
+ case FORMERR:
+ case NOTIMP:
+ case REFUSED:
+ default:
+ h_errno = NO_RECOVERY;
+ break;
+ }
+ reinfo.re_errors++;
+ /*
+ * If a bad error was returned, we stop here and dont send
+ * send any more (no retries granted).
+ */
+ if (h_errno != TRY_AGAIN)
+ {
+ Debug((DEBUG_DNS, "Fatal DNS error %d for %d",
+ h_errno, hptr->rcode));
+ rptr->resend = 0;
+ rptr->retries = 0;
+ }
+ return getres_err(rptr, lp);
+ }
+ a = proc_answer(rptr, hptr, buf, buf + rc);
+
+#ifdef DEBUG
+ Debug((DEBUG_INFO, "get_res:Proc answer = %d", a));
+#endif
+
+ switch(a)
+ {
+ case PROCANSWER_STRANGE:
+ rptr->resend = 1;
+ rptr->retries--;
+ if(rptr->retries <= 0)
+ {
+ h_errno = TRY_AGAIN; /* fail this lookup.. */
+ return getres_err(rptr, lp);
+ }
+ else
+ resend_query(rptr);
+ return NULL;
+
+ case PROCANSWER_MALICIOUS:
+ if (lp)
+ memcpy(lp, (char *) &rptr->cinfo, sizeof(Link));
+ rem_request(rptr);
+ return NULL;
+
+ default:
+ break;
+ }
+
+ if (a > 0 && rptr->type == T_PTR)
+ {
+ struct hostent *hp2 = NULL;
+
+ Debug((DEBUG_DNS, "relookup %s <-> %s",
+ rptr->he.h_name, inetntoa((char *) &rptr->he.h_addr)));
+ /*
+ * Lookup the 'authoritive' name that we were given for the ip#.
+ * By using this call rather than regenerating the type we
+ * automatically gain the use of the cache with no extra kludges.
+ */
+ if ((hp2 = gethost_byname(rptr->he.h_name, &rptr->cinfo)))
+ if (lp)
+ memcpy(lp, (char *) &rptr->cinfo, sizeof(Link));
+
+ if(!hp2)
+ {
+ memcpy(&last->he_rev, &rptr->he, sizeof(struct hent));
+ memset(&rptr->he, 0, sizeof(struct hent));
+ last->has_rev = 1;
+ }
+
+ rem_request(rptr);
+ return hp2;
+ }
+
+ if(a > 0 && rptr->type == T_A)
+ {
+ if(rptr->has_rev == 0)
+ {
+ sendto_realops_lev(DEBUG_LEV, "Blindly accepting dns result for %s",
+ rptr->he.h_name ? rptr->he.h_name :
+ inetntoa((char *)&rptr->addr));
+ }
+ else
+ {
+ int invalid_parms_name = 0;
+ int invalid_parms_ip = 0;
+ int found_match_ip = 0;
+ int nidx, tidx;
+ int numaddr, numnewaddr;
+ struct in_addr new_addr_list[IRC_MAXADDRS];
+
+ if(!(rptr->he.h_name && rptr->he_rev.h_name))
+ invalid_parms_name++;
+
+ if(!(rptr->he.h_addr_list[0].s_addr &&
+ rptr->he_rev.h_addr_list[0].s_addr))
+ invalid_parms_ip++;
+
+ if(invalid_parms_name || invalid_parms_ip)
+ {
+ sendto_realops_lev(DEBUG_LEV,
+ "DNS query missing things! name: %s ip: %s",
+ invalid_parms_name ? "MISSING" :
+ rptr->he.h_name,
+ invalid_parms_ip ? "MISSING" :
+ inetntoa((char *)&rptr->he.h_addr_list[0]));
+ if (lp)
+ memcpy(lp, (char *) &rptr->cinfo, sizeof(Link));
+ rem_request(rptr);
+ return NULL;
+ }
+
+ /*
+ * This must ensure that all IPs in the forward query (he)
+ * are also in the reverse query (he_rev).
+ * Those not in the reverse query must be zeroed out!
+ */
+
+ for(numaddr = numnewaddr = nidx = 0; nidx < IRC_MAXADDRS; nidx++)
+ {
+ int does_match;
+
+ if(rptr->he.h_addr_list[nidx].s_addr == 0)
+ break;
+
+ numaddr++;
+
+ for(tidx = does_match = 0; tidx < IRC_MAXADDRS; tidx++)
+ {
+ if(rptr->he_rev.h_addr_list[tidx].s_addr == 0)
+ break;
+
+ if(rptr->he_rev.h_addr_list[tidx].s_addr ==
+ rptr->he.h_addr_list[nidx].s_addr) /* MATCH */
+ {
+ found_match_ip++;
+ does_match = 1;
+ break;
+ }
+ }
+
+ if(does_match)
+ {
+ new_addr_list[numnewaddr++].s_addr =
+ rptr->he.h_addr_list[nidx].s_addr;
+ new_addr_list[numnewaddr].s_addr = 0;
+ }
+ }
+
+ if(!found_match_ip)
+ {
+ char ntoatmp_r[64];
+ char ntoatmp_f[64];
+
+ strcpy(ntoatmp_f, inetntoa((char *)&rptr->he.h_addr_list[0]));
+ strcpy(ntoatmp_r,
+ inetntoa((char *)&rptr->he_rev.h_addr_list[0]));
+#ifdef DNS_ANS_DEBUG
+ sendto_realops_lev(DEBUG_LEV, "Forward and Reverse queries do "
+ "not have matching IP! %s<>%s %s<>%s",
+ rptr->he.h_name, rptr->he_rev.h_name,
+ ntoatmp_f, ntoatmp_r);
+#endif
+ if(rptr->cinfo.flags == ASYNC_CLIENT && rptr->cinfo.value.cptr)
+ {
+ sendto_one(rptr->cinfo.value.cptr,
+ ":%s NOTICE AUTH :*** Your forward and "
+ "reverse DNS do not match, "
+ "ignoring hostname. [%s != %s]",
+ me.name, ntoatmp_f, ntoatmp_r);
+ }
+
+ if (lp)
+ memcpy(lp, (char *) &rptr->cinfo, sizeof(Link));
+
+ rem_request(rptr);
+ return NULL;
+ }
+
+ if(numnewaddr != numaddr)
+ {
+ memcpy(rptr->he.h_addr_list, new_addr_list,
+ sizeof(struct in_addr) * IRC_MAXADDRS);
+#ifdef DNS_ANS_DEBUG
+ sendto_realops_lev(DEBUG_LEV, "numaddr = %d, numnewaddr = %d",
+ numaddr, numnewaddr);
+#endif
+ }
+
+ /*
+ * Our DNS query was made based on the hostname, so the hostname
+ * part should be fine.
+ */
+ }
+ }
+
+ if (a > 0)
+ {
+ if (lp)
+ memcpy(lp, (char *) &rptr->cinfo, sizeof(Link));
+
+ cp = make_cache(rptr);
+#ifdef DEBUG
+ Debug((DEBUG_INFO, "get_res:cp=%#x rptr=%#x (made)", cp, rptr));
+#endif
+
+ rem_request(rptr);
+ }
+ else if (!rptr->sent)
+ rem_request(rptr);
+ return cp ? (struct hostent *) &cp->he : NULL;
+}
+
+static struct hostent *getres_err(ResRQ * rptr, char *lp)
+{
+ /*
+ * Reprocess an error if the nameserver didnt tell us to
+ * "TRY_AGAIN".
+ */
+ if (rptr)
+ {
+ if (h_errno != TRY_AGAIN)
+ {
+ /*
+ * If we havent tried with the default domain and its set,
+ * then give it a try next.
+ */
+ if (_res.options & RES_DEFNAMES && ++rptr->srch == 0)
+ {
+ rptr->retries = _res.retry;
+ rptr->sends = 0;
+ rptr->resend = 1;
+ resend_query(rptr);
+ }
+ else
+ resend_query(rptr);
+ }
+ else if (lp)
+ memcpy(lp, (char *) &rptr->cinfo, sizeof(Link));
+ }
+ return (struct hostent *) NULL;
+}
+
+static int hash_number(unsigned char *ip)
+{
+ u_int hashv = 0;
+
+ /* could use loop but slower */
+ hashv += (int) *ip++;
+ hashv += hashv + (int) *ip++;
+ hashv += hashv + (int) *ip++;
+ hashv += hashv + (int) *ip++;
+ hashv %= ARES_CACSIZE;
+ return (hashv);
+}
+
+#ifdef ALLOW_CACHE_NAMES
+static int hash_name(char *name)
+{
+ u_int hashv = 0;
+
+ for (; *name && *name != '.'; name++)
+ hashv += *name;
+ hashv %= ARES_CACSIZE;
+ return (hashv);
+}
+#endif
+
+static unsigned int hash_id(unsigned int id)
+{
+ return id % ARES_IDCACSIZE;
+}
+
+static unsigned int hash_cp(char *cp)
+{
+ return ((unsigned int) cp) % ARES_IDCACSIZE;
+}
+
+/* Add a new cache item to the queue and hash table. */
+static aCache *add_to_cache(aCache * ocp)
+{
+ aCache *cp = NULL;
+ int hashv;
+
+#ifdef DEBUG
+ Debug((DEBUG_INFO,
+ "add_to_cache:ocp %#x he %#x name %#x addrl %#x 0 %#x",
+ ocp, &ocp->he, ocp->he.h_name, ocp->he.h_addr_list,
+ ocp->he.h_addr_list[0]));
+#endif
+ ocp->list_next = cachetop;
+ cachetop = ocp;
+ /* Make sure non-bind resolvers don't blow up (Thanks to Yves) */
+ if (!ocp)
+ return NULL;
+ if (!(ocp->he.h_name))
+ return NULL;
+ if (!(ocp->he.h_addr))
+ return NULL;
+
+#ifdef ALLOW_CACHE_NAMES
+ hashv = hash_name(ocp->he.h_name);
+
+ ocp->hname_next = hashtable[hashv].name_list;
+ hashtable[hashv].name_list = ocp;
+#endif
+
+ hashv = hash_number((u_char *) ocp->he.h_addr);
+
+ ocp->hnum_next = hashtable[hashv].num_list;
+ hashtable[hashv].num_list = ocp;
+
+#ifdef DEBUG
+ Debug((DEBUG_INFO, "add_to_cache:added %s[%08x] cache %#x.",
+ ocp->he.h_name, ocp->he.h_addr_list[0], ocp));
+ Debug((DEBUG_INFO,
+ "add_to_cache:h1 %d h2 %x lnext %#x namnext %#x numnext %#x",
+ hash_name(ocp->he.h_name), hashv, ocp->list_next,
+ ocp->hname_next, ocp->hnum_next));
+#endif
+ /* LRU deletion of excessive cache entries. */
+ if (++incache > IRC_MAXCACHED)
+ {
+ for (cp = cachetop; cp->list_next; cp = cp->list_next);
+ rem_cache(cp);
+ }
+ cainfo.ca_adds++;
+
+ return ocp;
+}
+
+/*
+ * update_list does not alter the cache structure passed. It is
+ * assumed that * it already contains the correct expire time, if it is
+ * a new entry. Old * entries have the expirey time updated.
+ */
+static void update_list(ResRQ * rptr, aCache * cachep)
+{
+ aCache **cpp, *cp = cachep;
+ char *s, *t, **base;
+ int i, j;
+ int addrcount;
+
+ /*
+ * search for the new cache item in the cache list by hostname. *
+ * If found, move the entry to the top of the list and return.
+ */
+ cainfo.ca_updates++;
+
+ for (cpp = &cachetop; *cpp; cpp = &((*cpp)->list_next))
+ if (cp == *cpp)
+ break;
+ if (!*cpp)
+ return;
+ *cpp = cp->list_next;
+ cp->list_next = cachetop;
+ cachetop = cp;
+ if (!rptr)
+ return;
+
+#ifdef DEBUG
+ Debug((DEBUG_DEBUG, "u_l:cp %#x na %#x al %#x ad %#x",
+ cp, cp->he.h_name, cp->he.h_aliases, cp->he.h_addr));
+ Debug((DEBUG_DEBUG, "u_l:rptr %#x h_n %#x", rptr, rptr->he.h_name));
+#endif
+ /*
+ * Compare the cache entry against the new record. Add any
+ * previously missing names for this entry.
+ */
+ for (i = 0; cp->he.h_aliases[i]; i++);
+ addrcount = i;
+ for (i = 0, s = rptr->he.h_name; s && i < IRC_MAXALIASES;
+ s = rptr->he.h_aliases[i++])
+ {
+ for (j = 0, t = cp->he.h_name; t && j < IRC_MAXALIASES;
+ t = cp->he.h_aliases[j++])
+ if (!mycmp(t, s))
+ break;
+ if (!t && j < IRC_MAXALIASES - 1)
+ {
+ base = cp->he.h_aliases;
+
+ addrcount++;
+ base = (char **) MyRealloc(base,
+ sizeof(char *) * (addrcount + 1));
+
+ cp->he.h_aliases = base;
+#ifdef DEBUG
+ Debug((DEBUG_DNS, "u_l:add name %s hal %x ac %d",
+ s, cp->he.h_aliases, addrcount));
+#endif
+ base[addrcount - 1] = s;
+ base[addrcount] = NULL;
+ if (i)
+ rptr->he.h_aliases[i - 1] = NULL;
+ else
+ rptr->he.h_name = NULL;
+ }
+ }
+ for (i = 0; cp->he.h_addr_list[i]; i++);
+ addrcount = i;
+ /* Do the same again for IP#'s. */
+ for (s = (char *) &rptr->he.h_addr.s_addr;
+ ((struct in_addr *) s)->s_addr; s += sizeof(struct in_addr)) {
+ for (i = 0; (t = cp->he.h_addr_list[i]); i++)
+ if (!memcmp(s, t, sizeof(struct in_addr)))
+ break;
+
+ if (i >= IRC_MAXADDRS || addrcount >= IRC_MAXADDRS)
+ break;
+ /*
+ * Oh man this is bad...I *HATE* it. -avalon
+ *
+ * Whats it do ? Reallocate two arrays, one of pointers to "char *"
+ * and the other of IP addresses. Contents of the IP array *MUST*
+ * be preserved and the pointers into it recalculated.
+ */
+ if (!t)
+ {
+ base = cp->he.h_addr_list;
+ addrcount++;
+ t = (char *) MyRealloc(*base,
+ addrcount * sizeof(struct in_addr));
+
+ base = (char **) MyRealloc(base,
+ (addrcount + 1) * sizeof(char *));
+
+ cp->he.h_addr_list = base;
+#ifdef DEBUG
+ Debug((DEBUG_DNS, "u_l:add IP %x hal %x ac %d",
+ ntohl(((struct in_addr *) s)->s_addr),
+ cp->he.h_addr_list,
+ addrcount));
+#endif
+ for (; addrcount; addrcount--)
+ {
+ *base++ = t;
+ t += sizeof(struct in_addr);
+ }
+ *base = NULL;
+ memcpy(*--base, s, sizeof(struct in_addr));
+ }
+ }
+ return;
+}
+
+static aCache *find_cache_name(char *name)
+{
+#ifdef ALLOW_CACHE_NAMES
+ aCache *cp;
+ char *s;
+ int hashv, i;
+
+ if (name == (char *) NULL)
+ return (aCache *) NULL;
+ hashv = hash_name(name);
+
+ cp = hashtable[hashv].name_list;
+#ifdef DEBUG
+ Debug((DEBUG_DNS, "find_cache_name:find %s : hashv = %d", name, hashv));
+#endif
+
+ for (; cp; cp = cp->hname_next)
+ for (i = 0, s = cp->he.h_name; s; s = cp->he.h_aliases[i++])
+ if (mycmp(s, name) == 0)
+ {
+ cainfo.ca_na_hits++;
+ update_list(NULL, cp);
+ return cp;
+ }
+
+ for (cp = cachetop; cp; cp = cp->list_next)
+ {
+ /*
+ * if no aliases or the hash value matches, we've already done
+ * this entry and all possiblilities concerning it.
+ */
+ if (!*cp->he.h_aliases)
+ continue;
+ if (cp->he.h_name == (char *) NULL) /*
+ * don't trust anything
+ * -Dianora
+ */
+ continue;
+ if (hashv == hash_name(cp->he.h_name))
+ continue;
+ for (i = 0, s = cp->he.h_aliases[i]; s && i < IRC_MAXALIASES; i++)
+ if (!mycmp(name, s))
+ {
+ cainfo.ca_na_hits++;
+ update_list(NULL, cp);
+ return cp;
+ }
+ }
+#endif
+ return NULL;
+}
+
+/* find a cache entry by ip# and update its expire time */
+static aCache *
+find_cache_number(ResRQ * rptr, char *numb)
+{
+ aCache *cp;
+ int hashv, i;
+ struct in_addr *ip = (struct in_addr *) numb;
+
+ if ((u_char *) numb == (u_char *) NULL)
+ return ((aCache *) NULL);
+ hashv = hash_number((u_char *) numb);
+ cp = hashtable[hashv].num_list;
+#ifdef DEBUG
+ Debug((DEBUG_DNS, "find_cache_number:find %s[%08x]: hashv = %d",
+ inetntoa(numb), ntohl(ip->s_addr), hashv));
+#endif
+
+ for (; cp; cp = cp->hnum_next)
+ {
+ for (i = 0; cp->he.h_addr_list[i]; i++)
+ {
+ /*
+ * A 32 bit integer compare should be faster than this...
+ * if (!memcmp(cp->he.h_addr_list[i], numb,
+ * sizeof(struct in_addr)))
+ */
+ if(((struct in_addr *)cp->he.h_addr_list[i])->s_addr == ip->s_addr)
+ {
+ cainfo.ca_nu_hits++;
+ update_list(NULL, cp);
+ return cp;
+ }
+ }
+ }
+
+#ifdef SEARCH_CACHE_ADDRESSES
+ for (cp = cachetop; cp; cp = cp->list_next)
+ {
+ /*
+ * single address entry...would have been done by hashed search
+ * above...
+ */
+ if (!cp->he.h_addr_list[1])
+ continue;
+ /*
+ * if the first IP# has the same hashnumber as the IP# we are
+ * looking for, its been done already.
+ */
+ if (hashv == hash_number((u_char *) cp->he.h_addr_list[0]))
+ continue;
+ for (i = 1; cp->he.h_addr_list[i]; i++)
+ if (!memcmp(cp->he.h_addr_list[i], numb,
+ sizeof(struct in_addr)))
+ {
+ cainfo.ca_nu_hits++;
+ update_list(NULL, cp);
+ return cp;
+ }
+ }
+#endif
+ return NULL;
+}
+
+static aCache *make_cache(ResRQ * rptr)
+{
+ aCache *cp;
+ int i, n;
+ struct hostent *hp;
+ char *s, **t;
+
+ /* shouldn't happen but it just might... */
+ if (!rptr->he.h_name || !rptr->he.h_addr.s_addr)
+ return NULL;
+ /*
+ * Make cache entry. First check to see if the cache already
+ * exists and if so, return a pointer to it.
+ */
+ if ((cp = find_cache_number(rptr, (char *) &rptr->he.h_addr.s_addr)))
+ return cp;
+ for (i = 1; rptr->he.h_addr_list[i].s_addr && i < IRC_MAXADDRS; i++)
+ if ((cp =
+ find_cache_number(rptr,
+ (char *) &(rptr->he.h_addr_list[i].s_addr))))
+ return cp;
+ /* a matching entry wasnt found in the cache so go and make one up. */
+ cp = (aCache *) MyMalloc(sizeof(aCache));
+ memset((char *) cp, '\0', sizeof(aCache));
+ hp = &cp->he;
+ for (i = 0; i < IRC_MAXADDRS; i++)
+ if (!rptr->he.h_addr_list[i].s_addr)
+ break;
+ /* build two arrays, one for IP#'s, another of pointers to them. */
+ t = hp->h_addr_list = (char **) MyMalloc(sizeof(char *) * (i + 1));
+ memset((char *) t, '\0', sizeof(char *) * (i + 1));
+
+ s = (char *) MyMalloc(sizeof(struct in_addr) * i);
+ memset(s, '\0', sizeof(struct in_addr) * i);
+
+ for (n = 0; n < i; n++, s += sizeof(struct in_addr))
+ {
+ *t++ = s;
+ memcpy(s, (char *) &(rptr->he.h_addr_list[n].s_addr),
+ sizeof(struct in_addr));
+ }
+ *t = (char *) NULL;
+ /* an array of pointers to CNAMEs. */
+ for (i = 0; i < IRC_MAXALIASES; i++)
+ if (!rptr->he.h_aliases[i])
+ break;
+ i++;
+ t = hp->h_aliases = (char **) MyMalloc(sizeof(char *) * i);
+
+ for (n = 0; n < i; n++, t++)
+ {
+ *t = rptr->he.h_aliases[n];
+ rptr->he.h_aliases[n] = NULL;
+ }
+
+ hp->h_addrtype = rptr->he.h_addrtype;
+ hp->h_length = rptr->he.h_length;
+ hp->h_name = rptr->he.h_name;
+ if (rptr->ttl < 600)
+ {
+ reinfo.re_shortttl++;
+ cp->ttl = 600;
+ }
+ else
+ cp->ttl = rptr->ttl;
+ cp->expireat = timeofday + cp->ttl;
+ rptr->he.h_name = NULL;
+#ifdef DEBUG
+ Debug((DEBUG_INFO, "make_cache:made cache %#x", cp));
+#endif
+ return add_to_cache(cp);
+}
+
+/*
+ * rem_cache delete a cache entry from the cache structures and lists
+ * and return all memory used for the cache back to the memory pool.
+ */
+static void rem_cache(aCache * ocp)
+{
+ aCache **cp;
+ struct hostent *hp = &ocp->he;
+ int hashv;
+ aClient *cptr;
+
+#ifdef DEBUG
+ Debug((DEBUG_DNS, "rem_cache: ocp %#x hp %#x l_n %#x aliases %#x",
+ ocp, hp, ocp->list_next, hp->h_aliases));
+#endif
+ /*
+ * * Cleanup any references to this structure by destroying the *
+ * pointer.
+ */
+ for (hashv = highest_fd; hashv >= 0; hashv--)
+ if ((cptr = local[hashv]) && (cptr->hostp == hp))
+ cptr->hostp = NULL;
+ /*
+ * remove cache entry from linked list
+ */
+ for (cp = &cachetop; *cp; cp = &((*cp)->list_next))
+ if (*cp == ocp)
+ {
+ *cp = ocp->list_next;
+ break;
+ }
+ /* remove cache entry from hashed name lists */
+ if (hp->h_name == (char *) NULL)
+ return;
+#ifdef ALLOW_CACHE_NAMES
+ hashv = hash_name(hp->h_name);
+
+# ifdef DEBUG
+ Debug((DEBUG_DEBUG, "rem_cache: h_name %s hashv %d next %#x first %#x",
+ hp->h_name, hashv, ocp->hname_next,
+ hashtable[hashv].name_list));
+# endif
+ for (cp = &hashtable[hashv].name_list; *cp; cp = &((*cp)->hname_next))
+ if (*cp == ocp)
+ {
+ *cp = ocp->hname_next;
+ break;
+ }
+#endif
+ /* remove cache entry from hashed number list */
+ hashv = hash_number((u_char *) hp->h_addr);
+ if (hashv < 0)
+ return;
+#ifdef DEBUG
+ Debug((DEBUG_DEBUG, "rem_cache: h_addr %s hashv %d next %#x first %#x",
+ inetntoa(hp->h_addr), hashv, ocp->hnum_next,
+ hashtable[hashv].num_list));
+#endif
+ for (cp = &hashtable[hashv].num_list; *cp; cp = &((*cp)->hnum_next))
+ if (*cp == ocp)
+ {
+ *cp = ocp->hnum_next;
+ break;
+ }
+ /*
+ * free memory used to hold the various host names and the array of
+ * alias pointers.
+ */
+ if (hp->h_name)
+ MyFree(hp->h_name);
+ if (hp->h_aliases)
+ {
+ for (hashv = 0; hp->h_aliases[hashv]; hashv++)
+ MyFree(hp->h_aliases[hashv]);
+ MyFree(hp->h_aliases);
+ }
+ /* free memory used to hold ip numbers and the array of them. */
+ if (hp->h_addr_list)
+ {
+ if (*hp->h_addr_list)
+ MyFree(*hp->h_addr_list);
+ MyFree(hp->h_addr_list);
+ }
+
+ MyFree(ocp);
+
+ incache--;
+ cainfo.ca_dels++;
+
+ return;
+}
+
+/*
+ * removes entries from the cache which are older than their expirey
+ * times. returns the time at which the server should next poll the
+ * cache.
+ */
+time_t expire_cache(time_t now)
+{
+ aCache *cp, *cp2;
+ time_t next = 0;
+ time_t mmax = now + AR_TTL;
+
+ for (cp = cachetop; cp; cp = cp2)
+ {
+ cp2 = cp->list_next;
+
+ if (now >= cp->expireat)
+ {
+ cainfo.ca_expires++;
+ rem_cache(cp);
+ }
+ else if (!next || next > cp->expireat)
+ next = cp->expireat;
+ }
+ /*
+ * don't let one DNS record that happens to be first
+ * stop others from expiring.
+ */
+ return (next > now) ? (next < mmax ? next : mmax) : mmax;
+}
+
+/* remove all dns cache entries. */
+void flush_cache()
+{
+ aCache *cp;
+
+ while ((cp = cachetop))
+ rem_cache(cp);
+}
+
+int m_dns(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aCache *cp;
+ int i;
+
+ if (parv[1] && *parv[1] == 'l')
+ {
+ if (!MyClient(sptr) || !IsAdmin(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+ for (cp = cachetop; cp; cp = cp->list_next)
+ {
+ sendto_one(sptr, "NOTICE %s :Ex %d ttl %d host %s(%s)",
+ parv[0], cp->expireat - timeofday, cp->ttl,
+ cp->he.h_name, inetntoa(cp->he.h_addr));
+ for (i = 0; cp->he.h_aliases[i]; i++)
+ sendto_one(sptr, "NOTICE %s : %s = %s (CN)",
+ parv[0], cp->he.h_name,
+ cp->he.h_aliases[i]);
+ for (i = 1; cp->he.h_addr_list[i]; i++)
+ sendto_one(sptr, "NOTICE %s : %s = %s (IP)",
+ parv[0], cp->he.h_name,
+ inetntoa(cp->he.h_addr_list[i]));
+ }
+ return 0;
+ }
+ sendto_one(sptr, "NOTICE %s :Ca %d Cd %d Ce %d Cl %d Ch %d:%d Cu %d",
+ sptr->name,
+ cainfo.ca_adds, cainfo.ca_dels, cainfo.ca_expires,
+ cainfo.ca_lookups,
+ cainfo.ca_na_hits, cainfo.ca_nu_hits, cainfo.ca_updates);
+
+ sendto_one(sptr, "NOTICE %s :Re %d Rl %d/%d Rp %d Rq %d",
+ sptr->name, reinfo.re_errors, reinfo.re_nu_look,
+ reinfo.re_na_look, reinfo.re_replies, reinfo.re_requests);
+ sendto_one(sptr, "NOTICE %s :Ru %d Rsh %d Rs %d(%d) Rt %d", sptr->name,
+ reinfo.re_unkrep, reinfo.re_shortttl, reinfo.re_sent,
+ reinfo.re_resends, reinfo.re_timeouts);
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 1985 Regents of the University of California. All
+ * rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement: ``This product includes software
+ * developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with
+ * the distribution and in all advertising materials mentioning
+ * features or use of this software. Neither the name of the University
+ * 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 ``AS IS'' AND WITHOUT ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/* $Id: res_comp.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include "nameser.h"
+
+static dn_find();
+
+/*
+ * Expand compressed domain name 'comp_dn' to full domain name. 'msg'
+ * is a pointer to the begining of the message, 'eomorig' points to the
+ * first location after the message, 'exp_dn' is a pointer to a buffer
+ * of size 'length' for the result. Return size of compressed name or
+ * -1 if there was an error.
+ */
+int dn_expand(u_char *msg, u_char *eomorig, u_char *comp_dn, u_char *exp_dn,
+ int length)
+{
+ u_char *cp, *dn;
+ int n, c;
+ u_char *eom;
+ int len = -1, checked = 0;
+
+ dn = exp_dn;
+ cp = comp_dn;
+ eom = exp_dn + length;
+ /* fetch next label in domain name */
+ while (n = *cp++)
+ {
+ /* Check for indirection */
+ switch (n & INDIR_MASK)
+ {
+ case 0:
+ if (dn != exp_dn)
+ {
+ if (dn >= eom)
+ return (-1);
+ *dn++ = '.';
+ }
+ if (dn + n >= eom)
+ return (-1);
+ checked += n + 1;
+ while (--n >= 0)
+ {
+ if ((c = *cp++) == '.')
+ {
+ if (dn + n + 2 >= eom)
+ return (-1);
+ *dn++ = '\\';
+ }
+ *dn++ = c;
+ if (cp >= eomorig) /* out of range */
+ return (-1);
+ }
+ break;
+
+ case INDIR_MASK:
+ if (len < 0)
+ len = cp - comp_dn + 1;
+ cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff));
+ if (cp < msg || cp >= eomorig) /* out of range */
+ return (-1);
+ checked += 2;
+ /*
+ * Check for loops in the compressed name; if we've
+ * looked at the whole message, there must be a loop.
+ */
+ if (checked >= eomorig - msg)
+ return (-1);
+ break;
+
+ default:
+ return (-1); /*
+ * flag error
+ */
+ }
+ }
+ *dn = '\0';
+ if (len < 0)
+ len = cp - comp_dn;
+ return (len);
+}
+
+/*
+ * Compress domain name 'exp_dn' into 'comp_dn'. Return the size of the
+ * compressed name or -1. 'length' is the size of the array pointed to
+ * by 'comp_dn'. 'dnptrs' is a list of pointers to previous compressed
+ * names. dnptrs[0] is a pointer to the beginning of the message. The
+ * list ends with NULL. 'lastdnptr' is a pointer to the end of the
+ * arrary pointed to by 'dnptrs'. Side effect is to update the list of
+ * pointers for labels inserted into the message as we compress the
+ * name. If 'dnptr' is NULL, we don't try to compress names. If
+ * 'lastdnptr' is NULL, we don't update the list.
+ */
+int dn_comp(u_char *exp_dn, u_char *comp_dn, int length, u_char **dnptrs,
+ u_char **lastdnptr)
+{
+ u_char *cp, *dn;
+ int c, l;
+ u_char **cpp, **lpp, *sp, *eob;
+ u_char *msg;
+
+ dn = exp_dn;
+ cp = comp_dn;
+ eob = cp + length;
+ if (dnptrs != NULL)
+ {
+ if ((msg = *dnptrs++) != NULL)
+ {
+ for (cpp = dnptrs; *cpp != NULL; cpp++);
+ lpp = cpp; /* end of list to search */
+ }
+ }
+ else
+ msg = NULL;
+
+ for (c = *dn++; c != '\0';)
+ {
+ /* look to see if we can use pointers */
+ if (msg != NULL)
+ {
+ if ((l = dn_find(dn - 1, msg, dnptrs, lpp)) >= 0)
+ {
+ if (cp + 1 >= eob)
+ return (-1);
+ *cp++ = (l >> 8) | INDIR_MASK;
+ *cp++ = l % 256;
+ return (cp - comp_dn);
+ }
+ /* not found, save it */
+ if (lastdnptr != NULL && cpp < lastdnptr - 1)
+ {
+ *cpp++ = cp;
+ *cpp = NULL;
+ }
+ }
+ sp = cp++; /* save ptr to length byte */
+ do
+ {
+ if (c == '.')
+ {
+ c = *dn++;
+ break;
+ }
+ if (c == '\\')
+ {
+ if ((c = *dn++) == '\0')
+ break;
+ }
+ if (cp >= eob)
+ {
+ if (msg != NULL)
+ *lpp = NULL;
+ return (-1);
+ }
+ *cp++ = c;
+ } while ((c = *dn++) != '\0');
+
+ /* catch trailing '.'s but not '..' */
+ if ((l = cp - sp - 1) == 0 && c == '\0')
+ {
+ cp--;
+ break;
+ }
+ if (l <= 0 || l > MAXLABEL)
+ {
+ if (msg != NULL)
+ *lpp = NULL;
+ return (-1);
+ }
+ *sp = l;
+ }
+ if (cp >= eob)
+ {
+ if (msg != NULL)
+ *lpp = NULL;
+ return (-1);
+ }
+ *cp++ = '\0';
+ return (cp - comp_dn);
+}
+
+/* Skip over a compressed domain name. Return the size or -1. */
+dn_skipname(u_char *comp_dn, u_char *eom)
+{
+ u_char *cp;
+ int n;
+
+ cp = comp_dn;
+ while (cp < eom && (n = *cp++))
+ {
+ /* check for indirection */
+ switch (n & INDIR_MASK)
+ {
+ case 0: /* normal case, n == len */
+ cp += n;
+ continue;
+ default: /* illegal type */
+ return (-1);
+ case INDIR_MASK: /* indirection */
+ cp++;
+ }
+ break;
+ }
+ return (cp - comp_dn);
+}
+
+/*
+ * Search for expanded name from a list of previously compressed names.
+ * Return the offset from msg if found or -1. dnptrs is the pointer to
+ * the first name on the list, not the pointer to the start of the
+ * message.
+ */
+int staticdn_find(u_char *exp_dn, u_char *msg, u_char **dnptrs,
+ u_char **lastdnptr)
+{
+ u_char *dn, *cp, **cpp;
+ int n;
+ u_char *sp;
+
+ for (cpp = dnptrs; cpp < lastdnptr; cpp++)
+ {
+ dn = exp_dn;
+ sp = cp = *cpp;
+ while (n = *cp++)
+ {
+ /* check for indirection */
+ switch (n & INDIR_MASK)
+ {
+ case 0: /* normal case, n == len */
+ while (--n >= 0)
+ {
+ if (*dn == '.')
+ goto next;
+ if (*dn == '\\')
+ dn++;
+ if (*dn++ != *cp++)
+ goto next;
+ }
+ if ((n = *dn++) == '\0' && *cp == '\0')
+ return (sp - msg);
+ if (n == '.')
+ continue;
+ goto next;
+
+ default: /* illegal type */
+ return (-1);
+
+ case INDIR_MASK: /* indirection */
+ cp = msg + (((n & 0x3f) << 8) | *cp);
+ }
+ }
+ if (*dn == '\0')
+ return (sp - msg);
+ next:;
+ }
+ return (-1);
+}
+
+/*
+ * Routines to insert/extract short/long's. Must account for byte order
+ * and non-alignment problems. This code at least has the advantage of
+ * being portable.
+ *
+ * used by sendmail.
+ */
+
+u_short _getshort(u_char *msgp)
+{
+ u_char *p = (u_char *) msgp;
+
+#ifdef vax
+ /* vax compiler doesn't put shorts in registers */
+ u_long u;
+#else
+ u_short u;
+#endif
+
+ u = *p++ << 8;
+ return ((u_short) (u | *p));
+}
+
+u_long _getlong(u_char *msgp)
+{
+ u_char *p = (u_char *) msgp;
+ u_long u;
+
+ u = *p++;
+ u <<= 8;
+ u |= *p++;
+ u <<= 8;
+ u |= *p++;
+ u <<= 8;
+ return (u | *p);
+}
+
+int putshort(u_short s, u_char *msgp)
+{
+
+ msgp[1] = s;
+ msgp[0] = s >> 8;
+}
+
+int putlong(u_long l, u_char *msgp)
+{
+ msgp[3] = l;
+ msgp[2] = (l >>= 8);
+ msgp[1] = (l >>= 8);
+ msgp[0] = l >> 8;
+}
--- /dev/null
+/*-
+ * Copyright (c) 1985, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement: ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Id: res_init.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include "config.h" /* To get #define SOL20 */
+#include "sys.h"
+#include "nameser.h"
+#include "resolv.h"
+
+/* Resolver state default settings */
+struct state _res =
+{
+ RES_TIMEOUT, /* retransmition time interval */
+ 4, /* number of times to retransmit */
+ RES_DEFAULT, /* options flags */
+ 1, /* number of name servers */
+};
+
+/*
+ * Set up default settings. If the configuration file exist, the
+ * values there will have precedence. Otherwise, the server address is
+ * set to INADDR_ANY and the default domain name comes from the
+ * gethostname().
+ *
+ * The configuration file should only be used if you want to redefine your
+ * domain or run without a server on your machine.
+ *
+ * Return 0 if completes successfully, -1 on error
+ */
+int res_init()
+{
+ FILE *fp;
+ char *cp, *dp, **pp;
+ int n;
+ char buf[BUFSIZ];
+ extern u_long inet_addr();
+ extern char *getenv();
+ int nserv = 0; /* number of nameserver records read from file */
+ int norder = 0;
+ int haveenv = 0;
+ int havesearch = 0;
+
+ _res.nsaddr.sin_addr.s_addr = INADDR_ANY;
+ _res.nsaddr.sin_family = AF_INET;
+ _res.nsaddr.sin_port = htons(NAMESERVER_PORT);
+ _res.nscount = 1;
+
+ /* Allow user to override the local domain definition */
+ if ((cp = getenv("LOCALDOMAIN")) != NULL)
+ {
+ (void) strncpy(_res.defdname, cp, sizeof(_res.defdname));
+ haveenv++;
+ }
+
+ if ((fp = fopen(_PATH_RESCONF, "r")) != NULL)
+ {
+ /* read the config file */
+ while (fgets(buf, sizeof(buf), fp) != NULL)
+ {
+ /* read default domain name */
+ if (!strncmp(buf, "domain", sizeof("domain") - 1))
+ {
+ if (haveenv) /* skip if have from environ */
+ continue;
+ cp = buf + sizeof("domain") - 1;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if ((*cp == '\0') || (*cp == '\n'))
+ continue;
+ (void) strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
+ if ((cp = strchr(_res.defdname, '\n')) != NULL)
+ *cp = '\0';
+ havesearch = 0;
+ continue;
+ }
+ /* set search list */
+ if (!strncmp(buf, "search", sizeof("search") - 1)) {
+ if (haveenv) /* skip if have from environ */
+ continue;
+ cp = buf + sizeof("search") - 1;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if ((*cp == '\0') || (*cp == '\n'))
+ continue;
+ (void) strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
+ if ((cp = strchr(_res.defdname, '\n')) != NULL)
+ *cp = '\0';
+ /*
+ * Set search list to be blank-separated strings on rest of
+ * line.
+ */
+ cp = _res.defdname;
+ pp = _res.dnsrch;
+ *pp++ = cp;
+ for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++)
+ {
+ if (*cp == ' ' || *cp == '\t')
+ {
+ *cp = 0;
+ n = 1;
+ }
+ else if (n)
+ {
+ *pp++ = cp;
+ n = 0;
+ }
+ }
+ /* null terminate last domain if there are excess */
+ while (*cp != '\0' && *cp != ' ' && *cp != '\t')
+ cp++;
+ *cp = '\0';
+ *pp++ = 0;
+ havesearch = 1;
+ continue;
+ }
+ /* read nameservers to query */
+ if (!strncmp(buf, "nameserver", sizeof("nameserver") - 1) &&
+ nserv < MAXNS)
+ {
+ cp = buf + sizeof("nameserver") - 1;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if ((*cp == '\0') || (*cp == '\n'))
+ continue;
+ if ((_res.nsaddr_list[nserv].sin_addr.s_addr =
+ inet_addr(cp)) == (unsigned) -1)
+ {
+ _res.nsaddr_list[nserv].sin_addr.s_addr
+ = INADDR_ANY;
+ continue;
+ }
+ _res.nsaddr_list[nserv].sin_family = AF_INET;
+ _res.nsaddr_list[nserv].sin_port = htons(NAMESERVER_PORT);
+ nserv++;
+ continue;
+ }
+ /* read service order */
+ if (!strncmp(buf, "order", sizeof("order") - 1))
+ {
+ cp = buf + sizeof("order") - 1;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if ((*cp == '\0') || (*cp == '\n'))
+ continue;
+ norder = 0;
+ do
+ {
+ if ((dp = strchr(cp, ',')) != NULL)
+ *dp = '\0';
+ if (norder >= MAXSERVICES)
+ continue;
+ if (!strncmp(cp, "bind", sizeof("bind") - 1))
+ _res.order[norder++] = RES_SERVICE_BIND;
+ else if (!strncmp(cp, "local", sizeof("local") - 1))
+ _res.order[norder++] = RES_SERVICE_LOCAL;
+ cp = dp + 1;
+ } while (dp != NULL);
+ _res.order[norder] = RES_SERVICE_NONE;
+ continue;
+ }
+ }
+ if (nserv > 1)
+ _res.nscount = nserv;
+ (void) fclose(fp);
+ }
+ if (_res.defdname[0] == 0)
+ {
+ if (gethostname(buf, sizeof(_res.defdname)) == 0 &&
+ (cp = strchr(buf, '.')))
+ (void) strcpy(_res.defdname, cp + 1);
+ }
+
+ /* find components of local domain that might be searched */
+ if (havesearch == 0)
+ {
+ pp = _res.dnsrch;
+ *pp++ = _res.defdname;
+ for (cp = _res.defdname, n = 0; *cp; cp++)
+ if (*cp == '.')
+ n++;
+ cp = _res.defdname;
+ for (; n >= LOCALDOMAINPARTS && pp < _res.dnsrch + MAXDFLSRCH; n--)
+ {
+ cp = strchr(cp, '.');
+ *pp++ = ++cp;
+ }
+ *pp++ = 0;
+ }
+ /* default search order to bind only */
+ if (norder == 0)
+ {
+ _res.order[0] = RES_SERVICE_BIND;
+ _res.order[1] = RES_SERVICE_NONE;
+ }
+ _res.options |= RES_INIT;
+ return (0);
+}
--- /dev/null
+/*
+ * Copyright (c) 1985 Regents of the University of California. All
+ * rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement: ``This product includes software
+ * developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with
+ * the distribution and in all advertising materials mentioning
+ * features or use of this software. Neither the name of the University
+ * 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 ``AS IS'' AND WITHOUT ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/* $Id: res_mkquery.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include "config.h"
+#include "sys.h"
+#include "nameser.h"
+#include "resolv.h"
+
+/* Form all types of queries. Returns the size of the result or -1. */
+int res_mkquery(int op, char *dname, int class, int type, char *data,
+ int datalen, struct rrec *newrr, char *buf, int buflen)
+{
+ HEADER *hp;
+ char *cp;
+ int n;
+ char *dnptrs[10], **dpp, **lastdnptr;
+
+#ifdef DEBUG
+ if (_res.options & RES_DEBUG)
+ printf("res_mkquery(%d, %s, %d, %d)\n", op, dname, class, type);
+#endif /* DEBUG */
+ /* Initialize header fields. */
+ if ((buf == NULL) || (buflen < sizeof(HEADER)))
+ return (-1);
+ memset(buf, '\0', sizeof(HEADER));
+
+ hp = (HEADER *) buf;
+ hp->id = htons(++_res.id);
+ hp->opcode = op;
+ hp->pr = (_res.options & RES_PRIMARY) != 0;
+ hp->rd = (_res.options & RES_RECURSE) != 0;
+ hp->rcode = NOERROR;
+ cp = buf + sizeof(HEADER);
+ buflen -= sizeof(HEADER);
+
+ dpp = dnptrs;
+ *dpp++ = buf;
+ *dpp++ = NULL;
+ lastdnptr = dnptrs + sizeof(dnptrs) / sizeof(dnptrs[0]);
+ /* perform opcode specific processing */
+ switch (op)
+ {
+ case QUERY:
+ if ((buflen -= QFIXEDSZ) < 0)
+ return (-1);
+ if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
+ return (-1);
+ cp += n;
+ buflen -= n;
+ putshort(type, cp);
+ cp += sizeof(u_short);
+
+ putshort(class, cp);
+ cp += sizeof(u_short);
+
+ hp->qdcount = htons(1);
+ if (op == QUERY || data == NULL)
+ break;
+ /* Make an additional record for completion domain. */
+ buflen -= RRFIXEDSZ;
+ if ((n = dn_comp(data, cp, buflen, dnptrs, lastdnptr)) < 0)
+ return (-1);
+ cp += n;
+ buflen -= n;
+ putshort(T_NULL, cp);
+ cp += sizeof(u_short);
+
+ putshort(class, cp);
+ cp += sizeof(u_short);
+
+ putlong(0, cp);
+ cp += sizeof(u_long);
+
+ putshort(0, cp);
+ cp += sizeof(u_short);
+
+ hp->arcount = htons(1);
+ break;
+
+ case IQUERY:
+ /* Initialize answer section */
+ if (buflen < 1 + RRFIXEDSZ + datalen)
+ return (-1);
+ *cp++ = '\0'; /* no domain name */
+ putshort(type, cp);
+ cp += sizeof(u_short);
+
+ putshort(class, cp);
+ cp += sizeof(u_short);
+
+ putlong(0, cp);
+ cp += sizeof(u_long);
+
+ putshort(datalen, cp);
+ cp += sizeof(u_short);
+
+ if (datalen)
+ {
+ memcpy(cp, data, datalen);
+ cp += datalen;
+ }
+ hp->ancount = htons(1);
+ break;
+
+#ifdef ALLOW_UPDATES
+ /*
+ * For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by
+ * UPDATEA (Record to be modified is followed by its
+ * replacement in msg.)
+ */
+ case UPDATEM:
+ case UPDATEMA:
+
+ case UPDATED:
+ /*
+ * The res code for UPDATED and UPDATEDA is the same;
+ * user calls them differently: specifies data for
+ * UPDATED; server ignores data if specified for
+ * UPDATEDA.
+ */
+ case UPDATEDA:
+ buflen -= RRFIXEDSZ + datalen;
+ if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
+ return (-1);
+ cp += n;
+ putshort(type, cp);
+ cp += sizeof(u_short);
+
+ putshort(class, cp);
+ cp += sizeof(u_short);
+
+ putlong(0, cp);
+ cp += sizeof(u_long);
+
+ putshort(datalen, cp);
+ cp += sizeof(u_short);
+
+ if (datalen)
+ {
+ memcpy(cp, data, datalen);
+ cp += datalen;
+ }
+ if ((op == UPDATED) || (op == UPDATEDA))
+ {
+ hp->ancount = htons(0);
+ break;
+ }
+ /* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA */
+
+ case UPDATEA: /* Add new resource record */
+ buflen -= RRFIXEDSZ + datalen;
+ if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
+ return (-1);
+ cp += n;
+ putshort(newrr->r_type, cp);
+ cp += sizeof(u_short);
+
+ putshort(newrr->r_class, cp);
+ cp += sizeof(u_short);
+
+ putlong(0, cp);
+ cp += sizeof(u_long);
+
+ putshort(newrr->r_size, cp);
+ cp += sizeof(u_short);
+
+ if (newrr->r_size)
+ {
+ memcpy(cp, newrr->r_data, newrr->r_size);
+ cp += newrr->r_size;
+ }
+ hp->ancount = htons(0);
+ break;
+
+#endif /* ALLOW_UPDATES */
+ }
+ return (cp - buf);
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/s_auth.c
+ * Copyright (C) 1992 Darren Reed
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: s_auth.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "res.h"
+#include "numeric.h"
+#include "patchlevel.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#if defined(__hpux)
+#include "inet.h"
+#endif
+#include <fcntl.h>
+#include "sock.h" /* If FD_ZERO isn't define up to this point */
+/* define it (BSD4.2 needs this) */
+#include "h.h"
+#include "fdlist.h"
+#include "fds.h"
+
+static void authsenderr(aClient *);
+
+/*
+ * start_auth
+ *
+ * Flag the client to show that an attempt to contact the ident server on
+ * the client's host. The connect and subsequently the socket are all
+ * put into 'non-blocking' mode. Should the connect or any later phase
+ * of the identifing process fail, it is aborted and the user is given
+ * a username of "unknown".
+ */
+void start_auth(aClient *cptr)
+{
+ struct sockaddr_in sock;
+ struct sockaddr_in localaddr;
+ int locallen;
+
+ Debug((DEBUG_NOTICE, "start_auth(%x) fd %d status %d",
+ cptr, cptr->fd, cptr->status));
+ if ((cptr->authfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+#ifdef USE_SYSLOG
+ syslog(LOG_ERR, "Unable to create auth socket for %s:%m",
+ get_client_name(cptr, TRUE));
+#endif
+ ircstp->is_abad++;
+ return;
+ }
+ if (cptr->authfd >= MAXCONNECTIONS)
+ {
+ sendto_realops_lev(DEBUG_LEV,"Can't allocate fd for auth on %s",
+ get_client_name(cptr, (IsServer(cptr) ? HIDEME : TRUE)));
+ close(cptr->authfd);
+ cptr->authfd = -1;
+ return;
+ }
+#ifdef SHOW_HEADERS
+ sendto_one(cptr, REPORT_DO_ID);
+#endif
+ set_non_blocking(cptr->authfd, cptr);
+ /*
+ * get the local address of the client and bind to that to make the
+ * auth request. This used to be done only for ifdef VIRTTUAL_HOST,
+ * but needs to be done for all clients since the ident request must
+ * originate from that same address-- and machines with multiple IP
+ * addresses are common now
+ */
+ locallen = sizeof(struct sockaddr_in);
+
+ memset(&localaddr, '\0', locallen);
+ getsockname(cptr->fd, (struct sockaddr *) &localaddr, &locallen);
+ localaddr.sin_port = htons(0);
+
+ if (bind(cptr->authfd, (struct sockaddr *) &localaddr,
+ sizeof(localaddr)) == -1)
+ {
+ report_error("binding auth stream socket %s:%s", cptr);
+ close(cptr->authfd);
+ cptr->authfd = -1;
+ return;
+ }
+
+ memcpy((char *) &sock.sin_addr, (char *) &cptr->ip,
+ sizeof(struct in_addr));
+
+ sock.sin_port = htons(113);
+ sock.sin_family = AF_INET;
+
+ if (connect(cptr->authfd, (struct sockaddr *) &sock,
+ sizeof(sock)) == -1 && errno != EINPROGRESS)
+ {
+ ircstp->is_abad++;
+ /* No error report from this... */
+ close(cptr->authfd);
+ cptr->authfd = -1;
+#ifdef SHOW_HEADERS
+ sendto_one(cptr, REPORT_FAIL_ID);
+#endif
+ return;
+ }
+
+ cptr->flags |= (FLAGS_WRAUTH | FLAGS_AUTH);
+ if (cptr->authfd > highest_fd)
+ highest_fd = cptr->authfd;
+
+ add_fd(cptr->authfd, FDT_AUTH, cptr);
+ return;
+}
+
+/*
+ * send_authports
+ *
+ * Send the ident server a query giving "theirport , ourport". The write
+ * is only attempted *once* so it is deemed to be a fail if the entire
+ * write doesn't write all the data given. This shouldnt be a problem
+ * since the socket should have a write buffer far greater than this
+ * message to store it in should problems arise. -avalon
+ */
+void send_authports(aClient *cptr)
+{
+ struct sockaddr_in us, them;
+ char authbuf[32];
+ int ulen, tlen;
+
+ Debug((DEBUG_NOTICE, "write_authports(%x) fd %d authfd %d stat %d",
+ cptr, cptr->fd, cptr->authfd, cptr->status));
+ tlen = ulen = sizeof(us);
+
+ if (getsockname(cptr->fd, (struct sockaddr *) &us, &ulen) ||
+ getpeername(cptr->fd, (struct sockaddr *) &them, &tlen))
+ {
+#ifdef USE_SYSLOG
+ syslog(LOG_DEBUG, "auth get{sock,peer}name error for %s:%m",
+ get_client_name(cptr, TRUE));
+#endif
+ authsenderr(cptr);
+ return;
+ }
+
+ (void) ircsprintf(authbuf, "%u , %u\r\n",
+ (unsigned int) ntohs(them.sin_port),
+ (unsigned int) ntohs(us.sin_port));
+
+ Debug((DEBUG_SEND, "sending [%s] to auth port %s.113",
+ authbuf, inetntoa((char *) &them.sin_addr)));
+
+ if (send(cptr->authfd, authbuf, strlen(authbuf), 0) != strlen(authbuf)) {
+ authsenderr(cptr);
+ return;
+ }
+
+ cptr->flags &= ~FLAGS_WRAUTH;
+
+ return;
+}
+
+/*
+ * authsenderr() *
+ * input - pointer to aClient output
+ */
+static void authsenderr(aClient *cptr)
+{
+ ircstp->is_abad++;
+
+ del_fd(cptr->authfd);
+
+ close(cptr->authfd);
+ if (cptr->authfd == highest_fd)
+ while (!local[highest_fd])
+ highest_fd--;
+ cptr->authfd = -1;
+ cptr->flags &= ~(FLAGS_AUTH | FLAGS_WRAUTH);
+#ifdef SHOW_HEADERS
+ sendto_one(cptr, REPORT_FAIL_ID);
+#endif
+
+ return;
+}
+
+/*
+ * read_authports
+ *
+ * read the reply (if any) from the ident server we connected to. The
+ * actual read processing here is pretty weak - no handling of the
+ * reply if it is fragmented by IP.
+ *
+ * Whoever wrote this code should be shot.
+ * Looks like it's trouncing on memory it shouldn't be.
+ * Rewriting, some credit goes to wd for saving me time with his code.
+ * - lucas
+ */
+
+#define AUTHBUFLEN 128
+
+void read_authports(aClient *cptr)
+{
+ char buf[AUTHBUFLEN], usern[USERLEN + 1];
+ int len, userncnt;
+ char *userid = "", *s, *reply, *os, *tmp;
+
+ len = recv(cptr->authfd, buf, AUTHBUFLEN, 0);
+
+ if(len > 0)
+ {
+ do
+ {
+ if(buf[len - 1] != '\n')
+ break;
+
+ buf[--len] = '\0';
+
+ if(len == 0)
+ break;
+
+ if(buf[len - 1] == '\r')
+ buf[--len] = '\0';
+
+ if(len == 0)
+ break;
+
+ s = strchr(buf, ':');
+ if(!s)
+ break;
+ s++;
+
+ while(IsSpace(*s))
+ s++;
+
+ reply = s;
+ if(strncmp(reply, "USERID", 6))
+ break;
+
+ s = strchr(reply, ':');
+ if(!s)
+ break;
+ s++;
+
+ while(IsSpace(*s))
+ s++;
+
+ os = s;
+
+ s = strchr(os, ':');
+ if(!s)
+ break;
+ s++;
+
+ while(IsSpace(*s))
+ s++;
+
+ userid = tmp = usern;
+ /* s is the pointer to the beginning of the userid field */
+ for(userncnt = USERLEN; *s && userncnt; s++)
+ {
+ if(*s == '@')
+ break;
+
+ if(!IsSpace(*s) && *s != ':')
+ {
+ *tmp++ = *s;
+ userncnt--;
+ }
+ }
+ *tmp = '\0';
+
+ } while(0);
+ }
+
+ del_fd(cptr->authfd);
+ close(cptr->authfd);
+ if (cptr->authfd == highest_fd)
+ while (!local[highest_fd])
+ highest_fd--;
+ cptr->authfd = -1;
+ ClearAuth(cptr);
+
+ if (!*userid)
+ {
+ ircstp->is_abad++;
+ strcpy(cptr->username, "unknown");
+#ifdef SHOW_HEADERS
+ sendto_one(cptr, REPORT_FAIL_ID);
+#endif
+ return;
+ }
+#ifdef SHOW_HEADERS
+ else
+ sendto_one(cptr, REPORT_FIN_ID);
+#endif
+
+ ircstp->is_asuc++;
+ strncpyzt(cptr->username, userid, USERLEN + 1);
+ cptr->flags |= FLAGS_GOTID;
+ return;
+}
+
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/s_bsd.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: s_bsd.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "res.h"
+#include "numeric.h"
+#include "patchlevel.h"
+#include "zlink.h"
+#include "throttle.h"
+#include "userban.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#if defined(SOL20)
+#include <sys/filio.h>
+#include <sys/select.h>
+#include <unistd.h>
+#endif
+#include "inet.h"
+#include <stdio.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <utmp.h>
+#include <sys/resource.h>
+#include "hooks.h"
+
+#ifdef AIX
+#include <time.h>
+#include <arpa/nameser.h>
+#else
+#include "nameser.h"
+#endif
+#include "resolv.h"
+
+/* If FD_ZERO isn't define up to this point,
+ * define it (BSD4.2 needs this) */
+
+#include "h.h"
+#include "fdlist.h"
+#include "fds.h"
+
+extern void engine_init();
+extern fdlist default_fdlist;
+extern int forked;
+extern void free_port(aPort *);
+
+#ifndef IN_LOOPBACKNET
+#define IN_LOOPBACKNET 0x7f
+#endif
+
+#if defined(MAXBUFFERS)
+int rcvbufmax = 0, sndbufmax = 0;
+#endif
+
+#ifdef MAXBUFFERS
+void reset_sock_opts(int, int);
+#endif
+
+static void set_listener_sock_opts(int, aListener *);
+static void set_listener_non_blocking(int, aListener *);
+/* listener list, count */
+aListener *listen_list = NULL;
+int listen_count = 0;
+
+
+aClient *local[MAXCONNECTIONS];
+int highest_fd = 0, resfd = -1;
+time_t timeofday;
+static struct sockaddr_in mysk;
+
+static struct sockaddr *connect_inet(aConnect *, aClient *, int *);
+static int check_init(aClient *, char *);
+static void set_sock_opts(int, aClient *);
+
+#if defined(MAXBUFFERS)
+static char *readbuf;
+#else
+static char readbuf[8192];
+#endif
+
+/* Silly macro to ignore certain report error statements */
+#define silent_report_error(x,y)
+
+
+/*
+ * Try and find the correct name to use with getrlimit() for setting
+ * the max. number of files allowed to be open by this process.
+ */
+
+#ifdef RLIMIT_FDMAX
+#define RLIMIT_FD_MAX RLIMIT_FDMAX
+#else
+#ifdef RLIMIT_NOFILE
+#define RLIMIT_FD_MAX RLIMIT_NOFILE
+#else
+#ifdef RLIMIT_OPEN_MAX
+#define RLIMIT_FD_MAX RLIMIT_OPEN_MAX
+#else
+#undef RLIMIT_FD_MAX
+#endif
+#endif
+#endif
+
+/*
+ * add_local_domain()
+ * Add the domain to hostname, if it is missing
+ * (as suggested by eps@TOASTER.SFSU.EDU)
+ */
+
+void add_local_domain(char *hname, int size)
+{
+#ifdef RES_INIT
+ /* try to fix up unqualified name */
+ if (!strchr(hname, '.'))
+ {
+ if (size < 3)
+ return;
+ if (!(_res.options & RES_INIT))
+ {
+ Debug((DEBUG_DNS, "res_init()"));
+ res_init();
+ }
+ if (_res.defdname[0])
+ {
+ strncat(hname, ".", size - 1);
+ strncat(hname, _res.defdname, size - 2);
+ }
+ }
+#endif
+ return;
+}
+
+/*
+ * Cannot use perror() within daemon. stderr is closed in
+ * ircd and cannot be used. And, worse yet, it might have
+ * been reassigned to a normal connection...
+ */
+
+/*
+ * report_error
+ * This a replacement for perror(). Record error to log and
+ * also send a copy to all *LOCAL* opers online.
+ * text is a *format* string for outputting error. It must
+ * contain only two '%s', the first will be replaced by the
+ * sockhost from the cptr, and the latter will be taken from
+ * sys_errlist[errno].
+ *
+ * cptr, if not NULL, is the *LOCAL* client associated with
+ * the error.
+ */
+
+void report_error(char *text, aClient * cptr)
+{
+ int errtmp = errno; /* debug may change 'errno' */
+ char *host;
+ int err, len = sizeof(err);
+ extern char *strerror();
+
+ host = (cptr) ? get_client_name(cptr, (IsServer(cptr) ? HIDEME : FALSE))
+ : "";
+
+ Debug((DEBUG_ERROR, text, host, strerror(errtmp)));
+ /*
+ * Get the *real* error from the socket (well try to anyway..). This
+ * may only work when SO_DEBUG is enabled but its worth the gamble
+ * anyway.
+ */
+
+#ifdef SO_ERROR
+ if (!IsMe(cptr) && cptr->fd >= 0)
+ if (!getsockopt(cptr->fd, SOL_SOCKET, SO_ERROR, (char *) &err, &len))
+ if (err)
+ errtmp = err;
+#endif
+ sendto_realops_lev(DEBUG_LEV, text, host, strerror(errtmp));
+#ifdef USE_SYSLOG
+ syslog(LOG_WARNING, text, host, strerror(errtmp));
+ if (!forked)
+ {
+ fprintf(stderr, text, host, strerror(errtmp));
+ fprintf(stderr, "\n");
+ }
+#endif
+ return;
+}
+
+void report_listener_error(char *text, aListener *lptr)
+{
+ int errtmp = errno; /* debug may change 'errno' */
+ char *host;
+ int err, len = sizeof(err);
+ extern char *strerror();
+
+ host = get_listener_name(lptr);
+
+ Debug((DEBUG_ERROR, text, host, strerror(errtmp)));
+
+#ifdef SO_ERROR
+ if (lptr->fd >= 0)
+ if (!getsockopt(lptr->fd, SOL_SOCKET, SO_ERROR, (char *) &err, &len))
+ if (err)
+ errtmp = err;
+#endif
+ sendto_realops_lev(DEBUG_LEV, text, host, strerror(errtmp));
+#ifdef USE_SYSLOG
+ syslog(LOG_WARNING, text, host, strerror(errtmp));
+#endif
+ if (!forked)
+ {
+ fprintf(stderr, text, host, strerror(errtmp));
+ fprintf(stderr, "\n");
+ }
+ return;
+}
+
+/*
+ * open_listeners()
+ *
+ * cycle through our entire ports list and open them if they
+ * arent already open.
+ * Added Feb/04 -epi
+ */
+
+void
+open_listeners()
+{
+ aPort *tmp;
+ if(!ports)
+ sendto_realops("Lost all port configurations!");
+ for(tmp = ports; tmp; tmp = tmp->next)
+ {
+ if(tmp->lstn)
+ continue;
+ add_listener(tmp);
+ }
+ return;
+}
+
+/*
+ * add_listener
+ *
+ * Create a new client which is essentially the stub like 'me' to be used
+ * for a socket that is passive (listen'ing for connections to be
+ * accepted).
+ * Backported from defunct 1.6 and updated for aPort structure in Feb04.
+ * I'm assuming lucas rewrote this originally. -epi
+ */
+int add_listener(aPort *aport)
+{
+ aListener *lptr;
+ aListener lstn;
+ struct sockaddr_in server;
+ int ad[4], len = sizeof(server);
+ char ipname[20];
+
+ memset(&lstn, 0, sizeof(aListener));
+ ad[0] = ad[1] = ad[2] = ad[3] = 0;
+
+ if(!BadPtr(aport->allow))
+ {
+ strncpyzt(lstn.allow_string, aport->allow, sizeof(lstn.allow_string));
+ sscanf(lstn.allow_string, "%d.%d.%d.%d", &ad[0], &ad[1],
+ &ad[2], &ad[3]);
+ ircsprintf(ipname, "%d.%d.%d.%d", ad[0], ad[1], ad[2], ad[3]);
+ lstn.allow_ip.s_addr = inet_addr(ipname);
+ }
+
+ if (!BadPtr(aport->address) && (*aport->address != '*'))
+ {
+ lstn.vhost_ip.s_addr = inet_addr(aport->address);
+ strncpyzt(lstn.vhost_string, aport->address, sizeof(lstn.vhost_string));
+ }
+
+ lstn.port = aport->port;
+
+ if(lstn.port <= 0) /* stop stupidity cold */
+ return -1;
+
+ lstn.fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (lstn.fd < 0)
+ {
+ report_listener_error("opening stream socket %s:%s", &lstn);
+ return -1;
+ }
+
+ set_listener_sock_opts(lstn.fd, &lstn);
+
+ memset(&server, '\0', sizeof(server));
+ server.sin_family = AF_INET;
+
+ if (lstn.vhost_ip.s_addr)
+ server.sin_addr.s_addr = lstn.vhost_ip.s_addr;
+ else
+ server.sin_addr.s_addr = INADDR_ANY;
+
+ server.sin_port = htons(lstn.port);
+
+ if (bind(lstn.fd, (struct sockaddr *) &server, sizeof(struct sockaddr_in)))
+ {
+ report_listener_error("binding stream socket %s:%s", &lstn);
+ close(lstn.fd);
+ return -1;
+ }
+
+ if (getsockname(lstn.fd, (struct sockaddr *) &server, &len))
+ {
+ report_listener_error("getsockname failed for %s:%s", &lstn);
+ close(lstn.fd);
+ return -1;
+ }
+
+ if (lstn.fd > highest_fd)
+ highest_fd = lstn.fd;
+
+#ifdef SOMAXCONN
+ if(listen(lstn.fd, SOMAXCONN))
+#else
+ if(listen(lstn.fd, HYBRID_SOMAXCONN))
+#endif
+ {
+ report_listener_error("error listening on FD %s:%s", &lstn);
+ close(lstn.fd);
+ return -1;
+ }
+
+
+ lptr = (aListener *) MyMalloc(sizeof(aListener));
+ memcpy(lptr, &lstn, sizeof(aListener));
+
+ if(local[lptr->fd])
+ {
+ report_listener_error("!!!! listener fd is held by client"
+ " in local[] array %s:%s", &lstn);
+ abort();
+ }
+
+ lptr->aport = aport;
+ aport->lstn = lptr;
+
+ set_listener_non_blocking(lptr->fd, lptr);
+ add_fd(lptr->fd, FDT_LISTENER, lptr);
+ set_fd_flags(lptr->fd, FDF_WANTREAD);
+
+ listen_count++;
+ lptr->next = listen_list;
+ listen_list = lptr;
+
+ lptr->lasttime = timeofday;
+
+ return 0;
+}
+
+void close_listener(aListener *lptr)
+{
+ aListener *alptr, *alptrprev = NULL;
+ aPort *aport, *aportl, *aportn = NULL;
+
+ del_fd(lptr->fd);
+ close(lptr->fd);
+
+ /* drop our conf link */
+ aport = lptr->aport;
+ aport->lstn = NULL;
+
+ /* and now drop the conf itself */
+
+ for(aportl = ports ; aportl ; aportl = aportl->next)
+ {
+ if(aportl == aport)
+ {
+ if(aportn)
+ aportn->next = aportl->next;
+ else
+ ports = aportl->next;
+ free_port(aportl);
+ break;
+ }
+ aportn = aportl;
+ }
+
+ /* now drop the listener */
+
+ for(alptr = listen_list; alptr; alptr = alptr->next)
+ {
+ if(alptr == lptr)
+ {
+ if(alptrprev)
+ alptrprev->next = alptr->next;
+ else
+ listen_list = alptr->next;
+ MyFree(lptr);
+ listen_count--;
+ break;
+ }
+ alptrprev = alptr;
+ }
+}
+
+/*
+ * close_listeners
+ *
+ * Close and free all clients which are marked as having their socket open
+ * and in a state where they can accept connections. Unix sockets have
+ * the path to the socket unlinked for cleanliness.
+ */
+void close_listeners()
+{
+ aListener *lptr, *lptrnext;
+
+ lptr = listen_list;
+
+ while(lptr)
+ {
+ lptrnext = lptr->next;
+ if(lptr->clients <= 0)
+ close_listener(lptr);
+ else
+ /* if we cant close it, mark it for closing
+ * when we loose all of our connections */
+ lptr->aport->legal = -1;
+ lptr = lptrnext;
+ }
+}
+
+/* init_sys */
+void init_sys()
+{
+ int fd;
+
+#ifdef RLIMIT_FD_MAX
+ struct rlimit limit;
+
+ if (!getrlimit(RLIMIT_FD_MAX, &limit))
+ {
+ if (limit.rlim_max < MAXCONNECTIONS)
+ {
+ printf("FATAL: System is only allowing %ld open files.\n",
+ (long)limit.rlim_max);
+ printf("ircd requires at least %ld.\n", (long)MAXCONNECTIONS);
+ printf("Fix the system account limits or recompile ircd.\n");
+ printf("Aborting...\n");
+ exit(-1);
+ }
+ /* set limit to exactly what we can handle */
+ limit.rlim_cur = MAXCONNECTIONS;
+ if (setrlimit(RLIMIT_FD_MAX, &limit) == -1)
+ {
+ printf("FATAL: Unable to set open file limit to %ld:\n%s\n",
+ (long)limit.rlim_cur, strerror(errno));
+ printf("Aborting...\n");
+ exit(-1);
+ }
+ }
+#endif
+
+ printf("\nIrcd is now becoming a daemon.\n");
+
+#if !defined(SOL20)
+ setlinebuf(stderr);
+#endif
+
+ for (fd = 3; fd < MAXCONNECTIONS; fd++)
+ {
+ close(fd);
+ local[fd] = NULL;
+ }
+ local[1] = NULL;
+
+ if (bootopt & BOOT_TTY)
+ {
+ engine_init();
+
+ /* debugging is going to a tty */
+ resfd = init_resolver(0x1f);
+ add_fd(resfd, FDT_RESOLVER, NULL);
+ set_fd_flags(resfd, FDF_WANTREAD);
+ return;
+ }
+
+ close(1);
+
+ if (!(bootopt & BOOT_DEBUG) && !(bootopt & BOOT_STDERR))
+ close(2);
+
+
+ if ((isatty(0)) && !(bootopt & BOOT_OPER) && !(bootopt & BOOT_STDERR))
+ {
+ int pid;
+
+ if ((pid = fork()) < 0)
+ {
+ if ((fd = open("/dev/tty", O_RDWR)) >= 0)
+ write(fd, "Couldn't fork!\n", 15); /* crude, but effective */
+ exit(0);
+ }
+ else if (pid > 0)
+ exit(0);
+
+ setsid();
+
+ close(0); /* fd 0 opened by inetd */
+ local[0] = NULL;
+ }
+
+ engine_init();
+ resfd = init_resolver(0x1f);
+ add_fd(resfd, FDT_RESOLVER, NULL);
+ set_fd_flags(resfd, FDF_WANTREAD);
+ return;
+}
+
+void write_pidfile()
+{
+#ifdef IRCD_PIDFILE
+ int fd;
+ char buff[20];
+
+ if ((fd = open(IRCD_PIDFILE, O_CREAT | O_WRONLY, 0600)) >= 0)
+ {
+ ircsprintf(buff, "%5d\n", (int) getpid());
+ if (write(fd, buff, strlen(buff)) == -1)
+ Debug((DEBUG_NOTICE, "Error writing to pid file %s", IRCD_PIDFILE));
+ close(fd);
+ return;
+ }
+#ifdef DEBUGMODE
+ else
+ Debug((DEBUG_NOTICE, "Error opening pid file %s", IRCD_PIDFILE));
+#endif
+#endif
+}
+
+/*
+ * Initialize the various name strings used to store hostnames. This is
+ * set from either the server's sockhost (if client fd is a tty or
+ * localhost) or from the ip# converted into a string. 0 = success, -1
+ * = fail.
+ */
+static int check_init(aClient * cptr, char *sockn)
+{
+ struct sockaddr_in sk;
+ int len = sizeof(struct sockaddr_in);
+
+ /* If descriptor is a tty, special checking... * IT can't EVER be a tty */
+
+ if (getpeername(cptr->fd, (struct sockaddr *) &sk, &len) == -1)
+ return -1;
+
+ strcpy(sockn, (char *) inetntoa((char *) &sk.sin_addr));
+ if (inet_netof(sk.sin_addr) == IN_LOOPBACKNET)
+ {
+ cptr->hostp = NULL;
+ strncpyzt(sockn, me.sockhost, HOSTLEN);
+ }
+ memcpy((char *) &cptr->ip, (char *) &sk.sin_addr, sizeof(struct in_addr));
+
+ cptr->port = (int) (ntohs(sk.sin_port));
+
+ return 0;
+}
+
+/*
+ * Ordinary client access check. Look for conf lines which have the
+ * same status as the flags passed. 0 = Success -1 = Access denied -2 =
+ * Bad socket.
+ */
+int check_client(aClient *cptr)
+{
+ static char sockname[HOSTLEN + 1];
+ struct hostent *hp = NULL;
+ int i;
+
+ Debug((DEBUG_DNS, "ch_cl: check access for %s[%s]",
+ cptr->name, inetntoa((char *) &cptr->ip)));
+
+ if (check_init(cptr, sockname))
+ return -2;
+
+ hp = cptr->hostp;
+ /*
+ * Verify that the host to ip mapping is correct both ways and that
+ * the ip#(s) for the socket is listed for the host.
+ */
+ if (hp)
+ {
+ for (i = 0; hp->h_addr_list[i]; i++)
+ if (!memcmp(hp->h_addr_list[i], (char *) &cptr->ip,
+ sizeof(struct in_addr)))
+ break;
+
+ if (!hp->h_addr_list[i])
+ {
+ sendto_one(cptr, "NOTICE AUTH :*** Your forward and reverse"
+ " DNS do not match, ignoring hostname.");
+ hp = NULL;
+ }
+ }
+
+ if ((i = attach_Iline(cptr, hp, sockname)))
+ {
+ Debug((DEBUG_DNS, "ch_cl: access denied: %s[%s]",
+ cptr->name, sockname));
+ return i;
+ }
+
+ Debug((DEBUG_DNS, "ch_cl: access ok: %s[%s]", cptr->name, sockname));
+
+ if (inet_netof(cptr->ip) == IN_LOOPBACKNET ||
+ inet_netof(cptr->ip) == inet_netof(mysk.sin_addr))
+ {
+ ircstp->is_loc++;
+ cptr->flags |= FLAGS_LOCAL;
+ }
+ return 0;
+}
+
+#define CFLAG CONF_CONNECT_SERVER
+#define NFLAG CONF_NOCONNECT_SERVER
+
+/*
+ * check_server_init(), check_server() check access for a server given
+ * its name (passed in cptr struct). Must check for all C/N lines which
+ * have a name which matches the name given and a host which matches. A
+ * host alias which is the same as the server name is also acceptable
+ * in the host field of a C/N line. 0 = Success -1 = Access denied -2 =
+ * Bad socket.
+ *
+ * This was terrible code. Terrible! Almost fucking scary! Rewritten into
+ * a single function, much prettier. Feb04 -epi
+ */
+int check_server_init(aClient * cptr)
+{
+ aConnect *aconn = NULL;
+ struct hostent *hp = NULL;
+ char sockname[HOSTLEN + 1], fullname[HOSTLEN + 1];
+ char abuff[HOSTLEN + USERLEN + 2];
+ int i = 0, ok = 0;
+
+ if (check_init(cptr, sockname))
+ return -2;
+
+ if (!(aconn = find_aConnect(cptr->name)))
+ {
+ Debug((DEBUG_DNS, "No Connect block for %s", cptr->name));
+ return -1;
+ }
+
+ /*
+ * * If the servername is a hostname, either an alias (CNAME) or
+ * real name, then check with it as the host. Use gethostbyname()
+ * to check for servername as hostname.
+ */
+ if (!cptr->hostp)
+ {
+ char *s;
+ Link lin;
+
+ /*
+ * * Do a lookup for the CONF line *only* and not the server
+ * connection else we get stuck in a nasty state since it
+ * takes a SERVER message to get us here and we cant
+ * interrupt that very well.
+ */
+ lin.value.aconn = aconn;
+ lin.flags = ASYNC_CONF;
+ nextdnscheck = 1;
+ if ((s = strchr(aconn->host, '@')))
+ s++;
+ else
+ s = aconn->host;
+ Debug((DEBUG_DNS, "sv_ci:cache lookup (%s)", s));
+ if((hp = gethost_byname(s, &lin)))
+ {
+ for (i = 0; hp->h_addr_list[i]; i++)
+ if (!memcmp(hp->h_addr_list[i], (char *) &cptr->ip,
+ sizeof(struct in_addr)))
+ break;
+ if (!hp->h_addr_list[i])
+ {
+ sendto_realops_lev(DEBUG_LEV,
+ "Server IP# Mismatch: %s != %s[%08x]",
+ inetntoa((char *) &cptr->ip), hp->h_name,
+ *((unsigned long *) hp->h_addr));
+ hp = NULL;
+ }
+ }
+ }
+ else
+ {
+ hp = cptr->hostp;
+ for (i = 0; hp->h_addr_list[i]; i++)
+ if (!memcmp(hp->h_addr_list[i], (char *) &cptr->ip,
+ sizeof(struct in_addr)))
+ break;
+ }
+
+ if(hp)
+ {
+ strncpyzt(fullname, cptr->name, sizeof(fullname));
+ add_local_domain(fullname, HOSTLEN - strlen(fullname));
+ Debug((DEBUG_DNS, "sv_cl: gethostbyaddr: %s->%s",
+ sockname, fullname));
+ ircsprintf(abuff, "%s@%s", cptr->username, fullname);
+ get_sockhost(cptr, fullname);
+ for (i = 0; hp->h_addr_list[i]; i++)
+ {
+ if(!memcmp((char *) &aconn->ipnum, (char *) hp->h_addr_list[i],
+ sizeof(struct in_addr)))
+ ok = 1;
+ else
+ ok = 0;
+ }
+ }
+ else
+ {
+ /* having no luck finding a host.. check against IP */
+ if(!memcmp((char *) &aconn->ipnum, (char *) &cptr->ip,
+ sizeof(struct in_addr)))
+ ok = 1;
+ else
+ ok = 0;
+ }
+
+ /* if they dont match up, then away with them */
+ if (!ok)
+ {
+ get_sockhost(cptr, sockname);
+ return -1;
+ }
+ /* check for Ulined access and link it if nessecary */
+ if(find_aUserver(cptr->name))
+ cptr->flags |= FLAGS_ULINE;
+ make_server(cptr);
+ cptr->serv->aconn = aconn;
+ aconn->acpt = cptr;
+ set_effective_class(cptr);
+
+ if ((aconn->ipnum.s_addr == -1))
+ memcpy((char *) &aconn->ipnum, (char *) &cptr->ip,
+ sizeof(struct in_addr));
+
+ get_sockhost(cptr, aconn->host);
+
+ Debug((DEBUG_DNS, "sv_cl: access ok: %s[%s]", cptr->name, cptr->sockhost));
+ return 0;
+}
+
+/*
+ * completed_connection
+ * Complete non-blocking
+ * connect()-sequence. Check access and terminate connection,
+ * if trouble detected.
+ *
+ * Return TRUE if successfully completed - FALSE if failed and ClientExit
+ */
+int completed_connection(aClient * cptr)
+{
+ aConnect *aconn;
+
+ if(!(cptr->flags & FLAGS_BLOCKED))
+ unset_fd_flags(cptr->fd, FDF_WANTWRITE);
+ unset_fd_flags(cptr->fd, FDF_WANTREAD);
+
+ SetHandshake(cptr);
+
+ if (!(aconn = find_aConnect(cptr->name)))
+ {
+ sendto_realops("Lost Config for %s", get_client_name(cptr, HIDEME));
+ return -1;
+ }
+ if (!BadPtr(aconn->cpasswd))
+ sendto_one(cptr, "PASS %s :TS", aconn->cpasswd);
+
+ /* pass on our capabilities to the server we /connect'd */
+#ifdef HAVE_ENCRYPTION_ON
+ if(!(aconn->flags & CONN_DKEY))
+ sendto_one(cptr, "CAPAB SSJOIN NOQUIT BURST UNCONNECT ZIP"
+ " NICKIP TSMODE");
+ else
+ {
+ sendto_one(cptr, "CAPAB SSJOIN NOQUIT BURST UNCONNECT DKEY"
+ " ZIP NICKIP TSMODE");
+ SetWantDKEY(cptr);
+ }
+#else
+ sendto_one(cptr, "CAPAB SSJOIN NOQUIT BURST UNCONNECT ZIP NICKIP TSMODE");
+#endif
+
+ if(aconn->flags & CONN_ZIP)
+ cptr->capabilities |= CAPAB_DOZIP;
+
+ sendto_one(cptr, "SERVER %s 1 :%s", my_name_for_link(me.name, aconn),
+ me.info);
+#ifdef DO_IDENTD
+ /* Is this the right place to do this? dunno... -Taner */
+ if (!IsDead(cptr))
+ start_auth(cptr);
+#endif
+
+ check_client_fd(cptr);
+ return (IsDead(cptr)) ? -1 : 0;
+}
+
+/*
+ * close_connection
+ * Close the physical connection. This function must make
+ * MyConnect(cptr) == FALSE, and set cptr->from == NULL.
+ */
+void close_connection(aClient *cptr)
+{
+ aConnect *aconn;
+
+ if (IsServer(cptr))
+ {
+ ircstp->is_sv++;
+ ircstp->is_sbs += cptr->sendB;
+ ircstp->is_sbr += cptr->receiveB;
+ ircstp->is_sks += cptr->sendK;
+ ircstp->is_skr += cptr->receiveK;
+ ircstp->is_sti += timeofday - cptr->firsttime;
+ if (ircstp->is_sbs > 2047)
+ {
+ ircstp->is_sks += (ircstp->is_sbs >> 10);
+ ircstp->is_sbs &= 0x3ff;
+ }
+ if (ircstp->is_sbr > 2047)
+ {
+ ircstp->is_skr += (ircstp->is_sbr >> 10);
+ ircstp->is_sbr &= 0x3ff;
+ }
+ /* schedule a quick reconnect if we've been connected a long time */
+ if((aconn = find_aConnect_match(cptr->name, cptr->username,
+ cptr->sockhost)))
+ {
+ aconn->hold = time(NULL);
+ aconn->hold += (aconn->hold - cptr->since > HANGONGOODLINK) ?
+ HANGONRETRYDELAY : aconn->class->connfreq;
+ if (nextconnect > aconn->hold)
+ nextconnect = aconn->hold;
+ }
+ }
+ else if (IsClient(cptr))
+ {
+ ircstp->is_cl++;
+ ircstp->is_cbs += cptr->sendB;
+ ircstp->is_cbr += cptr->receiveB;
+ ircstp->is_cks += cptr->sendK;
+ ircstp->is_ckr += cptr->receiveK;
+ ircstp->is_cti += timeofday - cptr->firsttime;
+ if (ircstp->is_cbs > 2047)
+ {
+ ircstp->is_cks += (ircstp->is_cbs >> 10);
+ ircstp->is_cbs &= 0x3ff;
+ }
+ if (ircstp->is_cbr > 2047)
+ {
+ ircstp->is_ckr += (ircstp->is_cbr >> 10);
+ ircstp->is_cbr &= 0x3ff;
+ }
+ }
+ else
+ ircstp->is_ni++;
+
+ /* remove outstanding DNS queries. */
+ del_queries((char *) cptr);
+
+ if (cptr->authfd >= 0)
+ {
+ del_fd(cptr->authfd);
+ close(cptr->authfd);
+ cptr->authfd = -1;
+ }
+
+ if (cptr->fd >= 0)
+ {
+ dump_connections(cptr->fd);
+ local[cptr->fd] = NULL;
+ del_fd(cptr->fd);
+ close(cptr->fd);
+ cptr->fd = -2;
+ SBufClear(&cptr->sendQ);
+ SBufClear(&cptr->recvQ);
+ memset(cptr->passwd, '\0', sizeof(cptr->passwd));
+ if(cptr->lstn)
+ cptr->lstn->clients--;
+ }
+ for (; highest_fd > 0; highest_fd--)
+ if (local[highest_fd])
+ break;
+
+ clear_conflinks(cptr);
+
+ cptr->from = NULL; /* ...this should catch them! >:) --msa */
+
+ /* if we're the last socket open on this listener,
+ * check to make sure the listener is even supposed to be
+ * open, and close it if its not -epi
+ */
+ if (cptr->lstn && (cptr->lstn->clients <= 0) &&
+ (cptr->lstn->aport->legal == -1))
+ close_listener(cptr->lstn);
+
+ return;
+}
+
+#ifdef MAXBUFFERS
+/* reset_sock_opts type = 0 = client, 1 = server */
+void reset_sock_opts(int fd, int type)
+{
+#define CLIENT_BUFFER_SIZE 4096
+#define SEND_BUF_SIZE 2920
+ int opt;
+
+ opt = type ? rcvbufmax : CLIENT_BUFFER_SIZE;
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &opt, sizeof(opt)) < 0)
+ sendto_realops("REsetsockopt(SO_RCVBUF) for fd %d (%s) failed",
+ fd, type ? "server" : "client");
+ opt = type ? sndbufmax : SEND_BUF_SIZE;
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &opt, sizeof(opt)) < 0)
+ sendto_realops("REsetsockopt(SO_SNDBUF) for fd %d (%s) failed",
+ fd, type ? "server" : "client");
+}
+#endif /* MAXBUFFERS */
+
+/* set_sock_opts */
+static void set_sock_opts(int fd, aClient * cptr)
+{
+ int opt;
+
+#ifdef SO_REUSEADDR
+ opt = 1;
+ if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (char *) &opt,
+ sizeof(opt)) < 0)
+ silent_report_error("setsockopt(SO_REUSEADDR) %s:%s", cptr);
+#endif
+#if defined(SO_DEBUG) && defined(DEBUGMODE) && 0
+ /* Solaris with SO_DEBUG writes to syslog by default */
+#if !defined(SOL20) || defined(USE_SYSLOG)
+ opt = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_DEBUG, (char *) &opt, sizeof(opt)) < 0)
+ silent_report_error("setsockopt(SO_DEBUG) %s:%s", cptr);
+#endif /* SOL20 */
+#endif
+#ifdef SO_USELOOPBACK
+ opt = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_USELOOPBACK, (char *) &opt,
+ sizeof(opt)) < 0)
+ silent_report_error("setsockopt(SO_USELOOPBACK) %s:%s", cptr);
+#endif
+#ifdef SO_RCVBUF
+#if defined(MAXBUFFERS)
+ if (rcvbufmax == 0)
+ {
+ int optlen;
+
+ optlen = sizeof(rcvbufmax);
+ getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &rcvbufmax, &optlen);
+ while ((rcvbufmax < 16385) && (setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
+ (char *) (char *) &rcvbufmax,optlen) >= 0))
+ rcvbufmax += 1024;
+ getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &rcvbufmax, &optlen);
+ readbuf = (char *) malloc(rcvbufmax * sizeof(char));
+ }
+ if (IsServer(cptr))
+ opt = rcvbufmax;
+ else
+ opt = 4096;
+#else
+ opt = 8192;
+#endif
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &opt, sizeof(opt)) < 0)
+ silent_report_error("setsockopt(SO_RCVBUF) %s:%s", cptr);
+#endif
+#ifdef SO_SNDBUF
+#if defined(MAXBUFFERS)
+ if (sndbufmax == 0)
+ {
+ int optlen;
+
+ optlen = sizeof(sndbufmax);
+ getsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &sndbufmax, &optlen);
+ while ((sndbufmax < 16385) && (setsockopt (fd, SOL_SOCKET, SO_SNDBUF,
+ (char *) &sndbufmax, optlen) >= 0))
+ sndbufmax += 1024;
+ getsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &sndbufmax, &optlen);
+ }
+ if (IsServer(cptr))
+ opt = sndbufmax;
+ else
+ opt = 4096;
+#else
+ opt = 8192;
+#endif
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &opt, sizeof(opt)) < 0)
+ silent_report_error("setsockopt(SO_SNDBUF) %s:%s", cptr);
+#endif
+#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
+ {
+#if defined(MAXBUFFERS)
+ char *s = readbuf, *t = readbuf + (rcvbufmax * sizeof(char)) / 2;
+ opt = (rcvbufmax * sizeof(char)) / 8;
+#else
+ char *s = readbuf, *t = readbuf + sizeof(readbuf) / 2;
+
+ opt = sizeof(readbuf) / 8;
+#endif
+ if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS, t, &opt) < 0)
+ silent_report_error("getsockopt(IP_OPTIONS) %s:%s", cptr);
+ else if (opt > 0)
+ {
+ for (*readbuf = '\0'; opt > 0; opt--, s += 3)
+ ircsprintf(s, "%02.2x:", *t++);
+ *s = '\0';
+ sendto_realops("Connection %s using IP opts: (%s)",
+ get_client_name(cptr, HIDEME), readbuf);
+ }
+ if (setsockopt(fd, IPPROTO_IP, IP_OPTIONS, (char *) NULL, 0) < 0)
+ silent_report_error("setsockopt(IP_OPTIONS) %s:%s", cptr);
+ }
+#endif
+}
+
+static void set_listener_sock_opts(int fd, aListener *lptr)
+{
+ int opt;
+
+#ifdef SO_REUSEADDR
+ opt = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &opt,
+ sizeof(opt)) < 0)
+ report_listener_error("setsockopt(SO_REUSEADDR) %s:%s", lptr);
+#endif
+#if defined(SO_DEBUG) && defined(DEBUGMODE) && 0
+ /*
+ * Solaris with SO_DEBUG writes to syslog by default
+ */
+#if !defined(SOL20) || defined(USE_SYSLOG)
+ opt = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_DEBUG, (char *) &opt, sizeof(opt)) < 0)
+ report_listener_error("setsockopt(SO_DEBUG) %s:%s", lptr);
+#endif /* SOL20 */
+#endif
+#ifdef SO_USELOOPBACK
+ opt = 1;
+ if (setsockopt (fd, SOL_SOCKET, SO_USELOOPBACK, (char *) &opt,
+ sizeof(opt)) < 0)
+ report_listener_error("setsockopt(SO_USELOOPBACK) %s:%s", lptr);
+#endif
+#ifdef SO_RCVBUF
+# if defined(MAXBUFFERS)
+ if (rcvbufmax == 0)
+ {
+ int optlen;
+
+ optlen = sizeof(rcvbufmax);
+ getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &rcvbufmax, &optlen);
+ while ((rcvbufmax < 16385) && (setsockopt (fd, SOL_SOCKET, SO_RCVBUF,
+ (char *) (char *) &rcvbufmax, optlen) >= 0))
+ rcvbufmax += 1024;
+ getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &rcvbufmax, &optlen);
+ readbuf = (char *) malloc(rcvbufmax * sizeof(char));
+ }
+ opt = 4096;
+# else
+ opt = 8192;
+# endif
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &opt, sizeof(opt)) < 0)
+ report_listener_error("setsockopt(SO_RCVBUF) %s:%s", lptr);
+#endif
+#ifdef SO_SNDBUF
+#if defined(MAXBUFFERS)
+ if (sndbufmax == 0)
+ {
+ int optlen;
+
+ optlen = sizeof(sndbufmax);
+ getsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &sndbufmax, &optlen);
+ while ((sndbufmax < 16385) && (setsockopt (fd, SOL_SOCKET, SO_SNDBUF,
+ (char *) &sndbufmax, optlen) >= 0))
+ sndbufmax += 1024;
+ getsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &sndbufmax, &optlen);
+ }
+ opt = 4096;
+#else
+ opt = 8192;
+#endif
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &opt, sizeof(opt)) < 0)
+ report_listener_error("setsockopt(SO_SNDBUF) %s:%s", lptr);
+#endif
+}
+
+
+int get_sockerr(aClient * cptr)
+{
+ int errtmp = errno, err = 0, len = sizeof(err);
+
+#ifdef SO_ERROR
+ if (cptr->fd >= 0)
+ if (!getsockopt(cptr->fd, SOL_SOCKET, SO_ERROR, (char *) &err, &len))
+ if (err)
+ errtmp = err;
+#endif
+ return errtmp;
+}
+
+char *irc_get_sockerr(aClient *cptr)
+{
+ if(cptr->sockerr == 0)
+ return "No error";
+
+ if(cptr->sockerr > 0)
+ return strerror(cptr->sockerr);
+
+ switch(cptr->sockerr)
+ {
+ case -1: /* this is the default */
+ return "Unset error message [this is a bug!]";
+ case IRCERR_BUFALLOC:
+ return "dbuf allocation error";
+ case IRCERR_ZIP:
+ return "compression general failure";
+ default:
+ return "Unknown error!";
+ }
+
+ /* unreachable code, but the compiler is complaining.. */
+ return NULL;
+}
+
+/*
+ * * set_non_blocking
+ * Set the client connection into non-blocking mode.
+ */
+void set_non_blocking(int fd, aClient * cptr)
+{
+ int res, nonb = 0;
+
+ nonb |= O_NONBLOCK;
+ if ((res = fcntl(fd, F_GETFL, 0)) == -1)
+ silent_report_error("fcntl(fd, F_GETFL) failed for %s:%s", cptr);
+ else if (fcntl(fd, F_SETFL, res | nonb) == -1)
+ silent_report_error("fcntl(fd, F_SETL, nonb) failed for %s:%s", cptr);
+ return;
+}
+
+void set_listener_non_blocking(int fd, aListener *lptr)
+{
+ int res, nonb = 0;
+
+ nonb |= O_NONBLOCK;
+ if ((res = fcntl(fd, F_GETFL, 0)) == -1)
+ report_listener_error("fcntl(fd, F_GETFL) failed for %s:%s", lptr);
+ else if (fcntl(fd, F_SETFL, res | nonb) == -1)
+ report_listener_error("fcntl(fd, F_SETL, nonb) failed for %s:%s", lptr);
+ return;
+}
+
+
+/*
+ * Creates a client which has just connected to us on the given fd. The
+ * sockhost field is initialized with the ip# of the host. The client
+ * is added to the linked list of clients but isnt added to any hash
+ * tables yuet since it doesnt have a name.
+ */
+aClient *add_connection(aListener *lptr, int fd)
+{
+ Link lin;
+ aClient *acptr = NULL;
+ char *s, *t;
+ struct sockaddr_in addr;
+ int len = sizeof(struct sockaddr_in);
+ struct userBan *ban;
+
+ if (getpeername(fd, (struct sockaddr *) &addr, &len) == -1)
+ {
+ ircstp->is_ref++;
+ close(fd);
+ return NULL;
+ }
+
+ acptr = make_client(NULL, &me);
+
+ /*
+ * Copy ascii address to 'sockhost' just in case. Then we have
+ * something valid to put into error messages...
+ */
+ get_sockhost(acptr, (char *) inetntoa((char *) &addr.sin_addr));
+ memcpy((char *) &acptr->ip, (char *) &addr.sin_addr,
+ sizeof(struct in_addr));
+
+ acptr->port = ntohs(addr.sin_port);
+ /*
+ * Check that this socket (client) is allowed to accept
+ * connections from this IP#.
+ */
+ for (s = (char *) &lptr->allow_ip, t = (char *) &acptr->ip, len = 4;
+ len > 0; len--, s++, t++)
+ {
+ if (!*s)
+ continue;
+ if (*s != *t)
+ break;
+ }
+ if (len)
+ {
+ ircstp->is_ref++;
+ acptr->fd = -2;
+ free_client(acptr);
+ close(fd);
+ return NULL;
+ }
+
+ lptr->ccount++;
+ lptr->clients++;
+ add_fd(fd, FDT_CLIENT, acptr);
+ local[fd] = acptr;
+
+ acptr->fd = fd;
+ if (fd > highest_fd)
+ highest_fd = fd;
+
+ /* sockets inherit the options of their parents.. do we need these? */
+ set_non_blocking(acptr->fd, acptr);
+ set_sock_opts(acptr->fd, acptr);
+
+ acptr->lstn = lptr;
+ add_client_to_list(acptr);
+
+ ban = check_userbanned(acptr, UBAN_IP|UBAN_CIDR4|UBAN_WILDUSER, 0);
+ if(ban)
+ {
+ char *reason, *ktype;
+ int local;
+
+ local = (ban->flags & UBAN_LOCAL) ? 1 : 0;
+ ktype = local ? LOCAL_BANNED_NAME : NETWORK_BANNED_NAME;
+ reason = ban->reason ? ban->reason : ktype;
+
+ sendto_one(acptr, err_str(ERR_YOUREBANNEDCREEP), me.name, "*", ktype);
+ sendto_one(acptr, ":%s NOTICE * :*** You are not welcome on this %s.",
+ me.name, local ? "server" : "network");
+ sendto_one(acptr, ":%s NOTICE * :*** %s for %s",
+ me.name, ktype, reason);
+ sendto_one(acptr, ":%s NOTICE * :*** Your IP is %s",
+ me.name, inetntoa((char *)&acptr->ip.s_addr));
+ sendto_one(acptr, ":%s NOTICE * :*** For assistance, please email %s"
+ " and include everything shown here.", me.name,
+ local ? Local_Kline_Address : Network_Kline_Address);
+
+ ircstp->is_ref++;
+ ircstp->is_ref_1++;
+ throttle_force(inetntoa((char *)&acptr->ip.s_addr));
+ exit_client(acptr, acptr, &me, reason);
+
+ return NULL;
+ }
+
+ if(call_hooks(CHOOK_PREACCESS, acptr) == FLUSH_BUFFER)
+ return NULL;
+
+#ifdef SHOW_HEADERS
+ sendto_one(acptr, REPORT_DO_DNS);
+#endif
+ lin.flags = ASYNC_CLIENT;
+ lin.value.cptr = acptr;
+ Debug((DEBUG_DNS, "lookup %s", inetntoa((char *) &addr.sin_addr)));
+ acptr->hostp = gethost_byaddr((char *) &acptr->ip, &lin);
+ if (!acptr->hostp)
+ SetDNS(acptr);
+#ifdef SHOW_HEADERS
+ else
+ sendto_one(acptr, REPORT_FIN_DNSC);
+#endif
+ nextdnscheck = 1;
+
+#ifdef DO_IDENTD
+ start_auth(acptr);
+#endif
+ check_client_fd(acptr);
+ return acptr;
+}
+
+/* handle taking care of the client's recvq here */
+int do_client_queue(aClient *cptr)
+{
+ int dolen = 0, done;
+
+ while (SBufLength(&cptr->recvQ) && !NoNewLine(cptr) &&
+ ((cptr->status < STAT_UNKNOWN) || (cptr->since - timeofday < 10) ||
+ IsNegoServer(cptr)))
+ {
+ /* If it's become registered as a server, just parse the whole block */
+ if (IsServer(cptr) || IsNegoServer(cptr))
+ {
+#if defined(MAXBUFFERS)
+ dolen = sbuf_get(&cptr->recvQ, readbuf, rcvbufmax * sizeof(char));
+#else
+ dolen = sbuf_get(&cptr->recvQ, readbuf, sizeof(readbuf));
+#endif
+ if (dolen <= 0)
+ break;
+ if ((done = dopacket(cptr, readbuf, dolen)))
+ return done;
+ break;
+ }
+#if defined(MAXBUFFERS)
+ dolen = sbuf_getmsg(&cptr->recvQ, readbuf, rcvbufmax * sizeof(char));
+#else
+ dolen = sbuf_getmsg(&cptr->recvQ, readbuf, sizeof(readbuf));
+#endif
+
+ if (dolen <= 0)
+ {
+ if (dolen < 0)
+ return exit_client(cptr, cptr, cptr, "sbuf_getmsg fail");
+
+ if (SBufLength(&cptr->recvQ) < 510)
+ {
+ cptr->flags |= FLAGS_NONL;
+ break;
+ }
+ /* The buffer is full (more than 512 bytes) and it has no \n
+ * Some user is trying to trick us. Kill their recvq. */
+ SBufClear(&cptr->recvQ);
+ break;
+ }
+ else if(client_dopacket(cptr, readbuf, dolen) == FLUSH_BUFFER)
+ return FLUSH_BUFFER;
+ }
+
+ if(!(cptr->flags & FLAGS_HAVERECVQ) && SBufLength(&cptr->recvQ) &&
+ !NoNewLine(cptr))
+ {
+ add_to_list(&recvq_clients, cptr);
+ cptr->flags |= FLAGS_HAVERECVQ;
+ }
+
+ return 1;
+}
+
+/*
+ * read_packet
+ *
+ * Read a 'packet' of data from a connection and process it. Read in 8k
+ * chunks to give a better performance rating (for server connections).
+ * Do some tricky stuff for client connections to make sure they don't
+ * do any flooding >:-) -avalon
+ */
+
+#define MAX_CLIENT_RECVQ 8192
+
+int read_packet(aClient * cptr)
+{
+ int length = 0, done;
+
+ /* If data is ready, and the user is either not a person or
+ * is a person and has a recvq of less than MAX_CLIENT_RECVQ,
+ * read from this client
+ */
+ if (!(IsPerson(cptr) && SBufLength(&cptr->recvQ) > MAX_CLIENT_RECVQ))
+ {
+ errno = 0;
+
+#if defined(MAXBUFFERS)
+ if (IsPerson(cptr))
+ length = recv(cptr->fd, readbuf, 8192 * sizeof(char), 0);
+ else
+ length = recv(cptr->fd, readbuf, rcvbufmax * sizeof(char), 0);
+#else
+ length = recv(cptr->fd, readbuf, sizeof(readbuf), 0);
+#endif
+
+ cptr->lasttime = timeofday;
+ if (cptr->lasttime > cptr->since)
+ cptr->since = cptr->lasttime;
+ cptr->flags &= ~(FLAGS_PINGSENT | FLAGS_NONL);
+ /* If not ready, fake it so it isnt closed */
+ if (length == -1 && ((errno == EWOULDBLOCK) || (errno == EAGAIN)))
+ return 1;
+ if (length <= 0)
+ {
+ cptr->sockerr = length ? errno : 0;
+ return length;
+ }
+ }
+
+ /*
+ * For server connections, we process as many as we can without
+ * worrying about the time of day or anything :)
+ */
+ if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr) ||
+ IsNegoServer(cptr))
+ {
+ if (length > 0)
+ if ((done = dopacket(cptr, readbuf, length)))
+ return done;
+ }
+ else
+ {
+ /*
+ * Before we even think of parsing what we just read, stick
+ * it on the end of the receive queue and do it when its turn
+ * comes around. */
+ if (sbuf_put(&cptr->recvQ, readbuf, length) < 0)
+ return exit_client(cptr, cptr, cptr, "sbuf_put fail");
+
+ if (IsPerson(cptr) &&
+#ifdef NO_OPER_FLOOD
+ !IsAnOper(cptr) &&
+#endif
+ SBufLength(&cptr->recvQ) > CLIENT_FLOOD)
+ {
+ sendto_realops_lev(FLOOD_LEV, "Flood -- %s!%s@%s (%d) Exceeds %d"
+ " RecvQ", cptr->name[0] ? cptr->name : "*",
+ cptr->user ? cptr->user->username : "*",
+ cptr->user ? cptr->user->host : "*",
+ SBufLength(&cptr->recvQ), CLIENT_FLOOD);
+ return exit_client(cptr, cptr, cptr, "Excess Flood");
+ }
+ return do_client_queue(cptr);
+ }
+ return 1;
+}
+
+void read_error_exit(aClient *cptr, int length, int err)
+{
+ char fbuf[512];
+ char errmsg[512];
+
+ if (IsServer(cptr) || IsHandshake(cptr) || IsConnecting(cptr))
+ {
+ if (length == 0)
+ {
+ char *errtxt = "Server %s closed the connection";
+
+ ircsprintf(fbuf, "from %s: %s", me.name, errtxt);
+ sendto_gnotice(fbuf, get_client_name(cptr, HIDEME));
+ ircsprintf(fbuf, ":%s GNOTICE :%s", me.name, errtxt);
+ sendto_serv_butone(cptr, fbuf, get_client_name(cptr, HIDEME));
+ }
+ else
+ {
+ char *errtxt = (IsConnecting(cptr) || IsHandshake(cptr)) ?
+ "Connect error to %s (%s)" :
+ "Read error from %s, closing link (%s)";
+
+ ircsprintf(fbuf, "from %s: %s", me.name, errtxt);
+ sendto_gnotice(fbuf, get_client_name(cptr, HIDEME), strerror(err));
+ ircsprintf(fbuf, ":%s GNOTICE :%s", me.name, errtxt);
+ sendto_serv_butone(cptr, fbuf, get_client_name(cptr, HIDEME),
+ strerror(err));
+ }
+ }
+
+ if (err)
+ ircsprintf(errmsg, "Read error: %s", strerror(err));
+ else
+ ircsprintf(errmsg, "Client closed connection");
+
+ exit_client(cptr, cptr, &me, errmsg);
+}
+
+void accept_connection(aListener *lptr)
+{
+ static struct sockaddr_in addr;
+ int addrlen = sizeof(struct sockaddr_in);
+ char host[HOSTLEN + 2];
+ int newfd;
+ int i;
+
+ lptr->lasttime = timeofday;
+
+ for (i = 0; i < 100; i++) /* accept up to 100 times per call
+ * to deal with high connect rates */
+ {
+ if((newfd = accept(lptr->fd, (struct sockaddr *) &addr, &addrlen)) < 0)
+ {
+ switch(errno)
+ {
+#ifdef EMFILE
+ case EMFILE:
+ report_listener_error("Cannot accept connections %s:%s",
+ lptr);
+ break;
+#endif
+#ifdef ENFILE
+ case ENFILE:
+ report_listener_error("Cannot accept connections %s:%s",
+ lptr);
+ break;
+#endif
+ }
+ return;
+ }
+
+ strncpyzt(host, (char *) inetntoa((char *) &addr.sin_addr),
+ sizeof(host));
+
+ /* if they are throttled, drop them silently. */
+ if (throttle_check(host, newfd, NOW) == 0)
+ {
+ ircstp->is_ref++;
+ ircstp->is_throt++;
+ close(newfd);
+ return;
+ }
+
+ if (newfd >= MAX_ACTIVECONN)
+ {
+ ircstp->is_ref++;
+ sendto_realops_lev(CCONN_LEV,"All connections in use. fd: %d (%s)",
+ newfd,get_listener_name(lptr));
+ send(newfd, "ERROR :All connections in use\r\n", 32, 0);
+ close(newfd);
+ return;
+ }
+ if((lptr->aport->legal == -1))
+ {
+ ircstp->is_ref++;
+ send(newfd, "ERROR :This port is closed\r\n", 29, 0);
+ close(newfd);
+ return;
+ }
+ ircstp->is_ac++;
+
+ add_connection(lptr, newfd);
+#ifdef PINGNAZI
+ nextping = timeofday;
+#endif
+ }
+}
+
+int readwrite_client(aClient *cptr, int isread, int iswrite)
+{
+ /*
+ * NOTE
+ * We now do this in a more logical way.
+ * We request a write poll on a socket for two reasons
+ * - the socket is waiting for a connect() call
+ * - the socket is blocked
+ */
+
+ if(iswrite)
+ {
+ if (IsConnecting(cptr) && completed_connection(cptr))
+ {
+ char errmsg[512];
+
+ ircsprintf(errmsg, "Connect Error: %s", irc_get_sockerr(cptr));
+ return exit_client(cptr, cptr, &me, errmsg);
+ }
+
+ if(cptr->flags & FLAGS_BLOCKED)
+ {
+ cptr->flags &= ~FLAGS_BLOCKED;
+ unset_fd_flags(cptr->fd, FDF_WANTWRITE);
+ }
+ else
+ {
+ /* this may be our problem with occational 100% cpu looping
+ * we've experienced. jason suggested this, here we will try
+ * this and see if it happens at all -epi */
+ sendto_realops_lev(DEBUG_LEV, "Removing socket %d: reported ready"
+ " for write, but not blocking", cptr->fd);
+ /* This unset_fd_flags() does not appear to make any difference
+ * to the write set. The socket appears stuck, and there has
+ * to be a reason for it. Since we're experiencing a very low
+ * number of these, simply drop the client entirely, and treat
+ * this as a socket handling error. This is essentially a kludge
+ * however tracking down this bug will take a serious amount of
+ * time and testing - since its not easily reproducable. This
+ * will in the meantime prevent maxing the CPU. -epi
+ *
+ * unset_fd_flags(cptr->fd, FDF_WANTWRITE);
+ */
+ exit_client(cptr, cptr, &me, "Socket error (write)");
+ return FLUSH_BUFFER;
+ }
+
+ }
+
+ if (isread)
+ {
+ int length = read_packet(cptr);
+
+ if(length == FLUSH_BUFFER)
+ return length;
+
+ if(length <= 0)
+ {
+ read_error_exit(cptr, length, cptr->sockerr);
+ return FLUSH_BUFFER;
+ }
+ }
+
+ if (IsDead(cptr))
+ {
+ char errmsg[512];
+
+ ircsprintf(errmsg, "Write Error: %s", (cptr->flags & FLAGS_SENDQEX) ?
+ "SendQ Exceeded" : irc_get_sockerr(cptr));
+ return exit_client(cptr, cptr, &me, errmsg);
+ }
+
+ return 1;
+}
+
+/* connect_server */
+int connect_server(aConnect *aconn, aClient * by, struct hostent *hp)
+{
+ struct sockaddr *svp;
+ aClient *cptr, *c2ptr;
+ char *s;
+ int errtmp, len;
+
+ Debug((DEBUG_NOTICE, "Connect to %s[%s] @%s", aconn->name, aconn->host,
+ inetntoa((char *) &aconn->ipnum)));
+
+ if ((c2ptr = find_server(aconn->name, NULL)))
+ {
+ sendto_ops("Server %s already present from %s",
+ aconn->name, get_client_name(c2ptr, HIDEME));
+ if (by && IsPerson(by) && !MyClient(by))
+ sendto_one(by, ":%s NOTICE %s :Server %s already present from %s",
+ me.name, by->name, aconn->name,
+ get_client_name(c2ptr, HIDEME));
+ return -1;
+ }
+ /*
+ * If we dont know the IP# for this host and itis a hostname and not
+ * a ip# string, then try and find the appropriate host record.
+ */
+ if ((!aconn->ipnum.s_addr))
+ {
+ Link lin;
+
+ lin.flags = ASYNC_CONNECT;
+ lin.value.aconn = aconn;
+ nextdnscheck = 1;
+ s = (char *) strchr(aconn->host, '@');
+ s++; /* should NEVER be NULL */
+ if ((aconn->ipnum.s_addr = inet_addr(s)) == -1)
+ {
+ aconn->ipnum.s_addr = 0;
+ hp = gethost_byname(s, &lin);
+ Debug((DEBUG_NOTICE, "co_sv: hp %x ac %x na %s ho %s",
+ hp, aconn, aconn->name, s));
+ if (!hp)
+ return 0;
+ memcpy((char *) &aconn->ipnum, hp->h_addr, sizeof(struct in_addr));
+ }
+ }
+ cptr = make_client(NULL, &me);
+ cptr->hostp = hp;
+ /* Copy these in so we have something for error detection. */
+ strncpyzt(cptr->name, aconn->name, sizeof(cptr->name));
+ strncpyzt(cptr->sockhost, aconn->host, HOSTLEN + 1);
+ svp = connect_inet(aconn, cptr, &len);
+
+ if (!svp)
+ {
+ if (cptr->fd >= 0)
+ close(cptr->fd);
+ cptr->fd = -2;
+ free_client(cptr);
+ return -1;
+ }
+
+ set_non_blocking(cptr->fd, cptr);
+ set_sock_opts(cptr->fd, cptr);
+ signal(SIGALRM, dummy);
+ if (connect(cptr->fd, svp, len) < 0 && errno != EINPROGRESS)
+ {
+ errtmp = errno; /* other system calls may eat errno */
+ report_error("Connect to host %s failed: %s", cptr);
+ if (by && IsPerson(by) && !MyClient(by))
+ sendto_one(by, ":%s NOTICE %s :Connect to server %s failed.",
+ me.name, by->name, cptr->name);
+ close(cptr->fd);
+ cptr->fd = -2;
+ free_client(cptr);
+ errno = errtmp;
+ if (errno == EINTR)
+ errno = ETIMEDOUT;
+ return -1;
+ }
+
+ make_server(cptr);
+ cptr->serv->aconn = aconn;
+
+ /* The socket has been connected or connect is in progress. */
+ if (by && IsPerson(by))
+ {
+ strcpy(cptr->serv->bynick, by->name);
+ strcpy(cptr->serv->byuser, by->user->username);
+ strcpy(cptr->serv->byhost, by->user->host);
+ }
+ else
+ {
+ strcpy(cptr->serv->bynick, "AutoConn.");
+ *cptr->serv->byuser = '\0';
+ *cptr->serv->byhost = '\0';
+ }
+ cptr->serv->up = me.name;
+ if (cptr->fd > highest_fd)
+ highest_fd = cptr->fd;
+ local[cptr->fd] = cptr;
+ SetConnecting(cptr);
+
+ get_sockhost(cptr, aconn->host);
+ add_client_to_list(cptr);
+#ifdef PINGNAZI
+ nextping = timeofday;
+#endif
+
+ add_fd(cptr->fd, FDT_CLIENT, cptr);
+ cptr->flags |= FLAGS_BLOCKED;
+ set_fd_flags(cptr->fd, FDF_WANTREAD|FDF_WANTWRITE);
+
+ return 0;
+}
+
+static struct sockaddr *
+connect_inet(aConnect *aconn, aClient *cptr, int *lenp)
+{
+ static struct sockaddr_in server;
+ struct hostent *hp;
+ struct sockaddr_in sin;
+
+ /*
+ * Might as well get sockhost from here, the connection is attempted
+ * with it so if it fails its useless.
+ */
+ cptr->fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (cptr->fd >= MAX_ACTIVECONN)
+ {
+ sendto_realops("No more connections allowed (%s)", cptr->name);
+ return NULL;
+ }
+ memset((char *) &server, '\0', sizeof(server));
+ memset((char *) &sin, '\0', sizeof(sin));
+ server.sin_family = sin.sin_family = AF_INET;
+ get_sockhost(cptr, aconn->host);
+
+ if (aconn->source)
+ sin.sin_addr.s_addr = inet_addr(aconn->source);
+
+ if (cptr->fd < 0)
+ {
+ report_error("opening stream socket to server %s:%s", cptr);
+ cptr->fd = -2;
+ return NULL;
+ }
+ /*
+ * Bind to a local IP# (with unknown port - let unix decide) so *
+ * we have some chance of knowing the IP# that gets used for a host *
+ * with more than one IP#.
+ *
+ * No we don't bind it, not all OS's can handle connecting with an
+ * already bound socket, different ip# might occur anyway leading to
+ * a freezing select() on this side for some time.
+ */
+ if (aconn->source)
+ {
+ /*
+ * * No, we do bind it if we have virtual host support. If we
+ * don't explicitly bind it, it will default to IN_ADDR_ANY and
+ * we lose due to the other server not allowing our base IP
+ * --smg
+ */
+ if (bind(cptr->fd, (struct sockaddr *) &sin, sizeof(sin)) == -1)
+ {
+ report_error("error binding to local port for %s:%s", cptr);
+ close(cptr->fd);
+ return NULL;
+ }
+ }
+ /*
+ * By this point we should know the IP# of the host listed in the
+ * conf line, whether as a result of the hostname lookup or the ip#
+ * being present instead. If we dont know it, then the connect
+ * fails.
+ */
+ if (IsDigit(*aconn->host) && (aconn->ipnum.s_addr == -1))
+ aconn->ipnum.s_addr = inet_addr(aconn->host);
+ if (aconn->ipnum.s_addr == -1)
+ {
+ hp = cptr->hostp;
+ if (!hp)
+ {
+ Debug((DEBUG_FATAL, "%s: unknown host", aconn->host));
+ return NULL;
+ }
+ memcpy((char *) &aconn->ipnum, hp->h_addr, sizeof(struct in_addr));
+ }
+ memcpy((char *) &server.sin_addr, (char *) &aconn->ipnum,
+ sizeof(struct in_addr));
+
+ memcpy((char *) &cptr->ip, (char *) &aconn->ipnum,
+ sizeof(struct in_addr));
+
+ server.sin_port = htons((aconn->port > 0) ? aconn->port : PORTNUM);
+ *lenp = sizeof(server);
+ return (struct sockaddr *) &server;
+}
+
+/*
+ * find the real hostname for the host running the server (or one
+ * which matches the server's name) and its primary IP#. Hostname is
+ * stored in the client structure passed as a pointer.
+ */
+void get_my_name(aClient * cptr, char *name, int len)
+{
+ static char tmp[HOSTLEN + 1];
+ struct hostent *hp;
+
+ /*
+ * The following conflicts with both AIX and linux prototypes oh
+ * well, we can put up with the errors from other systems -Dianora
+ */
+
+ char *cname = cptr->name;
+
+ /* Setup local socket structure to use for binding to. */
+ memset((char *) &mysk, '\0', sizeof(mysk));
+ mysk.sin_family = AF_INET;
+
+ if (gethostname(name, len) == -1)
+ return;
+ name[len] = '\0';
+
+ /* assume that a name containing '.' is a FQDN */
+ if (!strchr(name, '.'))
+ add_local_domain(name, len - strlen(name));
+ /*
+ * If hostname gives another name than cname, then check if there
+ * is a CNAME record for cname pointing to hostname. If so accept
+ * cname as our name. meLazy
+ */
+ if (BadPtr(cname))
+ return;
+ if ((hp = gethostbyname(cname)) || (hp = gethostbyname(name)))
+ {
+ char *hname;
+ int i = 0;
+
+ for (hname = hp->h_name; hname; hname = hp->h_aliases[i++])
+ {
+ strncpyzt(tmp, hname, sizeof(tmp));
+ add_local_domain(tmp, sizeof(tmp) - strlen(tmp));
+ /*
+ * Copy the matching name over and store the 'primary' IP#
+ * as 'myip' which is used later for making the right one is
+ * used for connecting to other hosts.
+ */
+ if (!mycmp(me.name, tmp))
+ break;
+ }
+ if (mycmp(me.name, tmp))
+ strncpyzt(name, hp->h_name, len);
+ else
+ strncpyzt(name, tmp, len);
+ memcpy((char *) &mysk.sin_addr, hp->h_addr, sizeof(struct in_addr));
+
+ Debug((DEBUG_DEBUG, "local name is %s", get_client_name(&me, TRUE)));
+ }
+ return;
+}
+
+/*
+ * do_dns_async
+ *
+ * Called when the fd returned from init_resolver() has been selected for
+ * reading.
+ */
+void do_dns_async()
+{
+ static Link ln;
+ aClient *cptr;
+ aConnect *aconn;
+ struct hostent *hp;
+ int bytes, packets = 0;
+
+ do
+ {
+ ln.flags = -1;
+ hp = get_res((char *) &ln);
+ Debug((DEBUG_DNS, "%#x = get_res(%d,%#x)", hp, ln.flags,
+ ln.value.cptr));
+
+ switch (ln.flags)
+ {
+ case ASYNC_NONE:
+ /*
+ * no reply was processed that was outstanding or had
+ * a client still waiting.
+ */
+ break;
+ case ASYNC_CLIENT:
+ if ((cptr = ln.value.cptr))
+ {
+ del_queries((char *) cptr);
+#ifdef SHOW_HEADERS
+ sendto_one(cptr, REPORT_FIN_DNS);
+#endif
+ ClearDNS(cptr);
+ cptr->hostp = hp;
+ check_client_fd(cptr);
+ }
+ break;
+ case ASYNC_CONNECT:
+ aconn = ln.value.aconn;
+ if (hp && aconn)
+ {
+ memcpy((char *) &aconn->ipnum, hp->h_addr,
+ sizeof(struct in_addr));
+
+ connect_server(aconn, NULL, hp);
+ }
+ else
+ sendto_ops("Connect to %s failed: host lookup",
+ (aconn) ? aconn->host : "unknown");
+ break;
+ case ASYNC_CONF:
+ aconn = ln.value.aconn;
+ if (hp && aconn)
+ memcpy((char *) &aconn->ipnum, hp->h_addr,
+ sizeof(struct in_addr));
+
+ break;
+ default:
+ break;
+ }
+ if (ioctl(resfd, FIONREAD, &bytes) == -1)
+ bytes = 0;
+ packets++;
+ } while ((bytes > 0) && (packets < 512));
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/s_conf.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: s_conf.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "inet.h"
+#include <signal.h>
+#include "h.h"
+#include "userban.h"
+#include "confparse.h"
+
+/* This entire file has basically been rewritten from scratch with the
+ * exception of lookup_confhost and attach_Iline/attach_iline fucntions
+ * Feb04 -epi
+ */
+
+extern int rehashed;
+extern int forked;
+extern tConf tconftab[];
+extern sConf sconftab[];
+
+/* internally defined functions */
+
+static int lookup_confhost(aConnect *);
+static int attach_iline(aClient *, aAllow *, char *, int);
+
+/* externally defined functions */
+
+extern aClass *make_class();
+extern aOper *make_oper();
+extern aConnect *make_connect();
+extern aAllow *make_allow();
+extern struct Conf_Me *make_me();
+extern aPort *make_port();
+extern void read_shortmotd(char *);
+
+/* these are our global lists of ACTIVE conf entries */
+
+#define MAXUSERVS 24
+
+aConnect *connects = NULL; /* connects, C/N pairs */
+aAllow *allows = NULL; /* allows - I lines */
+Conf_Me *MeLine = NULL; /* meline - only one */
+aOper *opers = NULL; /* opers - Olines */
+aPort *ports = NULL; /* ports - P/M lines */
+aClass *classes = NULL;; /* classes - Ylines */
+char *uservers[MAXUSERVS]; /* uservers = Ulines */
+Conf_Modules *modules = NULL;
+
+/* this set of lists is used for loading and rehashing the config file */
+
+aConnect *new_connects = NULL;
+aAllow *new_allows = NULL;
+Conf_Me *new_MeLine = NULL;
+aOper *new_opers = NULL;
+aPort *new_ports = NULL;
+aClass *new_classes = NULL;
+char *new_uservers[MAXUSERVS+1]; /* null terminated array */
+Conf_Modules *new_modules = NULL;
+
+#ifdef LOCKFILE
+extern void do_pending_klines(void);
+#endif
+extern void confparse_error(char *, int);
+
+/* initclass()
+ * initialize the default class
+ */
+
+void initclass()
+{
+ new_classes = make_class();
+
+ DupString(new_classes->name, "default");
+ new_classes->connfreq = CONNECTFREQUENCY;
+ new_classes->pingfreq = PINGFREQUENCY;
+ new_classes->maxlinks = MAXIMUM_LINKS;
+ new_classes->maxsendq = MAXSENDQLENGTH;
+ new_classes->links = 0;
+}
+
+/* init_globals
+ * initialize our major globals to the defaults first
+ */
+
+void init_globals()
+{
+ strncpyzt(ProxyMonURL, DEFAULT_WGMON_URL, sizeof(ProxyMonURL));
+ strncpyzt(ProxyMonHost, DEFAULT_WGMON_HOST, sizeof(ProxyMonHost));
+ strncpyzt(Network_Name, DEFAULT_NETWORK, sizeof(Network_Name));
+ strncpyzt(Services_Name, DEFAULT_SERVICES_NAME, sizeof(Services_Name));
+ strncpyzt(Stats_Name, DEFAULT_STATS_NAME, sizeof(Stats_Name));
+ snprintf(NS_Services_Name, sizeof(NS_Services_Name), "%s@%s",
+ NICKSERV, Services_Name);
+ snprintf(CS_Services_Name, sizeof(CS_Services_Name), "%s@%s",
+ CHANSERV, Services_Name);
+ snprintf(MS_Services_Name, sizeof(MS_Services_Name), "%s@%s",
+ MEMOSERV, Services_Name);
+ snprintf(RS_Services_Name, sizeof(RS_Services_Name), "%s@%s",
+ ROOTSERV, Services_Name);
+ snprintf(OS_Stats_Name, sizeof(OS_Stats_Name), "%s@%s",
+ OPERSERV, Stats_Name);
+ snprintf(SS_Stats_Name, sizeof(SS_Stats_Name), "%s@%s",
+ STATSERV, Stats_Name);
+ snprintf(HS_Stats_Name, sizeof(HS_Stats_Name), "%s@%s",
+ HELPSERV, Stats_Name);
+ strncpyzt(NS_Register_URL, DEFAULT_NS_REGISTER_URL,
+ sizeof(NS_Register_URL));
+ strncpyzt(Network_Kline_Address, DEFAULT_NKLINE_ADDY,
+ sizeof(Network_Kline_Address));
+ strncpyzt(Local_Kline_Address, DEFAULT_LKLINE_ADDY,
+ sizeof(Local_Kline_Address));
+ strncpyzt(Staff_Address, DEFAULT_STAFF_ADDRESS, sizeof(Staff_Address));
+ maxchannelsperuser = DEFAULT_MAXCHANNELSPERUSER;
+ tsmaxdelta = DEFAULT_TSMAXDELTA;
+ tswarndelta = DEFAULT_TSWARNDELTA;
+ local_ip_limit = DEFAULT_LOCAL_IP_CLONES;
+ local_ip24_limit = DEFAULT_LOCAL_IP24_CLONES;
+ global_ip_limit = DEFAULT_GLOBAL_IP_CLONES;
+ global_ip24_limit = DEFAULT_GLOBAL_IP24_CLONES;
+}
+
+
+/* free_ routines
+ * free the requested conf structure
+ * feb.04 -epi
+ */
+
+void
+free_connect(aConnect *ptr)
+{
+ MyFree(ptr->host);
+ MyFree(ptr->apasswd);
+ MyFree(ptr->cpasswd);
+ MyFree(ptr->source);
+ MyFree(ptr->name);
+ MyFree(ptr->class_name);
+ MyFree(ptr);
+ return;
+}
+
+void
+free_allow(aAllow *ptr)
+{
+ MyFree(ptr->ipmask);
+ MyFree(ptr->passwd);
+ MyFree(ptr->hostmask);
+ MyFree(ptr->class_name);
+ MyFree(ptr);
+ return;
+}
+
+void
+free_oper(aOper *ptr)
+{
+ int i = 0;
+ while(ptr->hosts[i])
+ {
+ MyFree(ptr->hosts[i]);
+ i++;
+ }
+ MyFree(ptr->passwd);
+ MyFree(ptr->nick);
+ MyFree(ptr->class_name);
+ MyFree(ptr);
+ return;
+}
+
+void
+free_port(aPort *ptr)
+{
+ MyFree(ptr->allow);
+ MyFree(ptr->address);
+ MyFree(ptr);
+ return;
+}
+
+void
+free_class(aClass *ptr)
+{
+ MyFree(ptr->name);
+ MyFree(ptr);
+ return;
+}
+
+void expire_class(aClass *cl)
+{
+ aClass *ccl, *pcl = NULL;
+ if (cl->refs == 0 && cl->maxlinks == -1)
+ {
+ for (ccl = classes; ccl; ccl = ccl->next)
+ {
+ if (ccl == cl)
+ {
+ if (pcl)
+ pcl->next = ccl->next;
+ else
+ classes = ccl->next;
+ free_class(ccl);
+ break;
+ }
+ pcl = ccl;
+ }
+ }
+}
+
+/* clear_conflinks()
+ * remove associated confs from this client
+ * and free the conf if it is scheduled to be deleted
+ * Feb04 -epi
+ */
+
+void
+clear_conflinks(aClient *cptr)
+{
+ if (cptr->class)
+ {
+ cptr->class->links--;
+ cptr->class->refs--;
+ expire_class(cptr->class);
+ }
+ if(IsServer(cptr))
+ {
+ aConnect *x;
+ if((x = cptr->serv->aconn))
+ {
+ x->acpt = NULL;
+ if (x->legal == -1) /* scheduled for removal? */
+ {
+ aConnect *aconn = NULL;
+
+ if (x == connects)
+ connects = x->next;
+ else
+ {
+ for (aconn = connects;
+ aconn != NULL && aconn->next != x;
+ aconn = aconn->next);
+ if (aconn != NULL)
+ aconn->next = x->next;
+ else
+ sendto_realops_lev(DEBUG_LEV, "Deleting scheduled "
+ "connect, but it isn't in the "
+ "list?? [%s]", x->name);
+ }
+ x->class->refs--;
+ expire_class(x->class);
+ free_connect(x);
+ }
+ cptr->serv->aconn = NULL;
+ }
+ }
+ else if (cptr->user != NULL)
+ {
+ aAllow *x;
+ aOper *y;
+ if((x = cptr->user->allow))
+ {
+ x->clients--;
+ if(x->clients <= 0 && x->legal == -1)
+ {
+ /* remove this allow now that its empty */
+ aAllow *allow = NULL;
+ if (allows == x)
+ allows = x->next;
+ else
+ {
+ for (allow = allows;
+ allow != NULL && allow->next != x;
+ allow = allow->next);
+ if (allow != NULL)
+ allow->next = x->next;
+ else
+ sendto_realops_lev(DEBUG_LEV, "Deleting scheduled "
+ "allow, but it isn't in the list?? "
+ "[%s / %s]", x->ipmask,x->hostmask);
+ }
+ x->class->refs--;
+ expire_class(x->class);
+ free_allow(x);
+ }
+ cptr->user->allow = NULL;
+ }
+ if((y = cptr->user->oper))
+ {
+ y->opers--;
+ if(y->legal == -1 && y->opers <= 0)
+ {
+ aOper *oper = NULL;
+ if (opers == y)
+ opers = y->next;
+ else
+ {
+ for (oper = opers;
+ oper != NULL && oper->next != y;
+ oper = oper->next);
+ if (oper != NULL)
+ oper->next = y->next;
+ else
+ sendto_realops_lev(DEBUG_LEV, "Deleting scheduled "
+ "oper, but it isn't in the list?? "
+ "[%s]", y->nick);
+ }
+ y->class->refs--;
+ expire_class(y->class);
+ free_oper(y);
+ }
+ cptr->user->oper = NULL;
+ }
+ }
+ return;
+}
+
+/* find the appropriate conf and return it */
+
+aConnect *
+find_aConnect(char *name)
+{
+ aConnect *tmp;
+ for(tmp = connects; tmp; tmp = tmp->next)
+ if(!match(name, tmp->name))
+ break;
+ return tmp;
+}
+
+static inline aPort *
+find_port(int port, char *bind)
+{
+ aPort *tmp;
+ for(tmp = ports; tmp; tmp = tmp->next)
+ if (tmp->port == port)
+ {
+ if (tmp->address == bind) /* both NULL */
+ break;
+ if (tmp->address && bind && !mycmp(tmp->address, bind))
+ break;
+ }
+ return tmp;
+}
+
+aConnect *
+find_aConnect_match(char *name, char *username, char *host)
+{
+ aConnect *aconn;
+ char userhost[USERLEN + HOSTLEN + 3];
+
+ ircsprintf(userhost, "%s@%s", username, host);
+
+ for(aconn = connects; aconn; aconn = aconn->next)
+ {
+ if (aconn->legal == -1)
+ continue;
+ if(!mycmp(name, aconn->name) && !match(userhost, aconn->host))
+ break;
+ }
+ return aconn;
+}
+
+int
+find_aUserver(char *name)
+{
+ int i;
+ for(i = 0; uservers[i]; i++)
+ {
+ if(!mycmp(name, uservers[i]))
+ return 1;
+ }
+ return 0;
+}
+
+aOper *
+find_oper(char *name, char *username, char *sockhost, char *hostip)
+{
+ aOper *aoper;
+ char userhost[USERLEN + HOSTLEN + 3];
+ char userip[USERLEN + HOSTLEN + 3];
+ int i;
+
+ /* sockhost OR hostip must match our host field */
+
+
+ ircsprintf(userhost, "%s@%s", username, sockhost);
+ ircsprintf(userip, "%s@%s", username, hostip);
+
+ for(aoper = opers; aoper; aoper = aoper->next)
+ {
+ if (aoper->legal == -1)
+ continue;
+
+ for(i = 0; aoper->hosts[i]; i++)
+ {
+ if(!mycmp(name, aoper->nick) && (!match(aoper->hosts[i], userhost)
+ || !match(aoper->hosts[i], userip)))
+ return aoper;
+ }
+ }
+ return NULL;
+}
+
+static inline aOper *
+find_oper_byname(char *name)
+{
+ aOper *aoper;
+ for(aoper = opers; aoper; aoper = aoper->next)
+ if(!mycmp(name, aoper->nick))
+ break;
+ return aoper;
+}
+
+static inline aClass *
+find_class(char *name)
+{
+ aClass *tmp;
+ if(!name)
+ return find_class("default");
+ for(tmp = classes; tmp; tmp = tmp->next)
+ if(!mycmp(name, tmp->name))
+ break;
+ return tmp;
+}
+
+/* set_effective_class
+ * sets the class for cptr properly
+ */
+
+void
+set_effective_class(aClient *cptr)
+{
+ if (cptr->class)
+ {
+ cptr->class->links--;
+ cptr->class->refs--;
+ expire_class(cptr->class);
+ }
+ if(IsServer(cptr))
+ {
+ if(cptr->serv->aconn->class)
+ cptr->class = cptr->serv->aconn->class;
+ else
+ cptr->class = find_class("default");
+ }
+ else
+ {
+ if(cptr->user && cptr->user->oper)
+ cptr->class = cptr->user->oper->class;
+ else if(cptr->user && cptr->user->allow)
+ cptr->class = cptr->user->allow->class;
+ else
+ cptr->class = find_class("default");
+ }
+ cptr->class->refs++;
+ cptr->class->links++;
+ return;
+}
+
+
+/* find the first (best) I line to attach.
+ * rewritten in feb04 for the overdue death of aConfItem
+ * and all the shit that came with it. -epi
+ * Rewritten again in Mar04 to optimize and get rid of deceptive logic.
+ * Whoever wrote this originally must have been drunk... -Quension
+ */
+int
+attach_Iline(aClient *cptr, struct hostent *hp, char *sockhost)
+{
+ aAllow *allow;
+
+ static char useriphost[USERLEN + 1 + HOSTLEN + 1];
+ static char usernamehost[USERLEN + 1 + HOSTLEN + 1];
+ char *iphost;
+ char *namehost = NULL; /* squish compiler warning */
+ int len;
+
+ /* user@host in both buffers, plus pointers to host only */
+ len = ircsprintf(useriphost, "%s@", cptr->username);
+ iphost = useriphost + len;
+ strcpy(iphost, sockhost);
+ if (hp)
+ {
+ memcpy(usernamehost, useriphost, USERLEN+2);
+ namehost = usernamehost + len;
+ len = sizeof(usernamehost) - len;
+ strncpy(namehost, hp->h_name, len);
+ add_local_domain(namehost, len - strlen(namehost));
+ }
+
+ for (allow = allows; allow; allow = allow->next)
+ {
+ if(allow->legal == -1)
+ continue;
+
+ if (allow->port && (allow->port != cptr->lstn->port))
+ continue;
+
+ if (!allow->ipmask || !allow->hostmask)
+ return (attach_iline(cptr, allow, iphost, 0));
+
+ /* match hostmask against both resolved name and IP, prefer name */
+ if (allow->flags & CONF_FLAGS_I_MATCH_NAME)
+ {
+ if (allow->flags & CONF_FLAGS_I_NAME_HAS_AT)
+ {
+ if (hp && !match(allow->hostmask, usernamehost))
+ return (attach_iline(cptr, allow, namehost, 1));
+ if (!match(allow->hostmask, useriphost))
+ return (attach_iline(cptr, allow, hp?namehost:iphost, 1));
+ }
+ else
+ {
+ if (hp && !match(allow->hostmask, namehost))
+ return (attach_iline(cptr, allow, namehost, 0));
+ if (!match(allow->hostmask, iphost))
+ return (attach_iline(cptr, allow, hp?namehost:iphost, 0));
+ }
+ }
+
+ if (allow->flags & CONF_FLAGS_I_MATCH_HOST)
+ {
+ if (allow->flags & CONF_FLAGS_I_HOST_HAS_AT)
+ {
+ if (!match(allow->ipmask, useriphost))
+ return (attach_iline(cptr, allow, iphost, 1));
+ }
+ else
+ {
+ if (!match(allow->ipmask, iphost))
+ return (attach_iline(cptr, allow, iphost, 0));
+ }
+ }
+ }
+ return -1; /* no match */
+}
+
+/*
+ * rewrote to remove the "ONE" lamity *BLEH* I agree with comstud on
+ * this one. - Dianora
+ */
+static int
+attach_iline(aClient *cptr, aAllow *allow, char *uhost, int doid)
+{
+ if(allow->class->links >= allow->class->maxlinks)
+ return -3;
+
+ if (doid)
+ cptr->flags |= FLAGS_DOID;
+ get_sockhost(cptr, uhost);
+
+ cptr->user->allow = allow;
+ allow->clients++;
+
+ return 0;
+}
+
+/* confadd_ functions
+ * add a config item
+ * Feb.15/04 -epi
+ */
+static int oper_access[] =
+{
+ ~(OFLAG_ADMIN|OFLAG_SADMIN), '*',
+ OFLAG_LOCAL, 'o',
+ OFLAG_GLOBAL, 'O',
+ OFLAG_REHASH, 'r',
+ OFLAG_DIE, 'D',
+ OFLAG_RESTART, 'R',
+ OFLAG_GLOBOP, 'h',
+ OFLAG_WALLOP, 'w',
+ OFLAG_LOCOP, 'l',
+ OFLAG_LROUTE, 'c',
+ OFLAG_GROUTE, 'C',
+ OFLAG_LKILL, 'k',
+ OFLAG_GKILL, 'K',
+ OFLAG_KLINE, 'b',
+ OFLAG_UNKLINE, 'B',
+ OFLAG_LNOTICE, 'n',
+ OFLAG_GNOTICE, 'N',
+ OFLAG_ADMIN, 'A',
+ OFLAG_SADMIN, 'a',
+ OFLAG_UMODEc, 'u',
+ OFLAG_UMODEf, 'f',
+ OFLAG_UMODEF, 'F',
+ 0, 0 };
+
+int
+confadd_oper(cVar *vars[], int lnum)
+{
+ cVar *tmp;
+ aOper *x = make_oper();
+ int *i, flag, c = 0, hc = 0;
+ char *m = "*";
+
+ for(tmp = vars[c]; tmp; tmp = vars[++c])
+ {
+ if(tmp->type && (tmp->type->flag & SCONFF_NAME))
+ {
+ if(x->nick)
+ {
+ confparse_error("Multiple name definitions", lnum);
+ free_oper(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->nick, tmp->value);
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_HOST))
+ {
+ if((hc+1) > MAXHOSTS)
+ {
+ confparse_error("Excessive host definitions", lnum);
+ free_oper(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ if (!strchr(tmp->value, '@') && *tmp->value != '/')
+ {
+ char *newhost;
+ int len = 3;
+ len += strlen(tmp->value);
+ newhost = (char *) MyMalloc(len);
+ ircsprintf(newhost, "*@%s", tmp->value);
+ x->hosts[hc] = newhost;
+ }
+ else
+ DupString(x->hosts[hc], tmp->value);
+ hc++;
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_PASSWD))
+ {
+ if(x->passwd)
+ {
+ confparse_error("Multiple password definitions", lnum);
+ free_oper(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->passwd, tmp->value);
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_ACCESS))
+ {
+ if(x->flags > 0)
+ {
+ confparse_error("Multiple access definitions", lnum);
+ free_oper(x);
+ return -1;
+ }
+ for (m=(*tmp->value) ? tmp->value : m; *m; m++)
+ {
+ for (i=oper_access; (flag = *i); i+=2)
+ if (*m==(char)(*(i+1)))
+ {
+ x->flags |= flag;
+ break;
+ }
+ }
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_CLASS))
+ {
+ if(x->class_name)
+ {
+ confparse_error("Multiple class definitions", lnum);
+ free_oper(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->class_name, tmp->value);
+ }
+ }
+ if(!x->nick)
+ {
+ confparse_error("Lacking name in oper block", lnum);
+ free_oper(x);
+ return -1;
+ }
+ if(!x->hosts[0])
+ {
+ confparse_error("Lacking host in oper block", lnum);
+ free_oper(x);
+ return -1;
+ }
+ if(!x->passwd)
+ {
+ confparse_error("Lacking passwd in oper block", lnum);
+ free_oper(x);
+ return -1;
+ }
+ if(x->flags == 0)
+ {
+ confparse_error("Lacking access in oper block", lnum);
+ free_oper(x);
+ return -1;
+ }
+ x->next = new_opers;
+ new_opers = x;
+ return lnum;
+}
+
+static int server_info[] =
+{
+ CONN_ZIP, 'Z',
+ CONN_DKEY, 'E',
+ CONN_HUB, 'H',
+ 0, 0
+};
+
+int
+confadd_connect(cVar *vars[], int lnum)
+{
+ cVar *tmp;
+ aConnect *x = make_connect();
+ int *i, flag, c = 0;
+ char *m = "*";
+
+ for(tmp = vars[c]; tmp; tmp = vars[++c])
+ {
+ if(tmp->type && (tmp->type->flag & SCONFF_NAME))
+ {
+ if(x->name)
+ {
+ confparse_error("Multiple name definitions", lnum);
+ free_connect(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->name, tmp->value);
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_HOST))
+ {
+ if(x->host)
+ {
+ confparse_error("Multiple host definitions", lnum);
+ free_connect(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ if (!strchr(tmp->value, '@') && *tmp->value != '/')
+ {
+ char *newhost;
+ int len = 3;
+ len += strlen(tmp->value);
+ newhost = (char *) MyMalloc(len);
+ ircsprintf(newhost, "*@%s", tmp->value);
+ x->host = newhost;
+ }
+ else
+ DupString(x->host, tmp->value);
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_APASSWD))
+ {
+ if(x->apasswd)
+ {
+ confparse_error("Multiple apasswd definitions", lnum);
+ free_connect(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->apasswd, tmp->value);
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_CPASSWD))
+ {
+ if(x->cpasswd)
+ {
+ confparse_error("Multiple cpasswd definitions", lnum);
+ free_connect(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->cpasswd, tmp->value);
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_FLAGS))
+ {
+ if(x->flags > 0)
+ {
+ confparse_error("Multiple flag definitions", lnum);
+ free_connect(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ x->flags = 0;
+ for (m=(*tmp->value) ? tmp->value : m; *m; m++)
+ {
+ for (i=server_info; (flag = *i); i+=2)
+ if (*m==(char)(*(i+1)))
+ {
+ x->flags |= flag;
+ break;
+ }
+ }
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_PORT))
+ {
+ if(x->port > 0)
+ {
+ confparse_error("Multiple port definitions", lnum);
+ free_connect(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ x->port = atoi(tmp->value);
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_BIND))
+ {
+ if(x->source)
+ {
+ confparse_error("Multiple source definitions", lnum);
+ free_connect(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->source, tmp->value);
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_CLASS))
+ {
+ if(x->class_name)
+ {
+ confparse_error("Multiple class definitions", lnum);
+ free_connect(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->class_name, tmp->value);
+ }
+ }
+ if(!x->name)
+ {
+ confparse_error("Lacking name in connect block", lnum);
+ free_connect(x);
+ return -1;
+ }
+ if(!x->apasswd)
+ {
+ confparse_error("Lacking apasswd in connect block", lnum);
+ free_connect(x);
+ return -1;
+ }
+ if(!x->cpasswd)
+ {
+ confparse_error("Lacking cpasswd in connect block", lnum);
+ free_connect(x);
+ return -1;
+ }
+ if(!x->host)
+ {
+ confparse_error("Lacking host in connect block", lnum);
+ free_connect(x);
+ return -1;
+ }
+ x->next = new_connects;
+ new_connects = x;
+ return lnum;
+}
+
+int
+confadd_options(cVar *vars[], int lnum)
+{
+ cVar *tmp;
+ int c = 0;
+ char ctmp[512];
+ char *s;
+
+ /* here, because none of the option peice are interdependent
+ * all the items are added immediately. Makes life easier
+ * ...except the option flags, which are handled specially -Quension
+ */
+
+ for(tmp = vars[c]; tmp; tmp = vars[++c])
+ {
+ if(tmp->type && (tmp->type->flag & OPTF_NETNAME))
+ {
+ tmp->type = NULL;
+ strncpyzt(Network_Name, tmp->value, sizeof(Network_Name));
+ }
+ else if(tmp->type && (tmp->type->flag & OPTF_SERVNAME))
+ {
+ tmp->type = NULL;
+ strncpyzt(Services_Name, tmp->value, sizeof(Services_Name));
+ sprintf(ctmp, "%s@%s", NICKSERV, Services_Name);
+ strncpyzt(NS_Services_Name, ctmp, sizeof(NS_Services_Name));
+ sprintf(ctmp, "%s@%s", CHANSERV, Services_Name);
+ strncpyzt(CS_Services_Name, ctmp, sizeof(CS_Services_Name));
+ sprintf(ctmp, "%s@%s", MEMOSERV, Services_Name);
+ strncpyzt(MS_Services_Name, ctmp, sizeof(MS_Services_Name));
+ sprintf(ctmp, "%s@%s", ROOTSERV, Services_Name);
+ strncpyzt(RS_Services_Name, ctmp, sizeof(RS_Services_Name));
+ }
+ else if(tmp->type && (tmp->type->flag & OPTF_STATSNAME))
+ {
+ tmp->type = NULL;
+ strncpyzt(Stats_Name, tmp->value, sizeof(Stats_Name));
+ sprintf(ctmp, "%s@%s", OPERSERV, Stats_Name);
+ strncpyzt(OS_Stats_Name, ctmp, sizeof(OS_Stats_Name));
+ sprintf(ctmp, "%s@%s", STATSERV, Stats_Name);
+ strncpyzt(SS_Stats_Name, ctmp, sizeof(SS_Stats_Name));
+ sprintf(ctmp, "%s@%s", HELPSERV, Stats_Name);
+ strncpyzt(HS_Stats_Name, ctmp, sizeof(HS_Stats_Name));
+ }
+ else if(tmp->type && (tmp->type->flag & OPTF_WGMONHOST))
+ {
+ tmp->type = NULL;
+ new_confopts |= FLAGS_WGMONHOST;
+ strncpyzt(ProxyMonHost, tmp->value, sizeof(ProxyMonHost));
+ }
+ else if(tmp->type && (tmp->type->flag & OPTF_WGMONURL))
+ {
+ tmp->type = NULL;
+ new_confopts |= FLAGS_WGMONURL;
+ strncpyzt(ProxyMonURL, tmp->value, sizeof(ProxyMonURL));
+ }
+ else if(tmp->type && (tmp->type->flag & OPTF_NSREGURL))
+ {
+ tmp->type = NULL;
+ strncpyzt(NS_Register_URL, tmp->value, sizeof(NS_Register_URL));
+ }
+ else if(tmp->type && (tmp->type->flag & OPTF_MAXCHAN))
+ {
+ tmp->type = NULL;
+ maxchannelsperuser = atoi(tmp->value);
+ }
+ else if(tmp->type && (tmp->type->flag & OPTF_SERVTYPE))
+ {
+ tmp->type = NULL;
+ if(!mycmp("HUB", tmp->value))
+ {
+ new_confopts |= FLAGS_HUB;
+ new_confopts &= ~FLAGS_SERVHUB;
+ }
+ else if(!mycmp("SERVICESHUB", tmp->value))
+ {
+ new_confopts |= FLAGS_SERVHUB;
+ new_confopts |= FLAGS_HUB;
+ }
+ else if(!mycmp("CLIENT", tmp->value))
+ new_confopts &= ~(FLAGS_HUB|FLAGS_SERVHUB);
+ else
+ {
+ confparse_error("Unknown servtype in option block", lnum);
+ return -1;
+ }
+ }
+ else if(tmp->type && (tmp->type->flag & OPTF_NKLINEADDY))
+ {
+ tmp->type = NULL;
+ strncpyzt(Network_Kline_Address, tmp->value,
+ sizeof(Network_Kline_Address));
+ }
+ else if(tmp->type && (tmp->type->flag & OPTF_LKLINEADDY))
+ {
+ tmp->type = NULL;
+ strncpyzt(Local_Kline_Address, tmp->value,
+ sizeof(Local_Kline_Address));
+ }
+ else if(tmp->type && (tmp->type->flag & OPTF_STAFFADDY))
+ {
+ tmp->type = NULL;
+ strncpyzt(Staff_Address, tmp->value, sizeof(Staff_Address));
+ }
+ else if(tmp->type && (tmp->type->flag & OPTF_LCLONES))
+ {
+ tmp->type = NULL;
+ local_ip_limit = strtol(tmp->value, &s, 10);
+ if (*s == ':')
+ local_ip24_limit = atoi(s+1);
+ if (local_ip_limit < 1)
+ local_ip_limit = DEFAULT_LOCAL_IP_CLONES;
+ if (local_ip24_limit < 1)
+ local_ip24_limit = DEFAULT_LOCAL_IP24_CLONES;
+ }
+ else if(tmp->type && (tmp->type->flag & OPTF_GCLONES))
+ {
+ tmp->type = NULL;
+ global_ip_limit = strtol(tmp->value, &s, 10);
+ if (*s == ':')
+ global_ip24_limit = atoi(s+1);
+ if (global_ip_limit < 1)
+ global_ip_limit = DEFAULT_GLOBAL_IP_CLONES;
+ if (global_ip24_limit < 1)
+ global_ip24_limit = DEFAULT_GLOBAL_IP24_CLONES;
+ }
+ else if(tmp->type && (tmp->type->flag & OPTF_SMOTD))
+ {
+ tmp->type = NULL;
+ new_confopts |= FLAGS_SMOTD;
+ }
+ else if(tmp->type && (tmp->type->flag & OPTF_SMOTD))
+ {
+ tmp->type = NULL;
+ new_confopts |= FLAGS_SMOTD;
+ }
+ else if(tmp->type && (tmp->type->flag & OPTF_CRYPTPASS))
+ {
+ tmp->type = NULL;
+ new_confopts |= FLAGS_CRYPTPASS;
+ }
+ else if(tmp->type && (tmp->type->flag & OPTF_SHOWLINKS))
+ {
+ tmp->type = NULL;
+ new_confopts |= FLAGS_SHOWLINKS;
+ }
+ else if(tmp->type && (tmp->type->flag & OPTF_SPLITOPOK))
+ {
+ tmp->type = NULL;
+ new_confopts |= FLAGS_SPLITOPOK;
+ }
+ else if(tmp->type && (tmp->type->flag & OPTF_TSMAXDELTA))
+ {
+ tmp->type = NULL;
+ tsmaxdelta = atoi(tmp->value);
+ }
+ else if(tmp->type && (tmp->type->flag & OPTF_TSWARNDELTA))
+ {
+ tmp->type = NULL;
+ tswarndelta = atoi(tmp->value);
+ }
+ }
+ return lnum;
+}
+
+int
+confadd_allow(cVar *vars[], int lnum)
+{
+ cVar *tmp;
+ aAllow *x = make_allow();
+ int c = 0;
+ /* Currently, Allows are the only config types without
+ * easy identifiers - so we dont worry about duplicate types.
+ * -epi
+ */
+
+ for(tmp = vars[c]; tmp; tmp = vars[++c])
+ {
+ if(tmp->type && (tmp->type->flag & SCONFF_IPMASK))
+ {
+ if(x->ipmask)
+ {
+ confparse_error("Multiple ipmask definitions", lnum);
+ free_allow(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->ipmask, tmp->value);
+ if(strchr(x->ipmask, '@'))
+ x->flags |= CONF_FLAGS_I_HOST_HAS_AT;
+ x->flags |= CONF_FLAGS_I_MATCH_HOST;
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_HOST))
+ {
+ if(x->hostmask)
+ {
+ confparse_error("Multiple host definitions", lnum);
+ free_allow(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->hostmask, tmp->value);
+ if(strchr(x->hostmask, '@'))
+ x->flags |= CONF_FLAGS_I_NAME_HAS_AT;
+ x->flags |= CONF_FLAGS_I_MATCH_NAME;
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_PASSWD))
+ {
+ if(x->passwd)
+ {
+ confparse_error("Multiple passwd definitions", lnum);
+ free_allow(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->passwd, tmp->value);
+#if (RIDICULOUS_PARANOIA_LEVEL>=1)
+ if(myncmp(x->passwd, "oper", 4) == 0)
+ {
+ if((x->passwd[4] == '.') || (x->passwd[4] == '\0'))
+ {
+ char *tmpd = x->passwd;
+ char *tmp = x->passwd + 4;
+
+ x->flags |= CONF_FLAGS_I_OPERPORT;
+ if(*tmp)
+ tmp++;
+ DupString(x->passwd, tmp);
+ MyFree(tmpd);
+ }
+ }
+#endif
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_PORT))
+ {
+ if(x->port > 0)
+ {
+ confparse_error("Multiple host definitions", lnum);
+ free_allow(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ x->port = atoi(tmp->value);
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_CLASS))
+ {
+ if(x->class_name)
+ {
+ confparse_error("Multiple class definitions", lnum);
+ free_allow(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->class_name, tmp->value);
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_FLAGS))
+ {
+ char *s = tmp->value;
+
+ while (*s)
+ switch (*s++)
+ {
+ case 'm': x->flags |= CONF_FLAGS_I_OPERPORT; break;
+ case 'T': x->flags |= CONF_FLAGS_NOTHROTTLE; break;
+ case 'F': x->flags |= CONF_FLAGS_FORCEFLOOD; break;
+ case 'C': x->flags |= CONF_FLAGS_SKIPCLONES; break;
+ default:
+ confparse_error("Unknown flag", lnum);
+ free_allow(x);
+ return -1;
+ }
+
+ tmp->type = NULL;
+ }
+ }
+ if(!x->ipmask && !x->hostmask)
+ {
+ confparse_error("Lacking both ipmask and host for allow", lnum);
+ free_allow(x);
+ return -1;
+ }
+ if(!x->ipmask)
+ DupString(x->ipmask, "-");
+ if(!x->hostmask)
+ DupString(x->hostmask, "-");
+ x->next = new_allows;
+ new_allows = x;
+ return lnum;
+}
+
+int
+confadd_port(cVar *vars[], int lnum)
+{
+ cVar *tmp;
+ aPort *x;
+ int c = 0;
+
+ x = make_port();
+ for(tmp = vars[c]; tmp; tmp = vars[++c])
+ {
+ if(tmp->type && (tmp->type->flag & SCONFF_IPMASK))
+ {
+ if(x->allow)
+ {
+ confparse_error("Multiple ipmask definitions", lnum);
+ free_port(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->allow, tmp->value);
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_BIND))
+ {
+ if(x->address)
+ {
+ confparse_error("Multiple bind definitions", lnum);
+ free_port(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->address, tmp->value);
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_PORT))
+ {
+ if(x->port > 0)
+ {
+ confparse_error("Multiple port definitions", lnum);
+ free_port(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ x->port = atoi(tmp->value);
+ }
+ }
+ if(!(x->port > 0))
+ {
+ confparse_error("Lacking port in port block", lnum);
+ free_port(x);
+ return -1;
+ }
+ x->next = new_ports;
+ new_ports = x;
+ return lnum;
+}
+
+int
+confadd_global(cVar *vars[], int lnum)
+{
+ cVar *tmp;
+ Conf_Me *x = new_MeLine;
+ int c = 0;
+
+ /* note:
+ * we dont free this here because we'll do that if we pull out
+ */
+
+ if(!x)
+ {
+ x = make_me();
+ new_MeLine = x;
+ }
+
+ for(tmp = vars[c]; tmp; tmp = vars[++c])
+ {
+ if(tmp->type && (tmp->type->flag & SCONFF_NAME))
+ {
+ unsigned char *s;
+ int valid = 0;
+ if(x->servername)
+ {
+ confparse_error("Multiple name definitions", lnum);
+ return -1;
+ }
+ /* validate server name, based on m_server() */
+ for (s = tmp->value; *s; s++)
+ {
+ if (*s < ' ' || *s > '~')
+ {
+ valid = 0;
+ break;
+ }
+ if (*s == '.')
+ valid = 1;
+ }
+ if (!valid)
+ {
+ confparse_error("Invalid server name", lnum);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->servername, tmp->value);
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_INFO))
+ {
+ if(x->info)
+ {
+ confparse_error("Multiple info definitions", lnum);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->info, tmp->value);
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_DPASS))
+ {
+ if(x->diepass)
+ {
+ confparse_error("Multiple dpass definitions", lnum);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->diepass, tmp->value);
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_RPASS))
+ {
+ if(x->restartpass)
+ {
+ confparse_error("Multiple rpass definitions", lnum);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->restartpass, tmp->value);
+ }
+ }
+ if(!x->servername)
+ {
+ confparse_error("Lacking name definition in global block", lnum);
+ return -1;
+ }
+ if(!x->info)
+ {
+ confparse_error("Lacking info definition in global block", lnum);
+ return -1;
+ }
+ return lnum;
+}
+
+int
+confadd_admin(cVar *vars[], int lnum)
+{
+ cVar *tmp;
+ Conf_Me *x = new_MeLine;
+ int c = 0;
+
+ if(!x)
+ {
+ x = make_me();
+ new_MeLine = x;
+ }
+
+ if (x->admin[0])
+ {
+ confparse_error("Multiple admin blocks", lnum);
+ return -1;
+ }
+
+ for(tmp = vars[c]; tmp && (c != 3); tmp = vars[++c])
+ DupString(x->admin[c], tmp->value);
+
+ return lnum;
+}
+
+int
+confadd_class(cVar *vars[], int lnum)
+{
+ cVar *tmp;
+ aClass *x = make_class();
+ int c = 0;
+ char *s;
+
+ for(tmp = vars[c]; tmp; tmp = vars[++c])
+ {
+ if(tmp->type && (tmp->type->flag & SCONFF_NAME))
+ {
+ if(x->name)
+ {
+ confparse_error("Multiple name definitions", lnum);
+ free_class(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->name, tmp->value);
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_PINGFREQ))
+ {
+ if(x->pingfreq > 0)
+ {
+ confparse_error("Multiple pingfreq definitions", lnum);
+ free_class(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ x->pingfreq = atoi(tmp->value);
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_CONNFREQ))
+ {
+ if(x->connfreq > 0)
+ {
+ confparse_error("Multiple maxclones/connfreq definitions",
+ lnum);
+ free_class(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ x->connfreq = strtol(tmp->value, &s, 10);
+ if (*s == ':')
+ x->ip24clones = atoi(s+1);
+ if (x->connfreq < 1)
+ x->connfreq = 0;
+ if (x->ip24clones < 1)
+ x->ip24clones = 0;
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_MAXUSERS))
+ {
+ if(x->maxlinks > 0)
+ {
+ confparse_error("Multiple maxusers/maxlinks definitions"
+ " (you can only have one or the other)",
+ lnum);
+ free_class(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ x->maxlinks = atoi(tmp->value);
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_MAXSENDQ))
+ {
+ if(x->maxsendq > 0)
+ {
+ confparse_error("Multiple maxsendq definitions", lnum);
+ free_class(x);
+ return -1;
+ }
+ tmp->type = NULL;
+ x->maxsendq = atoi(tmp->value);
+ }
+ }
+ if(!x->name)
+ {
+ confparse_error("Lacking name definition", lnum);
+ free_class(x);
+ return -1;
+ }
+ if(!(x->maxsendq > 0))
+ {
+ confparse_error("Lacking maxsendq definition", lnum);
+ free_class(x);
+ return -1;
+ }
+ x->next = new_classes;
+ new_classes = x;
+ return lnum;
+}
+
+int
+confadd_kill(cVar *vars[], int lnum)
+{
+ cVar *tmp;
+ struct userBan *ban;
+ int i, c = 0;
+ char *ub_u = NULL, *ub_r = NULL, *host = NULL;
+ char fbuf[512];
+ aClient *ub_acptr;
+
+ for(tmp = vars[c]; tmp; tmp = vars[++c])
+ {
+ if(tmp->type && (tmp->type->flag & SCONFF_MASK))
+ {
+ if(host)
+ {
+ confparse_error("Multiple mask definitions", lnum);
+ return -1;
+ }
+ tmp->type = NULL;
+ if((host = strchr(tmp->value, '@')))
+ {
+ *host = '\0';
+ host++;
+ ub_u = tmp->value;
+ }
+ else
+ host = tmp->value;
+ }
+ if(tmp->type && (tmp->type->flag & SCONFF_REASON))
+ {
+ if(ub_r)
+ {
+ confparse_error("Multiple reason definitions", lnum);
+ return -1;
+ }
+ tmp->type = NULL;
+ ub_r = tmp->value;
+ break;
+ }
+ }
+ if(!host)
+ {
+ confparse_error("Lacking mask definition", lnum);
+ return -1;
+ }
+ ub_u = BadPtr(ub_u) ? "*" : ub_u;
+ ub_r = BadPtr(ub_r) ? "<No Reason>" : ub_r;
+
+ ban = make_hostbased_ban(ub_u, host);
+ if(!ban)
+ return lnum; /* this isnt a parser problem - dont pull out */
+
+ ban->flags |= UBAN_LOCAL;
+ DupString(ban->reason, ub_r);
+ ban->timeset = NOW;
+
+ add_hostbased_userban(ban);
+
+ /* Check local users against it */
+ for (i = 0; i <= highest_fd; i++)
+ {
+ if (!(ub_acptr = local[i]) || IsMe(ub_acptr) ||
+ IsLog(ub_acptr))
+ continue;
+
+ if (IsPerson(ub_acptr) && user_match_ban(ub_acptr, ban))
+ {
+ sendto_ops(LOCAL_BAN_NAME " active for %s",
+ get_client_name(ub_acptr, FALSE));
+ ircsprintf(fbuf, LOCAL_BANNED_NAME ": %s", ub_r);
+ exit_client(ub_acptr, ub_acptr, &me, fbuf);
+ i--;
+ }
+ }
+ return lnum;
+}
+
+int
+confadd_super(cVar *vars[], int lnum)
+{
+ cVar *tmp;
+ int c = 0;
+ int i;
+
+ /* If multiple super blocks are specified, set up to append */
+ for (i = 0; new_uservers[i]; i++)
+ ;
+
+ for(tmp = vars[c]; tmp; tmp = vars[++c])
+ {
+ if (i == MAXUSERVS)
+ {
+ confparse_error("Excessive super server definitions", lnum);
+ return -1;
+ }
+ DupString(new_uservers[i], tmp->value);
+ i++;
+ }
+ new_uservers[i] = NULL;
+ return lnum;
+}
+
+int
+confadd_restrict(cVar *vars[], int lnum)
+{
+ cVar *tmp;
+ int c = 0, type = 0;
+ char *mask = NULL, *reason = NULL;
+ struct simBan *ban;
+
+ for(tmp = vars[c]; tmp; tmp = vars[++c])
+ {
+ if(tmp->type && (tmp->type->flag & SCONFF_TYPE))
+ {
+ if(type > 0)
+ {
+ confparse_error("Multiple type definitions", lnum);
+ return -1;
+ }
+ tmp->type = NULL;
+ if(!mycmp("CHAN", tmp->value))
+ type = SBAN_CHAN;
+ else if(!mycmp("NICK", tmp->value))
+ type = SBAN_NICK;
+ else if(!mycmp("GCOS", tmp->value))
+ type = SBAN_GCOS;
+ else
+ {
+ confparse_error("Unknown type in restrict block", lnum);
+ return -1;
+ }
+ type |= SBAN_LOCAL;
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_MASK))
+ {
+ if(mask)
+ {
+ confparse_error("Mutliple mask definitions", lnum);
+ return -1;
+ }
+ tmp->type = NULL;
+ mask = tmp->value;
+ }
+ else if(tmp->type && (tmp->type->flag & SCONFF_REASON))
+ {
+ if(reason)
+ {
+ confparse_error("Multiple reason definitions", lnum);
+ return -1;
+ }
+ tmp->type = NULL;
+ reason = tmp->value;
+ }
+ }
+ if(!mask)
+ {
+ confparse_error("Missing mask in restrict block", lnum);
+ return -1;
+ }
+ if(!(type > 0))
+ {
+ confparse_error("Missing type in restrict block", lnum);
+ return -1;
+ }
+ ban = make_simpleban(type, mask);
+ if(!ban)
+ return lnum;
+ if(find_simban_exact(ban) != NULL) /* dont add duplicates */
+ {
+ simban_free(ban);
+ return lnum;
+ }
+ if(!reason)
+ {
+ if(type & SBAN_CHAN)
+ reason = "Reserved Channel";
+ else if(type & SBAN_NICK)
+ reason = "Reserved Nick";
+ else if(type & SBAN_GCOS)
+ reason = "Bad GCOS";
+ }
+ DupString(ban->reason, reason);
+ ban->timeset = NOW;
+
+ add_simban(ban);
+ return lnum;
+}
+
+int
+confadd_modules(cVar *vars[], int lnum)
+{
+ cVar *tmp;
+ Conf_Modules *x = new_modules;
+ int c = 0, ac = 0, oc = 0;
+
+ /* this is like the global block - we dont free here because we do
+ * it if we fail
+ */
+
+ if(!x)
+ {
+ x = (Conf_Modules *) MyMalloc(sizeof(Conf_Modules));
+ memset((char *) x, '\0', sizeof(Conf_Modules));
+ new_modules = x;
+ }
+ else
+ {
+ confparse_error("Multiple module blocks in config file", lnum);
+ return -1;
+ }
+
+ for(tmp = vars[c]; tmp; tmp = vars[++c])
+ {
+ if(tmp->type && (tmp->type->flag & MBTF_PATH))
+ {
+ if(x->module_path)
+ {
+ confparse_error("Multiple module paths defined", lnum);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->module_path, tmp->value);
+ }
+ else if(tmp->type && (tmp->type->flag & MBTF_AUTOLOAD))
+ {
+ if((ac+1) > 128)
+ {
+ confparse_error("Excessive autoloading modules (max 128)",
+ lnum);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->autoload[ac], tmp->value);
+ ac++;
+ }
+ else if(tmp->type && (tmp->type->flag & MBTF_OPTLOAD))
+ {
+ if((oc+1) > 128)
+ {
+ confparse_error("Excessive optional modules (max 128)", lnum);
+ return -1;
+ }
+ tmp->type = NULL;
+ DupString(x->optload[oc], tmp->value);
+ oc++;
+ }
+ }
+ if(!x->autoload[0] && !x->optload[0])
+ {
+ confparse_error("No modules defined in module block", lnum);
+ return -1;
+ }
+ return lnum;
+}
+
+
+/* set_classes
+ * after loading the config into temporary lists, we must
+ * set the appropriate classes for each conf. If we run into
+ * problems, then back out.
+ */
+
+static inline aClass *
+find_new_class(char *name)
+{
+ aClass *tmp;
+ if(!name)
+ return find_new_class("default");
+ for(tmp = new_classes; tmp; tmp = tmp->next)
+ if(!mycmp(name, tmp->name))
+ break;
+ return tmp;
+}
+
+char *
+set_classes(void)
+{
+ aConnect *aconn;
+ aAllow *allow;
+ aOper *aoper;
+
+ /* Note:
+ * You may be wondering why we're doing this here and appearently
+ * again in our merge routines! well, this is for sanity. if
+ * for whatever reason we dont have a class for each definition here,
+ * back out of the conf load immediately and we wont have distroyed
+ * or overwritten any of our active data.
+ * After we run our merge_classes() routine at the start of our
+ * merge, then some of these classes will update currently active
+ * classes and be free()'d - meaning some of these references are useless.
+ * That is why we run it again inside the merge routines.
+ * -epi
+ */
+
+ for(aconn = new_connects; aconn; aconn = aconn->next)
+ if(!(aconn->class = find_new_class(aconn->class_name)))
+ return aconn->class_name;
+ for(allow = new_allows; allow; allow = allow->next)
+ if(!(allow->class = find_new_class(allow->class_name)))
+ return allow->class_name;
+ for(aoper = new_opers; aoper; aoper = aoper->next)
+ if(!(aoper->class = find_new_class(aoper->class_name)))
+ return aoper->class_name;
+ return NULL;
+}
+
+
+/* merge routines. used to mirge together new lists and old lists
+ * after a rehash. Feb27/04 -epi
+ */
+
+static void
+merge_me()
+{
+ if(MeLine)
+ {
+ MyFree(MeLine->info);
+ MyFree(MeLine->diepass);
+ MyFree(MeLine->restartpass);
+ MyFree(MeLine->admin[0]);
+ MyFree(MeLine->admin[1]);
+ MyFree(MeLine->admin[2]);
+ /* MeLine->info is guaranteed to be replaced */
+ MeLine->diepass = NULL;
+ MeLine->restartpass = NULL;
+ MeLine->admin[0] = NULL;
+ MeLine->admin[1] = NULL;
+ MeLine->admin[2] = NULL;
+ }
+ else
+ {
+ MeLine = new_MeLine;
+ strncpyzt(me.name, MeLine->servername, sizeof(me.name));
+ strncpyzt(me.info, MeLine->info, sizeof(me.info));
+ new_MeLine = NULL;
+ return;
+ }
+ DupString(MeLine->info, new_MeLine->info);
+ strncpyzt(me.info, MeLine->info, sizeof(me.info));
+ if(new_MeLine->diepass)
+ DupString(MeLine->diepass, new_MeLine->diepass);
+ if(new_MeLine->restartpass)
+ DupString(MeLine->restartpass, new_MeLine->restartpass);
+ if(new_MeLine->admin[0])
+ DupString(MeLine->admin[0], new_MeLine->admin[0]);
+ if(new_MeLine->admin[1])
+ DupString(MeLine->admin[1], new_MeLine->admin[1]);
+ if(new_MeLine->admin[2])
+ DupString(MeLine->admin[2], new_MeLine->admin[2]);
+ MyFree(new_MeLine->servername);
+ MyFree(new_MeLine->info);
+ MyFree(new_MeLine->diepass);
+ MyFree(new_MeLine->restartpass);
+ MyFree(new_MeLine->admin[0]);
+ MyFree(new_MeLine->admin[1]);
+ MyFree(new_MeLine->admin[2]);
+ MyFree(new_MeLine);
+ new_MeLine = NULL;
+ return;
+}
+
+static void
+merge_connects()
+{
+ aConnect *aconn, *old_aconn, *ptr = NULL, *ptrn;
+
+ /* first merge the list, then prune the list */
+
+ /* set old as deletable */
+ for(old_aconn = connects; old_aconn; old_aconn = old_aconn->next)
+ old_aconn->legal = -1;
+ /* update or add new */
+ for (aconn = new_connects; aconn; aconn = ptrn)
+ {
+ ptrn = aconn->next;
+ if ((old_aconn = find_aConnect(aconn->name)))
+ {
+ MyFree(old_aconn->host);
+ MyFree(old_aconn->apasswd);
+ MyFree(old_aconn->cpasswd);
+ MyFree(old_aconn->source);
+ MyFree(old_aconn->class_name);
+ old_aconn->class->refs--;
+ expire_class(old_aconn->class);
+
+ old_aconn->host = aconn->host;
+ old_aconn->apasswd = aconn->apasswd;
+ old_aconn->cpasswd = aconn->cpasswd;
+ old_aconn->source = aconn->source;
+ old_aconn->class_name = aconn->class_name;
+ old_aconn->port = aconn->port;
+ old_aconn->flags = aconn->flags;
+ old_aconn->class = find_class(aconn->class_name);
+ old_aconn->class->refs++;
+ old_aconn->legal = 1;
+ lookup_confhost(old_aconn);
+
+ MyFree(aconn->name);
+ MyFree(aconn);
+ }
+ else
+ {
+ aconn->class = find_class(aconn->class_name);
+ aconn->class->refs++;
+ aconn->legal = 1;
+ lookup_confhost(aconn);
+ aconn->next = connects;
+ connects = aconn;
+ }
+ }
+ new_connects = NULL;
+
+ ptr = NULL;
+ /* and prune the active list */
+ aconn = connects;
+ while(aconn)
+ {
+ ptrn = aconn->next;
+ if((aconn->legal == -1) && !aconn->acpt)
+ {
+ if(ptr)
+ ptr->next = aconn->next;
+ else
+ connects = aconn->next;
+ aconn->class->refs--;
+ expire_class(aconn->class);
+ free_connect(aconn);
+ }
+ else
+ ptr = aconn;
+ aconn = ptrn;
+ }
+ return;
+}
+
+static void
+merge_allows()
+{
+ aAllow *allow, *ptr = NULL, *ptrn;
+
+ for(allow = allows; allow; allow = allow->next)
+ allow->legal = -1;
+ allow = new_allows;
+ while(allow)
+ {
+ allow->class = find_class(allow->class_name);
+ allow->class->refs++;
+ /* we dont really have to merge anything here.. */
+ /* ..but we should avoid duplicates anyway */
+ for (ptr = allows; ptr; ptr = ptr->next)
+ {
+ if (ptr->class != allow->class)
+ continue;
+ if (ptr->port != allow->port)
+ continue;
+ if (ptr->flags != allow->flags)
+ continue;
+ if (mycmp(ptr->ipmask, allow->ipmask))
+ continue;
+ if (mycmp(ptr->hostmask, allow->hostmask))
+ continue;
+ /* inverted logic below */
+ if (ptr->passwd && allow->passwd
+ && !mycmp(ptr->passwd, allow->passwd))
+ break;
+ if (ptr->passwd == allow->passwd)
+ break;
+ }
+ /* if duplicate, mark for deletion but add anyway */
+ if (ptr)
+ {
+ ptr->legal = 1;
+ allow->legal = -1;
+ }
+ ptr = allow->next;
+ allow->next = allows;
+ allows = allow;
+ allow = ptr;
+ }
+ new_allows = NULL;
+ ptr = NULL;
+ allow = allows;
+ while(allow)
+ {
+ ptrn = allow->next;
+ if((allow->legal == -1) && (allow->clients <= 0))
+ {
+ if(ptr)
+ ptr->next = allow->next;
+ else
+ allows = allow->next;
+ allow->class->refs--;
+ expire_class(allow->class);
+ free_allow(allow);
+ }
+ else
+ ptr = allow;
+ allow = ptrn;
+ }
+ return; /* this one is easy */
+}
+
+static void
+merge_opers()
+{
+ aOper *aoper, *old_oper, *ptrn = NULL, *ptr = NULL;
+
+ for(old_oper = opers; old_oper; old_oper = old_oper->next)
+ old_oper->legal = -1;
+
+ /* add or merge and del new ones */
+ for (aoper = new_opers; aoper; aoper = ptrn)
+ {
+ ptrn = aoper->next;
+ if ((old_oper = find_oper_byname(aoper->nick)))
+ {
+ int i;
+
+ for (i = 0; old_oper->hosts[i]; i++)
+ MyFree(old_oper->hosts[i]);
+ MyFree(old_oper->passwd);
+ MyFree(old_oper->class_name);
+ old_oper->class->refs--;
+ expire_class(old_oper->class);
+
+ for (i = 0; aoper->hosts[i]; i++)
+ old_oper->hosts[i] = aoper->hosts[i];
+ old_oper->hosts[i] = NULL;
+ old_oper->passwd = aoper->passwd;
+ old_oper->class_name = aoper->class_name;
+ old_oper->class = find_class(aoper->class_name);
+ old_oper->class->refs++;
+ old_oper->flags = aoper->flags;
+ old_oper->legal = 1;
+
+ MyFree(aoper->nick);
+ MyFree(aoper);
+ }
+ else
+ {
+ aoper->class = find_class(aoper->class_name);
+ aoper->class->refs++;
+ aoper->legal = 1;
+ aoper->next = opers;
+ opers = aoper;
+ }
+ }
+ new_opers = NULL;
+
+ /* del old ones */
+ ptr = NULL;
+ aoper = opers;
+ while(aoper)
+ {
+ ptrn = aoper->next;
+ if((aoper->legal == -1) && (aoper->opers <= 0))
+ {
+ if(ptr)
+ ptr->next = aoper->next;
+ else
+ opers = aoper->next;
+ free_oper(aoper);
+ }
+ else
+ ptr = aoper;
+ aoper = ptrn;
+ }
+ return;
+}
+
+static void
+merge_ports()
+{
+ aPort *aport, *old_port, *ptrn;
+
+ if(forked)
+ close_listeners(); /* marks ports for deletion */
+
+ /* add or merge and del new ones */
+ for (aport = new_ports; aport; aport = ptrn)
+ {
+ ptrn = aport->next;
+ if ((old_port = find_port(aport->port, aport->address)))
+ {
+ MyFree(old_port->allow);
+ old_port->allow = aport->allow;
+ old_port->legal = 1;
+ MyFree(aport->address);
+ MyFree(aport);
+ }
+ else
+ {
+ aport->next = ports;
+ ports = aport;
+ }
+ }
+ new_ports = NULL;
+
+ if(forked)
+ open_listeners();
+ return;
+}
+
+static void
+merge_classes()
+{
+ aClass *class, *old_class, *ptr;
+
+ for(old_class = classes; old_class; old_class = old_class->next)
+ old_class->maxlinks = -1;
+
+ for (class = new_classes; class; class = class->next)
+ {
+ if((old_class = find_class(class->name)))
+ {
+ old_class->connfreq = class->connfreq;
+ old_class->pingfreq = class->pingfreq;
+ old_class->maxlinks = class->maxlinks;
+ old_class->maxsendq = class->maxsendq;
+ old_class->ip24clones = class->ip24clones;
+ class->maxlinks = -1;
+ }
+ }
+
+ /* add classes from new_classes that are not maxlinks = -1 */
+ for (class = new_classes; class; class = old_class)
+ {
+ old_class = class->next;
+ if (class->maxlinks == -1)
+ free_class(class);
+ else
+ {
+ class->next = classes;
+ classes = class;
+ }
+ }
+ new_classes = NULL;
+
+ /* now remove any classes from the list marked and w/o refs */
+ for (class = classes; class; class = ptr)
+ {
+ ptr = class->next;
+ expire_class(class);
+ }
+ return;
+}
+
+void
+merge_options(void)
+{
+ if (forked && !(confopts & FLAGS_SMOTD) && (new_confopts & FLAGS_SMOTD))
+ read_shortmotd(SHORTMOTD);
+ confopts = new_confopts;
+}
+
+void
+merge_confs()
+{
+ int i;
+
+ merge_classes(); /* this should always be done first */
+ merge_me();
+ merge_connects();
+ merge_allows();
+ merge_opers();
+ merge_ports();
+ merge_options();
+ for(i = 0; uservers[i]; i++)
+ MyFree(uservers[i]);
+ for(i = 0; new_uservers[i]; i++)
+ {
+ DupString(uservers[i], new_uservers[i]);
+ MyFree(new_uservers[i]);
+ }
+ new_uservers[0] = NULL;
+ /* dont worry about accually merging module data - its fairly
+ * inactive and static data. Just replace it.
+ */
+ if(modules)
+ {
+ MyFree(modules->module_path);
+ for(i = 0; modules->autoload[i]; i++)
+ MyFree(modules->autoload[i]);
+ for(i = 0; modules->optload[i]; i++)
+ MyFree(modules->optload[i]);
+ MyFree(modules);
+ }
+ modules = new_modules;
+ new_modules = NULL;
+ return;
+}
+
+static void
+clear_newconfs()
+{
+ aConnect *aconn = new_connects, *aconn_p;
+ aClass *class = new_classes, *class_p;
+ aOper *aoper = new_opers, *aoper_p;
+ aPort *aport = new_ports, *aport_p;
+ aAllow *allow = new_allows, *allow_p;
+ int i = 0;
+
+ while(aconn)
+ {
+ aconn_p = aconn->next;
+ free_connect(aconn);
+ aconn = aconn_p;
+ }
+ new_connects = NULL;
+ while(class)
+ {
+ class_p = class->next;
+ free_class(class);
+ class = class_p;
+ }
+ new_classes = NULL;
+ while(aoper)
+ {
+ aoper_p = aoper->next;
+ free_oper(aoper);
+ aoper = aoper_p;
+ }
+ new_opers = NULL;
+ while(aport)
+ {
+ aport_p = aport->next;
+ free_port(aport);
+ aport = aport_p;
+ }
+ new_ports = NULL;
+ while(allow)
+ {
+ allow_p = allow->next;
+ free_allow(allow);
+ allow = allow_p;
+ }
+ new_allows = NULL;
+ if(new_MeLine)
+ {
+ MyFree(new_MeLine->servername);
+ MyFree(new_MeLine->info);
+ MyFree(new_MeLine->diepass);
+ MyFree(new_MeLine->restartpass);
+ MyFree(new_MeLine->admin[0]);
+ MyFree(new_MeLine->admin[1]);
+ MyFree(new_MeLine->admin[2]);
+ MyFree(new_MeLine);
+ new_MeLine = NULL;
+ }
+ while(new_uservers[i])
+ {
+ DupString(uservers[i], new_uservers[i]);
+ MyFree(new_uservers[i]);
+ i++;
+ }
+ new_uservers[0] = NULL;
+ if(new_modules)
+ {
+ for(i = 0; new_modules->autoload[i]; i++)
+ MyFree(new_modules->autoload[i]);
+ for(i = 0; new_modules->optload[i]; i++)
+ MyFree(new_modules->optload[i]);
+ MyFree(new_modules->module_path);
+ MyFree(new_modules);
+ new_modules = NULL;
+ }
+ return;
+}
+
+/*
+ * rehash
+ *
+ * Actual REHASH service routine. Called with sig == 0 if it has been
+ * called as a result of an operator issuing this command, else assume
+ * it has been called as a result of the server receiving a HUP signal.
+ */
+int rehash(aClient *cptr, aClient *sptr, int sig)
+{
+ aClient *acptr;
+ int i;
+ char *conferr;
+
+ if (sig == SIGHUP)
+ {
+ sendto_ops("Got signal SIGHUP, reloading ircd conf. file");
+ remove_userbans_match_flags(UBAN_NETWORK, 0);
+ remove_userbans_match_flags(UBAN_LOCAL|UBAN_TEMPORARY, 0);
+ remove_simbans_match_flags(SBAN_NICK|SBAN_LOCAL|SBAN_TEMPORARY, 0);
+ remove_simbans_match_flags(SBAN_CHAN|SBAN_LOCAL|SBAN_TEMPORARY, 0);
+ remove_simbans_match_flags(SBAN_GCOS|SBAN_LOCAL|SBAN_TEMPORARY, 0);
+
+ }
+
+ /* Shadowfax's LOCKFILE code */
+#ifdef LOCKFILE
+ do_pending_klines();
+#endif
+
+ for (i = 0; i <= highest_fd; i++)
+ if ((acptr = local[i]) && !IsMe(acptr))
+ {
+ /*
+ * Nullify any references from client structures to this host
+ * structure which is about to be freed. Could always keep
+ * reference counts instead of this....-avalon
+ */
+ acptr->hostp = NULL;
+ }
+
+ if (sig != SIGINT)
+ flush_cache(); /* Flush DNS cache */
+
+ /* remove perm klines */
+ remove_userbans_match_flags(UBAN_LOCAL, UBAN_TEMPORARY);
+ remove_simbans_match_flags(SBAN_NICK|SBAN_LOCAL, SBAN_TEMPORARY);
+ remove_simbans_match_flags(SBAN_CHAN|SBAN_LOCAL, SBAN_TEMPORARY);
+ remove_simbans_match_flags(SBAN_GCOS|SBAN_LOCAL, SBAN_TEMPORARY);
+
+
+ initclass();
+ new_confopts = 0;
+
+ if(initconf(configfile) == -1)
+ {
+ sendto_realops("Rehash Aborted");
+ clear_newconfs();
+ return 1;
+ }
+
+ conferr = finishconf();
+ if (conferr)
+ {
+ sendto_realops("Rehash Aborted: %s", conferr);
+ clear_newconfs();
+ return 1;
+ }
+
+ merge_confs();
+ build_rplcache();
+
+ rehashed = 1;
+
+ return 1;
+}
+
+/*
+ * lookup_confhost Do (start) DNS lookups of all hostnames in the conf
+ * line and convert an IP addresses in a.b.c.d number for to IP#s.
+ *
+ * cleaned up Aug 3'97 - Dianora
+ * rewritten to kill aConfItem, Feb/04 - epi
+ */
+static int lookup_confhost(aConnect *aconn)
+{
+ char *s;
+ struct hostent *hp;
+ Link ln;
+ if (BadPtr(aconn->host) || BadPtr(aconn->name))
+ {
+ if (aconn->ipnum.s_addr == -1)
+ memset((char *) &aconn->ipnum, '\0', sizeof(struct in_addr));
+
+ Debug((DEBUG_ERROR, "Host/server name error: (%s) (%s)",
+ aconn->host, aconn->name));
+ return -1;
+ }
+ if ((s = strchr(aconn->host, '@')))
+ s++;
+ else
+ s = aconn->host;
+ /*
+ * Do name lookup now on hostnames given and store the ip
+ * numbers in conf structure.
+ */
+ if (!IsAlpha(*s) && !IsDigit(*s))
+ {
+ if (aconn->ipnum.s_addr == -1)
+ memset((char *) &aconn->ipnum, '\0', sizeof(struct in_addr));
+
+ Debug((DEBUG_ERROR, "Host/server name error: (%s) (%s)",
+ aconn->host, aconn->name));
+ return -1;
+ }
+ /*
+ * Prepare structure in case we have to wait for a reply which
+ * we get later and store away.
+ */
+ ln.value.aconn = aconn;
+ ln.flags = ASYNC_CONF;
+
+ if (IsDigit(*s))
+ aconn->ipnum.s_addr = inet_addr(s);
+ else if ((hp = gethost_byname(s, &ln)))
+ memcpy((char *) &(aconn->ipnum), hp->h_addr,
+ sizeof(struct in_addr));
+
+ if (aconn->ipnum.s_addr == -1)
+ memset((char *) &aconn->ipnum, '\0', sizeof(struct in_addr));
+ {
+ Debug((DEBUG_ERROR, "Host/server name error: (%s) (%s)",
+ aconn->host, aconn->name));
+ return -1;
+ }
+ /* NOTREACHED */
+ return 0;
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/s_debug.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: s_debug.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include "patchlevel.h"
+#include "numeric.h"
+#include "channel.h"
+
+/* This file is hereby declared the nexus of all things ugly and preprocessed */
+
+static char rplisupport1[BUFSIZE];
+static char rplisupport2[BUFSIZE];
+static char rplversion[BUFSIZE];
+static char scratchbuf[BUFSIZE];
+
+/* send cached RPL_ISUPPORT */
+void send_rplisupport(aClient *acptr)
+{
+ sendto_one(acptr, rplisupport1, acptr->name);
+ sendto_one(acptr, rplisupport2, acptr->name);
+}
+
+/* send cached RPL_VERSION */
+void send_rplversion(aClient *acptr)
+{
+ sendto_one(acptr, rplversion, acptr->name);
+}
+
+
+/* build and cache complex strings */
+void build_rplcache(void)
+{
+ char *s;
+
+ /* build RPL_ISUPPORT */
+
+ /* Most of this tracks draft-brocklesby-irc-isupport-03, with a
+ * few differences:
+ * STD is not sent since there is no RFC
+ * MAXCHANNELS and MAXBANS are sent for compatibility with old clients
+ * SILENCE WATCH and ELIST are sent but not documented
+ */
+
+ /* put MAXBANS and MAXCHANNELS first so better tokens override them */
+ ircsprintf(scratchbuf,"NETWORK=%s SAFELIST MAXBANS=%i MAXCHANNELS=%i "
+ "CHANNELLEN=%i KICKLEN=%i NICKLEN=%i TOPICLEN=%i MODES=%i "
+ "CHANTYPES=# CHANLIMIT=#:%i PREFIX=(ov)@+ STATUSMSG=@+",
+ Network_Name, MAXBANS, maxchannelsperuser, CHANNELLEN,
+ TOPICLEN, NICKLEN, TOPICLEN, MAXMODEPARAMSUSER,
+ maxchannelsperuser);
+
+ ircsprintf(rplisupport1, rpl_str(RPL_ISUPPORT), me.name, "%s", scratchbuf);
+
+ s = scratchbuf;
+ s += ircsprintf(s, "CASEMAPPING=ascii WATCH=%i SILENCE=%i ELIST=cmntu",
+ MAXWATCH, MAXSILES);
+#ifdef EXEMPT_LISTS
+ s += ircsprintf(s, " EXCEPTS");
+#endif
+#ifdef INVITE_LISTS
+ s += ircsprintf(s, " INVEX");
+#endif
+ s += ircsprintf(s, " CHANMODES=b");
+#ifdef EXEMPT_LISTS
+ *s++ = 'e';
+#endif
+#ifdef INVITE_LISTS
+ *s++ = 'I';
+#endif
+ s += ircsprintf(s, ",k,jl,ci");
+#ifdef USE_CHANMODE_L
+ *s++ = 'L';
+#endif
+ s += ircsprintf(s, "mMnOprRst MAXLIST=b:%i", MAXBANS);
+#ifdef EXEMPT_LISTS
+ s += ircsprintf(s, ",e:%i", MAXEXEMPTLIST);
+#endif
+#ifdef INVITE_LISTS
+ s += ircsprintf(s, ",I:%i", MAXINVITELIST);
+#endif
+ s += ircsprintf(s, " TARGMAX=DCCALLOW:,JOIN:,KICK:4,KILL:20,NOTICE:%i,"
+ "PART:,PRIVMSG:%i,WHOIS:,WHOWAS:", MAXRECIPIENTS,
+ MAXRECIPIENTS);
+
+ ircsprintf(rplisupport2, rpl_str(RPL_ISUPPORT), me.name, "%s", scratchbuf);
+
+
+ /* build RPL_VERSION */
+ s = scratchbuf;
+
+#ifdef ANTI_SPAMBOT
+ *s++ = 'a';
+#endif
+#ifdef ALWAYS_SEND_DURING_SPLIT
+ *s++ = 'A';
+#endif
+#ifdef MAXBUFFERS
+ *s++ = 'B';
+#endif
+#ifdef CMDLINE_CONFIG
+ *s++ = 'C';
+#endif
+#ifdef DO_IDENTD
+ *s++ = 'd';
+#endif
+#ifdef DEBUGMODE
+ *s++ = 'D';
+#endif
+#ifdef HAVE_ENCRYPTION_ON
+ *s++ = 'E';
+#endif
+#ifdef FLUD
+ *s++ = 'F';
+#endif
+#ifdef SHOW_HEADERS
+ *s++ = 'h';
+#endif
+#ifdef SHOW_INVISIBLE_LUSERS
+ *s++ = 'i';
+#endif
+#ifdef NO_DEFAULT_INVISIBLE
+ *s++ = 'I';
+#endif
+#ifdef NO_DEFAULT_JOINRATE
+ *s++ = 'J';
+#endif
+#ifdef USE_HOOKMODULES
+ *s++ = 'M';
+#endif
+#ifdef DNS_DEBUG
+ *s++ = 'N';
+#endif
+#ifdef DENY_SERVICES_MSGS
+ *s++ = 'r';
+#endif
+#ifdef SUPER_TARGETS_ONLY
+ *s++ = 's';
+#endif
+#ifdef MSG_TARGET_LIMIT
+ *s++ = 't';
+#endif
+#ifdef THROTTLE_ENABLE
+ *s++ = 'T';
+#endif
+#ifdef IRCII_KLUDGE
+ *s++ = 'u';
+#endif
+#ifdef USE_SYSLOG
+ *s++ = 'Y';
+#endif
+ *s++ = '/';
+ if (confopts & FLAGS_HUB)
+ *s++ = 'H';
+ if (confopts & FLAGS_SMOTD)
+ *s++ = 'm';
+ if (confopts & FLAGS_SPLITOPOK)
+ *s++ = 'o';
+ if (confopts & FLAGS_CRYPTPASS)
+ *s++ = 'p';
+ if (confopts & FLAGS_SERVHUB)
+ *s++ = 'S';
+ if ((confopts & FLAGS_WGMON) == FLAGS_WGMON)
+ *s++ = 'w';
+
+ s += ircsprintf(s, " TS%iow", TS_CURRENT);
+#ifdef BRANCHSTATUS
+ s += ircsprintf(s, "-r[%s]",
+# if BRANCHSTATUS == CURRENT
+ "CURRENT"
+# elif BRANCHSTATUS == RELEASE
+ "RELEASE"
+# elif BRANCHSTATUS == STABLE
+ "STABLE"
+# elif BRANCHSTATUS == BETA
+ "BETA"
+# else
+ "UNKNOWN"
+# endif
+ );
+#endif
+
+#ifdef RIDICULOUS_PARANOIA_LEVEL
+ s += ircsprintf(s, " RPL%i", RIDICULOUS_PARANOIA_LEVEL);
+#endif
+
+ s += ircsprintf(s, " NP[");
+#ifdef FORCE_EVERYONE_HIDDEN
+ *s++ = 'A';
+#endif
+#ifdef ALLOW_HIDDEN_OPERS
+ *s++ = 'I';
+#endif
+#ifdef HIDE_KILL_ORIGINS
+ *s++ = 'K';
+#endif
+#ifdef NO_USER_SERVERKILLS
+ *s++ = 'k';
+#endif
+ if (!(confopts & FLAGS_SHOWLINKS))
+ *s++ = 'L';
+#ifdef HIDE_SERVERMODE_ORIGINS
+ *s++ = 'M';
+#endif
+#ifdef HIDE_NUMERIC_SOURCE
+ *s++ = 'N';
+#endif
+#ifdef NO_USER_OPERTARGETED_COMMANDS
+ *s++ = 'O';
+#endif
+#ifdef HIDE_SPLIT_SERVERS
+ *s++ = 'P';
+#endif
+#ifdef NO_USER_STATS
+ *s++ = 'S';
+#endif
+#ifdef NO_USER_OPERKILLS
+ *s++ = 's';
+#endif
+#ifdef NO_USER_TRACE
+ *s++ = 'T';
+#endif
+#ifdef HIDEULINEDSERVS
+ *s++ = 'U';
+#endif
+ *s++ = ']';
+ *s++ = 0;
+
+ ircsprintf(rplversion, rpl_str(RPL_VERSION), me.name, "%s", version,
+ debugmode, me.name, scratchbuf);
+}
+
+
+#if defined(DNS_DEBUG) || defined(DEBUGMODE)
+static char debugbuf[1024];
+
+void debug(int level, char *pattern, ...)
+{
+ va_list vl;
+ int err = errno;
+
+ va_start(vl, pattern);
+ (void) vsprintf(debugbuf, pattern, vl);
+ va_end(vl);
+
+#ifdef USE_SYSLOG
+ if (level == DEBUG_ERROR)
+ syslog(LOG_ERR, "%s", debugbuf);
+#endif
+
+ if ((debuglevel >= 0) && (level <= debuglevel)) {
+
+ if (local[2]) {
+ local[2]->sendM++;
+ local[2]->sendB += strlen(debugbuf);
+ }
+ (void) fprintf(stderr, "%s", debugbuf);
+ (void) fputc('\n', stderr);
+ }
+ errno = err;
+}
+
+#endif
--- /dev/null
+/* Copyright (C) 1992 Darren Reed
+ *
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, 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.
+ */
+
+#include "struct.h"
+#include "numeric.h"
+#include "h.h"
+
+static char *replies[] =
+{
+ /* 000 */ NULL,
+ /* 001 RPL_WELCOME */ ":%s 001 %s :Welcome to the %s IRC "
+ "Network %s!%s@%s",
+ /* 002 RPL_YOURHOST */ ":%s 002 %s :Your host is %s, running "
+ "version %s",
+ /* 003 RPL_CREATED */ ":%s 003 %s :This server was created %s",
+ /* 004 RPL_MYINFO */ ":%s 004 %s %s %s aAbcdefFghiIjkKmnoOrRswxXy "
+ "bceiIjklLmMnoOprRstv",
+ /* 005 RPL_ISUPPORT */ ":%s 005 %s %s :are available on this server",
+ /* 006 */ NULL,
+ /* 007 */ NULL,
+ /* 008 */ NULL,
+ /* 009 */ NULL,
+ /* 010 */ NULL,
+ /* 011 */ NULL,
+ /* 012 */ NULL,
+ /* 013 */ NULL,
+ /* 014 */ NULL,
+ /* 015 */ NULL,
+ /* 016 */ NULL,
+ /* 017 */ NULL,
+ /* 018 */ NULL,
+ /* 019 */ NULL,
+ /* 020 */ NULL,
+ /* 021 */ NULL,
+ /* 022 */ NULL,
+ /* 023 */ NULL,
+ /* 024 */ NULL,
+ /* 025 */ NULL,
+ /* 026 */ NULL,
+ /* 027 */ NULL,
+ /* 028 */ NULL,
+ /* 029 */ NULL,
+ /* 030 */ NULL,
+ /* 031 */ NULL,
+ /* 032 */ NULL,
+ /* 033 */ NULL,
+ /* 034 */ NULL,
+ /* 035 */ NULL,
+ /* 036 */ NULL,
+ /* 037 */ NULL,
+ /* 038 */ NULL,
+ /* 039 */ NULL,
+ /* 040 */ NULL,
+ /* 041 */ NULL,
+ /* 042 */ NULL,
+ /* 043 */ NULL,
+ /* 044 */ NULL,
+ /* 045 */ NULL,
+ /* 046 */ NULL,
+ /* 047 */ NULL,
+ /* 048 */ NULL,
+ /* 049 */ NULL,
+ /* 050 */ NULL,
+ /* 051 */ NULL,
+ /* 052 */ NULL,
+ /* 053 */ NULL,
+ /* 054 */ NULL,
+ /* 055 */ NULL,
+ /* 056 */ NULL,
+ /* 057 */ NULL,
+ /* 058 */ NULL,
+ /* 059 */ NULL,
+ /* 060 */ NULL,
+ /* 061 */ NULL,
+ /* 062 */ NULL,
+ /* 063 */ NULL,
+ /* 064 */ NULL,
+ /* 065 */ NULL,
+ /* 066 */ NULL,
+ /* 067 */ NULL,
+ /* 068 */ NULL,
+ /* 069 */ NULL,
+ /* 070 */ NULL,
+ /* 071 */ NULL,
+ /* 072 */ NULL,
+ /* 073 */ NULL,
+ /* 074 */ NULL,
+ /* 075 */ NULL,
+ /* 076 */ NULL,
+ /* 077 */ NULL,
+ /* 078 */ NULL,
+ /* 079 */ NULL,
+ /* 080 */ NULL,
+ /* 081 */ NULL,
+ /* 082 */ NULL,
+ /* 083 */ NULL,
+ /* 084 */ NULL,
+ /* 085 */ NULL,
+ /* 086 */ NULL,
+ /* 087 */ NULL,
+ /* 088 */ NULL,
+ /* 089 */ NULL,
+ /* 090 */ NULL,
+ /* 091 */ NULL,
+ /* 092 */ NULL,
+ /* 093 */ NULL,
+ /* 094 */ NULL,
+ /* 095 */ NULL,
+ /* 096 */ NULL,
+ /* 097 */ NULL,
+ /* 098 */ NULL,
+ /* 099 */ NULL,
+ /* 100 */ NULL,
+ /* 101 */ NULL,
+ /* 102 */ NULL,
+ /* 103 */ NULL,
+ /* 104 */ NULL,
+ /* 105 */ NULL,
+ /* 106 */ NULL,
+ /* 107 */ NULL,
+ /* 108 */ NULL,
+ /* 109 */ NULL,
+ /* 110 */ NULL,
+ /* 111 */ NULL,
+ /* 112 */ NULL,
+ /* 113 */ NULL,
+ /* 114 */ NULL,
+ /* 115 */ NULL,
+ /* 116 */ NULL,
+ /* 117 */ NULL,
+ /* 118 */ NULL,
+ /* 119 */ NULL,
+ /* 120 */ NULL,
+ /* 121 */ NULL,
+ /* 122 */ NULL,
+ /* 123 */ NULL,
+ /* 124 */ NULL,
+ /* 125 */ NULL,
+ /* 126 */ NULL,
+ /* 127 */ NULL,
+ /* 128 */ NULL,
+ /* 129 */ NULL,
+ /* 130 */ NULL,
+ /* 131 */ NULL,
+ /* 132 */ NULL,
+ /* 133 */ NULL,
+ /* 134 */ NULL,
+ /* 135 */ NULL,
+ /* 136 */ NULL,
+ /* 137 */ NULL,
+ /* 138 */ NULL,
+ /* 139 */ NULL,
+ /* 140 */ NULL,
+ /* 141 */ NULL,
+ /* 142 */ NULL,
+ /* 143 */ NULL,
+ /* 144 */ NULL,
+ /* 145 */ NULL,
+ /* 146 */ NULL,
+ /* 147 */ NULL,
+ /* 148 */ NULL,
+ /* 149 */ NULL,
+ /* 150 */ NULL,
+ /* 151 */ NULL,
+ /* 152 */ NULL,
+ /* 153 */ NULL,
+ /* 154 */ NULL,
+ /* 155 */ NULL,
+ /* 156 */ NULL,
+ /* 157 */ NULL,
+ /* 158 */ NULL,
+ /* 159 */ NULL,
+ /* 160 */ NULL,
+ /* 161 */ NULL,
+ /* 162 */ NULL,
+ /* 163 */ NULL,
+ /* 164 */ NULL,
+ /* 165 */ NULL,
+ /* 166 */ NULL,
+ /* 167 */ NULL,
+ /* 168 */ NULL,
+ /* 169 */ NULL,
+ /* 170 */ NULL,
+ /* 171 */ NULL,
+ /* 172 */ NULL,
+ /* 173 */ NULL,
+ /* 174 */ NULL,
+ /* 175 */ NULL,
+ /* 176 */ NULL,
+ /* 177 */ NULL,
+ /* 178 */ NULL,
+ /* 179 */ NULL,
+ /* 180 */ NULL,
+ /* 181 */ NULL,
+ /* 182 */ NULL,
+ /* 183 */ NULL,
+ /* 184 */ NULL,
+ /* 185 */ NULL,
+ /* 186 */ NULL,
+ /* 187 */ NULL,
+ /* 188 */ NULL,
+ /* 189 */ NULL,
+ /* 190 */ NULL,
+ /* 191 */ NULL,
+ /* 192 */ NULL,
+ /* 193 */ NULL,
+ /* 194 */ NULL,
+ /* 195 */ NULL,
+ /* 196 */ NULL,
+ /* 197 */ NULL,
+ /* 198 */ NULL,
+ /* 199 */ NULL,
+ /* 200 RPL_TRACELINK */ ":%s 200 %s Link %s%s %s %s",
+ /* 201 RPL_TRACECONNECTING */ ":%s 201 %s Attempt %s %s",
+ /* 202 RPL_TRACEHANDSHAKE */ ":%s 202 %s Handshaking %s %s",
+ /* 203 RPL_TRACEUNKNOWN */ ":%s 203 %s ???? %s %s %d",
+ /* 204 RPL_TRACEOPERATOR */ ":%s 204 %s Operator %s %s %ld",
+ /* 205 RPL_TRACEUSER */ ":%s 205 %s User %s %s %ld",
+ /* 206 RPL_TRACESERVER */ ":%s 206 %s Server %s %dS %dC %s %s!%s@%s %ld",
+ /* 207 */ NULL,
+ /* 208 RPL_TRACENEWTYPE */ ":%s 208 %s <newtype> 0 %s",
+ /* 209 RPL_TRACECLASS */ ":%s 209 %s Class %s %d",
+ /* 210 */ NULL,
+ /* 211 */ NULL,
+ /* 212 RPL_STATSCOMMANDS */ ":%s 212 %s %s %u %u",
+ /* 213 RPL_STATSCLINE */ ":%s 213 %s %s %s * %s %d %s",
+ /* 214 RPL_STATSNLINE */ ":%s 214 %s %s %s * %s %d %s",
+ /* 215 RPL_STATSILINE */ ":%s 215 %s %s %s %d %s %d %s",
+ /* 216 RPL_STATSKLINE */ ":%s 216 %s %s %s * %s %d :%s",
+ /* 217 RPL_STATSQLINE */ ":%s 217 %s %s * * %s %d :%s",
+ /* 218 RPL_STATSYLINE */ ":%s 218 %s %c %s %d %d:%d %d %ld",
+ /* 219 RPL_ENDOFSTATS */ ":%s 219 %s %c :End of /STATS report.",
+ /* 220 */ NULL,
+ /* 221 RPL_UMODEIS */ ":%s 221 %s %s",
+ /* 222 */ ":%s 222 %s %c %s * %s %d %d",
+ /* 223 */ ":%s 223 %s %c %s * %s %d %d",
+ /* 224 */ ":%s 224 %s %c %s * %s %d %d",
+ /* 225 RPL_STATSCLONE */ ":%s 225 %s D %s %d %d %d",
+ /* 226 RPL_STATSCOUNT */ ":%s 226 %s %s %l",
+ /* 227 RPL_STATSGLINE */ ":%s 227 %s %s * * %s %d :%s",
+ /* 228 */ NULL,
+ /* 229 */ NULL,
+ /* 230 */ NULL,
+ /* 231 */ NULL, /* In use by Undernet */
+ /* 232 */ NULL, /* In use by Undernet */
+ /* 233 */ NULL, /* In use by Undernet */
+ /* 234 */ NULL,
+ /* 235 */ NULL,
+ /* 236 */ NULL,
+ /* 237 */ NULL,
+ /* 238 */ NULL,
+ /* 239 */ NULL,
+ /* 240 */ NULL,
+ /* 241 RPL_STATSLLINE */ ":%s 241 %s %c %s * %s %d %d",
+ /* 242 RPL_STATSUPTIME */ ":%s 242 %s :Server Up %d days, %d:%02d:%02d",
+ /* 243 RPL_STATSOLINE */ ":%s 243 %s %s %s * %s %lu %s",
+ /* 244 RPL_STATSHLINE */ NULL,
+ /* 245 RPL_STATSSLINE */ NULL,
+ /* 246 RPL_STATSXLINE */ ":%s 246 %s %s %s * %s %d %d",
+ /* 247 */ NULL, /* Undernet's STATSGLINE */
+ /* 248 */ NULL, /* Undernet's STATSULINE */
+ /* 249 */ NULL,
+ /* 250 */ NULL,
+ /* 251 RPL_LUSERCLIENT */ ":%s 251 %s :There are %d users and %d "
+ "invisible on %d servers",
+ /* 252 RPL_LUSEROP */ ":%s 252 %s %d :IRC Operators online",
+ /* 253 RPL_LUSERUNKNOWN */ ":%s 253 %s %d :unknown connection(s)",
+ /* 254 RPL_LUSERCHANNELS */ ":%s 254 %s %d :channels formed",
+ /* 255 RPL_LUSERME */ ":%s 255 %s :I have %d clients and %d servers",
+ /* 256 RPL_ADMINME */ ":%s 256 %s :Administrative info about %s",
+ /* 257 RPL_ADMINLOC1 */ ":%s 257 %s :%s",
+ /* 258 RPL_ADMINLOC2 */ ":%s 258 %s :%s",
+ /* 259 RPL_ADMINEMAIL */ ":%s 259 %s :%s",
+ /* 260 */ NULL,
+ /* 261 RPL_TRACELOG */ ":%s 261 %s File %s %d",
+ /* 262 */ ":%s 262 %s %s :End of TRACE",
+ /* 263 */ ":%s 263 %s :Server load is temporarily too "
+ "heavy. Please wait a while and try again.",
+ /* 264 */ NULL,
+ /* 265 RPL_LOCALUSERS */ ":%s 265 %s :Current local users: %d Max: %d",
+ /* 266 RPL_GLOBALUSERS */ ":%s 266 %s :Current global users: %d Max: %d",
+ /* 267 */ NULL,
+ /* 268 */ NULL,
+ /* 269 */ NULL,
+ /* 270 */ NULL,
+ /* 271 RPL_SILELIST */ ":%s 271 %s %s %s",
+ /* 272 RPL_ENDOFSILELIST*/ ":%s 272 %s :End of /SILENCE list.",
+ /* 273 */ NULL,
+ /* 274 */ NULL,
+ /* 275 */ NULL, /* In use by Undernet */
+ /* 276 */ NULL,
+ /* 277 */ NULL,
+ /* 278 */ NULL,
+ /* 279 */ NULL,
+ /* 280 */ NULL, /* In use by Undernet */
+ /* 281 */ NULL, /* In use by Undernet */
+ /* 282 */ NULL,
+ /* 283 */ NULL,
+ /* 284 */ NULL,
+ /* 285 */ NULL,
+ /* 286 */ NULL,
+ /* 287 */ NULL,
+ /* 288 */ NULL,
+ /* 289 */ NULL,
+ /* 290 */ NULL,
+ /* 291 */ NULL,
+ /* 292 */ NULL,
+ /* 293 */ NULL,
+ /* 294 */ NULL,
+ /* 295 */ NULL,
+ /* 296 */ NULL,
+ /* 297 */ NULL,
+ /* 298 */ NULL,
+ /* 299 */ NULL,
+ /* 300 */ NULL,
+ /* 301 RPL_AWAY */ ":%s 301 %s %s :%s",
+ /* 302 RPL_USERHOST */ ":%s 302 %s :",
+ /* 303 RPL_ISON */ ":%s 303 %s :",
+ /* 304 */ NULL,
+ /* 305 RPL_UNAWAY */ ":%s 305 %s :You are no longer marked as "
+ "being away",
+ /* 306 RPL_NOWAWAY */ ":%s 306 %s :You have been marked as being "
+ "away",
+ /* 307 RPL_WHOISREGNICK */ ":%s 307 %s %s :has identified for this nick",
+ /* 308 RPL_WHOISADMIN */ ":%s 308 %s %s :is an IRC Server "
+ "Administrator",
+ /* 309 RPL_WHOISSADMIN */ ":%s 309 %s %s :is a Services Administrator",
+ /* 310 RPL_WHOISSVCMSG */ ":%s 310 %s %s",
+ /* 311 RPL_WHOISUSER */ ":%s 311 %s %s %s %s * :%s",
+ /* 312 RPL_WHOISSERVER */ ":%s 312 %s %s %s :%s",
+ /* 313 RPL_WHOISOPERATOR */ ":%s 313 %s %s :is %s",
+ /* 314 RPL_WHOWASUSER */ ":%s 314 %s %s %s %s * :%s",
+ /* 315 RPL_ENDOFWHO */ ":%s 315 %s %s :End of /%s list.",
+ /* 316 RPL_WHOISCHANOP */ NULL,
+ /* 317 RPL_WHOISIDLE */ ":%s 317 %s %s %ld %ld :seconds idle, "
+ "signon time",
+ /* 318 RPL_ENDOFWHOIS */ ":%s 318 %s %s :End of /WHOIS list.",
+ /* 319 RPL_WHOISCHANNELS */ ":%s 319 %s %s :%s",
+ /* 320 */ NULL,
+ /* 321 RPL_LISTSTART */ ":%s 321 %s Channel :Users Name",
+ /* 322 RPL_LIST */ ":%s 322 %s %s %d :%s",
+ /* 323 RPL_LISTEND */ ":%s 323 %s :End of /LIST",
+ /* 324 RPL_CHANNELMODEIS */ ":%s 324 %s %s %s %s",
+ /* 325 */ NULL,
+ /* 326 */ NULL,
+ /* 327 */ NULL,
+ /* 328 */ NULL,
+ /* 329 RPL_CREATIONTIME */ ":%s 329 %s %s %lu",
+ /* 330 */ NULL,
+ /* 331 RPL_NOTOPIC */ ":%s 331 %s %s :No topic is set.",
+ /* 332 RPL_TOPIC */ ":%s 332 %s %s :%s",
+ /* 333 RPL_TOPICWHOTIME */ ":%s 333 %s %s %s %lu",
+ /* 334 RPL_COMMANDSYNTAX */ ":%s 334 %s :%s",
+ /* 335 */ NULL,
+ /* 336 */ NULL,
+ /* 337 RPL_WHOISTEXT*/ ":%s 337 %s :%s",
+ /* 338 RPL_WHOISACTUALLY */ ":%s 338 %s :%s is actually %s@%s [%s]",
+ /* 339 */ NULL,
+ /* 340 */ NULL,
+ /* 341 RPL_INVITING */ ":%s 341 %s %s %s",
+ /* 342 RPL_SUMMONING */ ":%s 342 %s %s :User summoned to irc",
+ /* 343 */ NULL,
+ /* 344 */ NULL,
+ /* 345 */ NULL,
+#ifdef INVITE_LISTS
+ /* 346 RPL_INVITELIST */ ":%s 346 %s %s %s %s %lu",
+ /* 347 RPL_ENDOFINVITELIST */ ":%s 347 %s %s :End of Channel Invite List",
+#else
+ /* 346 */ NULL,
+ /* 347 */ NULL,
+#endif
+#ifdef EXEMPT_LISTS
+ /* 348 RPL_EXEMPTLIST */ ":%s 348 %s %s %s %s %lu",
+ /* 349 RPL_ENDOFEXEMPTLIST */ ":%s 349 %s %s :End of Channel Exempt List",
+#else
+ /* 348 */ NULL,
+ /* 349 */ NULL,
+#endif
+ /* 350 */ NULL,
+ /* 351 RPL_VERSION */ ":%s 351 %s %s.%s %s :%s",
+ /* 352 RPL_WHOREPLY */ ":%s 352 %s %s %s %s %s %s %s :%d %s",
+ /* 353 RPL_NAMREPLY */ ":%s 353 %s %s",
+ /* 354 RPL_RWHOREPLY */ ":%s 354 %s", /* also used for Undernet's WHOX */
+ /* 355 */ NULL,
+ /* 356 */ NULL,
+ /* 357 */ NULL,
+ /* 358 */ NULL,
+ /* 359 */ NULL,
+ /* 360 */ NULL,
+ /* 361 */ NULL,
+ /* 362 RPL_CLOSING */ ":%s 362 %s %s :Closed. Status = %d",
+ /* 363 RPL_CLOSEEND */ ":%s 363 %s %d: Connections Closed",
+ /* 364 RPL_LINKS */ ":%s 364 %s %s %s :%d %s",
+ /* 365 RPL_ENDOFLINKS */ ":%s 365 %s %s :End of /LINKS list.",
+ /* 366 RPL_ENDOFNAMES */ ":%s 366 %s %s :End of /NAMES list.",
+ /* 367 RPL_BANLIST */ ":%s 367 %s %s %s %s %lu",
+ /* 368 RPL_ENDOFBANLIST */ ":%s 368 %s %s :End of Channel Ban List",
+ /* 369 RPL_ENDOFWHOWAS */ ":%s 369 %s %s :End of WHOWAS",
+ /* 370 */ NULL,
+ /* 371 RPL_INFO */ ":%s 371 %s :%s",
+ /* 372 RPL_MOTD */ ":%s 372 %s :- %s",
+ /* 373 RPL_INFOSTART */ ":%s 373 %s :Server INFO",
+ /* 374 RPL_ENDOFINFO */ ":%s 374 %s :End of /INFO list.",
+ /* 375 RPL_MOTDSTART */ ":%s 375 %s :- %s Message of the Day - ",
+ /* 376 RPL_ENDOFMOTD */ ":%s 376 %s :End of /MOTD command.",
+ /* 377 */ NULL,
+ /* 378 */ NULL,
+ /* 379 */ NULL,
+ /* 380 */ NULL,
+ /* 381 RPL_YOUREOPER */ ":%s 381 %s :You are now an IRC Operator",
+ /* 382 RPL_REHASHING */ ":%s 382 %s %s :Rehashing",
+ /* 383 */ NULL,
+ /* 384 RPL_MYPORTIS */ ":%s 384 %s %d :Port to local server is\r\n",
+ /* 385 */ NULL,
+ /* 386 */ NULL,
+ /* 387 */ NULL,
+ /* 388 */ NULL,
+ /* 389 */ NULL,
+ /* 390 */ NULL,
+ /* 391 RPL_TIME */ ":%s 391 %s %s :%s",
+ /* 392 */ NULL,
+ /* 393 */ NULL,
+ /* 394 */ NULL,
+ /* 395 */ NULL,
+ /* 396 */ NULL,
+ /* 397 */ NULL,
+ /* 398 */ NULL,
+ /* 399 */ NULL,
+ /* 400 */ NULL,
+ /* 401 ERR_NOSUCHNICK */ ":%s 401 %s %s :No such nick/channel",
+ /* 402 ERR_NOSUCHSERVER */ ":%s 402 %s %s :No such server",
+ /* 403 ERR_NOSUCHCHANEL */ ":%s 403 %s %s :No such channel",
+ /* 404 ERR_CANNOTSENDTOCHAN */ ":%s 404 %s %s :Cannot send to "
+ "channel",
+ /* 405 ERR_TOOMANYCHANNELS */ ":%s 405 %s %s :You have joined too "
+ "many channels",
+ /* 406 ERR_WASNOSUCHNICK */ ":%s 406 %s %s :There was no such nickname",
+ /* 407 ERR_TOOMANYTARGETS */ ":%s 407 %s %s :Duplicate recipients. "
+ "No message delivered",
+ /* 408 ERR_NOCOLORSONCHAN */ ":%s 408 %s %s :You cannot use colors "
+ "on this channel. Not sent: %s",
+ /* 409 ERR_NOORIGIN */ ":%s 409 %s :No origin specified",
+ /* 410 */ NULL,
+ /* 411 ERR_NORECIPIENT */ ":%s 411 %s :No recipient given (%s)",
+ /* 412 ERR_NOTEXTOSEND */ ":%s 412 %s :No text to send",
+ /* 413 ERR_NOTOPLEVEL */ ":%s 413 %s %s :No toplevel domain specified",
+ /* 414 ERR_WILDTOPLEVEL */ ":%s 414 %s %s :Wildcard in toplevel Domain",
+ /* 415 */ NULL,
+ /* 416 */ NULL, /* In use by Undernet */
+ /* 417 */ NULL,
+ /* 418 */ NULL,
+ /* 419 */ NULL,
+ /* 420 */ NULL,
+ /* 421 ERR_UNKNOWNCOMMAND */ ":%s 421 %s %s :Unknown command",
+ /* 422 ERR_NOMOTD */ ":%s 422 %s :MOTD File is missing",
+ /* 423 ERR_NOADMININFO */ ":%s 423 %s %s :No administrative info "
+ "available",
+ /* 424 ERR_FILEERROR */ ":%s 424 %s :File error doing %s on %s",
+ /* 425 */ NULL,
+ /* 426 */ NULL,
+ /* 427 */ NULL,
+ /* 428 */ NULL,
+ /* 429 ERR_TOOMANYAWAY */ ":%s 429 %s :Too Many aways - Flood "
+ "Protection activated",
+ /* 430 */ NULL,
+ /* 431 ERR_NONICKNAMEGIVEN */ ":%s 431 %s :No nickname given",
+ /* 432 ERR_ERRONEOUSNICKNAME */ ":%s 432 %s %s :%s",
+ /* 433 ERR_NICKNAMEINUSE */ ":%s 433 %s %s :Nickname is already in use.",
+ /* 434 */ NULL,
+ /* 435 ERR_BANONCHAN */ ":%s 435 %s %s %s :Cannot change to a banned "
+ "nickname",
+ /* 436 ERR_NICKCOLLISION */ ":%s 436 %s %s :Nickname collision KILL",
+ /* 437 ERR_BANNICKCHANGE */ ":%s 437 %s %s :Cannot change nickname while "
+ "banned or moderated on channel",
+ /* 438 */ NULL, /* In use by Undernet */
+ /* 439 ERR_TARGETTOOFAST */ ":%s 439 %s %s :Message target change too fast. "
+ "Please wait %d seconds and then try again.",
+ /* 440 ERR_SERVICESDOWN */ ":%s 440 %s %s :Services is currently down. "
+ "Please wait a few moments, and then try "
+ "again.",
+ /* 441 ERR_USERNOTINCHANNEL */ ":%s 441 %s %s %s :They aren't on "
+ "that channel",
+ /* 442 ERR_NOTONCHANNEL */ ":%s 442 %s %s :You're not on that channel",
+ /* 443 ERR_USERONCHANNEL */ ":%s 443 %s %s %s :is already on channel",
+ /* 444 ERR_NOLOGIN */ ":%s 444 %s %s :User not logged in",
+ /* 445 ERR_SUMMONDISABLED */ ":%s 445 %s :SUMMON has been removed",
+ /* 446 ERR_USERSDISABLED */ ":%s 446 %s :USERS has been removed",
+ /* 447 */ NULL,
+ /* 448 */ NULL,
+ /* 449 */ NULL,
+ /* 450 */ NULL,
+ /* 451 ERR_NOTREGISTERED */ ":%s 451 %s :You have not registered",
+ /* 452 */ NULL,
+ /* 453 */ NULL,
+ /* 454 */ NULL,
+ /* 455 */ NULL,
+ /* 456 */ NULL,
+ /* 457 */ NULL,
+ /* 458 */ NULL,
+ /* 459 */ NULL,
+ /* 460 */ NULL,
+ /* 461 ERR_NEEDMOREPARAMS */ ":%s 461 %s %s :Not enough parameters",
+ /* 462 ERR_ALREADYREGISTERED */ ":%s 462 %s :You may not reregister",
+ /* 463 ERR_NOPERMFORHOST */ ":%s 463 %s :Your host isn't among the "
+ "privileged",
+ /* 464 ERR_PASSWDMISMATCH */ ":%s 464 %s :Password Incorrect",
+ /* 465 ERR_YOUREBANNEDCREEP */ ":%s 465 %s :You have been %s.",
+ /* 466 */ NULL,
+ /* 467 ERR_KEYSET */ ":%s 467 %s %s :Channel key already set",
+ /* 468 ERR_ONLYSERVERSCANCHANGE */ ":%s 468 %s %s :Only servers can "
+ "change that mode",
+ /* 469 */ NULL,
+ /* 470 */ NULL,
+ /* 471 ERR_CHANNELISFULL */ ":%s 471 %s %s :Cannot join channel (%s)",
+ /* 472 ERR_UNKNOWNMODE */ ":%s 472 %s %c :is unknown mode char to me",
+ /* 473 ERR_INVITEONLYCHAN */ ":%s 473 %s %s :Cannot join channel "
+ "(%s)",
+ /* 474 ERR_BANNEDFROMCHAN */ ":%s 474 %s %s :Cannot join channel "
+ "(+b)",
+ /* 475 ERR_BADCHANNELKEY */ ":%s 475 %s %s :Cannot join channel (+k)",
+ /* 476 ERR_BADCHANMASK */ ":%s 476 %s %s :Bad Channel Mask",
+ /* 477 ERR_NEEDREGGEDNICK */ ":%s 477 %s %s :You need to identify "
+ "to a registered nick to %s that "
+ "channel. For help with registering "
+ "your nickname, type \"/msg %s help "
+ "register\" or see %s",
+ /* 478 ERR_BANLISTFULL */ ":%s 478 %s %s %s :Channel %s list is full",
+ /* 479 ERR_BADCHANNAME */ ":%s 479 %s %s :Channel name contains illegal "
+ "characters",
+ /* 480 */ NULL,
+ /* 481 ERR_NOPRIVILEGES */ ":%s 481 %s :Permission Denied, You do not "
+ "have the correct irc operator privileges",
+ /* 482 ERR_CHANOPRIVSNEEDED */ ":%s 482 %s %s :You're not channel "
+ "operator",
+ /* 483 ERR_CANTKILLSERVER */ ":%s 483 %s :You cant kill a server!",
+ /* 484 */ NULL, /* In use by Undernet */
+ /* 485 ERR_CHANBANREASON */ ":%s 485 %s %s :Cannot join channel (%s)",
+ /* 486 ERR_NONONREG */ ":%s 486 %s :You must identify to a "
+ "registered nick to private message %s",
+ /* 487 ERR_MSGSERVICES */ ":%s 487 %s :Error! \"/msg %s\" is no longer supported. "
+ "Use \"/msg %s@%s\" or \"/%s\" instead.",
+ /* 488 */ NULL,
+ /* 489 */ NULL, /* In use by Undernet */
+ /* 490 */ NULL,
+ /* 491 ERR_NOOPERHOST */ ":%s 491 %s :No Oper block for your host",
+ /* 492 */ NULL,
+ /* 493 */ NULL,
+ /* 494 */ NULL,
+ /* 495 */ NULL,
+ /* 496 */ NULL,
+ /* 497 */ NULL,
+ /* 498 */ NULL,
+ /* 499 */ NULL,
+ /* 500 */ NULL,
+ /* 501 ERR_UMODEUNKNOWNFLAG */ ":%s 501 %s :Unknown MODE flag",
+ /* 502 ERR_USERSDONTMATCH */ ":%s 502 %s :Can't change mode for "
+ "other users",
+ /* 503 */ ":%s 503 %s :Message could not be delivered "
+ "to %s",
+ /* 504 */ NULL,
+ /* 505 */ NULL,
+ /* 506 */ NULL,
+ /* 507 */ NULL,
+ /* 508 */ NULL,
+ /* 509 */ NULL,
+ /* 510 */ NULL,
+ /* 511 ERR_SILELISTFULL */ ":%s 511 %s %s :Your silence list is full",
+ /* 512 ERR_TOOMANYWATCH */ ":%s 512 %s %s :Maximum size for WATCH-list "
+ "is 128 entries",
+ /* 513 */ NULL, /* In use by Undernet */
+ /* 514 ERR_TOOMANYDCC */ ":%s 514 %s %s :Your dcc allow list is full. "
+ "Maximum size is %d entries",
+ /* 515 */ NULL,
+ /* 516 */ NULL,
+ /* 517 */ NULL,
+ /* 518 */ NULL,
+ /* 519 */ NULL,
+ /* 520 */ NULL,
+ /* 521 ERR_LISTSYNTAX */ ":%s 521 %s :Bad list syntax, type /quote "
+ "list ? or /raw list ?",
+ /* 522 ERR_WHOSYNTAX */ ":%s 522 %s :/%s Syntax incorrect, use "
+ "/%s ? for help",
+ /* 523 ERR_WHOLIMEXCEED */ ":%s 523 %s %d :%s search limit exceeded.",
+ /* 524 */ NULL,
+ /* 525 */ NULL,
+ /* 526 */ NULL,
+ /* 527 */ NULL,
+ /* 528 */ NULL,
+ /* 529 */ NULL,
+ /* 530 */ NULL,
+ /* 531 */ NULL,
+ /* 532 */ NULL,
+ /* 533 */ NULL,
+ /* 534 */ NULL,
+ /* 535 */ NULL,
+ /* 536 */ NULL,
+ /* 537 */ NULL,
+ /* 538 */ NULL,
+ /* 539 */ NULL,
+ /* 540 */ NULL,
+ /* 541 */ NULL,
+ /* 542 */ NULL,
+ /* 543 */ NULL,
+ /* 544 */ NULL,
+ /* 545 */ NULL,
+ /* 546 */ NULL,
+ /* 547 */ NULL,
+ /* 548 */ NULL,
+ /* 549 */ NULL,
+ /* 550 */ NULL,
+ /* 551 */ NULL,
+ /* 552 */ NULL,
+ /* 553 */ NULL,
+ /* 554 */ NULL,
+ /* 555 */ NULL,
+ /* 556 */ NULL,
+ /* 557 */ NULL,
+ /* 558 */ NULL,
+ /* 559 */ NULL,
+ /* 560 */ NULL,
+ /* 561 */ NULL,
+ /* 562 */ NULL,
+ /* 563 */ NULL,
+ /* 564 */ NULL,
+ /* 565 */ NULL,
+ /* 566 */ NULL,
+ /* 567 */ NULL,
+ /* 568 */ NULL,
+ /* 569 */ NULL,
+ /* 570 */ NULL,
+ /* 571 */ NULL,
+ /* 572 */ NULL,
+ /* 573 */ NULL,
+ /* 574 */ NULL,
+ /* 575 */ NULL,
+ /* 576 */ NULL,
+ /* 577 */ NULL,
+ /* 578 */ NULL,
+ /* 579 */ NULL,
+ /* 580 */ NULL,
+ /* 581 */ NULL,
+ /* 582 */ NULL,
+ /* 583 */ NULL,
+ /* 584 */ NULL,
+ /* 585 */ NULL,
+ /* 586 */ NULL,
+ /* 587 */ NULL,
+ /* 588 */ NULL,
+ /* 589 */ NULL,
+ /* 590 */ NULL,
+ /* 591 */ NULL,
+ /* 592 */ NULL,
+ /* 593 */ NULL,
+ /* 594 */ NULL,
+ /* 595 */ NULL,
+ /* 596 */ NULL,
+ /* 597 */ NULL,
+ /* 598 */ NULL,
+ /* 599 */ NULL,
+ /* 600 RPL_LOGON */ ":%s 600 %s %s %s %s %d :logged online",
+ /* 601 RPL_LOGOFF */ ":%s 601 %s %s %s %s %d :logged offline",
+ /* 602 RPL_WATCHOFF */ ":%s 602 %s %s %s %s %d :stopped watching",
+ /* 603 RPL_WATCHSTAT */ ":%s 603 %s :You have %d and are on %d WATCH "
+ "entries",
+ /* 604 RPL_NOWON */ ":%s 604 %s %s %s %s %d :is online",
+ /* 605 RPL_NOWOFF */ ":%s 605 %s %s %s %s %d :is offline",
+ /* 606 RPL_WATCHLIST */ ":%s 606 %s :%s",
+ /* 607 RPL_ENDOFWATCHLIST */ ":%s 607 %s :End of WATCH %c",
+ /* 608 */ NULL, /* Do not use */
+ /* 609 */ NULL,
+ /* 610 */ NULL,
+ /* 611 */ NULL,
+ /* 612 */ NULL,
+ /* 613 */ NULL,
+ /* 614 */ NULL,
+ /* 615 */ NULL,
+ /* 616 */ NULL,
+ /* 617 RPL_DCCSTATUS */ ":%s 617 %s :%s has been %s your DCC allow "
+ "list",
+ /* 618 RPL_DCCLIST */ ":%s 618 %s :%s",
+ /* 619 RPL_ENDOFDCCLIST */ ":%s 619 %s :End of DCCALLOW %s",
+ /* 620 RPL_DCCINFO */ ":%s 620 %s :%s",
+ /* 621 */ NULL,
+ /* 622 */ NULL,
+ /* 623 */ NULL,
+ /* 624 */ NULL,
+ /* 625 */ NULL,
+ /* 626 */ NULL,
+ /* 627 */ NULL,
+ /* 628 */ NULL,
+ /* 629 */ NULL,
+ /* 630 */ NULL,
+ /* 631 */ NULL,
+ /* 632 */ NULL,
+ /* 633 */ NULL,
+ /* 634 */ NULL,
+ /* 635 */ NULL,
+ /* 636 */ NULL,
+ /* 637 */ NULL,
+ /* 638 */ NULL,
+ /* 639 */ NULL,
+ /* 640 */ NULL,
+ /* 641 */ NULL,
+ /* 642 */ NULL,
+ /* 643 */ NULL,
+ /* 644 */ NULL,
+ /* 645 */ NULL,
+ /* 646 */ NULL,
+ /* 647 */ NULL,
+ /* 648 */ NULL,
+ /* 649 */ NULL,
+ /* 650 */ NULL,
+ /* 651 */ NULL,
+ /* 652 */ NULL,
+ /* 653 */ NULL,
+ /* 654 */ NULL,
+ /* 655 */ NULL,
+ /* 656 */ NULL,
+ /* 657 */ NULL,
+ /* 658 */ NULL,
+ /* 659 */ NULL,
+ /* 660 */ NULL,
+ /* 661 */ NULL,
+ /* 662 */ NULL,
+ /* 663 */ NULL,
+ /* 664 */ NULL,
+ /* 665 */ NULL,
+ /* 666 */ NULL,
+ /* 667 */ NULL,
+ /* 668 */ NULL,
+ /* 669 */ NULL,
+ /* 670 */ NULL,
+ /* 671 */ NULL,
+ /* 672 */ NULL,
+ /* 673 */ NULL,
+ /* 674 */ NULL,
+ /* 675 */ NULL,
+ /* 676 */ NULL,
+ /* 677 */ NULL,
+ /* 678 */ NULL,
+ /* 679 */ NULL,
+ /* 680 */ NULL,
+ /* 681 */ NULL,
+ /* 682 */ NULL,
+ /* 683 */ NULL,
+ /* 684 */ NULL,
+ /* 685 */ NULL,
+ /* 686 */ NULL,
+ /* 687 */ NULL,
+ /* 688 */ NULL,
+ /* 689 */ NULL,
+ /* 690 */ NULL,
+ /* 691 */ NULL,
+ /* 692 */ NULL,
+ /* 693 */ NULL,
+ /* 694 */ NULL,
+ /* 695 */ NULL,
+ /* 696 */ NULL,
+ /* 697 */ NULL,
+ /* 698 */ NULL,
+ /* 699 */ NULL,
+ /* 700 */ NULL,
+ /* 701 */ NULL,
+ /* 702 */ NULL,
+ /* 703 */ NULL,
+ /* 704 */ NULL,
+ /* 705 */ NULL,
+ /* 706 */ NULL,
+ /* 707 */ NULL,
+ /* 708 */ NULL,
+ /* 709 */ NULL,
+ /* 710 */ NULL,
+ /* 711 */ NULL,
+ /* 712 */ NULL,
+ /* 713 */ NULL,
+ /* 714 */ NULL,
+ /* 715 */ NULL,
+ /* 716 */ NULL,
+ /* 717 */ NULL,
+ /* 718 */ NULL,
+ /* 719 */ NULL,
+ /* 720 */ NULL,
+ /* 721 */ NULL,
+ /* 722 */ NULL,
+ /* 723 */ NULL,
+ /* 724 */ NULL,
+ /* 725 */ NULL,
+ /* 726 */ NULL,
+ /* 727 */ NULL,
+ /* 728 */ NULL,
+ /* 729 */ NULL,
+ /* 730 */ NULL,
+ /* 731 */ NULL,
+ /* 732 */ NULL,
+ /* 733 */ NULL,
+ /* 734 */ NULL,
+ /* 735 */ NULL,
+ /* 736 */ NULL,
+ /* 737 */ NULL,
+ /* 738 */ NULL,
+ /* 739 */ NULL,
+ /* 740 */ NULL,
+ /* 741 */ NULL,
+ /* 742 */ NULL,
+ /* 743 */ NULL,
+ /* 744 */ NULL,
+ /* 745 */ NULL,
+ /* 746 */ NULL,
+ /* 747 */ NULL,
+ /* 748 */ NULL,
+ /* 749 */ NULL,
+ /* 750 */ NULL,
+ /* 751 */ NULL,
+ /* 752 */ NULL,
+ /* 753 */ NULL,
+ /* 754 */ NULL,
+ /* 755 */ NULL,
+ /* 756 */ NULL,
+ /* 757 */ NULL,
+ /* 758 */ NULL,
+ /* 759 */ NULL,
+ /* 760 */ NULL,
+ /* 761 */ NULL,
+ /* 762 */ NULL,
+ /* 763 */ NULL,
+ /* 764 */ NULL,
+ /* 765 */ NULL,
+ /* 766 */ NULL,
+ /* 767 */ NULL,
+ /* 768 */ NULL,
+ /* 769 */ NULL,
+ /* 770 */ NULL,
+ /* 771 */ NULL,
+ /* 772 */ NULL,
+ /* 773 */ NULL,
+ /* 774 */ NULL,
+ /* 775 */ NULL,
+ /* 776 */ NULL,
+ /* 777 */ NULL,
+ /* 778 */ NULL,
+ /* 779 */ NULL,
+ /* 780 */ NULL,
+ /* 781 */ NULL,
+ /* 782 */ NULL,
+ /* 783 */ NULL,
+ /* 784 */ NULL,
+ /* 785 */ NULL,
+ /* 786 */ NULL,
+ /* 787 */ NULL,
+ /* 788 */ NULL,
+ /* 789 */ NULL,
+ /* 790 */ NULL,
+ /* 791 */ NULL,
+ /* 792 */ NULL,
+ /* 793 */ NULL,
+ /* 794 */ NULL,
+ /* 795 */ NULL,
+ /* 796 */ NULL,
+ /* 797 */ NULL,
+ /* 798 */ NULL,
+ /* 799 */ NULL,
+ /* 800 */ NULL,
+ /* 801 */ NULL,
+ /* 802 */ NULL,
+ /* 803 */ NULL,
+ /* 804 */ NULL,
+ /* 805 */ NULL,
+ /* 806 */ NULL,
+ /* 807 */ NULL,
+ /* 808 */ NULL,
+ /* 809 */ NULL,
+ /* 810 */ NULL,
+ /* 811 */ NULL,
+ /* 812 */ NULL,
+ /* 813 */ NULL,
+ /* 814 */ NULL,
+ /* 815 */ NULL,
+ /* 816 */ NULL,
+ /* 817 */ NULL,
+ /* 818 */ NULL,
+ /* 819 */ NULL,
+ /* 820 */ NULL,
+ /* 821 */ NULL,
+ /* 822 */ NULL,
+ /* 823 */ NULL,
+ /* 824 */ NULL,
+ /* 825 */ NULL,
+ /* 826 */ NULL,
+ /* 827 */ NULL,
+ /* 828 */ NULL,
+ /* 829 */ NULL,
+ /* 830 */ NULL,
+ /* 831 */ NULL,
+ /* 832 */ NULL,
+ /* 833 */ NULL,
+ /* 834 */ NULL,
+ /* 835 */ NULL,
+ /* 836 */ NULL,
+ /* 837 */ NULL,
+ /* 838 */ NULL,
+ /* 839 */ NULL,
+ /* 840 */ NULL,
+ /* 841 */ NULL,
+ /* 842 */ NULL,
+ /* 843 */ NULL,
+ /* 844 */ NULL,
+ /* 845 */ NULL,
+ /* 846 */ NULL,
+ /* 847 */ NULL,
+ /* 848 */ NULL,
+ /* 849 */ NULL,
+ /* 850 */ NULL,
+ /* 851 */ NULL,
+ /* 852 */ NULL,
+ /* 853 */ NULL,
+ /* 854 */ NULL,
+ /* 855 */ NULL,
+ /* 856 */ NULL,
+ /* 857 */ NULL,
+ /* 858 */ NULL,
+ /* 859 */ NULL,
+ /* 860 */ NULL,
+ /* 861 */ NULL,
+ /* 862 */ NULL,
+ /* 863 */ NULL,
+ /* 864 */ NULL,
+ /* 865 */ NULL,
+ /* 866 */ NULL,
+ /* 867 */ NULL,
+ /* 868 */ NULL,
+ /* 869 */ NULL,
+ /* 870 */ NULL,
+ /* 871 */ NULL,
+ /* 872 */ NULL,
+ /* 873 */ NULL,
+ /* 874 */ NULL,
+ /* 875 */ NULL,
+ /* 876 */ NULL,
+ /* 877 */ NULL,
+ /* 878 */ NULL,
+ /* 879 */ NULL,
+ /* 880 */ NULL,
+ /* 881 */ NULL,
+ /* 882 */ NULL,
+ /* 883 */ NULL,
+ /* 884 */ NULL,
+ /* 885 */ NULL,
+ /* 886 */ NULL,
+ /* 887 */ NULL,
+ /* 888 */ NULL,
+ /* 889 */ NULL,
+ /* 890 */ NULL,
+ /* 891 */ NULL,
+ /* 892 */ NULL,
+ /* 893 */ NULL,
+ /* 894 */ NULL,
+ /* 895 */ NULL,
+ /* 896 */ NULL,
+ /* 897 */ NULL,
+ /* 898 */ NULL,
+ /* 899 */ NULL,
+ /* 900 */ NULL,
+ /* 901 */ NULL,
+ /* 902 */ NULL,
+ /* 903 */ NULL,
+ /* 904 */ NULL,
+ /* 905 */ NULL,
+ /* 906 */ NULL,
+ /* 907 */ NULL,
+ /* 908 */ NULL,
+ /* 909 */ NULL,
+ /* 910 */ NULL,
+ /* 911 */ NULL,
+ /* 912 */ NULL,
+ /* 913 */ NULL,
+ /* 914 */ NULL,
+ /* 915 */ NULL,
+ /* 916 */ NULL,
+ /* 917 */ NULL,
+ /* 918 */ NULL,
+ /* 919 */ NULL,
+ /* 920 */ NULL,
+ /* 921 */ NULL,
+ /* 922 */ NULL,
+ /* 923 */ NULL,
+ /* 924 */ NULL,
+ /* 925 */ NULL,
+ /* 926 */ NULL,
+ /* 927 */ NULL,
+ /* 928 */ NULL,
+ /* 929 */ NULL,
+ /* 930 */ NULL,
+ /* 931 */ NULL,
+ /* 932 */ NULL,
+ /* 933 */ NULL,
+ /* 934 */ NULL,
+ /* 935 */ NULL,
+ /* 936 */ NULL,
+ /* 937 */ NULL,
+ /* 938 */ NULL,
+ /* 939 */ NULL,
+ /* 940 */ NULL,
+ /* 941 */ NULL,
+ /* 942 */ NULL,
+ /* 943 */ NULL,
+ /* 944 */ NULL,
+ /* 945 */ NULL,
+ /* 946 */ NULL,
+ /* 947 */ NULL,
+ /* 948 */ NULL,
+ /* 949 */ NULL,
+ /* 950 */ NULL,
+ /* 951 */ NULL,
+ /* 952 */ NULL,
+ /* 953 */ NULL,
+ /* 954 */ NULL,
+ /* 955 */ NULL,
+ /* 956 */ NULL,
+ /* 957 */ NULL,
+ /* 958 */ NULL,
+ /* 959 */ NULL,
+ /* 960 */ NULL,
+ /* 961 */ NULL,
+ /* 962 */ NULL,
+ /* 963 */ NULL,
+ /* 964 */ NULL,
+ /* 965 */ NULL,
+ /* 966 */ NULL,
+ /* 967 */ NULL,
+ /* 968 */ NULL,
+ /* 969 */ NULL,
+ /* 970 */ NULL,
+ /* 971 */ NULL,
+ /* 972 */ NULL,
+ /* 973 */ NULL,
+ /* 974 */ NULL,
+ /* 975 */ NULL,
+ /* 976 */ NULL,
+ /* 977 */ NULL,
+ /* 978 */ NULL,
+ /* 979 */ NULL,
+ /* 980 */ NULL,
+ /* 981 */ NULL,
+ /* 982 */ NULL,
+ /* 983 */ NULL,
+ /* 984 */ NULL,
+ /* 985 */ NULL,
+ /* 986 */ NULL,
+ /* 987 */ NULL,
+ /* 988 */ NULL,
+ /* 989 */ NULL,
+ /* 990 */ NULL,
+ /* 991 */ NULL,
+ /* 992 */ NULL,
+ /* 993 */ NULL,
+ /* 994 */ NULL,
+ /* 995 */ NULL,
+ /* 996 */ NULL,
+ /* 997 */ NULL,
+ /* 998 */ NULL,
+ /* 999 */ ":%s 999 %s Numeric error! yikes!",
+ /* 1000 */ NULL
+};
+
+char *getreply(int numeric)
+{
+ if((numeric<0 || numeric>999) || !replies[numeric])
+ return(replies[ERR_NUMERIC_ERR]);
+ else
+ return(replies[numeric]);
+}
+
+char *err_str(int numeric)
+{
+ return getreply(numeric);
+}
+char *rpl_str(int numeric)
+{
+ return getreply(numeric);
+}
+
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/s_misc.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: s_misc.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include <sys/time.h>
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "zlink.h"
+#include "hooks.h"
+#include "clones.h"
+#include <sys/stat.h>
+#include <fcntl.h>
+#if !defined(ULTRIX) && !defined(SGI) && !defined(sequent) && \
+ !defined(__convex__)
+#include <sys/param.h>
+#endif
+#if defined(AIX) || defined(SVR3) || \
+ ((__GNU_LIBRARY__ == 6) && (__GLIBC__ >=2) && (__GLIBC_MINOR__ >= 2))
+#include <time.h>
+#endif
+#include "h.h"
+#include "fdlist.h"
+
+extern float curSendK, curRecvK;
+
+extern int server_was_split;
+
+#ifdef ALWAYS_SEND_DURING_SPLIT
+int currently_processing_netsplit = NO;
+#endif
+
+static void exit_one_client(aClient *, aClient *, aClient *, char *);
+
+static char *months[] =
+{
+ "January", "February", "March", "April",
+ "May", "June", "July", "August",
+ "September", "October", "November", "December"
+};
+
+static char *weekdays[] =
+{
+ "Sunday", "Monday", "Tuesday", "Wednesday",
+ "Thursday", "Friday", "Saturday"
+};
+
+/* stats stuff */
+struct stats ircst, *ircstp = &ircst;
+
+char *
+date(time_t clock)
+{
+ static char buf[80], plus;
+ struct tm *lt, *gm;
+ struct tm gmbuf;
+ int minswest;
+
+ if (!clock)
+ time(&clock);
+ gm = gmtime(&clock);
+ memcpy((char *) &gmbuf, (char *) gm, sizeof(gmbuf));
+ gm = &gmbuf;
+ lt = localtime(&clock);
+
+ if (lt->tm_yday == gm->tm_yday)
+ minswest = (gm->tm_hour - lt->tm_hour) * 60 + (gm->tm_min - lt->tm_min);
+ else if (lt->tm_yday > gm->tm_yday)
+ minswest = (gm->tm_hour - (lt->tm_hour + 24)) * 60;
+ else
+ minswest = ((gm->tm_hour + 24) - lt->tm_hour) * 60;
+
+ plus = (minswest > 0) ? '-' : '+';
+ if (minswest < 0)
+ minswest = -minswest;
+
+ ircsprintf(buf, "%s %s %d %04d -- %02d:%02d %c%02d:%02d",
+ weekdays[lt->tm_wday], months[lt->tm_mon], lt->tm_mday,
+ lt->tm_year + 1900, lt->tm_hour, lt->tm_min,
+ plus, minswest / 60, minswest % 60);
+
+ return buf;
+}
+
+char *
+smalldate(time_t clock)
+{
+ static char buf[MAX_DATE_STRING];
+ struct tm *lt, *gm;
+ struct tm gmbuf;
+
+ if (!clock)
+ time(&clock);
+ gm = gmtime(&clock);
+ memcpy((char *) &gmbuf, (char *) gm, sizeof(gmbuf));
+ gm = &gmbuf;
+ lt = localtime(&clock);
+
+ ircsprintf(buf, "%04d/%02d/%02d %02d.%02d", lt->tm_year + 1900,
+ lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min);
+
+ return buf;
+}
+
+/**
+ ** myctime()
+ ** This is like standard ctime()-function, but it zaps away
+ ** the newline from the end of that string. Also, it takes
+ ** the time value as parameter, instead of pointer to it.
+ ** Note that it is necessary to copy the string to alternate
+ ** buffer (who knows how ctime() implements it, maybe it statically
+ ** has newline there and never 'refreshes' it -- zapping that
+ ** might break things in other places...)
+ **
+ **/
+char *
+myctime(time_t value)
+{
+ static char buf[28];
+ char *p;
+
+ strcpy(buf, ctime(&value));
+ if ((p = (char *) strchr(buf, '\n')) != NULL)
+ *p = '\0';
+
+ return buf;
+}
+
+/*
+ * * check_registered_user is used to cancel message, if the *
+ * originator is a server or not registered yet. In other * words,
+ * passing this test, *MUST* guarantee that the * sptr->user exists
+ * (not checked after this--let there * be coredumps to catch bugs...
+ * this is intentional --msa ;) *
+ *
+ * There is this nagging feeling... should this NOT_REGISTERED * error
+ * really be sent to remote users? This happening means * that remote
+ * servers have this user registered, although this * one has it not...
+ * Not really users fault... Perhaps this * error message should be
+ * restricted to local clients and some * other thing generated for
+ * remotes...
+ */
+inline int
+check_registered_user(aClient *sptr)
+{
+ if (!IsRegisteredUser(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOTREGISTERED), me.name, "*");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * * check_registered user cancels message, if 'x' is not * registered
+ * (e.g. we don't know yet whether a server * or user)
+ */
+inline int
+check_registered(aClient *sptr)
+{
+ if (!IsRegistered(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOTREGISTERED), me.name, "*");
+ return -1;
+ }
+ return 0;
+}
+
+inline char *
+get_listener_name(aListener *lptr)
+{
+ static char nbuf[HOSTLEN * 2 + USERLEN + 5];
+
+ ircsprintf(nbuf, "%s[@%s.%d][%s]", me.name, BadPtr(lptr->vhost_string) ?
+ "0.0.0.0" : lptr->vhost_string, lptr->port,
+ BadPtr(lptr->allow_string) ? "*" : lptr->allow_string);
+
+ return nbuf;
+}
+
+/*
+ * * get_client_name * Return the name of the client for various
+ * tracking and * admin purposes. The main purpose of this
+ * function is to * return the "socket host" name of the client,
+ * if that * differs from the advertised name (other than case). *
+ * But, this can be used to any client structure. *
+ *
+ * Returns: * "name[user@ip#.port]" if 'showip' is true; *
+ * "name[sockethost]", if name and sockhost are different and *
+ * showip is false; else * "name". *
+ *
+ * NOTE 1: * Watch out the allocation of "nbuf", if either
+ * sptr->name * or sptr->sockhost gets changed into pointers instead of *
+ * directly allocated within the structure... *
+ *
+ * NOTE 2: * Function return either a pointer to the structure
+ * (sptr) or * to internal buffer (nbuf). *NEVER* use the returned
+ * pointer * to modify what it points!!!
+ */
+char *
+get_client_name(aClient *sptr, int showip)
+{
+ static char nbuf[HOSTLEN * 2 + USERLEN + 5];
+
+ if (MyConnect(sptr))
+ {
+ switch (showip)
+ {
+ case TRUE:
+#ifdef SHOW_UH
+ ircsprintf(nbuf, "%s[%s%s@%s]", sptr->name,
+ (!(sptr->flags & FLAGS_GOTID)) ? "" : "(+)",
+ sptr->user ? sptr->user->username : sptr->username,
+ inetntoa((char *) &sptr->ip));
+#else
+ ircsprintf(nbuf, "%s[%s@%s]", sptr->name,
+ (!(sptr->flags & FLAGS_GOTID)) ? "" : sptr->username,
+ inetntoa((char *) &sptr->ip));
+#endif
+ break;
+ case HIDEME:
+#ifdef SHOW_UH
+ ircsprintf(nbuf, "%s[%s%s@%s]", sptr->name,
+ (!(sptr->flags & FLAGS_GOTID)) ? "" : "(+)",
+ sptr->user ? sptr->user->username : sptr->username,
+ "0.0.0.0");
+#else
+ ircsprintf(nbuf, "%s[%s@%s]", sptr->name,
+ (!(sptr->flags & FLAGS_GOTID)) ? "" : sptr->username,
+ "0.0.0.0");
+#endif
+ break;
+ default:
+ if (mycmp(sptr->name, sptr->sockhost))
+#ifdef USERNAMES_IN_TRACE
+ ircsprintf(nbuf, "%s[%s@%s]", sptr->name,
+ sptr->user ? sptr->user->username :
+ sptr->username, sptr->sockhost);
+#else
+ ircsprintf(nbuf, "%s[%s]", sptr->name, sptr->sockhost);
+#endif
+ else
+ return sptr->name;
+ }
+ return nbuf;
+ }
+ return sptr->name;
+}
+
+char *
+get_client_host(aClient *cptr)
+{
+ static char nbuf[HOSTLEN * 2 + USERLEN + 5];
+
+ if (!MyConnect(cptr))
+ return cptr->name;
+ if (!cptr->hostp)
+ return get_client_name(cptr, FALSE);
+ else
+ ircsprintf(nbuf, "%s[%-.*s@%-.*s]", cptr->name, USERLEN,
+ (!(cptr->flags & FLAGS_GOTID)) ? "" : cptr->username,
+ HOSTLEN, cptr->hostp->h_name);
+ return nbuf;
+}
+
+/*
+ * Form sockhost such that if the host is of form user@host, only the
+ * host portion is copied.
+ */
+void
+get_sockhost(aClient *cptr, char *host)
+{
+ char *s;
+
+ if ((s = (char *) strchr(host, '@')))
+ s++;
+ else
+ s = host;
+ strncpyzt(cptr->sockhost, s, sizeof(cptr->sockhost));
+}
+
+/*
+ * Return wildcard name of my server name according to given config
+ * entry --Jto
+ */
+char *
+my_name_for_link(char *name, aConnect *aconn)
+{
+ static char namebuf[HOSTLEN];
+ int count = aconn->port;
+ char *start = name;
+
+ if (count <= 0 || count > 5)
+ return start;
+
+ while (count-- && name)
+ {
+ name++;
+ name = (char *) strchr(name, '.');
+ }
+ if (!name)
+ return start;
+
+ namebuf[0] = '*';
+ strncpy(&namebuf[1], name, HOSTLEN - 1);
+ namebuf[HOSTLEN - 1] = '\0';
+ return namebuf;
+}
+
+int remove_dcc_references(aClient *sptr)
+{
+ aClient *acptr;
+ Link *lp, *nextlp;
+ Link **lpp, *tmp;
+ int found;
+
+ lp = sptr->user->dccallow;
+
+ while(lp)
+ {
+ nextlp = lp->next;
+ acptr = lp->value.cptr;
+ for(found = 0, lpp = &(acptr->user->dccallow);
+ *lpp; lpp=&((*lpp)->next))
+ {
+ if(lp->flags == (*lpp)->flags)
+ continue; /* match only opposite types for sanity */
+ if((*lpp)->value.cptr == sptr)
+ {
+ if((*lpp)->flags == DCC_LINK_ME)
+ {
+ sendto_one(acptr, ":%s %d %s :%s has been removed from "
+ "your DCC allow list for signing off",
+ me.name, RPL_DCCINFO, acptr->name, sptr->name);
+ }
+ tmp = *lpp;
+ *lpp = tmp->next;
+ free_link(tmp);
+ found++;
+ break;
+ }
+ }
+
+ if(!found)
+ sendto_realops_lev(DEBUG_LEV, "rdr(): %s was in dccallowme "
+ "list[%d] of %s but not in dccallowrem list!",
+ acptr->name, lp->flags, sptr->name);
+ free_link(lp);
+ lp = nextlp;
+ }
+ return 0;
+}
+
+/*
+ * NOQUIT
+ * a method of reducing the stress on the network during server splits
+ * by sending only a simple "SQUIT" message for the server that is dropping,
+ * instead of thousands upon thousands of QUIT messages for each user,
+ * plus an SQUIT for each server behind the dead link.
+ *
+ * Original idea by Cabal95, implementation by lucas
+ */
+
+void
+exit_one_client_in_split(aClient *cptr, aClient *dead, char *reason)
+{
+ Link *lp;
+
+ /* send all the quit reasons to all the non-noquit servers we have */
+
+ /* yikes. We only want to do this if dead was OUR server. */
+ /* erm, no, that's not true. Doing that breaks things.
+ * If a non-noquit server is telling us a server has split,
+ * we will have already recieved hundreds of QUIT messages
+ * from it, which will be passed anyway, and this procedure
+ * will never be called. - lucas
+ */
+
+#ifdef NOQUIT
+ sendto_non_noquit_servs_butone(dead, ":%s QUIT :%s", cptr->name, reason);
+#endif
+
+ sendto_common_channels(cptr, ":%s QUIT :%s", cptr->name, reason);
+
+ while ((lp = cptr->user->channel))
+ remove_user_from_channel(cptr, lp->value.chptr);
+ while ((lp = cptr->user->invited))
+ del_invite(cptr, lp->value.chptr);
+ while ((lp = cptr->user->silence))
+ del_silence(cptr, lp->value.cp);
+
+ if (cptr->ip.s_addr)
+ clones_remove(cptr);
+
+ remove_dcc_references(cptr);
+
+ del_from_client_hash_table(cptr->name, cptr);
+
+ hash_check_watch(cptr, RPL_LOGOFF);
+
+ remove_client_from_list(cptr);
+}
+
+/* exit_one_server
+ *
+ * recursive function!
+ * therefore, we pass dead and reason to ourselves.
+ * in the beginning, dead == cptr, so it will be the one
+ * out of the loop last. therefore, dead should remain a good pointer.
+ * cptr: the server being exited
+ * dead: the actual server that split (if this belongs to us, we
+ * absolutely CANNOT send to it)
+ * from: the client that caused this split
+ * lcptr: the local client that initiated this
+ * spinfo: split reason, as generated in exit_server
+ * comment: comment provided
+ */
+
+void
+exit_one_server(aClient *cptr, aClient *dead, aClient *from,
+ aClient *lcptr, char *spinfo, char *comment)
+{
+ aClient *acptr, *next;
+ DLink *lp;
+
+ /* okay, this is annoying.
+ * first off, we need two loops.
+ * one: to remove all the clients.
+ * two: to remove all the servers.
+ * HOWEVER! removing a server may cause removal of more servers
+ * and more clients.
+ * and this may make our pointer to next bad. therefore, we have to restart
+ * the server loop each time we find a server.
+ * We _NEED_ two different loops: all clients must be removed "
+ * before the server is
+ * removed. Otherwise, bad things (tm) can happen.
+ */
+
+ Debug((DEBUG_NOTICE, "server noquit: %s", cptr->name));
+
+ for (acptr = client; acptr; acptr = next)
+ {
+ next = acptr->next; /* we might destroy this client record
+ * in the loop. */
+
+ if(acptr->uplink != cptr || !IsPerson(acptr))
+ continue;
+
+ exit_one_client_in_split(acptr, dead, spinfo);
+ }
+
+ for (acptr = client; acptr; acptr = next)
+ {
+ next = acptr->next; /* we might destroy this client record in
+ * the loop. */
+
+ if(acptr->uplink != cptr || !IsServer(acptr))
+ continue;
+
+ exit_one_server(acptr, dead, from, lcptr, spinfo, comment);
+ next = client; /* restart the loop */
+ }
+
+ Debug((DEBUG_NOTICE, "done exiting server: %s", cptr->name));
+
+ for (lp = server_list; lp; lp = lp->next)
+ {
+ acptr = lp->value.cptr;
+
+ if (acptr == cptr || IsMe(acptr) ||
+ acptr == dead || acptr == lcptr)
+ continue;
+
+ /* if the server is noquit, we only want to send it
+ * information about 'dead'
+ * if it's not, this server gets split information for ALL
+ * dead servers.
+ */
+
+ if(cptr != dead)
+ continue;
+
+ if (cptr->from == acptr) /* "upstream" squit */
+ sendto_one(acptr, ":%s SQUIT %s :%s", from->name, cptr->name,
+ comment);
+ else
+ sendto_one(acptr, "SQUIT %s :%s", cptr->name, comment);
+ }
+
+ del_from_client_hash_table(cptr->name, cptr);
+ hash_check_watch(cptr, RPL_LOGOFF);
+ remove_client_from_list(cptr);
+}
+
+/* exit_server
+ *
+ * lcptr: the local client that initiated this
+ * cptr: the server that is being dropped.
+ * from: the client/server that caused this to happen
+ * comment: reason this is happening
+ * we then call exit_one_server, the recursive function.
+ */
+
+void exit_server(aClient *lcptr, aClient *cptr, aClient *from, char *comment)
+{
+ char splitname[HOSTLEN + HOSTLEN + 2];
+
+#ifdef HIDE_SPLIT_SERVERS
+ ircsprintf(splitname, "%s %s", HIDDEN_SERVER_NAME, HIDDEN_SERVER_NAME);
+#else
+ ircsprintf(splitname, "%s %s", cptr->uplink->name, cptr->name);
+#endif
+
+ Debug((DEBUG_NOTICE, "exit_server(%s, %s, %s)", cptr->name, from->name,
+ comment));
+
+ exit_one_server(cptr, cptr, from, lcptr, splitname, comment);
+}
+
+/*
+ * exit_client
+ * This is old "m_bye". Name changed, because this is not a
+ * protocol function, but a general server utility function.
+ *
+ * This function exits a client of *any* type (user, server, etc)
+ * from this server. Also, this generates all necessary prototol
+ * messages that this exit may cause.
+ *
+ * 1) If the client is a local client, then this implicitly exits
+ * all other clients depending on this connection (e.g. remote
+ * clients having 'from'-field that points to this.
+ *
+ * 2) If the client is a remote client, then only this is exited.
+ *
+ * For convenience, this function returns a suitable value for
+ * m_function return value:
+ *
+ * FLUSH_BUFFER if (cptr == sptr)
+ * 0 if (cptr != sptr)
+ */
+int
+exit_client(aClient *cptr, aClient *sptr, aClient *from, char *comment)
+{
+#ifdef FNAME_USERLOG
+ time_t on_for;
+#endif
+
+ if (MyConnect(sptr))
+ {
+ call_hooks(CHOOK_SIGNOFF, sptr);
+
+ if (IsAnOper(sptr))
+ remove_from_list(&oper_list, sptr, NULL);
+ if (sptr->flags & FLAGS_HAVERECVQ)
+ remove_from_list(&recvq_clients, sptr, NULL);
+ if (IsClient(sptr))
+ Count.local--;
+ if (IsNegoServer(sptr))
+ sendto_realops("Lost server %s during negotiation: %s",
+ sptr->name, comment);
+
+ if (IsServer(sptr))
+ {
+ Count.myserver--;
+ if (IsULine(sptr))
+ Count.myulined--;
+ remove_from_list(&server_list, sptr, NULL);
+ if (server_list == NULL)
+ server_was_split = YES;
+ }
+ sptr->flags |= FLAGS_CLOSING;
+ if (IsPerson(sptr))
+ {
+ Link *lp, *next;
+ LOpts *lopt = sptr->user->lopt;
+ /* poof goes their watchlist! */
+ hash_del_watch_list(sptr);
+ /* if they have listopts, axe those, too */
+ if(lopt != NULL)
+ {
+ remove_from_list(&listing_clients, sptr, NULL);
+ for (lp = lopt->yeslist; lp; lp = next)
+ {
+ next = lp->next;
+ free_link(lp);
+ }
+ for (lp = lopt->nolist; lp; lp = next)
+ {
+ next = lp->next;
+ free_link(lp);
+ }
+
+ MyFree(sptr->user->lopt);
+ sptr->user->lopt = NULL;
+ }
+ sendto_realops_lev(CCONN_LEV,
+ "Client exiting: %s (%s@%s) [%s] [%s]",
+ sptr->name, sptr->user->username,
+ sptr->user->host,
+ (sptr->flags & FLAGS_NORMALEX) ?
+ "Client Quit" : comment,
+ sptr->hostip);
+ }
+#ifdef FNAME_USERLOG
+ on_for = timeofday - sptr->firsttime;
+#endif
+#if defined(USE_SYSLOG) && defined(SYSLOG_USERS)
+ if (IsPerson(sptr))
+ syslog(LOG_NOTICE, "%s (%3d:%02d:%02d): %s!%s@%s %d/%d\n",
+ myctime(sptr->firsttime),
+ on_for / 3600, (on_for % 3600) / 60,
+ on_for % 60, sptr->name,
+ sptr->user->username, sptr->user->host,
+ sptr->sendK, sptr->receiveK);
+#endif
+#if defined(FNAME_USERLOG)
+ {
+ char linebuf[300];
+ static int logfile = -1;
+ static long lasttime;
+
+ /*
+ * This conditional makes the logfile active only after it's
+ * been created - thus logging can be turned off by removing
+ * the file.
+ *
+ * stop NFS hangs...most systems should be able to open a file in
+ * 3 seconds. -avalon (curtesy of wumpus)
+ *
+ * Keep the logfile open, syncing it every 10 seconds -Taner
+ */
+ if (IsPerson(sptr))
+ {
+ if (logfile == -1)
+ {
+ alarm(3);
+ logfile = open(FNAME_USERLOG, O_WRONLY | O_APPEND);
+ alarm(0);
+ }
+ ircsprintf(linebuf, "%s (%3d:%02d:%02d): %s!%s@%s %d/%d\n",
+ myctime(sptr->firsttime), on_for / 3600,
+ (on_for % 3600) / 60, on_for % 60,
+ sptr->name, sptr->user->username,
+ sptr->user->host, sptr->sendK, sptr->receiveK);
+ alarm(3);
+ write(logfile, linebuf, strlen(linebuf));
+ alarm(0);
+ /* Resync the file evey 10 seconds*/
+ if (timeofday - lasttime > 10)
+ {
+ alarm(3);
+ close(logfile);
+ alarm(0);
+ logfile = -1;
+ lasttime = timeofday;
+ }
+ }
+ }
+#endif
+ if (sptr->fd >= 0)
+ {
+ if (cptr != NULL && sptr != cptr)
+ sendto_one(sptr, "ERROR :Closing Link: %s %s (%s)",
+ IsPerson(sptr) ? sptr->sockhost : "0.0.0.0",
+ sptr->name, comment);
+ else
+ sendto_one(sptr, "ERROR :Closing Link: %s (%s)",
+ IsPerson(sptr) ? sptr->sockhost : "0.0.0.0",
+ comment);
+ }
+ /*
+ * * Currently only server connections can have * depending
+ * remote clients here, but it does no * harm to check for all
+ * local clients. In * future some other clients than servers
+ * might * have remotes too... *
+ *
+ * Close the Client connection first and mark it * so that no
+ * messages are attempted to send to it. *, The following *must*
+ * make MyConnect(sptr) == FALSE!). * It also makes sptr->from ==
+ * NULL, thus it's unnecessary * to test whether "sptr != acptr"
+ * in the following loops.
+ */
+ if (IsServer(sptr))
+ {
+ sendto_ops("%s was connected for %lu seconds. %lu/%lu "
+ "sendK/recvK.", sptr->name, timeofday - sptr->firsttime,
+ sptr->sendK, sptr->receiveK);
+#ifdef USE_SYSLOG
+ syslog(LOG_NOTICE, "%s was connected for %lu seconds. %lu/%lu "
+ "sendK/recvK.", sptr->name,
+ (u_long) timeofday - sptr->firsttime,
+ sptr->sendK, sptr->receiveK);
+#endif
+ close_connection(sptr);
+ sptr->sockerr = 0;
+ sptr->flags |= FLAGS_DEADSOCKET;
+ }
+ else
+ {
+ close_connection(sptr);
+ sptr->sockerr = 0;
+ sptr->flags |= FLAGS_DEADSOCKET;
+ }
+
+ }
+ exit_one_client(cptr, sptr, from, comment);
+ return cptr == sptr ? FLUSH_BUFFER : 0;
+}
+
+/*
+ * Exit one client, local or remote. Assuming all dependants have
+ * been already removed, and socket closed for local client.
+ */
+static void
+exit_one_client(aClient *cptr, aClient *sptr, aClient *from, char *comment)
+{
+ Link *lp;
+
+ /*
+ * For a server or user quitting, propogate the information to
+ * other servers (except to the one where is came from (cptr))
+ */
+ if (IsMe(sptr))
+ {
+ sendto_ops("ERROR: tried to exit me! : %s", comment);
+ return; /* ...must *never* exit self!! */
+ }
+ else if (IsServer(sptr))
+ {
+#ifdef ALWAYS_SEND_DURING_SPLIT
+ currently_processing_netsplit = YES;
+#endif
+
+ exit_server(cptr, sptr, from, comment);
+
+#ifdef ALWAYS_SEND_DURING_SPLIT
+ currently_processing_netsplit = NO;
+#endif
+ return;
+ }
+ else if (!(IsPerson(sptr)))
+ /*
+ * ...this test is *dubious*, would need * some thought.. but for
+ * now it plugs a * nasty hole in the server... --msa
+ */
+ ; /* Nothing */
+ else if (sptr->name[0])
+ {
+ /* ...just clean all others with QUIT... */
+ /*
+ * If this exit is generated from "m_kill", then there is no
+ * sense in sending the QUIT--KILL's have been sent instead.
+ */
+ if ((sptr->flags & FLAGS_KILLED) == 0)
+ {
+ sendto_serv_butone(cptr, ":%s QUIT :%s",
+ sptr->name, comment);
+ }
+ /*
+ * * If a person is on a channel, send a QUIT notice * to every
+ * client (person) on the same channel (so * that the client can
+ * show the "**signoff" message). * (Note: The notice is to the
+ * local clients *only*)
+ */
+ if (sptr->user)
+ {
+ send_part_to_common_channels(sptr, comment);
+ send_quit_to_common_channels(sptr, comment);
+ while ((lp = sptr->user->channel))
+ remove_user_from_channel(sptr, lp->value.chptr);
+
+ if (sptr->ip.s_addr)
+ clones_remove(sptr);
+
+ /* Clean up invitefield */
+ while ((lp = sptr->user->invited))
+ del_invite(sptr, lp->value.chptr);
+ /* Clean up silences */
+ while ((lp = sptr->user->silence))
+ del_silence(sptr, lp->value.cp);
+ remove_dcc_references(sptr);
+ /* again, this is all that is needed */
+ }
+ }
+
+ /* Remove sptr from the client list */
+ if (del_from_client_hash_table(sptr->name, sptr) != 1)
+ {
+ Debug((DEBUG_ERROR, "%#x !in tab %s[%s] %#x %#x %#x %d %d %#x",
+ sptr, sptr->name,
+ sptr->from ? sptr->from->sockhost : "??host",
+ sptr->from, sptr->next, sptr->prev, sptr->fd,
+ sptr->status, sptr->user));
+ }
+ /* remove user from watchlists */
+ if(IsRegistered(sptr))
+ hash_check_watch(sptr, RPL_LOGOFF);
+ remove_client_from_list(sptr);
+ return;
+}
+
+void
+initstats()
+{
+ memset((char *) &ircst, '\0', sizeof(ircst));
+}
+
+char *
+make_parv_copy(char *pbuf, int parc, char *parv[])
+{
+ int pbpos = 0, i;
+
+ for(i = 1; i < parc; i++)
+ {
+ char *tmp = parv[i];
+
+ if(i != 1)
+ pbuf[pbpos++] = ' ';
+ if(i == (parc - 1))
+ pbuf[pbpos++] = ':';
+
+ while(*tmp)
+ pbuf[pbpos++] = *(tmp++);
+ }
+ pbuf[pbpos] = '\0';
+
+ return pbuf;
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/s_numeric.c
+ * Copyright (C) 1990 Jarkko Oikarinen
+ *
+ * Numerous fixes by Markku Savela
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: s_numeric.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "channel.h"
+#include "h.h"
+
+static char buffer[1024];
+
+/*
+ * * DoNumeric (replacement for the old do_numeric) *
+ *
+ * parc number of arguments ('sender' counted as one!)
+ * parv[0] pointer to 'sender' (may point to empty string)
+ * parv[1]..parv[parc-1]
+ * pointers to additional parameters, this is a NULL
+ * terminated list (parv[parc] == NULL).
+ *
+ * *WARNING*
+ * Numerics are mostly error reports. If there is something
+ * wrong with the message, just *DROP* it! Don't even think of
+ * sending back a neat error message -- big danger of creating
+ * a ping pong error message...
+ */
+int do_numeric(int numeric, aClient *cptr, aClient *sptr, int parc,
+ char *parv[])
+{
+ aClient *acptr;
+ aChannel *chptr;
+ char *nick, *p;
+ int i;
+
+ if (parc < 1 || !IsServer(sptr))
+ return 0;
+ /* Remap low number numerics. */
+ if (numeric < 100)
+ numeric += 100;
+ /*
+ * Prepare the parameter portion of the message into 'buffer'.
+ * (Because the buffer is twice as large as the message buffer for
+ * the socket, no overflow can occur here... ...on current
+ * assumptions--bets are off, if these are changed --msa)
+ * Note: if buffer is non-empty, it will begin with SPACE.
+ */
+ buffer[0] = '\0';
+ if (parc > 1)
+ {
+ int bpos = 0;
+ char *p;
+
+ for (i = 2; i < (parc - 1); i++)
+ {
+ buffer[bpos++] = ' ';
+ for(p = parv[i]; *p; p++)
+ buffer[bpos++] = *p;
+ }
+ buffer[bpos++] = ' ';
+ buffer[bpos++] = ':';
+ for(p = parv[parc - 1]; *p; p++)
+ buffer[bpos++] = *p;
+ buffer[bpos] = '\0';
+ }
+ for (; (nick = strtoken(&p, parv[1], ",")); parv[1] = NULL)
+ {
+ if ((acptr = find_client(nick, (aClient *) NULL)))
+ {
+ int dohide;
+
+ /*
+ * Drop to bit bucket if for me... ...one might consider
+ * sendto_ops * here... --msa * And so it was done. -avalon *
+ * And regretted. Dont do it that way. Make sure * it goes
+ * only to non-servers. -avalon * Check added to make sure
+ * servers don't try to loop * with numerics which can happen
+ * with nick collisions. * - Avalon
+ */
+
+#ifdef HIDE_NUMERIC_SOURCE
+ dohide = MyClient(acptr) ? 1 : 0;
+#else
+ dohide = 0;
+#endif
+
+ if (!IsMe(acptr) && IsPerson(acptr))
+ sendto_prefix_one(acptr, dohide ? &me : sptr, ":%s %d %s%s",
+ dohide ? me.name : parv[0], numeric, nick, buffer);
+ else if (IsServer(acptr) && acptr->from != cptr)
+ sendto_prefix_one(acptr, sptr, ":%s %d %s%s",
+ parv[0], numeric, nick, buffer);
+ }
+ else if ((chptr = find_channel(nick, (aChannel *) NULL)))
+ {
+ int dohide;
+
+#ifdef HIDE_NUMERIC_SOURCE
+ dohide = 1;
+#else
+ dohide = 0;
+#endif
+ sendto_channel_butserv(chptr, dohide ? &me : sptr, ":%s %d %s%s",
+ dohide ? me.name : parv[0], numeric,
+ chptr->chname, buffer);
+
+ sendto_channel_remote_butone(cptr, sptr, chptr,
+ parv[0], numeric,
+ chptr->chname, buffer);
+
+ }
+ }
+ return 0;
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/s_serv.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: s_serv.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "msg.h"
+#include "channel.h"
+#include "nameser.h"
+#include "resolv.h"
+#include "dh.h"
+#include "zlink.h"
+#include "userban.h"
+
+#if defined(AIX) || defined(SVR3)
+#include <time.h>
+#endif
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <utmp.h>
+#include "h.h"
+#if defined( HAVE_STRING_H )
+#include <string.h>
+#else
+/* older unices don't have strchr/strrchr .. help them out */
+#include <strings.h>
+#undef strchr
+#define strchr index
+#endif
+#include "fdlist.h"
+#include "throttle.h"
+#include "clones.h"
+
+static char buf[BUFSIZE];
+extern int rehashed;
+extern int forked;
+
+/* external variables */
+
+/* external functions */
+
+extern char *smalldate(time_t); /* defined in s_misc.c */
+extern void outofmemory(void); /* defined in list.c */
+extern void s_die(void);
+extern int match(char *, char *); /* defined in match.c */
+
+/* Local function prototypes */
+
+static int isnumber(char *); /* return 0 if not, else return number */
+static char *cluster(char *);
+
+int send_motd(aClient *, aClient *, int, char **);
+void read_motd(char *);
+void read_shortmotd(char *);
+
+char motd_last_changed_date[MAX_DATE_STRING]; /* enough room for date */
+
+void fakeserver_list(aClient *);
+int fakelinkscontrol(int, char **);
+void fakelinkserver_update(char *, char *);
+void fakeserver_sendserver(aClient *);
+
+int is_luserslocked();
+void send_fake_users(aClient *);
+void send_fake_lusers(aClient *);
+void fakelusers_sendlock(aClient *);
+
+#ifdef LOCKFILE
+/* Shadowfax's lockfile code */
+void do_pending_klines(void);
+
+struct pkl
+{
+ char *comment; /* Kline Comment */
+ char *kline; /* Actual Kline */
+ struct pkl *next; /* Next Pending Kline */
+} *pending_klines = NULL;
+
+time_t pending_kline_time = 0;
+
+#endif /* LOCKFILE */
+
+/*
+ * m_functions execute protocol messages on this server: *
+ *
+ * cptr:
+ ** always NON-NULL, pointing to a *LOCAL* client
+ ** structure (with an open socket connected!). This
+ ** is the physical socket where the message originated (or
+ ** which caused the m_function to be executed--some
+ ** m_functions may call others...).
+ *
+ * sptr:
+ ** the source of the message, defined by the
+ ** prefix part of the message if present. If not or
+ ** prefix not found, then sptr==cptr.
+ *
+ * *Always* true (if 'parse' and others are working correct):
+ *
+ * 1) sptr->from == cptr (note: cptr->from == cptr)
+ *
+ * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ * cannot be a local connection, unless it's actually cptr!).
+ *
+ * MyConnect(x) should probably be defined as (x == x->from) --msa
+ *
+ * parc:
+ ** number of variable parameter strings (if zero,
+ ** parv is allowed to be NULL)
+ *
+ * parv:
+ ** a NULL terminated list of parameter pointers,
+ *** parv[0], sender (prefix string), if not present his points to
+ *** an empty string.
+ *
+ ** [parc-1]:
+ *** pointers to additional parameters
+ *** parv[parc] == NULL, *always*
+ *
+ * note: it is guaranteed that parv[0]..parv[parc-1] are all
+ * non-NULL pointers.
+ */
+
+/*
+ * * m_version
+ * parv[0] = sender prefix
+ * parv[1] = remote server
+ */
+int
+m_version(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+
+ if (hunt_server(cptr, sptr, ":%s VERSION :%s", 1, parc, parv) ==
+ HUNTED_ISME)
+ send_rplversion(sptr);
+
+ return 0;
+}
+
+/*
+ * m_squit
+ * there are two types of squits: those going downstream (to the target server)
+ * and those going back upstream (from the target server).
+ * previously, it wasn't necessary to distinguish between these two types of
+ * squits because they neatly echoed back all of the QUIT messages during
+ * an squit. This, however, is no longer practical.
+ *
+ * To clarify here, DOWNSTREAM signifies an SQUIT heading towards the target
+ * server UPSTREAM signifies an SQUIT which has successfully completed,
+ * heading out everywhere.
+ *
+ * acptr is the server being squitted.
+ * a DOWNSTREAM squit is where the notice did not come from acptr->from.
+ * an UPSTREAM squit is where the notice DID come from acptr->from.
+ *
+ * parv[0] = sender prefix
+ * parv[1] = server name
+ * parv[2] = comment
+ */
+int
+m_squit(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aConnect *aconn;
+ char *server;
+ aClient *acptr;
+ char *comment = (parc > 2) ? parv[2] : sptr->name;
+
+ if (!IsPrivileged(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+
+ if (parc > 1)
+ {
+ server = parv[1];
+ /* To accomodate host masking, a squit for a masked server
+ * name is expanded if the incoming mask is the same as the
+ * server name for that link to the name of link.
+ */
+ while ((*server == '*') && IsServer(cptr))
+ {
+ aconn = cptr->serv->aconn;
+ if (!aconn)
+ break;
+ if (!mycmp(server, my_name_for_link(me.name, aconn)))
+ server = cptr->name;
+ break; /* WARNING is normal here */
+ /* NOTREACHED */
+ }
+ /*
+ * The following allows wild cards in SQUIT. Only useful when
+ * the command is issued by an oper.
+ */
+ for (acptr = client; (acptr = next_client(acptr, server));
+ acptr = acptr->next)
+ if (IsServer(acptr) || IsMe(acptr))
+ break;
+ if (acptr && IsMe(acptr))
+ {
+ acptr = cptr;
+ server = cptr->sockhost;
+ }
+ }
+ else
+ {
+ /* This is actually protocol error. But, well, closing the
+ * link is very proper answer to that...
+ */
+ server = cptr->sockhost;
+ acptr = cptr;
+ }
+
+ if (!acptr)
+ {
+ sendto_one(sptr, err_str(ERR_NOSUCHSERVER),
+ me.name, parv[0], server);
+ return 0;
+ }
+
+ if (MyClient(sptr) && ((!OPCanGRoute(sptr) && !MyConnect(acptr)) ||
+ (!OPCanLRoute(sptr) && MyConnect(acptr))))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+
+ /* If the server is mine, we don't care about upstream or downstream,
+ just kill it and do the notice. */
+
+ if (MyConnect(acptr))
+ {
+ sendto_gnotice("from %s: Received SQUIT %s from %s (%s)",
+ me.name, acptr->name, get_client_name(sptr, HIDEME),
+ comment);
+ sendto_serv_butone(NULL, ":%s GNOTICE :Received SQUIT %s from %s (%s)",
+ me.name, server, get_client_name(sptr, HIDEME),
+ comment);
+
+#if defined(USE_SYSLOG) && defined(SYSLOG_SQUIT)
+ syslog(LOG_DEBUG, "SQUIT From %s : %s (%s)",
+ parv[0], server, comment);
+#endif
+ /* I am originating this squit! Not cptr! */
+ /* ack, but if cptr is squitting itself.. */
+ if(cptr == sptr)
+ {
+ exit_client(&me, acptr, sptr, comment);
+ return FLUSH_BUFFER; /* kludge */
+ }
+ return exit_client(&me, acptr, sptr, comment);
+ }
+
+ /* the server is not connected to me. Determine whether this is an upstream
+ or downstream squit */
+
+ if(sptr->from == acptr->from) /* upstream */
+ {
+ sendto_realops_lev(DEBUG_LEV,
+ "Exiting server %s due to upstream squit by %s [%s]",
+ acptr->name, sptr->name, comment);
+ return exit_client(cptr, acptr, sptr, comment);
+ }
+
+ /* fallthrough: downstream */
+
+ if(!(IsUnconnect(acptr->from))) /* downstream not unconnect capable */
+ {
+ sendto_realops_lev(DEBUG_LEV,
+ "Exiting server %s due to non-unconnect server %s [%s]",
+ acptr->name, acptr->from->name, comment);
+ return exit_client(&me, acptr, sptr, comment);
+ }
+
+
+ sendto_realops_lev(DEBUG_LEV, "Passing along SQUIT for %s by %s [%s]",
+ acptr->name, sptr->name, comment);
+ sendto_one(acptr->from, ":%s SQUIT %s :%s", parv[0], acptr->name, comment);
+
+ return 0;
+}
+
+/*
+ * m_svinfo
+ * parv[0] = sender prefix
+ * parv[1] = TS_CURRENT for the server
+ * parv[2] = TS_MIN for the server
+ * parv[3] = server is standalone or connected to non-TS only
+ * parv[4] = server's idea of UTC time
+ */
+int m_svinfo(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ time_t deltat, tmptime, theirtime;
+
+ if (!IsServer(sptr) || !MyConnect(sptr))
+ return 0;
+
+ if(parc == 2 && mycmp(parv[1], "ZIP") == 0)
+ {
+ SetZipIn(sptr);
+ sptr->serv->zip_in = zip_create_input_session();
+ sendto_gnotice("from %s: Input from %s is now compressed",
+ me.name, get_client_name(sptr, HIDEME));
+ sendto_serv_butone(sptr,
+ ":%s GNOTICE :Input from %s is now compressed",
+ me.name, get_client_name(sptr, HIDEME));
+ return ZIP_NEXT_BUFFER;
+ }
+
+ if(parc < 5 || !DoesTS(sptr))
+ return 0;
+
+ if (TS_CURRENT < atoi(parv[2]) || atoi(parv[1]) < TS_MIN)
+ {
+ /* a server with the wrong TS version connected; since we're
+ * TS_ONLY we can't fall back to the non-TS protocol so we drop
+ * the link -orabidoo
+ */
+ sendto_ops("Link %s dropped, wrong TS protocol version (%s,%s)",
+ get_client_name(sptr, HIDEME), parv[1], parv[2]);
+ return exit_client(sptr, sptr, sptr, "Incompatible TS version");
+ }
+
+ tmptime = time(NULL);
+ theirtime = atol(parv[4]);
+ deltat = abs(theirtime - tmptime);
+
+ if (deltat > tsmaxdelta)
+ {
+ sendto_gnotice("from %s: Link %s dropped, excessive TS delta (my "
+ "TS=%d, their TS=%d, delta=%d)",
+ me.name, get_client_name(sptr, HIDEME), tmptime,
+ theirtime, deltat);
+ sendto_serv_butone(sptr, ":%s GNOTICE :Link %s dropped, excessive "
+ "TS delta (delta=%d)",
+ me.name, get_client_name(sptr, HIDEME), deltat);
+ return exit_client(sptr, sptr, sptr, "Excessive TS delta");
+ }
+
+ if (deltat > tswarndelta)
+ {
+ sendto_realops("Link %s notable TS delta (my TS=%d, their TS=%d, "
+ "delta=%d)", get_client_name(sptr, HIDEME), tmptime,
+ theirtime, deltat);
+ }
+
+ return 0;
+}
+
+/*
+ * m_burst
+ * parv[0] = sender prefix
+ * parv[1] = SendQ if an EOB
+ */
+int
+m_burst(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+
+ if (!IsServer(sptr) || sptr != cptr || parc > 2 || !IsBurst(sptr))
+ return 0;
+ if (parc == 2) { /* This is an EOB */
+ sptr->flags &= ~(FLAGS_EOBRECV);
+ if (sptr->flags & (FLAGS_SOBSENT|FLAGS_BURST)) return 0;
+
+ /* we've already sent our EOB.. we synched first
+ * no need to check IsBurst because we shouldn't receive a BURST if
+ * they're not BURST capab
+ */
+
+ sendto_gnotice("from %s: synch to %s in %d %s at %s sendq", me.name,
+ *parv, (timeofday-sptr->firsttime),
+ (timeofday-sptr->firsttime)==1?"sec":"secs", parv[1]);
+ sendto_serv_butone(NULL,
+ ":%s GNOTICE :synch to %s in %d %s at %s sendq",
+ me.name, sptr->name, (timeofday-sptr->firsttime),
+ (timeofday-sptr->firsttime)==1?"sec":"secs",
+ parv[1]);
+
+ }
+ else
+ {
+ sptr->flags |= FLAGS_EOBRECV;
+ }
+ return 0;
+}
+
+/*
+ * * m_info
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+int
+m_info(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ char **text = infotext;
+
+ static time_t last_used = 0L;
+ if (hunt_server(cptr,sptr,":%s INFO :%s",1,parc,parv) == HUNTED_ISME)
+ {
+ sendto_realops_lev(SPY_LEV, "INFO requested by %s (%s@%s) [%s]",
+ sptr->name, sptr->user->username, sptr->user->host,
+ sptr->user->server);
+
+ if (!IsAnOper(sptr))
+ {
+ if (IsSquelch(sptr)) {
+ sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, parv[0]);
+ return 0;
+ }
+ if (!MyConnect(sptr))
+ return 0;
+ if ((last_used + MOTD_WAIT) > NOW)
+ return 0;
+ else
+ last_used = NOW;
+ }
+ while (*text)
+ sendto_one(sptr, rpl_str(RPL_INFO),
+ me.name, parv[0], *text++);
+
+ sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], "");
+
+ /* I am -definately- going to come up with a replacement for this! */
+ /* you didnt, so i removed it.. kinda stupid anyway. -epi */
+
+ sendto_one(sptr,
+ ":%s %d %s :Birth Date: %s, compile #%s",
+ me.name, RPL_INFO, parv[0], creation, generation);
+ sendto_one(sptr, ":%s %d %s :On-line since %s",
+ me.name, RPL_INFO, parv[0],
+ myctime(me.firsttime));
+ sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, parv[0]);
+ }
+
+ return 0;
+}
+
+/*
+ * * m_links
+ * parv[0] = sender prefix
+ * parv[1] = servername mask
+ * or
+ * parv[0] = sender prefix
+ * parv[1] = server to query
+ * parv[2] = servername mask
+ */
+int
+m_links(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ char *mask;
+ aClient *acptr;
+ char clean_mask[(2 * HOSTLEN) + 1];
+ char *s;
+ char *d;
+ int n;
+
+ /* reject non-local requests */
+ if (IsServer(sptr) || (!IsAnOper(sptr) && !MyConnect(sptr)))
+ return 0;
+
+ mask = (parc < 2) ? NULL : parv[1];
+
+ /*
+ * * sigh* Before the kiddies find this new and exciting way of
+ * * annoying opers, lets clean up what is sent to all opers
+ * * -Dianora
+ */
+
+ if (mask)
+ { /* only necessary if there is a mask */
+ s = mask;
+ d = clean_mask;
+ n = (2 * HOSTLEN) - 2;
+ while (*s && n > 0)
+ {
+ /* Is it a control character? */
+ if ((unsigned char) *s < (unsigned char) ' ')
+ {
+ *d++ = '^';
+ /* turn it into a printable */
+ *d++ = (char) ((unsigned char)*s + 0x40);
+ s++;
+ n -= 2;
+ }
+ else if ((unsigned char) *s > (unsigned char) '~')
+ {
+ *d++ = '.';
+ s++;
+ n--;
+ }
+ else
+ {
+ *d++ = *s++;
+ n--;
+ }
+ }
+ *d = '\0';
+ }
+
+ if (MyConnect(sptr))
+ sendto_realops_lev(SPY_LEV,
+ "LINKS %s requested by %s (%s@%s) [%s]",
+ mask ? clean_mask : "all",
+ sptr->name, sptr->user->username,
+ sptr->user->host, sptr->user->server);
+
+ if(!(confopts & FLAGS_SHOWLINKS) && !IsAnOper(sptr))
+ fakeserver_list(sptr);
+ else
+ for (acptr = client, (void) collapse(mask); acptr; acptr = acptr->next)
+ {
+ if (!IsServer(acptr) && !IsMe(acptr))
+ continue;
+ if (!BadPtr(mask) && match(mask, acptr->name))
+ continue;
+#ifdef HIDEULINEDSERVS
+ if (!IsOper(sptr) && IsULine(acptr))
+ continue;
+#endif
+ sendto_one(sptr, rpl_str(RPL_LINKS),
+ me.name, parv[0], acptr->name, acptr->serv->up,
+ acptr->hopcount, (acptr->info[0] ? acptr->info :
+ "(Unknown Location)"));
+ }
+ sendto_one(sptr, rpl_str(RPL_ENDOFLINKS), me.name, parv[0],
+ BadPtr(mask) ? "*" : clean_mask);
+ return 0;
+}
+
+/*
+ * * m_users
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+int
+m_users(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ if (hunt_server(cptr, sptr, ":%s USERS :%s", 1, parc, parv) == HUNTED_ISME)
+ {
+ if(is_luserslocked())
+ {
+ send_fake_users(sptr);
+ return 0;
+ }
+ /* No one uses this any more... so lets remap it.. -Taner */
+ sendto_one(sptr, rpl_str(RPL_LOCALUSERS), me.name, parv[0],
+ Count.local, Count.max_loc);
+ sendto_one(sptr, rpl_str(RPL_GLOBALUSERS), me.name, parv[0],
+ Count.total, Count.max_tot);
+ }
+ return 0;
+}
+
+/*
+ * * Note: At least at protocol level ERROR has only one parameter,
+ * although this is called internally from other functions --msa
+ *
+ * parv[0] = sender prefix
+ * parv[*] = parameters
+ */
+int
+m_error(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ char *para;
+
+ para = (parc > 1 && *parv[1] != '\0') ? parv[1] : "<>";
+
+ Debug((DEBUG_ERROR, "Received ERROR message from %s: %s",
+ sptr->name, para));
+ /*
+ * * Ignore error messages generated by normal user clients
+ * (because ill-behaving user clients would flood opers screen
+ * otherwise). Pass ERROR's from other sources to the local
+ * operator...
+ */
+ if (IsPerson(cptr) || IsUnknown(cptr))
+ return 0;
+ if (cptr == sptr)
+ sendto_ops("ERROR :from %s -- %s",
+ get_client_name(cptr, HIDEME), para);
+ else
+ sendto_ops("ERROR :from %s via %s -- %s", sptr->name,
+ get_client_name(cptr, HIDEME), para);
+ return 0;
+}
+
+/*
+ * m_help
+ * parv[0] = sender prefix
+ *
+ * Forward help requests to HelpServ if defined, and is invoked
+ * by non-opers, otherwise sends opers.txt to opers (if present),
+ * or sends a big list of commands to non-opers (and opers if
+ * opers.txt is not present). -srd
+ */
+int
+m_help(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ int i;
+ aMotd *helpfile_ptr;
+
+ static time_t last_used = 0L;
+
+#ifdef HELP_FORWARD_HS
+ if (!IsAnOper(sptr))
+ {
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ sendto_one(sptr, ":%s NOTICE %s :For a list of help topics, type "
+ "/%s %s", me.name, sptr->name, HELPSERV, DEF_HELP_CMD);
+ return -1;
+ }
+ return m_hs(cptr, sptr, parc, parv);
+
+ return 0;
+ }
+#endif
+
+ if (!IsAnOper(sptr))
+ {
+ /* reject non local requests */
+ if ((last_used + MOTD_WAIT) > NOW)
+ return 0;
+ else
+ last_used = NOW;
+ }
+
+ if (!IsAnOper(sptr) || (helpfile == (aMotd *) NULL))
+ {
+ for (i = 0; msgtab[i].cmd; i++)
+ sendto_one(sptr, ":%s NOTICE %s :%s",
+ me.name, parv[0], msgtab[i].cmd);
+ return 0;
+ }
+
+ helpfile_ptr = helpfile;
+ while (helpfile_ptr)
+ {
+ sendto_one(sptr,
+ ":%s NOTICE %s :%s",
+ me.name, parv[0], helpfile_ptr->line);
+ helpfile_ptr = helpfile_ptr->next;
+ }
+
+ return 0;
+}
+
+/*
+ * parv[0] = sender parv[1] = host/server mask.
+ * parv[2] = server to query
+ *
+ * 199970918 JRL hacked to ignore parv[1] completely and require parc > 3
+ * to cause a force
+ */
+int
+m_lusers(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ int send_lusers(aClient *, aClient *, int, char **);
+
+ if (parc > 2)
+ {
+ if (hunt_server(cptr, sptr, ":%s LUSERS %s :%s", 2, parc, parv) !=
+ HUNTED_ISME)
+ return 0;
+ }
+
+ if(is_luserslocked())
+ {
+ send_fake_lusers(sptr);
+ return 0;
+ }
+
+ return send_lusers(cptr,sptr,parc,parv);
+}
+
+/*
+ * send_lusers
+ * parv[0] = sender
+ * parv[1] = host/server mask.
+ * parv[2] = server to query
+ */
+int send_lusers(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+#define LUSERS_CACHE_TIME 180
+ static long last_time=0;
+ static int s_count = 0, c_count = 0, u_count = 0, i_count = 0;
+ static int o_count = 0, m_client = 0, m_server = 0, m_ulined = 0;
+ int forced;
+ aClient *acptr;
+
+ forced = (IsAnOper(sptr) && (parc > 3));
+
+ Count.unknown = 0;
+ m_server = Count.myserver;
+ m_ulined = Count.myulined;
+ m_client = Count.local;
+ i_count = Count.invisi;
+ u_count = Count.unknown;
+ c_count = Count.total - Count.invisi;
+ s_count = Count.server;
+ o_count = Count.oper;
+ if (forced || (timeofday > last_time + LUSERS_CACHE_TIME))
+ {
+ last_time = timeofday;
+ /* only recount if more than a second has passed since last request
+ * use LUSERS_CACHE_TIME instead...
+ */
+ s_count = 0;
+ c_count = 0;
+ u_count = 0;
+ i_count = 0;
+ o_count = 0;
+ m_client = 0;
+ m_server = 0;
+ m_ulined = 0;
+
+ for (acptr = client; acptr; acptr = acptr->next)
+ {
+ switch (acptr->status)
+ {
+ case STAT_SERVER:
+ if (MyConnect(acptr))
+ {
+ m_server++;
+ if(IsULine(acptr))
+ m_ulined++;
+ }
+ case STAT_ME:
+ s_count++;
+ break;
+ case STAT_CLIENT:
+ if (IsAnOper(acptr))
+ o_count++;
+#ifdef SHOW_INVISIBLE_LUSERS
+ if (MyConnect(acptr))
+ m_client++;
+ if (!IsInvisible(acptr))
+ c_count++;
+ else
+ i_count++;
+#else
+ if (MyConnect(acptr))
+ {
+ if (IsInvisible(acptr))
+ {
+ if (IsAnOper(sptr))
+ m_client++;
+ }
+ else
+ m_client++;
+ }
+ if (!IsInvisible(acptr))
+ c_count++;
+ else
+ i_count++;
+#endif
+ break;
+ default:
+ u_count++;
+ break;
+ }
+ }
+ /*
+ * We only want to reassign the global counts if the recount time
+ * has expired, and NOT when it was forced, since someone may
+ * supply a mask which will only count part of the userbase
+ * -Taner
+ */
+ if (!forced)
+ {
+ if (m_server != Count.myserver)
+ {
+ sendto_realops_lev(DEBUG_LEV,
+ "Local server count off by %d",
+ Count.myserver - m_server);
+ Count.myserver = m_server;
+ }
+ if (m_ulined != Count.myulined)
+ {
+ sendto_realops_lev(DEBUG_LEV,
+ "Local superserver count off by %d",
+ Count.myulined - m_ulined);
+ Count.myulined = m_ulined;
+ }
+ if (s_count != Count.server)
+ {
+ sendto_realops_lev(DEBUG_LEV,
+ "Server count off by %d",
+ Count.server - s_count);
+ Count.server = s_count;
+ }
+ if (i_count != Count.invisi)
+ {
+ sendto_realops_lev(DEBUG_LEV,
+ "Invisible client count off by %d",
+ Count.invisi - i_count);
+ Count.invisi = i_count;
+ }
+ if ((c_count + i_count) != Count.total)
+ {
+ sendto_realops_lev(DEBUG_LEV, "Total client count off by %d",
+ Count.total - (c_count + i_count));
+ Count.total = c_count + i_count;
+ }
+ if (m_client != Count.local)
+ {
+ sendto_realops_lev(DEBUG_LEV,
+ "Local client count off by %d",
+ Count.local - m_client);
+ Count.local = m_client;
+ }
+ if (o_count != Count.oper)
+ {
+ sendto_realops_lev(DEBUG_LEV,
+ "Oper count off by %d",
+ Count.oper - o_count);
+ Count.oper = o_count;
+ }
+ Count.unknown = u_count;
+ } /* Complain & reset loop */
+ } /* Recount loop */
+
+ /* save stats */
+ if ((timeofday - last_stat_save) > 3600)
+ {
+ FILE *fp;
+ char tmp[PATH_MAX];
+
+ last_stat_save = timeofday;
+ ircsprintf(tmp, "%s/.maxclients", dpath);
+ fp = fopen(tmp, "w");
+ if (fp != NULL)
+ {
+ fprintf(fp, "%d %d %li %li %li %ld %ld %ld %ld", Count.max_loc,
+ Count.max_tot, Count.weekly, Count.monthly,
+ Count.yearly, Count.start, Count.week, Count.month,
+ Count.year);
+ fclose(fp);
+ sendto_realops_lev(DEBUG_LEV, "Saved maxclient statistics");
+ }
+ }
+
+
+#ifndef SHOW_INVISIBLE_LUSERS
+ if (IsAnOper(sptr) && i_count)
+#endif
+ sendto_one(sptr, rpl_str(RPL_LUSERCLIENT), me.name, parv[0],
+ c_count, i_count, s_count);
+#ifndef SHOW_INVISIBLE_LUSERS
+ else
+ sendto_one(sptr,
+ ":%s %d %s :There are %d users on %d servers", me.name,
+ RPL_LUSERCLIENT, parv[0], c_count,
+ s_count);
+#endif
+ if (o_count)
+ sendto_one(sptr, rpl_str(RPL_LUSEROP),
+ me.name, parv[0], o_count);
+ if (u_count > 0)
+ sendto_one(sptr, rpl_str(RPL_LUSERUNKNOWN),
+ me.name, parv[0], u_count);
+
+ /* This should be ok */
+ if (Count.chan > 0)
+ sendto_one(sptr, rpl_str(RPL_LUSERCHANNELS),
+ me.name, parv[0], Count.chan);
+ sendto_one(sptr, rpl_str(RPL_LUSERME),
+#ifdef HIDEULINEDSERVS
+ me.name, parv[0], m_client,
+ IsOper(sptr) ? m_server : m_server - m_ulined);
+#else
+ me.name, parv[0], m_client, m_server);
+#endif
+ sendto_one(sptr, rpl_str(RPL_LOCALUSERS), me.name, parv[0],
+ Count.local, Count.max_loc);
+ sendto_one(sptr, rpl_str(RPL_GLOBALUSERS), me.name, parv[0],
+ Count.total, Count.max_tot);
+ return 0;
+}
+
+/***********************************************************************
+ * m_connect() - Added by Jto 11 Feb 1989
+ ***********************************************************************/
+/*
+ * * m_connect
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ * parv[2] = port number
+ * parv[3] = remote server
+ */
+int
+m_connect(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ int port, tmpport, retval;
+ aConnect *aconn;
+ aClient *acptr;
+
+ if (!IsPrivileged(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return -1;
+ }
+
+ if ((MyClient(sptr) && !OPCanGRoute(sptr) && parc > 3) ||
+ (MyClient(sptr) && !OPCanLRoute(sptr) && parc <= 3))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+
+ if (hunt_server(cptr, sptr, ":%s CONNECT %s %s :%s",
+ 3, parc, parv) != HUNTED_ISME)
+ return 0;
+
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "CONNECT");
+ return -1;
+ }
+
+ if ((acptr = find_server(parv[1], NULL)))
+ {
+ sendto_one(sptr, ":%s NOTICE %s :Connect: Server %s %s %s.",
+ me.name, parv[0], parv[1], "already exists from",
+ acptr->from->name);
+ return 0;
+ }
+
+ if (!(aconn = find_aConnect(parv[1])))
+ {
+ sendto_one(sptr, "NOTICE %s :Connect: No Connect block found for %s.",
+ parv[0], parv[1]);
+ return 0;
+ }
+ /*
+ * * Get port number from user, if given. If not specified, use
+ * the default form configuration structure. If missing from
+ * there, then use the precompiled default.
+ */
+ tmpport = port = aconn->port;
+ if (parc > 2 && !BadPtr(parv[2]))
+ {
+ if ((port = atoi(parv[2])) <= 0)
+ {
+ sendto_one(sptr,
+ "NOTICE %s :Connect: Illegal port number",
+ parv[0]);
+ return 0;
+ }
+ }
+ else if (port <= 0 && (port = PORTNUM) <= 0)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :Connect: missing port number",
+ me.name, parv[0]);
+ return 0;
+ }
+ /*
+ * * Notify all operators about remote connect requests
+ * Let's notify about local connects, too. - lucas
+ * sendto_ops_butone -> sendto_serv_butone(), like in df. -mjs
+ */
+ sendto_gnotice("from %s: %s CONNECT %s %s from %s",
+ me.name, IsAnOper(cptr) ? "Local" : "Remote",
+ parv[1], parv[2] ? parv[2] : "",
+ get_client_name(sptr, HIDEME));
+ sendto_serv_butone(NULL, ":%s GNOTICE :%s CONNECT %s %s from %s",
+ me.name, IsAnOper(cptr) ? "Local" : "Remote",
+ parv[1], parv[2] ? parv[2] : "",
+ get_client_name(sptr, HIDEME));
+
+#if defined(USE_SYSLOG) && defined(SYSLOG_CONNECT)
+ syslog(LOG_DEBUG, "CONNECT From %s : %s %s", parv[0], parv[1],
+ parv[2] ? parv[2] : "");
+#endif
+
+ aconn->port = port;
+ switch (retval = connect_server(aconn, sptr, NULL))
+ {
+ case 0:
+ sendto_one(sptr, ":%s NOTICE %s :*** Connecting to %s.",
+ me.name, parv[0], aconn->name);
+ break;
+ case -1:
+ sendto_one(sptr, ":%s NOTICE %s :*** Couldn't connect to %s.",
+ me.name, parv[0], aconn->name);
+ break;
+ case -2:
+ sendto_one(sptr, ":%s NOTICE %s :*** Host %s is unknown.",
+ me.name, parv[0], aconn->name);
+ break;
+ default:
+ sendto_one(sptr, ":%s NOTICE %s :*** Connection to %s failed: %s",
+ me.name, parv[0], aconn->name, strerror(retval));
+ }
+ aconn->port = tmpport;
+ return 0;
+}
+
+/*
+ * * m_wallops (write to *all* opers currently online)
+ * parv[0] = sender prefix
+ * parv[1] = message text
+ */
+int
+m_wallops(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ char *message = parc > 1 ? parv[1] : NULL;
+
+ if (BadPtr(message))
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "WALLOPS");
+ return 0;
+ }
+
+ if (!IsServer(sptr) && MyConnect(sptr) && !OPCanWallOps(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return (0);
+ }
+
+ sendto_wallops_butone(IsServer(cptr) ? cptr : NULL, sptr,
+ ":%s WALLOPS :%s", parv[0], message);
+ return 0;
+}
+
+/*
+ * * m_locops (write to *all* local opers currently online)
+ * parv[0] = sender prefix
+ * parv[1] = message text
+ */
+int
+m_locops(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ char *message = parc > 1 ? parv[1] : NULL;
+
+ if (BadPtr(message))
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "LOCOPS");
+ return 0;
+ }
+
+ if (!IsServer(sptr) && MyConnect(sptr) && !OPCanLocOps(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return (0);
+ }
+ sendto_locops("from %s: %s", parv[0], message);
+ return (0);
+}
+
+/*
+ * m_goper (Russell) sort of like wallop, but only to ALL +o clients
+ * on every server.
+ * parv[0] = sender prefix
+ * parv[1] = message text
+ * Taken from df465, ported to hybrid. -mjs
+ */
+int
+m_goper(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ char *message = parc > 1 ? parv[1] : NULL;
+
+ if (check_registered(sptr))
+ return 0;
+
+ if (BadPtr(message))
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "GOPER");
+ return 0;
+ }
+ if (!IsServer(sptr) || !IsULine(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+
+ sendto_serv_butone(IsServer(cptr) ? cptr : NULL, ":%s GOPER :%s",
+ parv[0], message);
+ sendto_ops("from %s: %s", parv[0], message);
+ return 0;
+}
+
+/*
+ * m_gnotice (Russell) sort of like wallop, but only to +g clients on *
+ * this server.
+ * parv[0] = sender prefix
+ * parv[1] = message text
+ * ported from df465 to hybrid -mjs
+ *
+ * This function itself doesnt need any changes for the move to +n routing
+ * notices, to sendto takes care of it. Now only sends to +n clients -epi
+ */
+int
+m_gnotice(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+
+ char *message = parc > 1 ? parv[1] : NULL;
+
+ if (check_registered(sptr))
+ return 0;
+
+ if (BadPtr(message))
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "GNOTICE");
+ return 0;
+ }
+ if (!IsServer(sptr) && MyConnect(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+
+ sendto_serv_butone_services(IsServer(cptr) ? cptr : NULL, ":%s GNOTICE :%s",
+ parv[0], message);
+ sendto_gnotice("from %s: %s", parv[0], message);
+ return 0;
+}
+
+int
+m_globops(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ char *message = parc > 1 ? parv[1] : NULL;
+
+ /* a few changes, servers weren't able to globop -mjs */
+
+ if (check_registered(sptr))
+ return 0;
+
+ if (BadPtr(message))
+ {
+ if (MyClient(sptr))
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "GLOBOPS");
+ return 0;
+ }
+
+ /* must be a client, must be an oper or a Ulined server -mjs */
+
+ if (MyClient(sptr) && !OPCanGlobOps(sptr) && !IsULine(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+ if (strlen(message) > TOPICLEN)
+ message[TOPICLEN] = '\0';
+ sendto_serv_butone_services(IsServer(cptr) ? cptr : NULL, ":%s GLOBOPS :%s",
+ parv[0], message);
+ send_globops("from %s: %s", parv[0], message);
+ return 0;
+}
+
+int
+m_chatops(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ char *message = parc > 1 ? parv[1] : NULL;
+
+ if (check_registered(sptr))
+ return 0;
+ if (BadPtr(message))
+ {
+ if (MyClient(sptr))
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "CHATOPS");
+ return 0;
+ }
+
+ if (MyClient(sptr) && (!IsAnOper(sptr) || !SendChatops(sptr)) &&
+ !IsULine(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+
+ if (strlen(message) > TOPICLEN)
+ message[TOPICLEN] = '\0';
+ sendto_serv_butone_services(IsServer(cptr) ? cptr : NULL, ":%s CHATOPS :%s",
+ parv[0], message);
+ send_chatops("from %s: %s", parv[0], message);
+ return 0;
+}
+
+/*
+ * * m_time
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+
+int
+m_time(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ if (hunt_server(cptr, sptr, ":%s TIME :%s", 1, parc, parv) == HUNTED_ISME)
+ sendto_one(sptr, rpl_str(RPL_TIME), me.name,
+ parv[0], me.name, date((long) 0));
+ return 0;
+}
+
+/*
+ * * m_admin
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+int
+m_admin(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+
+ if (hunt_server(cptr, sptr, ":%s ADMIN :%s", 1, parc, parv) != HUNTED_ISME)
+ return 0;
+
+ if (IsPerson(sptr))
+ sendto_realops_lev(SPY_LEV, "ADMIN requested by %s (%s@%s) [%s]",
+ sptr->name, sptr->user->username, sptr->user->host,
+ sptr->user->server);
+
+ sendto_one(sptr, rpl_str(RPL_ADMINME),
+ me.name, parv[0], me.name);
+ sendto_one(sptr, rpl_str(RPL_ADMINLOC1),
+ me.name, parv[0], MeLine->admin[0] ? MeLine->admin[0] : "");
+ sendto_one(sptr, rpl_str(RPL_ADMINLOC2),
+ me.name, parv[0], MeLine->admin[1] ? MeLine->admin[1] : "");
+ sendto_one(sptr, rpl_str(RPL_ADMINEMAIL),
+ me.name, parv[0], MeLine->admin[2] ? MeLine->admin[2] : "");
+ return 0;
+}
+
+/* Shadowfax's server side, anti flood code */
+#ifdef FLUD
+extern int flud_num;
+extern int flud_time;
+extern int flud_block;
+#endif
+
+#ifdef ANTI_SPAMBOT
+extern int spam_num;
+extern int spam_time;
+#endif
+
+/* m_set - set options while running */
+int
+m_set(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ char *command;
+
+ if (!MyClient(sptr) || !IsOper(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+
+ if (parc > 1)
+ {
+ command = parv[1];
+ if (!strncasecmp(command, "MAX", 3))
+ {
+ if (parc > 2)
+ {
+ int new_value = atoi(parv[2]);
+
+ if (new_value > MAX_ACTIVECONN)
+ {
+ sendto_one(sptr,
+ ":%s NOTICE %s :You cannot set MAXCLIENTS "
+ "above the compiled FD limit (%d)", me.name,
+ parv[0], MAX_ACTIVECONN);
+ return 0;
+ }
+ if (new_value < 0)
+ new_value = 0;
+ MAXCLIENTS = new_value;
+ sendto_one(sptr, ":%s NOTICE %s :NEW MAXCLIENTS = %d (Current "
+ "= %d)", me.name, parv[0], MAXCLIENTS, Count.local);
+ sendto_realops("%s!%s@%s set new MAXCLIENTS to %d "
+ "(%d current)", parv[0], sptr->user->username,
+ sptr->sockhost, MAXCLIENTS, Count.local);
+ return 0;
+ }
+ sendto_one(sptr, ":%s NOTICE %s :MAXCLIENTS is %d (%d online)",
+ me.name, parv[0], MAXCLIENTS, Count.local);
+ return 0;
+ }
+#ifdef FLUD
+ else if (!strncasecmp(command, "FLUDNUM", 7))
+ {
+ if (parc > 2)
+ {
+ int newval = atoi(parv[2]);
+ if (newval <= 0)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :flud NUM must be > 0",
+ me.name, parv[0]);
+ return 0;
+ }
+ flud_num = newval;
+ sendto_ops("%s has changed flud NUM to %i", parv[0], flud_num);
+ sendto_one(sptr, ":%s NOTICE %s :flud NUM is now set to %i",
+ me.name, parv[0], flud_num);
+ return 0;
+ }
+ else
+ {
+ sendto_one(sptr, ":%s NOTICE %s :flud NUM is currently %i",
+ me.name, parv[0], flud_num);
+ return 0;
+ }
+ }
+ else if (!strncasecmp(command, "FLUDTIME", 8))
+ {
+ if (parc > 2)
+ {
+ int newval = atoi(parv[2]);
+ if (newval <= 0)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :flud TIME must be > 0",
+ me.name, parv[0]);
+ return 0;
+ }
+ flud_time = newval;
+ sendto_ops("%s has changed flud TIME to %i", parv[0],
+ flud_time);
+ sendto_one(sptr, ":%s NOTICE %s :flud TIME is now set to %i",
+ me.name, parv[0], flud_time);
+ return 0;
+ }
+ else
+ {
+ sendto_one(sptr, ":%s NOTICE %s :flud TIME is currently %i",
+ me.name, parv[0], flud_time);
+ return 0;
+ }
+ }
+ else if (!strncasecmp(command, "FLUDBLOCK", 9))
+ {
+ if (parc > 2)
+ {
+ int newval = atoi(parv[2]);
+ if (newval < 0)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :flud BLOCK must be >= 0",
+ me.name, parv[0]);
+ return 0;
+ }
+ flud_block = newval;
+ if (flud_block == 0)
+ {
+ sendto_ops("%s has disabled flud detection/protection",
+ parv[0]);
+ sendto_one(sptr, ":%s NOTICE %s :flud detection disabled",
+ me.name, parv[0]);
+ }
+ else
+ {
+ sendto_ops("%s has changed flud BLOCK to %i",
+ parv[0], flud_block);
+ sendto_one(sptr, ":%s NOTICE %s :flud BLOCK is now set "
+ "to %i", me.name, parv[0], flud_block);
+ }
+ return 0;
+ }
+ else
+ {
+ sendto_one(sptr, ":%s NOTICE %s :flud BLOCK is currently %i",
+ me.name, parv[0], flud_block);
+ return 0;
+ }
+ }
+#endif
+#ifdef ANTI_SPAMBOT
+ /* int spam_time = MIN_JOIN_LEAVE_TIME;
+ * int spam_num = MAX_JOIN_LEAVE_COUNT;
+ */
+ else if (!strncasecmp(command, "SPAMNUM", 7))
+ {
+ if (parc > 2)
+ {
+ int newval = atoi(parv[2]);
+ if (newval <= 0)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :spam NUM must be > 0",
+ me.name, parv[0]);
+ return 0;
+ }
+ if (newval < MIN_SPAM_NUM)
+ spam_num = MIN_SPAM_NUM;
+ else
+ spam_num = newval;
+ sendto_ops("%s has changed spam NUM to %i", parv[0], spam_num);
+ sendto_one(sptr, ":%s NOTICE %s :spam NUM is now set to %i",
+ me.name, parv[0], spam_num);
+ return 0;
+ }
+ else
+ {
+ sendto_one(sptr, ":%s NOTICE %s :spam NUM is currently %i",
+ me.name, parv[0], spam_num);
+ return 0;
+ }
+ }
+ else if (!strncasecmp(command, "SPAMTIME", 8))
+ {
+ if (parc > 2)
+ {
+ int newval = atoi(parv[2]);
+ if (newval <= 0)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :spam TIME must be > 0",
+ me.name, parv[0]);
+ return 0;
+ }
+ if (newval < MIN_SPAM_TIME)
+ spam_time = MIN_SPAM_TIME;
+ else
+ spam_time = newval;
+ sendto_ops("%s has changed spam TIME to %i", parv[0],
+ spam_time);
+ sendto_one(sptr, ":%s NOTICE %s :SPAM TIME is now set to %i",
+ me.name, parv[0], spam_time);
+ return 0;
+ }
+ else
+ {
+ sendto_one(sptr, ":%s NOTICE %s :spam TIME is currently %i",
+ me.name, parv[0], spam_time);
+ return 0;
+ }
+ }
+
+#endif
+#ifdef THROTTLE_ENABLE
+ else if (!strncasecmp(command, "THROTTLE", 8))
+ {
+ char *changed = NULL;
+ char *to = NULL;
+ /* several values available:
+ * ENABLE [on|off] to enable the code
+ * COUNT [n] to set a max count, must be > 1
+ * TIME [n] to set a max time before expiry, must be > 5
+ * RECORDTIME [n] to set a time for the throttle records to expire
+ * HASH [n] to set the size of the hash table, must be bigger than
+ * the default */
+
+
+ /* only handle individual settings if parc > 3 (they're actually
+ * changing stuff) */
+ if (parc > 3) {
+ if (!strcasecmp(parv[2], "ENABLE")) {
+ changed = "ENABLE";
+ if (ToLower(*parv[3]) == 'y' || !strcasecmp(parv[3], "on")) {
+ throttle_enable = 1;
+ to = "ON";
+ } else if (ToLower(*parv[3]) == 'n' ||
+ !strcasecmp(parv[3], "off")) {
+ throttle_enable = 0;
+ to = "OFF";
+ }
+ } else if (!strcasecmp(parv[2], "COUNT")) {
+ int cnt;
+ changed = "COUNT";
+ cnt = atoi(parv[3]);
+ if (cnt > 1) {
+ throttle_tcount = cnt;
+ to = parv[3];
+ }
+ } else if (!strcasecmp(parv[2], "TIME")) {
+ int cnt;
+ changed = "TIME";
+ cnt = atoi(parv[3]);
+ if (cnt >= 5) {
+ throttle_ttime = cnt;
+ to = parv[3];
+ }
+ } else if (!strcasecmp(parv[2], "RECORDTIME")) {
+ int cnt;
+ changed = "RECORDTIME";
+ cnt = atoi(parv[3]);
+ if (cnt >= 30) {
+ throttle_rtime = cnt;
+ to = parv[3];
+ }
+ } else if (!strcasecmp(parv[2], "HASH")) {
+ int cnt;
+ changed = "HASH";
+ cnt = atoi(parv[3]);
+ if (cnt >= THROTTLE_HASHSIZE) {
+ throttle_resize(cnt);
+ to = parv[3];
+ }
+ }
+
+ if (to != NULL) {
+ sendto_ops("%s has changed throttle %s to %s", parv[0],
+ changed, to);
+ sendto_one(sptr, ":%s NOTICE %s :set throttle %s to %s",
+ me.name, parv[0], changed, to);
+ }
+ } else {
+ /* report various things, we cannot easily get the hash size, so
+ * leave that alone. */
+ sendto_one(sptr, ":%s NOTICE %s :THROTTLE %s", me.name, parv[0],
+ throttle_enable ? "enabled" : "disabled");
+ sendto_one(sptr, ":%s NOTICE %s :THROTTLE COUNT=%d", me.name,
+ parv[0], throttle_tcount);
+ sendto_one(sptr, ":%s NOTICE %s :THROTTLE TIME=%d sec", me.name,
+ parv[0], throttle_ttime);
+ sendto_one(sptr, ":%s NOTICE %s :THROTTLE RECORDTIME=%d sec", me.name,
+ parv[0], throttle_rtime);
+ }
+ }
+ else if (!strncasecmp(command, "LCLONES", 3))
+ {
+ if (parc > 3)
+ {
+ int limit, rval;
+
+ limit = atoi(parv[3]);
+ rval = clones_set(parv[2], CLIM_SOFT_LOCAL, limit);
+
+ if (rval < 0)
+ sendto_one(sptr, ":%s NOTICE %s :Invalid IP or limit.",
+ me.name, parv[0]);
+ else if (rval > 0 && limit == 0)
+ {
+ sendto_ops("%s removed soft local clone limit for %s",
+ parv[0], parv[2]);
+ sendto_one(sptr, ":%s NOTICE %s :removed soft local clone"
+ " limit for %s", me.name, parv[0], parv[2]);
+ }
+ else if (rval > 0)
+ {
+ sendto_ops("%s changed soft local clone limit for %s from"
+ " %d to %d", parv[0], parv[2], rval, limit);
+ sendto_one(sptr, ":%s NOTICE %s :changed soft local clone"
+ " limit for %s from %d to %d", me.name, parv[0],
+ parv[2], rval, limit);
+ }
+ else if (limit == 0)
+ {
+ sendto_one(sptr, "%s NOTICE %s :no soft local clone limit"
+ " for %s", me.name, parv[0], parv[2]);
+ }
+ else
+ {
+ sendto_ops("%s set soft local clone limit for %s to %d",
+ parv[0], parv[2], limit);
+ sendto_one(sptr, ":%s NOTICE %s :set soft local clone"
+ " limit for %s to %d", me.name, parv[0],
+ parv[2], limit);
+ }
+ }
+ else if (parc > 2)
+ {
+ int hglimit, sglimit, sllimit;
+
+ clones_get(parv[2], &hglimit, &sglimit, &sllimit);
+
+ if (!sllimit)
+ sendto_one(sptr, ":%s NOTICE %s :no soft local clone limit"
+ " for %s", me.name, parv[0], parv[2]);
+ else
+ sendto_one(sptr, ":%s NOTICE %s :soft local clone limit"
+ " for %s is %d", me.name, parv[0], parv[2],
+ sllimit);
+ }
+ else
+ sendto_one(sptr, ":%s NOTICE %s :Usage: LCLONES <ip> [<limit>]",
+ me.name, parv[0]);
+ }
+ else if (!strncasecmp(command, "GCLONES", 3))
+ {
+ int hglimit, sglimit, sllimit, limit, rval;
+
+ if (parc > 3)
+ {
+ limit = atoi(parv[3]);
+ clones_get(parv[2], &hglimit, &sglimit, &sllimit);
+
+ if (hglimit && limit > hglimit)
+ sendto_one(sptr, ":%s NOTICE %s :Cannot set soft global"
+ " clone limit for %s above services-set hard"
+ " limit (%d)", me.name, parv[0], parv[2],
+ hglimit);
+ else
+ {
+ rval = clones_set(parv[2], CLIM_SOFT_GLOBAL, limit);
+
+ if (rval < 0)
+ sendto_one(sptr, ":%s NOTICE %s :Invalid IP or limit.",
+ me.name, parv[0]);
+ else if (rval > 0 && limit == 0)
+ {
+ sendto_ops("%s removed soft global clone limit for %s",
+ parv[0], parv[2]);
+ sendto_one(sptr, ":%s NOTICE %s :removed soft global"
+ " clone limit for %s", me.name, parv[0],
+ parv[2]);
+ }
+ else if (rval > 0)
+ {
+ sendto_ops("%s changed soft global clone limit for %s"
+ " from %d to %d", parv[0], parv[2], rval,
+ limit);
+ sendto_one(sptr, ":%s NOTICE %s :changed soft global"
+ " clone limit for %s from %d to %d",
+ me.name, parv[0], parv[2], rval, limit);
+ }
+ else if (limit == 0)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :no soft global clone"
+ " limit for %s", me.name, parv[0], parv[2]);
+ }
+ else
+ {
+ sendto_ops("%s set soft global clone limit for %s to"
+ " %d", parv[0], parv[2], limit);
+ sendto_one(sptr, ":%s NOTICE %s :set soft global clone"
+ " limit for %s to %d", me.name, parv[0],
+ parv[2], limit);
+ }
+ }
+ }
+ else if (parc > 2)
+ {
+ clones_get(parv[2], &hglimit, &sglimit, &sllimit);
+
+ if (sglimit)
+ sendto_one(sptr, ":%s NOTICE %s :soft global clone limit"
+ " for %s is %d", me.name, parv[0], parv[2],
+ sglimit);
+ else
+ sendto_one(sptr, ":%s NOTICE %s :no soft global clone"
+ " limit for %s", me.name, parv[0], parv[2]);
+
+ if (hglimit)
+ sendto_one(sptr, ":%s NOTICE %s :hard global clone limit"
+ " for %s is %d", me.name, parv[0], parv[2],
+ hglimit);
+ }
+ else
+ sendto_one(sptr, ":%s NOTICE %s :Usage: GCLONES <ip> [<limit>]",
+ me.name, parv[0]);
+ }
+ else if (!strncasecmp(command, "DEFLCLONE", 6))
+ {
+ char *eptr;
+
+ if (parc > 2)
+ {
+ local_ip_limit = strtol(parv[2], &eptr, 10);
+ if (*eptr != 0)
+ local_ip24_limit = atoi(eptr+1);
+
+ if (local_ip_limit < 1)
+ local_ip_limit = DEFAULT_LOCAL_IP_CLONES;
+ if (local_ip24_limit < 1)
+ local_ip24_limit = DEFAULT_LOCAL_IP24_CLONES;
+
+ sendto_ops("%s set default local clone limit to %d:%d"
+ " (host:site)", parv[0], local_ip_limit,
+ local_ip24_limit);
+ sendto_one(sptr, ":%s NOTICE %s :set default local clone limit"
+ " to %d:%d (host:site)", me.name, parv[0],
+ local_ip_limit, local_ip24_limit);
+ }
+ else
+ sendto_one(sptr, ":%s NOTICE %s :default local clone limit is"
+ " %d:%d (host:site)", me.name, parv[0],
+ local_ip_limit, local_ip24_limit);
+ }
+ else if (!strncasecmp(command, "DEFGCLONE", 6))
+ {
+ char *eptr;
+
+ if (parc > 2)
+ {
+ global_ip_limit = strtol(parv[2], &eptr, 10);
+ if (*eptr != 0)
+ global_ip24_limit = atoi(eptr+1);
+
+ if (global_ip_limit < 1)
+ global_ip_limit = DEFAULT_GLOBAL_IP_CLONES;
+ if (global_ip24_limit < 1)
+ global_ip24_limit = DEFAULT_GLOBAL_IP24_CLONES;
+
+ sendto_ops("%s set default global clone limit to %d:%d"
+ " (host:site)", parv[0], global_ip_limit,
+ global_ip24_limit);
+ sendto_one(sptr, ":%s NOTICE %s :set default global clone"
+ " limit to %d:%d (host:site)", me.name, parv[0],
+ global_ip_limit, global_ip24_limit);
+ }
+ else
+ sendto_one(sptr, ":%s NOTICE %s :default global clone limit is"
+ " %d:%d (host:site)", me.name, parv[0],
+ global_ip_limit, global_ip24_limit);
+ }
+#endif
+ }
+ else
+ {
+ sendto_one(sptr, ":%s NOTICE %s :Options: MAX",
+ me.name, parv[0]);
+#ifdef FLUD
+ sendto_one(sptr, ":%s NOTICE %s :Options: FLUDNUM, FLUDTIME, "
+ "FLUDBLOCK", me.name, parv[0]);
+#endif
+
+#ifdef ANTI_SPAMBOT
+ sendto_one(sptr, ":%s NOTICE %s :Options: SPAMNUM, SPAMTIME",
+ me.name, parv[0]);
+#endif
+
+#ifdef THROTTLE_ENABLE
+ sendto_one(sptr, ":%s NOTICE %s :Options: THROTTLE "
+ "<ENABLE|COUNT|TIME|RECORDTIME|HASH> [setting]", me.name, parv[0]);
+ sendto_one(sptr, ":%s NOTICE %s :Options: LCLONES, GCLONES, "
+ "DEFLCLONES, DEFGCLONES", me.name, parv[0]);
+#endif
+ }
+ return 0;
+}
+
+/*
+ * cluster() input
+ * - pointer to a hostname output
+ * pointer to a static of the hostname masked for use in a kline. side
+ * effects - NONE
+ *
+ * reworked a tad -Dianora
+ */
+
+static char *cluster(char *hostname)
+{
+ static char result[HOSTLEN + 1]; /* result to return */
+ char temphost[HOSTLEN + 1]; /* workplace */
+ char *ipp; /* used to find if host is ip # only */
+ char *host_mask; /* used to find host mask portion to '*' */
+ /* used to zap last nnn portion of an ip # */
+ char *zap_point = (char *) NULL;
+ char *tld; /* Top Level Domain */
+ int is_ip_number; /* flag if its an IP # */
+ int number_of_dots; /* count # of dots for ip# and domain klines */
+
+ if (!hostname)
+ return (char *) NULL; /* EEK! */
+
+ /*
+ * If a '@' is found in the hostname, this is bogus and must have
+ * been introduced by server that doesn't check for bogus domains
+ * (dns spoof) very well. *sigh* just return it... I could also
+ * legitimately return (char *)NULL as above.
+ *
+ * -Dianora
+ */
+
+ if (strchr(hostname, '@'))
+ {
+ strncpyzt(result, hostname, HOSTLEN);
+ return (result);
+ }
+
+ strncpyzt(temphost, hostname, HOSTLEN);
+
+ is_ip_number = YES; /* assume its an IP# */
+ ipp = temphost;
+ number_of_dots = 0;
+
+ while (*ipp)
+ {
+ if (*ipp == '.')
+ {
+ number_of_dots++;
+ if (number_of_dots == 3)
+ zap_point = ipp;
+ ipp++;
+ }
+ else if (!IsDigit(*ipp))
+ {
+ is_ip_number = NO;
+ break;
+ }
+ ipp++;
+ }
+
+ if (is_ip_number && (number_of_dots == 3))
+ {
+ zap_point++;
+ *zap_point++ = '*'; /* turn 111.222.333.444 into ... */
+ *zap_point = '\0'; /* 111.222.333.* */
+ strncpy(result, temphost, HOSTLEN);
+ return (result);
+ }
+ else
+ {
+ tld = strrchr(temphost, '.');
+ if (tld)
+ {
+ number_of_dots = 2;
+ if (tld[3]) /* its at least a 3 letter tld */
+ number_of_dots = 1;
+ if (tld != temphost) /* in these days of dns spoofers ... */
+ host_mask = tld - 1; /* Look for host portion to '*' */
+ else
+ host_mask = tld; /* degenerate case hostname is '.com' ect. */
+
+ while (host_mask != temphost)
+ {
+ if (*host_mask == '.')
+ number_of_dots--;
+ if (number_of_dots == 0)
+ {
+ result[0] = '*';
+ strncpy(result + 1, host_mask, HOSTLEN - 1);
+ return (result);
+ }
+ host_mask--;
+ }
+ result[0] = '*'; /* foo.com => *foo.com */
+ strncpy(result + 1, temphost, HOSTLEN);
+ }
+ else
+ { /* no tld found oops. just return it as is */
+ strncpy(result, temphost, HOSTLEN);
+ return (result);
+ }
+ }
+
+ return (result);
+}
+
+int m_kline(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ struct userBan *ban, *oban;
+#if defined (LOCKFILE)
+ struct pkl *k;
+#else
+ int out;
+#endif
+
+ char buffer[1024];
+
+ char *filename; /* filename to use for kline */
+ char *user, *host;
+ char *reason;
+ char *current_date;
+ aClient *acptr;
+ char tempuser[USERLEN + 2];
+ char temphost[HOSTLEN + 1];
+ int temporary_kline_time = 0; /* -Dianora */
+ time_t temporary_kline_time_seconds = 0;
+ int time_specified = 0;
+ char *argv;
+ int i;
+ char fbuf[512];
+
+ if (!MyClient(sptr) || !IsAnOper(sptr) || !OPCanKline(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+
+ if (parc < 2)
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "KLINE");
+ return 0;
+ }
+
+ argv = parv[1];
+
+ if ((temporary_kline_time = isnumber(argv)) >= 0)
+ {
+ if (parc < 3)
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "KLINE");
+ return 0;
+ }
+ if (temporary_kline_time > (24 * 60 * 7))
+ temporary_kline_time = (24 * 60 * 7); /* Max it at 1 week */
+
+ temporary_kline_time_seconds =
+ (time_t) temporary_kline_time *(time_t) 60;
+
+ /* turn it into minutes */
+ argv = parv[2];
+ parc--;
+ time_specified = 1;
+ }
+ else
+ {
+ temporary_kline_time = 0; /* -1 minute klines are bad... :) - lucas */
+ }
+
+ if(strchr(argv, ' '))
+ {
+ sendto_one(sptr, ":%s NOTICE %s :Poorly formatted hostname "
+ "(contains spaces). Be sure you are using the form: "
+ "/quote KLINE [time] <user@host/nick> :<reason>",
+ me.name, parv[0]);
+ return 0;
+ }
+
+
+ if ((host = strchr(argv, '@')) || *argv == '*')
+ {
+ /* Explicit user@host mask given */
+
+ if (host) /* Found user@host */
+ {
+ user = argv; /* here is user part */
+ *(host++) = '\0'; /* and now here is host */
+ }
+ else
+ {
+ user = "*"; /* no @ found, assume its *@somehost */
+ host = argv;
+ }
+
+ if (!*host) /* duh. no host found, assume its '*' host */
+ host = "*";
+ strncpyzt(tempuser, user, USERLEN + 2); /* allow for '*' in front */
+ strncpyzt(temphost, host, HOSTLEN);
+ user = tempuser;
+ host = temphost;
+ }
+ else
+ {
+ /* Try to find user@host mask from nick */
+
+ if (!(acptr = find_chasing(sptr, argv, NULL)))
+ return 0;
+
+ if (!acptr->user)
+ return 0;
+
+ if (IsServer(acptr))
+ {
+ sendto_one(sptr, ":%s NOTICE %s :Can't KLINE a server, use @'s "
+ "where appropriate", me.name, parv[0]);
+ return 0;
+ }
+ /*
+ * turn the "user" bit into "*user", blow away '~' if found in
+ * original user name (non-idented)
+ */
+
+ tempuser[0] = '*';
+ if (*acptr->user->username == '~')
+ strcpy(tempuser + 1, (char *) acptr->user->username + 1);
+ else
+ strcpy(tempuser + 1, acptr->user->username);
+ user = tempuser;
+ host = cluster(acptr->user->host);
+ }
+
+ if (time_specified)
+ argv = parv[3];
+ else
+ argv = parv[2];
+
+#ifdef DEFAULT_KLINE_TIME
+ if (time_specified == 0)
+ {
+ temporary_kline_time = DEFAULT_KLINE_TIME;
+ temporary_kline_time_seconds =
+ (time_t) temporary_kline_time *(time_t) 60;
+ }
+#endif
+
+ if (parc > 2)
+ {
+ if (*argv)
+ reason = argv;
+ else
+ reason = "No reason";
+ }
+ else
+ reason = "No reason";
+
+ if (!match(user, "akjhfkahfasfjd") &&
+ !match(host, "ldksjfl.kss...kdjfd.jfklsjf"))
+ {
+ sendto_one(sptr, ":%s NOTICE %s :Can't K-Line *@*", me.name,
+ parv[0]);
+ return 0;
+ }
+
+ /* we can put whatever we want in temp K: lines */
+ if (temporary_kline_time == 0 && strchr(reason, ':'))
+ {
+ sendto_one(sptr,
+ ":%s NOTICE %s :Invalid character ':' in comment",
+ me.name, parv[0]);
+ return 0;
+ }
+
+ if (temporary_kline_time == 0 && strchr(reason, '#'))
+ {
+ sendto_one(sptr,
+ ":%s NOTICE %s :Invalid character '#' in comment",
+ me.name, parv[0]);
+ return 0;
+ }
+
+ ban = make_hostbased_ban(user, host);
+ if(!ban)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :Malformed ban %s@%s", me.name, parv[0],
+ user, host);
+ return 0;
+ }
+
+ if ((oban = find_userban_exact(ban, 0)))
+ {
+ char *ktype = (oban->flags & UBAN_LOCAL) ?
+ LOCAL_BANNED_NAME : NETWORK_BANNED_NAME;
+
+ sendto_one(sptr, ":%s NOTICE %s :[%s@%s] already %s for %s",
+ me.name, parv[0], user, host, ktype,
+ oban->reason ? oban->reason : "<No Reason>");
+
+ userban_free(ban);
+ return 0;
+ }
+
+ current_date = smalldate((time_t) 0);
+ ircsprintf(buffer, "%s (%s)", reason, current_date);
+
+ ban->flags |= UBAN_LOCAL;
+ ban->reason = (char *) MyMalloc(strlen(buffer) + 1);
+ strcpy(ban->reason, buffer);
+
+ if (temporary_kline_time)
+ {
+ ban->flags |= UBAN_TEMPORARY;
+ ban->timeset = timeofday;
+ ban->duration = temporary_kline_time_seconds;
+ }
+
+ if(user_match_ban(sptr, ban))
+ {
+ sendto_one(sptr, ":%s NOTICE %s :You attempted to add a ban [%s@%s]"
+ " which would affect yourself. Aborted.",
+ me.name, parv[0], user, host);
+ userban_free(ban);
+ return 0;
+ }
+
+ add_hostbased_userban(ban);
+
+ /* Check local users against it */
+ for (i = 0; i <= highest_fd; i++)
+ {
+ if (!(acptr = local[i]) || IsMe(acptr) || IsLog(acptr))
+ continue;
+
+ if (IsPerson(acptr) && user_match_ban(acptr, ban))
+ {
+ sendto_ops(LOCAL_BAN_NAME" active for %s",
+ get_client_name(acptr, FALSE));
+ ircsprintf(fbuf, LOCAL_BANNED_NAME": %s", reason);
+ exit_client(acptr, acptr, &me, fbuf);
+ i--;
+ }
+ }
+
+ host = get_userban_host(ban, fbuf, 512);
+
+ if(temporary_kline_time)
+ {
+ sendto_realops("%s added temporary %d min. "LOCAL_BAN_NAME" for"
+ " [%s@%s] [%s]", parv[0], temporary_kline_time, user,
+ host, reason);
+ return 0;
+ }
+
+ /* from here on, we're dealing with a perm kline */
+
+ filename = configfile;
+
+ sendto_one(sptr, ":%s NOTICE %s :Added K-Line [%s@%s] to server "
+ "configfile", me.name, parv[0], user, host);
+
+ sendto_realops("%s added K-Line for [%s@%s] [%s]",
+ parv[0], user, host, reason);
+
+#if defined(LOCKFILE)
+ if ((k = (struct pkl *) malloc(sizeof(struct pkl))) == NULL)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :Problem allocating memory",
+ me.name, parv[0]);
+ return (0);
+ }
+
+ ircsprintf(buffer, "/* %s!%s@%s Added kill for: %s@%s\n"
+ " * at %s */\n",
+ sptr->name, sptr->user->username,
+ sptr->user->host, user, host, current_date);
+
+ if ((k->comment = strdup(buffer)) == NULL)
+ {
+ MyFree(k);
+ sendto_one(sptr, ":%s NOTICE %s :Problem allocating memory",
+ me.name, parv[0]);
+ return (0);
+ }
+
+ ircsprintf(buffer, "kill {\n"
+ " mask \"%s@%s\";\n"
+ " reason \"%s\";\n"
+ "};\n\n",
+ user, host, reason);
+
+ if ((k->kline = strdup(buffer)) == NULL)
+ {
+ MyFree(k->comment);
+ MyFree(k);
+ sendto_one(sptr, ":%s NOTICE %s :Problem allocating memory",
+ me.name, parv[0]);
+ return (0);
+ }
+ k->next = pending_klines;
+ pending_klines = k;
+
+ do_pending_klines();
+ return (0);
+
+#else /* LOCKFILE - MDP */
+
+ if ((out = open(filename, O_RDWR | O_APPEND | O_CREAT)) == -1)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :Problem opening %s ",
+ me.name, parv[0], filename);
+ return 0;
+ }
+
+ ircsprintf(buffer, "/* %s!%s@%s Added kill for: %s@%s\n"
+ " * at %s */\n",
+ sptr->name, sptr->user->username,
+ sptr->user->host, user, host, current_date);
+
+ if (write(out, buffer, strlen(buffer)) <= 0)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :Problem writing to %s",
+ me.name, parv[0], filename);
+ close(out);
+ return 0;
+ }
+
+ ircsprintf(buffer, "kill {\n"
+ " mask \"%s@%s\";\n"
+ " reason \"%s\";\n"
+ "};\n\n",
+ user, host, reason);
+
+ if (write(out, buffer, strlen(buffer)) <= 0)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :Problem writing to %s",
+ me.name, parv[0], filename);
+ close(out);
+ return 0;
+ }
+
+ close(out);
+
+#ifdef USE_SYSLOG
+ syslog(LOG_NOTICE, "%s added K-Line for [%s@%s] [%s]", parv[0],
+ user, host, reason);
+#endif
+
+ return 0;
+#endif /* LOCKFILE */
+}
+
+/*
+ * isnumber()
+ *
+ * inputs
+ * - pointer to ascii string in output
+ * - 0 if not an integer number, else the number side effects
+ * - none return -1 if not an integer.
+ * (if someone types in maxint, oh well..) - lucas
+ */
+
+static int isnumber(char *p)
+{
+ int result = 0;
+
+ while (*p)
+ {
+ if (IsDigit(*p))
+ {
+ result *= 10;
+ result += ((*p) & 0xF);
+ p++;
+ }
+ else
+ return (-1);
+ }
+ /*
+ * in the degenerate case where oper does a /quote kline 0 user@host
+ * :reason i.e. they specifically use 0, I am going to return 1
+ * instead as a return value of non-zero is used to flag it as a
+ * temporary kline
+ */
+
+ /*
+ * er, no. we return 0 because 0 means that it's a permanent kline. -lucas
+ * oh, and we only do this if DEFAULT_KLINE_TIME is specified.
+ */
+
+#ifndef DEFAULT_KLINE_TIME
+ if(result == 0)
+ result = 1;
+#endif
+
+ return (result);
+}
+
+#ifdef UNKLINE
+/*
+ * * m_unkline
+ * Added Aug 31, 1997
+ * common (Keith Fralick) fralick@gate.net
+ *
+ * parv[0] = sender
+ * parv[1] = address to remove
+ *
+ * re-worked and cleanedup for use in hybrid-5 -Dianora
+ *
+ */
+int m_unkline(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ struct userBan *ban;
+ char *user, *host;
+
+ if (!IsAnOper(sptr) || !OPCanUnKline(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+
+ if (parc < 2)
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "UNKLINE");
+ return 0;
+ }
+
+ if ((host = strchr(parv[1], '@')) || *parv[1] == '*')
+ {
+ /* Explicit user@host mask given */
+
+ if (host) /* Found user@host */
+ {
+ user = parv[1]; /* here is user part */
+ *(host++) = '\0'; /* and now here is host */
+ }
+ else
+ {
+ user = "*"; /* no @ found, assume its *@somehost */
+ host = parv[1];
+ }
+ }
+ else
+ {
+ sendto_one(sptr, ":%s NOTICE %s :Invalid parameters",
+ me.name, parv[0]);
+ return 0;
+ }
+
+ if ((user[0] == '*') && (user[1] == '\0') && (host[0] == '*') &&
+ (host[1] == '\0'))
+ {
+ sendto_one(sptr, ":%s NOTICE %s :Cannot UNK-Line everyone",
+ me.name, parv[0]);
+ return 0;
+ }
+
+ ban = make_hostbased_ban(user, host);
+ if(ban)
+ {
+ struct userBan *oban;
+
+ ban->flags |= (UBAN_LOCAL|UBAN_TEMPORARY);
+ if((oban = find_userban_exact(ban, UBAN_LOCAL|UBAN_TEMPORARY)))
+ {
+ char tmp[512];
+
+ host = get_userban_host(oban, tmp, 512);
+
+ remove_userban(oban);
+ userban_free(oban);
+ userban_free(ban);
+
+ sendto_one(sptr, ":%s NOTICE %s :K-Line for [%s@%s] is removed",
+ me.name, parv[0], user, host);
+ sendto_ops("%s has removed the K-Line for: [%s@%s] (%d matches)",
+ parv[0], user, host, 1);
+
+ return 0;
+ }
+ userban_free(ban);
+ }
+ sendto_one(sptr, ":%s NOTICE %s :No Kline matches [%s@%s]",
+ me.name, parv[0], user, host);
+ return 0;
+}
+
+#endif /* UNKLINE */
+
+/* m_rehash */
+int
+m_rehash(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ if (!OPCanRehash(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+
+ if (parc > 1)
+ {
+ if (mycmp(parv[1], "DNS") == 0)
+ {
+ sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0], "DNS");
+ flush_cache(); /* flush the dns cache */
+ res_init(); /* re-read /etc/resolv.conf */
+ sendto_ops("%s is rehashing DNS while whistling innocently",
+ parv[0]);
+ return 0;
+ }
+ else if (mycmp(parv[1], "TKLINES") == 0)
+ {
+ sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0],
+ "temp klines");
+ remove_userbans_match_flags(UBAN_LOCAL|UBAN_TEMPORARY, 0);
+ sendto_ops("%s is clearing temp klines while whistling innocently",
+ parv[0]);
+ return 0;
+ }
+ else if (mycmp(parv[1], "GC") == 0)
+ {
+ sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0],
+ "garbage collecting");
+ block_garbage_collect();
+ sendto_ops("%s is garbage collecting while whistling innocently",
+ parv[0]);
+ return 0;
+ }
+ else if (mycmp(parv[1], "MOTD") == 0)
+ {
+ sendto_ops("%s is forcing re-reading of MOTD file", parv[0]);
+ read_motd(MOTD);
+ if(confopts & FLAGS_SMOTD)
+ read_shortmotd(SHORTMOTD);
+ return (0);
+ }
+ else if(mycmp(parv[1], "AKILLS") == 0)
+ {
+ sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0],
+ "akills");
+ remove_userbans_match_flags(UBAN_NETWORK, 0);
+ sendto_ops("%s is rehashing akills", parv[0]);
+ return 0;
+ }
+ else if(mycmp(parv[1], "THROTTLES") == 0) {
+ sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0],
+ "throttles");
+ throttle_rehash();
+ sendto_ops("%s is rehashing throttles", parv[0]);
+ return 0;
+ }
+ else if(mycmp(parv[1], "SQLINES") == 0) {
+ sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0],
+ "sqlines");
+ sendto_ops("%s is rehashing sqlines", parv[0]);
+ remove_simbans_match_flags(SBAN_NICK|SBAN_NETWORK, 0);
+ remove_simbans_match_flags(SBAN_CHAN|SBAN_NETWORK, 0);
+ return 0;
+ }
+ else if(mycmp(parv[1], "SGLINES") == 0) {
+ sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0],
+ "sglines");
+ sendto_ops("%s is rehashing sglines", parv[0]);
+ remove_simbans_match_flags(SBAN_GCOS|SBAN_NETWORK, 0);
+ return 0;
+ }
+ else if(mycmp(parv[1], "TSQGLINES") == 0) {
+ sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0],
+ "tsqglines");
+ sendto_ops("%s is rehashing temporary sqlines/glines", parv[0]);
+ remove_simbans_match_flags(SBAN_GCOS|SBAN_TEMPORARY, 0);
+ remove_simbans_match_flags(SBAN_NICK|SBAN_TEMPORARY, 0);
+ remove_simbans_match_flags(SBAN_CHAN|SBAN_TEMPORARY, 0);
+ return 0;
+ }
+ }
+ else
+ {
+ sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0], configfile);
+ sendto_ops("%s is rehashing Server config file while whistling "
+ "innocently", parv[0]);
+# ifdef USE_SYSLOG
+ syslog(LOG_INFO, "REHASH From %s\n", get_client_name(sptr, FALSE));
+# endif
+ return rehash(cptr, sptr,
+ (parc > 1) ? ((*parv[1] == 'q') ? 2 : 0) : 0);
+ }
+ return 0; /* shouldn't ever get here */
+}
+
+/* m_restart */
+int
+m_restart(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ char *pass = NULL;
+
+ if (!OPCanRestart(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+ /*
+ * m_restart is now password protected as in df465 only change --
+ * this one doesn't allow a reason to be specified. future changes:
+ * crypt()ing of password, reason to be re-added -mjs
+ */
+ if ((pass = MeLine->restartpass))
+ {
+ if (parc < 2)
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0],
+ "RESTART");
+ return 0;
+ }
+ if (strcmp(pass, parv[1]))
+ {
+ sendto_one(sptr, err_str(ERR_PASSWDMISMATCH), me.name, parv[0]);
+ return 0;
+ }
+ }
+
+#ifdef USE_SYSLOG
+ syslog(LOG_WARNING, "Server RESTART by %s\n",
+ get_client_name(sptr, FALSE));
+#endif
+ sprintf(buf, "Server RESTART by %s", get_client_name(sptr, TRUE));
+ restart(buf);
+ return 0; /* NOT REACHED */
+}
+
+/*
+ * * m_trace
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+int
+m_trace(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ int i;
+ aClient *acptr=NULL;
+ aClass *cltmp;
+ char *tname;
+ int doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS];
+ int wilds = 0, dow = 0;
+
+ tname = (parc > 1) ? parv[1] : me.name;
+
+#ifdef NO_USER_TRACE
+ if(!IsAnOper(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+#endif
+
+#ifdef HIDEULINEDSERVS
+ if((acptr = next_client_double(client, tname)))
+ {
+ if (!(IsAnOper(sptr)) && IsULine(acptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+ acptr = NULL; /* shrug, we borrowed it, reset it just in case */
+ }
+#endif
+
+ if (parc > 2)
+ if (hunt_server(cptr, sptr, ":%s TRACE %s :%s", 2, parc, parv))
+ return 0;
+
+ switch (hunt_server(cptr, sptr, ":%s TRACE :%s", 1, parc, parv))
+ {
+ case HUNTED_PASS: /* note: gets here only if parv[1] exists */
+ {
+ aClient *ac2ptr = next_client_double(client, tname);
+ if (ac2ptr)
+ sendto_one(sptr, rpl_str(RPL_TRACELINK), me.name, parv[0],
+ version, debugmode, tname,
+ ac2ptr->from->name);
+ else
+ sendto_one(sptr, rpl_str(RPL_TRACELINK), me.name, parv[0],
+ version, debugmode, tname,
+ "ac2ptr_is_NULL!!");
+ return 0;
+ }
+ case HUNTED_ISME:
+ break;
+ default:
+ return 0;
+ }
+ if(!IsAnOper(sptr))
+ {
+ if (parv[1] && !strchr(parv[1],'.') &&
+ (strchr(parv[1], '*') || strchr(parv[1], '?')))
+ /* bzzzt, no wildcard nicks for nonopers */
+ {
+ sendto_one(sptr, rpl_str(RPL_ENDOFTRACE),me.name,
+ parv[0], parv[1]);
+ return 0;
+ }
+ }
+ sendto_realops_lev(SPY_LEV, "TRACE requested by %s (%s@%s) [%s]",
+ sptr->name, sptr->user->username, sptr->user->host,
+ sptr->user->server);
+
+ doall = (parv[1] && (parc > 1)) ? !match(tname, me.name) : TRUE;
+ wilds = !parv[1] || strchr(tname, '*') || strchr(tname, '?');
+ dow = wilds || doall;
+ if(!IsAnOper(sptr) || !dow) /* non-oper traces must be full nicks */
+ /* lets also do this for opers tracing nicks */
+ {
+ char *name, *class;
+ acptr = hash_find_client(tname,(aClient *)NULL);
+ if(!acptr || !IsPerson(acptr))
+ {
+ /* this should only be reached if the matching
+ target is this server */
+ sendto_one(sptr, rpl_str(RPL_ENDOFTRACE),me.name,
+ parv[0], tname);
+ return 0;
+
+ }
+ if(acptr->class)
+ class = acptr->class->name;
+ else
+ class = "NONE";
+ name = get_client_name(acptr,FALSE);
+ if (IsAnOper(acptr))
+ {
+ sendto_one(sptr, rpl_str(RPL_TRACEOPERATOR),
+ me.name, parv[0], class, name,
+ timeofday - acptr->lasttime);
+ }
+ else
+ {
+ sendto_one(sptr,rpl_str(RPL_TRACEUSER),
+ me.name, parv[0], class, name,
+ timeofday - acptr->lasttime);
+ }
+ sendto_one(sptr, rpl_str(RPL_ENDOFTRACE),me.name,
+ parv[0], tname);
+ return 0;
+ }
+
+ memset((char *) link_s, '\0', sizeof(link_s));
+ memset((char *) link_u, '\0', sizeof(link_u));
+ /* Count up all the servers and clients in a downlink. */
+ if (doall)
+ for (acptr = client; acptr; acptr = acptr->next)
+ {
+ if (IsPerson(acptr) && (!IsInvisible(acptr) || IsAnOper(sptr)))
+ link_u[acptr->from->fd]++;
+ else if (IsServer(acptr))
+#ifdef HIDEULINEDSERVS
+ if (IsOper(sptr) || !IsULine(acptr))
+#endif
+ link_s[acptr->from->fd]++;
+ }
+
+
+ /* report all direct connections */
+
+ for (i = 0; i <= highest_fd; i++)
+ {
+ char *name, *class;
+
+ if (!(acptr = local[i])) /* Local Connection? */
+ continue;
+#ifdef HIDEULINEDSERVS
+ if (!IsOper(sptr) && IsULine(acptr))
+ continue;
+#endif
+ if (IsInvisible(acptr) && dow &&
+ !(MyConnect(sptr) && IsAnOper(sptr)) &&
+ !IsAnOper(acptr) && (acptr != sptr))
+ continue;
+ if (!doall && wilds && match(tname, acptr->name))
+ continue;
+ if (!dow && mycmp(tname, acptr->name))
+ continue;
+ /* only show IPs of unknowns or clients to opers */
+ if (IsAnOper(sptr) &&
+ (acptr->status == STAT_CLIENT || acptr->status == STAT_UNKNOWN))
+ name = get_client_name(acptr, FALSE);
+ else
+ name = get_client_name(acptr, HIDEME);
+ if(acptr->class)
+ class = acptr->class->name;
+ else
+ class = "NONE";
+
+ switch (acptr->status)
+ {
+ case STAT_CONNECTING:
+ sendto_one(sptr, rpl_str(RPL_TRACECONNECTING), me.name,
+ parv[0], class, name);
+ break;
+ case STAT_HANDSHAKE:
+ sendto_one(sptr, rpl_str(RPL_TRACEHANDSHAKE), me.name,
+ parv[0], class, name);
+ break;
+ case STAT_ME:
+ break;
+ case STAT_UNKNOWN:
+ /* added time -Taner */
+ sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
+ me.name, parv[0], class, name,
+ acptr->firsttime ? timeofday - acptr->firsttime : -1);
+ break;
+ case STAT_CLIENT:
+ /*
+ * Only opers see users if there is a wildcard but
+ * anyone can see all the opers.
+ */
+ if (((IsAnOper(sptr) && (MyClient(sptr)))
+ || !(dow && IsInvisible(acptr))) || !dow ||
+ IsAnOper(acptr))
+ {
+ if (IsAnOper(acptr))
+ sendto_one(sptr, rpl_str(RPL_TRACEOPERATOR),
+ me.name, parv[0], class, name,
+ timeofday - acptr->lasttime);
+ }
+ break;
+ case STAT_SERVER:
+ sendto_one(sptr, rpl_str(RPL_TRACESERVER),
+ me.name, parv[0], class, link_s[i],
+ link_u[i], name,
+ *(acptr->serv->bynick) ? acptr->serv->bynick : "*",
+ *(acptr->serv->byuser) ? acptr->serv->byuser : "*",
+ *(acptr->serv->byhost) ? acptr->serv->byhost :
+ me.name);
+ break;
+ case STAT_LOG:
+ sendto_one(sptr, rpl_str(RPL_TRACELOG), me.name,
+ parv[0], LOGFILE, acptr->port);
+ break;
+ default: /* ...we actually shouldn't come here... */
+ sendto_one(sptr, rpl_str(RPL_TRACENEWTYPE), me.name,
+ parv[0], name);
+ break;
+ }
+ }
+
+ /* let the user have some idea that its at the end of the trace */
+ sendto_one(sptr, rpl_str(RPL_TRACESERVER),
+ me.name, parv[0], "NONE", link_s[me.fd],
+ link_u[me.fd], me.name, "*", "*", me.name,
+ acptr ? timeofday - acptr->lasttime : 0);
+#ifdef HIDEULINEDSERVS
+ if (IsOper(sptr))
+#endif
+ for (cltmp = classes; doall && cltmp; cltmp = cltmp->next)
+ if (cltmp->links > 0)
+ sendto_one(sptr, rpl_str(RPL_TRACECLASS), me.name,
+ parv[0], cltmp->name, cltmp->links);
+
+ sendto_one(sptr, rpl_str(RPL_ENDOFTRACE), me.name, parv[0], tname);
+ return 0;
+}
+
+/*
+ * * m_motd
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+int
+m_motd(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ static time_t last_used = 0L;
+ if (hunt_server(cptr, sptr, ":%s MOTD :%s", 1, parc, parv) != HUNTED_ISME)
+ return 0;
+ if(!IsAnOper(sptr))
+ {
+ if (IsSquelch(sptr))
+ {
+ sendto_one(sptr, rpl_str(RPL_ENDOFMOTD), me.name, parv[0]);
+ return 0;
+ }
+ if ((last_used + MOTD_WAIT) > NOW)
+ return 0;
+ else
+ last_used = NOW;
+
+ }
+ sendto_realops_lev(SPY_LEV, "MOTD requested by %s (%s@%s) [%s]",
+ sptr->name, sptr->user->username, sptr->user->host,
+ sptr->user->server);
+ send_motd(cptr, sptr, parc, parv);
+ return 0;
+}
+
+/*
+** send_motd
+** parv[0] = sender prefix
+** parv[1] = servername
+**
+** This function split off so a server notice could be generated on a
+** user requested motd, but not on each connecting client.
+** -Dianora
+*/
+int
+send_motd(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aMotd *temp;
+ struct tm *tm;
+
+ tm = motd_tm;
+ if (motd == (aMotd *) NULL)
+ {
+ sendto_one(sptr, err_str(ERR_NOMOTD), me.name, parv[0]);
+ return 0;
+ }
+ sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0], me.name);
+
+ if (tm)
+ sendto_one(sptr, ":%s %d %s :- %d/%d/%d %d:%02d", me.name, RPL_MOTD,
+ parv[0], tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year,
+ tm->tm_hour, tm->tm_min);
+
+ temp = motd;
+ while (temp)
+ {
+ sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0], temp->line);
+ temp = temp->next;
+ }
+ sendto_one(sptr, rpl_str(RPL_ENDOFMOTD), me.name, parv[0]);
+ return 0;
+}
+
+/*
+ * read_motd() - From CoMSTuD, added Aug 29, 1996
+ */
+void
+read_motd(char *filename)
+{
+ aMotd *temp, *last;
+ struct stat sb;
+ char buffer[MOTDLINELEN], *tmp;
+ int fd;
+
+ /* Clear out the old MOTD */
+
+ while (motd)
+ {
+ temp = motd->next;
+ MyFree(motd);
+ motd = temp;
+ }
+ fd = open(filename, O_RDONLY);
+ if (fd == -1)
+ {
+ if(!forked)
+ printf("WARNING: MOTD file %s could not be found. "
+ "Skipping MOTD load.\n", filename);
+ return;
+ }
+ fstat(fd, &sb);
+ motd_tm = localtime(&sb.st_mtime);
+ last = (aMotd *) NULL;
+
+ while (dgets(fd, buffer, MOTDLINELEN - 1) > 0)
+ {
+ if ((tmp = (char *) strchr(buffer, '\n')))
+ *tmp = '\0';
+ if ((tmp = (char *) strchr(buffer, '\r')))
+ *tmp = '\0';
+ temp = (aMotd *) MyMalloc(sizeof(aMotd));
+
+ strncpyzt(temp->line, buffer, MOTDLINELEN);
+ temp->next = (aMotd *) NULL;
+ if (!motd)
+ motd = temp;
+ else
+ last->next = temp;
+ last = temp;
+ }
+ close(fd);
+
+ if (motd_tm)
+ sprintf(motd_last_changed_date, "%d/%d/%d %d:%02d", motd_tm->tm_mday,
+ motd_tm->tm_mon + 1, 1900 + motd_tm->tm_year, motd_tm->tm_hour,
+ motd_tm->tm_min);
+}
+
+void
+read_shortmotd(char *filename)
+{
+ aMotd *temp, *last;
+ char buffer[MOTDLINELEN], *tmp;
+ int fd;
+
+ /* Clear out the old MOTD */
+
+ while (shortmotd)
+ {
+ temp = shortmotd->next;
+ MyFree(shortmotd);
+ shortmotd = temp;
+ }
+ fd = open(filename, O_RDONLY);
+ if (fd == -1)
+ {
+ if(!forked)
+ printf("WARNING: sMOTD file %s could not be found. "
+ "Skipping sMOTD load.\n", filename);
+ return;
+ }
+
+ last = (aMotd *) NULL;
+
+ while (dgets(fd, buffer, MOTDLINELEN - 1) > 0)
+ {
+ if ((tmp = (char *) strchr(buffer, '\n')))
+ *tmp = '\0';
+ if ((tmp = (char *) strchr(buffer, '\r')))
+ *tmp = '\0';
+ temp = (aMotd *) MyMalloc(sizeof(aMotd));
+
+ strncpyzt(temp->line, buffer, MOTDLINELEN);
+ temp->next = (aMotd *) NULL;
+ if (!shortmotd)
+ shortmotd = temp;
+ else
+ last->next = temp;
+ last = temp;
+ }
+ close(fd);
+}
+
+/*
+ * read_help() - modified from from CoMSTuD's read_motd added Aug 29,
+ * 1996 modifed Aug 31 1997 - Dianora
+ *
+ * Use the same idea for the oper helpfile
+ */
+void
+read_help(char *filename)
+{
+ aMotd *temp, *last;
+ char buffer[MOTDLINELEN], *tmp;
+ int fd;
+
+ /* Clear out the old HELPFILE */
+
+ while (helpfile)
+ {
+ temp = helpfile->next;
+ MyFree(helpfile);
+ helpfile = temp;
+ }
+
+ fd = open(filename, O_RDONLY);
+ if (fd == -1)
+ {
+ if(!forked)
+ printf("WARNING: Help file %s could not be found. "
+ "Skipping Help file load.\n", filename);
+ return;
+ }
+
+ last = (aMotd *) NULL;
+
+ while (dgets(fd, buffer, MOTDLINELEN - 1) > 0)
+ {
+ if ((tmp = (char *) strchr(buffer, '\n')))
+ *tmp = '\0';
+ if ((tmp = (char *) strchr(buffer, '\r')))
+ *tmp = '\0';
+ temp = (aMotd *) MyMalloc(sizeof(aMotd));
+
+ strncpyzt(temp->line, buffer, MOTDLINELEN);
+ temp->next = (aMotd *) NULL;
+ if (!helpfile)
+ helpfile = temp;
+ else
+ last->next = temp;
+ last = temp;
+ }
+ close(fd);
+}
+
+/* m_close - added by Darren Reed Jul 13 1992. */
+int
+m_close(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aClient *acptr;
+ int i;
+ int closed = 0;
+
+ if (!MyOper(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+
+ for (i = highest_fd; i; i--)
+ {
+ if (!(acptr = local[i]))
+ continue;
+ if (!IsUnknown(acptr) && !IsConnecting(acptr) &&
+ !IsHandshake(acptr))
+ continue;
+ sendto_one(sptr, rpl_str(RPL_CLOSING), me.name, parv[0],
+ get_client_name(acptr, TRUE), acptr->status);
+ exit_client(acptr, acptr, acptr, "Oper Closing");
+ closed++;
+ }
+ sendto_one(sptr, rpl_str(RPL_CLOSEEND), me.name, parv[0], closed);
+ return 0;
+}
+
+int
+m_die(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aClient *acptr;
+ int i;
+ char *pass = NULL;
+
+ if (!OPCanDie(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+ /* X line -mjs */
+
+ if ((pass = MeLine->diepass))
+ {
+ if (parc < 2)
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name,
+ parv[0], "DIE");
+ return 0;
+ }
+ if (strcmp(pass, parv[1]))
+ {
+ sendto_one(sptr, err_str(ERR_PASSWDMISMATCH), me.name, parv[0]);
+ return 0;
+ }
+ }
+
+ for (i = 0; i <= highest_fd; i++)
+ {
+ if (!(acptr = local[i]))
+ continue;
+ if (IsClient(acptr))
+ sendto_one(acptr,
+ ":%s NOTICE %s :Server Terminating. %s",
+ me.name, acptr->name,
+ get_client_name(sptr, FALSE));
+ else if (IsServer(acptr))
+ sendto_one(acptr, ":%s ERROR :Terminated by %s",
+ me.name, get_client_name(sptr, TRUE));
+ }
+ s_die();
+ return 0;
+}
+
+/*
+ * m_capab
+ * Communicate what I can do to another server
+ * This has to be able to be sent and understood while
+ * the client is UNREGISTERED. Therefore, we
+ * absolutely positively must not check to see if
+ * this is a server or a client. It's probably an unknown!
+ */
+int
+m_capab(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ int i;
+
+ /* If it's not local, or it has already set capabilities,
+ * silently ignore it.
+ * Dont ignore clients where we have set some capabilities already
+ * that would suck for connecting TO servers.
+ */
+
+ if(cptr != sptr)
+ return 0;
+
+ for (i = 1; i < parc; i++)
+ {
+ if (strcmp(parv[i], "BURST") == 0)
+ SetBurst(sptr);
+ else if (strcmp(parv[i], "UNCONNECT") == 0)
+ SetUnconnect(cptr);
+ else if (strcmp(parv[i], "DKEY") == 0)
+ SetDKEY(cptr);
+ else if (strcmp(parv[i], "ZIP") == 0)
+ SetZipCapable(cptr);
+#ifdef NOQUIT
+ else if (strcmp(parv[i], "NOQUIT") == 0)
+ SetNoquit(cptr);
+#endif
+ }
+
+ return 0;
+}
+
+/* Shadowfax's LOCKFILE code */
+#ifdef LOCKFILE
+
+int
+lock_kline_file()
+{
+ int fd;
+
+ /* Create Lockfile */
+
+ if ((fd = open(LOCKFILE, O_WRONLY | O_CREAT | O_EXCL, 0666)) < 0)
+ {
+ sendto_realops("%s is locked, klines pending", configfile);
+ pending_kline_time = time(NULL);
+ return (-1);
+ }
+ close(fd);
+ return 1;
+}
+
+void
+do_pending_klines()
+{
+ int fd;
+ char s[20];
+ struct pkl *k, *ok;
+
+ if (!pending_klines)
+ return;
+
+ /* Create Lockfile */
+ if ((fd = open(LOCKFILE, O_WRONLY | O_CREAT | O_EXCL, 0666)) < 0)
+ {
+ sendto_realops("%s is locked, klines pending", configfile);
+ pending_kline_time = time(NULL);
+ return;
+ }
+ ircsprintf(s, "%d\n", getpid());
+ write(fd, s, strlen(s));
+ close(fd);
+
+ /* Open klinefile */
+ if ((fd = open(configfile, O_WRONLY | O_APPEND)) == -1)
+ {
+ sendto_realops("Pending klines cannot be written, cannot open %s",
+ configfile);
+ unlink(LOCKFILE);
+ return;
+ }
+
+ /* Add the Pending Klines */
+
+ k = pending_klines;
+ while (k)
+ {
+ write(fd, k->comment, strlen(k->comment));
+ write(fd, k->kline, strlen(k->kline));
+ MyFree(k->comment);
+ MyFree(k->kline);
+ ok = k;
+ k = k->next;
+ MyFree(ok);
+ }
+ pending_klines = NULL;
+ pending_kline_time = 0;
+
+ close(fd);
+
+ /* Delete the Lockfile */
+ unlink(LOCKFILE);
+}
+#endif
+
+/* m_svskill - Just about the same as outta df
+ * - Raistlin
+ * parv[0] = servername
+ * parv[1] = client
+ * parv[2] = nick stamp
+ * parv[3] = kill message
+ */
+
+int
+m_svskill(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aClient *acptr;
+ char *comment;
+ char reason[TOPICLEN + 1];
+ ts_val ts = 0;
+
+ if (parc < 2)
+ return 0;
+
+ if (parc > 3)
+ {
+ comment = parv[3] ? parv[3] : parv[0];
+ ts = atol(parv[2]);
+ }
+ else
+ comment = (parc > 2 && parv[2]) ? parv[2] : parv[0];
+
+ if(!IsULine(sptr)) return -1;
+ if((acptr = find_client(parv[1], NULL)) && (!ts || ts == acptr->tsinfo))
+ {
+ if(MyClient(acptr))
+ {
+ strcpy(reason, "SVSKilled: ");
+ strncpy(reason + 11, comment, TOPICLEN - 11);
+ reason[TOPICLEN] = '\0';
+ exit_client(acptr, acptr, sptr, reason);
+ return (acptr == cptr) ? FLUSH_BUFFER : 0;
+ }
+ if(acptr->from == cptr)
+ {
+ sendto_realops_lev(DEBUG_LEV, "Received wrong-direction SVSKILL"
+ " for %s (behind %s) from %s",
+ acptr->name, cptr->name,
+ get_client_name(sptr, HIDEME));
+ return 0;
+ }
+ else if(ts == 0)
+ sendto_one(acptr->from, ":%s SVSKILL %s :%s", parv[0], parv[1],
+ comment);
+ else
+ sendto_one(acptr->from, ":%s SVSKILL %s %ld :%s", parv[0], parv[1],
+ ts, comment);
+ }
+ return 0;
+}
+
+/* m_akill -
+ * Parse AKILL command
+ * parv[1]=host
+ * parv[2]=user
+ * parv[3]=length
+ * parv[4]=akiller
+ * parv[5]=time set
+ * parv[6]=reason
+ */
+int
+m_akill(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aClient *acptr;
+ char *user, *host, *reason, *akiller, buffer[1024], *current_date,
+ fbuf[512];
+ time_t length=0, timeset=0;
+ int i;
+ struct userBan *ban, *oban;
+
+ if(!IsServer(sptr) || (parc < 6))
+ return 0;
+
+ if(!IsULine(sptr))
+ {
+ sendto_serv_butone(&me,":%s GLOBOPS :Non-ULined server %s trying to "
+ "AKILL!", me.name, sptr->name);
+ send_globops("From %s: Non-ULined server %s trying to AKILL!", me.name,
+ sptr->name);
+ return 0;
+ }
+
+ host=parv[1];
+ user=parv[2];
+ akiller=parv[4];
+ length=atoi(parv[3]);
+ timeset=atoi(parv[5]);
+ reason=(parv[6] ? parv[6] : "<no reason>");
+
+ if(length == 0) /* a "permanent" akill? */
+ length = (86400 * 7); /* hold it for a week */
+
+ /* is this an old bogus akill? */
+ if(timeset + length <= NOW)
+ return 0;
+
+ current_date=smalldate((time_t)timeset);
+ /* cut reason down a little, eh? */
+ /* 250 chars max */
+ if(strlen(reason)>250)
+ reason[251]=0;
+
+ ban = make_hostbased_ban(user, host);
+ if(!ban)
+ {
+ sendto_realops_lev(DEBUG_LEV, "make_hostbased_ban(%s, %s) failed"
+ " on akill", user, host);
+ return 0;
+ }
+
+ /* if it already exists, pass it on */
+ oban = find_userban_exact(ban, 0);
+ if(oban)
+ {
+ /* pass along the akill anyways */
+ sendto_serv_butone(cptr, ":%s AKILL %s %s %d %s %d :%s",
+ sptr->name, host, user, length, akiller,
+ timeset, reason);
+ userban_free(ban);
+ return 0;
+ }
+
+ ircsprintf(buffer, "%s (%s)", reason, current_date);
+ ban->flags |= (UBAN_NETWORK|UBAN_TEMPORARY);
+ ban->reason = (char *) MyMalloc(strlen(buffer) + 1);
+ strcpy(ban->reason, buffer);
+ ban->timeset = timeset;
+ ban->duration = length;
+
+ add_hostbased_userban(ban);
+
+ /* send it off to any other servers! */
+ sendto_serv_butone(cptr, ":%s AKILL %s %s %d %s %d :%s",
+ sptr->name, host, user, length, akiller,
+ timeset, reason);
+
+ /* Check local users against it */
+ for (i = 0; i <= highest_fd; i++)
+ {
+ if (!(acptr = local[i]) || IsMe(acptr) || IsLog(acptr))
+ continue;
+ if (IsPerson(acptr) && user_match_ban(acptr, ban))
+ {
+ sendto_ops(NETWORK_BAN_NAME" active for %s",
+ get_client_name(acptr, FALSE));
+ ircsprintf(fbuf, NETWORK_BANNED_NAME": %s", reason);
+ exit_client(acptr, acptr, &me, fbuf);
+ i--;
+ }
+ }
+
+ return 0;
+}
+
+int
+m_rakill(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ struct userBan *ban, *oban;
+
+ if(!IsServer(sptr))
+ return 0;
+
+ /* just quickly find the akill and be rid of it! */
+ if(parc<3)
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0],
+ "RAKILL");
+ return 0;
+ }
+
+ if(!IsULine(sptr))
+ {
+ sendto_serv_butone(&me, ":%s GLOBOPS :Non-ULined server %s trying to "
+ "RAKILL!", me.name, sptr->name);
+ send_globops("From %s: Non-ULined server %s trying to RAKILL!",
+ me.name,
+ sptr->name);
+ return 0;
+ }
+
+ ban = make_hostbased_ban(parv[2], parv[1]);
+ if(!ban)
+ return 0;
+
+ ban->flags |= UBAN_NETWORK;
+ oban = find_userban_exact(ban, UBAN_NETWORK);
+ if(oban)
+ {
+ remove_userban(oban);
+ userban_free(oban);
+ }
+
+ userban_free(ban);
+
+ sendto_serv_butone(cptr, ":%s RAKILL %s %s", sptr->name, parv[1], parv[2]);
+ return 0;
+}
+
+
+/*
+ * RPL_NOWON - Online at the moment (Succesfully added to WATCH-list)
+ * RPL_NOWOFF - Offline at the moement (Succesfully added to WATCH-list)
+ * RPL_WATCHOFF - Succesfully removed from WATCH-list.
+ * ERR_TOOMANYWATCH - Take a guess :> Too many WATCH entries.
+ */
+static void
+show_watch(aClient *cptr, char *name, int rpl1, int rpl2)
+{
+ aClient *acptr;
+
+ if ((acptr = find_person(name, NULL)))
+ sendto_one(cptr, rpl_str(rpl1), me.name, cptr->name,
+ acptr->name, acptr->user->username,
+ acptr->user->host, acptr->lasttime);
+ else
+ sendto_one(cptr, rpl_str(rpl2), me.name, cptr->name,
+ name, "*", "*", 0);
+}
+
+/* m_watch */
+int
+m_watch(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aClient *acptr;
+ char *s, *p, *user;
+ char def[2] = "l";
+
+ if (parc < 2)
+ {
+ /* Default to 'l' - list who's currently online */
+ parc = 2;
+ parv[1] = def;
+ }
+
+ for (p = NULL, s = strtoken(&p, parv[1], ", "); s;
+ s = strtoken(&p, NULL, ", "))
+ {
+ if ((user = (char *)strchr(s, '!')))
+ *user++ = '\0'; /* Not used */
+
+ /*
+ * Prefix of "+", they want to add a name to their WATCH
+ * list.
+ */
+ if (*s == '+')
+ {
+ if (*(s+1))
+ {
+ if (sptr->watches >= MAXWATCH)
+ {
+ sendto_one(sptr, err_str(ERR_TOOMANYWATCH),
+ me.name, cptr->name, s+1);
+ continue;
+ }
+ add_to_watch_hash_table(s+1, sptr);
+ }
+ show_watch(sptr, s+1, RPL_NOWON, RPL_NOWOFF);
+ continue;
+ }
+
+ /*
+ * Prefix of "-", coward wants to remove somebody from their
+ * WATCH list. So do it. :-)
+ */
+ if (*s == '-')
+ {
+ del_from_watch_hash_table(s+1, sptr);
+ show_watch(sptr, s+1, RPL_WATCHOFF, RPL_WATCHOFF);
+ continue;
+ }
+
+ /*
+ * Fancy "C" or "c", they want to nuke their WATCH list and start
+ * over, so be it.
+ */
+ if (*s == 'C' || *s == 'c')
+ {
+ hash_del_watch_list(sptr);
+ continue;
+ }
+
+ /*
+ * Now comes the fun stuff, "S" or "s" returns a status report of
+ * their WATCH list. I imagine this could be CPU intensive if its
+ * done alot, perhaps an auto-lag on this?
+ */
+ if (*s == 'S' || *s == 's')
+ {
+ Link *lp;
+ aWatch *anptr;
+ int count = 0;
+
+ /*
+ * Send a list of how many users they have on their WATCH list
+ * and how many WATCH lists they are on.
+ */
+ anptr = hash_get_watch(sptr->name);
+ if (anptr)
+ for (lp = anptr->watch, count = 1; (lp = lp->next); count++);
+ sendto_one(sptr, rpl_str(RPL_WATCHSTAT), me.name, parv[0],
+ sptr->watches, count);
+
+ /*
+ * Send a list of everybody in their WATCH list. Be careful
+ * not to buffer overflow.
+ */
+ if ((lp = sptr->watch) == NULL)
+ {
+ sendto_one(sptr, rpl_str(RPL_ENDOFWATCHLIST), me.name, parv[0],
+ *s);
+ continue;
+ }
+ *buf = '\0';
+ strcpy(buf, lp->value.wptr->nick);
+ count = strlen(parv[0])+strlen(me.name)+10+strlen(buf);
+ while ((lp = lp->next))
+ {
+ if (count+strlen(lp->value.wptr->nick)+1 > BUFSIZE - 2)
+ {
+ sendto_one(sptr, rpl_str(RPL_WATCHLIST), me.name,
+ parv[0], buf);
+ *buf = '\0';
+ count = strlen(parv[0])+strlen(me.name)+10;
+ }
+ strcat(buf, " ");
+ strcat(buf, lp->value.wptr->nick);
+ count += (strlen(lp->value.wptr->nick)+1);
+ }
+ sendto_one(sptr, rpl_str(RPL_WATCHLIST), me.name, parv[0], buf);
+ sendto_one(sptr, rpl_str(RPL_ENDOFWATCHLIST), me.name, parv[0],
+ *s);
+ continue;
+ }
+
+ /*
+ * Well that was fun, NOT. Now they want a list of everybody in
+ * their WATCH list AND if they are online or offline? Sheesh,
+ * greedy arn't we?
+ */
+ if (*s == 'L' || *s == 'l')
+ {
+ Link *lp = sptr->watch;
+
+ while (lp)
+ {
+ if ((acptr = find_person(lp->value.wptr->nick, NULL)))
+ sendto_one(sptr, rpl_str(RPL_NOWON), me.name, parv[0],
+ acptr->name, acptr->user->username,
+ acptr->user->host, acptr->tsinfo);
+ /*
+ * But actually, only show them offline if its a capital
+ * 'L' (full list wanted).
+ */
+ else if (IsUpper(*s))
+ sendto_one(sptr, rpl_str(RPL_NOWOFF), me.name, parv[0],
+ lp->value.wptr->nick, "*", "*",
+ lp->value.wptr->lasttime);
+ lp = lp->next;
+ }
+
+ sendto_one(sptr, rpl_str(RPL_ENDOFWATCHLIST), me.name, parv[0],
+ *s);
+ continue;
+ }
+ /* Hmm.. unknown prefix character.. Ignore it. :-) */
+ }
+
+ return 0;
+}
+
+int
+m_sqline(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ struct simBan *ban;
+ unsigned int flags;
+ char *reason;
+
+ if(!(IsServer(sptr) || IsULine(sptr)))
+ return 0;
+
+ if(parc < 2)
+ {
+ /* we should not get malformed sqlines. complain loud */
+ sendto_realops("%s attempted to add sqline with insufficient params!"
+ " (ignored) Contact coders!", sptr->name);
+ return 0;
+ }
+
+ /* if we have any Q:lines (SQ or Q) that match
+ * this Q:line, just return (no need to waste cpu */
+
+ flags = SBAN_NETWORK;
+ if(parv[1][0] == '#')
+ flags |= SBAN_CHAN;
+ else
+ flags |= SBAN_NICK;
+ ban = make_simpleban(flags, parv[1]);
+ if(!ban)
+ {
+ sendto_realops("make_simpleban(%s) failed on sqline!", parv[1]);
+ return 0;
+ }
+
+ reason = BadPtr(parv[2]) ? "Reserved" : parv[2];
+ ban->reason = NULL;
+
+ if (find_simban_exact(ban) == NULL)
+ {
+ ban->reason = (char *) MyMalloc(strlen(reason) + 1);
+ strcpy(ban->reason, reason);
+ ban->timeset = NOW;
+ add_simban(ban);
+ }
+ else
+ simban_free(ban);
+
+ sendto_serv_butone(cptr, ":%s SQLINE %s :%s", sptr->name, parv[1],
+ reason);
+ return 0;
+}
+
+int
+m_unsqline(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ int matchit = 0;
+ char *mask;
+
+ if(!(IsServer(sptr) || IsULine(sptr)))
+ return 0;
+
+ if(parc < 2)
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0],
+ "UNSQLINE");
+ return 0;
+ }
+
+ if (parc == 3)
+ {
+ matchit = atoi(parv[1]);
+ mask = parv[2];
+ }
+ else
+ mask = parv[1];
+
+ /* special case for "UNSQLINE 1 :*" */
+ if(mycmp(mask, "*") == 0 && matchit)
+ {
+ remove_simbans_match_mask(SBAN_CHAN|SBAN_NETWORK, mask, 1);
+ remove_simbans_match_mask(SBAN_NICK|SBAN_NETWORK, mask, 1);
+ }
+ else if(mask[0] == '#')
+ remove_simbans_match_mask(SBAN_CHAN|SBAN_NETWORK, mask, matchit);
+ else
+ remove_simbans_match_mask(SBAN_NICK|SBAN_NETWORK, mask, matchit);
+
+ if (parc == 3)
+ sendto_serv_butone(cptr, ":%s UNSQLINE %d :%s", sptr->name, matchit,
+ mask);
+ else
+ sendto_serv_butone(cptr, ":%s UNSQLINE :%s", sptr->name, mask);
+ return 0;
+}
+
+int m_sgline(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ struct simBan *ban;
+ int len;
+ unsigned int flags;
+ char *mask, *reason;
+
+ if(!(IsServer(sptr) || IsULine(sptr)))
+ return 0;
+
+ if(parc<3)
+ {
+ sendto_realops("%s attempted to add sgline with insufficient params!"
+ " (ignored) Contact coders!", sptr->name);
+ return 0;
+ }
+
+ len=atoi(parv[1]);
+ mask=parv[2];
+ if ((strlen(mask) > len) && (mask[len])==':')
+ {
+ mask[len] = '\0';
+ reason = mask+len+1;
+ }
+ else
+ { /* Bogus */
+ return 0;
+ }
+
+ /* if we have any G:lines (SG or G) that match
+ * this G:line, just return (no need to waste cpu */
+
+ flags = SBAN_NETWORK|SBAN_GCOS;
+ ban = make_simpleban(flags, mask);
+ if(!ban)
+ {
+ sendto_realops("make_simpleban(%s) failed on sgline!", parv[1]);
+ return 0;
+ }
+
+ if(BadPtr(reason))
+ reason = "Reserved";
+ ban->reason = NULL;
+
+ if (find_simban_exact(ban) == NULL)
+ {
+ ban->reason = (char *) MyMalloc(strlen(reason) + 1);
+ strcpy(ban->reason, reason);
+ ban->timeset = NOW;
+ add_simban(ban);
+ }
+ else
+ simban_free(ban);
+
+ sendto_serv_butone(cptr, ":%s SGLINE %d :%s:%s", sptr->name, len,
+ mask, reason);
+ return 0;
+}
+
+int
+m_unsgline(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ int matchit=0;
+ char *mask;
+
+ if(!(IsServer(sptr) || IsULine(sptr)))
+ return 0;
+
+ if(parc<2)
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0],
+ "UNSGLINE");
+ return 0;
+ }
+
+
+ if (parc==3)
+ {
+ matchit=atoi(parv[1]);
+ mask=parv[2];
+ }
+ else
+ mask=parv[1];
+
+ remove_simbans_match_mask(SBAN_GCOS|SBAN_NETWORK, mask, matchit);
+
+ if (parc==3)
+ sendto_serv_butone(cptr, ":%s UNSGLINE %d :%s", sptr->name, matchit,
+ mask);
+ else
+ sendto_serv_butone(cptr, ":%s UNSGLINE :%s",sptr->name,mask);
+ return 0;
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/s_user.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free softwmare; 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 1, 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.
+ */
+
+/* $Id: s_user.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "msg.h"
+#include "channel.h"
+#include "throttle.h"
+#include "clones.h"
+#include <sys/stat.h>
+#include <utmp.h>
+#include <fcntl.h>
+#include "h.h"
+#ifdef FLUD
+#include "blalloc.h"
+#endif /* FLUD */
+#include "userban.h"
+#include "hooks.h"
+
+#if defined( HAVE_STRING_H)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+int do_user(char *, aClient *, aClient *, char *, char *, char *,
+ unsigned long, unsigned int, char *);
+extern char motd_last_changed_date[];
+extern int send_motd(aClient *, aClient *, int, char **);
+extern void send_topic_burst(aClient *);
+extern void outofmemory(void); /* defined in list.c */
+#ifdef MAXBUFFERS
+extern void reset_sock_opts();
+extern int send_lusers(aClient *,aClient *,int, char **);
+#endif
+extern int server_was_split;
+
+static char buf[BUFSIZE], buf2[BUFSIZE];
+int user_modes[] =
+{
+ UMODE_o, 'o',
+ UMODE_O, 'O',
+ UMODE_i, 'i',
+ UMODE_w, 'w',
+ UMODE_s, 's',
+ UMODE_c, 'c',
+ UMODE_r, 'r',
+ UMODE_R, 'R',
+ UMODE_k, 'k',
+ UMODE_y, 'y',
+ UMODE_d, 'd',
+ UMODE_e, 'e',
+ UMODE_g, 'g',
+ UMODE_b, 'b',
+ UMODE_a, 'a',
+ UMODE_A, 'A',
+ UMODE_f, 'f',
+ UMODE_n, 'n',
+ UMODE_m, 'm',
+ UMODE_h, 'h',
+#ifdef NO_OPER_FLOOD
+ UMODE_F, 'F',
+#endif
+ UMODE_x, 'x',
+ UMODE_X, 'X',
+ UMODE_j, 'j',
+ UMODE_K, 'K',
+ UMODE_I, 'I',
+ 0, 0
+};
+
+/* externally defined functions */
+extern Link *find_channel_link(Link *, aChannel *); /* defined in list.c */
+#ifdef FLUD
+int flud_num = FLUD_NUM;
+int flud_time = FLUD_TIME;
+int flud_block = FLUD_BLOCK;
+extern BlockHeap *free_fludbots;
+extern BlockHeap *free_Links;
+
+void announce_fluder(aClient *, aClient *, aChannel *, int);
+struct fludbot *remove_fluder_reference(struct fludbot **, aClient *);
+Link *remove_fludee_reference(Link **, void *);
+int check_for_fludblock(aClient *, aClient *, aChannel *, int);
+int check_for_flud(aClient *, aClient *, aChannel *, int);
+void free_fluders(aClient *, aChannel *);
+void free_fludees(aClient *);
+#endif
+
+#ifdef ANTI_SPAMBOT
+int spam_time = MIN_JOIN_LEAVE_TIME;
+int spam_num = MAX_JOIN_LEAVE_COUNT;
+#endif
+
+/* defines for check_ctcp results */
+#define CTCP_NONE 0
+#define CTCP_YES 1
+#define CTCP_DCC 2
+#define CTCP_DCCSEND 3
+
+
+/*
+ * cptr:
+ ** always NON-NULL, pointing to a *LOCAL* client
+ ** structure (with an open socket connected!). This
+ ** is the physical socket where the message originated (or
+ ** which caused the m_function to be executed--some
+ ** m_functions may call others...).
+ *
+ * sptr:
+ ** the source of the message, defined by the
+ ** prefix part of the message if present. If not or
+ ** prefix not found, then sptr==cptr.
+ *
+ * *Always* true (if 'parse' and others are working correct):
+ *
+ * 1 sptr->from == cptr (note: cptr->from == cptr)
+ *
+ * 2 MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ * cannot be a local connection, unless it's actually cptr!).
+ *
+ * MyConnect(x) should probably be defined as (x == x->from) --msa
+ *
+ * parc:
+ ** number of variable parameter strings (if zero,
+ ** parv is allowed to be NULL)
+ *
+ * parv:
+ ** a NULL terminated list of parameter pointers,
+ *** parv[0], sender (prefix string), if not present his points to
+ *** an empty string.
+ *
+ ** [parc-1]:
+ *** pointers to additional parameters
+ *** parv[parc] == NULL, *always*
+ *
+ * note: it is guaranteed that parv[0]..parv[parc-1] are all
+ * non-NULL pointers.
+ */
+/*
+ * * next_client
+ * Local function to find the next matching
+ * client. The search can be continued from the specified client
+ * entry. Normal usage loop is:
+ *
+ * for (x = client; x = next_client(x,mask); x = x->next)
+ * HandleMatchingClient;
+ *
+ */
+aClient *
+next_client(aClient *next, char *ch)
+{
+ /* search string (may include wilds) */
+ aClient *tmp = next;
+
+ next = find_client(ch, tmp);
+ if (tmp && tmp->prev == next)
+ return ((aClient *) NULL);
+
+ if (next != tmp)
+ return next;
+ while(next)
+ {
+ if (!match(ch, next->name))
+ break;
+ next = next->next;
+ }
+ return next;
+}
+
+/* this slow version needs to be used for hostmasks *sigh * */
+
+aClient *
+next_client_double(aClient *next, char *ch)
+{
+ /* search string (may include wilds) */
+ aClient *tmp = next;
+
+ next = find_client(ch, tmp);
+ if (tmp && tmp->prev == next)
+ return NULL;
+ if (next != tmp)
+ return next;
+ while(next)
+ {
+ if (!match(ch, next->name) || !match(next->name, ch))
+ break;
+ next = next->next;
+ }
+ return next;
+}
+
+/*
+ * hunt_server
+ *
+ * Do the basic thing in delivering the message (command)
+ * across the relays to the specific server (server) for
+ * actions.
+ *
+ * Note: The command is a format string and *MUST* be
+ * of prefixed style (e.g. ":%s COMMAND %s ...").
+ * Command can have only max 8 parameters.
+ *
+ * server parv[server] is the parameter identifying the target server.
+ *
+ * *WARNING*
+ * parv[server] is replaced with the pointer to the
+ * real servername from the matched client
+ * I'm lazy now --msa
+ *
+ * returns: (see #defines)
+ */
+int
+hunt_server(aClient *cptr, aClient *sptr, char *command, int server,
+ int parc, char *parv[])
+{
+ aClient *acptr;
+ int wilds;
+
+ /* Assume it's me, if no server */
+ if (parc <= server || BadPtr(parv[server]) ||
+ match(me.name, parv[server]) == 0 ||
+ match(parv[server], me.name) == 0)
+ return (HUNTED_ISME);
+ /*
+ * These are to pickup matches that would cause the following
+ * message to go in the wrong direction while doing quick fast
+ * non-matching lookups.
+ */
+ if ((acptr = find_client(parv[server], NULL)))
+ if (acptr->from == sptr->from && !MyConnect(acptr))
+ acptr = NULL;
+ if (!acptr && (acptr = find_server(parv[server], NULL)))
+ if (acptr->from == sptr->from && !MyConnect(acptr))
+ acptr = NULL;
+
+ collapse(parv[server]);
+ wilds = (strchr(parv[server], '?') || strchr(parv[server], '*'));
+ /*
+ * Again, if there are no wild cards involved in the server name,
+ * use the hash lookup - Dianora
+ */
+
+ if (!acptr)
+ {
+ if (!wilds)
+ {
+ acptr = find_name(parv[server], (aClient *) NULL);
+ if (!acptr || !IsRegistered(acptr) || !IsServer(acptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name,
+ parv[0], parv[server]);
+ return (HUNTED_NOSUCH);
+ }
+ }
+ else
+ {
+ for (acptr = client;
+ (acptr = next_client(acptr, parv[server]));
+ acptr = acptr->next)
+ {
+ if (acptr->from == sptr->from && !MyConnect(acptr))
+ continue;
+ /*
+ * Fix to prevent looping in case the parameter for some
+ * reason happens to match someone from the from link --jto
+ */
+ if (IsRegistered(acptr) && (acptr != cptr))
+ break;
+ }
+ }
+ }
+
+ if (acptr)
+ {
+#ifdef NO_USER_OPERTARGETED_COMMANDS
+ if (!(IsAnOper(sptr) || IsULine(sptr) || IsServer(sptr)) &&
+ !IsServer(acptr) && IsUmodeI(acptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return (HUNTED_NOSUCH);
+ }
+#endif
+ if (IsMe(acptr) || MyClient(acptr))
+ return HUNTED_ISME;
+ if (match(acptr->name, parv[server]))
+ parv[server] = acptr->name;
+ sendto_one(acptr, command, parv[0],
+ parv[1], parv[2], parv[3], parv[4],
+ parv[5], parv[6], parv[7], parv[8]);
+ return (HUNTED_PASS);
+ }
+ sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name,
+ parv[0], parv[server]);
+ return (HUNTED_NOSUCH);
+}
+
+/*
+ * canonize
+ *
+ * reduce a string of duplicate list entries to contain only the unique
+ * items. Unavoidably O(n^2).
+ */
+char *
+canonize(char *buffer)
+{
+ static char cbuf[BUFSIZ];
+ char *s, *t, *cp = cbuf;
+ int l = 0;
+ char *p = NULL, *p2;
+
+ *cp = '\0';
+
+ for (s = strtoken(&p, buffer, ","); s; s = strtoken(&p, NULL, ","))
+ {
+ if (l)
+ {
+ for (p2 = NULL, t = strtoken(&p2, cbuf, ","); t;
+ t = strtoken(&p2, NULL, ","))
+ if (!mycmp(s, t))
+ break;
+ else if (p2)
+ p2[-1] = ',';
+ }
+ else
+ t = NULL;
+
+ if (!t)
+ {
+ if (l)
+ *(cp - 1) = ',';
+ else
+ l = 1;
+ (void) strcpy(cp, s);
+ if (p)
+ cp += (p - s);
+ }
+ else if (p2)
+ p2[-1] = ',';
+ }
+ return cbuf;
+}
+
+#if (RIDICULOUS_PARANOIA_LEVEL>=1)
+static int
+check_oper_can_mask(aClient *sptr, char *name, char *password, char **onick)
+{
+ aOper *aoper;
+ char *encr;
+ extern char *crypt();
+
+ if(!(aoper = find_oper(name, sptr->user->username, sptr->user->host,
+ sptr->hostip)))
+ {
+ sendto_realops("Failed OPERMASK attempt by %s (%s@%s) [No Entry for "
+ "%s]", sptr->name, sptr->user->username,
+ sptr->user->host, name);
+ return 0;
+ }
+
+ /* use first two chars of the password they send in as salt */
+ /* passwd may be NULL pointer. Head it off at the pass... */
+ if(confopts & FLAGS_CRYPTPASS)
+ {
+ if (password && *aoper->passwd)
+ encr = crypt(password, aoper->passwd);
+ else
+ encr = "";
+ }
+ else
+ encr = password;
+
+ if(StrEq(encr, aoper->passwd))
+ {
+#ifdef USE_SYSLOG
+ syslog(LOG_INFO, "OPERMASK: %s (%s!%s@%s)", aoper->nick, sptr->name,
+ sptr->user->username, sptr->user->host);
+#endif
+ *onick = aoper->nick;
+ sendto_realops("%s [%s] (%s@<hidden>) has masked their hostname.",
+ sptr->name, aoper->nick, sptr->user->username);
+ return 1;
+ }
+
+ sendto_realops("Failed OPERMASK attempt by %s (%s@%s) [Bad Password]",
+ sptr->name, sptr->user->username, sptr->user->host);
+
+ return 0;
+}
+#endif
+
+/*
+ * * register_user
+ * This function is called when both NICK and USER messages
+ * have been accepted for the client, in whatever order. Only
+ * after this, is the USER message propagated.
+ *
+ * NICK's must be propagated at once when received, although
+ * it would be better to delay them too until full info is
+ * available. Doing it is not so simple though, would have to
+ * implement the following:
+ *
+ * (actually it has been implemented already for a while)
+ * -orabidoo
+ *
+ * 1 user telnets in and gives only "NICK foobar" and waits
+ * 2 another user far away logs in normally with the nick
+ * "foobar" quite legal, as this server didnt propagate it.
+ * 3 now this server gets nick "foobar" from outside, but has
+ * already the same defined locally. Current server would just
+ * issue "KILL foobar" to clean out dups. But, this is not
+ * fair. It should actually request another nick from local user
+ * or kill him/her...
+ */
+
+int
+register_user(aClient *cptr, aClient *sptr, char *nick, char *username)
+{
+ aClient *nsptr;
+ aAllow *pwaconf = NULL;
+ char *parv[3];
+ static char ubuf[12];
+ char *p;
+ short oldstatus = sptr->status;
+ anUser *user = sptr->user;
+ struct userBan *ban;
+ aMotd *smotd;
+ int i, dots;
+ int bad_dns; /* flag a bad dns name */
+#ifdef ANTI_SPAMBOT
+ char spamchar = '\0';
+
+#endif
+ char tmpstr2[512];
+
+ user->last = timeofday;
+ parv[0] = sptr->name;
+ parv[1] = parv[2] = NULL;
+
+ p = inetntoa((char *) &sptr->ip);
+ strncpyzt(sptr->hostip, p, HOSTIPLEN + 1);
+ if (MyConnect(sptr))
+ {
+ if ((i = check_client(sptr)))
+ {
+ switch (i)
+ {
+ case -1:
+ ircstp->is_ref++;
+ sendto_realops_lev(REJ_LEV, "%s from %s [Unauthorized"
+ " client connection]",
+ get_client_host(sptr), p);
+ return exit_client(cptr, sptr, &me, "You are not"
+ " authorized to use this server");
+
+ case -2:
+ return exit_client(cptr, sptr, &me, "Socket Error");
+
+ case -3:
+ ircstp->is_ref++;
+ sendto_realops_lev(REJ_LEV, "%s for %s [Allow class is"
+ " full (server is full)]",
+ get_client_host(sptr), p);
+ return exit_client(cptr, sptr, &me, "No more connections"
+ " allowed in your connection class (the"
+ " server is full)");
+
+ default:
+ sendto_realops_lev(DEBUG_LEV, "I don't know why I dropped"
+ " %s (%d)", get_client_host(sptr), i);
+ return exit_client(cptr, sptr, &me, "Internal error");
+ }
+ }
+
+ if (sptr->user->allow->flags & CONF_FLAGS_NOTHROTTLE)
+ throttle_remove(cptr->hostip);
+
+ if (sptr->user->allow->flags & CONF_FLAGS_FORCEFLOOD)
+ SetNoMsgThrottle(sptr);
+
+#ifdef ANTI_SPAMBOT
+ /* This appears to be broken */
+ /* Check for single char in user->host -ThemBones */
+ if (*(user->host + 1) == '\0')
+ spamchar = *user->host;
+#endif
+
+ strncpyzt(user->host, sptr->sockhost, HOSTLEN);
+
+ dots = 0;
+ p = user->host;
+ bad_dns = NO;
+ while (*p)
+ {
+ if (!IsAlnum(*p))
+ {
+#ifdef RFC1035_ANAL
+ if ((*p != '-') && (*p != '.'))
+#else
+ if ((*p != '-') && (*p != '.') && (*p != '_') &&
+ (*p != '/'))
+#endif /* RFC1035_ANAL */
+ bad_dns = YES;
+ }
+ if (*p == '.')
+ dots++;
+ p++;
+ }
+ /*
+ * Check that the hostname has AT LEAST ONE dot (.) in it. If
+ * not, drop the client (spoofed host) -ThemBones
+ */
+ if (!dots)
+ {
+ sendto_realops("Invalid hostname for %s, dumping user %s",
+ sptr->hostip, sptr->name);
+ return exit_client(cptr, sptr, &me, "Invalid hostname");
+ }
+
+ if (bad_dns)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :*** Notice -- You have a bad "
+ "character in your hostname", me.name, cptr->name);
+ strcpy(user->host, sptr->hostip);
+ strcpy(sptr->sockhost, sptr->hostip);
+ }
+
+ pwaconf = sptr->user->allow;
+
+ if (sptr->flags & FLAGS_DOID && !(sptr->flags & FLAGS_GOTID))
+ {
+ /* because username may point to user->username */
+ char temp[USERLEN + 1];
+
+ strncpyzt(temp, username, USERLEN + 1);
+ *user->username = '~';
+ (void) strncpy(&user->username[1], temp, USERLEN);
+ user->username[USERLEN] = '\0';
+#ifdef IDENTD_COMPLAIN
+ /* tell them to install identd -Taner */
+ sendto_one(sptr, ":%s NOTICE %s :*** Notice -- It seems that you "
+ "don't have identd installed on your host.",
+ me.name, cptr->name);
+ sendto_one(sptr, ":%s NOTICE %s :*** Notice -- If you wish to "
+ "have your username show up without the ~ (tilde),",
+ me.name, cptr->name);
+ sendto_one(sptr, ":%s NOTICE %s :*** Notice -- then install "
+ "identd.", me.name, cptr->name);
+ /* end identd hack */
+#endif
+ }
+ else if (sptr->flags & FLAGS_GOTID && *sptr->username != '-')
+ strncpyzt(user->username, sptr->username, USERLEN + 1);
+ else if(username != user->username) /* don't overlap */
+ strncpyzt(user->username, username, USERLEN + 1);
+
+ if (!BadPtr(pwaconf->passwd))
+ {
+ char *tmpptr = strchr(sptr->passwd, ':');
+ char tmppwd[PASSWDLEN + 1];
+
+ /*
+ * If there's a : in the password, fix it so after this function,
+ * sptr->passwd changes from:
+ * moo:cow:test:asdf
+ * to
+ * cow:test:asdf
+ */
+
+ if(tmpptr)
+ {
+ *tmpptr++ = '\0';
+ strcpy(tmppwd, tmpptr);
+ }
+
+ if(!StrEq(sptr->passwd, pwaconf->passwd))
+ {
+ ircstp->is_ref++;
+ sendto_one(sptr, err_str(ERR_PASSWDMISMATCH),
+ me.name, parv[0]);
+ return exit_client(cptr, sptr, &me, "Bad Password");
+ }
+ if(tmpptr)
+ strcpy(sptr->passwd, tmppwd);
+ else
+ sptr->passwd[0] = '\0';
+ }
+
+
+ /* Limit clients */
+ /*
+ * We want to be able to have servers and F-line clients connect,
+ * so save room for "buffer" connections. Smaller servers may
+ * want to decrease this, and it should probably be just a
+ * percentage of the MAXCLIENTS... -Taner
+ * Flines are now no different than Elines
+ * And now there are no special clients, and this is the only thing
+ * MAXCLIENTS is checked against. So no more buffer space.
+ */
+ if (Count.local > MAXCLIENTS)
+ {
+ sendto_realops_lev(SPY_LEV, "Too many clients, rejecting %s[%s].",
+ nick, sptr->sockhost);
+ ircstp->is_ref++;
+ return exit_client(cptr, sptr, &me,
+ "Sorry, server is full - try later");
+ }
+
+#ifdef ANTI_SPAMBOT
+ /* It appears, this is catching normal clients */
+ /* Reject single char user-given user->host's */
+ if (spamchar == 'x')
+ {
+ sendto_realops_lev(REJ_LEV, "Rejecting possible Spambot: %s "
+ "(Single char user-given userhost: %c)",
+ get_client_name(sptr, FALSE), spamchar);
+ ircstp->is_ref++;
+ return exit_client(cptr, sptr, sptr, "Spambot detected, "
+ "rejected.");
+ }
+#endif
+
+
+ /* i really dont like the fact that we're calling m_oper from here.
+ * perhaps there is a better method...? Will investigate later
+ * -epi */
+ if (oldstatus == STAT_MASTER && MyConnect(sptr))
+ m_oper(&me, sptr, 1, parv);
+
+ /* hostile username checks begin here */
+
+ {
+ char *tmpstr;
+ u_char c, cc;
+ int lower, upper, special;
+
+ lower = upper = special = cc = 0;
+
+ /* check for "@" in identd reply -Taner */
+ if ((strchr(user->username, '@') != NULL) ||
+ (strchr(username, '@') != NULL))
+ {
+ sendto_realops_lev(REJ_LEV,
+ "Illegal \"@\" in username: %s (%s)",
+ get_client_name(sptr, FALSE), username);
+ ircstp->is_ref++;
+ (void) ircsprintf(tmpstr2,
+ "Invalid username [%s] - '@' is not allowed",
+ username);
+ return exit_client(cptr, sptr, sptr, tmpstr2);
+ }
+ /* First check user->username... */
+#ifdef IGNORE_FIRST_CHAR
+ tmpstr = (user->username[0] == '~' ? &user->username[2] :
+ &user->username[1]);
+ /*
+ * Ok, we don't want to TOTALLY ignore the first character. We
+ * should at least check it for control characters, etc -
+ * ThemBones
+ */
+ cc = (user->username[0] == '~' ? user->username[1] :
+ user->username[0]);
+ if ((!IsAlnum(cc) && !strchr(" -_.", cc)) || (cc > 127))
+ special++;
+#else
+ tmpstr = (user->username[0] == '~' ? &user->username[1] :
+ user->username);
+#endif /* IGNORE_FIRST_CHAR */
+
+ while (*tmpstr)
+ {
+ c = *(tmpstr++);
+ if (IsLower(c))
+ {
+ lower++;
+ continue;
+ }
+ if (IsUpper(c))
+ {
+ upper++;
+ continue;
+ }
+ if ((!IsAlnum(c) && !strchr(" -_.", c)) || (c > 127) || (c<32))
+ special++;
+ }
+ if (special)
+ {
+ sendto_realops_lev(REJ_LEV, "Invalid username: %s (%s@%s)",
+ nick, user->username, user->host);
+ ircstp->is_ref++;
+ ircsprintf(tmpstr2, "Invalid username [%s]", user->username);
+ return exit_client(cptr, sptr, &me, tmpstr2);
+ }
+ /* Ok, now check the username they provided, if different */
+ lower = upper = special = cc = 0;
+
+ if (strcmp(user->username, username))
+ {
+
+#ifdef IGNORE_FIRST_CHAR
+ tmpstr = (username[0] == '~' ? &username[2] : &username[1]);
+ /*
+ * Ok, we don't want to TOTALLY ignore the first character.
+ * We should at least check it for control charcters, etc
+ * -ThemBones
+ */
+ cc = (username[0] == '~' ? username[1] : username[0]);
+
+ if ((!IsAlnum(cc) && !strchr(" -_.", cc)) || (cc > 127))
+ special++;
+#else
+ tmpstr = (username[0] == '~' ? &username[1] : username);
+#endif /* IGNORE_FIRST_CHAR */
+ while (*tmpstr)
+ {
+ c = *(tmpstr++);
+ if (IsLower(c))
+ {
+ lower++;
+ continue;
+ }
+ if (IsUpper(c))
+ {
+ upper++;
+ continue;
+ }
+ if ((!IsAlnum(c) && !strchr(" -_.", c)) || (c > 127))
+ special++;
+ }
+#ifdef NO_MIXED_CASE
+ if (lower && upper)
+ {
+ sendto_realops_lev(REJ_LEV, "Invalid username: %s (%s@%s)",
+ nick, username, user->host);
+ ircstp->is_ref++;
+ ircsprintf(tmpstr2, "Invalid username [%s]", username);
+ return exit_client(cptr, sptr, &me, tmpstr2);
+ }
+#endif /* NO_MIXED_CASE */
+ if (special)
+ {
+ sendto_realops_lev(REJ_LEV, "Invalid username: %s (%s@%s)",
+ nick, username, user->host);
+ ircstp->is_ref++;
+ ircsprintf(tmpstr2, "Invalid username [%s]", username);
+ return exit_client(cptr, sptr, &me, tmpstr2);
+ }
+ } /* usernames different */
+ }
+
+ /*
+ * reject single character usernames which aren't alphabetic i.e.
+ * reject jokers who have '?@somehost' or '.@somehost'
+ *
+ * -Dianora
+ */
+
+ if ((user->username[1] == '\0') && !IsAlpha(user->username[0]))
+ {
+ sendto_realops_lev(REJ_LEV, "Invalid username: %s (%s@%s)",
+ nick, user->username, user->host);
+ ircstp->is_ref++;
+ ircsprintf(tmpstr2, "Invalid username [%s]", user->username);
+ return exit_client(cptr, sptr, &me, tmpstr2);
+ }
+
+ if (!(user->allow->flags & CONF_FLAGS_SKIPCLONES) &&
+ (i = clones_check(cptr)))
+ {
+ ircstp->is_ref++;
+ return exit_client(cptr, sptr, &me, i == 1
+ ? "Too many connections from your host"
+ : "Too many connections from your site");
+ }
+
+ if(!(ban = check_userbanned(sptr, UBAN_IP|UBAN_CIDR4, UBAN_WILDUSER)))
+ ban = check_userbanned(sptr, UBAN_HOST, 0);
+
+ if(ban)
+ {
+ char *reason, *ktype;
+ int local;
+
+ local = (ban->flags & UBAN_LOCAL) ? 1 : 0;
+ ktype = local ? LOCAL_BANNED_NAME : NETWORK_BANNED_NAME;
+ reason = ban->reason ? ban->reason : ktype;
+
+ sendto_one(sptr, err_str(ERR_YOUREBANNEDCREEP), me.name,
+ sptr->name, ktype);
+ sendto_one(sptr, ":%s NOTICE %s :*** You are not welcome on"
+ " this %s.", me.name, sptr->name,
+ local ? "server" : "network");
+ sendto_one(sptr, ":%s NOTICE %s :*** %s for %s",
+ me.name, sptr->name, ktype, reason);
+ sendto_one(sptr, ":%s NOTICE %s :*** Your hostmask is %s!%s@%s",
+ me.name, sptr->name, sptr->name, sptr->user->username,
+ sptr->sockhost);
+ sendto_one(sptr, ":%s NOTICE %s :*** Your IP is %s",
+ me.name, sptr->name, inetntoa((char *)&sptr->ip.s_addr));
+ sendto_one(sptr, ":%s NOTICE %s :*** For assistance, please"
+ " email %s and include everything shown here.",
+ me.name, sptr->name,
+ local ? Local_Kline_Address : Network_Kline_Address);
+
+ ircstp->is_ref++;
+ ircstp->is_ref_2++;
+
+ throttle_force(sptr->hostip);
+ return exit_client(cptr, sptr, &me, reason);
+ }
+
+ if(call_hooks(CHOOK_POSTACCESS, sptr) == FLUSH_BUFFER)
+ return FLUSH_BUFFER;
+
+ if ((++Count.local) > Count.max_loc)
+ {
+ Count.max_loc = Count.local;
+ if (!(Count.max_loc % 10))
+ sendto_ops("New Max Local Clients: %d", Count.max_loc);
+ }
+ if ((NOW - Count.day) > 86400)
+ {
+ Count.today = 0;
+ Count.day = NOW;
+ }
+ if ((NOW - Count.week) > 604800)
+ {
+ Count.weekly = 0;
+ Count.week = NOW;
+ }
+ if ((NOW - Count.month) > 2592000)
+ {
+ Count.monthly = 0;
+ Count.month = NOW;
+ }
+ if ((NOW - Count.year) > 31536000)
+ {
+ Count.yearly = 0;
+ Count.year = NOW;
+ }
+ Count.today++;
+ Count.weekly++;
+ Count.monthly++;
+ Count.yearly++;
+ if(sptr->flags & FLAGS_BAD_DNS)
+ sendto_realops_lev(SPY_LEV, "DNS lookup: %s (%s@%s) is a possible "
+ "cache polluter", sptr->name,
+ sptr->user->username, sptr->user->host);
+ }
+ else
+ strncpyzt(user->username, username, USERLEN + 1);
+
+ SetClient(sptr);
+ /* Increment our total user count here */
+ if (++Count.total > Count.max_tot)
+ Count.max_tot = Count.total;
+
+ if(IsInvisible(sptr)) Count.invisi++;
+
+ if (MyConnect(sptr))
+ {
+ set_effective_class(sptr);
+#ifdef MAXBUFFERS
+ /* Let's try changing the socket options for the client here... */
+ reset_sock_opts(sptr->fd, 0);
+ /* End sock_opt hack */
+#endif
+ sendto_one(sptr, rpl_str(RPL_WELCOME), me.name, nick, Network_Name,
+ nick, sptr->user->username, sptr->user->host);
+ /*
+ * This is a duplicate of the NOTICE but see below...
+ * um, why were we hiding it? they did make it on to the
+ * server and all.. -wd
+ */
+ sendto_one(sptr, rpl_str(RPL_YOURHOST), me.name, nick, me.name,
+ version);
+#ifdef IRCII_KLUDGE
+ /* Don't mess with this one - IRCII needs it! -Avalon */
+ sendto_one(sptr, "NOTICE %s :*** Your host is %s, running version %s",
+ nick, me.name, version);
+#endif
+ sendto_one(sptr, rpl_str(RPL_CREATED), me.name, nick, creation);
+ sendto_one(sptr, rpl_str(RPL_MYINFO), me.name, parv[0],
+ me.name, version);
+
+ send_rplisupport(sptr);
+
+#ifdef FORCE_EVERYONE_HIDDEN
+ sptr->umode |= UMODE_I;
+#endif
+
+#if (RIDICULOUS_PARANOIA_LEVEL>=1)
+ if(!BadPtr(sptr->passwd) && (pwaconf->flags & CONF_FLAGS_I_OPERPORT))
+ do
+ {
+ char *onptr = sptr->passwd;
+ char *opptr;
+ char *onick;
+ char *tmpptr;
+ char tmppwd[PASSWDLEN + 1];
+
+ if(!(opptr = strchr(onptr, ':')))
+ break;
+
+ *opptr++ = '\0';
+ if((tmpptr = strchr(opptr, ':')))
+ *tmpptr++ = '\0';
+ if(check_oper_can_mask(sptr, onptr, opptr, &onick) != 0)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :*** Your hostname has "
+ "been masked.",
+ me.name, sptr->name);
+
+#ifdef DEFAULT_MASKED_HIDDEN
+ sptr->umode |= UMODE_I;
+#endif
+
+ throttle_remove(sptr->hostip);
+ sptr->user->real_oper_host =
+ MyMalloc(strlen(sptr->user->host) + 1);
+ sptr->user->real_oper_username =
+ MyMalloc(strlen(sptr->user->username) + 1);
+ sptr->user->real_oper_ip =
+ MyMalloc(strlen(sptr->hostip) + 1);
+ strcpy(sptr->user->real_oper_host, sptr->user->host);
+ strcpy(sptr->user->real_oper_username, sptr->user->username);
+ strcpy(sptr->user->real_oper_ip, sptr->hostip);
+ strncpyzt(sptr->user->host, Staff_Address, HOSTLEN + 1);
+ strncpyzt(sptr->user->username, onick, USERLEN + 1);
+ strncpyzt(sptr->username, onick, USERLEN + 1);
+ sptr->flags |= FLAGS_GOTID; /* fake ident */
+ sptr->ip.s_addr = 0;
+ strcpy(sptr->hostip, "0.0.0.0");
+ strncpy(sptr->sockhost, Staff_Address, HOSTLEN + 1);
+ }
+
+ if(tmpptr)
+ {
+ strcpy(tmppwd, tmpptr);
+ strcpy(sptr->passwd, tmppwd);
+ }
+ else
+ sptr->passwd[0] = '\0';
+ } while(0);
+#endif
+
+ sendto_realops_lev(CCONN_LEV, "Client connecting: %s (%s@%s) [%s] {%s}",
+ nick, user->username, user->host, sptr->hostip,
+ sptr->class->name);
+
+ send_lusers(sptr, sptr, 1, parv);
+
+ sendto_one(sptr, ":%s NOTICE %s :*** Notice -- motd was last"
+ " changed at %s", me.name, nick, motd_last_changed_date);
+ if(confopts & FLAGS_SMOTD)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :*** Notice -- Please read the"
+ " motd if you haven't read it", me.name, nick);
+ sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0], me.name);
+ if((smotd = shortmotd) == NULL)
+ sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0],
+ "*** This is the short motd ***");
+ else
+ while (smotd)
+ {
+ sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0],
+ smotd->line);
+ smotd = smotd->next;
+ }
+
+ sendto_one(sptr, rpl_str(RPL_ENDOFMOTD), me.name, parv[0]);
+ }
+ else
+ send_motd(sptr, sptr, 1, parv);
+
+ if((confopts & FLAGS_WGMON) == FLAGS_WGMON)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :*** Notice -- This server runs an "
+ "open proxy monitor to prevent abuse.", me.name, nick);
+ sendto_one(sptr, ":%s NOTICE %s :*** Notice -- If you see"
+ " connections on various ports from %s", me.name,
+ nick, ProxyMonHost);
+ sendto_one(sptr, ":%s NOTICE %s :*** Notice -- please disregard"
+ " them, as they are the monitor in action.", me.name,
+ nick);
+ sendto_one(sptr, ":%s NOTICE %s :*** Notice -- For more information"
+ " please visit %s", me.name, nick, ProxyMonURL);
+ }
+
+ }
+ else if (IsServer(cptr))
+ {
+ aClient *acptr;
+
+ if ((acptr = find_server(user->server, NULL)) &&
+ acptr->from != sptr->from)
+ {
+ sendto_realops_lev(DEBUG_LEV,
+ "Bad User [%s] :%s USER %s@%s %s, != %s[%s]",
+ cptr->name, nick, user->username,
+ user->host, user->server,
+ acptr->name, acptr->from->name);
+ sendto_one(cptr, ":%s KILL %s :%s (%s != %s[%s] USER from wrong "
+ "direction)", me.name, sptr->name, me.name,
+ user->server, acptr->from->name, acptr->from->sockhost);
+ sptr->flags |= FLAGS_KILLED;
+ return exit_client(sptr, sptr, &me, "USER server wrong direction");
+
+ }
+ /*
+ * Super GhostDetect: If we can't find the server the user is
+ * supposed to be on, then simply blow the user away. -Taner
+ */
+ if (!acptr)
+ {
+ sendto_one(cptr,
+ ":%s KILL %s :%s GHOST (no server %s on the net)",
+ me.name, sptr->name, me.name, user->server);
+ sendto_realops("No server %s for user %s[%s@%s] from %s",
+ user->server, sptr->name, user->username,
+ user->host, sptr->from->name);
+ sptr->flags |= FLAGS_KILLED;
+ return exit_client(sptr, sptr, &me, "Ghosted Client");
+ }
+ }
+ send_umode(NULL, sptr, 0, SEND_UMODES, ubuf);
+ if (!*ubuf)
+ {
+ ubuf[0] = '+';
+ ubuf[1] = '\0';
+ }
+ hash_check_watch(sptr, RPL_LOGON);
+ sendto_serv_butone(cptr, "NICK %s %d %ld %s %s %s %s %lu %lu :%s",
+ nick, sptr->hopcount + 1, sptr->tsinfo, ubuf,
+ user->username, user->host, user->server,
+ sptr->user->servicestamp,
+ htonl(sptr->ip.s_addr), sptr->info);
+
+ if(MyClient(sptr))
+ {
+ /* if the I:line doesn't have a password and the user does
+ * send it over to NickServ
+ */
+ if(sptr->passwd[0] && (nsptr=find_person(NICKSERV,NULL))!=NULL)
+ sendto_one(nsptr,":%s PRIVMSG %s@%s :SIDENTIFY %s", sptr->name,
+ NICKSERV, Services_Name, sptr->passwd);
+
+ memset(sptr->passwd, '\0', PASSWDLEN);
+
+ if (ubuf[1]) send_umode(cptr, sptr, 0, ALL_UMODES, ubuf);
+
+ if(call_hooks(CHOOK_POSTMOTD, sptr) == FLUSH_BUFFER)
+ return FLUSH_BUFFER;
+ }
+
+ if (sptr->ip.s_addr)
+ clones_add(sptr);
+
+ return 0;
+}
+
+char *exploits_2char[] =
+{
+ "js",
+ "pl",
+ NULL
+};
+char *exploits_3char[] =
+{
+ "exe",
+ "com",
+ "bat",
+ "dll",
+ "ini",
+ "vbs",
+ "pif",
+ "mrc",
+ "scr",
+ "doc",
+ "xls",
+ "lnk",
+ "shs",
+ "htm",
+ "zip",
+ NULL
+};
+
+char *exploits_4char[] =
+{
+ "html",
+ NULL
+};
+
+static int
+allow_dcc(aClient *to, aClient *from)
+{
+ Link *lp;
+
+ for(lp = to->user->dccallow; lp; lp = lp->next)
+ {
+ if(lp->flags == DCC_LINK_ME && lp->value.cptr == from)
+ return 1;
+ }
+ return 0;
+}
+
+static int
+check_dccsend(aClient *from, aClient *to, char *msg)
+{
+ /*
+ * we already know that msg will consist of "DCC SEND" so we can skip
+ * to the end
+ */
+ char *filename = msg + 8;
+ char *ext;
+ char **farray = NULL;
+ int arraysz;
+ int len = 0, extlen = 0, i;
+
+ /* people can send themselves stuff all the like..
+ * opers need to be able to send cleaner files
+ * sanity checks..
+ */
+
+ if(from == to || !IsPerson(from) || IsAnOper(from) || !MyClient(to))
+ return 0;
+
+ while(*filename == ' ')
+ filename++;
+
+ if(!(*filename)) return 0;
+
+ while(*(filename + len) != ' ')
+ {
+ if(!(*(filename + len))) break;
+ len++;
+ }
+
+ for(ext = filename + len;; ext--)
+ {
+ if(ext == filename)
+ return 0;
+
+ if(*ext == '.')
+ {
+ ext++;
+ extlen--;
+ break;
+ }
+ extlen++;
+ }
+
+ switch(extlen)
+ {
+ case 0:
+ arraysz = 0;
+ break;
+
+ case 2:
+ farray = exploits_2char;
+ arraysz = 2;
+ break;
+
+ case 3:
+ farray = exploits_3char;
+ arraysz = 3;
+ break;
+
+ case 4:
+ farray = exploits_4char;
+ arraysz = 4;
+ break;
+
+ /* no executable file here.. */
+ default:
+ return 0;
+ }
+
+ if (arraysz != 0)
+ {
+ for(i = 0; farray[i]; i++)
+ {
+ if(myncmp(farray[i], ext, arraysz) == 0)
+ break;
+ }
+
+ if(farray[i] == NULL)
+ return 0;
+ }
+
+ if(!allow_dcc(to, from))
+ {
+ char tmpext[8];
+ char tmpfn[128];
+ Link *tlp, *flp;
+ aChannel *chptr = NULL;
+
+ strncpy(tmpext, ext, extlen);
+ tmpext[extlen] = '\0';
+
+ if(len > 127)
+ len = 127;
+ strncpy(tmpfn, filename, len);
+ tmpfn[len] = '\0';
+
+ /* use notices!
+ * server notices are hard to script around.
+ * server notices are not ignored by clients.
+ */
+
+ sendto_one(from, ":%s NOTICE %s :The user %s is not accepting DCC "
+ "sends of filetype *.%s from you. Your file %s was not "
+ "sent.", me.name, from->name, to->name, tmpext, tmpfn);
+
+ sendto_one(to, ":%s NOTICE %s :%s (%s@%s) has attempted to send you a "
+ "file named %s, which was blocked.", me.name, to->name,
+ from->name, from->user->username, from->user->host, tmpfn);
+
+ if(!SeenDCCNotice(to))
+ {
+ SetDCCNotice(to);
+
+ sendto_one(to, ":%s NOTICE %s :The majority of files sent of this "
+ "type are malicious viruses and trojan horses."
+ " In order to prevent the spread of this problem, we "
+ "are blocking DCC sends of these types of"
+ " files by default.", me.name, to->name);
+ sendto_one(to, ":%s NOTICE %s :If you trust %s, and want him/her "
+ "to send you this file, you may obtain"
+ " more information on using the dccallow system by "
+ "typing /dccallow help",
+ me.name, to->name, from->name, to->name);
+ }
+
+ for(tlp = to->user->channel; tlp && !chptr; tlp = tlp->next)
+ {
+ for(flp = from->user->channel; flp && !chptr; flp = flp->next)
+ {
+ if(tlp->value.chptr == flp->value.chptr)
+ chptr = tlp->value.chptr;
+ }
+ }
+
+ if(chptr)
+ sendto_realops_lev(DCCSEND_LEV, "%s (%s@%s) sending forbidden "
+ "filetyped file %s to %s (channel %s)",
+ from->name, from->user->username,
+ from->user->host, tmpfn, to->name,
+ chptr->chname);
+ else
+ sendto_realops_lev(DCCSEND_LEV, "%s (%s@%s) sending forbidden "
+ "filetyped file %s to %s", from->name,
+ from->user->username, from->user->host, tmpfn,
+ to->name);
+
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * check target limit: message target rate limiting
+ * anti spam control!
+ * should only be called for local PERSONS!
+ * sptr: client sending message
+ * acptr: client receiving message
+ *
+ * return value:
+ * 1: block
+ * 0: do nothing
+ */
+
+#ifdef MSG_TARGET_LIMIT
+int check_target_limit(aClient *sptr, aClient *acptr)
+{
+ int ti;
+ int max_targets;
+ time_t tmin = MSG_TARGET_TIME; /* minimum time to wait before
+ * another message can be sent */
+
+ /* don't limit opers, people talking to themselves,
+ * or people talking to services */
+ if(IsOper(sptr) || sptr == acptr || IsULine(acptr) || NoMsgThrottle(sptr))
+ return 0;
+
+ max_targets = ((NOW - sptr->firsttime) > MSG_TARGET_MINTOMAXTIME)
+ ? MSG_TARGET_MAX : MSG_TARGET_MIN;
+
+ for(ti = 0; ti < max_targets; ti++)
+ {
+ if (sptr->targets[ti].cli == NULL || sptr->targets[ti].cli == acptr ||
+ sptr->targets[ti].sent < (NOW - MSG_TARGET_TIME))
+ {
+ sptr->targets[ti].cli = acptr;
+ sptr->targets[ti].sent = NOW;
+ break;
+ }
+ else if((NOW - sptr->targets[ti].sent) < tmin)
+ tmin = NOW - sptr->targets[ti].sent;
+ }
+
+ if(ti == max_targets)
+ {
+ sendto_one(sptr, err_str(ERR_TARGETTOFAST), me.name, sptr->name,
+ acptr->name, MSG_TARGET_TIME - tmin);
+ sptr->since += 2; /* penalize them 2 seconds for this! */
+ sptr->num_target_errors++;
+
+ if(sptr->last_target_complain + 60 <= NOW)
+ {
+ sendto_realops_lev(SPAM_LEV, "Target limited: %s (%s@%s)"
+ " [%d failed targets]", sptr->name,
+ sptr->user->username, sptr->user->host,
+ sptr->num_target_errors);
+ sptr->num_target_errors = 0;
+ sptr->last_target_complain = NOW;
+ }
+ return 1;
+ }
+
+ return 0;
+}
+#endif
+
+/*
+ * m_message (used in m_private() and m_notice()) the general
+ * function to deliver MSG's between users/channels
+ *
+ * parv[0] = sender prefix
+ * parv[1] = receiver list
+ * parv[2] = message text
+ *
+ * massive cleanup * rev argv 6/91
+ *
+ */
+/*
+ * This function checks to see if a CTCP message (other than ACTION) is
+ * contained in the passed string. This might seem easier than I am
+ * doing it, but a CTCP message can be changed together, even after a
+ * normal message.
+ *
+ * If the message is found, and it's a DCC message, pass it back in
+ * *dccptr.
+ *
+ * Unfortunately, this makes for a bit of extra processing in the
+ * server.
+ */
+static int
+check_for_ctcp(char *str, char **dccptr)
+{
+ char *p = str;
+
+ while ((p = strchr(p, 1)) != NULL)
+ {
+ if (myncmp(++p, "DCC", 3) == 0)
+ {
+ if(dccptr)
+ *dccptr = p;
+ if(myncmp(p+3, " SEND", 5) == 0)
+ return CTCP_DCCSEND;
+ else
+ return CTCP_DCC;
+ }
+ if (myncmp(++p, "ACTION", 6) != 0)
+ return CTCP_YES;
+ if ((p = strchr(p, 1)) == NULL)
+ return CTCP_NONE;
+ if(!(*(++p)))
+ break;;
+ }
+ return CTCP_NONE;
+}
+
+/* is_silenced - Returns 1 if a sptr is silenced by acptr */
+static int
+is_silenced(aClient *sptr, aClient *acptr)
+{
+ Link *lp;
+ anUser *user;
+ char sender[HOSTLEN+NICKLEN+USERLEN+5];
+
+ if (!(acptr->user)||!(lp=acptr->user->silence)||!(user=sptr->user))
+ return 0;
+ ircsprintf(sender,"%s!%s@%s",sptr->name,user->username,user->host);
+ while(lp)
+ {
+ if (!match(lp->value.cp, sender))
+ {
+ if (!MyConnect(sptr))
+ {
+ sendto_one(sptr->from, ":%s SILENCE %s :%s",acptr->name,
+ sptr->name, lp->value.cp);
+ lp->flags = 1;
+ }
+ return 1;
+ }
+ lp = lp->next;
+ }
+ return 0;
+}
+
+static inline void
+send_msg_error(aClient *sptr, char *parv[], char *nick, int ret)
+{
+ if(ret == ERR_NOCOLORSONCHAN)
+ sendto_one(sptr, err_str(ERR_NOCOLORSONCHAN), me.name,
+ parv[0], nick, parv[2]);
+ else if(ret == ERR_NEEDREGGEDNICK)
+ sendto_one(sptr, err_str(ERR_NEEDREGGEDNICK), me.name,
+ parv[0], nick, "speak in", NS_Services_Name,
+ NS_Register_URL);
+ else
+ sendto_one(sptr, err_str(ERR_CANNOTSENDTOCHAN), me.name,
+ parv[0], nick);
+}
+
+static inline int
+m_message(aClient *cptr, aClient *sptr, int parc, char *parv[], int notice)
+{
+ aClient *acptr;
+ char *s;
+ int i, ret, ischan, ismine;
+ aChannel *chptr;
+ char *nick, *server, *p, *cmd, *dccmsg;
+
+ cmd = notice ? MSG_NOTICE : MSG_PRIVATE;
+ ismine = MyClient(sptr);
+
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NORECIPIENT),
+ me.name, parv[0], cmd);
+ return -1;
+ }
+
+ if (parc < 3 || *parv[2] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
+ return -1;
+ }
+
+ if (ismine)
+ {
+ /* if its a spambot, just ignore it */
+ if ((IsSquelch(sptr))
+#if defined(ANTI_SPAMBOT) && !defined(ANTI_SPAMBOT_WARN_ONLY)
+ || (sptr->join_leave_count >= MAX_JOIN_LEAVE_COUNT)
+#endif
+ )
+ {
+ if (mycmp(parv[0],parv[1]))
+ {
+ if (IsWSquelch(sptr))
+ sendto_one(sptr, ":%s NOTICE %s :You are currently "
+ "squelched. Message not sent.", me.name,
+ parv[0]);
+ return 0;
+ }
+ }
+
+ parv[1] = canonize(parv[1]);
+ }
+
+ if(ismine && call_hooks(CHOOK_MSG, sptr, notice, parv[2]) == FLUSH_BUFFER)
+ return FLUSH_BUFFER;
+
+ for (p = NULL, nick = strtoken(&p, parv[1], ","), i = 0; nick && i<20 ;
+ nick = strtoken(&p, NULL, ","))
+ {
+ /*
+ * If someone is spamming via "/msg nick1,nick2,nick3,nick4 SPAM"
+ * (or even to channels) then subject them to flood control!
+ * -Taner
+ */
+ if (ismine && i++ > 10 && !NoMsgThrottle(sptr))
+#ifdef NO_OPER_FLOOD
+ if (!IsAnOper(sptr))
+#endif
+ sptr->since += 4;
+
+ /* channel msg? */
+ ischan = IsChannelName(nick);
+ if (ischan && (chptr = find_channel(nick,NullChn)))
+ {
+ if(ismine && call_hooks(CHOOK_CHANMSG, sptr, chptr,
+ notice, parv[2]) == FLUSH_BUFFER)
+ return FLUSH_BUFFER;
+
+ if (!notice)
+ switch(check_for_ctcp(parv[2], NULL))
+ {
+ case CTCP_NONE:
+ break;
+
+ case CTCP_DCCSEND:
+ case CTCP_DCC:
+ sendto_one(sptr, ":%s NOTICE %s :You may not send a"
+ " DCC command to a channel (%s)",
+ me.name, parv[0], nick);
+ continue;
+
+ default:
+#ifdef FLUD
+ if(!(confopts & FLAGS_HUB))
+ if (check_for_flud(sptr, NULL, chptr, 1))
+ return 0;
+#endif
+ break;
+ }
+ ret = IsULine(sptr) ? 0 : can_send(sptr, chptr, parv[2]);
+
+ if(ret)
+ {
+ if(!notice)
+ send_msg_error(sptr, parv, nick, ret);
+ }
+ else
+ sendto_channel_butone(cptr, sptr, chptr, ":%s %s %s :%s",
+ parv[0], cmd, nick, parv[2]);
+ continue;
+ }
+
+ /* nickname addressed? */
+ if (!ischan)
+ {
+ if ((acptr = find_client(nick, NULL)))
+ {
+ /* A PRIVMSG or NOTICE to me.name! */
+ if (IsMe(acptr) && ismine)
+ {
+ if(call_hooks(CHOOK_MYMSG, sptr, notice, parv[2])
+ == FLUSH_BUFFER)
+ return FLUSH_BUFFER;
+ continue;
+ }
+ if(ismine && call_hooks(CHOOK_USERMSG, sptr, acptr, notice,
+ parv[2]) == FLUSH_BUFFER)
+ return FLUSH_BUFFER;
+
+
+ if (!IsClient(acptr))
+ acptr = NULL;
+ }
+
+ if(acptr)
+ {
+ if (IsNoNonReg(acptr) && !IsRegNick(sptr) && !IsULine(sptr) &&
+ !IsOper(sptr))
+ {
+ sendto_one(sptr, rpl_str(ERR_NONONREG), me.name, parv[0],
+ acptr->name);
+ continue;
+ }
+#ifdef MSG_TARGET_LIMIT
+ /* Only check target limits for my clients */
+ if (ismine && check_target_limit(sptr, acptr))
+ continue;
+#endif
+#ifdef FLUD
+ if (!notice && MyFludConnect(acptr))
+#else
+ if (!notice && MyConnect(acptr))
+#endif
+ {
+ switch(check_for_ctcp(parv[2], &dccmsg))
+ {
+ case CTCP_NONE:
+ break;
+
+ case CTCP_DCCSEND:
+#ifdef FLUD
+ if (check_for_flud(sptr, acptr, NULL, 1))
+ return 0;
+#endif
+ if(check_dccsend(sptr, acptr, dccmsg))
+ continue;
+ break;
+
+ default:
+#ifdef FLUD
+ if (check_for_flud(sptr, acptr, NULL, 1))
+ return 0;
+#endif
+ break;
+ }
+ }
+#ifdef DENY_SERVICES_MSGS
+ if(ismine)
+ {
+ char *tservice = NULL;
+ if(!mycmp(NICKSERV, nick))
+ tservice = NICKSERV;
+ else if(!mycmp(CHANSERV, nick))
+ tservice = CHANSERV;
+ else if(!mycmp(MEMOSERV, nick))
+ tservice = MEMOSERV;
+ else if(!mycmp(ROOTSERV, nick))
+ tservice = ROOTSERV;
+
+ if(tservice != NULL)
+ {
+ if(!notice)
+ sendto_one(sptr, rpl_str(ERR_MSGSERVICES),
+ me.name, parv[0], tservice, tservice,
+ Services_Name, tservice);
+ continue;
+ }
+ }
+#endif
+ if (!is_silenced(sptr, acptr))
+ {
+ if (!notice && MyClient(acptr) && acptr->user &&
+ acptr->user->away)
+ sendto_one(sptr, rpl_str(RPL_AWAY), me.name, parv[0],
+ acptr->name, acptr->user->away);
+ sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
+ parv[0], cmd, nick, parv[2]);
+ }
+ continue;
+ }
+ } /* if(!ischan) */
+
+ if (nick[1] == '#' && nick[0]!='#')
+ {
+ if (nick[0] == '@')
+ {
+ if ((chptr = find_channel(nick + 1, NullChn)))
+ {
+ ret = IsULine(sptr) ? 0 : can_send(sptr, chptr, parv[2]);
+ if (ret)
+ {
+ if(!notice)
+ send_msg_error(sptr, parv, nick, ret);
+ }
+ else
+ sendto_channelops_butone(cptr, sptr, chptr,
+ ":%s %s %s :%s", parv[0], cmd,
+ nick, parv[2]);
+ }
+ }
+ else if (nick[0] == '+')
+ {
+ if ((chptr = find_channel(nick + 1, NullChn)))
+ {
+ ret = IsULine(sptr) ? 0 : can_send(sptr, chptr, parv[2]);
+ if (ret)
+ {
+ if(!notice)
+ send_msg_error(sptr, parv, nick, ret);
+ }
+ else
+ sendto_channelvoice_butone(cptr, sptr, chptr,
+ ":%s %s %s :%s", parv[0],
+ cmd, nick, parv[2]);
+ }
+ }
+ else
+ sendto_one_services(sptr, err_str(ERR_NOSUCHNICK),
+ me.name, parv[0], nick);
+ continue;
+ }
+ if (nick[0] == '@' && nick[1] == '+' && nick[2] == '#')
+ {
+ if ((chptr = find_channel(nick + 2, NullChn)))
+ {
+ ret = IsULine(sptr) ? 0 : can_send(sptr, chptr, parv[2]);
+ if (ret)
+ {
+ if(!notice)
+ send_msg_error(sptr, parv, nick, ret);
+ }
+ else
+ sendto_channelvoiceops_butone(cptr, sptr, chptr,
+ ":%s %s %s :%s", parv[0],
+ cmd, nick, parv[2]);
+
+ }
+ else
+ sendto_one_services(sptr, err_str(ERR_NOSUCHNICK),
+ me.name, parv[0], nick);
+ continue;
+ }
+
+ if(IsAnOper(sptr))
+ {
+ /*
+ * the following two cases allow masks in NOTICEs
+ * (for OPERs only)
+ *
+ * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
+ */
+ if ((*nick == '$' || *nick == '#'))
+ {
+ if (!(s = (char *) strrchr(nick, '.')))
+ {
+ sendto_one(sptr, err_str(ERR_NOTOPLEVEL), me.name,
+ parv[0], nick);
+ continue;
+ }
+ while (*++s)
+ if (*s == '.' || *s == '*' || *s == '?')
+ break;
+ if (*s == '*' || *s == '?')
+ {
+ sendto_one(sptr, err_str(ERR_WILDTOPLEVEL), me.name,
+ parv[0], nick);
+ continue;
+ }
+ sendto_match_butone(IsServer(cptr) ? cptr : NULL, sptr,
+ nick + 1,
+ (*nick == '#') ? MATCH_HOST : MATCH_SERVER,
+ ":%s %s %s :%s", parv[0],
+ cmd, nick, parv[2]);
+ continue;
+ }
+ }
+
+ /* user@server addressed? */
+ if (!ischan && (server = (char *) strchr(nick, '@')) &&
+ (acptr = find_server(server + 1, NULL)))
+ {
+ /* Not destined for a user on me :-( */
+ if (!IsMe(acptr))
+ {
+ if(confopts & FLAGS_SERVHUB)
+ {
+ char *myparv[2];
+
+ if(mycmp(server+1, Services_Name)==0)
+ {
+ if(!mycmp(nick,NS_Services_Name))
+ {
+ myparv[0]=parv[0];
+ myparv[1]=parv[2];
+ m_ns(cptr, sptr, parc-1, myparv);
+ }
+ else if(!mycmp(nick,CS_Services_Name))
+ {
+ myparv[0]=parv[0];
+ myparv[1]=parv[2];
+ m_cs(cptr, sptr, parc-1, myparv);
+ }
+ else if(!mycmp(nick,MS_Services_Name))
+ {
+ myparv[0]=parv[0];
+ myparv[1]=parv[2];
+ m_ms(cptr, sptr, parc-1, myparv);
+ }
+ else if(!mycmp(nick,RS_Services_Name))
+ {
+ myparv[0]=parv[0];
+ myparv[1]=parv[2];
+ m_rs(cptr, sptr, parc-1, myparv);
+ }
+ else
+ {
+ sendto_one(acptr, ":%s %s %s :%s", parv[0], cmd,
+ nick, parv[2]);
+ }
+ continue;
+ }
+ }
+ sendto_one(acptr, ":%s %s %s :%s", parv[0], cmd, nick, parv[2]);
+ continue;
+ }
+ *server = '\0';
+
+ /*
+ * Look for users which match the destination host
+ * (no host == wildcard) and if one and one only is found
+ * connected to me, deliver message!
+ */
+ acptr = find_person(nick, NULL);
+ if (server)
+ *server = '@';
+ if (acptr)
+ {
+ /*
+ * Don't allow a /msg nick@server (we weren't before, anyway)
+ *
+ * if (count == 1)
+ * sendto_prefix_one(acptr, sptr, ":%s %s %s :%s", parv[0],
+ * cmd, nick, parv[2]);
+ */
+ if (!notice)
+ sendto_one(sptr, err_str(ERR_TOOMANYTARGETS), me.name,
+ parv[0], nick);
+ continue;
+ }
+ }
+ sendto_one_services(sptr, err_str(ERR_NOSUCHNICK), me.name,
+ parv[0], nick);
+ }
+ if ((i > 20) && sptr->user)
+ sendto_realops_lev(SPY_LEV, "User %s (%s@%s) tried to msg %d users",
+ sptr->name, sptr->user->username, sptr->user->host,
+ i);
+ return 0;
+}
+
+/*
+ * m_private
+ * parv[0] = sender prefix
+ * parv[1] = receiver list
+ * parv[2] = message text
+ */
+
+int
+m_private(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ return m_message(cptr, sptr, parc, parv, 0);
+}
+
+/*
+ * m_notice *
+ * parv[0] = sender prefix
+ * parv[1] = receiver list
+ * parv[2] = notice text
+ */
+
+int
+m_notice(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ return m_message(cptr, sptr, parc, parv, 1);
+}
+
+
+/*
+ * m_whois
+ * parv[0] = sender prefix
+ * parv[1] = nickname masklist
+ */
+int
+m_whois(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ Link *lp;
+ anUser *user;
+ aClient *acptr, *a2cptr;
+ aChannel *chptr;
+ char *nick, *tmp, *name;
+ char *p = NULL;
+ int len, mlen;
+
+ if (parc < 2)
+ {
+ sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN),
+ me.name, parv[0]);
+ return 0;
+ }
+
+ if (parc > 2)
+ {
+#ifdef NO_USER_OPERTARGETED_COMMANDS
+ /*
+ * Block /whois <anything> <nick1,nick2,nick3>
+ * Also block /whois <server> <nick> for +I users
+ */
+ if(!IsAnOper(sptr))
+ {
+ acptr = hash_find_client(parv[2], (aClient *) NULL);
+ if (!acptr || !IsPerson(acptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOSUCHNICK),
+ me.name, parv[0], parv[2]);
+ return 0;
+ }
+
+ if(IsUmodeI(acptr))
+ {
+ /* allow /whois nick nick, but nothing else */
+ if(mycmp(parv[1], parv[2]) == 0)
+ parv[1] = acptr->user->server; /* And kludge it */
+ else if(MyClient(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name,
+ parv[0]);
+ return 0;
+ }
+ }
+ }
+#endif
+ if (hunt_server(cptr, sptr, ":%s WHOIS %s :%s", 1, parc, parv) !=
+ HUNTED_ISME)
+ return 0;
+ parv[1] = parv[2];
+ }
+
+ for (p = NULL, tmp = parv[1]; (nick = strtoken(&p, tmp, ",")); tmp = NULL)
+ {
+ int invis, member, showchan;
+
+ acptr = hash_find_client(nick, (aClient *) NULL);
+ if (!acptr || !IsPerson(acptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick);
+ continue;
+ }
+
+ user = acptr->user;
+ name = (!*acptr->name) ? "?" : acptr->name;
+ invis = IsInvisible(acptr);
+ member = (user->channel) ? 1 : 0;
+
+ a2cptr = acptr->uplink;
+
+ sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name, parv[0], name,
+ user->username, user->host, acptr->info);
+#if (RIDICULOUS_PARANOIA_LEVEL>=1)
+#if (RIDICULOUS_PARANOIA_LEVEL==1)
+ if(MyConnect(acptr) && user->real_oper_host &&
+ (IsAdmin(sptr) || (sptr == acptr)))
+ sendto_one(sptr, rpl_str(RPL_WHOISACTUALLY), me.name, sptr->name,
+ name, user->real_oper_username, user->real_oper_host,
+ user->real_oper_ip);
+#endif
+#if (RIDICULOUS_PARANOIA_LEVEL==2)
+ if(MyConnect(acptr) && user->real_oper_host &&
+ (IsAdmin(sptr) || (sptr == acptr)) && MyConnect(sptr))
+ sendto_one(sptr, rpl_str(RPL_WHOISACTUALLY), me.name, sptr->name,
+ name, user->real_oper_username, user->real_oper_host,
+ user->real_oper_ip);
+#endif
+#endif
+ mlen = strlen(me.name) + strlen(parv[0]) + 6 + strlen(name);
+ for (len = 0, *buf = '\0', lp = user->channel; lp; lp = lp->next)
+ {
+ chptr = lp->value.chptr;
+ showchan=ShowChannel(sptr,chptr);
+ if (showchan || IsAdmin(sptr))
+ {
+ if (len + strlen(chptr->chname) > (size_t) BUFSIZE - 4 - mlen)
+ {
+ sendto_one(sptr, ":%s %d %s %s :%s", me.name,
+ RPL_WHOISCHANNELS, parv[0], name, buf);
+ *buf = '\0';
+ len = 0;
+ }
+ if(!showchan) /* if we're not really supposed to show the chan
+ * but do it anyways, mark it as such! */
+ *(buf + len++) = '%';
+ if (is_chan_op(acptr, chptr))
+ *(buf + len++) = '@';
+ else if (has_voice(acptr, chptr))
+ *(buf + len++) = '+';
+ if (len)
+ *(buf + len) = '\0';
+ strcpy(buf + len, chptr->chname);
+ len += strlen(chptr->chname);
+ strcat(buf + len, " ");
+ len++;
+ }
+ }
+ if (buf[0] != '\0')
+ sendto_one(sptr, rpl_str(RPL_WHOISCHANNELS), me.name,
+ parv[0], name, buf);
+ if(!(IsUmodeI(acptr) && !IsAnOper(sptr)) || (acptr == sptr))
+ {
+ sendto_one(sptr, rpl_str(RPL_WHOISSERVER), me.name, parv[0], name,
+ user->server, a2cptr ? a2cptr->info : "*Not On This Net*");
+ }
+ else /* hidden oper! */
+ {
+ sendto_one(sptr, rpl_str(RPL_WHOISSERVER), me.name, parv[0],
+ name, HIDDEN_SERVER_NAME, HIDDEN_SERVER_DESC);
+ }
+
+ if(IsAnOper(sptr) && IsSquelch(acptr))
+ sendto_one(sptr, rpl_str(RPL_WHOISTEXT), me.name, parv[0],
+ IsWSquelch(acptr) ? "User is squelched (warned)" :
+ "User is squelched (silent)");
+
+ if(IsRegNick(acptr))
+ sendto_one(sptr, rpl_str(RPL_WHOISREGNICK), me.name, parv[0], name);
+ if (user->away)
+ sendto_one(sptr, rpl_str(RPL_AWAY), me.name, parv[0], name,
+ user->away);
+
+ buf[0] = '\0';
+ if (IsAnOper(acptr))
+ strcat(buf, "an IRC Operator");
+ if (IsAdmin(acptr))
+ strcat(buf, " - Server Administrator");
+ else if (IsSAdmin(acptr))
+ strcat(buf, " - Services Administrator");
+ if (buf[0])
+ sendto_one(sptr, rpl_str(RPL_WHOISOPERATOR), me.name, parv[0],
+ name, buf);
+
+ /* don't give away that this oper is on this server if they're hidden! */
+ if (acptr->user && MyConnect(acptr) && ((sptr == acptr) ||
+ !IsUmodeI(acptr) || (parc > 2) || IsAnOper(sptr)))
+ sendto_one(sptr, rpl_str(RPL_WHOISIDLE), me.name, parv[0], name,
+ timeofday - user->last, acptr->firsttime);
+
+ continue;
+ }
+ sendto_one(sptr, rpl_str(RPL_ENDOFWHOIS), me.name, parv[0], parv[1]);
+ return 0;
+}
+
+/*
+ * m_user
+ * parv[0] = sender prefix
+ * parv[1] = username (login name, account)
+ * parv[2] = client host name (used only from other servers)
+ * parv[3] = server host name (used only from other servers)
+ * parv[4] = users real name info
+ */
+int
+m_user(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+#define UFLAGS (UMODE_i|UMODE_w|UMODE_s)
+ char *username, *host, *server, *realname;
+ struct simBan *ban;
+
+ if (parc > 2 && (username = (char *) strchr(parv[1], '@')))
+ *username = '\0';
+ if (parc < 5 || *parv[1] == '\0' || *parv[2] == '\0' ||
+ *parv[3] == '\0' || *parv[4] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "USER");
+ if (IsServer(cptr))
+ sendto_realops("bad USER param count for %s from %s",
+ parv[0], get_client_name(cptr, FALSE));
+ else
+ return 0;
+ }
+ /* Copy parameters into better documenting variables */
+ username = (parc < 2 || BadPtr(parv[1])) ? "<bad-boy>" : parv[1];
+ host = (parc < 3 || BadPtr(parv[2])) ? "<nohost>" : parv[2];
+ server = (parc < 4 || BadPtr(parv[3])) ? "<noserver>" : parv[3];
+ realname = (parc < 5 || BadPtr(parv[4])) ? "<bad-realname>" : parv[4];
+ if ((ban = check_mask_simbanned(realname, SBAN_GCOS)))
+ return exit_client(cptr, sptr, sptr, BadPtr(ban->reason) ?
+ "Bad GCOS: Reason unspecified" : ban->reason);
+ return do_user(parv[0], cptr, sptr, username, host, server, 0,0, realname);
+}
+
+/* do_user */
+int
+do_user(char *nick, aClient *cptr, aClient *sptr, char *username, char *host,
+ char *server, unsigned long serviceid, unsigned int ip, char *realname)
+{
+ anUser *user;
+
+ long oflags;
+
+ user = make_user(sptr);
+ oflags = sptr->umode;
+
+ /*
+ * changed the goto into if-else... -Taner
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GOOD FOR YOU Taner!!! - Dianora
+ */
+
+ if (!MyConnect(sptr))
+ {
+ user->server = find_or_add(server);
+ strncpyzt(user->host, host, sizeof(user->host));
+ }
+ else
+ {
+ if (!IsUnknown(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_ALREADYREGISTRED),
+ me.name, nick);
+ return 0;
+ }
+ sptr->umode |= (USER_UMODES & atoi(host));
+#ifndef NO_DEFAULT_INVISIBLE
+ sptr->umode |= UMODE_i;
+#endif
+#ifdef NO_USER_SERVERKILLS
+ sptr->umode &= ~UMODE_k;
+#endif
+#ifdef NO_USER_OPERKILLS
+ sptr->umode &= ~UMODE_s;
+#endif
+ strncpyzt(user->host, host, sizeof(user->host));
+ user->server = me.name;
+ }
+ strncpyzt(sptr->info, realname, sizeof(sptr->info));
+
+ sptr->user->servicestamp = serviceid;
+ if (!MyConnect(sptr))
+ {
+ sptr->ip.s_addr=ntohl(ip);
+
+ /* add non-local clients to the throttle checker. obviously, we only
+ * do this for REMOTE clients!@$$@! throttle_check() is called
+ * elsewhere for the locals! -wd */
+#ifdef THROTTLE_ENABLE
+ if (ip != 0)
+ throttle_check(inetntoa((char *)&sptr->ip), -1, sptr->tsinfo);
+#endif
+ }
+ if(MyConnect(sptr))
+ sptr->oflag=0;
+ if (sptr->name[0]) /* NICK already received, now I have USER... */
+ return register_user(cptr, sptr, sptr->name, username);
+ else
+ strncpyzt(sptr->user->username, username, USERLEN + 1);
+ return 0;
+}
+
+/*
+ * m_quit
+ * parv[0] = sender prefix
+ * parv[1] = comment
+ */
+int
+m_quit(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ char *reason = (parc > 1 && parv[1]) ? parv[1] : cptr->name;
+ char comment[TOPICLEN + 1];
+
+ sptr->flags |= FLAGS_NORMALEX;
+ if (!IsServer(cptr))
+ {
+ strcpy(comment, "Quit: ");
+ strncpy(comment + 6, reason, TOPICLEN - 6);
+ comment[TOPICLEN] = 0;
+ return exit_client(cptr, sptr, sptr, comment);
+ }
+ else
+ return exit_client(cptr, sptr, sptr, reason);
+}
+
+/*
+ * m_kill
+ * parv[0] = sender prefix
+ * parv[1] = kill victim
+ * parv[2] = kill path
+ */
+int
+m_kill(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aClient *acptr;
+ char *user, *path, *p, *nick, *reason;
+ char mypath[KILLLEN + 1];
+ char mymsg[KILLLEN + 1];
+ char *unknownfmt = "<Unknown>"; /*
+ * AFAIK this shouldnt happen
+ * but -Raist
+ */
+ int chasing = 0, kcount = 0;
+
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "KILL");
+ return 0;
+ }
+
+ user = parv[1];
+ path = parv[2]; /* Either defined or NULL (parc >= 2!!) */
+
+ if (!IsPrivileged(cptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+
+ if (!BadPtr(path))
+ if (strlen(path) > (size_t) KILLLEN)
+ path[KILLLEN] = '\0';
+
+ if (MyClient(sptr))
+ user = canonize(user);
+ for (p = NULL, nick = strtoken(&p, user, ","); nick;
+ nick = strtoken(&p, NULL, ","))
+ {
+ chasing = 0;
+ if (!(acptr = find_client(nick, NULL)))
+ {
+ /*
+ * If the user has recently changed nick, we automaticly
+ * rewrite the KILL for this new nickname--this keeps
+ * servers in synch when nick change and kill collide
+ */
+ if (!(acptr = get_history(nick, (long) KILLCHASETIMELIMIT)))
+ {
+ sendto_one(sptr, err_str(ERR_NOSUCHNICK),
+ me.name, parv[0], nick);
+ return 0;
+ }
+ sendto_one(sptr, ":%s NOTICE %s :KILL changed from %s to %s",
+ me.name, parv[0], nick, acptr->name);
+ chasing = 1;
+ }
+ if((!MyConnect(acptr) && MyClient(cptr) && !OPCanGKill(cptr)) ||
+ (MyConnect(acptr) && MyClient(cptr) && !OPCanLKill(cptr)))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ continue;
+ }
+ if(IsServer(acptr) || IsMe(acptr) || (MyClient(sptr) && IsULine(acptr)))
+ {
+ sendto_one(sptr, err_str(ERR_CANTKILLSERVER),
+ me.name, parv[0]);
+ continue;
+ }
+ kcount++;
+ if (!IsServer(sptr) && (kcount > MAXKILLS))
+ {
+ sendto_one(sptr,":%s NOTICE %s :Too many targets, kill list was "
+ "truncated. Maximum is %d.", me.name, sptr->name,
+ MAXKILLS);
+ break;
+ }
+ if(MyClient(sptr))
+ {
+ char myname[HOSTLEN+1], *s;
+
+ if(!BadPtr(path))
+ {
+ ircsnprintf(mymsg, KILLLEN + 1, "(%s)", path);
+ reason = mymsg;
+ }
+ else
+ reason = "(No reason specified)";
+
+ strncpy(myname, me.name, HOSTLEN + 1);
+ if((s = strchr(myname, '.')))
+ *s = 0;
+
+ ircsnprintf(mypath, KILLLEN + 1, "%s!%s!%s", myname,
+ sptr->user->host, sptr->name);
+ }
+ else
+ {
+ if(BadPtr(path) || !(reason = strchr(path, ' ')))
+ {
+ path = sptr->name;
+ reason = "(No reason specified)";
+ }
+ else
+ {
+ *reason = '\0';
+ reason++;
+ }
+ strncpyzt(mypath, path, KILLLEN + 1);
+ }
+ /*
+ * Notify all *local* opers about the KILL, this includes the
+ * one originating the kill, if from this server--the special
+ * numeric reply message is not generated anymore.
+ *
+ * Note: "acptr->name" is used instead of "user" because we may
+ * have changed the target because of the nickname change.
+ */
+ if (IsLocOp(sptr) && !MyConnect(acptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+ if(IsULine(sptr))
+ sendto_realops_lev(USKILL_LEV,
+ "Received KILL message for %s!%s@%s. "
+ "From %s Path: %s %s", acptr->name,
+ acptr->user ? acptr->user->username : unknownfmt,
+ acptr->user ? acptr->user->host : unknownfmt,
+ parv[0], mypath, reason);
+ else if (IsAnOper(sptr))
+ sendto_ops_lev(0,
+ "Received KILL message for %s!%s@%s. From %s "
+ "Path: %s %s", acptr->name,
+ acptr->user ? acptr->user->username : unknownfmt,
+ acptr->user ? acptr->user->host : unknownfmt,
+ parv[0], mypath, reason);
+ else
+ sendto_ops_lev(SKILL_LEV,
+ "Received KILL message for %s!%s@%s. "
+ "From %s Path: %s %s", acptr->name,
+ acptr->user ? acptr->user->username : unknownfmt,
+ acptr->user ? acptr->user->host : unknownfmt,
+ parv[0], mypath, reason);
+
+#if defined(USE_SYSLOG) && defined(SYSLOG_KILL)
+ if (IsOper(sptr))
+ syslog(LOG_INFO, "KILL From %s!%s@%s For %s Path %s %s",
+ parv[0], acptr->name,
+ acptr->user ? acptr->user->username : unknownfmt,
+ acptr->user ? acptr->user->host : unknownfmt, mypath, reason);
+#endif
+ /*
+ * And pass on the message to other servers. Note, that if KILL
+ * was changed, the message has to be sent to all links, also
+ * back. Suicide kills are NOT passed on --SRB
+ */
+ /*
+ * Set FLAGS_KILLED. This prevents exit_one_client from sending
+ * the unnecessary QUIT for this. ,This flag should never be
+ * set in any other place...
+ */
+ if(!MyConnect(acptr) || !MyConnect(sptr) || !IsAnOper(sptr))
+ {
+ sendto_serv_butone(cptr, ":%s KILL %s :%s %s",
+ parv[0], acptr->name, mypath, reason);
+ if (chasing && IsServer(cptr))
+ sendto_one(cptr, ":%s KILL %s :%s %s",
+ me.name, acptr->name, mypath, reason);
+ acptr->flags |= FLAGS_KILLED;
+ }
+ /*
+ * Tell the victim she/he has been zapped, but *only* if the
+ * victim is on current server--no sense in sending the
+ * notification chasing the above kill, it won't get far anyway
+ * as this user don't exist there any more either
+ */
+#ifndef HIDE_KILL_ORIGINS
+ if (MyConnect(acptr))
+ sendto_prefix_one(acptr, sptr, ":%s KILL %s :%s %s",
+ parv[0], acptr->name, mypath, reason);
+
+ if (MyConnect(acptr) && MyConnect(sptr) && IsAnOper(sptr))
+ ircsprintf(buf2, "Local kill by %s %s", sptr->name, reason);
+ else
+ ircsprintf(buf2, "Killed (%s %s)", sptr->name, reason);
+#else
+ if (MyConnect(acptr))
+ sendto_one(acptr, ":%s KILL %s :%s %s",
+ HIDDEN_SERVER_NAME, acptr->name,
+ HIDDEN_SERVER_NAME, reason);
+
+ ircsprintf(buf2, "Killed (%s %s)", HIDDEN_SERVER_NAME, reason);
+#endif
+
+ if (exit_client(cptr, acptr, sptr, buf2) == FLUSH_BUFFER)
+ return FLUSH_BUFFER;
+ }
+ return 0;
+}
+
+/***********************************************************************
+ * m_away() - Added 14 Dec 1988 by jto.
+ * Not currently really working, I don't like this
+ * call at all...
+ *
+ * ...trying to make it work. I don't like it either,
+ * but perhaps it's worth the load it causes to net.
+ * This requires flooding of the whole net like NICK,
+ * USER, MODE, etc messages... --msa
+ *
+ * Added FLUD-style limiting for those lame scripts out there.
+ ***********************************************************************/
+/*
+ * m_away
+ * parv[0] = sender prefix
+ * parv[1] = away message
+ */
+int
+m_away(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ char *away, *awy2 = parv[1];
+ /* make sure the user exists */
+ if (!(sptr->user))
+ {
+ sendto_realops_lev(DEBUG_LEV, "Got AWAY from nil user, from %s (%s)\n",
+ cptr->name, sptr->name);
+ return 0;
+ }
+
+ away = sptr->user->away;
+
+#ifdef NO_AWAY_FLUD
+ if(MyClient(sptr))
+ {
+ if ((sptr->alas + MAX_AWAY_TIME) < NOW)
+ sptr->acount = 0;
+ sptr->alas = NOW;
+ sptr->acount++;
+ }
+#endif
+
+ if (parc < 2 || !*awy2)
+ {
+ /* Marking as not away */
+ if (away)
+ {
+ MyFree(away);
+ sptr->user->away = NULL;
+ /* Don't spam unaway unless they were away - lucas */
+ sendto_serv_butone_services(cptr, ":%s AWAY", parv[0]);
+ }
+
+ if (MyConnect(sptr))
+ sendto_one(sptr, rpl_str(RPL_UNAWAY), me.name, parv[0]);
+ return 0;
+ }
+
+ /* Marking as away */
+#ifdef NO_AWAY_FLUD
+ /* we dont care if they are just unsetting away, hence this is here */
+ /* only care about local non-opers */
+ if (MyClient(sptr) && (sptr->acount > MAX_AWAY_COUNT) && !IsAnOper(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_TOOMANYAWAY), me.name, parv[0]);
+ return 0;
+ }
+#endif
+ if (strlen(awy2) > (size_t) TOPICLEN)
+ awy2[TOPICLEN] = '\0';
+ /*
+ * some lamers scripts continually do a /away, hence making a lot of
+ * unnecessary traffic. *sigh* so... as comstud has done, I've
+ * commented out this sendto_serv_butone() call -Dianora
+ * readded because of anti-flud stuffs -epi
+ */
+
+ sendto_serv_butone_services(cptr, ":%s AWAY :%s ", parv[0], parv[1]);
+
+ if (away)
+ MyFree(away);
+
+ away = (char *) MyMalloc(strlen(awy2) + 1);
+ strcpy(away, awy2);
+
+ sptr->user->away = away;
+
+ if (MyConnect(sptr))
+ sendto_one(sptr, rpl_str(RPL_NOWAWAY), me.name, parv[0]);
+ return 0;
+}
+
+/*
+ * m_ping
+ * parv[0] = sender prefix
+ * parv[1] = origin
+ * parv[2] = destination
+ */
+int
+m_ping(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aClient *acptr;
+ char *origin, *destination;
+
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NOORIGIN), me.name, parv[0]);
+ return 0;
+ }
+ origin = parv[1];
+ destination = parv[2]; /* Will get NULL or pointer (parc >= 2!!) */
+
+ acptr = find_client(origin, NULL);
+ if (!acptr)
+ acptr = find_server(origin, NULL);
+ if (acptr && acptr != sptr)
+ origin = cptr->name;
+ if (!BadPtr(destination) && mycmp(destination, me.name) != 0)
+ {
+ if ((acptr = find_server(destination, NULL)))
+ sendto_one(acptr, ":%s PING %s :%s", parv[0], origin, destination);
+ else
+ {
+ sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0],
+ destination);
+ return 0;
+ }
+ }
+ else
+ sendto_one(sptr, ":%s PONG %s :%s", me.name,
+ (destination) ? destination : me.name, origin);
+ return 0;
+}
+
+/*
+ * m_pong
+ * parv[0] = sender prefix
+ * parv[1] = origin
+ * parv[2] = destination
+ */
+int
+m_pong(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aClient *acptr;
+ char *origin, *destination;
+
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NOORIGIN), me.name, parv[0]);
+ return 0;
+ }
+
+ origin = parv[1];
+ destination = parv[2];
+ cptr->flags &= ~FLAGS_PINGSENT;
+ sptr->flags &= ~FLAGS_PINGSENT;
+
+ /* if it's my client and it's a server.. */
+ if(sptr == cptr && IsServer(cptr))
+ {
+ if(sptr->flags & FLAGS_USERBURST)
+ {
+ sptr->flags &= ~FLAGS_USERBURST;
+ sendto_gnotice("from %s: %s has processed user/channel burst, "
+ "sending topic burst.", me.name, sptr->name);
+ if(confopts & FLAGS_SERVHUB)
+ {
+ /* services doesn't care about
+ * TOPICs during a sync or AWAY messages
+ * ryan, i keeel you for putting C++ style comments in here.
+ * -epi */
+ if(mycmp(cptr->name,Services_Name)!=0 &&
+ mycmp(cptr->name,Stats_Name)!=0)
+ send_topic_burst(sptr);
+ }
+ else
+ send_topic_burst(sptr);
+ sptr->flags |= FLAGS_PINGSENT|FLAGS_SOBSENT;
+ sendto_one(sptr, "PING :%s", me.name);
+ }
+ else if(sptr->flags & FLAGS_TOPICBURST)
+ {
+ sptr->flags &= ~FLAGS_TOPICBURST;
+ sendto_gnotice("from %s: %s has processed topic burst (synched "
+ "to network data).", me.name, sptr->name);
+
+ if(server_was_split)
+ server_was_split = NO;
+
+ if(confopts & FLAGS_HUB)
+ sendto_serv_butone(sptr, ":%s GNOTICE :%s has synched to"
+ " network data.", me.name, sptr->name);
+ /* Kludge: Get the "sync" message on small networks
+ * immediately */
+ sendto_one(sptr, "PING :%s", me.name);
+ }
+ }
+
+ /*
+ * Now attempt to route the PONG, comstud pointed out routable PING
+ * is used for SPING. routable PING should also probably be left in
+ * -Dianora That being the case, we will route, but only for
+ * registered clients (a case can be made to allow them only from
+ * servers). -Shadowfax
+ */
+ if (!BadPtr(destination) && (mycmp(destination, me.name) != 0)
+ && IsRegistered(sptr))
+ {
+ if ((acptr = find_client(destination, NULL)) ||
+ (acptr = find_server(destination, NULL)))
+ sendto_one(acptr, ":%s PONG %s %s", parv[0], origin, destination);
+ else
+ {
+ sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0],
+ destination);
+ return 0;
+ }
+ }
+#ifdef DEBUGMODE
+ else
+ Debug((DEBUG_NOTICE, "PONG: %s %s", origin,
+ destination ? destination : "*"));
+#endif
+ return 0;
+}
+
+/* added Sat Jul 25 07:30:42 EST 1992 */
+/*
+ * extra argument evenTS added to send to TS servers or not -orabidoo
+ *
+ * extra argument evenTS no longer needed with TS only th+hybrid server
+ * -Dianora
+ */
+static inline void
+send_umode_out(aClient *cptr, aClient *sptr, int old)
+{
+ aClient *acptr;
+ DLink *lp;
+
+ send_umode(NULL, sptr, old, SEND_UMODES, buf);
+
+ if(*buf)
+ {
+ for(lp = server_list; lp; lp = lp->next)
+ {
+ acptr = lp->value.cptr;
+ if((acptr != cptr) && (acptr != sptr))
+ sendto_one(acptr, ":%s MODE %s :%s", sptr->name,
+ sptr->name, buf);
+ }
+ }
+
+ if (cptr && MyClient(cptr))
+ send_umode(cptr, sptr, old, ALL_UMODES, buf);
+}
+
+/*
+ * m_oper
+ * parv[0] = sender prefix
+ * parv[1] = oper name
+ * parv[2] = oper password
+ */
+int m_oper(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aOper *aoper;
+ char *name, *password, *encr, *oper_ip;
+ extern char *crypt();
+
+ name = parc > 1 ? parv[1] : (char *) NULL;
+ password = parc > 2 ? parv[2] : (char *) NULL;
+
+ if (!IsServer(cptr) && (BadPtr(name) || BadPtr(password)))
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "OPER");
+ return 0;
+ }
+
+ /* if message arrived from server, trust it, and set to oper */
+ /* an OPER message should never come from a server. complain */
+
+ if ((IsServer(cptr) || IsMe(cptr)) && !IsOper(sptr))
+ {
+ sendto_realops("Why is %s sending me an OPER? Contact Coders",
+ cptr->name);
+
+ /* sanity */
+ if (!IsPerson(sptr))
+ return 0;
+
+#ifdef DEFAULT_HELP_MODE
+ sptr->umode |= UMODE_o;
+ sptr->umode |= UMODE_h;
+ sendto_serv_butone(cptr, ":%s MODE %s :+oh", parv[0], parv[0]);
+#else
+ sptr->umode |= UMODE_o;
+ sendto_serv_butone(cptr, ":%s MODE %s :+o", parv[0], parv[0]);
+#endif
+#ifdef ALL_OPERS_HIDDEN
+ sptr->umode |= UMODE_I;
+ sendto_serv_butone(cptr, ":%s MODE %s :+I", parv[0], parv[0]);
+#endif
+ Count.oper++;
+ if (IsMe(cptr))
+ sendto_one(sptr, rpl_str(RPL_YOUREOPER), me.name, parv[0]);
+ return 0;
+ }
+ else if (IsAnOper(sptr) && MyConnect(sptr))
+ {
+ sendto_one(sptr, rpl_str(RPL_YOUREOPER), me.name, parv[0]);
+ return 0;
+ }
+#if (RIDICULOUS_PARANOIA_LEVEL>=1)
+ if(!sptr->user->real_oper_host)
+ {
+#endif
+ if(!(aoper = find_oper(name, sptr->user->username, sptr->user->host,
+ sptr->hostip)))
+ {
+ sendto_one(sptr, err_str(ERR_NOOPERHOST), me.name, parv[0]);
+ sendto_realops("Failed OPER attempt by %s (%s@%s)", parv[0],
+ sptr->user->username, sptr->user->host);
+ return 0;
+ }
+ oper_ip = sptr->hostip;
+#if (RIDICULOUS_PARANOIA_LEVEL>=1)
+ }
+ else
+ {
+ if (!(aoper = find_oper(name, sptr->user->real_oper_username,
+ sptr->user->real_oper_host,
+ sptr->user->real_oper_ip)))
+ {
+ sendto_one(sptr, err_str(ERR_NOOPERHOST), me.name, parv[0]);
+ sendto_realops("Failed OPER attempt by %s (%s@%s)", parv[0],
+ sptr->user->username, sptr->user->host);
+ return 0;
+ }
+ oper_ip = sptr->user->real_oper_ip;
+ }
+#endif
+ /* use first two chars of the password they send in as salt */
+ /* passwd may be NULL pointer. Head it off at the pass... */
+ if(confopts & FLAGS_CRYPTPASS)
+ {
+ if (password && *aoper->passwd)
+ encr = crypt(password, aoper->passwd);
+ else
+ encr = "";
+ }
+ else
+ encr = password;
+
+ if (StrEq(encr, aoper->passwd))
+ {
+ int old = (sptr->umode & ALL_UMODES);
+ /* attach our conf */
+ sptr->user->oper = aoper;
+ aoper->opers++;
+ if (!(aoper->flags & OFLAG_ISGLOBAL))
+ SetLocOp(sptr);
+ else
+ SetOper(sptr);
+#ifdef DEFAULT_HELP_MODE
+ sptr->umode|=(UMODE_s|UMODE_g|UMODE_w|UMODE_n|UMODE_h);
+#else
+ sptr->umode|=(UMODE_s|UMODE_g|UMODE_w|UMODE_n);
+#endif
+ sptr->oflag = aoper->flags;
+ Count.oper++;
+ add_to_list(&oper_list, sptr);
+ throttle_remove(oper_ip);
+ sendto_ops("%s (%s@%s) is now operator (%c)", parv[0],
+ sptr->user->username, sptr->sockhost,
+ IsOper(sptr) ? 'O' : 'o');
+ send_umode_out(cptr, sptr, old);
+ sendto_one(sptr, rpl_str(RPL_YOUREOPER), me.name, parv[0]);
+ set_effective_class(sptr);
+#if defined(USE_SYSLOG) && defined(SYSLOG_OPER)
+ syslog(LOG_INFO, "OPER (%s) (%s) by (%s!%s@%s)",
+ name, encr, parv[0], sptr->user->username, sptr->sockhost);
+#endif
+#ifdef MAXBUFFERS
+ /* give them server-sized socket buffers, throughput++ */
+ reset_sock_opts(sptr->fd, 1);
+#endif
+#if defined(FNAME_OPERLOG)
+ {
+ int logfile;
+
+ /*
+ * This conditional makes the logfile active only after it's
+ * been created - thus logging can be turned off by removing
+ * the file.
+ *
+ * stop NFS hangs...most systems should be able to open a file in
+ * 3 seconds. -avalon (curtesy of wumpus)
+ */
+ alarm(3);
+ if (IsPerson(sptr) &&
+ (logfile = open(FNAME_OPERLOG, O_WRONLY | O_APPEND)) != -1)
+ {
+ alarm(0);
+ ircsprintf(buf, "%s OPER (%s) (%s) by (%s!%s@%s)\n",
+ myctime(timeofday), name, encr,
+ parv[0], sptr->user->username,
+ sptr->sockhost);
+ alarm(3);
+ write(logfile, buf, strlen(buf));
+ alarm(0);
+ close(logfile);
+ }
+ alarm(0);
+ /* Modification by pjg */
+ }
+#endif
+ }
+ else
+ {
+ sendto_one(sptr, err_str(ERR_PASSWDMISMATCH), me.name, parv[0]);
+#ifdef FAILED_OPER_NOTICE
+ sendto_realops("Failed OPER attempt by %s (%s@%s)",
+ parv[0], sptr->user->username, sptr->sockhost);
+#endif
+ }
+ return 0;
+}
+
+/***************************************************************************
+ * m_pass() - Added Sat, 4 March 1989
+ ***************************************************************************/
+/*
+ * m_pass
+ * parv[0] = sender prefix
+ * parv[1] = password
+ * parv[2] = optional extra version information
+ */
+int
+m_pass(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ char *password = parc > 1 ? parv[1] : NULL;
+
+ if (BadPtr(password))
+ {
+ sendto_one(cptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "PASS");
+ return 0;
+ }
+ if (!MyConnect(sptr) || (!IsUnknown(cptr) && !IsHandshake(cptr)))
+ {
+ sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]);
+ return 0;
+ }
+ strncpyzt(cptr->passwd, password, sizeof(cptr->passwd));
+ if (parc > 2)
+ {
+ int l = strlen(parv[2]);
+
+ if (l < 2)
+ return 0;
+ if (parv[2][0] == 'T' && parv[2][1] == 'S')
+ cptr->tsinfo = (ts_val) TS_DOESTS;
+ }
+ return 0;
+}
+
+/*
+ * m_userhost added by Darren Reed 13/8/91 to aid clients and reduce
+ * the need for complicated requests like WHOIS. It returns user/host
+ * information only (no spurious AWAY labels or channels).
+ */
+int
+m_userhost(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ char *s, *p = NULL;
+ aClient *acptr;
+ int i, len, res = 0;
+
+ ircsprintf(buf, rpl_str(RPL_USERHOST), me.name, parv[0]);
+ len = strlen(buf);
+
+ for (i = 5, s = strtoken(&p, parv[1], " "); i && s;
+ s = strtoken(&p, (char *) NULL, " "), i--)
+ if ((acptr = find_person(s, NULL)))
+ {
+ if (++res > 1)
+ buf[len++] = ' ';
+ len += ircsnprintf(buf + len, sizeof(buf) - (len + 1),
+ "%s%s=%c%s@%s", acptr->name,
+ IsAnOper(acptr) ? "*" : "",
+ (acptr->user->away) ? '-' : '+',
+ acptr->user->username, acptr->user->host);
+ }
+ sendto_one(sptr, "%s", buf);
+ return 0;
+}
+
+int
+m_userip(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ char *s, *p = NULL;
+ aClient *acptr;
+ int i, len, res = 0;
+
+ if(!IsAnOper(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+ ircsprintf(buf, rpl_str(RPL_USERHOST), me.name, parv[0]);
+ len = strlen(buf);
+
+ for (i = 5, s = strtoken(&p, parv[1], " "); i && s;
+ s = strtoken(&p, (char *) NULL, " "), i--)
+ if ((acptr = find_person(s, NULL)))
+ {
+ if (++res > 1)
+ buf[len++] = ' ';
+ len += ircsnprintf(buf + len, sizeof(buf) - (len + 1),
+ "%s%s=%c%s@%s", acptr->name,
+ IsAnOper(acptr) ? "*" : "",
+ (acptr->user->away) ? '-' : '+',
+ acptr->user->username,
+ IsULine(acptr) ? "0.0.0.0" : acptr->hostip);
+ }
+ sendto_one(sptr, "%s", buf);
+ return 0;
+}
+
+/*
+ * m_ison added by Darren Reed 13/8/91 to act as an efficent user
+ * indicator with respect to cpu/bandwidth used. Implemented for NOTIFY
+ * feature in clients. Designed to reduce number of whois requests. Can
+ * process nicknames in batches as long as the maximum buffer length.
+ *
+ * format: ISON :nicklist
+ */
+/* Take care of potential nasty buffer overflow problem -Dianora */
+
+int
+m_ison(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aClient *acptr;
+ char *s, **pav = parv;
+ char *p = (char *) NULL;
+ int len, len2;
+
+ if (parc < 2)
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "ISON");
+ return 0;
+ }
+
+ ircsprintf(buf, rpl_str(RPL_ISON), me.name, *parv);
+ len = strlen(buf);
+ if (!IsOper(cptr))
+ cptr->priority += 20; /* this keeps it from moving to 'busy' list */
+ for (s = strtoken(&p, *++pav, " "); s;
+ s = strtoken(&p, (char *) NULL, " "))
+ if ((acptr = find_person(s, NULL)))
+ {
+ len2 = strlen(acptr->name);
+ if ((len + len2 + 5) < sizeof(buf)) /* make sure can never */
+ { /* overflow */
+ strcat(buf, acptr->name);
+ len += len2;
+ strcat(buf, " ");
+ len++;
+ }
+ else
+ break;
+ }
+ sendto_one(sptr, "%s", buf);
+ return 0;
+}
+
+/*
+ * m_umode() added 15/10/91 By Darren Reed.
+ * parv[0] - sender
+ * parv[1] - username to change mode for
+ * parv[2] - modes to change
+ */
+int
+m_umode(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ int flag, *s, setflags, what = MODE_ADD, badflag = NO;
+ char **p, *m;
+ aClient *acptr;
+
+ if (parc < 2)
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "MODE");
+ return 0;
+ }
+
+ if(IsServer(sptr))
+ return 0;
+
+ if (!(acptr = find_person(parv[1], NULL)))
+ {
+ if (MyConnect(sptr))
+ sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0],
+ parv[1]);
+ return 0;
+ }
+
+ if ((sptr != acptr) || (acptr->from != sptr->from))
+ {
+ sendto_one(sptr, err_str(ERR_USERSDONTMATCH), me.name, parv[0]);
+ return 0;
+ }
+
+
+ if (parc < 3)
+ {
+ m = buf;
+ *m++ = '+';
+ for (s = user_modes; (flag = *s) && (m - buf < BUFSIZE - 4); s += 2)
+ {
+ if (sptr->umode & (flag & ALL_UMODES))
+ *m++ = (char) (*(s + 1));
+ }
+ *m = '\0';
+ sendto_one(sptr, rpl_str(RPL_UMODEIS), me.name, parv[0], buf);
+ return 0;
+ }
+
+ /* find flags already set for user */
+ setflags = 0;
+ for (s = user_modes; (flag = *s); s += 2)
+ if (sptr->umode & flag)
+ setflags |= flag;
+ /* parse mode change string(s) */
+ for (p = &parv[2]; p && *p; p++)
+ for (m = *p; *m; m++)
+ switch (*m)
+ {
+ case '+':
+ what = MODE_ADD;
+ break;
+ case '-':
+ what = MODE_DEL;
+ break;
+ /* we may not get these, but they shouldnt be in default */
+ case ' ':
+ case '\r':
+ case '\n':
+ case '\t':
+ break;
+ case 'r':
+ case 'x':
+ case 'X':
+ break; /* users can't set themselves +r,+x, or +X! */
+ case 'A':
+ /* set auto +a if user is setting +A */
+ if (MyClient(sptr) && (what == MODE_ADD))
+ sptr->umode |= UMODE_a;
+ default:
+ for (s = user_modes; (flag = *s); s += 2)
+ if (*m == (char) (*(s + 1)))
+ {
+ if (what == MODE_ADD)
+ sptr->umode |= flag;
+ else
+ sptr->umode &= ~flag;
+ break;
+ }
+ if (flag == 0 && MyConnect(sptr))
+ badflag = YES;
+ break;
+ }
+
+ if (badflag)
+ sendto_one(sptr, err_str(ERR_UMODEUNKNOWNFLAG), me.name, parv[0]);
+
+ /* stop users making themselves operators too easily */
+ if (!(setflags & UMODE_o) && IsOper(sptr) && !IsServer(cptr))
+ ClearOper(sptr);
+
+ if (!(setflags & UMODE_O) && IsLocOp(sptr) && !IsServer(cptr))
+ sptr->umode &= ~UMODE_O;
+
+ if ((setflags & (UMODE_o | UMODE_O)) && !IsAnOper(sptr) && MyConnect(sptr))
+ {
+ set_effective_class(sptr);
+ sptr->oflag = 0;
+ }
+
+ if (!(setflags & (UMODE_o | UMODE_O)) && IsAnOper(sptr))
+ Count.oper++;
+
+ if ((setflags & (UMODE_o | UMODE_O)) && !IsAnOper(sptr))
+ {
+ Count.oper--;
+ if (MyConnect(sptr))
+ {
+ remove_from_list(&oper_list, sptr, NULL);
+
+ /*
+ * Now that the user is no longer opered, let's return
+ * them back to the appropriate Y:class -srd
+ */
+ sptr->user->oper->opers--;
+ sptr->user->oper = NULL;
+ set_effective_class(sptr);
+ }
+ }
+
+ if (!(setflags & UMODE_i) && IsInvisible(sptr))
+ Count.invisi++;
+ if ((setflags & UMODE_i) && !IsInvisible(sptr))
+ Count.invisi--;
+
+ /*
+ * compare new flags with old flags and send string which will cause
+ * servers to update correctly.
+ */
+ if (!IsAnOper(sptr) && !IsServer(cptr))
+ {
+ sptr->umode &= ~OPER_UMODES;
+#ifdef NO_USER_SERVERKILLS
+ sptr->umode &= ~UMODE_k;
+#endif
+#ifdef NO_USER_OPERKILLS
+ sptr->umode &= ~UMODE_s;
+#endif
+ }
+ if(MyClient(sptr))
+ {
+ if (IsAdmin(sptr) && !OPIsAdmin(sptr)) ClearAdmin(sptr);
+ if (IsSAdmin(sptr) && !OPIsSAdmin(sptr)) ClearSAdmin(sptr);
+ if (IsUmodef(sptr) && !OPCanUModef(sptr)) ClearUmodef(sptr);
+ if (IsUmodec(sptr) && !OPCanUModec(sptr)) ClearUmodec(sptr);
+ if (IsUmodej(sptr) && !OPCanUModec(sptr)) ClearUmodej(sptr);
+ if (IsUmodey(sptr) && !OPCanUModey(sptr)) ClearUmodey(sptr);
+ if (IsUmoded(sptr) && !OPCanUModed(sptr)) ClearUmoded(sptr);
+ if (IsUmodeb(sptr) && !OPCanUModeb(sptr)) ClearUmodeb(sptr);
+ if (NoMsgThrottle(sptr) && !OPCanUModeF(sptr)) ClearNoMsgThrottle(sptr);
+#ifdef ALLOW_HIDDEN_OPERS
+# ifdef FORCE_EVERYONE_HIDDEN
+ sptr->umode |= UMODE_I;
+# else
+# if (RIDICULOUS_PARANOIA_LEVEL>=1)
+ if (IsUmodeI(sptr) && !(sptr->user->real_oper_host || IsAnOper(sptr)))
+ ClearUmodeI(sptr);
+# endif
+
+# ifdef FORCE_OPERS_HIDDEN
+ if (IsAnOper(sptr)
+# if (RIDICULOUS_PARANOIA_LEVEL>=1)
+ || (sptr->user->real_oper_host != NULL)
+# endif
+ ) sptr->umode |= UMODE_I;
+# endif /* FORCE_OPERS_HIDDEN */
+# endif /* FORCE_EVERYONE_HIDDEN */
+#else /* ALLOW_HIDDEN_OPERS */
+ if (IsUmodeI(sptr)) ClearUmodeI(sptr);
+#endif
+ if (sptr->user->allow->flags & CONF_FLAGS_FORCEFLOOD)
+ SetNoMsgThrottle(sptr);
+ }
+ send_umode_out(cptr, sptr, setflags);
+
+ return 0;
+}
+
+/* send the MODE string for user (user) to connection cptr -avalon */
+void
+send_umode(aClient *cptr, aClient *sptr, int old, int sendmask, char *umode_buf)
+{
+ int *s, flag, what = MODE_NULL;
+ char *m;
+
+ /*
+ * build a string in umode_buf to represent the change in the user's
+ * mode between the new (sptr->flag) and 'old'.
+ */
+ m = umode_buf;
+ *m = '\0';
+ for (s = user_modes; (flag = *s); s += 2)
+ {
+ if (MyClient(sptr) && !(flag & sendmask))
+ continue;
+ if ((flag & old) && !(sptr->umode & flag))
+ {
+ if (what == MODE_DEL)
+ *m++ = *(s + 1);
+ else
+ {
+ what = MODE_DEL;
+ *m++ = '-';
+ *m++ = *(s + 1);
+ }
+ }
+ else if (!(flag & old) && (sptr->umode & flag))
+ {
+ if (what == MODE_ADD)
+ *m++ = *(s + 1);
+ else
+ {
+ what = MODE_ADD;
+ *m++ = '+';
+ *m++ = *(s + 1);
+ }
+ }
+ }
+ *m = '\0';
+ if (*umode_buf && cptr)
+ sendto_one(cptr, ":%s MODE %s :%s", sptr->name, sptr->name, umode_buf);
+}
+
+/* Shadowfax's FLUD code */
+#ifdef FLUD
+void
+announce_fluder(aClient *fluder, aClient *cptr, aChannel *chptr, int type)
+{
+ char *fludee;
+
+ if (cptr)
+ fludee = cptr->name;
+ else
+ fludee = chptr->chname;
+
+ sendto_realops_lev(FLOOD_LEV, "Flooder %s [%s@%s] on %s target: %s",
+ fluder->name, fluder->user->username, fluder->user->host,
+ fluder->user->server, fludee);
+}
+
+/*
+ * This is really just a "convenience" function. I can only keep three
+ * or * four levels of pointer dereferencing straight in my head. This
+ * remove * an entry in a fluders list. Use this when working on a
+ * fludees list :)
+ */
+struct fludbot *
+remove_fluder_reference(struct fludbot **fluders, aClient *fluder)
+{
+ struct fludbot *current, *prev, *next;
+
+ prev = NULL;
+ current = *fluders;
+ while (current)
+ {
+ next = current->next;
+ if (current->fluder == fluder)
+ {
+ if (prev)
+ prev->next = next;
+ else
+ *fluders = next;
+
+ BlockHeapFree(free_fludbots, current);
+ }
+ else
+ prev = current;
+ current = next;
+ }
+ return (*fluders);
+}
+
+/* Another function to unravel my mind. */
+Link *
+remove_fludee_reference(Link **fludees, void *fludee)
+{
+ Link *current, *prev, *next;
+
+ prev = NULL;
+ current = *fludees;
+ while (current)
+ {
+ next = current->next;
+ if (current->value.cptr == (aClient *) fludee)
+ {
+ if (prev)
+ prev->next = next;
+ else
+ *fludees = next;
+
+ BlockHeapFree(free_Links, current);
+ }
+ else
+ prev = current;
+ current = next;
+ }
+ return (*fludees);
+}
+
+int
+check_for_fludblock(aClient *fluder, aClient *cptr, aChannel *chptr, int type)
+{
+ time_t now;
+ int blocking;
+
+ /* If it's disabled, we don't need to process all of this */
+ if ((confopts & FLAGS_HUB) || (flud_block == 0))
+ return 0;
+
+ /* It's either got to be a client or a channel being fluded */
+ if ((cptr == NULL) && (chptr == NULL))
+ return 0;
+
+ if (cptr && !MyFludConnect(cptr))
+ {
+ sendto_ops("check_for_fludblock() called for non-local client");
+ return 0;
+ }
+
+ /* Are we blocking fluds at this moment? */
+ time(&now);
+ if (cptr)
+ blocking = (cptr->fludblock > (now - flud_block));
+ else
+ blocking = (chptr->fludblock > (now - flud_block));
+
+ return (blocking);
+}
+
+int
+check_for_flud(aClient *fluder, aClient *cptr, aChannel *chptr, int type)
+{
+ time_t now;
+ struct fludbot *current, *prev, *next;
+ int blocking, count, found;
+ Link *newfludee;
+
+ /* If it's disabled, we don't need to process all of this */
+ if ((confopts & (FLAGS_HUB|FLAGS_SERVHUB)) || (flud_block == 0))
+ return 0;
+
+ /* It's either got to be a client or a channel being fluded */
+ if ((cptr == NULL) && (chptr == NULL))
+ return 0;
+
+ if (cptr && !MyFludConnect(cptr))
+ {
+ sendto_ops("check_for_flud() called for non-local client");
+ return 0;
+ }
+
+ /* Are we blocking fluds at this moment? */
+ time(&now);
+ if (cptr)
+ blocking = (cptr->fludblock > (now - flud_block));
+ else
+ blocking = (chptr->fludblock > (now - flud_block));
+
+ /* Collect the Garbage */
+ if (!blocking)
+ {
+ if (cptr)
+ current = cptr->fluders;
+ else
+ current = chptr->fluders;
+ prev = NULL;
+ while (current)
+ {
+ next = current->next;
+ if (current->last_msg < (now - flud_time))
+ {
+ if (cptr)
+ remove_fludee_reference(¤t->fluder->fludees,
+ (void *) cptr);
+ else
+ remove_fludee_reference(¤t->fluder->fludees,
+ (void *) chptr);
+ if (prev)
+ prev->next = current->next;
+ else if (cptr)
+ cptr->fluders = current->next;
+ else
+ chptr->fluders = current->next;
+ BlockHeapFree(free_fludbots, current);
+ }
+ else
+ prev = current;
+ current = next;
+ }
+ }
+ /*
+ * Find or create the structure for the fluder, and update the
+ * counter * and last_msg members. Also make a running total count
+ */
+ if (cptr)
+ current = cptr->fluders;
+ else
+ current = chptr->fluders;
+ count = found = 0;
+ while (current)
+ {
+ if (current->fluder == fluder)
+ {
+ current->last_msg = now;
+ current->count++;
+ found = 1;
+ }
+ if (current->first_msg < (now - flud_time))
+ count++;
+ else
+ count += current->count;
+ current = current->next;
+ }
+ if (!found)
+ {
+ if ((current = BlockHeapALLOC(free_fludbots, struct fludbot)) != NULL)
+ {
+ current->fluder = fluder;
+ current->count = 1;
+ current->first_msg = now;
+ current->last_msg = now;
+ if (cptr)
+ {
+ current->next = cptr->fluders;
+ cptr->fluders = current;
+ }
+ else
+ {
+ current->next = chptr->fluders;
+ chptr->fluders = current;
+ }
+
+ count++;
+
+ if ((newfludee = BlockHeapALLOC(free_Links, Link)) != NULL)
+ {
+ if (cptr)
+ {
+ newfludee->flags = 0;
+ newfludee->value.cptr = cptr;
+ }
+ else
+ {
+ newfludee->flags = 1;
+ newfludee->value.chptr = chptr;
+ }
+ newfludee->next = fluder->fludees;
+ fluder->fludees = newfludee;
+ }
+ else
+ outofmemory();
+ /*
+ * If we are already blocking now, we should go ahead * and
+ * announce the new arrival
+ */
+ if (blocking)
+ announce_fluder(fluder, cptr, chptr, type);
+ }
+ else
+ outofmemory();
+ }
+ /*
+ * Okay, if we are not blocking, we need to decide if it's time to *
+ * begin doing so. We already have a count of messages received in *
+ * the last flud_time seconds
+ */
+ if (!blocking && (count > flud_num))
+ {
+ blocking = 1;
+ ircstp->is_flud++;
+ /*
+ * if we are going to say anything to the fludee, now is the *
+ * time to mention it to them.
+ */
+ if (cptr)
+ sendto_one(cptr,
+ ":%s NOTICE %s :*** Notice -- Server flood protection "
+ "activated for %s", me.name, cptr->name, cptr->name);
+ else
+ sendto_channel_butserv(chptr, &me,
+ ":%s NOTICE %s :*** Notice -- Server "
+ "flood protection activated for %s",
+ me.name, chptr->chname, chptr->chname);
+ /*
+ * Here we should go back through the existing list of * fluders
+ * and announce that they were part of the game as * well.
+ */
+ if (cptr)
+ current = cptr->fluders;
+ else
+ current = chptr->fluders;
+ while (current)
+ {
+ announce_fluder(current->fluder, cptr, chptr, type);
+ current = current->next;
+ }
+ }
+ /*
+ * update blocking timestamp, since we received a/another CTCP
+ * message
+ */
+ if (blocking)
+ {
+ if (cptr)
+ cptr->fludblock = now;
+ else
+ chptr->fludblock = now;
+ }
+ return (blocking);
+}
+
+void
+free_fluders(aClient *cptr, aChannel *chptr)
+{
+ struct fludbot *fluders, *next;
+
+ if ((cptr == NULL) && (chptr == NULL))
+ {
+ sendto_ops("free_fluders(NULL, NULL)");
+ return;
+ }
+
+ if (cptr && !MyFludConnect(cptr))
+ return;
+
+ if (cptr)
+ fluders = cptr->fluders;
+ else
+ fluders = chptr->fluders;
+
+ while (fluders)
+ {
+ next = fluders->next;
+
+ if (cptr)
+ remove_fludee_reference(&fluders->fluder->fludees, (void *) cptr);
+ else
+ remove_fludee_reference(&fluders->fluder->fludees, (void *) chptr);
+
+ BlockHeapFree(free_fludbots, fluders);
+ fluders = next;
+ }
+}
+
+void
+free_fludees(aClient *badguy)
+{
+ Link *fludees, *next;
+
+ if (badguy == NULL)
+ {
+ sendto_ops("free_fludees(NULL)");
+ return;
+ }
+ fludees = badguy->fludees;
+ while (fludees)
+ {
+ next = fludees->next;
+
+ if (fludees->flags)
+ remove_fluder_reference(&fludees->value.chptr->fluders, badguy);
+ else
+ {
+ if (!MyFludConnect(fludees->value.cptr))
+ sendto_ops("free_fludees() encountered non-local client");
+ else
+ remove_fluder_reference(&fludees->value.cptr->fluders, badguy);
+ }
+
+ BlockHeapFree(free_Links, fludees);
+ fludees = next;
+ }
+}
+#endif /* FLUD */
+
+
+int del_silence(aClient *sptr, char *mask)
+{
+ Link **lp, *tmp;
+ for (lp=&(sptr->user->silence);*lp;lp=&((*lp)->next))
+ if (mycmp(mask, (*lp)->value.cp)==0)
+ {
+ tmp = *lp;
+ *lp = tmp->next;
+ MyFree(tmp->value.cp);
+ free_link(tmp);
+ return 0;
+ }
+ return 1;
+}
+
+static int add_silence(aClient *sptr,char *mask)
+{
+ Link *lp;
+ int cnt=0, len=0;
+ for (lp=sptr->user->silence;lp;lp=lp->next)
+ {
+ len += strlen(lp->value.cp);
+ if (MyClient(sptr))
+ {
+ if ((len > MAXSILELENGTH) || (++cnt >= MAXSILES))
+ {
+ sendto_one(sptr, err_str(ERR_SILELISTFULL), me.name,
+ sptr->name, mask);
+ return -1;
+ }
+ else
+ {
+ if (!match(lp->value.cp, mask))
+ return -1;
+ }
+ }
+ else if (!mycmp(lp->value.cp, mask))
+ return -1;
+ }
+ lp = make_link();
+ lp->next = sptr->user->silence;
+ lp->value.cp = (char *)MyMalloc(strlen(mask)+1);
+ strcpy(lp->value.cp, mask);
+ sptr->user->silence = lp;
+ return 0;
+}
+
+/* m_silence
+ * parv[0] = sender prefix
+ * From local client:
+ * parv[1] = mask (NULL sends the list)
+ * From remote client:
+ * parv[1] = nick that must be silenced
+ * parv[2] = mask
+ */
+int
+m_silence(aClient *cptr,aClient *sptr,int parc,char *parv[])
+{
+ Link *lp;
+ aClient *acptr=NULL;
+ char c, *cp;
+
+ if (check_registered_user(sptr))
+ return 0;
+
+ if (MyClient(sptr))
+ {
+ acptr = sptr;
+ if (parc < 2 || *parv[1]=='\0' || (acptr = find_person(parv[1], NULL)))
+ {
+ if (!(acptr->user))
+ return 0;
+
+ for (lp = acptr->user->silence; lp; lp = lp->next)
+ sendto_one(sptr, rpl_str(RPL_SILELIST), me.name,
+ sptr->name, acptr->name, lp->value.cp);
+
+ sendto_one(sptr, rpl_str(RPL_ENDOFSILELIST), me.name, acptr->name);
+ return 0;
+ }
+ cp = parv[1];
+ c = *cp;
+ if (c=='-' || c=='+')
+ cp++;
+ else if (!(strchr(cp, '@') || strchr(cp, '.') ||
+ strchr(cp, '!') || strchr(cp, '*')))
+ {
+ sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0],
+ parv[1]);
+ return 0;
+ }
+ else c = '+';
+ cp = pretty_mask(cp);
+ if ((c=='-' && !del_silence(sptr,cp)) ||
+ (c!='-' && !add_silence(sptr,cp)))
+ {
+ sendto_prefix_one(sptr, sptr, ":%s SILENCE %c%s", parv[0], c, cp);
+ if (c=='-')
+ sendto_serv_butone(NULL, ":%s SILENCE * -%s", sptr->name, cp);
+ }
+ }
+ else if (parc < 3 || *parv[2]=='\0')
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0],
+ "SILENCE");
+ return -1;
+ }
+ else if ((c = *parv[2])=='-' || (acptr = find_person(parv[1], NULL)))
+ {
+ if (c=='-')
+ {
+ if (!del_silence(sptr,parv[2]+1))
+ sendto_serv_butone(cptr, ":%s SILENCE %s :%s",
+ parv[0], parv[1], parv[2]);
+ }
+ else
+ {
+ add_silence(sptr,parv[2]);
+ if (!MyClient(acptr))
+ sendto_one(acptr, ":%s SILENCE %s :%s",
+ parv[0], parv[1], parv[2]);
+ }
+ }
+ else
+ {
+ sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], parv[1]);
+ return 0;
+ }
+ return 0;
+}
+
+static int
+add_dccallow(aClient *sptr, aClient *optr)
+{
+ Link *lp;
+ int cnt = 0;
+
+ for(lp = sptr->user->dccallow; lp; lp = lp->next)
+ {
+ if(lp->flags != DCC_LINK_ME)
+ continue;
+ if(++cnt >= MAXDCCALLOW)
+ {
+ sendto_one(sptr, err_str(ERR_TOOMANYDCC), me.name, sptr->name,
+ optr->name, MAXDCCALLOW);
+ return 0;
+ }
+ else if(lp->value.cptr == optr)
+ return 0;
+ }
+
+ lp = make_link();
+ lp->value.cptr = optr;
+ lp->flags = DCC_LINK_ME;
+ lp->next = sptr->user->dccallow;
+ sptr->user->dccallow = lp;
+
+ lp = make_link();
+ lp->value.cptr = sptr;
+ lp->flags = DCC_LINK_REMOTE;
+ lp->next = optr->user->dccallow;
+ optr->user->dccallow = lp;
+
+ sendto_one(sptr, rpl_str(RPL_DCCSTATUS), me.name, sptr->name, optr->name,
+ "added to");
+ return 0;
+}
+
+static int
+del_dccallow(aClient *sptr, aClient *optr)
+{
+ Link **lpp, *lp;
+ int found = 0;
+
+ for (lpp = &(sptr->user->dccallow); *lpp; lpp=&((*lpp)->next))
+ {
+ if((*lpp)->flags != DCC_LINK_ME)
+ continue;
+
+ if((*lpp)->value.cptr == optr)
+ {
+ lp = *lpp;
+ *lpp = lp->next;
+ free_link(lp);
+ found++;
+ break;
+ }
+ }
+
+ if(!found)
+ {
+ sendto_one(sptr, ":%s %d %s :%s is not in your DCC allow list",
+ me.name, RPL_DCCINFO, sptr->name, optr->name);
+ return 0;
+ }
+
+ for (found = 0, lpp = &(optr->user->dccallow); *lpp; lpp=&((*lpp)->next))
+ {
+ if((*lpp)->flags != DCC_LINK_REMOTE)
+ continue;
+
+ if((*lpp)->value.cptr == sptr)
+ {
+ lp = *lpp;
+ *lpp = lp->next;
+ free_link(lp);
+ found++;
+ break;
+ }
+ }
+
+ if(!found)
+ sendto_realops_lev(DEBUG_LEV, "%s was in dccallowme list of %s but "
+ "not in dccallowrem list!", optr->name, sptr->name);
+
+ sendto_one(sptr, rpl_str(RPL_DCCSTATUS), me.name, sptr->name, optr->name,
+ "removed from");
+
+ return 0;
+}
+
+int
+m_dccallow(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ Link *lp;
+ char *p, *s;
+ char *cn;
+ aClient *acptr, *lastcptr = NULL;
+ int didlist = 0, didhelp = 0, didanything = 0;
+ char **ptr;
+ static char *dcc_help[] =
+ {
+ "/DCCALLOW [<+|->nick[,<+|->nick, ...]] [list] [help]",
+ "You may allow DCCs of filetypes which are otherwise blocked by "
+ "the IRC server",
+ "by specifying a DCC allow for the user you want to recieve files "
+ "from.",
+ "For instance, to allow the user bob to send you file.exe, you "
+ "would type:",
+ "/dccallow +bob",
+ "and bob would then be able to send you files. bob will have to "
+ "resend the file",
+ "if the server gave him an error message before you added him to "
+ "your allow list.",
+ "/dccallow -bob",
+ "Will do the exact opposite, removing him from your dcc allow "
+ "list.",
+ "/dccallow list",
+ "Will list the users currently on your dcc allow list.",
+ NULL
+ };
+
+ if(!MyClient(sptr))
+ return 0;
+
+ if(parc < 2)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :No command specified for DCCALLOW. "
+ "Type /dccallow help for more information.", me.name,
+ sptr->name);
+ return 0;
+ }
+
+ for (p = NULL, s = strtoken(&p, parv[1], ", "); s;
+ s = strtoken(&p, NULL, ", "))
+ {
+ if(*s == '+')
+ {
+ didanything++;
+ cn = s + 1;
+ if(*cn == '\0')
+ continue;
+
+ acptr = find_person(cn, NULL);
+
+ if(acptr == sptr) continue;
+
+ if(!acptr)
+ {
+ sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name,
+ sptr->name, cn);
+ continue;
+ }
+
+ if(lastcptr == acptr)
+ sendto_realops_lev(SPY_LEV, "User %s (%s@%s) may be flooding "
+ "dccallow: add %s", sptr->name,
+ sptr->user->username, sptr->user->host,
+ acptr->name);
+ lastcptr = acptr;
+ add_dccallow(sptr, acptr);
+ }
+ else if(*s == '-')
+ {
+ didanything++;
+ cn = s + 1;
+ if(*cn == '\0')
+ continue;
+
+ acptr = find_person(cn, NULL);
+ if(acptr == sptr)
+ continue;
+
+ if(!acptr)
+ {
+ sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name,
+ sptr->name, cn);
+ continue;
+ }
+
+ if(lastcptr == acptr)
+ sendto_realops_lev(SPY_LEV, "User %s (%s@%s) may be flooding "
+ "dccallow: del %s", sptr->name,
+ sptr->user->username, sptr->user->host,
+ acptr->name);
+
+ lastcptr = acptr;
+ del_dccallow(sptr, acptr);
+ }
+ else
+ {
+ if(!didlist && myncmp(s, "list", 4) == 0)
+ {
+ didanything++;
+ didlist++;
+ sendto_one(sptr, ":%s %d %s :The following users are on your "
+ "dcc allow list:", me.name, RPL_DCCINFO,
+ sptr->name);
+ for(lp = sptr->user->dccallow; lp; lp = lp->next)
+ {
+ if(lp->flags == DCC_LINK_REMOTE)
+ continue;
+ sendto_one(sptr, ":%s %d %s :%s (%s@%s)", me.name,
+ RPL_DCCLIST, sptr->name, lp->value.cptr->name,
+ lp->value.cptr->user->username,
+ lp->value.cptr->user->host);
+ }
+ sendto_one(sptr, rpl_str(RPL_ENDOFDCCLIST), me.name,
+ sptr->name, s);
+ }
+ else if(!didhelp && myncmp(s, "help", 4) == 0)
+ {
+ didanything++;
+ didhelp++;
+ for(ptr = dcc_help; *ptr; ptr++)
+ sendto_one(sptr, ":%s %d %s :%s", me.name, RPL_DCCINFO,
+ sptr->name, *ptr);
+ sendto_one(sptr, rpl_str(RPL_ENDOFDCCLIST), me.name,
+ sptr->name, s);
+ }
+ }
+ }
+
+ if(!didanything)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :Invalid syntax for DCCALLOW. Type "
+ "/dccallow help for more information.", me.name,
+ sptr->name);
+ return 0;
+ }
+
+ return 0;
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/sbuf.c
+ * Copyright (C) 2004 David Parton
+ *
+ * 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 1, 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.
+ *
+ * $Id: sbuf.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $
+ */
+
+#include "sbuf.h"
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern void outofmemory(void);
+
+typedef struct _SBuffer
+{
+ struct _SBuffer *next;
+ int shared;
+ int bufsize;
+ int refcount;
+ char *end;
+} SBuffer;
+
+typedef struct _SBufBlock
+{
+ int num;
+ SBuffer* bufs;
+ struct _SBufBlock *next;
+} SBufBlock;
+
+typedef struct _SBufUser
+{
+ char *start;
+ SBuffer *buf;
+ struct _SBufUser *next;
+} SBufUser;
+
+typedef struct _SBufUserBlock
+{
+ int num;
+ SBufUser *users;
+ struct _SBufUserBlock *next;
+} SBufUserBlock;
+
+SBuffer *largesbuf_pool = NULL, *smallsbuf_pool = NULL;
+SBufUser *user_pool = NULL;
+SBufBlock *sbuf_blocks = NULL;
+SBufUserBlock *sbufuser_blocks = NULL;
+int sbufuser_total = 0, sbufuser_used = 0;
+int sbufsmall_total = 0, sbufsmall_used = 0;
+int sbuflarge_total = 0, sbuflarge_used = 0;
+int sbufblock_used = 0, sbufuserblock_used = 0;
+
+#define SBUF_BASE sizeof(SBuffer)
+#define SBUF_LARGE_TOTAL (SBUF_BASE + SBUF_LARGE_BUFFER)
+#define SBUF_SMALL_TOTAL (SBUF_BASE + SBUF_SMALL_BUFFER)
+
+void sbuf_count(int* userUsed, int* userTotal, int* userSize,
+ int* smallUsed, int* smallTotal, int* smallSize,
+ int* largeUsed, int* largeTotal, int* largeSize,
+ int* blockUsed, int* blockSize, int* userblockUsed, int* userblockSize)
+{
+ *userUsed = sbufuser_used;
+ *userTotal = sbufuser_total;
+ *userSize = sizeof(SBufUser);
+
+ *smallUsed = sbufsmall_used;
+ *smallTotal = sbufsmall_total;
+ *smallSize = SBUF_SMALL_TOTAL;
+
+ *largeUsed = sbuflarge_used;
+ *largeTotal = sbuflarge_total;
+ *largeSize = SBUF_LARGE_TOTAL;
+
+ *blockUsed = sbufblock_used;
+ *blockSize = sizeof(SBufBlock);
+
+ *userblockUsed = sbufuserblock_used;
+ *userblockSize = sizeof(SBufUserBlock);
+}
+
+
+int sbuf_allocblock_general(int theMemorySize, int num, SBuffer** thePool)
+{
+ SBufBlock* block;
+ SBuffer* bufs;
+ int i;
+
+ block = (SBufBlock*)malloc(sizeof(SBufBlock));
+ if (!block)
+ outofmemory();
+
+ block->bufs = (SBuffer*)malloc(theMemorySize * num);
+ if (!block->bufs)
+ outofmemory();
+
+ block->num = num;
+ block->next = sbuf_blocks;
+ sbuf_blocks = block;
+ sbufblock_used++;
+
+ bufs = block->bufs;
+ for (i = 0; i < block->num - 1; ++i)
+ {
+ bufs->bufsize = theMemorySize - SBUF_BASE;
+ bufs->next = (SBuffer*)(((char*)bufs) + theMemorySize);
+ bufs = bufs->next;
+ }
+ bufs->bufsize = theMemorySize - SBUF_BASE;
+ bufs->next = *thePool;
+ *thePool = block->bufs;
+
+ return 0;
+}
+
+int sbuf_allocblock_small(int theMemorySize)
+{
+ if (theMemorySize % SBUF_SMALL_TOTAL != 0)
+ theMemorySize = (theMemorySize + SBUF_SMALL_TOTAL);
+
+ sbufsmall_total += theMemorySize / SBUF_SMALL_TOTAL;
+
+ return sbuf_allocblock_general(SBUF_SMALL_TOTAL, theMemorySize / SBUF_SMALL_TOTAL, &smallsbuf_pool);
+}
+
+int sbuf_allocblock_large(int theMemorySize)
+{
+ if (theMemorySize % SBUF_LARGE_TOTAL != 0)
+ theMemorySize = (theMemorySize + SBUF_LARGE_TOTAL);
+
+ sbuflarge_total += theMemorySize / SBUF_LARGE_TOTAL;
+
+ return sbuf_allocblock_general(SBUF_LARGE_TOTAL, theMemorySize / SBUF_LARGE_TOTAL, &largesbuf_pool);
+}
+
+int sbuf_allocblock_users(int theCount)
+{
+ SBufUserBlock* block;
+ SBufUser* users;
+ int i;
+
+ block = (SBufUserBlock*)malloc(sizeof(SBufUserBlock));
+ if (!block)
+ outofmemory();
+
+ block->users = (SBufUser*)malloc(sizeof(SBufUser) * theCount);
+ if (!block->users)
+ outofmemory();
+
+ block->num = theCount;
+ block->next = sbufuser_blocks;
+ sbufuser_blocks = block;
+
+ sbufuserblock_used++;
+ sbufuser_total += block->num;
+
+ users = block->users;
+ for (i = 0; i < block->num - 1; ++i)
+ {
+ users->next = users+1;
+ users++;
+ }
+ users->next = user_pool;
+ user_pool = block->users;
+
+ return 0;
+}
+
+
+int sbuf_init()
+{
+ sbuf_allocblock_small(INITIAL_SBUFS_SMALL);
+ sbuf_allocblock_large(INITIAL_SBUFS_LARGE);
+ sbuf_allocblock_users(INITIAL_SBUFS_USERS);
+ return 0;
+}
+
+int sbuf_free(SBuffer* buf)
+{
+ switch (buf->bufsize)
+ {
+ case SBUF_LARGE_BUFFER:
+ buf->next = largesbuf_pool;
+ largesbuf_pool = buf;
+ sbuflarge_used--;
+ break;
+
+ case SBUF_SMALL_BUFFER:
+ buf->next = smallsbuf_pool;
+ smallsbuf_pool = buf;
+ sbufsmall_used--;
+ break;
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+int sbuf_user_free(SBufUser* user)
+{
+ user->next = user_pool;
+ user_pool = user;
+ sbufuser_used--;
+ return 0;
+}
+
+SBuffer* sbuf_alloc(int theSize)
+{
+ SBuffer* buf;
+
+ if (theSize >= SBUF_SMALL_BUFFER)
+ {
+ buf = largesbuf_pool;
+ if (!buf) {
+ sbuf_allocblock_large(INITIAL_SBUFS_LARGE);
+ buf = largesbuf_pool;
+ if (!buf) return NULL;
+ }
+ largesbuf_pool = largesbuf_pool->next;
+
+ sbuflarge_used++;
+
+ buf->bufsize = SBUF_LARGE_BUFFER;
+ buf->refcount = 0;
+ buf->end = ((char*)buf) + SBUF_BASE;
+ buf->next = NULL;
+ buf->shared = 0;
+ return buf;
+ }
+ else
+ {
+ buf = smallsbuf_pool;
+ if (!buf) {
+ sbuf_allocblock_small(INITIAL_SBUFS_SMALL);
+ buf = smallsbuf_pool;
+ if (!buf) return sbuf_alloc(SBUF_SMALL_BUFFER+1); /* attempt to substitute a large buffer instead */
+ }
+ smallsbuf_pool = smallsbuf_pool->next;
+
+ sbufsmall_used++;
+
+ buf->bufsize = SBUF_SMALL_BUFFER;
+ buf->refcount = 0;
+ buf->end = ((char*)buf) + SBUF_BASE;
+ buf->next = NULL;
+ buf->shared = 0;
+ return buf;
+ }
+}
+
+SBufUser* sbuf_user_alloc()
+{
+ SBufUser* user;
+
+ user = user_pool;
+ if (!user)
+ {
+ sbuf_allocblock_users(INITIAL_SBUFS_USERS);
+ user = user_pool;
+ if (!user) return NULL;
+ }
+ user_pool = user_pool->next;
+
+ sbufuser_used++;
+
+ user->next = NULL;
+ user->start = NULL;
+ user->buf = NULL;
+ return user;
+}
+
+
+int sbuf_alloc_error()
+{
+ outofmemory();
+ return -1;
+}
+
+/* Global functions */
+
+int sbuf_begin_share(const char* theData, int theLength, void **thePtr)
+{
+ SBuffer *s;
+
+ if (theLength > 510) theLength = 510;
+
+ s = sbuf_alloc(theLength + 2); /* +2 for the \r\n we're tacking on to the buffer */
+ if (!s || theLength + 2 > s->bufsize) return sbuf_alloc_error();
+
+ memcpy(s->end, theData, theLength);
+ s->end += theLength;
+ *s->end++ = '\r';
+ *s->end++ = '\n';
+ s->refcount = 0;
+ s->shared = 1;
+
+ *thePtr = (void*)s;
+ return 1;
+}
+
+int sbuf_end_share(void **thePtr, int theNum)
+{
+ SBuffer **shares = (SBuffer**)thePtr;
+ int i;
+
+ for (i = 0; i < theNum; ++i)
+ {
+ if (!shares[i]) continue;
+
+ shares[i]->shared = 0;
+ if (shares[i]->refcount == 0) sbuf_free(shares[i]);
+ }
+
+ return 0;
+}
+
+int sbuf_put_share(SBuf* theBuf, void* theSBuffer)
+{
+ SBufUser *user;
+ SBuffer *s = (SBuffer*)theSBuffer;
+
+ if (!s) return -1;
+
+ s->refcount++;
+ user = sbuf_user_alloc();
+ user->buf = s;
+ user->start = (char*)(user->buf) + SBUF_BASE;
+
+ if (theBuf->length == 0)
+ theBuf->head = theBuf->tail = user;
+ else
+ {
+ theBuf->tail->next = user;
+ theBuf->tail = user;
+ }
+ theBuf->length += user->buf->end - user->start;
+ return 1;
+}
+
+int sbuf_put(SBuf* theBuf, const char* theData, int theLength)
+{
+ SBufUser **user, *u;
+ int chunk;
+
+ if (theBuf->length == 0)
+ user = &theBuf->head;
+ else
+ user = &theBuf->tail;
+
+ if ((u = *user) != NULL && u->buf->refcount > 1)
+ {
+ u->next = sbuf_user_alloc();
+ u = u->next;
+ if (!u) return sbuf_alloc_error();
+ *user = u; /* tail = u */
+
+ u->buf = sbuf_alloc(theLength);
+ u->buf->refcount = 1;
+ u->start = u->buf->end;
+ }
+
+ theBuf->length += theLength;
+
+ for (; theLength > 0; user = &(u->next))
+ {
+ if ((u = *user) == NULL)
+ {
+ u = sbuf_user_alloc();
+ if (!u) return sbuf_alloc_error();
+ *user = u;
+ theBuf->tail = u;
+
+ u->buf = sbuf_alloc(theLength);
+ u->buf->refcount = 1;
+ u->start = u->buf->end;
+ }
+ chunk = (((char*)u->buf) + SBUF_BASE + u->buf->bufsize) - u->buf->end;
+ if (chunk)
+ {
+ if (chunk > theLength) chunk = theLength;
+ memcpy(u->buf->end, theData, chunk);
+
+ u->buf->end += chunk;
+ theData += chunk;
+ theLength -= chunk;
+ }
+ }
+ return 1;
+}
+
+int sbuf_delete(SBuf* theBuf, int theLength)
+{
+ if (theLength > theBuf->length) theLength = theBuf->length;
+
+ theBuf->length -= theLength;
+
+ while (theLength)
+ {
+ int chunk = theBuf->head->buf->end - theBuf->head->start;
+ if (chunk > theLength) chunk = theLength;
+
+ theBuf->head->start += chunk;
+ theLength -= chunk;
+
+ if (theBuf->head->start == theBuf->head->buf->end)
+ {
+ SBufUser *tmp = theBuf->head;
+ theBuf->head = theBuf->head->next;
+
+ tmp->buf->refcount--;
+ if (tmp->buf->refcount == 0 && tmp->buf->shared == 0)
+ sbuf_free(tmp->buf);
+ sbuf_user_free(tmp);
+ }
+ }
+ if (theBuf->head == NULL) theBuf->tail = NULL;
+
+ return 1;
+}
+
+char* sbuf_map(SBuf* theBuf, int* theLength)
+{
+ if (theBuf->length != 0)
+ {
+ *theLength = theBuf->head->buf->end - theBuf->head->start;
+ return theBuf->head->start;
+ }
+ *theLength = 0;
+ return NULL;
+}
+
+#ifdef WRITEV_IOV
+int sbuf_mapiov(SBuf *theBuf, struct iovec *iov)
+{
+ int i = 0;
+ SBufUser *sbu;
+
+ if (theBuf->length == 0)
+ return 0;
+
+ for (sbu = theBuf->head; sbu; sbu = sbu->next)
+ {
+ iov[i].iov_base = sbu->start;
+ iov[i].iov_len = sbu->buf->end - sbu->start;
+ if (++i == WRITEV_IOV)
+ break;
+ }
+
+ return i;
+}
+#endif
+
+int sbuf_flush(SBuf* theBuf)
+{
+ SBufUser *tmp;
+
+ if (theBuf->length == 0) return 0;
+
+ while (theBuf->head)
+ {
+ char *ptr = theBuf->head->start;
+ while (ptr < theBuf->head->buf->end && IsEol(*ptr)) ptr++;
+
+ theBuf->length -= ptr - theBuf->head->start;
+ theBuf->head->start = ptr;
+ if (ptr < theBuf->head->buf->end) break;
+
+ tmp = theBuf->head;
+ theBuf->head = tmp->next;
+
+ tmp->buf->refcount--;
+ if (tmp->buf->refcount == 0 && tmp->buf->shared == 0)
+ sbuf_free(tmp->buf);
+ sbuf_user_free(tmp);
+ }
+ if (theBuf->head == NULL) theBuf->tail = NULL;
+ return theBuf->length;
+}
+
+int sbuf_getmsg(SBuf* theBuf, char* theData, int theLength)
+{
+ SBufUser *user;
+ int copied;
+
+ if (sbuf_flush(theBuf) == 0) return 0;
+
+ copied = 0;
+ for (user = theBuf->head; user && theLength; user = user->next)
+ {
+ char *ptr, *max = user->start + theLength;
+ if (max > user->buf->end) max = user->buf->end;
+
+ for (ptr = user->start; ptr < max && !IsEol(*ptr); )
+ *theData++ = *ptr++;
+
+ copied += ptr - user->start;
+ theLength -= ptr - user->start;
+
+ if (ptr < max)
+ {
+ *theData = 0;
+ sbuf_delete(theBuf, copied);
+ sbuf_flush(theBuf);
+ return copied;
+ }
+ }
+ return 0;
+}
+
+int sbuf_get(SBuf* theBuf, char* theData, int theLength)
+{
+ char *buf;
+ int chunk, copied;
+
+ if (theBuf->length == 0) return 0;
+
+ copied = 0;
+ while (theLength && (buf = sbuf_map(theBuf, &chunk)) != NULL)
+ {
+ if (chunk > theLength) chunk = theLength;
+
+ memcpy(theData, buf, chunk);
+ copied += chunk;
+ theData += chunk;
+ theLength -= chunk;
+ sbuf_delete(theBuf, chunk);
+ }
+ return copied;
+}
+
+
--- /dev/null
+
+/* $Id: scache.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "h.h"
+
+static int hash(char *); /* keep it hidden here */
+/*
+ * ircd used to store full servernames in anUser as well as in the
+ * whowas info. there can be some 40k such structures alive at any
+ * given time, while the number of unique server names a server sees in
+ * its lifetime is at most a few hundred. by tokenizing server names
+ * internally, the server can easily save 2 or 3 megs of RAM.
+ * -orabidoo
+ */
+/*
+ * I could have tucked this code into hash.c I suppose but lets keep it
+ * separate for now -Dianora
+ */
+
+#define SCACHE_HASH_SIZE 257
+
+typedef struct scache_entry
+{
+ char name[HOSTLEN + 1];
+ struct scache_entry *next;
+} SCACHE;
+
+static SCACHE *scache_hash[SCACHE_HASH_SIZE];
+
+/* renamed to keep it consistent with the other hash functions -Dianora */
+/* orabidoo had named it init_scache_hash(); */
+
+void clear_scache_hash_table(void)
+{
+ memset((char *) scache_hash, '\0', sizeof(scache_hash));
+}
+
+static int hash(char *string)
+{
+ int hash_value;
+
+ hash_value = 0;
+ while (*string)
+ hash_value += (*string++ & 0xDF);
+
+ return hash_value % SCACHE_HASH_SIZE;
+}
+
+/*
+ * this takes a server name, and returns a pointer to the same string
+ * (up to case) in the server name token list, adding it to the list if
+ * it's not there. care must be taken not to call this with
+ * user-supplied arguments that haven't been verified to be a valid,
+ * existing, servername. use the hash in list.c for those. -orabidoo
+ */
+char *find_or_add(char *name)
+{
+ int hash_index;
+ SCACHE *ptr, *newptr;
+
+ ptr = scache_hash[hash_index = hash(name)];
+ while (ptr)
+ {
+ if (!mycmp(ptr->name, name))
+ return (ptr->name);
+ else
+ ptr = ptr->next;
+ }
+
+ /* not found -- add it */
+ if ((ptr = scache_hash[hash_index]))
+ {
+ newptr = scache_hash[hash_index] = (SCACHE *) MyMalloc(sizeof(SCACHE));
+ strncpyzt(newptr->name, name, HOSTLEN);
+ newptr->next = ptr;
+ return (newptr->name);
+ }
+ else
+ {
+ ptr = scache_hash[hash_index] = (SCACHE *) MyMalloc(sizeof(SCACHE));
+ strncpyzt(ptr->name, name, HOSTLEN);
+ ptr->next = (SCACHE *) NULL;
+ return (ptr->name);
+ }
+}
+
+/* Added so s_debug could check memory usage in here -Dianora */
+
+void count_scache(int *number_servers_cached, u_long *mem_servers_cached)
+{
+ SCACHE *scache_ptr;
+ int i;
+
+ *number_servers_cached = 0;
+ *mem_servers_cached = 0;
+
+ for (i = 0; i < SCACHE_HASH_SIZE; i++)
+ {
+ scache_ptr = scache_hash[i];
+ while (scache_ptr)
+ {
+ *number_servers_cached = *number_servers_cached + 1;
+ *mem_servers_cached = *mem_servers_cached +
+ (strlen(scache_ptr->name) +
+ sizeof(SCACHE *));
+
+ scache_ptr = scache_ptr->next;
+ }
+ }
+}
+
+/* list all server names in scache very verbose */
+
+void list_scache(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ int hash_index;
+ SCACHE *ptr;
+
+ for (hash_index = 0; hash_index < SCACHE_HASH_SIZE; hash_index++)
+ {
+ ptr = scache_hash[hash_index];
+ while (ptr)
+ {
+ if (ptr->name)
+ sendto_one(sptr, ":%s NOTICE %s :%s",
+ me.name, parv[0], ptr->name);
+ ptr = ptr->next;
+ }
+ }
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/send.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: send.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include <stdio.h>
+#include "numeric.h"
+#include "dh.h"
+#include "zlink.h"
+#include "fds.h"
+
+/*
+ * STOP_SENDING_ON_SHORT_SEND:
+ * Treat a short send as a blocked socket
+ * Might not always be a good idea, esp. if using something that's
+ * Edge triggered (ie, kqueue, epoll, etc)
+ */
+#undef STOP_SENDING_ON_SHORT_SEND
+
+#ifdef ALWAYS_SEND_DURING_SPLIT
+extern int currently_processing_netsplit;
+#endif
+
+static char sendbuf[2048];
+static char remotebuf[2048];
+static char selfbuf[256];
+static int send_message(aClient *, char *, int, void*);
+
+#ifdef HAVE_ENCRYPTION_ON
+/*
+ * WARNING:
+ * Please be aware that if you are using both encryption
+ * and ziplinks, rc4buf in send.c MUST be the same size
+ * as zipOutBuf in zlink.c!
+ */
+static char rc4buf[16384];
+#endif
+
+static int sentalong[MAXCONNECTIONS];
+static int sent_serial;
+
+void init_send()
+{
+ memset(sentalong, 0, sizeof(int) * MAXCONNECTIONS);
+ sent_serial = 0;
+}
+
+/* This routine increments our serial number so it will
+ * be unique from anything in sentalong, no need for a memset
+ * except for every MAXINT calls - lucas
+ */
+
+/* This should work on any OS where an int is 32 bit, I hope.. */
+
+#define HIGHEST_SERIAL INT_MAX
+
+#define INC_SERIAL if(sent_serial == HIGHEST_SERIAL) \
+ { memset(sentalong, 0, sizeof(sentalong)); sent_serial = 0; } \
+ sent_serial++;
+
+
+/*
+ * dead_link
+ *
+ * somewhere along the lines of sending out, there was an error.
+ * we can't close it from the send loop, so mark it as dead
+ * and close it from the main loop.
+ *
+ * if this link is a server, tell routing people.
+ */
+
+static int dead_link(aClient *to, char *notice, int sockerr)
+{
+ int errtmp = errno; /* so we don't munge this later */
+
+ to->sockerr = sockerr;
+ to->flags |= FLAGS_DEADSOCKET;
+ /*
+ * If because of BUFFERPOOL problem then clean dbuf's now so that
+ * notices don't hurt operators below.
+ */
+ SBufClear(&to->recvQ);
+ SBufClear(&to->sendQ);
+ /* Ok, if the link we're dropping is a server, send a routing
+ * notice..
+ */
+ if (IsServer(to) && !(to->flags & FLAGS_CLOSING))
+ {
+ char fbuf[512];
+
+ ircsprintf(fbuf, "from %s: %s", me.name, notice);
+ sendto_gnotice(fbuf, get_client_name(to, HIDEME), strerror(errtmp));
+ ircsprintf(fbuf, ":%s GNOTICE :%s", me.name, notice);
+ sendto_serv_butone(to, fbuf, get_client_name(to, HIDEME),
+ strerror(errtmp));
+ }
+
+ return -1;
+}
+
+/*
+ * send_message
+ * Internal utility which delivers one message buffer to the
+ * socket. Takes care of the error handling and buffering, ifneeded.
+ */
+static int send_message(aClient *to, char *msg, int len, void* sbuf)
+{
+ static int SQinK;
+ int flag;
+
+#ifdef DUMP_DEBUG
+ fprintf(dumpfp, "-> %s: %s\n", (to->name ? to->name : "*"), msg);
+#endif
+
+ if (to->from)
+ to = to->from;
+
+ flag = (!sbuf || ZipOut(to) || IsRC4OUT(to)) ? 1 : 0;
+
+ if (flag == 1)
+ {
+ if(IsServer(to) || IsNegoServer(to))
+ {
+ if(len>510)
+ {
+ msg[511]='\n';
+ msg[512]='\0';
+ len=512;
+ }
+ else
+ {
+ msg[len] = '\n';
+ msg[len+1] = '\0';
+ len++;
+ }
+ }
+ else
+ {
+ if(len>509)
+ {
+ msg[510]='\r';
+ msg[511]='\n';
+ msg[512]='\0';
+ len=512;
+ }
+ else
+ {
+ msg[len] = '\r';
+ msg[len+1] = '\n';
+ msg[len+2] = '\0';
+ len+=2;
+ }
+ }
+ }
+
+ if (IsMe(to))
+ {
+ strncpyzt(selfbuf, msg, sizeof(selfbuf));
+ sendto_ops("Trying to send to myself! [%s]", selfbuf);
+ return 0;
+ }
+
+ if (IsDead(to))
+ return 0;
+
+ if (to->class && (SBufLength(&to->sendQ) > to->class->maxsendq))
+ {
+ /* this would be a duplicate notice, but it contains some useful
+ * information thatwould be spamming the rest of the network.
+ * Kept in. - lucas
+ */
+ if (IsServer(to))
+ sendto_ops("Max SendQ limit exceeded for %s: %d > %d",
+ get_client_name(to, HIDEME), SBufLength(&to->sendQ),
+ to->class->maxsendq);
+ to->flags |= FLAGS_SENDQEX;
+ return dead_link(to, "Max Sendq exceeded for %s, closing link", 0);
+ }
+
+ /*
+ * Update statistics. The following is slightly incorrect
+ * because it counts messages even if queued, but bytes only
+ * really sent. Queued bytes get updated in SendQueued.
+ */
+ to->sendM += 1;
+ me.sendM += 1;
+ if (to->lstn)
+ to->lstn->sendM += 1;
+
+ if(ZipOut(to))
+ {
+ int ldata = (to->flags & FLAGS_BURST);
+
+ msg = zip_output(to->serv->zip_out, msg, &len, 0, &ldata);
+ if(len == -1)
+ {
+ sendto_realops("Zipout error for %s: (%d) %s\n", to->name, ldata,
+ msg);
+ return dead_link(to, "Zip output error for %s", IRCERR_ZIP);
+ }
+
+ if(len == 0)
+ return 0;
+ }
+
+#ifdef HAVE_ENCRYPTION_ON
+ if(IsRC4OUT(to))
+ {
+ /* don't destroy the data in 'msg' */
+ rc4_process_stream_to_buf(to->serv->rc4_out, msg, rc4buf, len);
+ msg = rc4buf;
+ }
+#endif
+
+ if (!sbuf || flag)
+ {
+ if (sbuf_put(&to->sendQ, msg, len) < 0)
+ return dead_link(to, "Buffer allocation error for %s,"
+ " closing link", IRCERR_BUFALLOC);
+ }
+ else
+ {
+ if (sbuf_put_share(&to->sendQ, sbuf) < 0)
+ return dead_link(to, "Buffer allocation error for %s,"
+ " closing link", IRCERR_BUFALLOC);
+ }
+
+ /*
+ * This little bit is to stop the sendQ from growing too large
+ * when there is no need for it to. Thus we call send_queued()
+ * every time 2k has been added to the queue since the last
+ * non-fatal write. Also stops us from deliberately building a
+ * large sendQ and then trying to flood that link with data
+ * (possible during the net relinking done by servers with a large
+ * load).
+ */
+ /*
+ * Well, let's try every 4k for clients, and immediately for servers
+ * -Taner
+ */
+ /*
+ * Let's not waste time trying this on anyone who has a blocking socket.
+ * Also, let's send every 8k for servers, since there's lots of traffic
+ * there and we'd like to make it more efficient. - lucas
+ */
+
+ if(to->flags & FLAGS_BLOCKED)
+ return 0;
+
+#ifdef ALWAYS_SEND_DURING_SPLIT
+ if (currently_processing_netsplit)
+ {
+ send_queued(to);
+ return 0;
+ }
+#endif
+
+ SQinK = (SBufLength(&to->sendQ) >> 10);
+ if (IsServer(to))
+ {
+ if (SQinK > (to->lastsq + 8))
+ send_queued(to);
+ }
+ else
+ {
+ if (SQinK > (to->lastsq + 4))
+ send_queued(to);
+ }
+ return 0;
+}
+
+
+/*
+ * send_queued
+ * This function is called from the main select-loop (or whatever)
+ * when there is a chance the some output would be possible. This
+ * attempts to empty the send queue as far as possible...
+ */
+int send_queued(aClient *to)
+{
+ char *msg;
+ int len, rlen;
+ int more_data = 0; /* the hybrid approach.. */
+#ifdef WRITEV_IOV
+ struct iovec iov[WRITEV_IOV];
+#endif
+
+ /*
+ * Once socket is marked dead, we cannot start writing to it,
+ * even if the error is removed...
+ * this should never happen.
+ */
+ if (IsDead(to))
+ return -1;
+
+ if(ZipOut(to) && zip_is_data_out(to->serv->zip_out))
+ {
+ if(SBufLength(&to->sendQ))
+ more_data = 1;
+ else
+ {
+ int ldata = (to->flags & FLAGS_BURST);
+
+ msg = zip_output(to->serv->zip_out, NULL, &len, 1, &ldata);
+ if(len == -1)
+ {
+ sendto_realops("Zipout error for %s: (%d) %s\n", to->name,
+ ldata, msg);
+ return dead_link(to, "Zip output error for %s", IRCERR_ZIP);
+ }
+
+#ifdef HAVE_ENCRYPTION_ON
+ if(IsRC4OUT(to))
+ rc4_process_stream(to->serv->rc4_out, msg, len);
+#endif
+ /* silently stick this on the sendq... */
+ if (!sbuf_put(&to->sendQ, msg, len))
+ return dead_link(to, "Buffer allocation error for %s",
+ IRCERR_BUFALLOC);
+ }
+ }
+
+ while (SBufLength(&to->sendQ) > 0)
+ {
+#ifdef WRITEV_IOV
+ len = sbuf_mapiov(&to->sendQ, iov);
+ if ((rlen = deliver_it(to, iov, len)) < 0)
+#else
+ msg = sbuf_map(&to->sendQ, &len);
+ if ((rlen = deliver_it(to, msg, len)) < 0)
+#endif
+ return dead_link(to, "Write error to %s, closing link (%s)", errno);
+ sbuf_delete(&to->sendQ, rlen);
+ to->lastsq = (SBufLength(&to->sendQ) >> 10);
+
+#ifdef STOP_SENDING_ON_SHORT_SEND
+ if (rlen < len)
+ {
+ /* Treat this socket as blocking */
+ to->flags |= FLAGS_BLOCKED;
+ set_fd_flags(to->fd, FDF_WANTWRITE);
+#else
+ if (rlen == 0)
+ {
+ /* Socket is blocking... */
+#endif
+ break;
+ }
+
+ if(more_data && SBufLength(&to->sendQ) == 0)
+ {
+ int ldata = (to->flags & FLAGS_BURST);
+
+ more_data = 0;
+
+ msg = zip_output(to->serv->zip_out, NULL, &len, 1, &ldata);
+ if(len == -1)
+ {
+ sendto_realops("Zipout error for %s: (%d) %s\n", to->name,
+ ldata, msg);
+ return dead_link(to, "Zip output error for %s", IRCERR_ZIP);
+ }
+
+#ifdef HAVE_ENCRYPTION_ON
+ if(IsRC4OUT(to))
+ rc4_process_stream(to->serv->rc4_out, msg, len);
+#endif
+ /* silently stick this on the sendq... */
+ if (!sbuf_put(&to->sendQ, msg, len))
+ return dead_link(to, "Buffer allocation error for %s",
+ IRCERR_BUFALLOC);
+ }
+ }
+
+ if ((to->flags & FLAGS_SOBSENT) && IsBurst(to)
+ && SBufLength(&to->sendQ) < 20480)
+ {
+ if (!(to->flags & FLAGS_BURST))
+ {
+ to->flags &= (~FLAGS_SOBSENT);
+ sendto_one(to, "BURST %d", SBufLength(&to->sendQ));
+ }
+ }
+ return (IsDead(to)) ? -1 : 0;
+}
+
+/* send message to single client */
+void sendto_one(aClient *to, char *pattern, ...)
+{
+ va_list vl;
+ int len; /* used for the length of the current message */
+
+ va_start(vl, pattern);
+ len = ircvsprintf(sendbuf, pattern, vl);
+
+ if (to->from)
+ to = to->from;
+ if (IsMe(to))
+ {
+ strncpyzt(selfbuf, sendbuf, sizeof(selfbuf));
+ sendto_ops("Trying to send [%s] to myself!", selfbuf);
+ return;
+ }
+ send_message(to, sendbuf, len, NULL);
+ va_end(vl);
+}
+
+/* send message to single client */
+void sendto_one_services(aClient *to, char *pattern, ...)
+{
+ va_list vl;
+ int len; /* used for the length of the current message */
+
+ if(confopts & FLAGS_SERVHUB)
+ if(to && to->user && to->user->server &&
+ (!mycmp(to->user->server,Services_Name) ||
+ !mycmp(to->user->server,Stats_Name)))
+ return;
+
+ va_start(vl, pattern);
+ len = ircvsprintf(sendbuf, pattern, vl);
+
+ if (to->from)
+ to = to->from;
+ if (IsMe(to))
+ {
+ strncpyzt(selfbuf, sendbuf, sizeof(selfbuf));
+ sendto_ops("Trying to send [%s] to myself!", selfbuf);
+ return;
+ }
+ send_message(to, sendbuf, len, NULL);
+ va_end(vl);
+}
+
+void vsendto_one(aClient *to, char *pattern, va_list vl)
+{
+ int len; /* used for the length of the current message */
+
+ len = ircvsprintf(sendbuf, pattern, vl);
+
+ if (to->from)
+ to = to->from;
+ if (IsMe(to) && to->fd >= 0)
+ {
+ strncpyzt(selfbuf, sendbuf, sizeof(selfbuf));
+ sendto_ops("Trying to send [%s] to myself!", selfbuf);
+ return;
+ }
+ send_message(to, sendbuf, len, NULL);
+}
+
+/* prefix_buffer
+ *
+ * take varargs and dump prefixed message into a buffer
+ * remote: 1 if client is remote, 0 if local
+ * from: the client sending the message
+ * prefix: the prefix as specified (parv[0] usually)
+ * buffer: the buffer to dump this into (NO BOUNDS CHECKING!)
+ * pattern: varargs pattern
+ * vl: varargs variable list with one arg taken already
+ */
+static inline int prefix_buffer(int remote, aClient *from, char *prefix,
+ char *buffer, char *pattern, va_list vl)
+{
+ char *p; /* temp pointer */
+ int msglen; /* the length of the message we end up with */
+ int sidx = 1; /* start at offset 1 */
+
+ *buffer = ':';
+
+ if(!remote && IsPerson(from))
+ {
+ int flag = 0;
+ anUser *user = from->user;
+
+ for(p = from->name; *p; p++)
+ buffer[sidx++] = *p;
+
+ if (user)
+ {
+ if (*user->username)
+ {
+ buffer[sidx++] = '!';
+ for(p = user->username; *p; p++)
+ buffer[sidx++] = *p;
+ }
+ if (*user->host && !MyConnect(from))
+ {
+ buffer[sidx++] = '@';
+ for(p = user->host; *p; p++)
+ buffer[sidx++] = *p;
+ flag = 1;
+ }
+ }
+ if (!flag && MyConnect(from) && *user->host)
+ {
+ buffer[sidx++] = '@';
+ for(p = from->sockhost; *p; p++)
+ buffer[sidx++] = *p;
+ }
+ }
+ else
+ {
+ for(p = prefix; *p; p++)
+ buffer[sidx++] = *p;
+ }
+
+ msglen = ircvsprintf(&buffer[sidx], pattern + 3, vl);
+ msglen += sidx;
+
+ return msglen;
+}
+
+static inline int check_fake_direction(aClient *from, aClient *to)
+{
+ if (!MyClient(from) && IsPerson(to) && (to->from == from->from))
+ {
+ if (IsServer(from))
+ {
+ sendto_ops("Message to %s[%s] dropped from %s (Fake Direction)",
+ to->name, to->from->name, from->name);
+ return -1;
+ }
+
+ sendto_ops("Ghosted: %s[%s@%s] from %s[%s@%s] (%s)", to->name,
+ to->user->username, to->user->host, from->name,
+ from->user->username, from->user->host, to->from->name);
+ sendto_serv_butone(NULL, ":%s KILL %s :%s (%s[%s@%s] Ghosted %s)",
+ me.name, to->name, me.name, to->name,
+ to->user->username, to->user->host, to->from->name);
+
+ to->flags |= FLAGS_KILLED;
+ exit_client(NULL, to, &me, "Ghosted client");
+
+ if (IsPerson(from))
+ sendto_one(from, err_str(ERR_GHOSTEDCLIENT), me.name, from->name,
+ to->name, to->user->username, to->user->host, to->from);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void sendto_channel_butone(aClient *one, aClient *from, aChannel *chptr,
+ char *pattern, ...)
+{
+ chanMember *cm;
+ aClient *acptr;
+ int i;
+ int didlocal = 0, didremote = 0;
+ va_list vl;
+ char *pfix;
+ void *share_bufs[2] = { 0, 0 };
+
+ va_start(vl, pattern);
+
+ pfix = va_arg(vl, char *);
+
+ INC_SERIAL
+ for (cm = chptr->members; cm; cm = cm->next)
+ {
+ acptr = cm->cptr;
+ if (acptr->from == one)
+ continue; /* ...was the one I should skip */
+
+ if(confopts & FLAGS_SERVHUB)
+ if(acptr && acptr->user && acptr->user->server &&
+ (!mycmp(acptr->user->server,Services_Name) ||
+ !mycmp(acptr->user->server,Stats_Name)))
+ continue;
+
+ i = acptr->from->fd;
+ if (MyClient(acptr))
+ {
+ if(!didlocal)
+ {
+ didlocal = prefix_buffer(0, from, pfix, sendbuf,
+ pattern, vl);
+ sbuf_begin_share(sendbuf, didlocal, &share_bufs[0]);
+ }
+ if(check_fake_direction(from, acptr))
+ continue;
+
+ send_message(acptr, sendbuf, didlocal, share_bufs[0]);
+ sentalong[i] = sent_serial;
+ }
+ else
+ {
+ /*
+ * Now check whether a message has been sent to this remote
+ * link already
+ */
+ if(!didremote)
+ {
+ didremote = prefix_buffer(1, from, pfix, remotebuf,
+ pattern, vl);
+ sbuf_begin_share(remotebuf, didremote, &share_bufs[1]);
+ }
+
+ if(check_fake_direction(from, acptr))
+ continue;
+
+ if (sentalong[i] != sent_serial)
+ {
+ send_message(acptr, remotebuf, didremote, share_bufs[1]);
+ sentalong[i] = sent_serial;
+ }
+ }
+ }
+
+ sbuf_end_share(share_bufs, 2);
+ va_end(vl);
+ return;
+}
+
+/*
+ * Like sendto_channel_butone, but sends to all servers but 'one'
+ * that have clients in this channel.
+ */
+void sendto_channel_remote_butone(aClient *one, aClient *from, aChannel *chptr,
+ char *pattern, ...)
+{
+ chanMember *cm;
+ aClient *acptr;
+ int i;
+ int didremote = 0;
+ va_list vl;
+ char *pfix;
+ void *share_buf = NULL;
+
+ va_start(vl, pattern);
+
+ pfix = va_arg(vl, char *);
+
+ INC_SERIAL
+ for (cm = chptr->members; cm; cm = cm->next)
+ {
+ acptr = cm->cptr;
+ if (acptr->from == one)
+ continue; /* ...was the one I should skip */
+
+ if(confopts & FLAGS_SERVHUB)
+ if(acptr && acptr->user && acptr->user->server &&
+ (!mycmp(acptr->user->server,Services_Name) ||
+ !mycmp(acptr->user->server,Stats_Name)))
+ continue;
+
+ i = acptr->from->fd;
+ if (!MyClient(acptr))
+ {
+ /*
+ * Now check whether a message has been sent to this remote
+ * link already
+ */
+ if(!didremote)
+ {
+ didremote = prefix_buffer(1, from, pfix, remotebuf,
+ pattern, vl);
+ sbuf_begin_share(remotebuf, didremote, &share_buf);
+ }
+
+ if(check_fake_direction(from, acptr))
+ continue;
+
+ if (sentalong[i] != sent_serial)
+ {
+ send_message(acptr, remotebuf, didremote, share_buf);
+ sentalong[i] = sent_serial;
+ }
+ }
+ }
+
+ sbuf_end_share(&share_buf, 1);
+
+ va_end(vl);
+ return;
+}
+
+/*
+ * sendto_server_butone_services
+ *
+ * Send a message to all connected servers except the client 'one', and do not send to services.dal.net.
+ */
+void sendto_serv_butone_services(aClient *one, char *pattern, ...)
+{
+ aClient *cptr;
+ int k = 0;
+ fdlist send_fdlist;
+ va_list vl;
+ DLink *lp;
+
+
+ va_start(vl, pattern);
+ for (lp = server_list; lp; lp = lp->next)
+ {
+ cptr = lp->value.cptr;
+ if((confopts & FLAGS_SERVHUB) && (!mycmp(cptr->name,Services_Name)
+ || !mycmp(cptr->name,Stats_Name)))
+ continue;
+
+ if (one && cptr == one->from)
+ continue;
+ send_fdlist.entry[++k] = cptr->fd;
+ }
+ send_fdlist.last_entry = k;
+ if (k)
+ vsendto_fdlist(&send_fdlist, pattern, vl);
+ va_end(vl);
+ return;
+}
+
+#ifdef NOQUIT
+/*
+ * sendto_non_noquit_servs_butone
+ *
+ * Send a message to all non-noquit servs
+ */
+void sendto_non_noquit_servs_butone(aClient *one, char *pattern, ...)
+{
+ aClient *cptr;
+ int k = 0;
+ fdlist send_fdlist;
+ va_list vl;
+ DLink *lp;
+
+ va_start(vl, pattern);
+ for(lp = server_list; lp; lp = lp->next)
+ {
+ cptr = lp->value.cptr;
+
+ if (IsNoquit(cptr) || (one == cptr))
+ continue;
+
+ send_fdlist.entry[++k] = cptr->fd;
+ }
+ send_fdlist.last_entry = k;
+ if (k)
+ vsendto_fdlist(&send_fdlist, pattern, vl);
+ va_end(vl);
+ return;
+}
+#endif
+
+/*
+ * sendto_server_butone
+ *
+ * Send a message to all connected servers except the client 'one'.
+ */
+void sendto_serv_butone(aClient *one, char *pattern, ...)
+{
+ aClient *cptr;
+ int k = 0;
+ fdlist send_fdlist;
+ va_list vl;
+ DLink *lp;
+
+ va_start(vl, pattern);
+ for(lp = server_list; lp; lp = lp->next)
+ {
+ cptr = lp->value.cptr;
+ if (one && cptr == one->from)
+ continue;
+ send_fdlist.entry[++k] = cptr->fd;
+ }
+ send_fdlist.last_entry = k;
+ if (k)
+ vsendto_fdlist(&send_fdlist, pattern, vl);
+ va_end(vl);
+ return;
+}
+
+/*
+ * sendto_common_channels()
+ *
+ * Sends a message to all people (inclusing user) on local server who are
+ * in same channel with user.
+ */
+void sendto_common_channels(aClient *from, char *pattern, ...)
+{
+ Link *channels;
+ chanMember *users;
+ aClient *cptr;
+ va_list vl;
+ char *pfix;
+ int msglen = 0;
+ void *share_buf = NULL;
+
+ va_start(vl, pattern);
+
+ pfix = va_arg(vl, char *);
+
+ INC_SERIAL
+
+ if(from->fd >= 0)
+ sentalong[from->fd] = sent_serial;
+
+ if (from->user)
+ {
+ for (channels = from->user->channel; channels;
+ channels = channels->next)
+ {
+ for (users = channels->value.chptr->members; users;
+ users = users->next)
+ {
+ cptr = users->cptr;
+
+ if (!MyConnect(cptr) || sentalong[cptr->fd] == sent_serial)
+ continue;
+
+ sentalong[cptr->fd] = sent_serial;
+ if (!msglen)
+ {
+ msglen = prefix_buffer(0, from, pfix, sendbuf,
+ pattern, vl);
+ sbuf_begin_share(sendbuf, msglen, &share_buf);
+ }
+ if (check_fake_direction(from, cptr))
+ continue;
+ send_message(cptr, sendbuf, msglen, share_buf);
+ }
+ }
+ }
+
+ if(MyConnect(from))
+ {
+ if(!msglen)
+ msglen = prefix_buffer(0, from, pfix, sendbuf, pattern, vl);
+ /* send the share buf if others are using it too */
+ send_message(from, sendbuf, msglen, share_buf);
+ }
+
+ sbuf_end_share(&share_buf, 1);
+
+ va_end(vl);
+ return;
+}
+
+/*
+ * send_quit_to_common_channels()
+ *
+ * Sends a message to all people (inclusing user) on local server who are
+ * in same channel with user if the user can send to this channel.
+ */
+void send_quit_to_common_channels(aClient *from, char *reason)
+{
+ Link *channels;
+ chanMember *users;
+ aClient *cptr;
+ int msglen;
+ void *share_buf = NULL;
+
+ INC_SERIAL
+
+ msglen=sprintf(sendbuf,":%s!%s@%s QUIT :%s", from->name,
+ from->user->username,from->user->host, reason);
+ sbuf_begin_share(sendbuf, msglen, &share_buf);
+
+ if(from->fd >= 0)
+ sentalong[from->fd] = sent_serial;
+ for (channels = from->user->channel; channels; channels = channels->next)
+ {
+ if (!can_send(from, channels->value.chptr, reason))
+ {
+ for (users = channels->value.chptr->members; users;
+ users = users->next)
+ {
+ cptr = users->cptr;
+ if (!MyConnect(cptr) || sentalong[cptr->fd] == sent_serial)
+ continue;
+ sentalong[cptr->fd] = sent_serial;
+ if (check_fake_direction(from, cptr))
+ continue;
+ send_message(cptr, sendbuf, msglen, share_buf);
+ }
+ }
+ }
+ sbuf_end_share(&share_buf, 1);
+}
+
+/*
+ * send_part_to_common_channels()
+ *
+ * Sends a message to all people (inclusing user) on local server who are
+ * in same channel with user if the user cannot send to the channel.
+ */
+void send_part_to_common_channels(aClient *from, char *reason)
+{
+ Link *channels;
+ chanMember *users;
+ aClient *cptr;
+ int msglen = 0;
+ void *share_buf = NULL;
+
+ for (channels = from->user->channel; channels; channels = channels->next)
+ {
+ if (can_send(from, channels->value.chptr, reason))
+ {
+ msglen = sprintf(sendbuf,":%s!%s@%s PART %s",
+ from->name,from->user->username,from->user->host,
+ channels->value.chptr->chname);
+ sbuf_begin_share(sendbuf, msglen, &share_buf);
+
+ INC_SERIAL
+
+ if (from->fd >= 0)
+ sentalong[from->fd] = sent_serial;
+
+ for (users = channels->value.chptr->members; users;
+ users = users->next)
+ {
+ cptr = users->cptr;
+
+ if (!MyConnect(cptr) || sentalong[cptr->fd] == sent_serial)
+ continue;
+
+ sentalong[cptr->fd] = sent_serial;
+ if (check_fake_direction(from, cptr))
+ continue;
+ send_message(cptr, sendbuf, msglen, share_buf);
+ }
+ sbuf_end_share(&share_buf, 1);
+ }
+ }
+}
+
+#ifdef FLUD
+void sendto_channel_butlocal(aClient *one, aClient *from, aChannel *chptr,
+ char *pattern, ...)
+{
+ chanMember *cm;
+ aClient *acptr;
+ int i;
+ va_list vl;
+
+ va_start(vl, pattern);
+
+ INC_SERIAL
+
+ for (cm = chptr->members; cm; cm = cm->next)
+ {
+ acptr = cm->cptr;
+ if (acptr->from == one)
+ continue; /* ...was the one I should skip */
+ i = acptr->from->fd;
+ if (!MyFludConnect(acptr))
+ {
+ /*
+ * Now check whether a message has been sent to this remote
+ * link already
+ */
+ if (sentalong[i] != sent_serial)
+ {
+ vsendto_prefix_one(acptr, from, pattern, vl);
+ sentalong[i] = sent_serial;
+ }
+ }
+ }
+ va_end(vl);
+ return;
+}
+#endif /* FLUD */
+
+/*
+ * sendto_channel_butserv
+ *
+ * Send a message to all members of a channel that are connected to this
+ * server.
+ */
+void sendto_channel_butserv(aChannel *chptr, aClient *from, char *pattern, ...)
+{
+ chanMember *cm;
+ aClient *acptr;
+ va_list vl;
+ int didlocal = 0;
+ char *pfix;
+ void *share_buf = NULL;
+
+ va_start(vl, pattern);
+
+ pfix = va_arg(vl, char *);
+
+ for (cm = chptr->members; cm; cm = cm->next)
+ {
+ if (MyConnect(acptr = cm->cptr))
+ {
+ if(!didlocal)
+ {
+ didlocal = prefix_buffer(0, from, pfix, sendbuf, pattern, vl);
+ sbuf_begin_share(sendbuf, didlocal, &share_buf);
+ }
+
+ if (check_fake_direction(from, acptr))
+ continue;
+
+ send_message(acptr, sendbuf, didlocal, share_buf);
+
+ /* vsendto_prefix_one(acptr, from, pattern, vl); */
+ }
+ }
+ sbuf_end_share(&share_buf, 1);
+ va_end(vl);
+}
+
+/*
+ * sendto_channel_butserv_me
+ *
+ * Send a message to all members of a channel that are connected to this
+ * server. Possibly hide the origin, if it's a server, with me.name if certain paranoia is on.
+ */
+void sendto_channel_butserv_me(aChannel *chptr, aClient *from, char *pattern, ...)
+{
+ chanMember *cm;
+ aClient *acptr;
+ va_list vl;
+ int didlocal = 0;
+ char *pfix;
+ void *share_buf = NULL;
+
+ va_start(vl, pattern);
+
+ pfix = va_arg(vl, char *);
+
+#ifdef HIDE_SERVERMODE_ORIGINS
+ if(IsServer(from) && !IsULine(from))
+ {
+ from = &me;
+ pfix = me.name;
+ }
+#endif
+
+ for (cm = chptr->members; cm; cm = cm->next)
+ {
+ if (MyConnect(acptr = cm->cptr))
+ {
+ if (!didlocal)
+ {
+ didlocal = prefix_buffer(0, from, pfix, sendbuf, pattern, vl);
+ sbuf_begin_share(sendbuf, didlocal, &share_buf);
+ }
+
+ if(check_fake_direction(from, acptr))
+ continue;
+
+ send_message(acptr, sendbuf, didlocal, share_buf);
+
+ }
+ }
+ sbuf_end_share(&share_buf, 1);
+ va_end(vl);
+}
+
+/*
+ * sendto_channelops_butserv
+ *
+ * Send a message to all operators of a channel that are connected to this
+ * server.
+ */
+void sendto_channelops_butserv(aChannel *chptr, aClient *from, char *pattern, ...)
+{
+ chanMember *cm;
+ aClient *acptr;
+ va_list vl;
+ int didlocal = 0;
+ char *pfix;
+ void *share_buf = NULL;
+
+ va_start(vl, pattern);
+
+ pfix = va_arg(vl, char *);
+
+ for (cm = chptr->members; cm; cm = cm->next)
+ {
+ if (MyConnect(acptr = cm->cptr) && (cm->flags & CHFL_CHANOP))
+ {
+ if (!didlocal)
+ {
+ didlocal = prefix_buffer(0, from, pfix, sendbuf, pattern, vl);
+ sbuf_begin_share(sendbuf, didlocal, &share_buf);
+ }
+
+ if (check_fake_direction(from, acptr))
+ continue;
+
+ send_message(acptr, sendbuf, didlocal, share_buf);
+ }
+ }
+ sbuf_end_share(&share_buf, 1);
+ va_end(vl);
+}
+
+/*
+ * * send a msg to all ppl on servers/hosts that match a specified mask *
+ * (used for enhanced PRIVMSGs) *
+ *
+ * addition -- Armin, 8jun90 (gruner@informatik.tu-muenchen.de)
+ */
+static int match_it(aClient *one, char *mask, int what)
+{
+ if (what == MATCH_HOST)
+ return (match(mask, one->user->host) == 0);
+ else
+ return (match(mask, one->user->server) == 0);
+}
+
+/*
+ * sendto_match_butone
+ *
+ * Send to all clients which match the mask in a way defined on 'what';
+ * either by user hostname or user servername.
+ */
+void sendto_match_butone(aClient *one, aClient *from, char *mask, int what,
+ char *pattern, ...)
+{
+ int i;
+ aClient *cptr, *acptr;
+ char cansendlocal, cansendglobal;
+ va_list vl;
+
+ va_start(vl, pattern);
+ if (MyConnect(from))
+ {
+ cansendlocal = (OPCanLNotice(from)) ? 1 : 0;
+ cansendglobal = (OPCanGNotice(from)) ? 1 : 0;
+ }
+ else
+ cansendlocal = cansendglobal = 1;
+ for (i = 0; i <= highest_fd; i++)
+ {
+ if (!(cptr = local[i]))
+ continue; /* that clients are not mine */
+ if (cptr == one) /* must skip the origin !! */
+ continue;
+ if (IsServer(cptr))
+ {
+ if (!cansendglobal) continue;
+ for (acptr = client; acptr; acptr = acptr->next)
+ if (IsRegisteredUser(acptr)
+ && match_it(acptr, mask, what)
+ && acptr->from == cptr)
+ break;
+ /*
+ * a person on that server matches the mask, so we * send *one*
+ * msg to that server ...
+ */
+ if (acptr == NULL)
+ continue;
+ /* ... but only if there *IS* a matching person */
+ }
+ /* my client, does he match ? */
+ else if (!cansendlocal || !(IsRegisteredUser(cptr) &&
+ match_it(cptr, mask, what)))
+ continue;
+ vsendto_prefix_one(cptr, from, pattern, vl);
+ }
+ va_end(vl);
+ return;
+}
+
+/*
+ * sendto_all_butone.
+ *
+ * Send a message to all connections except 'one'. The basic wall type
+ * message generator.
+ */
+void sendto_all_butone(aClient *one, aClient *from, char *pattern, ...)
+{
+ int i;
+ aClient *cptr;
+ va_list vl;
+
+ va_start(vl, pattern);
+ for (i = 0; i <= highest_fd; i++)
+ if ((cptr = local[i]) && !IsMe(cptr) && one != cptr)
+ vsendto_prefix_one(cptr, from, pattern, vl);
+ va_end(vl);
+ return;
+}
+
+/*
+ * sendto_ops_lev
+ *
+ * Send to *local* ops only at a certain level... 0 = normal +s 1 = client
+ * connect/disconnect (+c) [IRCOPS ONLY] 2 = bot rejection
+ * (+r) 3 = server kills (+k)
+ */
+void sendto_ops_lev(int lev, char *pattern, ...)
+{
+ aClient *cptr;
+ int i;
+ char nbuf[1024];
+ va_list vl;
+ char *tmsg;
+
+#ifdef NICER_UMODENOTICE_SEPARATION
+ switch(lev)
+ {
+ case CCONN_LEV:
+ tmsg = "Client";
+ break;
+
+ case DEBUG_LEV:
+ tmsg = "Debug";
+ break;
+
+ case SPY_LEV:
+ tmsg = "Spy";
+ break;
+
+ case SPAM_LEV:
+ tmsg = "Spam";
+ break;
+
+ case FLOOD_LEV:
+ tmsg = "Flood";
+ break;
+
+ case DCCSEND_LEV:
+ tmsg = "DCCAllow";
+ break;
+
+ default:
+ tmsg = "Notice";
+ }
+#else
+ tmsg = "Notice";
+#endif
+
+ va_start(vl,pattern);
+ for (i = 0; i <= highest_fd; i++)
+ if ((cptr = local[i]) && !IsServer(cptr) && !IsMe(cptr))
+ {
+ switch (lev)
+ {
+ case CCONN_LEV:
+ if (!SendCConnNotice(cptr) || !IsAnOper(cptr))
+ continue;
+ break;
+ case REJ_LEV:
+ if (!SendRejNotice(cptr) || !IsAnOper(cptr))
+ continue;
+ break;
+ case SKILL_LEV:
+ if (!SendSkillNotice(cptr))
+ continue;
+ break;
+ case USKILL_LEV:
+ if (!SendSUkillNotice(cptr) || !IsAnOper(cptr))
+ continue;
+ break;
+ case SPY_LEV:
+ if (!SendSpyNotice(cptr) || !IsAnOper(cptr))
+ continue;
+ break;
+ case DCCSEND_LEV:
+ if (!SendDCCNotice(cptr) || !IsAnOper(cptr))
+ continue;
+ break;
+ case FLOOD_LEV:
+ if (!SendFloodNotice(cptr) || !IsAnOper(cptr))
+ continue;
+ break;
+ case SPAM_LEV:
+ if (!SendSpamNotice(cptr) || !IsAnOper(cptr))
+ continue;
+ break;
+ case DEBUG_LEV:
+ if (!SendDebugNotice(cptr) || !IsAnOper(cptr))
+ continue;
+ break;
+
+ default: /* this is stupid, but oh well */
+ if (!SendServNotice(cptr))
+ continue;
+ }
+ ircsprintf(nbuf, ":%s NOTICE %s :*** %s -- ", me.name,
+ cptr->name, tmsg);
+ strncat(nbuf, pattern, sizeof(nbuf) - strlen(nbuf));
+ vsendto_one(cptr, nbuf, vl);
+ }
+ va_end(vl);
+ return;
+}
+
+/*
+ * sendto_ops
+ *
+ * Send to *local* ops only.
+ */
+void sendto_ops(char *pattern, ...)
+{
+ va_list vl;
+
+ va_start(vl, pattern);
+ vsendto_realops(pattern, vl);
+ va_end(vl);
+ return;
+}
+
+/*
+ * sendto_ops_butone
+ * Send message to all operators.
+ * one - client not to send message to
+ * from- client which message is from *NEVER* NULL!!
+ */
+void sendto_ops_butone(aClient *one, aClient *from, char *pattern, ...)
+{
+ int i;
+ aClient *cptr;
+ va_list vl;
+
+ va_start(vl, pattern);
+
+ INC_SERIAL
+
+ for (cptr = client; cptr; cptr = cptr->next)
+ {
+ if (!SendWallops(cptr))
+ continue;
+ /*
+ * we want wallops if (MyClient(cptr) && !(IsServer(from) ||
+ * IsMe(from))) continue;
+ */
+ i = cptr->from->fd; /* find connection oper is on */
+ if (sentalong[i] == sent_serial) /* sent message along it already ? */
+ continue;
+ if (cptr->from == one)
+ continue; /* ...was the one I should skip */
+ sentalong[i] = sent_serial;
+ vsendto_prefix_one(cptr->from, from, pattern, vl);
+ }
+ va_end(vl);
+ return;
+}
+
+/*
+ * * sendto_wallops_butone * Send message to all operators. * one
+ * - client not to send message to * from- client which message is from
+ * *NEVER* NULL!!
+ */
+void sendto_wallops_butone(aClient *one, aClient *from, char *pattern, ...)
+{
+ int i;
+ aClient *cptr;
+ va_list vl;
+
+ va_start(vl, pattern);
+ for(i=0;i<=highest_fd;i++)
+ {
+ if((cptr=local[i])!=NULL)
+ {
+ if(!(IsRegistered(cptr) && (SendWallops(cptr) ||
+ IsServer(cptr))) || cptr==one)
+ continue;
+ vsendto_prefix_one(cptr, from, pattern, vl);
+ }
+ }
+ va_end(vl);
+ return;
+}
+
+void send_globops(char *pattern, ...)
+{
+ aClient *cptr;
+ char nbuf[1024];
+ va_list vl;
+ DLink *lp;
+
+ va_start(vl, pattern);
+ for (lp = oper_list; lp; lp = lp->next)
+ {
+ cptr = lp->value.cptr;
+ if (!SendGlobops(cptr) || !IsAnOper(cptr))
+ continue;
+
+ if (IsAnOper(cptr))
+ {
+ ircsprintf(nbuf, ":%s NOTICE %s :*** Global -- %s",
+ me.name, cptr->name, pattern);
+ vsendto_one(cptr, nbuf, vl);
+ }
+ }
+ va_end(vl);
+ return;
+}
+
+void send_chatops(char *pattern, ...)
+{
+ aClient *cptr;
+ char nbuf[1024];
+ va_list vl;
+ DLink *lp;
+
+ va_start(vl, pattern);
+ for (lp = oper_list; lp; lp = lp->next)
+ {
+ cptr = lp->value.cptr;
+ if (!SendChatops(cptr) || !IsAnOper(cptr))
+ continue;
+
+ if (IsAnOper(cptr))
+ {
+ ircsprintf(nbuf, ":%s NOTICE %s :*** ChatOps -- %s",
+ me.name, cptr->name, pattern);
+ vsendto_one(cptr, nbuf, vl);
+ }
+ }
+ va_end(vl);
+ return;
+}
+
+/*
+ * to - destination client from - client which message is from
+ *
+ * NOTE: NEITHER OF THESE SHOULD *EVER* BE NULL!! -avalon
+ */
+void sendto_prefix_one(aClient *to, aClient *from, char *pattern, ...)
+{
+ static char sender[HOSTLEN + NICKLEN + USERLEN + 5];
+ static char temp[1024];
+ anUser *user;
+ char *idx;
+ char *par;
+ int flag = 0, sidx = 0;
+ va_list vl, vl2;
+
+ va_start(vl, pattern);
+ VA_COPY(vl2, vl);
+
+ par = va_arg(vl, char *);
+ /*
+ * Optimize by checking if (from && to) before everything
+ * uhh, there's _always_ going to be a to!
+ */
+ if (from)
+ {
+ if (!MyClient(from) && IsPerson(to) && (to->from == from->from))
+ {
+ if (IsServer(from))
+ {
+ ircvsprintf(temp, pattern, vl2);
+ sendto_ops("Send message (%s) to %s[%s] dropped from "
+ "%s(Fake Dir)", temp, to->name, to->from->name,
+ from->name);
+ va_end(vl);
+ return;
+ }
+
+ sendto_ops("Ghosted: %s[%s@%s] from %s[%s@%s] (%s)", to->name,
+ to->user->username, to->user->host, from->name,
+ from->user->username, from->user->host, to->from->name);
+ sendto_serv_butone(NULL, ":%s KILL %s :%s (%s[%s@%s] Ghosted %s)",
+ me.name, to->name, me.name, to->name,
+ to->user->username, to->user->host,
+ to->from->name);
+
+ to->flags |= FLAGS_KILLED;
+ exit_client(NULL, to, &me, "Ghosted client");
+ if (IsPerson(from))
+ sendto_one(from, err_str(ERR_GHOSTEDCLIENT), me.name,
+ from->name, to->name, to->user->username,
+ to->user->host, to->from);
+ va_end(vl);
+ return;
+ }
+
+ if (MyClient(to) && IsPerson(from) && !mycmp(par, from->name))
+ {
+ user = from->user;
+
+ for(idx = from->name; *idx; idx++)
+ sender[sidx++] = *idx;
+
+ if (user)
+ {
+ if (*user->username)
+ {
+ sender[sidx++] = '!';
+ for(idx = user->username; *idx; idx++)
+ sender[sidx++] = *idx;
+ }
+ if (*user->host && !MyConnect(from))
+ {
+ sender[sidx++] = '@';
+ for(idx = user->host; *idx; idx++)
+ sender[sidx++] = *idx;
+ flag = 1;
+ }
+ }
+
+ /*
+ * flag is used instead of index(sender, '@') for speed and
+ * also since username/nick may have had a '@' in them.
+ * -avalon
+ */
+
+ if (!flag && MyConnect(from) && *user->host)
+ {
+ sender[sidx++] = '@';
+ for(idx = from->sockhost; *idx; idx++)
+ sender[sidx++] = *idx;
+ }
+
+ sender[sidx] = '\0';
+ par = sender;
+ }
+ }
+
+ temp[0] = ':';
+ sidx = 1;
+
+ /*
+ * okay, we more or less know that our sendto_prefix crap is going
+ * to be :%s <blah>, so it's easy to fix these lame problems...joy
+ */
+
+ for(idx = par; *idx; idx++)
+ temp[sidx++] = *idx;
+ for(idx = (pattern + 3); *idx; idx++)
+ temp[sidx++] = *idx;
+
+ temp[sidx] = '\0';
+
+ vsendto_one(to, temp, vl);
+ va_end(vl);
+}
+
+/* this is an incredibly expensive function.
+ * removed all strcat() calls. - lucas */
+void vsendto_prefix_one(aClient *to, aClient *from, char *pattern, va_list vl)
+{
+ static char sender[HOSTLEN + NICKLEN + USERLEN + 5];
+ static char temp[1024];
+ anUser *user;
+ char *idx;
+ char *par;
+ int flag = 0, sidx = 0;
+ va_list vl2;
+ VA_COPY(vl2, vl);
+
+ par = va_arg(vl2, char *);
+ /*
+ * Optimize by checking if (from && to) before everything
+ * uhh, there's _always_ going to be a to!
+ */
+ if (from)
+ {
+ if (!MyClient(from) && IsPerson(to) && (to->from == from->from))
+ {
+ if (IsServer(from))
+ {
+ ircvsprintf(temp, pattern, vl);
+ sendto_ops("Send message (%s) to %s[%s] dropped from "
+ "%s(Fake Dir)", temp,
+ to->name, to->from->name, from->name);
+ return;
+ }
+
+ sendto_ops("Ghosted: %s[%s@%s] from %s[%s@%s] (%s)", to->name,
+ to->user->username, to->user->host, from->name,
+ from->user->username, from->user->host, to->from->name);
+ sendto_serv_butone(NULL, ":%s KILL %s :%s (%s[%s@%s] Ghosted %s)",
+ me.name, to->name, me.name, to->name,
+ to->user->username, to->user->host,
+ to->from->name);
+
+ to->flags |= FLAGS_KILLED;
+ exit_client(NULL, to, &me, "Ghosted client");
+ if (IsPerson(from))
+ sendto_one(from, err_str(ERR_GHOSTEDCLIENT), me.name,
+ from->name, to->name, to->user->username,
+ to->user->host, to->from);
+ return;
+ }
+
+ if (MyClient(to) && IsPerson(from) && !mycmp(par, from->name))
+ {
+ user = from->user;
+
+ for(idx = from->name; *idx; idx++)
+ sender[sidx++] = *idx;
+
+ if (user)
+ {
+ if (*user->username)
+ {
+ sender[sidx++] = '!';
+ for(idx = user->username; *idx; idx++)
+ sender[sidx++] = *idx;
+ }
+ if (*user->host && !MyConnect(from))
+ {
+ sender[sidx++] = '@';
+ for(idx = user->host; *idx; idx++)
+ sender[sidx++] = *idx;
+ flag = 1;
+ }
+ }
+
+ /*
+ * flag is used instead of index(sender, '@') for speed and
+ * also since username/nick may have had a '@' in them.
+ * -avalon
+ */
+
+ if (!flag && MyConnect(from) && *user->host)
+ {
+ sender[sidx++] = '@';
+ for(idx = from->sockhost; *idx; idx++)
+ sender[sidx++] = *idx;
+ }
+
+ sender[sidx] = '\0';
+ par = sender;
+
+ }
+ }
+
+ temp[0] = ':';
+ sidx = 1;
+
+ /*
+ * okay, we more or less know that our sendto_prefix crap is
+ * going to be :%s <blah>, so it's easy to fix these lame problems...joy
+ */
+
+ for(idx = par; *idx; idx++)
+ temp[sidx++] = *idx;
+ for(idx = (pattern + 3); *idx; idx++)
+ temp[sidx++] = *idx;
+
+ temp[sidx] = '\0';
+
+ vsendto_one(to, temp, vl2);
+}
+
+void sendto_fdlist(fdlist *listp, char *pattern, ...)
+{
+ int len, j, fd;
+ va_list vl;
+ void *share_buf = NULL;
+
+ va_start(vl, pattern);
+ len = ircvsprintf(sendbuf, pattern, vl);
+ sbuf_begin_share(sendbuf, len, &share_buf);
+
+ for (fd = listp->entry[j = 1]; j <= listp->last_entry;
+ fd = listp->entry[++j])
+ send_message(local[fd], sendbuf, len, share_buf);
+ sbuf_end_share(&share_buf, 1);
+ va_end(vl);
+}
+
+void vsendto_fdlist(fdlist *listp, char *pattern, va_list vl)
+{
+ int len, j, fd;
+ void *share_buf = NULL;
+ len = ircvsprintf(sendbuf, pattern, vl);
+ sbuf_begin_share(sendbuf, len, &share_buf);
+
+ for (fd = listp->entry[j = 1]; j <= listp->last_entry;
+ fd = listp->entry[++j])
+ send_message(local[fd], sendbuf, len, share_buf);
+ sbuf_end_share(&share_buf, 1);
+}
+
+
+void vsendto_realops(char *pattern, va_list vl)
+{
+ aClient *cptr;
+ char nbuf[1024];
+ DLink *lp;
+
+ for (lp = oper_list; lp; lp = lp->next)
+ {
+ cptr = lp->value.cptr;
+ if (IsAnOper(cptr))
+ {
+ ircsprintf(nbuf, ":%s NOTICE %s :*** Notice -- %s",
+ me.name, cptr->name, pattern);
+ vsendto_one(cptr, nbuf, vl);
+ }
+ }
+ return;
+}
+
+/*
+ * sendto_realops
+ *
+ * Send to *local* ops only but NOT +s nonopers.
+ * If it's to local ops only and not +s nonopers, then SendServNotice is
+ * wrong. Changed to IsAnOper. -mjs
+ */
+void sendto_realops(char *pattern, ...)
+{
+ va_list vl;
+
+ va_start(vl, pattern);
+ vsendto_realops(pattern, vl);
+ va_end(vl);
+}
+
+/*
+ * sendto_realops_lev
+ *
+ * Send to *local* ops only but NOT +s nonopers at a certain level
+ */
+void sendto_realops_lev(int lev, char *pattern, ...)
+{
+ aClient *cptr;
+ char nbuf[1024];
+ va_list vl;
+ DLink *lp;
+ char *tmsg;
+
+ va_start(vl, pattern);
+
+#ifdef NICER_UMODENOTICE_SEPARATION
+ switch(lev)
+ {
+ case CCONN_LEV:
+ tmsg = "Client";
+ break;
+
+ case DEBUG_LEV:
+ tmsg = "Debug";
+ break;
+
+ case SPY_LEV:
+ tmsg = "Spy";
+ break;
+
+ case SPAM_LEV:
+ tmsg = "Spam";
+ break;
+
+ case FLOOD_LEV:
+ tmsg = "Flood";
+ break;
+
+ case DCCSEND_LEV:
+ tmsg = "DCCAllow";
+ break;
+
+ default:
+ tmsg = "Notice";
+ }
+#else
+ tmsg = "Notice";
+#endif
+
+ for (lp = oper_list; lp; lp = lp->next)
+ {
+ cptr = lp->value.cptr;
+ switch (lev)
+ {
+ case CCONN_LEV:
+ if (!SendCConnNotice(cptr))
+ continue;
+ break;
+ case REJ_LEV:
+ if (!SendRejNotice(cptr))
+ continue;
+ break;
+ case SKILL_LEV:
+ if (!SendSkillNotice(cptr))
+ continue;
+ break;
+ case USKILL_LEV:
+ if (!SendSUkillNotice(cptr))
+ continue;
+ break;
+ case SPY_LEV:
+ if (!SendSpyNotice(cptr))
+ continue;
+ break;
+ case DCCSEND_LEV:
+ if (!SendDCCNotice(cptr))
+ continue;
+ break;
+ case FLOOD_LEV:
+ if (!SendFloodNotice(cptr))
+ continue;
+ break;
+ case SPAM_LEV:
+ if (!SendSpamNotice(cptr))
+ continue;
+ break;
+ case DEBUG_LEV:
+ if (!SendDebugNotice(cptr))
+ continue;
+ break;
+ }
+ ircsnprintf(nbuf, 1024, ":%s NOTICE %s :*** %s -- %s",
+ me.name, cptr->name, tmsg, pattern);
+ vsendto_one(cptr, nbuf, vl);
+ }
+ va_end(vl);
+ return;
+}
+
+/*
+ * ts_warn
+ * Call sendto_ops, with some flood checking (at most 5 warnings
+ * every 5 seconds)
+ */
+
+void ts_warn(char * pattern, ...)
+{
+ static ts_val last = 0;
+ static int warnings = 0;
+ ts_val now;
+ va_list vl;
+
+ va_start(vl, pattern);
+ /*
+ * if we're running with TS_WARNINGS enabled and someone does
+ * something silly like (remotely) connecting a nonTS server,
+ * we'll get a ton of warnings, so we make sure we don't send more
+ * than 5 every 5 seconds. -orabidoo
+ */
+ now = time(NULL);
+ if (now - last < 5)
+ {
+ if (++warnings > 5)
+ return;
+ }
+ else
+ {
+ last = now;
+ warnings = 0;
+ }
+
+ vsendto_realops(pattern, vl);
+ va_end(vl);
+ return;
+}
+
+/*
+ * sendto_locops
+ */
+void sendto_locops(char *pattern, ...)
+{
+ aClient *cptr;
+ char nbuf[1024];
+ va_list vl;
+ DLink *lp;
+
+ va_start(vl, pattern);
+
+ for (lp = oper_list; lp; lp = lp->next)
+ {
+ cptr = lp->value.cptr;
+
+ if (SendGlobops(cptr))
+ {
+ ircsprintf(nbuf, ":%s NOTICE %s :*** LocOps -- %s",
+ me.name, cptr->name, pattern);
+ vsendto_one(cptr, nbuf, vl);
+ }
+ }
+ va_end(vl);
+ return;
+}
+
+/* sendto_gnotice - send a routing notice to all local +n users. */
+void sendto_gnotice(char *pattern, ...)
+{
+ aClient *cptr;
+ char nbuf[1024];
+ va_list vl;
+ DLink *lp;
+
+ va_start(vl, pattern);
+
+ for (lp = oper_list; lp; lp = lp->next)
+ {
+ cptr = lp->value.cptr;
+ if (SendRnotice(cptr))
+ {
+ ircsprintf(nbuf, ":%s NOTICE %s :*** Routing -- %s",
+ me.name, cptr->name, pattern);
+ vsendto_one(cptr, nbuf, vl);
+ }
+ }
+ va_end(vl);
+ return;
+}
+
+/*
+ * sendto_channelops_butone
+ * Send a message to all OPs in channel chptr that
+ * are directly on this server and sends the message
+ * on to the next server if it has any OPs.
+ */
+void sendto_channelops_butone(aClient *one, aClient *from, aChannel *chptr,
+ char *pattern, ...)
+{
+ chanMember *cm;
+ aClient *acptr;
+ int i;
+ va_list vl;
+
+ va_start(vl, pattern);
+
+ INC_SERIAL
+ for (cm = chptr->members; cm; cm = cm->next)
+ {
+ acptr = cm->cptr;
+ if (acptr->from == one ||
+ !(cm->flags & CHFL_CHANOP))
+ continue;
+
+ if(confopts & FLAGS_SERVHUB)
+ if(acptr && acptr->user && acptr->user->server &&
+ (!mycmp(acptr->user->server,Services_Name) ||
+ !mycmp(acptr->user->server,Stats_Name)))
+ continue;
+
+ i = acptr->from->fd;
+ if (MyConnect(acptr) && IsRegisteredUser(acptr))
+ {
+ vsendto_prefix_one(acptr, from, pattern, vl);
+ sentalong[i] = sent_serial;
+ }
+ else
+ {
+ /*
+ * Now check whether a message has been sent to this
+ * remote link already
+ */
+ if (sentalong[i] != sent_serial)
+ {
+ vsendto_prefix_one(acptr, from, pattern, vl);
+
+ sentalong[i] = sent_serial;
+ }
+ }
+ }
+ va_end(vl);
+ return;
+}
+
+/*
+ * sendto_channelvoice_butone
+ * Send a message to all voiced users in channel chptr that
+ * are directly on this server and sends the message
+ * on to the next server if it has any voiced users.
+ */
+void sendto_channelvoice_butone(aClient *one, aClient *from, aChannel *chptr,
+ char *pattern, ...)
+{
+ chanMember *cm;
+ aClient *acptr;
+ int i, didlocal = 0, didremote = 0;
+ va_list vl;
+ char *pfix;
+ void *share_buf[2] = { 0, 0 };
+
+ va_start(vl, pattern);
+ pfix = va_arg(vl, char *);
+
+ INC_SERIAL
+
+ for (cm = chptr->members; cm; cm = cm->next)
+ {
+ acptr = cm->cptr;
+ if (acptr->from == one || !(cm->flags & CHFL_VOICE))
+ continue;
+ if(confopts & FLAGS_SERVHUB)
+ if(acptr && acptr->user && acptr->user->server &&
+ (!mycmp(acptr->user->server,Services_Name) ||
+ !mycmp(acptr->user->server,Stats_Name)))
+ continue;
+ i = acptr->from->fd;
+ if (MyConnect(acptr) && IsRegisteredUser(acptr))
+ {
+ if (!didlocal)
+ {
+ didlocal = prefix_buffer(0, from, pfix, sendbuf, pattern, vl);
+ sbuf_begin_share(sendbuf, didlocal, &share_buf[0]);
+ }
+ send_message(acptr, sendbuf, didlocal, share_buf[0]);
+ /* vsendto_prefix_one(acptr, from, pattern, vl); */
+ sentalong[i] = sent_serial;
+ }
+ else
+ {
+ /*
+ * Now check whether a message has been sent to this
+ * remote link already
+ */
+ if (sentalong[i] != sent_serial)
+ {
+ if (!didremote)
+ {
+ didremote = prefix_buffer(1, from, pfix, remotebuf,
+ pattern, vl);
+ sbuf_begin_share(remotebuf, didremote, &share_buf[1]);
+ }
+ send_message(acptr, remotebuf, didremote, share_buf[1]);
+ /* vsendto_prefix_one(acptr, from, pattern, vl); */
+ sentalong[i] = sent_serial;
+ }
+ }
+ }
+ sbuf_end_share(share_buf, 2);
+ va_end(vl);
+}
+
+/*
+ * sendto_channelvoiceops_butone
+ * Send a message to all OPs or voiced users in channel chptr that
+ * are directly on this server and sends the message
+ * on to the next server if it has any OPs or voiced users.
+ */
+void sendto_channelvoiceops_butone(aClient *one, aClient *from, aChannel
+ *chptr, char *pattern, ...)
+{
+ chanMember *cm;
+ aClient *acptr;
+ int i, didlocal = 0, didremote = 0;
+ char *pfix;
+ va_list vl;
+ void *share_buf[2] = { 0, 0 };
+
+ va_start(vl, pattern);
+ pfix = va_arg(vl, char *);
+
+ INC_SERIAL
+
+ for (cm = chptr->members; cm; cm = cm->next)
+ {
+ acptr = cm->cptr;
+ if (acptr->from == one || !((cm->flags & CHFL_VOICE) ||
+ (cm->flags & CHFL_CHANOP)))
+ continue;
+
+ if(confopts & FLAGS_SERVHUB)
+ if(acptr && acptr->user && acptr->user->server &&
+ (!mycmp(acptr->user->server,Services_Name) ||
+ !mycmp(acptr->user->server,Stats_Name)))
+ continue;
+
+ i = acptr->from->fd;
+ if (MyConnect(acptr) && IsRegisteredUser(acptr))
+ {
+ if (!didlocal)
+ {
+ didlocal = prefix_buffer(0, from, pfix, sendbuf, pattern, vl);
+ sbuf_begin_share(sendbuf, didlocal, &share_buf[0]);
+ }
+ send_message(acptr, sendbuf, didlocal, share_buf[0]);
+ /* vsendto_prefix_one(acptr, from, pattern, vl); */
+ sentalong[i] = sent_serial;
+ }
+ else /* remote link */
+ {
+ if (sentalong[i] != sent_serial)
+ {
+ if (!didremote)
+ {
+ didremote = prefix_buffer(1, from, pfix, remotebuf,
+ pattern, vl);
+ sbuf_begin_share(remotebuf, didremote, &share_buf[1]);
+ }
+ send_message(acptr, remotebuf, didremote, share_buf[1]);
+ /* vsendto_prefix_one(acptr, from, pattern, vl); */
+ sentalong[i] = sent_serial;
+ }
+ }
+ }
+ sbuf_end_share(share_buf, 2);
+}
+
+/*******************************************
+ * Flushing functions (empty queues)
+ *******************************************/
+
+/*
+ * flush_connections
+ * Empty only buffers for clients without FLAGS_BLOCKED
+ * dump_connections
+ * Unintelligently try to empty all buffers.
+ */
+void flush_connections(int fd)
+{
+ int i;
+ aClient *cptr;
+
+ if (fd == me.fd)
+ {
+ for (i = highest_fd; i >= 0; i--)
+ {
+ if (!(cptr = local[i]))
+ continue;
+ if(!(cptr->flags & FLAGS_BLOCKED) &&
+ (SBufLength(&cptr->sendQ) > 0 ||
+ (ZipOut(cptr) && zip_is_data_out(cptr->serv->zip_out))))
+ send_queued(cptr);
+ }
+ }
+ else if (fd >= 0 && (cptr = local[fd]) &&
+ !(cptr->flags & FLAGS_BLOCKED) &&
+ (SBufLength(&cptr->sendQ) > 0 ||
+ (ZipOut(cptr) && zip_is_data_out(cptr->serv->zip_out))))
+ send_queued(cptr);
+}
+
+void dump_connections(int fd)
+{
+ int i;
+ aClient *cptr;
+
+ if (fd == me.fd)
+ {
+ for (i = highest_fd; i >= 0; i--)
+ if ((cptr = local[i]) &&
+ (SBufLength(&cptr->sendQ) > 0 ||
+ (ZipOut(cptr) && zip_is_data_out(cptr->serv->zip_out))))
+ send_queued(cptr);
+ }
+ else if (fd >= 0 && (cptr = local[fd]) &&
+ (SBufLength(&cptr->sendQ) > 0 ||
+ (ZipOut(cptr) && zip_is_data_out(cptr->serv->zip_out))))
+ send_queued(cptr);
+}
+
+/* flush an fdlist intelligently */
+void flush_fdlist_connections(fdlist *listp)
+{
+ int i, fd;
+ aClient *cptr;
+
+ for (fd = listp->entry[i = 1]; i <= listp->last_entry;
+ fd = listp->entry[++i])
+ if ((cptr = local[fd]) && !(cptr->flags & FLAGS_BLOCKED) &&
+ (SBufLength(&cptr->sendQ) > 0 ||
+ (ZipOut(cptr) && zip_is_data_out(cptr->serv->zip_out))))
+ send_queued(cptr);
+}
--- /dev/null
+************************************************************************
+* IRC - Internet Relay Chat, src/socketengine_devpoll.c
+* Copyright (C) 2004 David Parton
+*
+* engine functions for the /dev/poll socket engine
+*
+*/
+
+/* $Id: socketengine_devpoll.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include "fds.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/devpoll.h>
+#include <sys/poll.h>
+
+static int devpoll_id = -1, numfds = 0;
+
+void engine_init()
+{
+ devpoll_id = open("/dev/poll", O_RDWR);
+}
+
+void engine_add_fd(int fd)
+{
+ struct pollfd dev_fd;
+
+ if (numfds >= MAXCONNECTIONS)
+ abort();
+
+ dev_fd.events = 0;
+ dev_fd.revents = 0;
+ dev_fd.fd = fd;
+ if (write(devpoll_id, &dev_fd, sizeof(struct pollfd)) != sizeof(struct pollfd))
+ abort();
+
+ set_fd_internal(fd, 0);
+ ++numfds;
+}
+
+void engine_del_fd(int fd)
+{
+ struct pollfd dev_fd;
+
+ dev_fd.events = POLLREMOVE;
+ dev_fd.revents = 0;
+ dev_fd.fd = fd;
+ if (write(devpoll_id, &dev_fd, sizeof(struct pollfd)) != sizeof(struct pollfd))
+ abort();
+
+ --numfds;
+}
+
+void engine_change_fd_state(int fd, unsigned int stateplus)
+{
+ unsigned int events = 0;
+ struct pollfd dev_fd;
+
+ if (stateplus & FDF_WANTWRITE) events |= POLLOUT;
+ if (stateplus & FDF_WANTREAD) events |= POLLIN|POLLHUP|POLLERR;
+
+ dev_fd.events = events;
+ dev_fd.revents = 0;
+ dev_fd.fd = fd;
+
+ if (write(devpoll_id, &dev_fd, sizeof(struct pollfd)) != sizeof(struct pollfd))
+ abort();
+
+ set_fd_internal(fd, (void*)events);
+}
+
+#define ENGINE_MAX_EVENTS 512
+#define ENGINE_MAX_LOOPS (2 * (MAXCONNECTIONS / 512))
+
+int engine_read_message(time_t delay)
+{
+ struct pollfd events[ENGINE_MAX_EVENTS], *pevent;
+ struct dvpoll dopoll;
+ int nfds, i, numloops = 0, eventsfull;
+ unsigned int fdflags, fdevents;
+ int fdtype;
+ void *fdvalue;
+ aClient *cptr;
+ aListener *lptr;
+
+ dopoll.dp_fds = events;
+ dopoll.dp_nfds = ENGINE_MAX_EVENTS;
+ dopoll.dp_timeout = delay;
+ do
+ {
+ nfds = ioctl(devpoll_id, DP_POLL, &dopoll);
+
+ if (nfds < 0)
+ {
+ if (errno == EINTR || errno == EAGAIN)
+ return -1;
+
+ report_error("ioctl(devpoll): %s:%s", &me);
+ sleep(5);
+ return -1;
+ }
+ eventsfull = nfds == ENGINE_MAX_EVENTS;
+
+ if (delay || numloops)
+ NOW = timeofday = time(NULL);
+ numloops++;
+
+ for (i = 0, pevent = events; i < nfds; i++, pevent++)
+ {
+ fdevents = (unsigned int)get_fd_internal(pevent->fd);
+ if (pevent->fd != -1)
+ {
+ int rr = (pevent->revents & (POLLIN|POLLHUP|POLLERR)) && (fdevents & (POLLIN|POLLHUP|POLLERR));
+ int rw = (pevent->revents & POLLOUT) && (fdevents & POLLOUT);
+
+ get_fd_info(pevent->fd, &fdtype, &fdflags, &fdvalue);
+
+ switch (fdtype)
+ {
+ case FDT_NONE:
+ break;
+
+ case FDT_AUTH:
+ cptr = (aClient*)fdvalue;
+ if (rr) read_authports(cptr);
+ if (rw && cptr->authfd >= 0) send_authports(cptr);
+ check_client_fd(cptr);
+ break;
+
+ case FDT_LISTENER:
+ lptr = (aListener*)fdvalue;
+ if (rr) accept_connection(lptr);
+ break;
+
+ case FDT_RESOLVER:
+ do_dns_async();
+ break;
+
+ case FDT_CLIENT:
+ cptr = (aClient*)fdvalue;
+ readwrite_client(cptr, rr, rw);
+ break;
+
+ case FDT_CALLBACKP:
+ {
+ struct fd_callbackp *fdcb = (struct fd_callbackp*)fdvalue;
+
+ fdcb->rdf = rr;
+ fdcb->wrf = rw;
+ (*fdcb->callback)(fdcb);
+ break;
+ }
+
+ default:
+ abort();
+ }
+ }
+ }
+ } while (eventsfull && numloops < ENGINE_MAX_LOOPS);
+
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/socketengine_epoll.c
+ * Copyright (C) 2004 David Parton
+ *
+ * engine functions for the /dev/epoll socket engine
+ *
+ */
+
+ /* $Id: socketengine_epoll.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include "fds.h"
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/epoll.h>
+
+#ifdef NEED_EPOLL_DEFS
+#include <asm/unistd.h>
+
+_syscall1(int, epoll_create, int, size)
+_syscall4(int, epoll_ctl, int, epfd, int, op, int, fd, struct epoll_event*, event)
+_syscall4(int, epoll_wait, int, epfd, struct epoll_event*, pevents, int, maxevents, int, timeout)
+
+#endif
+
+static int epoll_id = -1, numfds = 0;
+static struct epoll_fd
+{
+ int fd;
+ unsigned int events;
+} epoll_fds[MAXCONNECTIONS];
+
+
+void engine_init()
+{
+ epoll_id = epoll_create(MAXCONNECTIONS);
+ memset(epoll_fds, 0, sizeof(epoll_fds));
+}
+
+void engine_add_fd(int fd)
+{
+ struct epoll_event ev;
+
+ if (numfds >= MAXCONNECTIONS)
+ abort();
+
+ ev.events = 0;
+ ev.data.ptr = &epoll_fds[numfds];
+ if (epoll_ctl(epoll_id, EPOLL_CTL_ADD, fd, &ev) < 0)
+ abort();
+
+ epoll_fds[numfds].fd = fd;
+ epoll_fds[numfds].events = 0;
+ set_fd_internal(fd, (void*)&epoll_fds[numfds]);
+ ++numfds;
+}
+
+void engine_del_fd(int fd)
+{
+ struct epoll_event ev;
+ struct epoll_fd *epfd = (struct epoll_fd*)get_fd_internal(fd);
+
+ if (epoll_ctl(epoll_id, EPOLL_CTL_DEL, fd, &ev) < 0)
+ abort();
+
+ if (epfd - epoll_fds != numfds - 1)
+ {
+ *epfd = epoll_fds[numfds-1];
+ set_fd_internal(epfd->fd, (void*)epfd);
+
+ /* update the epoll internal pointer as well */
+ ev.events = epfd->events;
+ ev.data.ptr = epfd;
+ if (epoll_ctl(epoll_id, EPOLL_CTL_MOD, epfd->fd, &ev) < 0)
+ abort();
+ }
+
+ --numfds;
+}
+
+void engine_change_fd_state(int fd, unsigned int stateplus)
+{
+ struct epoll_event ev;
+ struct epoll_fd *epfd = (struct epoll_fd*)get_fd_internal(fd);
+
+ ev.events = 0;
+ ev.data.ptr = epfd;
+ if (stateplus & FDF_WANTWRITE) ev.events |= EPOLLOUT;
+ if (stateplus & FDF_WANTREAD) ev.events |= EPOLLIN|EPOLLHUP|EPOLLERR;
+
+ if (ev.events != epfd->events)
+ {
+ epfd->events = ev.events;
+ if (epoll_ctl(epoll_id, EPOLL_CTL_MOD, fd, &ev) < 0)
+ abort();
+ }
+}
+
+#define ENGINE_MAX_EVENTS 512
+#define ENGINE_MAX_LOOPS (2 * (MAXCONNECTIONS / 512))
+
+int engine_read_message(time_t delay)
+{
+ struct epoll_event events[ENGINE_MAX_EVENTS], *pevent;
+ struct epoll_fd* epfd;
+ int nfds, i, numloops = 0, eventsfull;
+ unsigned int fdflags;
+ int fdtype;
+ void *fdvalue;
+ aClient *cptr;
+ aListener *lptr;
+
+ do
+ {
+ nfds = epoll_wait(epoll_id, events, ENGINE_MAX_EVENTS, delay * 1000);
+
+ if (nfds == -1)
+ {
+ if (errno == EINTR || errno == EAGAIN)
+ return -1;
+
+ report_error("epoll_wait: %s:%s", &me);
+ sleep(5);
+ return -1;
+ }
+ eventsfull = nfds == ENGINE_MAX_EVENTS;
+
+ if (delay || numloops)
+ NOW = timeofday = time(NULL);
+ numloops++;
+
+ for (i = 0, pevent = events; i < nfds; i++, pevent++)
+ {
+ epfd = pevent->data.ptr;
+ if (epfd->fd != -1)
+ {
+ int rr = (epfd->events & pevent->events) & (EPOLLIN|EPOLLHUP|EPOLLERR);
+ int rw = (epfd->events & pevent->events) & EPOLLOUT;
+
+ get_fd_info(epfd->fd, &fdtype, &fdflags, &fdvalue);
+
+ switch (fdtype)
+ {
+ case FDT_NONE:
+ break;
+
+ case FDT_AUTH:
+ cptr = (aClient*)fdvalue;
+ if (rr) read_authports(cptr);
+ if (rw && cptr->authfd >= 0) send_authports(cptr);
+ check_client_fd(cptr);
+ break;
+
+ case FDT_LISTENER:
+ lptr = (aListener*)fdvalue;
+ if (rr) accept_connection(lptr);
+ break;
+
+ case FDT_RESOLVER:
+ do_dns_async();
+ break;
+
+ case FDT_CLIENT:
+ cptr = (aClient*)fdvalue;
+ readwrite_client(cptr, rr, rw);
+ break;
+
+ case FDT_CALLBACKP:
+ {
+ struct fd_callbackp *fdcb = (struct fd_callbackp*)fdvalue;
+
+ fdcb->rdf = rr;
+ fdcb->wrf = rw;
+ (*fdcb->callback)(fdcb);
+ break;
+ }
+
+ default:
+ abort();
+ }
+ }
+ }
+ } while (eventsfull && numloops < ENGINE_MAX_LOOPS);
+
+ return 0;
+}
+
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/socketengine_kqueue.c
+ * Copyright (C) 2003 Lucas Madar
+ *
+ * engine functions for the kqueue() socket engine
+ *
+ */
+
+/* $Id: socketengine_kqueue.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include "fds.h"
+
+#include <sys/event.h>
+#include <sys/time.h>
+
+#define MAX_EVENT_QUEUE 64
+
+static int kqueue_id = -1;
+static struct kevent eventQs[2][MAX_EVENT_QUEUE+1];
+static struct kevent *eventQ = eventQs[0];
+static int eventQi = 0;
+static int numEvents = 0;
+
+static void
+kevent_add(struct kevent *e)
+{
+ if(kqueue_id == -1)
+ abort();
+
+ if(numEvents >= MAX_EVENT_QUEUE)
+ {
+ if(kevent(kqueue_id, eventQ, numEvents, NULL, 0, NULL) < 0)
+ sendto_realops_lev(DEBUG_LEV, "kevent() returned error: %s",
+ strerror(errno));
+ numEvents = 0;
+ }
+ memcpy(&eventQ[numEvents++], e, sizeof(struct kevent));
+}
+
+void
+engine_init()
+{
+ kqueue_id = kqueue();
+ numEvents = 0;
+}
+
+void
+engine_add_fd(int fd)
+{
+ struct kevent e;
+
+ e.ident = fd;
+ e.filter = EVFILT_READ;
+ e.flags = EV_ADD|EV_DISABLE;
+ e.fflags = 0;
+ e.data = 0;
+ e.udata = NULL;
+ kevent_add(&e);
+
+ e.ident = fd;
+ e.filter = EVFILT_WRITE;
+ e.flags = EV_ADD|EV_DISABLE;
+ e.fflags = 0;
+ e.data = 0;
+ e.udata = NULL;
+ kevent_add(&e);
+
+ set_fd_internal(fd, 0);
+}
+
+void
+engine_del_fd(int fd)
+{
+/* we dont accually need to do this, as a close() clears the kevent
+ * filters and automagically removes itself from the queue.
+ * With the way we handle kevent() calls in kevent_add(), accually
+ * running these EV_DELETE routines causes bad file descriptor returns
+ * due to the fact that they could be close()'d before the kevent() is
+ * run. --epi
+ */
+
+/********
+
+ struct kevent e;
+
+ e.ident = fd;
+ e.filter = EVFILT_READ;
+ e.flags = EV_DELETE;
+ e.fflags = 0;
+ e.data = 0;
+ e.udata = NULL;
+ kevent_add(&e);
+
+ e.ident = fd;
+ e.filter = EVFILT_WRITE;
+ e.flags = EV_DELETE;
+ e.fflags = 0;
+ e.data = 0;
+ e.udata = NULL;
+ kevent_add(&e);
+
+********/
+
+ /* But we should remove this fd from the change queue -- if it was closed
+ * and we have a change pending, kevent() will fail later. What's worse
+ * is that when the queue is flushed due to being full, a kevent() failure
+ * may leave some changes unprocessed. Reordering the change queue is not
+ * safe, hence the gymnastics below. -Quension
+ */
+ int i, j;
+
+ if (!numEvents)
+ return;
+
+ /* optimal case: fd isn't in the change queue */
+ for (i = 0; i < numEvents; i++)
+ if (eventQ[i].ident == fd)
+ break;
+
+ /* second optimal case: fd is last, truncate the queue */
+ if (i == numEvents - 1)
+ numEvents--;
+
+ if (i == numEvents)
+ return;
+
+ /* swap array index, copy all fds before this one */
+ eventQi ^= 1;
+ memcpy(eventQs[eventQi], eventQ, sizeof(struct kevent) * i);
+
+ /* selectively copy remaining fds, skip bad one */
+ for (j = i++; i < numEvents; i++)
+ if (eventQ[i].ident != fd)
+ memcpy(&eventQs[eventQi][j++], &eventQ[i], sizeof(struct kevent));
+
+ /* swap active array */
+ numEvents = j;
+ eventQ = eventQs[eventQi];
+}
+
+void
+engine_change_fd_state(int fd, unsigned int stateplus)
+{
+ unsigned int oldflags = (unsigned int) get_fd_internal(fd);
+ struct kevent e;
+
+ /* Something changed with our read state? */
+ if((oldflags ^ stateplus) & FDF_WANTREAD)
+ {
+ e.ident = fd;
+ e.filter = EVFILT_READ;
+ e.flags = EV_ADD|((stateplus & FDF_WANTREAD) ? EV_ENABLE : EV_DISABLE);
+ e.fflags = 0;
+ e.data = 0;
+ e.udata = 0;
+ kevent_add(&e);
+ }
+
+ /* Something changed with our write state? */
+ if((oldflags ^ stateplus) & FDF_WANTWRITE)
+ {
+ e.ident = fd;
+ e.filter = EVFILT_WRITE;
+ e.flags = EV_ADD|((stateplus & FDF_WANTWRITE) ? EV_ENABLE : EV_DISABLE);
+ e.fflags = 0;
+ e.data = 0;
+ e.udata = 0;
+ kevent_add(&e);
+ }
+
+ set_fd_internal(fd, (void *) stateplus);
+}
+
+#define ENGINE_MAX_EVENTS 512
+#define ENGINE_MAX_LOOPS (2 * (MAXCONNECTIONS / 512))
+
+int
+engine_read_message(time_t delay)
+{
+ static struct kevent events[ENGINE_MAX_EVENTS];
+
+ int nevs, length, i, numloops, eventsfull;
+ unsigned int fdflags;
+ int fdtype;
+ void *fdvalue;
+ aClient *cptr;
+ aListener *lptr;
+ struct timespec wait;
+
+ numloops = 0;
+ wait.tv_sec = delay;
+ wait.tv_nsec = 0;
+
+ do
+ {
+ nevs = kevent(kqueue_id, eventQ, numEvents, events,
+ ENGINE_MAX_EVENTS, &wait);
+ numEvents = 0;
+
+ if(nevs == 0)
+ return 0;
+
+ if (nevs < 0)
+ {
+ if((errno == EINTR) || (errno == EAGAIN))
+ return -1;
+
+ report_error("kevent %s:%s", &me);
+ sleep(5);
+ return -1;
+ }
+
+ eventsfull = (nevs == ENGINE_MAX_EVENTS) ? 1 : 0;
+ if(delay || numloops)
+ NOW = timeofday = time(NULL);
+ numloops++;
+
+ for(i = 0; i < nevs; i++)
+ {
+ int rr = 0, rw = 0;
+
+ if(events[i].flags & EV_ERROR)
+ {
+ errno = events[i].data;
+ /* this should be handled later i suppose */
+ continue;
+ }
+
+ get_fd_info(events[i].ident, &fdtype, &fdflags, &fdvalue);
+
+ if(events[i].filter == EVFILT_READ)
+ rr = 1;
+ else if(events[i].filter == EVFILT_WRITE)
+ rw = 1;
+
+ cptr = NULL;
+ length = -1;
+
+ switch(fdtype)
+ {
+ case FDT_NONE:
+ break;
+
+ case FDT_AUTH:
+ cptr = (aClient *) fdvalue;
+ if (rr)
+ read_authports(cptr);
+ else if (rw && cptr->authfd >= 0)
+ send_authports(cptr);
+ check_client_fd(cptr);
+ break;
+
+ case FDT_LISTENER:
+ lptr = (aListener *) fdvalue;
+ if(rr)
+ accept_connection(lptr);
+ break;
+
+ case FDT_RESOLVER:
+ do_dns_async();
+ break;
+
+ case FDT_CLIENT:
+ cptr = (aClient *) fdvalue;
+ readwrite_client(cptr, rr, rw);
+ break;
+
+ case FDT_CALLBACKP:
+ {
+ struct fd_callbackp *fdcb = (struct fd_callbackp *) fdvalue;
+
+ fdcb->rdf = rr;
+ fdcb->wrf = rw;
+ (*fdcb->callback)(fdcb);
+ }
+ break;
+
+ default:
+ abort(); /* unknown client type? bail! */
+ }
+ }
+ } while(eventsfull && (numloops < ENGINE_MAX_LOOPS));
+
+ return 0;
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/socketengine_poll.c
+ * Copyright (C) 2003 Lucas Madar
+ *
+ * engine functions for the poll() socket engine
+ *
+ */
+
+/* $Id: socketengine_poll.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include "fds.h"
+
+#include <sys/poll.h>
+
+struct pollfd poll_fds[MAXCONNECTIONS];
+int last_pfd = -1;
+
+void engine_init()
+{
+}
+
+void engine_add_fd(int fd)
+{
+ struct pollfd *pfd = &poll_fds[++last_pfd];
+
+ /* sanity check */
+ if(last_pfd >= MAXCONNECTIONS)
+ abort();
+
+ set_fd_internal(fd, (void *) last_pfd);
+
+ pfd->fd = fd;
+ pfd->events = 0;
+ pfd->revents = 0;
+}
+
+void engine_del_fd(int fd)
+{
+ int arrayidx = (int) get_fd_internal(fd);
+
+ /* If it's at the end of the array, just chop it off */
+ if(arrayidx == last_pfd)
+ {
+ fdfprintf(stderr, "Removing %d[%d] from end of pollfds\n", last_pfd, fd);
+ last_pfd--;
+ return;
+ }
+
+ /* Otherwise, move the last array member to where the old one was */
+ fdfprintf(stderr, "Moving pfd %d[%d] to vacated spot %d[%d] -- now %d[%d]\n",
+ last_pfd, poll_fds[last_pfd].fd, arrayidx, fd, last_pfd, fd);
+ memcpy(&poll_fds[arrayidx], &poll_fds[last_pfd], sizeof(struct pollfd));
+ last_pfd--;
+ set_fd_internal(poll_fds[arrayidx].fd, (void *) arrayidx);
+}
+
+void engine_change_fd_state(int fd, unsigned int stateplus)
+{
+ int arrayidx = (int) get_fd_internal(fd);
+ struct pollfd *pfd = &poll_fds[arrayidx];
+
+ pfd->events = 0;
+ if(stateplus & FDF_WANTREAD)
+ pfd->events |= POLLIN|POLLHUP|POLLERR;
+ if(stateplus & FDF_WANTWRITE)
+ pfd->events |= POLLOUT;
+}
+
+void engine_get_pollfds(struct pollfd **pfds, int *numpfds)
+{
+ *pfds = poll_fds;
+ *numpfds = (last_pfd + 1);
+}
+
+int engine_read_message(time_t delay)
+{
+ static struct pollfd poll_fdarray[MAXCONNECTIONS];
+
+ struct pollfd *pfd;
+ int nfds, nbr_pfds, length, i;
+ unsigned int fdflags;
+ int fdtype;
+ void *fdvalue;
+ aClient *cptr;
+ aListener *lptr;
+
+ engine_get_pollfds(&pfd, &nbr_pfds);
+ memcpy(poll_fdarray, pfd, sizeof(struct pollfd) * nbr_pfds);
+
+ nfds = poll(poll_fdarray, nbr_pfds, delay * 1000);
+ if (nfds == -1)
+ {
+ if(((errno == EINTR) || (errno == EAGAIN)))
+ return -1;
+ report_error("poll %s:%s", &me);
+ sleep(5);
+ return -1;
+ }
+
+ if(delay)
+ NOW = timeofday = time(NULL);
+
+ for (pfd = poll_fdarray, i = 0; nfds && (i < nbr_pfds); i++, pfd++)
+ {
+ get_fd_info(pfd->fd, &fdtype, &fdflags, &fdvalue);
+
+ cptr = NULL;
+ length = -1;
+
+ if (nfds && pfd->revents)
+ {
+ int rr = pfd->revents & (POLLIN|POLLHUP|POLLERR);
+ int rw = pfd->revents & (POLLOUT);
+
+ fdfprintf(stderr, "fd %d: %s%s\n", pfd->fd, rr ? "read " : "", rw ? "write" : "");
+
+ nfds--;
+
+ switch(fdtype)
+ {
+ case FDT_NONE:
+ break;
+
+ case FDT_AUTH:
+ cptr = (aClient *) fdvalue;
+ if (rr)
+ read_authports(cptr);
+ if (rw && cptr->authfd >= 0)
+ send_authports(cptr);
+ check_client_fd(cptr);
+ break;
+
+ case FDT_LISTENER:
+ lptr = (aListener *) fdvalue;
+ if(rr)
+ accept_connection(lptr);
+ break;
+
+ case FDT_RESOLVER:
+ do_dns_async();
+ break;
+
+ case FDT_CLIENT:
+ cptr = (aClient *) fdvalue;
+ readwrite_client(cptr, rr, rw);
+ break;
+
+ case FDT_CALLBACKP:
+ {
+ struct fd_callbackp *fdcb = (struct fd_callbackp *) fdvalue;
+
+ fdcb->rdf = rr;
+ fdcb->wrf = rw;
+ (*fdcb->callback)(fdcb);
+ }
+ break;
+
+ default:
+ abort(); /* unknown client type? bail! */
+ }
+ }
+ } /* end of for() loop for testing polled sockets */
+
+ return 0;
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/socketengine_select.c
+ * Copyright (C) 2003 Lucas Madar
+ *
+ * engine functions for the select() socket engine
+ *
+ */
+
+/* $Id: socketengine_select.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include "fds.h"
+
+static fd_set g_read_set, g_write_set;
+
+void engine_init()
+{
+ FD_ZERO(&g_read_set);
+ FD_ZERO(&g_write_set);
+}
+
+void engine_add_fd(int fd)
+{
+ set_fd_internal(fd, (void *) 0);
+}
+
+void engine_del_fd(int fd)
+{
+ FD_CLR(fd, &g_read_set);
+ FD_CLR(fd, &g_write_set);
+}
+
+void engine_change_fd_state(int fd, unsigned int stateplus)
+{
+ int prevstate = (int) get_fd_internal(fd);
+
+ if((stateplus & FDF_WANTREAD) && !(prevstate & FDF_WANTREAD))
+ {
+ FD_SET(fd, &g_read_set);
+ prevstate |= FDF_WANTREAD;
+ }
+ else if(!(stateplus & FDF_WANTREAD) && (prevstate & FDF_WANTREAD))
+ {
+ FD_CLR(fd, &g_read_set);
+ prevstate &= ~(FDF_WANTREAD);
+ }
+
+ if((stateplus & FDF_WANTWRITE) && !(prevstate & FDF_WANTWRITE))
+ {
+ FD_SET(fd, &g_write_set);
+ prevstate |= FDF_WANTWRITE;
+ }
+ else if(!(stateplus & FDF_WANTWRITE) && (prevstate & FDF_WANTWRITE))
+ {
+ FD_CLR(fd, &g_write_set);
+ prevstate &= ~(FDF_WANTWRITE);
+ }
+
+ set_fd_internal(fd, (void *) prevstate);
+}
+
+static void engine_get_fdsets(fd_set *r, fd_set *w)
+{
+ memcpy(r, &g_read_set, sizeof(fd_set));
+ memcpy(w, &g_write_set, sizeof(fd_set));
+}
+
+int engine_read_message(time_t delay)
+{
+ fd_set read_set, write_set;
+ struct timeval wt;
+ int nfds, length, i;
+ unsigned int fdflags;
+ int fdtype;
+ void *fdvalue;
+ aClient *cptr;
+ aListener *lptr;
+
+ engine_get_fdsets(&read_set, &write_set);
+
+ wt.tv_sec = delay;
+ wt.tv_usec = 0;
+
+ nfds = select(MAXCONNECTIONS, &read_set, &write_set, NULL, &wt);
+ if (nfds == -1)
+ {
+ if(((errno == EINTR) || (errno == EAGAIN)))
+ return -1;
+ report_error("select %s:%s", &me);
+ sleep(5);
+ return -1;
+ }
+ else if (nfds == 0)
+ return 0;
+
+ if(delay)
+ NOW = timeofday = time(NULL);
+
+ for (i = 0; i < MAXCONNECTIONS; i++)
+ {
+ get_fd_info(i, &fdtype, &fdflags, &fdvalue);
+
+ cptr = NULL;
+ length = -1;
+
+ if (nfds)
+ {
+ int rr = FD_ISSET(i, &read_set);
+ int rw = FD_ISSET(i, &write_set);
+
+ if(rr || rw)
+ nfds--;
+ else
+ continue;
+
+ fdfprintf(stderr, "fd %d: %s%s\n", i, rr ? "read " : "", rw ? "write" : "");
+
+ switch(fdtype)
+ {
+ case FDT_NONE:
+ break;
+
+ case FDT_AUTH:
+ cptr = (aClient *) fdvalue;
+ if (rr)
+ read_authports(cptr);
+ if (rw && cptr->authfd >= 0)
+ send_authports(cptr);
+ check_client_fd(cptr);
+ break;
+
+ case FDT_LISTENER:
+ lptr = (aListener *) fdvalue;
+ if(rr)
+ accept_connection(lptr);
+ break;
+
+ case FDT_RESOLVER:
+ do_dns_async();
+ break;
+
+ case FDT_CLIENT:
+ cptr = (aClient *) fdvalue;
+ readwrite_client(cptr, rr, rw);
+ break;
+
+ case FDT_CALLBACKP:
+ {
+ struct fd_callbackp *fdcb = (struct fd_callbackp *) fdvalue;
+
+ fdcb->rdf = rr;
+ fdcb->wrf = rw;
+ (*fdcb->callback)(fdcb);
+ }
+ break;
+
+ default:
+ abort(); /* unknown client type? bail! */
+ }
+ }
+ else
+ break; /* no more fds? break out of the loop */
+ } /* end of for() loop for testing selected sockets */
+
+ return 0;
+}
--- /dev/null
+/* src/struct.c
+ * Copyright(c) 2003, Aaron Wiebe
+ * Bahamut development team
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: struct.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+/* This file contains quick and dirty functions for retriving information
+ * from structures. */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "msg.h"
+#include "channel.h"
+#include "throttle.h"
+#include "sbuf.h"
+
+#include "structfunc.h" /* here for compiler prototype checks */
+
+aClient *ac_next(aClient *cptr)
+{
+ return cptr->next;
+}
+
+aClient *ac_prev(aClient *cptr)
+{
+ return cptr->prev;
+}
+
+anUser *ac_user(aClient *cptr)
+{
+ return cptr->user;
+}
+
+aServer *ac_server(aClient *cptr)
+{
+ return cptr->serv;
+}
+
+aWhowas *ac_whowas(aClient *cptr)
+{
+ return cptr->whowas;
+}
+
+aClient *ac_from(aClient *cptr)
+{
+ return cptr->from;
+}
+
+aClient *ac_uplink(aClient *cptr)
+{
+ return cptr->uplink;
+}
+
+time_t ac_lasttime(aClient *cptr)
+{
+ return cptr->lasttime;
+}
+
+time_t ac_firsttime(aClient *cptr)
+{
+ return cptr->firsttime;
+}
+
+time_t ac_since(aClient *cptr)
+{
+ return cptr->since;
+}
+
+ts_val ac_tsinfo(aClient *cptr)
+{
+ return cptr->tsinfo;
+}
+
+int ac_fd(aClient *cptr)
+{
+ return cptr->fd;
+}
+
+int ac_hopcount(aClient *cptr)
+{
+ return cptr->hopcount;
+}
+
+short ac_status(aClient *cptr)
+{
+ return cptr->status;
+}
+
+char ac_nicksent(aClient *cptr)
+{
+ return cptr->nicksent;
+}
+
+char *ac_name(aClient *cptr)
+{
+ return cptr->name;
+}
+
+char *ac_info(aClient *cptr)
+{
+ return cptr->info;
+}
+
+#ifdef FLUD
+Link *ac_fludees(aClient *cptr)
+{
+ return cptr->fludees;
+}
+#endif
+
+struct in_addr ac_ip(aClient *cptr)
+{
+ return cptr->ip;
+}
+
+char *ac_hostip(aClient *cptr)
+{
+ return cptr->hostip;
+}
+
+Link *ac_watch(aClient *cptr)
+{
+ return cptr->watch;
+}
+
+int ac_watches(aClient *cptr)
+{
+ return cptr->watches;
+}
+
+/*************************************
+ * local only stuff starts here
+ *************************************/
+
+int ac_count(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->count;
+}
+
+#ifdef FLUD
+time_t ac_fludblock(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->fludblock;
+}
+
+struct fludbot *ac_fluders(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->fluders;
+}
+#endif
+#ifdef ANTI_SPAMBOT
+time_t ac_last_join_time(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->last_join_time;
+}
+
+time_t ac_last_leave_time(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->last_leave_time;
+}
+
+int ac_join_leave_count(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->join_leave_count;
+}
+
+int ac_oper_warn_count_down(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->oper_warn_count_down;
+}
+#endif
+
+char *ac_buffer(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->buffer;
+}
+
+short ac_lastsq(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->lastsq;
+}
+
+SBuf *ac_sendQ(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return &cptr->sendQ;
+}
+
+SBuf *ac_recvQ(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return &cptr->recvQ;
+}
+
+long ac_sendM(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->sendM;
+}
+
+long ac_sendK(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->sendK;
+}
+
+long ac_receiveM(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->receiveM;
+}
+
+long ac_receiveK(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->receiveK;
+}
+
+u_short ac_sendB(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->sendB;
+}
+
+u_short ac_receiveB(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->receiveB;
+}
+
+long ac_lastrecvM(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->lastrecvM;
+}
+
+int ac_priority(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->priority;
+}
+
+aListener *ac_lstn(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->lstn;
+}
+
+int ac_authfd(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->authfd;
+}
+
+char *ac_username(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->username;
+}
+
+unsigned short ac_port(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->port;
+}
+
+struct hostent *ac_hostp(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->hostp;
+}
+
+#ifdef ANTI_NICK_FLOOD
+time_t ac_last_nick_change(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->last_nick_change;
+}
+
+int ac_number_of_nick_changes(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->number_of_nick_changes;
+}
+#endif
+#ifdef NO_AWAY_FLUD
+time_t ac_alas(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->alas;
+}
+
+int ac_acount(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->acount;
+}
+
+#endif
+
+char *ac_sockhost(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->sockhost;
+}
+
+char *ac_passwd(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->passwd;
+}
+
+int ac_oflag(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->oflag;
+}
+
+int ac_sockerr(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->sockerr;
+}
+
+int ac_capabilities(aClient *cptr)
+{
+ if(cptr->fd == -1)
+ abort();
+ return cptr->capabilities;
+}
+
+/* channel functions */
+
+aChannel *ch_next(aChannel *chptr)
+{
+ return chptr->nextch;
+}
+
+aChannel *ch_prev(aChannel *chptr)
+{
+ return chptr->prevch;
+}
+
+aChannel *ch_hnext(aChannel *chptr)
+{
+ return chptr->hnextch;
+}
+
+int ch_hashv(aChannel *chptr)
+{
+ return chptr->hashv;
+}
+
+Mode ch_mode(aChannel *chptr)
+{
+ return chptr->mode;
+}
+
+char *ch_topic(aChannel *chptr)
+{
+ return chptr->topic;
+}
+
+char *ch_topic_nick(aChannel *chptr)
+{
+ return chptr->topic_nick;
+}
+
+time_t ch_topic_time(aChannel *chptr)
+{
+ return chptr->topic_time;
+}
+
+int ch_users(aChannel *chptr)
+{
+ return chptr->users;
+}
+
+chanMember *ch_members(aChannel *chptr)
+{
+ return chptr->members;
+}
+
+Link *ch_invites(aChannel *chptr)
+{
+ return chptr->invites;
+}
+
+aBan *ch_banlist(aChannel *chptr)
+{
+ return chptr->banlist;
+}
+
+#ifdef INVITE_LISTS
+anInvite *ch_invite_list(aChannel *chptr)
+{
+ return chptr->invite_list;
+}
+#endif
+
+#ifdef EXEMPT_LISTS
+aBanExempt *ch_banexempt_list(aChannel *chptr)
+{
+ return chptr->banexempt_list;
+}
+#endif
+
+ts_val ch_channelts(aChannel *chptr)
+{
+ return chptr->channelts;
+}
+
+#ifdef FLUD
+time_t ch_fludblock(aChannel *chptr)
+{
+ return chptr->fludblock;
+}
+
+struct fludbot *ch_fluders(aChannel *chptr)
+{
+ return chptr->fluders;
+}
+#endif
+
+char *ch_chname(aChannel *chptr)
+{
+ return chptr->chname;
+}
+
+int ch_join_start(aChannel *chptr)
+{
+ return chptr->join_start;
+}
+
+int ch_join_count(aChannel *chptr)
+{
+ return chptr->join_count;
+}
--- /dev/null
+
+/************************************************************************
+ * IRC - Internet Relay Chat, src/support.c
+ * Copyright (C) 1990, 1991 Armin Gruner
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: support.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+
+#define FOREVER for(;;)
+
+extern int errno; /*
+ * ...seems that errno.h doesn't define this
+ * * everywhere
+ */
+extern void outofmemory();
+
+#if !defined( HAVE_STRTOKEN )
+/*
+ * * strtoken.c -- walk through a string of tokens, using a set
+ * of separators
+ * argv 9/90
+ *
+ * $Id: support.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $
+ */
+
+char *strtoken(char **save, char *str, char *fs)
+{
+ char *pos = *save; /* keep last position across calls */
+ char *tmp;
+
+ if (str)
+ pos = str; /* new string scan */
+
+ while (pos && *pos && strchr(fs, *pos) != NULL)
+ pos++; /* skip leading separators */
+
+ if (!pos || !*pos)
+ return (pos = *save = NULL); /* string contains only sep's */
+
+ tmp = pos; /* now, keep position of the token */
+
+ while (*pos && strchr(fs, *pos) == NULL)
+ pos++; /* skip content of the token */
+
+ if (*pos)
+ *pos++ = '\0'; /* remove first sep after the token */
+ else
+ pos = NULL; /* end of string */
+
+ *save = pos;
+ return (tmp);
+}
+#endif /* !HAVE_STRTOKEN */
+
+#if !defined( HAVE_STRTOK )
+/* NOT encouraged to use! */
+
+char *strtok(char *str, char *fs)
+{
+ static char *pos;
+ return strtoken(&pos, str, fs);
+}
+#endif /* !HAVE_STRTOK */
+
+#if !defined( HAVE_STRERROR )
+/*
+ * strerror - return an appropriate system error string to a given errno
+ *
+ */
+
+char *strerror(int err_no)
+{
+#if !defined(__FreeBSD__) && !defined(__NetBSD__)
+ extern char *sys_errlist[]; /* Sigh... hopefully on all systems */
+ extern int sys_nerr;
+#endif
+ static char buff[40];
+ char *errp;
+
+ errp = (err_no > sys_nerr ? (char *) NULL : sys_errlist[err_no]);
+
+ if (errp == (char *) NULL)
+ {
+ errp = buff;
+ (void) sprintf(errp, "Unknown Error %d", err_no);
+ }
+ return errp;
+}
+#endif /* !HAVE_STRERROR */
+
+/*
+ * inetntoa -- changed name to remove collision possibility
+ * and so behaviour is gaurunteed to take a pointer arg.
+ * -avalon 23/11/92
+ * inet_ntoa -- returned the dotted notation of a given
+ * internet number (some ULTRIX don't have this)
+ */
+
+char *inetntoa(char *in)
+{
+ static char buf[16];
+ u_char *s = (u_char *) in;
+ int a, b, c, d;
+
+ a = (int) *s++;
+ b = (int) *s++;
+ c = (int) *s++;
+ d = (int) *s++;
+ (void) ircsprintf(buf, "%d.%d.%d.%d", a, b, c, d);
+
+ return buf;
+}
+
+#if !defined( HAVE_INET_NETOF )
+/* inet_netof -- return the net portion of an internet number */
+
+int inet_netof(struct in_addr in)
+{
+ int addr = in.s_net;
+
+ if (addr & 0x80 == 0)
+ return ((int) in.s_net);
+
+ if (addr & 0x40 == 0)
+ return ((int) in.s_net * 256 + in.s_host);
+
+ return ((int) in.s_net * 256 + in.s_host * 256 + in.s_lh);
+}
+
+#endif /* !HAVE_INET_NETOF */
+
+void *MyMalloc(size_t x)
+{
+ void *ret = malloc(x);
+
+ if (!ret)
+ {
+ outofmemory();
+ }
+ return ret;
+}
+
+void *MyRealloc(void *x, size_t y)
+{
+ void *ret = realloc(x, y);
+
+ if (!ret)
+ {
+ outofmemory();
+ }
+ return ret;
+}
+
+/*
+ * read a string terminated by \r or \n in from a fd
+ *
+ * Created: Sat Dec 12 06:29:58 EST 1992 by avalon
+ * Returns:
+ * 0 - EOF
+ * -1 - error on read
+ * >0 - number of bytes returned (<=num)
+ * After opening a fd, it is necessary to init dgets() by calling it as
+ * dgets(x,y,0); * to mark the buffer as being empty.
+ *
+ * cleaned up by - Dianora aug 7 1997 *argh*
+ */
+int dgets(int fd, char *buf, int num)
+{
+ static char dgbuf[8192];
+ static char *head = dgbuf, *tail = dgbuf;
+ char *s, *t;
+ int n, nr;
+
+ /* Sanity checks. */
+ if (head == tail)
+ *head = '\0';
+
+ if (!num)
+ {
+ head = tail = dgbuf;
+ *head = '\0';
+ return 0;
+ }
+
+ if (num > sizeof(dgbuf) - 1)
+ num = sizeof(dgbuf) - 1;
+
+ FOREVER
+ {
+ if (head > dgbuf)
+ {
+ for (nr = tail - head, s = head, t = dgbuf; nr > 0; nr--)
+ *t++ = *s++;
+ tail = t;
+ head = dgbuf;
+ }
+ /* check input buffer for EOL and if present return string. */
+ if (head < tail &&
+ ((s = strchr(head, '\n')) ||
+ (s = strchr(head, '\r'))) && s < tail)
+ {
+ n = MIN(s - head + 1, num); /* at least 1 byte */
+ memcpy(buf, head, n);
+ head += n;
+ if (head == tail)
+ head = tail = dgbuf;
+ return n;
+ }
+
+ if (tail - head >= num)
+ { /* dgets buf is big enough */
+ n = num;
+ memcpy(buf, head, n);
+ head += n;
+ if (head == tail)
+ head = tail = dgbuf;
+ return n;
+ }
+
+ n = sizeof(dgbuf) - (tail - dgbuf) - 1;
+ nr = read(fd, tail, n);
+ if (nr == -1)
+ {
+ head = tail = dgbuf;
+ return -1;
+ }
+
+ if (!nr)
+ {
+ if (tail > head)
+ {
+ n = MIN(tail - head, num);
+ memcpy(buf, head, n);
+ head += n;
+ if (head == tail)
+ head = tail = dgbuf;
+ return n;
+ }
+ head = tail = dgbuf;
+ return 0;
+ }
+
+ tail += nr;
+ *tail = '\0';
+
+ for (t = head; (s = strchr(t, '\n'));)
+ {
+ if ((s > head) && (s > dgbuf))
+ {
+ t = s - 1;
+ for (nr = 0; *t == '\\'; nr++)
+ t--;
+ if (nr & 1)
+ {
+ t = s + 1;
+ s--;
+ nr = tail - t;
+ while (nr--)
+ *s++ = *t++;
+ tail -= 2;
+ *tail = '\0';
+ }
+ else
+ s++;
+ }
+ else
+ s++;
+ t = s;
+ }
+ *tail = '\0';
+ }
+}
--- /dev/null
+/*
+ * Copyright 2000, 2001 Chip Norkus
+ *
+ * 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 names of the maintainers, developers and contributors may not be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MAINTAINER, DEVELOPERS 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 DEVELOPERS 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.
+ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "res.h"
+#include "h.h"
+#include "numeric.h"
+#include "blalloc.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "queue.h"
+#include "throttle.h"
+
+BlockHeap *hashent_freelist;
+BlockHeap *throttle_freelist;
+
+/*******************************************************************************
+ * hash code here. why isn't it in hash.c? see the license. :)
+ ******************************************************************************/
+
+hashent *hashent_alloc()
+{
+ return BlockHeapALLOC(hashent_freelist, hashent);
+}
+
+void hashent_free(hashent *hp)
+{
+ BlockHeapFree(hashent_freelist, hp);
+}
+
+/* hash_table creation function. given the user's paramters, allocate
+ * and empty a new hash table and return it. */
+hash_table *
+create_hash_table(int elems, size_t offset, size_t len, int flags,
+ int (*cmpfunc)(void *, void *))
+{
+ hash_table *htp = malloc(sizeof(hash_table));
+
+ htp->size = elems;
+ htp->keyoffset = offset;
+ htp->keylen = len;
+ htp->flags = flags;
+ htp->cmpfunc = cmpfunc;
+
+ htp->table = malloc(sizeof(hashent_list) * htp->size);
+ memset(htp->table, 0, sizeof(hashent_list) * htp->size);
+
+ return htp;
+}
+
+/* hash_table destroyer. sweep through the given table and kill off every
+ * hashent */
+void
+destroy_hash_table(hash_table *table)
+{
+ hashent *hep;
+ int i;
+
+ for (i = 0;i < table->size;i++)
+ {
+ while (!SLIST_EMPTY(&table->table[i]))
+ {
+ hep = SLIST_FIRST(&table->table[i]);
+ SLIST_REMOVE_HEAD(&table->table[i], lp);
+ hashent_free(hep);
+ }
+ }
+ MyFree(table->table);
+ MyFree(table);
+}
+
+/* this is an expensive function. it's not the sort of thing one should be
+ * calling a lot, however, in the right situations it can provide a lot of
+ * benefit */
+void
+resize_hash_table(hash_table *table, int elems)
+{
+ hashent_list *oldtable;
+ int oldsize, i;
+ hashent *hep;
+
+ /* preserve the old table, then create a new one. */
+ oldtable = table->table;
+ oldsize = table->size;
+ table->size = elems;
+ table->table = malloc(sizeof(hashent_list) * table->size);
+ memset(table->table, 0, sizeof(hashent_list) * table->size);
+
+ /* now walk each bucket in the old table, pulling off individual entries
+ * and re-adding them to the table as we go */
+ for (i = 0;i < oldsize;i++)
+ {
+ while (!SLIST_EMPTY(&oldtable[i]))
+ {
+ hep = SLIST_FIRST(&oldtable[i]);
+ hash_insert(table, hep->ent);
+ SLIST_REMOVE_HEAD(&oldtable[i], lp);
+ hashent_free(hep);
+ }
+ }
+ MyFree(oldtable);
+}
+
+/* get the hash of a given key. really only useful for insert/delete */
+unsigned int
+hash_get_key_hash(hash_table *table, void *key, size_t offset)
+{
+ char *rkey = (char *)key + offset;
+ int len = table->keylen;
+ unsigned int hash = 0;
+
+ if (!len)
+ len = strlen(rkey);
+ else if (table->flags & HASH_FL_STRING)
+ {
+ len = strlen(rkey);
+ if (len > table->keylen)
+ len = table->keylen;
+ }
+ /* I borrowed this algorithm from perl5. Kudos to Larry Wall & co. */
+ if (table->flags & HASH_FL_NOCASE)
+ while (len--)
+ hash = hash * 33 + ToLower(*rkey++);
+ else
+ while (len--)
+ hash = hash * 33 + *rkey++;
+
+ return hash % table->size;
+}
+
+/* add the given item onto the hash */
+int
+hash_insert(hash_table *table, void *ent)
+{
+ int hash = hash_get_key_hash(table, ent, table->keyoffset);
+ hashent *hep = hashent_alloc();
+
+ hep->ent = ent;
+ SLIST_INSERT_HEAD(&table->table[hash], hep, lp);
+
+ return 1;
+}
+
+/* delete the given item from the hash */
+int
+hash_delete(hash_table *table, void *ent)
+{
+ int hash = hash_get_key_hash(table, ent, table->keyoffset);
+ hashent *hep;
+
+ SLIST_FOREACH(hep, &table->table[hash], lp)
+ {
+ if (hep->ent == ent)
+ break;
+ }
+ if (hep == NULL)
+ return 0;
+ SLIST_REMOVE(&table->table[hash], hep, hashent_t, lp);
+ hashent_free(hep);
+ return 1;
+}
+
+/* last, but not least, the find function. given the table and the key to
+ * look for, it hashes the key, and then calls the compare function in the
+ * given table slice until it finds the item, or reaches the end of the
+ * list. */
+void *
+hash_find(hash_table *table, void *key)
+{
+ int hash = hash_get_key_hash(table, key, 0);
+ hashent *hep;
+
+ SLIST_FOREACH(hep, &table->table[hash], lp)
+ {
+ if (!table->cmpfunc(&((char *)hep->ent)[table->keyoffset], key))
+ return hep->ent;
+ }
+
+ return NULL; /* not found */
+}
+
+/*******************************************************************************
+ * actual throttle code here ;)
+ ******************************************************************************/
+
+LIST_HEAD(throttle_list_t, throttle_t) throttles;
+
+typedef struct throttle_t
+{
+ char addr[HOSTIPLEN + 1]; /* address of the throttle */
+ int conns; /* number of connections seen from this
+ address. */
+ time_t first; /* first time we saw this IP
+ * in this stage */
+ time_t last; /* last time we saw this IP */
+ time_t zline_start; /* time we placed a zline for this host,
+ or 0 if no zline */
+ int stage; /* how many times this host has been
+ * z-lined */
+ int re_zlines; /* just a statistic -- how many times has
+ * this host reconnected and had their
+ * ban reset */
+
+ LIST_ENTRY(throttle_t) lp;
+} throttle;
+
+/* variables for the throttler */
+hash_table *throttle_hash;
+int throttle_tcount = THROTTLE_TRIGCOUNT;
+int throttle_ttime = THROTTLE_TRIGTIME;
+int throttle_rtime = THROTTLE_RECORDTIME;
+
+#ifdef THROTTLE_ENABLE
+int throttle_enable = 1;
+#else
+int throttle_enable = 0;
+#endif
+
+int numthrottles = 0; /* number of throttles in existence */
+
+#ifdef THROTTLE_ENABLE
+void throttle_init(void)
+{
+ hashent_freelist = BlockHeapCreate(sizeof(hashent), 1024);
+ throttle_freelist = BlockHeapCreate(sizeof(throttle), 1024);
+ /* create the throttle hash. */
+ throttle_hash = create_hash_table(THROTTLE_HASHSIZE,
+ offsetof(throttle, addr), HOSTIPLEN,
+ HASH_FL_STRING, (int (*)(void *, void *))strcmp);
+}
+
+throttle *throttle_alloc()
+{
+ return BlockHeapALLOC(throttle_freelist, throttle);
+}
+
+void throttle_free(throttle *tp)
+{
+ BlockHeapFree(throttle_freelist, tp);
+}
+
+/* returns the zline time, in seconds */
+static int
+throttle_get_zline_time(int stage)
+{
+ switch(stage)
+ {
+ case -1:
+ return 0; /* no throttle */
+
+ case 0:
+ return 120; /* 2 minutes */
+
+ case 1:
+ return 300; /* 5 minutes */
+
+ case 2:
+ return 900; /* 15 minutes */
+
+ case 3:
+ return 1800; /* a half hour */
+
+ default:
+ return 3600; /* an hour */
+ }
+
+ return 0; /* dumb compiler */
+}
+
+void
+throttle_remove(char *host)
+{
+ throttle *tp = hash_find(throttle_hash, host);
+
+ if(tp)
+ {
+ LIST_REMOVE(tp, lp);
+ hash_delete(throttle_hash, tp);
+ throttle_free(tp);
+ numthrottles--;
+ }
+}
+
+void
+throttle_force(char *host)
+{
+ throttle *tp = hash_find(throttle_hash, host);
+
+ if (tp == NULL)
+ {
+ /* we haven't seen this one before, create a new throttle and add it to
+ * the hash. XXX: blockheap code should be used, but the blockheap
+ * allocator available in ircd is broken beyond repair as far as I'm
+ * concerned. -wd */
+ tp = throttle_alloc();;
+ strcpy(tp->addr, host);
+
+ tp->stage = -1; /* no zline stage yet */
+ tp->zline_start = 0;
+ tp->conns = 0;
+ tp->first = NOW;
+ tp->re_zlines = 0;
+
+ hash_insert(throttle_hash, tp);
+ LIST_INSERT_HEAD(&throttles, tp, lp);
+ numthrottles++;
+ }
+
+ /* now force them to be autothrottled if they reconnect. */
+ tp->conns = -1;
+ tp->last = tp->first = NOW;
+}
+
+/* fd is -1 for remote signons */
+int
+throttle_check(char *host, int fd, time_t sotime)
+{
+ throttle *tp = hash_find(throttle_hash, host);
+
+ if (!throttle_enable)
+ return 1; /* always successful */
+
+ /* If this is an old remote signon, just ignore it */
+ if(fd == -1 && (NOW - sotime > throttle_ttime))
+ return 1;
+
+ /* If this user is signing on 'in the future', we need to
+ fix that. Someone has a bad remote TS, perhaps we should complain */
+ if(sotime > NOW)
+ sotime = NOW;
+
+ if (tp == NULL)
+ {
+ /* we haven't seen this one before, create a new throttle and add it to
+ * the hash. XXX: blockheap code should be used, but the blockheap
+ * allocator available in ircd is broken beyond repair as far as I'm
+ * concerned. -wd */
+ tp = throttle_alloc();;
+ strcpy(tp->addr, host);
+
+ tp->stage = -1; /* no zline stage yet */
+ tp->zline_start = 0;
+ tp->conns = 0;
+ tp->first = sotime;
+ tp->re_zlines = 0;
+
+ hash_insert(throttle_hash, tp);
+ LIST_INSERT_HEAD(&throttles, tp, lp);
+ numthrottles++;
+ }
+ else if(tp->zline_start)
+ {
+ time_t zlength = throttle_get_zline_time(tp->stage);
+
+ /* If they're zlined, drop them */
+ /* Also, reset the zline counter */
+ if(sotime - tp->zline_start < zlength)
+ {
+ /* don't reset throttle time for new remote signons */
+ if(fd == -1)
+ return 0;
+ /*
+ * Reset the z-line period to start now
+ * Mean, but should get the bots and help the humans
+ */
+ tp->re_zlines++;
+ tp->zline_start = sotime;
+ return 0;
+ }
+
+ /* may look redundant, but it fixes it if
+ someone sets throttle_ttime to something insane */
+ tp->conns = 0;
+ tp->first = sotime;
+ tp->zline_start = 0;
+ }
+
+ /* got a throttle, up the conns */
+ if(tp->conns >= 0)
+ tp->conns++;
+ tp->last = sotime;
+
+ /* check the time bits, if they exceeded the throttle timeout, we should
+ * actually remove this structure from the hash and free it and create a
+ * new one, except that would be preposterously expensive, so we just
+ * re-set variables ;) -wd */
+ if (sotime - tp->first > throttle_ttime)
+ {
+ tp->conns = 1;
+ tp->first = sotime;
+
+ /* we can probably gaurantee they aren't going to be throttled, return
+ * success */
+ return 1;
+ }
+
+ if (tp->conns == -1)
+ {
+ /* This is a forced throttle, drop 'em! */
+ return 0;
+ }
+
+ if (tp->conns >= throttle_tcount)
+ {
+ /* mark them as z:lined (we do not actually add a Z:line as this would
+ * be wasteful) and let local +c ops know about this */
+ if (fd != -1)
+ {
+ char errbufr[512];
+ int zlength, elength;
+
+ tp->stage++;
+ zlength = throttle_get_zline_time(tp->stage);
+
+ /* let +c ops know */
+ sendto_realops_lev(REJ_LEV, "throttled connections from %s (%d in"
+ " %d seconds) for %d minutes (offense %d)",
+ tp->addr, tp->conns, sotime - tp->first,
+ zlength / 60, tp->stage + 1);
+
+ elength = ircsnprintf(errbufr, 512, ":%s NOTICE ZUSR :You have"
+ " been throttled for %d minutes for too"
+ " many connections in a short period of time."
+ " Further connections in this period will"
+ " reset your throttle and you will have to"
+ " wait longer.\r\n", me.name, zlength / 60);
+ send(fd, errbufr, elength, 0);
+
+ if(throttle_get_zline_time(tp->stage+1) != zlength)
+ {
+ elength = ircsnprintf(errbufr, 512, ":%s NOTICE ZUSR :When you"
+ " return, if you are throttled again, "
+ "your throttle will last longer.\r\n",
+ me.name);
+ send(fd, errbufr, elength, 0);
+ }
+
+ /* We steal this message from undernet, because mIRC detects it
+ * and doesn't try to autoreconnect */
+ elength = ircsnprintf(errbufr, 512, "ERROR :Your host is trying "
+ "to (re)connect too fast -- throttled.\r\n",
+ tp->addr);
+ send(fd, errbufr, elength, 0);
+
+ tp->zline_start = sotime;
+ }
+ else
+ {
+ /* it might be desireable at some point to let people know about
+ * these problems. for now, however, don't. */
+ }
+ return 0; /* drop 'em */
+ }
+ return 1; /* they're okay. */
+}
+
+/* walk through our list of throttles, expire any as necessary. in the case of
+ * Z:lines, expire them at the end of the Z:line timeout period. */
+/* Expire at the end of the zline timeout period plus throttle_rtime */
+void
+throttle_timer(time_t now)
+{
+ throttle *tp, *tp2;
+ time_t zlength;
+
+ if (!throttle_enable)
+ return;
+
+ tp = LIST_FIRST(&throttles);
+ while (tp != NULL)
+ {
+ zlength = throttle_get_zline_time(tp->stage);
+ tp2=LIST_NEXT(tp, lp);
+ if ((now == 0) || (tp->zline_start &&
+ (now - tp->zline_start) >= (zlength + throttle_rtime)) ||
+ (!tp->zline_start && (now - tp->last) >= throttle_rtime))
+ {
+ /* delete this item */
+ LIST_REMOVE(tp, lp);
+ hash_delete(throttle_hash, tp);
+ throttle_free(tp);
+ numthrottles--;
+ }
+ tp=tp2;
+ }
+}
+
+void throttle_rehash(void)
+{
+ throttle_timer(0);
+}
+
+void throttle_resize(int size)
+{
+ resize_hash_table(throttle_hash, size);
+}
+
+void throttle_stats(aClient *cptr, char *name)
+{
+ int pending = 0, bans = 0;
+ throttle *tp;
+ unsigned int tcnt, tsz, hcnt, hsz;
+
+ tcnt = throttle_freelist->blocksAllocated *
+ throttle_freelist->elemsPerBlock;
+ tsz = tcnt * throttle_freelist->elemSize;
+
+ hcnt = hashent_freelist->blocksAllocated *
+ hashent_freelist->elemsPerBlock;
+ hsz = hcnt * hashent_freelist->elemSize;
+
+ sendto_one(cptr, ":%s %d %s :throttles: %d", me.name, RPL_STATSDEBUG, name,
+ numthrottles);
+ sendto_one(cptr, ":%s %d %s :alloc memory: %d throttles (%d bytes), "
+ "%d hashents (%d bytes)", me.name, RPL_STATSDEBUG, name,
+ tcnt, tsz, hcnt, hsz);
+ sendto_one(cptr, ":%s %d %s :throttle hash table size: %d", me.name,
+ RPL_STATSDEBUG, name, throttle_hash->size);
+
+ /* now count bans/pending */
+ LIST_FOREACH(tp, &throttles, lp)
+ {
+ if (tp->zline_start)
+ bans++;
+ else
+ pending++;
+ }
+ sendto_one(cptr, ":%s %d %s :throttles pending=%d bans=%d", me.name,
+ RPL_STATSDEBUG, name, pending, bans);
+ LIST_FOREACH(tp, &throttles, lp)
+ {
+ int ztime = throttle_get_zline_time(tp->stage);
+
+ if (tp->zline_start && tp->zline_start + ztime > NOW)
+ sendto_one(cptr, ":%s %d %s :throttled: %s [stage %d, %d secs"
+ " remain, %d futile retries]", me.name,
+ RPL_STATSDEBUG, name, tp->addr, tp->stage,
+ (tp->zline_start + ztime) - NOW, tp->re_zlines);
+ }
+}
+
+#else
+/* ignore this -- required for drone modules and the like */
+void throttle_force(char *host) {}
+#endif
+/* vi:set ts=8 sts=4 sw=4 tw=79: */
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/userban.c
+ * Copyright (C) 2002 Lucas Madar and
+ * the DALnet coding team
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: userban.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "inet.h"
+#include "h.h"
+#include "userban.h"
+#include "queue.h"
+
+#define HASH_SIZE (32749) /* largest prime < 32768 */
+
+LIST_HEAD(banlist_t, userBanEntry);
+typedef struct banlist_t ban_list;
+
+typedef struct userBanEntry {
+ struct userBan *ban;
+ LIST_ENTRY(userBanEntry) lp;
+} uBanEnt;
+
+typedef struct _abanlist {
+ ban_list wild_list;
+
+ int numbuckets;
+ ban_list *hash_list;
+} aBanList;
+
+typedef struct userBan auserBan;
+
+ban_list CIDR4BIG_bans = LIST_HEAD_INITIALIZER(CIDR4BIG_bans);
+ban_list **CIDR4_bans;
+
+aBanList host_bans;
+aBanList ip_bans;
+
+aBanList gcos_bans;
+aBanList nick_bans;
+aBanList chan_bans;
+
+struct userBan *userban_alloc();
+struct simBan *simban_alloc();
+uBanEnt *ubanent_alloc();
+void ubanent_free(uBanEnt *);
+void userban_free(struct userBan *);
+void simban_free(struct simBan *);
+unsigned int host_hash(char *n);
+unsigned int ip_hash(char *n);
+
+unsigned int cidr_to_netmask(unsigned int cidr)
+{
+ if (cidr == 0)
+ return 0;
+
+ return (0xFFFFFFFF - (1 << (32 - cidr)) + 1);
+}
+
+unsigned int netmask_to_cidr(unsigned int mask)
+{
+ int tmp = 0;
+
+ while (!(mask & (1 << tmp)) && tmp < 32)
+ tmp++;
+
+ return (32 - tmp);
+}
+
+/* userban (akill/kline) functions */
+
+void add_hostbased_userban(struct userBan *b)
+{
+ uBanEnt *bl;
+
+ bl = ubanent_alloc();
+ bl->ban = b;
+ b->internal_ent = (void *) bl;
+
+ if(b->flags & UBAN_CIDR4BIG)
+ {
+ LIST_INSERT_HEAD(&CIDR4BIG_bans, bl, lp);
+ return;
+ }
+
+ if(b->flags & UBAN_CIDR4)
+ {
+ unsigned char *s = (unsigned char *) &bl->ban->cidr4ip;
+ int a, b;
+
+ a = (int) *s++;
+ b = (int) *s;
+
+ LIST_INSERT_HEAD(&CIDR4_bans[a][b], bl, lp);
+ return;
+ }
+
+ if(b->flags & UBAN_IP)
+ {
+ if(b->flags & UBAN_WILD)
+ {
+ LIST_INSERT_HEAD(&ip_bans.wild_list, bl, lp);
+ }
+ else
+ {
+ unsigned int hv = ip_hash(b->h) % HASH_SIZE;
+
+ LIST_INSERT_HEAD(&ip_bans.hash_list[hv], bl, lp);
+ }
+
+ return;
+ }
+
+ if(b->flags & UBAN_HOST)
+ {
+ if(b->flags & UBAN_WILD)
+ {
+ LIST_INSERT_HEAD(&host_bans.wild_list, bl, lp);
+ }
+ else
+ {
+ unsigned int hv = host_hash(b->h) % HASH_SIZE;
+
+ LIST_INSERT_HEAD(&host_bans.hash_list[hv], bl, lp);
+ }
+
+ return;
+ }
+
+ /* unreachable code */
+ abort();
+}
+
+void remove_userban(struct userBan *b)
+{
+ uBanEnt *bl = (uBanEnt *) b->internal_ent;
+
+ LIST_REMOVE(bl, lp);
+
+ ubanent_free(bl);
+
+ return;
+}
+
+/*
+ * user_match_ban -- be sure to call only for fully-initialized users
+ * returns 0 on no match, 1 otherwise
+ */
+int user_match_ban(aClient *cptr, struct userBan *ban)
+{
+ /* first match the 'user' portion */
+
+ if((!(ban->flags & UBAN_WILDUSER)) && match(ban->u, cptr->user->username))
+ return 0;
+
+ if(ban->flags & UBAN_IP)
+ {
+ char iptmp[HOSTIPLEN + 1];
+
+ strncpyzt(iptmp, inetntoa((char *)&cptr->ip), HOSTIPLEN + 1);
+ if(ban->flags & UBAN_WILD)
+ {
+ if(match(ban->h, iptmp) == 0)
+ return 1;
+ }
+ else
+ {
+ if(mycmp(ban->h, iptmp) == 0)
+ return 1;
+ }
+ return 0;
+ }
+
+ if(ban->flags & UBAN_HOST)
+ {
+ if(ban->flags & UBAN_WILD)
+ {
+ if((ban->flags & UBAN_WILDHOST) || match(ban->h, cptr->user->host) == 0)
+ return 1;
+ }
+ else
+ {
+ if(mycmp(ban->h, cptr->user->host) == 0)
+ return 1;
+ }
+ return 0;
+ }
+
+ if(ban->flags & (UBAN_CIDR4|UBAN_CIDR4BIG))
+ {
+ if((cptr->ip.s_addr & ban->cidr4mask) == ban->cidr4ip)
+ return 1;
+ return 0;
+ }
+
+ return 0;
+}
+
+struct userBan *check_userbanned(aClient *cptr, unsigned int yflags, unsigned int nflags)
+{
+ char iptmp[HOSTIPLEN + 1];
+ uBanEnt *bl;
+
+ strncpyzt(iptmp, inetntoa((char *)&cptr->ip), HOSTIPLEN + 1);
+
+ if(yflags & UBAN_IP)
+ {
+ unsigned int hv = ip_hash(iptmp) % HASH_SIZE;
+
+ LIST_FOREACH(bl, &ip_bans.hash_list[hv], lp)
+ {
+ if((bl->ban->flags & UBAN_TEMPORARY) && bl->ban->timeset + bl->ban->duration <= NOW)
+ continue;
+
+ if( ((yflags & UBAN_WILDUSER) && !(bl->ban->flags & UBAN_WILDUSER)) ||
+ ((nflags & UBAN_WILDUSER) && (bl->ban->flags & UBAN_WILDUSER)))
+ continue;
+
+ if((!(bl->ban->flags & UBAN_WILDUSER)) && match(bl->ban->u, cptr->user->username))
+ continue;
+
+ if(mycmp(bl->ban->h, iptmp) == 0)
+ return bl->ban;
+ }
+
+ LIST_FOREACH(bl, &ip_bans.wild_list, lp)
+ {
+ if((bl->ban->flags & UBAN_TEMPORARY) && bl->ban->timeset + bl->ban->duration <= NOW)
+ continue;
+
+ if( ((yflags & UBAN_WILDUSER) && !(bl->ban->flags & UBAN_WILDUSER)) ||
+ ((nflags & UBAN_WILDUSER) && (bl->ban->flags & UBAN_WILDUSER)))
+ continue;
+
+ if((!(bl->ban->flags & UBAN_WILDUSER)) && match(bl->ban->u, cptr->user->username))
+ continue;
+
+ if(match(bl->ban->h, iptmp) == 0)
+ return bl->ban;
+ }
+ }
+
+ if(yflags & UBAN_CIDR4)
+ {
+ unsigned char *s = (unsigned char *) &cptr->ip.s_addr;
+ int a, b;
+
+ a = (int) *s++;
+ b = (int) *s;
+
+ LIST_FOREACH(bl, &CIDR4_bans[a][b], lp)
+ {
+ if((bl->ban->flags & UBAN_TEMPORARY) && bl->ban->timeset + bl->ban->duration <= NOW)
+ continue;
+
+ if( ((yflags & UBAN_WILDUSER) && !(bl->ban->flags & UBAN_WILDUSER)) ||
+ ((nflags & UBAN_WILDUSER) && (bl->ban->flags & UBAN_WILDUSER)))
+ continue;
+
+ if((!(bl->ban->flags & UBAN_WILDUSER)) && match(bl->ban->u, cptr->user->username))
+ continue;
+
+ if((cptr->ip.s_addr & bl->ban->cidr4mask) == bl->ban->cidr4ip)
+ return bl->ban;
+ }
+
+ LIST_FOREACH(bl, &CIDR4BIG_bans, lp)
+ {
+ if((bl->ban->flags & UBAN_TEMPORARY) && bl->ban->timeset + bl->ban->duration <= NOW)
+ continue;
+
+ if( ((yflags & UBAN_WILDUSER) && !(bl->ban->flags & UBAN_WILDUSER)) ||
+ ((nflags & UBAN_WILDUSER) && (bl->ban->flags & UBAN_WILDUSER)))
+ continue;
+
+ if((!(bl->ban->flags & UBAN_WILDUSER)) && match(bl->ban->u, cptr->user->username))
+ continue;
+
+ if((cptr->ip.s_addr & bl->ban->cidr4mask) == bl->ban->cidr4ip)
+ return bl->ban;
+ }
+ }
+
+ if(yflags & UBAN_HOST)
+ {
+ unsigned int hv = host_hash(cptr->user->host) % HASH_SIZE;
+
+ LIST_FOREACH(bl, &host_bans.hash_list[hv], lp)
+ {
+ if((bl->ban->flags & UBAN_TEMPORARY) && bl->ban->timeset + bl->ban->duration <= NOW)
+ continue;
+
+ if( ((yflags & UBAN_WILDUSER) && !(bl->ban->flags & UBAN_WILDUSER)) ||
+ ((nflags & UBAN_WILDUSER) && (bl->ban->flags & UBAN_WILDUSER)))
+ continue;
+
+ if((!(bl->ban->flags & UBAN_WILDUSER)) && match(bl->ban->u, cptr->user->username))
+ continue;
+
+ if(mycmp(bl->ban->h, cptr->user->host) == 0)
+ return bl->ban;
+ }
+
+ LIST_FOREACH(bl, &host_bans.wild_list, lp)
+ {
+ if((bl->ban->flags & UBAN_TEMPORARY) && bl->ban->timeset + bl->ban->duration <= NOW)
+ continue;
+
+ if( ((yflags & UBAN_WILDUSER) && !(bl->ban->flags & UBAN_WILDUSER)) ||
+ ((nflags & UBAN_WILDUSER) && (bl->ban->flags & UBAN_WILDUSER)))
+ continue;
+
+ if((!(bl->ban->flags & UBAN_WILDUSER)) && match(bl->ban->u, cptr->user->username))
+ continue;
+
+ if((bl->ban->flags & UBAN_WILDHOST) || match(bl->ban->h, cptr->user->host) == 0)
+ return bl->ban;
+ }
+ }
+ return NULL;
+}
+
+struct userBan *find_userban_exact(struct userBan *borig, unsigned int careflags)
+{
+ uBanEnt *bl;
+
+ if(borig->flags & UBAN_CIDR4BIG)
+ {
+ LIST_FOREACH(bl, &CIDR4BIG_bans, lp) {
+ /* must have same wilduser, etc setting */
+ if((bl->ban->flags ^ borig->flags) & (UBAN_WILDUSER|careflags))
+ continue;
+
+ /* user fields do not match? */
+ if(!(borig->flags & UBAN_WILDUSER) && mycmp(borig->u, bl->ban->u))
+ continue;
+
+ if(!((borig->cidr4ip == bl->ban->cidr4ip) && (borig->cidr4mask == bl->ban->cidr4mask)))
+ continue;
+
+ return bl->ban;
+ }
+
+ return NULL;
+ }
+
+ if(borig->flags & UBAN_CIDR4)
+ {
+ unsigned char *s = (unsigned char *) &borig->cidr4ip;
+ int a, b;
+
+ a = (int) *s++;
+ b = (int) *s;
+
+ LIST_FOREACH(bl, &CIDR4_bans[a][b], lp) {
+ if((bl->ban->flags ^ borig->flags) & (UBAN_WILDUSER|careflags))
+ continue;
+
+ if(!(borig->flags & UBAN_WILDUSER) && mycmp(borig->u, bl->ban->u))
+ continue;
+
+ if(!((borig->cidr4ip == bl->ban->cidr4ip) && (borig->cidr4mask == bl->ban->cidr4mask)))
+ continue;
+
+ return bl->ban;
+ }
+
+ return NULL;
+ }
+
+ if(borig->flags & UBAN_IP)
+ {
+ if(borig->flags & UBAN_WILD)
+ {
+ LIST_FOREACH(bl, &ip_bans.wild_list, lp) {
+ if((bl->ban->flags ^ borig->flags) & (UBAN_WILDUSER|careflags))
+ continue;
+
+ if(!(borig->flags & UBAN_WILDUSER) && mycmp(borig->u, bl->ban->u))
+ continue;
+
+ if(mycmp(borig->h, bl->ban->h))
+ continue;
+
+ return bl->ban;
+ }
+ }
+ else
+ {
+ unsigned int hv = ip_hash(borig->h) % HASH_SIZE;
+
+ LIST_FOREACH(bl, &ip_bans.hash_list[hv], lp) {
+ if((bl->ban->flags ^ borig->flags) & (UBAN_WILDUSER|careflags))
+ continue;
+
+ if(!(borig->flags & UBAN_WILDUSER) && mycmp(borig->u, bl->ban->u))
+ continue;
+
+ if(mycmp(borig->h, bl->ban->h))
+ continue;
+
+ return bl->ban;
+ }
+ }
+
+ return NULL;
+ }
+
+ if(borig->flags & UBAN_HOST)
+ {
+ if(borig->flags & UBAN_WILD)
+ {
+ LIST_FOREACH(bl, &host_bans.wild_list, lp) {
+ if((bl->ban->flags ^ borig->flags) & (UBAN_WILDUSER|careflags))
+ continue;
+
+ if(!(borig->flags & UBAN_WILDUSER) && mycmp(borig->u, bl->ban->u))
+ continue;
+
+ if(mycmp(borig->h, bl->ban->h))
+ continue;
+
+ return bl->ban;
+ }
+ }
+ else
+ {
+ unsigned int hv = host_hash(borig->h) % HASH_SIZE;
+
+ LIST_FOREACH(bl, &host_bans.hash_list[hv], lp) {
+ if((bl->ban->flags ^ borig->flags) & (UBAN_WILDUSER|careflags))
+ continue;
+
+ if(!(borig->flags & UBAN_WILDUSER) && mycmp(borig->u, bl->ban->u))
+ continue;
+
+ if(mycmp(borig->h, bl->ban->h))
+ continue;
+
+ return bl->ban;
+ }
+ }
+
+ return NULL;
+ }
+
+ /* unreachable code */
+ abort();
+}
+
+static inline void expire_list(uBanEnt *bl)
+{
+ uBanEnt *bln;
+ struct userBan *ban;
+
+ while(bl)
+ {
+ bln = LIST_NEXT(bl, lp);
+ ban = bl->ban;
+
+ if((ban->flags & UBAN_TEMPORARY) && ban->timeset + ban->duration <= NOW)
+ {
+ remove_userban(ban);
+ userban_free(ban);
+ }
+ bl = bln;
+ }
+}
+
+static inline void remove_list_match_flags(uBanEnt *bl, unsigned int flags, unsigned int nflags)
+{
+ uBanEnt *bln;
+ struct userBan *ban;
+
+ while(bl)
+ {
+ bln = LIST_NEXT(bl, lp);
+ ban = bl->ban;
+
+ if((flags == 0 && nflags == 0) || (((ban->flags & flags) == flags) && ((ban->flags & nflags) == 0)))
+ {
+ remove_userban(ban);
+ userban_free(ban);
+ }
+ bl = bln;
+ }
+}
+
+static inline void report_list_match_flags(aClient *cptr, uBanEnt *bl, unsigned int flags, unsigned int nflags, char rchar)
+{
+ struct userBan *ban;
+ char kset[8];
+ char host[128];
+
+ while(bl)
+ {
+ ban = bl->ban;
+
+ if((flags == 0 && nflags == 0) || (((ban->flags & flags) == flags) && ((ban->flags & nflags) == 0)))
+ {
+ if(ban->flags & UBAN_LOCAL)
+ {
+ if(ban->flags & UBAN_TEMPORARY)
+ kset[0] = 'k';
+ else
+ kset[0] = 'K';
+ }
+ else
+ {
+ kset[0] = 'a';
+ }
+ kset[1] = rchar;
+ kset[2] = '\0';
+
+ if(ban->flags & (UBAN_CIDR4|UBAN_CIDR4BIG))
+ snprintf(host, 128, "%s/%d", inetntoa((char *)&ban->cidr4ip), netmask_to_cidr(ntohl(ban->cidr4mask)));
+ else
+ strcpy(host, ban->h);
+
+ sendto_one(cptr, rpl_str(RPL_STATSKLINE), me.name,
+ cptr->name, kset, host,
+ (ban->flags & UBAN_WILDUSER) ? "*" : ban->u,
+ (ban->flags & UBAN_TEMPORARY) ? (((ban->timeset + ban->duration) - NOW) / 60) : -1,
+ (ban->reason) ? ban->reason : "No reason");
+ }
+
+ bl = LIST_NEXT(bl, lp);
+ }
+}
+
+void expire_userbans()
+{
+ uBanEnt *bl;
+ int a, b;
+
+ bl = LIST_FIRST(&CIDR4BIG_bans);
+ expire_list(bl);
+
+ for(a = 0; a < 256; a++)
+ {
+ for(b = 0; b < 256; b++)
+ {
+ bl = LIST_FIRST(&CIDR4_bans[a][b]);
+ expire_list(bl);
+ }
+ }
+
+ bl = LIST_FIRST(&host_bans.wild_list);
+ expire_list(bl);
+ bl = LIST_FIRST(&ip_bans.wild_list);
+ expire_list(bl);
+
+ for(a = 0; a < HASH_SIZE; a++)
+ {
+ bl = LIST_FIRST(&host_bans.hash_list[a]);
+ expire_list(bl);
+ bl = LIST_FIRST(&ip_bans.hash_list[a]);
+ expire_list(bl);
+ }
+}
+
+void remove_userbans_match_flags(unsigned int flags, unsigned int nflags)
+{
+ uBanEnt *bl;
+ int a, b;
+
+ bl = LIST_FIRST(&CIDR4BIG_bans);
+ remove_list_match_flags(bl, flags, nflags);
+
+ for(a = 0; a < 256; a++)
+ {
+ for(b = 0; b < 256; b++)
+ {
+ bl = LIST_FIRST(&CIDR4_bans[a][b]);
+ remove_list_match_flags(bl, flags, nflags);
+ }
+ }
+
+ bl = LIST_FIRST(&host_bans.wild_list);
+ remove_list_match_flags(bl, flags, nflags);
+ bl = LIST_FIRST(&ip_bans.wild_list);
+ remove_list_match_flags(bl, flags, nflags);
+
+ for(a = 0; a < HASH_SIZE; a++)
+ {
+ bl = LIST_FIRST(&host_bans.hash_list[a]);
+ remove_list_match_flags(bl, flags, nflags);
+ bl = LIST_FIRST(&ip_bans.hash_list[a]);
+ remove_list_match_flags(bl, flags, nflags);
+ }
+}
+
+void report_userbans_match_flags(aClient *cptr, unsigned int flags, unsigned int nflags)
+{
+ uBanEnt *bl;
+ int a, b;
+
+ bl = LIST_FIRST(&CIDR4BIG_bans);
+ report_list_match_flags(cptr, bl, flags, nflags, 'C');
+
+ for(a = 0; a < 256; a++)
+ {
+ for(b = 0; b < 256; b++)
+ {
+ bl = LIST_FIRST(&CIDR4_bans[a][b]);
+ report_list_match_flags(cptr, bl, flags, nflags, 'c');
+ }
+ }
+
+ bl = LIST_FIRST(&host_bans.wild_list);
+ report_list_match_flags(cptr, bl, flags, nflags, 'h');
+ bl = LIST_FIRST(&ip_bans.wild_list);
+ report_list_match_flags(cptr, bl, flags, nflags, 'i');
+
+ for(a = 0; a < HASH_SIZE; a++)
+ {
+ bl = LIST_FIRST(&host_bans.hash_list[a]);
+ report_list_match_flags(cptr, bl, flags, nflags, 'H');
+ bl = LIST_FIRST(&ip_bans.hash_list[a]);
+ report_list_match_flags(cptr, bl, flags, nflags, 'I');
+ }
+}
+
+char *get_userban_host(struct userBan *ban, char *buf, int buflen)
+{
+ *buf = '\0';
+
+ if(ban->flags & (UBAN_CIDR4|UBAN_CIDR4BIG))
+ snprintf(buf, buflen, "%s/%d", inetntoa((char *)&ban->cidr4ip), netmask_to_cidr(ntohl(ban->cidr4mask)));
+ else
+ snprintf(buf, buflen, "%s", ban->h);
+
+ return buf;
+}
+
+/*
+ * Fills in the following fields
+ * of a userban structure, or returns NULL if invalid stuff is passed.
+ * - flags, u, h, cidr4ip, cidr4mask
+ */
+struct userBan *make_hostbased_ban(char *user, char *phost)
+{
+ char host[512];
+ unsigned int flags = 0, c4h = 0, c4m = 0;
+ int numcount, othercount, wildcount, dotcount, slashcount;
+ char *tmp;
+ struct userBan *b;
+
+ strncpy(host, phost, 512);
+
+ numcount = othercount = wildcount = dotcount = slashcount = 0;
+
+ for(tmp = host; *tmp; tmp++)
+ {
+ switch(*tmp)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ numcount++;
+ break;
+
+ case '*':
+ case '?':
+ wildcount++;
+ break;
+
+ case '.':
+ dotcount++;
+ break;
+
+ case '/':
+ slashcount++;
+ break;
+
+ default:
+ othercount++;
+ break;
+ }
+ }
+
+ if(wildcount && !numcount && !othercount)
+ {
+ if(!user || !*user || mycmp(user, "*") == 0)
+ return NULL; /* all wildcards? aagh! */
+
+ flags = (UBAN_HOST|UBAN_WILD);
+
+ if(mycmp(host, "*.*") == 0 || mycmp(host, "*") == 0)
+ flags |= UBAN_WILDHOST;
+
+ goto success;
+ }
+
+ /* everything must have a dot. never more than one slash. */
+ if(dotcount == 0 || slashcount > 1)
+ return NULL;
+
+ /* wildcarded IP address? -- can we convert it to a CIDR? */
+ if(wildcount && numcount && !othercount)
+ {
+ char octet[4][8];
+ int i1, i2;
+ int gotwild;
+
+ if(slashcount)
+ return NULL; /* slashes and wildcards? */
+
+ /* I see... more than 3 dots? */
+ if(dotcount > 3)
+ return NULL;
+
+ i1 = i2 = 0;
+
+ /* separate this thing into dotcount octets. */
+ for(tmp = host; *tmp; tmp++)
+ {
+ if(*tmp == '.')
+ {
+ octet[i1][i2] = '\0';
+ i2 = 0;
+ i1++;
+ continue;
+ }
+ if(i2 < 6)
+ {
+ octet[i1][i2++] = *tmp;
+ }
+ }
+ octet[i1][i2] = '\0';
+
+ /* verify that each octet is all numbers or just a '*' */
+ /* bans that match 123.123.123.1?? are still valid, just not convertable to a CIDR */
+
+ for(gotwild = i1 = 0; i1 <= dotcount; i1++)
+ {
+ if(strcmp(octet[i1], "*") == 0)
+ {
+ gotwild++;
+ continue;
+ }
+
+ /* ban in the format of 1.2.*.4 */
+ if(gotwild)
+ {
+ flags = (UBAN_IP|UBAN_WILD);
+ goto success;
+ }
+
+ for(i2 = 0; octet[i1][i2]; i2++)
+ {
+ switch(octet[i1][i2])
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ break;
+
+ default:
+ flags = (UBAN_IP|UBAN_WILD);
+ goto success;
+ }
+ }
+ }
+
+ if(octet[0][0] == '*')
+ return NULL; /* the first octet is a wildcard? what the hell? */
+
+ if(octet[1][0] == '*')
+ {
+ sprintf(host, "%s.0.0.0/8", octet[0]);
+ goto cidrforce;
+ }
+ else if(dotcount >= 2 && octet[2][0] == '*')
+ {
+ sprintf(host, "%s.%s.0.0/16", octet[0], octet[1]);
+ goto cidrforce;
+ }
+ else if(dotcount >= 3 && octet[3][0] == '*')
+ {
+ sprintf(host, "%s.%s.%s.0/24", octet[0], octet[1], octet[2]);
+ goto cidrforce;
+ }
+
+ return NULL; /* we should never get here. If we do, something is wrong. */
+ }
+
+ /* CIDR IP4 address? */
+ if(!wildcount && numcount && !othercount && slashcount)
+ {
+ int sval;
+ char *sep, *err;
+ struct in_addr ia, na;
+
+cidrforce:
+ sep = strchr(host, '/'); /* guaranteed to be here because slashcount */
+ *sep = '\0';
+ sep++;
+
+ if((ia.s_addr = inet_addr(host)) == 0xFFFFFFFF) /* invalid ip4 address! */
+ return NULL;
+
+ /* is there a problem with the / mask? */
+ sval = strtol(sep, &err, 10);
+ if(*err != '\0')
+ return NULL;
+
+ if(sval < 0 || sval > 32)
+ return NULL;
+
+ na.s_addr = htonl(cidr_to_netmask(sval));
+ ia.s_addr &= na.s_addr;
+
+ c4h = ia.s_addr;
+ c4m = na.s_addr;
+
+ flags = (sval < 16) ? UBAN_CIDR4BIG : UBAN_CIDR4;
+ goto success;
+ }
+
+ if(slashcount)
+ return NULL;
+
+ if(!othercount)
+ {
+ flags = (UBAN_IP | (wildcount ? UBAN_WILD : 0));
+ goto success;
+ }
+
+ flags = (UBAN_HOST | (wildcount ? UBAN_WILD : 0));
+
+success:
+ b = userban_alloc();
+ if(!b)
+ return NULL;
+
+ b->reason = NULL;
+
+ if(flags & (UBAN_CIDR4BIG|UBAN_CIDR4))
+ {
+ b->cidr4ip = c4h;
+ b->cidr4mask = c4m;
+ b->h = NULL;
+ }
+ else
+ {
+ b->cidr4ip = b->cidr4mask = 0;
+ b->h = (char *)MyMalloc(strlen(host) + 1);
+ strcpy(b->h, host);
+ }
+
+ if(!user || !*user || mycmp(user, "*") == 0)
+ {
+ flags |= UBAN_WILDUSER;
+ b->u = NULL;
+ }
+ else
+ {
+ b->u = (char *)MyMalloc(strlen(user) + 1);
+ strcpy(b->u, user);
+ }
+
+ b->flags = flags;
+
+ return b;
+}
+
+/* simban (simple ban) functions */
+
+/*
+ * make_simpleban does only simple sanity checking.
+ * You must pass it one of each of the following flags in 'flags', or'd together:
+ * SBAN_GCOS (gline) or SBAN_NICK (qline) or SBAN_CHAN (channel qline)
+ * SBAN_LOCAL or SBAN_NETWORK (self-explanatory)
+ */
+struct simBan *make_simpleban(unsigned int flags, char *mask)
+{
+ char *tmp;
+ struct simBan *b;
+ int wildcount = 0, othercount = 0;
+
+ for(tmp = mask; *tmp; tmp++)
+ {
+ switch(*tmp)
+ {
+ case '*':
+ case '?':
+ wildcount++;
+ break;
+
+ default:
+ othercount++;
+ break;
+ }
+ }
+
+ if((flags & (SBAN_NETWORK|SBAN_LOCAL)) == 0)
+ return NULL;
+
+ if((flags & (SBAN_NICK|SBAN_GCOS|SBAN_CHAN)) == 0)
+ return NULL;
+
+ if(othercount == 0)
+ return NULL; /* No bans consisting only of wildcards */
+
+ if(wildcount)
+ flags |= SBAN_WILD;
+
+ b = simban_alloc();
+ if(!b)
+ return NULL;
+
+ b->reason = NULL;
+ b->mask = (char *) MyMalloc(strlen(mask) + 1);
+ strcpy(b->mask, mask);
+ b->flags = flags;
+
+ return b;
+}
+
+void add_simban(struct simBan *b)
+{
+ uBanEnt *bl;
+ aBanList *banlist;
+ ban_list *thelist;
+
+ bl = ubanent_alloc();
+ bl->ban = (struct userBan *) b;
+ b->internal_ent = (void *) bl;
+
+ if(b->flags & SBAN_NICK)
+ banlist = &nick_bans;
+ else if(b->flags & SBAN_CHAN)
+ banlist = &chan_bans;
+ else if(b->flags & SBAN_GCOS)
+ banlist = &gcos_bans;
+ else
+ abort(); /* ack! */
+
+ if(b->flags & SBAN_WILD)
+ {
+ thelist = &banlist->wild_list;
+ }
+ else
+ {
+ unsigned int hv = host_hash(b->mask) % HASH_SIZE;
+
+ thelist = &banlist->hash_list[hv];
+ }
+
+ LIST_INSERT_HEAD(thelist, bl, lp);
+}
+
+void remove_simban(struct simBan *b)
+{
+ uBanEnt *bl = (uBanEnt *) b->internal_ent;
+
+ LIST_REMOVE(bl, lp);
+
+ ubanent_free(bl);
+
+ return;
+}
+
+struct simBan *find_simban_exact(struct simBan *borig)
+{
+ uBanEnt *bl;
+ struct simBan *ban;
+ aBanList *banlist;
+ ban_list *thelist;
+
+ if(borig->flags & SBAN_NICK)
+ banlist = &nick_bans;
+ else if(borig->flags & SBAN_CHAN)
+ banlist = &chan_bans;
+ else if(borig->flags & SBAN_GCOS)
+ banlist = &gcos_bans;
+ else
+ return NULL;
+
+ if(borig->flags & SBAN_WILD)
+ {
+ thelist = &banlist->wild_list;
+ }
+ else
+ {
+ unsigned int hv = host_hash(borig->mask) % HASH_SIZE;
+
+ thelist = &banlist->hash_list[hv];
+ }
+
+ LIST_FOREACH(bl, thelist, lp)
+ {
+ ban = (struct simBan *) bl->ban;
+
+ if(ban->flags != borig->flags)
+ continue;
+
+ if(mycmp(ban->mask, borig->mask))
+ continue;
+
+ return ban;
+ }
+
+ return NULL;
+}
+
+/* does cptr match the ban specified in b?
+ * return: 0 = no
+ */
+int user_match_simban(aClient *cptr, struct simBan *b)
+{
+ char *userinfo;
+ int (*chkfnc)(char *, char *);
+
+ if(b->flags & SBAN_NICK)
+ userinfo = cptr->name;
+ else if(b->flags & SBAN_CHAN)
+ return 0; /* not applicable */
+ else if(b->flags & SBAN_GCOS)
+ userinfo = cptr->info;
+ else
+ abort(); /* aagh! */
+
+ if(b->flags & SBAN_WILD)
+ chkfnc = match;
+ else
+ chkfnc = mycmp;
+
+ if(chkfnc(b->mask, userinfo) == 0)
+ return 1;
+
+ return 0;
+}
+
+struct simBan *check_mask_simbanned(char *mask, unsigned int flags)
+{
+ uBanEnt *bl;
+ struct simBan *ban;
+ aBanList *banlist;
+ ban_list *thelist;
+ int (*chkfnc)(char *, char *);
+ unsigned int hv;
+
+ if(flags & SBAN_NICK)
+ banlist = &nick_bans;
+ else if(flags & SBAN_CHAN)
+ banlist = &chan_bans;
+ else if(flags & SBAN_GCOS)
+ banlist = &gcos_bans;
+ else
+ abort(); /* aagh! */
+
+ hv = host_hash(mask) % HASH_SIZE;
+ thelist = &banlist->hash_list[hv];
+ chkfnc = mycmp;
+ LIST_FOREACH(bl, thelist, lp)
+ {
+ ban = (struct simBan *) bl->ban;
+
+ if((ban->flags & SBAN_TEMPORARY) && ban->timeset + ban->duration <= NOW)
+ continue;
+
+ if(chkfnc(ban->mask, mask))
+ continue;
+
+ return ban;
+ }
+
+ thelist = &banlist->wild_list;
+ chkfnc = match;
+ LIST_FOREACH(bl, thelist, lp)
+ {
+ ban = (struct simBan *) bl->ban;
+
+ if((ban->flags & SBAN_TEMPORARY) && ban->timeset + ban->duration <= NOW)
+ continue;
+
+ if(chkfnc(ban->mask, mask))
+ continue;
+
+ return ban;
+ }
+
+ return NULL;
+}
+
+void report_simbans_match_flags(aClient *cptr, unsigned int flags, unsigned int nflags)
+{
+ uBanEnt *bl;
+ struct simBan *ban;
+ aBanList *banlist;
+ ban_list *thelist;
+ unsigned int hv;
+ char sbuf[16];
+ int slen;
+
+ if(flags & SBAN_NICK)
+ banlist = &nick_bans;
+ else if(flags & SBAN_CHAN)
+ banlist = &chan_bans;
+ else if(flags & SBAN_GCOS)
+ banlist = &gcos_bans;
+ else
+ abort(); /* aagh! */
+
+ for(hv = 0; hv < HASH_SIZE; hv++)
+ {
+ thelist = &banlist->hash_list[hv];
+ LIST_FOREACH(bl, thelist, lp)
+ {
+ ban = (struct simBan *) bl->ban;
+
+ if((ban->flags & SBAN_TEMPORARY) && ban->timeset + ban->duration <= NOW)
+ continue;
+
+ if(((ban->flags & flags) == flags) && ((ban->flags & nflags) == 0))
+ {
+ int rpl = RPL_STATSQLINE;
+ slen = 0;
+ if(flags & SBAN_NICK)
+ {
+ sbuf[slen++] = (flags & SBAN_LOCAL) ? 'Q' : 'q';
+ sbuf[slen++] = 'n';
+ }
+ else if(flags & SBAN_CHAN)
+ {
+ sbuf[slen++] = (flags & SBAN_LOCAL) ? 'Q' : 'q';
+ sbuf[slen++] = 'c';
+ }
+ else if(flags & SBAN_GCOS)
+ {
+ rpl = RPL_STATSGLINE;
+ sbuf[slen++] = (flags & SBAN_LOCAL) ? 'G' : 'g';
+ }
+ sbuf[slen] = '\0';
+
+ sendto_one(cptr, rpl_str(rpl), me.name, cptr->name,
+ sbuf,
+ ban->mask,
+ (ban->flags & SBAN_TEMPORARY) ? (((ban->timeset + ban->duration) - NOW) / 60) : -1,
+ ban->reason ? ban->reason : "No Reason");
+ }
+ }
+ }
+
+ thelist = &banlist->wild_list;
+ LIST_FOREACH(bl, thelist, lp)
+ {
+ ban = (struct simBan *) bl->ban;
+
+ if((ban->flags & SBAN_TEMPORARY) && ban->timeset + ban->duration <= NOW)
+ continue;
+
+ if(((ban->flags & flags) == flags) && ((ban->flags & nflags) == 0))
+ {
+ int rpl = RPL_STATSQLINE;
+ slen = 0;
+ if(flags & SBAN_NICK)
+ {
+ sbuf[slen++] = (flags & SBAN_LOCAL) ? 'Q' : 'q';
+ sbuf[slen++] = 'n';
+ }
+ else if(flags & SBAN_CHAN)
+ {
+ sbuf[slen++] = (flags & SBAN_LOCAL) ? 'Q' : 'q';
+ sbuf[slen++] = 'c';
+ }
+ else if(flags & SBAN_GCOS)
+ {
+ rpl = RPL_STATSGLINE;
+ sbuf[slen++] = (flags & SBAN_LOCAL) ? 'G' : 'g';
+ }
+ sbuf[slen++] = 'w';
+ sbuf[slen] = '\0';
+
+ sendto_one(cptr, rpl_str(rpl), me.name, cptr->name,
+ sbuf,
+ ban->mask,
+ (ban->flags & SBAN_TEMPORARY) ? (((ban->timeset + ban->duration) - NOW) / 60) : -1,
+ ban->reason ? ban->reason : "No Reason");
+ }
+ }
+}
+
+
+void remove_simbans_match_flags(unsigned int flags, unsigned int nflags)
+{
+ uBanEnt *bl;
+ struct simBan *ban;
+ aBanList *banlist;
+ ban_list *thelist;
+ unsigned int hv;
+
+ if(flags & SBAN_NICK)
+ banlist = &nick_bans;
+ else if(flags & SBAN_CHAN)
+ banlist = &chan_bans;
+ else if(flags & SBAN_GCOS)
+ banlist = &gcos_bans;
+ else
+ abort(); /* aagh! */
+
+ for(hv = 0; hv < HASH_SIZE; hv++)
+ {
+ thelist = &banlist->hash_list[hv];
+ LIST_FOREACH(bl, thelist, lp)
+ {
+ ban = (struct simBan *) bl->ban;
+
+ if((ban->flags & SBAN_TEMPORARY) && ban->timeset + ban->duration <= NOW)
+ continue;
+
+ if(((ban->flags & flags) == flags) && ((ban->flags & nflags) == 0))
+ {
+ /* Kludge it out! */
+ ban->flags |= SBAN_TEMPORARY;
+ ban->timeset = NOW - 5;
+ ban->duration = 1;
+ }
+ }
+ }
+
+ thelist = &banlist->wild_list;
+ LIST_FOREACH(bl, thelist, lp)
+ {
+ ban = (struct simBan *) bl->ban;
+
+ if((ban->flags & SBAN_TEMPORARY) && ban->timeset + ban->duration <= NOW)
+ continue;
+
+ if(((ban->flags & flags) == flags) && ((ban->flags & nflags) == 0))
+ {
+ /* Kludge it out! */
+ ban->flags |= SBAN_TEMPORARY;
+ ban->timeset = NOW - 5;
+ ban->duration = 1;
+ }
+ }
+}
+
+void send_simbans(aClient *cptr, unsigned int flags)
+{
+ uBanEnt *bl;
+ struct simBan *ban;
+ aBanList *banlist;
+ ban_list *thelist;
+ unsigned int hv;
+
+ if(flags & SBAN_NICK)
+ banlist = &nick_bans;
+ else if(flags & SBAN_CHAN)
+ banlist = &chan_bans;
+ else if(flags & SBAN_GCOS)
+ banlist = &gcos_bans;
+ else
+ abort(); /* aagh! */
+
+ for(hv = 0; hv < HASH_SIZE; hv++)
+ {
+ thelist = &banlist->hash_list[hv];
+ LIST_FOREACH(bl, thelist, lp)
+ {
+ ban = (struct simBan *) bl->ban;
+
+ if(ban->flags & SBAN_TEMPORARY)
+ continue;
+
+ if((ban->flags & flags) == flags)
+ {
+ if(ban->flags & SBAN_GCOS)
+ sendto_one(cptr, ":%s SGLINE %d :%s:%s", me.name, strlen(ban->mask),
+ ban->mask, ban->reason);
+ else
+ sendto_one(cptr, ":%s SQLINE %s :%s", me.name,
+ ban->mask, ban->reason);
+ }
+ }
+ }
+
+ thelist = &banlist->wild_list;
+ LIST_FOREACH(bl, thelist, lp)
+ {
+ ban = (struct simBan *) bl->ban;
+
+ if(ban->flags & SBAN_TEMPORARY)
+ continue;
+
+ if((ban->flags & flags) == flags)
+ {
+ if(ban->flags & SBAN_GCOS)
+ sendto_one(cptr, ":%s SGLINE %d :%s:%s", me.name, strlen(ban->mask),
+ ban->mask, ban->reason);
+ else
+ sendto_one(cptr, ":%s SQLINE %s :%s", me.name,
+ ban->mask, ban->reason);
+ }
+ }
+}
+
+void remove_simbans_match_mask(unsigned int flags, char *mask, int wild)
+{
+ uBanEnt *bl;
+ struct simBan *ban;
+ aBanList *banlist;
+ ban_list *thelist;
+ unsigned int hv;
+ int (*chkfnc)(char *, char *);
+
+ chkfnc = wild ? match : mycmp;
+
+ if(flags & SBAN_NICK)
+ banlist = &nick_bans;
+ else if(flags & SBAN_CHAN)
+ banlist = &chan_bans;
+ else if(flags & SBAN_GCOS)
+ banlist = &gcos_bans;
+ else
+ abort(); /* aagh! */
+
+ for(hv = 0; hv < HASH_SIZE; hv++)
+ {
+ thelist = &banlist->hash_list[hv];
+ LIST_FOREACH(bl, thelist, lp)
+ {
+ ban = (struct simBan *) bl->ban;
+
+ if((ban->flags & SBAN_TEMPORARY) && ban->timeset + ban->duration <= NOW)
+ continue;
+
+ if((ban->flags & flags) != flags)
+ continue;
+
+ if(chkfnc(mask, ban->mask) == 0)
+ {
+ /* Kludge it out! */
+ ban->flags |= SBAN_TEMPORARY;
+ ban->timeset = NOW - 5;
+ ban->duration = 1;
+ }
+ }
+ }
+
+ thelist = &banlist->wild_list;
+ LIST_FOREACH(bl, thelist, lp)
+ {
+ ban = (struct simBan *) bl->ban;
+
+ if((ban->flags & SBAN_TEMPORARY) && ban->timeset + ban->duration <= NOW)
+ continue;
+
+ if((ban->flags & flags) != flags)
+ continue;
+
+ if(chkfnc(mask, ban->mask) == 0)
+ {
+ /* Kludge it out! */
+ ban->flags |= SBAN_TEMPORARY;
+ ban->timeset = NOW - 5;
+ ban->duration = 1;
+ }
+ }
+}
+
+static inline void expire_simlist(uBanEnt *bl)
+{
+ uBanEnt *bln;
+ struct simBan *ban;
+
+ while(bl)
+ {
+ bln = LIST_NEXT(bl, lp);
+ ban = (struct simBan *)bl->ban;
+
+ if((ban->flags & SBAN_TEMPORARY) && ban->timeset + ban->duration <= NOW)
+ {
+ remove_simban(ban);
+ simban_free(ban);
+ }
+ bl = bln;
+ }
+}
+
+void expire_simbans()
+{
+ uBanEnt *bl;
+ int a;
+
+ bl = LIST_FIRST(&nick_bans.wild_list);
+ expire_simlist(bl);
+ bl = LIST_FIRST(&chan_bans.wild_list);
+ expire_simlist(bl);
+ bl = LIST_FIRST(&gcos_bans.wild_list);
+ expire_simlist(bl);
+
+ for(a = 0; a < HASH_SIZE; a++)
+ {
+ bl = LIST_FIRST(&nick_bans.hash_list[a]);
+ expire_simlist(bl);
+ bl = LIST_FIRST(&chan_bans.hash_list[a]);
+ expire_simlist(bl);
+ bl = LIST_FIRST(&gcos_bans.hash_list[a]);
+ expire_simlist(bl);
+ }
+}
+
+/* Hash and init functions */
+
+unsigned int ip_hash(char *n)
+{
+ unsigned int hv = 0;
+
+ while(*n)
+ {
+ hv = hv * 33 + tolowertab[(unsigned char) *n++];
+ }
+
+ return hv;
+}
+
+unsigned int host_hash(char *n)
+{
+ unsigned int hv = 0;
+
+ while(*n)
+ {
+ if(*n != '.')
+ {
+ hv <<= 5;
+ hv |= ((touppertab[(unsigned char) *n]) - 65) & 0xFF;
+ }
+ n++;
+ }
+
+ return hv;
+}
+
+void init_banlist(aBanList *a, int numbuckets)
+{
+ memset(a, 0, sizeof(aBanList));
+ a->numbuckets = numbuckets;
+ a->hash_list = (ban_list *) MyMalloc(numbuckets * sizeof(ban_list));
+ memset(a->hash_list, 0, numbuckets * sizeof(ban_list));
+}
+
+void init_userban()
+{
+ int i;
+
+ CIDR4_bans = (ban_list **) MyMalloc(256 * sizeof(ban_list *));
+ for(i = 0; i < 256; i++)
+ {
+ CIDR4_bans[i] = (ban_list *) MyMalloc(256 * sizeof(ban_list));
+ memset(CIDR4_bans[i], 0, 256 * sizeof(ban_list));
+ }
+
+ init_banlist(&host_bans, HASH_SIZE);
+ init_banlist(&ip_bans, HASH_SIZE);
+
+ init_banlist(&gcos_bans, HASH_SIZE);
+ init_banlist(&nick_bans, HASH_SIZE);
+ init_banlist(&chan_bans, HASH_SIZE);
+}
+
+unsigned int userban_count = 0, ubanent_count = 0, simban_count = 0;
+
+struct userBan *userban_alloc()
+{
+ struct userBan *b;
+
+ b = (struct userBan *) MyMalloc(sizeof(struct userBan));
+ if(b)
+ {
+ memset(b, 0, sizeof(struct userBan));
+ userban_count++;
+ }
+ return b;
+}
+
+void userban_free(struct userBan *b)
+{
+ if(b->u)
+ MyFree(b->u);
+
+ if(b->h)
+ MyFree(b->h);
+
+ if(b->reason)
+ MyFree(b->reason);
+
+ userban_count--;
+ MyFree(b);
+}
+
+uBanEnt *ubanent_alloc()
+{
+ uBanEnt *b;
+
+ b = (uBanEnt *) MyMalloc(sizeof(uBanEnt));
+ if(b)
+ {
+ memset(b, 0, sizeof(uBanEnt));
+ ubanent_count++;
+ }
+ return b;
+}
+
+void ubanent_free(uBanEnt *b)
+{
+ ubanent_count--;
+ MyFree(b);
+}
+
+struct simBan *simban_alloc()
+{
+ struct simBan *b;
+
+ b = (struct simBan *) MyMalloc(sizeof(struct simBan));
+ if(b)
+ {
+ memset(b, 0, sizeof(struct simBan));
+ simban_count++;
+ }
+ return b;
+}
+
+void simban_free(struct simBan *b)
+{
+ if(b->mask)
+ MyFree(b->mask);
+
+ if(b->reason)
+ MyFree(b->reason);
+
+ simban_count--;
+ MyFree(b);
+}
+
+int count_simlist(uBanEnt *bl, int *mem)
+{
+ uBanEnt *bln;
+ struct simBan *ban;
+ int umem = 0, ucnt = 0;
+
+ while(bl)
+ {
+ bln = LIST_NEXT(bl, lp);
+ ban = (struct simBan *)bl->ban;
+
+ ucnt++;
+ umem += sizeof(struct simBan);
+ if(ban->mask)
+ umem += (strlen(ban->mask) + 1);
+
+ if(ban->reason)
+ umem += (strlen(ban->reason) + 1);
+
+ bl = bln;
+ }
+
+ if(mem)
+ *mem = umem;
+
+ return ucnt;
+}
+
+int count_list(uBanEnt *bl, int *mem)
+{
+ uBanEnt *bln;
+ struct userBan *ban;
+ int umem = 0, ucnt = 0;
+
+ while(bl)
+ {
+ bln = LIST_NEXT(bl, lp);
+ ban = bl->ban;
+
+ ucnt++;
+ umem += sizeof(struct userBan);
+ if(ban->u)
+ umem += (strlen(ban->u) + 1);
+ if(ban->h)
+ umem += (strlen(ban->h) + 1);
+ if(ban->reason)
+ umem += (strlen(ban->reason) + 1);
+
+ bl = LIST_NEXT(bl, lp);
+ }
+
+ if(mem)
+ *mem = umem;
+
+ return ucnt;
+}
+
+int count_userbans(aClient *cptr)
+{
+ uBanEnt *bl;
+ int a, b;
+ int ic[16], im[16];
+ int ict = 0, imt = 0;
+
+ memset(ic, 0, sizeof(int) * 16);
+ memset(im, 0, sizeof(int) * 16);
+
+ bl = LIST_FIRST(&CIDR4BIG_bans);
+ ic[0] = count_list(bl, &im[0]);
+
+ for(a = 0; a < 256; a++)
+ {
+ for(b = 0; b < 256; b++)
+ {
+ int tmpim;
+
+ bl = LIST_FIRST(&CIDR4_bans[a][b]);
+ ic[1] += count_list(bl, &tmpim);
+ im[1] += tmpim;
+ }
+ }
+
+ bl = LIST_FIRST(&host_bans.wild_list);
+ ic[2] = count_list(bl, &im[2]);
+ bl = LIST_FIRST(&ip_bans.wild_list);
+ ic[3] = count_list(bl, &im[3]);
+
+ for(a = 0; a < HASH_SIZE; a++)
+ {
+ int tmpim;
+
+ bl = LIST_FIRST(&host_bans.hash_list[a]);
+ ic[4] += count_list(bl, &tmpim);
+ im[4] += tmpim;
+
+ bl = LIST_FIRST(&ip_bans.hash_list[a]);
+ ic[5] += count_list(bl, &tmpim);
+ im[5] += tmpim;
+ }
+
+ for(a = 0; a < 16; a++)
+ {
+ ict += ic[a];
+ imt += im[a];
+ }
+
+ sendto_one(cptr, ":%s %d %s :UserBans %d(%d) UserBanEnts %d(%d)",
+ me.name, RPL_STATSDEBUG, cptr->name, ict, imt, ubanent_count,
+ ubanent_count * sizeof(uBanEnt));
+
+ sendto_one(cptr, ":%s %d %s : CIDR4BIG %d(%d)",
+ me.name, RPL_STATSDEBUG, cptr->name, ic[0], im[0]);
+ sendto_one(cptr, ":%s %d %s : CIDR4 %d(%d)",
+ me.name, RPL_STATSDEBUG, cptr->name, ic[1], im[1]);
+ sendto_one(cptr, ":%s %d %s : Host %d(%d)",
+ me.name, RPL_STATSDEBUG, cptr->name, ic[4], im[4]);
+ sendto_one(cptr, ":%s %d %s : Host wild %d(%d)",
+ me.name, RPL_STATSDEBUG, cptr->name, ic[2], im[2]);
+ sendto_one(cptr, ":%s %d %s : IP %d(%d)",
+ me.name, RPL_STATSDEBUG, cptr->name, ic[5], im[5]);
+ sendto_one(cptr, ":%s %d %s : IP wild %d(%d)",
+ me.name, RPL_STATSDEBUG, cptr->name, ic[3], im[3]);
+
+ return imt + (ubanent_count * sizeof(uBanEnt));
+}
+
+int count_simbans(aClient *cptr)
+{
+ uBanEnt *bl;
+ int a;
+ int ic[16], im[16];
+ int ict = 0, imt = 0;
+
+ memset(ic, 0, sizeof(int) * 16);
+ memset(im, 0, sizeof(int) * 16);
+
+ bl = LIST_FIRST(&nick_bans.wild_list);
+ ic[1] = count_simlist(bl, &im[1]);
+ bl = LIST_FIRST(&chan_bans.wild_list);
+ ic[3] = count_simlist(bl, &im[3]);
+ bl = LIST_FIRST(&gcos_bans.wild_list);
+ ic[5] = count_simlist(bl, &im[5]);
+
+ for(a = 0; a < HASH_SIZE; a++)
+ {
+ int tmpim;
+
+ bl = LIST_FIRST(&nick_bans.hash_list[a]);
+ ic[0] += count_list(bl, &tmpim);
+ im[0] += tmpim;
+
+ bl = LIST_FIRST(&chan_bans.hash_list[a]);
+ ic[2] += count_list(bl, &tmpim);
+ im[2] += tmpim;
+
+ bl = LIST_FIRST(&gcos_bans.hash_list[a]);
+ ic[4] += count_list(bl, &tmpim);
+ im[4] += tmpim;
+ }
+
+ for(a = 0; a < 16; a++)
+ {
+ ict += ic[a];
+ imt += im[a];
+ }
+
+ sendto_one(cptr, ":%s %d %s :SimBans %d(%d)",
+ me.name, RPL_STATSDEBUG, cptr->name, ict, imt);
+
+ sendto_one(cptr, ":%s %d %s : Nick %d(%d)",
+ me.name, RPL_STATSDEBUG, cptr->name, ic[0], im[0]);
+ sendto_one(cptr, ":%s %d %s : Nick wild %d(%d)",
+ me.name, RPL_STATSDEBUG, cptr->name, ic[1], im[1]);
+ sendto_one(cptr, ":%s %d %s : Chan %d(%d)",
+ me.name, RPL_STATSDEBUG, cptr->name, ic[2], im[2]);
+ sendto_one(cptr, ":%s %d %s : Chan wild %d(%d)",
+ me.name, RPL_STATSDEBUG, cptr->name, ic[3], im[3]);
+ sendto_one(cptr, ":%s %d %s : GCOS %d(%d)",
+ me.name, RPL_STATSDEBUG, cptr->name, ic[4], im[4]);
+ sendto_one(cptr, ":%s %d %s : GCOS wild %d(%d)",
+ me.name, RPL_STATSDEBUG, cptr->name, ic[5], im[5]);
+
+ return imt;
+}
+
--- /dev/null
+#!/bin/sh
+spitshell=cat
+package=IRC
+
+echo "Extracting $package/src/version.c..."
+
+if test -r version.c.last
+then
+ generation=`sed -n 's/^char \*generation = \"\(.*\)\";/\1/p' < version.c.last`
+if test ! "$generation" ; then generation=0; fi
+else
+ generation=0
+fi
+
+generation=`expr $generation + 1`
+
+uname=`uname -a`
+
+creation=`date | \
+awk '{if (NF == 6) \
+{ print $1 " " $2 " " $3 " " $6 " at " $4 " " $5 } \
+else \
+{ print $1 " " $2 " " $3 " " $7 " at " $4 " " $5 " " $6 }}'`
+
+$spitshell >version.c <<!SUB!THIS!
+/*
+ * IRC - Internet Relay Chat, src/version.c
+ * Copyright (C) 1990 Chelsea Ashley Dyerman
+ *
+ * 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 1, 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.
+ */
+
+/*
+ * This file is generated by version.c.SH. Any changes made will go away.
+ */
+
+#include "struct.h"
+#include "patchlevel.h"
+
+char *generation = "$generation";
+char *creation = "$creation";
+char version[128];
+
+char *infotext[] =
+ {
+ "$package --",
+ "Based on the original code written by Jarkko Oikarinen",
+ "Copyright 1988, 1989, 1990, 1991 University of Oulu, Computing Center",
+ "",
+ "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 1, or",
+ "(at your option) any later version.",
+ "",
+ "Regular expression support is provided by the PCRE library package,",
+ "which is open source software, written by Philip Hazel, and copyright",
+ "by the University of Cambridge, England.",
+ "",
+ "Send bug reports to dalnet-src@dal.net",
+ "",
+ "The following people currently compose the bahamut team and",
+ "actively maintain the bahamut codebase:",
+ "epiphani Aaron Wiebe epiphani@dal.net",
+ "Quension Trevor Talbot quension@dal.net",
+ "sedition David Parton sedition@dal.net",
+ "",
+ "The following people have contributed code or support",
+ "to the bahamut team:",
+ "aClient Diane Bruce db@koruna.varner.com",
+ "Dakal David Knepper dakal@dal.net",
+ "Dalvenjah Sven Nielsen dalvenjah@dal.net",
+ "MSofty Mark Salerno msofty@dal.net",
+ "Raistlin_Majere Jason Slagle raistlin@bahamut.net",
+ "Rakarra Ian Westcott rakarra@dal.net",
+ "lucas Lucas Madar lucas@dal.net",
+ "srd Sean McKay srd@powertrip.net",
+ "White_Dragon Chip Norkus wd@dal.net",
+ "xPsycho Ryan Smith xpsycho@dal.net",
+ "",
+ "The following people have contributed ideas or testing to the",
+ "bahamut project:",
+ "driz David Friedman driz@dal.net",
+ "drone Mike Wilson drone@dal.net",
+ "habit Melinda Thompson habit@dal.net",
+ "Kevin Kevin Turner kevin@dal.net",
+ "",
+ "",
+ "Developers and Contributors for previous versions:",
+ "Chris A. Bongaarts Chris Behrens Diane Bruce",
+ "Johannes Erdfelt Roger Espel Llima Jon Lusky",
+ "Michael Pearce Brian Kraemer Joan Touzet",
+ "Chris Portman Keith Fralick Sam Noble",
+ "Taner Halicioglu Chris Behrens Darren Reed",
+ "Markku Savela Greg Lindahl Jarkko Oikarinen",
+ "Armin Gruner Matthew Green Chuck Kane",
+ "Matt Lyle Vesa Ruokonen Nicolas PIOCH",
+ "Stellan Klebom Dan Goodwin Mike Bolotski",
+ "Ian Frechette Markku Jarvinen Kimmo Suominen",
+ "Jeff Trim Vijay Subramaniam Karl Kleinpaste",
+ "Bill Wisner Tom Davis Hugo Calendar",
+ "Tom Hopkins Stephen van den Berg",
+ "Bo Adler Michael Sandrof Jon Solomon",
+ "Jan Peterson Helen Rose Paul Graham",
+ "",
+ "Thanks also goes to those persons not mentioned here who have added",
+ "their advice, opinions, and code to IRC.",
+ "Thanks also to those who provide the kind sys admins who let me and",
+ "others continue to develop IRC.",
+ "",
+ 0,
+};
+!SUB!THIS!
--- /dev/null
+/************************************************************************
+* IRC - Internet Relay Chat, src/whowas.c
+* Copyright (C) 1990 Markku Savela
+*
+* 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 1, 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.
+*/
+
+/* $Id: whowas.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "h.h"
+
+/* externally defined functions */
+unsigned int hash_whowas_name(char *); /* defined in hash.c */
+/* internally defined function */
+static void add_whowas_to_clist(aWhowas **, aWhowas *);
+static void del_whowas_from_clist(aWhowas **, aWhowas *);
+static void add_whowas_to_list(aWhowas **, aWhowas *);
+static void del_whowas_from_list(aWhowas **, aWhowas *);
+
+aWhowas WHOWAS[NICKNAMEHISTORYLENGTH];
+aWhowas *WHOWASHASH[WW_MAX];
+
+int whowas_next = 0;
+
+void add_history(aClient *cptr, int online)
+{
+ aWhowas *new;
+
+ new = &WHOWAS[whowas_next];
+
+ if (new->hashv != -1)
+ {
+ if (new->online)
+ del_whowas_from_clist(&(new->online->whowas), new);
+ del_whowas_from_list(&WHOWASHASH[new->hashv], new);
+ }
+ new->hashv = hash_whowas_name(cptr->name);
+ new->logoff = NOW;
+ strncpyzt(new->name, cptr->name, NICKLEN + 1);
+ strncpyzt(new->username, cptr->user->username, USERLEN + 1);
+ strncpyzt(new->hostname, cptr->user->host, HOSTLEN);
+ strncpyzt(new->realname, cptr->info, REALLEN);
+ /*
+ * Its not string copied, a pointer to the scache hash is copied
+ * -Dianora
+ */
+ new->servername = cptr->user->server;
+ new->umode = cptr->umode;
+
+ if (online)
+ {
+ new->online = cptr;
+ add_whowas_to_clist(&(cptr->whowas), new);
+ }
+ else
+ new->online = NULL;
+ add_whowas_to_list(&WHOWASHASH[new->hashv], new);
+ whowas_next++;
+ if (whowas_next == NICKNAMEHISTORYLENGTH)
+ whowas_next = 0;
+}
+
+void off_history(aClient *cptr)
+{
+ aWhowas *temp, *next;
+
+ for (temp = cptr->whowas; temp; temp = next)
+ {
+ next = temp->cnext;
+ temp->online = NULL;
+ del_whowas_from_clist(&(cptr->whowas), temp);
+ }
+}
+
+aClient *get_history(char *nick, time_t timelimit)
+{
+ aWhowas *temp;
+ int blah;
+
+ timelimit = NOW - timelimit;
+ blah = hash_whowas_name(nick);
+ temp = WHOWASHASH[blah];
+ for (; temp; temp = temp->next)
+ {
+ if (mycmp(nick, temp->name))
+ continue;
+ if (temp->logoff < timelimit)
+ continue;
+ return temp->online;
+ }
+ return NULL;
+}
+
+/*
+ * m_whowas
+ * parv[0] = sender prefix
+ * parv[1] = nickname queried
+ */
+int m_whowas(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+ aWhowas *temp;
+ int cur = 0;
+ int max = -1, found = 0;
+ char *p, *nick, *s;
+
+ if (parc < 2)
+ {
+ sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN),
+ me.name, parv[0]);
+ return 0;
+ }
+ if (parc > 2)
+ max = atoi(parv[2]);
+ if (parc > 3)
+ if (hunt_server(cptr, sptr, ":%s WHOWAS %s %s :%s", 3, parc, parv))
+ return 0;
+
+ parv[1] = canonize(parv[1]);
+ if (!MyConnect(sptr) && (max > 20))
+ max = 20;
+ for (s = parv[1]; (nick = strtoken(&p, s, ",")); s = NULL)
+ {
+ temp = WHOWASHASH[hash_whowas_name(nick)];
+ found = 0;
+ for (; temp; temp = temp->next)
+ {
+ if (!mycmp(nick, temp->name))
+ {
+ sendto_one(sptr, rpl_str(RPL_WHOWASUSER),
+ me.name, parv[0], temp->name,
+ temp->username,
+ temp->hostname,
+ temp->realname);
+ if((temp->umode & UMODE_I) && !IsAnOper(sptr))
+ sendto_one(sptr, rpl_str(RPL_WHOISSERVER),
+ me.name, parv[0], temp->name,
+ HIDDEN_SERVER_NAME, myctime(temp->logoff));
+ else
+ sendto_one(sptr, rpl_str(RPL_WHOISSERVER),
+ me.name, parv[0], temp->name,
+ temp->servername, myctime(temp->logoff));
+ cur++;
+ found++;
+ }
+ if (max > 0 && cur >= max)
+ break;
+ }
+ if (!found)
+ sendto_one(sptr, err_str(ERR_WASNOSUCHNICK),
+ me.name, parv[0], nick);
+ if (p)
+ p[-1] = ',';
+ }
+ sendto_one(sptr, rpl_str(RPL_ENDOFWHOWAS), me.name, parv[0], parv[1]);
+ return 0;
+}
+
+void initwhowas()
+{
+ int i;
+
+ for (i = 0; i < NICKNAMEHISTORYLENGTH; i++)
+ {
+ memset((char *) &WHOWAS[i], '\0', sizeof(aWhowas));
+ WHOWAS[i].hashv = -1;
+ }
+ for (i = 0; i < WW_MAX; i++)
+ WHOWASHASH[i] = NULL;
+}
+
+static void add_whowas_to_clist(aWhowas ** bucket, aWhowas * whowas)
+{
+ whowas->cprev = NULL;
+ if ((whowas->cnext = *bucket) != NULL)
+ whowas->cnext->cprev = whowas;
+ *bucket = whowas;
+}
+
+static void del_whowas_from_clist(aWhowas ** bucket, aWhowas * whowas)
+{
+ if (whowas->cprev)
+ whowas->cprev->cnext = whowas->cnext;
+ else
+ *bucket = whowas->cnext;
+ if (whowas->cnext)
+ whowas->cnext->cprev = whowas->cprev;
+}
+
+static void add_whowas_to_list(aWhowas ** bucket, aWhowas * whowas)
+{
+ whowas->prev = NULL;
+ if ((whowas->next = *bucket) != NULL)
+ whowas->next->prev = whowas;
+ *bucket = whowas;
+}
+
+static void del_whowas_from_list(aWhowas ** bucket, aWhowas * whowas)
+{
+ if (whowas->prev)
+ whowas->prev->next = whowas->next;
+ else
+ *bucket = whowas->next;
+ if (whowas->next)
+ whowas->next->prev = whowas->prev;
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, src/zlink.c
+ * Copyright (C) 2000 Lucas Madar
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: zlink.c,v 1.1 2005/01/12 07:44:57 mmondor Exp $ */
+
+/*
+ * This streaming ircd zlib implementation was
+ * inspired mostly by dianora's example in hybrid-6
+ * - lucas
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "zlib.h"
+
+#define COMPRESSION_LEVEL 3 /* 0 to 9, 0 = none */
+#define ZIP_MIN_BLOCK 1024 /* smallest block to compress */
+#define ZIP_MAX_BLOCK 8192 /* largest block to compress */
+
+/*
+ * This shouldn't be necessary.
+ * The outbuf should never be larger than
+ * the maximum block.. should it?
+ * I'll account for any weirdness in zlib.
+ *
+ * WARNING:
+ * Please be aware that if you are using both encryption
+ * and ziplinks, rc4buf in send.c MUST be the same size
+ * as zipOutBuf in zlink.c!
+ */
+#define zipOutBufSize (ZIP_MAX_BLOCK * 2)
+static char zipOutBuf[zipOutBufSize];
+
+/*
+ * 64k overflowed every now and then.
+ * This isn't that important, an overflow is
+ * non-fatal, but causes more calls to deflate()
+ * 96k seems to overflow a lot now.
+ */
+#define zipInBufSize (131072) /* 128K */
+static char zipInBuf[zipInBufSize];
+
+/* opaque "out" data structure */
+struct zipped_link_out
+{
+ z_stream stream; /* zip stream data */
+ char buf[ZIP_MAX_BLOCK]; /* zipped buffer */
+ int bufsize; /* size of inbuf content */
+};
+
+/* opaque "in" data structure */
+struct zipped_link_in
+{
+ z_stream stream; /* zip stream data */
+};
+
+/* returns a pointer to a setup opaque input session */
+void *zip_create_input_session()
+{
+ struct zipped_link_in *zip;
+
+ zip = (struct zipped_link_in *) malloc(sizeof(struct zipped_link_in));
+
+ memset(zip, 0, sizeof(struct zipped_link_in));
+
+ zip->stream.zalloc = NULL;
+ zip->stream.zfree = NULL;
+ zip->stream.data_type = Z_ASCII;
+
+ if(inflateInit(&zip->stream) != Z_OK)
+ return NULL;
+
+ return (void *) zip;
+}
+
+/* returns a pointer to an opaque output session */
+void *zip_create_output_session()
+{
+ struct zipped_link_out *zip;
+
+ zip = (struct zipped_link_out *) malloc(sizeof(struct zipped_link_out));
+
+ memset(zip, 0, sizeof(struct zipped_link_out));
+
+ zip->stream.zalloc = NULL;
+ zip->stream.zfree = NULL;
+ zip->stream.data_type = Z_ASCII;
+
+ if(deflateInit(&zip->stream, COMPRESSION_LEVEL) != Z_OK)
+ return NULL;
+
+ return (void *) zip;
+}
+
+/*
+ * zip_input()
+ *
+ * session - opaque in-session pointer
+ * buffer - compressed buffer
+ * len - length of buffer (will change)
+ * err - numeric error if length is -1 on return
+ * nbuf - set if this function needs to be called again
+ * nbuflen - if nbuf is set, length to call with again.
+ * -- nbuf, if set, should call zip_input when done processing
+ * first return, with buffer set to nbuf.
+ * returns:
+ * len > -1:
+ * compressed data
+ * len == -1:
+ * error message
+ */
+char *zip_input(void *session, char *buffer, int *len, int *err,
+ char **nbuf, int *nbuflen)
+{
+ struct zipped_link_in *z = (struct zipped_link_in *) session;
+ z_stream *zin = &z->stream;
+ int ret;
+
+ *nbuf = NULL;
+ *err = 0;
+
+ zin->next_in = buffer;
+ zin->avail_in = *len;
+ zin->next_out = zipInBuf;
+ zin->avail_out = zipInBufSize;
+
+ ret = inflate(zin, Z_SYNC_FLUSH);
+
+ switch(ret)
+ {
+ case Z_OK:
+ if(zin->avail_in) /* grrr, didn't take all the input */
+ {
+ if(zin->avail_out != 0) /* but there was still output left??? */
+ {
+ *len = -1;
+ return zin->msg ? zin->msg : "????";
+ }
+ *nbuf = zin->next_in;
+ *nbuflen = zin->avail_in;
+ *len = zipInBufSize - zin->avail_out;
+ return zipInBuf;
+ }
+ else
+ {
+ *len = zipInBufSize - zin->avail_out;
+ return zipInBuf;
+ }
+
+ default:
+ *len = -1;
+ *err = ret;
+ return zin->msg ? zin->msg : "????";
+ }
+}
+
+/* returns the amount of data waiting in the outgoing buffer */
+int zip_is_data_out(void *session)
+{
+ struct zipped_link_out *z = (struct zipped_link_out *) session;
+
+ return z->bufsize;
+}
+
+/*
+ * zip_output():
+ * session is opaque session pointer.
+ * buffer is buffer to compress.
+ * len is length of buffer, will change.
+ * forceflush forces inflate to return a buffer, even if it has
+ * not optimally compressed something.
+ * Largedata should be nonzero during a split.
+ * largedata is also an error number, it is set if len is -1.
+ * if len is -1, returns null terminated error string.
+ */
+char *zip_output(void *session, char *buffer, int *len,
+ int forceflush, int *largedata)
+{
+ struct zipped_link_out *z = (struct zipped_link_out *) session;
+ z_stream *zout = &z->stream;
+ int ret;
+
+ if(buffer)
+ {
+ memcpy(z->buf + z->bufsize, buffer, *len);
+ z->bufsize += *len;
+ }
+
+ if( !forceflush && ((z->bufsize < ZIP_MIN_BLOCK) ||
+ (largedata && (z->bufsize < (ZIP_MAX_BLOCK - 512)))))
+ {
+ *len = 0;
+ return NULL;
+ }
+
+ zout->next_in = z->buf;
+ zout->avail_in = z->bufsize;
+ zout->next_out = zipOutBuf;
+ zout->avail_out = zipOutBufSize;
+
+ /*
+ * We do our own internal buffering,
+ * so flush all the time.
+ */
+ ret = deflate(zout, Z_SYNC_FLUSH);
+
+ if(ret == Z_OK)
+ {
+ z->bufsize = 0;
+ *len = zipOutBufSize - zout->avail_out;
+ return zipOutBuf;
+ }
+
+ *len = -1;
+ *largedata = ret;
+ return zout->msg ? zout->msg : "???";
+}
+
+/* if *insiz is zero, there are no stats available for this session. */
+void zip_out_get_stats(void *session, unsigned long *insiz,
+ unsigned long *outsiz, double *ratio)
+{
+ struct zipped_link_out *z = (struct zipped_link_out *) session;
+
+ *insiz = z->stream.total_in;
+ *outsiz = z->stream.total_out;
+
+ if(*insiz)
+ *ratio = ((100.0 * (double)z->stream.total_out) /
+ (double) z->stream.total_in);
+}
+
+void zip_in_get_stats(void *session, unsigned long *insiz,
+ unsigned long *outsiz, double *ratio)
+{
+ struct zipped_link_in *z = (struct zipped_link_in *) session;
+
+ *insiz = z->stream.total_in;
+ *outsiz = z->stream.total_out;
+
+ if(*outsiz)
+ *ratio = ((100.0 * (double)z->stream.total_in) /
+ (double) z->stream.total_out);
+}
+
+void zip_destroy_output_session(void *session)
+{
+ struct zipped_link_out *z = (struct zipped_link_out *) session;
+
+ deflateEnd(&z->stream);
+ free(session);
+}
+
+void zip_destroy_input_session(void *session)
+{
+ struct zipped_link_in *z = (struct zipped_link_in *) session;
+
+ inflateEnd(&z->stream);
+ free(session);
+}
+
--- /dev/null
+CC=@CC@
+RM=@RM@
+MV=@MV@
+IRCDLIBS=@LIBS@
+INSTALL=@INSTALL@
+INSTALL_BIN=@INSTALL_PROGRAM@
+INSTALL_DIR=@INSTALL_DIR@
+INCLUDEDIR=-I../include
+
+mkpasswd_SOURCES = mkpasswd.c
+mkpasswd_OBJECTS = mkpasswd.o
+convert_conf_SOURCES = convert_conf.c
+convert_conf_OBJECTS = convert_conf.o ../src/match.o
+PROGRAMS = mkpasswd convert_conf
+
+all_OBJECTS = $(mkpasswd_OBJECTS) $(convert_conf_OBJECTS)
+
+all: mkpasswd convert_conf
+
+build: all
+
+mkpasswd: $(mkpasswd_OBJECTS)
+ $(CC) -o mkpasswd $(mkpasswd_OBJECTS) $(IRCDLIBS)
+
+convert_conf: $(convert_conf_OBJECTS)
+ $(CC) -o convert_conf $(convert_conf_OBJECTS) $(IRCDLIBS)
+
+clean:
+ $(RM) -f $(all_OBJECTS) mkpasswd convert_conf *~ core
+
+distclean: clean
+ $(RM) -f Makefile
+
+.c.o:
+ $(CC) $(CFLAGS) $(INCLUDEDIR) -c $<
+
+install:
+ @for i in $(PROGRAMS); do \
+ if test -f $(INSTALL_DIR)/$$i; then \
+ echo $(MV) $(INSTALL_DIR)/$$i $(INSTALL_DIR)/$$i.old; \
+ $(MV) $(INSTALL_DIR)/$$i $(INSTALL_DIR)/$$i.old; \
+ fi; \
+ echo $(INSTALL_BIN) $$i $(INSTALL_DIR); \
+ $(INSTALL_BIN) $$i $(INSTALL_DIR); \
+ done
--- /dev/null
+/* tools/convert_conf.c
+ * Copyright (c) 2004, Aaron Wiebe
+ * and The Bahamut Development Team
+ *
+ * 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 1, 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.
+ */
+
+/* $Id: convert_conf.c,v 1.1 2005/01/12 07:44:59 mmondor Exp $ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "inet.h"
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+
+/* the majority of this is just cut and paste from ircd */
+
+#define MyMalloc(x) malloc(x)
+#define SBAN_LOCAL 0x001
+#define SBAN_NETWORK 0x002
+#define SBAN_NICK 0x004 /* sban on the nick field */
+#define SBAN_GCOS 0x008 /* sban on the gcos field */
+#define SBAN_CHAN 0x010 /* sban on the chname field */
+#define SBAN_WILD 0x020 /* sban mask contains wildcards */
+#define SBAN_TEMPORARY 0x040 /* sban is temporary */
+
+#define MAX_USERVERS 32
+
+aConnect *connects = ((aConnect *) NULL); /* connects, C/N pairs */
+aAllow *allows = ((aAllow *) NULL); /* allows - I lines */
+Conf_Me *MeLine = ((Conf_Me *) NULL); /* meline - only one */
+aOper *opers = ((aOper *) NULL); /* opers - Olines */
+aPort *ports = ((aPort *) NULL); /* ports - P/M lines */
+aClass *classes = NULL;
+char *uservers[MAX_USERVERS];
+
+typedef struct _asimban SimBan;
+typedef struct _ahostban HostBan;
+
+struct _asimban
+{
+ int type;
+ char *reason;
+ char *target;
+ SimBan *next;
+};
+
+struct _ahostban
+{
+ char *username;
+ char *reason;
+ char *target;
+ HostBan *next;
+};
+
+SimBan *sbans = NULL;
+HostBan *hbans = NULL;
+int do_tline = 0;
+char ProxyMonHost[HOSTLEN+1];
+char ProxyMonURL[TOPICLEN+1];
+
+
+int dgets(int fd, char *buf, int num)
+{
+ static char dgbuf[8192];
+ static char *head = dgbuf, *tail = dgbuf;
+ char *s, *t;
+ int n, nr;
+
+ /* Sanity checks. */
+ if (head == tail)
+ *head = '\0';
+
+ if (!num)
+ {
+ head = tail = dgbuf;
+ *head = '\0';
+ return 0;
+ }
+
+ if (num > sizeof(dgbuf) - 1)
+ num = sizeof(dgbuf) - 1;
+
+ FOREVER
+ {
+ if (head > dgbuf)
+ {
+ for (nr = tail - head, s = head, t = dgbuf; nr > 0; nr--)
+ *t++ = *s++;
+ tail = t;
+ head = dgbuf;
+ }
+ /* check input buffer for EOL and if present return string. */
+ if (head < tail &&
+ ((s = strchr(head, '\n')) ||
+ (s = strchr(head, '\r'))) && s < tail)
+ {
+ n = MIN(s - head + 1, num); /* at least 1 byte */
+ memcpy(buf, head, n);
+ head += n;
+ if (head == tail)
+ head = tail = dgbuf;
+ return n;
+ }
+
+
+ if (tail - head >= num)
+ { /* dgets buf is big enough */
+ n = num;
+ memcpy(buf, head, n);
+ head += n;
+ if (head == tail)
+ head = tail = dgbuf;
+ return n;
+ }
+
+ n = sizeof(dgbuf) - (tail - dgbuf) - 1;
+ nr = read(fd, tail, n);
+ if (nr == -1)
+ {
+ head = tail = dgbuf;
+ return -1;
+ }
+
+ if (!nr)
+ {
+ if (tail > head)
+ {
+ n = MIN(tail - head, num);
+ memcpy(buf, head, n);
+ head += n;
+ if (head == tail)
+ head = tail = dgbuf;
+ return n;
+ }
+ head = tail = dgbuf;
+ return 0;
+ }
+
+ tail += nr;
+ *tail = '\0';
+
+ for (t = head; (s = strchr(t, '\n'));)
+ {
+ if ((s > head) && (s > dgbuf))
+ {
+ t = s - 1;
+ for (nr = 0; *t == '\\'; nr++)
+ t--;
+ if (nr & 1)
+ {
+ t = s + 1;
+ s--;
+ nr = tail - t;
+ while (nr--)
+ *s++ = *t++;
+ tail -= 2;
+ *tail = '\0';
+ }
+ else
+ s++;
+ }
+ else
+ s++;
+ t = s;
+ }
+ *tail = '\0';
+ }
+}
+
+
+char *getfield(char *newline)
+{
+ static char *line = (char *) NULL;
+ char *end, *field;
+
+ if (newline)
+ line = newline;
+
+ if (line == (char *) NULL)
+ return ((char *) NULL);
+
+ field = line;
+ if ((end = strchr(line, ':')) == NULL)
+ {
+ line = (char *) NULL;
+ if ((end = strchr(field, '\n')) == (char *) NULL)
+ end = field + strlen(field);
+ }
+ else
+ line = end + 1;
+ *end = '\0';
+ return (field);
+}
+
+
+aClass *make_class()
+{
+ aClass *tmp;
+
+ tmp = (aClass *) MyMalloc(sizeof(aClass));
+ return tmp;
+}
+
+void free_class(tmp)
+ aClass *tmp;
+{
+ MyFree(tmp);
+}
+
+aOper *make_oper()
+{
+ aOper *i;
+ i = (struct Conf_Oper *) MyMalloc(sizeof(aOper));
+ memset((char *) i, '\0', sizeof(aOper));
+ return i;
+}
+
+SimBan *make_simban()
+{
+ SimBan *i;
+ i = (struct _asimban *) MyMalloc(sizeof(SimBan));
+ memset((char *) i, '\0', sizeof(SimBan));
+ return i;
+}
+
+HostBan *make_hostban()
+{
+ HostBan *i;
+ i = (struct _ahostban *) MyMalloc(sizeof(HostBan));
+ memset((char *) i, '\0', sizeof(HostBan));
+ return i;
+}
+
+aConnect *make_connect()
+{
+ aConnect *i;
+ i = (struct Conf_Connect *) MyMalloc(sizeof(aConnect));
+ memset((char *) i, '\0', sizeof(aConnect));
+ return i;
+}
+
+aAllow *make_allow()
+{
+ aAllow *i;
+ i = (struct Conf_Allow *) MyMalloc(sizeof(aAllow));
+ memset((char *) i, '\0', sizeof(aAllow));
+ return i;
+}
+
+aPort *make_port()
+{
+ aPort *i;
+ i = (struct Conf_Port *) MyMalloc(sizeof(aPort));
+ memset((char *) i, '\0', sizeof(aPort));
+ return i;
+}
+
+Conf_Me *make_me()
+{
+ Conf_Me *i;
+ i = (struct Conf_Me *) MyMalloc(sizeof(Conf_Me));
+ memset((char *) i, '\0', sizeof(Conf_Me));
+ return i;
+}
+
+/* find the appropriate conf and return it */
+
+aConnect *
+find_aConnect(char *name)
+{
+ aConnect *tmp;
+ for(tmp = connects; tmp; tmp = tmp->next)
+ if(!match(name, tmp->name))
+ break;
+ return tmp;
+}
+
+aPort *
+find_port(int port)
+{
+ aPort *tmp;
+ for(tmp = ports; tmp; tmp = tmp->next)
+ if(tmp->port == port)
+ break;
+ return tmp;
+}
+
+aConnect *
+find_aConnect_match(char *name, char *username, char *host)
+{
+ aConnect *aconn;
+ char userhost[USERLEN + HOSTLEN + 3];
+
+ (void) sprintf(userhost, "%s@%s", username, host);
+
+ for(aconn = connects; aconn; aconn = aconn->next)
+ if(!mycmp(name, aconn->name) && !match(userhost, aconn->host))
+ break;
+ return aconn;
+}
+
+char *
+find_aUserver(char *name)
+{
+ int i;
+
+ for (i = 0; uservers[i]; ++i)
+ if (mycmp(name, uservers[i]) == 0)
+ break;
+ return uservers[i];
+}
+
+aOper *
+find_oper(char *name, char *username, char *sockhost, char *hostip)
+{
+ aOper *aoper;
+ char userhost[USERLEN + HOSTLEN + 3];
+ char userip[USERLEN + HOSTLEN + 3];
+ int i;
+
+ /* sockhost OR hostip must match our host field */
+
+
+ (void) sprintf(userhost, "%s@%s", username, sockhost);
+ (void) sprintf(userip, "%s@%s", username, sockhost);
+
+ for(aoper = opers; aoper; aoper = aoper->next)
+ {
+ for (i = 0; aoper->hosts[i]; ++i)
+ {
+ if(!(mycmp(name, aoper->nick) && (match(userhost, aoper->hosts[i]) ||
+ match(userip, aoper->hosts[i]))))
+ break;
+ }
+ if (aoper->hosts[i]) break;
+ }
+ return aoper;
+}
+
+aOper *
+find_oper_byname(char *name)
+{
+ aOper *aoper;
+ for(aoper = opers; aoper; aoper = aoper->next)
+ if(!mycmp(name, aoper->nick))
+ break;
+ return aoper;
+}
+
+aClass *
+find_class(char *name)
+{
+ aClass *tmp;
+ for(tmp = classes; tmp; tmp = tmp->next)
+ if(!mycmp(name, tmp->name))
+ break;
+ return tmp;
+}
+
+
+/* confadd_ functions
+ * add a config item
+ * Feb.15/04 -epi
+ */
+static int oper_access[] =
+{
+ ~(OFLAG_ADMIN|OFLAG_SADMIN|OFLAG_ZLINE|OFLAG_ADMIN), '*',
+ OFLAG_LOCAL, 'o',
+ OFLAG_GLOBAL, 'O',
+ OFLAG_REHASH, 'r',
+ OFLAG_DIE, 'D',
+ OFLAG_RESTART, 'R',
+ OFLAG_GLOBOP, 'h',
+ OFLAG_WALLOP, 'w',
+ OFLAG_LOCOP, 'l',
+ OFLAG_LROUTE, 'c',
+ OFLAG_GROUTE, 'C',
+ OFLAG_LKILL, 'k',
+ OFLAG_GKILL, 'K',
+ OFLAG_KLINE, 'b',
+ OFLAG_UNKLINE, 'B',
+ OFLAG_LNOTICE, 'n',
+ OFLAG_GNOTICE, 'N',
+ OFLAG_ADMIN, 'A',
+ OFLAG_SADMIN, 'a',
+ OFLAG_UMODEc, 'u',
+ OFLAG_UMODEf, 'f',
+ OFLAG_ZLINE, 'z',
+ OFLAG_UMODEF, 'F',
+ 0, 0 };
+
+
+void
+confadd_oper(char *name, char *host, char *passwd, char *flags, char *class)
+{
+ aOper *x;
+ int new, hostidx;
+
+ if (!strchr(host, '@') && *host != '/')
+ {
+ char *newhost;
+ int len = 3;
+ len += strlen(host);
+ newhost = (char *) MyMalloc(len);
+ (void) sprintf(newhost, "*@%s", host);
+ host = newhost;
+ }
+
+
+ if((x = find_oper_byname(name)))
+ {
+ new = 0;
+ for (hostidx = 0; x->hosts[hostidx]; ++hostidx)
+ {
+ if (mycmp(x->hosts[hostidx], host) == 0)
+ break;
+ }
+ if (x->hosts[hostidx] == NULL)
+ {
+ DupString(x->hosts[hostidx], host);
+ x->hosts[hostidx+1] = NULL;
+ }
+ }
+ else
+ {
+ x = make_oper();
+ DupString(x->nick, name);
+ DupString(x->passwd, passwd);
+ DupString(x->hosts[0], host);
+ x->hosts[1] = NULL;
+ new = 1;
+ }
+ x->legal = 1;
+ /* this kludge is just to get the string across.. *shrug* */
+ DupString(x->class_name, flags);
+ if(class)
+ x->class = find_class(class);
+ if(new)
+ {
+ x->next = opers;
+ opers = x;
+ }
+ return;
+}
+
+static int server_info[] =
+{
+ CONN_ZIP, 'Z',
+ CONN_DKEY, 'E',
+ CONN_HUB, 'H',
+ 0, 0
+};
+
+void
+confadd_connect(char *name, char *host, char *apasswd, char *cpasswd,
+ int port, char *flags, char *source, char *class)
+{
+ aConnect *x;
+ int *i, flag, new = 0;
+ char *m = "*";
+
+ if(!(x = find_aConnect(name)))
+ {
+ x = make_connect();
+ DupString(x->name, name);
+ x->port = 0;
+ new = 1;
+ }
+ x->legal = 1;
+ if(host)
+ {
+ MyFree(x->host);
+ DupString(x->host, host);
+ if (!strchr(x->host, '@') && *x->host != '/')
+ {
+ char *newhost;
+ int len = 3;
+ len += strlen(x->host);
+ newhost = (char *) MyMalloc(len);
+ (void) sprintf(newhost, "*@%s", x->host);
+ MyFree(x->host);
+ x->host = newhost;
+ }
+ }
+ if(class)
+ x->class = find_class(class);
+ if(port)
+ x->port = port;
+ if(apasswd)
+ {
+ MyFree(x->apasswd);
+ DupString(x->apasswd, apasswd);
+ }
+ if(cpasswd)
+ {
+ MyFree(x->cpasswd);
+ DupString(x->cpasswd, cpasswd);
+ }
+ if(flags)
+ {
+ x->flags = 0;
+ for (m=(*flags) ? flags : m; *m; m++)
+ {
+ for (i=server_info; (flag = *i); i+=2)
+ if (*m==(char)(*(i+1)))
+ {
+ x->flags |= flag;
+ break;
+ }
+ }
+ }
+ if(source)
+ {
+ int dots;
+ char *n = source;
+ while(*n)
+ {
+ if(*n == '.')
+ dots++;
+ n++;
+ }
+ if(dots == 3) /* make sure we dont add a class, since that
+ * worked in the old method */
+ {
+ MyFree(x->source);
+ DupString(x->source, source);
+ }
+ }
+ if(new)
+ {
+ x->next = connects;
+ connects = x;
+ }
+ return;
+}
+
+void
+confadd_allow(char *ipmask, char *passwd, char *hostmask, int port, char *class)
+{
+ aAllow *x;
+ /* Currently, Allows are the only config types without
+ * easy identifiers - so we dont worry about duplicate types.
+ * this will change once a new config parser is written
+ * -epi
+ */
+
+ x = make_allow();
+ if(ipmask)
+ DupString(x->ipmask, ipmask);
+ if(passwd && passwd != "")
+ DupString(x->passwd, passwd);
+ if(hostmask)
+ DupString(x->hostmask, hostmask);
+ if(port)
+ x->port = port;
+ else
+ x->port = 0;
+ if(class)
+ x->class = find_class(class);
+ if(strchr(x->ipmask, '@'))
+ x->flags |= CONF_FLAGS_I_HOST_HAS_AT;
+ if(strchr(x->hostmask, '@'))
+ x->flags |= CONF_FLAGS_I_NAME_HAS_AT;
+#if (RIDICULOUS_PARANOIA_LEVEL>=1)
+ if(myncmp(x->passwd, "oper", 4) == 0)
+ {
+ if((x->passwd[4] == '.') || (x->passwd[4] == '\0'))
+ {
+ char *tmpd = x->passwd;
+ char *tmp = x->passwd + 4;
+
+ x->flags |= CONF_FLAGS_I_OPERPORT;
+ if(*tmp)
+ tmp++;
+ DupString(x->passwd, tmp);
+ MyFree(tmpd);
+ }
+ }
+#endif
+ /* would help if we added it to our list, eh */
+ x->next = allows;
+ allows = x;
+ return;
+}
+
+void
+confadd_port(int port, char *allow, char *address)
+{
+ aPort *x;
+ int new;
+
+ if(!(port > 0))
+ return;
+
+ if((x = find_port(port)))
+ {
+ MyFree(x->allow);
+ MyFree(x->address);
+ x->legal = 1;
+ new = 0;
+ }
+ else
+ {
+ x = make_port();
+ x->port = port;
+ new = 1;
+ }
+ if(allow)
+ DupString(x->allow, allow);
+ if(address)
+ DupString(x->address, address);
+ if(new)
+ {
+ x->next = ports;
+ ports = x;
+ }
+ return;
+}
+
+void
+confadd_me(char *servername, char *info, char *dpass, char *rpass,
+ char *aline1, char *aline2, char *aline3)
+{
+ if(!MeLine)
+ MeLine = make_me();
+ if(servername)
+ {
+ DupString(MeLine->servername, servername);
+ }
+ if(info)
+ {
+ MyFree(MeLine->info);
+ DupString(MeLine->info, info);
+ }
+ if(aline1)
+ {
+ MyFree(MeLine->admin[0]);
+ DupString(MeLine->admin[0], aline1);
+ }
+ if(aline2)
+ {
+ MyFree(MeLine->admin[1]);
+ DupString(MeLine->admin[1], aline2);
+ }
+ if(aline3)
+ {
+ MyFree(MeLine->admin[2]);
+ DupString(MeLine->admin[2], aline3);
+ }
+ if(dpass)
+ {
+ MyFree(MeLine->diepass);
+ DupString(MeLine->diepass, dpass);
+ }
+ if(rpass)
+ {
+ MyFree(MeLine->restartpass);
+ DupString(MeLine->restartpass, rpass);
+ }
+ return;
+}
+
+void
+confadd_class(char *name, int ping, int connfreq, int maxlinks, long sendq)
+{
+ aClass *x;
+ int new = 0;
+
+ if(!(x = find_class(name)))
+ {
+ x = make_class();
+ DupString(x->name, name);
+ new = 1;
+ }
+ x->pingfreq = ping;
+ x->connfreq = connfreq;
+ x->maxlinks = maxlinks;
+ x->maxsendq = (sendq > 0) ? sendq : MAXSENDQLENGTH;
+ if(new)
+ {
+ x->next = classes;
+ classes = x;
+ }
+ return;
+}
+
+void
+confadd_simban(int flags, char *mask, char *reason)
+{
+ SimBan *x;
+ x = make_simban();
+ x->type = flags;
+ DupString(x->target, mask);
+ if(reason)
+ DupString(x->reason, reason);
+ x->next = sbans;
+ sbans = x;
+ return;
+}
+
+void
+confadd_hostban(char *username, char *mask, char *reason)
+{
+ HostBan *x;
+ x = make_hostban();
+ if(username)
+ DupString(x->username, username);
+ if(mask)
+ DupString(x->target, mask);
+ if(reason)
+ DupString(x->reason, reason);
+ x->next = hbans;
+ hbans = x;
+ return;
+}
+
+void
+confadd_uline(char *host)
+{
+ int i;
+
+ if (find_aUserver(host) != NULL)
+ return;
+
+ for (i = 0; uservers[i]; ++i);
+
+ DupString(uservers[i], host);
+ uservers[i+1] = NULL;
+}
+
+
+
+/*
+ * openconf
+ *
+ * returns -1 on any error or else the fd opened from which to read the
+ * configuration file from. This may either be the file direct or one
+ * end of a pipe from m4.
+ */
+int openconf(char *filename)
+{
+ return open(filename, O_RDONLY);
+}
+
+/*
+ * initconf()
+ * Read configuration file.
+ *
+ * - file descriptor pointing to config file to use returns -1,
+ * if file cannot be opened, 0 if file opened
+ * almost completely rewritten when killing aConfItem, feb04 -epi
+ */
+
+#define MAXCONFLINKS 150
+
+int
+initconf(int opt, int fd, aClient *rehasher)
+{
+ static char quotes[9][2] =
+ {
+ {'b', '\b'},
+ {'f', '\f'},
+ {'n', '\n'},
+ {'r', '\r'},
+ {'t', '\t'},
+ {'v', '\v'},
+ {'\\', '\\'},
+ {0, 0}
+ };
+
+ char *tmp, *s;
+ int i;
+ char line[512], c[80];
+
+ /* temp variables just til we complete the rest of the
+ * switch to separate conf structures. if this is still
+ * here in 2006, find me and beat me up. -epi
+ * there shouldnt be more than 5 fields per line
+ */
+
+ int t_status;
+ char *t_host;
+ char *t_passwd;
+ char *t_name;
+ char *t_flags;
+ char *t_class;
+
+
+ (void) dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+
+ while ((i = dgets(fd, line, sizeof(line) - 1)) > 0)
+ {
+ line[i] = '\0';
+ if ((tmp = (char *) strchr(line, '\n')))
+ *tmp = '\0';
+ else
+ while (dgets(fd, c, sizeof(c) - 1) > 0)
+ if ((tmp = (char *) strchr(c, '\n')))
+ {
+ *tmp = '\0';
+ break;
+ }
+
+ /* Do quoting of characters detection. */
+
+ for (tmp = line; *tmp; tmp++)
+ {
+ if (*tmp == '\\')
+ {
+ for (i = 0; quotes[i][0]; i++)
+ if (quotes[i][0] == *(tmp + 1))
+ {
+ *tmp = quotes[i][1];
+ break;
+ }
+ if (!quotes[i][0])
+ *tmp = *(tmp + 1);
+ if (!*(tmp + 1))
+ break;
+ else
+ for (s = tmp; (*s = *(s + 1)); s++);
+ }
+ }
+
+ if (!*line || line[0] == '#' || line[0] == '\n' ||
+ line[0] == ' ' || line[0] == '\t')
+ continue;
+
+ /* Could we test if it's conf line at all? -Vesa */
+
+ if (line[1] != ':')
+ {
+ printf("\nBad config line: \"%s\" - Ignored\n", line);
+ continue;
+ }
+
+ tmp = getfield(line);
+ if (!tmp)
+ continue;
+ switch (*tmp)
+ {
+ case 'A':
+ case 'a': /* Administrative info */
+ t_status = CONF_ADMIN;
+ break;
+
+ case 'C': /* Server I should try to connect */
+ case 'c':
+ t_status = CONF_CONNECT_SERVER;
+ break;
+
+ case 'G': /* restricted gcos */
+ case 'g':
+ t_status = CONF_GCOS;
+ break;
+
+ case 'H': /* Hub server line */
+ case 'h':
+ t_status = CONF_HUB;
+ break;
+
+ case 'i': /* to connect me */
+ case 'I':
+ t_status = CONF_CLIENT;
+ break;
+ case 'K': /* the infamous klines */
+ case 'k':
+ t_status = CONF_KILL;
+ break;
+
+ /*
+ * Me. Host field is name used for this host
+ * and port number is the number of the port
+ */
+ case 'M':
+ case 'm':
+ t_status = CONF_ME;
+ break;
+
+ case 'N':
+ case 'n':
+
+ /* Server where I should NOT try to
+ * connect in case of lp failures
+ * but which tries to connect ME
+ */
+ t_status = CONF_NOCONNECT_SERVER;
+ break;
+
+ case 'O': /* Operator line */
+ case 'o':
+ t_status = CONF_OPERATOR;
+ break;
+
+ case 'P': /* listen port line */
+ case 'p':
+ t_status = CONF_LISTEN_PORT;
+ break;
+
+ case 'Q': /* restricted nicknames */
+ case 'q':
+ t_status = CONF_QUARANTINE;
+ break;
+
+ case 'T':
+ case 't':
+ t_status = CONF_MONINFO;
+ break;
+
+ case 'U': /* Ultimate Servers (aka God) */
+ case 'u':
+ t_status = CONF_ULINE;
+ break;
+
+ case 'X': /* die/restart pass line */
+ case 'x':
+ t_status = CONF_DRPASS;
+ break;
+
+ case 'Y': /* Class line */
+ case 'y':
+ t_status = CONF_CLASS;
+ break;
+
+ default:
+ t_status = CONF_ILLEGAL;
+ printf("// Bad config line: \"%s\" - Ignored\n", line);
+ break;
+ }
+
+ if(t_status & CONF_ILLEGAL) /* skip this line */
+ continue;
+
+ t_host = getfield(NULL);
+ t_passwd = getfield(NULL);
+ t_name = getfield(NULL);
+ t_flags = getfield(NULL);
+ t_class = getfield(NULL);
+
+ /* from this point, every configuration line
+ * is taken care of within its own if statement.
+ * Everything should be contained. -epi
+ */
+
+ if(t_status & CONF_MONINFO)
+ {
+ if(t_host && t_host[0] != '\0')
+ strncpyzt(ProxyMonHost, t_host, sizeof(ProxyMonHost));
+ strcpy(ProxyMonURL, "http://");
+ if(t_passwd && t_passwd[0] != '\0')
+ strncpyzt(ProxyMonURL, t_passwd, sizeof(ProxyMonURL));
+ do_tline = 1;
+ continue;
+ }
+ if(t_status & CONF_ADMIN)
+ {
+ confadd_me(0,0,0,0, t_host, t_passwd, t_name);
+ continue;
+ }
+ if (t_status & CONF_OPS)
+ {
+ confadd_oper(t_name, t_host, t_passwd, t_flags, t_class);
+ continue;
+ }
+ if(t_status & CONF_NOCONNECT_SERVER)
+ {
+ confadd_connect(t_name, t_host, t_passwd, 0, 0, t_flags, 0,
+ t_class);
+ continue;
+ }
+ if (t_status & CONF_CONNECT_SERVER)
+ {
+ confadd_connect(t_name, t_host, 0, t_passwd, atoi(t_flags), 0,
+ t_class, 0);
+ continue;
+ }
+ if(t_status & CONF_HUB)
+ {
+ aConnect *x = find_aConnect(t_name);
+ if(!x)
+ confadd_connect(t_name, 0, 0, 0, 0, t_flags, 0, 0);
+ else
+ x->flags |= CONN_HUB;
+ continue;
+ }
+ if (t_status & CONF_CLASS)
+ {
+ confadd_class(t_host, atoi(t_passwd), atoi(t_name),
+ atoi(t_flags), atoi(t_class));
+ continue;
+ }
+
+ if (t_status & CONF_CLIENT)
+ {
+ confadd_allow(t_host, t_passwd, t_name, atoi(t_flags), t_class);
+ continue;
+ }
+ if(t_status & CONF_LISTEN_PORT)
+ {
+ confadd_port(atoi(t_flags), t_host, t_passwd);
+ continue;
+ }
+
+ /*
+ * Own port and name cannot be changed after the startup. (or
+ * could be allowed, but only if all links are closed first).
+ * Configuration info does not override the name and port if
+ * previously defined. Note, that "info"-field can be changed
+ * by "/rehash". Can't change vhost mode/address either
+ */
+ if (t_status == CONF_ME)
+ {
+ confadd_me(t_host, t_name, 0, 0, 0, 0, 0);
+ confadd_port(atoi(t_flags), NULL, t_passwd);
+ continue;
+ }
+
+#ifdef WINGATE_NOTICE
+ if (t_status == CONF_MONINFO)
+ {
+ if(!t_host || t_host[0] == '\0')
+ strncpyzt(ProxyMonHost, MONITOR_HOST, sizeof(ProxyMonHost));
+ else
+ strncpyzt(ProxyMonHost, t_host, sizeof(ProxyMonHost));
+
+ strcpy(ProxyMonURL, "http://");
+
+ if(!t_passwd || t_passwd[0] == '\0')
+ strncpyzt((ProxyMonURL + 7), DEFAULT_PROXY_INFO_URL,
+ sizeof(ProxyMonURL) - 7);
+ else
+ strncpyzt((ProxyMonURL + 7), t_passwd, sizeof(ProxyMonURL) - 7);
+ continue;
+ }
+#endif
+
+ if (t_status & CONF_QUARANTINE)
+ {
+ int flags;
+ char *sb_m, *sb_r;
+
+ if(BadPtr(t_name))
+ continue;
+
+ if(t_name[0] == '#')
+ {
+ flags |= SBAN_CHAN;
+ sb_r = BadPtr(t_passwd) ? "Reserved Channel" : t_passwd;
+ }
+ else
+ {
+ flags |= SBAN_NICK;
+ sb_r = BadPtr(t_passwd) ? "Reserved Nickname" : t_passwd;
+ }
+
+ sb_m = t_name;
+
+ confadd_simban(flags, sb_m, sb_r);
+
+ continue;
+ }
+
+ if (t_status & CONF_GCOS)
+ {
+ unsigned int flags;
+ char *sb_m, *sb_r;
+
+ if(BadPtr(t_name))
+ continue;
+
+ flags = SBAN_LOCAL|SBAN_GCOS;
+ sb_r = BadPtr(t_passwd) ? "Bad GCOS" : t_passwd;
+
+ sb_m = t_name;
+
+ confadd_simban(flags, sb_m, sb_r);
+ continue;
+ }
+
+ if (t_status & CONF_KILL)
+ {
+ char *ub_u, *ub_r;
+
+ if(BadPtr(t_host))
+ continue;
+
+ ub_u = BadPtr(t_name) ? "*" : t_name;
+ ub_r = BadPtr(t_passwd) ? "<No Reason>" : t_passwd;
+
+ confadd_hostban(ub_u, t_host, ub_r);
+
+ continue;
+ }
+ if (t_status & CONF_ULINE)
+ {
+ confadd_uline(t_host);
+ continue;
+ }
+ if(t_status & CONF_DRPASS)
+ {
+ confadd_me(0,0, t_host, t_passwd, 0, 0, 0);
+ continue;
+ }
+ /* oh shit! */
+ printf("Error parsing config file!\n");
+ printf("line: %s", line);
+ exit(-1);
+ }
+ (void) dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+ (void) close(fd);
+ return 0;
+}
+
+void
+printconf()
+{
+ /* print off the new config file */
+ aClass *class;
+ aAllow *allow;
+ aOper *aoper;
+ aConnect *aconn;
+ aPort *aport;
+ SimBan *sban;
+ HostBan *hban;
+
+ printf("/* Generated by Bahamut's convert_conf */ \n");
+ printf("\nglobal {\n");
+ printf(" name \"%s\";\n", MeLine->servername);
+ printf(" info \"%s\";\n", MeLine->info);
+ printf(" admin {\n");
+ if(MeLine->admin[0] && strcmp(MeLine->admin[0], ""))
+ printf(" \"%s\";\n", MeLine->admin[0]);
+ if(MeLine->admin[1] && strcmp(MeLine->admin[1], ""))
+ printf(" \"%s\";\n", MeLine->admin[1]);
+ if(MeLine->admin[2] && strcmp(MeLine->admin[2], ""))
+ printf(" \"%s\";\n", MeLine->admin[2]);
+ printf(" };\n");
+ if(MeLine->diepass && MeLine->diepass != "")
+ printf(" dpass \"%s\";\n", MeLine->diepass);
+ if(MeLine->restartpass && MeLine->restartpass != "")
+ printf(" rpass \"%s\";\n", MeLine->restartpass);
+ printf("};\n\n");
+ printf("/* Option Definitions */\n\n");
+ printf("options {\n");
+ printf(" servtype client; // MAKE SURE THIS IS CORRECT\n");
+ printf(" network_kline \"kline@dal.net\";\n");
+ printf(" local_kline \"poorly@configure.server\";\n");
+ if(do_tline)
+ {
+ printf(" wgmonhost \"%s\";\n", ProxyMonHost);
+ printf(" wgmonurl \"%s\";\n", ProxyMonURL);
+ }
+ printf("/********* other options worth reviewing *********/\n");
+ printf("# maxchannels 10;\n");
+ printf("# short_motd;\n");
+ printf("# crypt_oper_pass;\n");
+ printf("# staff_address staff.dalnet;\n");
+ printf("};\n\n");
+ printf("/* Class Definitions */\n\n");
+ for(class = classes; class; class = class->next)
+ {
+ printf("class {\n");
+ printf(" name %s;\n", class->name);
+ printf(" pingfreq %d;\n", class->pingfreq);
+ printf(" maxusers %d;\n", class->maxlinks);
+ if(class->connfreq > 0)
+ printf(" connfreq %d;\n", class->connfreq);
+ printf(" maxsendq %d;\n", class->maxsendq);
+ printf("};\n\n");
+ }
+ printf("/* Allow definitions */\n\n");
+ for(allow = allows; allow; allow = allow->next)
+ {
+ printf("allow {\n");
+ printf(" ipmask \"%s\";\n", allow->ipmask);
+ printf(" host \"%s\";\n", allow->hostmask);
+ if(allow->passwd && strcmp(allow->passwd, ""))
+ printf(" passwd \"%s\";\n", allow->passwd);
+ if(allow->port != 0)
+ printf(" port %d;\n", allow->port);
+ if(allow->class)
+ printf(" class \"%s\";\n", allow->class->name);
+ else
+ printf(" /** YOU SHOULD HAVE A CLASS HERE **/\n");
+ printf("};\n\n");
+ }
+ printf("/* Oper definitions */\n\n");
+ for(aoper = opers; aoper; aoper = aoper->next)
+ {
+ int i;
+ printf("oper {\n");
+ printf(" name \"%s\";\n", aoper->nick);
+ for (i = 0; aoper->hosts[i]; ++i)
+ printf(" host \"%s\";\n", aoper->hosts[i]);
+ printf(" passwd \"%s\";\n", aoper->passwd);
+ printf(" access %s;\n", aoper->class_name); /* kludge! */
+ if(aoper->class)
+ printf(" class \"%s\";\n", aoper->class->name);
+ else
+ printf(" /** YOU SHOULD HAVE A CLASS HERE **/\n");
+ printf("};\n\n");
+ }
+ printf("/* Connection Definitions */\n\n");
+ for(aconn = connects; aconn; aconn = aconn->next)
+ {
+ if(!aconn->host || aconn->host == "")
+ continue;
+ printf("connect {\n", aconn->name);
+ printf(" name \"%s\";\n", aconn->name);
+ printf(" host \"%s\";\n", aconn->host);
+ printf(" apasswd \"%s\";\n", aconn->apasswd);
+ printf(" cpasswd \"%s\";\n", aconn->cpasswd);
+ if(aconn->port > 0)
+ printf(" port %d;\n", aconn->port);
+ if(aconn->source && aconn->source != "")
+ printf(" bind \"%s\";\n", aconn->source);
+ if(aconn->flags != 0)
+ printf(" flags ");
+ if(aconn->flags & CONN_ZIP)
+ printf("Z");
+ if(aconn->flags & CONN_DKEY)
+ printf("E");
+ if(aconn->flags & CONN_HUB)
+ printf("H");
+ if(aconn->flags != 0)
+ printf(";\n");
+ if(aconn->class)
+ printf(" class \"%s\";\n", aconn->class->name);
+ else
+ printf(" /** YOU SHOULD HAVE A CLASS HERE **/\n");
+ printf("};\n\n");
+ }
+ if (uservers[0])
+ {
+ int i;
+ printf("/* Superservers */\n\n");
+ printf("super {\n");
+ for (i = 0; uservers[i]; ++i)
+ {
+ if (i != 0) printf(";\n");
+ printf(" %s", uservers[i]);
+ }
+ printf(";\n};\n\n");
+ }
+ printf("/* port configurations */\n\n");
+ for(aport = ports; aport; aport = aport->next)
+ {
+ printf("port {\n");
+ printf(" port %d;\n", aport->port);
+ if(aport->allow && strcmp(aport->allow, "") && aport->allow != "*")
+ printf(" ipmask \"%s\";\n", aport->allow);
+ if(aport->address && strcmp(aport->address, "") && aport->address != "*")
+ printf(" bind \"%s\";\n", aport->address);
+ printf("};\n\n");
+ }
+ if(sbans)
+ printf("/* Quarantines */\n\n");
+ for(sban = sbans; sban; sban = sban->next)
+ {
+ printf("restrict {\n");
+ printf(" type ");
+ if(sban->type & SBAN_NICK)
+ printf("NICK;\n");
+ else if(sban->type & SBAN_GCOS)
+ printf("GCOS;\n");
+ else if(sban->type & SBAN_CHAN)
+ printf("CHAN;\n");
+ else
+ {
+ printf("\n\n\nPROPLEM READING QLINE TYPE \n\n");
+ exit(-1);
+ }
+ printf(" mask \"%s\";\n", sban->target);
+ printf(" reason \"%s\";\n", sban->reason);
+ printf("};\n\n");
+ }
+ if(hbans)
+ printf("/* kill definitions */\n\n");
+ for(hban = hbans; hban; hban = hban->next)
+ {
+ printf("kill {\n");
+ printf(" mask \"%s@%s\";\n", hban->username ? hban->username : "*",
+ hban->target);
+ printf(" reason \"%s\";\n", hban->reason);
+ printf("};\n\n");
+ }
+ return;
+}
+
+int main(int argc, char *argv[])
+{
+ char *file;
+ int fd;
+
+ if(argc != 2)
+ {
+ printf("Useage: ./convert_conf ircd.conf > ircd.conf.new\n");
+ exit(0);
+ }
+ file = argv[1];
+
+ if((fd = openconf(file)) == -1)
+ {
+ printf("Cannot locate file %s\n", file);
+ exit(-1);
+ }
+ (void) initconf(0, fd, 0);
+
+ /* so far so good */
+
+ printconf();
+
+ exit(1);
+}
--- /dev/null
+/* simple password generator by Nelson Minar (minar@reed.edu)
+ * copyright 1991, all rights reserved.
+ * You can use this code as long as my name stays with it.
+ */
+
+#include "sys.h"
+#include <time.h>
+
+#ifndef lint
+/* static char *rcs_version = "$Id: mkpasswd.c,v 1.1 2005/01/12 07:44:59 mmondor Exp $"; */
+#endif
+
+extern char *getpass();
+extern char *crypt();
+/* extern long random(); */
+/* extern int srandom(unsigned); */
+
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+ static char saltChars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
+ char salt[3];
+ char * plaintext;
+
+ if (argc < 2) {
+ srandom(time(0)); /* may not be the BEST salt, but its close */
+ salt[0] = saltChars[random() % 64];
+ salt[1] = saltChars[random() % 64];
+ salt[2] = 0;
+ }
+ else {
+ salt[0] = argv[1][0];
+ salt[1] = argv[1][1];
+ salt[2] = '\0';
+ if ((strchr(saltChars, salt[0]) == NULL) || (strchr(saltChars, salt[1]) == NULL))
+ fprintf(stderr, "illegal salt %s\n", salt), exit(1);
+ }
+
+ plaintext = getpass("plaintext: ");
+
+ printf("%s\n", crypt(plaintext, salt));
+ return 0;
+}
+
--- /dev/null
+
+ ChangeLog file for zlib
+
+Changes in 1.2.1 (17 November 2003)
+- Remove a tab in contrib/gzappend/gzappend.c
+- Update some interfaces in contrib for new zlib functions
+- Update zlib version number in some contrib entries
+- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta]
+- Support shared libraries on Hurd and KFreeBSD [Brown]
+- Fix error in NO_DIVIDE option of adler32.c
+
+Changes in 1.2.0.8 (4 November 2003)
+- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas
+- Add experimental NO_DIVIDE #define in adler32.c
+ - Possibly faster on some processors (let me know if it is)
+- Correct Z_BLOCK to not return on first inflate call if no wrap
+- Fix strm->data_type on inflate() return to correctly indicate EOB
+- Add deflatePrime() function for appending in the middle of a byte
+- Add contrib/gzappend for an example of appending to a stream
+- Update win32/DLL_FAQ.txt [Truta]
+- Delete Turbo C comment in README [Truta]
+- Improve some indentation in zconf.h [Truta]
+- Fix infinite loop on bad input in configure script [Church]
+- Fix gzeof() for concatenated gzip files [Johnson]
+- Add example to contrib/visual-basic.txt [Michael B.]
+- Add -p to mkdir's in Makefile.in [vda]
+- Fix configure to properly detect presence or lack of printf functions
+- Add AS400 support [Monnerat]
+- Add a little Cygwin support [Wilson]
+
+Changes in 1.2.0.7 (21 September 2003)
+- Correct some debug formats in contrib/infback9
+- Cast a type in a debug statement in trees.c
+- Change search and replace delimiter in configure from % to # [Beebe]
+- Update contrib/untgz to 0.2 with various fixes [Truta]
+- Add build support for Amiga [Nikl]
+- Remove some directories in old that have been updated to 1.2
+- Add dylib building for Mac OS X in configure and Makefile.in
+- Remove old distribution stuff from Makefile
+- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X
+- Update links in README
+
+Changes in 1.2.0.6 (13 September 2003)
+- Minor FAQ updates
+- Update contrib/minizip to 1.00 [Vollant]
+- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta]
+- Update POSTINC comment for 68060 [Nikl]
+- Add contrib/infback9 with deflate64 decoding (unsupported)
+- For MVS define NO_vsnprintf and undefine FAR [van Burik]
+- Add pragma for fdopen on MVS [van Burik]
+
+Changes in 1.2.0.5 (8 September 2003)
+- Add OF to inflateBackEnd() declaration in zlib.h
+- Remember start when using gzdopen in the middle of a file
+- Use internal off_t counters in gz* functions to properly handle seeks
+- Perform more rigorous check for distance-too-far in inffast.c
+- Add Z_BLOCK flush option to return from inflate at block boundary
+- Set strm->data_type on return from inflate
+ - Indicate bits unused, if at block boundary, and if in last block
+- Replace size_t with ptrdiff_t in crc32.c, and check for correct size
+- Add condition so old NO_DEFLATE define still works for compatibility
+- FAQ update regarding the Windows DLL [Truta]
+- INDEX update: add qnx entry, remove aix entry [Truta]
+- Install zlib.3 into mandir [Wilson]
+- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta]
+- Adapt the zlib interface to the new DLL convention guidelines [Truta]
+- Introduce ZLIB_WINAPI macro to allow the export of functions using
+ the WINAPI calling convention, for Visual Basic [Vollant, Truta]
+- Update msdos and win32 scripts and makefiles [Truta]
+- Export symbols by name, not by ordinal, in win32/zlib.def [Truta]
+- Add contrib/ada [Anisimkov]
+- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta]
+- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant]
+- Add contrib/masm686 [Truta]
+- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm
+ [Truta, Vollant]
+- Update contrib/delphi; rename to contrib/pascal; add example [Truta]
+- Remove contrib/delphi2; add a new contrib/delphi [Truta]
+- Avoid inclusion of the nonstandard <memory.h> in contrib/iostream,
+ and fix some method prototypes [Truta]
+- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip
+ [Truta]
+- Avoid the use of backslash (\) in contrib/minizip [Vollant]
+- Fix file time handling in contrib/untgz; update makefiles [Truta]
+- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines
+ [Vollant]
+- Remove contrib/vstudio/vc15_16 [Vollant]
+- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta]
+- Update README.contrib [Truta]
+- Invert the assignment order of match_head and s->prev[...] in
+ INSERT_STRING [Truta]
+- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings
+ [Truta]
+- Compare function pointers with 0, not with NULL or Z_NULL [Truta]
+- Fix prototype of syncsearch in inflate.c [Truta]
+- Introduce ASMINF macro to be enabled when using an ASM implementation
+ of inflate_fast [Truta]
+- Change NO_DEFLATE to NO_GZCOMPRESS [Truta]
+- Modify test_gzio in example.c to take a single file name as a
+ parameter [Truta]
+- Exit the example.c program if gzopen fails [Truta]
+- Add type casts around strlen in example.c [Truta]
+- Remove casting to sizeof in minigzip.c; give a proper type
+ to the variable compared with SUFFIX_LEN [Truta]
+- Update definitions of STDC and STDC99 in zconf.h [Truta]
+- Synchronize zconf.h with the new Windows DLL interface [Truta]
+- Use SYS16BIT instead of __32BIT__ to distinguish between
+ 16- and 32-bit platforms [Truta]
+- Use far memory allocators in small 16-bit memory models for
+ Turbo C [Truta]
+- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in
+ zlibCompileFlags [Truta]
+- Cygwin has vsnprintf [Wilson]
+- In Windows16, OS_CODE is 0, as in MSDOS [Truta]
+- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson]
+
+Changes in 1.2.0.4 (10 August 2003)
+- Minor FAQ updates
+- Be more strict when checking inflateInit2's windowBits parameter
+- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well
+- Add gzip wrapper option to deflateInit2 using windowBits
+- Add updated QNX rule in configure and qnx directory [Bonnefoy]
+- Make inflate distance-too-far checks more rigorous
+- Clean up FAR usage in inflate
+- Add casting to sizeof() in gzio.c and minigzip.c
+
+Changes in 1.2.0.3 (19 July 2003)
+- Fix silly error in gzungetc() implementation [Vollant]
+- Update contrib/minizip and contrib/vstudio [Vollant]
+- Fix printf format in example.c
+- Correct cdecl support in zconf.in.h [Anisimkov]
+- Minor FAQ updates
+
+Changes in 1.2.0.2 (13 July 2003)
+- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons
+- Attempt to avoid warnings in crc32.c for pointer-int conversion
+- Add AIX to configure, remove aix directory [Bakker]
+- Add some casts to minigzip.c
+- Improve checking after insecure sprintf() or vsprintf() calls
+- Remove #elif's from crc32.c
+- Change leave label to inf_leave in inflate.c and infback.c to avoid
+ library conflicts
+- Remove inflate gzip decoding by default--only enable gzip decoding by
+ special request for stricter backward compatibility
+- Add zlibCompileFlags() function to return compilation information
+- More typecasting in deflate.c to avoid warnings
+- Remove leading underscore from _Capital #defines [Truta]
+- Fix configure to link shared library when testing
+- Add some Windows CE target adjustments [Mai]
+- Remove #define ZLIB_DLL in zconf.h [Vollant]
+- Add zlib.3 [Rodgers]
+- Update RFC URL in deflate.c and algorithm.txt [Mai]
+- Add zlib_dll_FAQ.txt to contrib [Truta]
+- Add UL to some constants [Truta]
+- Update minizip and vstudio [Vollant]
+- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h
+- Expand use of NO_DUMMY_DECL to avoid all dummy structures
+- Added iostream3 to contrib [Schwardt]
+- Replace rewind() with fseek() for WinCE [Truta]
+- Improve setting of zlib format compression level flags
+ - Report 0 for huffman and rle strategies and for level == 0 or 1
+ - Report 2 only for level == 6
+- Only deal with 64K limit when necessary at compile time [Truta]
+- Allow TOO_FAR check to be turned off at compile time [Truta]
+- Add gzclearerr() function [Souza]
+- Add gzungetc() function
+
+Changes in 1.2.0.1 (17 March 2003)
+- Add Z_RLE strategy for run-length encoding [Truta]
+ - When Z_RLE requested, restrict matches to distance one
+ - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE
+- Correct FASTEST compilation to allow level == 0
+- Clean up what gets compiled for FASTEST
+- Incorporate changes to zconf.in.h [Vollant]
+ - Refine detection of Turbo C need for dummy returns
+ - Refine ZLIB_DLL compilation
+ - Include additional header file on VMS for off_t typedef
+- Try to use _vsnprintf where it supplants vsprintf [Vollant]
+- Add some casts in inffast.c
+- Enchance comments in zlib.h on what happens if gzprintf() tries to
+ write more than 4095 bytes before compression
+- Remove unused state from inflateBackEnd()
+- Remove exit(0) from minigzip.c, example.c
+- Get rid of all those darn tabs
+- Add "check" target to Makefile.in that does the same thing as "test"
+- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in
+- Update contrib/inflate86 [Anderson]
+- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant]
+- Add msdos and win32 directories with makefiles [Truta]
+- More additions and improvements to the FAQ
+
+Changes in 1.2.0 (9 March 2003)
+- New and improved inflate code
+ - About 20% faster
+ - Does not allocate 32K window unless and until needed
+ - Automatically detects and decompresses gzip streams
+ - Raw inflate no longer needs an extra dummy byte at end
+ - Added inflateBack functions using a callback interface--even faster
+ than inflate, useful for file utilities (gzip, zip)
+ - Added inflateCopy() function to record state for random access on
+ externally generated deflate streams (e.g. in gzip files)
+ - More readable code (I hope)
+- New and improved crc32()
+ - About 50% faster, thanks to suggestions from Rodney Brown
+- Add deflateBound() and compressBound() functions
+- Fix memory leak in deflateInit2()
+- Permit setting dictionary for raw deflate (for parallel deflate)
+- Fix const declaration for gzwrite()
+- Check for some malloc() failures in gzio.c
+- Fix bug in gzopen() on single-byte file 0x1f
+- Fix bug in gzread() on concatenated file with 0x1f at end of buffer
+ and next buffer doesn't start with 0x8b
+- Fix uncompress() to return Z_DATA_ERROR on truncated input
+- Free memory at end of example.c
+- Remove MAX #define in trees.c (conflicted with some libraries)
+- Fix static const's in deflate.c, gzio.c, and zutil.[ch]
+- Declare malloc() and free() in gzio.c if STDC not defined
+- Use malloc() instead of calloc() in zutil.c if int big enough
+- Define STDC for AIX
+- Add aix/ with approach for compiling shared library on AIX
+- Add HP-UX support for shared libraries in configure
+- Add OpenUNIX support for shared libraries in configure
+- Use $cc instead of gcc to build shared library
+- Make prefix directory if needed when installing
+- Correct Macintosh avoidance of typedef Byte in zconf.h
+- Correct Turbo C memory allocation when under Linux
+- Use libz.a instead of -lz in Makefile (assure use of compiled library)
+- Update configure to check for snprintf or vsnprintf functions and their
+ return value, warn during make if using an insecure function
+- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that
+ is lost when library is used--resolution is to build new zconf.h
+- Documentation improvements (in zlib.h):
+ - Document raw deflate and inflate
+ - Update RFCs URL
+ - Point out that zlib and gzip formats are different
+ - Note that Z_BUF_ERROR is not fatal
+ - Document string limit for gzprintf() and possible buffer overflow
+ - Note requirement on avail_out when flushing
+ - Note permitted values of flush parameter of inflate()
+- Add some FAQs (and even answers) to the FAQ
+- Add contrib/inflate86/ for x86 faster inflate
+- Add contrib/blast/ for PKWare Data Compression Library decompression
+- Add contrib/puff/ simple inflate for deflate format description
+
+Changes in 1.1.4 (11 March 2002)
+- ZFREE was repeated on same allocation on some error conditions.
+ This creates a security problem described in
+ http://www.zlib.org/advisory-2002-03-11.txt
+- Returned incorrect error (Z_MEM_ERROR) on some invalid data
+- Avoid accesses before window for invalid distances with inflate window
+ less than 32K.
+- force windowBits > 8 to avoid a bug in the encoder for a window size
+ of 256 bytes. (A complete fix will be available in 1.1.5).
+
+Changes in 1.1.3 (9 July 1998)
+- fix "an inflate input buffer bug that shows up on rare but persistent
+ occasions" (Mark)
+- fix gzread and gztell for concatenated .gz files (Didier Le Botlan)
+- fix gzseek(..., SEEK_SET) in write mode
+- fix crc check after a gzeek (Frank Faubert)
+- fix miniunzip when the last entry in a zip file is itself a zip file
+ (J Lillge)
+- add contrib/asm586 and contrib/asm686 (Brian Raiter)
+ See http://www.muppetlabs.com/~breadbox/software/assembly.html
+- add support for Delphi 3 in contrib/delphi (Bob Dellaca)
+- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti)
+- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren)
+- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks)
+- added a FAQ file
+
+- Support gzdopen on Mac with Metrowerks (Jason Linhart)
+- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart)
+- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young)
+- avoid some warnings with Borland C (Tom Tanner)
+- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant)
+- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant)
+- allow several arguments to configure (Tim Mooney, Frodo Looijaard)
+- use libdir and includedir in Makefile.in (Tim Mooney)
+- support shared libraries on OSF1 V4 (Tim Mooney)
+- remove so_locations in "make clean" (Tim Mooney)
+- fix maketree.c compilation error (Glenn, Mark)
+- Python interface to zlib now in Python 1.5 (Jeremy Hylton)
+- new Makefile.riscos (Rich Walker)
+- initialize static descriptors in trees.c for embedded targets (Nick Smith)
+- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith)
+- add the OS/2 files in Makefile.in too (Andrew Zabolotny)
+- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane)
+- fix maketree.c to allow clean compilation of inffixed.h (Mark)
+- fix parameter check in deflateCopy (Gunther Nikl)
+- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler)
+- Many portability patches by Christian Spieler:
+ . zutil.c, zutil.h: added "const" for zmem*
+ . Make_vms.com: fixed some typos
+ . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists
+ . msdos/Makefile.msc: remove "default rtl link library" info from obj files
+ . msdos/Makefile.*: use model-dependent name for the built zlib library
+ . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc:
+ new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT)
+- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane)
+- replace __far with _far for better portability (Christian Spieler, Tom Lane)
+- fix test for errno.h in configure (Tim Newsham)
+
+Changes in 1.1.2 (19 March 98)
+- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant)
+ See http://www.winimage.com/zLibDll/unzip.html
+- preinitialize the inflate tables for fixed codes, to make the code
+ completely thread safe (Mark)
+- some simplifications and slight speed-up to the inflate code (Mark)
+- fix gzeof on non-compressed files (Allan Schrum)
+- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs)
+- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn)
+- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny)
+- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori)
+- do not wrap extern "C" around system includes (Tom Lane)
+- mention zlib binding for TCL in README (Andreas Kupries)
+- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert)
+- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson)
+- allow "configure --prefix $HOME" (Tim Mooney)
+- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson)
+- move Makefile.sas to amiga/Makefile.sas
+
+Changes in 1.1.1 (27 Feb 98)
+- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson)
+- remove block truncation heuristic which had very marginal effect for zlib
+ (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the
+ compression ratio on some files. This also allows inlining _tr_tally for
+ matches in deflate_slow.
+- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier)
+
+Changes in 1.1.0 (24 Feb 98)
+- do not return STREAM_END prematurely in inflate (John Bowler)
+- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler)
+- compile with -DFASTEST to get compression code optimized for speed only
+- in minigzip, try mmap'ing the input file first (Miguel Albrecht)
+- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain
+ on Sun but significant on HP)
+
+- add a pointer to experimental unzip library in README (Gilles Vollant)
+- initialize variable gcc in configure (Chris Herborth)
+
+Changes in 1.0.9 (17 Feb 1998)
+- added gzputs and gzgets functions
+- do not clear eof flag in gzseek (Mark Diekhans)
+- fix gzseek for files in transparent mode (Mark Diekhans)
+- do not assume that vsprintf returns the number of bytes written (Jens Krinke)
+- replace EXPORT with ZEXPORT to avoid conflict with other programs
+- added compress2 in zconf.h, zlib.def, zlib.dnt
+- new asm code from Gilles Vollant in contrib/asm386
+- simplify the inflate code (Mark):
+ . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new()
+ . ZALLOC the length list in inflate_trees_fixed() instead of using stack
+ . ZALLOC the value area for huft_build() instead of using stack
+ . Simplify Z_FINISH check in inflate()
+
+- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8
+- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi)
+- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with
+ the declaration of FAR (Gilles VOllant)
+- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann)
+- read_buf buf parameter of type Bytef* instead of charf*
+- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout)
+- do not redeclare unlink in minigzip.c for WIN32 (John Bowler)
+- fix check for presence of directories in "make install" (Ian Willis)
+
+Changes in 1.0.8 (27 Jan 1998)
+- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant)
+- fix gzgetc and gzputc for big endian systems (Markus Oberhumer)
+- added compress2() to allow setting the compression level
+- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong)
+- use constant arrays for the static trees in trees.c instead of computing
+ them at run time (thanks to Ken Raeburn for this suggestion). To create
+ trees.h, compile with GEN_TREES_H and run "make test".
+- check return code of example in "make test" and display result
+- pass minigzip command line options to file_compress
+- simplifying code of inflateSync to avoid gcc 2.8 bug
+
+- support CC="gcc -Wall" in configure -s (QingLong)
+- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn)
+- fix test for shared library support to avoid compiler warnings
+- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant)
+- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit)
+- do not use fdopen for Metrowerks on Mac (Brad Pettit))
+- add checks for gzputc and gzputc in example.c
+- avoid warnings in gzio.c and deflate.c (Andreas Kleinert)
+- use const for the CRC table (Ken Raeburn)
+- fixed "make uninstall" for shared libraries
+- use Tracev instead of Trace in infblock.c
+- in example.c use correct compressed length for test_sync
+- suppress +vnocompatwarnings in configure for HPUX (not always supported)
+
+Changes in 1.0.7 (20 Jan 1998)
+- fix gzseek which was broken in write mode
+- return error for gzseek to negative absolute position
+- fix configure for Linux (Chun-Chung Chen)
+- increase stack space for MSC (Tim Wegner)
+- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant)
+- define EXPORTVA for gzprintf (Gilles Vollant)
+- added man page zlib.3 (Rick Rodgers)
+- for contrib/untgz, fix makedir() and improve Makefile
+
+- check gzseek in write mode in example.c
+- allocate extra buffer for seeks only if gzseek is actually called
+- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant)
+- add inflateSyncPoint in zconf.h
+- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def
+
+Changes in 1.0.6 (19 Jan 1998)
+- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and
+ gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code)
+- Fix a deflate bug occuring only with compression level 0 (thanks to
+ Andy Buckler for finding this one).
+- In minigzip, pass transparently also the first byte for .Z files.
+- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress()
+- check Z_FINISH in inflate (thanks to Marc Schluper)
+- Implement deflateCopy (thanks to Adam Costello)
+- make static libraries by default in configure, add --shared option.
+- move MSDOS or Windows specific files to directory msdos
+- suppress the notion of partial flush to simplify the interface
+ (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4)
+- suppress history buffer provided by application to simplify the interface
+ (this feature was not implemented anyway in 1.0.4)
+- next_in and avail_in must be initialized before calling inflateInit or
+ inflateInit2
+- add EXPORT in all exported functions (for Windows DLL)
+- added Makefile.nt (thanks to Stephen Williams)
+- added the unsupported "contrib" directory:
+ contrib/asm386/ by Gilles Vollant <info@winimage.com>
+ 386 asm code replacing longest_match().
+ contrib/iostream/ by Kevin Ruland <kevin@rodin.wustl.edu>
+ A C++ I/O streams interface to the zlib gz* functions
+ contrib/iostream2/ by Tyge Løvset <Tyge.Lovset@cmr.no>
+ Another C++ I/O streams interface
+ contrib/untgz/ by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
+ A very simple tar.gz file extractor using zlib
+ contrib/visual-basic.txt by Carlos Rios <c_rios@sonda.cl>
+ How to use compress(), uncompress() and the gz* functions from VB.
+- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression
+ level) in minigzip (thanks to Tom Lane)
+
+- use const for rommable constants in deflate
+- added test for gzseek and gztell in example.c
+- add undocumented function inflateSyncPoint() (hack for Paul Mackerras)
+- add undocumented function zError to convert error code to string
+ (for Tim Smithers)
+- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code.
+- Use default memcpy for Symantec MSDOS compiler.
+- Add EXPORT keyword for check_func (needed for Windows DLL)
+- add current directory to LD_LIBRARY_PATH for "make test"
+- create also a link for libz.so.1
+- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura)
+- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX)
+- added -soname for Linux in configure (Chun-Chung Chen,
+- assign numbers to the exported functions in zlib.def (for Windows DLL)
+- add advice in zlib.h for best usage of deflateSetDictionary
+- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn)
+- allow compilation with ANSI keywords only enabled for TurboC in large model
+- avoid "versionString"[0] (Borland bug)
+- add NEED_DUMMY_RETURN for Borland
+- use variable z_verbose for tracing in debug mode (L. Peter Deutsch).
+- allow compilation with CC
+- defined STDC for OS/2 (David Charlap)
+- limit external names to 8 chars for MVS (Thomas Lund)
+- in minigzip.c, use static buffers only for 16-bit systems
+- fix suffix check for "minigzip -d foo.gz"
+- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee)
+- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau)
+- added makelcc.bat for lcc-win32 (Tom St Denis)
+- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe)
+- Avoid expanded $Id: ChangeLog,v 1.1 2005/01/12 07:44:59 mmondor Exp $. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion.
+- check for unistd.h in configure (for off_t)
+- remove useless check parameter in inflate_blocks_free
+- avoid useless assignment of s->check to itself in inflate_blocks_new
+- do not flush twice in gzclose (thanks to Ken Raeburn)
+- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h
+- use NO_ERRNO_H instead of enumeration of operating systems with errno.h
+- work around buggy fclose on pipes for HP/UX
+- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson)
+- fix configure if CC is already equal to gcc
+
+Changes in 1.0.5 (3 Jan 98)
+- Fix inflate to terminate gracefully when fed corrupted or invalid data
+- Use const for rommable constants in inflate
+- Eliminate memory leaks on error conditions in inflate
+- Removed some vestigial code in inflate
+- Update web address in README
+
+Changes in 1.0.4 (24 Jul 96)
+- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF
+ bit, so the decompressor could decompress all the correct data but went
+ on to attempt decompressing extra garbage data. This affected minigzip too.
+- zlibVersion and gzerror return const char* (needed for DLL)
+- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno)
+- use z_error only for DEBUG (avoid problem with DLLs)
+
+Changes in 1.0.3 (2 Jul 96)
+- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS
+ small and medium models; this makes the library incompatible with previous
+ versions for these models. (No effect in large model or on other systems.)
+- return OK instead of BUF_ERROR if previous deflate call returned with
+ avail_out as zero but there is nothing to do
+- added memcmp for non STDC compilers
+- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly)
+- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO)
+- better check for 16-bit mode MSC (avoids problem with Symantec)
+
+Changes in 1.0.2 (23 May 96)
+- added Windows DLL support
+- added a function zlibVersion (for the DLL support)
+- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model)
+- Bytef is define's instead of typedef'd only for Borland C
+- avoid reading uninitialized memory in example.c
+- mention in README that the zlib format is now RFC1950
+- updated Makefile.dj2
+- added algorithm.doc
+
+Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion]
+- fix array overlay in deflate.c which sometimes caused bad compressed data
+- fix inflate bug with empty stored block
+- fix MSDOS medium model which was broken in 0.99
+- fix deflateParams() which could generated bad compressed data.
+- Bytef is define'd instead of typedef'ed (work around Borland bug)
+- added an INDEX file
+- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32),
+ Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas)
+- speed up adler32 for modern machines without auto-increment
+- added -ansi for IRIX in configure
+- static_init_done in trees.c is an int
+- define unlink as delete for VMS
+- fix configure for QNX
+- add configure branch for SCO and HPUX
+- avoid many warnings (unused variables, dead assignments, etc...)
+- no fdopen for BeOS
+- fix the Watcom fix for 32 bit mode (define FAR as empty)
+- removed redefinition of Byte for MKWERKS
+- work around an MWKERKS bug (incorrect merge of all .h files)
+
+Changes in 0.99 (27 Jan 96)
+- allow preset dictionary shared between compressor and decompressor
+- allow compression level 0 (no compression)
+- add deflateParams in zlib.h: allow dynamic change of compression level
+ and compression strategy.
+- test large buffers and deflateParams in example.c
+- add optional "configure" to build zlib as a shared library
+- suppress Makefile.qnx, use configure instead
+- fixed deflate for 64-bit systems (detected on Cray)
+- fixed inflate_blocks for 64-bit systems (detected on Alpha)
+- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2)
+- always return Z_BUF_ERROR when deflate() has nothing to do
+- deflateInit and inflateInit are now macros to allow version checking
+- prefix all global functions and types with z_ with -DZ_PREFIX
+- make falloc completely reentrant (inftrees.c)
+- fixed very unlikely race condition in ct_static_init
+- free in reverse order of allocation to help memory manager
+- use zlib-1.0/* instead of zlib/* inside the tar.gz
+- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith
+ -Wconversion -Wstrict-prototypes -Wmissing-prototypes"
+- allow gzread on concatenated .gz files
+- deflateEnd now returns Z_DATA_ERROR if it was premature
+- deflate is finally (?) fully deterministic (no matches beyond end of input)
+- Document Z_SYNC_FLUSH
+- add uninstall in Makefile
+- Check for __cpluplus in zlib.h
+- Better test in ct_align for partial flush
+- avoid harmless warnings for Borland C++
+- initialize hash_head in deflate.c
+- avoid warning on fdopen (gzio.c) for HP cc -Aa
+- include stdlib.h for STDC compilers
+- include errno.h for Cray
+- ignore error if ranlib doesn't exist
+- call ranlib twice for NeXTSTEP
+- use exec_prefix instead of prefix for libz.a
+- renamed ct_* as _tr_* to avoid conflict with applications
+- clear z->msg in inflateInit2 before any error return
+- initialize opaque in example.c, gzio.c, deflate.c and inflate.c
+- fixed typo in zconf.h (_GNUC__ => __GNUC__)
+- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode)
+- fix typo in Make_vms.com (f$trnlnm -> f$getsyi)
+- in fcalloc, normalize pointer if size > 65520 bytes
+- don't use special fcalloc for 32 bit Borland C++
+- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc...
+- use Z_BINARY instead of BINARY
+- document that gzclose after gzdopen will close the file
+- allow "a" as mode in gzopen.
+- fix error checking in gzread
+- allow skipping .gz extra-field on pipes
+- added reference to Perl interface in README
+- put the crc table in FAR data (I dislike more and more the medium model :)
+- added get_crc_table
+- added a dimension to all arrays (Borland C can't count).
+- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast
+- guard against multiple inclusion of *.h (for precompiled header on Mac)
+- Watcom C pretends to be Microsoft C small model even in 32 bit mode.
+- don't use unsized arrays to avoid silly warnings by Visual C++:
+ warning C4746: 'inflate_mask' : unsized array treated as '__far'
+ (what's wrong with far data in far model?).
+- define enum out of inflate_blocks_state to allow compilation with C++
+
+Changes in 0.95 (16 Aug 95)
+- fix MSDOS small and medium model (now easier to adapt to any compiler)
+- inlined send_bits
+- fix the final (:-) bug for deflate with flush (output was correct but
+ not completely flushed in rare occasions).
+- default window size is same for compression and decompression
+ (it's now sufficient to set MAX_WBITS in zconf.h).
+- voidp -> voidpf and voidnp -> voidp (for consistency with other
+ typedefs and because voidnp was not near in large model).
+
+Changes in 0.94 (13 Aug 95)
+- support MSDOS medium model
+- fix deflate with flush (could sometimes generate bad output)
+- fix deflateReset (zlib header was incorrectly suppressed)
+- added support for VMS
+- allow a compression level in gzopen()
+- gzflush now calls fflush
+- For deflate with flush, flush even if no more input is provided.
+- rename libgz.a as libz.a
+- avoid complex expression in infcodes.c triggering Turbo C bug
+- work around a problem with gcc on Alpha (in INSERT_STRING)
+- don't use inline functions (problem with some gcc versions)
+- allow renaming of Byte, uInt, etc... with #define.
+- avoid warning about (unused) pointer before start of array in deflate.c
+- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c
+- avoid reserved word 'new' in trees.c
+
+Changes in 0.93 (25 June 95)
+- temporarily disable inline functions
+- make deflate deterministic
+- give enough lookahead for PARTIAL_FLUSH
+- Set binary mode for stdin/stdout in minigzip.c for OS/2
+- don't even use signed char in inflate (not portable enough)
+- fix inflate memory leak for segmented architectures
+
+Changes in 0.92 (3 May 95)
+- don't assume that char is signed (problem on SGI)
+- Clear bit buffer when starting a stored block
+- no memcpy on Pyramid
+- suppressed inftest.c
+- optimized fill_window, put longest_match inline for gcc
+- optimized inflate on stored blocks.
+- untabify all sources to simplify patches
+
+Changes in 0.91 (2 May 95)
+- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h
+- Document the memory requirements in zconf.h
+- added "make install"
+- fix sync search logic in inflateSync
+- deflate(Z_FULL_FLUSH) now works even if output buffer too short
+- after inflateSync, don't scare people with just "lo world"
+- added support for DJGPP
+
+Changes in 0.9 (1 May 95)
+- don't assume that zalloc clears the allocated memory (the TurboC bug
+ was Mark's bug after all :)
+- let again gzread copy uncompressed data unchanged (was working in 0.71)
+- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented
+- added a test of inflateSync in example.c
+- moved MAX_WBITS to zconf.h because users might want to change that.
+- document explicitly that zalloc(64K) on MSDOS must return a normalized
+ pointer (zero offset)
+- added Makefiles for Microsoft C, Turbo C, Borland C++
+- faster crc32()
+
+Changes in 0.8 (29 April 95)
+- added fast inflate (inffast.c)
+- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this
+ is incompatible with previous versions of zlib which returned Z_OK.
+- work around a TurboC compiler bug (bad code for b << 0, see infutil.h)
+ (actually that was not a compiler bug, see 0.81 above)
+- gzread no longer reads one extra byte in certain cases
+- In gzio destroy(), don't reference a freed structure
+- avoid many warnings for MSDOS
+- avoid the ERROR symbol which is used by MS Windows
+
+Changes in 0.71 (14 April 95)
+- Fixed more MSDOS compilation problems :( There is still a bug with
+ TurboC large model.
+
+Changes in 0.7 (14 April 95)
+- Added full inflate support.
+- Simplified the crc32() interface. The pre- and post-conditioning
+ (one's complement) is now done inside crc32(). WARNING: this is
+ incompatible with previous versions; see zlib.h for the new usage.
+
+Changes in 0.61 (12 April 95)
+- workaround for a bug in TurboC. example and minigzip now work on MSDOS.
+
+Changes in 0.6 (11 April 95)
+- added minigzip.c
+- added gzdopen to reopen a file descriptor as gzFile
+- added transparent reading of non-gziped files in gzread.
+- fixed bug in gzread (don't read crc as data)
+- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose).
+- don't allocate big arrays in the stack (for MSDOS)
+- fix some MSDOS compilation problems
+
+Changes in 0.5:
+- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but
+ not yet Z_FULL_FLUSH.
+- support decompression but only in a single step (forced Z_FINISH)
+- added opaque object for zalloc and zfree.
+- added deflateReset and inflateReset
+- added a variable zlib_version for consistency checking.
+- renamed the 'filter' parameter of deflateInit2 as 'strategy'.
+ Added Z_FILTERED and Z_HUFFMAN_ONLY constants.
+
+Changes in 0.4:
+- avoid "zip" everywhere, use zlib instead of ziplib.
+- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush
+ if compression method == 8.
+- added adler32 and crc32
+- renamed deflateOptions as deflateInit2, call one or the other but not both
+- added the method parameter for deflateInit2.
+- added inflateInit2
+- simplied considerably deflateInit and inflateInit by not supporting
+ user-provided history buffer. This is supported only in deflateInit2
+ and inflateInit2.
+
+Changes in 0.3:
+- prefix all macro names with Z_
+- use Z_FINISH instead of deflateEnd to finish compression.
+- added Z_HUFFMAN_ONLY
+- added gzerror()
--- /dev/null
+
+ Frequently Asked Questions about zlib
+
+
+If your question is not there, please check the zlib home page
+http://www.zlib.org which may have more recent information.
+The lastest zlib FAQ is at http://www.gzip.org/zlib/zlib_faq.html
+
+
+ 1. Is zlib Y2K-compliant?
+
+ Yes. zlib doesn't handle dates.
+
+ 2. Where can I get a Windows DLL version?
+
+ The zlib sources can be compiled without change to produce a DLL.
+ See the file win32/DLL_FAQ.txt in the zlib distribution.
+ Pointers to the precompiled DLL are found in the zlib web site at
+ http://www.zlib.org.
+
+ 3. Where can I get a Visual Basic interface to zlib?
+
+ See
+ * http://www.winimage.com/zLibDll/
+ * http://www.dogma.net/markn/articles/zlibtool/zlibtool.htm
+ * contrib/visual-basic.txt in the zlib distribution
+
+ 4. compress() returns Z_BUF_ERROR
+
+ Make sure that before the call of compress, the length of the compressed
+ buffer is equal to the total size of the compressed buffer and not
+ zero. For Visual Basic, check that this parameter is passed by reference
+ ("as any"), not by value ("as long").
+
+ 5. deflate() or inflate() returns Z_BUF_ERROR
+
+ Before making the call, make sure that avail_in and avail_out are not
+ zero. When setting the parameter flush equal to Z_FINISH, also make sure
+ that avail_out is big enough to allow processing all pending input.
+ Note that a Z_BUF_ERROR is not fatal--another call to deflate() or
+ inflate() can be made with more input or output space. A Z_BUF_ERROR
+ may in fact be unavoidable depending on how the functions are used, since
+ it is not possible to tell whether or not there is more output pending
+ when strm.avail_out returns with zero.
+
+ 6. Where's the zlib documentation (man pages, etc.)?
+
+ It's in zlib.h for the moment, and Francis S. Lin has converted it to a
+ web page zlib.html. Volunteers to transform this to Unix-style man pages,
+ please contact Jean-loup Gailly (jloup@gzip.org). Examples of zlib usage
+ are in the files example.c and minigzip.c.
+
+ 7. Why don't you use GNU autoconf or libtool or ...?
+
+ Because we would like to keep zlib as a very small and simple
+ package. zlib is rather portable and doesn't need much configuration.
+
+ 8. I found a bug in zlib.
+
+ Most of the time, such problems are due to an incorrect usage of
+ zlib. Please try to reproduce the problem with a small program and send
+ the corresponding source to us at zlib@gzip.org . Do not send
+ multi-megabyte data files without prior agreement.
+
+ 9. Why do I get "undefined reference to gzputc"?
+
+ If "make test" produces something like
+
+ example.o(.text+0x154): undefined reference to `gzputc'
+
+ check that you don't have old files libz.* in /usr/lib, /usr/local/lib or
+ /usr/X11R6/lib. Remove any old versions, then do "make install".
+
+10. I need a Delphi interface to zlib.
+
+ See the contrib/delphi directory in the zlib distribution.
+
+11. Can zlib handle .zip archives?
+
+ See the directory contrib/minizip in the zlib distribution.
+
+12. Can zlib handle .Z files?
+
+ No, sorry. You have to spawn an uncompress or gunzip subprocess, or adapt
+ the code of uncompress on your own.
+
+13. How can I make a Unix shared library?
+
+ make clean
+ ./configure -s
+ make
+
+14. How do I install a shared zlib library on Unix?
+
+ make install
+
+ However, many flavors of Unix come with a shared zlib already installed.
+ Before going to the trouble of compiling a shared version of zlib and
+ trying to install it, you may want to check if it's already there! If you
+ can #include <zlib.h>, it's there. The -lz option will probably link to it.
+
+15. I have a question about OttoPDF
+
+ We are not the authors of OttoPDF. The real author is on the OttoPDF web
+ site Joel Hainley jhainley@myndkryme.com.
+
+16. Why does gzip give an error on a file I make with compress/deflate?
+
+ The compress and deflate functions produce data in the zlib format, which
+ is different and incompatible with the gzip format. The gz* functions in
+ zlib on the other hand use the gzip format. Both the zlib and gzip
+ formats use the same compressed data format internally, but have different
+ headers and trailers around the compressed data.
+
+17. Ok, so why are there two different formats?
+
+ The gzip format was designed to retain the directory information about
+ a single file, such as the name and last modification date. The zlib
+ format on the other hand was designed for in-memory and communication
+ channel applications, and has a much more compact header and trailer and
+ uses a faster integrity check than gzip.
+
+18. Well that's nice, but how do I make a gzip file in memory?
+
+ You can request that deflate write the gzip format instead of the zlib
+ format using deflateInit2(). You can also request that inflate decode
+ the gzip format using inflateInit2(). Read zlib.h for more details.
+
+ Note that you cannot specify special gzip header contents (e.g. a file
+ name or modification date), nor will inflate tell you what was in the
+ gzip header. If you need to customize the header or see what's in it,
+ you can use the raw deflate and inflate operations and the crc32()
+ function and roll your own gzip encoding and decoding. Read the gzip
+ RFC 1952 for details of the header and trailer format.
+
+19. Is zlib thread-safe?
+
+ Yes. However any library routines that zlib uses and any application-
+ provided memory allocation routines must also be thread-safe. zlib's gz*
+ functions use stdio library routines, and most of zlib's functions use the
+ library memory allocation routines by default. zlib's Init functions allow
+ for the application to provide custom memory allocation routines.
+
+ Of course, you should only operate on any given zlib or gzip stream from a
+ single thread at a time.
+
+20. Can I use zlib in my commercial application?
+
+ Yes. Please read the license in zlib.h.
+
+21. Is zlib under the GNU license?
+
+ No. Please read the license in zlib.h.
+
+22. The license says that altered source versions must be "plainly marked". So
+ what exactly do I need to do to meet that requirement?
+
+ You need to change the ZLIB_VERSION and ZLIB_VERNUM #defines in zlib.h. In
+ particular, the final version number needs to be changed to "f", and an
+ identification string should be appended to ZLIB_VERSION. Version numbers
+ x.x.x.f are reserved for modifications to zlib by others than the zlib
+ maintainers. For example, if the version of the base zlib you are altering
+ is "1.2.3.4", then in zlib.h you should change ZLIB_VERNUM to 0x123f, and
+ ZLIB_VERSION to something like "1.2.3.f-zachary-mods-v3". You can also
+ update the version strings in deflate.c and inftrees.c.
+
+ For altered source distributions, you should also note the origin and
+ nature of the changes in zlib.h, as well as in ChangeLog and README, along
+ with the dates of the alterations. The origin should include at least your
+ name (or your company's name), and an email address to contact for help or
+ issues with the library.
+
+ Note that distributing a compiled zlib library along with zlib.h and
+ zconf.h is also a source distribution, and so you should change
+ ZLIB_VERSION and ZLIB_VERNUM and note the origin and nature of the changes
+ in zlib.h as you would for a full source distribution.
+
+23. Will zlib work on a big-endian or little-endian architecture, and can I
+ exchange compressed data between them?
+
+ Yes and yes.
+
+24. Will zlib work on a 64-bit machine?
+
+ It should. It has been tested on 64-bit machines, and has no dependence
+ on any data types being limited to 32-bits in length. If you have any
+ difficulties, please provide a complete problem report to zlib@gzip.org
+
+25. Will zlib decompress data from the PKWare Data Compression Library?
+
+ No. The PKWare DCL uses a completely different compressed data format
+ than does PKZIP and zlib. However, you can look in zlib's contrib/blast
+ directory for a possible solution to your problem.
+
+26. Can I access data randomly in a compressed stream?
+
+ No, not without some preparation. If when compressing you periodically
+ use Z_FULL_FLUSH, carefully write all the pending data at those points,
+ and keep an index of those locations, then you can start decompression
+ at those points. You have to be careful to not use Z_FULL_FLUSH too
+ often, since it can significantly degrade compression.
+
+27. Does zlib work on MVS, OS/390, CICS, etc.?
+
+ We don't know for sure. We have heard occasional reports of success on
+ these systems. If you do use it on one of these, please provide us with
+ a report, instructions, and patches that we can reference when we get
+ these questions. Thanks.
+
+28. Is there some simpler, easier to read version of inflate I can look at
+ to understand the deflate format?
+
+ First off, you should read RFC 1951. Second, yes. Look in zlib's
+ contrib/puff directory.
+
+29. Does zlib infringe on any patents?
+
+ As far as we know, no. In fact, that was originally the whole point behind
+ zlib. Look here for some more information:
+
+ http://www.gzip.org/#faq11
+
+30. Can zlib work with greater than 4 GB of data?
+
+ Yes. inflate() and deflate() will process any amount of data correctly.
+ Each call of inflate() or deflate() is limited to input and output chunks
+ of the maximum value that can be stored in the compiler's "unsigned int"
+ type, but there is no limit to the number of chunks. Note however that the
+ strm.total_in and strm_total_out counters may be limited to 4 GB. These
+ counters are provided as a convenience and are not used internally by
+ inflate() or deflate(). The application can easily set up its own counters
+ updated after each call of inflate() or deflate() to count beyond 4 GB.
+ compress() and uncompress() may be limited to 4 GB, since they operate in a
+ single call. gzseek() and gztell() may be limited to 4 GB depending on how
+ zlib is compiled. See the zlibCompileFlags() function in zlib.h.
+
+ The word "may" appears several times above since there is a 4 GB limit
+ only if the compiler's "long" type is 32 bits. If the compiler's "long"
+ type is 64 bits, then the limit is 16 exabytes.
+
+31. Does zlib have any security vulnerabilities?
+
+ The only one that we are aware of is potentially in gzprintf(). If zlib
+ is compiled to use sprintf() or vsprintf(), then there is no protection
+ against a buffer overflow of a 4K string space, other than the caller of
+ gzprintf() assuring that the output will not exceed 4K. On the other
+ hand, if zlib is compiled to use snprintf() or vsnprintf(), which should
+ normally be the case, then there is no vulnerability. The ./configure
+ script will display warnings if an insecure variation of sprintf() will
+ be used by gzprintf(). Also the zlibCompileFlags() function will return
+ information on what variant of sprintf() is used by gzprintf().
+
+ If you don't have snprintf() or vsnprintf() and would like one, you can
+ find a portable implementation here:
+
+ http://www.ijs.si/software/snprintf/
+
+ Note that you should be using the most recent version of zlib. Versions
+ 1.1.3 and before were subject to a double-free vulnerability.
+
+32. Is there a Java version of zlib?
+
+ Probably what you want is to use zlib in Java. zlib is already included
+ as part of the Java SDK in the java.util.zip package. If you really want
+ a version of zlib written in the Java language, look on the zlib home
+ page for links: http://www.zlib.org/
+
+33. I get this or that compiler or source-code scanner warning when I crank it
+ up to maximally-pendantic. Can't you guys write proper code?
+
+ Many years ago, we gave up attempting to avoid warnings on every compiler
+ in the universe. It just got to be a waste of time, and some compilers
+ were downright silly. So now, we simply make sure that the code always
+ works.
+
+34. Will zlib read the (insert any ancient or arcane format here) compressed
+ data format?
+
+ Probably not. Look in the comp.compression FAQ for pointers to various
+ formats and associated software.
+
+35. How can I encrypt/decrypt zip files with zlib?
+
+ zlib doesn't support encryption. The original PKZIP encryption is very weak
+ and can be broken with freely available programs. To get strong encryption,
+ use gpg ( http://www.gnupg.org/ ) which already includes zlib compression.
+ For PKZIP compatible "encryption", look at http://www.info-zip.org/
+
+36. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings?
+
+ "gzip" is the gzip format, and "deflate" is the zlib format. They should
+ probably have called the second one "zlib" instead to avoid confusion
+ with the raw deflate compressed data format. While the HTTP 1.1 RFC 2616
+ correctly points to the zlib specification in RFC 1950 for the "deflate"
+ transfer encoding, there have been reports of servers and browsers that
+ incorrectly produce or expect raw deflate data per the deflate
+ specficiation in RFC 1951, most notably Microsoft. So even though the
+ "deflate" transfer encoding using the zlib format would be the more
+ efficient approach (and in fact exactly what the zlib format was designed
+ for), using the "gzip" transfer encoding is probably more reliable due to
+ an unfortunate choice of name on the part of the HTTP 1.1 authors.
+
+ Bottom line: use the gzip format for HTTP 1.1 encoding.
+
+37. Does zlib support the new "Deflate64" format introduced by PKWare?
+
+ No. PKWare has apparently decided to keep that format proprietary, since
+ they have not documented it as they have previous compression formats.
+ In any case, the compression improvements are so modest compared to other
+ more modern approaches, that it's not worth the effort to implement.
+
+38. Can you please sign these lengthy legal documents and fax them back to us
+ so that we can use your software in our product?
+
+ No. Go away. Shoo.
--- /dev/null
+ChangeLog history of changes
+FAQ Frequently Asked Questions about zlib
+INDEX this file
+Makefile makefile for Unix (generated by configure)
+Makefile.in makefile for Unix (template for configure)
+README guess what
+algorithm.txt description of the (de)compression algorithm
+configure configure script for Unix
+zconf.in.h template for zconf.h (used by configure)
+
+msdos/ makefiles for MSDOS
+old/ makefiles for various architectures and zlib documentation
+ files that have not yet been updated for zlib 1.2.x
+qnx/ makefiles for QNX
+win32/ makefiles for Windows
+
+ zlib public header files (must be kept):
+zconf.h
+zlib.h
+
+ private source files used to build the zlib library:
+adler32.c
+compress.c
+crc32.c
+crc32.h
+deflate.c
+deflate.h
+gzio.c
+infback.c
+inffast.c
+inffast.h
+inffixed.h
+inflate.c
+inflate.h
+inftrees.c
+inftrees.h
+trees.c
+trees.h
+uncompr.c
+zutil.c
+zutil.h
+
+ source files for sample programs:
+example.c
+minigzip.c
+
+ unsupported contribution by third parties
+See contrib/README.contrib
--- /dev/null
+# Makefile for zlib
+# Copyright (C) 1995-2003 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile and test, type:
+# ./configure; make test
+# The call of configure is optional if you don't have special requirements
+# If you wish to build zlib as a shared library, use: ./configure -s
+
+# To use the asm code, type:
+# cp contrib/asm?86/match.S ./match.S
+# make LOC=-DASMV OBJA=match.o
+
+# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type:
+# make install
+# To install in $HOME instead of /usr/local, use:
+# make install prefix=$HOME
+
+CC=cc
+
+CFLAGS=-O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-g -DDEBUG
+#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+# -Wstrict-prototypes -Wmissing-prototypes
+
+LDFLAGS=libz.a
+LDSHARED=$(CC)
+CPP=$(CC) -E
+
+LIBS=libz.a
+SHAREDLIB=libz.so
+SHAREDLIBV=libz.so.1.2.1
+SHAREDLIBM=libz.so.1
+
+AR=ar rc
+RANLIB=ranlib
+TAR=tar
+SHELL=/bin/sh
+EXE=
+
+prefix = /usr/local
+exec_prefix = ${prefix}
+libdir = ${exec_prefix}/lib
+includedir = ${prefix}/include
+mandir = ${prefix}/share/man
+man3dir = ${mandir}/man3
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infback.o inftrees.o inffast.o
+
+OBJA =
+# to use the asm code: make OBJA=match.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example$(EXE) minigzip$(EXE)
+
+build: all
+
+check: test
+test: all
+ @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \
+ echo hello world | ./minigzip | ./minigzip -d || \
+ echo ' *** minigzip test FAILED ***' ; \
+ if ./example; then \
+ echo ' *** zlib test OK ***'; \
+ else \
+ echo ' *** zlib test FAILED ***'; \
+ fi
+
+libz.a: $(OBJS) $(OBJA)
+ $(AR) $@ $(OBJS) $(OBJA)
+ -@ ($(RANLIB) $@ || true) >/dev/null 2>&1
+
+match.o: match.S
+ $(CPP) match.S > _match.s
+ $(CC) -c _match.s
+ mv _match.o match.o
+ rm -f _match.s
+
+$(SHAREDLIBV): $(OBJS)
+ $(LDSHARED) -o $@ $(OBJS)
+ rm -f $(SHAREDLIB) $(SHAREDLIBM)
+ ln -s $@ $(SHAREDLIB)
+ ln -s $@ $(SHAREDLIBM)
+
+example$(EXE): example.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS)
+
+minigzip$(EXE): minigzip.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS)
+
+install: $(LIBS)
+ -@if [ ! -d $(exec_prefix) ]; then mkdir -p $(exec_prefix); fi
+ -@if [ ! -d $(includedir) ]; then mkdir -p $(includedir); fi
+ -@if [ ! -d $(libdir) ]; then mkdir -p $(libdir); fi
+ -@if [ ! -d $(man3dir) ]; then mkdir -p $(man3dir); fi
+ cp zlib.h zconf.h $(includedir)
+ chmod 644 $(includedir)/zlib.h $(includedir)/zconf.h
+ cp $(LIBS) $(libdir)
+ cd $(libdir); chmod 755 $(LIBS)
+ -@(cd $(libdir); $(RANLIB) libz.a || true) >/dev/null 2>&1
+ cd $(libdir); if test -f $(SHAREDLIBV); then \
+ rm -f $(SHAREDLIB) $(SHAREDLIBM); \
+ ln -s $(SHAREDLIBV) $(SHAREDLIB); \
+ ln -s $(SHAREDLIBV) $(SHAREDLIBM); \
+ (ldconfig || true) >/dev/null 2>&1; \
+ fi
+ cp zlib.3 $(man3dir)
+ chmod 644 $(man3dir)/zlib.3
+# The ranlib in install is needed on NeXTSTEP which checks file times
+# ldconfig is for Linux
+
+uninstall:
+ cd $(includedir); \
+ cd $(libdir); rm -f libz.a; \
+ if test -f $(SHAREDLIBV); then \
+ rm -f $(SHAREDLIBV) $(SHAREDLIB) $(SHAREDLIBM); \
+ fi
+ cd $(man3dir); rm -f zlib.3
+
+mostlyclean: clean
+clean:
+ rm -f *.o *~ example$(EXE) minigzip$(EXE) \
+ libz.* foo.gz so_locations \
+ _match.s maketree contrib/infback9/*.o
+
+maintainer-clean: distclean
+distclean: clean
+ cp -p Makefile.in Makefile
+ cp -p zconf.in.h zconf.h
+ rm -f .DS_Store
+
+tags:
+ etags *.[ch]
+
+depend:
+ makedepend -- $(CFLAGS) -- *.[ch]
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: crc32.h zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+minigzip.o: zlib.h zconf.h
+trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h
--- /dev/null
+ZLIB DATA COMPRESSION LIBRARY
+
+zlib 1.2.1 is a general purpose data compression library. All the code is
+thread safe. The data format used by the zlib library is described by RFCs
+(Request for Comments) 1950 to 1952 in the files
+http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format)
+and rfc1952.txt (gzip format). These documents are also available in other
+formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
+
+All functions of the compression library are documented in the file zlib.h
+(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example
+of the library is given in the file example.c which also tests that the library
+is working correctly. Another example is given in the file minigzip.c. The
+compression library itself is composed of all source files except example.c and
+minigzip.c.
+
+To compile all files and run the test program, follow the instructions given at
+the top of Makefile. In short "make test; make install" should work for most
+machines. For Unix: "./configure; make test; make install" For MSDOS, use one
+of the special makefiles such as Makefile.msc. For VMS, use Make_vms.com or
+descrip.mms.
+
+Questions about zlib should be sent to <zlib@gzip.org>, or to Gilles Vollant
+<info@winimage.com> for the Windows DLL version. The zlib home page is
+http://www.zlib.org or http://www.gzip.org/zlib/ Before reporting a problem,
+please check this site to verify that you have the latest version of zlib;
+otherwise get the latest version and check whether the problem still exists or
+not.
+
+PLEASE read the zlib FAQ http://www.gzip.org/zlib/zlib_faq.html before asking
+for help.
+
+Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997
+issue of Dr. Dobb's Journal; a copy of the article is available in
+http://dogma.net/markn/articles/zlibtool/zlibtool.htm
+
+The changes made in version 1.2.1 are documented in the file ChangeLog.
+
+Unsupported third party contributions are provided in directory "contrib".
+
+A Java implementation of zlib is available in the Java Development Kit
+http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/package-summary.html
+See the zlib home page http://www.zlib.org for details.
+
+A Perl interface to zlib written by Paul Marquess <pmqs@cpan.org> is in the
+CPAN (Comprehensive Perl Archive Network) sites
+http://www.cpan.org/modules/by-module/Compress/
+
+A Python interface to zlib written by A.M. Kuchling <amk@magnet.com> is
+available in Python 1.5 and later versions, see
+http://www.python.org/doc/lib/module-zlib.html
+
+A zlib binding for TCL written by Andreas Kupries <a.kupries@westend.com> is
+availlable at http://www.oche.de/~akupries/soft/trf/trf_zip.html
+
+An experimental package to read and write files in .zip format, written on top
+of zlib by Gilles Vollant <info@winimage.com>, is available in the
+contrib/minizip directory of zlib.
+
+
+Notes for some targets:
+
+- For Windows DLL versions, please see win32/DLL_FAQ.txt
+
+- For 64-bit Irix, deflate.c must be compiled without any optimization. With
+ -O, one libpng test fails. The test works in 32 bit mode (with the -n32
+ compiler flag). The compiler bug has been reported to SGI.
+
+- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works
+ when compiled with cc.
+
+- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is
+ necessary to get gzprintf working correctly. This is done by configure.
+
+- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with
+ other compilers. Use "make test" to check your compiler.
+
+- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers.
+
+- For PalmOs, see http://palmzlib.sourceforge.net/
+
+- When building a shared, i.e. dynamic library on Mac OS X, the library must be
+ installed before testing (do "make install" before "make test"), since the
+ library location is specified in the library.
+
+
+Acknowledgments:
+
+ The deflate format used by zlib was defined by Phil Katz. The deflate
+ and zlib specifications were written by L. Peter Deutsch. Thanks to all the
+ people who reported problems and suggested various improvements in zlib;
+ they are too numerous to cite here.
+
+Copyright notice:
+
+ (C) 1995-2003 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+If you use the zlib library in a product, we would appreciate *not*
+receiving lengthy legal documents to sign. The sources are provided
+for free but without warranty of any kind. The library has been
+entirely written by Jean-loup Gailly and Mark Adler; it does not
+include third-party code.
+
+If you redistribute modified sources, we would appreciate that you include
+in the file ChangeLog history information documenting your changes. Please
+read the FAQ for more information on the distribution of modified source
+versions.
--- /dev/null
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: adler32.c,v 1.1 2005/01/12 07:44:59 mmondor Exp $ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#define BASE 65521UL /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+#ifdef NO_DIVIDE
+# define MOD(a) \
+ do { \
+ if (a >= (BASE << 16)) a -= (BASE << 16); \
+ if (a >= (BASE << 15)) a -= (BASE << 15); \
+ if (a >= (BASE << 14)) a -= (BASE << 14); \
+ if (a >= (BASE << 13)) a -= (BASE << 13); \
+ if (a >= (BASE << 12)) a -= (BASE << 12); \
+ if (a >= (BASE << 11)) a -= (BASE << 11); \
+ if (a >= (BASE << 10)) a -= (BASE << 10); \
+ if (a >= (BASE << 9)) a -= (BASE << 9); \
+ if (a >= (BASE << 8)) a -= (BASE << 8); \
+ if (a >= (BASE << 7)) a -= (BASE << 7); \
+ if (a >= (BASE << 6)) a -= (BASE << 6); \
+ if (a >= (BASE << 5)) a -= (BASE << 5); \
+ if (a >= (BASE << 4)) a -= (BASE << 4); \
+ if (a >= (BASE << 3)) a -= (BASE << 3); \
+ if (a >= (BASE << 2)) a -= (BASE << 2); \
+ if (a >= (BASE << 1)) a -= (BASE << 1); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+#else
+# define MOD(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ unsigned long s1 = adler & 0xffff;
+ unsigned long s2 = (adler >> 16) & 0xffff;
+ int k;
+
+ if (buf == Z_NULL) return 1L;
+
+ while (len > 0) {
+ k = len < NMAX ? (int)len : NMAX;
+ len -= k;
+ while (k >= 16) {
+ DO16(buf);
+ buf += 16;
+ k -= 16;
+ }
+ if (k != 0) do {
+ s1 += *buf++;
+ s2 += s1;
+ } while (--k);
+ MOD(s1);
+ MOD(s2);
+ }
+ return (s2 << 16) | s1;
+}
--- /dev/null
+1. Compression algorithm (deflate)
+
+The deflation algorithm used by gzip (also zip and zlib) is a variation of
+LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in
+the input data. The second occurrence of a string is replaced by a
+pointer to the previous string, in the form of a pair (distance,
+length). Distances are limited to 32K bytes, and lengths are limited
+to 258 bytes. When a string does not occur anywhere in the previous
+32K bytes, it is emitted as a sequence of literal bytes. (In this
+description, `string' must be taken as an arbitrary sequence of bytes,
+and is not restricted to printable characters.)
+
+Literals or match lengths are compressed with one Huffman tree, and
+match distances are compressed with another tree. The trees are stored
+in a compact form at the start of each block. The blocks can have any
+size (except that the compressed data for one block must fit in
+available memory). A block is terminated when deflate() determines that
+it would be useful to start another block with fresh trees. (This is
+somewhat similar to the behavior of LZW-based _compress_.)
+
+Duplicated strings are found using a hash table. All input strings of
+length 3 are inserted in the hash table. A hash index is computed for
+the next 3 bytes. If the hash chain for this index is not empty, all
+strings in the chain are compared with the current input string, and
+the longest match is selected.
+
+The hash chains are searched starting with the most recent strings, to
+favor small distances and thus take advantage of the Huffman encoding.
+The hash chains are singly linked. There are no deletions from the
+hash chains, the algorithm simply discards matches that are too old.
+
+To avoid a worst-case situation, very long hash chains are arbitrarily
+truncated at a certain length, determined by a runtime option (level
+parameter of deflateInit). So deflate() does not always find the longest
+possible match but generally finds a match which is long enough.
+
+deflate() also defers the selection of matches with a lazy evaluation
+mechanism. After a match of length N has been found, deflate() searches for
+a longer match at the next input byte. If a longer match is found, the
+previous match is truncated to a length of one (thus producing a single
+literal byte) and the process of lazy evaluation begins again. Otherwise,
+the original match is kept, and the next match search is attempted only N
+steps later.
+
+The lazy match evaluation is also subject to a runtime parameter. If
+the current match is long enough, deflate() reduces the search for a longer
+match, thus speeding up the whole process. If compression ratio is more
+important than speed, deflate() attempts a complete second search even if
+the first match is already long enough.
+
+The lazy match evaluation is not performed for the fastest compression
+modes (level parameter 1 to 3). For these fast modes, new strings
+are inserted in the hash table only when no match was found, or
+when the match is not too long. This degrades the compression ratio
+but saves time since there are both fewer insertions and fewer searches.
+
+
+2. Decompression algorithm (inflate)
+
+2.1 Introduction
+
+The key question is how to represent a Huffman code (or any prefix code) so
+that you can decode fast. The most important characteristic is that shorter
+codes are much more common than longer codes, so pay attention to decoding the
+short codes fast, and let the long codes take longer to decode.
+
+inflate() sets up a first level table that covers some number of bits of
+input less than the length of longest code. It gets that many bits from the
+stream, and looks it up in the table. The table will tell if the next
+code is that many bits or less and how many, and if it is, it will tell
+the value, else it will point to the next level table for which inflate()
+grabs more bits and tries to decode a longer code.
+
+How many bits to make the first lookup is a tradeoff between the time it
+takes to decode and the time it takes to build the table. If building the
+table took no time (and if you had infinite memory), then there would only
+be a first level table to cover all the way to the longest code. However,
+building the table ends up taking a lot longer for more bits since short
+codes are replicated many times in such a table. What inflate() does is
+simply to make the number of bits in the first table a variable, and then
+to set that variable for the maximum speed.
+
+For inflate, which has 286 possible codes for the literal/length tree, the size
+of the first table is nine bits. Also the distance trees have 30 possible
+values, and the size of the first table is six bits. Note that for each of
+those cases, the table ended up one bit longer than the ``average'' code
+length, i.e. the code length of an approximately flat code which would be a
+little more than eight bits for 286 symbols and a little less than five bits
+for 30 symbols.
+
+
+2.2 More details on the inflate table lookup
+
+Ok, you want to know what this cleverly obfuscated inflate tree actually
+looks like. You are correct that it's not a Huffman tree. It is simply a
+lookup table for the first, let's say, nine bits of a Huffman symbol. The
+symbol could be as short as one bit or as long as 15 bits. If a particular
+symbol is shorter than nine bits, then that symbol's translation is duplicated
+in all those entries that start with that symbol's bits. For example, if the
+symbol is four bits, then it's duplicated 32 times in a nine-bit table. If a
+symbol is nine bits long, it appears in the table once.
+
+If the symbol is longer than nine bits, then that entry in the table points
+to another similar table for the remaining bits. Again, there are duplicated
+entries as needed. The idea is that most of the time the symbol will be short
+and there will only be one table look up. (That's whole idea behind data
+compression in the first place.) For the less frequent long symbols, there
+will be two lookups. If you had a compression method with really long
+symbols, you could have as many levels of lookups as is efficient. For
+inflate, two is enough.
+
+So a table entry either points to another table (in which case nine bits in
+the above example are gobbled), or it contains the translation for the symbol
+and the number of bits to gobble. Then you start again with the next
+ungobbled bit.
+
+You may wonder: why not just have one lookup table for how ever many bits the
+longest symbol is? The reason is that if you do that, you end up spending
+more time filling in duplicate symbol entries than you do actually decoding.
+At least for deflate's output that generates new trees every several 10's of
+kbytes. You can imagine that filling in a 2^15 entry table for a 15-bit code
+would take too long if you're only decoding several thousand symbols. At the
+other extreme, you could make a new table for every bit in the code. In fact,
+that's essentially a Huffman tree. But then you spend two much time
+traversing the tree while decoding, even for short symbols.
+
+So the number of bits for the first lookup table is a trade of the time to
+fill out the table vs. the time spent looking at the second level and above of
+the table.
+
+Here is an example, scaled down:
+
+The code being decoded, with 10 symbols, from 1 to 6 bits long:
+
+A: 0
+B: 10
+C: 1100
+D: 11010
+E: 11011
+F: 11100
+G: 11101
+H: 11110
+I: 111110
+J: 111111
+
+Let's make the first table three bits long (eight entries):
+
+000: A,1
+001: A,1
+010: A,1
+011: A,1
+100: B,2
+101: B,2
+110: -> table X (gobble 3 bits)
+111: -> table Y (gobble 3 bits)
+
+Each entry is what the bits decode as and how many bits that is, i.e. how
+many bits to gobble. Or the entry points to another table, with the number of
+bits to gobble implicit in the size of the table.
+
+Table X is two bits long since the longest code starting with 110 is five bits
+long:
+
+00: C,1
+01: C,1
+10: D,2
+11: E,2
+
+Table Y is three bits long since the longest code starting with 111 is six
+bits long:
+
+000: F,2
+001: F,2
+010: G,2
+011: G,2
+100: H,2
+101: H,2
+110: I,3
+111: J,3
+
+So what we have here are three tables with a total of 20 entries that had to
+be constructed. That's compared to 64 entries for a single table. Or
+compared to 16 entries for a Huffman tree (six two entry tables and one four
+entry table). Assuming that the code ideally represents the probability of
+the symbols, it takes on the average 1.25 lookups per symbol. That's compared
+to one lookup for the single table, or 1.66 lookups per symbol for the
+Huffman tree.
+
+There, I think that gives you a picture of what's going on. For inflate, the
+meaning of a particular symbol is often more than just a letter. It can be a
+byte (a "literal"), or it can be either a length or a distance which
+indicates a base value and a number of bits to fetch after the code that is
+added to the base value. Or it might be the special end-of-block code. The
+data structures created in inftrees.c try to encode all that information
+compactly in the tables.
+
+
+Jean-loup Gailly Mark Adler
+jloup@gzip.org madler@alumni.caltech.edu
+
+
+References:
+
+[LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data
+Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3,
+pp. 337-343.
+
+``DEFLATE Compressed Data Format Specification'' available in
+http://www.ietf.org/rfc/rfc1951.txt
--- /dev/null
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: compress.c,v 1.1 2005/01/12 07:44:59 mmondor Exp $ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least 0.1% larger than sourceLen plus
+ 12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+ int level;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+#ifdef MAXSEG_64K
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+#endif
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+ stream.opaque = (voidpf)0;
+
+ err = deflateInit(&stream, level);
+ if (err != Z_OK) return err;
+
+ err = deflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ deflateEnd(&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *destLen = stream.total_out;
+
+ err = deflateEnd(&stream);
+ return err;
+}
+
+/* ===========================================================================
+ */
+int ZEXPORT compress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
+
+/* ===========================================================================
+ If the default memLevel or windowBits for deflateInit() is changed, then
+ this function needs to be updated.
+ */
+uLong ZEXPORT compressBound (sourceLen)
+ uLong sourceLen;
+{
+ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11;
+}
--- /dev/null
+#!/bin/sh
+# configure script for zlib. This script is needed only if
+# you wish to build a shared library and your system supports them,
+# of if you need special compiler, flags or install directory.
+# Otherwise, you can just use directly "make test; make install"
+#
+# To create a shared library, use "configure --shared"; by default a static
+# library is created. If the primitive shared library support provided here
+# does not work, use ftp://prep.ai.mit.edu/pub/gnu/libtool-*.tar.gz
+#
+# To impose specific compiler or flags or install directory, use for example:
+# prefix=$HOME CC=cc CFLAGS="-O4" ./configure
+# or for csh/tcsh users:
+# (setenv prefix $HOME; setenv CC cc; setenv CFLAGS "-O4"; ./configure)
+# LDSHARED is the command to be used to create a shared library
+
+# Incorrect settings of CC or CFLAGS may prevent creating a shared library.
+# If you have problems, try without defining CC and CFLAGS before reporting
+# an error.
+
+LIBS=libz.a
+LDFLAGS="-L. ${LIBS}"
+VER=`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`
+VER2=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\)\\..*/\1/p' < zlib.h`
+VER1=`sed -n -e '/VERSION "/s/.*"\([0-9]*\)\\..*/\1/p' < zlib.h`
+AR=${AR-"ar rc"}
+RANLIB=${RANLIB-"ranlib"}
+prefix=${prefix-/usr/local}
+exec_prefix=${exec_prefix-'${prefix}'}
+libdir=${libdir-'${exec_prefix}/lib'}
+includedir=${includedir-'${prefix}/include'}
+mandir=${mandir-'${prefix}/share/man'}
+shared_ext='.so'
+shared=0
+gcc=0
+old_cc="$CC"
+old_cflags="$CFLAGS"
+
+while test $# -ge 1
+do
+case "$1" in
+ -h* | --h*)
+ echo 'usage:'
+ echo ' configure [--shared] [--prefix=PREFIX] [--exec_prefix=EXPREFIX]'
+ echo ' [--libdir=LIBDIR] [--includedir=INCLUDEDIR]'
+ exit 0;;
+ -p*=* | --p*=*) prefix=`echo $1 | sed 's/[-a-z_]*=//'`; shift;;
+ -e*=* | --e*=*) exec_prefix=`echo $1 | sed 's/[-a-z_]*=//'`; shift;;
+ -l*=* | --libdir=*) libdir=`echo $1 | sed 's/[-a-z_]*=//'`; shift;;
+ -i*=* | --includedir=*) includedir=`echo $1 | sed 's/[-a-z_]*=//'`;shift;;
+ -p* | --p*) prefix="$2"; shift; shift;;
+ -e* | --e*) exec_prefix="$2"; shift; shift;;
+ -l* | --l*) libdir="$2"; shift; shift;;
+ -i* | --i*) includedir="$2"; shift; shift;;
+ -s* | --s*) shared=1; shift;;
+ *) echo "unknown option: $1"; echo "$0 --help for help"; exit 1;;
+ esac
+done
+
+test=ztest$$
+cat > $test.c <<EOF
+extern int getchar();
+int hello() {return getchar();}
+EOF
+
+test -z "$CC" && echo Checking for gcc...
+cc=${CC-gcc}
+cflags=${CFLAGS-"-O3"}
+# to force the asm version use: CFLAGS="-O3 -DASMV" ./configure
+case "$cc" in
+ *gcc*) gcc=1;;
+esac
+
+if test "$gcc" -eq 1 && ($cc -c $cflags $test.c) 2>/dev/null; then
+ CC="$cc"
+ SFLAGS=${CFLAGS-"-fPIC -O3"}
+ CFLAGS="$cflags"
+ case `(uname -s || echo unknown) 2>/dev/null` in
+ Linux | linux | GNU | GNU/*) LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1"};;
+ CYGWIN* | Cygwin* | cygwin* )
+ EXE='.exe';;
+ QNX*) # This is for QNX6. I suppose that the QNX rule below is for QNX2,QNX4
+ # (alain.bonnefoy@icbt.com)
+ LDSHARED=${LDSHARED-"$cc -shared -Wl,-hlibz.so.1"};;
+ HP-UX*) LDSHARED=${LDSHARED-"$cc -shared $SFLAGS"}
+ shared_ext='.sl'
+ SHAREDLIB='libz.sl';;
+ Darwin*) shared_ext='.dylib'
+ SHAREDLIB=libz$shared_ext
+ SHAREDLIBV=libz.$VER$shared_ext
+ SHAREDLIBM=libz.$VER1$shared_ext
+ LDSHARED=${LDSHARED-"$cc -dynamiclib -install_name /usr/lib/$SHAREDLIBV -compatibility_version $VER2 -current_version $VER"}
+ libdir='/usr/lib'
+ includedir='/usr/include';;
+ *) LDSHARED=${LDSHARED-"$cc -shared"};;
+ esac
+else
+ # find system name and corresponding cc options
+ CC=${CC-cc}
+ case `(uname -sr || echo unknown) 2>/dev/null` in
+ HP-UX*) SFLAGS=${CFLAGS-"-O +z"}
+ CFLAGS=${CFLAGS-"-O"}
+# LDSHARED=${LDSHARED-"ld -b +vnocompatwarnings"}
+ LDSHARED=${LDSHARED-"ld -b"}
+ shared_ext='.sl'
+ SHAREDLIB='libz.sl';;
+ IRIX*) SFLAGS=${CFLAGS-"-ansi -O2 -rpath ."}
+ CFLAGS=${CFLAGS-"-ansi -O2"}
+ LDSHARED=${LDSHARED-"cc -shared"};;
+ OSF1\ V4*) SFLAGS=${CFLAGS-"-O -std1"}
+ CFLAGS=${CFLAGS-"-O -std1"}
+ LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so -Wl,-msym -Wl,-rpath,$(libdir) -Wl,-set_version,${VER}:1.0"};;
+ OSF1*) SFLAGS=${CFLAGS-"-O -std1"}
+ CFLAGS=${CFLAGS-"-O -std1"}
+ LDSHARED=${LDSHARED-"cc -shared"};;
+ QNX*) SFLAGS=${CFLAGS-"-4 -O"}
+ CFLAGS=${CFLAGS-"-4 -O"}
+ LDSHARED=${LDSHARED-"cc"}
+ RANLIB=${RANLIB-"true"}
+ AR="cc -A";;
+ SCO_SV\ 3.2*) SFLAGS=${CFLAGS-"-O3 -dy -KPIC "}
+ CFLAGS=${CFLAGS-"-O3"}
+ LDSHARED=${LDSHARED-"cc -dy -KPIC -G"};;
+ SunOS\ 5*) SFLAGS=${CFLAGS-"-fast -xcg89 -KPIC -R."}
+ CFLAGS=${CFLAGS-"-fast -xcg89"}
+ LDSHARED=${LDSHARED-"cc -G"};;
+ SunOS\ 4*) SFLAGS=${CFLAGS-"-O2 -PIC"}
+ CFLAGS=${CFLAGS-"-O2"}
+ LDSHARED=${LDSHARED-"ld"};;
+ UNIX_System_V\ 4.2.0)
+ SFLAGS=${CFLAGS-"-KPIC -O"}
+ CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"cc -G"};;
+ UNIX_SV\ 4.2MP)
+ SFLAGS=${CFLAGS-"-Kconform_pic -O"}
+ CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"cc -G"};;
+ OpenUNIX\ 5)
+ SFLAGS=${CFLAGS-"-KPIC -O"}
+ CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"cc -G"};;
+ AIX*) # Courtesy of dbakker@arrayasolutions.com
+ SFLAGS=${CFLAGS-"-O -qmaxmem=8192"}
+ CFLAGS=${CFLAGS-"-O -qmaxmem=8192"}
+ LDSHARED=${LDSHARED-"xlc -G"};;
+ # send working options for other systems to support@gzip.org
+ *) SFLAGS=${CFLAGS-"-O"}
+ CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"cc -shared"};;
+ esac
+fi
+
+SHAREDLIB=${SHAREDLIB-"libz$shared_ext"}
+SHAREDLIBV=${SHAREDLIBV-"libz$shared_ext.$VER"}
+SHAREDLIBM=${SHAREDLIBM-"libz$shared_ext.$VER1"}
+
+if test $shared -eq 1; then
+ echo Checking for shared library support...
+ # we must test in two steps (cc then ld), required at least on SunOS 4.x
+ if test "`($CC -c $SFLAGS $test.c) 2>&1`" = "" &&
+ test "`($LDSHARED -o $test$shared_ext $test.o) 2>&1`" = ""; then
+ CFLAGS="$SFLAGS"
+ LIBS="$SHAREDLIBV"
+ echo Building shared library $SHAREDLIBV with $CC.
+ elif test -z "$old_cc" -a -z "$old_cflags"; then
+ echo No shared library support.
+ shared=0;
+ else
+ echo 'No shared library support; try without defining CC and CFLAGS'
+ shared=0;
+ fi
+fi
+if test $shared -eq 0; then
+ LDSHARED="$CC"
+ echo Building static library $LIBS version $VER with $CC.
+else
+ LDFLAGS="-L. ${SHAREDLIBV}"
+fi
+
+cat > $test.c <<EOF
+#include <unistd.h>
+int main() { return 0; }
+EOF
+if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ sed < zconf.in.h "/HAVE_UNISTD_H/s%0%1%" > zconf.h
+ echo "Checking for unistd.h... Yes."
+else
+ cp -p zconf.in.h zconf.h
+ echo "Checking for unistd.h... No."
+fi
+
+cat > $test.c <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+#include "zconf.h"
+
+int main()
+{
+#ifndef STDC
+ choke me
+#endif
+
+ return 0;
+}
+EOF
+
+if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ echo "Checking whether to use vs[n]printf() or s[n]printf()... using vs[n]printf()"
+
+ cat > $test.c <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+
+int mytest(char *fmt, ...)
+{
+ char buf[20];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ return 0;
+}
+
+int main()
+{
+ return (mytest("Hello%d\n", 1));
+}
+EOF
+
+ if test "`($CC $CFLAGS -o $test $test.c) 2>&1`" = ""; then
+ echo "Checking for vsnprintf() in stdio.h... Yes."
+
+ cat >$test.c <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+
+int mytest(char *fmt, ...)
+{
+ int n;
+ char buf[20];
+ va_list ap;
+
+ va_start(ap, fmt);
+ n = vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ return n;
+}
+
+int main()
+{
+ return (mytest("Hello%d\n", 1));
+}
+EOF
+
+ if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ echo "Checking for return value of vsnprintf()... Yes."
+ else
+ CFLAGS="$CFLAGS -DHAS_vsnprintf_void"
+ echo "Checking for return value of vsnprintf()... No."
+ echo " WARNING: apparently vsnprintf() does not return a value. zlib"
+ echo " can build but will be open to possible string-format security"
+ echo " vulnerabilities."
+ fi
+ else
+ CFLAGS="$CFLAGS -DNO_vsnprintf"
+ echo "Checking for vsnprintf() in stdio.h... No."
+ echo " WARNING: vsnprintf() not found, falling back to vsprintf(). zlib"
+ echo " can build but will be open to possible buffer-overflow security"
+ echo " vulnerabilities."
+
+ cat >$test.c <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+
+int mytest(char *fmt, ...)
+{
+ int n;
+ char buf[20];
+ va_list ap;
+
+ va_start(ap, fmt);
+ n = vsprintf(buf, fmt, ap);
+ va_end(ap);
+ return n;
+}
+
+int main()
+{
+ return (mytest("Hello%d\n", 1));
+}
+EOF
+
+ if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ echo "Checking for return value of vsprintf()... Yes."
+ else
+ CFLAGS="$CFLAGS -DHAS_vsprintf_void"
+ echo "Checking for return value of vsprintf()... No."
+ echo " WARNING: apparently vsprintf() does not return a value. zlib"
+ echo " can build but will be open to possible string-format security"
+ echo " vulnerabilities."
+ fi
+ fi
+else
+ echo "Checking whether to use vs[n]printf() or s[n]printf()... using s[n]printf()"
+
+ cat >$test.c <<EOF
+#include <stdio.h>
+
+int mytest()
+{
+ char buf[20];
+
+ snprintf(buf, sizeof(buf), "%s", "foo");
+ return 0;
+}
+
+int main()
+{
+ return (mytest());
+}
+EOF
+
+ if test "`($CC $CFLAGS -o $test $test.c) 2>&1`" = ""; then
+ echo "Checking for snprintf() in stdio.h... Yes."
+
+ cat >$test.c <<EOF
+#include <stdio.h>
+
+int mytest()
+{
+ char buf[20];
+
+ return snprintf(buf, sizeof(buf), "%s", "foo");
+}
+
+int main()
+{
+ return (mytest());
+}
+EOF
+
+ if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ echo "Checking for return value of snprintf()... Yes."
+ else
+ CFLAGS="$CFLAGS -DHAS_snprintf_void"
+ echo "Checking for return value of snprintf()... No."
+ echo " WARNING: apparently snprintf() does not return a value. zlib"
+ echo " can build but will be open to possible string-format security"
+ echo " vulnerabilities."
+ fi
+ else
+ CFLAGS="$CFLAGS -DNO_snprintf"
+ echo "Checking for snprintf() in stdio.h... No."
+ echo " WARNING: snprintf() not found, falling back to sprintf(). zlib"
+ echo " can build but will be open to possible buffer-overflow security"
+ echo " vulnerabilities."
+
+ cat >$test.c <<EOF
+#include <stdio.h>
+
+int mytest()
+{
+ char buf[20];
+
+ return sprintf(buf, "%s", "foo");
+}
+
+int main()
+{
+ return (mytest());
+}
+EOF
+
+ if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ echo "Checking for return value of sprintf()... Yes."
+ else
+ CFLAGS="$CFLAGS -DHAS_sprintf_void"
+ echo "Checking for return value of sprintf()... No."
+ echo " WARNING: apparently sprintf() does not return a value. zlib"
+ echo " can build but will be open to possible string-format security"
+ echo " vulnerabilities."
+ fi
+ fi
+fi
+
+cat >$test.c <<EOF
+#include <errno.h>
+int main() { return 0; }
+EOF
+if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ echo "Checking for errno.h... Yes."
+else
+ echo "Checking for errno.h... No."
+ CFLAGS="$CFLAGS -DNO_ERRNO_H"
+fi
+
+cat > $test.c <<EOF
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+caddr_t hello() {
+ return mmap((caddr_t)0, (off_t)0, PROT_READ, MAP_SHARED, 0, (off_t)0);
+}
+EOF
+if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ CFLAGS="$CFLAGS -DUSE_MMAP"
+ echo Checking for mmap support... Yes.
+else
+ echo Checking for mmap support... No.
+fi
+
+CPP=${CPP-"$CC -E"}
+case $CFLAGS in
+ *ASMV*)
+ if test "`nm $test.o | grep _hello`" = ""; then
+ CPP="$CPP -DNO_UNDERLINE"
+ echo Checking for underline in external names... No.
+ else
+ echo Checking for underline in external names... Yes.
+ fi;;
+esac
+
+rm -f $test.[co] $test $test$shared_ext
+
+# udpate Makefile
+sed < Makefile.in "
+/^CC *=/s#=.*#=$CC#
+/^CFLAGS *=/s#=.*#=$CFLAGS#
+/^CPP *=/s#=.*#=$CPP#
+/^LDSHARED *=/s#=.*#=$LDSHARED#
+/^LIBS *=/s#=.*#=$LIBS#
+/^SHAREDLIB *=/s#=.*#=$SHAREDLIB#
+/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV#
+/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM#
+/^AR *=/s#=.*#=$AR#
+/^RANLIB *=/s#=.*#=$RANLIB#
+/^EXE *=/s#=.*#=$EXE#
+/^prefix *=/s#=.*#=$prefix#
+/^exec_prefix *=/s#=.*#=$exec_prefix#
+/^libdir *=/s#=.*#=$libdir#
+/^includedir *=/s#=.*#=$includedir#
+/^mandir *=/s#=.*#=$mandir#
+/^LDFLAGS *=/s#=.*#=$LDFLAGS#
+" > Makefile
--- /dev/null
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors. This results about a factor
+ * of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* @(#) $Id: crc32.c,v 1.1 2005/01/12 07:44:59 mmondor Exp $ */
+
+#ifdef MAKECRCH
+# include <stdio.h>
+# ifndef DYNAMIC_CRC_TABLE
+# define DYNAMIC_CRC_TABLE
+# endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h" /* for STDC and FAR definitions */
+
+#define local static
+
+/* Find a four-byte integer type for crc32_little() and crc32_big(). */
+#ifndef NOBYFOUR
+# ifdef STDC /* need ANSI C limits.h to determine sizes */
+# include <limits.h>
+# define BYFOUR
+# if (UINT_MAX == 0xffffffffUL)
+ typedef unsigned int u4;
+# else
+# if (ULONG_MAX == 0xffffffffUL)
+ typedef unsigned long u4;
+# else
+# if (USHRT_MAX == 0xffffffffUL)
+ typedef unsigned short u4;
+# else
+# undef BYFOUR /* can't find a four-byte integer type! */
+# endif
+# endif
+# endif
+# endif /* STDC */
+#endif /* !NOBYFOUR */
+
+/* Definitions for doing the crc four data bytes at a time. */
+#ifdef BYFOUR
+# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \
+ (((w)&0xff00)<<8)+(((w)&0xff)<<24))
+ local unsigned long crc32_little OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+ local unsigned long crc32_big OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+# define TBLS 8
+#else
+# define TBLS 1
+#endif /* BYFOUR */
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local int crc_table_empty = 1;
+local unsigned long FAR crc_table[TBLS][256];
+local void make_crc_table OF((void));
+#ifdef MAKECRCH
+ local void write_table OF((FILE *, const unsigned long FAR *));
+#endif /* MAKECRCH */
+
+/*
+ Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+ x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+ Polynomials over GF(2) are represented in binary, one bit per coefficient,
+ with the lowest powers in the most significant bit. Then adding polynomials
+ is just exclusive-or, and multiplying a polynomial by x is a right shift by
+ one. If we call the above polynomial p, and represent a byte as the
+ polynomial q, also with the lowest power in the most significant bit (so the
+ byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+ where a mod b means the remainder after dividing a by b.
+
+ This calculation is done using the shift-register method of multiplying and
+ taking the remainder. The register is initialized to zero, and for each
+ incoming bit, x^32 is added mod p to the register if the bit is a one (where
+ x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+ x (which is shifting right by one and adding x^32 mod p if the bit shifted
+ out is a one). We start with the highest power (least significant bit) of
+ q and repeat for all eight bits of q.
+
+ The first table is simply the CRC of all possible eight bit values. This is
+ all the information needed to generate CRCs on data a byte at a time for all
+ combinations of CRC register values and incoming bytes. The remaining tables
+ allow for word-at-a-time CRC calculation for both big-endian and little-
+ endian machines, where a word is four bytes.
+*/
+local void make_crc_table()
+{
+ unsigned long c;
+ int n, k;
+ unsigned long poly; /* polynomial exclusive-or pattern */
+ /* terms of polynomial defining this crc (except x^32): */
+ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* make exclusive-or pattern from polynomial (0xedb88320UL) */
+ poly = 0UL;
+ for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)
+ poly |= 1UL << (31 - p[n]);
+
+ /* generate a crc for every 8-bit value */
+ for (n = 0; n < 256; n++) {
+ c = (unsigned long)n;
+ for (k = 0; k < 8; k++)
+ c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+ crc_table[0][n] = c;
+ }
+
+#ifdef BYFOUR
+ /* generate crc for each value followed by one, two, and three zeros, and
+ then the byte reversal of those as well as the first table */
+ for (n = 0; n < 256; n++) {
+ c = crc_table[0][n];
+ crc_table[4][n] = REV(c);
+ for (k = 1; k < 4; k++) {
+ c = crc_table[0][c & 0xff] ^ (c >> 8);
+ crc_table[k][n] = c;
+ crc_table[k + 4][n] = REV(c);
+ }
+ }
+#endif /* BYFOUR */
+
+ crc_table_empty = 0;
+
+#ifdef MAKECRCH
+ /* write out CRC tables to crc32.h */
+ {
+ FILE *out;
+
+ out = fopen("crc32.h", "w");
+ if (out == NULL) return;
+ fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
+ fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
+ fprintf(out, "local const unsigned long FAR ");
+ fprintf(out, "crc_table[TBLS][256] =\n{\n {\n");
+ write_table(out, crc_table[0]);
+# ifdef BYFOUR
+ fprintf(out, "#ifdef BYFOUR\n");
+ for (k = 1; k < 8; k++) {
+ fprintf(out, " },\n {\n");
+ write_table(out, crc_table[k]);
+ }
+ fprintf(out, "#endif\n");
+# endif /* BYFOUR */
+ fprintf(out, " }\n};\n");
+ fclose(out);
+ }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+local void write_table(out, table)
+ FILE *out;
+ const unsigned long FAR *table;
+{
+ int n;
+
+ for (n = 0; n < 256; n++)
+ fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n],
+ n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
+}
+#endif /* MAKECRCH */
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables of CRC-32s of all single-byte values, made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const unsigned long FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty) make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+ return (const unsigned long FAR *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ if (buf == Z_NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+ if (sizeof(void *) == sizeof(ptrdiff_t)) {
+ u4 endian;
+
+ endian = 1;
+ if (*((unsigned char *)(&endian)))
+ return crc32_little(crc, buf, len);
+ else
+ return crc32_big(crc, buf, len);
+ }
+#endif /* BYFOUR */
+ crc = crc ^ 0xffffffffUL;
+ while (len >= 8) {
+ DO8;
+ len -= 8;
+ }
+ if (len) do {
+ DO1;
+ } while (--len);
+ return crc ^ 0xffffffffUL;
+}
+
+#ifdef BYFOUR
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = (u4)crc;
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)buf;
+ while (len >= 32) {
+ DOLIT32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOLIT4;
+ len -= 4;
+ }
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *++buf4; \
+ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = REV((u4)crc);
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)buf;
+ buf4--;
+ while (len >= 32) {
+ DOBIG32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOBIG4;
+ len -= 4;
+ }
+ buf4++;
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)(REV(c));
+}
+
+#endif /* BYFOUR */
--- /dev/null
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const unsigned long FAR crc_table[TBLS][256] =
+{
+ {
+ 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+ 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+ 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+ 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+ 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+ 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+ 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+ 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+ 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+ 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+ 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+ 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+ 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+ 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+ 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+ 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+ 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+ 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+ 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+ 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+ 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+ 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+ 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+ 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+ 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+ 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+ 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+ 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+ 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+ 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+ 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+ 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+ 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+ 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+ 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+ 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+ 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+ 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+ 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+ 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+ 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+ 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+ 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+ 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+ 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+ 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+ 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+ 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+ 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+ 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+ 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+ 0x2d02ef8dUL
+#ifdef BYFOUR
+ },
+ {
+ 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+ 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+ 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+ 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+ 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+ 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+ 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+ 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+ 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+ 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+ 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+ 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+ 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+ 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+ 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+ 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+ 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+ 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+ 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+ 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+ 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+ 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+ 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+ 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+ 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+ 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+ 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+ 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+ 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+ 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+ 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+ 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+ 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+ 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+ 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+ 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+ 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+ 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+ 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+ 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+ 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+ 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+ 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+ 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+ 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+ 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+ 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+ 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+ 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+ 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+ 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+ 0x9324fd72UL
+ },
+ {
+ 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+ 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+ 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+ 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+ 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+ 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+ 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+ 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+ 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+ 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+ 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+ 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+ 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+ 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+ 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+ 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+ 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+ 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+ 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+ 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+ 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+ 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+ 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+ 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+ 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+ 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+ 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+ 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+ 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+ 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+ 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+ 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+ 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+ 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+ 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+ 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+ 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+ 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+ 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+ 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+ 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+ 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+ 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+ 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+ 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+ 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+ 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+ 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+ 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+ 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+ 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+ 0xbe9834edUL
+ },
+ {
+ 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+ 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+ 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+ 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+ 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+ 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+ 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+ 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+ 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+ 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+ 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+ 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+ 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+ 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+ 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+ 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+ 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+ 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+ 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+ 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+ 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+ 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+ 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+ 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+ 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+ 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+ 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+ 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+ 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+ 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+ 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+ 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+ 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+ 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+ 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+ 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+ 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+ 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+ 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+ 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+ 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+ 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+ 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+ 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+ 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+ 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+ 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+ 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+ 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+ 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+ 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+ 0xde0506f1UL
+ },
+ {
+ 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+ 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+ 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+ 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+ 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+ 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+ 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+ 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+ 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+ 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+ 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+ 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+ 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+ 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+ 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+ 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+ 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+ 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+ 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+ 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+ 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+ 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+ 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+ 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+ 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+ 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+ 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+ 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+ 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+ 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+ 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+ 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+ 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+ 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+ 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+ 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+ 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+ 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+ 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+ 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+ 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+ 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+ 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+ 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+ 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+ 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+ 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+ 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+ 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+ 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+ 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+ 0x8def022dUL
+ },
+ {
+ 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+ 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+ 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+ 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+ 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+ 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+ 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+ 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+ 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+ 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+ 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+ 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+ 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+ 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+ 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+ 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+ 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+ 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+ 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+ 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+ 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+ 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+ 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+ 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+ 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+ 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+ 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+ 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+ 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+ 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+ 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+ 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+ 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+ 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+ 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+ 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+ 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+ 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+ 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+ 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+ 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+ 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+ 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+ 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+ 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+ 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+ 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+ 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+ 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+ 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+ 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+ 0x72fd2493UL
+ },
+ {
+ 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+ 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+ 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+ 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+ 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+ 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+ 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+ 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+ 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+ 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+ 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+ 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+ 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+ 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+ 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+ 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+ 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+ 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+ 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+ 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+ 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+ 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+ 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+ 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+ 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+ 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+ 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+ 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+ 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+ 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+ 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+ 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+ 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+ 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+ 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+ 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+ 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+ 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+ 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+ 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+ 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+ 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+ 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+ 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+ 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+ 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+ 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+ 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+ 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+ 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+ 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+ 0xed3498beUL
+ },
+ {
+ 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+ 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+ 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+ 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+ 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+ 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+ 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+ 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+ 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+ 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+ 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+ 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+ 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+ 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+ 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+ 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+ 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+ 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+ 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+ 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+ 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+ 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+ 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+ 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+ 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+ 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+ 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+ 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+ 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+ 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+ 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+ 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+ 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+ 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+ 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+ 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+ 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+ 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+ 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+ 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+ 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+ 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+ 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+ 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+ 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+ 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+ 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+ 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+ 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+ 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+ 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+ 0xf10605deUL
+#endif
+ }
+};
--- /dev/null
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process depends on being able to identify portions
+ * of the input text which are identical to earlier input (within a
+ * sliding window trailing behind the input currently being processed).
+ *
+ * The most straightforward technique turns out to be the fastest for
+ * most input files: try all possible matches and select the longest.
+ * The key feature of this algorithm is that insertions into the string
+ * dictionary are very simple and thus fast, and deletions are avoided
+ * completely. Insertions are performed at each input character, whereas
+ * string matches are performed only when the previous match ends. So it
+ * is preferable to spend more time in matches to allow very fast string
+ * insertions and avoid deletions. The matching algorithm for small
+ * strings is inspired from that of Rabin & Karp. A brute force approach
+ * is used to find longer strings when a small match has been found.
+ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ * (by Leonid Broukhis).
+ * A previous version of this file used a more sophisticated algorithm
+ * (by Fiala and Greene) which is guaranteed to run in linear amortized
+ * time, but has a larger average cost, uses more memory and is patented.
+ * However the F&G algorithm may be faster for some highly redundant
+ * files if the parameter max_chain_length (described below) is too large.
+ *
+ * ACKNOWLEDGEMENTS
+ *
+ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ * I found it in 'freeze' written by Leonid Broukhis.
+ * Thanks to many people for bug reports and testing.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ * Available in http://www.ietf.org/rfc/rfc1951.txt
+ *
+ * A description of the Rabin and Karp algorithm is given in the book
+ * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ * Fiala,E.R., and Greene,D.H.
+ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id: deflate.c,v 1.1 2005/01/12 07:44:59 mmondor Exp $ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+ " deflate 1.2.1 Copyright 1995-2003 Jean-loup Gailly ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ * Function prototypes.
+ */
+typedef enum {
+ need_more, /* block not completed, need more input or more output */
+ block_done, /* block flush performed */
+ finish_started, /* finish started, need only more output at next deflate */
+ finish_done /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast OF((deflate_state *s, int flush));
+#ifndef FASTEST
+local block_state deflate_slow OF((deflate_state *s, int flush));
+#endif
+local void lm_init OF((deflate_state *s));
+local void putShortMSB OF((deflate_state *s, uInt b));
+local void flush_pending OF((z_streamp strm));
+local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifndef FASTEST
+#ifdef ASMV
+ void match_init OF((void)); /* asm code initialization */
+ uInt longest_match OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match OF((deflate_state *s, IPos cur_match));
+#endif
+#endif
+local uInt longest_match_fast OF((deflate_state *s, IPos cur_match));
+
+#ifdef DEBUG
+local void check_match OF((deflate_state *s, IPos start, IPos match,
+ int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+ ush good_length; /* reduce lazy search above this match length */
+ ush max_lazy; /* do not perform lazy search above this match length */
+ ush nice_length; /* quit search above this match length */
+ ush max_chain;
+ compress_func func;
+} config;
+
+#ifdef FASTEST
+local const config configuration_table[2] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */
+#else
+local const config configuration_table[10] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */
+/* 2 */ {4, 5, 16, 8, deflate_fast},
+/* 3 */ {4, 6, 32, 32, deflate_fast},
+
+/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */
+/* 5 */ {8, 16, 32, 32, deflate_slow},
+/* 6 */ {8, 16, 128, 128, deflate_slow},
+/* 7 */ {8, 32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */
+#endif
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of str are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+ s->head[s->hash_size-1] = NIL; \
+ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+ z_streamp strm;
+ int level;
+ const char *version;
+ int stream_size;
+{
+ return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY, version, stream_size);
+ /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+ version, stream_size)
+ z_streamp strm;
+ int level;
+ int method;
+ int windowBits;
+ int memLevel;
+ int strategy;
+ const char *version;
+ int stream_size;
+{
+ deflate_state *s;
+ int wrap = 1;
+ static const char my_version[] = ZLIB_VERSION;
+
+ ushf *overlay;
+ /* We overlay pending_buf and d_buf+l_buf. This works since the average
+ * output size for (length,distance) codes is <= 24 bits.
+ */
+
+ if (version == Z_NULL || version[0] != my_version[0] ||
+ stream_size != sizeof(z_stream)) {
+ return Z_VERSION_ERROR;
+ }
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->msg = Z_NULL;
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+
+ if (windowBits < 0) { /* suppress zlib wrapper */
+ wrap = 0;
+ windowBits = -windowBits;
+ }
+#ifdef GZIP
+ else if (windowBits > 15) {
+ wrap = 2; /* write gzip wrapper instead */
+ windowBits -= 16;
+ }
+#endif
+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+ windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+ strategy < 0 || strategy > Z_RLE) {
+ return Z_STREAM_ERROR;
+ }
+ if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */
+ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+ if (s == Z_NULL) return Z_MEM_ERROR;
+ strm->state = (struct internal_state FAR *)s;
+ s->strm = strm;
+
+ s->wrap = wrap;
+ s->w_bits = windowBits;
+ s->w_size = 1 << s->w_bits;
+ s->w_mask = s->w_size - 1;
+
+ s->hash_bits = memLevel + 7;
+ s->hash_size = 1 << s->hash_bits;
+ s->hash_mask = s->hash_size - 1;
+ s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+ s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+ s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
+ s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+ s->pending_buf = (uchf *) overlay;
+ s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+ if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+ s->pending_buf == Z_NULL) {
+ s->status = FINISH_STATE;
+ strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+ deflateEnd (strm);
+ return Z_MEM_ERROR;
+ }
+ s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+ s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+ s->level = level;
+ s->strategy = strategy;
+ s->method = (Byte)method;
+
+ return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+ z_streamp strm;
+ const Bytef *dictionary;
+ uInt dictLength;
+{
+ deflate_state *s;
+ uInt length = dictLength;
+ uInt n;
+ IPos hash_head = 0;
+
+ if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
+ strm->state->wrap == 2 ||
+ (strm->state->wrap == 1 && strm->state->status != INIT_STATE))
+ return Z_STREAM_ERROR;
+
+ s = strm->state;
+ if (s->wrap)
+ strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+ if (length < MIN_MATCH) return Z_OK;
+ if (length > MAX_DIST(s)) {
+ length = MAX_DIST(s);
+#ifndef USE_DICT_HEAD
+ dictionary += dictLength - length; /* use the tail of the dictionary */
+#endif
+ }
+ zmemcpy(s->window, dictionary, length);
+ s->strstart = length;
+ s->block_start = (long)length;
+
+ /* Insert all strings in the hash table (except for the last two bytes).
+ * s->lookahead stays null, so s->ins_h will be recomputed at the next
+ * call of fill_window.
+ */
+ s->ins_h = s->window[0];
+ UPDATE_HASH(s, s->ins_h, s->window[1]);
+ for (n = 0; n <= length - MIN_MATCH; n++) {
+ INSERT_STRING(s, n, hash_head);
+ }
+ if (hash_head) hash_head = 0; /* to make compiler happy */
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+ z_streamp strm;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) {
+ return Z_STREAM_ERROR;
+ }
+
+ strm->total_in = strm->total_out = 0;
+ strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+ strm->data_type = Z_UNKNOWN;
+
+ s = (deflate_state *)strm->state;
+ s->pending = 0;
+ s->pending_out = s->pending_buf;
+
+ if (s->wrap < 0) {
+ s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
+ }
+ s->status = s->wrap ? INIT_STATE : BUSY_STATE;
+ strm->adler =
+#ifdef GZIP
+ s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
+#endif
+ adler32(0L, Z_NULL, 0);
+ s->last_flush = Z_NO_FLUSH;
+
+ _tr_init(s);
+ lm_init(s);
+
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePrime (strm, bits, value)
+ z_streamp strm;
+ int bits;
+ int value;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ strm->state->bi_valid = bits;
+ strm->state->bi_buf = (ush)(value & ((1 << bits) - 1));
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+ z_streamp strm;
+ int level;
+ int strategy;
+{
+ deflate_state *s;
+ compress_func func;
+ int err = Z_OK;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+ if (level < 0 || level > 9 || strategy < 0 || strategy > Z_RLE) {
+ return Z_STREAM_ERROR;
+ }
+ func = configuration_table[s->level].func;
+
+ if (func != configuration_table[level].func && strm->total_in != 0) {
+ /* Flush the last buffer: */
+ err = deflate(strm, Z_PARTIAL_FLUSH);
+ }
+ if (s->level != level) {
+ s->level = level;
+ s->max_lazy_match = configuration_table[level].max_lazy;
+ s->good_match = configuration_table[level].good_length;
+ s->nice_match = configuration_table[level].nice_length;
+ s->max_chain_length = configuration_table[level].max_chain;
+ }
+ s->strategy = strategy;
+ return err;
+}
+
+/* =========================================================================
+ * For the default windowBits of 15 and memLevel of 8, this function returns
+ * a close to exact, as well as small, upper bound on the compressed size.
+ * They are coded as constants here for a reason--if the #define's are
+ * changed, then this function needs to be changed as well. The return
+ * value for 15 and 8 only works for those exact settings.
+ *
+ * For any setting other than those defaults for windowBits and memLevel,
+ * the value returned is a conservative worst case for the maximum expansion
+ * resulting from using fixed blocks instead of stored blocks, which deflate
+ * can emit on compressed data for some combinations of the parameters.
+ *
+ * This function could be more sophisticated to provide closer upper bounds
+ * for every combination of windowBits and memLevel, as well as wrap.
+ * But even the conservative upper bound of about 14% expansion does not
+ * seem onerous for output buffer allocation.
+ */
+uLong ZEXPORT deflateBound(strm, sourceLen)
+ z_streamp strm;
+ uLong sourceLen;
+{
+ deflate_state *s;
+ uLong destLen;
+
+ /* conservative upper bound */
+ destLen = sourceLen +
+ ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11;
+
+ /* if can't get parameters, return conservative bound */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return destLen;
+
+ /* if not default parameters, return conservative bound */
+ s = strm->state;
+ if (s->w_bits != 15 || s->hash_bits != 8 + 7)
+ return destLen;
+
+ /* default settings: return tight bound for that case */
+ return compressBound(sourceLen);
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+ deflate_state *s;
+ uInt b;
+{
+ put_byte(s, (Byte)(b >> 8));
+ put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+ z_streamp strm;
+{
+ unsigned len = strm->state->pending;
+
+ if (len > strm->avail_out) len = strm->avail_out;
+ if (len == 0) return;
+
+ zmemcpy(strm->next_out, strm->state->pending_out, len);
+ strm->next_out += len;
+ strm->state->pending_out += len;
+ strm->total_out += len;
+ strm->avail_out -= len;
+ strm->state->pending -= len;
+ if (strm->state->pending == 0) {
+ strm->state->pending_out = strm->state->pending_buf;
+ }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+ z_streamp strm;
+ int flush;
+{
+ int old_flush; /* value of flush param for previous deflate call */
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ flush > Z_FINISH || flush < 0) {
+ return Z_STREAM_ERROR;
+ }
+ s = strm->state;
+
+ if (strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+ (s->status == FINISH_STATE && flush != Z_FINISH)) {
+ ERR_RETURN(strm, Z_STREAM_ERROR);
+ }
+ if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+ s->strm = strm; /* just in case */
+ old_flush = s->last_flush;
+ s->last_flush = flush;
+
+ /* Write the header */
+ if (s->status == INIT_STATE) {
+#ifdef GZIP
+ if (s->wrap == 2) {
+ put_byte(s, 31);
+ put_byte(s, 139);
+ put_byte(s, 8);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, 255);
+ s->status = BUSY_STATE;
+ strm->adler = crc32(0L, Z_NULL, 0);
+ }
+ else
+#endif
+ {
+ uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+ uInt level_flags;
+
+ if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+ level_flags = 0;
+ else if (s->level < 6)
+ level_flags = 1;
+ else if (s->level == 6)
+ level_flags = 2;
+ else
+ level_flags = 3;
+ header |= (level_flags << 6);
+ if (s->strstart != 0) header |= PRESET_DICT;
+ header += 31 - (header % 31);
+
+ s->status = BUSY_STATE;
+ putShortMSB(s, header);
+
+ /* Save the adler32 of the preset dictionary: */
+ if (s->strstart != 0) {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ strm->adler = adler32(0L, Z_NULL, 0);
+ }
+ }
+
+ /* Flush as much pending output as possible */
+ if (s->pending != 0) {
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ /* Since avail_out is 0, deflate will be called again with
+ * more output space, but possibly with both pending and
+ * avail_in equal to zero. There won't be anything to do,
+ * but this is not an error situation so make sure we
+ * return OK instead of BUF_ERROR at next call of deflate:
+ */
+ s->last_flush = -1;
+ return Z_OK;
+ }
+
+ /* Make sure there is something to do and avoid duplicate consecutive
+ * flushes. For repeated and useless calls with Z_FINISH, we keep
+ * returning Z_STREAM_END instead of Z_BUF_ERROR.
+ */
+ } else if (strm->avail_in == 0 && flush <= old_flush &&
+ flush != Z_FINISH) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* User must not provide more input after the first FINISH: */
+ if (s->status == FINISH_STATE && strm->avail_in != 0) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* Start a new block or continue the current one.
+ */
+ if (strm->avail_in != 0 || s->lookahead != 0 ||
+ (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+ block_state bstate;
+
+ bstate = (*(configuration_table[s->level].func))(s, flush);
+
+ if (bstate == finish_started || bstate == finish_done) {
+ s->status = FINISH_STATE;
+ }
+ if (bstate == need_more || bstate == finish_started) {
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+ }
+ return Z_OK;
+ /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+ * of deflate should use the same flush parameter to make sure
+ * that the flush is complete. So we don't have to output an
+ * empty block here, this will be done at next call. This also
+ * ensures that for a very small output buffer, we emit at most
+ * one empty block.
+ */
+ }
+ if (bstate == block_done) {
+ if (flush == Z_PARTIAL_FLUSH) {
+ _tr_align(s);
+ } else { /* FULL_FLUSH or SYNC_FLUSH */
+ _tr_stored_block(s, (char*)0, 0L, 0);
+ /* For a full flush, this empty block will be recognized
+ * as a special marker by inflate_sync().
+ */
+ if (flush == Z_FULL_FLUSH) {
+ CLEAR_HASH(s); /* forget history */
+ }
+ }
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+ return Z_OK;
+ }
+ }
+ }
+ Assert(strm->avail_out > 0, "bug2");
+
+ if (flush != Z_FINISH) return Z_OK;
+ if (s->wrap <= 0) return Z_STREAM_END;
+
+ /* Write the trailer */
+#ifdef GZIP
+ if (s->wrap == 2) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 24) & 0xff));
+ put_byte(s, (Byte)(strm->total_in & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));
+ }
+ else
+#endif
+ {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ flush_pending(strm);
+ /* If avail_out is zero, the application will call deflate again
+ * to flush the rest.
+ */
+ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
+ return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+ z_streamp strm;
+{
+ int status;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+ status = strm->state->status;
+ if (status != INIT_STATE && status != BUSY_STATE &&
+ status != FINISH_STATE) {
+ return Z_STREAM_ERROR;
+ }
+
+ /* Deallocate in reverse order of allocations: */
+ TRY_FREE(strm, strm->state->pending_buf);
+ TRY_FREE(strm, strm->state->head);
+ TRY_FREE(strm, strm->state->prev);
+ TRY_FREE(strm, strm->state->window);
+
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+
+ return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+ z_streamp dest;
+ z_streamp source;
+{
+#ifdef MAXSEG_64K
+ return Z_STREAM_ERROR;
+#else
+ deflate_state *ds;
+ deflate_state *ss;
+ ushf *overlay;
+
+
+ if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+ return Z_STREAM_ERROR;
+ }
+
+ ss = source->state;
+
+ *dest = *source;
+
+ ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+ if (ds == Z_NULL) return Z_MEM_ERROR;
+ dest->state = (struct internal_state FAR *) ds;
+ *ds = *ss;
+ ds->strm = dest;
+
+ ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+ ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
+ ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
+ overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+ ds->pending_buf = (uchf *) overlay;
+
+ if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+ ds->pending_buf == Z_NULL) {
+ deflateEnd (dest);
+ return Z_MEM_ERROR;
+ }
+ /* following zmemcpy do not work for 16-bit MSDOS */
+ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+ zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+ zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+ zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+ ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+ ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+ ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+ ds->l_desc.dyn_tree = ds->dyn_ltree;
+ ds->d_desc.dyn_tree = ds->dyn_dtree;
+ ds->bl_desc.dyn_tree = ds->bl_tree;
+
+ return Z_OK;
+#endif /* MAXSEG_64K */
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read. All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+ z_streamp strm;
+ Bytef *buf;
+ unsigned size;
+{
+ unsigned len = strm->avail_in;
+
+ if (len > size) len = size;
+ if (len == 0) return 0;
+
+ strm->avail_in -= len;
+
+ if (strm->state->wrap == 1) {
+ strm->adler = adler32(strm->adler, strm->next_in, len);
+ }
+#ifdef GZIP
+ else if (strm->state->wrap == 2) {
+ strm->adler = crc32(strm->adler, strm->next_in, len);
+ }
+#endif
+ zmemcpy(buf, strm->next_in, len);
+ strm->next_in += len;
+ strm->total_in += len;
+
+ return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+ deflate_state *s;
+{
+ s->window_size = (ulg)2L*s->w_size;
+
+ CLEAR_HASH(s);
+
+ /* Set the default configuration parameters:
+ */
+ s->max_lazy_match = configuration_table[s->level].max_lazy;
+ s->good_match = configuration_table[s->level].good_length;
+ s->nice_match = configuration_table[s->level].nice_length;
+ s->max_chain_length = configuration_table[s->level].max_chain;
+
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->lookahead = 0;
+ s->match_length = s->prev_length = MIN_MATCH-1;
+ s->match_available = 0;
+ s->ins_h = 0;
+#ifdef ASMV
+ match_init(); /* initialize the asm code */
+#endif
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ unsigned chain_length = s->max_chain_length;/* max hash chain length */
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = s->prev_length; /* best match length so far */
+ int nice_match = s->nice_match; /* stop if match long enough */
+ IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+ s->strstart - (IPos)MAX_DIST(s) : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+ Posf *prev = s->prev;
+ uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ushf*)scan;
+ register ush scan_end = *(ushf*)(scan+best_len-1);
+#else
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+ register Byte scan_end1 = scan[best_len-1];
+ register Byte scan_end = scan[best_len];
+#endif
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ /* Do not waste too much time if we already have a good match: */
+ if (s->prev_length >= s->good_match) {
+ chain_length >>= 2;
+ }
+ /* Do not look for matches beyond the end of the input. This is necessary
+ * to make deflate deterministic.
+ */
+ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ do {
+ Assert(cur_match < s->strstart, "no future");
+ match = s->window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2:
+ */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+ /* This code assumes sizeof(unsigned short) == 2. Do not use
+ * UNALIGNED_OK if your compiler uses a different size.
+ */
+ if (*(ushf*)(match+best_len-1) != scan_end ||
+ *(ushf*)match != scan_start) continue;
+
+ /* It is not necessary to compare scan[2] and match[2] since they are
+ * always equal when the other bytes match, given that the hash keys
+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
+ * lookahead only every 4th comparison; the 128th check will be made
+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ * necessary to put more guard bytes at the end of the window, or
+ * to check more often for insufficient lookahead.
+ */
+ Assert(scan[2] == match[2], "scan[2]?");
+ scan++, match++;
+ do {
+ } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+ if (*scan == *match) scan++;
+
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+ if (match[best_len] != scan_end ||
+ match[best_len-1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if (len > best_len) {
+ s->match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+ scan_end = *(ushf*)(scan+best_len-1);
+#else
+ scan_end1 = scan[best_len-1];
+ scan_end = scan[best_len];
+#endif
+ }
+ } while ((cur_match = prev[cur_match & wmask]) > limit
+ && --chain_length != 0);
+
+ if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+ return s->lookahead;
+}
+#endif /* ASMV */
+#endif /* FASTEST */
+
+/* ---------------------------------------------------------------------------
+ * Optimized version for level == 1 or strategy == Z_RLE only
+ */
+local uInt longest_match_fast(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ Assert(cur_match < s->strstart, "no future");
+
+ match = s->window + cur_match;
+
+ /* Return failure if the match length is less than 2:
+ */
+ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match += 2;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+
+ if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+ s->match_start = cur_match;
+ return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
+}
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+ deflate_state *s;
+ IPos start, match;
+ int length;
+{
+ /* check that the match is indeed a match */
+ if (zmemcmp(s->window + match,
+ s->window + start, length) != EQUAL) {
+ fprintf(stderr, " start %u, match %u, length %d\n",
+ start, match, length);
+ do {
+ fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+ } while (--length != 0);
+ z_error("invalid match");
+ }
+ if (z_verbose > 1) {
+ fprintf(stderr,"\\[%d,%d]", start-match, length);
+ do { putc(s->window[start++], stderr); } while (--length != 0);
+ }
+}
+#else
+# define check_match(s, start, match, length)
+#endif /* DEBUG */
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ * At least one byte has been read, or avail_in == 0; reads are
+ * performed for at least two bytes (required for the zip translate_eol
+ * option -- not supported here).
+ */
+local void fill_window(s)
+ deflate_state *s;
+{
+ register unsigned n, m;
+ register Posf *p;
+ unsigned more; /* Amount of free space at the end of the window. */
+ uInt wsize = s->w_size;
+
+ do {
+ more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+ /* Deal with !@#$% 64K limit: */
+ if (sizeof(int) <= 2) {
+ if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+ more = wsize;
+
+ } else if (more == (unsigned)(-1)) {
+ /* Very unlikely, but possible on 16 bit machine if
+ * strstart == 0 && lookahead == 1 (input done a byte at time)
+ */
+ more--;
+ }
+ }
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ if (s->strstart >= wsize+MAX_DIST(s)) {
+
+ zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+ s->match_start -= wsize;
+ s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
+ s->block_start -= (long) wsize;
+
+ /* Slide the hash table (could be avoided with 32 bit values
+ at the expense of memory usage). We slide even when level == 0
+ to keep the hash table consistent if we switch back to level > 0
+ later. (Using level 0 permanently is not an optimal usage of
+ zlib, so we don't care about this pathological case.)
+ */
+ n = s->hash_size;
+ p = &s->head[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ } while (--n);
+
+ n = wsize;
+#ifndef FASTEST
+ p = &s->prev[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ } while (--n);
+#endif
+ more += wsize;
+ }
+ if (s->strm->avail_in == 0) return;
+
+ /* If there was no sliding:
+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ * more == window_size - lookahead - strstart
+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ * => more >= window_size - 2*WSIZE + 2
+ * In the BIG_MEM or MMAP case (not yet supported),
+ * window_size == input_size + MIN_LOOKAHEAD &&
+ * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ * Otherwise, window_size == 2*WSIZE so more >= 2.
+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+ */
+ Assert(more >= 2, "more < 2");
+
+ n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+ s->lookahead += n;
+
+ /* Initialize the hash value now that we have some input: */
+ if (s->lookahead >= MIN_MATCH) {
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ }
+ /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+ * but this is not important since only literal bytes will be emitted.
+ */
+
+ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, eof) { \
+ _tr_flush_block(s, (s->block_start >= 0L ? \
+ (charf *)&s->window[(unsigned)s->block_start] : \
+ (charf *)Z_NULL), \
+ (ulg)((long)s->strstart - s->block_start), \
+ (eof)); \
+ s->block_start = s->strstart; \
+ flush_pending(s->strm); \
+ Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+ FLUSH_BLOCK_ONLY(s, eof); \
+ if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+ * to pending_buf_size, and each stored block has a 5 byte header:
+ */
+ ulg max_block_size = 0xffff;
+ ulg max_start;
+
+ if (max_block_size > s->pending_buf_size - 5) {
+ max_block_size = s->pending_buf_size - 5;
+ }
+
+ /* Copy as much as possible from input to output: */
+ for (;;) {
+ /* Fill the window as much as possible: */
+ if (s->lookahead <= 1) {
+
+ Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+ s->block_start >= (long)s->w_size, "slide too late");
+
+ fill_window(s);
+ if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+ Assert(s->block_start >= 0L, "block gone");
+
+ s->strstart += s->lookahead;
+ s->lookahead = 0;
+
+ /* Emit a stored block if pending_buf will be full: */
+ max_start = s->block_start + max_block_size;
+ if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+ /* strstart == 0 is possible when wraparound on 16-bit machine */
+ s->lookahead = (uInt)(s->strstart - max_start);
+ s->strstart = (uInt)max_start;
+ FLUSH_BLOCK(s, 0);
+ }
+ /* Flush if we may have to slide, otherwise block_start may become
+ * negative and the data will be gone:
+ */
+ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+ FLUSH_BLOCK(s, 0);
+ }
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of the hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+#ifdef FASTEST
+ if ((s->strategy < Z_HUFFMAN_ONLY) ||
+ (s->strategy == Z_RLE && s->strstart - hash_head == 1)) {
+ s->match_length = longest_match_fast (s, hash_head);
+ }
+#else
+ if (s->strategy < Z_HUFFMAN_ONLY) {
+ s->match_length = longest_match (s, hash_head);
+ } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+ s->match_length = longest_match_fast (s, hash_head);
+ }
+#endif
+ /* longest_match() or longest_match_fast() sets match_start */
+ }
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->match_start, s->match_length);
+
+ _tr_tally_dist(s, s->strstart - s->match_start,
+ s->match_length - MIN_MATCH, bflush);
+
+ s->lookahead -= s->match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+#ifndef FASTEST
+ if (s->match_length <= s->max_insert_length &&
+ s->lookahead >= MIN_MATCH) {
+ s->match_length--; /* string at strstart already in table */
+ do {
+ s->strstart++;
+ INSERT_STRING(s, s->strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead.
+ */
+ } while (--s->match_length != 0);
+ s->strstart++;
+ } else
+#endif
+ {
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+ * matter since it will be recomputed at next deflate call.
+ */
+ }
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ /* Process the input block. */
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ s->prev_length = s->match_length, s->prev_match = s->match_start;
+ s->match_length = MIN_MATCH-1;
+
+ if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+ s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ if (s->strategy < Z_HUFFMAN_ONLY) {
+ s->match_length = longest_match (s, hash_head);
+ } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+ s->match_length = longest_match_fast (s, hash_head);
+ }
+ /* longest_match() or longest_match_fast() sets match_start */
+
+ if (s->match_length <= 5 && (s->strategy == Z_FILTERED
+#if TOO_FAR <= 32767
+ || (s->match_length == MIN_MATCH &&
+ s->strstart - s->match_start > TOO_FAR)
+#endif
+ )) {
+
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ s->match_length = MIN_MATCH-1;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+ uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+ /* Do not insert strings in hash table beyond this. */
+
+ check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+ _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+ s->prev_length - MIN_MATCH, bflush);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted. If there is not
+ * enough lookahead, the last two strings are not inserted in
+ * the hash table.
+ */
+ s->lookahead -= s->prev_length-1;
+ s->prev_length -= 2;
+ do {
+ if (++s->strstart <= max_insert) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+ } while (--s->prev_length != 0);
+ s->match_available = 0;
+ s->match_length = MIN_MATCH-1;
+ s->strstart++;
+
+ if (bflush) FLUSH_BLOCK(s, 0);
+
+ } else if (s->match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ if (bflush) {
+ FLUSH_BLOCK_ONLY(s, 0);
+ }
+ s->strstart++;
+ s->lookahead--;
+ if (s->strm->avail_out == 0) return need_more;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ s->match_available = 1;
+ s->strstart++;
+ s->lookahead--;
+ }
+ }
+ Assert (flush != Z_NO_FLUSH, "no flush?");
+ if (s->match_available) {
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ s->match_available = 0;
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif /* FASTEST */
--- /dev/null
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2002 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id: deflate.h,v 1.1 2005/01/12 07:44:59 mmondor Exp $ */
+
+#ifndef DEFLATE_H
+#define DEFLATE_H
+
+#include "zutil.h"
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer creation by deflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip encoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GZIP
+#endif
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS 256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES 30
+/* number of distance codes */
+
+#define BL_CODES 19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE 42
+#define BUSY_STATE 113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+typedef struct static_tree_desc_s static_tree_desc;
+
+typedef struct tree_desc_s {
+ ct_data *dyn_tree; /* the dynamic tree */
+ int max_code; /* largest code with non zero frequency */
+ static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+ z_streamp strm; /* pointer back to this zlib stream */
+ int status; /* as the name implies */
+ Bytef *pending_buf; /* output still pending */
+ ulg pending_buf_size; /* size of pending_buf */
+ Bytef *pending_out; /* next pending byte to output to the stream */
+ int pending; /* nb of bytes in the pending buffer */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ Byte data_type; /* UNKNOWN, BINARY or ASCII */
+ Byte method; /* STORED (for zip only) or DEFLATED */
+ int last_flush; /* value of flush param for previous deflate call */
+
+ /* used by deflate.c: */
+
+ uInt w_size; /* LZ77 window size (32K by default) */
+ uInt w_bits; /* log2(w_size) (8..16) */
+ uInt w_mask; /* w_size - 1 */
+
+ Bytef *window;
+ /* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least wSize
+ * bytes. With this organization, matches are limited to a distance of
+ * wSize-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: use the user input buffer as sliding window.
+ */
+
+ ulg window_size;
+ /* Actual size of window: 2*wSize, except when the user input buffer
+ * is directly used as sliding window.
+ */
+
+ Posf *prev;
+ /* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+ Posf *head; /* Heads of the hash chains or NIL. */
+
+ uInt ins_h; /* hash index of string to be inserted */
+ uInt hash_size; /* number of elements in hash table */
+ uInt hash_bits; /* log2(hash_size) */
+ uInt hash_mask; /* hash_size-1 */
+
+ uInt hash_shift;
+ /* Number of bits by which ins_h must be shifted at each input
+ * step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * hash_shift * MIN_MATCH >= hash_bits
+ */
+
+ long block_start;
+ /* Window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+ uInt match_length; /* length of best match */
+ IPos prev_match; /* previous match */
+ int match_available; /* set if previous match exists */
+ uInt strstart; /* start of string to insert */
+ uInt match_start; /* start of matching string */
+ uInt lookahead; /* number of valid bytes ahead in window */
+
+ uInt prev_length;
+ /* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ uInt max_chain_length;
+ /* To speed up deflation, hash chains are never searched beyond this
+ * length. A higher limit improves compression ratio but degrades the
+ * speed.
+ */
+
+ uInt max_lazy_match;
+ /* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+# define max_insert_length max_lazy_match
+ /* Insert new strings in the hash table only if the match length is not
+ * greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+ int level; /* compression level (1..9) */
+ int strategy; /* favor or force Huffman coding*/
+
+ uInt good_match;
+ /* Use a faster search when the previous match is longer than this */
+
+ int nice_match; /* Stop searching when current match exceeds this */
+
+ /* used by trees.c: */
+ /* Didn't use ct_data typedef below to supress compiler warning */
+ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
+
+ struct tree_desc_s l_desc; /* desc. for literal tree */
+ struct tree_desc_s d_desc; /* desc. for distance tree */
+ struct tree_desc_s bl_desc; /* desc. for bit length tree */
+
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+ int heap_len; /* number of elements in the heap */
+ int heap_max; /* element of largest frequency */
+ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+ uch depth[2*L_CODES+1];
+ /* Depth of each subtree used as tie breaker for trees of equal frequency
+ */
+
+ uchf *l_buf; /* buffer for literals or lengths */
+
+ uInt lit_bufsize;
+ /* Size of match buffer for literals/lengths. There are 4 reasons for
+ * limiting lit_bufsize to 64K:
+ * - frequencies can be kept in 16 bit counters
+ * - if compression is not successful for the first block, all input
+ * data is still in the window so we can still emit a stored block even
+ * when input comes from standard input. (This can also be done for
+ * all blocks if lit_bufsize is not greater than 32K.)
+ * - if compression is not successful for a file smaller than 64K, we can
+ * even emit a stored file instead of a stored block (saving 5 bytes).
+ * This is applicable only for zip (not gzip or zlib).
+ * - creating new Huffman trees less frequently may not provide fast
+ * adaptation to changes in the input data statistics. (Take for
+ * example a binary file with poorly compressible code followed by
+ * a highly compressible string table.) Smaller buffer sizes give
+ * fast adaptation but have of course the overhead of transmitting
+ * trees more frequently.
+ * - I can't count above 4
+ */
+
+ uInt last_lit; /* running index in l_buf */
+
+ ushf *d_buf;
+ /* Buffer for distances. To simplify the code, d_buf and l_buf have
+ * the same number of elements. To use different lengths, an extra flag
+ * array would be necessary.
+ */
+
+ ulg opt_len; /* bit length of current block with optimal trees */
+ ulg static_len; /* bit length of current block with static trees */
+ uInt matches; /* number of string matches in current block */
+ int last_eob_len; /* bit length of EOB code for last block */
+
+#ifdef DEBUG
+ ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
+#endif
+
+ ush bi_buf;
+ /* Output buffer. bits are inserted starting at the bottom (least
+ * significant bits).
+ */
+ int bi_valid;
+ /* Number of valid bits in bi_buf. All bits above the last valid bit
+ * are always zero.
+ */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+ /* in trees.c */
+void _tr_init OF((deflate_state *s));
+int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
+void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+void _tr_align OF((deflate_state *s));
+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+
+#define d_code(dist) \
+ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+ extern uch _length_code[];
+ extern uch _dist_code[];
+#else
+ extern const uch _length_code[];
+ extern const uch _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+ { uch cc = (c); \
+ s->d_buf[s->last_lit] = 0; \
+ s->l_buf[s->last_lit++] = cc; \
+ s->dyn_ltree[cc].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+# define _tr_tally_dist(s, distance, length, flush) \
+ { uch len = (length); \
+ ush dist = (distance); \
+ s->d_buf[s->last_lit] = dist; \
+ s->l_buf[s->last_lit++] = len; \
+ dist--; \
+ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+ s->dyn_dtree[d_code(dist)].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+ flush = _tr_tally(s, distance, length)
+#endif
+
+#endif /* DEFLATE_H */
--- /dev/null
+/* example.c -- usage example of the zlib compression library
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: example.c,v 1.1 2005/01/12 07:44:59 mmondor Exp $ */
+
+#include <stdio.h>
+#include "zlib.h"
+
+#ifdef STDC
+# include <string.h>
+# include <stdlib.h>
+#else
+ extern void exit OF((int));
+#endif
+
+#if defined(VMS) || defined(RISCOS)
+# define TESTFILE "foo-gz"
+#else
+# define TESTFILE "foo.gz"
+#endif
+
+#define CHECK_ERR(err, msg) { \
+ if (err != Z_OK) { \
+ fprintf(stderr, "%s error: %d\n", msg, err); \
+ exit(1); \
+ } \
+}
+
+const char hello[] = "hello, hello!";
+/* "hello world" would be more standard, but the repeated "hello"
+ * stresses the compression code better, sorry...
+ */
+
+const char dictionary[] = "hello";
+uLong dictId; /* Adler32 value of the dictionary */
+
+void test_compress OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_gzio OF((const char *fname,
+ Byte *uncompr, uLong uncomprLen));
+void test_deflate OF((Byte *compr, uLong comprLen));
+void test_inflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_large_deflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_large_inflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_flush OF((Byte *compr, uLong *comprLen));
+void test_sync OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_dict_deflate OF((Byte *compr, uLong comprLen));
+void test_dict_inflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+int main OF((int argc, char *argv[]));
+
+/* ===========================================================================
+ * Test compress() and uncompress()
+ */
+void test_compress(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ uLong len = (uLong)strlen(hello)+1;
+
+ err = compress(compr, &comprLen, (const Bytef*)hello, len);
+ CHECK_ERR(err, "compress");
+
+ strcpy((char*)uncompr, "garbage");
+
+ err = uncompress(uncompr, &uncomprLen, compr, comprLen);
+ CHECK_ERR(err, "uncompress");
+
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad uncompress\n");
+ exit(1);
+ } else {
+ printf("uncompress(): %s\n", (char *)uncompr);
+ }
+}
+
+/* ===========================================================================
+ * Test read/write of .gz files
+ */
+void test_gzio(fname, uncompr, uncomprLen)
+ const char *fname; /* compressed file name */
+ Byte *uncompr;
+ uLong uncomprLen;
+{
+#ifdef NO_GZCOMPRESS
+ fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n");
+#else
+ int err;
+ int len = (int)strlen(hello)+1;
+ gzFile file;
+ z_off_t pos;
+
+ file = gzopen(fname, "wb");
+ if (file == NULL) {
+ fprintf(stderr, "gzopen error\n");
+ exit(1);
+ }
+ gzputc(file, 'h');
+ if (gzputs(file, "ello") != 4) {
+ fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err));
+ exit(1);
+ }
+ if (gzprintf(file, ", %s!", "hello") != 8) {
+ fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err));
+ exit(1);
+ }
+ gzseek(file, 1L, SEEK_CUR); /* add one zero byte */
+ gzclose(file);
+
+ file = gzopen(fname, "rb");
+ if (file == NULL) {
+ fprintf(stderr, "gzopen error\n");
+ exit(1);
+ }
+ strcpy((char*)uncompr, "garbage");
+
+ if (gzread(file, uncompr, (unsigned)uncomprLen) != len) {
+ fprintf(stderr, "gzread err: %s\n", gzerror(file, &err));
+ exit(1);
+ }
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad gzread: %s\n", (char*)uncompr);
+ exit(1);
+ } else {
+ printf("gzread(): %s\n", (char*)uncompr);
+ }
+
+ pos = gzseek(file, -8L, SEEK_CUR);
+ if (pos != 6 || gztell(file) != pos) {
+ fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n",
+ (long)pos, (long)gztell(file));
+ exit(1);
+ }
+
+ if (gzgetc(file) != ' ') {
+ fprintf(stderr, "gzgetc error\n");
+ exit(1);
+ }
+
+ if (gzungetc(' ', file) != ' ') {
+ fprintf(stderr, "gzungetc error\n");
+ exit(1);
+ }
+
+ gzgets(file, (char*)uncompr, (int)uncomprLen);
+ if (strlen((char*)uncompr) != 7) { /* " hello!" */
+ fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err));
+ exit(1);
+ }
+ if (strcmp((char*)uncompr, hello + 6)) {
+ fprintf(stderr, "bad gzgets after gzseek\n");
+ exit(1);
+ } else {
+ printf("gzgets() after gzseek: %s\n", (char*)uncompr);
+ }
+
+ gzclose(file);
+#endif
+}
+
+/* ===========================================================================
+ * Test deflate() with small buffers
+ */
+void test_deflate(compr, comprLen)
+ Byte *compr;
+ uLong comprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+ uLong len = (uLong)strlen(hello)+1;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
+ CHECK_ERR(err, "deflateInit");
+
+ c_stream.next_in = (Bytef*)hello;
+ c_stream.next_out = compr;
+
+ while (c_stream.total_in != len && c_stream.total_out < comprLen) {
+ c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+ }
+ /* Finish the stream, still forcing small buffers: */
+ for (;;) {
+ c_stream.avail_out = 1;
+ err = deflate(&c_stream, Z_FINISH);
+ if (err == Z_STREAM_END) break;
+ CHECK_ERR(err, "deflate");
+ }
+
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with small buffers
+ */
+void test_inflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = 0;
+ d_stream.next_out = uncompr;
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) {
+ d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */
+ err = inflate(&d_stream, Z_NO_FLUSH);
+ if (err == Z_STREAM_END) break;
+ CHECK_ERR(err, "inflate");
+ }
+
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad inflate\n");
+ exit(1);
+ } else {
+ printf("inflate(): %s\n", (char *)uncompr);
+ }
+}
+
+/* ===========================================================================
+ * Test deflate() with large buffers and dynamic change of compression level
+ */
+void test_large_deflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_BEST_SPEED);
+ CHECK_ERR(err, "deflateInit");
+
+ c_stream.next_out = compr;
+ c_stream.avail_out = (uInt)comprLen;
+
+ /* At this point, uncompr is still mostly zeroes, so it should compress
+ * very well:
+ */
+ c_stream.next_in = uncompr;
+ c_stream.avail_in = (uInt)uncomprLen;
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+ if (c_stream.avail_in != 0) {
+ fprintf(stderr, "deflate not greedy\n");
+ exit(1);
+ }
+
+ /* Feed in already compressed data and switch to no compression: */
+ deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY);
+ c_stream.next_in = compr;
+ c_stream.avail_in = (uInt)comprLen/2;
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+
+ /* Switch back to compressing mode: */
+ deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED);
+ c_stream.next_in = uncompr;
+ c_stream.avail_in = (uInt)uncomprLen;
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+
+ err = deflate(&c_stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ fprintf(stderr, "deflate should report Z_STREAM_END\n");
+ exit(1);
+ }
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with large buffers
+ */
+void test_large_inflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = (uInt)comprLen;
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ for (;;) {
+ d_stream.next_out = uncompr; /* discard the output */
+ d_stream.avail_out = (uInt)uncomprLen;
+ err = inflate(&d_stream, Z_NO_FLUSH);
+ if (err == Z_STREAM_END) break;
+ CHECK_ERR(err, "large inflate");
+ }
+
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ if (d_stream.total_out != 2*uncomprLen + comprLen/2) {
+ fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out);
+ exit(1);
+ } else {
+ printf("large_inflate(): OK\n");
+ }
+}
+
+/* ===========================================================================
+ * Test deflate() with full flush
+ */
+void test_flush(compr, comprLen)
+ Byte *compr;
+ uLong *comprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+ uInt len = (uInt)strlen(hello)+1;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
+ CHECK_ERR(err, "deflateInit");
+
+ c_stream.next_in = (Bytef*)hello;
+ c_stream.next_out = compr;
+ c_stream.avail_in = 3;
+ c_stream.avail_out = (uInt)*comprLen;
+ err = deflate(&c_stream, Z_FULL_FLUSH);
+ CHECK_ERR(err, "deflate");
+
+ compr[3]++; /* force an error in first compressed block */
+ c_stream.avail_in = len - 3;
+
+ err = deflate(&c_stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ CHECK_ERR(err, "deflate");
+ }
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+
+ *comprLen = c_stream.total_out;
+}
+
+/* ===========================================================================
+ * Test inflateSync()
+ */
+void test_sync(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = 2; /* just read the zlib header */
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ d_stream.next_out = uncompr;
+ d_stream.avail_out = (uInt)uncomprLen;
+
+ inflate(&d_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "inflate");
+
+ d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */
+ err = inflateSync(&d_stream); /* but skip the damaged part */
+ CHECK_ERR(err, "inflateSync");
+
+ err = inflate(&d_stream, Z_FINISH);
+ if (err != Z_DATA_ERROR) {
+ fprintf(stderr, "inflate should report DATA_ERROR\n");
+ /* Because of incorrect adler32 */
+ exit(1);
+ }
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ printf("after inflateSync(): hel%s\n", (char *)uncompr);
+}
+
+/* ===========================================================================
+ * Test deflate() with preset dictionary
+ */
+void test_dict_deflate(compr, comprLen)
+ Byte *compr;
+ uLong comprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_BEST_COMPRESSION);
+ CHECK_ERR(err, "deflateInit");
+
+ err = deflateSetDictionary(&c_stream,
+ (const Bytef*)dictionary, sizeof(dictionary));
+ CHECK_ERR(err, "deflateSetDictionary");
+
+ dictId = c_stream.adler;
+ c_stream.next_out = compr;
+ c_stream.avail_out = (uInt)comprLen;
+
+ c_stream.next_in = (Bytef*)hello;
+ c_stream.avail_in = (uInt)strlen(hello)+1;
+
+ err = deflate(&c_stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ fprintf(stderr, "deflate should report Z_STREAM_END\n");
+ exit(1);
+ }
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with a preset dictionary
+ */
+void test_dict_inflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = (uInt)comprLen;
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ d_stream.next_out = uncompr;
+ d_stream.avail_out = (uInt)uncomprLen;
+
+ for (;;) {
+ err = inflate(&d_stream, Z_NO_FLUSH);
+ if (err == Z_STREAM_END) break;
+ if (err == Z_NEED_DICT) {
+ if (d_stream.adler != dictId) {
+ fprintf(stderr, "unexpected dictionary");
+ exit(1);
+ }
+ err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary,
+ sizeof(dictionary));
+ }
+ CHECK_ERR(err, "inflate with dict");
+ }
+
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad inflate with dict\n");
+ exit(1);
+ } else {
+ printf("inflate with dictionary: %s\n", (char *)uncompr);
+ }
+}
+
+/* ===========================================================================
+ * Usage: example [output.gz [input.gz]]
+ */
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ Byte *compr, *uncompr;
+ uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */
+ uLong uncomprLen = comprLen;
+ static const char* myVersion = ZLIB_VERSION;
+
+ if (zlibVersion()[0] != myVersion[0]) {
+ fprintf(stderr, "incompatible zlib version\n");
+ exit(1);
+
+ } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) {
+ fprintf(stderr, "warning: different zlib version\n");
+ }
+
+ printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n",
+ ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags());
+
+ compr = (Byte*)calloc((uInt)comprLen, 1);
+ uncompr = (Byte*)calloc((uInt)uncomprLen, 1);
+ /* compr and uncompr are cleared to avoid reading uninitialized
+ * data and to ensure that uncompr compresses well.
+ */
+ if (compr == Z_NULL || uncompr == Z_NULL) {
+ printf("out of memory\n");
+ exit(1);
+ }
+ test_compress(compr, comprLen, uncompr, uncomprLen);
+
+ test_gzio((argc > 1 ? argv[1] : TESTFILE),
+ uncompr, uncomprLen);
+
+ test_deflate(compr, comprLen);
+ test_inflate(compr, comprLen, uncompr, uncomprLen);
+
+ test_large_deflate(compr, comprLen, uncompr, uncomprLen);
+ test_large_inflate(compr, comprLen, uncompr, uncomprLen);
+
+ test_flush(compr, &comprLen);
+ test_sync(compr, comprLen, uncompr, uncomprLen);
+ comprLen = uncomprLen;
+
+ test_dict_deflate(compr, comprLen);
+ test_dict_inflate(compr, comprLen, uncompr, uncomprLen);
+
+ free(compr);
+ free(uncompr);
+
+ return 0;
+}
--- /dev/null
+/* gzio.c -- IO on .gz files
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Compile this file with -DNO_GZCOMPRESS to avoid the compression code.
+ */
+
+/* @(#) $Id: gzio.c,v 1.1 2005/01/12 07:44:59 mmondor Exp $ */
+
+#include <stdio.h>
+
+#include "zutil.h"
+
+#ifdef NO_DEFLATE /* for compatiblity with old definition */
+# define NO_GZCOMPRESS
+#endif
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+#ifndef Z_BUFSIZE
+# ifdef MAXSEG_64K
+# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
+# else
+# define Z_BUFSIZE 16384
+# endif
+#endif
+#ifndef Z_PRINTF_BUFSIZE
+# define Z_PRINTF_BUFSIZE 4096
+#endif
+
+#ifdef __MVS__
+# pragma map (fdopen , "\174\174FDOPEN")
+ FILE *fdopen(int, const char *);
+#endif
+
+#ifndef STDC
+extern voidp malloc OF((uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+#define ALLOC(size) malloc(size)
+#define TRYFREE(p) {if (p) free(p);}
+
+static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define RESERVED 0xE0 /* bits 5..7: reserved */
+
+typedef struct gz_stream {
+ z_stream stream;
+ int z_err; /* error code for last stream operation */
+ int z_eof; /* set if end of input file */
+ FILE *file; /* .gz file */
+ Byte *inbuf; /* input buffer */
+ Byte *outbuf; /* output buffer */
+ uLong crc; /* crc32 of uncompressed data */
+ char *msg; /* error message */
+ char *path; /* path name for debugging only */
+ int transparent; /* 1 if input file is not a .gz file */
+ char mode; /* 'w' or 'r' */
+ z_off_t start; /* start of compressed data in file (header skipped) */
+ z_off_t in; /* bytes into deflate or inflate */
+ z_off_t out; /* bytes out of deflate or inflate */
+ int back; /* one character push-back */
+ int last; /* true if push-back is last character */
+} gz_stream;
+
+
+local gzFile gz_open OF((const char *path, const char *mode, int fd));
+local int do_flush OF((gzFile file, int flush));
+local int get_byte OF((gz_stream *s));
+local void check_header OF((gz_stream *s));
+local int destroy OF((gz_stream *s));
+local void putLong OF((FILE *file, uLong x));
+local uLong getLong OF((gz_stream *s));
+
+/* ===========================================================================
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb"). The file is given either by file descriptor
+ or path name (if fd == -1).
+ gz_open returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR).
+*/
+local gzFile gz_open (path, mode, fd)
+ const char *path;
+ const char *mode;
+ int fd;
+{
+ int err;
+ int level = Z_DEFAULT_COMPRESSION; /* compression level */
+ int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
+ char *p = (char*)mode;
+ gz_stream *s;
+ char fmode[80]; /* copy of mode, without the compression level */
+ char *m = fmode;
+
+ if (!path || !mode) return Z_NULL;
+
+ s = (gz_stream *)ALLOC(sizeof(gz_stream));
+ if (!s) return Z_NULL;
+
+ s->stream.zalloc = (alloc_func)0;
+ s->stream.zfree = (free_func)0;
+ s->stream.opaque = (voidpf)0;
+ s->stream.next_in = s->inbuf = Z_NULL;
+ s->stream.next_out = s->outbuf = Z_NULL;
+ s->stream.avail_in = s->stream.avail_out = 0;
+ s->file = NULL;
+ s->z_err = Z_OK;
+ s->z_eof = 0;
+ s->in = 0;
+ s->out = 0;
+ s->back = EOF;
+ s->crc = crc32(0L, Z_NULL, 0);
+ s->msg = NULL;
+ s->transparent = 0;
+
+ s->path = (char*)ALLOC(strlen(path)+1);
+ if (s->path == NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ strcpy(s->path, path); /* do this early for debugging */
+
+ s->mode = '\0';
+ do {
+ if (*p == 'r') s->mode = 'r';
+ if (*p == 'w' || *p == 'a') s->mode = 'w';
+ if (*p >= '0' && *p <= '9') {
+ level = *p - '0';
+ } else if (*p == 'f') {
+ strategy = Z_FILTERED;
+ } else if (*p == 'h') {
+ strategy = Z_HUFFMAN_ONLY;
+ } else if (*p == 'R') {
+ strategy = Z_RLE;
+ } else {
+ *m++ = *p; /* copy the mode */
+ }
+ } while (*p++ && m != fmode + sizeof(fmode));
+ if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
+
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ err = Z_STREAM_ERROR;
+#else
+ err = deflateInit2(&(s->stream), level,
+ Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
+ /* windowBits is passed < 0 to suppress zlib header */
+
+ s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+#endif
+ if (err != Z_OK || s->outbuf == Z_NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ } else {
+ s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
+
+ err = inflateInit2(&(s->stream), -MAX_WBITS);
+ /* windowBits is passed < 0 to tell that there is no zlib header.
+ * Note that in this case inflate *requires* an extra "dummy" byte
+ * after the compressed stream in order to complete decompression and
+ * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
+ * present after the compressed stream.
+ */
+ if (err != Z_OK || s->inbuf == Z_NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+
+ errno = 0;
+ s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
+
+ if (s->file == NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ if (s->mode == 'w') {
+ /* Write a very simple .gz header:
+ */
+ fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
+ Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
+ s->start = 10L;
+ /* We use 10L instead of ftell(s->file) to because ftell causes an
+ * fflush on some systems. This version of the library doesn't use
+ * start anyway in write mode, so this initialization is not
+ * necessary.
+ */
+ } else {
+ check_header(s); /* skip the .gz header */
+ s->start = ftell(s->file) - s->stream.avail_in;
+ }
+
+ return (gzFile)s;
+}
+
+/* ===========================================================================
+ Opens a gzip (.gz) file for reading or writing.
+*/
+gzFile ZEXPORT gzopen (path, mode)
+ const char *path;
+ const char *mode;
+{
+ return gz_open (path, mode, -1);
+}
+
+/* ===========================================================================
+ Associate a gzFile with the file descriptor fd. fd is not dup'ed here
+ to mimic the behavio(u)r of fdopen.
+*/
+gzFile ZEXPORT gzdopen (fd, mode)
+ int fd;
+ const char *mode;
+{
+ char name[20];
+
+ if (fd < 0) return (gzFile)Z_NULL;
+ sprintf(name, "<fd:%d>", fd); /* for debugging */
+
+ return gz_open (name, mode, fd);
+}
+
+/* ===========================================================================
+ * Update the compression level and strategy
+ */
+int ZEXPORT gzsetparams (file, level, strategy)
+ gzFile file;
+ int level;
+ int strategy;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ /* Make room to allow flushing */
+ if (s->stream.avail_out == 0) {
+
+ s->stream.next_out = s->outbuf;
+ if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+ s->z_err = Z_ERRNO;
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+
+ return deflateParams (&(s->stream), level, strategy);
+}
+
+/* ===========================================================================
+ Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+ for end of file.
+ IN assertion: the stream s has been sucessfully opened for reading.
+*/
+local int get_byte(s)
+ gz_stream *s;
+{
+ if (s->z_eof) return EOF;
+ if (s->stream.avail_in == 0) {
+ errno = 0;
+ s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+ if (s->stream.avail_in == 0) {
+ s->z_eof = 1;
+ if (ferror(s->file)) s->z_err = Z_ERRNO;
+ return EOF;
+ }
+ s->stream.next_in = s->inbuf;
+ }
+ s->stream.avail_in--;
+ return *(s->stream.next_in)++;
+}
+
+/* ===========================================================================
+ Check the gzip header of a gz_stream opened for reading. Set the stream
+ mode to transparent if the gzip magic header is not present; set s->err
+ to Z_DATA_ERROR if the magic header is present but the rest of the header
+ is incorrect.
+ IN assertion: the stream s has already been created sucessfully;
+ s->stream.avail_in is zero for the first time, but may be non-zero
+ for concatenated .gz files.
+*/
+local void check_header(s)
+ gz_stream *s;
+{
+ int method; /* method byte */
+ int flags; /* flags byte */
+ uInt len;
+ int c;
+
+ /* Assure two bytes in the buffer so we can peek ahead -- handle case
+ where first byte of header is at the end of the buffer after the last
+ gzip segment */
+ len = s->stream.avail_in;
+ if (len < 2) {
+ if (len) s->inbuf[0] = s->stream.next_in[0];
+ errno = 0;
+ len = fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file);
+ if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO;
+ s->stream.avail_in += len;
+ s->stream.next_in = s->inbuf;
+ if (s->stream.avail_in < 2) {
+ s->transparent = s->stream.avail_in;
+ return;
+ }
+ }
+
+ /* Peek ahead to check the gzip magic header */
+ if (s->stream.next_in[0] != gz_magic[0] ||
+ s->stream.next_in[1] != gz_magic[1]) {
+ s->transparent = 1;
+ return;
+ }
+ s->stream.avail_in -= 2;
+ s->stream.next_in += 2;
+
+ /* Check the rest of the gzip header */
+ method = get_byte(s);
+ flags = get_byte(s);
+ if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
+ s->z_err = Z_DATA_ERROR;
+ return;
+ }
+
+ /* Discard time, xflags and OS code: */
+ for (len = 0; len < 6; len++) (void)get_byte(s);
+
+ if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
+ len = (uInt)get_byte(s);
+ len += ((uInt)get_byte(s))<<8;
+ /* len is garbage if EOF but the loop below will quit anyway */
+ while (len-- != 0 && get_byte(s) != EOF) ;
+ }
+ if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
+ while ((c = get_byte(s)) != 0 && c != EOF) ;
+ }
+ if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
+ while ((c = get_byte(s)) != 0 && c != EOF) ;
+ }
+ if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
+ for (len = 0; len < 2; len++) (void)get_byte(s);
+ }
+ s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
+}
+
+ /* ===========================================================================
+ * Cleanup then free the given gz_stream. Return a zlib error code.
+ Try freeing in the reverse order of allocations.
+ */
+local int destroy (s)
+ gz_stream *s;
+{
+ int err = Z_OK;
+
+ if (!s) return Z_STREAM_ERROR;
+
+ TRYFREE(s->msg);
+
+ if (s->stream.state != NULL) {
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ err = Z_STREAM_ERROR;
+#else
+ err = deflateEnd(&(s->stream));
+#endif
+ } else if (s->mode == 'r') {
+ err = inflateEnd(&(s->stream));
+ }
+ }
+ if (s->file != NULL && fclose(s->file)) {
+#ifdef ESPIPE
+ if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
+#endif
+ err = Z_ERRNO;
+ }
+ if (s->z_err < 0) err = s->z_err;
+
+ TRYFREE(s->inbuf);
+ TRYFREE(s->outbuf);
+ TRYFREE(s->path);
+ TRYFREE(s);
+ return err;
+}
+
+/* ===========================================================================
+ Reads the given number of uncompressed bytes from the compressed file.
+ gzread returns the number of bytes actually read (0 for end of file).
+*/
+int ZEXPORT gzread (file, buf, len)
+ gzFile file;
+ voidp buf;
+ unsigned len;
+{
+ gz_stream *s = (gz_stream*)file;
+ Bytef *start = (Bytef*)buf; /* starting point for crc computation */
+ Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
+
+ if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
+
+ if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
+ if (s->z_err == Z_STREAM_END) return 0; /* EOF */
+
+ next_out = (Byte*)buf;
+ s->stream.next_out = (Bytef*)buf;
+ s->stream.avail_out = len;
+
+ if (s->stream.avail_out && s->back != EOF) {
+ *next_out++ = s->back;
+ s->stream.next_out++;
+ s->stream.avail_out--;
+ s->back = EOF;
+ s->out++;
+ if (s->last) {
+ s->z_err = Z_STREAM_END;
+ return 1;
+ }
+ }
+
+ while (s->stream.avail_out != 0) {
+
+ if (s->transparent) {
+ /* Copy first the lookahead bytes: */
+ uInt n = s->stream.avail_in;
+ if (n > s->stream.avail_out) n = s->stream.avail_out;
+ if (n > 0) {
+ zmemcpy(s->stream.next_out, s->stream.next_in, n);
+ next_out += n;
+ s->stream.next_out = next_out;
+ s->stream.next_in += n;
+ s->stream.avail_out -= n;
+ s->stream.avail_in -= n;
+ }
+ if (s->stream.avail_out > 0) {
+ s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out,
+ s->file);
+ }
+ len -= s->stream.avail_out;
+ s->in += len;
+ s->out += len;
+ if (len == 0) s->z_eof = 1;
+ return (int)len;
+ }
+ if (s->stream.avail_in == 0 && !s->z_eof) {
+
+ errno = 0;
+ s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+ if (s->stream.avail_in == 0) {
+ s->z_eof = 1;
+ if (ferror(s->file)) {
+ s->z_err = Z_ERRNO;
+ break;
+ }
+ }
+ s->stream.next_in = s->inbuf;
+ }
+ s->in += s->stream.avail_in;
+ s->out += s->stream.avail_out;
+ s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
+ s->in -= s->stream.avail_in;
+ s->out -= s->stream.avail_out;
+
+ if (s->z_err == Z_STREAM_END) {
+ /* Check CRC and original size */
+ s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+ start = s->stream.next_out;
+
+ if (getLong(s) != s->crc) {
+ s->z_err = Z_DATA_ERROR;
+ } else {
+ (void)getLong(s);
+ /* The uncompressed length returned by above getlong() may be
+ * different from s->out in case of concatenated .gz files.
+ * Check for such files:
+ */
+ check_header(s);
+ if (s->z_err == Z_OK) {
+ inflateReset(&(s->stream));
+ s->crc = crc32(0L, Z_NULL, 0);
+ }
+ }
+ }
+ if (s->z_err != Z_OK || s->z_eof) break;
+ }
+ s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+
+ return (int)(len - s->stream.avail_out);
+}
+
+
+/* ===========================================================================
+ Reads one byte from the compressed file. gzgetc returns this byte
+ or -1 in case of end of file or error.
+*/
+int ZEXPORT gzgetc(file)
+ gzFile file;
+{
+ unsigned char c;
+
+ return gzread(file, &c, 1) == 1 ? c : -1;
+}
+
+
+/* ===========================================================================
+ Push one byte back onto the stream.
+*/
+int ZEXPORT gzungetc(c, file)
+ int c;
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF;
+ s->back = c;
+ s->out--;
+ s->last = (s->z_err == Z_STREAM_END);
+ if (s->last) s->z_err = Z_OK;
+ s->z_eof = 0;
+ return c;
+}
+
+
+/* ===========================================================================
+ Reads bytes from the compressed file until len-1 characters are
+ read, or a newline character is read and transferred to buf, or an
+ end-of-file condition is encountered. The string is then terminated
+ with a null character.
+ gzgets returns buf, or Z_NULL in case of error.
+
+ The current implementation is not optimized at all.
+*/
+char * ZEXPORT gzgets(file, buf, len)
+ gzFile file;
+ char *buf;
+ int len;
+{
+ char *b = buf;
+ if (buf == Z_NULL || len <= 0) return Z_NULL;
+
+ while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
+ *buf = '\0';
+ return b == buf && len > 0 ? Z_NULL : b;
+}
+
+
+#ifndef NO_GZCOMPRESS
+/* ===========================================================================
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of bytes actually written (0 in case of error).
+*/
+int ZEXPORT gzwrite (file, buf, len)
+ gzFile file;
+ voidpc buf;
+ unsigned len;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ s->stream.next_in = (Bytef*)buf;
+ s->stream.avail_in = len;
+
+ while (s->stream.avail_in != 0) {
+
+ if (s->stream.avail_out == 0) {
+
+ s->stream.next_out = s->outbuf;
+ if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+ s->z_err = Z_ERRNO;
+ break;
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+ s->in += s->stream.avail_in;
+ s->out += s->stream.avail_out;
+ s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
+ s->in -= s->stream.avail_in;
+ s->out -= s->stream.avail_out;
+ if (s->z_err != Z_OK) break;
+ }
+ s->crc = crc32(s->crc, (const Bytef *)buf, len);
+
+ return (int)(len - s->stream.avail_in);
+}
+
+
+/* ===========================================================================
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written (0 in case of error).
+*/
+#ifdef STDC
+#include <stdarg.h>
+
+int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
+{
+ char buf[Z_PRINTF_BUFSIZE];
+ va_list va;
+ int len;
+
+ buf[sizeof(buf) - 1] = 0;
+ va_start(va, format);
+#ifdef NO_vsnprintf
+# ifdef HAS_vsprintf_void
+ (void)vsprintf(buf, format, va);
+ va_end(va);
+ for (len = 0; len < sizeof(buf); len++)
+ if (buf[len] == 0) break;
+# else
+ len = vsprintf(buf, format, va);
+ va_end(va);
+# endif
+#else
+# ifdef HAS_vsnprintf_void
+ (void)vsnprintf(buf, sizeof(buf), format, va);
+ va_end(va);
+ len = strlen(buf);
+# else
+ len = vsnprintf(buf, sizeof(buf), format, va);
+ va_end(va);
+# endif
+#endif
+ if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0)
+ return 0;
+ return gzwrite(file, buf, (unsigned)len);
+}
+#else /* not ANSI C */
+
+int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
+ gzFile file;
+ const char *format;
+ int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
+{
+ char buf[Z_PRINTF_BUFSIZE];
+ int len;
+
+ buf[sizeof(buf) - 1] = 0;
+#ifdef NO_snprintf
+# ifdef HAS_sprintf_void
+ sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+ for (len = 0; len < sizeof(buf); len++)
+ if (buf[len] == 0) break;
+# else
+ len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+# endif
+#else
+# ifdef HAS_snprintf_void
+ snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+ len = strlen(buf);
+# else
+ len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+# endif
+#endif
+ if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0)
+ return 0;
+ return gzwrite(file, buf, len);
+}
+#endif
+
+/* ===========================================================================
+ Writes c, converted to an unsigned char, into the compressed file.
+ gzputc returns the value that was written, or -1 in case of error.
+*/
+int ZEXPORT gzputc(file, c)
+ gzFile file;
+ int c;
+{
+ unsigned char cc = (unsigned char) c; /* required for big endian systems */
+
+ return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
+}
+
+
+/* ===========================================================================
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+int ZEXPORT gzputs(file, s)
+ gzFile file;
+ const char *s;
+{
+ return gzwrite(file, (char*)s, (unsigned)strlen(s));
+}
+
+
+/* ===========================================================================
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function.
+*/
+local int do_flush (file, flush)
+ gzFile file;
+ int flush;
+{
+ uInt len;
+ int done = 0;
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ s->stream.avail_in = 0; /* should be zero already anyway */
+
+ for (;;) {
+ len = Z_BUFSIZE - s->stream.avail_out;
+
+ if (len != 0) {
+ if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
+ s->z_err = Z_ERRNO;
+ return Z_ERRNO;
+ }
+ s->stream.next_out = s->outbuf;
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+ if (done) break;
+ s->out += s->stream.avail_out;
+ s->z_err = deflate(&(s->stream), flush);
+ s->out -= s->stream.avail_out;
+
+ /* Ignore the second of two consecutive flushes: */
+ if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
+
+ /* deflate has finished flushing only when it hasn't used up
+ * all the available space in the output buffer:
+ */
+ done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
+
+ if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
+ }
+ return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+
+int ZEXPORT gzflush (file, flush)
+ gzFile file;
+ int flush;
+{
+ gz_stream *s = (gz_stream*)file;
+ int err = do_flush (file, flush);
+
+ if (err) return err;
+ fflush(s->file);
+ return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+#endif /* NO_GZCOMPRESS */
+
+/* ===========================================================================
+ Sets the starting position for the next gzread or gzwrite on the given
+ compressed file. The offset represents a number of bytes in the
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error.
+ SEEK_END is not implemented, returns error.
+ In this version of the library, gzseek can be extremely slow.
+*/
+z_off_t ZEXPORT gzseek (file, offset, whence)
+ gzFile file;
+ z_off_t offset;
+ int whence;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || whence == SEEK_END ||
+ s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
+ return -1L;
+ }
+
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ return -1L;
+#else
+ if (whence == SEEK_SET) {
+ offset -= s->in;
+ }
+ if (offset < 0) return -1L;
+
+ /* At this point, offset is the number of zero bytes to write. */
+ if (s->inbuf == Z_NULL) {
+ s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
+ if (s->inbuf == Z_NULL) return -1L;
+ zmemzero(s->inbuf, Z_BUFSIZE);
+ }
+ while (offset > 0) {
+ uInt size = Z_BUFSIZE;
+ if (offset < Z_BUFSIZE) size = (uInt)offset;
+
+ size = gzwrite(file, s->inbuf, size);
+ if (size == 0) return -1L;
+
+ offset -= size;
+ }
+ return s->in;
+#endif
+ }
+ /* Rest of function is for reading only */
+
+ /* compute absolute position */
+ if (whence == SEEK_CUR) {
+ offset += s->out;
+ }
+ if (offset < 0) return -1L;
+
+ if (s->transparent) {
+ /* map to fseek */
+ s->back = EOF;
+ s->stream.avail_in = 0;
+ s->stream.next_in = s->inbuf;
+ if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
+
+ s->in = s->out = offset;
+ return offset;
+ }
+
+ /* For a negative seek, rewind and use positive seek */
+ if (offset >= s->out) {
+ offset -= s->out;
+ } else if (gzrewind(file) < 0) {
+ return -1L;
+ }
+ /* offset is now the number of bytes to skip. */
+
+ if (offset != 0 && s->outbuf == Z_NULL) {
+ s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+ if (s->outbuf == Z_NULL) return -1L;
+ }
+ if (offset && s->back != EOF) {
+ s->back = EOF;
+ s->out++;
+ offset--;
+ if (s->last) s->z_err = Z_STREAM_END;
+ }
+ while (offset > 0) {
+ int size = Z_BUFSIZE;
+ if (offset < Z_BUFSIZE) size = (int)offset;
+
+ size = gzread(file, s->outbuf, (uInt)size);
+ if (size <= 0) return -1L;
+ offset -= size;
+ }
+ return s->out;
+}
+
+/* ===========================================================================
+ Rewinds input file.
+*/
+int ZEXPORT gzrewind (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'r') return -1;
+
+ s->z_err = Z_OK;
+ s->z_eof = 0;
+ s->back = EOF;
+ s->stream.avail_in = 0;
+ s->stream.next_in = s->inbuf;
+ s->crc = crc32(0L, Z_NULL, 0);
+ if (!s->transparent) (void)inflateReset(&s->stream);
+ s->in = 0;
+ s->out = 0;
+ return fseek(s->file, s->start, SEEK_SET);
+}
+
+/* ===========================================================================
+ Returns the starting position for the next gzread or gzwrite on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+*/
+z_off_t ZEXPORT gztell (file)
+ gzFile file;
+{
+ return gzseek(file, 0L, SEEK_CUR);
+}
+
+/* ===========================================================================
+ Returns 1 when EOF has previously been detected reading the given
+ input stream, otherwise zero.
+*/
+int ZEXPORT gzeof (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ /* With concatenated compressed files that can have embedded
+ * crc trailers, z_eof is no longer the only/best indicator of EOF
+ * on a gz_stream. Handle end-of-stream error explicitly here.
+ */
+ if (s == NULL || s->mode != 'r') return 0;
+ if (s->z_eof) return 1;
+ return s->z_err == Z_STREAM_END;
+}
+
+/* ===========================================================================
+ Outputs a long in LSB order to the given file
+*/
+local void putLong (file, x)
+ FILE *file;
+ uLong x;
+{
+ int n;
+ for (n = 0; n < 4; n++) {
+ fputc((int)(x & 0xff), file);
+ x >>= 8;
+ }
+}
+
+/* ===========================================================================
+ Reads a long in LSB order from the given gz_stream. Sets z_err in case
+ of error.
+*/
+local uLong getLong (s)
+ gz_stream *s;
+{
+ uLong x = (uLong)get_byte(s);
+ int c;
+
+ x += ((uLong)get_byte(s))<<8;
+ x += ((uLong)get_byte(s))<<16;
+ c = get_byte(s);
+ if (c == EOF) s->z_err = Z_DATA_ERROR;
+ x += ((uLong)c)<<24;
+ return x;
+}
+
+/* ===========================================================================
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state.
+*/
+int ZEXPORT gzclose (file)
+ gzFile file;
+{
+ int err;
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) return Z_STREAM_ERROR;
+
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ return Z_STREAM_ERROR;
+#else
+ err = do_flush (file, Z_FINISH);
+ if (err != Z_OK) return destroy((gz_stream*)file);
+
+ putLong (s->file, s->crc);
+ putLong (s->file, (uLong)(s->in & 0xffffffff));
+#endif
+ }
+ return destroy((gz_stream*)file);
+}
+
+/* ===========================================================================
+ Returns the error message for the last error which occured on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occured in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+const char * ZEXPORT gzerror (file, errnum)
+ gzFile file;
+ int *errnum;
+{
+ char *m;
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) {
+ *errnum = Z_STREAM_ERROR;
+ return (const char*)ERR_MSG(Z_STREAM_ERROR);
+ }
+ *errnum = s->z_err;
+ if (*errnum == Z_OK) return (const char*)"";
+
+ m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
+
+ if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
+
+ TRYFREE(s->msg);
+ s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
+ if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR);
+ strcpy(s->msg, s->path);
+ strcat(s->msg, ": ");
+ strcat(s->msg, m);
+ return (const char*)s->msg;
+}
+
+/* ===========================================================================
+ Clear the error and end-of-file flags, and do the same for the real file.
+*/
+void ZEXPORT gzclearerr (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) return;
+ if (s->z_err != Z_STREAM_END) s->z_err = Z_OK;
+ s->z_eof = 0;
+ clearerr(s->file);
+}
--- /dev/null
+/* infback.c -- inflate using a call-back interface
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ This code is largely copied from inflate.c. Normally either infback.o or
+ inflate.o would be linked into an application--not both. The interface
+ with inffast.c is retained so that optimized assembler-coded versions of
+ inflate_fast() can be used with either inflate.c or infback.c.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+
+/*
+ strm provides memory allocation functions in zalloc and zfree, or
+ Z_NULL to use the library memory allocation functions.
+
+ windowBits is in the range 8..15, and window is a user-supplied
+ window and output buffer that is 2**windowBits bytes.
+ */
+int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size)
+z_stream FAR *strm;
+int windowBits;
+unsigned char FAR *window;
+const char *version;
+int stream_size;
+{
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL || window == Z_NULL ||
+ windowBits < 8 || windowBits > 15)
+ return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+ state = (struct inflate_state FAR *)ZALLOC(strm, 1,
+ sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (voidpf)state;
+ state->wbits = windowBits;
+ state->wsize = 1U << windowBits;
+ state->window = window;
+ state->write = 0;
+ state->whave = 0;
+ return Z_OK;
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+/* Macros for inflateBack(): */
+
+/* Load returned state from inflate_fast() */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Set state from registers for inflate_fast() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Assure that some input is available. If input is requested, but denied,
+ then return a Z_BUF_ERROR from inflateBack(). */
+#define PULL() \
+ do { \
+ if (have == 0) { \
+ have = in(in_desc, &next); \
+ if (have == 0) { \
+ next = Z_NULL; \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflateBack()
+ with an error if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ PULL(); \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflateBack() with
+ an error. */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Assure that some output space is available, by writing out the window
+ if it's full. If the write fails, return from inflateBack() with a
+ Z_BUF_ERROR. */
+#define ROOM() \
+ do { \
+ if (left == 0) { \
+ put = state->window; \
+ left = state->wsize; \
+ state->whave = left; \
+ if (out(out_desc, put, left)) { \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/*
+ strm provides the memory allocation functions and window buffer on input,
+ and provides information on the unused input on return. For Z_DATA_ERROR
+ returns, strm will also provide an error message.
+
+ in() and out() are the call-back input and output functions. When
+ inflateBack() needs more input, it calls in(). When inflateBack() has
+ filled the window with output, or when it completes with data in the
+ window, it calls out() to write out the data. The application must not
+ change the provided input until in() is called again or inflateBack()
+ returns. The application must not change the window/output buffer until
+ inflateBack() returns.
+
+ in() and out() are called with a descriptor parameter provided in the
+ inflateBack() call. This parameter can be a structure that provides the
+ information required to do the read or write, as well as accumulated
+ information on the input and output such as totals and check values.
+
+ in() should return zero on failure. out() should return non-zero on
+ failure. If either in() or out() fails, than inflateBack() returns a
+ Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it
+ was in() or out() that caused in the error. Otherwise, inflateBack()
+ returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
+ error, or Z_MEM_ERROR if it could not allocate memory for the state.
+ inflateBack() can also return Z_STREAM_ERROR if the input parameters
+ are not correct, i.e. strm is Z_NULL or the state was not initialized.
+ */
+int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc)
+z_stream FAR *strm;
+in_func in;
+void FAR *in_desc;
+out_func out;
+void FAR *out_desc;
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code this; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ /* Check that the strm exists and that the state was initialized */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* Reset the state */
+ strm->msg = Z_NULL;
+ state->mode = TYPE;
+ state->last = 0;
+ state->whave = 0;
+ next = strm->next_in;
+ have = next != Z_NULL ? strm->avail_in : 0;
+ hold = 0;
+ bits = 0;
+ put = state->window;
+ left = state->wsize;
+
+ /* Inflate until end of block marked as last */
+ for (;;)
+ switch (state->mode) {
+ case TYPE:
+ /* determine and dispatch block type */
+ if (state->last) {
+ BYTEBITS();
+ state->mode = DONE;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN; /* decode codes */
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+
+ case STORED:
+ /* get and verify stored block length */
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+
+ /* copy stored block from input to output */
+ while (state->length != 0) {
+ copy = state->length;
+ PULL();
+ ROOM();
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+
+ case TABLE:
+ /* get dynamic table entries descriptor */
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+
+ /* get code length code lengths (not a typo) */
+ state->have = 0;
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+
+ /* get length and distance code code lengths */
+ state->have = 0;
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.val < 16) {
+ NEEDBITS(this.bits);
+ DROPBITS(this.bits);
+ state->lens[state->have++] = this.val;
+ }
+ else {
+ if (this.val == 16) {
+ NEEDBITS(this.bits + 2);
+ DROPBITS(this.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = (unsigned)(state->lens[state->have - 1]);
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (this.val == 17) {
+ NEEDBITS(this.bits + 3);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(this.bits + 7);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* build code tables */
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (code const FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN;
+
+ case LEN:
+ /* use inflate_fast() if we have enough input and output */
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ if (state->whave < state->wsize)
+ state->whave = state->wsize - left;
+ inflate_fast(strm, state->wsize);
+ LOAD();
+ break;
+ }
+
+ /* get a literal, length, or end-of-block code */
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.op && (this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ state->length = (unsigned)this.val;
+
+ /* process literal */
+ if (this.op == 0) {
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ ROOM();
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ }
+
+ /* process end of block */
+ if (this.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+
+ /* invalid code */
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+
+ /* length code -- get extra bits, if any */
+ state->extra = (unsigned)(this.op) & 15;
+ if (state->extra != 0) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+
+ /* get distance code */
+ for (;;) {
+ this = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)this.val;
+
+ /* get distance extra bits, if any */
+ state->extra = (unsigned)(this.op) & 15;
+ if (state->extra != 0) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ if (state->offset > state->wsize - (state->whave < state->wsize ?
+ left : 0)) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+
+ /* copy match from window to output */
+ do {
+ ROOM();
+ copy = state->wsize - state->offset;
+ if (copy < left) {
+ from = put + copy;
+ copy = left - copy;
+ }
+ else {
+ from = put - state->offset;
+ copy = left;
+ }
+ if (copy > state->length) copy = state->length;
+ state->length -= copy;
+ left -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ } while (state->length != 0);
+ break;
+
+ case DONE:
+ /* inflate stream terminated properly -- write leftover output */
+ ret = Z_STREAM_END;
+ if (left < state->wsize) {
+ if (out(out_desc, state->window, state->wsize - left))
+ ret = Z_BUF_ERROR;
+ }
+ goto inf_leave;
+
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+
+ default: /* can't happen, but makes compilers happy */
+ ret = Z_STREAM_ERROR;
+ goto inf_leave;
+ }
+
+ /* Return unused input */
+ inf_leave:
+ strm->next_in = next;
+ strm->avail_in = have;
+ return ret;
+}
+
+int ZEXPORT inflateBackEnd(strm)
+z_stream FAR *strm;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
--- /dev/null
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+ Based on testing to date,
+ Pre-increment preferred for:
+ - PowerPC G3 (Adler)
+ - MIPS R5000 (Randers-Pehrson)
+ Post-increment preferred for:
+ - none
+ No measurable difference:
+ - Pentium III (Anderson)
+ - 68060 (Nikl)
+ */
+#ifdef POSTINC
+# define OFF 0
+# define PUP(a) *(a)++
+#else
+# define OFF 1
+# define PUP(a) *++(a)
+#endif
+
+/*
+ Decode literal, length, and distance codes and write out the resulting
+ literal and match bytes until either not enough input or output is
+ available, an end-of-block is encountered, or a data error is encountered.
+ When large enough input and output buffers are supplied to inflate(), for
+ example, a 16K input buffer and a 64K output buffer, more than 95% of the
+ inflate execution time is spent in this routine.
+
+ Entry assumptions:
+
+ state->mode == LEN
+ strm->avail_in >= 6
+ strm->avail_out >= 258
+ start >= strm->avail_out
+ state->bits < 8
+
+ On return, state->mode is one of:
+
+ LEN -- ran out of enough output space or enough available input
+ TYPE -- reached end of block code, inflate() to interpret next block
+ BAD -- error in block data
+
+ Notes:
+
+ - The maximum input bits used by a length/distance pair is 15 bits for the
+ length code, 5 bits for the length extra, 15 bits for the distance code,
+ and 13 bits for the distance extra. This totals 48 bits, or six bytes.
+ Therefore if strm->avail_in >= 6, then there is enough input to avoid
+ checking for available input while decoding.
+
+ - The maximum bytes that a single length/distance pair can output is 258
+ bytes, which is the maximum length that can be coded. inflate_fast()
+ requires strm->avail_out >= 258 for each loop to avoid checking for
+ output space.
+ */
+void inflate_fast(strm, start)
+z_streamp strm;
+unsigned start; /* inflate()'s starting value for strm->avail_out */
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *in; /* local strm->next_in */
+ unsigned char FAR *last; /* while in < last, enough input available */
+ unsigned char FAR *out; /* local strm->next_out */
+ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */
+ unsigned char FAR *end; /* while out < end, enough space available */
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned write; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */
+ unsigned long hold; /* local strm->hold */
+ unsigned bits; /* local strm->bits */
+ code const FAR *lcode; /* local strm->lencode */
+ code const FAR *dcode; /* local strm->distcode */
+ unsigned lmask; /* mask for first level of length codes */
+ unsigned dmask; /* mask for first level of distance codes */
+ code this; /* retrieved table entry */
+ unsigned op; /* code bits, operation, extra bits, or */
+ /* window position, window bytes to copy */
+ unsigned len; /* match length, unused bytes */
+ unsigned dist; /* match distance */
+ unsigned char FAR *from; /* where to copy match from */
+
+ /* copy state to local variables */
+ state = (struct inflate_state FAR *)strm->state;
+ in = strm->next_in - OFF;
+ last = in + (strm->avail_in - 5);
+ out = strm->next_out - OFF;
+ beg = out - (start - strm->avail_out);
+ end = out + (strm->avail_out - 257);
+ wsize = state->wsize;
+ whave = state->whave;
+ write = state->write;
+ window = state->window;
+ hold = state->hold;
+ bits = state->bits;
+ lcode = state->lencode;
+ dcode = state->distcode;
+ lmask = (1U << state->lenbits) - 1;
+ dmask = (1U << state->distbits) - 1;
+
+ /* decode literals and length/distances until end-of-block or not enough
+ input data or output space */
+ do {
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ this = lcode[hold & lmask];
+ dolen:
+ op = (unsigned)(this.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(this.op);
+ if (op == 0) { /* literal */
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ PUP(out) = (unsigned char)(this.val);
+ }
+ else if (op & 16) { /* length base */
+ len = (unsigned)(this.val);
+ op &= 15; /* number of extra bits */
+ if (op) {
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ len += (unsigned)hold & ((1U << op) - 1);
+ hold >>= op;
+ bits -= op;
+ }
+ Tracevv((stderr, "inflate: length %u\n", len));
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ this = dcode[hold & dmask];
+ dodist:
+ op = (unsigned)(this.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(this.op);
+ if (op & 16) { /* distance base */
+ dist = (unsigned)(this.val);
+ op &= 15; /* number of extra bits */
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ }
+ dist += (unsigned)hold & ((1U << op) - 1);
+ hold >>= op;
+ bits -= op;
+ Tracevv((stderr, "inflate: distance %u\n", dist));
+ op = (unsigned)(out - beg); /* max distance in output */
+ if (dist > op) { /* see if copy from window */
+ op = dist - op; /* distance back in window */
+ if (op > whave) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ from = window - OFF;
+ if (write == 0) { /* very common case */
+ from += wsize - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ else if (write < op) { /* wrap around window */
+ from += wsize + write - op;
+ op -= write;
+ if (op < len) { /* some from end of window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = window - OFF;
+ if (write < len) { /* some from start of window */
+ op = write;
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ }
+ else { /* contiguous in window */
+ from += write - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ while (len > 2) {
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ }
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ else {
+ from = out - dist; /* copy direct from output */
+ do { /* minimum length is three */
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ } while (len > 2);
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level distance code */
+ this = dcode[this.val + (hold & ((1U << op) - 1))];
+ goto dodist;
+ }
+ else {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level length code */
+ this = lcode[this.val + (hold & ((1U << op) - 1))];
+ goto dolen;
+ }
+ else if (op & 32) { /* end-of-block */
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+ else {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ } while (in < last && out < end);
+
+ /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+ len = bits >> 3;
+ in -= len;
+ bits -= len << 3;
+ hold &= (1U << bits) - 1;
+
+ /* update state and return */
+ strm->next_in = in + OFF;
+ strm->next_out = out + OFF;
+ strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+ strm->avail_out = (unsigned)(out < end ?
+ 257 + (end - out) : 257 - (out - end));
+ state->hold = hold;
+ state->bits = bits;
+ return;
+}
+
+/*
+ inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+ - Using bit fields for code structure
+ - Different op definition to avoid & for extra bits (do & for table bits)
+ - Three separate decoding do-loops for direct, window, and write == 0
+ - Special case for distance > 1 copies to do overlapped load and store copy
+ - Explicit branch predictions (based on measured branch probabilities)
+ - Deferring match copy and interspersed it with decoding subsequent codes
+ - Swapping literal/length else
+ - Swapping window/direct else
+ - Larger unrolled copy loops (three is about right)
+ - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
--- /dev/null
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+void inflate_fast OF((z_streamp strm, unsigned start));
--- /dev/null
+ /* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by makefixed().
+ */
+
+ /* WARNING: this file should *not* be used by applications. It
+ is part of the implementation of the compression library and
+ is subject to change. Applications should only use zlib.h.
+ */
+
+ static const code lenfix[512] = {
+ {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+ {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+ {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+ {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+ {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+ {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+ {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+ {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+ {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+ {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+ {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+ {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+ {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+ {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+ {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+ {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+ {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+ {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+ {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+ {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+ {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+ {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+ {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+ {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+ {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+ {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+ {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+ {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+ {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+ {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+ {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+ {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+ {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+ {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+ {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+ {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+ {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+ {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+ {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+ {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+ {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+ {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+ {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+ {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+ {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+ {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+ {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+ {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+ {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+ {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+ {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+ {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+ {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+ {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+ {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+ {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+ {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+ {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+ {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+ {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+ {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+ {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+ {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+ {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+ {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+ {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+ {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+ {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+ {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+ {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+ {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+ {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+ {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+ {0,9,255}
+ };
+
+ static const code distfix[32] = {
+ {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+ {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+ {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+ {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+ {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+ {22,5,193},{64,5,0}
+ };
--- /dev/null
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * Change history:
+ *
+ * 1.2.beta0 24 Nov 2002
+ * - First version -- complete rewrite of inflate to simplify code, avoid
+ * creation of window when not needed, minimize use of window when it is
+ * needed, make inffast.c even faster, implement gzip decoding, and to
+ * improve code readability and style over the previous zlib inflate code
+ *
+ * 1.2.beta1 25 Nov 2002
+ * - Use pointers for available input and output checking in inffast.c
+ * - Remove input and output counters in inffast.c
+ * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
+ * - Remove unnecessary second byte pull from length extra in inffast.c
+ * - Unroll direct copy to three copies per loop in inffast.c
+ *
+ * 1.2.beta2 4 Dec 2002
+ * - Change external routine names to reduce potential conflicts
+ * - Correct filename to inffixed.h for fixed tables in inflate.c
+ * - Make hbuf[] unsigned char to match parameter type in inflate.c
+ * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
+ * to avoid negation problem on Alphas (64 bit) in inflate.c
+ *
+ * 1.2.beta3 22 Dec 2002
+ * - Add comments on state->bits assertion in inffast.c
+ * - Add comments on op field in inftrees.h
+ * - Fix bug in reuse of allocated window after inflateReset()
+ * - Remove bit fields--back to byte structure for speed
+ * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
+ * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
+ * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
+ * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
+ * - Use local copies of stream next and avail values, as well as local bit
+ * buffer and bit count in inflate()--for speed when inflate_fast() not used
+ *
+ * 1.2.beta4 1 Jan 2003
+ * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
+ * - Move a comment on output buffer sizes from inffast.c to inflate.c
+ * - Add comments in inffast.c to introduce the inflate_fast() routine
+ * - Rearrange window copies in inflate_fast() for speed and simplification
+ * - Unroll last copy for window match in inflate_fast()
+ * - Use local copies of window variables in inflate_fast() for speed
+ * - Pull out common write == 0 case for speed in inflate_fast()
+ * - Make op and len in inflate_fast() unsigned for consistency
+ * - Add FAR to lcode and dcode declarations in inflate_fast()
+ * - Simplified bad distance check in inflate_fast()
+ * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
+ * source file infback.c to provide a call-back interface to inflate for
+ * programs like gzip and unzip -- uses window as output buffer to avoid
+ * window copying
+ *
+ * 1.2.beta5 1 Jan 2003
+ * - Improved inflateBack() interface to allow the caller to provide initial
+ * input in strm.
+ * - Fixed stored blocks bug in inflateBack()
+ *
+ * 1.2.beta6 4 Jan 2003
+ * - Added comments in inffast.c on effectiveness of POSTINC
+ * - Typecasting all around to reduce compiler warnings
+ * - Changed loops from while (1) or do {} while (1) to for (;;), again to
+ * make compilers happy
+ * - Changed type of window in inflateBackInit() to unsigned char *
+ *
+ * 1.2.beta7 27 Jan 2003
+ * - Changed many types to unsigned or unsigned short to avoid warnings
+ * - Added inflateCopy() function
+ *
+ * 1.2.0 9 Mar 2003
+ * - Changed inflateBack() interface to provide separate opaque descriptors
+ * for the in() and out() functions
+ * - Changed inflateBack() argument and in_func typedef to swap the length
+ * and buffer address return values for the input function
+ * - Check next_in and next_out for Z_NULL on entry to inflate()
+ *
+ * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef MAKEFIXED
+# ifndef BUILDFIXED
+# define BUILDFIXED
+# endif
+#endif
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+local int updatewindow OF((z_streamp strm, unsigned out));
+#ifdef BUILDFIXED
+ void makefixed OF((void));
+#endif
+local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf,
+ unsigned len));
+
+int ZEXPORT inflateReset(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ strm->total_in = strm->total_out = state->total = 0;
+ strm->msg = Z_NULL;
+ state->mode = HEAD;
+ state->last = 0;
+ state->havedict = 0;
+ state->wsize = 0;
+ state->whave = 0;
+ state->hold = 0;
+ state->bits = 0;
+ state->lencode = state->distcode = state->next = state->codes;
+ Tracev((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
+z_streamp strm;
+int windowBits;
+const char *version;
+int stream_size;
+{
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+ state = (struct inflate_state FAR *)
+ ZALLOC(strm, 1, sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (voidpf)state;
+ if (windowBits < 0) {
+ state->wrap = 0;
+ windowBits = -windowBits;
+ }
+ else {
+ state->wrap = (windowBits >> 4) + 1;
+#ifdef GUNZIP
+ if (windowBits < 48) windowBits &= 15;
+#endif
+ }
+ if (windowBits < 8 || windowBits > 15) {
+ ZFREE(strm, state);
+ strm->state = Z_NULL;
+ return Z_STREAM_ERROR;
+ }
+ state->wbits = (unsigned)windowBits;
+ state->window = Z_NULL;
+ return inflateReset(strm);
+}
+
+int ZEXPORT inflateInit_(strm, version, stream_size)
+z_streamp strm;
+const char *version;
+int stream_size;
+{
+ return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+ Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also
+ defines BUILDFIXED, so the tables are built on the fly. makefixed() writes
+ those tables to stdout, which would be piped to inffixed.h. A small program
+ can simply call makefixed to do this:
+
+ void makefixed(void);
+
+ int main(void)
+ {
+ makefixed();
+ return 0;
+ }
+
+ Then that can be linked with zlib built with MAKEFIXED defined and run:
+
+ a.out > inffixed.h
+ */
+void makefixed()
+{
+ unsigned low, size;
+ struct inflate_state state;
+
+ fixedtables(&state);
+ puts(" /* inffixed.h -- table for decoding fixed codes");
+ puts(" * Generated automatically by makefixed().");
+ puts(" */");
+ puts("");
+ puts(" /* WARNING: this file should *not* be used by applications.");
+ puts(" It is part of the implementation of this library and is");
+ puts(" subject to change. Applications should only use zlib.h.");
+ puts(" */");
+ puts("");
+ size = 1U << 9;
+ printf(" static const code lenfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 7) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits,
+ state.lencode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+ size = 1U << 5;
+ printf("\n static const code distfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 6) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+ state.distcode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+}
+#endif /* MAKEFIXED */
+
+/*
+ Update the window with the last wsize (normally 32K) bytes written before
+ returning. If window does not exist yet, create it. This is only called
+ when a window is already in use, or when output has been written during this
+ inflate call, but the end of the deflate stream has not been reached yet.
+ It is also called to create a window for dictionary data when a dictionary
+ is loaded.
+
+ Providing output buffers larger than 32K to inflate() should provide a speed
+ advantage, since only the last 32K of output is copied to the sliding window
+ upon return from inflate(), and since all distances after the first 32K of
+ output will fall in the output data, making match copies simpler and faster.
+ The advantage may be dependent on the size of the processor's data caches.
+ */
+local int updatewindow(strm, out)
+z_streamp strm;
+unsigned out;
+{
+ struct inflate_state FAR *state;
+ unsigned copy, dist;
+
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* if it hasn't been done already, allocate space for the window */
+ if (state->window == Z_NULL) {
+ state->window = (unsigned char FAR *)
+ ZALLOC(strm, 1U << state->wbits,
+ sizeof(unsigned char));
+ if (state->window == Z_NULL) return 1;
+ }
+
+ /* if window not in use yet, initialize */
+ if (state->wsize == 0) {
+ state->wsize = 1U << state->wbits;
+ state->write = 0;
+ state->whave = 0;
+ }
+
+ /* copy state->wsize or less output bytes into the circular window */
+ copy = out - strm->avail_out;
+ if (copy >= state->wsize) {
+ zmemcpy(state->window, strm->next_out - state->wsize, state->wsize);
+ state->write = 0;
+ state->whave = state->wsize;
+ }
+ else {
+ dist = state->wsize - state->write;
+ if (dist > copy) dist = copy;
+ zmemcpy(state->window + state->write, strm->next_out - copy, dist);
+ copy -= dist;
+ if (copy) {
+ zmemcpy(state->window, strm->next_out - copy, copy);
+ state->write = copy;
+ state->whave = state->wsize;
+ }
+ else {
+ state->write += dist;
+ if (state->write == state->wsize) state->write = 0;
+ if (state->whave < state->wsize) state->whave += dist;
+ }
+ }
+ return 0;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#ifdef GUNZIP
+# define UPDATE(check, buf, len) \
+ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+# define UPDATE(check, buf, len) adler32(check, buf, len)
+#endif
+
+/* check macros for header crc */
+#ifdef GUNZIP
+# define CRC2(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ check = crc32(check, hbuf, 2); \
+ } while (0)
+
+# define CRC4(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ hbuf[2] = (unsigned char)((word) >> 16); \
+ hbuf[3] = (unsigned char)((word) >> 24); \
+ check = crc32(check, hbuf, 4); \
+ } while (0)
+#endif
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+ if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ if (have == 0) goto inf_leave; \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Reverse the bytes in a 32-bit value */
+#define REVERSE(q) \
+ ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+/*
+ inflate() uses a state machine to process as much input data and generate as
+ much output data as possible before returning. The state machine is
+ structured roughly as follows:
+
+ for (;;) switch (state) {
+ ...
+ case STATEn:
+ if (not enough input data or output space to make progress)
+ return;
+ ... make progress ...
+ state = STATEm;
+ break;
+ ...
+ }
+
+ so when inflate() is called again, the same case is attempted again, and
+ if the appropriate resources are provided, the machine proceeds to the
+ next state. The NEEDBITS() macro is usually the way the state evaluates
+ whether it can proceed or should return. NEEDBITS() does the return if
+ the requested bits are not available. The typical use of the BITS macros
+ is:
+
+ NEEDBITS(n);
+ ... do something with BITS(n) ...
+ DROPBITS(n);
+
+ where NEEDBITS(n) either returns from inflate() if there isn't enough
+ input left to load n bits into the accumulator, or it continues. BITS(n)
+ gives the low n bits in the accumulator. When done, DROPBITS(n) drops
+ the low n bits off the accumulator. INITBITS() clears the accumulator
+ and sets the number of available bits to zero. BYTEBITS() discards just
+ enough bits to put the accumulator on a byte boundary. After BYTEBITS()
+ and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+ NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+ if there is no input available. The decoding of variable length codes uses
+ PULLBYTE() directly in order to pull just enough bytes to decode the next
+ code, and no more.
+
+ Some states loop until they get enough input, making sure that enough
+ state information is maintained to continue the loop where it left off
+ if NEEDBITS() returns in the loop. For example, want, need, and keep
+ would all have to actually be part of the saved state in case NEEDBITS()
+ returns:
+
+ case STATEw:
+ while (want < need) {
+ NEEDBITS(n);
+ keep[want++] = BITS(n);
+ DROPBITS(n);
+ }
+ state = STATEx;
+ case STATEx:
+
+ As shown above, if the next state is also the next case, then the break
+ is omitted.
+
+ A state may also return if there is not enough output space available to
+ complete that state. Those states are copying stored data, writing a
+ literal byte, and copying a matching string.
+
+ When returning, a "goto inf_leave" is used to update the total counters,
+ update the check value, and determine whether any progress has been made
+ during that inflate() call in order to return the proper return code.
+ Progress is defined as a change in either strm->avail_in or strm->avail_out.
+ When there is a window, goto inf_leave will update the window with the last
+ output written. If a goto inf_leave occurs in the middle of decompression
+ and there is no window currently, goto inf_leave will create one and copy
+ output to the window for the next call of inflate().
+
+ In this implementation, the flush parameter of inflate() only affects the
+ return code (per zlib.h). inflate() always writes as much as possible to
+ strm->next_out, given the space available and the provided input--the effect
+ documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers
+ the allocation of and copying into a sliding window until necessary, which
+ provides the effect documented in zlib.h for Z_FINISH when the entire input
+ stream available. So the only thing the flush parameter actually does is:
+ when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it
+ will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int ZEXPORT inflate(strm, flush)
+z_streamp strm;
+int flush;
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned in, out; /* save starting available input and output */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code this; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+#ifdef GUNZIP
+ unsigned char hbuf[4]; /* buffer for gzip header crc calculation */
+#endif
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0))
+ return Z_STREAM_ERROR;
+
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */
+ LOAD();
+ in = have;
+ out = left;
+ ret = Z_OK;
+ for (;;)
+ switch (state->mode) {
+ case HEAD:
+ if (state->wrap == 0) {
+ state->mode = TYPEDO;
+ break;
+ }
+ NEEDBITS(16);
+#ifdef GUNZIP
+ if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */
+ state->check = crc32(0L, Z_NULL, 0);
+ CRC2(state->check, hold);
+ INITBITS();
+ state->mode = FLAGS;
+ break;
+ }
+ state->flags = 0; /* expect zlib header */
+ if (!(state->wrap & 1) || /* check if zlib header allowed */
+#else
+ if (
+#endif
+ ((BITS(8) << 8) + (hold >> 8)) % 31) {
+ strm->msg = (char *)"incorrect header check";
+ state->mode = BAD;
+ break;
+ }
+ if (BITS(4) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ DROPBITS(4);
+ if (BITS(4) + 8 > state->wbits) {
+ strm->msg = (char *)"invalid window size";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: zlib header ok\n"));
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = hold & 0x200 ? DICTID : TYPE;
+ INITBITS();
+ break;
+#ifdef GUNZIP
+ case FLAGS:
+ NEEDBITS(16);
+ state->flags = (int)(hold);
+ if ((state->flags & 0xff) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ if (state->flags & 0xe000) {
+ strm->msg = (char *)"unknown header flags set";
+ state->mode = BAD;
+ break;
+ }
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = TIME;
+ case TIME:
+ NEEDBITS(32);
+ if (state->flags & 0x0200) CRC4(state->check, hold);
+ INITBITS();
+ state->mode = OS;
+ case OS:
+ NEEDBITS(16);
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = EXLEN;
+ case EXLEN:
+ if (state->flags & 0x0400) {
+ NEEDBITS(16);
+ state->length = (unsigned)(hold);
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ }
+ state->mode = EXTRA;
+ case EXTRA:
+ if (state->flags & 0x0400) {
+ copy = state->length;
+ if (copy > have) copy = have;
+ if (copy) {
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ state->length -= copy;
+ }
+ if (state->length) goto inf_leave;
+ }
+ state->mode = NAME;
+ case NAME:
+ if (state->flags & 0x0800) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ } while (len && copy < have);
+ if (state->flags & 0x02000)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ state->mode = COMMENT;
+ case COMMENT:
+ if (state->flags & 0x1000) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ } while (len && copy < have);
+ if (state->flags & 0x02000)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ state->mode = HCRC;
+ case HCRC:
+ if (state->flags & 0x0200) {
+ NEEDBITS(16);
+ if (hold != (state->check & 0xffff)) {
+ strm->msg = (char *)"header crc mismatch";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ }
+ strm->adler = state->check = crc32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ break;
+#endif
+ case DICTID:
+ NEEDBITS(32);
+ strm->adler = state->check = REVERSE(hold);
+ INITBITS();
+ state->mode = DICT;
+ case DICT:
+ if (state->havedict == 0) {
+ RESTORE();
+ return Z_NEED_DICT;
+ }
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ case TYPE:
+ if (flush == Z_BLOCK) goto inf_leave;
+ case TYPEDO:
+ if (state->last) {
+ BYTEBITS();
+ state->mode = CHECK;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN; /* decode codes */
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+ case STORED:
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+ state->mode = COPY;
+ case COPY:
+ copy = state->length;
+ if (copy) {
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ if (copy == 0) goto inf_leave;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ break;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ state->have = 0;
+ state->mode = LENLENS;
+ case LENLENS:
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+ state->have = 0;
+ state->mode = CODELENS;
+ case CODELENS:
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.val < 16) {
+ NEEDBITS(this.bits);
+ DROPBITS(this.bits);
+ state->lens[state->have++] = this.val;
+ }
+ else {
+ if (this.val == 16) {
+ NEEDBITS(this.bits + 2);
+ DROPBITS(this.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = state->lens[state->have - 1];
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (this.val == 17) {
+ NEEDBITS(this.bits + 3);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(this.bits + 7);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* build code tables */
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (code const FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN;
+ case LEN:
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ inflate_fast(strm, out);
+ LOAD();
+ break;
+ }
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.op && (this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ state->length = (unsigned)this.val;
+ if ((int)(this.op) == 0) {
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ state->mode = LIT;
+ break;
+ }
+ if (this.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ state->extra = (unsigned)(this.op) & 15;
+ state->mode = LENEXT;
+ case LENEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+ state->mode = DIST;
+ case DIST:
+ for (;;) {
+ this = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)this.val;
+ state->extra = (unsigned)(this.op) & 15;
+ state->mode = DISTEXT;
+ case DISTEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ if (state->offset > state->whave + out - left) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+ state->mode = MATCH;
+ case MATCH:
+ if (left == 0) goto inf_leave;
+ copy = out - left;
+ if (state->offset > copy) { /* copy from window */
+ copy = state->offset - copy;
+ if (copy > state->write) {
+ copy -= state->write;
+ from = state->window + (state->wsize - copy);
+ }
+ else
+ from = state->window + (state->write - copy);
+ if (copy > state->length) copy = state->length;
+ }
+ else { /* copy from output */
+ from = put - state->offset;
+ copy = state->length;
+ }
+ if (copy > left) copy = left;
+ left -= copy;
+ state->length -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ if (state->length == 0) state->mode = LEN;
+ break;
+ case LIT:
+ if (left == 0) goto inf_leave;
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ case CHECK:
+ if (state->wrap) {
+ NEEDBITS(32);
+ out -= left;
+ strm->total_out += out;
+ state->total += out;
+ if (out)
+ strm->adler = state->check =
+ UPDATE(state->check, put - out, out);
+ out = left;
+ if ((
+#ifdef GUNZIP
+ state->flags ? hold :
+#endif
+ REVERSE(hold)) != state->check) {
+ strm->msg = (char *)"incorrect data check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: check matches trailer\n"));
+ }
+#ifdef GUNZIP
+ state->mode = LENGTH;
+ case LENGTH:
+ if (state->wrap && state->flags) {
+ NEEDBITS(32);
+ if (hold != (state->total & 0xffffffffUL)) {
+ strm->msg = (char *)"incorrect length check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: length matches trailer\n"));
+ }
+#endif
+ state->mode = DONE;
+ case DONE:
+ ret = Z_STREAM_END;
+ goto inf_leave;
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+ case MEM:
+ return Z_MEM_ERROR;
+ case SYNC:
+ default:
+ return Z_STREAM_ERROR;
+ }
+
+ /*
+ Return from inflate(), updating the total counts and the check value.
+ If there was no progress during the inflate() call, return a buffer
+ error. Call updatewindow() to create and/or update the window state.
+ Note: a memory error from inflate() is non-recoverable.
+ */
+ inf_leave:
+ RESTORE();
+ if (state->wsize || (state->mode < CHECK && out != strm->avail_out))
+ if (updatewindow(strm, out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ in -= strm->avail_in;
+ out -= strm->avail_out;
+ strm->total_in += in;
+ strm->total_out += out;
+ state->total += out;
+ if (state->wrap && out)
+ strm->adler = state->check =
+ UPDATE(state->check, strm->next_out - out, out);
+ strm->data_type = state->bits + (state->last ? 64 : 0) +
+ (state->mode == TYPE ? 128 : 0);
+ if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+ ret = Z_BUF_ERROR;
+ return ret;
+}
+
+int ZEXPORT inflateEnd(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->window != Z_NULL) ZFREE(strm, state->window);
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+const Bytef *dictionary;
+uInt dictLength;
+{
+ struct inflate_state FAR *state;
+ unsigned long id;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->mode != DICT) return Z_STREAM_ERROR;
+
+ /* check for correct dictionary id */
+ id = adler32(0L, Z_NULL, 0);
+ id = adler32(id, dictionary, dictLength);
+ if (id != state->check) return Z_DATA_ERROR;
+
+ /* copy dictionary to window */
+ if (updatewindow(strm, strm->avail_out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ if (dictLength > state->wsize) {
+ zmemcpy(state->window, dictionary + dictLength - state->wsize,
+ state->wsize);
+ state->whave = state->wsize;
+ }
+ else {
+ zmemcpy(state->window + state->wsize - dictLength, dictionary,
+ dictLength);
+ state->whave = dictLength;
+ }
+ state->havedict = 1;
+ Tracev((stderr, "inflate: dictionary set\n"));
+ return Z_OK;
+}
+
+/*
+ Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found
+ or when out of input. When called, *have is the number of pattern bytes
+ found in order so far, in 0..3. On return *have is updated to the new
+ state. If on return *have equals four, then the pattern was found and the
+ return value is how many bytes were read including the last byte of the
+ pattern. If *have is less than four, then the pattern has not been found
+ yet and the return value is len. In the latter case, syncsearch() can be
+ called again with more data and the *have state. *have is initialized to
+ zero for the first call.
+ */
+local unsigned syncsearch(have, buf, len)
+unsigned FAR *have;
+unsigned char FAR *buf;
+unsigned len;
+{
+ unsigned got;
+ unsigned next;
+
+ got = *have;
+ next = 0;
+ while (next < len && got < 4) {
+ if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+ got++;
+ else if (buf[next])
+ got = 0;
+ else
+ got = 4 - got;
+ next++;
+ }
+ *have = got;
+ return next;
+}
+
+int ZEXPORT inflateSync(strm)
+z_streamp strm;
+{
+ unsigned len; /* number of bytes to look at or looked at */
+ unsigned long in, out; /* temporary to save total_in and total_out */
+ unsigned char buf[4]; /* to restore bit buffer to byte string */
+ struct inflate_state FAR *state;
+
+ /* check parameters */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+ /* if first time, start search in bit buffer */
+ if (state->mode != SYNC) {
+ state->mode = SYNC;
+ state->hold <<= state->bits & 7;
+ state->bits -= state->bits & 7;
+ len = 0;
+ while (state->bits >= 8) {
+ buf[len++] = (unsigned char)(state->hold);
+ state->hold >>= 8;
+ state->bits -= 8;
+ }
+ state->have = 0;
+ syncsearch(&(state->have), buf, len);
+ }
+
+ /* search available input */
+ len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
+ strm->avail_in -= len;
+ strm->next_in += len;
+ strm->total_in += len;
+
+ /* return no joy or set up to restart inflate() on a new block */
+ if (state->have != 4) return Z_DATA_ERROR;
+ in = strm->total_in; out = strm->total_out;
+ inflateReset(strm);
+ strm->total_in = in; strm->total_out = out;
+ state->mode = TYPE;
+ return Z_OK;
+}
+
+/*
+ Returns true if inflate is currently at the end of a block generated by
+ Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ implementation to provide an additional safety check. PPP uses
+ Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+ block. When decompressing, PPP checks that at the end of input packet,
+ inflate is waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ return state->mode == STORED && state->bits == 0;
+}
+
+int ZEXPORT inflateCopy(dest, source)
+z_streamp dest;
+z_streamp source;
+{
+ struct inflate_state FAR *state;
+ struct inflate_state FAR *copy;
+ unsigned char FAR *window;
+
+ /* check input */
+ if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
+ source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)source->state;
+
+ /* allocate space */
+ copy = (struct inflate_state FAR *)
+ ZALLOC(source, 1, sizeof(struct inflate_state));
+ if (copy == Z_NULL) return Z_MEM_ERROR;
+ window = Z_NULL;
+ if (state->window != Z_NULL) {
+ window = (unsigned char FAR *)
+ ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
+ if (window == Z_NULL) {
+ ZFREE(source, copy);
+ return Z_MEM_ERROR;
+ }
+ }
+
+ /* copy state */
+ *dest = *source;
+ *copy = *state;
+ copy->lencode = copy->codes + (state->lencode - state->codes);
+ copy->distcode = copy->codes + (state->distcode - state->codes);
+ copy->next = copy->codes + (state->next - state->codes);
+ if (window != Z_NULL)
+ zmemcpy(window, state->window, 1U << state->wbits);
+ copy->window = window;
+ dest->state = (voidpf)copy;
+ return Z_OK;
+}
--- /dev/null
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer decoding by inflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip decoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GUNZIP
+#endif
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+ HEAD, /* i: waiting for magic header */
+#ifdef GUNZIP
+ FLAGS, /* i: waiting for method and flags (gzip) */
+ TIME, /* i: waiting for modification time (gzip) */
+ OS, /* i: waiting for extra flags and operating system (gzip) */
+ EXLEN, /* i: waiting for extra length (gzip) */
+ EXTRA, /* i: waiting for extra bytes (gzip) */
+ NAME, /* i: waiting for end of file name (gzip) */
+ COMMENT, /* i: waiting for end of comment (gzip) */
+ HCRC, /* i: waiting for header crc (gzip) */
+#endif
+ DICTID, /* i: waiting for dictionary check value */
+ DICT, /* waiting for inflateSetDictionary() call */
+ TYPE, /* i: waiting for type bits, including last-flag bit */
+ TYPEDO, /* i: same, but skip check to exit inflate on new block */
+ STORED, /* i: waiting for stored size (length and complement) */
+ COPY, /* i/o: waiting for input or output to copy stored block */
+ TABLE, /* i: waiting for dynamic block table lengths */
+ LENLENS, /* i: waiting for code length code lengths */
+ CODELENS, /* i: waiting for length/lit and distance code lengths */
+ LEN, /* i: waiting for length/lit code */
+ LENEXT, /* i: waiting for length extra bits */
+ DIST, /* i: waiting for distance code */
+ DISTEXT, /* i: waiting for distance extra bits */
+ MATCH, /* o: waiting for output space to copy string */
+ LIT, /* o: waiting for output space to write literal */
+ CHECK, /* i: waiting for 32-bit check value */
+#ifdef GUNZIP
+ LENGTH, /* i: waiting for 32-bit length (gzip) */
+#endif
+ DONE, /* finished check, done -- remain here until reset */
+ BAD, /* got a data error -- remain here until reset */
+ MEM, /* got an inflate() memory error -- remain here until reset */
+ SYNC /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+ State transitions between above modes -
+
+ (most modes can go to the BAD or MEM mode -- not shown for clarity)
+
+ Process header:
+ HEAD -> (gzip) or (zlib)
+ (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME
+ NAME -> COMMENT -> HCRC -> TYPE
+ (zlib) -> DICTID or TYPE
+ DICTID -> DICT -> TYPE
+ Read deflate blocks:
+ TYPE -> STORED or TABLE or LEN or CHECK
+ STORED -> COPY -> TYPE
+ TABLE -> LENLENS -> CODELENS -> LEN
+ Read deflate codes:
+ LEN -> LENEXT or LIT or TYPE
+ LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+ LIT -> LEN
+ Process trailer:
+ CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls. Approximately 7K bytes. */
+struct inflate_state {
+ inflate_mode mode; /* current inflate mode */
+ int last; /* true if processing last block */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ int havedict; /* true if dictionary provided */
+ int flags; /* gzip header method and flags (0 if zlib) */
+ unsigned long check; /* protected copy of check value */
+ unsigned long total; /* protected copy of output count */
+ /* sliding window */
+ unsigned wbits; /* log base 2 of requested window size */
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned write; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if needed */
+ /* bit accumulator */
+ unsigned long hold; /* input bit accumulator */
+ unsigned bits; /* number of bits in "in" */
+ /* for string and stored block copying */
+ unsigned length; /* literal or length of data to copy */
+ unsigned offset; /* distance back to copy string from */
+ /* for table and code decoding */
+ unsigned extra; /* extra bits needed */
+ /* fixed and dynamic code tables */
+ code const FAR *lencode; /* starting table for length/literal codes */
+ code const FAR *distcode; /* starting table for distance codes */
+ unsigned lenbits; /* index bits for lencode */
+ unsigned distbits; /* index bits for distcode */
+ /* dynamic table building */
+ unsigned ncode; /* number of code length code lengths */
+ unsigned nlen; /* number of length code lengths */
+ unsigned ndist; /* number of distance code lengths */
+ unsigned have; /* number of code lengths in lens[] */
+ code FAR *next; /* next available space in codes[] */
+ unsigned short lens[320]; /* temporary storage for code lengths */
+ unsigned short work[288]; /* work area for code table building */
+ code codes[ENOUGH]; /* space for code tables */
+};
--- /dev/null
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+ " inflate 1.2.1 Copyright 1995-2003 Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/*
+ Build a set of tables to decode the provided canonical Huffman code.
+ The code lengths are lens[0..codes-1]. The result starts at *table,
+ whose indices are 0..2^bits-1. work is a writable array of at least
+ lens shorts, which is used as a work area. type is the type of code
+ to be generated, CODES, LENS, or DISTS. On return, zero is success,
+ -1 is an invalid code, and +1 means that ENOUGH isn't enough. table
+ on return points to the next available entry's address. bits is the
+ requested root table index bits, and on return it is the actual root
+ table index bits. It will differ if the request is greater than the
+ longest code or if it is less than the shortest code.
+ */
+int inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+ unsigned len; /* a code's length in bits */
+ unsigned sym; /* index of code symbols */
+ unsigned min, max; /* minimum and maximum code lengths */
+ unsigned root; /* number of index bits for root table */
+ unsigned curr; /* number of index bits for current table */
+ unsigned drop; /* code bits to drop for sub-table */
+ int left; /* number of prefix codes available */
+ unsigned used; /* code entries in table used */
+ unsigned huff; /* Huffman code */
+ unsigned incr; /* for incrementing code, index */
+ unsigned fill; /* index for replicating entries */
+ unsigned low; /* low bits for current root entry */
+ unsigned mask; /* mask for low root bits */
+ code this; /* table entry for duplication */
+ code FAR *next; /* next available space in table */
+ const unsigned short FAR *base; /* base value table to use */
+ const unsigned short FAR *extra; /* extra bits table to use */
+ int end; /* use base and extra for symbol > end */
+ unsigned short count[MAXBITS+1]; /* number of codes of each length */
+ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
+ static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+ 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 76, 66};
+ static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577, 0, 0};
+ static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+ 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+ 28, 28, 29, 29, 64, 64};
+
+ /*
+ Process a set of code lengths to create a canonical Huffman code. The
+ code lengths are lens[0..codes-1]. Each length corresponds to the
+ symbols 0..codes-1. The Huffman code is generated by first sorting the
+ symbols by length from short to long, and retaining the symbol order
+ for codes with equal lengths. Then the code starts with all zero bits
+ for the first code of the shortest length, and the codes are integer
+ increments for the same length, and zeros are appended as the length
+ increases. For the deflate format, these bits are stored backwards
+ from their more natural integer increment ordering, and so when the
+ decoding tables are built in the large loop below, the integer codes
+ are incremented backwards.
+
+ This routine assumes, but does not check, that all of the entries in
+ lens[] are in the range 0..MAXBITS. The caller must assure this.
+ 1..MAXBITS is interpreted as that code length. zero means that that
+ symbol does not occur in this code.
+
+ The codes are sorted by computing a count of codes for each length,
+ creating from that a table of starting indices for each length in the
+ sorted table, and then entering the symbols in order in the sorted
+ table. The sorted table is work[], with that space being provided by
+ the caller.
+
+ The length counts are used for other purposes as well, i.e. finding
+ the minimum and maximum length codes, determining if there are any
+ codes at all, checking for a valid set of lengths, and looking ahead
+ at length counts to determine sub-table sizes when building the
+ decoding tables.
+ */
+
+ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+ for (len = 0; len <= MAXBITS; len++)
+ count[len] = 0;
+ for (sym = 0; sym < codes; sym++)
+ count[lens[sym]]++;
+
+ /* bound code lengths, force root to be within code lengths */
+ root = *bits;
+ for (max = MAXBITS; max >= 1; max--)
+ if (count[max] != 0) break;
+ if (root > max) root = max;
+ if (max == 0) return -1; /* no codes! */
+ for (min = 1; min <= MAXBITS; min++)
+ if (count[min] != 0) break;
+ if (root < min) root = min;
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1;
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1;
+ left -= count[len];
+ if (left < 0) return -1; /* over-subscribed */
+ }
+ if (left > 0 && (type == CODES || (codes - count[0] != 1)))
+ return -1; /* incomplete set */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + count[len];
+
+ /* sort symbols by length, by symbol order within each length */
+ for (sym = 0; sym < codes; sym++)
+ if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+ /*
+ Create and fill in decoding tables. In this loop, the table being
+ filled is at next and has curr index bits. The code being used is huff
+ with length len. That code is converted to an index by dropping drop
+ bits off of the bottom. For codes where len is less than drop + curr,
+ those top drop + curr - len bits are incremented through all values to
+ fill the table with replicated entries.
+
+ root is the number of index bits for the root table. When len exceeds
+ root, sub-tables are created pointed to by the root entry with an index
+ of the low root bits of huff. This is saved in low to check for when a
+ new sub-table should be started. drop is zero when the root table is
+ being filled, and drop is root when sub-tables are being filled.
+
+ When a new sub-table is needed, it is necessary to look ahead in the
+ code lengths to determine what size sub-table is needed. The length
+ counts are used for this, and so count[] is decremented as codes are
+ entered in the tables.
+
+ used keeps track of how many table entries have been allocated from the
+ provided *table space. It is checked when a LENS table is being made
+ against the space in *table, ENOUGH, minus the maximum space needed by
+ the worst case distance code, MAXD. This should never happen, but the
+ sufficiency of ENOUGH has not been proven exhaustively, hence the check.
+ This assumes that when type == LENS, bits == 9.
+
+ sym increments through all symbols, and the loop terminates when
+ all codes of length max, i.e. all codes, have been processed. This
+ routine permits incomplete codes, so another loop after this one fills
+ in the rest of the decoding tables with invalid code markers.
+ */
+
+ /* set up for code type */
+ switch (type) {
+ case CODES:
+ base = extra = work; /* dummy value--not used */
+ end = 19;
+ break;
+ case LENS:
+ base = lbase;
+ base -= 257;
+ extra = lext;
+ extra -= 257;
+ end = 256;
+ break;
+ default: /* DISTS */
+ base = dbase;
+ extra = dext;
+ end = -1;
+ }
+
+ /* initialize state for loop */
+ huff = 0; /* starting code */
+ sym = 0; /* starting code symbol */
+ len = min; /* starting code length */
+ next = *table; /* current table to fill in */
+ curr = root; /* current table index bits */
+ drop = 0; /* current bits to drop from code for index */
+ low = (unsigned)(-1); /* trigger new sub-table when len > root */
+ used = 1U << root; /* use root table entries */
+ mask = used - 1; /* mask for comparing low */
+
+ /* check available table space */
+ if (type == LENS && used >= ENOUGH - MAXD)
+ return 1;
+
+ /* process all codes and make table entries */
+ for (;;) {
+ /* create table entry */
+ this.bits = (unsigned char)(len - drop);
+ if ((int)(work[sym]) < end) {
+ this.op = (unsigned char)0;
+ this.val = work[sym];
+ }
+ else if ((int)(work[sym]) > end) {
+ this.op = (unsigned char)(extra[work[sym]]);
+ this.val = base[work[sym]];
+ }
+ else {
+ this.op = (unsigned char)(32 + 64); /* end of block */
+ this.val = 0;
+ }
+
+ /* replicate for those indices with low len bits equal to huff */
+ incr = 1U << (len - drop);
+ fill = 1U << curr;
+ do {
+ fill -= incr;
+ next[(huff >> drop) + fill] = this;
+ } while (fill != 0);
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+
+ /* go to next symbol, update count, len */
+ sym++;
+ if (--(count[len]) == 0) {
+ if (len == max) break;
+ len = lens[work[sym]];
+ }
+
+ /* create new sub-table if needed */
+ if (len > root && (huff & mask) != low) {
+ /* if first time, transition to sub-tables */
+ if (drop == 0)
+ drop = root;
+
+ /* increment past last table */
+ next += 1U << curr;
+
+ /* determine length of next table */
+ curr = len - drop;
+ left = (int)(1 << curr);
+ while (curr + drop < max) {
+ left -= count[curr + drop];
+ if (left <= 0) break;
+ curr++;
+ left <<= 1;
+ }
+
+ /* check for enough space */
+ used += 1U << curr;
+ if (type == LENS && used >= ENOUGH - MAXD)
+ return 1;
+
+ /* point entry in root table to sub-table */
+ low = huff & mask;
+ (*table)[low].op = (unsigned char)curr;
+ (*table)[low].bits = (unsigned char)root;
+ (*table)[low].val = (unsigned short)(next - *table);
+ }
+ }
+
+ /*
+ Fill in rest of table for incomplete codes. This loop is similar to the
+ loop above in incrementing huff for table indices. It is assumed that
+ len is equal to curr + drop, so there is no loop needed to increment
+ through high index bits. When the current sub-table is filled, the loop
+ drops back to the root table to fill in any remaining entries there.
+ */
+ this.op = (unsigned char)64; /* invalid code marker */
+ this.bits = (unsigned char)(len - drop);
+ this.val = (unsigned short)0;
+ while (huff != 0) {
+ /* when done with sub-table, drop back to root table */
+ if (drop != 0 && (huff & mask) != low) {
+ drop = 0;
+ len = root;
+ next = *table;
+ curr = root;
+ this.bits = (unsigned char)len;
+ }
+
+ /* put invalid code marker in table */
+ next[huff >> drop] = this;
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+ }
+
+ /* set return parameters */
+ *table += used;
+ *bits = root;
+ return 0;
+}
--- /dev/null
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables. Each entry provides either the
+ information needed to do the operation requested by the code that
+ indexed that table entry, or it provides a pointer to another
+ table that indexes more bits of the code. op indicates whether
+ the entry is a pointer to another table, a literal, a length or
+ distance, an end-of-block, or an invalid code. For a table
+ pointer, the low four bits of op is the number of index bits of
+ that table. For a length or distance, the low four bits of op
+ is the number of extra bits to get after the code. bits is
+ the number of bits in this code or part of the code to drop off
+ of the bit buffer. val is the actual byte to output in the case
+ of a literal, the base length or distance, or the offset from
+ the current table to the next table. Each entry is four bytes. */
+typedef struct {
+ unsigned char op; /* operation, extra bits, table bits */
+ unsigned char bits; /* bits in this part of the code */
+ unsigned short val; /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+ 00000000 - literal
+ 0000tttt - table link, tttt != 0 is the number of table index bits
+ 0001eeee - length or distance, eeee is the number of extra bits
+ 01100000 - end of block
+ 01000000 - invalid code
+ */
+
+/* Maximum size of dynamic tree. The maximum found in a long but non-
+ exhaustive search was 1004 code structures (850 for length/literals
+ and 154 for distances, the latter actually the result of an
+ exhaustive search). The true maximum is not known, but the value
+ below is more than safe. */
+#define ENOUGH 1440
+#define MAXD 154
+
+/* Type of code to build for inftable() */
+typedef enum {
+ CODES,
+ LENS,
+ DISTS
+} codetype;
+
+extern int inflate_table OF((codetype type, unsigned short FAR *lens,
+ unsigned codes, code FAR * FAR *table,
+ unsigned FAR *bits, unsigned short FAR *work));
--- /dev/null
+/* minigzip.c -- simulate gzip using the zlib compression library
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * minigzip is a minimal implementation of the gzip utility. This is
+ * only an example of using zlib and isn't meant to replace the
+ * full-featured gzip. No attempt is made to deal with file systems
+ * limiting names to 14 or 8+3 characters, etc... Error checking is
+ * very limited. So use minigzip only for testing; use gzip for the
+ * real thing. On MSDOS, use only on file names without extension
+ * or in pipe mode.
+ */
+
+/* @(#) $Id: minigzip.c,v 1.1 2005/01/12 07:44:59 mmondor Exp $ */
+
+#include <stdio.h>
+#include "zlib.h"
+
+#ifdef STDC
+# include <string.h>
+# include <stdlib.h>
+#else
+ extern void exit OF((int));
+#endif
+
+#ifdef USE_MMAP
+# include <sys/types.h>
+# include <sys/mman.h>
+# include <sys/stat.h>
+#endif
+
+#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
+# include <fcntl.h>
+# include <io.h>
+# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
+#else
+# define SET_BINARY_MODE(file)
+#endif
+
+#ifdef VMS
+# define unlink delete
+# define GZ_SUFFIX "-gz"
+#endif
+#ifdef RISCOS
+# define unlink remove
+# define GZ_SUFFIX "-gz"
+# define fileno(file) file->__file
+#endif
+#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+# include <unix.h> /* for fileno */
+#endif
+
+#ifndef WIN32 /* unlink already in stdio.h for WIN32 */
+ extern int unlink OF((const char *));
+#endif
+
+#ifndef GZ_SUFFIX
+# define GZ_SUFFIX ".gz"
+#endif
+#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1)
+
+#define BUFLEN 16384
+#define MAX_NAME_LEN 1024
+
+#ifdef MAXSEG_64K
+# define local static
+ /* Needed for systems with limitation on stack size. */
+#else
+# define local
+#endif
+
+char *prog;
+
+void error OF((const char *msg));
+void gz_compress OF((FILE *in, gzFile out));
+#ifdef USE_MMAP
+int gz_compress_mmap OF((FILE *in, gzFile out));
+#endif
+void gz_uncompress OF((gzFile in, FILE *out));
+void file_compress OF((char *file, char *mode));
+void file_uncompress OF((char *file));
+int main OF((int argc, char *argv[]));
+
+/* ===========================================================================
+ * Display error message and exit
+ */
+void error(msg)
+ const char *msg;
+{
+ fprintf(stderr, "%s: %s\n", prog, msg);
+ exit(1);
+}
+
+/* ===========================================================================
+ * Compress input to output then close both files.
+ */
+
+void gz_compress(in, out)
+ FILE *in;
+ gzFile out;
+{
+ local char buf[BUFLEN];
+ int len;
+ int err;
+
+#ifdef USE_MMAP
+ /* Try first compressing with mmap. If mmap fails (minigzip used in a
+ * pipe), use the normal fread loop.
+ */
+ if (gz_compress_mmap(in, out) == Z_OK) return;
+#endif
+ for (;;) {
+ len = (int)fread(buf, 1, sizeof(buf), in);
+ if (ferror(in)) {
+ perror("fread");
+ exit(1);
+ }
+ if (len == 0) break;
+
+ if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err));
+ }
+ fclose(in);
+ if (gzclose(out) != Z_OK) error("failed gzclose");
+}
+
+#ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech@eso.org> */
+
+/* Try compressing the input file at once using mmap. Return Z_OK if
+ * if success, Z_ERRNO otherwise.
+ */
+int gz_compress_mmap(in, out)
+ FILE *in;
+ gzFile out;
+{
+ int len;
+ int err;
+ int ifd = fileno(in);
+ caddr_t buf; /* mmap'ed buffer for the entire input file */
+ off_t buf_len; /* length of the input file */
+ struct stat sb;
+
+ /* Determine the size of the file, needed for mmap: */
+ if (fstat(ifd, &sb) < 0) return Z_ERRNO;
+ buf_len = sb.st_size;
+ if (buf_len <= 0) return Z_ERRNO;
+
+ /* Now do the actual mmap: */
+ buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0);
+ if (buf == (caddr_t)(-1)) return Z_ERRNO;
+
+ /* Compress the whole file at once: */
+ len = gzwrite(out, (char *)buf, (unsigned)buf_len);
+
+ if (len != (int)buf_len) error(gzerror(out, &err));
+
+ munmap(buf, buf_len);
+ fclose(in);
+ if (gzclose(out) != Z_OK) error("failed gzclose");
+ return Z_OK;
+}
+#endif /* USE_MMAP */
+
+/* ===========================================================================
+ * Uncompress input to output then close both files.
+ */
+void gz_uncompress(in, out)
+ gzFile in;
+ FILE *out;
+{
+ local char buf[BUFLEN];
+ int len;
+ int err;
+
+ for (;;) {
+ len = gzread(in, buf, sizeof(buf));
+ if (len < 0) error (gzerror(in, &err));
+ if (len == 0) break;
+
+ if ((int)fwrite(buf, 1, (unsigned)len, out) != len) {
+ error("failed fwrite");
+ }
+ }
+ if (fclose(out)) error("failed fclose");
+
+ if (gzclose(in) != Z_OK) error("failed gzclose");
+}
+
+
+/* ===========================================================================
+ * Compress the given file: create a corresponding .gz file and remove the
+ * original.
+ */
+void file_compress(file, mode)
+ char *file;
+ char *mode;
+{
+ local char outfile[MAX_NAME_LEN];
+ FILE *in;
+ gzFile out;
+
+ strcpy(outfile, file);
+ strcat(outfile, GZ_SUFFIX);
+
+ in = fopen(file, "rb");
+ if (in == NULL) {
+ perror(file);
+ exit(1);
+ }
+ out = gzopen(outfile, mode);
+ if (out == NULL) {
+ fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile);
+ exit(1);
+ }
+ gz_compress(in, out);
+
+ unlink(file);
+}
+
+
+/* ===========================================================================
+ * Uncompress the given file and remove the original.
+ */
+void file_uncompress(file)
+ char *file;
+{
+ local char buf[MAX_NAME_LEN];
+ char *infile, *outfile;
+ FILE *out;
+ gzFile in;
+ uInt len = (uInt)strlen(file);
+
+ strcpy(buf, file);
+
+ if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) {
+ infile = file;
+ outfile = buf;
+ outfile[len-3] = '\0';
+ } else {
+ outfile = file;
+ infile = buf;
+ strcat(infile, GZ_SUFFIX);
+ }
+ in = gzopen(infile, "rb");
+ if (in == NULL) {
+ fprintf(stderr, "%s: can't gzopen %s\n", prog, infile);
+ exit(1);
+ }
+ out = fopen(outfile, "wb");
+ if (out == NULL) {
+ perror(file);
+ exit(1);
+ }
+
+ gz_uncompress(in, out);
+
+ unlink(infile);
+}
+
+
+/* ===========================================================================
+ * Usage: minigzip [-d] [-f] [-h] [-r] [-1 to -9] [files...]
+ * -d : decompress
+ * -f : compress with Z_FILTERED
+ * -h : compress with Z_HUFFMAN_ONLY
+ * -r : compress with Z_RLE
+ * -1 to -9 : compression level
+ */
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int uncompr = 0;
+ gzFile file;
+ char outmode[20];
+
+ strcpy(outmode, "wb6 ");
+
+ prog = argv[0];
+ argc--, argv++;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "-d") == 0)
+ uncompr = 1;
+ else if (strcmp(*argv, "-f") == 0)
+ outmode[3] = 'f';
+ else if (strcmp(*argv, "-h") == 0)
+ outmode[3] = 'h';
+ else if (strcmp(*argv, "-r") == 0)
+ outmode[3] = 'R';
+ else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' &&
+ (*argv)[2] == 0)
+ outmode[2] = (*argv)[1];
+ else
+ break;
+ argc--, argv++;
+ }
+ if (argc == 0) {
+ SET_BINARY_MODE(stdin);
+ SET_BINARY_MODE(stdout);
+ if (uncompr) {
+ file = gzdopen(fileno(stdin), "rb");
+ if (file == NULL) error("can't gzdopen stdin");
+ gz_uncompress(file, stdout);
+ } else {
+ file = gzdopen(fileno(stdout), outmode);
+ if (file == NULL) error("can't gzdopen stdout");
+ gz_compress(stdin, file);
+ }
+ } else {
+ do {
+ if (uncompr) {
+ file_uncompress(*argv);
+ } else {
+ file_compress(*argv, outmode);
+ }
+ } while (argv++, --argc);
+ }
+ return 0;
+}
--- /dev/null
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2003 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values). The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id: trees.c,v 1.1 2005/01/12 07:44:59 mmondor Exp $ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+# include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN 512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+# include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+ const ct_data *static_tree; /* static tree or NULL */
+ const intf *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+};
+
+local static_tree_desc static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc static_d_desc =
+{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
+
+local static_tree_desc static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block OF((deflate_state *s));
+local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
+local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree OF((deflate_state *s, tree_desc *desc));
+local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local int build_bl_tree OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+ int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+ ct_data *dtree));
+local void set_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup OF((deflate_state *s));
+local void bi_flush OF((deflate_state *s));
+local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
+ int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+ /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+# define send_code(s, c, tree) \
+ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+ send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+ put_byte(s, (uch)((w) & 0xff)); \
+ put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+ deflate_state *s;
+ int value; /* value to send */
+ int length; /* number of bits */
+{
+ Tracevv((stderr," l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ s->bits_sent += (ulg)length;
+
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if (s->bi_valid > (int)Buf_size - length) {
+ s->bi_buf |= (value << s->bi_valid);
+ put_short(s, s->bi_buf);
+ s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+ s->bi_valid += length - Buf_size;
+ } else {
+ s->bi_buf |= value << s->bi_valid;
+ s->bi_valid += length;
+ }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+ if (s->bi_valid > (int)Buf_size - len) {\
+ int val = value;\
+ s->bi_buf |= (val << s->bi_valid);\
+ put_short(s, s->bi_buf);\
+ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+ s->bi_valid += len - Buf_size;\
+ } else {\
+ s->bi_buf |= (value) << s->bi_valid;\
+ s->bi_valid += len;\
+ }\
+}
+#endif /* DEBUG */
+
+
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+ static int static_init_done = 0;
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ if (static_init_done) return;
+
+ /* For some embedded targets, global variables are not initialized: */
+ static_l_desc.static_tree = static_ltree;
+ static_l_desc.extra_bits = extra_lbits;
+ static_d_desc.static_tree = static_dtree;
+ static_d_desc.extra_bits = extra_dbits;
+ static_bl_desc.extra_bits = extra_blbits;
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES-1; code++) {
+ base_length[code] = length;
+ for (n = 0; n < (1<<extra_lbits[code]); n++) {
+ _length_code[length++] = (uch)code;
+ }
+ }
+ Assert (length == 256, "tr_static_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ _length_code[length-1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0 ; code < 16; code++) {
+ base_dist[code] = dist;
+ for (n = 0; n < (1<<extra_dbits[code]); n++) {
+ _dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for ( ; code < D_CODES; code++) {
+ base_dist[code] = dist << 7;
+ for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+ _dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+ n = 0;
+ while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+ while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+ while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+ while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ static_dtree[n].Len = 5;
+ static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+ }
+ static_init_done = 1;
+
+# ifdef GEN_TREES_H
+ gen_trees_header();
+# endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+# ifndef DEBUG
+# include <stdio.h>
+# endif
+
+# define SEPARATOR(i, last, width) \
+ ((i) == (last)? "\n};\n\n" : \
+ ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+ FILE *header = fopen("trees.h", "w");
+ int i;
+
+ Assert (header != NULL, "Can't open trees.h");
+ fprintf(header,
+ "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+ fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+ for (i = 0; i < L_CODES+2; i++) {
+ fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+ static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+ }
+
+ fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+ static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+ }
+
+ fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n");
+ for (i = 0; i < DIST_CODE_LEN; i++) {
+ fprintf(header, "%2u%s", _dist_code[i],
+ SEPARATOR(i, DIST_CODE_LEN-1, 20));
+ }
+
+ fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+ for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+ fprintf(header, "%2u%s", _length_code[i],
+ SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+ }
+
+ fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+ for (i = 0; i < LENGTH_CODES; i++) {
+ fprintf(header, "%1u%s", base_length[i],
+ SEPARATOR(i, LENGTH_CODES-1, 20));
+ }
+
+ fprintf(header, "local const int base_dist[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "%5u%s", base_dist[i],
+ SEPARATOR(i, D_CODES-1, 10));
+ }
+
+ fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void _tr_init(s)
+ deflate_state *s;
+{
+ tr_static_init();
+
+ s->l_desc.dyn_tree = s->dyn_ltree;
+ s->l_desc.stat_desc = &static_l_desc;
+
+ s->d_desc.dyn_tree = s->dyn_dtree;
+ s->d_desc.stat_desc = &static_d_desc;
+
+ s->bl_desc.dyn_tree = s->bl_tree;
+ s->bl_desc.stat_desc = &static_bl_desc;
+
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG
+ s->compressed_len = 0L;
+ s->bits_sent = 0L;
+#endif
+
+ /* Initialize the first block of the first file: */
+ init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+ deflate_state *s;
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+ s->dyn_ltree[END_BLOCK].Freq = 1;
+ s->opt_len = s->static_len = 0L;
+ s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+ top = s->heap[SMALLEST]; \
+ s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+ pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+ (tree[n].Freq < tree[m].Freq || \
+ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+ deflate_state *s;
+ ct_data *tree; /* the tree to restore */
+ int k; /* node to move down */
+{
+ int v = s->heap[k];
+ int j = k << 1; /* left son of k */
+ while (j <= s->heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < s->heap_len &&
+ smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+ j++;
+ }
+ /* Exit if v is smaller than both sons */
+ if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+ /* Exchange v with the smallest son */
+ s->heap[k] = s->heap[j]; k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+local void gen_bitlen(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ int max_code = desc->max_code;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ const intf *extra = desc->stat_desc->extra_bits;
+ int base = desc->stat_desc->extra_base;
+ int max_length = desc->stat_desc->max_length;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+ for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+ n = s->heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if (bits > max_length) bits = max_length, overflow++;
+ tree[n].Len = (ush)bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if (n > max_code) continue; /* not a leaf node */
+
+ s->bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n-base];
+ f = tree[n].Freq;
+ s->opt_len += (ulg)f * (bits + xbits);
+ if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+ }
+ if (overflow == 0) return;
+
+ Trace((stderr,"\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length-1;
+ while (s->bl_count[bits] == 0) bits--;
+ s->bl_count[bits]--; /* move one leaf down the tree */
+ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+ s->bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = s->bl_count[bits];
+ while (n != 0) {
+ m = s->heap[--h];
+ if (m > max_code) continue;
+ if (tree[m].Len != (unsigned) bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ s->opt_len += ((long)bits - (long)tree[m].Len)
+ *(long)tree[m].Freq;
+ tree[m].Len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+ ct_data *tree; /* the tree to decorate */
+ int max_code; /* largest code with non zero frequency */
+ ushf *bl_count; /* number of codes at each bit length */
+{
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].Code = bi_reverse(next_code[len]++, len);
+
+ Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ int elems = desc->stat_desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node; /* new node being created */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ s->heap[++(s->heap_len)] = max_code = n;
+ s->depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (s->heap_len < 2) {
+ node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+ tree[node].Freq = 1;
+ s->depth[node] = 0;
+ s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+ /* node is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ node = elems; /* next internal node of the tree */
+ do {
+ pqremove(s, tree, n); /* n = node of least frequency */
+ m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+ s->heap[--(s->heap_max)] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?
+ s->depth[n] : s->depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+ if (tree == s->bl_tree) {
+ fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+ }
+#endif
+ /* and insert the new node in the heap */
+ s->heap[SMALLEST] = node++;
+ pqdownheap(s, tree, SMALLEST);
+
+ } while (s->heap_len >= 2);
+
+ s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen(s, (tree_desc *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) max_count = 138, min_count = 3;
+ tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ s->bl_tree[curlen].Freq += count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+ s->bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ s->bl_tree[REPZ_3_10].Freq++;
+ } else {
+ s->bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].Len = -1; */ /* guard already set */
+ if (nextlen == 0) max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(s, curlen, s->bl_tree); count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+ } else if (count <= 10) {
+ send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+ } else {
+ send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+ deflate_state *s;
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+ scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree(s, (tree_desc *)(&(s->bl_desc)));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+ if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ s->opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+ s->opt_len, s->static_len));
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+ deflate_state *s;
+ int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+ int rank; /* index in bl_order */
+
+ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(s, dcodes-1, 5);
+ send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void _tr_stored_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */
+#ifdef DEBUG
+ s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+ s->compressed_len += (stored_len + 4) << 3;
+#endif
+ copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void _tr_align(s)
+ deflate_state *s;
+{
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+ bi_flush(s);
+ /* Of the 10 bits for the empty block, we have already sent
+ * (10 - bi_valid) bits. The lookahead for the last real code (before
+ * the EOB of the previous block) was thus at least one plus the length
+ * of the EOB plus what we have just sent of the empty static block.
+ */
+ if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L;
+#endif
+ bi_flush(s);
+ }
+ s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void _tr_flush_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block, or NULL if too old */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex = 0; /* index of last bit length code of non zero freq */
+
+ /* Build the Huffman trees unless a stored block is forced */
+ if (s->level > 0) {
+
+ /* Check if the file is ascii or binary */
+ if (s->data_type == Z_UNKNOWN) set_data_type(s);
+
+ /* Construct the literal and distance trees */
+ build_tree(s, (tree_desc *)(&(s->l_desc)));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+
+ build_tree(s, (tree_desc *)(&(s->d_desc)));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree(s);
+
+ /* Determine the best encoding. Compute the block lengths in bytes. */
+ opt_lenb = (s->opt_len+3+7)>>3;
+ static_lenb = (s->static_len+3+7)>>3;
+
+ Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+ opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+ s->last_lit));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ } else {
+ Assert(buf != (char*)0, "lost buf");
+ opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+ }
+
+#ifdef FORCE_STORED
+ if (buf != (char*)0) { /* force stored block */
+#else
+ if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+ /* 4: two words for the lengths */
+#endif
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ _tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+ } else if (static_lenb >= 0) { /* force static trees */
+#else
+ } else if (static_lenb == opt_lenb) {
+#endif
+ send_bits(s, (STATIC_TREES<<1)+eof, 3);
+ compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->static_len;
+#endif
+ } else {
+ send_bits(s, (DYN_TREES<<1)+eof, 3);
+ send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+ max_blindex+1);
+ compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->opt_len;
+#endif
+ }
+ Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+ /* The above check is made mod 2^32, for files larger than 512 MB
+ * and uLong implemented on 32 bits.
+ */
+ init_block(s);
+
+ if (eof) {
+ bi_windup(s);
+#ifdef DEBUG
+ s->compressed_len += 7; /* align on byte boundary */
+#endif
+ }
+ Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+ s->compressed_len-7*eof));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int _tr_tally (s, dist, lc)
+ deflate_state *s;
+ unsigned dist; /* distance of matched string */
+ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ s->d_buf[s->last_lit] = (ush)dist;
+ s->l_buf[s->last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ s->dyn_ltree[lc].Freq++;
+ } else {
+ s->matches++;
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST(s) &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
+
+ s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+ s->dyn_dtree[d_code(dist)].Freq++;
+ }
+
+#ifdef TRUNCATE_BLOCK
+ /* Try to guess if it is profitable to stop the current block here */
+ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)s->last_lit*8L;
+ ulg in_length = (ulg)((long)s->strstart - s->block_start);
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)s->dyn_dtree[dcode].Freq *
+ (5L+extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+ s->last_lit, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+ }
+#endif
+ return (s->last_lit == s->lit_bufsize-1);
+ /* We avoid equality with lit_bufsize because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+ deflate_state *s;
+ ct_data *ltree; /* literal tree */
+ ct_data *dtree; /* distance tree */
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (s->last_lit != 0) do {
+ dist = s->d_buf[lx];
+ lc = s->l_buf[lx++];
+ if (dist == 0) {
+ send_code(s, lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = _length_code[lc];
+ send_code(s, code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(s, lc, extra); /* send the extra length bits */
+ }
+ dist--; /* dist is now the match distance - 1 */
+ code = d_code(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ send_code(s, code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= base_dist[code];
+ send_bits(s, dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+
+ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+ Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
+ "pendingBuf overflow");
+
+ } while (lx < s->last_lit);
+
+ send_code(s, END_BLOCK, ltree);
+ s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to ASCII or BINARY, using a crude approximation:
+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ */
+local void set_data_type(s)
+ deflate_state *s;
+{
+ int n = 0;
+ unsigned ascii_freq = 0;
+ unsigned bin_freq = 0;
+ while (n < 7) bin_freq += s->dyn_ltree[n++].Freq;
+ while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq;
+ while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
+ s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+ unsigned code; /* the value to invert */
+ int len; /* its bit length */
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+ deflate_state *s;
+{
+ if (s->bi_valid == 16) {
+ put_short(s, s->bi_buf);
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ } else if (s->bi_valid >= 8) {
+ put_byte(s, (Byte)s->bi_buf);
+ s->bi_buf >>= 8;
+ s->bi_valid -= 8;
+ }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+ deflate_state *s;
+{
+ if (s->bi_valid > 8) {
+ put_short(s, s->bi_buf);
+ } else if (s->bi_valid > 0) {
+ put_byte(s, (Byte)s->bi_buf);
+ }
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef DEBUG
+ s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+ deflate_state *s;
+ charf *buf; /* the input data */
+ unsigned len; /* its length */
+ int header; /* true if block header must be written */
+{
+ bi_windup(s); /* align on byte boundary */
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+
+ if (header) {
+ put_short(s, (ush)len);
+ put_short(s, (ush)~len);
+#ifdef DEBUG
+ s->bits_sent += 2*16;
+#endif
+ }
+#ifdef DEBUG
+ s->bits_sent += (ulg)len<<3;
+#endif
+ while (len--) {
+ put_byte(s, *buf++);
+ }
+}
--- /dev/null
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}},
+{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}},
+{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}},
+{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}},
+{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}},
+{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}},
+{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}},
+{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}},
+{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}},
+{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}},
+{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}},
+{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}},
+{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}},
+{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}},
+{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}},
+{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}},
+{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}},
+{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}},
+{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}},
+{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}},
+{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}},
+{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}},
+{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}},
+{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}},
+{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}},
+{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}},
+{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}},
+{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}},
+{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}},
+{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}},
+{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}},
+{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}},
+{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}},
+{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}},
+{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}},
+{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}},
+{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}},
+{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}},
+{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}},
+{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}},
+{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}},
+{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}},
+{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}},
+{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}},
+{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}},
+{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}},
+{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}},
+{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}},
+{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}},
+{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}},
+{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}},
+{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}},
+{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}},
+{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}},
+{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}},
+{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}},
+{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}},
+{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch _dist_code[DIST_CODE_LEN] = {
+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+ 0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
+ 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
+ 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
+};
+
--- /dev/null
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: uncompr.c,v 1.1 2005/01/12 07:44:59 mmondor Exp $ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+
+ err = inflateInit(&stream);
+ if (err != Z_OK) return err;
+
+ err = inflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ inflateEnd(&stream);
+ if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
+ return Z_DATA_ERROR;
+ return err;
+ }
+ *destLen = stream.total_out;
+
+ err = inflateEnd(&stream);
+ return err;
+}
--- /dev/null
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: zconf.in.h,v 1.1 2005/01/12 07:44:59 mmondor Exp $ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+# define deflateInit_ z_deflateInit_
+# define deflate z_deflate
+# define deflateEnd z_deflateEnd
+# define inflateInit_ z_inflateInit_
+# define inflate z_inflate
+# define inflateEnd z_inflateEnd
+# define deflateInit2_ z_deflateInit2_
+# define deflateSetDictionary z_deflateSetDictionary
+# define deflateCopy z_deflateCopy
+# define deflateReset z_deflateReset
+# define deflatePrime z_deflatePrime
+# define deflateParams z_deflateParams
+# define deflateBound z_deflateBound
+# define inflateInit2_ z_inflateInit2_
+# define inflateSetDictionary z_inflateSetDictionary
+# define inflateSync z_inflateSync
+# define inflateSyncPoint z_inflateSyncPoint
+# define inflateCopy z_inflateCopy
+# define inflateReset z_inflateReset
+# define compress z_compress
+# define compress2 z_compress2
+# define compressBound z_compressBound
+# define uncompress z_uncompress
+# define adler32 z_adler32
+# define crc32 z_crc32
+# define get_crc_table z_get_crc_table
+
+# define Byte z_Byte
+# define uInt z_uInt
+# define uLong z_uLong
+# define Bytef z_Bytef
+# define charf z_charf
+# define intf z_intf
+# define uIntf z_uIntf
+# define uLongf z_uLongf
+# define voidpf z_voidpf
+# define voidp z_voidp
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+# define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+# define WINDOWS
+#endif
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
+# define WIN32
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+# ifndef SYS16BIT
+# define SYS16BIT
+# endif
+# endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+# define MAXSEG_64K
+#endif
+#ifdef MSDOS
+# define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+# ifndef STDC
+# define STDC
+# endif
+# if __STDC_VERSION__ >= 199901L
+# ifndef STDC99
+# define STDC99
+# endif
+# endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+# define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
+# define STDC
+#endif
+
+#ifndef STDC
+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+# define const /* note: need a more gentle solution here */
+# endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+# define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ (1 << (windowBits+2)) + (1 << (memLevel+9))
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+# if defined(M_I86SM) || defined(M_I86MM)
+ /* MSC small or medium model */
+# define SMALL_MEDIUM
+# ifdef _MSC_VER
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+# if (defined(__SMALL__) || defined(__MEDIUM__))
+ /* Turbo C small or medium model */
+# define SMALL_MEDIUM
+# ifdef __BORLANDC__
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+ /* If building or using zlib as a DLL, define ZLIB_DLL.
+ * This is not mandatory, but it offers a little performance increase.
+ */
+# ifdef ZLIB_DLL
+# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+# ifdef ZLIB_INTERNAL
+# define ZEXTERN extern __declspec(dllexport)
+# else
+# define ZEXTERN extern __declspec(dllimport)
+# endif
+# endif
+# endif /* ZLIB_DLL */
+ /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+ * define ZLIB_WINAPI.
+ * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+ */
+# ifdef ZLIB_WINAPI
+# ifdef FAR
+# undef FAR
+# endif
+# include <windows.h>
+ /* No need for _export, use ZLIB.DEF instead. */
+ /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+# define ZEXPORT WINAPI
+# ifdef WIN32
+# define ZEXPORTVA WINAPIV
+# else
+# define ZEXPORTVA FAR CDECL
+# endif
+# endif
+#endif
+
+#if defined (__BEOS__)
+# ifdef ZLIB_DLL
+# ifdef ZLIB_INTERNAL
+# define ZEXPORT __declspec(dllexport)
+# define ZEXPORTVA __declspec(dllexport)
+# else
+# define ZEXPORT __declspec(dllimport)
+# define ZEXPORTVA __declspec(dllimport)
+# endif
+# endif
+#endif
+
+#ifndef ZEXTERN
+# define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+# define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+# define ZEXPORTVA
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char Byte; /* 8 bits */
+#endif
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+# define Bytef Byte FAR
+#else
+ typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void const *voidpc;
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte const *voidpc;
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */
+# include <sys/types.h> /* for off_t */
+# include <unistd.h> /* for SEEK_* and off_t */
+# ifdef VMS
+# include <unixio.h> /* for off_t */
+# endif
+# define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+# define SEEK_SET 0 /* Seek from beginning of file. */
+# define SEEK_CUR 1 /* Seek from current position. */
+# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+# define z_off_t long
+#endif
+
+#if defined(__OS400__)
+#define NO_vsnprintf
+#endif
+
+#if defined(__MVS__)
+# define NO_vsnprintf
+# ifdef FAR
+# undef FAR
+# endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+# pragma map(deflateInit_,"DEIN")
+# pragma map(deflateInit2_,"DEIN2")
+# pragma map(deflateEnd,"DEEND")
+# pragma map(deflateBound,"DEBND")
+# pragma map(inflateInit_,"ININ")
+# pragma map(inflateInit2_,"ININ2")
+# pragma map(inflateEnd,"INEND")
+# pragma map(inflateSync,"INSY")
+# pragma map(inflateSetDictionary,"INSEDI")
+# pragma map(compressBound,"CMBND")
+# pragma map(inflate_table,"INTABL")
+# pragma map(inflate_fast,"INFA")
+# pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
--- /dev/null
+.TH ZLIB 3 "17 November 2003"
+.SH NAME
+zlib \- compression/decompression library
+.SH SYNOPSIS
+[see
+.I zlib.h
+for full description]
+.SH DESCRIPTION
+The
+.I zlib
+library is a general purpose data compression library.
+The code is thread safe.
+It provides in-memory compression and decompression functions,
+including integrity checks of the uncompressed data.
+This version of the library supports only one compression method (deflation)
+but other algorithms will be added later
+and will have the same stream interface.
+.LP
+Compression can be done in a single step if the buffers are large enough
+(for example if an input file is mmap'ed),
+or can be done by repeated calls of the compression function.
+In the latter case,
+the application must provide more input and/or consume the output
+(providing more output space) before each call.
+.LP
+The library also supports reading and writing files in
+.IR gzip (1)
+(.gz) format
+with an interface similar to that of stdio.
+.LP
+The library does not install any signal handler.
+The decoder checks the consistency of the compressed data,
+so the library should never crash even in case of corrupted input.
+.LP
+All functions of the compression library are documented in the file
+.IR zlib.h .
+The distribution source includes examples of use of the library
+in the files
+.I example.c
+and
+.IR minigzip.c .
+.LP
+Changes to this version are documented in the file
+.I ChangeLog
+that accompanies the source,
+and are concerned primarily with bug fixes and portability enhancements.
+.LP
+A Java implementation of
+.I zlib
+is available in the Java Development Kit 1.1:
+.IP
+http://www.javasoft.com/products/JDK/1.1/docs/api/Package-java.util.zip.html
+.LP
+A Perl interface to
+.IR zlib ,
+written by Paul Marquess (pmqs@cpan.org),
+is available at CPAN (Comprehensive Perl Archive Network) sites,
+including:
+.IP
+http://www.cpan.org/modules/by-module/Compress/
+.LP
+A Python interface to
+.IR zlib ,
+written by A.M. Kuchling (amk@magnet.com),
+is available in Python 1.5 and later versions:
+.IP
+http://www.python.org/doc/lib/module-zlib.html
+.LP
+A
+.I zlib
+binding for
+.IR tcl (1),
+written by Andreas Kupries (a.kupries@westend.com),
+is availlable at:
+.IP
+http://www.westend.com/~kupries/doc/trf/man/man.html
+.LP
+An experimental package to read and write files in .zip format,
+written on top of
+.I zlib
+by Gilles Vollant (info@winimage.com),
+is available at:
+.IP
+http://www.winimage.com/zLibDll/unzip.html
+and also in the
+.I contrib/minizip
+directory of the main
+.I zlib
+web site.
+.SH "SEE ALSO"
+The
+.I zlib
+web site can be found at either of these locations:
+.IP
+http://www.zlib.org
+.br
+http://www.gzip.org/zlib/
+.LP
+The data format used by the zlib library is described by RFC
+(Request for Comments) 1950 to 1952 in the files:
+.IP
+http://www.ietf.org/rfc/rfc1950.txt (concerning zlib format)
+.br
+http://www.ietf.org/rfc/rfc1951.txt (concerning deflate format)
+.br
+http://www.ietf.org/rfc/rfc1952.txt (concerning gzip format)
+.LP
+These documents are also available in other formats from:
+.IP
+ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
+.LP
+Mark Nelson (markn@ieee.org) wrote an article about
+.I zlib
+for the Jan. 1997 issue of Dr. Dobb's Journal;
+a copy of the article is available at:
+.IP
+http://dogma.net/markn/articles/zlibtool/zlibtool.htm
+.SH "REPORTING PROBLEMS"
+Before reporting a problem,
+please check the
+.I zlib
+web site to verify that you have the latest version of
+.IR zlib ;
+otherwise,
+obtain the latest version and see if the problem still exists.
+Please read the
+.I zlib
+FAQ at:
+.IP
+http://www.gzip.org/zlib/zlib_faq.html
+.LP
+before asking for help.
+Send questions and/or comments to zlib@gzip.org,
+or (for the Windows DLL version) to Gilles Vollant (info@winimage.com).
+.SH AUTHORS
+Version 1.2.1
+Copyright (C) 1995-2003 Jean-loup Gailly (jloup@gzip.org)
+and Mark Adler (madler@alumni.caltech.edu).
+.LP
+This software is provided "as-is,"
+without any express or implied warranty.
+In no event will the authors be held liable for any damages
+arising from the use of this software.
+See the distribution directory with respect to requirements
+governing redistribution.
+The deflate format used by
+.I zlib
+was defined by Phil Katz.
+The deflate and
+.I zlib
+specifications were written by L. Peter Deutsch.
+Thanks to all the people who reported problems and suggested various
+improvements in
+.IR zlib ;
+who are too numerous to cite here.
+.LP
+UNIX manual page by R. P. C. Rodgers,
+U.S. National Library of Medicine (rodgers@nlm.nih.gov).
+.\" end of man page
--- /dev/null
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.2.1, November 17th, 2003
+
+ Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.1"
+#define ZLIB_VERNUM 0x1210
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed
+ data. This version of the library supports only one compression method
+ (deflation) but other algorithms will be added later and will have the same
+ stream interface.
+
+ Compression can be done in a single step if the buffers are large
+ enough (for example if an input file is mmap'ed), or can be done by
+ repeated calls of the compression function. In the latter case, the
+ application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The compressed data format used by the in-memory functions is the zlib
+ format, which is a zlib wrapper documented in RFC 1950, wrapped around a
+ deflate stream, which is itself documented in RFC 1951.
+
+ The library also supports reading and writing files in gzip (.gz) format
+ with an interface similar to that of stdio using the functions that start
+ with "gz". The gzip format is different from the zlib format. gzip is a
+ gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+ The zlib format was designed to be compact and fast for use in memory
+ and on communications channels. The gzip format was designed for single-
+ file compression on file systems, has a larger header than zlib to maintain
+ directory information, and uses a different, slower check method than zlib.
+
+ This library does not provide any functions to write gzip files in memory.
+ However such functions could be easily written using zlib's deflate function,
+ the documentation in the gzip RFC, and the examples in gzio.c.
+
+ The library does not install any signal handler. The decoder checks
+ the consistency of the compressed data, so the library should never
+ crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total nb of bytes output so far */
+
+ char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidpf opaque; /* private data object passed to zalloc and zfree */
+
+ int data_type; /* best guess about the data type: ascii or binary */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+ The application must update next_in and avail_in when avail_in has
+ dropped to zero. It must update next_out and avail_out when avail_out
+ has dropped to zero. The application must initialize zalloc, zfree and
+ opaque before calling the init function. All other fields are set by the
+ compression library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ If zlib is used in a multi-threaded application, zalloc and zfree must be
+ thread safe.
+
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this
+ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+ pointers returned by zalloc for objects of exactly 65536 bytes *must*
+ have their offset normalized to zero. The default allocation function
+ provided by this library ensures this (see zutil.c). To reduce memory
+ requirements and avoid any allocation of 64K objects, at the expense of
+ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or
+ progress reports. After compression, total_in holds the total size of
+ the uncompressed data and may be saved for use in the decompressor
+ (particularly if the decompressor wants to decompress everything in
+ a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+#define Z_BLOCK 5
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_RLE 3
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_ASCII 1
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+ /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is
+ not compatible with the zlib.h header file used by the application.
+ This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller.
+ If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+ use default allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at
+ all (the input data is simply copied a block at a time).
+ Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+ compression (currently equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION).
+ msg is set to null if there is no error message. deflateInit does not
+ perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+ deflate compresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce some
+ output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. deflate performs one or both of the
+ following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications).
+ Some output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating avail_in or avail_out accordingly; avail_out
+ should never be zero before the call. The application can consume the
+ compressed output when it wants, for example when the output buffer is full
+ (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+ and with zero avail_out, it must be called again after making room in the
+ output buffer because there might be more output pending.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+ flushed to the output buffer and the output is aligned on a byte boundary, so
+ that the decompressor can get all input data available so far. (In particular
+ avail_in is zero after the call if enough output space has been provided
+ before the call.) Flushing may degrade compression for some compression
+ algorithms and so it should be used only when necessary.
+
+ If flush is set to Z_FULL_FLUSH, all output is flushed as with
+ Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+ restart from this point if previous compressed data has been damaged or if
+ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+ the compression.
+
+ If deflate returns with avail_out == 0, this function must be called again
+ with the same value of the flush parameter and more output space (updated
+ avail_out), until the flush is complete (deflate returns with non-zero
+ avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+ avail_out is greater than six to avoid repeated flush markers due to
+ avail_out == 0 on return.
+
+ If the parameter flush is set to Z_FINISH, pending input is processed,
+ pending output is flushed and deflate returns with Z_STREAM_END if there
+ was enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the
+ stream are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least
+ the value returned by deflateBound (see below). If deflate does not return
+ Z_STREAM_END, then it must be called again as described above.
+
+ deflate() sets strm->adler to the adler32 checksum of all input read
+ so far (that is, total_in bytes).
+
+ deflate() may update data_type if it can make a good guess about
+ the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect
+ the compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+ (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
+ fatal, and deflate() can be called again with more input and more output
+ space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case,
+ msg may be set but then points to a static string (which must not be
+ deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+ Initializes the internal stream state for decompression. The fields
+ next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+ the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+ value depends on the compression method), inflateInit determines the
+ compression method from the zlib header and allocates all data structures
+ accordingly; otherwise the allocation will be deferred to the first call of
+ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+ use default allocation functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller. msg is set to null if there is no error
+ message. inflateInit does not perform any decompression apart from reading
+ the zlib header if present: this will be done by inflate(). (So next_in and
+ avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+ inflate decompresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. inflate performs one or both of the
+ following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing
+ will resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there
+ is no more input data or no more space in the output buffer (see below
+ about the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating the next_* and avail_* values accordingly.
+ The application can consume the uncompressed output when it wants, for
+ example when the output buffer is full (avail_out == 0), or after each
+ call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+ must be called again after making room in the output buffer because there
+ might be more output pending.
+
+ The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH,
+ Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much
+ output as possible to the output buffer. Z_BLOCK requests that inflate() stop
+ if and when it get to the next deflate block boundary. When decoding the zlib
+ or gzip format, this will cause inflate() to return immediately after the
+ header and before the first block. When doing a raw inflate, inflate() will
+ go ahead and process the first block, and will return when it gets to the end
+ of that block, or when it runs out of data.
+
+ The Z_BLOCK option assists in appending to or combining deflate streams.
+ Also to assist in this, on return inflate() will set strm->data_type to the
+ number of unused bits in the last byte taken from strm->next_in, plus 64
+ if inflate() is currently decoding the last block in the deflate stream,
+ plus 128 if inflate() returned immediately after decoding an end-of-block
+ code or decoding the complete header up to just before the first byte of the
+ deflate stream. The end-of-block will not be indicated until all of the
+ uncompressed data from that block has been written to strm->next_out. The
+ number of unused bits may in general be greater than seven, except when
+ bit 7 of data_type is set, in which case the number of unused bits will be
+ less than eight.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step
+ (a single call of inflate), the parameter flush should be set to
+ Z_FINISH. In this case all pending input is processed and all pending
+ output is flushed; avail_out must be large enough to hold all the
+ uncompressed data. (The size of the uncompressed data may have been saved
+ by the compressor for this purpose.) The next operation on this stream must
+ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+ is never required, but can be used to inform inflate that a faster approach
+ may be used for the single inflate() call.
+
+ In this implementation, inflate() always flushes as much output as
+ possible to the output buffer, and always uses the faster approach on the
+ first call. So the only effect of the flush parameter in this implementation
+ is on the return value of inflate(), as noted below, or when it returns early
+ because Z_BLOCK is used.
+
+ If a preset dictionary is needed after this call (see inflateSetDictionary
+ below), inflate sets strm-adler to the adler32 checksum of the dictionary
+ chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+ strm->adler to the adler32 checksum of all output produced so far (that is,
+ total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+ below. At the end of the stream, inflate() checks that its computed adler32
+ checksum is equal to that saved by the compressor and returns Z_STREAM_END
+ only if the checksum is correct.
+
+ inflate() will decompress and check either zlib-wrapped or gzip-wrapped
+ deflate data. The header type is detected automatically. Any information
+ contained in the gzip header is not retained, so applications that need that
+ information should instead use raw inflate, see inflateInit2() below, or
+ inflateBack() and perform their own processing of the gzip header and
+ trailer.
+
+ inflate() returns Z_OK if some progress has been made (more input processed
+ or more output produced), Z_STREAM_END if the end of the compressed data has
+ been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+ corrupted (input stream not conforming to the zlib format or incorrect check
+ value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+ if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+ Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+ output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+ inflate() can be called again with more input and more output space to
+ continue decompressing. If Z_DATA_ERROR is returned, the application may then
+ call inflateSync() to look for a good compression block if a partial recovery
+ of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+ /* Advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy));
+
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc, zfree and opaque must be initialized before by
+ the caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library.
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library. Larger values of this parameter result in better
+ compression at the expense of memory usage. The default value is 15 if
+ deflateInit is used instead.
+
+ windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
+ determines the window size. deflate() will then generate raw deflate data
+ with no zlib header or trailer, and will not compute an adler32 check value.
+
+ windowBits can also be greater than 15 for optional gzip encoding. Add
+ 16 to windowBits to write a simple gzip header and trailer around the
+ compressed data instead of a zlib wrapper. The gzip header will have no
+ file name, no extra data, no comment, no modification time (set to zero),
+ no header crc, and the operating system will be set to 255 (unknown).
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but
+ is slow and reduces compression ratio; memLevel=9 uses maximum memory
+ for optimal speed. The default value is 8. See zconf.h for total memory
+ usage as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match), or Z_RLE to limit match distances to one (run-length
+ encoding). Filtered data consists mostly of small values with a somewhat
+ random distribution. In this case, the compression algorithm is tuned to
+ compress them better. The effect of Z_FILTERED is to force more Huffman
+ coding and less string matching; it is somewhat intermediate between
+ Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as
+ Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy
+ parameter only affects the compression ratio but not the correctness of the
+ compressed output even if it is not set appropriately.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+ method). msg is set to null if there is no error message. deflateInit2 does
+ not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the compression dictionary from the given byte sequence
+ without producing any compressed output. This function must be called
+ immediately after deflateInit, deflateInit2 or deflateReset, before any
+ call of deflate. The compressor and decompressor must use exactly the same
+ dictionary (see inflateSetDictionary).
+
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and can be
+ predicted with good accuracy; the data can then be compressed better than
+ with the default empty dictionary.
+
+ Depending on the size of the compression data structures selected by
+ deflateInit or deflateInit2, a part of the dictionary may in effect be
+ discarded, for example if the dictionary is larger than the window size in
+ deflate or deflate2. Thus the strings most likely to be useful should be
+ put at the end of the dictionary, not at the front.
+
+ Upon return of this function, strm->adler is set to the adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.) If a raw deflate was requested, then the
+ adler32 value is not computed and strm->adler is not set.
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent (for example if deflate has already been called for this stream
+ or if the compression method is bsort). deflateSetDictionary does not
+ perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and
+ can consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state.
+ The stream will keep the same compression level and any other attributes
+ that may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+ int level,
+ int strategy));
+/*
+ Dynamically update the compression level and compression strategy. The
+ interpretation of level and strategy is as in deflateInit2. This can be
+ used to switch between compression and straight copy of the input data, or
+ to switch to a different kind of input data requiring a different
+ strategy. If the compression level is changed, the input available so far
+ is compressed with the old level (and may be flushed); the new level will
+ take effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to
+ be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+ if strm->avail_out was zero.
+*/
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+ uLong sourceLen));
+/*
+ deflateBound() returns an upper bound on the compressed size after
+ deflation of sourceLen bytes. It must be called after deflateInit()
+ or deflateInit2(). This would be used to allocate an output buffer
+ for deflation in a single pass, and so would be called before deflate().
+*/
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ deflatePrime() inserts bits in the deflate output stream. The intent
+ is that this function is used to start off the deflate output with the
+ bits leftover from a previous deflate stream when appending to it. As such,
+ this function can only be used for raw deflate, and must be used before the
+ first deflate() call after a deflateInit2() or deflateReset(). bits must be
+ less than or equal to 16, and that many of the least significant bits of
+ value will be inserted in the output.
+
+ deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+ int windowBits));
+
+ This is another version of inflateInit with an extra parameter. The
+ fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+ before by the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library. The default value is 15 if inflateInit is used
+ instead. windowBits must be greater than or equal to the windowBits value
+ provided to deflateInit2() while compressing, or it must be equal to 15 if
+ deflateInit2() was not used. If a compressed stream with a larger window
+ size is given as input, inflate() will return with the error code
+ Z_DATA_ERROR instead of trying to allocate a larger window.
+
+ windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+ determines the window size. inflate() will then process raw deflate data,
+ not looking for a zlib or gzip header, not generating a check value, and not
+ looking for any check values for comparison at the end of the stream. This
+ is for use with other formats that use the deflate compressed data format
+ such as zip. Those formats provide their own check values. If a custom
+ format is developed using the raw deflate format for compressed data, it is
+ recommended that a check value such as an adler32 or a crc32 be applied to
+ the uncompressed data as is done in the zlib, gzip, and zip formats. For
+ most applications, the zlib format should be used as is. Note that comments
+ above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+ windowBits can also be greater than 15 for optional gzip decoding. Add
+ 32 to windowBits to enable zlib and gzip decoding with automatic header
+ detection, or add 16 to decode only the gzip format (the zlib format will
+ return a Z_DATA_ERROR).
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
+ memLevel). msg is set to null if there is no error message. inflateInit2
+ does not perform any decompression apart from reading the zlib header if
+ present: this will be done by inflate(). (So next_in and avail_in may be
+ modified, but next_out and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the decompression dictionary from the given uncompressed byte
+ sequence. This function must be called immediately after a call of inflate
+ if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
+ can be determined from the adler32 value returned by this call of
+ inflate. The compressor and decompressor must use exactly the same
+ dictionary (see deflateSetDictionary).
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+ Skips invalid compressed data until a full flush point (see above the
+ description of deflate with Z_FULL_FLUSH) can be found, or until all
+ available input is skipped. No output is provided.
+
+ inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+ case, the application may save the current current value of total_in which
+ indicates where valid compressed data was found. In the error case, the
+ application may repeatedly call inflateSync, providing more input each time,
+ until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when randomly accessing a large stream. The
+ first pass through the stream can periodically record the inflate state,
+ allowing restarting inflate at those points when randomly accessing the
+ stream.
+
+ inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state.
+ The stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_stream FAR *strm, int windowBits,
+ unsigned char FAR *window));
+
+ Initialize the internal stream state for decompression using inflateBack()
+ calls. The fields zalloc, zfree and opaque in strm must be initialized
+ before the call. If zalloc and zfree are Z_NULL, then the default library-
+ derived memory allocation routines are used. windowBits is the base two
+ logarithm of the window size, in the range 8..15. window is a caller
+ supplied buffer of that size. Except for special applications where it is
+ assured that deflate was used with small window sizes, windowBits must be 15
+ and a 32K byte window must be supplied to be able to decompress general
+ deflate streams.
+
+ See inflateBack() for the usage of these routines.
+
+ inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+ the paramaters are invalid, Z_MEM_ERROR if the internal state could not
+ be allocated, or Z_VERSION_ERROR if the version of the library does not
+ match the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_stream FAR *strm,
+ in_func in, void FAR *in_desc,
+ out_func out, void FAR *out_desc));
+/*
+ inflateBack() does a raw inflate with a single call using a call-back
+ interface for input and output. This is more efficient than inflate() for
+ file i/o applications in that it avoids copying between the output and the
+ sliding window by simply making the window itself the output buffer. This
+ function trusts the application to not change the output buffer passed by
+ the output function, at least until inflateBack() returns.
+
+ inflateBackInit() must be called first to allocate the internal state
+ and to initialize the state with the user-provided window buffer.
+ inflateBack() may then be used multiple times to inflate a complete, raw
+ deflate stream with each call. inflateBackEnd() is then called to free
+ the allocated state.
+
+ A raw deflate stream is one with no zlib or gzip header or trailer.
+ This routine would normally be used in a utility that reads zip or gzip
+ files and writes out uncompressed files. The utility would decode the
+ header and process the trailer on its own, hence this routine expects
+ only the raw deflate stream to decompress. This is different from the
+ normal behavior of inflate(), which expects either a zlib or gzip header and
+ trailer around the deflate stream.
+
+ inflateBack() uses two subroutines supplied by the caller that are then
+ called by inflateBack() for input and output. inflateBack() calls those
+ routines until it reads a complete deflate stream and writes out all of the
+ uncompressed data, or until it encounters an error. The function's
+ parameters and return types are defined above in the in_func and out_func
+ typedefs. inflateBack() will call in(in_desc, &buf) which should return the
+ number of bytes of provided input, and a pointer to that input in buf. If
+ there is no input available, in() must return zero--buf is ignored in that
+ case--and inflateBack() will return a buffer error. inflateBack() will call
+ out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out()
+ should return zero on success, or non-zero on failure. If out() returns
+ non-zero, inflateBack() will return with an error. Neither in() nor out()
+ are permitted to change the contents of the window provided to
+ inflateBackInit(), which is also the buffer that out() uses to write from.
+ The length written by out() will be at most the window size. Any non-zero
+ amount of input may be provided by in().
+
+ For convenience, inflateBack() can be provided input on the first call by
+ setting strm->next_in and strm->avail_in. If that input is exhausted, then
+ in() will be called. Therefore strm->next_in must be initialized before
+ calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called
+ immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in
+ must also be initialized, and then if strm->avail_in is not zero, input will
+ initially be taken from strm->next_in[0 .. strm->avail_in - 1].
+
+ The in_desc and out_desc parameters of inflateBack() is passed as the
+ first parameter of in() and out() respectively when they are called. These
+ descriptors can be optionally used to pass any information that the caller-
+ supplied in() and out() functions need to do their job.
+
+ On return, inflateBack() will set strm->next_in and strm->avail_in to
+ pass back any unused input that was provided by the last in() call. The
+ return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+ if in() or out() returned an error, Z_DATA_ERROR if there was a format
+ error in the deflate stream (in which case strm->msg is set to indicate the
+ nature of the error), or Z_STREAM_ERROR if the stream was not properly
+ initialized. In the case of Z_BUF_ERROR, an input or output error can be
+ distinguished using strm->next_in which will be Z_NULL only if in() returned
+ an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to
+ out() returning non-zero. (in() will always be called before out(), so
+ strm->next_in is assured to be defined if out() returns non-zero.) Note
+ that inflateBack() cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_stream FAR *strm));
+/*
+ All memory allocated by inflateBackInit() is freed.
+
+ inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+ state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+ Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+ 1.0: size of uInt
+ 3.2: size of uLong
+ 5.4: size of voidpf (pointer)
+ 7.6: size of z_off_t
+
+ Compiler, assembler, and debug options:
+ 8: DEBUG
+ 9: ASMV or ASMINF -- use ASM code
+ 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+ 11: 0 (reserved)
+
+ One-time table building (smaller code, but not thread-safe if true):
+ 12: BUILDFIXED -- build static block decoding tables when needed
+ 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+ 14,15: 0 (reserved)
+
+ Library content (indicates missing functionality):
+ 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+ deflate code when not needed)
+ 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+ and decode gzip streams (to avoid linking crc code)
+ 18-19: 0 (reserved)
+
+ Operation variations (changes in library functionality):
+ 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+ 21: FASTEST -- deflate algorithm with only one, lowest compression level
+ 22,23: 0 (reserved)
+
+ The sprintf variant used by gzprintf (zero is best):
+ 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+ 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+ 26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+ Remainder:
+ 27-31: 0 (reserved)
+ */
+
+
+ /* utility functions */
+
+/*
+ The following utility functions are implemented on top of the
+ basic stream-oriented functions. To simplify the interface, some
+ default options are assumed (compression level and memory usage,
+ standard memory allocation functions). The source code of these
+ utility functions can easily be modified if you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be at least the value returned
+ by compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+ This function can be used to compress a whole file at once if the
+ input file is mmap'ed.
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen,
+ int level));
+/*
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least the value returned by
+ compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+ compressBound() returns an upper bound on the compressed size after
+ compress() or compress2() on sourceLen bytes. It would be used before
+ a compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
+*/
+
+
+typedef voidp gzFile;
+
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+/*
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb") but can also include a compression level
+ ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+ Huffman only compression as in "wb1h", or 'R' for run-length encoding
+ as in "wb1R". (See the description of deflateInit2 for more information
+ about the strategy parameter.)
+
+ gzopen can be used to read a file which is not in gzip format; in this
+ case gzread will directly read from the file without decompression.
+
+ gzopen returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR). */
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+ gzdopen() associates a gzFile with the file descriptor fd. File
+ descriptors are obtained from calls like open, dup, creat, pipe or
+ fileno (in the file has been previously opened with fopen).
+ The mode parameter is as in gzopen.
+ The next call of gzclose on the returned gzFile will also close the
+ file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+ descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+ gzdopen returns NULL if there was insufficient memory to allocate
+ the (de)compression state.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+ Dynamically update the compression level or strategy. See the description
+ of deflateInit2 for the meaning of these parameters.
+ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+ opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+ Reads the given number of uncompressed bytes from the compressed file.
+ If the input file was not in gzip format, gzread copies the given number
+ of bytes into the buffer.
+ gzread returns the number of uncompressed bytes actually read (0 for
+ end of file, -1 for error). */
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+ voidpc buf, unsigned len));
+/*
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes actually written
+ (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...));
+/*
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written (0 in case of error). The number of
+ uncompressed bytes written is limited to 4095. The caller should assure that
+ this limit is not exceeded. If it is exceeded, then gzprintf() will return
+ return an error (0) with nothing written. In this case, there may also be a
+ buffer overflow with unpredictable consequences, which is possible only if
+ zlib was compiled with the insecure functions sprintf() or vsprintf()
+ because the secure snprintf() or vsnprintf() functions were not available.
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+ Reads bytes from the compressed file until len-1 characters are read, or
+ a newline character is read and transferred to buf, or an end-of-file
+ condition is encountered. The string is then terminated with a null
+ character.
+ gzgets returns buf, or Z_NULL in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+ Writes c, converted to an unsigned char, into the compressed file.
+ gzputc returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+ Reads one byte from the compressed file. gzgetc returns this byte
+ or -1 in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
+/*
+ Push one character back onto the stream to be read again later.
+ Only one character of push-back is allowed. gzungetc() returns the
+ character pushed, or -1 on failure. gzungetc() will fail if a
+ character has been pushed but not read yet, or if c is -1. The pushed
+ character will be discarded if the stream is repositioned with gzseek()
+ or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function. The return value is the zlib
+ error number (see function gzerror below). gzflush returns Z_OK if
+ the flush parameter is Z_FINISH and all output could be flushed.
+ gzflush should be called only when strictly necessary because it can
+ degrade compression.
+*/
+
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+ z_off_t offset, int whence));
+/*
+ Sets the starting position for the next gzread or gzwrite on the
+ given compressed file. The offset represents a number of bytes in the
+ uncompressed data stream. The whence parameter is defined as in lseek(2);
+ the value SEEK_END is not supported.
+ If the file is opened for reading, this function is emulated but can be
+ extremely slow. If the file is opened for writing, only forward seeks are
+ supported; gzseek then compresses a sequence of zeroes up to the new
+ starting position.
+
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error, in
+ particular if the file is opened for writing and the new starting position
+ would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
+/*
+ Rewinds the given file. This function is supported only for reading.
+
+ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
+/*
+ Returns the starting position for the next gzread or gzwrite on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+
+ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+ Returns 1 when EOF has previously been detected reading the given
+ input stream, otherwise zero.
+*/
+
+ZEXTERN int ZEXPORT gzclose OF((gzFile file));
+/*
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state. The return value is the zlib
+ error number (see function gzerror below).
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+ Returns the error message for the last error which occurred on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occurred in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+ Clears the error and end-of-file flags for file. This is analogous to the
+ clearerr() function in stdio. This is useful for continuing to read a gzip
+ file that is being written concurrently.
+*/
+
+ /* checksum functions */
+
+/*
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the
+ compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is NULL, this function returns
+ the required initial value for the checksum.
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster. Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
+/*
+ Update a running crc with the bytes buf[0..len-1] and return the updated
+ crc. If buf is NULL, this function returns the required initial value
+ for the crc. Pre- and post-conditioning (one's complement) is performed
+ within this function so it shouldn't be done by the application.
+ Usage example:
+
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = crc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+
+ /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
+ int windowBits, int memLevel,
+ int strategy, const char *version,
+ int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_stream FAR *strm, int windowBits,
+ unsigned char FAR *window,
+ const char *version,
+ int stream_size));
+#define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+ inflateBackInit_((strm), (windowBits), (window), \
+ ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+ struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char * ZEXPORT zError OF((int err));
+ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
--- /dev/null
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: zutil.c,v 1.1 2005/01/12 07:44:59 mmondor Exp $ */
+
+#include "zutil.h"
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+#ifndef STDC
+extern void exit OF((int));
+#endif
+
+const char * const z_errmsg[10] = {
+"need dictionary", /* Z_NEED_DICT 2 */
+"stream end", /* Z_STREAM_END 1 */
+"", /* Z_OK 0 */
+"file error", /* Z_ERRNO (-1) */
+"stream error", /* Z_STREAM_ERROR (-2) */
+"data error", /* Z_DATA_ERROR (-3) */
+"insufficient memory", /* Z_MEM_ERROR (-4) */
+"buffer error", /* Z_BUF_ERROR (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+ return ZLIB_VERSION;
+}
+
+uLong ZEXPORT zlibCompileFlags()
+{
+ uLong flags;
+
+ flags = 0;
+ switch (sizeof(uInt)) {
+ case 2: break;
+ case 4: flags += 1; break;
+ case 8: flags += 2; break;
+ default: flags += 3;
+ }
+ switch (sizeof(uLong)) {
+ case 2: break;
+ case 4: flags += 1 << 2; break;
+ case 8: flags += 2 << 2; break;
+ default: flags += 3 << 2;
+ }
+ switch (sizeof(voidpf)) {
+ case 2: break;
+ case 4: flags += 1 << 4; break;
+ case 8: flags += 2 << 4; break;
+ default: flags += 3 << 4;
+ }
+ switch (sizeof(z_off_t)) {
+ case 2: break;
+ case 4: flags += 1 << 6; break;
+ case 8: flags += 2 << 6; break;
+ default: flags += 3 << 6;
+ }
+#ifdef DEBUG
+ flags += 1 << 8;
+#endif
+#if defined(ASMV) || defined(ASMINF)
+ flags += 1 << 9;
+#endif
+#ifdef ZLIB_WINAPI
+ flags += 1 << 10;
+#endif
+#ifdef BUILDFIXED
+ flags += 1 << 12;
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+ flags += 1 << 13;
+#endif
+#ifdef NO_GZCOMPRESS
+ flags += 1 << 16;
+#endif
+#ifdef NO_GZIP
+ flags += 1 << 17;
+#endif
+#ifdef PKZIP_BUG_WORKAROUND
+ flags += 1 << 20;
+#endif
+#ifdef FASTEST
+ flags += 1 << 21;
+#endif
+#ifdef STDC
+# ifdef NO_vsnprintf
+ flags += 1 << 25;
+# ifdef HAS_vsprintf_void
+ flags += 1 << 26;
+# endif
+# else
+# ifdef HAS_vsnprintf_void
+ flags += 1 << 26;
+# endif
+# endif
+#else
+ flags += 1 << 24;
+# ifdef NO_snprintf
+ flags += 1 << 25;
+# ifdef HAS_sprintf_void
+ flags += 1 << 26;
+# endif
+# else
+# ifdef HAS_snprintf_void
+ flags += 1 << 26;
+# endif
+# endif
+#endif
+ return flags;
+}
+
+#ifdef DEBUG
+
+# ifndef verbose
+# define verbose 0
+# endif
+int z_verbose = verbose;
+
+void z_error (m)
+ char *m;
+{
+ fprintf(stderr, "%s\n", m);
+ exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+ int err;
+{
+ return ERR_MSG(err);
+}
+
+#if defined(_WIN32_WCE)
+ /* does not exist on WCE */
+ int errno = 0;
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+ Bytef* dest;
+ const Bytef* source;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = *source++; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+ const Bytef* s1;
+ const Bytef* s2;
+ uInt len;
+{
+ uInt j;
+
+ for (j = 0; j < len; j++) {
+ if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+ }
+ return 0;
+}
+
+void zmemzero(dest, len)
+ Bytef* dest;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = 0; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+#endif
+
+
+#ifdef SYS16BIT
+
+#ifdef __TURBOC__
+/* Turbo C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+ voidpf org_ptr;
+ voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ voidpf buf = opaque; /* just to make some compilers happy */
+ ulg bsize = (ulg)items*size;
+
+ /* If we allocate less than 65520 bytes, we assume that farmalloc
+ * will return a usable pointer which doesn't have to be normalized.
+ */
+ if (bsize < 65520L) {
+ buf = farmalloc(bsize);
+ if (*(ush*)&buf != 0) return buf;
+ } else {
+ buf = farmalloc(bsize + 16L);
+ }
+ if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+ table[next_ptr].org_ptr = buf;
+
+ /* Normalize the pointer to seg:0 */
+ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+ *(ush*)&buf = 0;
+ table[next_ptr++].new_ptr = buf;
+ return buf;
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ int n;
+ if (*(ush*)&ptr != 0) { /* object < 64K */
+ farfree(ptr);
+ return;
+ }
+ /* Find the original pointer */
+ for (n = 0; n < next_ptr; n++) {
+ if (ptr != table[n].new_ptr) continue;
+
+ farfree(table[n].org_ptr);
+ while (++n < next_ptr) {
+ table[n-1] = table[n];
+ }
+ next_ptr--;
+ return;
+ }
+ ptr = opaque; /* just to make some compilers happy */
+ Assert(0, "zcfree: ptr not found");
+}
+
+#endif /* __TURBOC__ */
+
+
+#ifdef M_I86
+/* Microsoft C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+# define _halloc halloc
+# define _hfree hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ return _halloc((long)items, size);
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ _hfree(ptr);
+}
+
+#endif /* M_I86 */
+
+#endif /* SYS16BIT */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp malloc OF((uInt size));
+extern voidp calloc OF((uInt items, uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+ voidpf opaque;
+ unsigned items;
+ unsigned size;
+{
+ if (opaque) items += size - size; /* make compiler happy */
+ return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
+ (voidpf)calloc(items, size);
+}
+
+void zcfree (opaque, ptr)
+ voidpf opaque;
+ voidpf ptr;
+{
+ free(ptr);
+ if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
--- /dev/null
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id: zutil.h,v 1.1 2005/01/12 07:44:59 mmondor Exp $ */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#ifdef STDC
+# include <stddef.h>
+# include <string.h>
+# include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+ extern int errno;
+#else
+# include <errno.h>
+#endif
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+ return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+ /* common constants */
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+ /* target dependencies */
+
+#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
+# define OS_CODE 0x00
+# if defined(__TURBOC__) || defined(__BORLANDC__)
+# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+ /* Allow compilation with ANSI keywords only enabled */
+ void _Cdecl farfree( void *block );
+ void *_Cdecl farmalloc( unsigned long nbytes );
+# else
+# include <alloc.h>
+# endif
+# else /* MSC or DJGPP */
+# include <malloc.h>
+# endif
+#endif
+
+#ifdef AMIGA
+# define OS_CODE 0x01
+#endif
+
+#if defined(VAXC) || defined(VMS)
+# define OS_CODE 0x02
+# define F_OPEN(name, mode) \
+ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#if defined(ATARI) || defined(atarist)
+# define OS_CODE 0x05
+#endif
+
+#ifdef OS2
+# define OS_CODE 0x06
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+# define OS_CODE 0x07
+# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+# include <unix.h> /* for fdopen */
+# else
+# ifndef fdopen
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# endif
+# endif
+#endif
+
+#ifdef TOPS20
+# define OS_CODE 0x0a
+#endif
+
+#ifdef WIN32
+# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */
+# define OS_CODE 0x0b
+# endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+# define OS_CODE 0x0f
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600))
+# if defined(_WIN32_WCE)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# ifndef _PTRDIFF_T_DEFINED
+ typedef int ptrdiff_t;
+# define _PTRDIFF_T_DEFINED
+# endif
+# else
+# define fdopen(fd,type) _fdopen(fd,type)
+# endif
+#endif
+
+ /* common defaults */
+
+#ifndef OS_CODE
+# define OS_CODE 0x03 /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+# define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+ /* functions */
+
+#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+#if defined(__CYGWIN__)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+#ifndef HAVE_VSNPRINTF
+# ifdef MSDOS
+ /* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
+ but for now we just assume it doesn't. */
+# define NO_vsnprintf
+# endif
+# ifdef __TURBOC__
+# define NO_vsnprintf
+# endif
+# ifdef WIN32
+ /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
+# if !defined(vsnprintf) && !defined(NO_vsnprintf)
+# define vsnprintf _vsnprintf
+# endif
+# endif
+# ifdef __SASC
+# define NO_vsnprintf
+# endif
+#endif
+
+#ifdef HAVE_STRERROR
+ extern char *strerror OF((int));
+# define zstrerror(errnum) strerror(errnum)
+#else
+# define zstrerror(errnum) ""
+#endif
+
+#if defined(pyr)
+# define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+ * You may have to use the same strategy for Borland C (untested).
+ * The __SC__ check is for Symantec.
+ */
+# define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+# define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+# define zmemcpy _fmemcpy
+# define zmemcmp _fmemcmp
+# define zmemzero(dest, len) _fmemset(dest, 0, len)
+# else
+# define zmemcpy memcpy
+# define zmemcmp memcmp
+# define zmemzero(dest, len) memset(dest, 0, len)
+# endif
+#else
+ extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
+ extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
+ extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# include <stdio.h>
+ extern int z_verbose;
+ extern void z_error OF((char *m));
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) {if (z_verbose>=0) fprintf x ;}
+# define Tracev(x) {if (z_verbose>0) fprintf x ;}
+# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void zcfree OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* ZUTIL_H */