mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 00:37:15 +01:00
Implemented the IRC library.
Fixed a bug in the Routine system that caused crashes when constructed with only the first three arguments because it wasn't attached. Implemented a gentle release of functions to not release them if the reference count is 1. Adjusted the Routine and Command system to not be necessary to include them in the module core. Moved the INI and XML libraries into their own namespace. Various other modifications and fixes.
This commit is contained in:
parent
b6e72e93a2
commit
bedf03c9cd
177
cbp/LibIRC.cbp
Normal file
177
cbp/LibIRC.cbp
Normal file
@ -0,0 +1,177 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<CodeBlocks_project_file>
|
||||
<FileVersion major="1" minor="6" />
|
||||
<Project>
|
||||
<Option title="LibIRC" />
|
||||
<Option pch_mode="2" />
|
||||
<Option compiler="gcc" />
|
||||
<Build>
|
||||
<Target title="Win32 Debug Static">
|
||||
<Option output="../lib/mingw32-d/irclib" prefix_auto="1" extension_auto="1" />
|
||||
<Option working_dir="" />
|
||||
<Option object_output="../obj/mingw32-d/" />
|
||||
<Option type="2" />
|
||||
<Option compiler="gcc" />
|
||||
<Option createDefFile="1" />
|
||||
<Compiler>
|
||||
<Add option="-m32" />
|
||||
<Add option="-g" />
|
||||
<Add option="-D_DEBUG" />
|
||||
<Add directory="../config/mingw32" />
|
||||
</Compiler>
|
||||
<Linker>
|
||||
<Add option="-m32" />
|
||||
</Linker>
|
||||
</Target>
|
||||
<Target title="Win32 Release Static">
|
||||
<Option output="../lib/mingw32/irclib" prefix_auto="1" extension_auto="1" />
|
||||
<Option working_dir="" />
|
||||
<Option object_output="../obj/mingw32/" />
|
||||
<Option type="2" />
|
||||
<Option compiler="gcc" />
|
||||
<Option createDefFile="1" />
|
||||
<Compiler>
|
||||
<Add option="-fexpensive-optimizations" />
|
||||
<Add option="-O3" />
|
||||
<Add option="-m32" />
|
||||
<Add option="-DNDEBUG" />
|
||||
<Add directory="../config/mingw32" />
|
||||
</Compiler>
|
||||
<Linker>
|
||||
<Add option="-s" />
|
||||
<Add option="-m32" />
|
||||
</Linker>
|
||||
</Target>
|
||||
<Target title="Win64 Debug Static">
|
||||
<Option output="../lib/mingw64-d/irclib" prefix_auto="1" extension_auto="1" />
|
||||
<Option working_dir="" />
|
||||
<Option object_output="../obj/mingw64-d/" />
|
||||
<Option type="2" />
|
||||
<Option compiler="gcc" />
|
||||
<Option createDefFile="1" />
|
||||
<Compiler>
|
||||
<Add option="-m64" />
|
||||
<Add option="-g" />
|
||||
<Add option="-D_DEBUG" />
|
||||
<Add directory="../config/mingw64" />
|
||||
</Compiler>
|
||||
<Linker>
|
||||
<Add option="-m64" />
|
||||
</Linker>
|
||||
</Target>
|
||||
<Target title="Win64 Release Static">
|
||||
<Option output="../lib/mingw64/irclib" prefix_auto="1" extension_auto="1" />
|
||||
<Option working_dir="" />
|
||||
<Option object_output="../obj/mingw64/" />
|
||||
<Option type="2" />
|
||||
<Option compiler="gcc" />
|
||||
<Option createDefFile="1" />
|
||||
<Compiler>
|
||||
<Add option="-fexpensive-optimizations" />
|
||||
<Add option="-O3" />
|
||||
<Add option="-m64" />
|
||||
<Add option="-DNDEBUG" />
|
||||
<Add directory="../config/mingw64" />
|
||||
</Compiler>
|
||||
<Linker>
|
||||
<Add option="-s" />
|
||||
<Add option="-m64" />
|
||||
</Linker>
|
||||
</Target>
|
||||
<Target title="Linux32 Debug Static">
|
||||
<Option output="../lib/gcc32-d/irclib" prefix_auto="1" extension_auto="1" />
|
||||
<Option working_dir="" />
|
||||
<Option object_output="../obj/gcc32-d/" />
|
||||
<Option type="2" />
|
||||
<Option compiler="gcc" />
|
||||
<Option createDefFile="1" />
|
||||
<Compiler>
|
||||
<Add option="-m32" />
|
||||
<Add option="-g" />
|
||||
<Add option="-fPIC" />
|
||||
<Add option="-D_DEBUG" />
|
||||
<Add directory="../config/gcc32" />
|
||||
</Compiler>
|
||||
<Linker>
|
||||
<Add option="-m32" />
|
||||
</Linker>
|
||||
</Target>
|
||||
<Target title="Linux32 Release Static">
|
||||
<Option output="../lib/gcc32/irclib" prefix_auto="1" extension_auto="1" />
|
||||
<Option working_dir="" />
|
||||
<Option object_output="../obj/gcc32/" />
|
||||
<Option type="2" />
|
||||
<Option compiler="gcc" />
|
||||
<Option createDefFile="1" />
|
||||
<Compiler>
|
||||
<Add option="-fexpensive-optimizations" />
|
||||
<Add option="-O3" />
|
||||
<Add option="-m32" />
|
||||
<Add option="-fPIC" />
|
||||
<Add option="-DNDEBUG" />
|
||||
<Add directory="../config/gcc32" />
|
||||
</Compiler>
|
||||
<Linker>
|
||||
<Add option="-s" />
|
||||
<Add option="-m32" />
|
||||
</Linker>
|
||||
</Target>
|
||||
<Target title="Linux64 Debug Static">
|
||||
<Option output="../lib/gcc64-d/irclib" prefix_auto="1" extension_auto="1" />
|
||||
<Option working_dir="" />
|
||||
<Option object_output="../obj/gcc64-d/" />
|
||||
<Option type="2" />
|
||||
<Option compiler="gcc" />
|
||||
<Option createDefFile="1" />
|
||||
<Compiler>
|
||||
<Add option="-m64" />
|
||||
<Add option="-g" />
|
||||
<Add option="-fPIC" />
|
||||
<Add option="-D_DEBUG" />
|
||||
<Add directory="../config/gcc64" />
|
||||
</Compiler>
|
||||
<Linker>
|
||||
<Add option="-m64" />
|
||||
</Linker>
|
||||
</Target>
|
||||
<Target title="Linux64 Release Static">
|
||||
<Option output="../lib/gcc64/irclib" prefix_auto="1" extension_auto="1" />
|
||||
<Option working_dir="" />
|
||||
<Option object_output="../obj/gcc64/" />
|
||||
<Option type="2" />
|
||||
<Option compiler="gcc" />
|
||||
<Option createDefFile="1" />
|
||||
<Compiler>
|
||||
<Add option="-fexpensive-optimizations" />
|
||||
<Add option="-O3" />
|
||||
<Add option="-m64" />
|
||||
<Add option="-fPIC" />
|
||||
<Add option="-DNDEBUG" />
|
||||
<Add directory="../config/gcc64" />
|
||||
</Compiler>
|
||||
<Linker>
|
||||
<Add option="-s" />
|
||||
<Add option="-m64" />
|
||||
</Linker>
|
||||
</Target>
|
||||
</Build>
|
||||
<Compiler>
|
||||
<Add option="-Wall" />
|
||||
<Add option="-DSQLITE_ENABLE_FTS3" />
|
||||
<Add option="-DSQLITE_ENABLE_FTS4" />
|
||||
<Add option="-DSQLITE_ENABLE_FTS5" />
|
||||
<Add option="-DSQLITE_THREADSAFE=0" />
|
||||
<Add directory="../include" />
|
||||
<Add directory="../config/common" />
|
||||
<Add directory="../external/LibIRC" />
|
||||
</Compiler>
|
||||
<Unit filename="../external/LibIRC/libircclient.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
<Extensions>
|
||||
<code_completion />
|
||||
<envvars />
|
||||
<debugger />
|
||||
</Extensions>
|
||||
</Project>
|
||||
</CodeBlocks_project_file>
|
@ -194,6 +194,7 @@
|
||||
<Linker>
|
||||
<Add library="squirrel" />
|
||||
<Add library="sqlite" />
|
||||
<Add library="irclib" />
|
||||
</Linker>
|
||||
<Unit filename="../external/Hash/crc32.cpp" />
|
||||
<Unit filename="../external/Hash/crc32.h" />
|
||||
@ -272,6 +273,8 @@
|
||||
<Unit filename="../source/Library/Hashing.hpp" />
|
||||
<Unit filename="../source/Library/INI.cpp" />
|
||||
<Unit filename="../source/Library/INI.hpp" />
|
||||
<Unit filename="../source/Library/IRC.cpp" />
|
||||
<Unit filename="../source/Library/IRC.hpp" />
|
||||
<Unit filename="../source/Library/Math.cpp" />
|
||||
<Unit filename="../source/Library/Math.hpp" />
|
||||
<Unit filename="../source/Library/Numeric.cpp" />
|
||||
|
482
external/LibIRC/LICENSE
vendored
Normal file
482
external/LibIRC/LICENSE
vendored
Normal file
@ -0,0 +1,482 @@
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 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.
|
||||
|
||||
[This is the first released version of the library GPL. It is
|
||||
numbered 2 because it goes with version 2 of the ordinary GPL.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Library General Public License, applies to some
|
||||
specially designated Free Software Foundation software, and to any
|
||||
other libraries whose authors decide to use it. You can use it for
|
||||
your libraries, 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 library, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link a program with the library, you must provide
|
||||
complete object files to the recipients so that they can relink them
|
||||
with the library, after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
Our method of protecting your rights has two steps: (1) copyright
|
||||
the library, and (2) offer you this license which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
Also, for each distributor's protection, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
library. If the library is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original
|
||||
version, 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 companies distributing free
|
||||
software will individually obtain patent licenses, thus in effect
|
||||
transforming the program into proprietary software. To prevent this,
|
||||
we have made it clear that any patent must be licensed for everyone's
|
||||
free use or not licensed at all.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the ordinary
|
||||
GNU General Public License, which was designed for utility programs. This
|
||||
license, the GNU Library General Public License, applies to certain
|
||||
designated libraries. This license is quite different from the ordinary
|
||||
one; be sure to read it in full, and don't assume that anything in it is
|
||||
the same as in the ordinary license.
|
||||
|
||||
The reason we have a separate public license for some libraries is that
|
||||
they blur the distinction we usually make between modifying or adding to a
|
||||
program and simply using it. Linking a program with a library, without
|
||||
changing the library, is in some sense simply using the library, and is
|
||||
analogous to running a utility program or application program. However, in
|
||||
a textual and legal sense, the linked executable is a combined work, a
|
||||
derivative of the original library, and the ordinary General Public License
|
||||
treats it as such.
|
||||
|
||||
Because of this blurred distinction, using the ordinary General
|
||||
Public License for libraries did not effectively promote software
|
||||
sharing, because most developers did not use the libraries. We
|
||||
concluded that weaker conditions might promote sharing better.
|
||||
|
||||
However, unrestricted linking of non-free programs would deprive the
|
||||
users of those programs of all benefit from the free status of the
|
||||
libraries themselves. This Library General Public License is intended to
|
||||
permit developers of non-free programs to use free libraries, while
|
||||
preserving your freedom as a user of such programs to change the free
|
||||
libraries that are incorporated in them. (We have not seen how to achieve
|
||||
this as regards changes in header files, but we have achieved it as regards
|
||||
changes in the actual functions of the Library.) The hope is that this
|
||||
will lead to faster development of free libraries.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, while the latter only
|
||||
works together with the library.
|
||||
|
||||
Note that it is possible for a library to be covered by the ordinary
|
||||
General Public License rather than by this special one.
|
||||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library which
|
||||
contains a notice placed by the copyright holder or other authorized
|
||||
party saying it may be distributed under the terms of this Library
|
||||
General Public License (also called "this License"). Each licensee is
|
||||
addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, 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 library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete 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 distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
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 Library or any portion
|
||||
of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
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 Library, 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 Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you 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.
|
||||
|
||||
If distribution of 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 satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also compile or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
c) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
d) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. 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.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library 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.
|
||||
|
||||
9. 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 Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
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.
|
||||
|
||||
11. 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 Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library 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 Library.
|
||||
|
||||
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.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library 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.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Library 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 Library
|
||||
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 Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
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
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "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
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. 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 LIBRARY 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
|
||||
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. 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 library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; 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.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
388
external/LibIRC/colors.c
vendored
Normal file
388
external/LibIRC/colors.c
vendored
Normal file
@ -0,0 +1,388 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This library 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 Lesser General Public
|
||||
* License for more details.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#define LIBIRC_COLORPARSER_BOLD (1<<1)
|
||||
#define LIBIRC_COLORPARSER_UNDERLINE (1<<2)
|
||||
#define LIBIRC_COLORPARSER_REVERSE (1<<3)
|
||||
#define LIBIRC_COLORPARSER_COLOR (1<<4)
|
||||
|
||||
#define LIBIRC_COLORPARSER_MAXCOLORS 15
|
||||
|
||||
|
||||
static const char * color_replacement_table[] =
|
||||
{
|
||||
"WHITE",
|
||||
"BLACK",
|
||||
"DARKBLUE",
|
||||
"DARKGREEN",
|
||||
"RED",
|
||||
"BROWN",
|
||||
"PURPLE",
|
||||
"OLIVE",
|
||||
"YELLOW",
|
||||
"GREEN",
|
||||
"TEAL",
|
||||
"CYAN",
|
||||
"BLUE",
|
||||
"MAGENTA",
|
||||
"DARKGRAY",
|
||||
"LIGHTGRAY",
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
static inline void libirc_colorparser_addorcat (char ** destline, unsigned int * destlen, const char * str)
|
||||
{
|
||||
unsigned int len = strlen(str);
|
||||
|
||||
if ( *destline )
|
||||
{
|
||||
strcpy (*destline, str);
|
||||
*destline += len;
|
||||
}
|
||||
else
|
||||
*destlen += len;
|
||||
}
|
||||
|
||||
|
||||
static void libirc_colorparser_applymask (unsigned int * mask,
|
||||
char ** destline, unsigned int * destlen,
|
||||
unsigned int bitmask, const char * start, const char * end)
|
||||
{
|
||||
if ( (*mask & bitmask) != 0 )
|
||||
{
|
||||
*mask &= ~bitmask;
|
||||
libirc_colorparser_addorcat (destline, destlen, end);
|
||||
}
|
||||
else
|
||||
{
|
||||
*mask |= bitmask;
|
||||
libirc_colorparser_addorcat (destline, destlen, start);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void libirc_colorparser_applycolor (unsigned int * mask,
|
||||
char ** destline, unsigned int * destlen,
|
||||
unsigned int colorid, unsigned int bgcolorid)
|
||||
{
|
||||
const char * end = "[/COLOR]";
|
||||
char startbuf[64];
|
||||
|
||||
if ( bgcolorid != 0 )
|
||||
sprintf (startbuf, "[COLOR=%s/%s]", color_replacement_table[colorid], color_replacement_table[bgcolorid]);
|
||||
else
|
||||
sprintf (startbuf, "[COLOR=%s]", color_replacement_table[colorid]);
|
||||
|
||||
if ( (*mask & LIBIRC_COLORPARSER_COLOR) != 0 )
|
||||
libirc_colorparser_addorcat (destline, destlen, end);
|
||||
|
||||
*mask |= LIBIRC_COLORPARSER_COLOR;
|
||||
libirc_colorparser_addorcat (destline, destlen, startbuf);
|
||||
}
|
||||
|
||||
|
||||
static void libirc_colorparser_closetags (unsigned int * mask,
|
||||
char ** destline, unsigned int * destlen)
|
||||
{
|
||||
if ( *mask & LIBIRC_COLORPARSER_BOLD )
|
||||
libirc_colorparser_applymask (mask, destline, destlen, LIBIRC_COLORPARSER_BOLD, 0, "[/B]");
|
||||
|
||||
if ( *mask & LIBIRC_COLORPARSER_UNDERLINE )
|
||||
libirc_colorparser_applymask (mask, destline, destlen, LIBIRC_COLORPARSER_UNDERLINE, 0, "[/U]");
|
||||
|
||||
if ( *mask & LIBIRC_COLORPARSER_REVERSE )
|
||||
libirc_colorparser_applymask (mask, destline, destlen, LIBIRC_COLORPARSER_REVERSE, 0, "[/I]");
|
||||
|
||||
if ( *mask & LIBIRC_COLORPARSER_COLOR )
|
||||
libirc_colorparser_applymask (mask, destline, destlen, LIBIRC_COLORPARSER_COLOR, 0, "[/COLOR]");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* IRC to [code] color conversion. Or strip.
|
||||
*/
|
||||
static char * libirc_colorparser_irc2code (const char * source, int strip)
|
||||
{
|
||||
unsigned int mask = 0, destlen = 0;
|
||||
char * destline = 0, *d = 0;
|
||||
const char *p;
|
||||
int current_bg = 0;
|
||||
|
||||
/*
|
||||
* There will be two passes. First pass calculates the total length of
|
||||
* the destination string. The second pass allocates memory for the string,
|
||||
* and fills it.
|
||||
*/
|
||||
while ( destline == 0 ) // destline will be set after the 2nd pass
|
||||
{
|
||||
if ( destlen > 0 )
|
||||
{
|
||||
// This is the 2nd pass; allocate memory.
|
||||
if ( (destline = malloc (destlen)) == 0 )
|
||||
return 0;
|
||||
|
||||
d = destline;
|
||||
}
|
||||
|
||||
for ( p = source; *p; p++ )
|
||||
{
|
||||
switch (*p)
|
||||
{
|
||||
case 0x02: // bold
|
||||
if ( strip )
|
||||
continue;
|
||||
|
||||
libirc_colorparser_applymask (&mask, &d, &destlen, LIBIRC_COLORPARSER_BOLD, "[B]", "[/B]");
|
||||
break;
|
||||
|
||||
case 0x1F: // underline
|
||||
if ( strip )
|
||||
continue;
|
||||
|
||||
libirc_colorparser_applymask (&mask, &d, &destlen, LIBIRC_COLORPARSER_UNDERLINE, "[U]", "[/U]");
|
||||
break;
|
||||
|
||||
case 0x16: // reverse
|
||||
if ( strip )
|
||||
continue;
|
||||
|
||||
libirc_colorparser_applymask (&mask, &d, &destlen, LIBIRC_COLORPARSER_REVERSE, "[I]", "[/I]");
|
||||
break;
|
||||
|
||||
case 0x0F: // reset colors
|
||||
if ( strip )
|
||||
continue;
|
||||
|
||||
libirc_colorparser_closetags (&mask, &d, &destlen);
|
||||
break;
|
||||
|
||||
case 0x03: // set color
|
||||
if ( isdigit (p[1]) )
|
||||
{
|
||||
// Parse
|
||||
int bgcolor = -1, color = p[1] - 0x30;
|
||||
p++;
|
||||
|
||||
if ( isdigit (p[1]) )
|
||||
{
|
||||
color = color * 10 + (p[1] - 0x30);
|
||||
p++;
|
||||
}
|
||||
|
||||
// If there is a comma, search for the following
|
||||
// background color
|
||||
if ( p[1] == ',' && isdigit (p[2]) )
|
||||
{
|
||||
bgcolor = p[2] - 0x30;
|
||||
p += 2;
|
||||
|
||||
if ( isdigit (p[1]) )
|
||||
{
|
||||
bgcolor = bgcolor * 10 + (p[1] - 0x30);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for range
|
||||
if ( color <= LIBIRC_COLORPARSER_MAXCOLORS
|
||||
&& bgcolor <= LIBIRC_COLORPARSER_MAXCOLORS )
|
||||
{
|
||||
if ( strip )
|
||||
continue;
|
||||
|
||||
if ( bgcolor != -1 )
|
||||
current_bg = bgcolor;
|
||||
|
||||
libirc_colorparser_applycolor (&mask, &d, &destlen, color, current_bg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if ( destline )
|
||||
*d++ = *p;
|
||||
else
|
||||
destlen++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Close all the opened tags
|
||||
libirc_colorparser_closetags (&mask, &d, &destlen);
|
||||
destlen++; // for 0-terminator
|
||||
}
|
||||
|
||||
*d = '\0';
|
||||
return destline;
|
||||
}
|
||||
|
||||
|
||||
static int libirc_colorparser_colorlookup (const char * color)
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; color_replacement_table[i]; i++ )
|
||||
if ( !strcmp (color, color_replacement_table[i]) )
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* [code] to IRC color conversion.
|
||||
*/
|
||||
char * irc_color_convert_to_mirc (const char * source)
|
||||
{
|
||||
unsigned int destlen = 0;
|
||||
char * destline = 0, *d = 0;
|
||||
const char *p1, *p2, *cur;
|
||||
|
||||
/*
|
||||
* There will be two passes. First pass calculates the total length of
|
||||
* the destination string. The second pass allocates memory for the string,
|
||||
* and fills it.
|
||||
*/
|
||||
while ( destline == 0 ) // destline will be set after the 2nd pass
|
||||
{
|
||||
if ( destlen > 0 )
|
||||
{
|
||||
// This is the 2nd pass; allocate memory.
|
||||
if ( (destline = malloc (destlen)) == 0 )
|
||||
return 0;
|
||||
|
||||
d = destline;
|
||||
}
|
||||
|
||||
cur = source;
|
||||
while ( (p1 = strchr (cur, '[')) != 0 )
|
||||
{
|
||||
const char * replacedval = 0;
|
||||
p2 = 0;
|
||||
|
||||
// Check if the closing bracket is available after p1
|
||||
// and the tag length is suitable
|
||||
if ( p1[1] != '\0'
|
||||
&& (p2 = strchr (p1, ']')) != 0
|
||||
&& (p2 - p1) > 1
|
||||
&& (p2 - p1) < 31 )
|
||||
{
|
||||
// Get the tag
|
||||
char tagbuf[32];
|
||||
int taglen = p2 - p1 - 1;
|
||||
|
||||
memcpy (tagbuf, p1 + 1, taglen);
|
||||
tagbuf[taglen] = '\0';
|
||||
|
||||
if ( !strcmp (tagbuf, "/COLOR") )
|
||||
replacedval = "\x0F";
|
||||
else if ( strstr (tagbuf, "COLOR=") == tagbuf )
|
||||
{
|
||||
int color, bgcolor = -2;
|
||||
char * bcol;
|
||||
|
||||
bcol = strchr (tagbuf + 6, '/');
|
||||
|
||||
if ( bcol )
|
||||
{
|
||||
*bcol++ = '\0';
|
||||
bgcolor = libirc_colorparser_colorlookup (bcol);
|
||||
}
|
||||
|
||||
color = libirc_colorparser_colorlookup (tagbuf + 6);
|
||||
|
||||
if ( color != -1 && bgcolor == -2 )
|
||||
{
|
||||
sprintf (tagbuf, "\x03%02d", color);
|
||||
replacedval = tagbuf;
|
||||
}
|
||||
else if ( color != -1 && bgcolor >= 0 )
|
||||
{
|
||||
sprintf (tagbuf, "\x03%02d,%02d", color, bgcolor);
|
||||
replacedval = tagbuf;
|
||||
}
|
||||
}
|
||||
else if ( !strcmp (tagbuf, "B") || !strcmp (tagbuf, "/B") )
|
||||
replacedval = "\x02";
|
||||
else if ( !strcmp (tagbuf, "U") || !strcmp (tagbuf, "/U") )
|
||||
replacedval = "\x1F";
|
||||
else if ( !strcmp (tagbuf, "I") || !strcmp (tagbuf, "/I") )
|
||||
replacedval = "\x16";
|
||||
}
|
||||
|
||||
if ( replacedval )
|
||||
{
|
||||
// add a part before the tag
|
||||
int partlen = p1 - cur;
|
||||
|
||||
if ( destline )
|
||||
{
|
||||
memcpy (d, cur, partlen);
|
||||
d += partlen;
|
||||
}
|
||||
else
|
||||
destlen += partlen;
|
||||
|
||||
// Add the replacement
|
||||
libirc_colorparser_addorcat (&d, &destlen, replacedval);
|
||||
|
||||
// And move the pointer
|
||||
cur = p2 + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// add a whole part before the end tag
|
||||
int partlen;
|
||||
|
||||
if ( !p2 )
|
||||
p2 = cur + strlen(cur);
|
||||
|
||||
partlen = p2 - cur + 1;
|
||||
|
||||
if ( destline )
|
||||
{
|
||||
memcpy (d, cur, partlen);
|
||||
d += partlen;
|
||||
}
|
||||
else
|
||||
destlen += partlen;
|
||||
|
||||
// And move the pointer
|
||||
cur = p2 + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the rest of string
|
||||
libirc_colorparser_addorcat (&d, &destlen, cur);
|
||||
destlen++; // for 0-terminator
|
||||
}
|
||||
|
||||
*d = '\0';
|
||||
return destline;
|
||||
}
|
||||
|
||||
|
||||
char * irc_color_strip_from_mirc (const char * message)
|
||||
{
|
||||
return libirc_colorparser_irc2code (message, 1);
|
||||
}
|
||||
|
||||
|
||||
char * irc_color_convert_from_mirc (const char * message)
|
||||
{
|
||||
return libirc_colorparser_irc2code (message, 0);
|
||||
}
|
892
external/LibIRC/dcc.c
vendored
Normal file
892
external/LibIRC/dcc.c
vendored
Normal file
@ -0,0 +1,892 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This library 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 Lesser General Public
|
||||
* License for more details.
|
||||
*/
|
||||
|
||||
#define LIBIRC_DCC_CHAT 1
|
||||
#define LIBIRC_DCC_SENDFILE 2
|
||||
#define LIBIRC_DCC_RECVFILE 3
|
||||
|
||||
|
||||
static irc_dcc_session_t * libirc_find_dcc_session (irc_session_t * session, irc_dcc_t dccid, int lock_list)
|
||||
{
|
||||
irc_dcc_session_t * s, *found = 0;
|
||||
|
||||
if ( lock_list )
|
||||
libirc_mutex_lock (&session->mutex_dcc);
|
||||
|
||||
for ( s = session->dcc_sessions; s; s = s->next )
|
||||
{
|
||||
if ( s->id == dccid )
|
||||
{
|
||||
found = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( found == 0 && lock_list )
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
static void libirc_dcc_destroy_nolock (irc_session_t * session, irc_dcc_t dccid)
|
||||
{
|
||||
irc_dcc_session_t * dcc = libirc_find_dcc_session (session, dccid, 0);
|
||||
|
||||
if ( dcc )
|
||||
{
|
||||
if ( dcc->sock >= 0 )
|
||||
socket_close (&dcc->sock);
|
||||
|
||||
dcc->state = LIBIRC_STATE_REMOVED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void libirc_remove_dcc_session (irc_session_t * session, irc_dcc_session_t * dcc, int lock_list)
|
||||
{
|
||||
if ( dcc->sock >= 0 )
|
||||
socket_close (&dcc->sock);
|
||||
|
||||
if ( dcc->dccsend_file_fp )
|
||||
fclose (dcc->dccsend_file_fp);
|
||||
|
||||
dcc->dccsend_file_fp = 0;
|
||||
|
||||
libirc_mutex_destroy (&dcc->mutex_outbuf);
|
||||
|
||||
if ( lock_list )
|
||||
libirc_mutex_lock (&session->mutex_dcc);
|
||||
|
||||
if ( session->dcc_sessions != dcc )
|
||||
{
|
||||
irc_dcc_session_t * s;
|
||||
for ( s = session->dcc_sessions; s; s = s->next )
|
||||
{
|
||||
if ( s->next == dcc )
|
||||
{
|
||||
s->next = dcc->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
session->dcc_sessions = dcc->next;
|
||||
|
||||
if ( lock_list )
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
|
||||
free (dcc);
|
||||
}
|
||||
|
||||
|
||||
static void libirc_dcc_add_descriptors (irc_session_t * ircsession, fd_set *in_set, fd_set *out_set, int * maxfd)
|
||||
{
|
||||
irc_dcc_session_t * dcc, *dcc_next;
|
||||
time_t now = time (0);
|
||||
|
||||
libirc_mutex_lock (&ircsession->mutex_dcc);
|
||||
|
||||
// Preprocessing DCC list:
|
||||
// - ask DCC send callbacks for data;
|
||||
// - remove unused DCC structures
|
||||
for ( dcc = ircsession->dcc_sessions; dcc; dcc = dcc_next )
|
||||
{
|
||||
dcc_next = dcc->next;
|
||||
|
||||
// Remove timed-out sessions
|
||||
if ( (dcc->state == LIBIRC_STATE_CONNECTING
|
||||
|| dcc->state == LIBIRC_STATE_INIT
|
||||
|| dcc->state == LIBIRC_STATE_LISTENING)
|
||||
&& now - dcc->timeout > ircsession->dcc_timeout )
|
||||
{
|
||||
// Inform the caller about DCC timeout.
|
||||
// Do not inform when state is LIBIRC_STATE_INIT - session
|
||||
// was initiated from someone else, and callbacks aren't set yet.
|
||||
if ( dcc->state != LIBIRC_STATE_INIT )
|
||||
{
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
|
||||
if ( dcc->cb )
|
||||
(*dcc->cb)(ircsession, dcc->id, LIBIRC_ERR_TIMEOUT, dcc->ctx, 0, 0);
|
||||
|
||||
libirc_mutex_lock (&ircsession->mutex_dcc);
|
||||
}
|
||||
|
||||
libirc_remove_dcc_session (ircsession, dcc, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're sending file, and the output buffer is empty, we need
|
||||
* to provide some data.
|
||||
*/
|
||||
if ( dcc->state == LIBIRC_STATE_CONNECTED
|
||||
&& dcc->dccmode == LIBIRC_DCC_SENDFILE
|
||||
&& dcc->dccsend_file_fp
|
||||
&& dcc->outgoing_offset == 0 )
|
||||
{
|
||||
int len = fread (dcc->outgoing_buf, 1, sizeof (dcc->outgoing_buf), dcc->dccsend_file_fp);
|
||||
|
||||
if ( len <= 0 )
|
||||
{
|
||||
int err = (len < 0 ? LIBIRC_ERR_READ : 0);
|
||||
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
|
||||
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
|
||||
libirc_mutex_lock (&ircsession->mutex_dcc);
|
||||
libirc_dcc_destroy_nolock (ircsession, dcc->id);
|
||||
}
|
||||
else
|
||||
dcc->outgoing_offset = len;
|
||||
}
|
||||
|
||||
// Clean up unused sessions
|
||||
if ( dcc->state == LIBIRC_STATE_REMOVED )
|
||||
libirc_remove_dcc_session (ircsession, dcc, 0);
|
||||
}
|
||||
|
||||
for ( dcc = ircsession->dcc_sessions; dcc; dcc = dcc->next )
|
||||
{
|
||||
switch (dcc->state)
|
||||
{
|
||||
case LIBIRC_STATE_LISTENING:
|
||||
// While listening, only in_set descriptor should be set
|
||||
libirc_add_to_set (dcc->sock, in_set, maxfd);
|
||||
break;
|
||||
|
||||
case LIBIRC_STATE_CONNECTING:
|
||||
// While connection, only out_set descriptor should be set
|
||||
libirc_add_to_set (dcc->sock, out_set, maxfd);
|
||||
break;
|
||||
|
||||
case LIBIRC_STATE_CONNECTED:
|
||||
// Add input descriptor if there is space in input buffer
|
||||
// and it is DCC chat (during DCC send, there is nothing to recv)
|
||||
if ( dcc->incoming_offset < sizeof(dcc->incoming_buf) - 1 )
|
||||
libirc_add_to_set (dcc->sock, in_set, maxfd);
|
||||
|
||||
// Add output descriptor if there is something in output buffer
|
||||
libirc_mutex_lock (&dcc->mutex_outbuf);
|
||||
|
||||
if ( dcc->outgoing_offset > 0 )
|
||||
libirc_add_to_set (dcc->sock, out_set, maxfd);
|
||||
|
||||
libirc_mutex_unlock (&dcc->mutex_outbuf);
|
||||
break;
|
||||
|
||||
case LIBIRC_STATE_CONFIRM_SIZE:
|
||||
/*
|
||||
* If we're receiving file, then WE should confirm the transferred
|
||||
* part (so we have to sent data). But if we're sending the file,
|
||||
* then RECEIVER should confirm the packet, so we have to receive
|
||||
* data.
|
||||
*
|
||||
* We don't need to LOCK_DCC_OUTBUF - during file transfer, buffers
|
||||
* can't change asynchronously.
|
||||
*/
|
||||
if ( dcc->dccmode == LIBIRC_DCC_RECVFILE && dcc->outgoing_offset > 0 )
|
||||
libirc_add_to_set (dcc->sock, out_set, maxfd);
|
||||
|
||||
if ( dcc->dccmode == LIBIRC_DCC_SENDFILE && dcc->incoming_offset < 4 )
|
||||
libirc_add_to_set (dcc->sock, in_set, maxfd);
|
||||
}
|
||||
}
|
||||
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
}
|
||||
|
||||
|
||||
static void libirc_dcc_process_descriptors (irc_session_t * ircsession, fd_set *in_set, fd_set *out_set)
|
||||
{
|
||||
irc_dcc_session_t * dcc;
|
||||
|
||||
/*
|
||||
* We need to use such a complex scheme here, because on every callback
|
||||
* a number of DCC sessions could be destroyed.
|
||||
*/
|
||||
libirc_mutex_lock (&ircsession->mutex_dcc);
|
||||
|
||||
for ( dcc = ircsession->dcc_sessions; dcc; dcc = dcc->next )
|
||||
{
|
||||
if ( dcc->state == LIBIRC_STATE_LISTENING
|
||||
&& FD_ISSET (dcc->sock, in_set) )
|
||||
{
|
||||
socklen_t len = sizeof(dcc->remote_addr);
|
||||
int nsock, err = 0;
|
||||
|
||||
// New connection is available; accept it.
|
||||
if ( socket_accept (&dcc->sock, (socket_t*)&nsock, (struct sockaddr *) &dcc->remote_addr, &len) )
|
||||
err = LIBIRC_ERR_ACCEPT;
|
||||
|
||||
// On success, change the active socket and change the state
|
||||
if ( err == 0 )
|
||||
{
|
||||
// close the listen socket, and replace it by a newly
|
||||
// accepted
|
||||
socket_close (&dcc->sock);
|
||||
dcc->sock = nsock;
|
||||
dcc->state = LIBIRC_STATE_CONNECTED;
|
||||
}
|
||||
|
||||
// If this is DCC chat, inform the caller about accept()
|
||||
// success or failure.
|
||||
// Otherwise (DCC send) there is no reason.
|
||||
if ( dcc->dccmode == LIBIRC_DCC_CHAT )
|
||||
{
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
|
||||
libirc_mutex_lock (&ircsession->mutex_dcc);
|
||||
}
|
||||
|
||||
if ( err )
|
||||
libirc_dcc_destroy_nolock (ircsession, dcc->id);
|
||||
}
|
||||
|
||||
if ( dcc->state == LIBIRC_STATE_CONNECTING
|
||||
&& FD_ISSET (dcc->sock, out_set) )
|
||||
{
|
||||
// Now we have to determine whether the socket is connected
|
||||
// or the connect is failed
|
||||
struct sockaddr_in saddr;
|
||||
socklen_t slen = sizeof(saddr);
|
||||
int err = 0;
|
||||
|
||||
if ( getpeername (dcc->sock, (struct sockaddr*)&saddr, &slen) < 0 )
|
||||
err = LIBIRC_ERR_CONNECT;
|
||||
|
||||
// On success, change the state
|
||||
if ( err == 0 )
|
||||
dcc->state = LIBIRC_STATE_CONNECTED;
|
||||
|
||||
// If this is DCC chat, inform the caller about connect()
|
||||
// success or failure.
|
||||
// Otherwise (DCC send) there is no reason.
|
||||
if ( dcc->dccmode == LIBIRC_DCC_CHAT )
|
||||
{
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
|
||||
libirc_mutex_lock (&ircsession->mutex_dcc);
|
||||
}
|
||||
|
||||
if ( err )
|
||||
libirc_dcc_destroy_nolock (ircsession, dcc->id);
|
||||
}
|
||||
|
||||
if ( dcc->state == LIBIRC_STATE_CONNECTED
|
||||
|| dcc->state == LIBIRC_STATE_CONFIRM_SIZE )
|
||||
{
|
||||
if ( FD_ISSET (dcc->sock, in_set) )
|
||||
{
|
||||
int length, offset = 0, err = 0;
|
||||
|
||||
unsigned int amount = sizeof (dcc->incoming_buf) - dcc->incoming_offset;
|
||||
|
||||
length = socket_recv (&dcc->sock, dcc->incoming_buf + dcc->incoming_offset, amount);
|
||||
|
||||
if ( length < 0 )
|
||||
{
|
||||
err = LIBIRC_ERR_READ;
|
||||
}
|
||||
else if ( length == 0 )
|
||||
{
|
||||
err = LIBIRC_ERR_CLOSED;
|
||||
|
||||
if ( dcc->dccsend_file_fp )
|
||||
{
|
||||
fclose (dcc->dccsend_file_fp);
|
||||
dcc->dccsend_file_fp = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dcc->incoming_offset += length;
|
||||
|
||||
if ( dcc->dccmode != LIBIRC_DCC_CHAT )
|
||||
offset = dcc->incoming_offset;
|
||||
else
|
||||
offset = libirc_findcrorlf (dcc->incoming_buf, dcc->incoming_offset);
|
||||
|
||||
/*
|
||||
* In LIBIRC_STATE_CONFIRM_SIZE state we don't call any
|
||||
* callbacks (except there is an error). We just receive
|
||||
* the data, and compare it with the amount sent.
|
||||
*/
|
||||
if ( dcc->state == LIBIRC_STATE_CONFIRM_SIZE )
|
||||
{
|
||||
if ( dcc->dccmode != LIBIRC_DCC_SENDFILE )
|
||||
abort();
|
||||
|
||||
if ( dcc->incoming_offset == 4 )
|
||||
{
|
||||
// The order is big-endian
|
||||
const unsigned char * bptr = (const unsigned char *) dcc->incoming_buf;
|
||||
unsigned int received_size = (bptr[0] << 24) | (bptr[1] << 16) | (bptr[2] << 8) | bptr[3];
|
||||
|
||||
// Sent size confirmed
|
||||
if ( dcc->file_confirm_offset == received_size )
|
||||
{
|
||||
dcc->state = LIBIRC_STATE_CONNECTED;
|
||||
dcc->incoming_offset = 0;
|
||||
}
|
||||
else
|
||||
err = LIBIRC_ERR_WRITE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If it is DCC_CHAT, we send a 0-terminated string
|
||||
* (which is smaller than offset). Otherwise we send
|
||||
* a full buffer.
|
||||
*/
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
|
||||
if ( dcc->dccmode != LIBIRC_DCC_CHAT )
|
||||
{
|
||||
if ( dcc->dccmode != LIBIRC_DCC_RECVFILE )
|
||||
abort();
|
||||
|
||||
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, dcc->incoming_buf, offset);
|
||||
|
||||
/*
|
||||
* If the session is not terminated in callback,
|
||||
* put the sent amount into the sent_packet_size_net_byteorder
|
||||
*/
|
||||
if ( dcc->state != LIBIRC_STATE_REMOVED )
|
||||
{
|
||||
dcc->state = LIBIRC_STATE_CONFIRM_SIZE;
|
||||
dcc->file_confirm_offset += offset;
|
||||
|
||||
// Store as big endian
|
||||
dcc->outgoing_buf[0] = (char) dcc->file_confirm_offset >> 24;
|
||||
dcc->outgoing_buf[1] = (char) dcc->file_confirm_offset >> 16;
|
||||
dcc->outgoing_buf[2] = (char) dcc->file_confirm_offset >> 8;
|
||||
dcc->outgoing_buf[3] = (char) dcc->file_confirm_offset;
|
||||
dcc->outgoing_offset = 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, dcc->incoming_buf, strlen(dcc->incoming_buf));
|
||||
|
||||
libirc_mutex_lock (&ircsession->mutex_dcc);
|
||||
|
||||
if ( dcc->incoming_offset - offset > 0 )
|
||||
memmove (dcc->incoming_buf, dcc->incoming_buf + offset, dcc->incoming_offset - offset);
|
||||
|
||||
dcc->incoming_offset -= offset;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If error arises somewhere above, we inform the caller
|
||||
* of failure, and destroy this session.
|
||||
*/
|
||||
if ( err )
|
||||
{
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
|
||||
libirc_mutex_lock (&ircsession->mutex_dcc);
|
||||
libirc_dcc_destroy_nolock (ircsession, dcc->id);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Session might be closed (with sock = -1) after the in_set
|
||||
* processing, so before out_set processing we should check
|
||||
* for this case
|
||||
*/
|
||||
if ( dcc->state == LIBIRC_STATE_REMOVED )
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Write bit set - we can send() something, and it won't block.
|
||||
*/
|
||||
if ( FD_ISSET (dcc->sock, out_set) )
|
||||
{
|
||||
int length, offset, err = 0;
|
||||
|
||||
/*
|
||||
* Because in some cases outgoing_buf could be changed
|
||||
* asynchronously (by another thread), we should lock
|
||||
* it.
|
||||
*/
|
||||
libirc_mutex_lock (&dcc->mutex_outbuf);
|
||||
|
||||
offset = dcc->outgoing_offset;
|
||||
|
||||
if ( offset > 0 )
|
||||
{
|
||||
length = socket_send (&dcc->sock, dcc->outgoing_buf, offset);
|
||||
|
||||
if ( length < 0 )
|
||||
err = LIBIRC_ERR_WRITE;
|
||||
else if ( length == 0 )
|
||||
err = LIBIRC_ERR_CLOSED;
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If this was DCC_SENDFILE, and we just sent a packet,
|
||||
* change the state to wait for confirmation (and store
|
||||
* sent packet size)
|
||||
*/
|
||||
if ( dcc->state == LIBIRC_STATE_CONNECTED
|
||||
&& dcc->dccmode == LIBIRC_DCC_SENDFILE )
|
||||
{
|
||||
dcc->file_confirm_offset += offset;
|
||||
dcc->state = LIBIRC_STATE_CONFIRM_SIZE;
|
||||
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
libirc_mutex_unlock (&dcc->mutex_outbuf);
|
||||
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, offset);
|
||||
libirc_mutex_lock (&ircsession->mutex_dcc);
|
||||
libirc_mutex_lock (&dcc->mutex_outbuf);
|
||||
}
|
||||
|
||||
if ( dcc->outgoing_offset - length > 0 )
|
||||
memmove (dcc->outgoing_buf, dcc->outgoing_buf + length, dcc->outgoing_offset - length);
|
||||
|
||||
dcc->outgoing_offset -= length;
|
||||
|
||||
/*
|
||||
* If we just sent the confirmation data, change state
|
||||
* back.
|
||||
*/
|
||||
if ( dcc->state == LIBIRC_STATE_CONFIRM_SIZE
|
||||
&& dcc->dccmode == LIBIRC_DCC_RECVFILE
|
||||
&& dcc->outgoing_offset == 0 )
|
||||
{
|
||||
/*
|
||||
* If the file is already received, we should inform
|
||||
* the caller, and close the session.
|
||||
*/
|
||||
if ( dcc->received_file_size == dcc->file_confirm_offset )
|
||||
{
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
libirc_mutex_unlock (&dcc->mutex_outbuf);
|
||||
(*dcc->cb)(ircsession, dcc->id, 0, dcc->ctx, 0, 0);
|
||||
libirc_dcc_destroy_nolock (ircsession, dcc->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Continue to receive the file */
|
||||
dcc->state = LIBIRC_STATE_CONNECTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
libirc_mutex_unlock (&dcc->mutex_outbuf);
|
||||
|
||||
/*
|
||||
* If error arises somewhere above, we inform the caller
|
||||
* of failure, and destroy this session.
|
||||
*/
|
||||
if ( err )
|
||||
{
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
|
||||
libirc_mutex_lock (&ircsession->mutex_dcc);
|
||||
|
||||
libirc_dcc_destroy_nolock (ircsession, dcc->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
}
|
||||
|
||||
|
||||
static int libirc_new_dcc_session (irc_session_t * session, unsigned long ip, unsigned short port, int dccmode, void * ctx, irc_dcc_session_t ** pdcc)
|
||||
{
|
||||
irc_dcc_session_t * dcc = malloc (sizeof(irc_dcc_session_t));
|
||||
|
||||
if ( !dcc )
|
||||
return LIBIRC_ERR_NOMEM;
|
||||
|
||||
// setup
|
||||
memset (dcc, 0, sizeof(irc_dcc_session_t));
|
||||
|
||||
dcc->dccsend_file_fp = 0;
|
||||
|
||||
if ( libirc_mutex_init (&dcc->mutex_outbuf) )
|
||||
goto cleanup_exit_error;
|
||||
|
||||
if ( socket_create (PF_INET, SOCK_STREAM, &dcc->sock) )
|
||||
goto cleanup_exit_error;
|
||||
|
||||
if ( !ip )
|
||||
{
|
||||
unsigned long arg = 1;
|
||||
|
||||
setsockopt (dcc->sock, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, sizeof(arg));
|
||||
|
||||
#if defined (ENABLE_IPV6)
|
||||
if ( session->flags & SESSIONFL_USES_IPV6 )
|
||||
{
|
||||
struct sockaddr_in6 saddr6;
|
||||
|
||||
memset (&saddr6, 0, sizeof(saddr6));
|
||||
saddr6.sin6_family = AF_INET6;
|
||||
memcpy (&saddr6.sin6_addr, &session->local_addr6, sizeof(session->local_addr6));
|
||||
saddr6.sin6_port = htons (0);
|
||||
|
||||
if ( bind (dcc->sock, (struct sockaddr *) &saddr6, sizeof(saddr6)) < 0 )
|
||||
goto cleanup_exit_error;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
struct sockaddr_in saddr;
|
||||
memset (&saddr, 0, sizeof(saddr));
|
||||
saddr.sin_family = AF_INET;
|
||||
memcpy (&saddr.sin_addr, &session->local_addr, sizeof(session->local_addr));
|
||||
saddr.sin_port = htons (0);
|
||||
|
||||
if ( bind (dcc->sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0 )
|
||||
goto cleanup_exit_error;
|
||||
}
|
||||
|
||||
if ( listen (dcc->sock, 5) < 0 )
|
||||
goto cleanup_exit_error;
|
||||
|
||||
dcc->state = LIBIRC_STATE_LISTENING;
|
||||
}
|
||||
else
|
||||
{
|
||||
// make socket non-blocking, so connect() call won't block
|
||||
if ( socket_make_nonblocking (&dcc->sock) )
|
||||
goto cleanup_exit_error;
|
||||
|
||||
memset (&dcc->remote_addr, 0, sizeof(dcc->remote_addr));
|
||||
dcc->remote_addr.sin_family = AF_INET;
|
||||
dcc->remote_addr.sin_addr.s_addr = htonl (ip); // what idiot came up with idea to send IP address in host-byteorder?
|
||||
dcc->remote_addr.sin_port = htons(port);
|
||||
|
||||
dcc->state = LIBIRC_STATE_INIT;
|
||||
}
|
||||
|
||||
dcc->dccmode = dccmode;
|
||||
dcc->ctx = ctx;
|
||||
time (&dcc->timeout);
|
||||
|
||||
// and store it
|
||||
libirc_mutex_lock (&session->mutex_dcc);
|
||||
|
||||
dcc->id = session->dcc_last_id++;
|
||||
dcc->next = session->dcc_sessions;
|
||||
session->dcc_sessions = dcc;
|
||||
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
|
||||
*pdcc = dcc;
|
||||
return 0;
|
||||
|
||||
cleanup_exit_error:
|
||||
if ( dcc->sock >= 0 )
|
||||
socket_close (&dcc->sock);
|
||||
|
||||
free (dcc);
|
||||
return LIBIRC_ERR_SOCKET;
|
||||
}
|
||||
|
||||
|
||||
int irc_dcc_destroy (irc_session_t * session, irc_dcc_t dccid)
|
||||
{
|
||||
// This function doesn't actually destroy the session; it just changes
|
||||
// its state to "removed" and closes the socket. The memory is actually
|
||||
// freed after the processing loop.
|
||||
irc_dcc_session_t * dcc = libirc_find_dcc_session (session, dccid, 1);
|
||||
|
||||
if ( !dcc )
|
||||
return 1;
|
||||
|
||||
if ( dcc->sock >= 0 )
|
||||
socket_close (&dcc->sock);
|
||||
|
||||
dcc->state = LIBIRC_STATE_REMOVED;
|
||||
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int irc_dcc_chat (irc_session_t * session, void * ctx, const char * nick, irc_dcc_callback_t callback, irc_dcc_t * dccid)
|
||||
{
|
||||
struct sockaddr_in saddr;
|
||||
socklen_t len = sizeof(saddr);
|
||||
char cmdbuf[128], notbuf[128];
|
||||
irc_dcc_session_t * dcc;
|
||||
int err;
|
||||
|
||||
if ( session->state != LIBIRC_STATE_CONNECTED )
|
||||
{
|
||||
session->lasterror = LIBIRC_ERR_STATE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
err = libirc_new_dcc_session (session, 0, 0, LIBIRC_DCC_CHAT, ctx, &dcc);
|
||||
|
||||
if ( err )
|
||||
{
|
||||
session->lasterror = err;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( getsockname (dcc->sock, (struct sockaddr*) &saddr, &len) < 0 )
|
||||
{
|
||||
session->lasterror = LIBIRC_ERR_SOCKET;
|
||||
libirc_remove_dcc_session (session, dcc, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sprintf (notbuf, "DCC Chat (%s)", inet_ntoa (saddr.sin_addr));
|
||||
sprintf (cmdbuf, "DCC CHAT chat %lu %u", (unsigned long) ntohl (saddr.sin_addr.s_addr), ntohs (saddr.sin_port));
|
||||
|
||||
if ( irc_cmd_notice (session, nick, notbuf)
|
||||
|| irc_cmd_ctcp_request (session, nick, cmdbuf) )
|
||||
{
|
||||
libirc_remove_dcc_session (session, dcc, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
*dccid = dcc->id;
|
||||
dcc->cb = callback;
|
||||
dcc->dccmode = LIBIRC_DCC_CHAT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int irc_dcc_msg (irc_session_t * session, irc_dcc_t dccid, const char * text)
|
||||
{
|
||||
irc_dcc_session_t * dcc = libirc_find_dcc_session (session, dccid, 1);
|
||||
|
||||
if ( !dcc )
|
||||
return 1;
|
||||
|
||||
if ( dcc->dccmode != LIBIRC_DCC_CHAT )
|
||||
{
|
||||
session->lasterror = LIBIRC_ERR_INVAL;
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( (strlen(text) + 2) >= (sizeof(dcc->outgoing_buf) - dcc->outgoing_offset) )
|
||||
{
|
||||
session->lasterror = LIBIRC_ERR_NOMEM;
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
libirc_mutex_lock (&dcc->mutex_outbuf);
|
||||
|
||||
strcpy (dcc->outgoing_buf + dcc->outgoing_offset, text);
|
||||
dcc->outgoing_offset += strlen (text);
|
||||
dcc->outgoing_buf[dcc->outgoing_offset++] = 0x0D;
|
||||
dcc->outgoing_buf[dcc->outgoing_offset++] = 0x0A;
|
||||
|
||||
libirc_mutex_unlock (&dcc->mutex_outbuf);
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void libirc_dcc_request (irc_session_t * session, const char * nick, const char * req)
|
||||
{
|
||||
char filenamebuf[256];
|
||||
unsigned long ip, size;
|
||||
unsigned short port;
|
||||
|
||||
if ( sscanf (req, "DCC CHAT chat %lu %hu", &ip, &port) == 2 )
|
||||
{
|
||||
if ( session->callbacks.event_dcc_chat_req )
|
||||
{
|
||||
irc_dcc_session_t * dcc;
|
||||
|
||||
int err = libirc_new_dcc_session (session, ip, port, LIBIRC_DCC_CHAT, 0, &dcc);
|
||||
if ( err )
|
||||
{
|
||||
session->lasterror = err;
|
||||
return;
|
||||
}
|
||||
|
||||
(*session->callbacks.event_dcc_chat_req) (session,
|
||||
nick,
|
||||
inet_ntoa (dcc->remote_addr.sin_addr),
|
||||
dcc->id);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else if ( sscanf (req, "DCC SEND %s %lu %hu %lu", filenamebuf, &ip, &port, &size) == 4 )
|
||||
{
|
||||
if ( session->callbacks.event_dcc_send_req )
|
||||
{
|
||||
irc_dcc_session_t * dcc;
|
||||
|
||||
int err = libirc_new_dcc_session (session, ip, port, LIBIRC_DCC_RECVFILE, 0, &dcc);
|
||||
if ( err )
|
||||
{
|
||||
session->lasterror = err;
|
||||
return;
|
||||
}
|
||||
|
||||
(*session->callbacks.event_dcc_send_req) (session,
|
||||
nick,
|
||||
inet_ntoa (dcc->remote_addr.sin_addr),
|
||||
filenamebuf,
|
||||
size,
|
||||
dcc->id);
|
||||
|
||||
dcc->received_file_size = size;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#if defined (ENABLE_DEBUG)
|
||||
fprintf (stderr, "BUG: Unhandled DCC message: %s\n", req);
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int irc_dcc_accept (irc_session_t * session, irc_dcc_t dccid, void * ctx, irc_dcc_callback_t callback)
|
||||
{
|
||||
irc_dcc_session_t * dcc = libirc_find_dcc_session (session, dccid, 1);
|
||||
|
||||
if ( !dcc )
|
||||
return 1;
|
||||
|
||||
if ( dcc->state != LIBIRC_STATE_INIT )
|
||||
{
|
||||
session->lasterror = LIBIRC_ERR_STATE;
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dcc->cb = callback;
|
||||
dcc->ctx = ctx;
|
||||
|
||||
// Initiate the connect
|
||||
if ( socket_connect (&dcc->sock, (struct sockaddr *) &dcc->remote_addr, sizeof(dcc->remote_addr)) )
|
||||
{
|
||||
libirc_dcc_destroy_nolock (session, dccid);
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
session->lasterror = LIBIRC_ERR_CONNECT;
|
||||
return 1;
|
||||
}
|
||||
|
||||
dcc->state = LIBIRC_STATE_CONNECTING;
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int irc_dcc_decline (irc_session_t * session, irc_dcc_t dccid)
|
||||
{
|
||||
irc_dcc_session_t * dcc = libirc_find_dcc_session (session, dccid, 1);
|
||||
|
||||
if ( !dcc )
|
||||
return 1;
|
||||
|
||||
if ( dcc->state != LIBIRC_STATE_INIT )
|
||||
{
|
||||
session->lasterror = LIBIRC_ERR_STATE;
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
libirc_dcc_destroy_nolock (session, dccid);
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int irc_dcc_sendfile (irc_session_t * session, void * ctx, const char * nick, const char * filename, irc_dcc_callback_t callback, irc_dcc_t * dccid)
|
||||
{
|
||||
struct sockaddr_in saddr;
|
||||
socklen_t len = sizeof(saddr);
|
||||
char cmdbuf[128], notbuf[128];
|
||||
irc_dcc_session_t * dcc;
|
||||
const char * p;
|
||||
int err;
|
||||
long filesize;
|
||||
|
||||
if ( !session || !dccid || !filename || !callback )
|
||||
{
|
||||
session->lasterror = LIBIRC_ERR_INVAL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( session->state != LIBIRC_STATE_CONNECTED )
|
||||
{
|
||||
session->lasterror = LIBIRC_ERR_STATE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( (err = libirc_new_dcc_session (session, 0, 0, LIBIRC_DCC_SENDFILE, ctx, &dcc)) != 0 )
|
||||
{
|
||||
session->lasterror = err;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( (dcc->dccsend_file_fp = fopen (filename, "rb")) == 0 )
|
||||
{
|
||||
libirc_remove_dcc_session (session, dcc, 1);
|
||||
session->lasterror = LIBIRC_ERR_OPENFILE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Get file length */
|
||||
if ( fseek (dcc->dccsend_file_fp, 0, SEEK_END)
|
||||
|| (filesize = ftell (dcc->dccsend_file_fp)) == -1
|
||||
|| fseek (dcc->dccsend_file_fp, 0, SEEK_SET) )
|
||||
{
|
||||
libirc_remove_dcc_session (session, dcc, 1);
|
||||
session->lasterror = LIBIRC_ERR_NODCCSEND;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( getsockname (dcc->sock, (struct sockaddr*) &saddr, &len) < 0 )
|
||||
{
|
||||
libirc_remove_dcc_session (session, dcc, 1);
|
||||
session->lasterror = LIBIRC_ERR_SOCKET;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Remove path from the filename
|
||||
if ( (p = strrchr (filename, '\\')) == 0
|
||||
&& (p = strrchr (filename, '/')) == 0 )
|
||||
p = filename;
|
||||
else
|
||||
p++; // skip directory slash
|
||||
|
||||
sprintf (notbuf, "DCC Send %s (%s)", p, inet_ntoa (saddr.sin_addr));
|
||||
sprintf (cmdbuf, "DCC SEND %s %lu %u %ld", p, (unsigned long) ntohl (saddr.sin_addr.s_addr), ntohs (saddr.sin_port), filesize);
|
||||
|
||||
if ( irc_cmd_notice (session, nick, notbuf)
|
||||
|| irc_cmd_ctcp_request (session, nick, cmdbuf) )
|
||||
{
|
||||
libirc_remove_dcc_session (session, dcc, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
*dccid = dcc->id;
|
||||
dcc->cb = callback;
|
||||
|
||||
return 0;
|
||||
}
|
54
external/LibIRC/dcc.h
vendored
Normal file
54
external/LibIRC/dcc.h
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This library 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 Lesser General Public
|
||||
* License for more details.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_IRC_DCC_H
|
||||
#define INCLUDE_IRC_DCC_H
|
||||
|
||||
|
||||
/*
|
||||
* This structure keeps the state of a single DCC connection.
|
||||
*/
|
||||
struct irc_dcc_session_s
|
||||
{
|
||||
irc_dcc_session_t * next;
|
||||
|
||||
irc_dcc_t id;
|
||||
void * ctx;
|
||||
socket_t sock; /*!< DCC socket */
|
||||
int dccmode; /*!< Boolean value to differ chat vs send
|
||||
requests. Changes the cb behavior - when
|
||||
it is chat, data is sent by lines with
|
||||
stripped CRLFs. In file mode, the data
|
||||
is sent as-is */
|
||||
int state;
|
||||
time_t timeout;
|
||||
|
||||
FILE * dccsend_file_fp;
|
||||
unsigned int received_file_size;
|
||||
unsigned int file_confirm_offset;
|
||||
|
||||
struct sockaddr_in remote_addr;
|
||||
|
||||
char incoming_buf[LIBIRC_DCC_BUFFER_SIZE];
|
||||
unsigned int incoming_offset;
|
||||
|
||||
char outgoing_buf[LIBIRC_DCC_BUFFER_SIZE];
|
||||
unsigned int outgoing_offset;
|
||||
port_mutex_t mutex_outbuf;
|
||||
|
||||
irc_dcc_callback_t cb;
|
||||
};
|
||||
|
||||
|
||||
#endif /* INCLUDE_IRC_DCC_H */
|
54
external/LibIRC/errors.c
vendored
Normal file
54
external/LibIRC/errors.c
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This library 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 Lesser General Public
|
||||
* License for more details.
|
||||
*/
|
||||
|
||||
static const char * libirc_strerror[LIBIRC_ERR_MAX] =
|
||||
{
|
||||
"No error",
|
||||
"Invalid argument",
|
||||
"Host not resolved",
|
||||
"Socket error",
|
||||
"Could not connect",
|
||||
"Remote connection closed",
|
||||
"Out of memory",
|
||||
"Could not accept new connection",
|
||||
"Object not found",
|
||||
"Could not DCC send this object",
|
||||
"Read error",
|
||||
"Write error",
|
||||
"Illegal operation for this state",
|
||||
"Timeout error",
|
||||
"Could not open file",
|
||||
"IRC session terminated",
|
||||
"IPv6 not supported",
|
||||
"SSL not supported",
|
||||
"SSL initialization failed",
|
||||
"SSL connection failed",
|
||||
"SSL certificate verify failed",
|
||||
};
|
||||
|
||||
|
||||
int irc_errno (irc_session_t * session)
|
||||
{
|
||||
return session->lasterror;
|
||||
}
|
||||
|
||||
|
||||
const char * irc_strerror (int ircerrno)
|
||||
{
|
||||
if ( ircerrno >= 0 && ircerrno < LIBIRC_ERR_MAX )
|
||||
return libirc_strerror[ircerrno];
|
||||
else
|
||||
return "Invalid irc_errno value";
|
||||
}
|
||||
|
1258
external/LibIRC/libircclient.c
vendored
Normal file
1258
external/LibIRC/libircclient.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
36
external/LibIRC/params.h
vendored
Normal file
36
external/LibIRC/params.h
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This library 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 Lesser General Public
|
||||
* License for more details.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_IRC_PARAMS_H
|
||||
#define INCLUDE_IRC_PARAMS_H
|
||||
|
||||
|
||||
#define LIBIRC_VERSION_HIGH 1
|
||||
#define LIBIRC_VERSION_LOW 8
|
||||
|
||||
#define LIBIRC_BUFFER_SIZE 1024
|
||||
#define LIBIRC_DCC_BUFFER_SIZE 1024
|
||||
|
||||
#define LIBIRC_STATE_INIT 0
|
||||
#define LIBIRC_STATE_LISTENING 1
|
||||
#define LIBIRC_STATE_CONNECTING 2
|
||||
#define LIBIRC_STATE_CONNECTED 3
|
||||
#define LIBIRC_STATE_DISCONNECTED 4
|
||||
#define LIBIRC_STATE_CONFIRM_SIZE 5 // Used only by DCC send to confirm the amount of sent data
|
||||
#define LIBIRC_STATE_REMOVED 10 // this state is used only in DCC
|
||||
|
||||
|
||||
#define SSL_PREFIX '#'
|
||||
|
||||
#endif /* INCLUDE_IRC_PARAMS_H */
|
156
external/LibIRC/portable.c
vendored
Normal file
156
external/LibIRC/portable.c
vendored
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This library 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 Lesser General Public
|
||||
* License for more details.
|
||||
*/
|
||||
|
||||
#if !defined (_WIN32)
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
|
||||
#if defined (ENABLE_THREADS)
|
||||
#include <pthread.h>
|
||||
typedef pthread_mutex_t port_mutex_t;
|
||||
|
||||
#if !defined (PTHREAD_MUTEX_RECURSIVE) && defined (PTHREAD_MUTEX_RECURSIVE_NP)
|
||||
#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <windows.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined (ENABLE_THREADS)
|
||||
typedef CRITICAL_SECTION port_mutex_t;
|
||||
#endif
|
||||
|
||||
#define inline
|
||||
#define snprintf _snprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#define strncasecmp _strnicmp
|
||||
#endif
|
||||
|
||||
|
||||
#if defined (ENABLE_SSL)
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
#endif
|
||||
|
||||
|
||||
#if defined (ENABLE_THREADS)
|
||||
static inline int libirc_mutex_init (port_mutex_t * mutex)
|
||||
{
|
||||
#if defined (_WIN32)
|
||||
InitializeCriticalSection (mutex);
|
||||
return 0;
|
||||
#elif defined (PTHREAD_MUTEX_RECURSIVE)
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
return (pthread_mutexattr_init (&attr)
|
||||
|| pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE)
|
||||
|| pthread_mutex_init (mutex, &attr));
|
||||
#else /* !defined (PTHREAD_MUTEX_RECURSIVE) */
|
||||
|
||||
return pthread_mutex_init (mutex, 0);
|
||||
|
||||
#endif /* defined (_WIN32) */
|
||||
}
|
||||
|
||||
|
||||
static inline void libirc_mutex_destroy (port_mutex_t * mutex)
|
||||
{
|
||||
#if defined (_WIN32)
|
||||
DeleteCriticalSection (mutex);
|
||||
#else
|
||||
pthread_mutex_destroy (mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static inline void libirc_mutex_lock (port_mutex_t * mutex)
|
||||
{
|
||||
#if defined (_WIN32)
|
||||
EnterCriticalSection (mutex);
|
||||
#else
|
||||
pthread_mutex_lock (mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static inline void libirc_mutex_unlock (port_mutex_t * mutex)
|
||||
{
|
||||
#if defined (_WIN32)
|
||||
LeaveCriticalSection (mutex);
|
||||
#else
|
||||
pthread_mutex_unlock (mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
typedef void * port_mutex_t;
|
||||
|
||||
static inline int libirc_mutex_init (port_mutex_t * mutex) { return 0; }
|
||||
static inline void libirc_mutex_destroy (port_mutex_t * mutex) {}
|
||||
static inline void libirc_mutex_lock (port_mutex_t * mutex) {}
|
||||
static inline void libirc_mutex_unlock (port_mutex_t * mutex) {}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Stub for WIN32 dll to initialize winsock API
|
||||
*/
|
||||
#if defined (WIN32_DLL)
|
||||
BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
WORD wVersionRequested = MAKEWORD (1, 1);
|
||||
WSADATA wsaData;
|
||||
|
||||
switch(fdwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
if ( WSAStartup (wVersionRequested, &wsaData) != 0 )
|
||||
return FALSE;
|
||||
|
||||
DisableThreadLibraryCalls (hinstDll);
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
WSACleanup();
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
79
external/LibIRC/session.h
vendored
Normal file
79
external/LibIRC/session.h
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This library 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 Lesser General Public
|
||||
* License for more details.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_IRC_SESSION_H
|
||||
#define INCLUDE_IRC_SESSION_H
|
||||
|
||||
|
||||
#include "params.h"
|
||||
#include "dcc.h"
|
||||
#include "libirc_events.h"
|
||||
|
||||
|
||||
// Session flags
|
||||
#define SESSIONFL_MOTD_RECEIVED (0x00000001)
|
||||
#define SESSIONFL_SSL_CONNECTION (0x00000002)
|
||||
#define SESSIONFL_SSL_WRITE_WANTS_READ (0x00000004)
|
||||
#define SESSIONFL_SSL_READ_WANTS_WRITE (0x00000008)
|
||||
#define SESSIONFL_USES_IPV6 (0x00000010)
|
||||
|
||||
|
||||
|
||||
struct irc_session_s
|
||||
{
|
||||
void * ctx;
|
||||
int dcc_timeout;
|
||||
|
||||
int options;
|
||||
int lasterror;
|
||||
|
||||
char incoming_buf[LIBIRC_BUFFER_SIZE];
|
||||
unsigned int incoming_offset;
|
||||
|
||||
char outgoing_buf[LIBIRC_BUFFER_SIZE];
|
||||
unsigned int outgoing_offset;
|
||||
port_mutex_t mutex_session;
|
||||
|
||||
socket_t sock;
|
||||
int state;
|
||||
int flags;
|
||||
|
||||
char * server;
|
||||
char * server_password;
|
||||
char * realname;
|
||||
char * username;
|
||||
char * nick;
|
||||
char * ctcp_version;
|
||||
|
||||
#if defined( ENABLE_IPV6 )
|
||||
struct in6_addr local_addr6;
|
||||
#endif
|
||||
|
||||
struct in_addr local_addr;
|
||||
irc_dcc_t dcc_last_id;
|
||||
irc_dcc_session_t * dcc_sessions;
|
||||
port_mutex_t mutex_dcc;
|
||||
|
||||
irc_callbacks_t callbacks;
|
||||
|
||||
#if defined (ENABLE_SSL)
|
||||
SSL * ssl;
|
||||
#endif
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* INCLUDE_IRC_SESSION_H */
|
159
external/LibIRC/sockets.c
vendored
Normal file
159
external/LibIRC/sockets.c
vendored
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This library 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 Lesser General Public
|
||||
* License for more details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The sockets interface was moved out to simplify going OpenSSL integration.
|
||||
*/
|
||||
#if !defined (_WIN32)
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define IS_SOCKET_ERROR(a) ((a)<0)
|
||||
typedef int socket_t;
|
||||
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <windows.h>
|
||||
|
||||
#define IS_SOCKET_ERROR(a) ((a)==SOCKET_ERROR)
|
||||
|
||||
#if !defined(EWOULDBLOCK)
|
||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
#endif
|
||||
#if !defined(EINPROGRESS)
|
||||
#define EINPROGRESS WSAEINPROGRESS
|
||||
#endif
|
||||
#if !defined(EINTR)
|
||||
#define EINTR WSAEINTR
|
||||
#endif
|
||||
#if !defined(EAGAIN)
|
||||
#define EAGAIN EWOULDBLOCK
|
||||
#endif
|
||||
|
||||
typedef SOCKET socket_t;
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef INADDR_NONE
|
||||
#define INADDR_NONE 0xFFFFFFFF
|
||||
#endif
|
||||
|
||||
|
||||
static int socket_error()
|
||||
{
|
||||
#if !defined (_WIN32)
|
||||
return errno;
|
||||
#else
|
||||
return WSAGetLastError();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int socket_create (int domain, int type, socket_t * sock)
|
||||
{
|
||||
*sock = socket (domain, type, 0);
|
||||
return IS_SOCKET_ERROR(*sock) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static int socket_make_nonblocking (socket_t * sock)
|
||||
{
|
||||
#if !defined (_WIN32)
|
||||
return fcntl (*sock, F_SETFL, fcntl (*sock, F_GETFL,0 ) | O_NONBLOCK) != 0;
|
||||
#else
|
||||
unsigned long mode = 0;
|
||||
return ioctlsocket (*sock, FIONBIO, &mode) == SOCKET_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int socket_close (socket_t * sock)
|
||||
{
|
||||
#if !defined (_WIN32)
|
||||
close (*sock);
|
||||
#else
|
||||
closesocket (*sock);
|
||||
#endif
|
||||
|
||||
*sock = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int socket_connect (socket_t * sock, const struct sockaddr *saddr, socklen_t len)
|
||||
{
|
||||
while ( 1 )
|
||||
{
|
||||
if ( connect (*sock, saddr, len) < 0 )
|
||||
{
|
||||
if ( socket_error() == EINTR )
|
||||
continue;
|
||||
|
||||
if ( socket_error() != EINPROGRESS && socket_error() != EWOULDBLOCK )
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int socket_accept (socket_t * sock, socket_t * newsock, struct sockaddr *saddr, socklen_t * len)
|
||||
{
|
||||
while ( IS_SOCKET_ERROR(*newsock = accept (*sock, saddr, len)) )
|
||||
{
|
||||
if ( socket_error() == EINTR )
|
||||
continue;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int socket_recv (socket_t * sock, void * buf, size_t len)
|
||||
{
|
||||
int length;
|
||||
|
||||
while ( (length = recv (*sock, buf, len, 0)) < 0 )
|
||||
{
|
||||
int err = socket_error();
|
||||
|
||||
if ( err != EINTR && err != EAGAIN )
|
||||
break;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
static int socket_send (socket_t * sock, const void *buf, size_t len)
|
||||
{
|
||||
int length;
|
||||
|
||||
while ( (length = send (*sock, buf, len, 0)) < 0 )
|
||||
{
|
||||
int err = socket_error();
|
||||
|
||||
if ( err != EINTR && err != EAGAIN )
|
||||
break;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
390
external/LibIRC/ssl.c
vendored
Normal file
390
external/LibIRC/ssl.c
vendored
Normal file
@ -0,0 +1,390 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This library 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 Lesser General Public
|
||||
* License for more details.
|
||||
*/
|
||||
|
||||
|
||||
#if defined (ENABLE_SSL)
|
||||
|
||||
// Nonzero if OpenSSL has been initialized
|
||||
static SSL_CTX * ssl_context = 0;
|
||||
|
||||
#if defined (_WIN32)
|
||||
#include <windows.h>
|
||||
// This array will store all of the mutexes available to OpenSSL
|
||||
static CRITICAL_SECTION * mutex_buf = 0;
|
||||
|
||||
// OpenSSL callback to utilize static locks
|
||||
static void cb_openssl_locking_function( int mode, int n, const char * file, int line )
|
||||
{
|
||||
if ( mode & CRYPTO_LOCK)
|
||||
EnterCriticalSection( &mutex_buf[n] );
|
||||
else
|
||||
LeaveCriticalSection( &mutex_buf[n] );
|
||||
}
|
||||
|
||||
// OpenSSL callback to get the thread ID
|
||||
static unsigned long cb_openssl_id_function(void)
|
||||
{
|
||||
return ((unsigned long) GetCurrentThreadId() );
|
||||
}
|
||||
|
||||
static int alloc_mutexes( unsigned int total )
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
// Enable thread safety in OpenSSL
|
||||
mutex_buf = (CRITICAL_SECTION*) malloc( total * sizeof(CRITICAL_SECTION) );
|
||||
|
||||
if ( !mutex_buf )
|
||||
return -1;
|
||||
|
||||
for ( i = 0; i < total; i++)
|
||||
InitializeCriticalSection( &(mutex_buf[i]) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
// This array will store all of the mutexes available to OpenSSL
|
||||
static pthread_mutex_t * mutex_buf = 0;
|
||||
|
||||
// OpenSSL callback to utilize static locks
|
||||
static void cb_openssl_locking_function( int mode, int n, const char * file, int line )
|
||||
{
|
||||
(void)file;
|
||||
(void)line;
|
||||
|
||||
if ( mode & CRYPTO_LOCK)
|
||||
pthread_mutex_lock( &mutex_buf[n] );
|
||||
else
|
||||
pthread_mutex_unlock( &mutex_buf[n] );
|
||||
}
|
||||
|
||||
// OpenSSL callback to get the thread ID
|
||||
static unsigned long cb_openssl_id_function()
|
||||
{
|
||||
return ((unsigned long) pthread_self() );
|
||||
}
|
||||
|
||||
static int alloc_mutexes( unsigned int total )
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
// Enable thread safety in OpenSSL
|
||||
mutex_buf = (pthread_mutex_t*) malloc( total * sizeof(pthread_mutex_t) );
|
||||
|
||||
if ( !mutex_buf )
|
||||
return -1;
|
||||
|
||||
for ( i = 0; i < total; i++)
|
||||
pthread_mutex_init( &(mutex_buf[i]), 0 );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int ssl_init_context( irc_session_t * session )
|
||||
{
|
||||
// Load the strings and init the library
|
||||
SSL_load_error_strings();
|
||||
|
||||
// Enable thread safety in OpenSSL
|
||||
if ( alloc_mutexes( CRYPTO_num_locks() ) )
|
||||
return LIBIRC_ERR_NOMEM;
|
||||
|
||||
// Register our callbacks
|
||||
CRYPTO_set_id_callback( cb_openssl_id_function );
|
||||
CRYPTO_set_locking_callback( cb_openssl_locking_function );
|
||||
|
||||
// Init it
|
||||
if ( !SSL_library_init() )
|
||||
return LIBIRC_ERR_SSL_INIT_FAILED;
|
||||
|
||||
if ( RAND_status() == 0 )
|
||||
return LIBIRC_ERR_SSL_INIT_FAILED;
|
||||
|
||||
// Create an SSL context; currently a single context is used for all connections
|
||||
ssl_context = SSL_CTX_new( SSLv23_method() );
|
||||
|
||||
if ( !ssl_context )
|
||||
return LIBIRC_ERR_SSL_INIT_FAILED;
|
||||
|
||||
// Disable SSLv2 as it is unsecure
|
||||
if ( (SSL_CTX_set_options( ssl_context, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) == 0 )
|
||||
return LIBIRC_ERR_SSL_INIT_FAILED;
|
||||
|
||||
// Enable only strong ciphers
|
||||
if ( SSL_CTX_set_cipher_list( ssl_context, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH" ) != 1 )
|
||||
return LIBIRC_ERR_SSL_INIT_FAILED;
|
||||
|
||||
// Set the verification
|
||||
if ( session->options & LIBIRC_OPTION_SSL_NO_VERIFY )
|
||||
SSL_CTX_set_verify( ssl_context, SSL_VERIFY_NONE, 0 );
|
||||
else
|
||||
SSL_CTX_set_verify( ssl_context, SSL_VERIFY_PEER, 0 );
|
||||
|
||||
// Disable session caching
|
||||
SSL_CTX_set_session_cache_mode( ssl_context, SSL_SESS_CACHE_OFF );
|
||||
|
||||
// Enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER so we can move the buffer during sending
|
||||
SSL_CTX_set_mode( ssl_context, SSL_CTX_get_mode(ssl_context) | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if defined (_WIN32)
|
||||
#define SSLINIT_LOCK_MUTEX(a) WaitForSingleObject( a, INFINITE )
|
||||
#define SSLINIT_UNLOCK_MUTEX(a) ReleaseMutex( a )
|
||||
#else
|
||||
#define SSLINIT_LOCK_MUTEX(a) pthread_mutex_lock( &a )
|
||||
#define SSLINIT_UNLOCK_MUTEX(a) pthread_mutex_unlock( &a )
|
||||
#endif
|
||||
|
||||
// Initializes the SSL context. Must be called after the socket is created.
|
||||
static int ssl_init( irc_session_t * session )
|
||||
{
|
||||
static int ssl_context_initialized = 0;
|
||||
|
||||
#if defined (_WIN32)
|
||||
static HANDLE initmutex = 0;
|
||||
|
||||
// First time run? Create the mutex
|
||||
if ( initmutex == 0 )
|
||||
{
|
||||
HANDLE m = CreateMutex( 0, FALSE, 0 );
|
||||
|
||||
// Now we check if the mutex has already been created by another thread performing the init concurrently.
|
||||
// If it was, we close our mutex and use the original one. This could be done synchronously by using the
|
||||
// InterlockedCompareExchangePointer function.
|
||||
if ( InterlockedCompareExchangePointer( &m, m, 0 ) != 0 )
|
||||
CloseHandle( m );
|
||||
}
|
||||
#else
|
||||
static pthread_mutex_t initmutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#endif
|
||||
|
||||
// This initialization needs to be performed only once. The problem is that it is called from
|
||||
// irc_connect() and this function may be called simultaneously from different threads. So we have
|
||||
// to use mutex on Linux because it allows static mutex initialization. Windows doesn't, so here
|
||||
// we do the sabre dance around it.
|
||||
SSLINIT_LOCK_MUTEX( initmutex );
|
||||
|
||||
if ( ssl_context_initialized == 0 )
|
||||
{
|
||||
int res = ssl_init_context( session );
|
||||
|
||||
if ( res )
|
||||
{
|
||||
SSLINIT_UNLOCK_MUTEX( initmutex );
|
||||
return res;
|
||||
}
|
||||
|
||||
ssl_context_initialized = 1;
|
||||
}
|
||||
|
||||
SSLINIT_UNLOCK_MUTEX( initmutex );
|
||||
|
||||
// Get the SSL context
|
||||
session->ssl = SSL_new( ssl_context );
|
||||
|
||||
if ( !session->ssl )
|
||||
return LIBIRC_ERR_SSL_INIT_FAILED;
|
||||
|
||||
// Let OpenSSL use our socket
|
||||
if ( SSL_set_fd( session->ssl, session->sock) != 1 )
|
||||
return LIBIRC_ERR_SSL_INIT_FAILED;
|
||||
|
||||
// Since we're connecting on our own, tell openssl about it
|
||||
SSL_set_connect_state( session->ssl );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ssl_handle_error( irc_session_t * session, int ssl_error )
|
||||
{
|
||||
if ( ERR_GET_LIB(ssl_error) == ERR_LIB_SSL )
|
||||
{
|
||||
if ( ERR_GET_REASON(ssl_error) == SSL_R_CERTIFICATE_VERIFY_FAILED )
|
||||
{
|
||||
session->lasterror = LIBIRC_ERR_SSL_CERT_VERIFY_FAILED;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ERR_GET_REASON(ssl_error) == SSL_R_UNKNOWN_PROTOCOL )
|
||||
{
|
||||
session->lasterror = LIBIRC_ERR_CONNECT_SSL_FAILED;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined (ENABLE_DEBUG)
|
||||
if ( IS_DEBUG_ENABLED(session) )
|
||||
fprintf (stderr, "[DEBUG] SSL error: %s\n\t(%d, %d)\n",
|
||||
ERR_error_string( ssl_error, NULL), ERR_GET_LIB( ssl_error), ERR_GET_REASON(ssl_error) );
|
||||
#endif
|
||||
}
|
||||
|
||||
static int ssl_recv( irc_session_t * session )
|
||||
{
|
||||
int count;
|
||||
unsigned int amount = (sizeof (session->incoming_buf) - 1) - session->incoming_offset;
|
||||
|
||||
ERR_clear_error();
|
||||
|
||||
// Read up to m_bufferLength bytes
|
||||
count = SSL_read( session->ssl, session->incoming_buf + session->incoming_offset, amount );
|
||||
|
||||
if ( count > 0 )
|
||||
return count;
|
||||
else if ( count == 0 )
|
||||
return -1; // remote connection closed
|
||||
else
|
||||
{
|
||||
int ssl_error = SSL_get_error( session->ssl, count );
|
||||
|
||||
// Handle SSL error since not all of them are actually errors
|
||||
switch ( ssl_error )
|
||||
{
|
||||
case SSL_ERROR_WANT_READ:
|
||||
// This is not really an error. We received something, but
|
||||
// OpenSSL gave nothing to us because all it read was
|
||||
// internal data. Repeat the same read.
|
||||
return 0;
|
||||
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
// This is not really an error. We received something, but
|
||||
// now OpenSSL needs to send the data before returning any
|
||||
// data to us (like negotiations). This means we'd need
|
||||
// to wait for WRITE event, but call SSL_read() again.
|
||||
session->flags |= SESSIONFL_SSL_READ_WANTS_WRITE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This is an SSL error, handle it
|
||||
ssl_handle_error( session, ERR_get_error() );
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int ssl_send( irc_session_t * session )
|
||||
{
|
||||
int count;
|
||||
ERR_clear_error();
|
||||
|
||||
count = SSL_write( session->ssl, session->outgoing_buf, session->outgoing_offset );
|
||||
|
||||
if ( count > 0 )
|
||||
return count;
|
||||
else if ( count == 0 )
|
||||
return -1;
|
||||
else
|
||||
{
|
||||
int ssl_error = SSL_get_error( session->ssl, count );
|
||||
|
||||
switch ( ssl_error )
|
||||
{
|
||||
case SSL_ERROR_WANT_READ:
|
||||
// This is not really an error. We sent some internal OpenSSL data,
|
||||
// but now it needs to read more data before it can send anything.
|
||||
// Thus we wait for READ event, but will call SSL_write() again.
|
||||
session->flags |= SESSIONFL_SSL_WRITE_WANTS_READ;
|
||||
return 0;
|
||||
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
// This is not really an error. We sent some data, but now OpenSSL
|
||||
// wants to send some internal data before sending ours.
|
||||
// Repeat the same write.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This is an SSL error, handle it
|
||||
ssl_handle_error( session, ERR_get_error() );
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// Handles both SSL and non-SSL reads.
|
||||
// Returns -1 in case there is an error and socket should be closed/connection terminated
|
||||
// Returns 0 in case there is a temporary error and the call should be retried (SSL_WANTS_WRITE case)
|
||||
// Returns a positive number if we actually read something
|
||||
static int session_socket_read( irc_session_t * session )
|
||||
{
|
||||
int length;
|
||||
|
||||
#if defined (ENABLE_SSL)
|
||||
if ( session->ssl )
|
||||
{
|
||||
// Yes, I know this is tricky
|
||||
if ( session->flags & SESSIONFL_SSL_READ_WANTS_WRITE )
|
||||
{
|
||||
session->flags &= ~SESSIONFL_SSL_READ_WANTS_WRITE;
|
||||
ssl_send( session );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ssl_recv( session );
|
||||
}
|
||||
#endif
|
||||
|
||||
length = socket_recv( &session->sock,
|
||||
session->incoming_buf + session->incoming_offset,
|
||||
(sizeof (session->incoming_buf) - 1) - session->incoming_offset );
|
||||
|
||||
// There is no "retry" errors for regular sockets
|
||||
if ( length <= 0 )
|
||||
return -1;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
// Handles both SSL and non-SSL writes.
|
||||
// Returns -1 in case there is an error and socket should be closed/connection terminated
|
||||
// Returns 0 in case there is a temporary error and the call should be retried (SSL_WANTS_WRITE case)
|
||||
// Returns a positive number if we actually sent something
|
||||
static int session_socket_write( irc_session_t * session )
|
||||
{
|
||||
int length;
|
||||
|
||||
#if defined (ENABLE_SSL)
|
||||
if ( session->ssl )
|
||||
{
|
||||
// Yep
|
||||
if ( session->flags & SESSIONFL_SSL_WRITE_WANTS_READ )
|
||||
{
|
||||
session->flags &= ~SESSIONFL_SSL_WRITE_WANTS_READ;
|
||||
ssl_recv( session );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ssl_send( session );
|
||||
}
|
||||
#endif
|
||||
|
||||
length = socket_send (&session->sock, session->outgoing_buf, session->outgoing_offset);
|
||||
|
||||
// There is no "retry" errors for regular sockets
|
||||
if ( length <= 0 )
|
||||
return -1;
|
||||
|
||||
return length;
|
||||
}
|
130
external/LibIRC/utils.c
vendored
Normal file
130
external/LibIRC/utils.c
vendored
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This library 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 Lesser General Public
|
||||
* License for more details.
|
||||
*/
|
||||
|
||||
static void libirc_add_to_set (int fd, fd_set *set, int * maxfd)
|
||||
{
|
||||
FD_SET (fd, set);
|
||||
|
||||
if ( *maxfd < fd )
|
||||
*maxfd = fd;
|
||||
}
|
||||
|
||||
#if defined (ENABLE_DEBUG)
|
||||
static void libirc_dump_data (const char * prefix, const char * buf, unsigned int length)
|
||||
{
|
||||
printf ("%s: ", prefix);
|
||||
for ( ; length > 0; length -- )
|
||||
printf ("%c", *buf++);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Finds a separator (\x0D\x0A), which separates two lines.
|
||||
*/
|
||||
static int libirc_findcrlf (const char * buf, int length)
|
||||
{
|
||||
int offset = 0;
|
||||
for ( ; offset < length; offset++ )
|
||||
{
|
||||
if ( buf[offset] == 0x0D && offset < length - 1 && buf[offset+1] == 0x0A )
|
||||
return offset;
|
||||
if ( buf[offset] == 0x0A)
|
||||
return offset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int libirc_findcrlf_offset(const char *buf, int offset, const int length)
|
||||
{
|
||||
for(; offset < length; offset++)
|
||||
{
|
||||
if(buf[offset] != 0x0D && buf[offset] != 0x0A)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int libirc_findcrorlf (char * buf, int length)
|
||||
{
|
||||
int offset = 0;
|
||||
for ( ; offset < length; offset++ )
|
||||
{
|
||||
if ( buf[offset] == 0x0D || buf[offset] == 0x0A )
|
||||
{
|
||||
buf[offset++] = '\0';
|
||||
|
||||
if ( offset < (length - 1)
|
||||
&& (buf[offset] == 0x0D || buf[offset] == 0x0A) )
|
||||
offset++;
|
||||
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void libirc_event_ctcp_internal (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count)
|
||||
{
|
||||
(void)event;
|
||||
(void)count;
|
||||
|
||||
if ( origin )
|
||||
{
|
||||
char nickbuf[128], textbuf[256];
|
||||
irc_target_get_nick (origin, nickbuf, sizeof(nickbuf));
|
||||
|
||||
if ( strstr (params[0], "PING") == params[0] )
|
||||
irc_cmd_ctcp_reply (session, nickbuf, params[0]);
|
||||
else if ( !strcmp (params[0], "VERSION") )
|
||||
{
|
||||
if ( !session->ctcp_version )
|
||||
{
|
||||
unsigned int high, low;
|
||||
irc_get_version (&high, &low);
|
||||
|
||||
snprintf (textbuf, sizeof (textbuf), "VERSION libircclient by Georgy Yunaev ver.%d.%d", high, low);
|
||||
}
|
||||
else
|
||||
snprintf (textbuf, sizeof (textbuf), "VERSION %s", session->ctcp_version);
|
||||
|
||||
irc_cmd_ctcp_reply (session, nickbuf, textbuf);
|
||||
}
|
||||
else if ( !strcmp (params[0], "FINGER") )
|
||||
{
|
||||
sprintf (textbuf, "FINGER %s (%s) Idle 0 seconds",
|
||||
session->username ? session->username : "nobody",
|
||||
session->realname ? session->realname : "noname");
|
||||
|
||||
irc_cmd_ctcp_reply (session, nickbuf, textbuf);
|
||||
}
|
||||
else if ( !strcmp (params[0], "TIME") )
|
||||
{
|
||||
time_t now = time(0);
|
||||
|
||||
#if defined (ENABLE_THREADS) && defined (HAVE_LOCALTIME_R)
|
||||
struct tm tmtmp, *ltime = localtime_r (&now, &tmtmp);
|
||||
#else
|
||||
struct tm * ltime = localtime (&now);
|
||||
#endif
|
||||
strftime (textbuf, sizeof(textbuf), "%a %b %d %H:%M:%S %Z %Y", ltime);
|
||||
irc_cmd_ctcp_reply (session, nickbuf, textbuf);
|
||||
}
|
||||
}
|
||||
}
|
235
include/libirc_errors.h
Normal file
235
include/libirc_errors.h
Normal file
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This library 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 Lesser General Public
|
||||
* License for more details.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_IRC_ERRORS_H
|
||||
#define INCLUDE_IRC_ERRORS_H
|
||||
|
||||
#ifndef IN_INCLUDE_LIBIRC_H
|
||||
#error This file should not be included directly, include just libircclient.h
|
||||
#endif
|
||||
|
||||
|
||||
/*! brief No error
|
||||
* \ingroup errorcodes
|
||||
*/
|
||||
#define LIBIRC_ERR_OK 0
|
||||
|
||||
|
||||
/*! \brief Invalid argument
|
||||
*
|
||||
* An invalid value was given for one of the arguments to a function.
|
||||
* For example, supplying the NULL value for \a channel argument of
|
||||
* irc_cmd_join() produces LIBIRC_ERR_INVAL error. You should fix the code.
|
||||
*
|
||||
* \ingroup errorcodes
|
||||
*/
|
||||
#define LIBIRC_ERR_INVAL 1
|
||||
|
||||
|
||||
/*! \brief Could not resolve host.
|
||||
*
|
||||
* The host name supplied for irc_connect() function could not be resolved
|
||||
* into valid IP address. Usually means that host name is invalid.
|
||||
*
|
||||
* \ingroup errorcodes
|
||||
*/
|
||||
#define LIBIRC_ERR_RESOLV 2
|
||||
|
||||
|
||||
/*! \brief Could not create socket.
|
||||
*
|
||||
* The new socket could not be created or made non-blocking. Usually means
|
||||
* that the server is out of resources, or (rarely :) a bug in libircclient.
|
||||
*
|
||||
* \ingroup errorcodes
|
||||
*/
|
||||
#define LIBIRC_ERR_SOCKET 3
|
||||
|
||||
|
||||
/*! \brief Could not connect.
|
||||
*
|
||||
* The socket could not connect to the IRC server, or to the destination DCC
|
||||
* part. Usually means that either the IRC server is down or its address is
|
||||
* invalid. For DCC the reason usually is the firewall on your or destination
|
||||
* computer, which refuses DCC transfer.
|
||||
*
|
||||
* \sa irc_run irc_connect
|
||||
* \ingroup errorcodes
|
||||
*/
|
||||
#define LIBIRC_ERR_CONNECT 4
|
||||
|
||||
|
||||
/*! \brief Connection closed by remote peer.
|
||||
*
|
||||
* The IRC connection was closed by the IRC server (which could mean that an
|
||||
* IRC operator just have banned you from the server :)), or the DCC connection
|
||||
* was closed by remote peer - for example, the other side just quits his mIrc.
|
||||
* Usually it is not an error.
|
||||
*
|
||||
* \sa irc_run irc_connect irc_dcc_callback_t
|
||||
* \ingroup errorcodes
|
||||
*/
|
||||
#define LIBIRC_ERR_CLOSED 5
|
||||
|
||||
|
||||
/*! \brief Out of memory
|
||||
*
|
||||
* There are two possible reasons for this error. First is that memory could
|
||||
* not be allocated for libircclient use, and this error usually is fatal.
|
||||
* Second reason is that the command queue (which keeps command ready to be
|
||||
* sent to the IRC server) is full, and could not accept more commands yet.
|
||||
* In this case you should just wait, and repeat the command later.
|
||||
*
|
||||
* \ingroup errorcodes
|
||||
*/
|
||||
#define LIBIRC_ERR_NOMEM 6
|
||||
|
||||
|
||||
/*! \brief Could not accept new connection
|
||||
*
|
||||
* A DCC chat/send connection from the remote peer could not be accepted.
|
||||
* Either the connection was just terminated before it is accepted, or there
|
||||
* is a bug in libircclient.
|
||||
*
|
||||
* \ingroup errorcodes
|
||||
*/
|
||||
#define LIBIRC_ERR_ACCEPT 7
|
||||
|
||||
|
||||
/*! \brief Could not send this
|
||||
*
|
||||
* A \a filename supplied to irc_dcc_sendfile() could not be sent. Either is
|
||||
* is not a file (a directory or a socket, for example), or it is not readable. *
|
||||
*
|
||||
* \sa LIBIRC_ERR_OPENFILE
|
||||
* \ingroup errorcodes
|
||||
*/
|
||||
#define LIBIRC_ERR_NODCCSEND 9
|
||||
|
||||
|
||||
/*! \brief Could not read DCC file or socket
|
||||
*
|
||||
* Either a DCC file could not be read (for example, was truncated during
|
||||
* sending), or a DCC socket returns a read error, which usually means that
|
||||
* the network connection is terminated.
|
||||
*
|
||||
* \ingroup errorcodes
|
||||
*/
|
||||
#define LIBIRC_ERR_READ 10
|
||||
|
||||
|
||||
/*! \brief Could not write DCC file or socket
|
||||
*
|
||||
* Either a DCC file could not be written (for example, there is no free space
|
||||
* on disk), or a DCC socket returns a write error, which usually means that
|
||||
* the network connection is terminated.
|
||||
*
|
||||
* \ingroup errorcodes
|
||||
*/
|
||||
#define LIBIRC_ERR_WRITE 11
|
||||
|
||||
|
||||
/*! \brief Invalid state
|
||||
*
|
||||
* The function is called when it is not allowed to be called. For example,
|
||||
* irc_cmd_join() was called before the connection to IRC server succeed, and
|
||||
* ::event_connect is called.
|
||||
*
|
||||
* \ingroup errorcodes
|
||||
*/
|
||||
#define LIBIRC_ERR_STATE 12
|
||||
|
||||
|
||||
/*! \brief Operation timed out
|
||||
*
|
||||
* The DCC request is timed out.
|
||||
* There is a timer for each DCC request, which tracks connecting, accepting
|
||||
* and non-accepted/declined DCC requests. For every request this timer
|
||||
* is currently 60 seconds. If the DCC request was not connected, accepted
|
||||
* or declined during this time, it will be terminated with this error.
|
||||
*
|
||||
* \ingroup errorcodes
|
||||
*/
|
||||
#define LIBIRC_ERR_TIMEOUT 13
|
||||
|
||||
|
||||
/*! \brief Could not open file for DCC send
|
||||
*
|
||||
* The file specified in irc_dcc_sendfile() could not be opened.
|
||||
*
|
||||
* \ingroup errorcodes
|
||||
*/
|
||||
#define LIBIRC_ERR_OPENFILE 14
|
||||
|
||||
|
||||
/*! \brief IRC server connection terminated
|
||||
*
|
||||
* The connection to the IRC server was terminated - possibly, by network
|
||||
* error. Try to irc_connect() again.
|
||||
*
|
||||
* \ingroup errorcodes
|
||||
*/
|
||||
#define LIBIRC_ERR_TERMINATED 15
|
||||
|
||||
|
||||
/*! \brief IPv6 not supported
|
||||
*
|
||||
* The function which requires IPv6 support was called, but the IPv6 support was not compiled
|
||||
* into the application
|
||||
*
|
||||
* \ingroup errorcodes
|
||||
*/
|
||||
#define LIBIRC_ERR_NOIPV6 16
|
||||
|
||||
|
||||
/*! \brief SSL not supported
|
||||
*
|
||||
* The SSL connection was required but the library was not compiled with SSL support
|
||||
*
|
||||
* \ingroup errorcodes
|
||||
*/
|
||||
#define LIBIRC_ERR_SSL_NOT_SUPPORTED 17
|
||||
|
||||
|
||||
/*! \brief SSL initialization failed
|
||||
*
|
||||
* The SSL connection was required but the library was not compiled with SSL support
|
||||
*
|
||||
* \ingroup errorcodes
|
||||
*/
|
||||
#define LIBIRC_ERR_SSL_INIT_FAILED 18
|
||||
|
||||
|
||||
/*! \brief SSL connection failed
|
||||
*
|
||||
* SSL handshare failed when attempting to connect to the server. Typically this means you're trying
|
||||
* to use SSL but attempting to connect to a non-SSL port.
|
||||
* \ingroup errorcodes
|
||||
*/
|
||||
#define LIBIRC_ERR_CONNECT_SSL_FAILED 19
|
||||
|
||||
|
||||
/*! \brief SSL certificate verify failed
|
||||
*
|
||||
* The server is using the self-signed certificate. Use LIBIRC_OPTION_SSL_NO_VERIFY option to connect to it.
|
||||
* \ingroup errorcodes
|
||||
*/
|
||||
#define LIBIRC_ERR_SSL_CERT_VERIFY_FAILED 20
|
||||
|
||||
|
||||
// Internal max error value count.
|
||||
// If you added more errors, add them to errors.c too!
|
||||
#define LIBIRC_ERR_MAX 21
|
||||
|
||||
#endif /* INCLUDE_IRC_ERRORS_H */
|
389
include/libirc_events.h
Normal file
389
include/libirc_events.h
Normal file
@ -0,0 +1,389 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This library 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 Lesser General Public
|
||||
* License for more details.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_IRC_EVENTS_H
|
||||
#define INCLUDE_IRC_EVENTS_H
|
||||
|
||||
|
||||
#ifndef IN_INCLUDE_LIBIRC_H
|
||||
#error This file should not be included directly, include just libircclient.h
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
* \fn typedef void (*irc_event_callback_t) (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count)
|
||||
* \brief A most common event callback
|
||||
*
|
||||
* \param session the session, which generates an event
|
||||
* \param event the text name of the event. Useful in case you use a single
|
||||
* event handler for several events simultaneously.
|
||||
* \param origin the originator of the event. See the note below.
|
||||
* \param params a list of event params. Depending on the event nature, it
|
||||
* could have zero or more params. The actual number of params
|
||||
* is specified in count. None of the params can be NULL, but
|
||||
* 'params' pointer itself could be NULL for some events.
|
||||
* \param count the total number of params supplied.
|
||||
*
|
||||
* Every event generates a callback. This callback is generated by most events.
|
||||
* Depending on the event nature, it can provide zero or more params. For each
|
||||
* event, the number of provided params is fixed, and their meaning is
|
||||
* described.
|
||||
*
|
||||
* Every event has origin, though the \a origin variable may be NULL, which
|
||||
* means that event origin is unknown. The origin usually looks like
|
||||
* nick!host\@ircserver, i.e. like tim!home\@irc.krasnogorsk.ru. Such origins
|
||||
* can not be used in IRC commands, and need to be stripped (i.e. host and
|
||||
* server part should be cut off) before using. This can be done either
|
||||
* explicitly, by calling irc_target_get_nick(), or implicitly for all the
|
||||
* events - by setting the #LIBIRC_OPTION_STRIPNICKS option with irc_option_set().
|
||||
*
|
||||
* \ingroup events
|
||||
*/
|
||||
typedef void (*irc_event_callback_t) (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count);
|
||||
|
||||
|
||||
/*!
|
||||
* \fn typedef void (*irc_eventcode_callback_t) (irc_session_t * session, unsigned int event, const char * origin, const char ** params, unsigned int count)
|
||||
* \brief A numeric event callback
|
||||
*
|
||||
* \param session the session, which generates an event
|
||||
* \param event the numeric code of the event. Useful in case you use a
|
||||
* single event handler for several events simultaneously.
|
||||
* \param origin the originator of the event. See the note below.
|
||||
* \param params a list of event params. Depending on the event nature, it
|
||||
* could have zero or more params. The actual number of params
|
||||
* is specified in count. None of the params can be NULL, but
|
||||
* 'params' pointer itself could be NULL for some events.
|
||||
* \param count the total number of params supplied.
|
||||
*
|
||||
* Most times in reply to your actions the IRC server generates numeric
|
||||
* callbacks. Most of them are error codes, and some of them mark list start
|
||||
* and list stop markers. Every code has its own set of params; for details
|
||||
* you can either experiment, or read RFC 1459.
|
||||
*
|
||||
* Every event has origin, though the \a origin variable may be NULL, which
|
||||
* means that event origin is unknown. The origin usually looks like
|
||||
* nick!host\@ircserver, i.e. like tim!home\@irc.krasnogorsk.ru. Such origins
|
||||
* can not be used in IRC commands, and need to be stripped (i.e. host and
|
||||
* server part should be cut off) before using. This can be done either
|
||||
* explicitly, by calling irc_target_get_nick(), or implicitly for all the
|
||||
* events - by setting the #LIBIRC_OPTION_STRIPNICKS option with irc_option_set().
|
||||
*
|
||||
* \ingroup events
|
||||
*/
|
||||
typedef void (*irc_eventcode_callback_t) (irc_session_t * session, unsigned int event, const char * origin, const char ** params, unsigned int count);
|
||||
|
||||
|
||||
/*!
|
||||
* \fn typedef void (*irc_event_dcc_chat_t) (irc_session_t * session, const char * nick, const char * addr, irc_dcc_t dccid)
|
||||
* \brief A remote DCC CHAT request callback
|
||||
*
|
||||
* \param session the session, which generates an event
|
||||
* \param nick the person who requested DCC CHAT with you.
|
||||
* \param addr the person's IP address in decimal-dot notation.
|
||||
* \param dccid an id associated with this request. Use it in calls to
|
||||
* irc_dcc_accept() or irc_dcc_decline().
|
||||
*
|
||||
* This callback is called when someone requests DCC CHAT with you. In respond
|
||||
* you should call either irc_dcc_accept() to accept chat request, or
|
||||
* irc_dcc_decline() to decline chat request.
|
||||
*
|
||||
* \sa irc_dcc_accept or irc_dcc_decline
|
||||
* \ingroup events
|
||||
*/
|
||||
typedef void (*irc_event_dcc_chat_t) (irc_session_t * session, const char * nick, const char * addr, irc_dcc_t dccid);
|
||||
|
||||
|
||||
/*!
|
||||
* \fn typedef void (*irc_event_dcc_send_t) (irc_session_t * session, const char * nick, const char * addr, const char * filename, unsigned long size, irc_dcc_t dccid)
|
||||
* \brief A remote DCC CHAT request callback
|
||||
*
|
||||
* \param session the session, which generates an event
|
||||
* \param nick the person who requested DCC CHAT with you.
|
||||
* \param addr the person's IP address in decimal-dot notation.
|
||||
* \param filename the sent filename.
|
||||
* \param size the filename size.
|
||||
* \param dccid an id associated with this request. Use it in calls to
|
||||
* irc_dcc_accept() or irc_dcc_decline().
|
||||
*
|
||||
* This callback is called when someone wants to send a file to you using
|
||||
* DCC SEND. As with chat, in respond you should call either irc_dcc_accept()
|
||||
* to accept this request and receive the file, or irc_dcc_decline() to
|
||||
* decline this request.
|
||||
*
|
||||
* \sa irc_dcc_accept or irc_dcc_decline
|
||||
* \ingroup events
|
||||
*/
|
||||
typedef void (*irc_event_dcc_send_t) (irc_session_t * session, const char * nick, const char * addr, const char * filename, unsigned long size, irc_dcc_t dccid);
|
||||
|
||||
|
||||
/*! \brief Event callbacks structure.
|
||||
*
|
||||
* All the communication with the IRC network is based on events. Generally
|
||||
* speaking, event is anything generated by someone else in the network,
|
||||
* or by the IRC server itself. "Someone sends you a message", "Someone
|
||||
* has joined the channel", "Someone has quits IRC" - all these messages
|
||||
* are events.
|
||||
*
|
||||
* Every event has its own event handler, which is called when the
|
||||
* appropriate event is received. You don't have to define all the event
|
||||
* handlers; define only the handlers for the events you need to intercept.
|
||||
*
|
||||
* Most event callbacks are the types of ::irc_event_callback_t. There are
|
||||
* also events, which generate ::irc_eventcode_callback_t,
|
||||
* ::irc_event_dcc_chat_t and ::irc_event_dcc_send_t callbacks.
|
||||
*
|
||||
* \ingroup events
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/*!
|
||||
* The "on_connect" event is triggered when the client successfully
|
||||
* connects to the server, and could send commands to the server.
|
||||
* No extra params supplied; \a params is 0.
|
||||
*/
|
||||
irc_event_callback_t event_connect;
|
||||
|
||||
/*!
|
||||
* The "nick" event is triggered when the client receives a NICK message,
|
||||
* meaning that someone (including you) on a channel with the client has
|
||||
* changed their nickname.
|
||||
*
|
||||
* \param origin the person, who changes the nick. Note that it can be you!
|
||||
* \param params[0] mandatory, contains the new nick.
|
||||
*/
|
||||
irc_event_callback_t event_nick;
|
||||
|
||||
/*!
|
||||
* The "quit" event is triggered upon receipt of a QUIT message, which
|
||||
* means that someone on a channel with the client has disconnected.
|
||||
*
|
||||
* \param origin the person, who is disconnected
|
||||
* \param params[0] optional, contains the reason message (user-specified).
|
||||
*/
|
||||
irc_event_callback_t event_quit;
|
||||
|
||||
/*!
|
||||
* The "join" event is triggered upon receipt of a JOIN message, which
|
||||
* means that someone has entered a channel that the client is on.
|
||||
*
|
||||
* \param origin the person, who joins the channel. By comparing it with
|
||||
* your own nickname, you can check whether your JOIN
|
||||
* command succeed.
|
||||
* \param params[0] mandatory, contains the channel name.
|
||||
*/
|
||||
irc_event_callback_t event_join;
|
||||
|
||||
/*!
|
||||
* The "part" event is triggered upon receipt of a PART message, which
|
||||
* means that someone has left a channel that the client is on.
|
||||
*
|
||||
* \param origin the person, who leaves the channel. By comparing it with
|
||||
* your own nickname, you can check whether your PART
|
||||
* command succeed.
|
||||
* \param params[0] mandatory, contains the channel name.
|
||||
* \param params[1] optional, contains the reason message (user-defined).
|
||||
*/
|
||||
irc_event_callback_t event_part;
|
||||
|
||||
/*!
|
||||
* The "mode" event is triggered upon receipt of a channel MODE message,
|
||||
* which means that someone on a channel with the client has changed the
|
||||
* channel's parameters.
|
||||
*
|
||||
* \param origin the person, who changed the channel mode.
|
||||
* \param params[0] mandatory, contains the channel name.
|
||||
* \param params[1] mandatory, contains the changed channel mode, like
|
||||
* '+t', '-i' and so on.
|
||||
* \param params[2] optional, contains the mode argument (for example, a
|
||||
* key for +k mode, or user who got the channel operator status for
|
||||
* +o mode)
|
||||
*/
|
||||
irc_event_callback_t event_mode;
|
||||
|
||||
/*!
|
||||
* The "umode" event is triggered upon receipt of a user MODE message,
|
||||
* which means that your user mode has been changed.
|
||||
*
|
||||
* \param origin the person, who changed the channel mode.
|
||||
* \param params[0] mandatory, contains the user changed mode, like
|
||||
* '+t', '-i' and so on.
|
||||
*/
|
||||
irc_event_callback_t event_umode;
|
||||
|
||||
/*!
|
||||
* The "topic" event is triggered upon receipt of a TOPIC message, which
|
||||
* means that someone on a channel with the client has changed the
|
||||
* channel's topic.
|
||||
*
|
||||
* \param origin the person, who changes the channel topic.
|
||||
* \param params[0] mandatory, contains the channel name.
|
||||
* \param params[1] optional, contains the new topic.
|
||||
*/
|
||||
irc_event_callback_t event_topic;
|
||||
|
||||
/*!
|
||||
* The "kick" event is triggered upon receipt of a KICK message, which
|
||||
* means that someone on a channel with the client (or possibly the
|
||||
* client itself!) has been forcibly ejected.
|
||||
*
|
||||
* \param origin the person, who kicked the poor.
|
||||
* \param params[0] mandatory, contains the channel name.
|
||||
* \param params[0] optional, contains the nick of kicked person.
|
||||
* \param params[1] optional, contains the kick text
|
||||
*/
|
||||
irc_event_callback_t event_kick;
|
||||
|
||||
/*!
|
||||
* The "channel" event is triggered upon receipt of a PRIVMSG message
|
||||
* to an entire channel, which means that someone on a channel with
|
||||
* the client has said something aloud. Your own messages don't trigger
|
||||
* PRIVMSG event.
|
||||
*
|
||||
* \param origin the person, who generates the message.
|
||||
* \param params[0] mandatory, contains the channel name.
|
||||
* \param params[1] optional, contains the message text
|
||||
*/
|
||||
irc_event_callback_t event_channel;
|
||||
|
||||
/*!
|
||||
* The "privmsg" event is triggered upon receipt of a PRIVMSG message
|
||||
* which is addressed to one or more clients, which means that someone
|
||||
* is sending the client a private message.
|
||||
*
|
||||
* \param origin the person, who generates the message.
|
||||
* \param params[0] mandatory, contains your nick.
|
||||
* \param params[1] optional, contains the message text
|
||||
*/
|
||||
irc_event_callback_t event_privmsg;
|
||||
|
||||
/*!
|
||||
* The "notice" event is triggered upon receipt of a NOTICE message
|
||||
* which means that someone has sent the client a public or private
|
||||
* notice. According to RFC 1459, the only difference between NOTICE
|
||||
* and PRIVMSG is that you should NEVER automatically reply to NOTICE
|
||||
* messages. Unfortunately, this rule is frequently violated by IRC
|
||||
* servers itself - for example, NICKSERV messages require reply, and
|
||||
* are NOTICEs.
|
||||
*
|
||||
* \param origin the person, who generates the message.
|
||||
* \param params[0] mandatory, contains the target nick name.
|
||||
* \param params[1] optional, contains the message text
|
||||
*/
|
||||
irc_event_callback_t event_notice;
|
||||
|
||||
/*!
|
||||
* The "channel_notice" event is triggered upon receipt of a NOTICE
|
||||
* message which means that someone has sent the client a public
|
||||
* notice. According to RFC 1459, the only difference between NOTICE
|
||||
* and PRIVMSG is that you should NEVER automatically reply to NOTICE
|
||||
* messages. Unfortunately, this rule is frequently violated by IRC
|
||||
* servers itself - for example, NICKSERV messages require reply, and
|
||||
* are NOTICEs.
|
||||
*
|
||||
* \param origin the person, who generates the message.
|
||||
* \param params[0] mandatory, contains the channel name.
|
||||
* \param params[1] optional, contains the message text
|
||||
*/
|
||||
irc_event_callback_t event_channel_notice;
|
||||
|
||||
/*!
|
||||
* The "invite" event is triggered upon receipt of an INVITE message,
|
||||
* which means that someone is permitting the client's entry into a +i
|
||||
* channel.
|
||||
*
|
||||
* \param origin the person, who INVITEs you.
|
||||
* \param params[0] mandatory, contains your nick.
|
||||
* \param params[1] mandatory, contains the channel name you're invited into.
|
||||
*
|
||||
* \sa irc_cmd_invite irc_cmd_chanmode_invite
|
||||
*/
|
||||
irc_event_callback_t event_invite;
|
||||
|
||||
/*!
|
||||
* The "ctcp" event is triggered when the client receives the CTCP
|
||||
* request. By default, the built-in CTCP request handler is used. The
|
||||
* build-in handler automatically replies on most CTCP messages, so you
|
||||
* will rarely need to override it.
|
||||
*
|
||||
* \param origin the person, who generates the message.
|
||||
* \param params[0] mandatory, the complete CTCP message, including its
|
||||
* arguments.
|
||||
*
|
||||
* Mirc generates PING, FINGER, VERSION, TIME and ACTION messages,
|
||||
* check the source code of \c libirc_event_ctcp_internal function to
|
||||
* see how to write your own CTCP request handler. Also you may find
|
||||
* useful this question in FAQ: \ref faq4
|
||||
*/
|
||||
irc_event_callback_t event_ctcp_req;
|
||||
|
||||
/*!
|
||||
* The "ctcp" event is triggered when the client receives the CTCP reply.
|
||||
*
|
||||
* \param origin the person, who generates the message.
|
||||
* \param params[0] mandatory, the CTCP message itself with its arguments.
|
||||
*/
|
||||
irc_event_callback_t event_ctcp_rep;
|
||||
|
||||
/*!
|
||||
* The "action" event is triggered when the client receives the CTCP
|
||||
* ACTION message. These messages usually looks like:\n
|
||||
* \code
|
||||
* [23:32:55] * Tim gonna sleep.
|
||||
* \endcode
|
||||
*
|
||||
* \param origin the person, who generates the message.
|
||||
* \param params[0] mandatory, the ACTION message.
|
||||
*/
|
||||
irc_event_callback_t event_ctcp_action;
|
||||
|
||||
/*!
|
||||
* The "unknown" event is triggered upon receipt of any number of
|
||||
* unclassifiable miscellaneous messages, which aren't handled by the
|
||||
* library.
|
||||
*/
|
||||
irc_event_callback_t event_unknown;
|
||||
|
||||
/*!
|
||||
* The "numeric" event is triggered upon receipt of any numeric response
|
||||
* from the server. There is a lot of such responses, see the full list
|
||||
* here: \ref rfcnumbers.
|
||||
*
|
||||
* See the params in ::irc_eventcode_callback_t specification.
|
||||
*/
|
||||
irc_eventcode_callback_t event_numeric;
|
||||
|
||||
/*!
|
||||
* The "dcc chat" event is triggered when someone requests a DCC CHAT from
|
||||
* you.
|
||||
*
|
||||
* See the params in ::irc_event_dcc_chat_t specification.
|
||||
*/
|
||||
irc_event_dcc_chat_t event_dcc_chat_req;
|
||||
|
||||
/*!
|
||||
* The "dcc chat" event is triggered when someone wants to send a file
|
||||
* to you via DCC SEND request.
|
||||
*
|
||||
* See the params in ::irc_event_dcc_send_t specification.
|
||||
*/
|
||||
irc_event_dcc_send_t event_dcc_send_req;
|
||||
|
||||
|
||||
} irc_callbacks_t;
|
||||
|
||||
|
||||
#endif /* INCLUDE_IRC_EVENTS_H */
|
56
include/libirc_options.h
Normal file
56
include/libirc_options.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This library 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 Lesser General Public
|
||||
* License for more details.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_IRC_OPTIONS_H
|
||||
#define INCLUDE_IRC_OPTIONS_H
|
||||
|
||||
#ifndef IN_INCLUDE_LIBIRC_H
|
||||
#error This file should not be included directly, include just libircclient.h
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* enables additional debug output
|
||||
* \ingroup options
|
||||
*/
|
||||
#define LIBIRC_OPTION_DEBUG (1 << 1)
|
||||
|
||||
/*! \brief allows to strip origins automatically.
|
||||
*
|
||||
* For every IRC server event, the event origin is sent in standard form:
|
||||
* nick!host\@ircserver, i.e. like tim!home\@irc.freenet.org. Such origins
|
||||
* can not be used in IRC commands, and need to be stripped (i.e. host and
|
||||
* server part should be cut off) before using. This can be done either
|
||||
* explicitly, by calling irc_target_get_nick(), or implicitly for all the
|
||||
* events - by setting this option with irc_option_set().
|
||||
* \ingroup options
|
||||
*/
|
||||
#define LIBIRC_OPTION_STRIPNICKS (1 << 2)
|
||||
|
||||
|
||||
/*! \brief Disables the certificate verification for SSL connections
|
||||
*
|
||||
* By default the SSL connection authenticy is ensured by verifying that the certificate
|
||||
* presented by the server is signed by a known trusted certificate authority. Since those
|
||||
* typically cost money, some IRC servers use the self-signed certificates. They provide the
|
||||
* benefits of the SSL connection but since they are not signed by the Certificate Authority,
|
||||
* their authencity cannot be verified. This option, if set, disables the certificate
|
||||
* verification - the library will accept any certificate presented by the server.
|
||||
*
|
||||
* This option must be set before the irc_connect function is called.
|
||||
* \ingroup options
|
||||
*/
|
||||
#define LIBIRC_OPTION_SSL_NO_VERIFY (1 << 3)
|
||||
|
||||
|
||||
#endif /* INCLUDE_IRC_OPTIONS_H */
|
1272
include/libirc_rfcnumeric.h
Normal file
1272
include/libirc_rfcnumeric.h
Normal file
File diff suppressed because it is too large
Load Diff
1499
include/libircclient.h
Normal file
1499
include/libircclient.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -223,7 +223,7 @@ public:
|
||||
/// This doesn't call release if the reference count is 1.
|
||||
///
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void Release2() {
|
||||
void ReleaseGently() {
|
||||
if(!IsNull()) {
|
||||
sq_release(vm, &env);
|
||||
if (sq_getrefcount(vm, &obj) > 1)
|
||||
|
@ -60,16 +60,16 @@ void CmdManager::Terminate()
|
||||
{
|
||||
if (itr->second)
|
||||
{
|
||||
itr->second->m_OnExec.Release2();
|
||||
itr->second->m_OnAuth.Release2();
|
||||
itr->second->m_OnPost.Release2();
|
||||
itr->second->m_OnFail.Release2();
|
||||
itr->second->m_OnExec.ReleaseGently();
|
||||
itr->second->m_OnAuth.ReleaseGently();
|
||||
itr->second->m_OnPost.ReleaseGently();
|
||||
itr->second->m_OnFail.ReleaseGently();
|
||||
}
|
||||
}
|
||||
// Release the script resources from this class
|
||||
m_Argv.clear();
|
||||
m_OnError.Release2();
|
||||
m_OnAuth.Release2();
|
||||
m_OnError.ReleaseGently();
|
||||
m_OnAuth.ReleaseGently();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@ -648,10 +648,10 @@ CmdListener::~CmdListener()
|
||||
if (!m_Name.empty())
|
||||
_Cmd->Detach(m_Name);
|
||||
// Release callbacks
|
||||
m_OnExec.Release2();
|
||||
m_OnAuth.Release2();
|
||||
m_OnPost.Release2();
|
||||
m_OnFail.Release2();
|
||||
m_OnExec.ReleaseGently();
|
||||
m_OnAuth.ReleaseGently();
|
||||
m_OnPost.ReleaseGently();
|
||||
m_OnFail.ReleaseGently();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@ -1226,6 +1226,22 @@ bool CmdListener::ProcSpec(CSStr str)
|
||||
return good;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Forward the call to run a command.
|
||||
*/
|
||||
Int32 RunCommand(Int32 invoker, CSStr command)
|
||||
{
|
||||
return _Cmd->Run(invoker, command);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Forward the call to terminate the command system.
|
||||
*/
|
||||
void TerminateCommand()
|
||||
{
|
||||
_Cmd->Terminate();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static Function & Cmd_GetOnError()
|
||||
{
|
||||
|
@ -1,8 +1,6 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Core.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include "Command.hpp"
|
||||
#include "Routine.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Entity/Blip.hpp"
|
||||
@ -39,6 +37,18 @@ namespace SqMod {
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
extern bool RegisterAPI(HSQUIRRELVM vm);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
extern void ProcessIrc();
|
||||
extern void TerminateIrc();
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
extern void ProcessRoutine();
|
||||
extern void TerminateRoutine();
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
extern Int32 RunCommand(Int32 invoker, CSStr command);
|
||||
extern void TerminateCommand();
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Core * _Core = NULL;
|
||||
|
||||
@ -332,10 +342,12 @@ void Core::Terminate()
|
||||
m_Textdraws.clear();
|
||||
m_Vehicles.clear();
|
||||
m_Scripts.clear();
|
||||
// Release all resources from command manager
|
||||
_Cmd->Terminate();
|
||||
// Release all resources from routines
|
||||
Routine::Cleanup();
|
||||
TerminateRoutine();
|
||||
// Release all resources from command manager
|
||||
TerminateCommand();
|
||||
// Release all resources from irc sessions
|
||||
TerminateIrc();
|
||||
// Is there a VM to close?
|
||||
if (m_VM)
|
||||
{
|
||||
@ -1251,7 +1263,7 @@ void Core::EmitPlayerCommand(Int32 player, CCStr command)
|
||||
Emit(_player.mOnCommand, command);
|
||||
Emit(mOnPlayerCommand, _player.mObj, command);
|
||||
// Send it to the command manager
|
||||
_Cmd->Run(player, command);
|
||||
RunCommand(player, command);
|
||||
}
|
||||
|
||||
void Core::EmitPlayerMessage(Int32 player, Int32 receiver, CCStr message)
|
||||
@ -1664,7 +1676,10 @@ void Core::EmitForcefieldExited(Int32 player, Int32 forcefield)
|
||||
void Core::EmitServerFrame(Float32 delta)
|
||||
{
|
||||
Emit(mOnServerFrame, delta);
|
||||
Routine::Process();
|
||||
// Update routines
|
||||
ProcessRoutine();
|
||||
// Update IRC sessions
|
||||
ProcessIrc();
|
||||
}
|
||||
|
||||
void Core::EmitServerStartup()
|
||||
|
@ -6,9 +6,10 @@
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
namespace INI {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Int32 IniEntries::Cmp(const IniEntries & o) const
|
||||
Int32 Entries::Cmp(const Entries & o) const
|
||||
{
|
||||
if (m_Elem == o.m_Elem)
|
||||
return 0;
|
||||
@ -19,13 +20,13 @@ Int32 IniEntries::Cmp(const IniEntries & o) const
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CSStr IniEntries::ToString() const
|
||||
CSStr Entries::ToString() const
|
||||
{
|
||||
return GetItem();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void IniEntries::Next()
|
||||
void Entries::Next()
|
||||
{
|
||||
// Are there any other elements ahead?
|
||||
if (!m_List.empty() && m_Elem != m_List.end())
|
||||
@ -33,7 +34,7 @@ void IniEntries::Next()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void IniEntries::Prev()
|
||||
void Entries::Prev()
|
||||
{
|
||||
// Are there any other elements behind?
|
||||
if (!m_List.empty() && m_Elem != m_List.begin())
|
||||
@ -41,7 +42,7 @@ void IniEntries::Prev()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void IniEntries::Advance(Int32 n)
|
||||
void Entries::Advance(Int32 n)
|
||||
{
|
||||
// Are there any other elements ahead?
|
||||
if (m_List.empty() || m_Elem == m_List.end())
|
||||
@ -51,7 +52,7 @@ void IniEntries::Advance(Int32 n)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void IniEntries::Retreat(Int32 n)
|
||||
void Entries::Retreat(Int32 n)
|
||||
{
|
||||
// Are there any other elements behind?
|
||||
if (m_List.empty() || m_Elem == m_List.begin())
|
||||
@ -61,7 +62,7 @@ void IniEntries::Retreat(Int32 n)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CSStr IniEntries::GetItem() const
|
||||
CSStr Entries::GetItem() const
|
||||
{
|
||||
if (m_List.empty() || m_Elem == m_List.end())
|
||||
SqThrow("Invalid INI entry [item]");
|
||||
@ -71,7 +72,7 @@ CSStr IniEntries::GetItem() const
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CSStr IniEntries::GetComment() const
|
||||
CSStr Entries::GetComment() const
|
||||
{
|
||||
if (m_List.empty() || m_Elem == m_List.end())
|
||||
SqThrow("Invalid INI entry [comment]");
|
||||
@ -81,7 +82,7 @@ CSStr IniEntries::GetComment() const
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Int32 IniEntries::GetOrder() const
|
||||
Int32 Entries::GetOrder() const
|
||||
{
|
||||
if (m_List.empty() || m_Elem == m_List.end())
|
||||
SqThrow("Invalid INI entry [order]");
|
||||
@ -91,27 +92,27 @@ Int32 IniEntries::GetOrder() const
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
IniDocument::IniDocument()
|
||||
Document::Document()
|
||||
: m_Doc(false, false, true)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
IniDocument::IniDocument(bool utf8, bool multikey, bool multiline)
|
||||
Document::Document(bool utf8, bool multikey, bool multiline)
|
||||
: m_Doc(utf8, multikey, multiline)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
IniDocument::~IniDocument()
|
||||
Document::~Document()
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Int32 IniDocument::Cmp(const IniDocument & o) const
|
||||
Int32 Document::Cmp(const Document & o) const
|
||||
{
|
||||
if (m_Doc == o.m_Doc)
|
||||
return 0;
|
||||
@ -122,91 +123,91 @@ Int32 IniDocument::Cmp(const IniDocument & o) const
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CSStr IniDocument::ToString() const
|
||||
CSStr Document::ToString() const
|
||||
{
|
||||
return _SC("");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void IniDocument::LoadFile(CSStr filepath)
|
||||
void Document::LoadFile(CSStr filepath)
|
||||
{
|
||||
if (!Validate())
|
||||
return; /* Unable to proceed */
|
||||
// Attempt to load the file from disk
|
||||
const SI_Error ini_ret = m_Doc->LoadFile(filepath);
|
||||
const SI_Error ret = m_Doc->LoadFile(filepath);
|
||||
// See if the file could be loaded
|
||||
if (ini_ret < 0)
|
||||
if (ret < 0)
|
||||
{
|
||||
// Identify the error type
|
||||
switch (ini_ret)
|
||||
switch (ret)
|
||||
{
|
||||
case SI_FAIL:
|
||||
SqThrow("Failed to load the ini file. Probably invalid");
|
||||
SqThrow("Failed to load the INI file. Probably invalid");
|
||||
break;
|
||||
case SI_NOMEM:
|
||||
SqThrow("Ran out of memory while loading the ini file");
|
||||
SqThrow("Ran out of memory while loading the INI file");
|
||||
break;
|
||||
case SI_FILE:
|
||||
SqThrow("Failed to load the ini file. %s", strerror(errno));
|
||||
SqThrow("Failed to load the INI file. %s", strerror(errno));
|
||||
break;
|
||||
default:
|
||||
SqThrow("Failed to load the ini file for some unforeseen reason");
|
||||
SqThrow("Failed to load the INI file for some unforeseen reason");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void IniDocument::LoadData(CSStr source, Int32 size)
|
||||
void Document::LoadData(CSStr source, Int32 size)
|
||||
{
|
||||
if (!Validate())
|
||||
return; /* Unable to proceed */
|
||||
// Attempt to load the source from memory
|
||||
const SI_Error ini_ret = m_Doc->LoadData(source, size < 0 ? strlen(source) : size);
|
||||
const SI_Error ret = m_Doc->LoadData(source, size < 0 ? strlen(source) : size);
|
||||
// See if the source could be loaded
|
||||
if (ini_ret < 0)
|
||||
if (ret < 0)
|
||||
{
|
||||
// Identify the error type
|
||||
switch (ini_ret)
|
||||
switch (ret)
|
||||
{
|
||||
case SI_FAIL:
|
||||
SqThrow("Failed to load the ini data. Probably invalid");
|
||||
SqThrow("Failed to load the INI data. Probably invalid");
|
||||
break;
|
||||
case SI_NOMEM:
|
||||
SqThrow("Ran out of memory while loading the ini data");
|
||||
SqThrow("Ran out of memory while loading the INI data");
|
||||
break;
|
||||
default:
|
||||
SqThrow("Failed to load the ini data for some unforeseen reason");
|
||||
SqThrow("Failed to load the INI data for some unforeseen reason");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void IniDocument::SaveFile(CSStr filepath, bool signature)
|
||||
void Document::SaveFile(CSStr filepath, bool signature)
|
||||
{
|
||||
if (!Validate())
|
||||
return; /* Unable to proceed */
|
||||
// Attempt to save the file to disk
|
||||
const SI_Error ini_ret = m_Doc->SaveFile(filepath, signature);
|
||||
const SI_Error ret = m_Doc->SaveFile(filepath, signature);
|
||||
// See if the file could be saved
|
||||
if (ini_ret == SI_FAIL)
|
||||
if (ret == SI_FAIL)
|
||||
{
|
||||
SqThrow("Failed to save the ini file. Probably invalid");
|
||||
SqThrow("Failed to save the INI file. Probably invalid");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object IniDocument::SaveData(bool signature)
|
||||
Object Document::SaveData(bool signature)
|
||||
{
|
||||
if (!Validate())
|
||||
return NullObject(); /* Unable to proceed */
|
||||
// The string where the content will be saved
|
||||
String source;
|
||||
// Attempt to save the data to string
|
||||
const SI_Error ini_ret = m_Doc->Save(source, signature);
|
||||
const SI_Error ret = m_Doc->Save(source, signature);
|
||||
// See if the data could be saved
|
||||
if (ini_ret == SI_FAIL)
|
||||
if (ret == SI_FAIL)
|
||||
{
|
||||
SqThrow("Failed to save the ini data. Probably invalid");
|
||||
SqThrow("Failed to save the INI data. Probably invalid");
|
||||
return NullObject(); /* Unable to proceed */
|
||||
}
|
||||
// Transform it into a script object
|
||||
@ -223,46 +224,46 @@ Object IniDocument::SaveData(bool signature)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
IniEntries IniDocument::GetAllSections() const
|
||||
Entries Document::GetAllSections() const
|
||||
{
|
||||
if (!Validate())
|
||||
return IniEntries(); /* Unable to proceed */
|
||||
return Entries(); /* Unable to proceed */
|
||||
// Prepare a container to receive the entries
|
||||
static Container entries;
|
||||
// Obtain all sections from the ini document
|
||||
// Obtain all sections from the INI document
|
||||
m_Doc->GetAllSections(entries);
|
||||
// Return the entries and take over content
|
||||
return IniEntries(m_Doc, entries);
|
||||
return Entries(m_Doc, entries);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
IniEntries IniDocument::GetAllKeys(CSStr section) const
|
||||
Entries Document::GetAllKeys(CSStr section) const
|
||||
{
|
||||
if (!Validate())
|
||||
return IniEntries(); /* Unable to proceed */
|
||||
return Entries(); /* Unable to proceed */
|
||||
// Prepare a container to receive the entries
|
||||
static Container entries;
|
||||
// Obtain all sections from the ini document
|
||||
// Obtain all sections from the INI document
|
||||
m_Doc->GetAllKeys(section, entries);
|
||||
// Return the entries and take over content
|
||||
return IniEntries(m_Doc, entries);
|
||||
return Entries(m_Doc, entries);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
IniEntries IniDocument::GetAllValues(CSStr section, CSStr key) const
|
||||
Entries Document::GetAllValues(CSStr section, CSStr key) const
|
||||
{
|
||||
if (!Validate())
|
||||
return IniEntries(); /* Unable to proceed */
|
||||
return Entries(); /* Unable to proceed */
|
||||
// Prepare a container to receive the entries
|
||||
static Container entries;
|
||||
// Obtain all sections from the ini document
|
||||
// Obtain all sections from the INI document
|
||||
m_Doc->GetAllValues(section, key, entries);
|
||||
// Return the entries and take over content
|
||||
return IniEntries(m_Doc, entries);
|
||||
return Entries(m_Doc, entries);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Int32 IniDocument::GetSectionSize(CSStr section) const
|
||||
Int32 Document::GetSectionSize(CSStr section) const
|
||||
{
|
||||
if (Validate())
|
||||
// Return the requested information
|
||||
@ -272,7 +273,7 @@ Int32 IniDocument::GetSectionSize(CSStr section) const
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool IniDocument::HasMultipleKeys(CSStr section, CSStr key) const
|
||||
bool Document::HasMultipleKeys(CSStr section, CSStr key) const
|
||||
{
|
||||
if (!Validate())
|
||||
return false; /* Unable to proceed */
|
||||
@ -285,7 +286,7 @@ bool IniDocument::HasMultipleKeys(CSStr section, CSStr key) const
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CCStr IniDocument::GetValue(CSStr section, CSStr key, CSStr def) const
|
||||
CCStr Document::GetValue(CSStr section, CSStr key, CSStr def) const
|
||||
{
|
||||
if (!Validate())
|
||||
return _SC(""); /* Unable to proceed */
|
||||
@ -294,7 +295,7 @@ CCStr IniDocument::GetValue(CSStr section, CSStr key, CSStr def) const
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQInteger IniDocument::GetInteger(CSStr section, CSStr key, SQInteger def) const
|
||||
SQInteger Document::GetInteger(CSStr section, CSStr key, SQInteger def) const
|
||||
{
|
||||
if (!Validate())
|
||||
return 0; /* Unable to proceed */
|
||||
@ -303,7 +304,7 @@ SQInteger IniDocument::GetInteger(CSStr section, CSStr key, SQInteger def) const
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQFloat IniDocument::GetFloat(CSStr section, CSStr key, SQFloat def) const
|
||||
SQFloat Document::GetFloat(CSStr section, CSStr key, SQFloat def) const
|
||||
{
|
||||
if (!Validate())
|
||||
return 0.0; /* Unable to proceed */
|
||||
@ -312,7 +313,7 @@ SQFloat IniDocument::GetFloat(CSStr section, CSStr key, SQFloat def) const
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool IniDocument::GetBoolean(CSStr section, CSStr key, bool def) const
|
||||
bool Document::GetBoolean(CSStr section, CSStr key, bool def) const
|
||||
{
|
||||
if (!Validate())
|
||||
return false; /* Unable to proceed */
|
||||
@ -321,205 +322,209 @@ bool IniDocument::GetBoolean(CSStr section, CSStr key, bool def) const
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void IniDocument::SetValue(CSStr section, CSStr key, CSStr value, bool force, CSStr comment)
|
||||
void Document::SetValue(CSStr section, CSStr key, CSStr value, bool force, CSStr comment)
|
||||
{
|
||||
if (!Validate())
|
||||
return; /* Unable to proceed */
|
||||
// Attempt to apply the specified information
|
||||
const SI_Error ini_ret = m_Doc->SetValue(section, key, value, comment, force);
|
||||
const SI_Error ret = m_Doc->SetValue(section, key, value, comment, force);
|
||||
// See if the information could be applied
|
||||
if (ini_ret < 0)
|
||||
if (ret < 0)
|
||||
{
|
||||
// Identify the error type
|
||||
switch (ini_ret)
|
||||
switch (ret)
|
||||
{
|
||||
case SI_FAIL:
|
||||
SqThrow("Failed to set the ini value. Probably invalid");
|
||||
SqThrow("Failed to set the INI value. Probably invalid");
|
||||
break;
|
||||
case SI_NOMEM:
|
||||
SqThrow("Ran out of memory while setting ini value");
|
||||
SqThrow("Ran out of memory while setting INI value");
|
||||
break;
|
||||
default:
|
||||
SqThrow("Failed to set the ini value for some unforeseen reason");
|
||||
SqThrow("Failed to set the INI value for some unforeseen reason");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void IniDocument::SetInteger(CSStr section, CSStr key, SQInteger value, bool hex, bool force, CSStr comment)
|
||||
void Document::SetInteger(CSStr section, CSStr key, SQInteger value, bool hex, bool force, CSStr comment)
|
||||
{
|
||||
if (!Validate())
|
||||
return; /* Unable to proceed */
|
||||
// Attempt to apply the specified information
|
||||
const SI_Error ini_ret = m_Doc->SetLongValue(section, key, value, comment, hex, force);
|
||||
const SI_Error ret = m_Doc->SetLongValue(section, key, value, comment, hex, force);
|
||||
// See if the information could be applied
|
||||
if (ini_ret < 0)
|
||||
if (ret < 0)
|
||||
{
|
||||
// Identify the error type
|
||||
switch (ini_ret)
|
||||
switch (ret)
|
||||
{
|
||||
case SI_FAIL:
|
||||
SqThrow("Failed to set the ini integer. Probably invalid");
|
||||
SqThrow("Failed to set the INI integer. Probably invalid");
|
||||
break;
|
||||
case SI_NOMEM:
|
||||
SqThrow("Ran out of memory while setting ini integer");
|
||||
SqThrow("Ran out of memory while setting INI integer");
|
||||
break;
|
||||
default:
|
||||
SqThrow("Failed to set the ini integer for some unforeseen reason");
|
||||
SqThrow("Failed to set the INI integer for some unforeseen reason");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void IniDocument::SetFloat(CSStr section, CSStr key, SQFloat value, bool force, CSStr comment)
|
||||
void Document::SetFloat(CSStr section, CSStr key, SQFloat value, bool force, CSStr comment)
|
||||
{
|
||||
if (!Validate())
|
||||
return; /* Unable to proceed */
|
||||
// Attempt to apply the specified information
|
||||
const SI_Error ini_ret = m_Doc->SetDoubleValue(section, key, value, comment, force);
|
||||
const SI_Error ret = m_Doc->SetDoubleValue(section, key, value, comment, force);
|
||||
// See if the information could be applied
|
||||
if (ini_ret < 0)
|
||||
if (ret < 0)
|
||||
{
|
||||
// Identify the error type
|
||||
switch (ini_ret)
|
||||
switch (ret)
|
||||
{
|
||||
case SI_FAIL:
|
||||
SqThrow("Failed to set the ini float. Probably invalid");
|
||||
SqThrow("Failed to set the INI float. Probably invalid");
|
||||
break;
|
||||
case SI_NOMEM:
|
||||
SqThrow("Ran out of memory while setting ini float");
|
||||
SqThrow("Ran out of memory while setting INI float");
|
||||
break;
|
||||
default:
|
||||
SqThrow("Failed to set the ini float for some unforeseen reason");
|
||||
SqThrow("Failed to set the INI float for some unforeseen reason");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void IniDocument::SetBoolean(CSStr section, CSStr key, bool value, bool force, CSStr comment)
|
||||
void Document::SetBoolean(CSStr section, CSStr key, bool value, bool force, CSStr comment)
|
||||
{
|
||||
if (!Validate())
|
||||
return; /* Unable to proceed */
|
||||
// Attempt to apply the specified information
|
||||
const SI_Error ini_ret = m_Doc->SetBoolValue(section, key, value, comment, force);
|
||||
const SI_Error ret = m_Doc->SetBoolValue(section, key, value, comment, force);
|
||||
// See if the information could be applied
|
||||
if (ini_ret < 0)
|
||||
if (ret < 0)
|
||||
{
|
||||
// Identify the error type
|
||||
switch (ini_ret)
|
||||
switch (ret)
|
||||
{
|
||||
case SI_FAIL:
|
||||
SqThrow("Failed to set the ini boolean. Probably invalid");
|
||||
SqThrow("Failed to set the INI boolean. Probably invalid");
|
||||
break;
|
||||
case SI_NOMEM:
|
||||
SqThrow("Ran out of memory while setting ini boolean");
|
||||
SqThrow("Ran out of memory while setting INI boolean");
|
||||
break;
|
||||
default:
|
||||
SqThrow("Failed to set the ini boolean for some unforeseen reason");
|
||||
SqThrow("Failed to set the INI boolean for some unforeseen reason");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool IniDocument::DeleteValue(CSStr section, CSStr key, CSStr value, bool empty)
|
||||
bool Document::DeleteValue(CSStr section, CSStr key, CSStr value, bool empty)
|
||||
{
|
||||
if (!Validate())
|
||||
return false; /* Unable to proceed */
|
||||
else if (!section)
|
||||
{
|
||||
SqThrow("Invalid ini section");
|
||||
SqThrow("Invalid INI section");
|
||||
return false; /* Unable to proceed */
|
||||
}
|
||||
else if (!key)
|
||||
{
|
||||
SqThrow("Invalid ini key");
|
||||
SqThrow("Invalid INI key");
|
||||
return false; /* Unable to proceed */
|
||||
}
|
||||
// Attempt to remove the specified value
|
||||
return m_Doc->DeleteValue(section, key, value, empty);
|
||||
}
|
||||
|
||||
} // Namespace:: INI
|
||||
|
||||
// ================================================================================================
|
||||
void Register_INI(HSQUIRRELVM vm)
|
||||
{
|
||||
using namespace INI;
|
||||
|
||||
Table inins(vm);
|
||||
|
||||
inins.Bind(_SC("Entries"), Class< IniEntries >(vm, _SC("SqIniEntries"))
|
||||
inins.Bind(_SC("Entries"), Class< Entries >(vm, _SC("SqIniEntries"))
|
||||
/* Constructors */
|
||||
.Ctor()
|
||||
.Ctor< const IniEntries & >()
|
||||
.Ctor< const Entries & >()
|
||||
/* Core Metamethods */
|
||||
.Func(_SC("_tostring"), &IniEntries::ToString)
|
||||
.Func(_SC("_cmp"), &IniEntries::Cmp)
|
||||
.Func(_SC("_tostring"), &Entries::ToString)
|
||||
.Func(_SC("_cmp"), &Entries::Cmp)
|
||||
/* Properties */
|
||||
.Prop(_SC("Valid"), &IniEntries::IsValid)
|
||||
.Prop(_SC("Empty"), &IniEntries::IsEmpty)
|
||||
.Prop(_SC("References"), &IniEntries::GetRefCount)
|
||||
.Prop(_SC("Size"), &IniEntries::GetSize)
|
||||
.Prop(_SC("Item"), &IniEntries::GetItem)
|
||||
.Prop(_SC("Comment"), &IniEntries::GetComment)
|
||||
.Prop(_SC("Order"), &IniEntries::GetOrder)
|
||||
.Prop(_SC("Valid"), &Entries::IsValid)
|
||||
.Prop(_SC("Empty"), &Entries::IsEmpty)
|
||||
.Prop(_SC("References"), &Entries::GetRefCount)
|
||||
.Prop(_SC("Size"), &Entries::GetSize)
|
||||
.Prop(_SC("Item"), &Entries::GetItem)
|
||||
.Prop(_SC("Comment"), &Entries::GetComment)
|
||||
.Prop(_SC("Order"), &Entries::GetOrder)
|
||||
/* Functions */
|
||||
.Func(_SC("Reset"), &IniEntries::Reset)
|
||||
.Func(_SC("Next"), &IniEntries::Next)
|
||||
.Func(_SC("Prev"), &IniEntries::Prev)
|
||||
.Func(_SC("Advance"), &IniEntries::Advance)
|
||||
.Func(_SC("Retreat"), &IniEntries::Retreat)
|
||||
.Func(_SC("Sort"), &IniEntries::Sort)
|
||||
.Func(_SC("SortByKeyOrder"), &IniEntries::SortByKeyOrder)
|
||||
.Func(_SC("SortByLoadOrder"), &IniEntries::SortByLoadOrder)
|
||||
.Func(_SC("SortByLoadOrderEmptyFirst"), &IniEntries::SortByLoadOrderEmptyFirst)
|
||||
.Func(_SC("Reset"), &Entries::Reset)
|
||||
.Func(_SC("Next"), &Entries::Next)
|
||||
.Func(_SC("Prev"), &Entries::Prev)
|
||||
.Func(_SC("Advance"), &Entries::Advance)
|
||||
.Func(_SC("Retreat"), &Entries::Retreat)
|
||||
.Func(_SC("Sort"), &Entries::Sort)
|
||||
.Func(_SC("SortByKeyOrder"), &Entries::SortByKeyOrder)
|
||||
.Func(_SC("SortByLoadOrder"), &Entries::SortByLoadOrder)
|
||||
.Func(_SC("SortByLoadOrderEmptyFirst"), &Entries::SortByLoadOrderEmptyFirst)
|
||||
);
|
||||
|
||||
inins.Bind(_SC("Document"), Class< IniDocument, NoCopy< IniDocument > >(vm, _SC("SqIniDocument"))
|
||||
inins.Bind(_SC("Document"), Class< Document, NoCopy< Document > >(vm, _SC("SqIniDocument"))
|
||||
/* Constructors */
|
||||
.Ctor()
|
||||
.Ctor< bool, bool, bool >()
|
||||
/* Core Metamethods */
|
||||
.Func(_SC("_tostring"), &IniDocument::ToString)
|
||||
.Func(_SC("_cmp"), &IniDocument::Cmp)
|
||||
.Func(_SC("_tostring"), &Document::ToString)
|
||||
.Func(_SC("_cmp"), &Document::Cmp)
|
||||
/* Properties */
|
||||
.Prop(_SC("Valid"), &IniDocument::IsValid)
|
||||
.Prop(_SC("Empty"), &IniDocument::IsEmpty)
|
||||
.Prop(_SC("References"), &IniDocument::GetRefCount)
|
||||
.Prop(_SC("Unicode"), &IniDocument::GetUnicode, &IniDocument::SetUnicode)
|
||||
.Prop(_SC("MultiKey"), &IniDocument::GetMultiKey, &IniDocument::SetMultiKey)
|
||||
.Prop(_SC("MultiLine"), &IniDocument::GetMultiLine, &IniDocument::SetMultiLine)
|
||||
.Prop(_SC("Spaces"), &IniDocument::GetSpaces, &IniDocument::SetSpaces)
|
||||
.Prop(_SC("Valid"), &Document::IsValid)
|
||||
.Prop(_SC("Empty"), &Document::IsEmpty)
|
||||
.Prop(_SC("References"), &Document::GetRefCount)
|
||||
.Prop(_SC("Unicode"), &Document::GetUnicode, &Document::SetUnicode)
|
||||
.Prop(_SC("MultiKey"), &Document::GetMultiKey, &Document::SetMultiKey)
|
||||
.Prop(_SC("MultiLine"), &Document::GetMultiLine, &Document::SetMultiLine)
|
||||
.Prop(_SC("Spaces"), &Document::GetSpaces, &Document::SetSpaces)
|
||||
/* Functions */
|
||||
.Func(_SC("Reset"), &IniDocument::Reset)
|
||||
.Func(_SC("LoadFile"), &IniDocument::LoadFile)
|
||||
.Overload< void (IniDocument::*)(CSStr) >(_SC("LoadData"), &IniDocument::LoadData)
|
||||
.Overload< void (IniDocument::*)(CSStr, Int32) >(_SC("LoadData"), &IniDocument::LoadData)
|
||||
.Overload< void (IniDocument::*)(CSStr) >(_SC("SaveFile"), &IniDocument::SaveFile)
|
||||
.Overload< void (IniDocument::*)(CSStr, bool) >(_SC("SaveFile"), &IniDocument::SaveFile)
|
||||
.Func(_SC("SaveData"), &IniDocument::SaveData)
|
||||
.Func(_SC("GetSections"), &IniDocument::GetAllSections)
|
||||
.Func(_SC("GetKeys"), &IniDocument::GetAllKeys)
|
||||
.Func(_SC("GetValues"), &IniDocument::GetAllValues)
|
||||
.Func(_SC("GetSectionSize"), &IniDocument::GetSectionSize)
|
||||
.Func(_SC("HasMultipleKeys"), &IniDocument::HasMultipleKeys)
|
||||
.Func(_SC("GetValue"), &IniDocument::GetValue)
|
||||
.Func(_SC("GetInteger"), &IniDocument::GetInteger)
|
||||
.Func(_SC("GetFloat"), &IniDocument::GetFloat)
|
||||
.Func(_SC("GetBoolean"), &IniDocument::GetBoolean)
|
||||
.Overload< void (IniDocument::*)(CSStr, CSStr, CSStr) >(_SC("SetValue"), &IniDocument::SetValue)
|
||||
.Overload< void (IniDocument::*)(CSStr, CSStr, CSStr, bool) >(_SC("SetValue"), &IniDocument::SetValue)
|
||||
.Overload< void (IniDocument::*)(CSStr, CSStr, CSStr, bool, CSStr) >(_SC("SetValue"), &IniDocument::SetValue)
|
||||
.Overload< void (IniDocument::*)(CSStr, CSStr, SQInteger) >(_SC("SetInteger"), &IniDocument::SetInteger)
|
||||
.Overload< void (IniDocument::*)(CSStr, CSStr, SQInteger, bool) >(_SC("SetInteger"), &IniDocument::SetInteger)
|
||||
.Overload< void (IniDocument::*)(CSStr, CSStr, SQInteger, bool, bool) >(_SC("SetInteger"), &IniDocument::SetInteger)
|
||||
.Overload< void (IniDocument::*)(CSStr, CSStr, SQInteger, bool, bool, CSStr) >(_SC("SetInteger"), &IniDocument::SetInteger)
|
||||
.Overload< void (IniDocument::*)(CSStr, CSStr, SQFloat) >(_SC("SetFloat"), &IniDocument::SetFloat)
|
||||
.Overload< void (IniDocument::*)(CSStr, CSStr, SQFloat, bool) >(_SC("SetFloat"), &IniDocument::SetFloat)
|
||||
.Overload< void (IniDocument::*)(CSStr, CSStr, SQFloat, bool, CSStr) >(_SC("SetFloat"), &IniDocument::SetFloat)
|
||||
.Overload< void (IniDocument::*)(CSStr, CSStr, bool) >(_SC("SetBoolean"), &IniDocument::SetBoolean)
|
||||
.Overload< void (IniDocument::*)(CSStr, CSStr, bool, bool) >(_SC("SetBoolean"), &IniDocument::SetBoolean)
|
||||
.Overload< void (IniDocument::*)(CSStr, CSStr, bool, bool, CSStr) >(_SC("SetBoolean"), &IniDocument::SetBoolean)
|
||||
.Overload< bool (IniDocument::*)(CSStr) >(_SC("DeleteValue"), &IniDocument::DeleteValue)
|
||||
.Overload< bool (IniDocument::*)(CSStr, CSStr) >(_SC("DeleteValue"), &IniDocument::DeleteValue)
|
||||
.Overload< bool (IniDocument::*)(CSStr, CSStr, CSStr) >(_SC("DeleteValue"), &IniDocument::DeleteValue)
|
||||
.Overload< bool (IniDocument::*)(CSStr, CSStr, CSStr, bool) >(_SC("DeleteValue"), &IniDocument::DeleteValue)
|
||||
.Func(_SC("Reset"), &Document::Reset)
|
||||
.Func(_SC("LoadFile"), &Document::LoadFile)
|
||||
.Overload< void (Document::*)(CSStr) >(_SC("LoadData"), &Document::LoadData)
|
||||
.Overload< void (Document::*)(CSStr, Int32) >(_SC("LoadData"), &Document::LoadData)
|
||||
.Overload< void (Document::*)(CSStr) >(_SC("SaveFile"), &Document::SaveFile)
|
||||
.Overload< void (Document::*)(CSStr, bool) >(_SC("SaveFile"), &Document::SaveFile)
|
||||
.Func(_SC("SaveData"), &Document::SaveData)
|
||||
.Func(_SC("GetSections"), &Document::GetAllSections)
|
||||
.Func(_SC("GetKeys"), &Document::GetAllKeys)
|
||||
.Func(_SC("GetValues"), &Document::GetAllValues)
|
||||
.Func(_SC("GetSectionSize"), &Document::GetSectionSize)
|
||||
.Func(_SC("HasMultipleKeys"), &Document::HasMultipleKeys)
|
||||
.Func(_SC("GetValue"), &Document::GetValue)
|
||||
.Func(_SC("GetInteger"), &Document::GetInteger)
|
||||
.Func(_SC("GetFloat"), &Document::GetFloat)
|
||||
.Func(_SC("GetBoolean"), &Document::GetBoolean)
|
||||
.Overload< void (Document::*)(CSStr, CSStr, CSStr) >(_SC("SetValue"), &Document::SetValue)
|
||||
.Overload< void (Document::*)(CSStr, CSStr, CSStr, bool) >(_SC("SetValue"), &Document::SetValue)
|
||||
.Overload< void (Document::*)(CSStr, CSStr, CSStr, bool, CSStr) >(_SC("SetValue"), &Document::SetValue)
|
||||
.Overload< void (Document::*)(CSStr, CSStr, SQInteger) >(_SC("SetInteger"), &Document::SetInteger)
|
||||
.Overload< void (Document::*)(CSStr, CSStr, SQInteger, bool) >(_SC("SetInteger"), &Document::SetInteger)
|
||||
.Overload< void (Document::*)(CSStr, CSStr, SQInteger, bool, bool) >(_SC("SetInteger"), &Document::SetInteger)
|
||||
.Overload< void (Document::*)(CSStr, CSStr, SQInteger, bool, bool, CSStr) >(_SC("SetInteger"), &Document::SetInteger)
|
||||
.Overload< void (Document::*)(CSStr, CSStr, SQFloat) >(_SC("SetFloat"), &Document::SetFloat)
|
||||
.Overload< void (Document::*)(CSStr, CSStr, SQFloat, bool) >(_SC("SetFloat"), &Document::SetFloat)
|
||||
.Overload< void (Document::*)(CSStr, CSStr, SQFloat, bool, CSStr) >(_SC("SetFloat"), &Document::SetFloat)
|
||||
.Overload< void (Document::*)(CSStr, CSStr, bool) >(_SC("SetBoolean"), &Document::SetBoolean)
|
||||
.Overload< void (Document::*)(CSStr, CSStr, bool, bool) >(_SC("SetBoolean"), &Document::SetBoolean)
|
||||
.Overload< void (Document::*)(CSStr, CSStr, bool, bool, CSStr) >(_SC("SetBoolean"), &Document::SetBoolean)
|
||||
.Overload< bool (Document::*)(CSStr) >(_SC("DeleteValue"), &Document::DeleteValue)
|
||||
.Overload< bool (Document::*)(CSStr, CSStr) >(_SC("DeleteValue"), &Document::DeleteValue)
|
||||
.Overload< bool (Document::*)(CSStr, CSStr, CSStr) >(_SC("DeleteValue"), &Document::DeleteValue)
|
||||
.Overload< bool (Document::*)(CSStr, CSStr, CSStr, bool) >(_SC("DeleteValue"), &Document::DeleteValue)
|
||||
);
|
||||
|
||||
RootTable(vm).Bind(_SC("SqIni"), inins);
|
||||
|
@ -9,30 +9,31 @@
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
namespace INI {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
class IniEntries;
|
||||
class IniDocument;
|
||||
class Entries;
|
||||
class Document;
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Manages a reference counted ini document instance.
|
||||
* Manages a reference counted INI document instance.
|
||||
*/
|
||||
class IniDocumentRef
|
||||
class DocumentRef
|
||||
{
|
||||
// --------------------------------------------------------------------------------------------
|
||||
friend class IniDocument;
|
||||
friend class Document;
|
||||
|
||||
private:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef CSimpleIniA Document;
|
||||
typedef CSimpleIniA IrcDocument;
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef unsigned int Counter;
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Document* m_Ptr; /* The document reader, writer and manager instance. */
|
||||
Counter* m_Ref; /* Reference count to the managed instance. */
|
||||
IrcDocument* m_Ptr; /* The document reader, writer and manager instance. */
|
||||
Counter* m_Ref; /* Reference count to the managed instance. */
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Grab a strong reference to a document instance.
|
||||
@ -62,8 +63,8 @@ private:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Base constructor.
|
||||
*/
|
||||
IniDocumentRef(bool utf8, bool multikey, bool multiline)
|
||||
: m_Ptr(new Document(utf8, multikey, multiline)), m_Ref(new Counter(1))
|
||||
DocumentRef(bool utf8, bool multikey, bool multiline)
|
||||
: m_Ptr(new IrcDocument(utf8, multikey, multiline)), m_Ref(new Counter(1))
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
@ -73,7 +74,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor (null).
|
||||
*/
|
||||
IniDocumentRef()
|
||||
DocumentRef()
|
||||
: m_Ptr(NULL), m_Ref(NULL)
|
||||
{
|
||||
/* ... */
|
||||
@ -82,7 +83,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor.
|
||||
*/
|
||||
IniDocumentRef(const IniDocumentRef & o)
|
||||
DocumentRef(const DocumentRef & o)
|
||||
: m_Ptr(o.m_Ptr), m_Ref(o.m_Ref)
|
||||
|
||||
{
|
||||
@ -92,7 +93,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~IniDocumentRef()
|
||||
~DocumentRef()
|
||||
{
|
||||
Drop();
|
||||
}
|
||||
@ -100,7 +101,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator.
|
||||
*/
|
||||
IniDocumentRef & operator = (const IniDocumentRef & o)
|
||||
DocumentRef & operator = (const DocumentRef & o)
|
||||
{
|
||||
if (m_Ptr != o.m_Ptr)
|
||||
{
|
||||
@ -115,7 +116,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Perform an equality comparison between two document instances.
|
||||
*/
|
||||
bool operator == (const IniDocumentRef & o) const
|
||||
bool operator == (const DocumentRef & o) const
|
||||
{
|
||||
return (m_Ptr == o.m_Ptr);
|
||||
}
|
||||
@ -123,7 +124,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Perform an inequality comparison between two document instances.
|
||||
*/
|
||||
bool operator != (const IniDocumentRef & o) const
|
||||
bool operator != (const DocumentRef & o) const
|
||||
{
|
||||
return (m_Ptr != o.m_Ptr);
|
||||
}
|
||||
@ -139,7 +140,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Member operator for dereferencing the managed pointer.
|
||||
*/
|
||||
Document * operator -> () const
|
||||
IrcDocument * operator -> () const
|
||||
{
|
||||
assert(m_Ptr != NULL);
|
||||
return m_Ptr;
|
||||
@ -148,7 +149,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Indirection operator for obtaining a reference of the managed pointer.
|
||||
*/
|
||||
Document & operator * () const
|
||||
IrcDocument & operator * () const
|
||||
{
|
||||
assert(m_Ptr != NULL);
|
||||
return *m_Ptr;
|
||||
@ -165,20 +166,20 @@ public:
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Class that can access and iterate a series of entries in the ini document.
|
||||
* Class that can access and iterate a series of entries in the INI document.
|
||||
*/
|
||||
class IniEntries
|
||||
class Entries
|
||||
{
|
||||
// --------------------------------------------------------------------------------------------
|
||||
friend class IniDocument;
|
||||
friend class Document;
|
||||
|
||||
protected:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef CSimpleIniA Document;
|
||||
typedef CSimpleIniA IrcDocument;
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef Document::TNamesDepend Container;
|
||||
typedef IrcDocument::TNamesDepend Container;
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef Container::iterator Iterator;
|
||||
@ -186,7 +187,7 @@ protected:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
IniEntries(const IniDocumentRef & ini, Container & list)
|
||||
Entries(const DocumentRef & ini, Container & list)
|
||||
: m_Doc(ini), m_List(), m_Elem()
|
||||
{
|
||||
m_List.swap(list);
|
||||
@ -196,7 +197,7 @@ protected:
|
||||
private:
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
IniDocumentRef m_Doc; /* The document that contains the elements. */
|
||||
DocumentRef m_Doc; /* The document that contains the elements. */
|
||||
Container m_List; /* The list of elements to iterate. */
|
||||
Iterator m_Elem; /* The currently processed element. */
|
||||
|
||||
@ -205,7 +206,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor. (null)
|
||||
*/
|
||||
IniEntries()
|
||||
Entries()
|
||||
: m_Doc(), m_List(), m_Elem(m_List.end())
|
||||
{
|
||||
/* ... */
|
||||
@ -214,7 +215,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor.
|
||||
*/
|
||||
IniEntries(const IniEntries & o)
|
||||
Entries(const Entries & o)
|
||||
: m_Doc(o.m_Doc), m_List(o.m_List), m_Elem()
|
||||
{
|
||||
Reset();
|
||||
@ -223,7 +224,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~IniEntries()
|
||||
~Entries()
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
@ -231,7 +232,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator.
|
||||
*/
|
||||
IniEntries & operator = (const IniEntries & o)
|
||||
Entries & operator = (const Entries & o)
|
||||
{
|
||||
m_Doc = o.m_Doc;
|
||||
m_List = o.m_List;
|
||||
@ -242,7 +243,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Used by the script engine to compare two instances of this type.
|
||||
*/
|
||||
Int32 Cmp(const IniEntries & o) const;
|
||||
Int32 Cmp(const Entries & o) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Used by the script engine to convert an instance of this type to a string.
|
||||
@ -318,7 +319,7 @@ public:
|
||||
void Sort()
|
||||
{
|
||||
if (!m_List.empty())
|
||||
m_List.sort(Document::Entry::KeyOrder());
|
||||
m_List.sort(IrcDocument::Entry::KeyOrder());
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -327,7 +328,7 @@ public:
|
||||
void SortByKeyOrder()
|
||||
{
|
||||
if (!m_List.empty())
|
||||
m_List.sort(Document::Entry::KeyOrder());
|
||||
m_List.sort(IrcDocument::Entry::KeyOrder());
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -336,7 +337,7 @@ public:
|
||||
void SortByLoadOrder()
|
||||
{
|
||||
if (!m_List.empty())
|
||||
m_List.sort(Document::Entry::LoadOrder());
|
||||
m_List.sort(IrcDocument::Entry::LoadOrder());
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -345,7 +346,7 @@ public:
|
||||
void SortByLoadOrderEmptyFirst()
|
||||
{
|
||||
if (!m_List.empty())
|
||||
m_List.sort(Document::Entry::LoadOrderEmptyFirst());
|
||||
m_List.sort(IrcDocument::Entry::LoadOrderEmptyFirst());
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -365,27 +366,27 @@ public:
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Class that can read/write and alter the contents of ini files.
|
||||
* Class that can read/write and alter the contents of INI files.
|
||||
*/
|
||||
class IniDocument
|
||||
class Document
|
||||
{
|
||||
protected:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef CSimpleIniA Document;
|
||||
typedef CSimpleIniA IrcDocument;
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef Document::TNamesDepend Container;
|
||||
typedef IrcDocument::TNamesDepend Container;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor. (disabled)
|
||||
*/
|
||||
IniDocument(const IniDocument & o);
|
||||
Document(const Document & o);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator. (disabled)
|
||||
*/
|
||||
IniDocument & operator = (const IniDocument & o);
|
||||
Document & operator = (const Document & o);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Validate the document reference.
|
||||
@ -394,36 +395,36 @@ protected:
|
||||
{
|
||||
if (m_Doc)
|
||||
return true;
|
||||
SqThrow("Invalid ini document reference");
|
||||
SqThrow("Invalid INI document reference");
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
IniDocumentRef m_Doc; /* The main ini document instance. */
|
||||
DocumentRef m_Doc; /* The main INI document instance. */
|
||||
|
||||
public:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
IniDocument();
|
||||
Document();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Explicit constructor.
|
||||
*/
|
||||
IniDocument(bool utf8, bool multikey, bool multiline);
|
||||
Document(bool utf8, bool multikey, bool multiline);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~IniDocument();
|
||||
~Document();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Used by the script engine to compare two instances of this type.
|
||||
*/
|
||||
Int32 Cmp(const IniDocument & o) const;
|
||||
Int32 Cmp(const Document & o) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Used by the script engine to convert an instance of this type to a string.
|
||||
@ -431,7 +432,7 @@ public:
|
||||
CSStr ToString() const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* See whether this instance references a valid ini document.
|
||||
* See whether this instance references a valid INI document.
|
||||
*/
|
||||
bool IsValid() const
|
||||
{
|
||||
@ -463,7 +464,7 @@ public:
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* See whether the ini data is treated as unicode.
|
||||
* See whether the INI data is treated as unicode.
|
||||
*/
|
||||
bool GetUnicode() const
|
||||
{
|
||||
@ -471,7 +472,7 @@ public:
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set whether the ini data should be treated as unicode.
|
||||
* Set whether the INI data should be treated as unicode.
|
||||
*/
|
||||
void SetUnicode(bool toggle)
|
||||
{
|
||||
@ -565,17 +566,17 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve all section names.
|
||||
*/
|
||||
IniEntries GetAllSections() const;
|
||||
Entries GetAllSections() const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve all unique key names in a section.
|
||||
*/
|
||||
IniEntries GetAllKeys(CSStr section) const;
|
||||
Entries GetAllKeys(CSStr section) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve all values for a specific key.
|
||||
*/
|
||||
IniEntries GetAllValues(CSStr section, CSStr key) const;
|
||||
Entries GetAllValues(CSStr section, CSStr key) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Query the number of keys in a specific section.
|
||||
@ -729,6 +730,7 @@ public:
|
||||
bool DeleteValue(CSStr section, CSStr key, CSStr value, bool empty);
|
||||
};
|
||||
|
||||
} // Namespace:: INI
|
||||
} // Namespace:: SqMod
|
||||
|
||||
#endif // _LIBRARY_INI_HPP_
|
||||
|
1045
source/Library/IRC.cpp
Normal file
1045
source/Library/IRC.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1434
source/Library/IRC.hpp
Normal file
1434
source/Library/IRC.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,7 @@
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
namespace XML {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void XmlParseResult::Check() const
|
||||
@ -25,9 +26,13 @@ XmlNode XmlDocument::GetNode() const
|
||||
return XmlNode();
|
||||
}
|
||||
|
||||
} // Namespace:: XML
|
||||
|
||||
// ================================================================================================
|
||||
void Register_XML(HSQUIRRELVM vm)
|
||||
{
|
||||
using namespace XML;
|
||||
|
||||
Table xmlns(vm);
|
||||
|
||||
xmlns.Bind(_SC("ParseResult"), Class< XmlParseResult >(vm, _SC("SqXmlParseResult"))
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
namespace XML {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
using namespace pugi;
|
||||
@ -2030,6 +2031,7 @@ public:
|
||||
|
||||
};
|
||||
|
||||
} // Namespace:: XML
|
||||
} // Namespace:: SqMod
|
||||
|
||||
#endif // _LIBRARY_XML_HPP_
|
||||
|
@ -117,7 +117,7 @@ template < Uint8 L, bool S > static SQInteger LogBasicMessage(HSQUIRRELVM vm)
|
||||
void Register_Log(HSQUIRRELVM vm)
|
||||
{
|
||||
RootTable(vm)
|
||||
.Bind(_SC("Log"), Table(vm)
|
||||
.Bind(_SC("SqLog"), Table(vm)
|
||||
.SquirrelFunc(_SC("Dbg"), &LogBasicMessage< LL_DBG, false >)
|
||||
.SquirrelFunc(_SC("Usr"), &LogBasicMessage< LL_USR, false >)
|
||||
.SquirrelFunc(_SC("Scs"), &LogBasicMessage< LL_SCS, false >)
|
||||
|
@ -36,6 +36,7 @@ extern void Register_Entity(HSQUIRRELVM vm);
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
extern void Register_Hash(HSQUIRRELVM vm);
|
||||
extern void Register_INI(HSQUIRRELVM vm);
|
||||
extern void Register_IRC(HSQUIRRELVM vm);
|
||||
extern void Register_Numeric(HSQUIRRELVM vm);
|
||||
extern void Register_Random(HSQUIRRELVM vm);
|
||||
extern void Register_SQLite(HSQUIRRELVM vm);
|
||||
@ -81,6 +82,7 @@ bool RegisterAPI(HSQUIRRELVM vm)
|
||||
|
||||
Register_Hash(vm);
|
||||
Register_INI(vm);
|
||||
Register_IRC(vm);
|
||||
Register_Random(vm);
|
||||
Register_Numeric(vm);
|
||||
//Register_SQLite(vm);
|
||||
|
@ -15,6 +15,62 @@ Routine::Time Routine::s_Prev = 0;
|
||||
Routine::Queue Routine::s_Queue;
|
||||
Routine::Buckets Routine::s_Buckets;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Routine::Process()
|
||||
{
|
||||
s_Lock = false; /* In case an exception prevented the unlock last time */
|
||||
if (!s_Queue.empty())
|
||||
{
|
||||
for (Queue::iterator itr = s_Queue.begin(); itr != s_Queue.end(); ++itr)
|
||||
{
|
||||
if (itr->first && itr->second)
|
||||
itr->second->Attach();
|
||||
else if (itr->second)
|
||||
itr->second->Terminate();
|
||||
}
|
||||
s_Queue.clear();
|
||||
}
|
||||
// Is this the first call?
|
||||
if (s_Last == 0)
|
||||
{
|
||||
s_Last = GetCurrentSysTime();
|
||||
return;
|
||||
}
|
||||
s_Lock = true;
|
||||
s_Prev = s_Last;
|
||||
s_Last = GetCurrentSysTime();
|
||||
Int32 delta = Int32((s_Last - s_Prev) / 1000L);
|
||||
for (Buckets::iterator bucket = s_Buckets.begin(); bucket != s_Buckets.end(); ++bucket)
|
||||
{
|
||||
bucket->mElapsed += delta;
|
||||
if (bucket->mElapsed < bucket->mInterval)
|
||||
continue;
|
||||
Routines::iterator itr = bucket->mRoutines.begin();
|
||||
Routines::iterator end = bucket->mRoutines.end();
|
||||
for (; itr != end; ++itr)
|
||||
(*itr)->Execute();
|
||||
bucket->mElapsed = 0;
|
||||
}
|
||||
s_Lock = false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Routine::TerminateAll()
|
||||
{
|
||||
for (Buckets::iterator bucket = s_Buckets.begin(); bucket != s_Buckets.end(); ++bucket)
|
||||
{
|
||||
Routines::iterator itr = bucket->mRoutines.begin();
|
||||
Routines::iterator end = bucket->mRoutines.end();
|
||||
for (; itr != end; ++itr)
|
||||
{
|
||||
(*itr)->Release();
|
||||
(*itr)->m_Terminated = true;
|
||||
}
|
||||
}
|
||||
// Clear all references
|
||||
s_Buckets.clear();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Routine::Routine(Object & env, Function & func, Interval interval)
|
||||
: m_Iterations(0)
|
||||
@ -24,7 +80,7 @@ Routine::Routine(Object & env, Function & func, Interval interval)
|
||||
, m_Terminated(false)
|
||||
, m_Callback(env.GetVM(), env, func.GetFunc())
|
||||
{
|
||||
/* ... */
|
||||
Create();
|
||||
}
|
||||
|
||||
Routine::Routine(Object & env, Function & func, Interval interval, Iterate iterations)
|
||||
@ -142,6 +198,7 @@ void Routine::Terminate()
|
||||
{
|
||||
Detach();
|
||||
Release();
|
||||
m_Terminated = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -298,7 +355,7 @@ void Routine::Release()
|
||||
if (m_Terminated)
|
||||
return;
|
||||
m_Terminated = true;
|
||||
m_Callback.Release2();
|
||||
m_Callback.ReleaseGently();
|
||||
m_Arg1.Release();
|
||||
m_Arg2.Release();
|
||||
m_Arg3.Release();
|
||||
@ -426,55 +483,20 @@ void Routine::Execute()
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Routine::Process()
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Forward the call to process routines.
|
||||
*/
|
||||
void ProcessRoutine()
|
||||
{
|
||||
s_Lock = false; /* In case an exception prevented the unlock last time */
|
||||
if (!s_Queue.empty())
|
||||
{
|
||||
for (Queue::iterator itr = s_Queue.begin(); itr != s_Queue.end(); ++itr)
|
||||
{
|
||||
if (itr->first && itr->second)
|
||||
itr->second->Attach();
|
||||
else if (itr->second)
|
||||
itr->second->Terminate();
|
||||
}
|
||||
s_Queue.clear();
|
||||
}
|
||||
// Is this the first call?
|
||||
if (s_Last == 0)
|
||||
{
|
||||
s_Last = GetCurrentSysTime();
|
||||
return;
|
||||
}
|
||||
s_Lock = true;
|
||||
s_Prev = s_Last;
|
||||
s_Last = GetCurrentSysTime();
|
||||
Int32 delta = Int32((s_Last - s_Prev) / 1000L);
|
||||
for (Buckets::iterator bucket = s_Buckets.begin(); bucket != s_Buckets.end(); ++bucket)
|
||||
{
|
||||
bucket->mElapsed += delta;
|
||||
if (bucket->mElapsed < bucket->mInterval)
|
||||
continue;
|
||||
Routines::iterator itr = bucket->mRoutines.begin();
|
||||
Routines::iterator end = bucket->mRoutines.end();
|
||||
for (; itr != end; ++itr)
|
||||
(*itr)->Execute();
|
||||
bucket->mElapsed = 0;
|
||||
}
|
||||
s_Lock = false;
|
||||
Routine::Process();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Routine::Cleanup()
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Forward the call to terminate routines.
|
||||
*/
|
||||
void TerminateRoutine()
|
||||
{
|
||||
for (Buckets::iterator bucket = s_Buckets.begin(); bucket != s_Buckets.end(); ++bucket)
|
||||
{
|
||||
Routines::iterator itr = bucket->mRoutines.begin();
|
||||
Routines::iterator end = bucket->mRoutines.end();
|
||||
for (; itr != end; ++itr)
|
||||
(*itr)->Release();
|
||||
}
|
||||
Routine::TerminateAll();
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
|
@ -25,6 +25,16 @@ public:
|
||||
typedef Uint32 Iterate;
|
||||
typedef std::vector< Routine * > Routines;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Process all active routines and update elapsed time.
|
||||
*/
|
||||
static void Process();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Release all resources and prepare for shutdown.
|
||||
*/
|
||||
static void TerminateAll();
|
||||
|
||||
protected:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -117,6 +127,8 @@ protected:
|
||||
static Queue s_Queue; /* Actions to be performed when the buckets aren't locked */
|
||||
static Buckets s_Buckets; /* Buckets of routines grouped by similar intervals. */
|
||||
|
||||
private:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor. (disabled)
|
||||
*/
|
||||
@ -127,6 +139,24 @@ protected:
|
||||
*/
|
||||
Routine & operator = (const Routine &);
|
||||
|
||||
private:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Iterate m_Iterations; /* Number of iterations before self destruct. */
|
||||
Interval m_Interval; /* Interval between calls. */
|
||||
Uint8 m_Arguments; /* Number of arguments to forward. */
|
||||
bool m_Suspended; /* Whether calls should be ignored. */
|
||||
bool m_Terminated; /* Whether the routine was terminated. */
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Function m_Callback; /* The callback to be executed when triggered. */
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Arguments to be forwarded to the callback.
|
||||
*/
|
||||
Object m_Arg1, m_Arg2, m_Arg3, m_Arg4, m_Arg5, m_Arg6, m_Arg7,
|
||||
m_Arg8, m_Arg9, m_Arg10, m_Arg11, m_Arg12, m_Arg13, m_Arg14;
|
||||
|
||||
public:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -280,36 +310,6 @@ protected:
|
||||
* Execute the binded callback.
|
||||
*/
|
||||
void Execute();
|
||||
|
||||
private:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Iterate m_Iterations; /* Number of iterations before self destruct. */
|
||||
Interval m_Interval; /* Interval between calls. */
|
||||
Uint8 m_Arguments; /* Number of arguments to forward. */
|
||||
bool m_Suspended; /* Whether calls should be ignored. */
|
||||
bool m_Terminated; /* Whether the routine was terminated. */
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Function m_Callback; /* The callback to be executed when triggered. */
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Arguments to be forwarded to the callback.
|
||||
*/
|
||||
Object m_Arg1, m_Arg2, m_Arg3, m_Arg4, m_Arg5, m_Arg6, m_Arg7,
|
||||
m_Arg8, m_Arg9, m_Arg10, m_Arg11, m_Arg12, m_Arg13, m_Arg14;
|
||||
|
||||
public:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Process all active routines and update elapsed time.
|
||||
*/
|
||||
static void Process();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Release all resources and prepare for shutdown.
|
||||
*/
|
||||
static void Cleanup();
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
Loading…
Reference in New Issue
Block a user