1
0
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:
Sandu Liviu Catalin 2016-02-23 05:23:56 +02:00
parent b6e72e93a2
commit bedf03c9cd
32 changed files with 10554 additions and 297 deletions

177
cbp/LibIRC.cbp Normal file
View 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>

View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

36
external/LibIRC/params.h vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

1499
include/libircclient.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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)

View File

@ -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()
{

View File

@ -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()

View File

@ -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);

View File

@ -9,29 +9,30 @@
// ------------------------------------------------------------------------------------------------
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. */
IrcDocument* m_Ptr; /* The document reader, writer and manager instance. */
Counter* m_Ref; /* Reference count to the managed 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

File diff suppressed because it is too large Load Diff

1434
source/Library/IRC.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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"))

View File

@ -10,6 +10,7 @@
// ------------------------------------------------------------------------------------------------
namespace SqMod {
namespace XML {
// ------------------------------------------------------------------------------------------------
using namespace pugi;
@ -2030,6 +2031,7 @@ public:
};
} // Namespace:: XML
} // Namespace:: SqMod
#endif // _LIBRARY_XML_HPP_

View File

@ -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 >)

View File

@ -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);

View File

@ -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();
}
// ================================================================================================

View File

@ -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