summaryrefslogtreecommitdiffstats
path: root/lanbrowsing/lisa
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitbcb704366cb5e333a626c18c308c7e0448a8e69f (patch)
treef0d6ab7d78ecdd9207cf46536376b44b91a1ca71 /lanbrowsing/lisa
downloadtdenetwork-bcb704366cb5e333a626c18c308c7e0448a8e69f.tar.gz
tdenetwork-bcb704366cb5e333a626c18c308c7e0448a8e69f.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdenetwork@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'lanbrowsing/lisa')
-rw-r--r--lanbrowsing/lisa/AUTHORS2
-rw-r--r--lanbrowsing/lisa/COPYING347
-rw-r--r--lanbrowsing/lisa/ChangeLog8
-rw-r--r--lanbrowsing/lisa/INSTALL176
-rw-r--r--lanbrowsing/lisa/Makefile.am41
-rw-r--r--lanbrowsing/lisa/NEWS1
-rw-r--r--lanbrowsing/lisa/README419
-rw-r--r--lanbrowsing/lisa/addressvalidator.cpp228
-rw-r--r--lanbrowsing/lisa/addressvalidator.h55
-rw-r--r--lanbrowsing/lisa/client.cpp122
-rw-r--r--lanbrowsing/lisa/client.h45
-rw-r--r--lanbrowsing/lisa/configfile.cpp136
-rw-r--r--lanbrowsing/lisa/configfile.h33
-rw-r--r--lanbrowsing/lisa/ipaddress.cpp97
-rw-r--r--lanbrowsing/lisa/ipaddress.h55
-rw-r--r--lanbrowsing/lisa/lisadefines.h19
-rw-r--r--lanbrowsing/lisa/main.cpp290
-rw-r--r--lanbrowsing/lisa/mystring.cpp52
-rw-r--r--lanbrowsing/lisa/mystring.h42
-rw-r--r--lanbrowsing/lisa/netmanager.cpp1058
-rw-r--r--lanbrowsing/lisa/netmanager.h109
-rw-r--r--lanbrowsing/lisa/netscanner.cpp663
-rw-r--r--lanbrowsing/lisa/netscanner.h102
-rw-r--r--lanbrowsing/lisa/strictmain.cpp261
-rw-r--r--lanbrowsing/lisa/stringlist.cpp110
-rw-r--r--lanbrowsing/lisa/stringlist.h40
-rw-r--r--lanbrowsing/lisa/tcpnode.h29
27 files changed, 4540 insertions, 0 deletions
diff --git a/lanbrowsing/lisa/AUTHORS b/lanbrowsing/lisa/AUTHORS
new file mode 100644
index 00000000..d13cadc9
--- /dev/null
+++ b/lanbrowsing/lisa/AUTHORS
@@ -0,0 +1,2 @@
+Written and maintained by
+ Alexander Neundorf <neundorf@kde.org>
diff --git a/lanbrowsing/lisa/COPYING b/lanbrowsing/lisa/COPYING
new file mode 100644
index 00000000..ded002ea
--- /dev/null
+++ b/lanbrowsing/lisa/COPYING
@@ -0,0 +1,347 @@
+NOTE! The GPL below is copyrighted by the Free Software Foundation, but
+the instance of code that it refers to (the kde programs) are copyrighted
+by the authors who actually wrote it.
+
+---------------------------------------------------------------------------
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/lanbrowsing/lisa/ChangeLog b/lanbrowsing/lisa/ChangeLog
new file mode 100644
index 00000000..7d0ef7e8
--- /dev/null
+++ b/lanbrowsing/lisa/ChangeLog
@@ -0,0 +1,8 @@
+0.1.3
+-security fixes: fixed LOGNAME vulnerabilty and another possible buffer overflow
+
+Version 0.1.2
+-various fixes and improvements...
+
+Version 0.1
+-initial version
diff --git a/lanbrowsing/lisa/INSTALL b/lanbrowsing/lisa/INSTALL
new file mode 100644
index 00000000..f8bad0c1
--- /dev/null
+++ b/lanbrowsing/lisa/INSTALL
@@ -0,0 +1,176 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes a while. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/kde/bin', `/usr/local/kde/lib', etc. You can specify an
+installation prefix other than `/usr/local/kde' by giving `configure'
+the option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made.
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
+
diff --git a/lanbrowsing/lisa/Makefile.am b/lanbrowsing/lisa/Makefile.am
new file mode 100644
index 00000000..ff1f8433
--- /dev/null
+++ b/lanbrowsing/lisa/Makefile.am
@@ -0,0 +1,41 @@
+##
+AM_CXXFALGS = -fno-rtti -fno-exceptions
+
+#CXXFLAGS = -fno-rtti -fno-exceptions
+
+bin_PROGRAMS = lisa reslisa
+#
+# Programs to compile, Manpages to install and Versions
+#
+#INCLUDES = $(all_includes)
+
+lisa_SOURCES = \
+addressvalidator.cpp \
+netmanager.cpp \
+netscanner.cpp \
+ipaddress.cpp \
+main.cpp \
+mystring.cpp \
+client.cpp \
+configfile.cpp
+
+reslisa_SOURCES = \
+addressvalidator.cpp \
+netmanager.cpp \
+netscanner.cpp \
+ipaddress.cpp \
+strictmain.cpp \
+mystring.cpp \
+client.cpp \
+configfile.cpp
+
+lisa_LDADD = $(LIBSOCKET)
+lisa_LDFLAGS = $(KDE_EXTRA_RPATH)
+
+reslisa_LDADD = $(LIBSOCKET)
+reslisa_LDFLAGS = $(KDE_EXTRA_RPATH)
+
+misc_DATA = README
+miscdir = $(kde_datadir)/lisa
+EXTRA_DIST=$(misc_DATA)
+
diff --git a/lanbrowsing/lisa/NEWS b/lanbrowsing/lisa/NEWS
new file mode 100644
index 00000000..898a3dab
--- /dev/null
+++ b/lanbrowsing/lisa/NEWS
@@ -0,0 +1 @@
+See ChangeLog.
diff --git a/lanbrowsing/lisa/README b/lanbrowsing/lisa/README
new file mode 100644
index 00000000..c6d5d1bd
--- /dev/null
+++ b/lanbrowsing/lisa/README
@@ -0,0 +1,419 @@
+This is the readme to the Lan Information Server LISa and the Restricted LAN
+Information Server resLISa.
+
++---------------+
+| LISa |
++---------------+
+
+LISa is intended to provide a kind of "network neighbourhood" but only
+relying on the TCP/IP protocol stack, no smb or whatever.
+It is completely independent from KDE/Qt.
+The list of running hosts is provided via TCP port 7741.
+
+LISa supports two ways of finding hosts:
+
+1. you give LISa a range of of IP-addresses, then LISa will send
+ICMP echo requests to all given IP addresses and wait for the answers
+
+2. you can say LISa to execute "nmblookup "*" ", i.e. the command line tool
+nmblookup must be installed, it is part of the samba package.
+nmblookup "*" sends a broadcast to the attached networks and all hosts
+running smb-services will answer this broadcast
+
+lisa and reslisa are distributed under the GNU General Public License.
+
+
+
+How it works
+-------------
+
+In the configuration file you provide a range of IP-addresses which
+LISa should check, wether they are running. In the most simple case
+this could be your network address/subnetmask, then LISa would
+check every possible host of your network wether it is running.
+The hosts are checked using ICMP echo requests. To be able to send and receive
+ICMP echo requests and replies the program has to open a so-called
+"raw socket". Therefor it needs root privileges. This socket is opened
+right after the start of the program, after successfully opening the socket
+root privileges are dropped immediately (see main.cpp and strictmain.cpp).
+If you configure LISa this way, that it also uses nmblookup, it will
+popen("nmblookup \"*\"") and then parse the results.
+
+Since the ICMP requests and the broadcasts can cause some network traffic
+if there are more than one such server running in one network, the servers
+cooperate with each other. Before they start pinging (or nmblookup),
+they send a broadcast on port 7741.
+If somebody answers this broadcast, they will retrieve the complete list
+of running hosts via TCP port 7741 from this host and will not start to
+ping (or nmblookup) theirselves. If nobody answers, the host which sent
+the broadcast will start pinging the hosts (or nmblookup) and then open a
+socket which listens for the mentioned broadcasts. If the host received an
+answer to his broadcast, it won't have the socket for listening to the
+broadcasts open. So usually exactly one of the servers will have this
+socket open and only this one will actually ping (or nmblookup) the hosts.
+In other words, the servers are lazy, they work like "I will only do something
+if nobody else can do it for me".
+
+There is another feature which reduces the network load. Let's say you configured LISa
+to update all 10 minutes. Now you don't access your server very often.
+If nobody accesses the server for the last update period, the server will
+update (either itself or from the one which actually does the work) and then
+double its update period, i.e. the next update will happen after 20 minutes.
+This will happen 4 times, so if nobody accesses the server with update period
+10 minutes for a long time, its update interval will increase up to
+160 minutes, almost three hours. If then somebody accesses the data from the
+server, he will get an old list ( up to 160 minutes old). With accessing
+the server will reset its update interval to its initial value,
+i.e. 10 minutes and immediately start updating if the last update is more
+than these 10 minutes over. This means if you get a very old list, you can try
+some seconds later again and you should get a current version.
+This will have fast effect for the servers, which don't ping (or nmblookup)
+theirselves, since only one user usually accesses them, and it will have
+less effect for the server which does the pinging (or nmblookup), since
+this server is accessed from all other servers in the network.
+
+
+This way it is possible that many hosts in a network run this server, but
+the net load will remain low. For the user it is not necessary to know
+wether there is a server (i.e. a name server or fileserver or whatever)
+in the network which also runs LISa. He can always run LISa locally
+and LISa will detect if there is one, transparently to the user.
+The first client for LISa is an ioslave for KDE2, so the user
+can enter there lan://localhost/ or lan:/, which will both
+contact LISa on the own system.
+If there is a machine which runs all the time and the user knows
+that this machine also runs LISa, he can use his LISa client directly with
+this server (would be with the mentioned ioslave lan://the_server_name/).
+
+If you don't want that your LISa takes part in the broadcasting, but always
+does the pinging itself, make it use another port with the
+command line option --port or -p.
+This is not recommended !
+
+If you send SIGHUP to LISa, it will reread its configfile.
+If you send SIGUSR1 to LISa, it will print some status information to stdout.
+
+The data provided over the socket has a simple format:
+
+<decimal ip address in network byte order><one space 0x20><full name of the host><a terminating '\0'><newline '\n'>
+and the last line
+0 succeeded<'\n'>
+
+e.g.
+
+"17302538 some_host.whatever.de
+18285834 linux.whatever.de
+17827082 nameserver.whatever.de
+0 succeeded
+"
+
+This should make it easy parseable.
+
+If there are very strict security rules in your network, some people
+might consider the pinging a potential attack. If you
+have problems with this, try the restricted version, resLISa.
+
++------------------+
+| resLISa |
++------------------+
+
+If you hav very strict security rules in your network or you don't want to
+have another port open or whatever, you can use resLISa.
+
+With resLISa you can't ping whole networks and address ranges, you can give
+resLISa up to currently 64 hosts by their names in its config file. These
+will be pinged. You are still able to use nmblookup.
+resLISa will also only provide the information over a unix domain socket, i.e.
+not over the network. The name of the socket is "/tmp/resLisa-YourLoginname",
+so resLISa can be safely run by more users on one machine.
+Since it should also not produce a security risk of any kind it is
+safe to install reslisa setuid root. root privileges will be dropped
+right after startup (see strictmain.cpp), they are only needed to create a raw socket
+for sending the ICMP echo requests..
+It will also not send or receive broadcasts.
+The first client for this is also an ioslave for KDE2 (makes rlan:/ in e.g. konqy).
+
+
+
+Configuration
+-------------
+
+Now an example config file:
+
+PingAddresses = 192.168.100.0/255.255.255.0;192.168.100.10-192.168.199.19;192.168.200.1;192-192.168-168.100-199.0-9;
+PingNames = bb_mail;
+AllowedAddresses = 192.168.0.0/255.255.0.0
+BroadcastNetwork = 192.168.100.0/255.255.255.0
+SearchUsingNmblookup = 1 #also try nmblookup
+FirstWait = 30 #30 hundredth seconds
+SecondWait = -1 #only one try
+#SecondWait = 60 #try twice, and the second time wait 0.6 seconds
+UpdatePeriod = 300 #update after 300 secs
+DeliverUnnamedHosts = 0 #don't publish hosts without name
+MaxPingsAtOnce = 256 #send up to 256 ICMP echo requests at once
+
+
+PingAddresses
+
+This is probably the most important entry.
+Here you say which addresses will be pinged. You can specify multiple
+ranges, they are divided by semicolons.
+
+There are four possible ways to define addresses:
+-net address/network mask: 192.168.100.0/255.255.255.0, i.e. an IP address
+ and the assigned network mask. This doesn't have the real network address
+ and netmask of your machine, it can be less. E.g. if you have
+ 10.0.0.0/255.0.0.0, you could specify 10.1.2.0/255.255.255.0 if you are only
+ interested in these addresses. The combination IP address-network mask
+ must be divided by a slash "/" and the address does not have to be a real
+ network address, it can also be a host address of the desired network,
+ i.e. 10.12.34.67/255.0.0.0 is the same as 10.0.0.0/255.0.0.0 .
+
+-a range of following IP addresses: 192.168.100.10-192.168.199.19, i.e.
+ an IP-address where pinging will start and an IP-address where pinging will end.
+ Both addresses must be divided by a "-".
+ In this example this would produce 199-100+1=100, 100*256=25.600,
+ 25.600+(19-10+1)=25.590 addresses
+
+-an IP-address can be presented by its four decimal numbers, you can specify
+ ranges four each of these four numbers: 192-192.169-171.100-199.0-9
+ In this example all IP addresses with first number 192, second number from
+ 168 to 168, third number from 100 up to 199 and last number from 0 up
+ to 9 will be pinged. This would give 1*1*100*10=1.000 addresses.
+ This is probably only useful in very seldom cases.
+ Here you have to provide ranges for every four numbers, always divided
+ by "-".
+
+-single IP-addresses: 192.168.200.1
+ well, single IP addresses or host names
+
+It is also valid to leave this entry empty.
+
+
+PingNames
+ here you can additionally specify hosts to ping using their names.
+ The names have to be divided by semicolons.
+
+It is also valid to leave this entry empty.
+
+
+AllowedAddresses
+
+ This is also very important. LISa will only ping addresses,
+ accept clients and answer broadcasts from addresses, which are covered by the
+ addresses given in this line. You can add up to 32 network addresses/network masks
+ or single addresses. Divide them by ; and don't put empty space between the
+ addresses !
+ Example: 192.168.0.0/255.255.0.0;192.169.0.0
+ -> a complete network and a single address are valid
+ Always make this as strict as possible, usually
+ your network address/subnetmask is a good choice.
+
+
+BroadcastNetwork
+
+ This entry contains exactly one network address/subnet mask.
+ To this network broadcasts will be sent. Usually this should be your
+ own network address/subnetmask.
+ Example: 192.168.0.0/255.255.0.0
+
+
+SearchUsingNmblookup
+
+ Here you can give 0 or 1.
+ 1 means that LISa will execute "nmblookup "*" " and parse the output
+ from this command. This produces less network traffic than the pinging,
+ but you will only get hosts which have a smb-service running (Windows
+ machines or machines running samba).
+ If you enable this option and also give IP addresses to ping, then nmblookup
+ will be executed first and then the pinging will start.
+ Then only addresses will be pinged, which were not already delivered
+ from nmblookup. This should slightly decrease the network load.
+
+
+FirstWait
+
+ If LISa pings, i.e. if it sends the ICMP echo requests, it sends a bunch
+ of requests at once, and the it will wait for the number of hundredth seconds
+ you specify here. Usually values from 5 to 50 should be good, the maximum
+ is 99 (gives 0.99 seconds, a very long time).
+ Try to make this value as small as possible while still finding all
+ running hosts.
+
+
+SecondWait
+
+ After LISa sent the echo requests the first time, it can be possible
+ that some hosts were not found. To improve the results, LISa can ping a
+ second time. This time it will only ping hosts, from which it didn't receive
+ answers. If you have good results with pinging only once, you can disable
+ the second time with setting SecondWait to -1.
+ Otherwise it might be a good idea to make this value a little bit bigger
+ than the value for FirstWait, since the hosts which were not found
+ on the first try, are probably slower or further away so they might take
+ some milliseconds longer to answer.
+ Usually values from 5 to 50 should be good or -1 to disable the second scan.
+ The maximum is 99 (gives 0.99 seconds, a very long time).
+
+
+UpdatePeriod
+
+ This is the interval after which LISa will update, i.e. ping or nmblookup
+ or get the list of hosts from the LISa server which actually does the pinging.
+ Valid values are between 30 seconds and 1800 seconds (half an hour).
+ If you have a big network, don't make the interval to small (to keep
+ network load low). Values from 300 to 900 seconds (5 to 15 minutes) might be
+ a good idea. Keep in mind that the update period is doubled
+ if nobody accesses the server, up to 4 times, so the interval will become
+ 16 times the value given here and will be reseted to the value given here
+ if somebody accesses the server.
+
+
+DeliverUnnamedHosts
+
+ If an answer to an echo request from an IP address was received, were LISa
+ could not determine a name, it will be only delivered over the port
+ if you set this to 1.
+ I am not really sure if this is a useful feature, but maybe
+ there are some infrastructure devices in your network without assigned names,
+ so they don't have to be published. Set this to 0 if you want to keep them
+ secret ;-)
+ If unsure, say 0.
+
+MaxPingsAtOnce
+
+ When sending the pings (echo requests), LISa sends a bunch of these at once
+ and then waits for the answers. By default there are 256 pings sent at once,
+ usually you should not need the change this value. If you make it much bigger,
+ the internal receive buffers for the answers to the echo requests may become to small,
+ if you make it to small, the updating will be slower.
+
+
+Three different example config files:
+
+You are member of a small network with 24 bit network mask, i.e.
+up to 256 hosts:
+
+PingAddresses = 192.168.100.0/255.255.255.0
+AllowedAddresses = 192.168.100.0/255.255.255.0
+BroadcastNetwork = 192.168.100.0/255.255.255.0
+SearchUsingNmblookup = 0 #don't use nmblookup
+FirstWait = 20 #20 hundredth seconds
+SecondWait = 30 #30 hundredth seconds on the seconds try
+UpdatePeriod = 300 #update after 300 secs
+DeliverUnnamedHosts = 0 #don't publish hosts without name
+
+
+You are only interested in hosts running smb services and you don't have
+routers in your network:
+
+AllowedAddresses = 192.168.100.0/255.255.255.0
+BroadcastNetwork = 192.168.100.0/255.255.255.0
+SearchUsingNmblookup = 1 #use nmblookup
+UpdatePeriod = 300 #update after 300 secs
+DeliverUnnamedHosts = 0 #don't publish hosts without name
+
+
+The same network, but here both nmblookup and pinging is used.
+
+PingAddresses = 192.168.100.0/255.255.255.0
+PingNames = bb_mail
+AllowedAddresses = 192.168.0.0/255.255.0.0
+BroadcastNetwork = 192.168.100.0/255.255.255.0
+SearchUsingNmblookup = 1 #also try nmblookup
+FirstWait = 30 #30 hundredth seconds
+SecondWait = -1 #only one try
+#SecondWait = 60 #try twice, and the second time wait 0.6 seconds
+UpdatePeriod = 300 #update after 300 secs
+DeliverUnnamedHosts = 0 #don't publish hosts without name
+MaxPingsAtOnce = 256 #send up to 256 ICMP echo requests at once
+
+And now a configuration file for resLISa, PingAddresses is not used by resLISa,
+neither is BroadcastNetwork.
+
+PingNames = bb_mail;some_host;some_other_host
+AllowedAddresses = 192.168.0.0/255.255.0.0
+SearchUsingNmblookup = 1 # use nmblookup
+FirstWait = 30 #30 hundredth seconds
+SecondWait = -1 #only one try
+#SecondWait = 60 #try twice, and the second time wait 0.6 seconds
+UpdatePeriod = 300 #update after 300 secs
+DeliverUnnamedHosts = 1 #also publish hosts without name
+MaxPingsAtOnce = 256 #send up to 256 ICMP echo requests at once
+
+
++----------------------+
+| Installation |
++----------------------+
+
+Both reslisa and lisa open a so called raw socket to send and receive
+ICMP echo requests (pings). To do this, they need root privileges.
+
+lisa offers a service on TCP port 7741, it should be installed by root
+and started when the system comes up, it depends on your distribution
+how to do this.
+
+reslisa is intended to be started per user, it doesn't offer anything to
+the network. It needs to be installed setuid root.
+
+If you use the rlan-ioslave from KDE2, reslisa can be started automatically
+by reslisa.
+
+lisa reads the file lisarc, reslisa reads the file reslisarc.
+If you want to be able to configure both from the KDE Control Center,
+you have to start them using the command line switch -K.
+
+For more information where they look for configuration files read
+the next chapter.
+
+
++--------------------------------------------+
+| Command Line Options and other usage |
++--------------------------------------------+
+
+The following command line options are supported:
+
+-v, --version prints a short version info
+-h, --help gives an overview over teh command line options
+
+Some options regarding search order for the configuration files.
+For reslisa the file is named reslisarc instead lisarc.
+
+-u, --unix search at first for $HOME/.lisarc, then
+ for /etc/lisarc, this is the default behaviour
+
+-k, --kde1 search at first for $HOME/.kde/share/config/lisarc,
+ then for $KDEDIR/share/config/lisarc
+
+-K, --kde2 looks for the file lisarc in every directory
+ returned by running "kde-config --path config"
+
+-c, --config=FILE read this and no other configuration file
+
+
+This one is only available for LISa, not for resLISa.
+
+-p, --port PORTNR start the server om this portnumber
+ if you use this LISa won't be able to
+ cooperate with other LISa's in the network
+
+
+If you send the Hangup-Signal to lisa or reslisa, it will reread its
+configuration file (killall -HUP lisa).
+
+If you send the User1-Signal to lisa or reslisa, it will print some status
+information to the standard output (killall -USR1 lisa). You won't see
+anything if the console from which lisa/reslisa was started has terminated.
+
+
+LISa and resLISa need a libstdc++ (it uses only the string-class from it),
+it *doesn't* need neither Qt nor KDE.
+
+So, that's it for now.
+If you have suggestions, problems or whatever, contact me.
+
+
+Have fun
+Alexander Neundorf
+<neundorf@kde.org>
+
diff --git a/lanbrowsing/lisa/addressvalidator.cpp b/lanbrowsing/lisa/addressvalidator.cpp
new file mode 100644
index 00000000..aa292806
--- /dev/null
+++ b/lanbrowsing/lisa/addressvalidator.cpp
@@ -0,0 +1,228 @@
+/* addressvalidator.cpp
+ *
+ * Copyright (c) 2000, Alexander Neundorf
+ * neundorf@kde.org
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the COPYING file.
+ *
+ * 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.
+ *
+ */
+
+#include "addressvalidator.h"
+#include "mystring.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <iostream>
+using namespace std;
+
+#ifdef LISA_DEBUG
+#undef LISA_DEBUG
+#endif
+#define LISA_DEBUG 0
+#define dcerr if (LISA_DEBUG==1) std::cerr<<"AddressValidator::"
+
+AddressValidator::AddressValidator(const MyString& addressSpecs)
+//this is 127.0.0.0
+:localhostNet(htonl(0x7f000000))
+//with mask 255.255.255.0
+,localhostMask(htonl(0xffffff00))
+{
+ clearSpecs();
+ MyString tmp=addressSpecs;
+ setValidAddresses(tmp);
+}
+
+AddressValidator::AddressValidator()
+ //this is 127.0.0.0
+ :localhostNet(htonl(0x7f000000))
+ //with mask 255.255.255.0
+ ,localhostMask(htonl(0xffffff00))
+{
+ clearSpecs();
+}
+
+AddressValidator::~AddressValidator()
+{}
+
+void AddressValidator::configure(Config& config)
+{
+ MyString tmp=stripWhiteSpace(config.getEntry("AllowedAddresses",""));
+ tmp=tmp+";";
+ setValidAddresses(tmp);
+ dcerr<<"configure(): "<<tmp<<std::endl;
+}
+
+
+void AddressValidator::setValidAddresses(MyString addressSpecs)
+{
+ dcerr<<"setValidAddresses"<<std::endl;
+ allowedHosts=addressSpecs;
+ MyString nextPart;
+ while (!addressSpecs.isEmpty())
+ {
+ dcerr<<"setValidAddresses: "<<addressSpecs<<std::endl;
+ int pos=addressSpecs.find(";");
+ nextPart=addressSpecs.left(pos);
+ addressSpecs=addressSpecs.mid(pos+1);
+ dcerr<<"setValidAddresses: nextPart: "<<nextPart<<std::endl;
+ if ((nextPart.contains('.')==3) && (nextPart.contains('-')==0))
+ {
+ addSpec(EXACTADDR_SPEC,inet_addr(nextPart.data()));
+ dcerr<<"setValidAddresses: exact addr: "
+ <<std::ios::hex<<inet_addr(nextPart.data())<<std::ios::dec<<std::endl;
+ }
+ else if ((nextPart.contains('-')==1) && (nextPart.contains('.')==6))
+ {
+ int p2=nextPart.find("-");
+ MyString from=nextPart.left(p2);
+ MyString to=nextPart.mid(p2+1);
+ addSpec(RANGE_SPEC,ntohl(inet_addr(from.data())),ntohl(inet_addr(to.data())));
+ }
+ else if ((nextPart.contains('-')==4) && (nextPart.contains('.')==3))
+ {
+ unsigned int i1=0;
+ unsigned int i2=0;
+ int p2=0;
+ MyString rest=nextPart+'.';
+ MyString digit;
+
+ for (int i=0; i<4; i++)
+ {
+ p2=rest.find("-");
+ digit=rest.left(p2);
+ i1=i1<<8;
+ i1+=atoi(digit.data());
+ rest=rest.mid(p2+1);
+ p2=rest.find(".");
+ digit=rest.left(p2);
+ i2=i2<<8;
+ i2+=atoi(digit.data());
+ rest=rest.mid(p2+1);
+ };
+ addSpec(MULTIRANGE_SPEC,i1,i2);
+ }
+ else
+ {
+ pos=nextPart.find('/');
+ MyString netStr=nextPart.left(pos);
+ MyString maskStr=nextPart.mid(pos+1);
+ int mask=inet_addr(maskStr.data());
+ int net= (inet_addr(netStr.data()) & mask);
+ dcerr<<"setValidAddresses: net/mask: "
+ <<std::ios::hex<<net<<"/"<<mask<<std::ios::dec<<std::endl;
+ addSpec(NETMASK_SPEC,net,mask);
+ }
+ }
+}
+
+void AddressValidator::clearSpecs()
+{
+ allowedHosts="";
+ for (int i=0; i<MAX_SPECS; i++)
+ {
+ specs[i].address=0;
+ specs[i].mask=0;
+ specs[i].typeOfSpec=NO_SPEC;
+ }
+}
+
+void AddressValidator::addSpec(int type, int address, int mask)
+{
+ for (int i=0; i<MAX_SPECS; i++)
+ {
+ if (specs[i].typeOfSpec==NO_SPEC)
+ {
+ specs[i].address=address;
+ specs[i].mask=mask;
+ specs[i].typeOfSpec=type;
+ return;
+ }
+ }
+}
+
+int AddressValidator::isValid(int addressNBO)
+{
+ dcerr<<"isValid: "
+ <<std::ios::hex<<addressNBO<<std::ios::dec<<std::endl;
+ //localhost is always allowed
+ dcerr<<"isValid() local net: "<<
+ std::ios::hex<<localhostNet<<" mask: "<<localhostMask<<" AND: "<<(addressNBO &
+ localhostMask)<<std::ios::dec<<std::endl;
+ if ((addressNBO & localhostMask) == localhostNet)
+ return 1;
+
+ for (int i=0; i<MAX_SPECS; i++)
+ {
+ if (specs[i].typeOfSpec==NO_SPEC)
+ {
+ //since the specifications are always entered from the beginning
+ //of the array, we already passed the last one if we get here
+ //so we can return now "it is invalid !" ;-)
+ return 0;
+ //continue;
+ }
+ else if (specs[i].typeOfSpec==EXACTADDR_SPEC)
+ {
+ dcerr<<"isValid: comparing "
+ <<std::ios::hex<<specs[i].address<<std::ios::dec<<std::endl;
+ if (addressNBO==specs[i].address)
+ {
+ dcerr<<"isValid: exact address"<<std::endl;
+ return 1; // this one is allowed to :-)
+ }
+ }
+ else if (specs[i].typeOfSpec==NETMASK_SPEC)
+ {
+ dcerr<<"isValid: ANDing "<<
+ std::ios::hex<<(addressNBO & specs[i].mask)<<" "<<
+ specs[i].address<<std::ios::dec<<std::endl;
+ if ((addressNBO & specs[i].mask) == specs[i].address)
+ {
+ dcerr<<"isValid: net/mask"<<std::endl;
+ return 1;
+ }
+ }
+ else if (specs[i].typeOfSpec==RANGE_SPEC)
+ {
+ if ((ntohl(addressNBO)>=specs[i].address) && (ntohl(addressNBO)<=specs[i].mask))
+ {
+ dcerr<<"isValid: range"<<std::endl;
+ return 1;
+ }
+ }
+ else if (specs[i].typeOfSpec==MULTIRANGE_SPEC)
+ {
+ unsigned int addr=ntohl(addressNBO);
+ dcerr<<"isValid ntohl="<<hex<<addr<<" addr: "<<specs[i].address<<" ma: "<<specs[i].mask<<dec<<std::endl;
+ unsigned int mask=0x000000ff;
+ int failure=0;
+ for (int j=0; j<4; j++)
+ {
+ dcerr<<"isValid "<<hex<<"mask="<<mask<<" addr="<<(addr&mask)<<" addr="<<(specs[i].address & mask)<<" ma="<<(specs[i].mask&mask)<<std::endl;
+ if (((addr & mask) < (specs[i].address & mask))
+ || ((addr & mask) > (specs[i].mask & mask)))
+ {
+ failure=1;
+ break;
+ }
+ mask=mask<<8;
+ }
+ dcerr<<"isValid: multirange"<<std::endl;
+ if (!failure)
+ return 1;
+ }
+ }
+ //if ((addressNBO==htonl(0x0a040801)) || (addressNBO==htonl(0xc0a80001))) return 0;
+ dcerr<<"isValid: invalid address"<<std::endl;
+ return 0;
+}
+
diff --git a/lanbrowsing/lisa/addressvalidator.h b/lanbrowsing/lisa/addressvalidator.h
new file mode 100644
index 00000000..6f1c723e
--- /dev/null
+++ b/lanbrowsing/lisa/addressvalidator.h
@@ -0,0 +1,55 @@
+/* addressvalidator.h
+ *
+ * Copyright (c) 2000, Alexander Neundorf
+ * neundorf@kde.org
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the COPYING file.
+ *
+ * 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.
+ *
+ */
+
+#ifndef ADDRESSVALIDATOR_H
+#define ADDRESSVALIDATOR_H
+
+#include "lisadefines.h"
+#include "mystring.h"
+#include "configfile.h"
+
+#define NO_SPEC 0
+#define NETMASK_SPEC 1
+#define EXACTADDR_SPEC 2
+#define RANGE_SPEC 3
+#define MULTIRANGE_SPEC 4
+
+struct AddressSpec
+{
+ int address;
+ int mask;
+ int typeOfSpec;
+};
+
+class AddressValidator
+{
+ public:
+ AddressValidator(const MyString& addressSpecs);
+ AddressValidator();
+ ~AddressValidator();
+ void configure(Config& config);
+ void setValidAddresses(MyString addressSpecs);
+ void clearSpecs();
+ int isValid(int addressNBO);
+ MyString validAddresses() {return allowedHosts;};
+ private:
+ int localhostNet;
+ int localhostMask;
+ MyString allowedHosts;
+ void addSpec(int type, int address, int mask=0);
+ AddressSpec specs[MAX_SPECS];
+};
+
+#endif
diff --git a/lanbrowsing/lisa/client.cpp b/lanbrowsing/lisa/client.cpp
new file mode 100644
index 00000000..21069a17
--- /dev/null
+++ b/lanbrowsing/lisa/client.cpp
@@ -0,0 +1,122 @@
+/* client.cpp
+ *
+ * Copyright (c) 2000, Alexander Neundorf
+ * neundorf@kde.org
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the COPYING file.
+ *
+ * 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.
+ *
+ */
+
+#include "netmanager.h"
+#include "client.h"
+#include "lisadefines.h"
+
+#include <iostream>
+#include <unistd.h>
+
+#include <strings.h>
+
+#ifdef LISA_DEBUG
+#undef LISA_DEBUG
+#endif
+
+#ifdef dcerr
+#undef dcerr
+#endif
+
+#define LISA_DEBUG 0
+#define dcerr if (LISA_DEBUG==1) std::cerr<<"Client::"
+
+
+Client::Client(NetManager* parent, int socketFD, int closeOnDelete)
+:parentServer(parent)
+,m_fd(socketFD)
+,m_done(0)
+,m_closeOnDelete(closeOnDelete)
+{
+ dcerr<<"ctor created new client"<<std::endl;
+ if (m_fd==-1) m_done=1;
+ m_creationTime=time(0);
+}
+
+Client::Client()
+:parentServer(0)
+,m_fd(-1)
+,m_done(1)
+,m_closeOnDelete(1)
+{
+ m_creationTime=time(0);
+}
+
+Client::Client(const Client& c)
+:parentServer(c.parentServer)
+,m_fd(c.m_fd)
+,m_creationTime(c.m_creationTime)
+,m_done(c.m_done)
+,m_closeOnDelete(1)
+{
+ dcerr<<"Client copy ctor"<<std::endl;
+}
+
+int Client::tryToGetInfo()
+{
+ dcerr<<"tryToGetInfo: m_done: "<<m_done<<std::endl;
+ if (done()) return 1;
+ if (m_fd==-1)
+ {
+ close();
+ return 1;
+ }
+ dcerr<<"tryToGetInfo: calling data.getFile()"<<std::endl;
+ if (!parentServer->isInformed()) return 0;
+ //we fork now, so that writing to the client can't block the server process
+ /* int pid=fork();
+ if (pid==-1)
+ {
+ //parent
+ dcerr<<"NetScanner::scan: error occurred"<<std::endl;
+ return 1;
+ }
+ else if (pid!=0)
+ {
+ //parent
+ return 1;
+ };*/
+ //child
+ //this one does it all :-)
+ dcerr<<"tryToGetInfo: sending data to client"<<std::endl;
+ parentServer->writeDataToFD(fd(),0);
+ close();
+ //exit(0);
+ return 1;
+}
+
+void Client::close()
+{
+ if (m_fd!=-1) ::close(m_fd);
+ m_fd=-1;
+ m_done=1;
+}
+
+void Client::read()
+{
+ dcerr<<"read()"<<std::endl;
+ if (m_fd==-1) return;
+ char buf[1024];
+ //the clients should not send us something !
+ int result=::read(m_fd,buf,1024);
+ if (result>=0) close();
+}
+
+Client::~Client()
+{
+ if (m_closeOnDelete)
+ close();
+}
+
diff --git a/lanbrowsing/lisa/client.h b/lanbrowsing/lisa/client.h
new file mode 100644
index 00000000..efcf5f86
--- /dev/null
+++ b/lanbrowsing/lisa/client.h
@@ -0,0 +1,45 @@
+/* client.h
+ *
+ * Copyright (c) 2000, Alexander Neundorf
+ * neundorf@kde.org
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the COPYING file.
+ *
+ * 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.
+ *
+ */
+
+#ifndef CLIENT_H
+#define CLIENT_H
+
+#include <time.h>
+
+class NetManager;
+
+class Client
+{
+ public:
+ Client(NetManager* parent, int socketFD, int closeOnDelete=1);
+ Client();
+ Client(const Client& c);
+ ~Client();
+ int tryToGetInfo();
+ int done() {return m_done;};
+ int fd() {return m_fd;};
+ void read();
+ void close();
+ time_t age() {return time(0)-m_creationTime;};
+ private:
+ NetManager *parentServer;
+ int m_fd;
+ //if something goes wrong close the connection after a timeout
+ time_t m_creationTime;
+ int m_done;
+ int m_closeOnDelete;
+};
+
+#endif
diff --git a/lanbrowsing/lisa/configfile.cpp b/lanbrowsing/lisa/configfile.cpp
new file mode 100644
index 00000000..5c1e4a65
--- /dev/null
+++ b/lanbrowsing/lisa/configfile.cpp
@@ -0,0 +1,136 @@
+/* configfile.cpp
+ *
+ * Copyright (c) 1998, 2000, Alexander Neundorf
+ * neundorf@kde.org
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the COPYING file.
+ *
+ * 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.
+ *
+ */
+
+#include "configfile.h"
+
+#include <iostream>
+#include <fstream>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef LISA_DEBUG
+#undef LISA_DEBUG
+#endif
+#define LISA_DEBUG 0
+
+#ifdef dcerr
+#undef dcerr
+#endif
+
+#define dcerr if (LISA_DEBUG==1) std::cerr<<"Config::"
+
+
+#define CFGBUFSIZE 16*1024
+
+Config::Config(const MyString& name/*,String path*/)
+{
+ char buff[CFGBUFSIZE],c;
+/* String s,empty="#############################################################################################################################################################";
+ String home=getenv("HOME");
+
+ if (!home.empty()) home+=String("/")+name;
+ if (fexists(home)==0)
+ {
+ home=path+"/"+name;
+ if (fexists(home)==0)
+ {
+ home=name;
+ if (fexists(home)==0) return;
+ };
+ };*/
+ std::ifstream inf(name.data());
+ if (!inf)
+ {
+ std::cout<<"could not open file "<<name<<std::endl;
+ return;
+ }
+ dcerr<<"Config(): opened file "<<name<<std::endl;
+ //read the file
+ char key[CFGBUFSIZE], value[CFGBUFSIZE];
+ do
+ {
+ char* buffStart=buff;
+ //inf.getline(buff,16*1024,'\n');
+ int bufSize(CFGBUFSIZE);
+ int lineBroken(0);
+ do
+ {
+ lineBroken=0;
+ inf.get(buffStart,bufSize,'\n');
+ inf.get(c);
+ int l=strlen(buffStart);
+ if (l==0)
+ break;
+ if (buffStart[l-1]=='\\')
+ {
+ buffStart=buffStart+l-1;
+ bufSize=bufSize+1-l;
+ lineBroken=1;
+ }
+ } while ((lineBroken) && (!inf.eof()));
+ //make it ignore comments
+ char *theChar=strchr(buff,'#');
+ if (theChar!=0)
+ *theChar='\0';
+ //now divide the line into key and value
+ theChar=strchr(buff,'=');
+ if (theChar!=0)
+ {
+ *theChar='\0';
+ key[0]='\0';
+ sscanf(buff,"%8000s",key);
+ //do we have something valid ?
+ if (key[0]!='\0')
+ {
+ //the char behind the = should be at least the terminating \0
+ // so I can be sure to access valid memory here, IMO
+ value[0]='\0';
+
+ strncpy(value,theChar+1,CFGBUFSIZE);
+ if (value[0]!='\0')
+ {
+ //here we can be sure that the list will only contain
+ //strings which are at least one char long
+ dcerr<<"Config(): adding "<<key<<std::endl;
+ m_entries[key]=value;
+ }
+ }
+ }
+ }
+ while (!inf.eof());
+}
+
+MyString Config::getEntry(const char *key, const char* defaultValue)
+{
+ if ((key==0) || (key[0]=='\0'))
+ return defaultValue;
+ if (m_entries.find(key)==m_entries.end())
+ return defaultValue;
+ return m_entries[key];
+}
+
+int Config::getEntry(const char *key, int defaultValue)
+{
+ char def[100];
+ sprintf(def,"%d",defaultValue);
+ MyString tmp=stripWhiteSpace(getEntry(key,def));
+ int i(0);
+ int ok=sscanf(tmp.c_str(),"%d",&i);
+ if (ok==1) return i;
+ return defaultValue;
+}
+
diff --git a/lanbrowsing/lisa/configfile.h b/lanbrowsing/lisa/configfile.h
new file mode 100644
index 00000000..1879e3b9
--- /dev/null
+++ b/lanbrowsing/lisa/configfile.h
@@ -0,0 +1,33 @@
+/* configfile.h
+ *
+ * Copyright (c) 1998,2000 Alexander Neundorf
+ * neundorf@kde.org
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the COPYING file.
+ *
+ * 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.
+ *
+ */
+
+#ifndef CONFIGFILE_H
+#define CONFIGFILE_H
+
+#include <map>
+
+#include "mystring.h"
+
+class Config
+{
+ public:
+ Config(const MyString& name);
+ MyString getEntry(const char *key, const char* defaultValue);
+ int getEntry(const char *key, int defaultValue);
+ protected:
+ std::map<MyString, MyString> m_entries;
+};
+
+#endif
diff --git a/lanbrowsing/lisa/ipaddress.cpp b/lanbrowsing/lisa/ipaddress.cpp
new file mode 100644
index 00000000..8dc98194
--- /dev/null
+++ b/lanbrowsing/lisa/ipaddress.cpp
@@ -0,0 +1,97 @@
+/* ipaddress.cpp
+ *
+ * Copyright (c) 1998, 1999, Alexander Neundorf, Lukas Pustina
+ * alexander.neundorf@rz.tu-ilmenau.de
+ * lukas@tronet.de
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the COPYING file.
+ *
+ * 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.
+ *
+ */
+
+#include "ipaddress.h"
+
+#include <iostream>
+
+IPAddress::IPAddress()
+{
+}
+
+IPAddress::IPAddress(const MyString& ip)
+{
+ if (ip.length()==0)
+ s="0.0.0.0";
+ else s=ip;
+ i=string2Int(s);
+ n=string2Struct(s);
+}
+
+IPAddress::IPAddress(unsigned int ip)
+{
+ i=ip;
+ s=int2String(i);
+ n.s_addr=htonl(i);
+ //n=string2Struct(s);
+}
+
+IPAddress::IPAddress(struct in_addr ip)
+{
+ n=ip;
+ s=struct2String(n);
+ i=string2Int(s);
+}
+
+IPAddress::IPAddress(int b1, int b2, int b3, int b4)
+{
+ char tmp[30];
+ sprintf(tmp,"%i.%i.%i.%i",b1,b2,b3,b4);
+ s=tmp;
+ i=string2Int(s);
+ n=string2Struct(s);
+}
+
+
+MyString IPAddress::int2String(unsigned int ip)
+{
+ MyString tmp("");
+ struct in_addr addr;
+ addr.s_addr=htonl(ip);
+ tmp=inet_ntoa(addr);
+ return tmp;
+}
+
+MyString IPAddress::struct2String(struct in_addr ip)
+{
+ return MyString(inet_ntoa(ip));
+}
+
+unsigned int IPAddress::string2Int(MyString ip)
+{
+// struct in_addr addr;
+// inet_aton(ip.c_str(),&addr);
+// cout<<addr.s_addr<<endl;
+// return ntohl(addr.s_addr);
+ return ntohl(inet_addr(ip.c_str()));
+}
+
+struct in_addr IPAddress::string2Struct(MyString ip)
+{
+ struct in_addr tmp;
+// inet_aton(ip.c_str(),&tmp);
+ tmp.s_addr = inet_addr(ip.c_str());
+ return tmp;
+}
+
+void IPAddress::print()
+{
+ std::cout<<"address as string: "<<s<<std::endl;
+ std::cout<<"address in host byte order: "<<std::ios::hex<<i<<std::ios::dec<<std::endl;
+ std::cout<<"address in network byte order: "<<std::ios::hex<<n.s_addr<<std::ios::dec<<std::endl;
+}
+
+
diff --git a/lanbrowsing/lisa/ipaddress.h b/lanbrowsing/lisa/ipaddress.h
new file mode 100644
index 00000000..ecca928a
--- /dev/null
+++ b/lanbrowsing/lisa/ipaddress.h
@@ -0,0 +1,55 @@
+/* ipaddress.h
+ *
+ * Copyright (c) 1998, 1999, Alexander Neundorf, Lukas Pustina
+ * alexander.neundorf@rz.tu-ilmenau.de
+ * lukas@tronet.de
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the COPYING file.
+ *
+ * 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.
+ *
+ */
+
+#ifndef IPADDRESS_H
+#define IPADDRESS_H
+
+#include "lisadefines.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include "mystring.h"
+
+class IPAddress
+{
+ public:
+ IPAddress();
+ IPAddress(const MyString& ip);
+ IPAddress(unsigned int ip);
+ IPAddress(struct in_addr ip);
+ IPAddress(int b1, int b2, int b3, int b4);
+ //you know
+ MyString asString() {return s;};
+ //in host byte order
+ unsigned int asInt() {return i;};
+ //in network byte order
+ struct in_addr asStruct() {return n;};
+ /*operator= (IPAddress ip);
+ operator+= (unsigned int add);*/
+ void print();
+ private:
+ MyString int2String(unsigned int ip);
+ MyString struct2String(struct in_addr ip);
+ unsigned int string2Int(MyString ip);
+ struct in_addr string2Struct(MyString ip);
+ MyString s;
+ unsigned int i;
+ struct in_addr n;
+};
+
+#endif
diff --git a/lanbrowsing/lisa/lisadefines.h b/lanbrowsing/lisa/lisadefines.h
new file mode 100644
index 00000000..ac15d2c5
--- /dev/null
+++ b/lanbrowsing/lisa/lisadefines.h
@@ -0,0 +1,19 @@
+#ifndef LISADEFINES_H
+#define LISADEFINES_H
+
+
+#define MYVERSION "0.2.3"
+#define MY_ID 7741
+#define MYPORT 7741
+#define MAX_SPECS 128
+#define SELECT_TIMEOUT 7
+
+#define EXTRACONFIGSTYLE 0
+#define UNIXCONFIGSTYLE 1
+
+#define CONFIGFILEBASENAME "lisarc"
+#define STRICTCONFIGFILEBASENAME "reslisarc"
+
+#define STRICTMODEMAXHOSTS 64
+
+#endif
diff --git a/lanbrowsing/lisa/main.cpp b/lanbrowsing/lisa/main.cpp
new file mode 100644
index 00000000..7de59389
--- /dev/null
+++ b/lanbrowsing/lisa/main.cpp
@@ -0,0 +1,290 @@
+/* main.cpp
+ *
+ * Copyright (c) 1998-2000 Alexander Neundorf
+ * neundorf@kde.org
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the COPYING file.
+ *
+ * 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.
+ *
+ */
+
+#include "lisadefines.h"
+#include "netmanager.h"
+
+#ifdef LISA_DEBUG
+#undef LISA_DEBUG
+#endif
+
+#ifdef dcerr
+#undef dcerr
+#endif
+
+#define LISA_DEBUG 0
+#define dcerr if (LISA_DEBUG==1) std::cerr<<"main "
+
+#include <iostream>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+// detect linux/glibc for the gnu style --args
+#if defined(__linux__) || defined(__linux) || defined(linux)
+# include <features.h>
+# ifdef __GLIBC__
+// only gnu libc has getopt.h... getopt(3) is defined to be in unistd.h
+// by POSIX.2
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+# include <getopt.h>
+# endif // __GLIBC__
+# define GNU_GETOPT
+#endif // linux
+
+
+void printVersion()
+{
+ const char * versionInfo=\
+ "\r\nThis is the LAN Information Server LISa "MYVERSION"\r\n"\
+ "It is free software according the GNU General Public License\r\n"\
+ "Copyright (c) 2000-2003 by Alexander Neundorf\r\n"\
+ "email: neundorf@kde.org\r\n";
+ std::cout<<versionInfo<<std::endl;
+}
+
+void usage()
+{
+ printVersion();
+ const char * usageInfo=\
+ "-v, --version prints out a short version info\n"\
+ "-u, --unix deprecated\n"\
+ "-k, --kde1 deprecated\n"\
+ "-K, --kde2 deprecated\n"\
+ " lisa now looks always first for $(HOME)/.lisarc, then for /etc/lisarc\n"\
+ "-c, --config=FILE read this and no other configuration file\n"\
+ "-q, --quiet start quiet without the greeting message\n"\
+ "-p, --port PORTNR start the server on this portnumber\n"\
+ " if you use this LISa won't be able to\n"\
+ " cooperate with other LISa's in the network\n"\
+ "-h, --help you are currently reading it ;-)\n";
+ std::cout<<usageInfo<<std::endl;
+//I thought this would be the way to check wether long options are supported...
+//#ifndef _GNU_SOURCE
+// std::cout<<"Please note that the long options are not supported on
+// this system"<<std::endl;
+//#endif
+}
+
+NetManager *manager(0);
+
+
+void destruct(int sigNumber)
+{
+ signal(sigNumber,SIG_IGN);
+ dcerr<<"signal caught: "<<sigNumber<<", exiting"<<std::endl;
+ //signal(sigNumber,&destruct);
+ if (manager!=0)
+ manager->~NetManager();
+ exit(0);
+}
+
+void readConfig(int sigNumber)
+{
+ dcerr<<"readConfig(): signal caught: "<<sigNumber<<std::endl;
+ signal(SIGHUP,SIG_IGN);
+ if (manager!=0)
+ manager->readConfig();
+ signal(SIGHUP,&readConfig);
+}
+
+void printState(int sigNumber)
+{
+ dcerr<<"printState(): signal caught: "<<sigNumber<<std::endl;
+ signal(SIGUSR1,SIG_IGN);
+ if (manager!=0)
+ manager->printState();
+ signal(SIGUSR1,&printState);
+}
+
+void setSignalHandler()
+{
+ signal(SIGHUP,&readConfig);
+ signal(SIGUSR1,&printState);
+
+ signal(SIGINT,&destruct);
+ signal(SIGQUIT,&destruct);
+ signal(SIGILL,&destruct);
+ signal(SIGTRAP,&destruct);
+ signal(SIGABRT,&destruct);
+ signal(SIGBUS,&destruct);
+ signal(SIGSEGV,&destruct);
+ signal(SIGUSR2,&destruct);
+ signal(SIGPIPE,&destruct);
+ signal(SIGALRM,&destruct);
+ signal(SIGTERM,&destruct);
+ signal(SIGFPE,&destruct);
+#ifdef SIGPOLL
+ signal(SIGPOLL, &destruct);
+#endif
+#ifdef SIGSYS
+ signal(SIGSYS, &destruct);
+#endif
+#ifdef SIGVTALRM
+ signal(SIGVTALRM, &destruct);
+#endif
+#ifdef SIGXCPU
+ signal(SIGXCPU, &destruct);
+#endif
+#ifdef SIGXFSZ
+ signal(SIGXFSZ, &destruct);
+#endif
+}
+
+#ifdef GNU_GETOPT
+static struct option const long_opts[] =
+{
+ {"version", no_argument, 0, 'v'},
+ {"quiet", no_argument, 0, 'q'},
+ {"unix", no_argument, 0, 'u'},
+ {"kde1", no_argument, 0, 'k'},
+ {"kde2", no_argument, 0, 'K'},
+ {"config", required_argument, 0, 'c'},
+ {"port", required_argument, 0, 'p'},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+};
+#endif
+
+int main(int argc, char** argv)
+{
+ int quiet(0);
+ int c(0);
+ int configStyle(UNIXCONFIGSTYLE);
+ MyString configFile;
+ int portToUse(MYPORT);
+
+//I thought this would be the way to check wether long options are supported...
+#ifdef GNU_GETOPT
+ while ((c=getopt_long(argc, argv, "vqukKc:h", long_opts, 0))!=-1)
+#else
+ while ((c=getopt(argc, argv, "vqukKc:h"))!=-1)
+#endif
+
+ {
+ char *endp(0);
+ switch (c)
+ {
+ case 0:
+ break;
+ case 'v':
+ printVersion();
+ exit(0);
+ break;
+ case 'q':
+ quiet=1;
+ break;
+ case 'u':
+ case 'k':
+ case 'K':
+ std::cout<<"\a\nThe command line switches -k, -K, -u and \ntheir long versions "\
+ "--kde1, --kde2 and --unix are not supported anymore.\n"\
+ "Lisa will always first look for $(HOME)/.lisarc , then for /etc/lisarc.\n"\
+ "If your lisa configuration file was created using an older version of \n"\
+ "the KDE control center, copy the /root/.kde/share/config/lisarc to /etc and \n"\
+ "then start lisa without any command line options.\n"<<std::endl;
+ return 0;
+ break;
+
+ case 'c':
+ configFile = optarg;
+ configStyle = EXTRACONFIGSTYLE;
+ break;
+
+ case 'p':
+ portToUse=strtol(optarg,&endp,10);
+ if (endp!=0)
+ {
+ usage();
+ exit(0);
+ }
+ break;
+
+ case 'h':
+ default:
+ usage();
+ exit(0);
+ break;
+ }
+ }
+
+ //fork and let the parent exit
+ pid_t pid=fork();
+ if (pid>0)
+ {
+ //this is the parent
+ exit(0);
+ }
+ else if (pid<0)
+ {
+ std::cout<<"could not fork()"<<std::endl;
+ exit(0);
+ }
+ //we will only read/write to/from this socket in the child process
+ int rawSocket=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
+ if (rawSocket==-1)
+ {
+ std::cout<<"could not create raw socket, root privileges required"<<std::endl;
+ std::cout<<"take a look at the README for more information"<<std::endl;
+ exit(0);
+ }
+ int bufferSize(60*1024);
+ int on(1);
+ setsockopt(rawSocket, SOL_SOCKET, SO_RCVBUF, (char*)&bufferSize,
+ sizeof(bufferSize));
+ int result=setsockopt(rawSocket, SOL_SOCKET, SO_BROADCAST, (char*)&on,
+ sizeof(on));
+ dcerr<<"setsockopt returns "<<result<<std::endl;
+ //dropping root privileges
+ //they will be regained once in the child process
+ //for creating a raw socket
+
+ //now dropping root privileges once and ever
+
+
+ setuid(getuid());
+ if (geteuid() != getuid())
+ _exit(255);
+
+ //according to R. Stevens the following three lines
+ //make daemons feel good :)
+ setsid();
+ chdir("/");
+ umask(0);
+
+ dcerr<<"starting, dropped root privileges"<<std::endl;
+ dcerr<<"port: "<<portToUse<<" file: "<<configFile<<std::endl;
+ NetManager netmanager(rawSocket,portToUse,configFile,configStyle,0);
+ manager=&netmanager;
+ dcerr<<"NetManager created"<<std::endl;
+ setSignalHandler();
+
+ netmanager.readConfig();
+ if (netmanager.prepare())
+ {
+ if (!quiet)
+ {
+ printVersion();
+ std::cout<<"\n\rrunning on port "<<portToUse<<"\n\rHave fun ! :-)"<<std::endl;
+ }
+ netmanager.run();
+ };
+ dcerr<<"server finished"<<std::endl;
+}
diff --git a/lanbrowsing/lisa/mystring.cpp b/lanbrowsing/lisa/mystring.cpp
new file mode 100644
index 00000000..2b7af2d2
--- /dev/null
+++ b/lanbrowsing/lisa/mystring.cpp
@@ -0,0 +1,52 @@
+#include "mystring.h"
+
+#include <ctype.h>
+
+//this one is taken from Qt/QCString
+
+MyString stripWhiteSpace(MyString str)
+{
+ if ( str.isEmpty() ) // nothing to do
+ return "";
+
+ char const *s = str.data();
+ MyString result = s;
+ int reslen = result.length();
+ if ( !isspace(s[0]) && !isspace(s[reslen-1]) )
+ return result; // returns a copy
+
+ s = result.data();
+ int start = 0;
+ int end = reslen - 1;
+ while ( isspace(s[start]) ) // skip white space from start
+ start++;
+ if ( s[start] == '\0' )
+ { // only white space
+ result.resize( 1 );
+ return "";
+ }
+
+ while ( end && isspace(s[end]) ) // skip white space from end
+ end--;
+
+ end -= start - 1;
+
+ result=str.mid(start,end);
+ //memmove( result.data(), &s[start], end );
+ //result.resize( end + 1 );
+ return result;
+}
+
+//mainly taken from qcstring
+int MyString::contains(char c)
+{
+ int count = 0;
+ char const *d = c_str();
+ if ( d==0 )
+ return 0;
+ while ( *d )
+ if ( *d++ == c )
+ count++;
+ return count;
+}
+
diff --git a/lanbrowsing/lisa/mystring.h b/lanbrowsing/lisa/mystring.h
new file mode 100644
index 00000000..20d40e59
--- /dev/null
+++ b/lanbrowsing/lisa/mystring.h
@@ -0,0 +1,42 @@
+#ifndef MYSTRING_H
+#define MYSTRING_H
+
+#include <string>
+#include <string.h>
+#include <strings.h>
+#include <stdio.h>
+
+class MyString: public std::string
+{
+ public:
+ MyString(const char c) : std::string(1,c) {};
+ MyString(const char* c)
+ : std::string(c==0?"":c)
+ {};
+ MyString(const std::string& s) : std::string(s) {};
+ MyString() : std::string() {};
+
+ int isEmpty() const {return empty();};
+ MyString mid(int pos, int length=-1) const {return substr(pos,length);};
+ MyString left(int len) const {return substr(0,len);};
+ MyString right(int len) const
+ {
+ if (len<1) return "";
+ else if (len<int(size())) return substr(size()-len);
+ else return (*this);
+ };
+
+ int contains(char c);
+ //char & operator[] (unsigned int i) {return ((string)(*this))[i];}
+ //operator const char* () const {return c_str();}
+ const char* data() const {return c_str();}
+ /*void setNum(int value) {char c[15]; bzero(c,15); sprintf(c,"%d",value); (*this)=c;};
+ void setNum(double value) {char c[25]; bzero(c,25); sprintf(c,"%g",value); (*this)=c;};
+ void simplifyWhiteSpace();*/
+};
+
+//taken from Qt/QCString
+MyString stripWhiteSpace(MyString str);
+
+#endif
+
diff --git a/lanbrowsing/lisa/netmanager.cpp b/lanbrowsing/lisa/netmanager.cpp
new file mode 100644
index 00000000..e652ce97
--- /dev/null
+++ b/lanbrowsing/lisa/netmanager.cpp
@@ -0,0 +1,1058 @@
+ /* netmanager.cpp
+ *
+ * Copyright (c) 2000, Alexander Neundorf
+ * neundorf@kde.org
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the COPYING file.
+ *
+ * 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.
+ *
+ */
+
+#include "config.h"
+
+#include "netmanager.h"
+#include "lisadefines.h"
+
+#include <iostream>
+#include <unistd.h>
+
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <strings.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <pwd.h>
+
+#ifndef AF_LOCAL
+#define AF_LOCAL AF_UNIX
+#endif
+
+
+#ifdef LISA_DEBUG
+#undef LISA_DEBUG
+#endif
+
+#ifdef dcerr
+#undef dcerr
+#endif
+
+#ifdef mdcerr
+#undef mdcerr
+#endif
+
+#define LISA_DEBUG 0
+#define dcerr if (LISA_DEBUG==1) std::cerr<<"NetManager "
+#define mdcerr if (LISA_DEBUG==1) std::cerr<<procId<<" NetManager "
+
+static void sig_child_handler(int)
+{
+ int saved_errno = errno;
+
+ while (waitpid(-1, NULL, WNOHANG) > 0)
+ ; // repeat
+
+ errno = saved_errno;
+}
+
+NetManager::NetManager(int& rawSocketFD, int portToUse, MyString configFile, int configStyle, int strictMode)
+:NetScanner(rawSocketFD,strictMode)
+//,validator()
+,m_listenFD(-1)
+,m_bcFD(-1)
+,m_basePort(portToUse)
+,m_pipeFD(-1)
+,m_receiveBuffer(0)
+,m_receivedBytes(0)
+,m_childPid(0)
+,m_lastUpdate(0)
+
+,m_isInformed(0)
+,m_isBeingScanned(0)
+,m_firstRun(1)
+,m_serverServer(0)
+,m_servedThisPeriod(0)
+
+,m_serveCount(0)
+,m_refreshTime(60)
+,m_initialRefreshTime(60)
+,m_increasedRefreshTime(0)
+,m_broadcastAddress(0)
+,m_extraConfigFile(configFile)
+,m_configStyle(configStyle)
+,m_usedConfigFileName("")
+{
+ mdcerr<<"NetManager::NetManager"<<std::endl;
+ m_startedAt=time(0);
+
+ struct sigaction act;
+ act.sa_handler=sig_child_handler;
+ sigemptyset(&(act.sa_mask));
+ sigaddset(&(act.sa_mask), SIGCHLD);
+ // Make sure we don't block this signal. gdb tends to do that :-(
+ sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0);
+
+ act.sa_flags = SA_NOCLDSTOP;
+#ifdef SA_RESTART
+ act.sa_flags |= SA_RESTART;
+#endif
+
+ sigaction( SIGCHLD, &act, NULL );
+}
+
+NetManager::~NetManager()
+{
+ mdcerr<<"NetManager destructor ..."<<std::endl;
+ if (m_receiveBuffer!=0) delete [] m_receiveBuffer;
+ ::close(m_listenFD);
+ ::close(m_bcFD);
+}
+
+void NetManager::readConfig()
+{
+ m_usedConfigFileName=getConfigFileName();
+ if (m_usedConfigFileName.isEmpty())
+ {
+ std::cout<<"configfile not found"<<std::endl;
+ std::cout<<"use the command line option --help and \ntake a look at the README for more information"<<std::endl;
+ exit(1);
+ }
+
+ Config config(m_usedConfigFileName);
+ NetManager::configure(config);
+ NetScanner::configure(config);
+ validator.configure(config);
+ //after reading the new configuration we should really update
+ m_lastUpdate=0;
+}
+
+void NetManager::configure(Config& config)
+{
+ m_refreshTime=config.getEntry("UpdatePeriod",300);
+ MyString tmp=stripWhiteSpace(config.getEntry("BroadcastNetwork","0.0.0.0/255.255.255.255;"));
+ tmp=tmp+";";
+ mdcerr<<"NetManager::readConfig: "<<tmp<<std::endl;
+ MyString netAddressStr=tmp.left(tmp.find('/'));
+ tmp=tmp.mid(tmp.find('/')+1);
+ tmp=tmp.left(tmp.find(';'));
+ mdcerr<<"NetManager::readConfig: broadcastNet "<<netAddressStr<<" with mask "<<tmp<<std::endl;
+ int netMask=inet_addr(tmp.c_str());
+ int netAddress=inet_addr(netAddressStr.c_str());
+ m_broadcastAddress= netAddress | (~netMask);
+ mdcerr<<"NetManager::readConfig: net "<<std::ios::hex<<netAddress<<" with mask "<<netMask<<" gives "<<m_broadcastAddress<<std::endl;
+
+ //maybe this way we can avoid that all servers on the net send
+ //their requests synchronously, since now the refreshtime isn't
+ //always the eact value of m_refreshTime, but differs always slightly
+ if ((m_refreshTime%SELECT_TIMEOUT)==0) m_refreshTime+=2;
+ //some limits from half a minute to half an hour
+ if (m_refreshTime<30) m_refreshTime=30;
+ if (m_refreshTime>1800) m_refreshTime=1800;
+ m_initialRefreshTime=m_refreshTime;
+}
+
+int NetManager::prepare()
+{
+ mdcerr<<"NetManager::prepare"<<std::endl;
+
+ ::close(m_listenFD);
+ ::close(m_bcFD);
+ int result(0);
+ if (m_strictMode)
+ {
+ m_listenFD=::socket(AF_LOCAL, SOCK_STREAM, 0);
+ //m_listenFD=::socket(AF_LOCAL, SOCK_STREAM, IPPROTO_TCP);
+ MyString socketName("/tmp/resLisa-");
+ struct passwd *user = getpwuid( getuid() );
+ if ( user )
+ socketName+=user->pw_name;
+ else
+ //should never happen
+ socketName+="???";
+ ::unlink(socketName.data());
+ sockaddr_un serverAddr;
+ if (socketName.length() >= sizeof(serverAddr.sun_path))
+ {
+ std::cout<<"NetManager::prepare: your user name \""<<user->pw_name<<"\" is too long, exiting."<<std::endl;
+ return 0;
+ }
+ memset((void*)&serverAddr, 0, sizeof(serverAddr));
+ serverAddr.sun_family=AF_LOCAL;
+ strncpy(serverAddr.sun_path,socketName.data(),sizeof(serverAddr.sun_path));
+ result=::bind(m_listenFD,(sockaddr*) &serverAddr,sizeof(serverAddr));
+ if (result!=0)
+ {
+ std::cout<<"NetManager::prepare: bind (UNIX socket) failed, errno: "<<errno<<std::endl;
+ return 0;
+ }
+ }
+ else
+ {
+ //create a listening port and listen
+ m_listenFD = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (m_listenFD==-1)
+ {
+ std::cout<<"NetManager::prepare: socket(TCP) failed, errno: "<<errno<<std::endl;
+ return 0;
+ }
+
+ sockaddr_in serverAddress;
+// bzero((char*)&serverAddress, sizeof(serverAddress));
+ memset((void*)&serverAddress, 0, sizeof(serverAddress));
+ serverAddress.sin_family = AF_INET;
+ serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
+ serverAddress.sin_port = htons(m_basePort);
+
+ int on(1);
+ result=setsockopt(m_listenFD, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on));
+ if (result!=0)
+ {
+ std::cout<<"NetManager::prepare: setsockopt(SO_REUSEADDR) failed"<<std::endl;
+ return 0;
+ }
+ result=::bind(m_listenFD, (struct sockaddr *) &serverAddress, sizeof(serverAddress));
+ if (result!=0)
+ {
+ std::cout<<"NetManager::prepare: bind (TCP) failed, errno: "<<errno<<std::endl;
+ return 0;
+ }
+ }
+ result=::listen(m_listenFD, 32);
+ if (result!=0)
+ {
+ std::cout<<"NetManager::prepare: listen failed"<<std::endl;
+ return 0;
+ }
+ mdcerr<<"NetManager::prepare: listening on port "<<m_basePort<<"..."<<std::endl;
+
+ return 1;
+}
+
+void NetManager::generateFDset(fd_set *tmpFDs)
+{
+ mdcerr<<"NetManager::generateFDset"<<std::endl;
+
+ FD_ZERO(tmpFDs);
+ FD_SET(m_listenFD,tmpFDs);
+ mdcerr<<"NetManager::generateFDset: adding listen FD="<<m_listenFD<<std::endl;
+// for (Client* tmpClient=clients.first(); tmpClient!=0; tmpClient=clients.next())
+ for (std::list<Client>::iterator tmpClient=clients.begin(); tmpClient != clients.end(); tmpClient++)
+ if (tmpClient->fd()!=-1)
+ {
+ mdcerr<<"NetManager::generateFDset: adding client FD="<<tmpClient->fd()<<std::endl;
+ FD_SET(tmpClient->fd(),tmpFDs);
+ }
+
+ if (m_pipeFD!=-1)
+ {
+ mdcerr<<"NetManager::generateFDset: adding pipeFD="<<m_pipeFD<<std::endl;
+ FD_SET(m_pipeFD,tmpFDs);
+ }
+
+ if ((m_bcFD!=-1) && (!m_strictMode))
+ {
+ mdcerr<<"NetManager::generateFDset: adding m_bcFD="<<m_bcFD<<std::endl;
+ FD_SET(m_bcFD,tmpFDs);
+ }
+}
+
+int NetManager::waitForSomethingToHappen(fd_set *tmpFDs)
+{
+ mdcerr<<"NetManager::waitForSomethingToHappen for 10 seconds"<<std::endl;
+ if (m_firstRun)
+ {
+ tv.tv_sec = 1;
+ m_firstRun=0;
+ }
+ else
+ tv.tv_sec = SELECT_TIMEOUT;
+
+ tv.tv_usec = 0;
+ //generateFDset(tmpFDs);
+ int result=select(getMaxFD(),tmpFDs,0,0,&tv);
+ if (result>0) return 1;
+ else return 0;
+}
+
+int NetManager::getMaxFD()
+{
+ int maxFD(m_listenFD);
+// for (Client* tmpClient=clients.first(); tmpClient!=0; tmpClient=clients.next())
+ for (std::list<Client>::iterator tmpClient=clients.begin(); tmpClient != clients.end(); tmpClient++)
+ if (tmpClient->fd()>maxFD)
+ maxFD=tmpClient->fd();
+
+ if (m_pipeFD>maxFD) maxFD=m_pipeFD;
+ if (m_bcFD>maxFD) maxFD=m_bcFD;
+
+ mdcerr<<"NetManager::getMaxFD()="<<maxFD+1<<std::endl;
+ return maxFD+1;
+}
+
+int fileReadable(const MyString& filename)
+{
+ FILE *file=::fopen(filename.data(), "r");
+ if (file==0)
+ return 0;
+ fclose(file);
+ return 1;
+}
+
+MyString NetManager::getConfigFileName()
+{
+ MyString tmpBase(CONFIGFILEBASENAME);
+
+ if (m_strictMode)
+ tmpBase=STRICTCONFIGFILEBASENAME;
+
+ if (!m_extraConfigFile.isEmpty())
+ m_configStyle=EXTRACONFIGSTYLE;
+
+ MyString tmpFilename;
+ if (m_configStyle==EXTRACONFIGSTYLE)
+ {
+ tmpFilename=m_extraConfigFile;
+ if (fileReadable(tmpFilename))
+ return tmpFilename;
+ return "";
+ }
+ else if (m_configStyle==UNIXCONFIGSTYLE)
+ {
+ tmpFilename=getenv("HOME");
+ tmpFilename+=MyString("/.")+tmpBase;
+ if (fileReadable(tmpFilename))
+ return tmpFilename;
+ tmpFilename="/etc/";
+ tmpFilename+=tmpBase;
+ if (fileReadable(tmpFilename))
+ return tmpFilename;
+ return "";
+ }
+/* else if (m_configStyle==KDE1CONFIGSTYLE)
+ {
+ tmpFilename=getenv("HOME");
+ tmpFilename+=MyString("/.kde/share/config/")+tmpBase;
+ if (fileReadable(tmpFilename))
+ return tmpFilename;
+ tmpFilename=getenv("KDEDIR");
+ tmpFilename+=MyString("/share/config/")+tmpBase;
+ if (fileReadable(tmpFilename))
+ return tmpFilename;
+ return "";
+ }
+ else if (m_configStyle==KDE2CONFIGSTYLE)
+ {
+ FILE *kdeConfig=popen("kde-config --path config","r");
+ if (kdeConfig==0)
+ {
+ std::cout<<"could not execute kde-config, check your KDE 2 installation\n"<<std::endl;
+ return "";
+ };
+ //this should be large enough
+ char buf[4*1024];
+ memset(buf,0,4*1024);
+ fgets(buf,4*1024-1,kdeConfig);
+ // Warning: The return value of plcose may be incorrect due to the
+ // SIGCHLD handler that is installed. Ignore it!
+ pclose(kdeConfig);
+ int length=strlen(buf);
+ if (buf[length-1]=='\n') buf[length-1]='\0';
+ MyString kdeDirs(buf);
+ while (kdeDirs.contains(':'))
+ {
+ MyString nextDir=kdeDirs.left(kdeDirs.find(':'));
+ kdeDirs=kdeDirs.mid(kdeDirs.find(':')+1);
+ nextDir=nextDir+tmpBase;
+ mdcerr<<"trying to open "<<nextDir<<std::endl;
+ if (fileReadable(nextDir))
+ return nextDir;
+ };
+ kdeDirs=kdeDirs+tmpBase;
+ mdcerr<<"trying to open "<<kdeDirs<<std::endl;
+ if (fileReadable(kdeDirs))
+ return kdeDirs;
+ kdeDirs="/etc/";
+ kdeDirs=kdeDirs+tmpBase;
+ if (fileReadable(kdeDirs))
+ return kdeDirs;
+ return "";
+ }*/
+ return "";
+}
+
+int NetManager::run()
+{
+ int continueMainLoop(1);
+ //not forever
+ while(continueMainLoop)
+ {
+ mdcerr<<"\nNetManager::run: next loop: "<<clients.size()<<" clients"<<std::endl;
+ fd_set tmpFDs;
+ generateFDset(&tmpFDs);
+
+ int result=waitForSomethingToHappen(&tmpFDs);
+ mdcerr<<"NetManager::run: something happened..."<<std::endl;
+ //timeout
+ if (result==0)
+ {
+ mdcerr<<"NetManager::run: serverServer=="<<m_serverServer<<std::endl;
+ mdcerr<<"NetManager::run: scanning after timeout"<<std::endl;
+ scan();
+ }
+ else
+ {
+ //a new connection ?
+ if (FD_ISSET(m_listenFD,&tmpFDs))
+ {
+ mdcerr<<"NetManager::run: on m_listenFD"<<std::endl;
+ struct sockaddr_in clientAddress;
+ socklen_t clilen(sizeof(clientAddress));
+// bzero((char*)&clientAddress, clilen);
+ memset((void*)&clientAddress,0,sizeof(clientAddress));
+ int connectionFD=::accept(m_listenFD,(struct sockaddr *) &clientAddress, &clilen);
+ if ((validator.isValid(clientAddress.sin_addr.s_addr)) || (m_strictMode))
+ {
+ mdcerr<<"NetManager::run: adding client"<<std::endl;
+ addClient(connectionFD);
+ m_servedThisPeriod=1;
+ m_refreshTime=m_initialRefreshTime;
+ m_increasedRefreshTime=0;
+ }
+ else
+ {
+ mdcerr<<"NetManager::run: kicking client"<<std::endl;
+ ::close(connectionFD);
+ }
+ }
+ checkClientsAndPipes(&tmpFDs);
+ }
+ serveAndClean();
+ }
+ return 1;
+}
+
+void NetManager::addClient(int socketFD)
+{
+ mdcerr<<"NetManager::addClient on FD="<<socketFD<<std::endl;
+ if (socketFD==-1) return;
+ Client c(this,socketFD,0);
+ clients.push_back(c);
+}
+
+void NetManager::checkClientsAndPipes(fd_set *tmpFDs)
+{
+ mdcerr<<"NetManager::checkClientsAndPipes()"<<std::endl;
+ //actually the clients should not send anything
+// for (Client *tmpClient=clients.first(); tmpClient!=0; tmpClient=clients.next())
+ for (std::list<Client>::iterator tmpClient=clients.begin(); tmpClient != clients.end(); tmpClient++)
+ {
+ mdcerr<<"NetManager::checkClientsAndPipes: checking client"<<std::endl;
+ if (FD_ISSET(tmpClient->fd(),tmpFDs))
+ {
+ mdcerr<<"NetManager::checkClientsAndPipes: client sent something"<<std::endl;
+ tmpClient->read();
+ }
+ }
+
+ //now check wether we received a broadcast
+ //m_bcFD should always be -1 in strictMode
+ if ((m_bcFD!=-1) && (!m_strictMode))
+ {
+ mdcerr<<"NetManager::checkClientsAndPipe: checking bcFD"<<std::endl;
+ //yes !
+ if (FD_ISSET(m_bcFD,tmpFDs))
+ answerBroadcast();
+ }
+
+ //read the stuff from the forked pipe
+ if (m_pipeFD!=-1)
+ {
+ mdcerr<<"NetManager::checkClientsAndPipe: checking pipe"<<std::endl;
+ if (FD_ISSET(m_pipeFD,tmpFDs))
+ {
+ mdcerr<<"NetManager::checkClientsAndPipes: pipe sent something"<<std::endl;
+ int result=readDataFromFD(m_pipeFD);
+ if (result!=1)
+ {
+ ::close(m_pipeFD);
+ m_pipeFD=-1;
+ mdcerr<<"NetManager::checkClientsAndPipes: everything read from pipe from proc "<<m_childPid<<std::endl;
+ processScanResults();
+ }
+ }
+ }
+}
+
+void NetManager::answerBroadcast()
+{
+ //actually we should never get here in strictMode
+ if (m_strictMode) return;
+
+ //this one is called only in checkClientsAndPipes()
+ //if we are sure that we received something on m_bcFD
+ //so we don't need to check here again
+
+ mdcerr<<"NetManager::answerBroadcast: received BC"<<std::endl;
+ struct sockaddr_in sAddr;
+ socklen_t length(sizeof(sockaddr_in));
+ char buf[1024];
+ int result=recvfrom(m_bcFD, (char*)buf, 1024, 0, (sockaddr*)&sAddr,&length);
+ mdcerr<<"NetManager::answerBroadcast: received successfully"<<std::endl;
+ //did recvfrom() succeed ?
+ //our frame is exactly MYFRAMELENGTH bytes big, if the received one has a different size,
+ //it must be something different
+ if (result!=MYFRAMELENGTH) return;
+ //if it has the correct size, it also must have the correct identifier
+ MyFrameType *frame=(MyFrameType*)(void*)buf;
+ if ((ntohl(frame->id)!=MY_ID) ||
+ ((ntohl(frame->unused1)==getpid()) && (ntohl(frame->unused2)==m_startedAt)))
+ {
+ mdcerr<<"NetManager::answerBroadcast: must be the same machine"<<std::endl;
+ return;
+ }
+
+ //mdcerr<<"received "<<ntohl(buf[0])<<" from "<<inet_ntoa(sAddr.sin_addr)<<hex<<" ";
+ //mdcerr<<sAddr.sin_addr.s_addr<<" //"<<ntohl(sAddr.sin_addr.s_addr)<<dec<<std::endl;
+ //will we answer this request ?
+ if (!validator.isValid(sAddr.sin_addr.s_addr))
+ {
+ mdcerr<<"NetManager::answerBroadcast: invalid sender"<<std::endl;
+ return;
+ }
+
+ //create the answering socket
+
+ int answerFD=::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (answerFD==-1)
+ {
+ mdcerr<<"NetManager::answerBroadcast: could not create answering socket"<<std::endl;
+ return;
+ }
+
+ sAddr.sin_family=AF_INET;
+ sAddr.sin_port=htons(m_basePort+1);
+ MyFrameType answerFrame;
+ answerFrame.id=htonl(MY_ID);
+ answerFrame.unused1=0;
+ answerFrame.unused2=0;
+ //don't care about the result
+ mdcerr<<"NetManager::answerBroadcast: sending answer"<<std::endl;
+
+ result=::sendto(answerFD,(char*)&answerFrame,sizeof(answerFrame),0,(sockaddr*)&sAddr,length);
+ mdcerr<<"sent "<<result<<" byte using sendto"<<std::endl;
+ ::close(answerFD);
+ //sent answer
+}
+
+void NetManager::serveAndClean()
+{
+ //try to serve the request
+// for (Client *tmpClient=clients.first(); tmpClient!=0; tmpClient=clients.next())
+ for (std::list<Client>::iterator tmpClient=clients.begin(); tmpClient != clients.end(); tmpClient++)
+ {
+ mdcerr<<"NetManager::serveAndClean: trying to get info"<<std::endl;
+ tmpClient->tryToGetInfo();
+ }
+
+ //try to delete served the clients
+ /** PM: substituted STL code
+ for (Client* tmpClient=clients.first();tmpClient!=0; tmpClient=clients.next())
+ {
+ //if we served the client or if he's already half a minute
+ //connected remove it
+ //this way we get rid of clients if something went wrong and
+ //maybe it's even a security point, I don't know
+ if ((tmpClient->done()) || (tmpClient->age()>30))
+ {
+ mdcerr<<"NetManager::serveAndClean: removing Client"<<std::endl;
+ clients.remove(tmpClient);
+ tmpClient=clients.first();
+ }
+ }*/
+ clients.remove_if(client_is_done());
+}
+
+void NetManager::scan()
+{
+ mdcerr<<"NetManager::scan()"<<std::endl;
+ if (isBeingScanned()) return;
+
+ time_t currentTime=time(0);
+ mdcerr<<"currentTime: "<<currentTime<<" lastUpdate: "<<m_lastUpdate<<std::endl;
+ if ((currentTime-m_lastUpdate)<m_refreshTime) return;
+ mdcerr<<"NetManager::scan: scanning..."<<std::endl;
+
+ m_isBeingScanned=1;
+ int fileDescr[2];
+ ::pipe(fileDescr);
+ mdcerr<<"NetScanner::scan: file-descr[0]: "<<fileDescr[0]<<std::endl;
+ mdcerr<<"NetScanner::scan: file-descr[1]: "<<fileDescr[1]<<std::endl;
+ int pid=fork();
+ if (pid==-1)
+ {
+ mdcerr<<"NetScanner::scan: error occurred"<<std::endl;
+ return;
+ }
+ else if (pid!=0)
+ {
+ //parent
+ ::close(fileDescr[1]);
+ m_pipeFD=fileDescr[0];
+ m_childPid=pid;
+ return;
+ }
+ //child
+ procId="** child ** ";
+ mdcerr<<" NetManager::scan: a child was born"<<std::endl;
+ if (m_strictMode)
+ {
+ mdcerr<<" NetManager::scan: scanning myself in strict mode, becoming serverServer"<<std::endl;
+ doScan();
+ //in the child we don't have to call setServerServer()
+ //since this opens the listening socket, what has to be done
+ //in the parent process
+ m_serverServer=1;
+ }
+ else
+ {
+ int serverAddress=findServerServer();
+ if (serverAddress==0)
+ {
+ mdcerr<<" NetManager::scan: scanning myself, becoming serverServer"<<std::endl;
+ doScan();
+ //in the child we don't have to call setServerServer()
+ //since this opens the listening socket, what has to be done
+ //in the parent process
+ m_serverServer=1;
+ }
+ else
+ {
+ mdcerr<<" NetManager::scan: getting list from serverServer"<<std::endl;
+ getListFromServerServer(serverAddress);
+ m_serverServer=0;
+ }
+ }
+ mdcerr<<" NetScanner::scan: sending information to parent process"<<std::endl;
+ writeDataToFD(fileDescr[1],m_serverServer);
+ mdcerr<<" NetScanner::scan: closed FD: "<<::close(fileDescr[1])<<std::endl;
+ mdcerr<<" NetScanner::scan: exiting now"<<std::endl;
+ ::exit(0);
+}
+
+int NetManager::writeDataToFD(int fd, int serverServer)
+{
+ mdcerr<<" NetManager::writeDataToFD fd="<<fd<<std::endl;
+ m_serveCount++;
+ char buffer[1024];
+
+ int length;
+// for (Node* tmpNode=hostList->first(); tmpNode!=0; tmpNode=hostList->next())
+ for (std::list<Node>::iterator tmpNode=hostList->begin(); tmpNode!=hostList->end(); tmpNode++)
+ {
+ sprintf(buffer,"%u %s\n",tmpNode->ip,tmpNode->name.left(1000).c_str());
+ length=strlen(buffer)+1;
+ const char *currentBuf=buffer;
+ //make sure that everything is written
+ while (length>0)
+ {
+ int result=::write(fd,currentBuf,length);
+ mdcerr<<"NetManager::writeDataToFD: wrote "<<result<<" bytes"<<std::endl;
+ if (result==-1)
+ {
+ perror("hmmpf: ");
+ return 0;
+ }
+ length-=result;
+ currentBuf+=result;
+ }
+ }
+ //and a last line
+ sprintf(buffer,"%d succeeded\n",serverServer);
+ length=strlen(buffer)+1;
+ const char *currentBuf=buffer;
+ //make sure that everything is written
+ while (length>0)
+ {
+ int result=::write(fd,currentBuf,length);
+ if (result==-1) return 0;
+ length-=result;
+ currentBuf+=result;
+ }
+ return 1;
+}
+
+int NetManager::readDataFromFD(int fd)
+{
+ mdcerr<<"NetManager::readDataFromFD"<<std::endl;
+ char tmpBuf[64*1024];
+ int result=::read(fd,tmpBuf,64*1024);
+ mdcerr<<"NetManager::readDataFromFD: read "<<result<<" bytes"<<std::endl;
+ if (result==-1) return -1;
+ if (result==0)
+ {
+ mdcerr<<"NetManager::readDataFromFD: FD was closed"<<std::endl;
+ return 0;
+ }
+ char *newBuf=new char[m_receivedBytes+result];
+ if (m_receiveBuffer!=0) memcpy(newBuf,m_receiveBuffer,m_receivedBytes);
+ memcpy(newBuf+m_receivedBytes,tmpBuf,result);
+ m_receivedBytes+=result;
+ if (m_receiveBuffer!=0) delete [] m_receiveBuffer;
+ m_receiveBuffer=newBuf;
+ // too much data - abort at 2MB to avoid memory exhaustion
+ if (m_receivedBytes>2*1024*1024)
+ return 0;
+
+ return 1;
+}
+
+int NetManager::processScanResults()
+{
+ mdcerr<<"NetManager::processScanResults"<<std::endl;
+ if (m_receiveBuffer==0) return 0;
+ std::list<Node> *newNodes=new std::list<Node>;
+
+ char *tmpBuf=m_receiveBuffer;
+ int bytesLeft=m_receivedBytes;
+ mdcerr<<"m_receivedBytes: "<<m_receivedBytes<<" bytesLeft: "<<bytesLeft<<std::endl;
+ //this should be large enough for a name
+ //and the stuff which is inserted into the buffer
+ //comes only from ourselves ... or attackers :-(
+ char tmpName[1024*4];
+ while (bytesLeft>0)
+ {
+ int tmpIP=2; // well, some impossible IP address, 0 and 1 are already used for the last line of output
+ tmpName[0]='\0';
+ if ((memchr(tmpBuf,0,bytesLeft)==0) || (memchr(tmpBuf,int('\n'),bytesLeft)==0))
+ {
+ delete newNodes;
+ hostList->clear();
+
+ m_lastUpdate=time(0);
+ delete [] m_receiveBuffer;
+ m_receiveBuffer=0;
+ m_receivedBytes=0;
+ m_isInformed=1;
+ m_isBeingScanned=0;
+ return 0;
+ }
+ //mdcerr<<"NetManager::processScanResults: processing -"<<tmpBuf;
+ //since we check for 0 and \n with memchr() we can be sure
+ //at this point that tmpBuf is correctly terminated
+ int length=strlen(tmpBuf)+1;
+ if (length<(4*1024))
+ sscanf(tmpBuf,"%u %s\n",&tmpIP,tmpName);
+
+ bytesLeft-=length;
+ tmpBuf+=length;
+ mdcerr<<"length: "<<length<<" bytesLeft: "<<bytesLeft<<std::endl;
+ if ((bytesLeft==0) && ((tmpIP==0) ||(tmpIP==1)) && (strstr(tmpName,"succeeded")!=0))
+ {
+ mdcerr<<"NetManager::processScanResults: succeeded :-)"<<std::endl;
+ delete hostList;
+ hostList=newNodes;
+
+ m_lastUpdate=time(0);
+ delete [] m_receiveBuffer;
+ m_receiveBuffer=0;
+ m_receivedBytes=0;
+ m_isInformed=1;
+ m_isBeingScanned=0;
+ adjustRefreshTime(tmpIP);
+ enableServerServer(tmpIP);
+ //m_serverServer=tmpIP;
+
+ return 1;
+ }
+ else if (tmpIP!=2)
+ {
+ //mdcerr<<"NetManager::processScanResults: adding host: "<<tmpName<<" with ip: "<<tmpIP<<std::endl;
+ newNodes->push_back(Node(tmpName,tmpIP));
+ }
+ }
+ //something failed :-(
+ delete newNodes;
+ hostList->clear();
+
+ m_lastUpdate=time(0);
+ delete [] m_receiveBuffer;
+ m_receiveBuffer=0;
+ m_receivedBytes=0;
+ m_isInformed=1;
+ m_isBeingScanned=0;
+
+ mdcerr<<"NetScanner::processScanResult: finished"<<std::endl;
+ return 0;
+}
+
+void NetManager::adjustRefreshTime(int serverServer)
+{
+ //we are becoming server server
+ if (((m_serverServer==0) && (serverServer)) || (m_servedThisPeriod))
+ {
+ m_increasedRefreshTime=0;
+ m_refreshTime=m_initialRefreshTime;
+ }
+ //nobody accessed the server since the last update
+ //so increase the refresh time
+ //this should happen more seldom to the serverServer
+ //than to others
+ else
+ {
+ //up to the 16 times refresh time
+ if (m_increasedRefreshTime<4)
+ {
+ m_increasedRefreshTime++;
+ m_refreshTime*=2;
+ };
+ };
+ m_servedThisPeriod=0;
+
+}
+
+void NetManager::enableServerServer(int on)
+{
+ mdcerr<<"NetManager::enableServerServer: "<<on<<std::endl;
+ //in strictMode we don't listen to broadcasts from the network
+ if (m_strictMode) return;
+
+ m_serverServer=on;
+ if (on)
+ {
+ //nothing has to be done
+ if (m_bcFD!=-1) return;
+ // otherwise create the socket which will listen for broadcasts
+ sockaddr_in my_addr;
+ my_addr.sin_family=AF_INET;
+ my_addr.sin_port=htons(m_basePort);
+ my_addr.sin_addr.s_addr=0;
+
+ m_bcFD=::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (m_bcFD==-1)
+ {
+ mdcerr<<"NetManager::enableServerServer: socket() failed"<<std::endl;
+ m_serverServer=0;
+ return;
+ };
+ int on(1);
+ int result=setsockopt(m_bcFD, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on));
+ if (result!=0)
+ {
+ mdcerr<<"NetManager::enableServerServer: setsockopt(SO_REUSEADDR) failed"<<std::endl;
+ m_serverServer=0;
+ ::close(m_bcFD);
+ m_bcFD=-1;
+ return;
+ };
+ result=::bind(m_bcFD, (struct sockaddr *) &my_addr, sizeof(my_addr));
+ if (result!=0)
+ {
+ mdcerr<<"NetManager::enableServerServer: bind (UDP) failed"<<std::endl;
+ m_serverServer=0;
+ ::close(m_bcFD);
+ m_bcFD=-1;
+ return;
+ };
+ }
+ else
+ {
+ ::close(m_bcFD);
+ m_bcFD=-1;
+ };
+}
+
+int NetManager::findServerServer()
+{
+ mdcerr<<" NetManager::findServerServer"<<std::endl;
+ //actually this should never be called in strictMode
+ if (m_strictMode) return 0;
+ if (!validator.isValid(m_broadcastAddress))
+ {
+ mdcerr<<" NetManager::findServerServer: invalid broadcastAddress"<<std::endl;
+ return 0;
+ };
+ //create a socket for sending the broadcast
+ //we don't have to set SO_REUSEADDR, since we don't call bind()
+ //to this socket
+ int requestFD=::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (requestFD==-1)
+ {
+ mdcerr<<" NetManager::findServerServer: could not create request socket"<<std::endl;
+ return 0;
+ };
+
+ int on(1);
+ //this is actually the only socket which will send broacasts
+ int result=setsockopt(requestFD, SOL_SOCKET, SO_BROADCAST,(char*)&on, sizeof(on));
+ if (result!=0)
+ {
+ mdcerr<<"setsockopt(SO_BROADCAST) failed"<<std::endl;
+ ::close(requestFD);
+ return 0;
+ };
+
+ //create a socket for receiving the answers
+ int answerFD=::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (answerFD==-1)
+ {
+ mdcerr<<" NetManager::findServerServer"<<std::endl;
+ ::close(requestFD);
+ return 0;
+ };
+
+ //since this socket will be bound, we have to set SO_REUSEADDR
+ result=setsockopt(answerFD, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on));
+ if (result!=0)
+ {
+ mdcerr<<"setsockopt(SO_REUSEADDR) failed"<<std::endl;
+ ::close(answerFD);
+ ::close(requestFD);
+ return 0;
+ };
+
+ sockaddr_in my_addr;
+ my_addr.sin_family=AF_INET;
+ my_addr.sin_port=htons(m_basePort+1);
+ my_addr.sin_addr.s_addr=0;
+ //this one has to be bound
+ result=::bind(answerFD, (struct sockaddr *) &my_addr, sizeof(my_addr));
+ if (result!=0)
+ {
+ mdcerr<<"bind (UDP) failed"<<std::endl;
+ ::close(answerFD);
+ ::close(requestFD);
+ return 0;
+ };
+
+ //now send the broadcast
+ struct sockaddr_in sAddr;
+ sAddr.sin_addr.s_addr=m_broadcastAddress;
+ sAddr.sin_family=AF_INET;
+ sAddr.sin_port=htons(m_basePort);
+ socklen_t length(sizeof(sockaddr_in));
+ mdcerr<<" NetManager::findServerServer: broadcasting to: "
+ <<std::ios::hex<<m_broadcastAddress<<std::ios::dec<<std::endl;
+
+ MyFrameType requestFrame;
+ requestFrame.id=htonl(MY_ID);
+ requestFrame.unused1=htonl(getppid());
+ requestFrame.unused2=htonl(m_startedAt);
+
+ result=::sendto(requestFD,(char*)&requestFrame,sizeof(requestFrame),0,(sockaddr*)&sAddr,length);
+ ::close(requestFD);
+ if (result!=MYFRAMELENGTH)
+ {
+ mdcerr<<" NetManager::findServerServer: sent wrong number of bytes: "<<result<<std::endl;
+ ::close(answerFD);
+ return 0;
+ };
+ //wait for an answer
+ struct timeval tv;
+ tv.tv_sec=0;
+ tv.tv_usec=1000*250; //0.1 sec
+ fd_set fdSet;
+ FD_ZERO(&fdSet);
+ FD_SET(answerFD,&fdSet);
+ result=select(answerFD+1,&fdSet,0,0,&tv);
+ if (result<0)
+ {
+ mdcerr<<" NetManager::findServerServer: select() failed: "<<result<<std::endl;
+ mdcerr<<" NetManager::findServerServer: answerFD="<<answerFD<<std::endl;
+ perror("select:");
+ ::close(answerFD);
+ return 0;
+ }
+ if (result==0)
+ {
+ mdcerr<<" NetManager::findServerServer: nobody answered "<<std::endl;
+ ::close(answerFD);
+ return 0;
+ }
+ mdcerr<<"received offer "<<std::endl;
+ struct sockaddr_in addr;
+ length=sizeof(sockaddr_in);
+ char buf[1024];
+ result=recvfrom(answerFD, (char*)buf, 1024, 0, (sockaddr*) &addr,&length);
+ if (result!=MYFRAMELENGTH)
+ {
+ mdcerr<<" NetManager::findServerServer: wrong number of bytes: "<<result<<std::endl;
+ ::close(answerFD);
+ return 0;
+ };
+ MyFrameType *frame=(MyFrameType*)(void*)buf;
+ //wrong identifier ?
+ if (ntohl(frame->id)!=MY_ID)
+ {
+ mdcerr<<" NetManager::findServerServer: wrong id"<<std::endl;
+ ::close(answerFD);
+ return 0;
+ };
+
+ mdcerr<<"received from "<<inet_ntoa(addr.sin_addr)<<std::endl;
+
+ ::close(answerFD);
+ //return the ip of the server server in network byte order
+ return addr.sin_addr.s_addr;
+}
+
+void NetManager::getListFromServerServer( int address)
+{
+ mdcerr<<"NetManager::getListFromServerServer"<<std::endl;
+ //actually we should never get here in strictMode
+ if (m_strictMode) return;
+ //open a tcp socket to the serverserver
+ int serverServerFD=::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (serverServerFD==-1)
+ return;
+ sockaddr_in addr;
+ //we get the address already in network byte order
+ addr.sin_addr.s_addr=address;
+ addr.sin_family=AF_INET;
+ addr.sin_port=htons(m_basePort);
+ int result=::connect(serverServerFD,(sockaddr*)&addr,sizeof(addr));
+ if (result!=0)
+ {
+ ::close(serverServerFD);
+ return;
+ };
+ do
+ {
+ result=readDataFromFD(serverServerFD);
+ } while (result==1);
+ ::close(serverServerFD);
+ processScanResults();
+ mdcerr<<"NetManager::getListFromServerServer succeeded"<<std::endl;
+}
+
+void NetManager::printState()
+{
+ std::cerr<<"LAN Information Server Lisa "MYVERSION"\nAlexander Neundorf <neundorf@kde.org>\n";
+ std::cerr<<"Reading options from config file: "<<m_usedConfigFileName<<std::endl;
+ std::cerr<<"StrictMode: "<<m_strictMode<<std::endl;
+ std::cerr<<"ServerServer: "<<m_serverServer<<std::endl;
+ std::cerr<<"UseNmblookup: "<<m_useNmblookup<<std::endl;
+ std::cerr<<"Pinging: "<<ipRangeStr<<std::endl;
+ std::cerr<<"Allowed hosts: "<<validator.validAddresses()<<std::endl;
+ std::cerr<<"Broadcasting to: "<<std::ios::hex<<ntohl(m_broadcastAddress)<<std::ios::dec<<std::endl;
+ std::cerr<<"Initial update period: "<<m_initialRefreshTime<<" seconds"<<std::endl;
+ std::cerr<<"Current update period: "<<m_refreshTime<<" seconds"<<std::endl;
+ std::cerr<<"Last update: "<<time(0)-m_lastUpdate<<" seconds over"<<std::endl;
+ std::cerr<<"Waiting "<<m_firstWait<<" 1/100th seconds for echo answers on the first try"<<std::endl;
+ std::cerr<<"Waiting "<<m_secondWait<<" 1/100th seconds for echo answers on the second try"<<std::endl;
+ std::cerr<<"Sending "<<m_maxPings<<" echo requests at once"<<std::endl;
+ std::cerr<<"Publishing unnamed hosts: "<<m_deliverUnnamedHosts<<std::endl;
+ std::cerr<<"Already served "<<m_serveCount<<" times"<<std::endl;
+}
+
+//this one is not used at the moment
+/*int NetManager::uptime()
+{
+ return (time(0)-m_startedAt);
+};*/
diff --git a/lanbrowsing/lisa/netmanager.h b/lanbrowsing/lisa/netmanager.h
new file mode 100644
index 00000000..dee5fb27
--- /dev/null
+++ b/lanbrowsing/lisa/netmanager.h
@@ -0,0 +1,109 @@
+/* netmanager.h
+ *
+ * Copyright (c) 1998, 1999, Alexander Neundorf
+ * alexander.neundorf@rz.tu-ilmenau.de
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the COPYING file.
+ *
+ * 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.
+ *
+ */
+
+#ifndef NETMANAGER_H
+#define NETMANAGER_H
+
+#include <list>
+
+#include "netscanner.h"
+#include "client.h"
+#include "mystring.h"
+#include "configfile.h"
+#include "lisadefines.h"
+
+struct MyFrameType
+{
+ int id;
+ //keep some room for later extensions
+ int unused1;
+ int unused2;
+ int unused3;
+};
+
+#define MYFRAMELENGTH 16
+
+class NetManager:public NetScanner
+{
+ public:
+ NetManager(int& rawSocketFD, int portToUse, MyString configFile, int configStyle=UNIXCONFIGSTYLE, int strictMode=0);
+ ~NetManager();
+
+ int prepare();
+ int run();
+ int writeDataToFD(int fd, int serverServer);
+
+ void readConfig();
+ void configure(Config& config);
+ int isBeingScanned() {return m_isBeingScanned;};
+ int isInformed() {return m_isInformed;};
+ //int uptime();
+ void printState();
+ protected:
+ int m_listenFD;
+ int m_bcFD;
+ int m_basePort;
+
+ int m_pipeFD;
+ char *m_receiveBuffer;
+ size_t m_receivedBytes;
+
+ struct timeval tv;
+ pid_t m_childPid;
+ time_t m_lastUpdate;
+ time_t m_startedAt;
+
+ int m_isInformed;
+ int m_isBeingScanned;
+ int m_firstRun;
+ int m_serverServer;
+ int m_servedThisPeriod;
+
+ int m_serveCount;
+ int m_refreshTime;
+ int m_initialRefreshTime;
+ int m_increasedRefreshTime;
+ int m_broadcastAddress;
+ std::list<Client> clients;
+ struct client_is_done : std::unary_function<Client, bool>
+ {
+ bool operator() (Client& c)
+ {
+ return (c.done() != 0 || c.age() > 30);
+ }
+ };
+
+ int getMaxFD();
+ void generateFDset(fd_set *tmpFDs);
+ //returns 0 on timeout, otherwise 1
+ int waitForSomethingToHappen(fd_set *tmpFDs);
+ void scan();
+ void addClient(int socketFD);
+ void checkClientsAndPipes(fd_set *tmpFDs);
+ int readDataFromFD(int fd);
+ int processScanResults();
+ int findServerServer();
+ void getListFromServerServer(int address);
+ void enableServerServer(int on);
+ void serveAndClean();
+ void answerBroadcast();
+ void adjustRefreshTime(int serverServer);
+
+ MyString m_extraConfigFile;
+ int m_configStyle;
+ MyString getConfigFileName();
+ MyString m_usedConfigFileName;
+};
+#endif
diff --git a/lanbrowsing/lisa/netscanner.cpp b/lanbrowsing/lisa/netscanner.cpp
new file mode 100644
index 00000000..acf0515c
--- /dev/null
+++ b/lanbrowsing/lisa/netscanner.cpp
@@ -0,0 +1,663 @@
+/* netscanner.cpp
+ *
+ * Copyright (c) 2000, Alexander Neundorf,
+ * neundorf@kde.org
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the COPYING file.
+ *
+ * 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.
+ *
+ */
+
+#include "config.h"
+#include "netscanner.h"
+#include "ipaddress.h"
+#include "lisadefines.h"
+#include <iostream>
+
+#ifdef LISA_DEBUG
+#undef LISA_DEBUG
+#endif
+#define LISA_DEBUG 0
+
+#ifdef dcerr
+#undef dcerr
+#endif
+
+#ifdef mdcerr
+#undef mdcerr
+#endif
+
+#define dcerr if (LISA_DEBUG==1) std::cerr<<"NetScanner::"
+#define mdcerr if (LISA_DEBUG==1) std::cerr<<procId<<" NetScanner::"
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#ifdef __osf__
+#undef BYTE_ORDER
+#define _OSF_SOURCE
+#undef _MACHINE_ENDIAN_H_
+#undef __STDC__
+#define __STDC__ 0
+#include <netinet/ip.h>
+#undef __STDC__
+#define __STDC__ 1
+#endif
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+
+#ifndef INADDR_NONE
+#define INADDR_NONE -1
+#endif
+
+struct ICMPEchoRequest
+{
+ unsigned char type;
+ unsigned char code;
+ unsigned short int checkSum;
+ unsigned short id;
+ unsigned short seqNumber;
+};
+
+unsigned short in_cksum(unsigned short *addr, int len)
+{
+ int nleft = len;
+ int sum(0);
+ unsigned short *w = addr;
+ unsigned short answer = 0;
+
+ /*
+ * Our algorithm is simple, using a 32 bit accumulator (sum), we add
+ * sequential 16 bit words to it, and at the end, fold back all the
+ * carry bits from the top 16 bits into the lower 16 bits.
+ */
+ while (nleft > 1)
+ {
+ sum += *w++;
+ nleft -= 2;
+ }
+
+ /* 4mop up an odd byte, if necessary */
+ if (nleft == 1)
+ {
+ *(unsigned char *)(&answer) = *(unsigned char *)w ;
+ sum += answer;
+ }
+
+ /* 4add back carry outs from top 16 bits to low 16 bits */
+ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
+ sum += (sum >> 16); /* add carry */
+ answer = ~sum; /* truncate to 16 bits */
+ return(answer);
+}
+
+
+NetScanner::NetScanner(int& rawSocketFD, int strictMode)
+:procId("")
+,m_firstWait(5)
+,m_secondWait(15)
+,m_strictMode(strictMode)
+,m_rawSocketFD(rawSocketFD)
+,validator()
+,ipRangeStr(";")
+,m_maxPings(256)
+,m_deliverUnnamedHosts(0)
+,m_useNmblookup(0)
+,hostList(0)
+,tmpIPRange("")
+{}
+
+NetScanner::~NetScanner()
+{
+// std::cerr<<"----------- Netscanner dtor "<<std::endl;
+ delete hostList;
+ ::close(m_rawSocketFD);
+}
+
+void addMissingSemicolon(MyString& text)
+{
+ if (text.isEmpty()) return;
+ if (text[text.length()-1]!=';')
+ text+=';';
+}
+
+void NetScanner::configure(Config& config)
+{
+ //ranges are not allowed in strict mode
+ if (!m_strictMode)
+ {
+ ipRangeStr=stripWhiteSpace(config.getEntry("PingAddresses",""));
+ addMissingSemicolon(ipRangeStr);
+ }
+ MyString pingNames=stripWhiteSpace(config.getEntry("PingNames",""));
+ addMissingSemicolon(pingNames);
+ MyString nextName;
+ int semicolonPos=pingNames.find(';');
+ int hostsAdded(0);
+ while (semicolonPos!=-1)
+ {
+ nextName=pingNames.left(semicolonPos);
+ mdcerr<<"configure(): looking up -"<<nextName<<"-"<<std::endl;
+ //now the name lookup
+ in_addr server_addr;
+ hostent *hp=gethostbyname(nextName.data());
+ if (hp!=0)
+ {
+ if ((m_strictMode) && (hostsAdded>=STRICTMODEMAXHOSTS))
+ break;
+ memcpy(&server_addr, hp->h_addr, sizeof(server_addr));
+ char *ip=inet_ntoa(server_addr);
+ mdcerr<<"configure(): looking up "<<nextName<<" gives -"<<ip<<"-"<<std::endl;
+ ipRangeStr=ipRangeStr+ip+';';
+ hostsAdded++;
+ }
+
+ pingNames=pingNames.mid(semicolonPos+1);
+ semicolonPos=pingNames.find(';');
+ }
+ if ((!ipRangeStr.isEmpty()) && (ipRangeStr[0]==';'))
+ ipRangeStr=ipRangeStr.mid(1);
+ m_deliverUnnamedHosts=config.getEntry("DeliverUnnamedHosts",0);
+ m_useNmblookup=config.getEntry("SearchUsingNmblookup",0);
+ m_maxPings=config.getEntry("MaxPingsAtOnce",256);
+ m_firstWait=config.getEntry("FirstWait",5);
+ m_secondWait=config.getEntry("SecondWait",15);
+ if (m_firstWait<1) m_firstWait=1;
+ if (m_maxPings<8) m_maxPings=8;
+ if (m_maxPings>1024) m_maxPings=1024;
+ //on some systems (Solaris ?) select() doesn't work correctly
+ // if the microseconds are more than 1.000.000
+ if (m_firstWait>99) m_firstWait=99;
+ if (m_secondWait>99) m_secondWait=99;
+ mdcerr<<"configure(): "<<ipRangeStr<<std::endl;
+}
+
+struct in_addr NetScanner::getIPfromArray(unsigned int index)
+{
+ //mdcerr<<std::endl<<"*** start ***"<<std::endl;
+ unsigned int tmpIndex(0),indexLeft(index);
+ resetIPRange();
+ MyString tmp(getNextIPRange());
+// mdcerr<<"NetScanner::getIPFromArray: -"<<tmp<<"-"<<std::endl;
+ while (!tmp.isEmpty())
+ {
+ if (tmp.contains('/'))
+ {
+ //mdcerr<<"net/mask combination detected"<<std::endl;
+ MyString netStr(tmp.left(tmp.find("/")));
+ MyString maskStr(tmp.mid(tmp.find("/")+1));
+ unsigned int mask(IPAddress(maskStr).asInt());
+ unsigned int net(IPAddress(netStr).asInt()&mask);
+ if ((~mask)<indexLeft)
+ {
+ indexLeft=indexLeft-(~mask+1);
+ tmpIndex+=(~mask)+1;
+ //mdcerr<<"i: "<<tmpIndex<<" left: "<<indexLeft<<std::endl;
+ }
+ else
+ {
+ net+=indexLeft;
+ return IPAddress(net).asStruct();
+ //return string2Struct(ipInt2String(net));
+ }
+ }
+ else if (tmp.contains('-')==1)
+ {
+ //mdcerr<<"single range detected"<<std::endl;
+ MyString fromIPStr(tmp.left(tmp.find("-")));
+ MyString toIPStr(tmp.mid(tmp.find("-")+1));
+ //mdcerr<<"fromIPStr: "<<fromIPStr<<std::endl;
+ //mdcerr<<"toIPStr: "<<toIPStr<<std::endl;
+ unsigned int fromIP(IPAddress(fromIPStr).asInt());
+ unsigned int toIP(IPAddress(toIPStr).asInt());
+ //unsigned int fromIP(ipString2Int(fromIPStr)), toIP(ipString2Int(toIPStr));
+ //index hinter diesem bereich
+ if ((fromIP+indexLeft)>toIP)
+ {
+ tmpIndex+=1+toIP-fromIP;
+ indexLeft=indexLeft-(1+toIP-fromIP);
+ //mdcerr<<"i: "<<tmpIndex<<" left: "<<indexLeft<<std::endl;
+ }
+ //index in diesem bereich
+ else
+ {
+ fromIP+=indexLeft;
+ return IPAddress(fromIP).asStruct();
+ //return string2Struct(ipInt2String(fromIP));
+ }
+
+ }
+ else if (tmp.contains('-')==4)
+ {
+ //mdcerr<<"multiple range detected"<<std::endl;
+ int cp(tmp.find('-'));
+ int from1(atoi(tmp.left(cp).data()));
+ tmp=tmp.mid(cp+1);
+
+ cp=tmp.find('.');
+ int to1(atoi(tmp.left(cp).data()));
+ tmp=tmp.mid(cp+1);
+
+ cp=tmp.find('-');
+ int from2(atoi(tmp.left(cp).data()));
+ tmp=tmp.mid(cp+1);
+
+ cp=tmp.find('.');
+ int to2(atoi(tmp.left(cp).data()));
+ tmp=tmp.mid(cp+1);
+
+ cp=tmp.find('-');
+ int from3(atoi(tmp.left(cp).data()));
+ tmp=tmp.mid(cp+1);
+
+ cp=tmp.find('.');
+ int to3(atoi(tmp.left(cp).data()));
+ tmp=tmp.mid(cp+1);
+
+ cp=tmp.find('-');
+ int from4(atoi(tmp.left(cp).data()));
+ tmp=tmp.mid(cp+1);
+
+ int to4(atoi(tmp.data()));
+
+ unsigned int count((1+to4-from4)*(1+to3-from3)*(1+to2-from2)*(1+to1-from1));
+ if (count<indexLeft)
+ {
+ tmpIndex+=count;
+ indexLeft-=count;
+ //mdcerr<<"i: "<<tmpIndex<<" left: "<<indexLeft<<std::endl;
+ }
+ else
+ {
+ for (int b1=from1; b1<=to1; b1++)
+ for (int b2=from2; b2<=to2; b2++)
+ for (int b3=from3; b3<=to3; b3++)
+ for (int b4=from4; b4<=to4; b4++)
+ {
+ if (tmpIndex==index)
+ {
+ return IPAddress(b1,b2,b3,b4).asStruct();
+ };
+ tmpIndex++;
+ indexLeft--;
+ //mdcerr<<"i: "<<tmpIndex<<" left:"<<indexLeft<<std::endl;
+ }
+ }
+ }
+ //single IP address
+ else if (tmp.contains('.')==3)
+ {
+ //mdcerr<<"single IP address detected"<<std::endl;
+ //if (tmpIndex==index) return string2Struct(tmp);
+ if (tmpIndex==index) return IPAddress(tmp).asStruct();
+ else
+ {
+ tmpIndex++;
+ indexLeft--;
+ //mdcerr<<"i: "<<tmpIndex<<" left: "<<indexLeft<<std::endl;
+ }
+ }
+ //mdcerr<<"nextIPRange: *"<<tmp<<"*"<<std::endl;
+ tmp=getNextIPRange();
+ }
+ return IPAddress("0.0.0.0").asStruct();
+}
+
+void NetScanner::resetIPRange()
+{
+ tmpIPRange=ipRangeStr;
+}
+
+MyString NetScanner::getNextIPRange()
+{
+ if (tmpIPRange.contains(';')<1) return "";
+ int cp(tmpIPRange.find(';'));
+ MyString tmp(tmpIPRange.left(cp));
+ tmpIPRange=tmpIPRange.mid(cp+1);
+ return tmp;
+}
+
+char* NetScanner::ip2Name(struct in_addr ip)
+{
+ struct hostent *hostname=0;
+ // Set the hostname of node
+ if ( ( hostname = gethostbyaddr( (char *) &ip.s_addr, 4, AF_INET ) ) == 0 )
+ {
+ mdcerr << "ip2Name gethostbyname* error" << std::endl;
+ return inet_ntoa( ip );
+ }
+ mdcerr<<"ip2name -"<<hostname->h_name<<std::endl;
+ return hostname->h_name;
+}
+
+void NetScanner::nmblookupScan(std::list<Node>* newList)
+{
+ mdcerr<<"nmblookupScan()"<<std::endl;
+ //newList->clear();
+ FILE * nmblookupFile=popen("nmblookup \"*\"","r");
+ //no success
+ if (nmblookupFile==0)
+ {
+ mdcerr<<"nmblookupScan(): could not start nmblookup"<<std::endl;
+ return;
+ };
+ MyString dummy("");
+ char *receiveBuffer=0;
+ int bufferSize(0);
+ int nmblookupFd=fileno(nmblookupFile);
+ struct timeval tv;
+ fd_set fds;
+ int done(0);
+ int timeOuts(0);
+ char *tmpBuf=new char[16*1024];
+ do
+ {
+ FD_ZERO(&fds);
+ FD_SET(nmblookupFd,&fds);
+ tv.tv_sec=10;
+ tv.tv_usec=0;
+ int result=select(nmblookupFd+1,&fds,0,0,&tv);
+ //error
+ if (result<0)
+ done=1;
+ //timeout
+ else if (result==0)
+ {
+ timeOuts++;
+ //3 time outs make 30 seconds, this should be *much* more than enough
+ if (timeOuts>=3)
+ done=1;
+ }
+ else if (result>0)
+ {
+ //read stuff
+ int bytesRead=::read(nmblookupFd,tmpBuf,16*1024);
+ //pipe closed
+ if (bytesRead==0)
+ done=1;
+ else
+ {
+ char *newBuf=new char[bufferSize+bytesRead];
+ if (receiveBuffer!=0)
+ {
+ memcpy(newBuf,receiveBuffer,bufferSize);
+ delete [] receiveBuffer;
+ }
+ memcpy(newBuf+bufferSize,tmpBuf,bytesRead);
+ receiveBuffer=newBuf;
+ bufferSize+=bytesRead;
+ }
+ }
+ } while (!done);
+
+ // Warning: The return value of pclose may be incorrect due to the
+ // SIGCHLD handler that is installed. Ignore it!
+ pclose(nmblookupFile);
+
+ delete [] tmpBuf;
+ //we received nothing
+ if (receiveBuffer==0)
+ return;
+
+ //check for a terrminating '\0'
+ if (receiveBuffer[bufferSize-1]=='\0')
+ receiveBuffer[bufferSize-1]='\0';
+
+ //std::cerr<<receiveBuffer<<std::endl;
+
+ tmpBuf=receiveBuffer;
+ int bytesLeft=bufferSize;
+
+ int bufferState=0;
+ while (bytesLeft>0)
+ {
+ //mdcerr<<"bytesLeft: "<<bytesLeft<<" received: "<<bufferSize<<std::endl;
+ //since we added a terminating \0 we can be sure here
+ char *endOfLine=(char*)memchr(tmpBuf,'\n',bytesLeft);
+ //point to the last character
+ if (endOfLine==0)
+ endOfLine=receiveBuffer+bufferSize-1;
+
+ //0-terminate the string
+ *endOfLine='\0';
+ //now tmpBuf to endOfLine is a 0-terminated string
+ int strLength=strlen(tmpBuf);
+ //hmm, if this happens, there must be something really wrong
+ if (strLength>1000)
+ break;
+
+ bytesLeft=bytesLeft-strLength-1;
+
+ if (bufferState==0)
+ {
+ if (isdigit(tmpBuf[0]))
+ bufferState=1;
+ }
+ //yes, no else !
+ if (bufferState==1)
+ {
+ char tmpIP[1024];
+ //std::cerr<<"tmpBuf: -"<<tmpBuf<<"-"<<std::endl;
+ if (sscanf(tmpBuf,"%s *<00>\n",tmpIP) == 1) {
+ mdcerr<<"nmblookupScan: tmpIP: -"<<tmpIP<<"-"<<std::endl;
+ struct sockaddr_in addr;
+ if ((addr.sin_addr.s_addr = inet_addr(tmpIP)) != INADDR_NONE)
+ if (!hostAlreadyInList(addr.sin_addr.s_addr,newList))
+ {
+ if (validator.isValid(addr.sin_addr.s_addr))
+ {
+ mdcerr<<"nmblookupScan: adding "<<inet_ntoa(addr.sin_addr)<<std::endl;
+ newList->push_back(Node(dummy,addr.sin_addr.s_addr));
+ }
+ }
+ }
+ }
+ tmpBuf=endOfLine+1;
+ };
+ mdcerr<<"nmblookupScan: finished"<<std::endl;
+ delete [] receiveBuffer;
+}
+
+void NetScanner::pingScan(std::list<Node>* newList) //the ping-version
+{
+ mdcerr<<"pingScan()"<<std::endl;
+ //newList->clear();
+ MyString dummy("");
+ mdcerr<<"pingScan: m_maxPings: "<<m_maxPings<<std::endl;
+
+ pid_t pid=getpid();
+ ICMPEchoRequest echo;
+ echo.type=ICMP_ECHO;
+ echo.code=0;
+ echo.id=pid;
+ echo.seqNumber=0;
+ echo.checkSum=0;
+ echo.checkSum=in_cksum((unsigned short *)&echo,8);
+
+ char receiveBuf[16*1024];
+ //before we start first read everything what might be in the receive buffer
+ //of the raw socket
+
+ timeval tv1;
+ //wait a moment for answers
+ tv1.tv_sec = 0;
+ tv1.tv_usec = 0;
+ fd_set clearSet;
+ FD_ZERO(&clearSet);
+ FD_SET(m_rawSocketFD,&clearSet);
+ while(select(m_rawSocketFD,&clearSet,0,0,&tv1)>0)
+ {
+ ::recvfrom(m_rawSocketFD,(char*)&receiveBuf,16*1024,0,0,0);
+ tv1.tv_sec = 0;
+ tv1.tv_usec = 0;
+ FD_ZERO(&clearSet);
+ FD_SET(m_rawSocketFD,&clearSet);
+ }
+ //now the buffer should be empty
+
+ //wait a moment for answers
+ tv1.tv_sec = 0;
+ tv1.tv_usec = m_firstWait*10*1000;//0.5 sec
+
+ int loopCount(2);
+ if (m_secondWait<0)
+ loopCount=1;
+ for (int repeatOnce=0; repeatOnce<loopCount; repeatOnce++)
+ {
+ mdcerr<<"******************** starting loop *****************"<<std::endl;
+ unsigned int current(0);
+ int finished(0);
+ while (!finished)
+ {
+ for (int con=0; con<m_maxPings; con++)
+ {
+ struct in_addr tmpIP;
+ do
+ {
+ tmpIP=getIPfromArray(current);
+ current++;
+// mdcerr<<"pingScan(): trying "<<inet_ntoa(tmpIP)<<std::endl;
+ if (hostAlreadyInList(tmpIP.s_addr,newList))
+ mdcerr<<"already in list :-)"<<std::endl;
+ if (!validator.isValid(tmpIP.s_addr))
+ mdcerr<<"pingScan(): invalid IP :-("<<std::endl;
+ //ping only hosts which are allowed to receive the results
+ //and which are not in the list
+ } while ( (tmpIP.s_addr!=0)
+ && ((!validator.isValid(tmpIP.s_addr))
+ || (hostAlreadyInList(tmpIP.s_addr,newList))));
+
+ finished=(tmpIP.s_addr==0);
+ if (!finished)
+ {
+ //send the icmp echo request
+ struct sockaddr_in toAddr;
+ toAddr.sin_family = AF_INET;
+ toAddr.sin_addr = tmpIP;
+ toAddr.sin_port = 0;
+ (void)sendto(m_rawSocketFD,(char*)&echo,sizeof(echo),0,(sockaddr*)&toAddr,sizeof(toAddr));
+ //int sb=sendto(sockFD,(char*)&echo,sizeof(echo),0,(sockaddr*)&toAddr,sizeof(toAddr));
+// mdcerr<<"pingScan: pinging "<<inet_ntoa(toAddr.sin_addr)<<std::endl;
+ }
+ else break;
+ }
+ select(0,0,0,0,&tv1);
+ //now read the answers, hopefully
+ struct sockaddr_in fromAddr;
+ socklen_t length(sizeof(fromAddr));
+ int received(0);
+
+ fd_set sockFDset;
+ FD_ZERO(&sockFDset);
+ FD_SET(m_rawSocketFD,&sockFDset);
+ tv1.tv_sec=0;
+ tv1.tv_usec=0;
+ while(select(m_rawSocketFD+1,&sockFDset,0,0,&tv1)>0)
+ {
+ received=recvfrom(m_rawSocketFD, (char*)&receiveBuf, 16*1024, 0,
+ (sockaddr*)&fromAddr, &length);
+ if (received!=-1)
+ {
+// mdcerr<<"pingScan: received from "<<inet_ntoa(fromAddr.sin_addr)<<" "<<received<<" b, ";
+ struct ip *ipFrame=(ip*)&receiveBuf;
+ int icmpOffset=(ipFrame->ip_hl)*4;
+ icmp *recIcmpFrame=(icmp*)(receiveBuf+icmpOffset);
+ int iType=recIcmpFrame->icmp_type;
+ //if its a ICMP echo reply
+ if ((iType==ICMP_ECHOREPLY)
+ //to an echo request we sent
+ && (recIcmpFrame->icmp_id==pid)
+ //and the host is not yet in the list
+ && (!hostAlreadyInList(fromAddr.sin_addr.s_addr,newList)))
+ {
+ //this is an answer to our request :-)
+// mdcerr<<"pingScan: adding "<<inet_ntoa(fromAddr.sin_addr)<<std::endl;
+ newList->push_back(Node(dummy,fromAddr.sin_addr.s_addr));
+ }
+ }
+ tv1.tv_sec=0;
+ tv1.tv_usec=0;
+ FD_ZERO(&sockFDset);
+ FD_SET(m_rawSocketFD,&sockFDset);
+ //FD_SET(sockFD,&sockFDset);
+ }
+ }
+ tv1.tv_sec = 0;
+ tv1.tv_usec = m_secondWait*10*1000;//0.5 sec
+ }
+ mdcerr<<"pingScan() ends"<<std::endl;
+}
+
+void NetScanner::doScan()
+{
+ mdcerr<<"doScan"<<std::endl;
+ //child
+ std::list<Node>* tmpPingList=new std::list<Node>;
+ mdcerr<<"doScan: created list"<<std::endl;
+ if (m_useNmblookup)
+ nmblookupScan(tmpPingList);
+ pingScan(tmpPingList);
+ // get the names from cache or lookup
+ completeNames(tmpPingList);
+ mdcerr<<"doScan: completed names"<<std::endl;
+ if (m_deliverUnnamedHosts==0)
+ removeUnnamedHosts(tmpPingList);
+
+ mdcerr<<"doScan: added hosts"<<std::endl;
+
+ delete hostList;
+ hostList=tmpPingList;
+}
+
+int NetScanner::hostAlreadyInList(int ip, std::list<Node>* nodes)
+{
+ for (std::list<Node>::iterator node = nodes->begin(); node != nodes->end(); node++)
+ {
+ if (node->ip==ip)
+ return 1;
+ }
+ return 0;
+}
+
+void NetScanner::removeUnnamedHosts(std::list<Node>* nodes)
+{
+ nodes->remove_if(is_unnamed_node());
+}
+
+void NetScanner::completeNames(std::list<Node>* nodes)
+{
+ struct sockaddr_in tmpAddr;
+ //for every host
+ for (std::list<Node>::iterator node = nodes->begin(); node != nodes->end(); node++)
+ {
+ tmpAddr.sin_addr.s_addr=node->ip;
+ mdcerr<<"completeNames: looking up "<<inet_ntoa(tmpAddr.sin_addr)<<std::endl;
+ int done(0);
+ //first look wether we have the name already
+ if (hostList!=0) for (std::list<Node>::iterator oldNode=hostList->begin(); oldNode!=hostList->end(); oldNode++)
+ {
+ if (node->ip==oldNode->ip)
+ {
+ mdcerr<<"completeNames: cached: "<<oldNode->name<<" :-)"<<std::endl;
+ node->name=oldNode->name;
+ done=1;
+ break;
+ }
+ }
+ //otherwise do a name lookup
+ if (!done)
+ {
+ //IPAddress tmpAddress(node->ip);
+ //mdcerr<<"NetScanner::completeNames: doing actual lookup"<<std::endl;
+ node->name=ip2Name(tmpAddr.sin_addr);
+ mdcerr<<"completeNames: resolved: "<<node->name<<std::endl;
+ }
+ }
+}
+
diff --git a/lanbrowsing/lisa/netscanner.h b/lanbrowsing/lisa/netscanner.h
new file mode 100644
index 00000000..a93bf3ee
--- /dev/null
+++ b/lanbrowsing/lisa/netscanner.h
@@ -0,0 +1,102 @@
+/* netscanner.h
+ *
+ * Copyright (c) 1998, 1999, 2000 Alexander Neundorf
+ * neundorf@kde.org
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the COPYING file.
+ *
+ * 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.
+ *
+ */
+
+#ifndef NETSCANNER_H
+#define NETSCANNER_H
+
+#include <list>
+
+#include "mystring.h"
+#include "addressvalidator.h"
+#include "tcpnode.h"
+#include "configfile.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <time.h>
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/time.h>
+
+#include <stdio.h>
+
+class NetScanner
+{
+ public:
+ NetScanner(int& rawSocket, int strictMode);
+ ~NetScanner();
+
+ void doScan();
+
+ void completeNames(std::list<Node>* nodes);
+
+ //using nmblookup to determine the ip-address
+ //MyString ip2NetbiosName(const MyString& target, MyString& groupName);
+
+ char* ip2Name(struct in_addr ip);
+
+ MyString procId;
+ int m_firstWait;
+ int m_secondWait;
+ void configure(Config& config);
+ protected:
+ int m_strictMode;
+ int& m_rawSocketFD;
+ AddressValidator validator;
+ MyString ipRangeStr;
+ MyString nameMask;
+
+ int m_maxPings;
+ int m_deliverUnnamedHosts;
+ int m_useNmblookup;
+ //return ip-address with number index from a virtual array
+ //with all ip-addresses according to ipRangeStr
+ struct in_addr getIPfromArray(unsigned int index);
+
+ std::list<Node>* hostList;
+
+ //needed for getIPfromArray()
+ //contains the part of ipRangeStr, which is not yet parsed
+ MyString tmpIPRange;
+ //has to be called before every first call of getNextIPRange
+ void resetIPRange();
+ //returns the next range/part from tmpIPRange before the next semicolon
+ MyString getNextIPRange();
+
+ void pingScan(std::list<Node>* newList); //the ping-version
+ void nmblookupScan(std::list<Node>* newList); //the nmblookup "*"-version
+ int hostAlreadyInList(int ip, std::list<Node>* nodes);
+ void removeUnnamedHosts(std::list<Node>* nodes);
+
+ struct is_unnamed_node : std::unary_function<Node&, bool>
+ {
+ bool operator() (Node& n)
+ {
+ struct in_addr tmpAddr;
+ tmpAddr.s_addr = n.ip;
+ return (strcmp(inet_ntoa(tmpAddr), n.name.data()) == 0);
+ }
+ };
+};
+
+#endif
diff --git a/lanbrowsing/lisa/strictmain.cpp b/lanbrowsing/lisa/strictmain.cpp
new file mode 100644
index 00000000..a948d6df
--- /dev/null
+++ b/lanbrowsing/lisa/strictmain.cpp
@@ -0,0 +1,261 @@
+/* strictmain.cpp
+ *
+ * Copyright (c) 1998-2000 Alexander Neundorf
+ * neundorf@kde.org
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the COPYING file.
+ *
+ * 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.
+ *
+ */
+
+#include "lisadefines.h"
+#include "netmanager.h"
+
+#include <iostream>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+// detect linux/glibc for the gnu style --args
+#if defined(__linux__) || defined(__linux) || defined(linux)
+# include <features.h>
+# ifdef __GLIBC__
+// only gnu libc has getopt.h... getopt(3) is defined to be in unistd.h
+// by POSIX.2
+# ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+# endif
+# include <getopt.h>
+# endif // __GLIBC__
+# define GNU_GETOPT
+#endif // linux
+
+#ifdef LISA_DEBUG
+#undef LISA_DEBUG
+#endif
+#define LISA_DEBUG 0
+
+#ifdef dcerr
+#undef dcerr
+#endif
+
+#define dcerr if (LISA_DEBUG==1) std::cerr<<"strictmain "
+
+void printVersion()
+{
+ const char * versionInfo=\
+ "\r\nThis is the restricted LAN Information Server resLISa "MYVERSION"\r\n"\
+ "It is free software according the GNU General Public License\r\n"\
+ "Copyright (c) 2000-2003 by Alexander Neundorf\r\n"\
+ "email: neundorf@kde.org\r\n";
+ std::cout<<versionInfo<<std::endl;
+}
+
+void usage()
+{
+ printVersion();
+ const char * usageInfo=\
+ "-v, --version prints out a short version info\n"\
+ "-u, --unix deprecated\n"\
+ "-k, --kde1 deprecated\n"\
+ "-K, --kde2 deprecated\n"\
+ " reslisa now always looks first for $(HOME)/.reslisarc, then for /etc/reslisarc\"\n"\
+ "-c, --config=FILE read this and no other configuration file\n"\
+ "-q, --quiet start quiet without the greeting message\n"\
+ "-h, --help you are currently reading it ;-)\n";
+ std::cout<<usageInfo<<std::endl;
+//I thought this would be the way to check wether long options are supported...
+//#ifndef _GNU_SOURCE
+// cout<<"Please note that the long options are not supported on this system"<<endl;
+//#endif
+}
+
+void destruct(int sigNumber)
+{
+ signal(sigNumber,SIG_IGN);
+ std::cout<<"signal caught: "<<sigNumber<<", exiting"<<std::endl;
+ //signal(sigNumber,&destruct);
+ exit(0);
+}
+
+NetManager *manager(0);
+
+void readConfig(int sigNumber)
+{
+ std::cout<<"readConfig(): signal caught: "<<sigNumber<<std::endl;
+ signal(SIGHUP,SIG_IGN);
+ if (manager!=0)
+ manager->readConfig();
+ signal(SIGHUP,&readConfig);
+}
+
+void printState(int sigNumber)
+{
+ std::cout<<"printState(): signal caught: "<<sigNumber<<std::endl;
+ signal(SIGUSR1,SIG_IGN);
+ if (manager!=0)
+ manager->printState();
+ signal(SIGUSR1,&printState);
+}
+
+void setSignalHandler()
+{
+ signal(SIGHUP,&readConfig);
+ signal(SIGUSR1,&printState);
+
+ signal(SIGINT,&destruct);
+ signal(SIGQUIT,&destruct);
+ signal(SIGILL,&destruct);
+ signal(SIGTRAP,&destruct);
+ signal(SIGABRT,&destruct);
+ signal(SIGBUS,&destruct);
+ signal(SIGSEGV,&destruct);
+ signal(SIGUSR2,&destruct);
+ signal(SIGPIPE,&destruct);
+ signal(SIGALRM,&destruct);
+ signal(SIGTERM,&destruct);
+ signal(SIGFPE,&destruct);
+#ifdef SIGPOLL
+ signal(SIGPOLL, &destruct);
+#endif
+#ifdef SIGSYS
+ signal(SIGSYS, &destruct);
+#endif
+#ifdef SIGVTALRM
+ signal(SIGVTALRM, &destruct);
+#endif
+#ifdef SIGXCPU
+ signal(SIGXCPU, &destruct);
+#endif
+#ifdef SIGXFSZ
+ signal(SIGXFSZ, &destruct);
+#endif
+}
+
+#ifdef GNU_GETOPT
+static struct option const long_opts[] =
+{
+ {"version", no_argument, 0, 'v'},
+ {"quiet", no_argument, 0, 'q'},
+ {"unix", no_argument, 0, 'u'},
+ {"kde1", no_argument, 0, 'k'},
+ {"kde2", no_argument, 0, 'K'},
+ {"config", required_argument, 0, 'c'},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+};
+#endif
+
+int main(int argc, char** argv)
+{
+ int quiet(0);
+ int c(0);
+ int configStyle(UNIXCONFIGSTYLE);
+ MyString configFile;
+ int portToUse(MYPORT);
+
+//I thought this would be the way to check wether long options are supported...
+#ifdef GNU_GETOPT
+ while ((c=getopt_long(argc, argv, "vqukKc:h", long_opts, 0))!=-1)
+#else
+ while ((c=getopt(argc, argv, "vqukKc:h"))!=-1)
+#endif
+ {
+ switch (c)
+ {
+ case 0:
+ break;
+ case 'v':
+ printVersion();
+ exit(0);
+ break;
+ case 'q':
+ quiet=1;
+ break;
+ case 'u':
+ case 'k':
+ case 'K':
+ std::cerr<<"\a\nThe command line switches -k, -K, -u and \ntheir long versions "\
+ "--kde1, --kde2 and --unix are not supported anymore.\n"\
+ "ResLisa will always first look for $(HOME)/.reslisarc , then for /etc/reslisarc.\n"\
+ "If your lisa configuration file was created using an older version of \n"\
+ "the KDE control center, copy the $(HOME)/.kde/share/config/reslisarc to $(HOME)/.reslisarc.\n"<<std::endl;
+ break;
+
+ case 'c':
+ configFile = optarg;
+ configStyle = EXTRACONFIGSTYLE;
+ break;
+
+ case 'h':
+ default:
+ usage();
+ exit(0);
+ break;
+ }
+ }
+
+ //fork and let the parent exit
+ pid_t pid=fork();
+ if (pid>0)
+ {
+ //this is the parent
+ exit(0);
+ }
+ else if (pid<0)
+ {
+ dcerr<<"could not fork()"<<std::endl;
+ exit(0);
+ }
+ //we will only read/write to/from this socket in the child process
+ int rawSocket=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
+ if (rawSocket==-1)
+ {
+ std::cout<<"could not create raw socket, root privileges required"<<std::endl;
+ std::cout<<"take a look at the README for more information"<<std::endl;
+ exit(0);
+ }
+ int bufferSize(60*1024);
+ int on(1);
+ setsockopt(rawSocket, SOL_SOCKET, SO_RCVBUF, (char*)&bufferSize,
+ sizeof(bufferSize));
+ int result=setsockopt(rawSocket, SOL_SOCKET, SO_BROADCAST, (char*)&on,
+ sizeof(on));
+ dcerr<<"setsockopt returns "<<result<<std::endl;
+ //dropping root privileges
+ //they will be regained once in the child process
+ //for creating a raw socket
+
+ //now dropping root privileges once and ever
+ setuid(getuid());
+
+ //according to R. Stevens the following three lines
+ //make daemons feel good :)
+ setsid();
+ chdir("/");
+ umask(0);
+
+ dcerr<<"starting, dropped root privileges"<<std::endl;
+ dcerr<<"port: "<<portToUse<<" file: "<<configFile<<std::endl;
+ NetManager netmanager(rawSocket,portToUse,configFile,configStyle,1);
+ manager=&netmanager;
+ dcerr<<"NetManager created"<<std::endl;
+ setSignalHandler();
+
+ netmanager.readConfig();
+ if (netmanager.prepare())
+ {
+ if (!quiet)
+ printVersion();
+ netmanager.run();
+ }
+ dcerr<<"server finished"<<std::endl;
+}
diff --git a/lanbrowsing/lisa/stringlist.cpp b/lanbrowsing/lisa/stringlist.cpp
new file mode 100644
index 00000000..3bf82f9c
--- /dev/null
+++ b/lanbrowsing/lisa/stringlist.cpp
@@ -0,0 +1,110 @@
+#include "simplelist.h"
+
+template <class T>
+SimpleList<T>::SimpleList()
+ :m_list(0)
+ ,m_current(0)
+ ,m_last(0)
+ ,m_size(0)
+{};
+
+template <class T>
+SimpleList<T>::~SimpleList()
+{
+ clear();
+};
+
+template <class T>
+void SimpleList<T>::append(const T& text)
+{
+ if (m_list==0)
+ {
+ m_list=new TemplNode<T>(text);
+ m_last=m_list;
+ }
+ else
+ {
+ m_last->m_next=new TemplNode<T>(text);
+ m_last=m_last->m_next;
+ };
+ m_size++;
+};
+
+template <class T>
+void SimpleList<T>::removeFirst()
+{
+ if (m_list==0) return;
+ TemplNode<T> *first=m_list;
+ m_list=m_list->m_next;
+ m_size--;
+ if (m_list==0)
+ m_last=0;
+ m_current=0;
+ delete first;
+};
+
+template <class T>
+void SimpleList<T>::clear()
+{
+ while (m_list!=0)
+ removeFirst();
+ m_current=0;
+ m_last=0;
+ m_list=0;
+ m_size=0;
+};
+
+template <class T>
+void SimpleList<T>::remove(T* item)
+{
+ if (item==0) return;
+ TemplNode<T>* pre(0);
+ for (T* tmp=first(); tmp!=0; tmp=next())
+ {
+ if (tmp==item)
+ {
+ if (m_current==m_list)
+ {
+ removeFirst();
+ return;
+ }
+ else
+ {
+ TemplNode<T> *succ=m_current->m_next;
+ if (m_current==m_last)
+ m_last=pre;
+ delete m_current;
+ pre->m_next=succ;
+ m_size--;
+ m_current=0;
+
+ };
+ };
+ pre=m_current;
+ };
+
+};
+
+template <class T>
+T* SimpleList<T>::first()
+{
+ m_current=m_list;
+ if (m_list==0)
+ return 0;
+ return &m_current->m_item;
+};
+
+template <class T>
+T* SimpleList<T>::next()
+{
+ if (m_current==0) return 0;
+ m_current=m_current->m_next;
+ if (m_current==0) return 0;
+ return &m_current->m_item;
+};
+
+template <class T>
+int SimpleList<T>::size()
+{
+ return m_size;
+}
diff --git a/lanbrowsing/lisa/stringlist.h b/lanbrowsing/lisa/stringlist.h
new file mode 100644
index 00000000..44f0d0d3
--- /dev/null
+++ b/lanbrowsing/lisa/stringlist.h
@@ -0,0 +1,40 @@
+#ifndef SIMPLELIST_H
+#define SIMPLELIST_H
+
+#include "mystring.h"
+
+template <class T>
+struct TemplNode
+{
+ TemplNode(const T& text)
+ :m_item(text),m_next(0) {};
+ T m_item;
+ TemplNode* m_next;
+};
+
+
+template <class T>
+class SimpleList
+{
+ public:
+ SimpleList();
+ ~SimpleList();
+ void append(const T& item);
+ void clear();
+ int size();
+ T* first();
+ T* next();
+ void removeFirst();
+ void remove(T* item);
+ protected:
+ TemplNode<T>* m_list;
+ TemplNode<T>* m_current;
+ TemplNode<T>* m_last;
+ int m_size;
+};
+
+
+template class SimpleList<int>;
+
+#endif
+
diff --git a/lanbrowsing/lisa/tcpnode.h b/lanbrowsing/lisa/tcpnode.h
new file mode 100644
index 00000000..394ca928
--- /dev/null
+++ b/lanbrowsing/lisa/tcpnode.h
@@ -0,0 +1,29 @@
+/* tcpnode.h
+ *
+ * Copyright (c) 2000 Alexander Neundorf
+ * neundorf@kde.org
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the COPYING file.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _TCPNODE_H_
+#define _TCPNODE_H_
+
+#include "mystring.h"
+
+struct Node
+{
+ Node(const MyString& n, int ipAddress)
+ :name(n),ip(ipAddress) {};
+ MyString name;
+ unsigned int ip;
+};
+
+#endif