Wed, 28 Sep 2016 16:07:11 -0500
gg: Remove internal libgadu in favor of always using an external one
--- a/configure.ac Wed Sep 28 09:32:19 2016 -0500 +++ b/configure.ac Wed Sep 28 16:07:11 2016 -0500 @@ -1181,58 +1181,38 @@ dnl ####################################################################### dnl # Check for Gadu-Gadu protocol library (libgadu) dnl ####################################################################### - -PKG_CHECK_MODULES(LIBGADU, [libgadu >= 1.12.0], [have_libgadu=yes], [have_libgadu=no]) +AC_ARG_ENABLE(libgadu, + [AS_HELP_STRING([--disable-libgadu], + [compile without libgadu (required for GaduGadu support)])], + enable_libgadu="$enableval", enable_libgadu="yes") -if test "x$have_libgadu" = "xyes"; then - AC_CHECK_LIB(gadu, gg_is_gpl_compliant, , [ - LIBGADU_LIBS="" - LIBGADU_CFLAGS="" - have_libgadu=no - AC_MSG_WARN([ +if test "x$enable_libgadu" = "xyes"; then + PKG_CHECK_MODULES(LIBGADU, [libgadu >= 1.12.0], [ + have_libgadu=yes + AC_CHECK_LIB(gadu, gg_is_gpl_compliant, , [ + LIBGADU_LIBS="" + LIBGADU_CFLAGS="" + have_libgadu=no + if test "x$force_deps" = "xyes" ; then + AC_MSG_WARN([ libgadu is not compatible with the GPL when compiled with OpenSSL support. To compile against system libgadu, please recompile libgadu using: ./configure --with-openssl=no Then rerun this ./configure - -Falling back to using our own copy of libgadu. - ]) - ], [$LIBGADU_LIBS]) -fi - -AM_CONDITIONAL(HAVE_LIBGADU, test "x$have_libgadu" = "xyes") -if test "x$have_libgadu" = "xyes"; then - AC_DEFINE(HAVE_LIBGADU, 1, [Linked with external libgadu]) -else - AC_CHECK_LIB(gnutls, gnutls_certificate_set_x509_system_trust, [gg_have_gnutls_csxst=yes], [gg_have_gnutls_csxst=no]) + ]) + fi + ], [$LIBGADU_LIBS]) + ], [ + have_libgadu=no + ]) - gg_gnutls_sts="" - if test "x$gg_have_gnutls_csxst" = "xno"; then - for i in /etc/ssl/ca-bundle.pem \ - /etc/ssl/certs/ca-certificates.crt \ - /etc/pki/tls/cert.pem \ - /usr/local/share/certs/ca-root-nss.crt \ - /etc/ssl/cert.pem - do - if test -e $i; then - gg_gnutls_sts="$i" - break - fi - done + if test "x$have_libgadu" != "xyes" -a "x$force_deps" = "xyes" ; then + AC_MSG_ERROR([ +Libgadu development headers not found. +Use --disable-libgadu if you do not need GG (GaduGadu) support. +]) fi - - if test "x$gg_have_gnutls_csxst" = "xyes"; then - AC_DEFINE(HAVE_GNUTLS_CERTIFICATE_SET_X509_SYSTEM_TRUST, 1, [gnutls contains the gnutls_certificate_set_x509_system_trust function]) - fi - if test "x$gg_gnutls_sts" != "x"; then - AC_DEFINE_UNQUOTED(GG_CONFIG_GNUTLS_SYSTEM_TRUST_STORE, ["$gg_gnutls_sts"], [use the given file as GnuTLS default trust store]) - fi - - dnl # redundant - only here to stay compatible with libgadu upstream - PKG_CHECK_MODULES([GNUTLS_2_10], [gnutls >= 2.10.0], [ - AC_DEFINE([HAVE_GNUTLS_2_10], [], [Defined if GnuTLS >= 2.10.0 is available.]) - ],:) fi AC_SUBST(LIBGADU_LIBS) @@ -1259,6 +1239,9 @@ if test "x$silcincludes" != "xyes" -o "x$silcclient" != "xyes"; then STATIC_PRPLS=`echo $STATIC_PRPLS | $sedpath 's/silc//'` fi +if test "x$have_libgadu" != "xyes" ; then + STATIC_PRPLS=`echo $STATIC_PRPLS | $sedpath 's/gg//'` +fi if test "x$is_win32" = "xyes" ; then STATIC_PRPLS=`echo $STATIC_PRPLS | $sedpath 's/zephyr//'` fi @@ -1333,6 +1316,9 @@ if test "x$silcincludes" != "xyes" -o "x$silcclient" != "xyes"; then DYNAMIC_PRPLS=`echo $DYNAMIC_PRPLS | $sedpath 's/silc//'` fi +if test "x$have_libgadu" != "xyes"; then + DYNAMIC_PRPLS=`echo $DYNAMIC_PRPLS | $sedpath 's/gg//'` +fi if test "x$is_win32" = "xyes" ; then DYNAMIC_PRPLS=`echo $DYNAMIC_PRPLS | $sedpath 's/zephyr//'` fi @@ -2254,7 +2240,6 @@ echo Build with Cyrus SASL support. : $enable_cyrus_sasl echo Use kerberos 4 with zephyr.... : $kerberos echo Use external libzephyr........ : $zephyr -echo Use external libgadu.......... : $have_libgadu echo Install pixmaps............... : $enable_pixmaps echo Old tray icon compatibility... : $enable_traycompat echo Install translations.......... : $enable_i18n
--- a/libpurple/protocols/gg/Makefile.am Wed Sep 28 09:32:19 2016 -0500 +++ b/libpurple/protocols/gg/Makefile.am Wed Sep 28 16:07:11 2016 -0500 @@ -3,64 +3,9 @@ EXTRA_DIST = \ account.c \ account.h \ - Makefile.mingw \ - lib/COPYING - -if ! HAVE_LIBGADU -INTGG_SOURCES = \ - lib/common.c \ - lib/config.h \ - lib/dcc.c \ - lib/dcc7.c \ - lib/debug.c \ - lib/debug.h \ - lib/deflate.c \ - lib/deflate.h \ - lib/encoding.c \ - lib/encoding.h \ - lib/endian.c \ - lib/events.c \ - lib/fileio.h \ - lib/handlers.c \ - lib/http.c \ - lib/internal.h \ - lib/libgadu.c \ - lib/libgadu.h \ - lib/message.c \ - lib/message.h \ - lib/network.c \ - lib/network.h \ - lib/obsolete.c \ - lib/packets.pb-c.c \ - lib/packets.pb-c.h \ - lib/protobuf-c.c \ - lib/protobuf-c.h \ - lib/protobuf.c \ - lib/protobuf.h \ - lib/protocol.h \ - lib/pubdir.c \ - lib/pubdir50.c \ - lib/resolver.c \ - lib/resolver.h \ - lib/session.h \ - lib/strman.h \ - lib/sha1.c \ - lib/tvbuff.c \ - lib/tvbuff.h \ - lib/tvbuilder.c \ - lib/tvbuilder.h - -INTGG_LIBS = $(ZLIB_LIBS) $(GNUTLS_LIBS) -INTGG_CFLAGS = \ - -I$(top_srcdir)/libpurple/protocols/gg/lib \ - $(ZLIB_CFLAGS) \ - $(GNUTLS_CFLAGS) \ - -DGG_IGNORE_DEPRECATED - -endif + Makefile.mingw GGSOURCES = \ - $(INTGG_SOURCES) \ avatar.c \ avatar.h \ blist.c \ @@ -131,13 +76,12 @@ endif -libgg_la_LIBADD = @PURPLE_LIBS@ $(LIBGADU_LIBS) $(INTGG_LIBS) $(JSON_LIBS) +libgg_la_LIBADD = @PURPLE_LIBS@ $(LIBGADU_LIBS) $(JSON_LIBS) AM_CPPFLAGS = \ -I$(top_srcdir)/libpurple \ -I$(top_builddir)/libpurple \ $(LIBGADU_CFLAGS) \ - $(INTGG_CFLAGS) \ $(GLIB_CFLAGS) \ $(JSON_CFLAGS) \ $(GPLUGIN_CFLAGS) \
--- a/libpurple/protocols/gg/lib/COPYING Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 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 Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - 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 Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -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 and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -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 other code 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. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - 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, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser 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 combine 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) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) 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. - - d) 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. - - e) 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 materials to be 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 with -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 Lesser 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 - - 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 Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 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. - - You should have received a copy of the GNU Lesser 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! - -
--- a/libpurple/protocols/gg/lib/common.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,882 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl> - * Robert J. Woźny <speedy@ziew.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file common.c - * - * \brief Funkcje wykorzystywane przez różne moduły biblioteki - */ - -#include "network.h" -#include "strman.h" -#include "fileio.h" - -#include <errno.h> -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <time.h> - -#include "config.h" -#include "libgadu.h" -#include "internal.h" - -#ifndef GG_CONFIG_HAVE_VA_COPY -# ifdef GG_CONFIG_HAVE___VA_COPY -# define va_copy(dest, src) __va_copy((dest), (src)) -# else -/* Taka wersja va_copy() działa poprawnie tylko na platformach, które - * va_copy() de facto wcale nie potrzebują, np. MSVC. Definicja tylko dla - * przejrzystości kodu. */ -# define va_copy(dest, src) (dest) = (src) -# endif -#endif - -/** - * \internal Odpowiednik funkcji \c vsprintf alokujący miejsce na wynik. - * - * Funkcja korzysta z funkcji \c vsnprintf, sprawdzając czy dostępna funkcja - * systemowa jest zgodna ze standardem C99 czy wcześniejszymi. - * - * \param format Format wiadomości (zgodny z \c printf) - * \param ap Lista argumentów (zgodna z \c printf) - * - * \return Zaalokowany bufor lub NULL, jeśli zabrakło pamięci. - * - * \ingroup helper - */ -char *gg_vsaprintf(const char *format, va_list ap) -{ - int size; - char *buf = NULL; - va_list aq; - -#if !defined(GG_CONFIG_HAVE_C99_VSNPRINTF) && !defined(HAVE__VSCPRINTF) - { - int res = 0; - char *tmp; - - size = 128; - do { - if (res > size) { - /* Jednak zachowanie zgodne z C99. */ - size = res + 1; - } else { - size *= 2; - } - - if (!(tmp = realloc(buf, size))) { - free(buf); - return NULL; - } - - buf = tmp; - va_copy(aq, ap); - res = vsnprintf(buf, size, format, aq); - va_end(aq); - } while (res >= size || res < 0); - } -#else - va_copy(aq, ap); - -# ifdef HAVE__VSCPRINTF - size = _vscprintf(format, aq) + 1; -# else - { - char tmp[2]; - - /* libce Solarisa przy buforze NULL zawsze zwracają -1, więc - * musimy podać coś istniejącego jako cel printf()owania. */ - size = vsnprintf(tmp, sizeof(tmp), format, aq) + 1; - } -# endif - va_end(aq); - if (!(buf = malloc(size))) - return NULL; - - vsnprintf(buf, size, format, ap); -#endif - - return buf; -} - -/** - * \internal Odpowiednik funkcji \c sprintf alokujący miejsce na wynik. - * - * Funkcja korzysta z funkcji \c vsnprintf, sprawdzając czy dostępna funkcja - * systemowa jest zgodna ze standardem C99 czy wcześniejszymi. - * - * \param format Format wiadomości (zgodny z \c printf) - * - * \return Zaalokowany bufor lub NULL, jeśli zabrakło pamięci. - * - * \ingroup helper - */ -char *gg_saprintf(const char *format, ...) -{ - va_list ap; - char *res; - - va_start(ap, format); - res = gg_vsaprintf(format, ap); - va_end(ap); - - return res; -} - -/** - * \internal Pobiera linię tekstu z bufora. - * - * Funkcja niszczy bufor źródłowy bezpowrotnie, dzieląc go na kolejne ciągi - * znaków i obcina znaki końca linii. - * - * \param ptr Wskaźnik do zmiennej, która przechowuje aktualne położenie - * w analizowanym buforze - * - * \note Funkcja nie jest już używana. Pozostała dla zachowania ABI. - * - * \return Wskaźnik do kolejnej linii tekstu lub NULL, jeśli to już koniec - * bufora. - */ -char *gg_get_line(char **ptr) -{ - char *foo, *res; - - if (!ptr || !*ptr || !strcmp(*ptr, "")) - return NULL; - - res = *ptr; - - if (!(foo = strchr(*ptr, '\n'))) - *ptr += strlen(*ptr); - else { - size_t len; - *ptr = foo + 1; - *foo = 0; - - len = strlen(res); - - if (len > 1 && res[len - 1] == '\r') - res[len - 1] = 0; - } - - return res; -} - -/** - * \internal Czyta linię tekstu z gniazda. - * - * Funkcja czyta tekst znak po znaku, więc nie jest efektywna, ale dzięki - * brakowi buforowania, nie koliduje z innymi funkcjami odczytu. - * - * \note W przypadku zakończenia połączenia przez drugą stronę, ostatnia - * linia nie jest zwracana. - * - * \param sock Deskryptor gniazda - * \param buf Wskaźnik do bufora - * \param length Długość bufora - * - * \return Zwraca wskaźnik na koniec odebranej linii jeśli się powiodło, - * lub \c NULL w przypadku błędu. - */ -char *gg_read_line(int sock, char *buf, int length) -{ - int ret; - - if (!buf || length < 0) - return NULL; - - for (; length > 1; buf++, length--) { - do { - if ((ret = recv(sock, buf, 1, 0)) == -1 && - errno != EINTR && errno != EAGAIN) - { - gg_debug(GG_DEBUG_MISC, "// gg_read_line() " - "error on read (errno=%d, %s)\n", - errno, strerror(errno)); - *buf = 0; - return NULL; - } else if (ret == 0) { - gg_debug(GG_DEBUG_MISC, "// gg_read_line() " - "eof reached\n"); - *buf = 0; - return NULL; - } - } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); - - if (*buf == '\n') { - buf++; - break; - } - } - - *buf = 0; - return buf; -} - -/** - * \internal Nawiązuje połączenie TCP. - * - * \param addr Wskaźnik na strukturę \c in_addr z adresem serwera - * \param port Port serwera - * \param async Flaga asynchronicznego połączenia - * - * \return Deskryptor gniazda lub -1 w przypadku błędu - * - * \ingroup helper - */ -int gg_connect(void *addr, int port, int async) -{ - int sock, errno2; - struct sockaddr_in sin; - struct in_addr *a = addr; - struct sockaddr_in myaddr; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_connect(%s, %d, %d);\n", - inet_ntoa(*a), port, async); - - if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_connect() socket() failed " - "(errno=%d, %s)\n", errno, strerror(errno)); - return -1; - } - - memset(&myaddr, 0, sizeof(myaddr)); - myaddr.sin_family = AF_INET; - - myaddr.sin_addr.s_addr = gg_local_ip; - - if (bind(sock, (struct sockaddr *) &myaddr, sizeof(myaddr)) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_connect() bind() failed " - "(errno=%d, %s)\n", errno, strerror(errno)); - errno2 = errno; - close(sock); - errno = errno2; - return -1; - } - - if (async) { - if (!gg_fd_set_nonblocking(sock)) { - gg_debug(GG_DEBUG_MISC, "// gg_connect() can't set " - "nonblocking (errno=%d, %s)\n", - errno, strerror(errno)); - errno2 = errno; - close(sock); - errno = errno2; - return -1; - } - } - - memset(&sin, 0, sizeof(sin)); - sin.sin_port = htons(port); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = a->s_addr; - - if (connect(sock, (struct sockaddr*) &sin, sizeof(sin)) == -1) { - if (errno && (!async || errno != EINPROGRESS)) { - gg_debug(GG_DEBUG_MISC, "// gg_connect() connect() " - "failed (errno=%d, %s)\n", - errno, strerror(errno)); - errno2 = errno; - close(sock); - errno = errno2; - return -1; - } - gg_debug(GG_DEBUG_MISC, - "// gg_connect() connect() in progress\n"); - } - - return sock; -} - -/** - * \internal Usuwa znaki końca linii. - * - * Funkcja działa bezpośrednio na buforze. - * - * \param line Bufor z tekstem - * - * \ingroup helper - */ -void gg_chomp(char *line) -{ - int len; - - if (!line) - return; - - len = strlen(line); - - if (len > 0 && line[len - 1] == '\n') - line[--len] = 0; - if (len > 0 && line[len - 1] == '\r') - line[--len] = 0; -} - -/** - * \internal Koduje ciąg znaków do postacji adresu HTTP. - * - * Zamienia znaki niedrukowalne, spoza ASCII i mające specjalne znaczenie - * dla protokołu HTTP na encje postaci \c %XX, gdzie \c XX jest szesnastkową - * wartością znaku. - * - * \param str Ciąg znaków do zakodowania - * - * \return Zaalokowany bufor lub \c NULL w przypadku błędu. - * - * \ingroup helper - */ -char *gg_urlencode(const char *str) -{ - char *q, *buf; - const char hex[] = "0123456789abcdef"; - const char *p; - unsigned int size = 0; - - if (!str) - str = ""; - - for (p = str; *p; p++, size++) { - if (!((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || - (*p >= '0' && *p <= '9') || *p == ' ') || (*p == '@') || - (*p == '.') || (*p == '-')) - { - size += 2; - } - } - - if (!(buf = malloc(size + 1))) - return NULL; - - for (p = str, q = buf; *p; p++, q++) { - if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || - (*p >= '0' && *p <= '9') || (*p == '@') || - (*p == '.') || (*p == '-')) - { - *q = *p; - } else { - if (*p == ' ') - *q = '+'; - else { - *q++ = '%'; - *q++ = hex[*p >> 4 & 15]; - *q = hex[*p & 15]; - } - } - } - - *q = 0; - - return buf; -} - -/** - * \internal Wyznacza skrót dla usług HTTP. - * - * Funkcja jest wykorzystywana do wyznaczania skrótu adresu e-mail, hasła - * i innych wartości przekazywanych jako parametry usług HTTP. - * - * W parametrze \c format należy umieścić znaki określające postać kolejnych - * parametrów: \c 's' jeśli parametr jest ciągiem znaków, \c 'u' jeśli jest - * liczbą. - * - * \param format Format kolejnych parametrów (niezgodny z \c printf) - * - * \return Wartość skrótu - */ -int gg_http_hash(const char *format, ...) -{ - unsigned int a, c, i, j; - va_list ap; - int b = -1; - - va_start(ap, format); - - for (j = 0; j < strlen(format); j++) { - const char *arg; - char buf[16]; - - if (format[j] == 'u') { - snprintf(buf, sizeof(buf), "%d", va_arg(ap, uin_t)); - arg = buf; - } else { - if (!(arg = va_arg(ap, char*))) - arg = ""; - } - - i = 0; - while ((c = (unsigned char) arg[i++]) != 0) { - a = (c ^ b) + (c << 8); - b = (a >> 24) | (a << 8); - } - } - - va_end(ap); - - return (b < 0 ? -b : b); -} - -/** - * \internal Zestaw znaków kodowania base64. - */ -static char gg_base64_charset[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -/** - * \internal Koduje ciąg znaków do base64. - * - * Wynik funkcji należy zwolnić za pomocą \c free. - * - * \param buf Bufor z danami do zakodowania - * - * \return Zaalokowany bufor z zakodowanymi danymi - * - * \ingroup helper - */ -char *gg_base64_encode(const char *buf) -{ - char *out, *res; - unsigned int i = 0, j = 0, k = 0, len = strlen(buf); - - res = out = malloc((len / 3 + 1) * 4 + 2); - - if (!res) - return NULL; - - while (j <= len) { - switch (i % 4) { - case 0: - k = (buf[j] & 252) >> 2; - break; - case 1: - if (j < len) - k = ((buf[j] & 3) << 4) | ((buf[j + 1] & 240) >> 4); - else - k = (buf[j] & 3) << 4; - - j++; - break; - case 2: - if (j < len) - k = ((buf[j] & 15) << 2) | ((buf[j + 1] & 192) >> 6); - else - k = (buf[j] & 15) << 2; - - j++; - break; - case 3: - k = buf[j++] & 63; - break; - } - *out++ = gg_base64_charset[k]; - i++; - } - - if (i % 4) - for (j = 0; j < 4 - (i % 4); j++, out++) - *out = '='; - - *out = 0; - - return res; -} - -/** - * \internal Dekoduje ciąg znaków zapisany w base64. - * - * Wynik funkcji należy zwolnić za pomocą \c free. - * - * \param buf Bufor źródłowy z danymi do zdekodowania - * - * \return Zaalokowany bufor ze zdekodowanymi danymi - * - * \ingroup helper - */ -char *gg_base64_decode(const char *buf) -{ - char *res, *save, *foo, val; - const char *end; - unsigned int idx = 0; - - if (!buf) - return NULL; - - save = res = calloc(1, (strlen(buf) / 4 + 1) * 3 + 2); - - if (!save) - return NULL; - - end = buf + strlen(buf); - - while (*buf && buf < end) { - if (*buf == '\r' || *buf == '\n') { - buf++; - continue; - } - if (!(foo = memchr(gg_base64_charset, *buf, sizeof(gg_base64_charset)))) - foo = gg_base64_charset; - val = (int)(foo - gg_base64_charset); - buf++; - switch (idx) { - case 0: - *res |= val << 2; - break; - case 1: - *res++ |= val >> 4; - *res |= val << 4; - break; - case 2: - *res++ |= val >> 2; - *res |= val << 6; - break; - case 3: - *res++ |= val; - break; - } - idx++; - idx %= 4; - } - *res = 0; - - return save; -} - -/** - * \internal Tworzy nagłówek autoryzacji serwera pośredniczącego. - * - * Dane pobiera ze zmiennych globalnych \c gg_proxy_username i - * \c gg_proxy_password. - * - * \return Zaalokowany bufor z tekstem lub NULL, jeśli serwer pośredniczący - * nie jest używany lub nie wymaga autoryzacji. - */ -char *gg_proxy_auth(void) -{ - char *tmp, *enc, *out; - unsigned int tmp_size; - - if (!gg_proxy_enabled || !gg_proxy_username || !gg_proxy_password) - return NULL; - - tmp_size = strlen(gg_proxy_username) + strlen(gg_proxy_password) + 2; - tmp = malloc(tmp_size); - if (!tmp) - return NULL; - - snprintf(tmp, tmp_size, "%s:%s", gg_proxy_username, gg_proxy_password); - - enc = gg_base64_encode(tmp); - if (!enc) { - free(tmp); - return NULL; - } - - free(tmp); - - out = malloc(strlen(enc) + 40); - if (!out) { - free(enc); - return NULL; - } - - snprintf(out, strlen(enc) + 40, "Proxy-Authorization: Basic %s\r\n", enc); - - free(enc); - - return out; -} - -/** - * \internal Tablica pomocnicza do wyznaczania sumy kontrolnej. - */ -static const uint32_t gg_crc32_table[256] = -{ - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, - 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, - 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, - 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, - 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, - 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, - 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, - 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, - 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, - 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, - 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, - 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, - 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, - 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, - 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, - 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, - 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, - 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, - 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, - 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, - 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, - 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, - 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, - 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, - 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, - 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, - 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, - 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, - 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, - 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, - 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, - 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, - 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, - 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, - 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, - 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, - 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, - 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, - 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d -}; - -/** - * Wyznacza sumę kontrolną CRC32. - * - * \param crc Suma kontrola poprzedniego bloku danych lub 0 jeśli liczona - * jest suma kontrolna pierwszego bloku - * \param buf Bufor danych - * \param len Długość bufora danych - * - * \return Suma kontrolna. - */ -uint32_t gg_crc32(uint32_t crc, const unsigned char *buf, int len) -{ - if (buf == NULL || len < 0) - return crc; - - crc ^= 0xffffffffL; - - while (len--) - crc = (crc >> 8) ^ gg_crc32_table[(crc ^ *buf++) & 0xff]; - - return crc ^ 0xffffffffL; -} - -/** - * \internal Parsuje identyfikator użytkownika. - * - * \param str Ciąg tekstowy, zawierający identyfikator - * \param len Długość identyfikatora - * - * \return Identyfikator, lub 0, jeżeli nie udało się odczytać - */ -uin_t gg_str_to_uin(const char *str, int len) -{ - char buff[11]; - char *endptr; - uin_t uin; - - if (len < 0) - len = strlen(str); - if (len > 10) - return 0; - memcpy(buff, str, len); - buff[len] = '\0'; - - errno = 0; - uin = strtoul(buff, &endptr, 10); - if (errno == ERANGE || endptr[0] != '\0') - return 0; - - return uin; -} - -/** - * Szuka informacji o konferencji o podanym identyfikatorze. - * - * \param sess Struktura sesji - * \param id Identyfikator konferencji - * - * \return Struktura z informacjami o konferencji - */ -gg_chat_list_t *gg_chat_find(struct gg_session *sess, uint64_t id) -{ - gg_chat_list_t *chat_list = sess->private_data->chat_list; - - while (chat_list != NULL) { - if (chat_list->id == id) - return chat_list; - chat_list = chat_list->next; - } - - return NULL; -} - -/** - * \internal Aktualizuje informacje o konferencji. - * - * \param sess Struktura sesji - * \param id Identyfikator konferencji - * \param version Wersja informacji o konferencji - * \param participants Lista uczestników konferencji - * \param participants_count Ilość uczestników konferencji - * - * \return Wartość równa 0, jeżeli zakończono powodzeniem - */ -int gg_chat_update(struct gg_session *sess, uint64_t id, uint32_t version, - const uin_t *participants, unsigned int participants_count) -{ - gg_chat_list_t *chat; - uin_t *participants_new; - - if (participants_count >= ~(unsigned int)0 / sizeof(uin_t)) - return -1; - - chat = gg_chat_find(sess, id); - - if (!chat) { - chat = malloc(sizeof(gg_chat_list_t)); - - if (!chat) - return -1; - - memset(chat, 0, sizeof(gg_chat_list_t)); - chat->id = id; - chat->next = sess->private_data->chat_list; - sess->private_data->chat_list = chat; - } - - participants_new = realloc(chat->participants, - sizeof(uin_t) * participants_count); - - if (participants_new == NULL) - return -1; - - chat->version = version; - chat->participants = participants_new; - chat->participants_count = participants_count; - memcpy(chat->participants, participants, - sizeof(uin_t) * participants_count); - - return 0; -} - -void gg_connection_failure(struct gg_session *gs, struct gg_event *ge, - enum gg_failure_t failure) -{ - gg_close(gs); - - if (ge != NULL) { - ge->type = GG_EVENT_CONN_FAILED; - ge->event.failure = failure; - } - gs->state = GG_STATE_IDLE; -} - -time_t gg_server_time(struct gg_session *gs) -{ - time_t now = time(NULL); - - if (gs == NULL || gs->private_data == NULL) { - gg_debug_session(gs, GG_DEBUG_ERROR, "time diff data is not " - "accessible\n"); - return now; - } - - return now + gs->private_data->time_diff; -} - -void gg_strarr_free(char **strarr) -{ - char **it; - - if (strarr == NULL) - return; - - for (it = strarr; *it != NULL; it++) - free(*it); - free(strarr); -} - -char ** gg_strarr_dup(char **strarr) -{ - size_t i, len, size; - char **it, **out; - - if (strarr == NULL) - return NULL; - - len = 0; - for (it = strarr; *it != NULL; it++) - len++; - - size = (len + 1) * sizeof(char*); - out = malloc(size); - - if (out == NULL) { - gg_debug(GG_DEBUG_MISC | GG_DEBUG_ERROR, "// gg_strarr_dup() " - "not enough memory for the array\n"); - return NULL; - } - memset(out, 0, size); - - for (i = 0; i < len; i++) { - out[i] = strdup(strarr[i]); - if (out[i] == NULL) { - gg_debug(GG_DEBUG_MISC | GG_DEBUG_ERROR, - "// gg_strarr_dup() " - "not enough memory for the array element\n"); - gg_strarr_free(out); - return NULL; - } - } - - return out; -} - -/* - * Local variables: - * c-indentation-style: k&r - * c-basic-offset: 8 - * indent-tabs-mode: notnil - * End: - * - * vim: shiftwidth=8: - */
--- a/libpurple/protocols/gg/lib/config.h Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ -/* Local libgadu configuration file. */ - -#undef printf - -/* libpurple's config */ -#include <config.h> - -#define GG_LIBGADU_VERSION "1.12.1" - -/* Defined if libgadu was compiled for bigendian machine. */ -#undef GG_CONFIG_BIGENDIAN -#ifdef WORDS_BIGENDIAN -# define GG_CONFIG_BIGENDIAN -#endif - -/* Defined if this machine has gethostbyname_r(). */ -#undef GG_CONFIG_HAVE_GETHOSTBYNAME_R - -/* Define to 1 if you have the `_exit' function. */ -#define HAVE__EXIT 1 - -/* Defined if libgadu was compiled and linked with fork support. */ -#undef GG_CONFIG_HAVE_FORK -#ifndef _WIN32 -# define GG_CONFIG_HAVE_FORK -#endif - -/* Defined if libgadu was compiled and linked with pthread support. */ -/* We don't use pthreads - they may not be safe. */ -#undef GG_CONFIG_HAVE_PTHREAD - -/* Defined if this machine has C99-compiliant vsnprintf(). */ -#undef HAVE_C99_VSNPRINTF -#if !defined(_WIN32) || (defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR >= 3) -# define HAVE_C99_VSNPRINTF -#endif - -/* Defined if this machine has va_copy(). */ -#define GG_CONFIG_HAVE_VA_COPY - -/* Defined if this machine has __va_copy(). */ -#define GG_CONFIG_HAVE___VA_COPY - -/* Defined if this machine supports long long. */ -#undef GG_CONFIG_HAVE_LONG_LONG -#ifdef HAVE_LONG_LONG -# define GG_CONFIG_HAVE_LONG_LONG -#endif - -/* Defined if libgadu was compiled and linked with GnuTLS support. */ -#undef GG_CONFIG_HAVE_GNUTLS -#if defined(HAVE_GNUTLS) && defined(HAVE_GNUTLS_2_10) -# define GG_CONFIG_HAVE_GNUTLS -#endif - -/* Defined if libgadu was compiled and linked with OpenSSL support. */ -/* OpenSSL cannot be used with libpurple due to licence type. */ -#undef GG_CONFIG_HAVE_OPENSSL - -/* Defined if libgadu was compiled and linked with zlib support. */ -#define GG_CONFIG_HAVE_ZLIB - -/* Defined if uintX_t types are defined in <stdint.h>. */ -#undef GG_CONFIG_HAVE_STDINT_H -#ifdef HAVE_STDINT_H -# define GG_CONFIG_HAVE_STDINT_H -#endif - -/* Defined if uintX_t types are defined in <inttypes.h>. */ -#undef GG_CONFIG_HAVE_INTTYPES_H -#ifdef HAVE_INTTYPES_H -# define GG_CONFIG_HAVE_INTTYPES_H -#endif - -/* Defined if uintX_t types are defined in <sys/types.h>. */ -#undef GG_CONFIG_HAVE_SYS_TYPES_H -#ifdef HAVE_SYS_TYPES_H -# define GG_CONFIG_HAVE_SYS_TYPES_H -#endif - -/* Defined if this machine has uint64_t. */ -#define GG_CONFIG_HAVE_UINT64_T - -/* Defined if libgadu is GPL compliant (was not linked with OpenSSL or any - * other non-GPL compliant library support). */ -#define GG_CONFIG_IS_GPL_COMPLIANT - -/* Defined if libgadu uses system defalt trusted CAs. */ -#define GG_CONFIG_SSL_SYSTEM_TRUST - -/* Defined if libgadu is GPL compliant (was not linked with OpenSSL or any - other non-GPL compliant library support). */ -#define GG_CONFIG_IS_GPL_COMPLIANT
--- a/libpurple/protocols/gg/lib/dcc.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1410 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2001-2008 Wojtek Kaniewski <wojtekka@irc.pl> - * Tomasz Chiliński <chilek@chilan.com> - * Adam Wysocki <gophi@ekg.chmurka.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file dcc.c - * - * \brief Obsługa połączeń bezpośrednich do wersji Gadu-Gadu 6.x - */ - -#include "fileio.h" -#include "network.h" - -#include <ctype.h> -#include <errno.h> -#include <string.h> -#include <stdlib.h> - -#include "libgadu.h" -#include "debug.h" -#include "internal.h" - -/** - * \internal Przekazuje zawartość pakietu do odpluskwiania. - * - * \param prefix Prefiks informacji - * \param fd Deskryptor gniazda - * \param buf Bufor z danumi - * \param size Rozmiar bufora z danymi - */ -static void gg_dcc_debug_data(const char *prefix, int fd, const void *buf, unsigned int size) -{ - gg_debug(GG_DEBUG_MISC, "++ gg_dcc %s (fd=%d,len=%d)", prefix, fd, size); - gg_debug_dump(NULL, GG_DEBUG_DUMP, buf, size); - gg_debug(GG_DEBUG_MISC, "\n"); -} - -/** - * Wysyła żądanie zwrotnego połączenia bezpośredniego. - * - * Funkcję wykorzystuje się, jeśli nie ma możliwości połączenia się z odbiorcą - * pliku lub rozmowy głosowej. Po otrzymaniu żądania druga strona spróbuje - * nawiązać zwrotne połączenie bezpośrednie z nadawcą. - * gg_dcc_request() - * - * \param sess Struktura sesji - * \param uin Numer odbiorcy - * - * \return Patrz \c gg_send_message_ctcp() - * - * \ingroup dcc6 - */ -int gg_dcc_request(struct gg_session *sess, uin_t uin) -{ - return gg_send_message_ctcp(sess, GG_CLASS_CTCP, uin, (const unsigned char*) "\002", 1); -} - -/** - * \internal Zamienia znacznik czasu w postaci uniksowej na format API WIN32. - * - * \note Funkcja działa jedynie gdy kompilator obsługuje typ danych - * \c long \c long. - * - * \param ut Czas w postaci uniksowej - * \param ft Czas w postaci API WIN32 - */ -static void gg_dcc_fill_filetime(uint32_t ut, uint32_t *ft) -{ - uint64_t tmp; - - tmp = ut; - tmp += 11644473600LL; - tmp *= 10000000LL; - - tmp = gg_fix64(tmp); - - memcpy(ft, &tmp, sizeof(tmp)); -} - -/** - * Wypełnia pola struktury \c gg_dcc niezbędne do wysłania pliku. - * - * \note Większą funkcjonalność zapewnia funkcja \c gg_dcc_fill_file_info2(). - * - * \param d Struktura połączenia - * \param filename Nazwa pliku - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup dcc6 - */ -int gg_dcc_fill_file_info(struct gg_dcc *d, const char *filename) -{ - return gg_dcc_fill_file_info2(d, filename, filename); -} - -/** - * Wypełnia pola struktury \c gg_dcc niezbędne do wysłania pliku. - * - * \param d Struktura połączenia - * \param filename Nazwa pliku zapisywana w strukturze - * \param local_filename Nazwa pliku w lokalnym systemie plików - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup dcc6 - */ -int gg_dcc_fill_file_info2(struct gg_dcc *d, const char *filename, const char *local_filename) -{ - struct stat st; - const char *name, *ext, *p; - unsigned char *q; - int i, j; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_fill_file_info2(%p, \"%s\", \"%s\");\n", d, filename, local_filename); - - if (!d || d->type != GG_SESSION_DCC_SEND) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() invalid arguments\n"); - errno = EINVAL; - return -1; - } - - if ((d->file_fd = open(local_filename, O_RDONLY)) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() open() failed (%s)\n", strerror(errno)); - return -1; - } - - if (fstat(d->file_fd, &st) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() " - "fstat() failed (%s)\n", strerror(errno)); - close(d->file_fd); - d->file_fd = -1; - return -1; - } - - if ((st.st_mode & S_IFDIR)) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() that's a directory\n"); - errno = EINVAL; - close(d->file_fd); - d->file_fd = -1; - return -1; - } - - memset(&d->file_info, 0, sizeof(d->file_info)); - - if (!(st.st_mode & S_IWUSR)) - d->file_info.mode |= gg_fix32(GG_DCC_FILEATTR_READONLY); - - gg_dcc_fill_filetime(st.st_atime, d->file_info.atime); - gg_dcc_fill_filetime(st.st_mtime, d->file_info.mtime); - gg_dcc_fill_filetime(st.st_ctime, d->file_info.ctime); - - d->file_info.size = gg_fix32(st.st_size); - d->file_info.mode = gg_fix32(0x20); /* FILE_ATTRIBUTE_ARCHIVE */ - - if (!(name = strrchr(filename, '/'))) - name = filename; - else - name++; - - if (!(ext = strrchr(name, '.'))) - ext = name + strlen(name); - - for (i = 0, p = name; i < 8 && p < ext; i++, p++) - d->file_info.short_filename[i] = toupper(name[i]); - - if (i == 8 && p < ext) { - d->file_info.short_filename[6] = '~'; - d->file_info.short_filename[7] = '1'; - } - - if (strlen(ext) > 0) { - for (j = 0; *ext && j < 4; j++, p++) - d->file_info.short_filename[i + j] = toupper(ext[j]); - } - - for (q = d->file_info.short_filename; *q; q++) { - if (*q == 185) { - *q = 165; - } else if (*q == 230) { - *q = 198; - } else if (*q == 234) { - *q = 202; - } else if (*q == 179) { - *q = 163; - } else if (*q == 241) { - *q = 209; - } else if (*q == 243) { - *q = 211; - } else if (*q == 156) { - *q = 140; - } else if (*q == 159) { - *q = 143; - } else if (*q == 191) { - *q = 175; - } - } - - gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() short name \"%s\"," - " dos name \"%s\"\n", name, d->file_info.short_filename); - strncpy((char*) d->file_info.filename, name, sizeof(d->file_info.filename) - 1); - - return 0; -} - -/** - * \internal Rozpoczyna połączenie bezpośrednie z danym klientem. - * - * \param ip Adres IP odbiorcy - * \param port Port odbiorcy - * \param my_uin Własny numer - * \param peer_uin Numer odbiorcy - * \param type Rodzaj połączenia (\c GG_SESSION_DCC_SEND lub \c GG_SESSION_DCC_GET) - * - * \return Struktura \c gg_dcc lub \c NULL w przypadku błędu - */ -static struct gg_dcc *gg_dcc_transfer(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin, int type) -{ - struct gg_dcc *d = NULL; - struct in_addr addr; - - addr.s_addr = ip; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_transfer(%s, %d, %u, %u, " - "%s);\n", inet_ntoa(addr), port, my_uin, peer_uin, - (type == GG_SESSION_DCC_SEND) ? "SEND" : "GET"); - - if (!ip || ip == INADDR_NONE || !port || !my_uin || !peer_uin) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_transfer() invalid arguments\n"); - errno = EINVAL; - return NULL; - } - - if (!(d = (void*) calloc(1, sizeof(*d)))) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_transfer() not enough memory\n"); - return NULL; - } - - d->check = GG_CHECK_WRITE; - d->state = GG_STATE_CONNECTING; - d->type = type; - d->timeout = GG_DEFAULT_TIMEOUT; - d->file_fd = -1; - d->active = 1; - d->fd = -1; - d->uin = my_uin; - d->peer_uin = peer_uin; - - if ((d->fd = gg_connect(&addr, port, 1)) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_transfer() connection failed\n"); - free(d); - return NULL; - } - - return d; -} - -/** - * Rozpoczyna odbieranie pliku przez zwrotne połączenie bezpośrednie. - * - * \param ip Adres IP nadawcy - * \param port Port nadawcy - * \param my_uin Własny numer - * \param peer_uin Numer nadawcy - * - * \return Struktura \c gg_dcc lub \c NULL w przypadku błędu - * - * \ingroup dcc6 - */ -struct gg_dcc *gg_dcc_get_file(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin) -{ - gg_debug(GG_DEBUG_MISC, "// gg_dcc_get_file() handing over to gg_dcc_transfer()\n"); - - return gg_dcc_transfer(ip, port, my_uin, peer_uin, GG_SESSION_DCC_GET); -} - -/** - * Rozpoczyna wysyłanie pliku. - * - * \param ip Adres IP odbiorcy - * \param port Port odbiorcy - * \param my_uin Własny numer - * \param peer_uin Numer odbiorcy - * - * \return Struktura \c gg_dcc lub \c NULL w przypadku błędu - * - * \ingroup dcc6 - */ -struct gg_dcc *gg_dcc_send_file(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin) -{ - gg_debug(GG_DEBUG_MISC, "// gg_dcc_send_file() handing over to gg_dcc_transfer()\n"); - - return gg_dcc_transfer(ip, port, my_uin, peer_uin, GG_SESSION_DCC_SEND); -} - -/** - * Rozpoczyna połączenie głosowe. - * - * \param ip Adres IP odbiorcy - * \param port Port odbiorcy - * \param my_uin Własny numer - * \param peer_uin Numer odbiorcy - * - * \return Struktura \c gg_dcc lub \c NULL w przypadku błędu - * - * \ingroup dcc6 - */ -struct gg_dcc *gg_dcc_voice_chat(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin) -{ - gg_debug(GG_DEBUG_MISC, "// gg_dcc_voice_chat() handing over to gg_dcc_transfer()\n"); - - return gg_dcc_transfer(ip, port, my_uin, peer_uin, GG_SESSION_DCC_VOICE); -} - -/** - * Ustawia typ przychodzącego połączenia bezpośredniego. - * - * Funkcję należy wywołać po otrzymaniu zdarzenia \c GG_EVENT_DCC_CALLBACK. - * - * \param d Struktura połączenia - * \param type Rodzaj połączenia (\c GG_SESSION_DCC_SEND lub - * \c GG_SESSION_DCC_VOICE) - * - * \ingroup dcc6 - */ -void gg_dcc_set_type(struct gg_dcc *d, int type) -{ - d->type = type; - d->state = (type == GG_SESSION_DCC_SEND) ? GG_STATE_SENDING_FILE_INFO : GG_STATE_SENDING_VOICE_REQUEST; -} - -/** - * \internal Funkcja zwrotna połączenia bezpośredniego. - * - * Pole \c callback struktury \c gg_dcc zawiera wskaźnik do tej funkcji. - * Wywołuje ona \c gg_dcc_watch_fd() i zachowuje wynik w polu \c event. - * - * \note Funkcjonalność funkcji zwrotnej nie jest już wspierana. - * - * \param d Struktura połączenia - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -static int gg_dcc_callback(struct gg_dcc *d) -{ - struct gg_event *e = gg_dcc_watch_fd(d); - - d->event = e; - - return (e != NULL) ? 0 : -1; -} - -/** - * Tworzy gniazdo nasłuchujące dla połączeń bezpośrednich. - * - * Funkcja przywiązuje gniazdo do pierwszego wolnego portu TCP. - * - * \param uin Własny numer - * \param port Preferowany port (jeśli równy 0 lub -1, próbuje się domyślnego) - * - * \note Ze względu na możliwość podania wartości -1 do parametru będącego - * 16-bitową liczbą bez znaku, port 65535 nie jest dostępny. - * - * \return Struktura \c gg_dcc lub \c NULL w przypadku błędu - * - * \ingroup dcc6 - */ -struct gg_dcc *gg_dcc_socket_create(uin_t uin, uint16_t port) -{ - struct gg_dcc *c; - int sock, bound = 0, errno2; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_create_dcc_socket(%d, %d);\n", uin, port); - - if (!uin) { - gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() invalid arguments\n"); - errno = EINVAL; - return NULL; - } - - if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() can't create socket (%s)\n", strerror(errno)); - return NULL; - } - - if (port == 0 || port == (uint16_t)-1) - port = GG_DEFAULT_DCC_PORT; - - while (!bound) { - struct sockaddr_in sin; - - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = INADDR_ANY; - sin.sin_port = htons(port); - - gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() trying port %d\n", port); - if (!bind(sock, (struct sockaddr*) &sin, sizeof(sin))) - bound = 1; - else { - if (++port == 65535) { - gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() no free port found\n"); - close(sock); - return NULL; - } - } - } - - if (listen(sock, 10)) { - gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() unable to listen (%s)\n", strerror(errno)); - errno2 = errno; - close(sock); - errno = errno2; - return NULL; - } - - gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() bound to port %d\n", port); - - if (!(c = malloc(sizeof(*c)))) { - gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() not enough memory for struct\n"); - close(sock); - return NULL; - } - memset(c, 0, sizeof(*c)); - - c->port = c->id = port; - c->fd = sock; - c->file_fd = -1; - c->type = GG_SESSION_DCC_SOCKET; - c->uin = uin; - c->timeout = -1; - c->state = GG_STATE_LISTENING; - c->check = GG_CHECK_READ; - c->callback = gg_dcc_callback; - c->destroy = gg_dcc_free; - - return c; -} - -/** - * Wysyła ramkę danych połączenia głosowego. - * - * \param d Struktura połączenia - * \param buf Bufor z danymi - * \param length Długość bufora z danymi - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup dcc6 - */ -int gg_dcc_voice_send(struct gg_dcc *d, char *buf, int length) -{ - struct packet_s { - uint8_t type; - uint32_t length; - } GG_PACKED; - struct packet_s packet; - - gg_debug(GG_DEBUG_FUNCTION, "++ gg_dcc_voice_send(%p, %p, %d);\n", d, buf, length); - if (!d || !buf || length < 0 || d->type != GG_SESSION_DCC_VOICE) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_voice_send() invalid argument\n"); - errno = EINVAL; - return -1; - } - - packet.type = 0x03; /* XXX */ - packet.length = gg_fix32(length); - - if (send(d->fd, &packet, sizeof(packet), 0) < (signed)sizeof(packet)) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_voice_send() send() failed\n"); - return -1; - } - gg_dcc_debug_data("write", d->fd, &packet, sizeof(packet)); - - if (send(d->fd, buf, length, 0) < length) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_voice_send() send() failed\n"); - return -1; - } - gg_dcc_debug_data("write", d->fd, buf, length); - - return 0; -} - -/** - * \internal Odbiera dane z połączenia bezpośredniego z obsługą błędów. - * - * \param fd Deskryptor gniazda - * \param buf Bufor na dane - * \param size Rozmiar bufora na dane - */ -#define gg_dcc_read(fd, buf, size) \ -{ \ - int _tmp = recv(fd, buf, size, 0); \ - \ - if (_tmp < (int) size) { \ - if (_tmp == -1) { \ - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() recv() failed " \ - "(errno=%d, %s)\n", errno, strerror(errno)); \ - } else if (_tmp == 0) { \ - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() recv() failed, " \ - "connection broken\n"); \ - } else { \ - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() recv() failed " \ - "(%d bytes, %" GG_SIZE_FMT " needed)\n", \ - _tmp, size); \ - } \ - e->type = GG_EVENT_DCC_ERROR; \ - e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; \ - return e; \ - } \ - gg_dcc_debug_data("read", fd, buf, size); \ -} - -/** - * \internal Wysyła dane do połączenia bezpośredniego z obsługą błędów. - * - * \param fd Deskryptor gniazda - * \param buf Bufor z danymi - * \param size Rozmiar bufora z danymi - */ -#define gg_dcc_write(fd, buf, size) \ -{ \ - int write_res; \ - gg_dcc_debug_data("write", fd, buf, size); \ - write_res = send(fd, buf, size, 0); \ - if (write_res < (int) size) { \ - if (write_res == -1) { \ - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() send() " \ - "failed (errno=%d, %s)\n", errno, strerror(errno)); \ - } else { \ - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() send() " \ - "failed (%" GG_SIZE_FMT " needed, %d done)\n", \ - size, write_res); \ - } \ - e->type = GG_EVENT_DCC_ERROR; \ - e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; \ - return e; \ - } \ -} - -/** - * Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze połączenia. - * - * Funkcja zwraca strukturę zdarzenia \c gg_event. Jeśli rodzaj zdarzenia - * to \c GG_EVENT_NONE, nie wydarzyło się jeszcze nic wartego odnotowania. - * Strukturę zdarzenia należy zwolnić funkcja \c gg_event_free. - * - * \param h Struktura połączenia - * - * \return Struktura zdarzenia lub \c NULL jeśli wystąpił błąd - * - * \ingroup dcc6 - */ -struct gg_event *gg_dcc_watch_fd(struct gg_dcc *h) -{ - struct gg_event *e; - int foo; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_watch_fd(%p);\n", h); - - if (!h || (h->type != GG_SESSION_DCC && - h->type != GG_SESSION_DCC_SOCKET && - h->type != GG_SESSION_DCC_SEND && - h->type != GG_SESSION_DCC_GET && - h->type != GG_SESSION_DCC_VOICE)) - { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() invalid argument\n"); - errno = EINVAL; - return NULL; - } - - if (!(e = (void*) calloc(1, sizeof(*e)))) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() not enough memory\n"); - return NULL; - } - - e->type = GG_EVENT_NONE; - - if (h->type == GG_SESSION_DCC_SOCKET) { - struct sockaddr_in sin; - struct gg_dcc *c; - int fd; - socklen_t sin_len = sizeof(sin); - - if ((fd = accept(h->fd, (struct sockaddr*) &sin, &sin_len)) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() can't " - "accept() new connection (errno=%d, %s)\n", - errno, strerror(errno)); - return e; - } - - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() new direct " - "connection from %s:%d\n", inet_ntoa(sin.sin_addr), - htons(sin.sin_port)); - - if (!gg_fd_set_nonblocking(fd)) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() can't set" - " nonblocking (errno=%d, %s)\n", - errno, strerror(errno)); - close(fd); - e->type = GG_EVENT_DCC_ERROR; - e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; - return e; - } - - if (!(c = (void*) calloc(1, sizeof(*c)))) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() not enough memory for client data\n"); - - free(e); - close(fd); - return NULL; - } - - c->fd = fd; - c->check = GG_CHECK_READ; - c->state = GG_STATE_READING_UIN_1; - c->type = GG_SESSION_DCC; - c->timeout = GG_DEFAULT_TIMEOUT; - c->file_fd = -1; - c->remote_addr = sin.sin_addr.s_addr; - c->remote_port = ntohs(sin.sin_port); - - e->type = GG_EVENT_DCC_NEW; - e->event.dcc_new = c; - - return e; - } else { - struct gg_dcc_tiny_packet tiny_pkt; - struct gg_dcc_small_packet small_pkt; - struct gg_dcc_big_packet big_pkt; - int size, tmp, res; - unsigned int utmp; - socklen_t res_size = sizeof(res); - char buf[1024], ack[] = "UDAG"; - void *tmp_buf; - - struct gg_dcc_file_info_packet { - struct gg_dcc_big_packet big; - struct gg_file_info file_info; - } GG_PACKED; - struct gg_dcc_file_info_packet file_info_packet; - - switch (h->state) { - case GG_STATE_READING_UIN_1: - case GG_STATE_READING_UIN_2: - { - uin_t uin; - - gg_debug(GG_DEBUG_MISC, - "// gg_dcc_watch_fd() GG_READING_UIN_%d\n", - (h->state == GG_STATE_READING_UIN_1) ? 1 : 2); - - gg_dcc_read(h->fd, &uin, sizeof(uin)); - - if (h->state == GG_STATE_READING_UIN_1) { - h->state = GG_STATE_READING_UIN_2; - h->check = GG_CHECK_READ; - h->timeout = GG_DEFAULT_TIMEOUT; - h->peer_uin = gg_fix32(uin); - } else { - h->state = GG_STATE_SENDING_ACK; - h->check = GG_CHECK_WRITE; - h->timeout = GG_DEFAULT_TIMEOUT; - h->uin = gg_fix32(uin); - e->type = GG_EVENT_DCC_CLIENT_ACCEPT; - } - - return e; - } - - case GG_STATE_SENDING_ACK: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_SENDING_ACK\n"); - - gg_dcc_write(h->fd, ack, (size_t)4); - - h->state = GG_STATE_READING_TYPE; - h->check = GG_CHECK_READ; - h->timeout = GG_DEFAULT_TIMEOUT; - - return e; - - case GG_STATE_READING_TYPE: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_TYPE\n"); - - gg_dcc_read(h->fd, &small_pkt, sizeof(small_pkt)); - - small_pkt.type = gg_fix32(small_pkt.type); - - switch (small_pkt.type) { - case 0x0003: /* XXX */ - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() callback\n"); - h->type = GG_SESSION_DCC_SEND; - h->state = GG_STATE_SENDING_FILE_INFO; - h->check = GG_CHECK_WRITE; - h->timeout = GG_DEFAULT_TIMEOUT; - - e->type = GG_EVENT_DCC_CALLBACK; - - break; - - case 0x0002: /* XXX */ - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() dialin\n"); - h->type = GG_SESSION_DCC_GET; - h->state = GG_STATE_READING_REQUEST; - h->check = GG_CHECK_READ; - h->timeout = GG_DEFAULT_TIMEOUT; - h->incoming = 1; - - break; - - default: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() unknown dcc type " - "(%.4x) from %u\n", small_pkt.type, h->peer_uin); - e->type = GG_EVENT_DCC_ERROR; - e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; - } - - return e; - - case GG_STATE_READING_REQUEST: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_REQUEST\n"); - - gg_dcc_read(h->fd, &small_pkt, sizeof(small_pkt)); - - small_pkt.type = gg_fix32(small_pkt.type); - - switch (small_pkt.type) { - case 0x0001: /* XXX */ - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() file transfer request\n"); - h->state = GG_STATE_READING_FILE_INFO; - h->check = GG_CHECK_READ; - h->timeout = GG_DEFAULT_TIMEOUT; - break; - - case 0x0003: /* XXX */ - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() voice chat request\n"); - h->state = GG_STATE_SENDING_VOICE_ACK; - h->check = GG_CHECK_WRITE; - h->timeout = GG_DCC_TIMEOUT_VOICE_ACK; - h->type = GG_SESSION_DCC_VOICE; - e->type = GG_EVENT_DCC_NEED_VOICE_ACK; - - break; - - default: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() unknown " - "dcc request (%.4x) from %u\n", - small_pkt.type, h->peer_uin); - e->type = GG_EVENT_DCC_ERROR; - e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; - } - - return e; - - case GG_STATE_READING_FILE_INFO: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_FILE_INFO\n"); - - gg_dcc_read(h->fd, &file_info_packet, sizeof(file_info_packet)); - - memcpy(&h->file_info, &file_info_packet.file_info, sizeof(h->file_info)); - - h->file_info.mode = gg_fix32(h->file_info.mode); - h->file_info.size = gg_fix32(h->file_info.size); - - h->state = GG_STATE_SENDING_FILE_ACK; - h->check = GG_CHECK_WRITE; - h->timeout = GG_DCC_TIMEOUT_FILE_ACK; - - e->type = GG_EVENT_DCC_NEED_FILE_ACK; - - return e; - - case GG_STATE_SENDING_FILE_ACK: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE_ACK\n"); - - big_pkt.type = gg_fix32(0x0006); /* XXX */ - big_pkt.dunno1 = gg_fix32(h->offset); - big_pkt.dunno2 = 0; - - gg_dcc_write(h->fd, &big_pkt, sizeof(big_pkt)); - - h->state = GG_STATE_READING_FILE_HEADER; - h->chunk_size = sizeof(big_pkt); - h->chunk_offset = 0; - h->chunk_buf = NULL; - tmp_buf = malloc(sizeof(big_pkt)); - if (!tmp_buf) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() out of memory\n"); - free(e); - return NULL; - } - h->chunk_buf = tmp_buf; - h->check = GG_CHECK_READ; - h->timeout = GG_DEFAULT_TIMEOUT; - - return e; - - case GG_STATE_SENDING_VOICE_ACK: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_VOICE_ACK\n"); - - tiny_pkt.type = 0x01; /* XXX */ - - gg_dcc_write(h->fd, &tiny_pkt, sizeof(tiny_pkt)); - - h->state = GG_STATE_READING_VOICE_HEADER; - h->check = GG_CHECK_READ; - h->timeout = GG_DEFAULT_TIMEOUT; - - h->offset = 0; - - return e; - - case GG_STATE_READING_FILE_HEADER: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_FILE_HEADER\n"); - - tmp = recv(h->fd, h->chunk_buf + h->chunk_offset, h->chunk_size - h->chunk_offset, 0); - - if (tmp == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() recv() " - "failed (errno=%d, %s)\n", errno, strerror(errno)); - e->type = GG_EVENT_DCC_ERROR; - e->event.dcc_error = GG_ERROR_DCC_NET; - return e; - } - - gg_dcc_debug_data("read", h->fd, - h->chunk_buf + h->chunk_offset, - h->chunk_size - h->chunk_offset); - - h->chunk_offset += tmp; - - if (h->chunk_offset < h->chunk_size) - return e; - - memcpy(&big_pkt, h->chunk_buf, sizeof(big_pkt)); - free(h->chunk_buf); - h->chunk_buf = NULL; - - big_pkt.type = gg_fix32(big_pkt.type); - h->chunk_size = gg_fix32(big_pkt.dunno1); - h->chunk_offset = 0; - - if (big_pkt.type == 0x0005) { /* XXX */ - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() transfer refused\n"); - e->type = GG_EVENT_DCC_ERROR; - e->event.dcc_error = GG_ERROR_DCC_REFUSED; - return e; - } - - if (h->chunk_size == 0) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() empty chunk, EOF\n"); - e->type = GG_EVENT_DCC_DONE; - return e; - } - - h->state = GG_STATE_GETTING_FILE; - h->check = GG_CHECK_READ; - h->timeout = GG_DEFAULT_TIMEOUT; - h->established = 1; - - return e; - - case GG_STATE_READING_VOICE_HEADER: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_HEADER\n"); - - gg_dcc_read(h->fd, &tiny_pkt, sizeof(tiny_pkt)); - - switch (tiny_pkt.type) { - case 0x03: /* XXX */ - h->state = GG_STATE_READING_VOICE_SIZE; - h->check = GG_CHECK_READ; - h->timeout = GG_DEFAULT_TIMEOUT; - h->established = 1; - break; - case 0x04: /* XXX */ - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() " - "peer breaking connection\n"); - /* XXX zwracać odpowiedni event */ - default: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() " - "unknown request (%.2x)\n", tiny_pkt.type); - e->type = GG_EVENT_DCC_ERROR; - e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; - } - - return e; - - case GG_STATE_READING_VOICE_SIZE: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_SIZE\n"); - - gg_dcc_read(h->fd, &small_pkt, sizeof(small_pkt)); - - small_pkt.type = gg_fix32(small_pkt.type); - - if (small_pkt.type < 16 || small_pkt.type > sizeof(buf)) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() " - "invalid voice frame size (%d)\n", small_pkt.type); - e->type = GG_EVENT_DCC_ERROR; - e->event.dcc_error = GG_ERROR_DCC_NET; - - return e; - } - - h->chunk_size = small_pkt.type; - h->chunk_offset = 0; - - if (!(h->voice_buf = malloc(h->chunk_size))) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() out of memory for voice frame\n"); - free(e); - return NULL; - } - - h->state = GG_STATE_READING_VOICE_DATA; - h->check = GG_CHECK_READ; - h->timeout = GG_DEFAULT_TIMEOUT; - - return e; - - case GG_STATE_READING_VOICE_DATA: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_DATA\n"); - - tmp = recv(h->fd, h->voice_buf + h->chunk_offset, h->chunk_size - h->chunk_offset, 0); - if (tmp < 1) { - if (tmp == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() " - "recv() failed (errno=%d, %s)\n", - errno, strerror(errno)); - } else { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() " - "recv() failed, connection broken\n"); - } - e->type = GG_EVENT_DCC_ERROR; - e->event.dcc_error = GG_ERROR_DCC_NET; - return e; - } - - gg_dcc_debug_data("read", h->fd, h->voice_buf + h->chunk_offset, tmp); - - h->chunk_offset += tmp; - - if (h->chunk_offset >= h->chunk_size) { - e->type = GG_EVENT_DCC_VOICE_DATA; - e->event.dcc_voice_data.data = (unsigned char*) h->voice_buf; - e->event.dcc_voice_data.length = h->chunk_size; - h->state = GG_STATE_READING_VOICE_HEADER; - h->voice_buf = NULL; - } - - h->check = GG_CHECK_READ; - h->timeout = GG_DEFAULT_TIMEOUT; - - return e; - - case GG_STATE_CONNECTING: - { - uin_t uins[2]; - - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_CONNECTING\n"); - - res = 0; - if ((foo = getsockopt(h->fd, SOL_SOCKET, SO_ERROR, &res, &res_size)) || res) { - gg_debug(GG_DEBUG_MISC, - "// gg_dcc_watch_fd() connection failed " - "(fd=%d,errno=%d(%s),foo=%d,res=%d(%s))\n", - h->fd, errno, strerror(errno), foo, res, strerror(res)); - e->type = GG_EVENT_DCC_ERROR; - e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; - return e; - } - - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() connected, sending uins\n"); - - uins[0] = gg_fix32(h->uin); - uins[1] = gg_fix32(h->peer_uin); - - gg_dcc_write(h->fd, uins, sizeof(uins)); - - h->state = GG_STATE_READING_ACK; - h->check = GG_CHECK_READ; - h->timeout = GG_DEFAULT_TIMEOUT; - - return e; - } - - case GG_STATE_READING_ACK: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_ACK\n"); - - gg_dcc_read(h->fd, buf, (size_t)4); - - if (strncmp(buf, ack, 4)) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() did't get ack\n"); - - e->type = GG_EVENT_DCC_ERROR; - e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; - return e; - } - - h->check = GG_CHECK_WRITE; - h->timeout = GG_DEFAULT_TIMEOUT; - h->state = GG_STATE_SENDING_REQUEST; - - return e; - - case GG_STATE_SENDING_VOICE_REQUEST: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_VOICE_REQUEST\n"); - - small_pkt.type = gg_fix32(0x0003); - - gg_dcc_write(h->fd, &small_pkt, sizeof(small_pkt)); - - h->state = GG_STATE_READING_VOICE_ACK; - h->check = GG_CHECK_READ; - h->timeout = GG_DEFAULT_TIMEOUT; - - return e; - - case GG_STATE_SENDING_REQUEST: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_REQUEST\n"); - - small_pkt.type = (h->type == GG_SESSION_DCC_GET) ? - gg_fix32(0x0003) : gg_fix32(0x0002); /* XXX */ - - gg_dcc_write(h->fd, &small_pkt, sizeof(small_pkt)); - - switch (h->type) { - case GG_SESSION_DCC_GET: - h->state = GG_STATE_READING_REQUEST; - h->check = GG_CHECK_READ; - h->timeout = GG_DEFAULT_TIMEOUT; - break; - - case GG_SESSION_DCC_SEND: - h->state = GG_STATE_SENDING_FILE_INFO; - h->check = GG_CHECK_WRITE; - h->timeout = GG_DEFAULT_TIMEOUT; - - if (h->file_fd == -1) - e->type = GG_EVENT_DCC_NEED_FILE_INFO; - break; - - case GG_SESSION_DCC_VOICE: - h->state = GG_STATE_SENDING_VOICE_REQUEST; - h->check = GG_CHECK_WRITE; - h->timeout = GG_DEFAULT_TIMEOUT; - break; - } - - return e; - - case GG_STATE_SENDING_FILE_INFO: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE_INFO\n"); - - if (h->file_fd == -1) { - e->type = GG_EVENT_DCC_NEED_FILE_INFO; - return e; - } - - small_pkt.type = gg_fix32(0x0001); /* XXX */ - - gg_dcc_write(h->fd, &small_pkt, sizeof(small_pkt)); - - file_info_packet.big.type = gg_fix32(0x0003); /* XXX */ - file_info_packet.big.dunno1 = 0; - file_info_packet.big.dunno2 = 0; - - memcpy(&file_info_packet.file_info, &h->file_info, sizeof(h->file_info)); - - /* zostają teraz u nas, więc odwracamy z powrotem */ - h->file_info.size = gg_fix32(h->file_info.size); - h->file_info.mode = gg_fix32(h->file_info.mode); - - gg_dcc_write(h->fd, &file_info_packet, sizeof(file_info_packet)); - - h->state = GG_STATE_READING_FILE_ACK; - h->check = GG_CHECK_READ; - h->timeout = GG_DCC_TIMEOUT_FILE_ACK; - - return e; - - case GG_STATE_READING_FILE_ACK: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_FILE_ACK\n"); - - gg_dcc_read(h->fd, &big_pkt, sizeof(big_pkt)); - - /* XXX sprawdzać wynik */ - h->offset = gg_fix32(big_pkt.dunno1); - - h->state = GG_STATE_SENDING_FILE_HEADER; - h->check = GG_CHECK_WRITE; - h->timeout = GG_DEFAULT_TIMEOUT; - - e->type = GG_EVENT_DCC_ACK; - - return e; - - case GG_STATE_READING_VOICE_ACK: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_ACK\n"); - - gg_dcc_read(h->fd, &tiny_pkt, sizeof(tiny_pkt)); - - if (tiny_pkt.type != 0x01) { - gg_debug(GG_DEBUG_MISC, "// invalid " - "reply (%.2x), connection " - "refused\n", tiny_pkt.type); - e->type = GG_EVENT_DCC_ERROR; - e->event.dcc_error = GG_ERROR_DCC_REFUSED; - return e; - } - - h->state = GG_STATE_READING_VOICE_HEADER; - h->check = GG_CHECK_READ; - h->timeout = GG_DEFAULT_TIMEOUT; - - e->type = GG_EVENT_DCC_ACK; - - return e; - - case GG_STATE_SENDING_FILE_HEADER: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE_HEADER\n"); - - h->chunk_offset = 0; - - if ((h->chunk_size = h->file_info.size - h->offset) > 4096) { - h->chunk_size = 4096; - big_pkt.type = gg_fix32(0x0003); /* XXX */ - } else - big_pkt.type = gg_fix32(0x0002); /* XXX */ - - big_pkt.dunno1 = gg_fix32(h->chunk_size); - big_pkt.dunno2 = 0; - - gg_dcc_write(h->fd, &big_pkt, sizeof(big_pkt)); - - h->state = GG_STATE_SENDING_FILE; - h->check = GG_CHECK_WRITE; - h->timeout = GG_DEFAULT_TIMEOUT; - h->established = 1; - - return e; - - case GG_STATE_SENDING_FILE: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE\n"); - - if ((utmp = h->chunk_size - h->chunk_offset) > sizeof(buf)) - utmp = sizeof(buf); - - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() " - "offset=%d, size=%d\n", - h->offset, h->file_info.size); - - /* koniec pliku? */ - if (h->file_info.size == 0) { - gg_debug(GG_DEBUG_MISC, - "// gg_dcc_watch_fd() read()" - "reached eof on empty file\n"); - e->type = GG_EVENT_DCC_DONE; - - return e; - } - - if (h->offset >= h->file_info.size) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() offset >= size, finished\n"); - e->type = GG_EVENT_DCC_DONE; - return e; - } - - if (lseek(h->file_fd, h->offset, SEEK_SET) != (off_t)h->offset) { - gg_debug(GG_DEBUG_MISC, - "// gg_dcc_watch_fd() lseek() " - "failed. (errno=%d, %s)\n", - errno, strerror(errno)); - - e->type = GG_EVENT_DCC_ERROR; - e->event.dcc_error = GG_ERROR_DCC_FILE; - - return e; - } - - size = read(h->file_fd, buf, utmp); - - /* błąd */ - if (size == -1) { - gg_debug(GG_DEBUG_MISC, - "// gg_dcc_watch_fd() read() " - "failed. (errno=%d, %s)\n", - errno, strerror(errno)); - - e->type = GG_EVENT_DCC_ERROR; - e->event.dcc_error = GG_ERROR_DCC_FILE; - - return e; - } - - /* koniec pliku? */ - if (size == 0) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() reached eof\n"); - e->type = GG_EVENT_DCC_ERROR; - e->event.dcc_error = GG_ERROR_DCC_EOF; - - return e; - } - - /* jeśli wczytaliśmy więcej, utnijmy. */ - if (h->offset + size > h->file_info.size) { - gg_debug(GG_DEBUG_MISC, - "// gg_dcc_watch_fd() read() " - "too much (read=%d, ofs=%d, " - "size=%d)\n", size, h->offset, - h->file_info.size); - size = h->file_info.size - h->offset; - - if (size < 1) { - gg_debug(GG_DEBUG_MISC, - "// gg_dcc_watch_fd() " - "reached EOF after cutting\n"); - e->type = GG_EVENT_DCC_DONE; - return e; - } - } - - tmp = send(h->fd, buf, size, 0); - - if (tmp == -1) { - gg_debug(GG_DEBUG_MISC, - "// gg_dcc_watch_fd() send() " - "failed (%s)\n", strerror(errno)); - e->type = GG_EVENT_DCC_ERROR; - e->event.dcc_error = GG_ERROR_DCC_NET; - return e; - } - - if (tmp == 0) { - gg_debug(GG_DEBUG_MISC, - "// gg_dcc_watch_fd() send() " - "failed (connection reset)\n"); - e->type = GG_EVENT_DCC_ERROR; - e->event.dcc_error = GG_ERROR_DCC_NET; - return e; - } - - h->offset += tmp; - - if (h->offset >= h->file_info.size) { - e->type = GG_EVENT_DCC_DONE; - return e; - } - - h->chunk_offset += tmp; - - if (h->chunk_offset >= h->chunk_size) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() chunk finished\n"); - h->state = GG_STATE_SENDING_FILE_HEADER; - h->timeout = GG_DEFAULT_TIMEOUT; - } else { - h->state = GG_STATE_SENDING_FILE; - h->timeout = GG_DCC_TIMEOUT_SEND; - } - - h->check = GG_CHECK_WRITE; - - return e; - - case GG_STATE_GETTING_FILE: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_GETTING_FILE\n"); - - if ((utmp = h->chunk_size - h->chunk_offset) > sizeof(buf)) - utmp = sizeof(buf); - - if (h->offset >= h->file_info.size) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() offset >= size, finished\n"); - e->type = GG_EVENT_DCC_DONE; - return e; - } - - size = recv(h->fd, buf, utmp, 0); - - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() " - "ofs=%d, size=%d, recv()=%d\n", - h->offset, h->file_info.size, size); - - /* błąd */ - if (size == -1) { - gg_debug(GG_DEBUG_MISC, - "// gg_dcc_watch_fd() recv() " - "failed. (errno=%d, %s)\n", - errno, strerror(errno)); - - e->type = GG_EVENT_DCC_ERROR; - e->event.dcc_error = GG_ERROR_DCC_NET; - - return e; - } - - /* koniec? */ - if (size == 0) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() recv() reached eof\n"); - e->type = GG_EVENT_DCC_ERROR; - e->event.dcc_error = GG_ERROR_DCC_EOF; - - return e; - } - - tmp = write(h->file_fd, buf, size); - - if (tmp == -1 || tmp < size) { - gg_debug(GG_DEBUG_MISC, - "// gg_dcc_watch_fd() write() " - "failed (%d:fd=%d:res=%d:%s)\n", - tmp, h->file_fd, size, - strerror(errno)); - e->type = GG_EVENT_DCC_ERROR; - e->event.dcc_error = GG_ERROR_DCC_NET; - return e; - } - - h->offset += size; - - if (h->offset >= h->file_info.size) { - e->type = GG_EVENT_DCC_DONE; - return e; - } - - h->chunk_offset += size; - - if (h->chunk_offset >= h->chunk_size) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() chunk finished\n"); - h->state = GG_STATE_READING_FILE_HEADER; - h->timeout = GG_DEFAULT_TIMEOUT; - h->chunk_offset = 0; - h->chunk_size = sizeof(big_pkt); - h->chunk_buf = NULL; - tmp_buf = malloc(sizeof(big_pkt)); - if (!tmp_buf) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() out of memory\n"); - free(e); - return NULL; - } - h->chunk_buf = tmp_buf; - } else { - h->state = GG_STATE_GETTING_FILE; - h->timeout = GG_DCC_TIMEOUT_GET; - } - - h->check = GG_CHECK_READ; - - return e; - - default: - gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_???\n"); - e->type = GG_EVENT_DCC_ERROR; - e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; - - return e; - } - } - - return e; -} - -/** - * Zwalnia zasoby używane przez połączenie bezpośrednie. - * - * \param d Struktura połączenia - * - * \ingroup dcc6 - */ -void gg_dcc_free(struct gg_dcc *d) -{ - gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_free(%p);\n", d); - - if (!d) - return; - - if (d->fd != -1) - close(d->fd); - - if (d->file_fd != -1) - gg_file_close(d->file_fd); - - free(d->chunk_buf); - free(d); -} - -/* - * Local variables: - * c-indentation-style: k&r - * c-basic-offset: 8 - * indent-tabs-mode: notnil - * End: - * - * vim: shiftwidth=8: - */
--- a/libpurple/protocols/gg/lib/dcc7.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1660 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2001-2010 Wojtek Kaniewski <wojtekka@irc.pl> - * Tomasz Chiliński <chilek@chilan.com> - * Adam Wysocki <gophi@ekg.chmurka.net> - * Bartłomiej Zimoń <uzi18@o2.pl> - * - * Thanks to Jakub Zawadzki <darkjames@darkjames.ath.cx> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, - * USA. - */ - -/** - * \file dcc7.c - * - * \brief Obsługa połączeń bezpośrednich od wersji Gadu-Gadu 7.x - */ - -#include "fileio.h" -#include "network.h" -#include "strman.h" - -#include <ctype.h> -#include <errno.h> -#include <string.h> -#include <stdlib.h> -#include <time.h> - -#include "libgadu.h" -#include "protocol.h" -#include "resolver.h" -#include "internal.h" -#include "debug.h" - -#ifdef _MSC_VER -# define gg_debug_dcc(dcc, level, fmt, ...) \ - gg_debug_session(((dcc) != NULL) ? (dcc)->sess : NULL, level, fmt, __VA_ARGS__) -#else -# define gg_debug_dcc(dcc, level, fmt...) \ - gg_debug_session(((dcc) != NULL) ? (dcc)->sess : NULL, level, fmt) -#endif - -#define gg_debug_dump_dcc(dcc, level, buf, len) \ - gg_debug_dump(((dcc) != NULL) ? (dcc)->sess : NULL, level, buf, len) - -/** - * \internal Dodaje połączenie bezpośrednie do sesji. - * - * \param sess Struktura sesji - * \param dcc Struktura połączenia - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -static int gg_dcc7_session_add(struct gg_session *sess, struct gg_dcc7 *dcc) -{ - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_session_add(%p, %p)\n", sess, dcc); - - if (!sess || !dcc || dcc->next) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_session_add() invalid parameters\n"); - errno = EINVAL; - return -1; - } - - dcc->next = sess->dcc7_list; - sess->dcc7_list = dcc; - - return 0; -} - -/** - * \internal Usuwa połączenie bezpośrednie z sesji. - * - * \param sess Struktura sesji - * \param dcc Struktura połączenia - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -static int gg_dcc7_session_remove(struct gg_session *sess, struct gg_dcc7 *dcc) -{ - struct gg_dcc7 *tmp; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_session_remove(%p, %p)\n", sess, dcc); - - if (sess == NULL || dcc == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_session_remove() invalid parameters\n"); - errno = EINVAL; - return -1; - } - - if (sess->dcc7_list == dcc) { - sess->dcc7_list = dcc->next; - dcc->next = NULL; - return 0; - } - - for (tmp = sess->dcc7_list; tmp != NULL; tmp = tmp->next) { - if (tmp->next == dcc) { - tmp->next = dcc->next; - dcc->next = NULL; - return 0; - } - } - - errno = ENOENT; - return -1; -} - -/** - * \internal Zwraca strukturę połączenia o danym identyfikatorze. - * - * \param sess Struktura sesji - * \param id Identyfikator połączenia - * \param uin Numer nadawcy lub odbiorcy - * - * \return Struktura połączenia lub \c NULL jeśli nie znaleziono - */ -static struct gg_dcc7 *gg_dcc7_session_find(struct gg_session *sess, gg_dcc7_id_t id, uin_t uin) -{ - struct gg_dcc7 *tmp; - int empty; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_session_find(%p, ..., %d)\n", sess, (int) uin); - - empty = !memcmp(&id, "\0\0\0\0\0\0\0\0", 8); - - for (tmp = sess->dcc7_list; tmp; tmp = tmp->next) { - if (empty) { - if (tmp->peer_uin == uin && tmp->state == GG_STATE_WAITING_FOR_ACCEPT) - return tmp; - } else { - if (!memcmp(&tmp->cid, &id, sizeof(id))) - return tmp; - } - } - - return NULL; -} - -/** - * \internal Rozpoczyna proces pobierania adresu - * - * \param dcc Struktura połączenia - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -static int gg_dcc7_get_relay_addr(struct gg_dcc7 *dcc) -{ - gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_get_relay_addr(%p)\n", dcc); - - if (dcc == NULL || dcc->sess == NULL) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_get_relay_addr() invalid parameters\n"); - errno = EINVAL; - return -1; - } - - if (dcc->sess->resolver_start(&dcc->fd, &dcc->resolver, GG_RELAY_HOST) == -1) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_get_relay_addr() " - "resolving failed (errno=%d, %s)\n", - errno, strerror(errno)); - return -1; - } - - dcc->state = GG_STATE_RESOLVING_RELAY; - dcc->check = GG_CHECK_READ; - dcc->timeout = GG_DEFAULT_TIMEOUT; - - return 0; -} - -/** - * \internal Nawiązuje połączenie bezpośrednie - * - * \param dcc Struktura połączenia - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -static int gg_dcc7_connect(struct gg_dcc7 *dcc) -{ - gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_connect(%p)\n", dcc); - - if (dcc == NULL) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_connect() invalid parameters\n"); - errno = EINVAL; - return -1; - } - - if ((dcc->fd = gg_connect(&dcc->remote_addr, dcc->remote_port, 1)) == -1) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_connect() connection failed\n"); - return -1; - } - - dcc->state = GG_STATE_CONNECTING; - dcc->check = GG_CHECK_WRITE; - dcc->timeout = GG_DCC7_TIMEOUT_CONNECT; - dcc->soft_timeout = 1; - - return 0; -} - -/** - * \internal Tworzy gniazdo nasłuchujące dla połączenia bezpośredniego - * - * \param dcc Struktura połączenia - * \param addr Preferowany adres (jeśli równy 0, nasłuchujemy na wszystkich interfejsach) - * \param port Preferowany port (jeśli równy 0, nasłuchujemy na losowym) - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -static int gg_dcc7_listen(struct gg_dcc7 *dcc, uint32_t addr, uint16_t port) -{ - struct sockaddr_in sin; - socklen_t sin_len = sizeof(sin); - int errsv; - int fd; - - gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_listen(%p, %d)\n", dcc, port); - - if (!dcc) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() invalid parameters\n"); - errno = EINVAL; - return -1; - } - - if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() can't create socket (%s)\n", strerror(errno)); - return -1; - } - - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = addr; - sin.sin_port = htons(port); - - if (bind(fd, (struct sockaddr*) &sin, sizeof(sin)) == -1) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() unable to" - " bind to %s:%d\n", inet_ntoa(sin.sin_addr), port); - goto fail; - } - - if (port == 0 && getsockname(fd, (struct sockaddr*) &sin, &sin_len) == -1) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() unable to bind to port %d\n", port); - goto fail; - } - - if (listen(fd, 1)) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() unable to listen (%s)\n", strerror(errno)); - goto fail; - } - - dcc->fd = fd; - dcc->local_addr = sin.sin_addr.s_addr; - dcc->local_port = ntohs(sin.sin_port); - - dcc->state = GG_STATE_LISTENING; - dcc->check = GG_CHECK_READ; - dcc->timeout = GG_DCC7_TIMEOUT_FILE_ACK; - - return 0; - -fail: - errsv = errno; - close(fd); - errno = errsv; - return -1; -} - -/** - * \internal Tworzy gniazdo nasłuchujące i wysyła jego parametry - * - * \param dcc Struktura połączenia - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -static int gg_dcc7_listen_and_send_info(struct gg_dcc7 *dcc) -{ - struct gg_dcc7_info pkt; - uint16_t external_port; - uint32_t external_addr; - struct in_addr addr; - - gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_listen_and_send_info(%p)\n", dcc); - - if (gg_dcc7_listen(dcc, dcc->sess->client_addr, dcc->sess->client_port) == -1) - return -1; - - if (dcc->sess->external_port != 0) - external_port = dcc->sess->external_port; - else - external_port = dcc->local_port; - - if (dcc->sess->external_addr != 0) - external_addr = dcc->sess->external_addr; - else - external_addr = dcc->local_addr; - - addr.s_addr = external_addr; - - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// dcc7_listen_and_send_info() " - "sending IP address %s and port %d\n", - inet_ntoa(addr), external_port); - - memset(&pkt, 0, sizeof(pkt)); - pkt.uin = gg_fix32(dcc->peer_uin); - pkt.type = GG_DCC7_TYPE_P2P; - pkt.id = dcc->cid; - snprintf((char*) pkt.info, sizeof(pkt.info), "%s %d", inet_ntoa(addr), external_port); - snprintf((char*) pkt.hash, sizeof(pkt.hash), "%u", external_addr + external_port * rand()); - - return gg_send_packet(dcc->sess, GG_DCC7_INFO, &pkt, sizeof(pkt), NULL); -} - -/** - * \internal Odwraca połączenie po nieudanym connect() - * - * \param dcc Struktura połączenia - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -static int gg_dcc7_reverse_connect(struct gg_dcc7 *dcc) -{ - gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_reverse_connect(%p)\n", dcc); - - if (dcc == NULL) - return -1; - - if (dcc->reverse) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_reverse_connect() already reverse connection\n"); - return -1; - } - - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_reverse_connect() timeout, trying reverse connection\n"); - close(dcc->fd); - dcc->fd = -1; - dcc->reverse = 1; - - return gg_dcc7_listen_and_send_info(dcc); -} - -/** - * \internal Wysyła do serwera żądanie nadania identyfikatora sesji - * - * \param sess Struktura sesji - * \param type Rodzaj połączenia (\c GG_DCC7_TYPE_FILE lub \c GG_DCC7_TYPE_VOICE) - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -static int gg_dcc7_request_id(struct gg_session *sess, uint32_t type) -{ - struct gg_dcc7_id_request pkt; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_request_id(%p, %d)\n", sess, type); - - if (!sess) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_request_id() invalid parameters\n"); - errno = EFAULT; - return -1; - } - - if (sess->state != GG_STATE_CONNECTED) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_request_id() not connected\n"); - errno = ENOTCONN; - return -1; - } - - if (type != GG_DCC7_TYPE_VOICE && type != GG_DCC7_TYPE_FILE) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_request_id() invalid transfer type (%d)\n", type); - errno = EINVAL; - return -1; - } - - memset(&pkt, 0, sizeof(pkt)); - pkt.type = gg_fix32(type); - - return gg_send_packet(sess, GG_DCC7_ID_REQUEST, &pkt, sizeof(pkt), NULL); -} - -/** - * \internal Rozpoczyna wysyłanie pliku. - * - * Funkcja jest wykorzystywana przez \c gg_dcc7_send_file() oraz - * \c gg_dcc_send_file_fd(). - * - * \param sess Struktura sesji - * \param rcpt Numer odbiorcy - * \param fd Deskryptor pliku - * \param size Rozmiar pliku - * \param filename1250 Nazwa pliku w kodowaniu CP-1250 - * \param hash Skrót SHA-1 pliku - * \param seek Flaga mówiąca, czy można używać lseek() - * - * \return Struktura \c gg_dcc7 lub \c NULL w przypadku błędu - * - * \ingroup dcc7 - */ -static struct gg_dcc7 *gg_dcc7_send_file_common(struct gg_session *sess, - uin_t rcpt, int fd, size_t size, const char *filename1250, - const char *hash, int seek) -{ - struct gg_dcc7 *dcc = NULL; - - if (!sess || !rcpt || !filename1250 || !hash || fd == -1) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_send_file_common() invalid parameters\n"); - errno = EINVAL; - goto fail; - } - - if (!(dcc = malloc(sizeof(struct gg_dcc7)))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_send_file_common() not enough memory\n"); - goto fail; - } - - if (gg_dcc7_request_id(sess, GG_DCC7_TYPE_FILE) == -1) - goto fail; - - memset(dcc, 0, sizeof(struct gg_dcc7)); - dcc->type = GG_SESSION_DCC7_SEND; - dcc->dcc_type = GG_DCC7_TYPE_FILE; - dcc->state = GG_STATE_REQUESTING_ID; - dcc->timeout = GG_DEFAULT_TIMEOUT; - dcc->sess = sess; - dcc->fd = -1; - dcc->uin = sess->uin; - dcc->peer_uin = rcpt; - dcc->file_fd = fd; - dcc->size = size; - dcc->seek = seek; - - strncpy((char*) dcc->filename, filename1250, GG_DCC7_FILENAME_LEN); - dcc->filename[GG_DCC7_FILENAME_LEN] = 0; - - memcpy(dcc->hash, hash, GG_DCC7_HASH_LEN); - - if (gg_dcc7_session_add(sess, dcc) == -1) - goto fail; - - return dcc; - -fail: - free(dcc); - return NULL; -} - -/** - * Rozpoczyna wysyłanie pliku o danej nazwie. - * - * \param sess Struktura sesji - * \param rcpt Numer odbiorcy - * \param filename Nazwa pliku w lokalnym systemie plików - * \param filename1250 Nazwa pliku w kodowaniu CP-1250 - * \param hash Skrót SHA-1 pliku (lub \c NULL jeśli ma być wyznaczony) - * - * \return Struktura \c gg_dcc7 lub \c NULL w przypadku błędu - * - * \ingroup dcc7 - */ -struct gg_dcc7 *gg_dcc7_send_file(struct gg_session *sess, uin_t rcpt, - const char *filename, const char *filename1250, const char *hash) -{ - struct gg_dcc7 *dcc = NULL; - const char *tmp; - char hash_buf[GG_DCC7_HASH_LEN]; - struct stat st; - int fd = -1; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_send_file(%p, %d," - " \"%s\", %p)\n", sess, rcpt, filename, hash); - - if (!sess || !rcpt || !filename) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_send_file() invalid parameters\n"); - errno = EINVAL; - goto fail; - } - - if (!filename1250) - filename1250 = filename; - - if ((fd = open(filename, O_RDONLY)) == -1) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_send_file() open() failed (%s)\n", strerror(errno)); - goto fail; - } - - if (fstat(fd, &st) == -1) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_send_file() " - "fstat() failed (%s)\n", strerror(errno)); - goto fail; - } - - if ((st.st_mode & S_IFDIR)) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_send_file() that's a directory\n"); - errno = EINVAL; - goto fail; - } - - if (!hash) { - if (gg_file_hash_sha1(fd, (uint8_t*) hash_buf) == -1) - goto fail; - - hash = hash_buf; - } - - if ((tmp = strrchr(filename1250, '/'))) - filename1250 = tmp + 1; - - if (!(dcc = gg_dcc7_send_file_common(sess, rcpt, fd, st.st_size, filename1250, hash, 1))) - goto fail; - - return dcc; - -fail: - if (fd != -1) { - int errsv = errno; - gg_file_close(fd); - errno = errsv; - } - - free(dcc); - return NULL; -} - -/** - * \internal Rozpoczyna wysyłanie pliku o danym deskryptorze. - * - * \note Wysyłanie pliku nie będzie działać poprawnie, jeśli deskryptor - * źródłowy jest w trybie nieblokującym i w pewnym momencie zabraknie danych. - * - * \param sess Struktura sesji - * \param rcpt Numer odbiorcy - * \param fd Deskryptor pliku - * \param size Rozmiar pliku - * \param filename1250 Nazwa pliku w kodowaniu CP-1250 - * \param hash Skrót SHA-1 pliku - * - * \return Struktura \c gg_dcc7 lub \c NULL w przypadku błędu - * - * \ingroup dcc7 - */ -struct gg_dcc7 *gg_dcc7_send_file_fd(struct gg_session *sess, uin_t rcpt, - int fd, size_t size, const char *filename1250, const char *hash) -{ - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_send_file_fd(%p, " - "%d, %d, %" GG_SIZE_FMT ", \"%s\", %p)\n", - sess, rcpt, fd, size, filename1250, hash); - - return gg_dcc7_send_file_common(sess, rcpt, fd, size, filename1250, hash, 0); -} - - -/** - * Potwierdza chęć odebrania pliku. - * - * \param dcc Struktura połączenia - * \param offset Początkowy offset przy wznawianiu przesyłania pliku - * - * \note Biblioteka nie zmienia położenia w odbieranych plikach. Jeśli offset - * początkowy jest różny od zera, należy ustawić go funkcją \c lseek() lub - * podobną. - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup dcc7 - */ -int gg_dcc7_accept(struct gg_dcc7 *dcc, unsigned int offset) -{ - struct gg_dcc7_accept pkt; - - gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_accept(%p, %d)\n", dcc, offset); - - if (!dcc || !dcc->sess) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_accept() invalid parameters\n"); - errno = EFAULT; - return -1; - } - - memset(&pkt, 0, sizeof(pkt)); - pkt.uin = gg_fix32(dcc->peer_uin); - pkt.id = dcc->cid; - pkt.offset = gg_fix32(offset); - - if (gg_send_packet(dcc->sess, GG_DCC7_ACCEPT, &pkt, sizeof(pkt), NULL) == -1) - return -1; - - dcc->offset = offset; - - return gg_dcc7_listen_and_send_info(dcc); -} - -/** - * Odrzuca próbę przesłania pliku. - * - * \param dcc Struktura połączenia - * \param reason Powód odrzucenia - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup dcc7 - */ -int gg_dcc7_reject(struct gg_dcc7 *dcc, int reason) -{ - struct gg_dcc7_reject pkt; - - gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_reject(%p, %d)\n", dcc, reason); - - if (!dcc || !dcc->sess) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_reject() invalid parameters\n"); - errno = EFAULT; - return -1; - } - - memset(&pkt, 0, sizeof(pkt)); - pkt.uin = gg_fix32(dcc->peer_uin); - pkt.id = dcc->cid; - pkt.reason = gg_fix32(reason); - - return gg_send_packet(dcc->sess, GG_DCC7_REJECT, &pkt, sizeof(pkt), NULL); -} - -/** - * \internal Obsługuje pakiet identyfikatora połączenia bezpośredniego. - * - * \param sess Struktura sesji - * \param e Struktura zdarzenia - * \param payload Treść pakietu - * \param len Długość pakietu - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -int gg_dcc7_handle_id(struct gg_session *sess, struct gg_event *e, const void *payload, int len) -{ - const struct gg_dcc7_id_reply *p = payload; - struct gg_dcc7 *tmp; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_handle_id(%p, %p, %p, %d)\n", sess, e, payload, len); - - for (tmp = sess->dcc7_list; tmp; tmp = tmp->next) { - gg_debug_session(sess, GG_DEBUG_MISC, "// checking dcc %p, " - "state %d, type %d\n", tmp, tmp->state, tmp->dcc_type); - - if (tmp->state != GG_STATE_REQUESTING_ID || tmp->dcc_type != (int) gg_fix32(p->type)) - continue; - - tmp->cid = p->id; - - switch (tmp->dcc_type) { - case GG_DCC7_TYPE_FILE: - { - struct gg_dcc7_new s; - - memset(&s, 0, sizeof(s)); - s.id = tmp->cid; - s.type = gg_fix32(GG_DCC7_TYPE_FILE); - s.uin_from = gg_fix32(tmp->uin); - s.uin_to = gg_fix32(tmp->peer_uin); - s.size = gg_fix32(tmp->size); - - /* Uwaga: To nie jest ciąg kończony zerem. - * Note: This is not a null-terminated string. */ - GG_STATIC_ASSERT( - sizeof(s.filename) == sizeof(tmp->filename) - 1, - filename_sizes_does_not_match); - memcpy((char*)s.filename, (char*)tmp->filename, sizeof(s.filename)); - - tmp->state = GG_STATE_WAITING_FOR_ACCEPT; - tmp->timeout = GG_DCC7_TIMEOUT_FILE_ACK; - - return gg_send_packet(sess, GG_DCC7_NEW, &s, sizeof(s), NULL); - } - } - } - - return 0; -} - -/** - * \internal Obsługuje pakiet akceptacji połączenia bezpośredniego. - * - * \param sess Struktura sesji - * \param e Struktura zdarzenia - * \param payload Treść pakietu - * \param len Długość pakietu - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -int gg_dcc7_handle_accept(struct gg_session *sess, struct gg_event *e, const void *payload, int len) -{ - const struct gg_dcc7_accept *p = payload; - struct gg_dcc7 *dcc; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_handle_accept(%p, %p, %p, %d)\n", sess, e, payload, len); - - if (!(dcc = gg_dcc7_session_find(sess, p->id, gg_fix32(p->uin)))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_accept() unknown dcc session\n"); - /* XXX wysłać reject? */ - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE; - return 0; - } - - if (dcc->state != GG_STATE_WAITING_FOR_ACCEPT) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_accept() invalid state\n"); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE; - return 0; - } - - /* XXX czy dla odwrotnego połączenia powinniśmy wywołać już zdarzenie GG_DCC7_ACCEPT? */ - - dcc->offset = gg_fix32(p->offset); - dcc->state = GG_STATE_WAITING_FOR_INFO; - - return 0; -} - -/** - * \internal Obsługuje pakiet informacji o połączeniu bezpośrednim. - * - * \param sess Struktura sesji - * \param e Struktura zdarzenia - * \param payload Treść pakietu - * \param len Długość pakietu - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -int gg_dcc7_handle_info(struct gg_session *sess, struct gg_event *e, const void *payload, int len) -{ - const struct gg_dcc7_info *p = payload; - struct gg_dcc7 *dcc; - char *tmp; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_handle_info(%p, %p, %p, %d)\n", sess, e, payload, len); - gg_debug_session(sess, GG_DEBUG_FUNCTION, "// gg_dcc7_handle_info() " - "received address: %s, hash: %s\n", p->info, p->hash); - - if (!(dcc = gg_dcc7_session_find(sess, p->id, gg_fix32(p->uin)))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() unknown dcc session\n"); - return 0; - } - - if (dcc->state == GG_STATE_CONNECTED) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() state is already connected\n"); - return 0; - } - - switch (p->type) - { - case GG_DCC7_TYPE_P2P: - if ((dcc->remote_addr = inet_addr(p->info)) == INADDR_NONE) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() invalid IP address\n"); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE; - return 0; - } - - if (!(tmp = strchr(p->info, ' ')) || !(dcc->remote_port = atoi(tmp + 1))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() invalid IP port\n"); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE; - return 0; - } - - if (dcc->state == GG_STATE_WAITING_FOR_INFO) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_dcc7_handle_info() waiting for info " - "so send one\n"); - gg_dcc7_listen_and_send_info(dcc); - e->type = GG_EVENT_DCC7_PENDING; - e->event.dcc7_pending.dcc7 = dcc; - return 0; - } - - break; - - case GG_DCC7_TYPE_SERVER: - if (!(tmp = strstr(p->info, "GG"))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() unknown info packet\n"); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE; - return 0; - } - -#if defined(HAVE__STRTOUI64) || defined(HAVE_STRTOULL) - { - uint64_t cid; - -# ifdef HAVE__STRTOUI64 - cid = _strtoui64(tmp + 2, NULL, 0); -# else - cid = strtoull(tmp + 2, NULL, 0); -# endif - - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_dcc7_handle_info() info.str=%s, " - "info.id=%llu, sess.id=%llu\n", tmp + 2, cid, - *((unsigned long long*) &dcc->cid)); - - cid = gg_fix64(cid); - - if (memcmp(&dcc->cid, &cid, sizeof(cid)) != 0) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() invalid session id\n"); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE; - return 0; - } - } -#else - (void)tmp; -#endif - - if (gg_dcc7_get_relay_addr(dcc) == -1) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_handle_info() unable to retrieve relay address\n"); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc7_error = GG_ERROR_DCC7_RELAY; - return 0; - } - - /* XXX wysyłać dopiero jeśli uda się połączyć z serwerem? */ - - gg_send_packet(dcc->sess, GG_DCC7_INFO, payload, len, NULL); - - return 0; - - default: - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info()" - " unhandled transfer type (%d)\n", p->type); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE; - return 0; - } - -#if 0 - /* jeśli nadal czekamy na połączenie przychodzące, a druga strona nie - * daje rady i oferuje namiary na siebie, bierzemy co dają. - */ - if (dcc->state != GG_STATE_WAITING_FOR_INFO && (dcc->state != GG_STATE_LISTENING || dcc->reverse)) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() invalid state\n"); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE; - return 0; - } -#endif - - if (dcc->state == GG_STATE_LISTENING) { - close(dcc->fd); - dcc->fd = -1; - dcc->reverse = 1; - } - - if (dcc->type == GG_SESSION_DCC7_SEND) { - e->type = GG_EVENT_DCC7_ACCEPT; - e->event.dcc7_accept.dcc7 = dcc; - e->event.dcc7_accept.type = gg_fix32(p->type); - e->event.dcc7_accept.remote_ip = dcc->remote_addr; - e->event.dcc7_accept.remote_port = dcc->remote_port; - } else { - e->type = GG_EVENT_DCC7_PENDING; - e->event.dcc7_pending.dcc7 = dcc; - } - - if (gg_dcc7_connect(dcc) == -1) { - if (gg_dcc7_reverse_connect(dcc) == -1) { - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc7_error = GG_ERROR_DCC7_NET; - return 0; - } - } - - return 0; -} - -/** - * \internal Obsługuje pakiet odrzucenia połączenia bezpośredniego. - * - * \param sess Struktura sesji - * \param e Struktura zdarzenia - * \param payload Treść pakietu - * \param len Długość pakietu - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -int gg_dcc7_handle_reject(struct gg_session *sess, struct gg_event *e, const void *payload, int len) -{ - const struct gg_dcc7_reject *p = payload; - struct gg_dcc7 *dcc; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_handle_reject(%p, %p, %p, %d)\n", sess, e, payload, len); - - if (!(dcc = gg_dcc7_session_find(sess, p->id, gg_fix32(p->uin)))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_reject() unknown dcc session\n"); - return 0; - } - - if (dcc->state != GG_STATE_WAITING_FOR_ACCEPT) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_reject() invalid state\n"); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE; - return 0; - } - - e->type = GG_EVENT_DCC7_REJECT; - e->event.dcc7_reject.dcc7 = dcc; - e->event.dcc7_reject.reason = gg_fix32(p->reason); - - /* XXX ustawić state na rejected? */ - - return 0; -} - -/** - * \internal Obsługuje pakiet nowego połączenia bezpośredniego. - * - * \param sess Struktura sesji - * \param e Struktura zdarzenia - * \param payload Treść pakietu - * \param len Długość pakietu - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -int gg_dcc7_handle_new(struct gg_session *sess, struct gg_event *e, const void *payload, int len) -{ - const struct gg_dcc7_new *p = payload; - struct gg_dcc7 *dcc; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_handle_new(%p, %p, %p, %d)\n", sess, e, payload, len); - - switch (gg_fix32(p->type)) { - case GG_DCC7_TYPE_FILE: - if (!(dcc = malloc(sizeof(struct gg_dcc7)))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_new() not enough memory\n"); - return -1; - } - - memset(dcc, 0, sizeof(struct gg_dcc7)); - dcc->type = GG_SESSION_DCC7_GET; - dcc->dcc_type = GG_DCC7_TYPE_FILE; - dcc->fd = -1; - dcc->file_fd = -1; - dcc->uin = sess->uin; - dcc->peer_uin = gg_fix32(p->uin_from); - dcc->cid = p->id; - dcc->sess = sess; - - if (gg_dcc7_session_add(sess, dcc) == -1) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_dcc7_handle_new() unable to " - "add to session\n"); - gg_dcc7_free(dcc); - return -1; - } - - dcc->size = gg_fix32(p->size); - strncpy((char*) dcc->filename, (char*) p->filename, GG_DCC7_FILENAME_LEN); - dcc->filename[GG_DCC7_FILENAME_LEN] = 0; - memcpy(dcc->hash, p->hash, GG_DCC7_HASH_LEN); - - e->type = GG_EVENT_DCC7_NEW; - e->event.dcc7_new = dcc; - - break; - - case GG_DCC7_TYPE_VOICE: - if (!(dcc = malloc(sizeof(struct gg_dcc7)))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_packet() not enough memory\n"); - return -1; - } - - memset(dcc, 0, sizeof(struct gg_dcc7)); - - dcc->type = GG_SESSION_DCC7_VOICE; - dcc->dcc_type = GG_DCC7_TYPE_VOICE; - dcc->fd = -1; - dcc->file_fd = -1; - dcc->uin = sess->uin; - dcc->peer_uin = gg_fix32(p->uin_from); - dcc->cid = p->id; - dcc->sess = sess; - - if (gg_dcc7_session_add(sess, dcc) == -1) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_dcc7_handle_new() unable to add " - "to session\n"); - gg_dcc7_free(dcc); - return -1; - } - - e->type = GG_EVENT_DCC7_NEW; - e->event.dcc7_new = dcc; - - break; - - default: - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_dcc7_handle_new() unknown dcc type (%d) " - "from %u\n", gg_fix32(p->type), - gg_fix32(p->uin_from)); - - break; - } - - return 0; -} - -/** - * \internal Ustawia odpowiednie stany wewnętrzne w zależności od rodzaju - * połączenia. - * - * \param dcc Struktura połączenia - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu. - */ -static int gg_dcc7_postauth_fixup(struct gg_dcc7 *dcc) -{ - gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_postauth_fixup(%p)\n", dcc); - - if (!dcc) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_postauth_fixup() invalid parameters\n"); - errno = EINVAL; - return -1; - } - - switch (dcc->type) { - case GG_SESSION_DCC7_GET: - dcc->state = GG_STATE_GETTING_FILE; - dcc->check = GG_CHECK_READ; - return 0; - - case GG_SESSION_DCC7_SEND: - dcc->state = GG_STATE_SENDING_FILE; - dcc->check = GG_CHECK_WRITE; - return 0; - - case GG_SESSION_DCC7_VOICE: - dcc->state = GG_STATE_READING_VOICE_DATA; - dcc->check = GG_CHECK_READ; - return 0; - } - - errno = EINVAL; - - return -1; -} - -/** - * Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze połączenia. - * - * Funkcja zwraca strukturę zdarzenia \c gg_event. Jeśli rodzaj zdarzenia - * to \c GG_EVENT_NONE, nie wydarzyło się jeszcze nic wartego odnotowania. - * Strukturę zdarzenia należy zwolnić funkcja \c gg_event_free(). - * - * \param dcc Struktura połączenia - * - * \return Struktura zdarzenia lub \c NULL jeśli wystąpił błąd - * - * \ingroup dcc7 - */ -struct gg_event *gg_dcc7_watch_fd(struct gg_dcc7 *dcc) -{ - struct gg_event *e; - - gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_watch_fd(%p)\n", dcc); - - if (!dcc || (dcc->type != GG_SESSION_DCC7_SEND && - dcc->type != GG_SESSION_DCC7_GET && - dcc->type != GG_SESSION_DCC7_VOICE)) - { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() invalid parameters\n"); - errno = EINVAL; - return NULL; - } - - if (!(e = malloc(sizeof(struct gg_event)))) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() not enough memory\n"); - return NULL; - } - - memset(e, 0, sizeof(struct gg_event)); - e->type = GG_EVENT_NONE; - - switch (dcc->state) { - case GG_STATE_LISTENING: - { - struct sockaddr_in sin; - int fd; - socklen_t sin_len = sizeof(sin); - - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_LISTENING\n"); - - if ((fd = accept(dcc->fd, (struct sockaddr*) &sin, &sin_len)) == -1) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, - "// gg_dcc7_watch_fd() accept() failed " - "(%s)\n", strerror(errno)); - return e; - } - - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd()" - " connection from %s:%d\n", - inet_ntoa(sin.sin_addr), htons(sin.sin_port)); - - if (!gg_fd_set_nonblocking(fd)) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, - "// gg_dcc7_watch_fd() can't set " - "nonblocking (%s)\n", strerror(errno)); - close(fd); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = GG_ERROR_DCC7_HANDSHAKE; - return e; - } - - close(dcc->fd); - dcc->fd = fd; - - dcc->state = GG_STATE_READING_ID; - dcc->check = GG_CHECK_READ; - dcc->timeout = GG_DEFAULT_TIMEOUT; - dcc->incoming = 1; - - dcc->remote_port = ntohs(sin.sin_port); - dcc->remote_addr = sin.sin_addr.s_addr; - - e->type = GG_EVENT_DCC7_CONNECTED; - e->event.dcc7_connected.dcc7 = dcc; - - return e; - } - - case GG_STATE_CONNECTING: - { - int res = 0, error = 0; - socklen_t error_size = sizeof(error); - - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_CONNECTING\n"); - - dcc->soft_timeout = 0; - - if (dcc->timeout == 0) - error = ETIMEDOUT; - - if (error || (res = getsockopt(dcc->fd, SOL_SOCKET, - SO_ERROR, &error, &error_size)) == -1 || - error != 0) - { - gg_debug_dcc(dcc, GG_DEBUG_MISC, - "// gg_dcc7_watch_fd() connection " - "failed (%s)\n", (res == -1) ? - strerror(errno) : strerror(error)); - - if (dcc->relay) { - for (dcc->relay_index++; - dcc->relay_index < dcc->relay_count; - dcc->relay_index++) - { - dcc->remote_addr = dcc->relay_list[dcc->relay_index].addr; - dcc->remote_port = dcc->relay_list[dcc->relay_index].port; - - if (gg_dcc7_connect(dcc) == 0) - break; - } - - if (dcc->relay_index >= dcc->relay_count) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, - "// gg_dcc7_watch_fd() " - "no relay available\n"); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = GG_ERROR_DCC7_RELAY; - return e; - } - } else { - if (gg_dcc7_reverse_connect(dcc) != -1) { - e->type = GG_EVENT_DCC7_PENDING; - e->event.dcc7_pending.dcc7 = dcc; - } else { - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = GG_ERROR_DCC7_NET; - } - - return e; - } - } - - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() connected, sending id\n"); - - dcc->state = GG_STATE_SENDING_ID; - dcc->check = GG_CHECK_WRITE; - dcc->timeout = GG_DEFAULT_TIMEOUT; - dcc->incoming = 0; - - return e; - } - - case GG_STATE_READING_ID: - { - int res; - - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_READING_ID\n"); - - if (!dcc->relay) { - struct gg_dcc7_welcome_p2p welcome, welcome_ok; - welcome_ok.id = dcc->cid; - - if ((res = recv(dcc->fd, &welcome, sizeof(welcome), 0)) != sizeof(welcome)) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, - "// gg_dcc7_watch_fd() recv() " - "failed (%d, %s)\n", res, - strerror(errno)); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = GG_ERROR_DCC7_HANDSHAKE; - return e; - } - - if (memcmp(&welcome, &welcome_ok, sizeof(welcome))) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() invalid id\n"); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = GG_ERROR_DCC7_HANDSHAKE; - return e; - } - } else { - struct gg_dcc7_welcome_server welcome, welcome_ok; - welcome_ok.magic = GG_DCC7_WELCOME_SERVER; - welcome_ok.id = dcc->cid; - - if ((res = recv(dcc->fd, &welcome, sizeof(welcome), 0)) != sizeof(welcome)) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, - "// gg_dcc7_watch_fd() recv() " - "failed (%d, %s)\n", - res, strerror(errno)); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = GG_ERROR_DCC7_HANDSHAKE; - return e; - } - - if (memcmp(&welcome, &welcome_ok, sizeof(welcome)) != 0) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() invalid id\n"); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = GG_ERROR_DCC7_HANDSHAKE; - return e; - } - } - - if (dcc->incoming) { - dcc->state = GG_STATE_SENDING_ID; - dcc->check = GG_CHECK_WRITE; - dcc->timeout = GG_DEFAULT_TIMEOUT; - } else { - gg_dcc7_postauth_fixup(dcc); - dcc->timeout = GG_DEFAULT_TIMEOUT; - } - - return e; - } - - case GG_STATE_SENDING_ID: - { - int res; - - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_SENDING_ID\n"); - - if (!dcc->relay) { - struct gg_dcc7_welcome_p2p welcome; - - welcome.id = dcc->cid; - - if ((res = send(dcc->fd, &welcome, sizeof(welcome), 0)) != sizeof(welcome)) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, - "// gg_dcc7_watch_fd() send() " - "failed (%d, %s)\n", - res, strerror(errno)); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = GG_ERROR_DCC7_HANDSHAKE; - return e; - } - } else { - struct gg_dcc7_welcome_server welcome; - - welcome.magic = gg_fix32(GG_DCC7_WELCOME_SERVER); - welcome.id = dcc->cid; - - if ((res = send(dcc->fd, &welcome, sizeof(welcome), 0)) != sizeof(welcome)) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, - "// gg_dcc7_watch_fd() send() " - "failed (%d, %s)\n", res, - strerror(errno)); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = GG_ERROR_DCC7_HANDSHAKE; - return e; - } - } - - if (dcc->incoming) { - gg_dcc7_postauth_fixup(dcc); - dcc->timeout = GG_DEFAULT_TIMEOUT; - } else { - dcc->state = GG_STATE_READING_ID; - dcc->check = GG_CHECK_READ; - dcc->timeout = GG_DEFAULT_TIMEOUT; - } - - return e; - } - - case GG_STATE_SENDING_FILE: - { - char buf[1024]; - size_t chunk; - int res; - - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd()" - " GG_STATE_SENDING_FILE (offset=%d, size=%d)\n", - dcc->offset, dcc->size); - - if (dcc->offset >= dcc->size) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() offset >= size, finished\n"); - e->type = GG_EVENT_DCC7_DONE; - e->event.dcc7_done.dcc7 = dcc; - return e; - } - - if (dcc->seek && lseek(dcc->file_fd, dcc->offset, SEEK_SET) == (off_t) -1) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, - "// gg_dcc7_watch_fd() lseek() failed " - "(%s)\n", strerror(errno)); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = GG_ERROR_DCC7_FILE; - return e; - } - - if ((chunk = dcc->size - dcc->offset) > sizeof(buf)) - chunk = sizeof(buf); - - if ((res = read(dcc->file_fd, buf, chunk)) < 1) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, - "// gg_dcc7_watch_fd() read() failed " - "(res=%d, %s)\n", res, strerror(errno)); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = (res == -1) ? GG_ERROR_DCC7_FILE : GG_ERROR_DCC7_EOF; - return e; - } - - if ((res = send(dcc->fd, buf, res, 0)) == -1) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, - "// gg_dcc7_watch_fd() send() failed " - "(%s)\n", strerror(errno)); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = GG_ERROR_DCC7_NET; - return e; - } - - dcc->offset += res; - - if (dcc->offset >= dcc->size) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() finished\n"); - e->type = GG_EVENT_DCC7_DONE; - e->event.dcc7_done.dcc7 = dcc; - return e; - } - - dcc->state = GG_STATE_SENDING_FILE; - dcc->check = GG_CHECK_WRITE; - dcc->timeout = GG_DCC7_TIMEOUT_SEND; - - return e; - } - - case GG_STATE_GETTING_FILE: - { - char buf[1024]; - int res, wres; - - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd()" - " GG_STATE_GETTING_FILE (offset=%d, size=%d)\n", - dcc->offset, dcc->size); - - if (dcc->offset >= dcc->size) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() finished\n"); - e->type = GG_EVENT_DCC7_DONE; - e->event.dcc7_done.dcc7 = dcc; - return e; - } - - if ((res = recv(dcc->fd, buf, sizeof(buf), 0)) < 1) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, - "// gg_dcc7_watch_fd() recv() failed " - "(fd=%d, res=%d, %s)\n", dcc->fd, res, - strerror(errno)); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = (res == -1) ? GG_ERROR_DCC7_NET : GG_ERROR_DCC7_EOF; - return e; - } - - /* XXX zapisywać do skutku? */ - - if ((wres = write(dcc->file_fd, buf, res)) < res) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, - "// gg_dcc7_watch_fd() write() failed " - "(fd=%d, res=%d, %s)\n", dcc->file_fd, - wres, strerror(errno)); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = GG_ERROR_DCC7_FILE; - return e; - } - - dcc->offset += res; - - if (dcc->offset >= dcc->size) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() finished\n"); - e->type = GG_EVENT_DCC7_DONE; - e->event.dcc7_done.dcc7 = dcc; - return e; - } - - dcc->state = GG_STATE_GETTING_FILE; - dcc->check = GG_CHECK_READ; - dcc->timeout = GG_DCC7_TIMEOUT_GET; - - return e; - } - - case GG_STATE_RESOLVING_RELAY: - { - struct in_addr addr; - int res; - - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_RESOLVING_RELAY\n"); - - do { - res = gg_resolver_recv(dcc->fd, &addr, sizeof(addr)); - } while (res == -1 && errno == EINTR); - - dcc->sess->resolver_cleanup(&dcc->resolver, 0); - - if (res != sizeof(addr) || addr.s_addr == INADDR_NONE) { - int errno_save = errno; - - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() resolving failed\n"); - close(dcc->fd); - dcc->fd = -1; - errno = errno_save; - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = GG_ERROR_DCC7_RELAY; - return e; - } - - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd()" - " resolved, connecting to %s:%d\n", - inet_ntoa(addr), GG_RELAY_PORT); - - if ((dcc->fd = gg_connect(&addr, GG_RELAY_PORT, 1)) == -1) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, - "// gg_dcc7_watch_fd() connection " - "failed (errno=%d, %s), critical\n", - errno, strerror(errno)); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = GG_ERROR_DCC7_RELAY; - return e; - } - - dcc->state = GG_STATE_CONNECTING_RELAY; - dcc->check = GG_CHECK_WRITE; - dcc->timeout = GG_DEFAULT_TIMEOUT; - - e->type = GG_EVENT_DCC7_PENDING; - e->event.dcc7_pending.dcc7 = dcc; - - return e; - } - - case GG_STATE_CONNECTING_RELAY: - { - int res; - socklen_t res_size = sizeof(res); - struct gg_dcc7_relay_req pkt; - - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_CONNECTING_RELAY\n"); - - if (getsockopt(dcc->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) != 0 || res != 0) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, - "// gg_dcc7_watch_fd() connection " - "failed (errno=%d, %s)\n", - res, strerror(res)); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = GG_ERROR_DCC7_RELAY; - return e; - } - - memset(&pkt, 0, sizeof(pkt)); - pkt.magic = gg_fix32(GG_DCC7_RELAY_REQUEST); - pkt.len = gg_fix32(sizeof(pkt)); - pkt.id = dcc->cid; - pkt.type = gg_fix16(GG_DCC7_RELAY_TYPE_SERVER); - pkt.dunno1 = gg_fix16(GG_DCC7_RELAY_DUNNO1); - - gg_debug_dcc(dcc, GG_DEBUG_DUMP, "// gg_dcc7_watch_fd()" - " send pkt(0x%.2x)\n", gg_fix32(pkt.magic)); - gg_debug_dump_dcc(dcc, GG_DEBUG_DUMP, (const char*) &pkt, sizeof(pkt)); - - if ((res = send(dcc->fd, &pkt, sizeof(pkt), 0)) != sizeof(pkt)) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() sending failed\n"); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = GG_ERROR_DCC7_RELAY; - return e; - } - - dcc->state = GG_STATE_READING_RELAY; - dcc->check = GG_CHECK_READ; - dcc->timeout = GG_DEFAULT_TIMEOUT; - - return e; - } - - case GG_STATE_READING_RELAY: - { - char buf[256]; - struct gg_dcc7_relay_reply *pkt; - struct gg_dcc7_relay_reply_server srv; - size_t max_relay_count = (sizeof(buf) - sizeof(*pkt)) / sizeof(srv); - int res; - int i; - - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_READING_RELAY\n"); - - if ((res = recv(dcc->fd, buf, sizeof(buf), 0)) < (int) sizeof(*pkt)) { - if (res == 0) - errno = ECONNRESET; - gg_debug_dcc(dcc, GG_DEBUG_MISC, - "// gg_dcc7_watch_fd() recv() failed " - "(%d, %s)\n", res, strerror(errno)); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = GG_ERROR_DCC7_RELAY; - return e; - } - - pkt = (struct gg_dcc7_relay_reply*) buf; - - if (gg_fix32(pkt->magic) != GG_DCC7_RELAY_REPLY || - gg_fix32(pkt->rcount) < 1 || - gg_fix32(pkt->rcount) > 256 || - gg_fix32(pkt->len) < sizeof(*pkt) + - gg_fix32(pkt->rcount) * sizeof(srv)) - { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_wathc_fd() invalid reply\n"); - errno = EINVAL; - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = GG_ERROR_DCC7_RELAY; - return e; - } - - gg_debug_dcc(dcc, GG_DEBUG_DUMP, - "// gg_dcc7_get_relay() read pkt(0x%.2x)\n", - gg_fix32(pkt->magic)); - gg_debug_dump_dcc(dcc, GG_DEBUG_DUMP, buf, res); - - free(dcc->relay_list); - - dcc->relay_index = 0; - dcc->relay_count = gg_fix32(pkt->rcount); - - if (dcc->relay_count > 0xffff || - (size_t)dcc->relay_count > max_relay_count) - { - gg_debug_dcc(dcc, GG_DEBUG_MISC, - "// gg_dcc7_watch_fd() relay_count out " - "of bounds (%d)\n", dcc->relay_count); - dcc->relay_count = 0; - free(e); - return NULL; - } - - dcc->relay_list = malloc(dcc->relay_count * sizeof(gg_dcc7_relay_t)); - - if (dcc->relay_list == NULL) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() not enough memory\n"); - dcc->relay_count = 0; - free(e); - return NULL; - } - - for (i = 0; i < dcc->relay_count; i++) { - struct in_addr addr; - - memcpy(&srv, buf + sizeof(*pkt) + i * sizeof(srv), sizeof(srv)); - dcc->relay_list[i].addr = srv.addr; - dcc->relay_list[i].port = gg_fix16(srv.port); - dcc->relay_list[i].family = srv.family; - - addr.s_addr = srv.addr; - gg_debug_dcc(dcc, GG_DEBUG_MISC, - "// %s %d %d\n", inet_ntoa(addr), - gg_fix16(srv.port), srv.family); - } - - dcc->relay = 1; - - for (; dcc->relay_index < dcc->relay_count; dcc->relay_index++) { - dcc->remote_addr = dcc->relay_list[dcc->relay_index].addr; - dcc->remote_port = dcc->relay_list[dcc->relay_index].port; - - if (gg_dcc7_connect(dcc) == 0) - break; - } - - if (dcc->relay_index >= dcc->relay_count) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() no relay available\n"); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = GG_ERROR_DCC7_RELAY; - return e; - } - - return e; - } - - default: - { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_???\n"); - e->type = GG_EVENT_DCC7_ERROR; - e->event.dcc_error = GG_ERROR_DCC7_HANDSHAKE; - - return e; - } - } - - return e; -} - -/** - * Zwalnia zasoby używane przez połączenie bezpośrednie. - * - * \param dcc Struktura połączenia - * - * \ingroup dcc7 - */ -void gg_dcc7_free(struct gg_dcc7 *dcc) -{ - gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_free(%p)\n", dcc); - - if (!dcc) - return; - - if (dcc->fd != -1) - close(dcc->fd); - - if (dcc->file_fd != -1) - gg_file_close(dcc->file_fd); - - if (dcc->sess) - gg_dcc7_session_remove(dcc->sess, dcc); - - free(dcc->relay_list); - - free(dcc); -}
--- a/libpurple/protocols/gg/lib/debug.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,397 +0,0 @@ -/* - * (C) Copyright 2001-2006 Wojtek Kaniewski <wojtekka@irc.pl> - * Robert J. Woźny <speedy@ziew.org> - * Arkadiusz Miśkiewicz <arekm@pld-linux.org> - * Tomasz Chiliński <chilek@chilan.com> - * Adam Wysocki <gophi@ekg.chmurka.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file debug.c - * - * \brief Funkcje odpluskwiania - */ -#include <sys/types.h> -#include <errno.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> - -#include "libgadu.h" -#include "debug.h" - -/** - * Poziom rejestracji informacji odpluskwiających. Zmienna jest maską bitową - * składającą się ze stałych \c GG_DEBUG_... - * - * \ingroup debug - */ -int gg_debug_level = 0; - -/** - * Funkcja, do której są przekazywane informacje odpluskwiające. Jeśli zarówno - * ten \c gg_debug_handler, jak i \c gg_debug_handler_session, są równe - * \c NULL, informacje są wysyłane do standardowego wyjścia błędu (\c stderr). - * - * \param level Poziom rejestracji - * \param format Format wiadomości (zgodny z \c printf) - * \param ap Lista argumentów (zgodna z \c printf) - * - * \note Funkcja jest przesłaniana przez \c gg_debug_handler_session. - * - * \ingroup debug - */ -void (*gg_debug_handler)(int level, const char *format, va_list ap) = NULL; - -/** - * Funkcja, do której są przekazywane informacje odpluskwiające. Jeśli zarówno - * ten \c gg_debug_handler, jak i \c gg_debug_handler_session, są równe - * \c NULL, informacje są wysyłane do standardowego wyjścia błędu. - * - * \param sess Sesja której dotyczy informacja lub \c NULL - * \param level Poziom rejestracji - * \param format Format wiadomości (zgodny z \c printf) - * \param ap Lista argumentów (zgodna z \c printf) - * - * \note Funkcja przesłania przez \c gg_debug_handler_session. - * - * \ingroup debug - */ -void (*gg_debug_handler_session)(struct gg_session *sess, int level, const char *format, va_list ap) = NULL; - -/** - * Plik, do którego będą przekazywane informacje odpluskwiania. - * - * Funkcja \c gg_debug() i pochodne mogą być przechwytywane przez aplikację - * korzystającą z biblioteki, by wyświetlić je na żądanie użytkownika lub - * zapisać do późniejszej analizy. Jeśli nie określono pliku, wybrane - * informacje będą wysyłane do standardowego wyjścia błędu (\c stderr). - * - * \ingroup debug - */ -FILE *gg_debug_file = NULL; - -#ifndef GG_DEBUG_DISABLE - -/** - * \internal Przekazuje informacje odpluskwiania do odpowiedniej funkcji. - * - * Jeśli aplikacja ustawiła odpowiednią funkcję obsługi w - * \c gg_debug_handler_session lub \c gg_debug_handler, jest ona wywoływana. - * W przeciwnym wypadku wynik jest wysyłany do standardowego wyjścia błędu. - * - * \param sess Struktura sesji (może być \c NULL) - * \param level Poziom informacji - * \param format Format wiadomości (zgodny z \c printf) - * \param ap Lista argumentów (zgodna z \c printf) - */ -void gg_debug_common(struct gg_session *sess, int level, const char *format, va_list ap) -{ - if (gg_debug_handler_session != NULL) - (*gg_debug_handler_session)(sess, level, format, ap); - else if (gg_debug_handler != NULL) - (*gg_debug_handler)(level, format, ap); - else if ((gg_debug_level & level) != 0) - vfprintf((gg_debug_file) ? gg_debug_file : stderr, format, ap); -} - - -/** - * \internal Przekazuje informację odpluskawiania. - * - * \param level Poziom wiadomości - * \param format Format wiadomości (zgodny z \c printf) - * - * \ingroup debug - */ -void gg_debug(int level, const char *format, ...) -{ - va_list ap; - int old_errno = errno; - - va_start(ap, format); - gg_debug_common(NULL, level, format, ap); - va_end(ap); - errno = old_errno; -} - -/** - * \internal Przekazuje informację odpluskwiania związaną z sesją. - * - * \param gs Struktura sesji - * \param level Poziom wiadomości - * \param format Format wiadomości (zgodny z \c printf) - * - * \ingroup debug - */ -void gg_debug_session(struct gg_session *gs, int level, const char *format, ...) -{ - va_list ap; - int old_errno = errno; - - va_start(ap, format); - gg_debug_common(gs, level, format, ap); - va_end(ap); - errno = old_errno; -} - -/** - * \internal Przekazuje zrzut bufora do odpluskwiania. - * - * \param gs Struktura sesji - * \param level Poziom wiadomości - * \param buf Bufor danych - * \param len Długość bufora danych - * - * \ingroup debug - */ -void gg_debug_dump(struct gg_session *gs, int level, const char *buf, size_t len) -{ - char line[80]; - unsigned int i, j; - - for (i = 0; i < len; i += 16) { - int ofs; - - sprintf(line, "%.4x: ", i); - ofs = 6; - - for (j = 0; j < 16; j++) { - if (i + j < len) - sprintf(line + ofs, " %02x", (unsigned char) buf[i + j]); - else - sprintf(line + ofs, " "); - - ofs += 3; - } - - sprintf(line + ofs, " "); - ofs += 2; - - for (j = 0; j < 16; j++) { - unsigned char ch; - - if (i + j < len) { - ch = buf[i + j]; - - if (ch < 32 || ch > 126) - ch = '.'; - } else { - ch = ' '; - } - - line[ofs++] = ch; - } - - line[ofs++] = '\n'; - line[ofs++] = 0; - - gg_debug_session(gs, level, "%s", line); - } -} - -/** - * \internal Zwraca ciąg z nazwą podanego stanu sesji. - * - * \param state Stan sesji. - * - * \return Ciąg z nazwą stanu - * - * \ingroup debug - */ -const char *gg_debug_state(enum gg_state_t state) -{ - switch (state) { -#define GG_DEBUG_STATE(x) case x: return #x; - GG_DEBUG_STATE(GG_STATE_IDLE) - GG_DEBUG_STATE(GG_STATE_RESOLVING) - GG_DEBUG_STATE(GG_STATE_CONNECTING) - GG_DEBUG_STATE(GG_STATE_READING_DATA) - GG_DEBUG_STATE(GG_STATE_ERROR) - GG_DEBUG_STATE(GG_STATE_CONNECTING_HUB) - GG_DEBUG_STATE(GG_STATE_CONNECTING_GG) - GG_DEBUG_STATE(GG_STATE_READING_KEY) - GG_DEBUG_STATE(GG_STATE_READING_REPLY) - GG_DEBUG_STATE(GG_STATE_CONNECTED) - GG_DEBUG_STATE(GG_STATE_SENDING_QUERY) - GG_DEBUG_STATE(GG_STATE_READING_HEADER) - GG_DEBUG_STATE(GG_STATE_PARSING) - GG_DEBUG_STATE(GG_STATE_DONE) - GG_DEBUG_STATE(GG_STATE_LISTENING) - GG_DEBUG_STATE(GG_STATE_READING_UIN_1) - GG_DEBUG_STATE(GG_STATE_READING_UIN_2) - GG_DEBUG_STATE(GG_STATE_SENDING_ACK) - GG_DEBUG_STATE(GG_STATE_READING_ACK) - GG_DEBUG_STATE(GG_STATE_READING_REQUEST) - GG_DEBUG_STATE(GG_STATE_SENDING_REQUEST) - GG_DEBUG_STATE(GG_STATE_SENDING_FILE_INFO) - GG_DEBUG_STATE(GG_STATE_READING_PRE_FILE_INFO) - GG_DEBUG_STATE(GG_STATE_READING_FILE_INFO) - GG_DEBUG_STATE(GG_STATE_SENDING_FILE_ACK) - GG_DEBUG_STATE(GG_STATE_READING_FILE_ACK) - GG_DEBUG_STATE(GG_STATE_SENDING_FILE_HEADER) - GG_DEBUG_STATE(GG_STATE_READING_FILE_HEADER) - GG_DEBUG_STATE(GG_STATE_GETTING_FILE) - GG_DEBUG_STATE(GG_STATE_SENDING_FILE) - GG_DEBUG_STATE(GG_STATE_READING_VOICE_ACK) - GG_DEBUG_STATE(GG_STATE_READING_VOICE_HEADER) - GG_DEBUG_STATE(GG_STATE_READING_VOICE_SIZE) - GG_DEBUG_STATE(GG_STATE_READING_VOICE_DATA) - GG_DEBUG_STATE(GG_STATE_SENDING_VOICE_ACK) - GG_DEBUG_STATE(GG_STATE_SENDING_VOICE_REQUEST) - GG_DEBUG_STATE(GG_STATE_READING_TYPE) - GG_DEBUG_STATE(GG_STATE_TLS_NEGOTIATION) - GG_DEBUG_STATE(GG_STATE_REQUESTING_ID) - GG_DEBUG_STATE(GG_STATE_WAITING_FOR_ACCEPT) - GG_DEBUG_STATE(GG_STATE_WAITING_FOR_INFO) - GG_DEBUG_STATE(GG_STATE_READING_ID) - GG_DEBUG_STATE(GG_STATE_SENDING_ID) - GG_DEBUG_STATE(GG_STATE_RESOLVING_GG) - GG_DEBUG_STATE(GG_STATE_RESOLVING_RELAY) - GG_DEBUG_STATE(GG_STATE_CONNECTING_RELAY) - GG_DEBUG_STATE(GG_STATE_READING_RELAY) - GG_DEBUG_STATE(GG_STATE_DISCONNECTING) - GG_DEBUG_STATE(GG_STATE_CONNECT_HUB) - GG_DEBUG_STATE(GG_STATE_CONNECT_PROXY_HUB) - GG_DEBUG_STATE(GG_STATE_CONNECT_GG) - GG_DEBUG_STATE(GG_STATE_CONNECT_PROXY_GG) - GG_DEBUG_STATE(GG_STATE_CONNECTING_PROXY_HUB) - GG_DEBUG_STATE(GG_STATE_CONNECTING_PROXY_GG) - GG_DEBUG_STATE(GG_STATE_RESOLVE_HUB_SYNC) - GG_DEBUG_STATE(GG_STATE_RESOLVE_HUB_ASYNC) - GG_DEBUG_STATE(GG_STATE_RESOLVE_PROXY_HUB_SYNC) - GG_DEBUG_STATE(GG_STATE_RESOLVE_PROXY_HUB_ASYNC) - GG_DEBUG_STATE(GG_STATE_RESOLVE_PROXY_GG_SYNC) - GG_DEBUG_STATE(GG_STATE_RESOLVE_PROXY_GG_ASYNC) - GG_DEBUG_STATE(GG_STATE_RESOLVE_GG_SYNC) - GG_DEBUG_STATE(GG_STATE_RESOLVE_GG_ASYNC) - GG_DEBUG_STATE(GG_STATE_RESOLVING_HUB) - GG_DEBUG_STATE(GG_STATE_RESOLVING_PROXY_HUB) - GG_DEBUG_STATE(GG_STATE_RESOLVING_PROXY_GG) - GG_DEBUG_STATE(GG_STATE_SEND_HUB) - GG_DEBUG_STATE(GG_STATE_SEND_PROXY_HUB) - GG_DEBUG_STATE(GG_STATE_SEND_PROXY_GG) - GG_DEBUG_STATE(GG_STATE_SENDING_HUB) - GG_DEBUG_STATE(GG_STATE_SENDING_PROXY_HUB) - GG_DEBUG_STATE(GG_STATE_SENDING_PROXY_GG) - GG_DEBUG_STATE(GG_STATE_READING_HUB) - GG_DEBUG_STATE(GG_STATE_READING_PROXY_HUB) - GG_DEBUG_STATE(GG_STATE_READING_PROXY_GG) -#undef GG_DEBUG_STATE - - /* Celowo nie ma default, żeby kompilator wyłapał brakujące stany */ - } - - return NULL; -} - -/** - * \internal Zwraca ciąg z nazwą podanego zdarzenia. - * - * \param event Zdarzenie. - * - * \return Ciąg z nazwą zdarzenia - * - * \ingroup debug - */ -const char *gg_debug_event(enum gg_event_t event) -{ - switch (event) { -#define GG_DEBUG_EVENT(x) case x: return #x; - GG_DEBUG_EVENT(GG_EVENT_NONE) - GG_DEBUG_EVENT(GG_EVENT_MSG) - GG_DEBUG_EVENT(GG_EVENT_NOTIFY) - GG_DEBUG_EVENT(GG_EVENT_NOTIFY_DESCR) - GG_DEBUG_EVENT(GG_EVENT_STATUS) - GG_DEBUG_EVENT(GG_EVENT_ACK) - GG_DEBUG_EVENT(GG_EVENT_PONG) - GG_DEBUG_EVENT(GG_EVENT_CONN_FAILED) - GG_DEBUG_EVENT(GG_EVENT_CONN_SUCCESS) - GG_DEBUG_EVENT(GG_EVENT_DISCONNECT) - GG_DEBUG_EVENT(GG_EVENT_DCC_NEW) - GG_DEBUG_EVENT(GG_EVENT_DCC_ERROR) - GG_DEBUG_EVENT(GG_EVENT_DCC_DONE) - GG_DEBUG_EVENT(GG_EVENT_DCC_CLIENT_ACCEPT) - GG_DEBUG_EVENT(GG_EVENT_DCC_CALLBACK) - GG_DEBUG_EVENT(GG_EVENT_DCC_NEED_FILE_INFO) - GG_DEBUG_EVENT(GG_EVENT_DCC_NEED_FILE_ACK) - GG_DEBUG_EVENT(GG_EVENT_DCC_NEED_VOICE_ACK) - GG_DEBUG_EVENT(GG_EVENT_DCC_VOICE_DATA) - GG_DEBUG_EVENT(GG_EVENT_PUBDIR50_SEARCH_REPLY) - GG_DEBUG_EVENT(GG_EVENT_PUBDIR50_READ) - GG_DEBUG_EVENT(GG_EVENT_PUBDIR50_WRITE) - GG_DEBUG_EVENT(GG_EVENT_STATUS60) - GG_DEBUG_EVENT(GG_EVENT_NOTIFY60) - GG_DEBUG_EVENT(GG_EVENT_USERLIST) - GG_DEBUG_EVENT(GG_EVENT_IMAGE_REQUEST) - GG_DEBUG_EVENT(GG_EVENT_IMAGE_REPLY) - GG_DEBUG_EVENT(GG_EVENT_DCC_ACK) - GG_DEBUG_EVENT(GG_EVENT_DCC7_NEW) - GG_DEBUG_EVENT(GG_EVENT_DCC7_ACCEPT) - GG_DEBUG_EVENT(GG_EVENT_DCC7_REJECT) - GG_DEBUG_EVENT(GG_EVENT_DCC7_CONNECTED) - GG_DEBUG_EVENT(GG_EVENT_DCC7_ERROR) - GG_DEBUG_EVENT(GG_EVENT_DCC7_DONE) - GG_DEBUG_EVENT(GG_EVENT_DCC7_PENDING) - GG_DEBUG_EVENT(GG_EVENT_XML_EVENT) - GG_DEBUG_EVENT(GG_EVENT_JSON_EVENT) - GG_DEBUG_EVENT(GG_EVENT_ACK110) - GG_DEBUG_EVENT(GG_EVENT_DISCONNECT_ACK) - GG_DEBUG_EVENT(GG_EVENT_TYPING_NOTIFICATION) - GG_DEBUG_EVENT(GG_EVENT_USER_DATA) - GG_DEBUG_EVENT(GG_EVENT_MULTILOGON_MSG) - GG_DEBUG_EVENT(GG_EVENT_MULTILOGON_INFO) - GG_DEBUG_EVENT(GG_EVENT_USERLIST100_VERSION) - GG_DEBUG_EVENT(GG_EVENT_USERLIST100_REPLY) - GG_DEBUG_EVENT(GG_EVENT_IMTOKEN) - GG_DEBUG_EVENT(GG_EVENT_PONG110) - GG_DEBUG_EVENT(GG_EVENT_CHAT_INFO) - GG_DEBUG_EVENT(GG_EVENT_CHAT_INFO_GOT_ALL) - GG_DEBUG_EVENT(GG_EVENT_CHAT_INFO_UPDATE) - GG_DEBUG_EVENT(GG_EVENT_CHAT_CREATED) - GG_DEBUG_EVENT(GG_EVENT_CHAT_INVITE_ACK) -#undef GG_DEBUG_EVENT - - /* Celowo nie ma default, żeby kompilator wyłapał brakujące zdarzenia */ - } - - return NULL; -} - -#else - -#undef gg_debug_common -void gg_debug_common(struct gg_session *sess, int level, const char *format, va_list ap) -{ -} - -#undef gg_debug -void gg_debug(int level, const char *format, ...) -{ -} - -#undef gg_debug_session -void gg_debug_session(struct gg_session *gs, int level, const char *format, ...) -{ -} - -#undef gg_debug_dump -void gg_debug_dump(struct gg_session *gs, int level, const char *buf, size_t len) -{ -} - -#endif
--- a/libpurple/protocols/gg/lib/debug.h Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * (C) Copyright 2009 Wojtek Kaniewski <wojtekka@irc.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef LIBGADU_DEBUG_H -#define LIBGADU_DEBUG_H - -#include "libgadu.h" - -void gg_debug_dump(struct gg_session *sess, int level, const char *buf, size_t len); -void gg_debug_common(struct gg_session *sess, int level, const char *format, va_list ap); - -#endif /* LIBGADU_DEBUG_H */
--- a/libpurple/protocols/gg/lib/deflate.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,231 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2011 Bartosz Brachaczek <b.brachaczek@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file deflate.c - * - * \brief Funkcje kompresji Deflate - */ - -#include <stdlib.h> -#include <string.h> - -#include "libgadu.h" -#include "internal.h" -#include "deflate.h" - -#ifdef GG_CONFIG_HAVE_ZLIB -#include <zlib.h> -#endif - -/** - * \internal Kompresuje dane wejściowe algorytmem Deflate z najwyższym - * stopniem kompresji, tak samo jak oryginalny klient. - * - * Wynik funkcji należy zwolnić za pomocą \c free. - * - * \param in Ciąg znaków do skompresowania, zakończony \c \\0 - * \param out_lenp Wskaźnik na zmienną, do której zostanie zapisana - * długość bufora wynikowego - * - * \return Skompresowany ciąg znaków lub \c NULL w przypadku niepowodzenia. - */ -unsigned char *gg_deflate(const char *in, size_t *out_lenp) -{ -#ifdef GG_CONFIG_HAVE_ZLIB - int ret; - z_stream strm; - unsigned char *out, *out2; - size_t out_len; - - if (in == NULL || out_lenp == NULL) - return NULL; - - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - strm.avail_in = strlen(in); - strm.next_in = (unsigned char*) in; - - ret = deflateInit(&strm, Z_BEST_COMPRESSION); - if (ret != Z_OK) { - gg_debug(GG_DEBUG_MISC, "// gg_deflate() deflateInit() failed (%d)\n", ret); - return NULL; - } - - out_len = deflateBound(&strm, strm.avail_in); - out = malloc(out_len); - - if (out == NULL) { - gg_debug(GG_DEBUG_MISC, "// gg_deflate() not enough memory for " - "output data (%" GG_SIZE_FMT ")\n", out_len); - goto fail; - } - - strm.avail_out = out_len; - strm.next_out = out; - - for (;;) { - ret = deflate(&strm, Z_FINISH); - - if (ret == Z_STREAM_END) - break; - - /* raczej nie powinno się zdarzyć przy Z_FINISH i out_len == deflateBound(), - * ale dokumentacja zlib nie wyklucza takiej możliwości */ - if (ret == Z_OK) { - out_len *= 2; - out2 = realloc(out, out_len); - - if (out2 == NULL) { - gg_debug(GG_DEBUG_MISC, "// gg_deflate() not " - "enough memory for output data (%" - GG_SIZE_FMT ")\n", out_len); - goto fail; - } - - out = out2; - - strm.avail_out = out_len / 2; - strm.next_out = out + out_len / 2; - } else { - gg_debug(GG_DEBUG_MISC, "// gg_deflate() deflate() " - "failed (ret=%d, msg=%s)\n", ret, - strm.msg != NULL ? strm.msg : - "no error message provided"); - goto fail; - } - } - - out_len = strm.total_out; - out2 = realloc(out, out_len); - - if (out2 == NULL) { - gg_debug(GG_DEBUG_MISC, "// gg_deflate() not enough memory for " - "output data (%" GG_SIZE_FMT ")\n", out_len); - goto fail; - } - - *out_lenp = out_len; - deflateEnd(&strm); - - return out2; - -fail: - *out_lenp = 0; - deflateEnd(&strm); - free(out); -#endif - return NULL; -} - -/** - * \internal Dekompresuje dane wejściowe w formacie Deflate. - * - * Wynik funkcji należy zwolnić za pomocą \c free. - * - * \param in Bufor danych skompresowanych algorytmem Deflate - * \param length Długość bufora wejściowego - * - * \note Dokleja \c \\0 na końcu bufora wynikowego. - * - * \return Zdekompresowany ciąg znaków, zakończony \c \\0, - * lub \c NULL w przypadku niepowodzenia. - */ -char *gg_inflate(const unsigned char *in, size_t length) -{ -#ifdef GG_CONFIG_HAVE_ZLIB - int ret; - z_stream strm; - char *out = NULL, *out2; - size_t out_len = 1024; - int first = 1; - - if (in == NULL) - return NULL; - - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - strm.avail_in = length; - strm.next_in = (unsigned char*) in; - - ret = inflateInit(&strm); - if (ret != Z_OK) { - gg_debug(GG_DEBUG_MISC, "// gg_inflate() inflateInit() failed (%d)\n", ret); - return NULL; - } - - do { - out_len *= 2; - out2 = realloc(out, out_len); - - if (out2 == NULL) { - gg_debug(GG_DEBUG_MISC, "// gg_inflate() not enough " - "memory for output data (%" GG_SIZE_FMT ")\n", out_len); - goto fail; - } - - out = out2; - - if (first) { - strm.avail_out = out_len; - strm.next_out = (unsigned char*) out; - } else { - strm.avail_out = out_len / 2; - strm.next_out = (unsigned char*) out + out_len / 2; - } - - ret = inflate(&strm, Z_NO_FLUSH); - - if (ret != Z_OK && ret != Z_STREAM_END) { - gg_debug(GG_DEBUG_MISC, "// gg_inflate() inflate() " - "failed (ret=%d, msg=%s)\n", ret, - strm.msg != NULL ? strm.msg : - "no error message provided"); - goto fail; - } - - first = 0; - } while (ret != Z_STREAM_END); - - /* rezerwujemy ostatni znak na NULL-a */ - out_len = strm.total_out + 1; - out2 = realloc(out, out_len); - - if (out2 == NULL) { - gg_debug(GG_DEBUG_MISC, "// gg_inflate() not enough memory for " - "output data (%" GG_SIZE_FMT ")\n", out_len); - goto fail; - } - - out = out2; - out[out_len - 1] = '\0'; - - inflateEnd(&strm); - - return out; - -fail: - inflateEnd(&strm); - free(out); -#endif - return NULL; -}
--- a/libpurple/protocols/gg/lib/deflate.h Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2011 Bartosz Brachaczek <b.brachaczek@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef LIBGADU_DEFLATE_H -#define LIBGADU_DEFLATE_H - -#include "libgadu.h" - -unsigned char *gg_deflate(const char *in, size_t *out_lenp); -char *gg_inflate(const unsigned char *in, size_t length); - -#endif /* LIBGADU_DEFLATE_H */
--- a/libpurple/protocols/gg/lib/encoding.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,272 +0,0 @@ -/* - * (C) Copyright 2008-2009 Jakub Zawadzki <darkjames@darkjames.ath.cx> - * Wojtek Kaniewski <wojtekka@irc.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#include "strman.h" -#include <stdlib.h> -#include <errno.h> - -#include "libgadu.h" -#include "encoding.h" - -/** - * \file encoding.c - * - * \brief Funkcje konwersji kodowania tekstu - */ - -/** - * \internal Tablica konwersji CP1250 na Unikod. - */ -static const uint16_t table_cp1250[] = -{ - 0x20ac, '?', 0x201a, '?', 0x201e, 0x2026, 0x2020, 0x2021, - '?', 0x2030, 0x0160, 0x2039, 0x015a, 0x0164, 0x017d, 0x0179, - '?', 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, - '?', 0x2122, 0x0161, 0x203a, 0x015b, 0x0165, 0x017e, 0x017a, - 0x00a0, 0x02c7, 0x02d8, 0x0141, 0x00a4, 0x0104, 0x00a6, 0x00a7, - 0x00a8, 0x00a9, 0x015e, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x017b, - 0x00b0, 0x00b1, 0x02db, 0x0142, 0x00b4, 0x00b5, 0x00b6, 0x00b7, - 0x00b8, 0x0105, 0x015f, 0x00bb, 0x013d, 0x02dd, 0x013e, 0x017c, - 0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7, - 0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e, - 0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7, - 0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df, - 0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7, - 0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f, - 0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7, - 0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9, -}; - -/** - * \internal Zamienia tekst kodowany CP1250 na UTF-8. - * - * \param src Tekst źródłowy w CP1250. - * \param src_length Długość ciągu źródłowego (nigdy ujemna). - * \param dst_length Długość ciągu docelowego (jeśli -1, nieograniczona). - * - * \return Zaalokowany bufor z tekstem w UTF-8. - */ -static char *gg_encoding_convert_cp1250_utf8(const char *src, int src_length, int dst_length) -{ - int i, j, len; - char *result = NULL; - - for (i = 0, len = 0; (src[i] != 0) && (i < src_length); i++) { - uint16_t uc; - - if ((unsigned char) src[i] < 0x80) - uc = (unsigned char) src[i]; - else - uc = table_cp1250[(unsigned char) src[i] - 128]; - - if (uc < 0x80) - len += 1; - else if (uc < 0x800) - len += 2; - else - len += 3; - } - - if ((dst_length != -1) && (len > dst_length)) - len = dst_length; - - result = malloc(len + 1); - - if (result == NULL) - return NULL; - - for (i = 0, j = 0; (src[i] != 0) && (i < src_length) && (j < len); i++) { - uint16_t uc; - - if ((unsigned char) src[i] < 0x80) - uc = (unsigned char) src[i]; - else - uc = table_cp1250[(unsigned char) src[i] - 128]; - - if (uc < 0x80) - result[j++] = (char) uc; - else if (uc < 0x800) { - if (j + 1 > len) - break; - result[j++] = 0xc0 | ((uc >> 6) & 0x1f); - result[j++] = 0x80 | (uc & 0x3f); - } else { - if (j + 2 > len) - break; - result[j++] = 0xe0 | ((uc >> 12) & 0x1f); - result[j++] = 0x80 | ((uc >> 6) & 0x3f); - result[j++] = 0x80 | (uc & 0x3f); - } - } - - result[j] = 0; - - return result; -} - -/** - * \internal Zamienia tekst kodowany UTF-8 na CP1250. - * - * \param src Tekst źródłowy w UTF-8. - * \param src_length Długość ciągu źródłowego (nigdy ujemna). - * \param dst_length Długość ciągu docelowego (jeśli -1, nieograniczona). - * - * \return Zaalokowany bufor z tekstem w CP1250. - */ -static char *gg_encoding_convert_utf8_cp1250(const char *src, int src_length, int dst_length) -{ - char *result; - int i, j, len, uc_left = 0; - uint32_t uc = 0, uc_min = 0; - - for (i = 0, len = 0; (src[i] != 0) && (i < src_length); i++) { - if ((src[i] & 0xc0) != 0x80) - len++; - } - - if ((dst_length != -1) && (len > dst_length)) - len = dst_length; - - result = malloc(len + 1); - - if (result == NULL) - return NULL; - - for (i = 0, j = 0; (src[i] != 0) && (i < src_length) && (j < len); i++) { - if ((unsigned char) src[i] >= 0xf5) { - if (uc_left != 0) - result[j++] = '?'; - /* Restricted sequences */ - result[j++] = '?'; - uc_left = 0; - } else if ((src[i] & 0xf8) == 0xf0) { - if (uc_left != 0) - result[j++] = '?'; - uc = src[i] & 0x07; - uc_left = 3; - uc_min = 0x10000; - } else if ((src[i] & 0xf0) == 0xe0) { - if (uc_left != 0) - result[j++] = '?'; - uc = src[i] & 0x0f; - uc_left = 2; - uc_min = 0x800; - } else if ((src[i] & 0xe0) == 0xc0) { - if (uc_left != 0) - result[j++] = '?'; - uc = src[i] & 0x1f; - uc_left = 1; - uc_min = 0x80; - } else if ((src[i] & 0xc0) == 0x80) { - if (uc_left > 0) { - uc <<= 6; - uc |= src[i] & 0x3f; - uc_left--; - - if (uc_left == 0) { - int valid = 0; - int k; - - if (uc >= uc_min) { - for (k = 0; k < 128; k++) { - if (uc == table_cp1250[k]) { - result[j++] = k + 128; - valid = 1; - break; - } - } - } - - if (!valid && uc != 0xfeff) /* Byte Order Mark */ - result[j++] = '?'; - } - } - } else { - if (uc_left != 0) { - result[j++] = '?'; - uc_left = 0; - } - result[j++] = src[i]; - } - } - - if ((uc_left != 0) && (src[i] == 0)) - result[j++] = '?'; - - result[j] = 0; - - return result; -} - -/** - * \internal Zamienia kodowanie tekstu. - * - * \param src Tekst źródłowy. - * \param src_encoding Kodowanie tekstu źródłowego. - * \param dst_encoding Kodowanie tekstu docelowego. - * \param src_length Długość ciągu źródłowego w bajtach (jeśli -1, zostanie obliczona na podstawie zawartości \p src). - * \param dst_length Długość ciągu docelowego w bajtach (jeśli -1, nieograniczona). - * - * \return Zaalokowany bufor z tekstem w kodowaniu docelowym. - */ -char *gg_encoding_convert(const char *src, gg_encoding_t src_encoding, - gg_encoding_t dst_encoding, int src_length, int dst_length) -{ - char *result; - - if (src == NULL) { - errno = EINVAL; - return NULL; - } - - /* specjalny przypadek obsługiwany ekspresowo */ - if ((dst_encoding == src_encoding) && (dst_length == -1) && (src_length == -1)) - return strdup(src); - - if (src_length == -1) - src_length = strlen(src); - - if (dst_encoding == src_encoding) { - int len; - - if (dst_length == -1) - len = src_length; - else - len = (src_length < dst_length) ? src_length : dst_length; - - result = malloc(len + 1); - - if (result == NULL) - return NULL; - - strncpy(result, src, len); - result[len] = 0; - - return result; - } - - if (dst_encoding == GG_ENCODING_CP1250 && src_encoding == GG_ENCODING_UTF8) - return gg_encoding_convert_utf8_cp1250(src, src_length, dst_length); - - if (dst_encoding == GG_ENCODING_UTF8 && src_encoding == GG_ENCODING_CP1250) - return gg_encoding_convert_cp1250_utf8(src, src_length, dst_length); - - errno = EINVAL; - return NULL; -}
--- a/libpurple/protocols/gg/lib/encoding.h Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -/* - * (C) Copyright 2008-2009 Jakub Zawadzki <darkjames@darkjames.ath.cx> - * Wojtek Kaniewski <wojtekka@irc.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef LIBGADU_ENCODING_H -#define LIBGADU_ENCODING_H - -#include "libgadu.h" - -char *gg_encoding_convert(const char *src, gg_encoding_t src_encoding, - gg_encoding_t dst_encoding, int src_length, int dst_length); - -#endif /* LIBGADU_SESSION_H */
--- a/libpurple/protocols/gg/lib/endian.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,109 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2001-2010 Wojtek Kaniewski <wojtekka@irc.pl> - * Robert J. Woźny <speedy@ziew.org> - * Arkadiusz Miśkiewicz <arekm@pld-linux.org> - * Tomasz Chiliński <chilek@chilan.com> - * Adam Wysocki <gophi@ekg.chmurka.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file endian.c - * - * \brief Konwersja między różnymi kolejnościami bajtów - */ - -#include "libgadu.h" -#include "internal.h" - -/** - * \internal Zamienia kolejność bajtów w 64-bitowym słowie. - * - * Ze względu na little-endianowość protokołu Gadu-Gadu, na maszynach - * big-endianowych odwraca kolejność bajtów w słowie. - * - * \param x Liczba do zamiany - * - * \return Liczba z odpowiednią kolejnością bajtów - * - * \ingroup helper - */ -uint64_t gg_fix64(uint64_t x) -{ -#ifndef GG_CONFIG_BIGENDIAN - return x; -#else - return (uint64_t) - (((x & (uint64_t) 0x00000000000000ffULL) << 56) | - ((x & (uint64_t) 0x000000000000ff00ULL) << 40) | - ((x & (uint64_t) 0x0000000000ff0000ULL) << 24) | - ((x & (uint64_t) 0x00000000ff000000ULL) << 8) | - ((x & (uint64_t) 0x000000ff00000000ULL) >> 8) | - ((x & (uint64_t) 0x0000ff0000000000ULL) >> 24) | - ((x & (uint64_t) 0x00ff000000000000ULL) >> 40) | - ((x & (uint64_t) 0xff00000000000000ULL) >> 56)); -#endif -} - -/** - * \internal Zamienia kolejność bajtów w 32-bitowym słowie. - * - * Ze względu na little-endianowość protokołu Gadu-Gadu, na maszynach - * big-endianowych odwraca kolejność bajtów w słowie. - * - * \param x Liczba do zamiany - * - * \return Liczba z odpowiednią kolejnością bajtów - * - * \ingroup helper - */ -uint32_t gg_fix32(uint32_t x) -{ -#ifndef GG_CONFIG_BIGENDIAN - return x; -#else - return (uint32_t) - (((x & (uint32_t) 0x000000ffU) << 24) | - ((x & (uint32_t) 0x0000ff00U) << 8) | - ((x & (uint32_t) 0x00ff0000U) >> 8) | - ((x & (uint32_t) 0xff000000U) >> 24)); -#endif -} - -/** - * \internal Zamienia kolejność bajtów w 16-bitowym słowie. - * - * Ze względu na little-endianowość protokołu Gadu-Gadu, na maszynach - * big-endianowych zamienia kolejność bajtów w słowie. - * - * \param x Liczba do zamiany - * - * \return Liczba z odpowiednią kolejnością bajtów - * - * \ingroup helper - */ -uint16_t gg_fix16(uint16_t x) -{ -#ifndef GG_CONFIG_BIGENDIAN - return x; -#else - return (uint16_t) - (((x & (uint16_t) 0x00ffU) << 8) | - ((x & (uint16_t) 0xff00U) >> 8)); -#endif -}
--- a/libpurple/protocols/gg/lib/events.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1901 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2001-2006 Wojtek Kaniewski <wojtekka@irc.pl> - * Robert J. Woźny <speedy@ziew.org> - * Arkadiusz Miśkiewicz <arekm@pld-linux.org> - * Adam Wysocki <gophi@ekg.chmurka.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file events.c - * - * \brief Obsługa zdarzeń - * - * \todo Poprawna obsługa gg_proxy_http_only - */ - -#include "strman.h" -#include "network.h" - -#include "libgadu.h" -#include "protocol.h" -#include "internal.h" -#include "encoding.h" -#include "debug.h" -#include "session.h" -#include "resolver.h" -#include "config.h" - -#include <errno.h> -#include <string.h> -#include <stdlib.h> -#include <time.h> -#include <ctype.h> -#ifdef GG_CONFIG_HAVE_GNUTLS -# include <gnutls/gnutls.h> -# include <gnutls/x509.h> -#endif -#ifdef GG_CONFIG_HAVE_OPENSSL -# include <openssl/err.h> -# include <openssl/x509.h> -# include <openssl/rand.h> -#endif - -/** - * Zwalnia pamięć zajmowaną przez informację o zdarzeniu. - * - * Funkcję należy wywoływać za każdym razem gdy funkcja biblioteki zwróci - * strukturę \c gg_event. - * - * \param e Struktura zdarzenia - * - * \ingroup events - */ -void gg_event_free(struct gg_event *e) -{ - gg_debug(GG_DEBUG_FUNCTION, "** gg_event_free(%p);\n", e); - - if (!e) - return; - - switch (e->type) { - case GG_EVENT_MSG: - case GG_EVENT_MULTILOGON_MSG: - free(e->event.msg.message); - free(e->event.msg.formats); - free(e->event.msg.recipients); - free(e->event.msg.xhtml_message); - break; - - case GG_EVENT_NOTIFY: - free(e->event.notify); - break; - - case GG_EVENT_NOTIFY60: - { - int i; - - for (i = 0; e->event.notify60[i].uin; i++) - free(e->event.notify60[i].descr); - - free(e->event.notify60); - - break; - } - - case GG_EVENT_STATUS60: - free(e->event.status60.descr); - break; - - case GG_EVENT_STATUS: - free(e->event.status.descr); - break; - - case GG_EVENT_NOTIFY_DESCR: - free(e->event.notify_descr.notify); - free(e->event.notify_descr.descr); - break; - - case GG_EVENT_DCC_VOICE_DATA: - free(e->event.dcc_voice_data.data); - break; - - case GG_EVENT_PUBDIR50_SEARCH_REPLY: - case GG_EVENT_PUBDIR50_READ: - case GG_EVENT_PUBDIR50_WRITE: - gg_pubdir50_free(e->event.pubdir50); - break; - - case GG_EVENT_USERLIST: - free(e->event.userlist.reply); - break; - - case GG_EVENT_IMAGE_REPLY: - free(e->event.image_reply.filename); - free(e->event.image_reply.image); - break; - - case GG_EVENT_XML_EVENT: - free(e->event.xml_event.data); - break; - - case GG_EVENT_JSON_EVENT: - free(e->event.json_event.data); - free(e->event.json_event.type); - break; - - case GG_EVENT_USER_DATA: - { - unsigned int i, j; - - for (i = 0; i < e->event.user_data.user_count; i++) { - for (j = 0; j < e->event.user_data.users[i].attr_count; j++) { - free(e->event.user_data.users[i].attrs[j].key); - free(e->event.user_data.users[i].attrs[j].value); - } - - free(e->event.user_data.users[i].attrs); - } - - free(e->event.user_data.users); - - break; - } - - case GG_EVENT_MULTILOGON_INFO: - { - int i; - - for (i = 0; i < e->event.multilogon_info.count; i++) - free(e->event.multilogon_info.sessions[i].name); - - free(e->event.multilogon_info.sessions); - - break; - } - - case GG_EVENT_USERLIST100_REPLY: - free(e->event.userlist100_reply.reply); - break; - - case GG_EVENT_IMTOKEN: - free(e->event.imtoken.imtoken); - break; - - case GG_EVENT_CHAT_INFO: - free(e->event.chat_info.participants); - break; - } - - free(e); -} - -/** \cond internal */ - -/** - * \internal Usuwa obrazek z kolejki do wysłania. - * - * \param s Struktura sesji - * \param q Struktura obrazka - * \param freeq Flaga zwolnienia elementu kolejki - * - * \return 0 jeśli się powiodło, -1 jeśli wystąpił błąd - */ -int gg_image_queue_remove(struct gg_session *s, struct gg_image_queue *q, int freeq) -{ - if (!s || !q) { - errno = EFAULT; - return -1; - } - - if (s->images == q) - s->images = q->next; - else { - struct gg_image_queue *qq; - - for (qq = s->images; qq; qq = qq->next) { - if (qq->next == q) { - qq->next = q->next; - break; - } - } - } - - if (freeq) { - free(q->image); - free(q->filename); - free(q); - } - - return 0; -} - -/** \endcond */ - -/** - * \internal Inicjalizuje struktury SSL. - * - * \param gs Struktura sesji - * - * \return 0 jeśli się powiodło, -1 jeśli wystąpił błąd - */ -int gg_session_init_ssl(struct gg_session *gs) -{ -#ifdef GG_CONFIG_HAVE_GNUTLS - gg_session_gnutls_t *tmp; - - tmp = (gg_session_gnutls_t*) gs->ssl; - - if (tmp == NULL) { - tmp = malloc(sizeof(gg_session_gnutls_t)); - - if (tmp == NULL) { - gg_debug(GG_DEBUG_MISC, "// gg_session_connect() out of memory for GnuTLS session\n"); - return -1; - } - - memset(tmp, 0, sizeof(gg_session_gnutls_t)); - - gs->ssl = tmp; - - gnutls_global_init(); - gnutls_certificate_allocate_credentials(&tmp->xcred); -#ifdef GG_CONFIG_SSL_SYSTEM_TRUST -#ifdef HAVE_GNUTLS_CERTIFICATE_SET_X509_SYSTEM_TRUST - gnutls_certificate_set_x509_system_trust(tmp->xcred); -#else - gnutls_certificate_set_x509_trust_file(tmp->xcred, - GG_CONFIG_GNUTLS_SYSTEM_TRUST_STORE, - GNUTLS_X509_FMT_PEM); -#endif -#endif - } else { - gnutls_deinit(tmp->session); - } - - gnutls_init(&tmp->session, GNUTLS_CLIENT); - gnutls_set_default_priority(tmp->session); - gnutls_credentials_set(tmp->session, GNUTLS_CRD_CERTIFICATE, tmp->xcred); - gnutls_transport_set_ptr(tmp->session, (gnutls_transport_ptr_t) (intptr_t) gs->fd); -#endif - -#ifdef GG_CONFIG_HAVE_OPENSSL - char buf[1024]; - - OpenSSL_add_ssl_algorithms(); - - if (!RAND_status()) { - char rdata[1024]; - struct { - time_t time; - void *ptr; - } rstruct; - - time(&rstruct.time); - rstruct.ptr = (void *) &rstruct; - - RAND_seed((void *) rdata, sizeof(rdata)); - RAND_seed((void *) &rstruct, sizeof(rstruct)); - } - - if (gs->ssl_ctx == NULL) { - gs->ssl_ctx = SSL_CTX_new(SSLv3_client_method()); - - if (gs->ssl_ctx == NULL) { - ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); - gg_debug(GG_DEBUG_MISC, "// gg_session_connect() SSL_CTX_new() failed: %s\n", buf); - return -1; - } - - SSL_CTX_set_verify(gs->ssl_ctx, SSL_VERIFY_NONE, NULL); -#ifdef GG_CONFIG_SSL_SYSTEM_TRUST - SSL_CTX_set_default_verify_paths(gs->ssl_ctx); -#endif - } - - if (gs->ssl != NULL) - SSL_free(gs->ssl); - - gs->ssl = SSL_new(gs->ssl_ctx); - - if (gs->ssl == NULL) { - ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); - gg_debug(GG_DEBUG_MISC, "// gg_session_connect() SSL_new() failed: %s\n", buf); - return -1; - } - - SSL_set_fd(gs->ssl, gs->fd); -#endif - - return 0; -} - -/** - * \internal Funkcja próbuje wysłać dane zakolejkowane do wysyłki. - * - * \param sess Struktura sesji - * - * \return 0 jeśli się powiodło, -1 jeśli wystąpił błąd - */ -static int gg_send_queued_data(struct gg_session *sess) -{ - int res; - - if (sess->send_buf == NULL || sess->send_left == 0) - return 0; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() sending %d bytes of queued data\n", sess->send_left); - - res = send(sess->fd, sess->send_buf, sess->send_left, 0); - - if (res == -1) { - if (errno == EAGAIN || errno == EINTR) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd()" - " non-critical send error (errno=%d, %s)\n", - errno, strerror(errno)); - - return 0; - } - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() send() " - "failed (errno=%d, %s)\n", errno, strerror(errno)); - - return -1; - } - - if (res == sess->send_left) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() sent all queued data\n"); - free(sess->send_buf); - sess->send_buf = NULL; - sess->send_left = 0; - } else if (res > 0) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() sent %d" - " bytes of queued data, %d bytes left\n", - res, sess->send_left - res); - - memmove(sess->send_buf, sess->send_buf + res, sess->send_left - res); - sess->send_left -= res; - } - - return 0; -} - -/** - * \internal Sprawdza wynik połączenia asynchronicznego. - * \param gs Struktura sesji - * \param res_ptr Wskaźnik na kod błędu - * \return 0 jeśli się powiodło, -1 jeśli wystąpił błąd - */ -static int gg_async_connect_failed(struct gg_session *gs, int *res_ptr) -{ - int res = 0; - socklen_t res_size = sizeof(res); - - if (!gs->async) - return 0; - - if (gs->timeout == 0) { - *res_ptr = ETIMEDOUT; - return 1; - } - - if (getsockopt(gs->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) == -1) { - *res_ptr = errno; - return 1; - } - - if (res != 0) { - *res_ptr = res; - return 1; - } - - *res_ptr = 0; - - return 0; -} - -typedef enum -{ - GG_ACTION_WAIT, - GG_ACTION_NEXT, - GG_ACTION_FAIL -} gg_action_t; - -typedef gg_action_t (*gg_state_handler_t)(struct gg_session *gs, - struct gg_event *ge, enum gg_state_t next_state, - enum gg_state_t alt_state, enum gg_state_t alt2_state); - -typedef struct -{ - enum gg_state_t state; - gg_state_handler_t handler; - enum gg_state_t next_state; - enum gg_state_t alt_state; - enum gg_state_t alt2_state; -} gg_state_transition_t; - -/* zwraca: - * -1 w przypadku błędu - * 0 jeżeli nie ma ustawionego specjalnego managera gniazdek - * 1 w przypadku powodzenia - */ -static int gg_handle_resolve_custom(struct gg_session *sess, enum gg_state_t next_state) -{ - struct gg_session_private *p = sess->private_data; - int is_tls = 0; - int port; - - if (p->socket_manager_type == GG_SOCKET_MANAGER_TYPE_INTERNAL) - return 0; - - if (p->socket_manager.connect_cb == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR, - "// gg_handle_resolve_custom() socket_manager.connect " - "callback is empty\n"); - return -1; - } - - if (p->socket_handle != NULL) { - gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR, - "// gg_handle_resolve_custom() socket_handle is not " - "NULL\n"); - return -1; - } - - port = sess->connect_port[sess->connect_index]; - if (next_state == GG_STATE_SEND_HUB) - port = GG_APPMSG_PORT; - - if (sess->ssl_flag != GG_SSL_DISABLED && - next_state == GG_STATE_READING_KEY) - { - /* XXX: w tej chwili nie ma możliwości łączenia się do HUBa po - * SSL, ale może będzie w przyszłości */ - is_tls = 1; - } - - if (is_tls && p->socket_manager_type == GG_SOCKET_MANAGER_TYPE_TCP) { - is_tls = 0; - next_state = GG_STATE_TLS_NEGOTIATION; - } - - if (port <= 0) { - gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR, - "// gg_handle_resolve_custom() port <= 0\n"); - return -1; - } - - p->socket_failure = 0; - p->socket_next_state = next_state; - p->socket_handle = p->socket_manager.connect_cb( - p->socket_manager.cb_data, sess->resolver_host, port, is_tls, - sess->async, sess); - - if (p->socket_failure != 0) { - if (p->socket_handle != NULL) { - gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_WARNING, - "// gg_handle_resolve_custom() handle should be" - " empty on error\n"); - } - return -1; - } - - if (p->socket_handle == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR, - "// gg_handle_resolve_custom() returned empty " - "handle\n"); - return -1; - } - - return 1; -} - -static gg_action_t gg_handle_resolve_sync(struct gg_session *sess, - struct gg_event *e, enum gg_state_t next_state, - enum gg_state_t alt_state, enum gg_state_t alt2_state) -{ - struct in_addr addr; - int res; - - res = gg_handle_resolve_custom(sess, alt_state); - if (res == 1) - return GG_ACTION_NEXT; - else if (res == -1) - return GG_ACTION_FAIL; - - addr.s_addr = inet_addr(sess->resolver_host); - - if (addr.s_addr == INADDR_NONE) { - struct in_addr *addr_list = NULL; - unsigned int addr_count; - - if (gg_gethostbyname_real(sess->resolver_host, &addr_list, &addr_count, 0) == -1) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd()" - " host %s not found\n", sess->resolver_host); - e->event.failure = GG_FAILURE_RESOLVING; - free(addr_list); - return GG_ACTION_FAIL; - } - - sess->resolver_result = addr_list; - sess->resolver_count = addr_count; - sess->resolver_index = 0; - } else { - sess->resolver_result = malloc(sizeof(struct in_addr)); - - if (sess->resolver_result == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() out of memory\n"); - return GG_ACTION_FAIL; - } - - sess->resolver_result[0].s_addr = addr.s_addr; - sess->resolver_count = 1; - sess->resolver_index = 0; - } - - sess->state = next_state; - - return GG_ACTION_NEXT; -} - -static gg_action_t gg_handle_resolve_async(struct gg_session *sess, - struct gg_event *e, enum gg_state_t next_state, - enum gg_state_t alt_state, enum gg_state_t alt2_state) -{ - int res; - - res = gg_handle_resolve_custom(sess, alt_state); - if (res == 1) - return GG_ACTION_WAIT; - else if (res == -1) - return GG_ACTION_FAIL; - - if (sess->resolver_start(&sess->fd, &sess->resolver, sess->resolver_host) == -1) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() " - "resolving failed (errno=%d, %s)\n", - errno, strerror(errno)); - e->event.failure = GG_FAILURE_RESOLVING; - return GG_ACTION_FAIL; - } - - sess->state = next_state; - sess->check = GG_CHECK_READ; - sess->timeout = GG_DEFAULT_TIMEOUT; - - return GG_ACTION_WAIT; -} - -static gg_action_t gg_handle_resolving(struct gg_session *sess, - struct gg_event *e, enum gg_state_t next_state, - enum gg_state_t alt_state, enum gg_state_t alt2_state) -{ - char buf[256]; - int count = -1; - int res; - unsigned int i; - struct in_addr *addrs; - - res = gg_resolver_recv(sess->fd, buf, sizeof(buf)); - - if (res == -1 && (errno == EAGAIN || errno == EINTR)) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() " - "non-critical error (errno=%d, %s)\n", - errno, strerror(errno)); - return GG_ACTION_WAIT; - } - - sess->resolver_cleanup(&sess->resolver, 0); - - if (res == -1) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() read " - "error (errno=%d, %s)\n", errno, strerror(errno)); - e->event.failure = GG_FAILURE_RESOLVING; - return GG_ACTION_FAIL; - } - - if (res > 0) { - char *tmp; - - tmp = realloc(sess->recv_buf, sess->recv_done + res); - - if (tmp == NULL) - return GG_ACTION_FAIL; - - sess->recv_buf = tmp; - memcpy(sess->recv_buf + sess->recv_done, buf, res); - sess->recv_done += res; - } - - /* Sprawdź, czy mamy listę zakończoną INADDR_NONE */ - - addrs = (struct in_addr *)(void *)sess->recv_buf; - - for (i = 0; i < sess->recv_done / sizeof(struct in_addr); i++) { - if (addrs[i].s_addr == INADDR_NONE) { - count = i; - break; - } - } - - /* Nie znaleziono hosta */ - - if (count == 0) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() host not found\n"); - e->event.failure = GG_FAILURE_RESOLVING; - return GG_ACTION_FAIL; - } - - /* Nie mamy pełnej listy, ale połączenie zerwane */ - - if (res == 0 && count == -1) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection broken\n"); - e->event.failure = GG_FAILURE_RESOLVING; - return GG_ACTION_FAIL; - } - - /* Nie mamy pełnej listy, normalna sytuacja */ - - if (count == -1) - return GG_ACTION_WAIT; - -#ifndef GG_DEBUG_DISABLE - if ((gg_debug_level & GG_DEBUG_DUMP) && (count > 0)) { - char *list; - size_t len; - - len = 0; - - for (i = 0; i < (unsigned int) count; i++) { - if (i > 0) - len += 2; - - len += strlen(inet_ntoa(addrs[i])); - } - - list = malloc(len + 1); - - if (list == NULL) - return GG_ACTION_FAIL; - - list[0] = 0; - - for (i = 0; i < (unsigned int) count; i++) { - if (i > 0) - strcat(list, ", "); - - strcat(list, inet_ntoa(addrs[i])); - } - - gg_debug_session(sess, GG_DEBUG_DUMP, "// gg_watch_fd() resolved: %s\n", list); - - free(list); - } -#endif - - gg_close(sess); - - sess->state = next_state; - sess->resolver_result = addrs; - sess->resolver_count = count; - sess->resolver_index = 0; - sess->recv_buf = NULL; - sess->recv_done = 0; - - return GG_ACTION_NEXT; -} - -static gg_action_t gg_handle_connect(struct gg_session *sess, - struct gg_event *e, enum gg_state_t next_state, - enum gg_state_t alt_state, enum gg_state_t alt2_state) -{ - struct in_addr addr; - int port; - - if (sess->resolver_index >= sess->resolver_count) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() out of addresses to connect to\n"); - e->event.failure = GG_FAILURE_CONNECTING; - return GG_ACTION_FAIL; - } - - addr = sess->resolver_result[sess->resolver_index]; - - if (sess->state == GG_STATE_CONNECT_HUB) { - sess->hub_addr = addr.s_addr; - port = GG_APPMSG_PORT; - } else { - sess->proxy_addr = addr.s_addr; - port = sess->proxy_port; - } - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connecting to %s:%d\n", inet_ntoa(addr), port); - - sess->fd = gg_connect(&addr, port, sess->async); - - if (sess->fd == -1) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() " - "connection failed (errno=%d, %s)\n", - errno, strerror(errno)); - sess->resolver_index++; - return GG_ACTION_NEXT; - } - - sess->state = next_state; - sess->check = GG_CHECK_WRITE; - sess->timeout = GG_DEFAULT_TIMEOUT; - sess->soft_timeout = 1; - - return GG_ACTION_WAIT; -} - -static gg_action_t gg_handle_connecting(struct gg_session *sess, - struct gg_event *e, enum gg_state_t next_state, - enum gg_state_t alt_state, enum gg_state_t alt2_state) -{ - int res; - - sess->soft_timeout = 0; - - if (gg_async_connect_failed(sess, &res)) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() " - "connection failed (errno=%d, %s)\n", - res, strerror(res)); - gg_close(sess); - sess->resolver_index++; - sess->state = alt_state; - } else { - /* Z proxy zwykle łączymy się dwa razy, więc nie zwalniamy - * adresów IP po pierwszym połączeniu. */ - if (sess->state != GG_STATE_CONNECTING_PROXY_HUB) { - free(sess->resolver_result); - sess->resolver_result = NULL; - } - - sess->state = next_state; - } - - return GG_ACTION_NEXT; -} - -static gg_action_t gg_handle_connect_gg(struct gg_session *sess, - struct gg_event *e, enum gg_state_t next_state, - enum gg_state_t alt_state, enum gg_state_t alt2_state) -{ - struct in_addr addr; - uint16_t port; - - gg_debug_session(sess, GG_DEBUG_MISC, "resolver_index=%d, " - "connect_index=%d, connect_port={%d,%d}\n", - sess->resolver_index, sess->connect_index, - sess->connect_port[0], sess->connect_port[1]); - - if ((unsigned int) sess->connect_index >= - sizeof(sess->connect_port) / sizeof(sess->connect_port[0]) || - sess->connect_port[sess->connect_index] == 0) - { - sess->connect_index = 0; - sess->resolver_index++; - if (sess->resolver_index >= sess->resolver_count) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() out of addresses to connect to\n"); - e->event.failure = GG_FAILURE_CONNECTING; - return GG_ACTION_FAIL; - } - } - - addr = sess->resolver_result[sess->resolver_index]; - port = sess->connect_port[sess->connect_index]; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connecting to %s:%d\n", inet_ntoa(addr), port); - - sess->server_addr = addr.s_addr; - sess->fd = gg_connect(&addr, port, sess->async); - - if (sess->fd == -1) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() " - "connection failed (errno=%d, %s)\n", - errno, strerror(errno)); - sess->connect_index++; - return GG_ACTION_NEXT; - } - - sess->state = next_state; - sess->check = GG_CHECK_WRITE; - sess->timeout = GG_DEFAULT_TIMEOUT; - sess->soft_timeout = 1; - - return GG_ACTION_WAIT; -} - -static gg_action_t gg_handle_connecting_gg(struct gg_session *sess, - struct gg_event *e, enum gg_state_t next_state, - enum gg_state_t alt_state, enum gg_state_t alt2_state) -{ - int res; - - sess->soft_timeout = 0; - - /* jeśli wystąpił błąd podczas łączenia się... */ - if (gg_async_connect_failed(sess, &res)) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() " - "connection failed (errno=%d, %s)\n", - res, strerror(res)); - gg_close(sess); - sess->connect_index++; - sess->state = alt_state; - return GG_ACTION_NEXT; - } - - free(sess->resolver_result); - sess->resolver_result = NULL; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connected\n"); - - if (sess->ssl_flag != GG_SSL_DISABLED) { - if (gg_session_init_ssl(sess) == -1) { - e->event.failure = GG_FAILURE_TLS; - return GG_ACTION_FAIL; - } - - sess->state = alt2_state; - sess->check = GG_CHECK_WRITE; - sess->timeout = GG_DEFAULT_TIMEOUT; - - return GG_ACTION_NEXT; - } else { - sess->state = next_state; - sess->check = GG_CHECK_READ; - sess->timeout = GG_DEFAULT_TIMEOUT; - - return GG_ACTION_WAIT; - } -} - -static gg_action_t gg_handle_send_hub(struct gg_session *sess, - struct gg_event *e, enum gg_state_t next_state, - enum gg_state_t alt_state, enum gg_state_t alt2_state) -{ - char *req, *client, *auth; - const char *host; - int res; - int proxy; - size_t req_len; - - if (sess->client_version != NULL && isdigit(sess->client_version[0])) - client = gg_urlencode(sess->client_version); - else if (sess->protocol_version <= GG_PROTOCOL_VERSION_100) - client = gg_urlencode(GG_DEFAULT_CLIENT_VERSION_100); - else /* sess->protocol_version >= GG_PROTOCOL_VERSION_110 */ - client = gg_urlencode(GG_DEFAULT_CLIENT_VERSION_110); - - if (client == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() out of memory for client version\n"); - return GG_ACTION_FAIL; - } - - if (sess->proxy_addr && sess->proxy_port) { - host = "http://" GG_APPMSG_HOST; - proxy = 1; - } else { - host = ""; - proxy = 0; - } - - auth = gg_proxy_auth(); - - if (sess->ssl_flag != GG_SSL_DISABLED) { - req = gg_saprintf - ("GET %s/appsvc/appmsg_ver10.asp?fmnumber=%u&fmt=2&" - "lastmsg=%d&version=%s&age=2&gender=1 HTTP/1.0\r\n" - "Connection: close\r\n" - "Host: " GG_APPMSG_HOST "\r\n" - "%s" - "\r\n", host, sess->uin, sess->last_sysmsg, client, (auth) ? auth : ""); - } else { - req = gg_saprintf - ("GET %s/appsvc/appmsg_ver8.asp?fmnumber=%u&fmt=2&lastmsg=%d&version=%s HTTP/1.0\r\n" - "Host: " GG_APPMSG_HOST "\r\n" - "%s" - "\r\n", host, sess->uin, sess->last_sysmsg, client, (auth) ? auth : ""); - } - - free(auth); - free(client); - - if (req == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() out of memory\n"); - e->event.failure = GG_FAILURE_PROXY; - return GG_ACTION_FAIL; - } - - req_len = strlen(req); - - gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// sending http query:\n%s", req); - - res = send(sess->fd, req, req_len, 0); - - free(req); - - if (res == -1 && errno != EINTR && errno != EAGAIN) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() sending query failed\n"); - e->event.failure = (!proxy) ? GG_FAILURE_HUB : GG_FAILURE_PROXY; - return GG_ACTION_FAIL; - } - - if ((size_t) res < req_len) { - sess->state = alt_state; - sess->check = GG_CHECK_WRITE; - sess->timeout = GG_DEFAULT_TIMEOUT; - } else { - sess->state = next_state; - sess->check = GG_CHECK_READ; - sess->timeout = GG_DEFAULT_TIMEOUT; - } - - return GG_ACTION_WAIT; -} - -static gg_action_t gg_handle_sending_hub_proxy(struct gg_session *sess, - struct gg_event *e, enum gg_state_t next_state, - enum gg_state_t alt_state, enum gg_state_t alt2_state) -{ - if (gg_send_queued_data(sess) == -1) { - e->event.failure = GG_FAILURE_WRITING; - return GG_ACTION_FAIL; - } - - if (sess->send_left > 0) - return GG_ACTION_WAIT; - - sess->state = next_state; - sess->check = GG_CHECK_READ; - sess->timeout = GG_DEFAULT_TIMEOUT; - - return GG_ACTION_WAIT; -} - -static gg_action_t gg_handle_reading_hub_proxy(struct gg_session *sess, - struct gg_event *e, enum gg_state_t next_state, - enum gg_state_t alt_state, enum gg_state_t alt2_state) -{ - char buf[1024], *tmp, host[129]; - int port = GG_DEFAULT_PORT; - int reply; - const char *body; - struct in_addr addr; - int res; - char **host_white; - char *host_white_default[] = GG_DEFAULT_HOST_WHITE_LIST; - - res = recv(sess->fd, buf, sizeof(buf), 0); - - if (res == -1 && (errno == EAGAIN || errno == EINTR)) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() " - "non-critical recv error (errno=%d, %s)\n", - errno, strerror(errno)); - return GG_ACTION_WAIT; - } - - if (res == -1) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() recv " - "error (errno=%d, %s)\n", errno, strerror(errno)); - e->event.failure = GG_FAILURE_CONNECTING; - return GG_ACTION_FAIL; - } - - if (res != 0) { - tmp = realloc(sess->recv_buf, sess->recv_done + res + 1); - - if (tmp == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() not enough memory for http reply\n"); - return GG_ACTION_FAIL; - } - - sess->recv_buf = tmp; - memcpy(sess->recv_buf + sess->recv_done, buf, res); - sess->recv_done += res; - sess->recv_buf[sess->recv_done] = 0; - } - - if (res == 0 && sess->recv_buf == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection closed\n"); - e->event.failure = GG_FAILURE_CONNECTING; - return GG_ACTION_FAIL; - } - - if (res != 0) - return GG_ACTION_WAIT; - - gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// received http reply:\n%s", sess->recv_buf); - - res = sscanf(sess->recv_buf, "HTTP/1.%*d %3d ", &reply); - - /* sprawdzamy, czy wszystko w porządku. */ - if (res != 1 || reply != 200) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() invalid http reply, connection failed\n"); - e->event.failure = GG_FAILURE_CONNECTING; - return GG_ACTION_FAIL; - } - - /* szukamy początku treści */ - body = strstr(sess->recv_buf, "\r\n\r\n"); - - if (body == NULL) { - body = strstr(sess->recv_buf, "\n\n"); - - if (body == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() can't find body\n"); - e->event.failure = GG_FAILURE_CONNECTING; - return GG_ACTION_FAIL; - } else { - body += 2; - } - } else { - body += 4; - } - - /* 17591 0 91.197.13.71:8074 91.197.13.71 */ - res = sscanf(body, "%d %*d %128s", &reply, host); - - if (res != 2) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() invalid hub reply, connection failed\n"); - e->event.failure = GG_FAILURE_CONNECTING; - return GG_ACTION_FAIL; - } - - gg_debug_session(sess, GG_DEBUG_MISC, "reply=%d, host=\"%s\"\n", reply, host); - - /* jeśli pierwsza liczba w linii nie jest równa zeru, - * oznacza to, że mamy wiadomość systemową. */ - if (reply != 0) { - tmp = strchr(body, '\n'); - - if (tmp != NULL) { - e->type = GG_EVENT_MSG; - e->event.msg.msgclass = reply; - e->event.msg.sender = 0; - e->event.msg.message = (unsigned char*) strdup(tmp + 1); - - if (e->event.msg.message == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_watch_fd() not enough memory " - "for system message\n"); - return GG_ACTION_FAIL; - } - } - } - - gg_close(sess); - - tmp = strchr(host, ':'); - - if (tmp != NULL) { - *tmp = 0; - port = atoi(tmp + 1); - } - - if (strcmp(host, "notoperating") == 0) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() service unavailable\n"); - e->event.failure = GG_FAILURE_UNAVAILABLE; - return GG_ACTION_FAIL; - } - - addr.s_addr = inet_addr(host); - if (addr.s_addr == INADDR_NONE) - addr.s_addr = 0; - sess->server_addr = addr.s_addr; - - free(sess->recv_buf); - sess->recv_buf = NULL; - sess->recv_done = 0; - - if (sess->state != GG_STATE_READING_PROXY_HUB) { - if (sess->port == 0) { - sess->connect_port[0] = port; - sess->connect_port[1] = (port != GG_HTTPS_PORT) ? GG_HTTPS_PORT : 0; - } else { - sess->connect_port[0] = sess->port; - sess->connect_port[1] = 0; - } - } else { - sess->connect_port[0] = (sess->port == 0) ? GG_HTTPS_PORT : sess->port; - sess->connect_port[1] = 0; - } - - free(sess->connect_host); - sess->connect_host = strdup(host); - - if (sess->connect_host == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() not enough memory\n"); - return GG_ACTION_FAIL; - } - - host_white = sess->private_data->host_white_list; - if (!host_white) - host_white = host_white_default; - - if (sess->ssl_flag == GG_SSL_REQUIRED && host_white[0] != NULL) { - int host_ok = 0; - char **it; - int host_len; - - host_len = strlen(sess->connect_host); - - for (it = host_white; *it != NULL; it++) { - const char *white = *it; - int white_len, dom_offset; - - white_len = strlen(white); - if (white_len > host_len) - continue; - - dom_offset = host_len - white_len; - if (strncasecmp(sess->connect_host + dom_offset, white, - white_len) != 0) - { - continue; - } - - if (white_len < host_len) { - if (sess->connect_host[dom_offset - 1] != '.') - continue; - } - - host_ok = 1; - break; - } - - if (!host_ok) { - gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR, - "// gg_watch_fd() the HUB server returned " - "a host that is not trusted (%s)\n", - sess->connect_host); - e->event.failure = GG_FAILURE_TLS; - return GG_ACTION_FAIL; - } - } - - if (sess->state == GG_STATE_READING_HUB) - sess->resolver_host = sess->connect_host; - - /* Jeśli łączymy się przez proxy, zacznijmy od początku listy */ - sess->resolver_index = 0; - - sess->state = (sess->async) ? next_state : alt_state; - - return GG_ACTION_NEXT; -} - -static gg_action_t gg_handle_send_proxy_gg(struct gg_session *sess, - struct gg_event *e, enum gg_state_t next_state, - enum gg_state_t alt_state, enum gg_state_t alt2_state) -{ - char *req, *auth; - size_t req_len; - int res; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() %s\n", gg_debug_state(sess->state)); - - if (sess->connect_index > 1 || sess->connect_port[sess->connect_index] == 0) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() out of connection candidates\n"); - e->event.failure = GG_FAILURE_CONNECTING; - return GG_ACTION_FAIL; - } - - auth = gg_proxy_auth(); - - req = gg_saprintf("CONNECT %s:%d HTTP/1.0\r\n%s\r\n", - sess->connect_host, sess->connect_port[sess->connect_index], - (auth) ? auth : ""); - - free(auth); - - sess->connect_index++; - - if (req == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() out of memory\n"); - e->event.failure = GG_FAILURE_PROXY; - return GG_ACTION_FAIL; - } - - req_len = strlen(req); - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() proxy request:\n%s", req); - - res = send(sess->fd, req, req_len, 0); - - free(req); - - if (res == -1 && errno != EINTR && errno != EAGAIN) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() sending query failed\n"); - e->event.failure = GG_FAILURE_PROXY; - return GG_ACTION_FAIL; - } - - if ((size_t) res < req_len) { - sess->state = alt_state; - sess->check = GG_CHECK_WRITE; - sess->timeout = GG_DEFAULT_TIMEOUT; - } else { - sess->state = next_state; - sess->check = GG_CHECK_READ; - sess->timeout = GG_DEFAULT_TIMEOUT; - } - - return GG_ACTION_WAIT; -} - -static gg_action_t gg_handle_tls_negotiation(struct gg_session *sess, - struct gg_event *e, enum gg_state_t next_state, - enum gg_state_t alt_state, enum gg_state_t alt2_state) -{ -#if defined(GG_CONFIG_HAVE_GNUTLS) || defined(GG_CONFIG_HAVE_OPENSSL) - int valid_hostname = 0; -#endif - -#ifdef GG_CONFIG_HAVE_GNUTLS - unsigned int status; - int res; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_TLS_NEGOTIATION\n"); - - for (;;) { - res = gnutls_handshake(GG_SESSION_GNUTLS(sess)); - - if (res == GNUTLS_E_AGAIN) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() TLS handshake GNUTLS_E_AGAIN\n"); - - if (gnutls_record_get_direction(GG_SESSION_GNUTLS(sess)) == 0) - sess->check = GG_CHECK_READ; - else - sess->check = GG_CHECK_WRITE; - sess->timeout = GG_DEFAULT_TIMEOUT; - return GG_ACTION_WAIT; - } - - if (res == GNUTLS_E_INTERRUPTED) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() TLS handshake GNUTLS_E_INTERRUPTED\n"); - continue; - } - - if (res != GNUTLS_E_SUCCESS) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd()" - " TLS handshake error: %d, %s\n", - res, gnutls_strerror(res)); - e->event.failure = GG_FAILURE_TLS; - return GG_ACTION_FAIL; - } - - break; - } - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() TLS negotiation succeded:\n"); - gg_debug_session(sess, GG_DEBUG_MISC, "// cipher: VERS-%s:%s:%s:%s:COMP-%s\n", - gnutls_protocol_get_name(gnutls_protocol_get_version(GG_SESSION_GNUTLS(sess))), - gnutls_cipher_get_name(gnutls_cipher_get(GG_SESSION_GNUTLS(sess))), - gnutls_kx_get_name(gnutls_kx_get(GG_SESSION_GNUTLS(sess))), - gnutls_mac_get_name(gnutls_mac_get(GG_SESSION_GNUTLS(sess))), - gnutls_compression_get_name(gnutls_compression_get(GG_SESSION_GNUTLS(sess)))); - - if (gnutls_certificate_type_get(GG_SESSION_GNUTLS(sess)) == GNUTLS_CRT_X509) { - unsigned int peer_count; - const gnutls_datum_t *peers; - gnutls_x509_crt_t cert; - - if (gnutls_x509_crt_init(&cert) == 0) { - peers = gnutls_certificate_get_peers(GG_SESSION_GNUTLS(sess), &peer_count); - - if (peers != NULL) { - char buf[256]; - size_t size; - - if (gnutls_x509_crt_import(cert, &peers[0], GNUTLS_X509_FMT_DER) == 0) { - size = sizeof(buf); - gnutls_x509_crt_get_dn(cert, buf, &size); - gg_debug_session(sess, GG_DEBUG_MISC, "// cert subject: %s\n", buf); - size = sizeof(buf); - gnutls_x509_crt_get_issuer_dn(cert, buf, &size); - gg_debug_session(sess, GG_DEBUG_MISC, "// cert issuer: %s\n", buf); - - if (gnutls_x509_crt_check_hostname(cert, sess->connect_host) != 0) - valid_hostname = 1; - } - } - - gnutls_x509_crt_deinit(cert); - } - } - - res = gnutls_certificate_verify_peers2(GG_SESSION_GNUTLS(sess), &status); - - if (res != 0 || status != 0) { - gg_debug_session(sess, GG_DEBUG_MISC, "// WARNING! unable to" - " verify peer certificate: 0x%x, %d, %s\n", status, res, - gnutls_strerror(res)); - - if (sess->ssl_flag == GG_SSL_REQUIRED) { - e->event.failure = GG_FAILURE_TLS; - return GG_ACTION_FAIL; - } - } else { - gg_debug_session(sess, GG_DEBUG_MISC, "// verified peer certificate\n"); - } - - -#elif defined GG_CONFIG_HAVE_OPENSSL - - X509 *peer; - int res; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() %s\n", gg_debug_state(sess->state)); - - res = SSL_connect(GG_SESSION_OPENSSL(sess)); - - if (res <= 0) { - int err; - - err = SSL_get_error(GG_SESSION_OPENSSL(sess), res); - - if (res == 0) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() disconnected during TLS negotiation\n"); - e->event.failure = GG_FAILURE_TLS; - return GG_ACTION_FAIL; - } - - if (err == SSL_ERROR_WANT_READ) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() wants to read\n"); - - sess->check = GG_CHECK_READ; - sess->timeout = GG_DEFAULT_TIMEOUT; - return GG_ACTION_WAIT; - } else if (err == SSL_ERROR_WANT_WRITE) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() wants to write\n"); - - sess->check = GG_CHECK_WRITE; - sess->timeout = GG_DEFAULT_TIMEOUT; - return GG_ACTION_WAIT; - } else { - char buf[256]; - - ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() bailed out: %s\n", buf); - - e->event.failure = GG_FAILURE_TLS; - return GG_ACTION_FAIL; - } - } - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() TLS negotiation" - " succeded:\n// cipher: %s\n", - SSL_get_cipher_name(GG_SESSION_OPENSSL(sess))); - - peer = SSL_get_peer_certificate(GG_SESSION_OPENSSL(sess)); - - if (peer == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// WARNING! unable to get peer certificate!\n"); - - if (sess->ssl_flag == GG_SSL_REQUIRED) { - e->event.failure = GG_FAILURE_TLS; - return GG_ACTION_FAIL; - } - } else { - char buf[256]; - long res; - - X509_NAME_oneline(X509_get_subject_name(peer), buf, sizeof(buf)); - gg_debug_session(sess, GG_DEBUG_MISC, "// cert subject: %s\n", buf); - - X509_NAME_oneline(X509_get_issuer_name(peer), buf, sizeof(buf)); - gg_debug_session(sess, GG_DEBUG_MISC, "// cert issuer: %s\n", buf); - - res = SSL_get_verify_result(GG_SESSION_OPENSSL(sess)); - - if (res != X509_V_OK) { - gg_debug_session(sess, GG_DEBUG_MISC, "// WARNING! " - "unable to verify peer certificate! " - "res=%ld\n", res); - - if (sess->ssl_flag == GG_SSL_REQUIRED) { - e->event.failure = GG_FAILURE_TLS; - return GG_ACTION_FAIL; - } - } else { - gg_debug_session(sess, GG_DEBUG_MISC, "// verified peer certificate\n"); - } - - if (X509_NAME_get_text_by_NID(X509_get_subject_name(peer), NID_commonName, buf, sizeof(buf)) == -1) - buf[0] = 0; - - /* Obsługa certyfikatów z wieloznacznikiem */ - if (strchr(buf, '*') == buf && strchr(buf + 1, '*') == NULL) { - char *tmp; - - tmp = strchr(sess->connect_host, '.'); - - if (tmp != NULL) - valid_hostname = (strcasecmp(tmp, buf + 1) == 0); - } else { - valid_hostname = (strcasecmp(sess->connect_host, buf) == 0); - } - } - -#else - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() no SSL support\n"); - e->event.failure = GG_FAILURE_TLS; - return GG_ACTION_FAIL; - -#endif - -#if defined(GG_CONFIG_HAVE_GNUTLS) || defined(GG_CONFIG_HAVE_OPENSSL) - if (!valid_hostname) { - gg_debug_session(sess, GG_DEBUG_MISC, "// WARNING! unable to verify hostname\n"); - - if (sess->ssl_flag == GG_SSL_REQUIRED) { - e->event.failure = GG_FAILURE_TLS; - return GG_ACTION_FAIL; - } - } - - sess->state = next_state; - sess->check = GG_CHECK_READ; - sess->timeout = GG_DEFAULT_TIMEOUT; - - return GG_ACTION_WAIT; -#endif -} - -static gg_action_t gg_handle_reading_proxy_gg(struct gg_session *sess, - struct gg_event *e, enum gg_state_t next_state, - enum gg_state_t alt_state, enum gg_state_t alt2_state) -{ - char buf[256]; - int res; - int reply; - char *body; - - res = recv(sess->fd, buf, sizeof(buf), 0); - - gg_debug_session(sess, GG_DEBUG_MISC, "recv() = %d\n", res); - - if (res == -1 && (errno == EAGAIN || errno == EINTR)) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() " - "non-critical recv error (errno=%d, %s)\n", - errno, strerror(errno)); - return GG_ACTION_WAIT; - } - - if (res == -1) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() recv " - "error (errno=%d, %s)\n", errno, strerror(errno)); - e->event.failure = GG_FAILURE_CONNECTING; - return GG_ACTION_FAIL; - } - - if (res != 0) { - char *tmp; - - tmp = realloc(sess->recv_buf, sess->recv_done + res + 1); - - if (tmp == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() not enough memory for http reply\n"); - return GG_ACTION_FAIL; - } - - sess->recv_buf = tmp; - memcpy(sess->recv_buf + sess->recv_done, buf, res); - sess->recv_done += res; - sess->recv_buf[sess->recv_done] = 0; - } - - if (res == 0 && sess->recv_buf == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection closed\n"); - e->event.failure = GG_FAILURE_CONNECTING; - return GG_ACTION_FAIL; - } - - /* szukamy początku treści */ - body = strstr(sess->recv_buf, "\r\n\r\n"); - - if (body == NULL) { - body = strstr(sess->recv_buf, "\n\n"); - - if (body == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() can't find body\n"); - e->event.failure = GG_FAILURE_CONNECTING; - return GG_ACTION_FAIL; - } else { - body += 2; - } - } else { - body += 4; - } - - gg_debug_session(sess, GG_DEBUG_MISC, "// found body!\n"); - - gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// received proxy reply:\n%s\n", sess->recv_buf); - - res = sscanf(sess->recv_buf, "HTTP/1.%*d %3d ", &reply); - - gg_debug_session(sess, GG_DEBUG_MISC, "res = %d, reply = %d\n", res, reply); - - /* sprawdzamy, czy wszystko w porządku. */ - if (res != 1 || reply != 200) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() invalid http reply, connection failed\n"); - e->event.failure = GG_FAILURE_CONNECTING; - return GG_ACTION_FAIL; - } - - if (sess->ssl_flag != GG_SSL_DISABLED) { - if (gg_session_init_ssl(sess) == -1) { - e->event.failure = GG_FAILURE_TLS; - return GG_ACTION_FAIL; - } - - /* Teoretycznie SSL jest inicjowany przez klienta, więc serwer - * nie powinien niczego wysłać. */ - if (sess->recv_buf + sess->recv_done > body) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() unexpected SSL data\n"); - e->event.failure = GG_FAILURE_TLS; - return GG_ACTION_FAIL; - } - - free(sess->recv_buf); - sess->recv_buf = NULL; - sess->recv_done = 0; - - sess->state = alt_state; - sess->check = GG_CHECK_WRITE; - sess->timeout = GG_DEFAULT_TIMEOUT; - - return GG_ACTION_WAIT; - } - - sess->state = next_state; - sess->check = GG_CHECK_READ; - sess->timeout = GG_DEFAULT_TIMEOUT; /* Pierwszy pakiet musi przyjść */ - - /* Jeśli zbuforowaliśmy za dużo, przeanalizuj */ - - if (sess->recv_buf + sess->recv_done > body) { - sess->recv_done = sess->recv_done - (body - sess->recv_buf); - memmove(sess->recv_buf, body, sess->recv_done); - sess->state = alt2_state; - return GG_ACTION_NEXT; - } else { - free(sess->recv_buf); - sess->recv_buf = NULL; - sess->recv_done = 0; - } - - return GG_ACTION_WAIT; -} - -static gg_action_t gg_handle_connected(struct gg_session *sess, - struct gg_event *e, enum gg_state_t next_state, - enum gg_state_t alt_state, enum gg_state_t alt2_state) -{ -#if 0 - char buf[1024]; - int res; - - if (gg_send_queued_data(sess) == -1) - return GG_ACTION_FAIL; - - res = gg_read(sess, buf, sizeof(buf)); - - if (res == -1 && (errno == EAGAIN || errno == EINTR)) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() " - "non-critical read error (errno=%d, %s)\n", - errno, strerror(errno)); - return GG_ACTION_WAIT; - } - - if (res == -1 || res == 0) { - if (res == -1) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd()" - " read error (errno=%d, %s)\n", - errno, strerror(errno)); - } else { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd()" - " connection closed\n"); - } - - if (sess->state == GG_STATE_DISCONNECTING && res == 0) { - e->type = GG_EVENT_DISCONNECT_ACK; - } else if (sess->state == GG_STATE_READING_KEY) { - e->event.failure = GG_FAILURE_INVALID; - return GG_ACTION_FAIL; - } - - return GG_ACTION_FAIL; - } - - gg_debug_dump(sess, GG_DEBUG_DUMP, buf, res); - - if (gg_session_handle_data(sess, buf, res, e) == -1) - return GG_ACTION_FAIL; - - if (sess->send_buf != NULL) - sess->check |= GG_CHECK_WRITE; - - return GG_ACTION_WAIT; -#else - struct gg_header *gh; - - if (gg_send_queued_data(sess) == -1) - return GG_ACTION_FAIL; - - gh = gg_recv_packet(sess); - - if (gh == NULL) { - if (sess->state == GG_STATE_DISCONNECTING) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection broken expectedly\n"); - e->type = GG_EVENT_DISCONNECT_ACK; - return GG_ACTION_WAIT; - } - - if (errno != EAGAIN) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd()" - " gg_recv_packet failed (errno=%d, %s)\n", - errno, strerror(errno)); - return GG_ACTION_FAIL; - } - } else { - if (gg_session_handle_packet(sess, gh->type, - (const char *) gh + sizeof(struct gg_header), - gh->length, e) == -1) - { - free(gh); - return GG_ACTION_FAIL; - } - - free(gh); - } - - sess->check = GG_CHECK_READ; - - if (sess->send_buf != NULL) - sess->check |= GG_CHECK_WRITE; - - return GG_ACTION_WAIT; -#endif -} - -static gg_action_t gg_handle_error(struct gg_session *sess, struct gg_event *e, - enum gg_state_t next_state, enum gg_state_t alt_state, - enum gg_state_t alt2_state) -{ - struct gg_session_private *p = sess->private_data; - - gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR, "// gg_handle_error() failure=%d\n", p->socket_failure); - - e->event.failure = p->socket_failure; - - return GG_ACTION_FAIL; -} - -static const gg_state_transition_t handlers[] = -{ - /* style:maxlinelength:start-ignore */ - { GG_STATE_RESOLVE_HUB_SYNC, gg_handle_resolve_sync, GG_STATE_CONNECT_HUB, GG_STATE_SEND_HUB, 0 }, - { GG_STATE_RESOLVE_GG_SYNC, gg_handle_resolve_sync, GG_STATE_CONNECT_GG, GG_STATE_READING_KEY, 0 }, - { GG_STATE_RESOLVE_PROXY_HUB_SYNC, gg_handle_resolve_sync, GG_STATE_CONNECT_PROXY_HUB, GG_STATE_SEND_PROXY_HUB, 0 }, - { GG_STATE_RESOLVE_PROXY_GG_SYNC, gg_handle_resolve_sync, GG_STATE_CONNECT_PROXY_GG, GG_STATE_SEND_PROXY_GG, 0 }, - - { GG_STATE_RESOLVE_HUB_ASYNC, gg_handle_resolve_async, GG_STATE_RESOLVING_HUB, GG_STATE_SEND_HUB, 0 }, - { GG_STATE_RESOLVE_GG_ASYNC, gg_handle_resolve_async, GG_STATE_RESOLVING_GG, GG_STATE_READING_KEY, 0 }, - { GG_STATE_RESOLVE_PROXY_HUB_ASYNC, gg_handle_resolve_async, GG_STATE_RESOLVING_PROXY_HUB, GG_STATE_SEND_PROXY_HUB, 0 }, - { GG_STATE_RESOLVE_PROXY_GG_ASYNC, gg_handle_resolve_async, GG_STATE_RESOLVING_PROXY_GG, GG_STATE_SEND_PROXY_GG, 0 }, - - { GG_STATE_RESOLVING_HUB, gg_handle_resolving, GG_STATE_CONNECT_HUB, 0, 0 }, - { GG_STATE_RESOLVING_GG, gg_handle_resolving, GG_STATE_CONNECT_GG, 0, 0 }, - { GG_STATE_RESOLVING_PROXY_HUB, gg_handle_resolving, GG_STATE_CONNECT_PROXY_HUB, 0, 0 }, - { GG_STATE_RESOLVING_PROXY_GG, gg_handle_resolving, GG_STATE_CONNECT_PROXY_GG, 0, 0 }, - - { GG_STATE_CONNECT_HUB, gg_handle_connect, GG_STATE_CONNECTING_HUB, 0, 0 }, - { GG_STATE_CONNECT_PROXY_HUB, gg_handle_connect, GG_STATE_CONNECTING_PROXY_HUB, 0, 0 }, - { GG_STATE_CONNECT_PROXY_GG, gg_handle_connect, GG_STATE_CONNECTING_PROXY_GG, 0, 0 }, - - { GG_STATE_CONNECT_GG, gg_handle_connect_gg, GG_STATE_CONNECTING_GG, 0, 0 }, - - { GG_STATE_CONNECTING_HUB, gg_handle_connecting, GG_STATE_SEND_HUB, GG_STATE_CONNECT_HUB, 0 }, - { GG_STATE_CONNECTING_PROXY_HUB, gg_handle_connecting, GG_STATE_SEND_PROXY_HUB, GG_STATE_CONNECT_PROXY_HUB, 0 }, - { GG_STATE_CONNECTING_PROXY_GG, gg_handle_connecting, GG_STATE_SEND_PROXY_GG, GG_STATE_CONNECT_PROXY_GG, 0 }, - - { GG_STATE_CONNECTING_GG, gg_handle_connecting_gg, GG_STATE_READING_KEY, GG_STATE_CONNECT_GG, GG_STATE_TLS_NEGOTIATION }, - - { GG_STATE_SEND_HUB, gg_handle_send_hub, GG_STATE_READING_HUB, GG_STATE_SENDING_HUB, 0 }, - { GG_STATE_SEND_PROXY_HUB, gg_handle_send_hub, GG_STATE_READING_PROXY_HUB, GG_STATE_SENDING_PROXY_HUB, 0 }, - - { GG_STATE_SEND_PROXY_GG, gg_handle_send_proxy_gg, GG_STATE_READING_PROXY_GG, GG_STATE_SENDING_PROXY_GG, 0 }, - - { GG_STATE_SENDING_HUB, gg_handle_sending_hub_proxy, GG_STATE_READING_HUB, 0, 0 }, - { GG_STATE_SENDING_PROXY_HUB, gg_handle_sending_hub_proxy, GG_STATE_READING_PROXY_HUB, 0, 0 }, - { GG_STATE_SENDING_PROXY_GG, gg_handle_sending_hub_proxy, GG_STATE_READING_PROXY_GG, 0, 0 }, - - { GG_STATE_READING_HUB, gg_handle_reading_hub_proxy, GG_STATE_RESOLVE_GG_ASYNC, GG_STATE_RESOLVE_GG_SYNC, 0 }, - { GG_STATE_READING_PROXY_HUB, gg_handle_reading_hub_proxy, GG_STATE_CONNECT_PROXY_GG, GG_STATE_CONNECT_PROXY_GG, 0 }, - - { GG_STATE_READING_PROXY_GG, gg_handle_reading_proxy_gg, GG_STATE_READING_KEY, GG_STATE_TLS_NEGOTIATION, GG_STATE_READING_KEY }, - - { GG_STATE_TLS_NEGOTIATION, gg_handle_tls_negotiation, GG_STATE_READING_KEY, 0, 0 }, - - { GG_STATE_READING_KEY, gg_handle_connected, 0, 0, 0 }, - { GG_STATE_READING_REPLY, gg_handle_connected, 0, 0, 0 }, - { GG_STATE_CONNECTED, gg_handle_connected, 0, 0, 0 }, - { GG_STATE_DISCONNECTING, gg_handle_connected, 0, 0, 0 }, - { GG_STATE_ERROR, gg_handle_error, 0, 0, 0 }, - /* style:maxlinelength:end-ignore */ -}; - -struct gg_event *gg_eventqueue_add(struct gg_session *sess) -{ - struct gg_event *ge; - gg_eventqueue_t *queue_el, *it; - - queue_el = gg_new0(sizeof(gg_eventqueue_t)); - ge = gg_new0(sizeof(struct gg_event)); - - if (queue_el == NULL || ge == NULL) { - free(queue_el); - free(ge); - return NULL; - } - - ge->type = GG_EVENT_NONE; - - queue_el->event = ge; - if (sess->private_data->event_queue == NULL) - sess->private_data->event_queue = queue_el; - else { - it = sess->private_data->event_queue; - while (it->next != NULL) - it = it->next; - it->next = queue_el; - } - - return ge; -} - -/** - * Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze sesji. - * - * Funkcja zwraca strukturę zdarzenia \c gg_event. Jeśli rodzaj zdarzenia - * to \c GG_EVENT_NONE, nie wydarzyło się jeszcze nic wartego odnotowania. - * Strukturę zdarzenia należy zwolnić funkcja \c gg_event_free(). - * - * \param sess Struktura sesji - * - * \return Struktura zdarzenia lub \c NULL jeśli wystąpił błąd - * - * \ingroup events - */ -struct gg_event *gg_watch_fd(struct gg_session *sess) -{ - struct gg_event *ge; - struct gg_session_private *priv; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_watch_fd(%p);\n", sess); - - if (sess == NULL) { - errno = EFAULT; - return NULL; - } - - priv = sess->private_data; - - if (priv->event_queue != NULL) { - gg_eventqueue_t *next; - - ge = priv->event_queue->event; - next = priv->event_queue->next; - free(priv->event_queue); - priv->event_queue = next; - - if (next == NULL) { - sess->check = priv->check_after_queue; - sess->fd = priv->fd_after_queue; - } - return ge; - } - - ge = malloc(sizeof(struct gg_event)); - - if (ge == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() not enough memory for event data\n"); - return NULL; - } - - memset(ge, 0, sizeof(struct gg_event)); - - ge->type = GG_EVENT_NONE; - - for (;;) { - unsigned int i, found = 0; - gg_action_t res; - - res = GG_ACTION_FAIL; - - for (i = 0; i < sizeof(handlers) / sizeof(handlers[0]); i++) { - if (handlers[i].state == (enum gg_state_t) sess->state) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_watch_fd() %s\n", - gg_debug_state(sess->state)); - res = (*handlers[i].handler)(sess, ge, - handlers[i].next_state, - handlers[i].alt_state, - handlers[i].alt2_state); - found = 1; - break; - } - } - - if (!found) { - gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR, - "// gg_watch_fd() invalid state %s\n", - gg_debug_state(sess->state)); - ge->event.failure = GG_FAILURE_INTERNAL; - } - - if (!sess->async && ge->type == GG_EVENT_NONE && res == GG_ACTION_WAIT) - res = GG_ACTION_NEXT; - - switch (res) { - case GG_ACTION_WAIT: - if (priv->event_queue != NULL) { - priv->fd_after_queue = sess->fd; - priv->check_after_queue = sess->check; - /* wymuszamy ponowne wywołanie gg_watch_fd */ - sess->fd = gg_get_dummy_fd(sess); - if (sess->fd < 0) - sess->fd = priv->fd_after_queue; - sess->check = GG_CHECK_READ | GG_CHECK_WRITE; - } - return ge; - - case GG_ACTION_NEXT: - continue; - - case GG_ACTION_FAIL: - sess->state = GG_STATE_IDLE; - - gg_close(sess); - - if (ge->event.failure != 0) { - ge->type = GG_EVENT_CONN_FAILED; - } else { - free(ge); - ge = NULL; - } - - return ge; - - /* Celowo nie ma default */ - } - } -} - -/* - * Local variables: - * c-indentation-style: k&r - * c-basic-offset: 8 - * indent-tabs-mode: notnil - * End: - * - * vim: shiftwidth=8: - */
--- a/libpurple/protocols/gg/lib/fileio.h Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2011 Bartosz Brachaczek <b.brachaczek@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file fileio.h - * - * \brief Makra zapewniające kompatybilność API do obsługi operacji na plikach na różnych systemach - */ - -#ifndef LIBGADU_FILEIO_H -#define LIBGADU_FILEIO_H - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -#ifdef _WIN32 -# include <io.h> -# define gg_file_close _close -# undef lseek -# define lseek _lseek -# undef open -# define open _open -# undef read -# define read _read -# undef stat -# define stat _stat -# undef fstat -# define fstat _fstat -# undef write -# define write _write -# define S_IRWXO 0 -# define S_IRWXG 0 -#else -# ifdef sun -# include <sys/filio.h> -# endif -# include <unistd.h> -# define gg_file_close close -#endif - -#ifndef S_IWUSR -# define S_IWUSR S_IWRITE -#endif - -#endif /* LIBGADU_FILEIO_H */
--- a/libpurple/protocols/gg/lib/handlers.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2881 +0,0 @@ -/* - * (C) Copyright 2001-2011 Wojtek Kaniewski <wojtekka@irc.pl> - * Robert J. Woźny <speedy@ziew.org> - * Arkadiusz Miśkiewicz <arekm@pld-linux.org> - * Tomasz Chiliński <chilek@chilan.com> - * Adam Wysocki <gophi@ekg.chmurka.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file handlers.c - * - * \brief Funkcje obsługi przychodzących pakietów - */ - -#include <ctype.h> - -#include "fileio.h" -#include "network.h" -#include "strman.h" -#include "libgadu.h" -#include "resolver.h" -#include "session.h" -#include "protocol.h" -#include "encoding.h" -#include "message.h" -#include "internal.h" -#include "deflate.h" -#include "tvbuff.h" -#include "protobuf.h" -#include "packets.pb-c.h" - -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - -/* Ograniczenie długości listy kontaktów - * z pakietów GG_USERLIST_REPLY do 10MB. */ -#define GG_USERLIST_REPLY_MAX_LENGTH 10485760 - -/** - * \internal Struktura opisująca funkcję obsługi pakietu. - */ -typedef struct { - /* Typ pakietu */ - uint32_t type; - /* Stan w którym pakiet jest obsługiwany */ - enum gg_state_t state; - /* Minimalny rozmiar danych pakietu */ - size_t min_length; - /* Funkcja obsługująca pakiet. Patrz gg_session_handle_packet(). */ - int (*handler)(struct gg_session *, uint32_t, const char *, size_t, struct gg_event *); -} gg_packet_handler_t; - -static int gg_ack_110(struct gg_session *gs, GG110Ack__Type type, uint32_t seq, struct gg_event *ge) -{ - GG110Ack msg = GG110_ACK__INIT; - - msg.type = type; - msg.seq = seq; - - if (!GG_PROTOBUF_SEND(gs, ge, GG_ACK110, gg110_ack, msg)) - return -1; - return 0; -} - -static void gg_sync_time(struct gg_session *gs, time_t server_time) -{ - time_t local_time = time(NULL); - int time_diff = server_time - local_time; - - if (gs->private_data->time_diff == time_diff) - return; - - gs->private_data->time_diff = time_diff; - gg_debug_session(gs, GG_DEBUG_MISC | GG_DEBUG_VERBOSE, - "// time synchronized (diff = %d)\n", time_diff); -} - -static int gg_session_handle_welcome_110(struct gg_session *gs, uint32_t seed, - struct gg_event *ge) -{ - GG105Login msg = GG105_LOGIN__INIT; - char client_str[1000]; - uint8_t hash[64]; - const char *client_name = GG11_VERSION; - const char *client_version = GG_DEFAULT_CLIENT_VERSION_110; - const char *client_target = GG11_TARGET; - uint8_t dummy4[4] = {0, 0, 0, 0}; - - if (gs->hash_type != GG_LOGIN_HASH_SHA1) { - gg_debug_session(gs, GG_DEBUG_ERROR, "// Unsupported hash type " - "for this protocol version\n"); - gg_connection_failure(gs, ge, GG_FAILURE_INTERNAL); - return -1; - } - - if (gg_login_hash_sha1_2(gs->password, seed, hash) == -1) { - gg_debug_session(gs, GG_DEBUG_ERROR, "// gg_watch_fd() " - "gg_login_hash_sha1_2() failed, " - "probably out of memory\n"); - gg_connection_failure(gs, ge, GG_FAILURE_INTERNAL); - return -1; - } - - if (gs->client_version != NULL && !isdigit(gs->client_version[0])) { - client_name = ""; - client_target = ""; - } - if (gs->client_version != NULL) - client_version = gs->client_version; - snprintf(client_str, sizeof(client_str), "%s%s%s", - client_name, client_version, client_target); - client_str[sizeof(client_str) - 1] = '\0'; - - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() " - "sending GG_LOGIN105 packet\n"); - - msg.lang = GG8_LANG; - gg_protobuf_set_uin(&msg.uin, gs->uin, NULL); - msg.hash.len = 20; - msg.hash.data = hash; - msg.client = client_str; - - /* flagi gg8 są różne od tych dla gg11 */ - msg.initial_status = gs->initial_status ? - (gs->initial_status & 0xFF) : GG_STATUS_AVAIL; - - if (gs->initial_descr != NULL) { - msg.initial_descr = gs->initial_descr; - } - - /* GG11.0 - msg.supported_features = "avatar,StatusComments,gg_account_sdp," - "edisc,bot,fanpage,pubdir,botCaps"; */ - /* GG11.2 */ - msg.supported_features = "avatar,StatusComments,ggaccount,edisc," - "music_shared,bot,fanpage,pubdir,botCaps,gifts,Gift"; - - msg.dummy4.len = sizeof(dummy4); - msg.dummy4.data = dummy4; - - msg.has_dummy7 = 1; - msg.has_dummy8 = 1; - msg.has_dummy10 = 1; - - if (!GG_PROTOBUF_SEND(gs, ge, GG_LOGIN105, gg105_login, msg)) - return -1; - - gs->state = GG_STATE_READING_REPLY; - gs->check = GG_CHECK_READ; - return 0; -} - -static int gg_session_handle_login110_ok(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - GG110LoginOK *msg = gg110_login_ok__unpack(NULL, len, (uint8_t*)ptr); - - if (!GG_PROTOBUF_VALID(gs, "GG110LoginOK", msg)) - return -1; - - gg_protobuf_expected(gs, "GG110LoginOK.dummy1", msg->dummy1, 1); - gg_sync_time(gs, msg->server_time); - - gg_debug_session(gs, GG_DEBUG_MISC, "// login110_ok: " - "uin=%u, dummyhash=%s\n", msg->uin, msg->dummyhash); - - gg110_login_ok__free_unpacked(msg, NULL); - - ge->type = GG_EVENT_CONN_SUCCESS; - gs->state = GG_STATE_CONNECTED; - gs->check = GG_CHECK_READ; - gs->timeout = -1; - gs->status = (gs->initial_status) ? gs->initial_status : GG_STATUS_AVAIL; -#if 0 - free(gs->status_descr); - gs->status_descr = gs->initial_descr; -#else - free(gs->initial_descr); -#endif - gs->initial_descr = NULL; - - return 0; -} - -/** - * \internal Obsługuje pakiet GG_WELCOME. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_welcome(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - const struct gg_welcome *w; - int ret; - uint8_t hash_buf[64]; - uint32_t local_ip; - struct sockaddr_in sin; - socklen_t sin_len = sizeof(sin); - uint32_t seed; - - struct gg_login80 l80; - const char *client_name, *version, *descr; - uint32_t client_name_len, version_len, descr_len; - - if (len < sizeof(struct gg_welcome)) { - ge->type = GG_EVENT_CONN_FAILED; - ge->event.failure = GG_FAILURE_INVALID; - gs->state = GG_STATE_IDLE; - gg_close(gs); - return 0; - } - - w = (const struct gg_welcome*) ptr; - seed = gg_fix32(w->key); - - if (gs->protocol_version >= GG_PROTOCOL_VERSION_110) - return gg_session_handle_welcome_110(gs, seed, ge); - - memset(hash_buf, 0, sizeof(hash_buf)); - - switch (gs->hash_type) { - case GG_LOGIN_HASH_GG32: - { - uint32_t hash; - - hash = gg_fix32(gg_login_hash((unsigned char*) gs->password, seed)); - gg_debug_session(gs, GG_DEBUG_DUMP, "// gg_watch_fd() " - "challenge %.4x --> GG32 hash %.8x\n", - seed, hash); - memcpy(hash_buf, &hash, sizeof(hash)); - - break; - } - - case GG_LOGIN_HASH_SHA1: - { -#ifndef GG_DEBUG_DISABLE - char tmp[41]; - int i; -#endif - - if (gg_login_hash_sha1_2(gs->password, seed, hash_buf) == -1) { - gg_debug_session(gs, GG_DEBUG_MISC, - "// gg_watch_fd() gg_login_hash_sha1_2()" - " failed, probably out of memory\n"); - gg_close(gs); - ge->type = GG_EVENT_CONN_FAILED; - ge->event.failure = GG_FAILURE_INTERNAL; - gs->state = GG_STATE_IDLE; - return -1; - } - -#ifndef GG_DEBUG_DISABLE - for (i = 0; i < 40; i += 2) - snprintf(tmp + i, sizeof(tmp) - i, "%02x", hash_buf[i / 2]); - - gg_debug_session(gs, GG_DEBUG_DUMP, "// gg_watch_fd() " - "challenge %.4x --> SHA1 hash: %s\n", - seed, tmp); -#endif - - break; - } - - default: - break; - } - -#if 0 - if (gs->password != NULL && (gs->flags & (1 << GG_SESSION_FLAG_CLEAR_PASSWORD))) { - memset(gs->password, 0, strlen(gs->password)); - free(gs->password); - gs->password = NULL; - } -#endif - - if (!getsockname(gs->fd, (struct sockaddr*) &sin, &sin_len)) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() " - "detected address to %s\n", inet_ntoa(sin.sin_addr)); - local_ip = sin.sin_addr.s_addr; - } else { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() unable to detect address\n"); - local_ip = 0; - } - - if (gs->external_addr == 0) - gs->external_addr = local_ip; - - memset(&l80, 0, sizeof(l80)); - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() sending GG_LOGIN80 packet\n"); - l80.uin = gg_fix32(gs->uin); - memcpy(l80.language, GG8_LANG, sizeof(l80.language)); - l80.hash_type = gs->hash_type; - memcpy(l80.hash, hash_buf, sizeof(l80.hash)); - l80.status = gg_fix32(gs->initial_status ? gs->initial_status : GG_STATUS_AVAIL); - l80.flags = gg_fix32(gs->status_flags); - l80.features = gg_fix32(gs->protocol_features); - l80.image_size = gs->image_size; - l80.dunno2 = 0x64; - - if (gs->client_version != NULL && !isdigit(gs->client_version[0])) { - client_name = ""; - client_name_len = 0; - } else { - client_name = GG8_VERSION; - client_name_len = strlen(GG8_VERSION); - } - - version = (gs->client_version != NULL) ? gs->client_version : GG_DEFAULT_CLIENT_VERSION_100; - version_len = gg_fix32(client_name_len + strlen(version)); - - descr = (gs->initial_descr != NULL) ? gs->initial_descr : ""; - descr_len = (gs->initial_descr != NULL) ? gg_fix32(strlen(gs->initial_descr)) : 0; - - ret = gg_send_packet(gs, - GG_LOGIN80, - &l80, sizeof(l80), - &version_len, sizeof(version_len), - client_name, client_name_len, - version, strlen(version), - &descr_len, sizeof(descr_len), - descr, strlen(descr), - NULL); - - if (ret == -1) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() " - "sending packet failed. (errno=%d, %s)\n", - errno, strerror(errno)); - gg_close(gs); - ge->type = GG_EVENT_CONN_FAILED; - ge->event.failure = GG_FAILURE_WRITING; - gs->state = GG_STATE_IDLE; - return -1; - } - - gs->state = GG_STATE_READING_REPLY; - gs->check = GG_CHECK_READ; - - return 0; -} - -/** - * \internal Obsługuje pakiet GG_LOGIN_OK. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_login_ok(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() login succeded\n"); - ge->type = GG_EVENT_CONN_SUCCESS; - gs->state = GG_STATE_CONNECTED; - gs->check = GG_CHECK_READ; - gs->timeout = -1; - gs->status = (gs->initial_status) ? gs->initial_status : GG_STATUS_AVAIL; -#if 0 - free(gs->status_descr); - gs->status_descr = gs->initial_descr; -#else - free(gs->initial_descr); -#endif - gs->initial_descr = NULL; - - return 0; -} - -/** - * \internal Obsługuje pakiet GG_LOGIN_FAILED. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_login_failed(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - if (type != GG_DISCONNECTING) - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() login failed\n"); - else - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() too many incorrect password attempts\n"); - ge->type = GG_EVENT_CONN_FAILED; - ge->event.failure = (type != GG_DISCONNECTING) ? GG_FAILURE_PASSWORD : GG_FAILURE_INTRUDER; - gs->state = GG_STATE_IDLE; - gg_close(gs); - errno = EACCES; - - return 0; -} - -/** - * \internal Obsługuje pakiet GG_SEND_MSG_ACK. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_send_msg_ack(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - struct gg_session_private *p = gs->private_data; - const struct gg_send_msg_ack *s = (const struct gg_send_msg_ack*) ptr; - - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a message ack\n"); - - ge->type = GG_EVENT_ACK; - ge->event.ack.status = gg_fix32(s->status); - ge->event.ack.recipient = gg_fix32(s->recipient); - ge->event.ack.seq = gg_fix32(s->seq); - - if (ge->event.ack.seq == 0 && p->imgout_waiting_ack > 0) - p->imgout_waiting_ack--; - gg_image_sendout(gs); - - return 0; -} - -/** - * \internal Obsługuje pakiet GG_SEND_MSG_ACK110. - */ -static int gg_session_handle_send_msg_ack_110(struct gg_session *gs, - uint32_t type, const char *ptr, size_t len, struct gg_event *ge) -{ - struct gg_session_private *p = gs->private_data; - GG110MessageAck *msg = gg110_message_ack__unpack(NULL, len, (uint8_t*)ptr); - size_t i; - - if (!GG_PROTOBUF_VALID(gs, "GG110MessageAck", msg)) - return -1; - - if (msg->dummy1 == 0x4000) { - /* zaobserwowane w EKG rev2856, po wywołaniu check_conn, czyli - * gg_image_request(sess, uin, 0, time(NULL)); - */ - gg_debug_session(gs, GG_DEBUG_MISC | GG_DEBUG_WARNING, - "// gg_session_handle_send_msg_ack_110() magic dummy1 " - "value 0x4000\n"); - } else if (msg->dummy1 != 0) { - gg_debug_session(gs, GG_DEBUG_MISC | GG_DEBUG_WARNING, - "// gg_session_handle_send_msg_ack_110() unknown dummy1 " - "value: %x\n", msg->dummy1); - } - - gg_debug_session(gs, GG_DEBUG_VERBOSE, - "// gg_session_handle_send_msg_ack_110() " - "%s=%016" PRIx64 " %s=%016" PRIx64 "\n", - msg->has_msg_id ? "msg_id" : "0", msg->msg_id, - msg->has_conv_id ? "conv_id" : "0", msg->conv_id); - - for (i = 0; i < msg->n_links; i++) { - GG110MessageAckLink *link = msg->links[i]; - if (!GG_PROTOBUF_VALID(gs, "GG110MessageAckLink", link)) - continue; - gg_debug_session(gs, GG_DEBUG_MISC, - "// gg_session_handle_send_msg_ack_110() " - "got link (id=%" PRIx64 ") \"%s\"\n", link->id, link->url); - } - - ge->type = GG_EVENT_ACK110; - ge->event.ack110.msg_type = msg->msg_type; - ge->event.ack110.seq = msg->seq; - ge->event.ack110.time = msg->time; - - gg_compat_message_ack(gs, msg->seq); - - gg110_message_ack__free_unpacked(msg, NULL); - - if (msg->seq == 0 && p->imgout_waiting_ack > 0) - p->imgout_waiting_ack--; - gg_image_sendout(gs); - - return 0; -} - -/** - * \internal Obsługuje pakiet GG_PONG. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_pong(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a pong\n"); - - ge->type = GG_EVENT_PONG; - - gs->last_pong = time(NULL); - - return 0; -} - -/** - * \internal Obsługuje pakiet GG_DISCONNECTING. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_disconnecting(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received disconnection warning\n"); - - ge->type = GG_EVENT_DISCONNECT; - - return 0; -} - -/** - * \internal Obsługuje pakiet GG_DISCONNECT_ACK. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_disconnect_ack(struct gg_session *gs, - uint32_t type, const char *ptr, size_t len, struct gg_event *ge) -{ - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received logoff acknowledge\n"); - - ge->type = GG_EVENT_DISCONNECT_ACK; - - return 0; -} - -/** - * \internal Obsługuje pakiety GG_XML_EVENT i GG_XML_ACTION. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_xml_event(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received XML event\n"); - - ge->type = GG_EVENT_XML_EVENT; - ge->event.xml_event.data = malloc(len + 1); - - if (ge->event.xml_event.data == NULL) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n"); - return -1; - } - - memcpy(ge->event.xml_event.data, ptr, len); - ge->event.xml_event.data[len] = 0; - - return 0; -} - -static int gg_session_handle_event_110(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - GG110Event *msg = gg110_event__unpack(NULL, len, (uint8_t*)ptr); - int succ = 1; - - if (!GG_PROTOBUF_VALID(gs, "GG110Event", msg)) - return -1; - - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_session_handle_event_110: " - "received GG11 event (type=%d, id=%" PRIx64 ")\n", msg->type, msg->id); - - if (msg->type == GG110_EVENT__TYPE__XML) { - ge->type = GG_EVENT_XML_EVENT; - ge->event.xml_event.data = strdup(msg->data); - succ = succ && (ge->event.xml_event.data != NULL); - } else if (msg->type == GG110_EVENT__TYPE__JSON) { - ge->type = GG_EVENT_JSON_EVENT; - ge->event.json_event.data = strdup(msg->data); - succ = succ && (ge->event.json_event.data != NULL); - ge->event.json_event.type = strdup(msg->subtype); - succ = succ && (ge->event.json_event.type != NULL); - } else { - gg_debug_session(gs, GG_DEBUG_WARNING, - "// gg_session_handle_event_110: " - "unsupported GG11 event type: %d\n", msg->type); - succ = 0; - } - - if (gg_ack_110(gs, GG110_ACK__TYPE__MPA, msg->seq, ge) != 0) { - succ = 0; - } - - gg110_event__free_unpacked(msg, NULL); - - return succ ? 0 : -1; -} - -/** - * \internal Obsługuje pakiet GG_PUBDIR50_REPLY. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_pubdir50_reply(struct gg_session *gs, - uint32_t type, const char *ptr, size_t len, struct gg_event *ge) -{ - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received pubdir/search reply\n"); - - return gg_pubdir50_handle_reply_sess(gs, ge, ptr, len); -} - -/** - * \internal Obsługuje pakiet GG_USERLIST_REPLY. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_userlist_reply(struct gg_session *gs, - uint32_t type, const char *ptr, size_t len, struct gg_event *ge) -{ - char reply_type; - - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received userlist reply\n"); - - reply_type = ptr[0]; - - /* jeśli odpowiedź na eksport, wywołaj zdarzenie tylko - * gdy otrzymano wszystkie odpowiedzi */ - if (reply_type == GG_USERLIST_PUT_REPLY || reply_type == GG_USERLIST_PUT_MORE_REPLY) { - if (--gs->userlist_blocks) - return 0; - - reply_type = GG_USERLIST_PUT_REPLY; - } - - if (len > 1) { - unsigned int reply_len = (gs->userlist_reply != NULL) ? strlen(gs->userlist_reply) : 0; - char *tmp; - - gg_debug_session(gs, GG_DEBUG_MISC, "userlist_reply=%p, len=%" - GG_SIZE_FMT "\n", gs->userlist_reply, len); - - if (reply_len + len > GG_USERLIST_REPLY_MAX_LENGTH) { - gg_debug_session(gs, GG_DEBUG_MISC, - "// gg_session_handle_userlist_reply() " - "too many userlist replies\n"); - return -1; - } - - tmp = realloc(gs->userlist_reply, reply_len + len); - - if (tmp == NULL) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n"); - return -1; - } - - gs->userlist_reply = tmp; - memcpy(gs->userlist_reply + reply_len, ptr + 1, len - 1); - gs->userlist_reply[reply_len + len - 1] = 0; - } - - if (reply_type == GG_USERLIST_GET_MORE_REPLY) - return 0; - - ge->type = GG_EVENT_USERLIST; - ge->event.userlist.type = reply_type; - ge->event.userlist.reply = gs->userlist_reply; - - gs->userlist_reply = NULL; - - return 0; -} - -/** - * \internal Obsługuje pakiet GG_DCC7_ID_REPLY. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_dcc7_id_reply(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received dcc7 id packet\n"); - - return gg_dcc7_handle_id(gs, ge, ptr, len); -} - -/** - * \internal Obsługuje pakiet GG_DCC7_ACCEPT. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_dcc7_accept(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received dcc7 accept\n"); - - return gg_dcc7_handle_accept(gs, ge, ptr, len); -} - -/** - * \internal Obsługuje pakiet GG_DCC7_NEW. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_dcc7_new(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received dcc7 request\n"); - - return gg_dcc7_handle_new(gs, ge, ptr, len); -} - -/** - * \internal Obsługuje pakiet GG_DCC7_REJECT. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_dcc7_reject(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received dcc7 reject\n"); - - return gg_dcc7_handle_reject(gs, ge, ptr, len); -} - -/** - * \internal Obsługuje pakiet GG_DCC7_INFO. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_dcc7_info(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received dcc7 info\n"); - - return gg_dcc7_handle_info(gs, ge, ptr, len); -} - -/** - * \internal Analizuje przychodzący pakiet z obrazkiem. - * - * \param e Struktura zdarzenia - * \param p Bufor z danymi - * \param len Długość bufora - * \param sess Struktura sesji - * \param sender Numer nadawcy - * \param type Typ pakietu (NIE typ GG_MSG_OPTION_IMAGE_*) - */ -static void gg_image_queue_parse(struct gg_event *e, const char *p, - unsigned int len, struct gg_session *sess, uin_t sender, - uint32_t type) -{ - const struct gg_msg_image_reply *i = (const void*) p; - struct gg_image_queue *q, *qq; - - gg_debug_session(sess, GG_DEBUG_VERBOSE, - "// gg_image_queue_parse(%p, %p, %d, %p, %u, %d)\n", - e, p, len, sess, sender, type); - - if (!p || !sess || !e) { - errno = EFAULT; - return; - } - - if (i->flag == GG_MSG_OPTION_IMAGE_REQUEST) { - e->type = GG_EVENT_IMAGE_REQUEST; - e->event.image_request.sender = sender; - e->event.image_reply.size = i->size; - e->event.image_request.crc32 = i->crc32; - return; - } - - /* znajdź dany obrazek w kolejce danej sesji */ - - for (qq = sess->images, q = NULL; qq; qq = qq->next) { - if (sender == qq->sender && i->size == qq->size && i->crc32 == qq->crc32) { - q = qq; - break; - } - } - - if (!q) { - gg_debug_session(sess, GG_DEBUG_WARNING, - "// gg_image_queue_parse() unknown image from %d, " - "size=%d, crc32=%.8x\n", sender, i->size, i->crc32); - return; - } - - if (q->packet_type == 0) - q->packet_type = type; - if (q->packet_type != type) - return; - - if (i->flag == GG_MSG_OPTION_IMAGE_REPLY) { - q->done = 0; - - len -= sizeof(struct gg_msg_image_reply); - p += sizeof(struct gg_msg_image_reply); - - if (memchr(p, 0, len) == NULL) { - gg_debug_session(sess, GG_DEBUG_ERROR, - "// gg_image_queue_parse() malformed packet " - "from %d, unlimited filename\n", sender); - return; - } - - if (!(q->filename = strdup(p))) { - gg_debug_session(sess, GG_DEBUG_ERROR, "// gg_image_queue_parse() out of memory\n"); - return; - } - - len -= strlen(p) + 1; - p += strlen(p) + 1; - } else if (i->flag == GG_MSG_OPTION_IMAGE_REPLY_MORE) { - len -= sizeof(struct gg_msg_image_reply); - p += sizeof(struct gg_msg_image_reply); - } else { - gg_debug_session(sess, GG_DEBUG_WARNING, "// gg_image_queue_parse() unexpected flag\n"); - return; - } - - if (q->done + len > q->size) { - gg_debug_session(sess, GG_DEBUG_ERROR, "// gg_image_queue_parse() got too much\n"); - len = q->size - q->done; - } - - memcpy(q->image + q->done, p, len); - q->done += len; - - gg_debug_session(sess, GG_DEBUG_VERBOSE, - "// gg_image_queue_parse() got image part (done: %d of %d)\n", - q->done, q->size); - - /* jeśli skończono odbierać obrazek, wygeneruj zdarzenie */ - - if (q->done >= q->size) { - gg_debug_session(sess, GG_DEBUG_VERBOSE, - "// gg_image_queue_parse() image ready\n"); - - e->type = GG_EVENT_IMAGE_REPLY; - e->event.image_reply.sender = sender; - e->event.image_reply.size = q->size; - e->event.image_reply.crc32 = q->crc32; - e->event.image_reply.filename = q->filename; - e->event.image_reply.image = q->image; - - gg_image_queue_remove(sess, q, 0); - - free(q); - } -} - -/** - * \internal Analizuje informacje rozszerzone wiadomości. - * - * \param sess Struktura sesji. - * \param e Struktura zdarzenia. - * \param sender Numer nadawcy. - * \param p Wskaźnik na dane rozszerzone. - * \param packet_end Wskaźnik na koniec pakietu. - * \param packet_type Typ pakietu, w którym otrzymaliśmy wiadomość. - * - * \return 0 jeśli się powiodło, -1 jeśli wiadomość obsłużono i wynik ma - * zostać przekazany aplikacji, -2 jeśli wystąpił błąd ogólny, -3 jeśli - * wiadomość jest niepoprawna. - */ -static int gg_handle_recv_msg_options(struct gg_session *sess, - struct gg_event *e, uin_t sender, const char *p, const char *packet_end, - uint32_t packet_type) -{ - while (p < packet_end) { - switch (*p) { - case GG_MSG_OPTION_CONFERENCE: - { - const struct gg_msg_recipients *m = (const void*) p; - uint32_t i, count; - - p += sizeof(*m); - - if (p > packet_end) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_handle_recv_msg_options()" - " packet out of bounds (1)\n"); - goto malformed; - } - - count = gg_fix32(m->count); - - if (p + count * sizeof(uin_t) > packet_end || - p + count * sizeof(uin_t) < p || - count > 0xffff) - { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_handle_recv_msg_options()" - " packet out of bounds (1.5)\n"); - goto malformed; - } - - if (e->event.msg.recipients != NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_handle_recv_msg_options()" - " e->event.msg.recipients already exist\n"); - goto malformed; - } - - e->event.msg.recipients = malloc(count * sizeof(uin_t)); - - if (e->event.msg.recipients == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_handle_recv_msg_options()" - " not enough memory for recipients data\n"); - goto fail; - } - - memcpy(e->event.msg.recipients, p, count * sizeof(uin_t)); - p += count * sizeof(uin_t); - - for (i = 0; i < count; i++) - e->event.msg.recipients[i] = gg_fix32(e->event.msg.recipients[i]); - - e->event.msg.recipients_count = count; - - break; - } - - case GG_MSG_OPTION_ATTRIBUTES: - { - uint16_t len; - char *buf; - - if (p + 3 > packet_end) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_handle_recv_msg_options()" - " packet out of bounds (2)\n"); - goto malformed; - } - - memcpy(&len, p + 1, sizeof(uint16_t)); - len = gg_fix16(len); - - if (e->event.msg.formats != NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_handle_recv_msg_options()" - " e->event.msg.formats already exist\n"); - goto malformed; - } - - buf = malloc(len); - - if (buf == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_handle_recv_msg_options()" - " not enough memory for richtext data\n"); - goto fail; - } - - p += 3; - - if (p + len > packet_end) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_handle_recv_msg_options()" - " packet out of bounds (3)\n"); - free(buf); - goto malformed; - } - - memcpy(buf, p, len); - - e->event.msg.formats = buf; - e->event.msg.formats_length = len; - - p += len; - - break; - } - - case GG_MSG_OPTION_IMAGE_REQUEST: - { - const struct gg_msg_image_request *i = (const void*) p; - - if (p + sizeof(*i) > packet_end) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_handle_recv_msg() " - "packet out of bounds (3)\n"); - goto malformed; - } - - if (e->event.msg.formats != NULL || e->event.msg.recipients != NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_handle_recv_msg_options()" - " mixed options (1)\n"); - goto malformed; - } - - e->event.image_request.sender = sender; - e->event.image_request.size = gg_fix32(i->size); - e->event.image_request.crc32 = gg_fix32(i->crc32); - - e->type = GG_EVENT_IMAGE_REQUEST; - - goto handled; - } - - case GG_MSG_OPTION_IMAGE_REPLY: - case GG_MSG_OPTION_IMAGE_REPLY_MORE: - { - struct gg_msg_image_reply *rep = (void*) p; - - if (e->event.msg.formats != NULL || e->event.msg.recipients != NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_handle_recv_msg_options() " - "mixed options (2)\n"); - goto malformed; - } - - if (p + sizeof(struct gg_msg_image_reply) == packet_end) { - - /* pusta odpowiedź - klient po drugiej stronie nie ma żądanego obrazka */ - - e->type = GG_EVENT_IMAGE_REPLY; - e->event.image_reply.sender = sender; - e->event.image_reply.size = 0; - e->event.image_reply.crc32 = gg_fix32(rep->crc32); - e->event.image_reply.filename = NULL; - e->event.image_reply.image = NULL; - goto handled; - - } else if (p + sizeof(struct gg_msg_image_reply) + 1 > packet_end) { - - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_handle_recv_msg() " - "packet out of bounds (4)\n"); - goto malformed; - } - - rep->size = gg_fix32(rep->size); - rep->crc32 = gg_fix32(rep->crc32); - gg_image_queue_parse(e, p, (unsigned int)(packet_end - p), sess, sender, packet_type); - - goto handled; - } - - default: - { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_handle_recv_msg() " - "unknown payload 0x%.2x\n", *p); - p = packet_end; - } - } - } - - return 0; - -handled: - return -1; - -fail: - return -2; - -malformed: - return -3; -} - -/** - * \internal Wysyła potwierdzenie odebrania wiadomości. - * - * \param gs Struktura sesji - * \param seq Numer sekwencyjny odebranej wiadomości - * - * \return 0 jeśli się powiodło, -1 jeśli wystąpił błąd - */ -static int gg_session_send_msg_ack(struct gg_session *gs, uint32_t seq) -{ - struct gg_recv_msg_ack pkt; - - gg_debug_session(gs, GG_DEBUG_FUNCTION, "** gg_session_send_msg_ack(%p);\n", gs); - - if ((gs->protocol_features & GG_FEATURE_MSG_ACK) == 0) - return 0; - - /* Kiedyś zdawało nam się, że mamy wysyłać liczbę odebranych - * wiadomości, ale okazało się, że numer sekwencyjny. */ - gs->recv_msg_count++; - - pkt.seq = gg_fix32(seq); - - return gg_send_packet(gs, GG_RECV_MSG_ACK, &pkt, sizeof(pkt), NULL); -} - -/** - * \internal Obsługuje pakiet GG_RECV_MSG. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_recv_msg(struct gg_session *sess, uint32_t type, - const char *packet, size_t length, struct gg_event *e) -{ - const struct gg_recv_msg *r = (const struct gg_recv_msg*) packet; - const char *payload = packet + sizeof(struct gg_recv_msg); - const char *payload_end = packet + length; - size_t len; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_handle_recv_msg(%p, %" - GG_SIZE_FMT ", %p);\n", packet, length, e); - - if (sess == NULL) - goto fail; - - if ((r->seq == 0) && (r->msgclass == 0)) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() oops, silently ignoring the bait\n"); - goto malformed; - } - - /* jednobajtowa wiadomość o treści \x02 to żądanie połączenia DCC */ - if (*payload == GG_MSG_CALLBACK && payload == payload_end - 1) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() received ctcp packet\n"); - length = 1; - } else { - const char *options; - - options = memchr(payload, 0, (size_t) (payload_end - payload)); - - if (options == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_handle_recv_msg() malformed packet, " - "message out of bounds (0)\n"); - goto malformed; - } - - length = (size_t) (options - payload); - - switch (gg_handle_recv_msg_options(sess, e, gg_fix32(r->sender), options + 1, payload_end, type)) { - case -1: /* handled */ - gg_session_send_msg_ack(sess, gg_fix32(r->seq)); - return 0; - - case -2: /* failed */ - goto fail; - - case -3: /* malformed */ - goto malformed; - } - } - - e->type = GG_EVENT_MSG; - e->event.msg.msgclass = gg_fix32(r->msgclass); - e->event.msg.sender = gg_fix32(r->sender); - e->event.msg.time = gg_fix32(r->time); - e->event.msg.seq = gg_fix32(r->seq); - - e->event.msg.message = (unsigned char*)gg_encoding_convert(payload, - GG_ENCODING_CP1250, sess->encoding, length, -1); - if (e->event.msg.message == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_session_handle_recv_msg() out of memory\n"); - goto fail; - } - - len = gg_message_text_to_html(NULL, (char*)e->event.msg.message, - sess->encoding, e->event.msg.formats, - e->event.msg.formats_length); - e->event.msg.xhtml_message = malloc(len + 1); - - if (e->event.msg.xhtml_message == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_session_handle_recv_msg() out of memory\n"); - goto fail; - } - - gg_message_text_to_html(e->event.msg.xhtml_message, - (char*)e->event.msg.message, sess->encoding, - e->event.msg.formats, e->event.msg.formats_length); - - gg_session_send_msg_ack(sess, gg_fix32(r->seq)); - return 0; - -fail: - free(e->event.msg.message); - free(e->event.msg.xhtml_message); - free(e->event.msg.recipients); - free(e->event.msg.formats); - return -1; - -malformed: - e->type = GG_EVENT_NONE; - free(e->event.msg.message); - free(e->event.msg.xhtml_message); - free(e->event.msg.recipients); - free(e->event.msg.formats); - gg_session_send_msg_ack(sess, gg_fix32(r->seq)); - return 0; -} - -/** - * \internal Obsługuje pakiet GG_RECV_MSG80. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_recv_msg_80(struct gg_session *sess, uint32_t type, - const char *packet, size_t length, struct gg_event *e) -{ - const struct gg_recv_msg80 *r = (const struct gg_recv_msg80*) packet; - uint32_t offset_plain; - uint32_t offset_attr; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, - "** gg_handle_recv_msg80(%p, %" GG_SIZE_FMT ", %p);\n", - packet, length, e); - - if (sess == NULL) - goto fail; - - if (r->seq == 0 && r->msgclass == 0) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg80() oops, silently ignoring the bait\n"); - goto malformed; - } - - offset_plain = gg_fix32(r->offset_plain); - offset_attr = gg_fix32(r->offset_attr); - - if (offset_plain < sizeof(struct gg_recv_msg80) || offset_plain >= length) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_handle_recv_msg80() malformed packet, " - "message out of bounds (0)\n"); - goto malformed; - } - - if (offset_attr < sizeof(struct gg_recv_msg80) || offset_attr > length) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_handle_recv_msg80() malformed packet, " - "attr out of bounds (1)\n"); - offset_attr = 0; /* nie parsuj attr. */ - } - - /* Normalna sytuacja, więc nie podpada pod powyższy warunek. */ - if (offset_attr == length) - offset_attr = 0; - - if (memchr(packet + offset_plain, 0, length - offset_plain) == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_handle_recv_msg80() malformed packet, " - "message out of bounds (2)\n"); - goto malformed; - } - - if (offset_plain > sizeof(struct gg_recv_msg80) && memchr(packet + - sizeof(struct gg_recv_msg80), 0, offset_plain - - sizeof(struct gg_recv_msg80)) == NULL) - { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_handle_recv_msg80() malformed packet, " - "message out of bounds (3)\n"); - goto malformed; - } - - e->type = (type != GG_RECV_OWN_MSG) ? GG_EVENT_MSG : GG_EVENT_MULTILOGON_MSG; - e->event.msg.msgclass = gg_fix32(r->msgclass); - e->event.msg.sender = gg_fix32(r->sender); - e->event.msg.time = gg_fix32(r->time); - e->event.msg.seq = gg_fix32(r->seq); - - if (offset_attr != 0) { - switch (gg_handle_recv_msg_options(sess, e, gg_fix32(r->sender), - packet + offset_attr, packet + length, type)) - { - case -1: /* handled */ - gg_session_send_msg_ack(sess, gg_fix32(r->seq)); - return 0; - - case -2: /* failed */ - goto fail; - - case -3: /* malformed */ - goto malformed; - } - } - - if (sess->encoding == GG_ENCODING_CP1250) { - e->event.msg.message = (unsigned char*) strdup(packet + offset_plain); - - if (e->event.msg.message == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_session_handle_recv_msg_80() out of memory\n"); - goto fail; - } - } else { - if (offset_plain > sizeof(struct gg_recv_msg80)) { - size_t len, fmt_len; - - len = gg_message_html_to_text(NULL, NULL, &fmt_len, - packet + sizeof(struct gg_recv_msg80), - GG_ENCODING_UTF8); - e->event.msg.message = malloc(len + 1); - - if (e->event.msg.message == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_session_handle_recv_msg_80() " - "out of memory\n"); - goto fail; - } - - free(e->event.msg.formats); - e->event.msg.formats_length = fmt_len; - e->event.msg.formats = malloc(fmt_len); - - if (e->event.msg.formats == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_session_handle_recv_msg_80() " - "out of memory\n"); - goto fail; - } - - gg_message_html_to_text((char*)e->event.msg.message, - e->event.msg.formats, NULL, - packet + sizeof(struct gg_recv_msg80), - GG_ENCODING_UTF8); - } else { - e->event.msg.message = (unsigned char*)gg_encoding_convert( - packet + offset_plain, GG_ENCODING_CP1250, - sess->encoding, -1, -1); - - if (e->event.msg.message == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_session_handle_recv_msg_80() " - "out of memory\n"); - goto fail; - } - } - } - - if (offset_plain > sizeof(struct gg_recv_msg80)) { - e->event.msg.xhtml_message = gg_encoding_convert( - packet + sizeof(struct gg_recv_msg80), GG_ENCODING_UTF8, - sess->encoding, -1, -1); - - if (e->event.msg.xhtml_message == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_session_handle_recv_msg_80() out of memory\n"); - goto fail; - } - } else { - size_t len; - - len = gg_message_text_to_html(NULL, - (char*)e->event.msg.message, sess->encoding, - e->event.msg.formats, e->event.msg.formats_length); - e->event.msg.xhtml_message = malloc(len + 1); - - if (e->event.msg.xhtml_message == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_session_handle_recv_msg_80() out of memory\n"); - goto fail; - } - - gg_message_text_to_html(e->event.msg.xhtml_message, - (char*)e->event.msg.message, sess->encoding, - e->event.msg.formats, e->event.msg.formats_length); - } - - gg_session_send_msg_ack(sess, gg_fix32(r->seq)); - return 0; - -fail: - free(e->event.msg.message); - free(e->event.msg.xhtml_message); - free(e->event.msg.recipients); - free(e->event.msg.formats); - return -1; - -malformed: - e->type = GG_EVENT_NONE; - free(e->event.msg.message); - free(e->event.msg.xhtml_message); - free(e->event.msg.recipients); - free(e->event.msg.formats); - gg_session_send_msg_ack(sess, gg_fix32(r->seq)); - return 0; -} - -static int gg_session_handle_recv_msg_110(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - GG110RecvMessage *msg = gg110_recv_message__unpack(NULL, len, (uint8_t*)ptr); - uint8_t ack_type; - uin_t sender = 0; - uint32_t seq; - int succ = 1; - struct gg_event_msg *ev = &ge->event.msg; - - gg_debug_session(gs, GG_DEBUG_FUNCTION, - "** gg_session_handle_recv_msg_110(%p, %" GG_SIZE_FMT - ", %p);\n", ptr, len, ge); - - if (!GG_PROTOBUF_VALID(gs, "GG110RecvMessage", msg)) - return -1; - - seq = msg->seq; - if (type == GG_CHAT_RECV_MSG || type == GG_CHAT_RECV_OWN_MSG) - ack_type = GG110_ACK__TYPE__CHAT; - else - ack_type = GG110_ACK__TYPE__MSG; - - if (msg->has_msg_id || msg->has_conv_id) { - msg->msg_id = msg->has_msg_id ? msg->msg_id : 0; - msg->conv_id = msg->has_conv_id ? msg->conv_id : 0; - gg_debug_session(gs, GG_DEBUG_VERBOSE, - "// gg_session_handle_recv_msg_110() " - "msg_id=%016" PRIx64 " conv_id=%016" PRIx64 "\n", - msg->msg_id, msg->conv_id); - } - - if (msg->has_sender) - sender = gg_protobuf_get_uin(msg->sender); - else if (type == GG_CHAT_RECV_OWN_MSG) - sender = gs->uin; - - if (msg->has_data && msg->msg_plain[0] == '\0') { - if (msg->data.len < sizeof(struct gg_msg_image_reply)) { - gg_debug_session(gs, GG_DEBUG_ERROR, - "// gg_session_handle_recv_msg_110() " - "packet too small (%" GG_SIZE_FMT " < %" - GG_SIZE_FMT ")\n", msg->data.len, - sizeof(struct gg_msg_image_reply)); - } else { - gg_image_queue_parse(ge, (char *)msg->data.data, - msg->data.len, gs, sender, type); - } - gg110_recv_message__free_unpacked(msg, NULL); - return gg_ack_110(gs, GG110_ACK__TYPE__MSG, seq, ge); - } - - if (type == GG_RECV_OWN_MSG110 || type == GG_CHAT_RECV_OWN_MSG) - ge->type = GG_EVENT_MULTILOGON_MSG; - else - ge->type = GG_EVENT_MSG; - ev->msgclass = GG_CLASS_CHAT; - ev->seq = seq; - ev->sender = sender; - ev->flags = msg->flags; - ev->seq = seq; - ev->time = msg->time; - - if (abs(msg->time - gg_server_time(gs)) > 2) - ev->msgclass |= GG_CLASS_QUEUED; - - ev->message = NULL; - if (msg->msg_plain[0] != '\0') { - ev->message = (unsigned char*)gg_encoding_convert( - msg->msg_plain, GG_ENCODING_UTF8, gs->encoding, -1, -1); - succ = succ && (ev->message != NULL); - } - ev->xhtml_message = NULL; - if (msg->msg_xhtml != NULL) { - ev->xhtml_message = gg_encoding_convert( - msg->msg_xhtml, GG_ENCODING_UTF8, gs->encoding, -1, -1); - succ = succ && (ev->xhtml_message != NULL); - } - - /* wiadomości wysłane z mobilnego gg nie posiadają wersji xhtml */ - if (ev->message == NULL && ev->xhtml_message == NULL) { - ev->message = (unsigned char*)strdup(""); - succ = succ && (ev->message != NULL); - } else if (ev->message == NULL) { - ev->message = (unsigned char*)gg_message_html_to_text_110( - ev->xhtml_message); - succ = succ && (ev->message != NULL); - } else if (ev->xhtml_message == NULL) { - ev->xhtml_message = gg_message_text_to_html_110( - (char*)ev->message, -1); - succ = succ && (ev->xhtml_message != NULL); - } - - /* otrzymywane tylko od gg <= 10.5 */ - ev->formats = NULL; - ev->formats_length = 0; - if (msg->has_data && succ) { - ev->formats_length = msg->data.len; - ev->formats = malloc(msg->data.len); - if (ev->formats == NULL) - succ = 0; - else - memcpy(ev->formats, msg->data.data, msg->data.len); - } - - if (msg->has_chat_id && succ) { - gg_chat_list_t *chat; - - ev->chat_id = msg->chat_id; - - chat = gg_chat_find(gs, msg->chat_id); - if (chat) { - size_t rcpt_size = chat->participants_count * - sizeof(uin_t); - ev->recipients = malloc(rcpt_size); - ev->recipients_count = chat->participants_count; - if (ev->recipients == NULL) - succ = 0; - else { - memcpy(ev->recipients, chat->participants, - rcpt_size); - } - } - } - - gg110_recv_message__free_unpacked(msg, NULL); - - if (gg_ack_110(gs, ack_type, seq, ge) != 0) - succ = 0; - - if (succ) - return 0; - else { - free(ev->message); - free(ev->xhtml_message); - free(ev->formats); - free(ev->recipients); - return -1; - } -} - -/** - * \internal Obsługuje pakiet GG_STATUS. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_status(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - const struct gg_status *s = (const void*) ptr; - - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a status change\n"); - - ge->type = GG_EVENT_STATUS; - ge->event.status.uin = gg_fix32(s->uin); - ge->event.status.status = gg_fix32(s->status); - ge->event.status.descr = NULL; - - if (len > sizeof(*s)) { - ge->event.status.descr = gg_encoding_convert(ptr + sizeof(*s), - GG_ENCODING_CP1250, gs->encoding, len - sizeof(*s), -1); - - if (ge->event.status.descr == NULL) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n"); - return -1; - } - } - - return 0; -} - -/** - * \internal Obsługuje pakiety GG_STATUS60, GG_STATUS77 i GG_STATUS80BETA. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_status_60_77_80beta(struct gg_session *gs, - uint32_t type, const char *ptr, size_t len, struct gg_event *ge) -{ - const struct gg_status60 *s60 = (const void*) ptr; - const struct gg_status77 *s77 = (const void*) ptr; - size_t struct_len; - uint32_t uin; - - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a status change\n"); - - ge->type = GG_EVENT_STATUS60; - ge->event.status60.descr = NULL; - ge->event.status60.time = 0; - - if (type == GG_STATUS60) { - uin = gg_fix32(s60->uin); - ge->event.status60.status = s60->status; - ge->event.status60.remote_ip = s60->remote_ip; - ge->event.status60.remote_port = gg_fix16(s60->remote_port); - ge->event.status60.version = s60->version; - ge->event.status60.image_size = s60->image_size; - struct_len = sizeof(*s60); - } else { - uin = gg_fix32(s77->uin); - ge->event.status60.status = s77->status; - ge->event.status60.remote_ip = s77->remote_ip; - ge->event.status60.remote_port = gg_fix16(s77->remote_port); - ge->event.status60.version = s77->version; - ge->event.status60.image_size = s77->image_size; - struct_len = sizeof(*s77); - } - - ge->event.status60.uin = uin & 0x00ffffff; - - if (uin & 0x40000000) - ge->event.status60.version |= GG_HAS_AUDIO_MASK; - if (uin & 0x20000000) - ge->event.status60.version |= GG_HAS_AUDIO7_MASK; - if (uin & 0x08000000) - ge->event.status60.version |= GG_ERA_OMNIX_MASK; - - if (len > struct_len) { - size_t descr_len; - - descr_len = len - struct_len; - - ge->event.status60.descr = gg_encoding_convert(ptr + struct_len, - (type == GG_STATUS80BETA) ? GG_ENCODING_UTF8 : GG_ENCODING_CP1250, - gs->encoding, descr_len, -1); - - if (ge->event.status60.descr == NULL) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n"); - return -1; - } - - if (descr_len > 4 && ptr[len - 5] == 0) { - uint32_t t; - memcpy(&t, ptr + len - 4, sizeof(uint32_t)); - ge->event.status60.time = gg_fix32(t); - } - } - - return 0; -} - -/** - * \internal Obsługuje pakiet GG_NOTIFY_REPLY. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_notify_reply(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - const struct gg_notify_reply *n = (const void*) ptr; - char *descr; - - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n"); - - if (gg_fix32(n->status) == GG_STATUS_BUSY_DESCR || - gg_fix32(n->status) == GG_STATUS_NOT_AVAIL_DESCR || - gg_fix32(n->status) == GG_STATUS_AVAIL_DESCR) - { - size_t descr_len; - - ge->type = GG_EVENT_NOTIFY_DESCR; - - if (!(ge->event.notify_descr.notify = (void*) malloc(sizeof(*n) * 2))) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n"); - return -1; - } - ge->event.notify_descr.notify[1].uin = 0; - memcpy(ge->event.notify_descr.notify, ptr, sizeof(*n)); - ge->event.notify_descr.notify[0].uin = gg_fix32(ge->event.notify_descr.notify[0].uin); - ge->event.notify_descr.notify[0].status = gg_fix32(ge->event.notify_descr.notify[0].status); - ge->event.notify_descr.notify[0].remote_port = gg_fix16(ge->event.notify_descr.notify[0].remote_port); - ge->event.notify_descr.notify[0].version = gg_fix32(ge->event.notify_descr.notify[0].version); - - descr_len = len - sizeof(*n); - - descr = gg_encoding_convert(ptr + sizeof(*n), GG_ENCODING_CP1250, gs->encoding, descr_len, -1); - - if (descr == NULL) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n"); - return -1; - } - - ge->event.notify_descr.descr = descr; - - } else { - unsigned int i, count; - - ge->type = GG_EVENT_NOTIFY; - - if (!(ge->event.notify = (void*) malloc(len + 2 * sizeof(*n)))) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n"); - return -1; - } - - memcpy(ge->event.notify, ptr, len); - count = len / sizeof(*n); - ge->event.notify[count].uin = 0; - - for (i = 0; i < count; i++) { - ge->event.notify[i].uin = gg_fix32(ge->event.notify[i].uin); - ge->event.notify[i].status = gg_fix32(ge->event.notify[i].status); - ge->event.notify[i].remote_port = gg_fix16(ge->event.notify[i].remote_port); - ge->event.notify[i].version = gg_fix32(ge->event.notify[i].version); - } - } - - return 0; -} - -/** - * \internal Obsługuje pakiet GG_STATUS80. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_status_80(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - const struct gg_notify_reply80 *n = (const void*) ptr; - size_t descr_len; - - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a status change\n"); - - ge->type = GG_EVENT_STATUS60; - ge->event.status60.uin = gg_fix32(n->uin); - ge->event.status60.status = gg_fix32(n->status); - ge->event.status60.remote_ip = n->remote_ip; - ge->event.status60.remote_port = gg_fix16(n->remote_port); - ge->event.status60.version = 0; - ge->event.status60.image_size = n->image_size; - ge->event.status60.descr = NULL; - ge->event.status60.time = 0; - - descr_len = gg_fix32(n->descr_len); - - if (descr_len != 0 && sizeof(struct gg_notify_reply80) + descr_len <= len) { - ge->event.status60.descr = gg_encoding_convert( - (const char*) n + sizeof(struct gg_notify_reply80), - GG_ENCODING_UTF8, gs->encoding, descr_len, -1); - - if (ge->event.status60.descr == NULL) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n"); - return -1; - } - - /* XXX czas */ - } - - return 0; -} - -/** - * \internal Obsługuje pakiet GG_NOTIFY_REPLY80. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_notify_reply_80(struct gg_session *gs, - uint32_t type, const char *ptr, size_t len, struct gg_event *ge) -{ - const struct gg_notify_reply80 *n = (const void*) ptr; - unsigned int length = len, i = 0; - - /* TODO: najpierw przeanalizować strukturę i określić - * liczbę rekordów, żeby obyć się bez realloc() - */ - - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n"); - - ge->type = GG_EVENT_NOTIFY60; - ge->event.notify60 = malloc(sizeof(*ge->event.notify60)); - - if (!ge->event.notify60) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n"); - return -1; - } - - ge->event.notify60[0].uin = 0; - - while (length >= sizeof(struct gg_notify_reply80)) { - uin_t uin = gg_fix32(n->uin); - int descr_len; - void *tmp; - - ge->event.notify60[i].uin = uin; - ge->event.notify60[i].status = gg_fix32(n->status); - ge->event.notify60[i].remote_ip = n->remote_ip; - ge->event.notify60[i].remote_port = gg_fix16(n->remote_port); - ge->event.notify60[i].version = 0; - ge->event.notify60[i].image_size = n->image_size; - ge->event.notify60[i].descr = NULL; - ge->event.notify60[i].time = 0; - - descr_len = gg_fix32(n->descr_len); - - if (descr_len != 0) { - if (sizeof(struct gg_notify_reply80) + descr_len <= length) { - ge->event.notify60[i].descr = gg_encoding_convert( - (const char*) n + sizeof(struct gg_notify_reply80), - GG_ENCODING_UTF8, gs->encoding, descr_len, -1); - - if (ge->event.notify60[i].descr == NULL) { - gg_debug_session(gs, GG_DEBUG_MISC, - "// gg_watch_fd_connected() " - "out of memory\n"); - return -1; - } - - /* XXX czas */ - - length -= sizeof(struct gg_notify_reply80) + descr_len; - n = (const void*) ((const char*) n + sizeof(struct gg_notify_reply80) + descr_len); - } else { - length = 0; - } - - } else { - length -= sizeof(struct gg_notify_reply80); - n = (const void*) ((const char*) n + sizeof(struct gg_notify_reply80)); - } - - if (!(tmp = realloc(ge->event.notify60, (i + 2) * sizeof(*ge->event.notify60)))) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n"); - free(ge->event.notify60); - return -1; - } - - ge->event.notify60 = tmp; - ge->event.notify60[++i].uin = 0; - } - - return 0; -} - -/** - * \internal Obsługuje pakiety GG_NOTIFY_REPLY77 i GG_NOTIFY_REPLY80BETA. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_notify_reply_77_80beta(struct gg_session *gs, - uint32_t type, const char *ptr, size_t len, struct gg_event *ge) -{ - const struct gg_notify_reply77 *n = (const void*) ptr; - unsigned int length = len, i = 0; - - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n"); - - ge->type = GG_EVENT_NOTIFY60; - ge->event.notify60 = malloc(sizeof(*ge->event.notify60)); - - if (ge->event.notify60 == NULL) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n"); - return -1; - } - - ge->event.notify60[0].uin = 0; - - while (length >= sizeof(struct gg_notify_reply77)) { - uin_t uin = gg_fix32(n->uin); - void *tmp; - - ge->event.notify60[i].uin = uin & 0x00ffffff; - ge->event.notify60[i].status = n->status; - ge->event.notify60[i].remote_ip = n->remote_ip; - ge->event.notify60[i].remote_port = gg_fix16(n->remote_port); - ge->event.notify60[i].version = n->version; - ge->event.notify60[i].image_size = n->image_size; - ge->event.notify60[i].descr = NULL; - ge->event.notify60[i].time = 0; - - if (uin & 0x40000000) - ge->event.notify60[i].version |= GG_HAS_AUDIO_MASK; - if (uin & 0x20000000) - ge->event.notify60[i].version |= GG_HAS_AUDIO7_MASK; - if (uin & 0x08000000) - ge->event.notify60[i].version |= GG_ERA_OMNIX_MASK; - - if (GG_S_D(n->status)) { - unsigned char descr_len = *((const char*) n + sizeof(struct gg_notify_reply77)); - - if (sizeof(struct gg_notify_reply77) + descr_len <= length) { - ge->event.notify60[i].descr = gg_encoding_convert( - (const char*) n + sizeof(struct gg_notify_reply77) + 1, - (type == GG_NOTIFY_REPLY80BETA) ? GG_ENCODING_UTF8 : GG_ENCODING_CP1250, - gs->encoding, descr_len, -1); - - if (ge->event.notify60[i].descr == NULL) { - gg_debug_session(gs, GG_DEBUG_MISC, - "// gg_watch_fd_connected() " - "out of memory\n"); - return -1; - } - - /* XXX czas */ - - length -= sizeof(struct gg_notify_reply77) + descr_len + 1; - n = (const void*) ((const char*) n + sizeof(struct gg_notify_reply77) + descr_len + 1); - } else { - length = 0; - } - - } else { - length -= sizeof(struct gg_notify_reply77); - n = (const void*) ((const char*) n + sizeof(struct gg_notify_reply77)); - } - - if (!(tmp = realloc(ge->event.notify60, (i + 2) * sizeof(*ge->event.notify60)))) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n"); - free(ge->event.notify60); - return -1; - } - - ge->event.notify60 = tmp; - ge->event.notify60[++i].uin = 0; - } - - return 0; -} - -/** - * \internal Obsługuje pakiet GG_NOTIFY_REPLY60. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_notify_reply_60(struct gg_session *gs, - uint32_t type, const char *ptr, size_t len, struct gg_event *ge) -{ - const struct gg_notify_reply60 *n = (const void*) ptr; - unsigned int length = len, i = 0; - - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n"); - - ge->type = GG_EVENT_NOTIFY60; - ge->event.notify60 = malloc(sizeof(*ge->event.notify60)); - - if (ge->event.notify60 == NULL) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n"); - return -1; - } - - ge->event.notify60[0].uin = 0; - - while (length >= sizeof(struct gg_notify_reply60)) { - uin_t uin = gg_fix32(n->uin); - void *tmp; - - ge->event.notify60[i].uin = uin & 0x00ffffff; - ge->event.notify60[i].status = n->status; - ge->event.notify60[i].remote_ip = n->remote_ip; - ge->event.notify60[i].remote_port = gg_fix16(n->remote_port); - ge->event.notify60[i].version = n->version; - ge->event.notify60[i].image_size = n->image_size; - ge->event.notify60[i].descr = NULL; - ge->event.notify60[i].time = 0; - - if (uin & 0x40000000) - ge->event.notify60[i].version |= GG_HAS_AUDIO_MASK; - if (uin & 0x08000000) - ge->event.notify60[i].version |= GG_ERA_OMNIX_MASK; - - if (GG_S_D(n->status)) { - unsigned char descr_len = *((const char*) n + sizeof(struct gg_notify_reply60)); - - if (sizeof(struct gg_notify_reply60) + descr_len <= length) { - char *descr; - - descr = gg_encoding_convert((const char*) n + - sizeof(struct gg_notify_reply60) + 1, - GG_ENCODING_CP1250, gs->encoding, - descr_len, -1); - - if (descr == NULL) { - gg_debug_session(gs, GG_DEBUG_MISC, - "// gg_watch_fd_connected() " - "out of memory\n"); - return -1; - } - - ge->event.notify60[i].descr = descr; - - /* XXX czas */ - - length -= sizeof(struct gg_notify_reply60) + descr_len + 1; - n = (const void*) ((const char*) n + sizeof(struct gg_notify_reply60) + descr_len + 1); - } else { - length = 0; - } - - } else { - length -= sizeof(struct gg_notify_reply60); - n = (const void*) ((const char*) n + sizeof(struct gg_notify_reply60)); - } - - if (!(tmp = realloc(ge->event.notify60, (i + 2) * sizeof(*ge->event.notify60)))) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n"); - free(ge->event.notify60); - return -1; - } - - ge->event.notify60 = tmp; - ge->event.notify60[++i].uin = 0; - } - - return 0; -} - -/** - * \internal Obsługuje pakiet GG_USER_DATA. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_user_data(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - struct gg_user_data d; - const char *p = (const char*) ptr; - const char *packet_end = (const char*) ptr + len; - struct gg_event_user_data_user *users; - unsigned int i, j; - int res = 0; - - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received user data\n"); - - ge->event.user_data.user_count = 0; - ge->event.user_data.users = NULL; - - if (ptr + sizeof(d) > packet_end) - goto malformed; - - memcpy(&d, p, sizeof(d)); - p += sizeof(d); - - d.type = gg_fix32(d.type); - d.user_count = gg_fix32(d.user_count); - - if (d.user_count > 0xffff) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_session_handle_user_data() malformed packet (1)\n"); - goto malformed; - } - - if (d.user_count > 0) { - users = calloc(d.user_count, sizeof(struct gg_event_user_data_user)); - - if (users == NULL) { - gg_debug_session(gs, GG_DEBUG_MISC, - "// gg_session_handle_user_data() out of memory" - " (%d*%" GG_SIZE_FMT ")\n", d.user_count, - sizeof(struct gg_event_user_data_user)); - goto fail; - } - } else { - users = NULL; - } - - ge->type = GG_EVENT_USER_DATA; - ge->event.user_data.type = d.type; - ge->event.user_data.user_count = d.user_count; - ge->event.user_data.users = users; - - gg_debug_session(gs, GG_DEBUG_DUMP, "type=%d, count=%d\n", d.type, d.user_count); - - for (i = 0; i < d.user_count; i++) { - struct gg_user_data_user u; - struct gg_event_user_data_attr *attrs; - - if (p + sizeof(u) > packet_end) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_session_handle_user_data() malformed packet (2)\n"); - goto malformed; - } - - memcpy(&u, p, sizeof(u)); - p += sizeof(u); - - u.uin = gg_fix32(u.uin); - u.attr_count = gg_fix32(u.attr_count); - - if (u.attr_count > 0xffff) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_session_handle_user_data() malformed packet (2)\n"); - goto malformed; - } - - if (u.attr_count > 0) { - attrs = calloc(u.attr_count, sizeof(struct gg_event_user_data_attr)); - - if (attrs == NULL) { - gg_debug_session(gs, GG_DEBUG_MISC, - "// gg_session_handle_user_data() " - "out of memory (%d*%" GG_SIZE_FMT - ")\n", u.attr_count, - sizeof(struct gg_event_user_data_attr)); - goto fail; - } - } else { - attrs = NULL; - } - - users[i].uin = u.uin; - users[i].attr_count = u.attr_count; - users[i].attrs = attrs; - - gg_debug_session(gs, GG_DEBUG_DUMP, " uin=%d, count=%d\n", u.uin, u.attr_count); - - for (j = 0; j < u.attr_count; j++) { - uint32_t key_size; - uint32_t attr_type; - uint32_t value_size; - char *key; - char *value; - - if (p + sizeof(key_size) > packet_end) { - gg_debug_session(gs, GG_DEBUG_MISC, - "// gg_session_handle_user_data()" - "malformed packet (3)\n"); - goto malformed; - } - - memcpy(&key_size, p, sizeof(key_size)); - p += sizeof(key_size); - - key_size = gg_fix32(key_size); - - if (key_size > 0xffff || p + key_size > packet_end) { - gg_debug_session(gs, GG_DEBUG_MISC, - "// gg_session_handle_user_data() " - "malformed packet (3)\n"); - goto malformed; - } - - key = malloc(key_size + 1); - - if (key == NULL) { - gg_debug_session(gs, GG_DEBUG_MISC, - "// gg_session_handle_user_data() " - "out of memory (%d)\n", key_size + 1); - goto fail; - } - - memcpy(key, p, key_size); - p += key_size; - - key[key_size] = 0; - - attrs[j].key = key; - - if (p + sizeof(attr_type) + sizeof(value_size) > packet_end) { - gg_debug_session(gs, GG_DEBUG_MISC, - "// gg_session_handle_user_data() " - "malformed packet (4)\n"); - goto malformed; - } - - memcpy(&attr_type, p, sizeof(attr_type)); - p += sizeof(attr_type); - memcpy(&value_size, p, sizeof(value_size)); - p += sizeof(value_size); - - attrs[j].type = gg_fix32(attr_type); - value_size = gg_fix32(value_size); - - if (value_size > 0xffff || p + value_size > packet_end) { - gg_debug_session(gs, GG_DEBUG_MISC, - "// gg_session_handle_user_data() " - "malformed packet (5)\n"); - goto malformed; - } - - value = malloc(value_size + 1); - - if (value == NULL) { - gg_debug_session(gs, GG_DEBUG_MISC, - "// gg_session_handle_user_data() " - "out of memory (%d)\n", value_size + 1); - goto fail; - } - - memcpy(value, p, value_size); - p += value_size; - - value[value_size] = 0; - - attrs[j].value = value; - - gg_debug_session(gs, GG_DEBUG_DUMP, " key=\"%s\", " - "type=%d, value=\"%s\"\n", key, attr_type, value); - } - } - - return 0; - -fail: - res = -1; - -malformed: - ge->type = GG_EVENT_NONE; - - for (i = 0; i < ge->event.user_data.user_count; i++) { - for (j = 0; j < ge->event.user_data.users[i].attr_count; j++) { - free(ge->event.user_data.users[i].attrs[j].key); - free(ge->event.user_data.users[i].attrs[j].value); - } - - free(ge->event.user_data.users[i].attrs); - } - - free(ge->event.user_data.users); - - return res; -} - -/** - * \internal Obsługuje pakiet GG_TYPING_NOTIFICATION. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_typing_notification(struct gg_session *gs, - uint32_t type, const char *ptr, size_t len, struct gg_event *ge) -{ - const struct gg_typing_notification *n = (const void*) ptr; - uin_t uin; - - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received typing notification\n"); - - memcpy(&uin, &n->uin, sizeof(uin_t)); - - ge->type = GG_EVENT_TYPING_NOTIFICATION; - ge->event.typing_notification.uin = gg_fix32(uin); - ge->event.typing_notification.length = gg_fix16(n->length); - - return 0; -} - -/** - * \internal Obsługuje pakiet GG_MULTILOGON_INFO. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_multilogon_info(struct gg_session *gs, - uint32_t type, const char *ptr, size_t len, struct gg_event *ge) -{ - const char *packet_end = (const char*) ptr + len; - const struct gg_multilogon_info *info = (const struct gg_multilogon_info*) ptr; - const char *p = (const char*) ptr + sizeof(*info); - struct gg_multilogon_session *sessions = NULL; - size_t count; - size_t i; - int res = 0; - - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received multilogon info\n"); - - count = gg_fix32(info->count); - - if (count > 0xffff) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_handle_multilogon_info() malformed packet (1)\n"); - goto malformed; - } - - sessions = calloc(count, sizeof(struct gg_multilogon_session)); - - if (sessions == NULL) { - gg_debug_session(gs, GG_DEBUG_MISC, "// " - "gg_handle_multilogon_info() out of memory (%" - GG_SIZE_FMT "*%" GG_SIZE_FMT ")\n", - count, sizeof(struct gg_multilogon_session)); - return -1; - } - - ge->type = GG_EVENT_MULTILOGON_INFO; - ge->event.multilogon_info.count = count; - ge->event.multilogon_info.sessions = sessions; - - for (i = 0; i < count; i++) { - struct gg_multilogon_info_item item; - size_t name_size; - - if (p + sizeof(item) > packet_end) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_handle_multilogon_info() malformed packet (2)\n"); - goto malformed; - } - - memcpy(&item, p, sizeof(item)); - - sessions[i].id = item.conn_id; - sessions[i].remote_addr = item.addr; - sessions[i].status_flags = gg_fix32(item.flags); - sessions[i].protocol_features = gg_fix32(item.features); - sessions[i].logon_time = gg_fix32(item.logon_time); - - p += sizeof(item); - - name_size = gg_fix32(item.name_size); - - if (name_size > 0xffff || p + name_size > packet_end) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_handle_multilogon_info() malformed packet (3)\n"); - goto malformed; - } - - sessions[i].name = malloc(name_size + 1); - - if (sessions[i].name == NULL) { - gg_debug_session(gs, GG_DEBUG_MISC, - "// gg_handle_multilogon_info() out of " - "memory (%" GG_SIZE_FMT ")\n", name_size); - goto fail; - } - - memcpy(sessions[i].name, p, name_size); - sessions[i].name[name_size] = 0; - - p += name_size; - } - - return 0; - -fail: - res = -1; - -malformed: - ge->type = GG_EVENT_NONE; - - for (i = 0; (int) i < ge->event.multilogon_info.count; i++) - free(ge->event.multilogon_info.sessions[i].name); - - free(ge->event.multilogon_info.sessions); - - return res; -} - -/** - * \internal Obsługuje pakiet GG_USERLIST100_VERSION. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_userlist_100_version(struct gg_session *gs, - uint32_t type, const char *ptr, size_t len, struct gg_event *ge) -{ - const struct gg_userlist100_version *version = (const struct gg_userlist100_version*) ptr; - - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received userlist 100 version\n"); - - ge->type = GG_EVENT_USERLIST100_VERSION; - ge->event.userlist100_version.version = gg_fix32(version->version); - - return 0; -} - -/** - * \internal Obsługuje pakiet GG_USERLIST100_REPLY. - * - * Patrz gg_packet_handler_t - */ -static int gg_session_handle_userlist_100_reply(struct gg_session *gs, - uint32_t type, const char *ptr, size_t len, struct gg_event *ge) -{ - const struct gg_userlist100_reply *reply = (const struct gg_userlist100_reply*) ptr; - char *data = NULL; - - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received userlist 100 reply\n"); - - if (len > sizeof(*reply)) { - data = gg_inflate((const unsigned char*) ptr + sizeof(*reply), len - sizeof(*reply)); - - if (data == NULL) { - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_handle_userlist_100_reply() gg_inflate() failed\n"); - return -1; - } - } - - ge->type = GG_EVENT_USERLIST100_REPLY; - ge->event.userlist100_reply.type = reply->type; - ge->event.userlist100_reply.version = gg_fix32(reply->version); - ge->event.userlist100_reply.format_type = reply->format_type; - ge->event.userlist100_reply.reply = data; - - return 0; -} - -static int gg_session_handle_imtoken(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - GG110Imtoken *msg = gg110_imtoken__unpack(NULL, len, (uint8_t*)ptr); - char *imtoken = NULL; - int succ = 1; - - if (!GG_PROTOBUF_VALID(gs, "GG110Imtoken", msg)) - return -1; - - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() " - "received imtoken\n"); - - if (msg->imtoken[0] != '\0') { - imtoken = strdup(msg->imtoken); - succ = succ && (imtoken != NULL); - } - - gg110_imtoken__free_unpacked(msg, NULL); - - ge->type = GG_EVENT_IMTOKEN; - ge->event.imtoken.imtoken = imtoken; - - return succ ? 0 : -1; -} - -static int gg_session_handle_pong_110(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - GG110Pong *msg = gg110_pong__unpack(NULL, len, (uint8_t*)ptr); - - if (!GG_PROTOBUF_VALID(gs, "GG110Pong", msg)) - return -1; - - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() " - "received pong110\n"); - - ge->type = GG_EVENT_PONG110; - ge->event.pong110.time = msg->server_time; - - gg_sync_time(gs, msg->server_time); - - gg110_pong__free_unpacked(msg, NULL); - - return 0; -} - -static int gg_session_handle_chat_info(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - gg_tvbuff_t *tvb; - uint32_t i; - - uint64_t id; - uint32_t version; - uint32_t dummy1; - uint32_t participants_count; - uin_t *participants = NULL; - - tvb = gg_tvbuff_new(ptr, len); - - id = gg_tvbuff_read_uint64(tvb); - gg_tvbuff_expected_uint32(tvb, 0); /* unknown */ - version = gg_tvbuff_read_uint32(tvb); - dummy1 = gg_tvbuff_read_uint32(tvb); - if (gg_tvbuff_is_valid(tvb) && dummy1 == 1) { - uint32_t name_length; - - name_length = gg_tvbuff_read_uint32(tvb); - gg_tvbuff_skip(tvb, name_length); - - gg_tvbuff_expected_uint32(tvb, 0); /* unknown */ - gg_tvbuff_expected_uint32(tvb, 2); /* unknown */ - } - participants_count = gg_tvbuff_read_uint32(tvb); - if (id == 0 && participants_count > 0) { - gg_debug_session(gs, GG_DEBUG_MISC | GG_DEBUG_WARNING, - "// gg_session_handle_chat_info() terminating packet " - "shouldn't contain participants\n"); - participants_count = 0; - } - - if (participants_count > 0) { - participants = malloc(sizeof(uin_t) * participants_count); - if (participants == NULL) { - gg_tvbuff_close(tvb); - return -1; - } - } - - for (i = 0; i < participants_count && gg_tvbuff_is_valid(tvb); i++) { - participants[i] = gg_tvbuff_read_uint32(tvb); - gg_tvbuff_read_uint32(tvb); /* 0x1e lub 0x18 */ - } - - if (!gg_tvbuff_close(tvb)) { - free(participants); - return -1; - } - - if (id == 0) { - ge->type = GG_EVENT_CHAT_INFO_GOT_ALL; - return 0; - } - - if (0 != gg_chat_update(gs, id, version, participants, - participants_count)) - { - free(participants); - return -1; - } - - ge->type = GG_EVENT_CHAT_INFO; - ge->event.chat_info.id = id; - ge->event.chat_info.version = version; - ge->event.chat_info.participants_count = participants_count; - ge->event.chat_info.participants = participants; - - return 0; -} - -static int gg_session_handle_chat_info_update(struct gg_session *gs, - uint32_t type, const char *ptr, size_t len, struct gg_event *ge) -{ - GG110ChatInfoUpdate *msg = gg110_chat_info_update__unpack(NULL, len, (uint8_t*)ptr); - gg_chat_list_t *chat; - uin_t participant; - - if (!GG_PROTOBUF_VALID(gs, "GG110ChatInfoUpdate", msg)) - return -1; - - gg_debug_session(gs, GG_DEBUG_VERBOSE, - "// gg_session_handle_chat_info_update() " - "msg_id=%016" PRIx64 " conv_id=%016" PRIx64 "\n", - msg->msg_id, msg->conv_id); - - ge->type = GG_EVENT_CHAT_INFO_UPDATE; - ge->event.chat_info_update.id = msg->chat_id; - ge->event.chat_info_update.type = msg->update_type; - ge->event.chat_info_update.participant = participant = gg_protobuf_get_uin(msg->participant); - ge->event.chat_info_update.inviter = gg_protobuf_get_uin(msg->inviter); - ge->event.chat_info_update.version = msg->version; - ge->event.chat_info_update.time = msg->time; - - chat = gg_chat_find(gs, msg->chat_id); - if (!chat) { - gg110_chat_info_update__free_unpacked(msg, NULL); - return 0; - } - - chat->version = msg->version; - if (msg->update_type == GG_CHAT_INFO_UPDATE_ENTERED) { - uin_t *old_part = chat->participants; - chat->participants = realloc(chat->participants, - sizeof(uin_t) * chat->participants_count); - if (chat->participants == NULL) { - chat->participants = old_part; - gg_debug_session(gs, GG_DEBUG_ERROR, - "// gg_session_handle_chat_info_update() " - "out of memory (count=%u)\n", - chat->participants_count); - return -1; - } - chat->participants_count++; - chat->participants[chat->participants_count - 1] = participant; - } else if (msg->update_type == GG_CHAT_INFO_UPDATE_EXITED) { - uint32_t idx; - for (idx = 0; idx < chat->participants_count; idx++) - if (chat->participants[idx] == participant) - break; - if (chat->participants_count > 1 && - idx < chat->participants_count) - chat->participants[idx] = chat->participants[chat->participants_count - 1]; - if (idx < chat->participants_count) { - chat->participants_count--; - if (chat->participants_count == 0) { - free(chat->participants); - chat->participants = NULL; - } else { - chat->participants = realloc(chat->participants, - sizeof(uin_t)*chat->participants_count); - } - } - } - - gg110_chat_info_update__free_unpacked(msg, NULL); - return 0; -} - -static int gg_session_handle_chat_created(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - const struct gg_chat_created *p = (const struct gg_chat_created *)ptr; - - if (0 != gg_chat_update(gs, gg_fix64(p->id), 0, &gs->uin, 1)) - return -1; - - ge->type = GG_EVENT_CHAT_CREATED; - ge->event.chat_created.id = gg_fix64(p->id); - ge->event.chat_created.seq = gg_fix32(p->seq); - return 0; -} - -static int gg_session_handle_chat_invite_ack(struct gg_session *gs, - uint32_t type, const char *ptr, size_t len, struct gg_event *ge) -{ - const struct gg_chat_invite_ack *p = - (const struct gg_chat_invite_ack *)ptr; - - ge->type = GG_EVENT_CHAT_INVITE_ACK; - ge->event.chat_invite_ack.id = gg_fix64(p->id); - ge->event.chat_invite_ack.seq = gg_fix32(p->seq); - - return 0; -} - -static int gg_session_handle_chat_left(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - const struct gg_chat_left *p = (const struct gg_chat_left *)ptr; - - ge->type = GG_EVENT_CHAT_INFO_UPDATE; - ge->event.chat_info_update.id = gg_fix64(p->id); - ge->event.chat_info_update.type = GG_CHAT_INFO_UPDATE_EXITED; - /* Właściwie, to nie wiadomo, czy to jest "osoba wychodząca", czy - * "osoba wyrzucająca nas" z konferencji. */ - ge->event.chat_info_update.participant = gg_fix32(p->uin); - ge->event.chat_info_update.inviter = gg_fix32(p->uin); - ge->event.chat_info_update.version = 0; - ge->event.chat_info_update.time = time(NULL); - - return 0; -} - -static int gg_session_handle_options(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - GG110Options *msg = gg110_options__unpack(NULL, len, (uint8_t*)ptr); - size_t i; - - if (!GG_PROTOBUF_VALID(gs, "GG110Options", msg)) - return -1; - - gg_protobuf_expected(gs, "GG110Options.dummy1", msg->dummy1, 0); - - for (i = 0; i < msg->n_options; i++) { - ProtobufKVP *kvp = msg->options[i]; - if (!GG_PROTOBUF_VALID(gs, "ProtobufKVP", kvp)) - continue; - gg_debug_session(gs, GG_DEBUG_MISC, - "// gg_session_handle_options[%s] = \"%s\"\n", - kvp->key, kvp->value); - } - - gg110_options__free_unpacked(msg, NULL); - - return 0; -} - -static int gg_session_handle_access_info(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - GG110AccessInfo *msg = gg110_access_info__unpack(NULL, len, (uint8_t*)ptr); - - if (!GG_PROTOBUF_VALID(gs, "GG110AccessInfo", msg)) - return -1; - - gg_debug_session(gs, GG_DEBUG_MISC, - "// gg_session_handle_access_info: dummy[%02x, %02x], " - "last[message=%u, file_transfer=%u, conference_ch=%u]\n", - msg->dummy1, msg->dummy2, msg->last_message, - msg->last_file_transfer, msg->last_conference_ch); - - gg110_access_info__free_unpacked(msg, NULL); - - return 0; -} - -/* ten pakiet jest odbierany tylko, jeżeli przy logowaniu użyliśmy identyfikatora typu 0x01 */ -static int gg_session_handle_uin_info(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - gg_tvbuff_t *tvb; - char *uin1 = NULL, *uin2 = NULL; - - tvb = gg_tvbuff_new(ptr, len); - - gg_tvbuff_expected_uint32(tvb, 1); /* unknown */ - gg_tvbuff_expected_uint32(tvb, 2); /* unknown */ - - /* podstawowy identyfikator (numer GG) */ - gg_tvbuff_expected_uint8(tvb, 0); - gg_tvbuff_read_str_dup(tvb, &uin1); - - /* identyfikator użyty przy logowaniu (numer GG lub email) */ - gg_tvbuff_expected_uint8(tvb, 1); - gg_tvbuff_read_str_dup(tvb, &uin2); - - if (!gg_tvbuff_close(tvb)) { - free(uin1); - free(uin2); - return -1; - } - - gg_debug_session(gs, GG_DEBUG_MISC, "// gg_session_handle_uin_info: " - "uin1=\"%s\", uin2=\"%s\"\n", uin1, uin2); - - free(uin1); - free(uin2); - - return 0; -} - -static int gg_session_handle_transfer_info(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - GG112TransferInfo *msg = gg112_transfer_info__unpack(NULL, len, (uint8_t*)ptr); - int succ = 1; - size_t i; - uin_t peer = 0, sender = 0; - - if (!GG_PROTOBUF_VALID(gs, "GG112TransferInfo", msg)) - return -1; - - /* see packets.proto */ - if (msg->dummy1 != 5 && msg->dummy1 != 6) { - gg_debug_session(gs, GG_DEBUG_MISC | GG_DEBUG_WARNING, - "// gg_session_handle_transfer_info: " - "unknown dummy1 value: %d\n", msg->dummy1); - } - - if (GG_PROTOBUF_VALID(gs, "GG112TransferInfoUin", msg->peer)) { - gg_protobuf_expected(gs, "GG112TransferInfoUin.dummy1", - msg->peer->dummy1, 1); - peer = gg_protobuf_get_uin(msg->peer->uin); - } - if (GG_PROTOBUF_VALID(gs, "GG112TransferInfoUin", msg->sender)) { - gg_protobuf_expected(gs, "GG112TransferInfoUin.dummy1", - msg->sender->dummy1, 1); - sender = gg_protobuf_get_uin(msg->sender->uin); - } - - gg_debug_session(gs, GG_DEBUG_MISC, - "// gg_session_handle_transfer_info: dummy1=%#x, time=%u, " - "sender=%u, peer=%u, msg_id=%#016" PRIx64 ", " - "conv_id=%#016" PRIx64 "\n", - msg->dummy1, msg->time, sender, peer, msg->msg_id, - msg->conv_id); - - for (i = 0; i < msg->n_data; i++) { - ProtobufKVP *kvp = msg->data[i]; - if (!GG_PROTOBUF_VALID(gs, "ProtobufKVP", kvp)) - continue; - gg_debug_session(gs, GG_DEBUG_MISC, - "// gg_session_handle_transfer_info[%s] = \"%s\"\n", - kvp->key, kvp->value); - } - - if (msg->file && GG_PROTOBUF_VALID(gs, "GG112TransferInfoFile", msg->file)) { - GG112TransferInfoFile *file = msg->file; - gg_debug_session(gs, GG_DEBUG_MISC, - "// gg_session_handle_transfer_info file: " - "type=\"%s\", content_type=\"%s\", filename=\"%s\", " - "filesize=%u, msg_id=%#016" PRIx64 " url=\"%s\"\n", - file->type, file->content_type, file->filename, - file->filesize, file->msg_id, file->url); - } - - succ = (gg_ack_110(gs, GG110_ACK__TYPE__TRANSFER_INFO, - msg->seq, ge) == 0); - - gg112_transfer_info__free_unpacked(msg, NULL); - - return succ ? 0 : -1; -} - -static int gg_session_handle_magic_notification(struct gg_session *gs, uint32_t type, - const char *ptr, size_t len, struct gg_event *ge) -{ - GG110MagicNotification *msg = gg110_magic_notification__unpack(NULL, len, (uint8_t*)ptr); - int succ = 1; - - if (!GG_PROTOBUF_VALID(gs, "GG110MagicNotification", msg)) - return -1; - - gg_debug_session(gs, GG_DEBUG_MISC, - "// gg_session_handle_magic_notification \n"); - - gg_protobuf_expected(gs, "GG110MagicNotification.dummy1", msg->dummy1, 2); - gg_protobuf_expected(gs, "GG110MagicNotification.dummy2", msg->dummy2, 1); - gg_protobuf_expected(gs, "GG110MagicNotification.dummy3", msg->dummy3, 1); - - succ = (gg_ack_110(gs, GG110_ACK__TYPE__MAGIC_NOTIFICATION, msg->seq, ge) == 0); - - gg110_magic_notification__free_unpacked(msg, NULL); - - return succ ? 0 : -1; -} - -/** - * \internal Tablica obsługiwanych pakietów - */ -static const gg_packet_handler_t handlers[] = -{ - /* style:maxlinelength:start-ignore */ - { GG_WELCOME, GG_STATE_READING_KEY, 0, gg_session_handle_welcome }, - { GG_LOGIN_OK, GG_STATE_READING_REPLY, 0, gg_session_handle_login_ok }, - { GG_LOGIN80_OK, GG_STATE_READING_REPLY, 0, gg_session_handle_login_ok }, - { GG_LOGIN110_OK, GG_STATE_READING_REPLY, 0, gg_session_handle_login110_ok }, - { GG_NEED_EMAIL, GG_STATE_READING_REPLY, 0, gg_session_handle_login_ok }, - { GG_LOGIN_FAILED, GG_STATE_READING_REPLY, 0, gg_session_handle_login_failed }, - { GG_LOGIN80_FAILED, GG_STATE_READING_REPLY, 0, gg_session_handle_login_failed }, - { GG_SEND_MSG_ACK, GG_STATE_CONNECTED, sizeof(struct gg_send_msg_ack), gg_session_handle_send_msg_ack }, - { GG_SEND_MSG_ACK110, GG_STATE_CONNECTED, 0, gg_session_handle_send_msg_ack_110 }, - { GG_PONG, GG_STATE_CONNECTED, 0, gg_session_handle_pong }, - { GG_DISCONNECTING, GG_STATE_CONNECTED, 0, gg_session_handle_disconnecting }, - { GG_DISCONNECT_ACK, GG_STATE_DISCONNECTING, 0, gg_session_handle_disconnect_ack }, - { GG_XML_EVENT, GG_STATE_CONNECTED, 0, gg_session_handle_xml_event }, - { GG_EVENT110, GG_STATE_CONNECTED, 0, gg_session_handle_event_110 }, - { GG_PUBDIR50_REPLY, GG_STATE_CONNECTED, 0, gg_session_handle_pubdir50_reply }, - { GG_USERLIST_REPLY, GG_STATE_CONNECTED, sizeof(char), gg_session_handle_userlist_reply }, - { GG_DCC7_ID_REPLY, GG_STATE_CONNECTED, sizeof(struct gg_dcc7_id_reply), gg_session_handle_dcc7_id_reply }, - { GG_DCC7_ACCEPT, GG_STATE_CONNECTED, sizeof(struct gg_dcc7_accept), gg_session_handle_dcc7_accept }, - { GG_DCC7_NEW, GG_STATE_CONNECTED, sizeof(struct gg_dcc7_new), gg_session_handle_dcc7_new }, - { GG_DCC7_REJECT, GG_STATE_CONNECTED, sizeof(struct gg_dcc7_reject), gg_session_handle_dcc7_reject }, - { GG_DCC7_INFO, GG_STATE_CONNECTED, sizeof(struct gg_dcc7_info), gg_session_handle_dcc7_info }, - { GG_RECV_MSG, GG_STATE_CONNECTED, sizeof(struct gg_recv_msg), gg_session_handle_recv_msg }, - { GG_RECV_MSG80, GG_STATE_CONNECTED, sizeof(struct gg_recv_msg80), gg_session_handle_recv_msg_80 }, - { GG_RECV_MSG110, GG_STATE_CONNECTED, 0, gg_session_handle_recv_msg_110 }, - { GG_RECV_OWN_MSG110, GG_STATE_CONNECTED, 0, gg_session_handle_recv_msg_110 }, - { GG_STATUS, GG_STATE_CONNECTED, sizeof(struct gg_status), gg_session_handle_status }, - { GG_STATUS60, GG_STATE_CONNECTED, sizeof(struct gg_status60), gg_session_handle_status_60_77_80beta }, - { GG_STATUS77, GG_STATE_CONNECTED, sizeof(struct gg_status77), gg_session_handle_status_60_77_80beta }, - { GG_STATUS80BETA, GG_STATE_CONNECTED, sizeof(struct gg_status77), gg_session_handle_status_60_77_80beta }, - { GG_STATUS80, GG_STATE_CONNECTED, sizeof(struct gg_notify_reply80), gg_session_handle_status_80 }, - { GG_NOTIFY_REPLY, GG_STATE_CONNECTED, sizeof(struct gg_notify_reply), gg_session_handle_notify_reply }, - { GG_NOTIFY_REPLY60, GG_STATE_CONNECTED, sizeof(struct gg_notify_reply60), gg_session_handle_notify_reply_60 }, - { GG_NOTIFY_REPLY77, GG_STATE_CONNECTED, sizeof(struct gg_notify_reply77), gg_session_handle_notify_reply_77_80beta }, - { GG_NOTIFY_REPLY80BETA, GG_STATE_CONNECTED, sizeof(struct gg_notify_reply77), gg_session_handle_notify_reply_77_80beta }, - { GG_NOTIFY_REPLY80, GG_STATE_CONNECTED, sizeof(struct gg_notify_reply80), gg_session_handle_notify_reply_80 }, - { GG_USER_DATA, GG_STATE_CONNECTED, sizeof(struct gg_user_data), gg_session_handle_user_data }, - { GG_TYPING_NOTIFICATION, GG_STATE_CONNECTED, sizeof(struct gg_typing_notification), gg_session_handle_typing_notification }, - { GG_MULTILOGON_INFO, GG_STATE_CONNECTED, sizeof(struct gg_multilogon_info), gg_session_handle_multilogon_info }, - { GG_XML_ACTION, GG_STATE_CONNECTED, 0, gg_session_handle_xml_event }, - { GG_RECV_OWN_MSG, GG_STATE_CONNECTED, sizeof(struct gg_recv_msg80), gg_session_handle_recv_msg_80 }, - { GG_USERLIST100_VERSION, GG_STATE_CONNECTED, sizeof(struct gg_userlist100_version), gg_session_handle_userlist_100_version }, - { GG_USERLIST100_REPLY, GG_STATE_CONNECTED, sizeof(struct gg_userlist100_reply), gg_session_handle_userlist_100_reply }, - { GG_IMTOKEN, GG_STATE_CONNECTED, 0, gg_session_handle_imtoken }, - { GG_PONG110, GG_STATE_CONNECTED, 0, gg_session_handle_pong_110 }, - { GG_CHAT_INFO, GG_STATE_CONNECTED, 0, gg_session_handle_chat_info }, - { GG_CHAT_INFO_UPDATE, GG_STATE_CONNECTED, 0, gg_session_handle_chat_info_update }, - { GG_CHAT_CREATED, GG_STATE_CONNECTED, sizeof(struct gg_chat_created), gg_session_handle_chat_created }, - { GG_CHAT_INVITE_ACK, GG_STATE_CONNECTED, sizeof(struct gg_chat_invite_ack), gg_session_handle_chat_invite_ack }, - { GG_CHAT_RECV_MSG, GG_STATE_CONNECTED, 0, gg_session_handle_recv_msg_110 }, - { GG_CHAT_RECV_OWN_MSG, GG_STATE_CONNECTED, 0, gg_session_handle_recv_msg_110 }, - { GG_CHAT_LEFT, GG_STATE_CONNECTED, sizeof(struct gg_chat_left), gg_session_handle_chat_left }, - { GG_OPTIONS, GG_STATE_CONNECTED, 0, gg_session_handle_options }, - { GG_ACCESS_INFO, GG_STATE_CONNECTED, 0, gg_session_handle_access_info }, - { GG_UIN_INFO, GG_STATE_CONNECTED, 0, gg_session_handle_uin_info }, - { GG_TRANSFER_INFO, GG_STATE_CONNECTED, 0, gg_session_handle_transfer_info }, - { GG_MAGIC_NOTIFICATION, GG_STATE_CONNECTED, 0, gg_session_handle_magic_notification } - /* style:maxlinelength:end-ignore */ -}; - -/** - * \internal Obsługuje przychodzący pakiet danych. - * - * \param gs Struktura sesji - * \param type Typ pakietu - * \param ptr Wskaźnik do bufora pakietu - * \param len Długość bufora pakietu - * \param[out] ge Struktura zdarzenia - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -int gg_session_handle_packet(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge) -{ - unsigned int i; - - gg_debug_session(gs, GG_DEBUG_FUNCTION, - "// gg_session_handle_packet(%d, %p, %" GG_SIZE_FMT ")\n", - type, ptr, len); - - gs->last_event = time(NULL); - -#if 0 - if ((gs->flags & (1 << GG_SESSION_FLAG_RAW_PACKET)) != 0) { - char *tmp; - - tmp = malloc(len); - - if (tmp == NULL) { - gg_debug_session(gs, GG_DEBUG_ERROR, - "// gg_session_handle_packet() out of memory " - "(%d bytes)\n", len); - return -1; - } - - memcpy(tmp, ptr, len); - - ge->type = GG_EVENT_RAW_PACKET; - ge->event.raw_packet.type = type; - ge->event.raw_packet.length = len; - ge->event.raw_packet.data = tmp; - - return 0; - } -#endif - - for (i = 0; i < sizeof(handlers) / sizeof(handlers[0]); i++) { - if (handlers[i].type != 0 && handlers[i].type != type) - continue; - - if (handlers[i].state != 0 && handlers[i].state != (enum gg_state_t) gs->state) { - gg_debug_session(gs, GG_DEBUG_WARNING, - "// gg_session_handle_packet() packet 0x%02x " - "unexpected in state %d\n", type, gs->state); - continue; - } - - if (len < handlers[i].min_length) { - gg_debug_session(gs, GG_DEBUG_ERROR, - "// gg_session_handle_packet() packet 0x%02x " - "too short (%" GG_SIZE_FMT " bytes)\n", - type, len); - continue; - } - - return (*handlers[i].handler)(gs, type, ptr, len, ge); - } - - gg_debug_session(gs, GG_DEBUG_WARNING, "// gg_session_handle_packet() " - "unhandled packet 0x%02x, len %" GG_SIZE_FMT ", state %d\n", - type, len, gs->state); - - return 0; -}
--- a/libpurple/protocols/gg/lib/http.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,592 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file http.c - * - * \brief Obsługa połączeń HTTP - */ - -#include "strman.h" -#include "network.h" -#include "libgadu.h" -#include "resolver.h" -#include "internal.h" - -#include <ctype.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> - -#define GG_HTTP_MAX_LENGTH 1000000000 - -/** - * Rozpoczyna połączenie HTTP. - * - * Funkcja przeprowadza połączenie HTTP przy połączeniu synchronicznym, - * zwracając wynik w polach struktury \c gg_http, lub błąd, gdy sesja się - * nie powiedzie. - * - * Przy połączeniu asynchronicznym, funkcja rozpoczyna połączenie, a dalsze - * etapy będą przeprowadzane po wykryciu zmian (\c watch) na obserwowanym - * deskryptorze (\c fd) i wywołaniu funkcji \c gg_http_watch_fd(). - * - * Po zakończeniu, należy zwolnić strukturę za pomocą funkcji - * \c gg_http_free(). Połączenie asynchroniczne można zatrzymać w każdej - * chwili za pomocą \c gg_http_stop(). - * - * \param hostname Adres serwera - * \param port Port serwera - * \param async Flaga asynchronicznego połączenia - * \param method Metoda HTTP - * \param path Ścieżka do zasobu (musi być poprzedzona znakiem '/') - * \param header Nagłówek zapytania plus ewentualne dane dla POST - * - * \return Zaalokowana struktura \c gg_http lub NULL, jeśli wystąpił błąd. - * - * \ingroup http - */ -struct gg_http *gg_http_connect(const char *hostname, int port, int async, - const char *method, const char *path, const char *header) -{ - struct gg_http *h; - - if (!hostname || !port || !method || !path || !header) { - gg_debug(GG_DEBUG_MISC, "// gg_http_connect() invalid arguments\n"); - errno = EFAULT; - return NULL; - } - - if (!(h = malloc(sizeof(*h)))) - return NULL; - memset(h, 0, sizeof(*h)); - - h->async = async; - h->port = port; - h->fd = -1; - h->type = GG_SESSION_HTTP; - - gg_http_set_resolver(h, GG_RESOLVER_DEFAULT); - - if (gg_proxy_enabled) { - char *auth = gg_proxy_auth(); - - h->query = gg_saprintf("%s http://%s:%d%s HTTP/1.0\r\n%s%s", - method, hostname, port, path, (auth) ? auth : - "", header); - hostname = gg_proxy_host; - h->port = port = gg_proxy_port; - free(auth); - - } else { - h->query = gg_saprintf("%s %s HTTP/1.0\r\n%s", - method, path, header); - } - - if (h->query == NULL) { - gg_debug(GG_DEBUG_MISC, "// gg_http_connect() not enough memory for query\n"); - free(h); - errno = ENOMEM; - return NULL; - } - - gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-QUERY-----\n%s\n=> -----END-HTTP-QUERY-----\n", h->query); - - if (async) { - if (h->resolver_start(&h->fd, &h->resolver, hostname) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_http_connect() resolver failed\n"); - gg_http_free(h); - errno = ENOENT; - return NULL; - } - - gg_debug(GG_DEBUG_MISC, "// gg_http_connect() resolver = %p\n", h->resolver); - - h->state = GG_STATE_RESOLVING; - h->check = GG_CHECK_READ; - h->timeout = GG_DEFAULT_TIMEOUT; - } else { - struct in_addr *addr_list = NULL; - unsigned int addr_count; - - if (gg_gethostbyname_real(hostname, &addr_list, &addr_count, 0) == -1 || addr_count == 0) { - gg_debug(GG_DEBUG_MISC, "// gg_http_connect() host not found\n"); - gg_http_free(h); - free(addr_list); - errno = ENOENT; - return NULL; - } - - h->fd = gg_connect(&addr_list[0], port, 0); - - if (h->fd == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_http_connect() " - "connection failed (errno=%d, %s)\n", - errno, strerror(errno)); - gg_http_free(h); - free(addr_list); - return NULL; - } - - free(addr_list); - - h->state = GG_STATE_CONNECTING; - - while (h->state != GG_STATE_ERROR && h->state != GG_STATE_PARSING) { - if (gg_http_watch_fd(h) == -1) - break; - } - - if (h->state != GG_STATE_PARSING) { - gg_debug(GG_DEBUG_MISC, "// gg_http_connect() some strange error\n"); - gg_http_free(h); - return NULL; - } - } - - h->callback = gg_http_watch_fd; - h->destroy = gg_http_free; - - return h; -} - -#ifndef DOXYGEN - -#define gg_http_error(x) \ - if (h->fd > -1) \ - close(h->fd); \ - h->fd = -1; \ - h->state = GG_STATE_ERROR; \ - h->error = x; \ - return 0; - -#endif /* DOXYGEN */ - -/** - * Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze połączenia. - * - * Operacja będzie zakończona, gdy pole \c state będzie równe - * \c GG_STATE_PARSING. W tym miejscu działanie przejmuje zwykle funkcja - * korzystająca z \c gg_http_watch_fd(). W przypadku błędu połączenia, - * pole \c state będzie równe \c GG_STATE_ERROR, a kod błędu znajdzie się - * w polu \c error. - * - * \param h Struktura połączenia - * - * \return \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup http - */ -int gg_http_watch_fd(struct gg_http *h) -{ - gg_debug(GG_DEBUG_FUNCTION, "** gg_http_watch_fd(%p);\n", h); - - if (h == NULL) { - gg_debug(GG_DEBUG_MISC, "// gg_http_watch_fd() invalid arguments\n"); - errno = EFAULT; - return -1; - } - - if (h->state == GG_STATE_RESOLVING) { - struct in_addr addr; - int res; - - gg_debug(GG_DEBUG_MISC, "=> http, resolving done\n"); - - do { - res = gg_resolver_recv(h->fd, &addr, sizeof(addr)); - } while (res == -1 && errno == EINTR); - - h->resolver_cleanup(&h->resolver, 0); - - if (res != sizeof(addr) || addr.s_addr == INADDR_NONE) { - gg_debug(GG_DEBUG_MISC, "=> http, resolver thread failed\n"); - gg_http_error(GG_ERROR_RESOLVING); - } - - close(h->fd); - h->fd = -1; - - gg_debug(GG_DEBUG_MISC, "=> http, connecting to %s:%d\n", inet_ntoa(addr), h->port); - - h->fd = gg_connect(&addr, h->port, h->async); - - if (h->fd == -1) { - gg_debug(GG_DEBUG_MISC, "=> http, connection failed (errno=%d, %s)\n", errno, strerror(errno)); - gg_http_error(GG_ERROR_CONNECTING); - } - - h->state = GG_STATE_CONNECTING; - h->check = GG_CHECK_WRITE; - h->timeout = GG_DEFAULT_TIMEOUT; - - return 0; - } - - if (h->state == GG_STATE_CONNECTING) { - int res = 0; - socklen_t res_size = sizeof(res); - - if (h->async && (getsockopt(h->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) { - gg_debug(GG_DEBUG_MISC, "=> http, async connection " - "failed (errno=%d, %s)\n", (res) ? res : errno, - strerror((res) ? res : errno)); - close(h->fd); - h->fd = -1; - h->state = GG_STATE_ERROR; - h->error = GG_ERROR_CONNECTING; - if (res) - errno = res; - return 0; - } - - gg_debug(GG_DEBUG_MISC, "=> http, connected, sending request\n"); - - h->state = GG_STATE_SENDING_QUERY; - } - - if (h->state == GG_STATE_SENDING_QUERY) { - int res; - - res = send(h->fd, h->query, strlen(h->query), 0); - - if (res == -1 && errno != EINTR && errno != EAGAIN) { - gg_debug(GG_DEBUG_MISC, "=> http, send() failed " - "(len=%" GG_SIZE_FMT ", res=%d, errno=%d)\n", - strlen(h->query), res, errno); - gg_http_error(GG_ERROR_WRITING); - } - - if (res == -1) { - gg_debug(GG_DEBUG_MISC, "=> http, non-critical send " - "error (errno=%d, %s)\n", - errno, strerror(errno)); - return 0; - } - - if ((size_t) res < strlen(h->query)) { - gg_debug(GG_DEBUG_MISC, "=> http, partial header sent " - "(led=%" GG_SIZE_FMT ", sent=%d)\n", - strlen(h->query), res); - - memmove(h->query, h->query + res, strlen(h->query) - res + 1); - h->state = GG_STATE_SENDING_QUERY; - h->check = GG_CHECK_WRITE; - h->timeout = GG_DEFAULT_TIMEOUT; - } else { - gg_debug(GG_DEBUG_MISC, "=> http, request sent (len=%" - GG_SIZE_FMT ")\n", strlen(h->query)); - free(h->query); - h->query = NULL; - - h->state = GG_STATE_READING_HEADER; - h->check = GG_CHECK_READ; - h->timeout = GG_DEFAULT_TIMEOUT; - } - - return 0; - } - - if (h->state == GG_STATE_READING_HEADER) { - char buf[1024], *tmp; - int res; - - res = recv(h->fd, buf, sizeof(buf), 0); - - if (res == -1 && errno != EINTR && errno != EAGAIN) { - gg_debug(GG_DEBUG_MISC, "=> http, reading header failed (errno=%d)\n", errno); - free(h->header); - h->header = NULL; - gg_http_error(GG_ERROR_READING); - } - - if (res == -1) { - gg_debug(GG_DEBUG_MISC, "=> http, non-critical recv " - "error (errno=%d, %s)\n", - errno, strerror(errno)); - return 0; - } - - if (res == 0) { - gg_debug(GG_DEBUG_MISC, "=> http, connection reset by peer\n"); - free(h->header); - h->header = NULL; - gg_http_error(GG_ERROR_READING); - } - - gg_debug(GG_DEBUG_MISC, "=> http, read %d bytes of header\n", res); - - tmp = realloc(h->header, h->header_size + res + 1); - - if (tmp == NULL) { - gg_debug(GG_DEBUG_MISC, "=> http, not enough memory for header\n"); - free(h->header); - h->header = NULL; - gg_http_error(GG_ERROR_READING); - } - - h->header = tmp; - - memcpy(h->header + h->header_size, buf, res); - h->header_size += res; - - gg_debug(GG_DEBUG_MISC, "=> http, header_buf=%p, header_size=%d\n", h->header, h->header_size); - - h->header[h->header_size] = 0; - - if ((tmp = strstr(h->header, "\r\n\r\n")) || (tmp = strstr(h->header, "\n\n"))) { - int sep_len = (*tmp == '\r') ? 4 : 2; - unsigned int left; - char *line; - - left = h->header_size - ((size_t)(tmp) - (size_t)(h->header) + sep_len); - - gg_debug(GG_DEBUG_MISC, "=> http, got all header " - "(%d bytes, %d left)\n", - h->header_size - left, left); - - /* HTTP/1.1 200 OK */ - if (strlen(h->header) < 16 || strncmp(h->header + 9, "200", 3)) { - gg_debug(GG_DEBUG_MISC, - "=> -----BEGIN-HTTP-HEADER-----\n%s\n" - "=> -----END-HTTP-HEADER-----\n", - h->header); - - gg_debug(GG_DEBUG_MISC, "=> http, didn't get 200 OK -- no results\n"); - free(h->header); - h->header = NULL; - gg_http_error(GG_ERROR_CONNECTING); - } - - h->body_size = 0; - line = h->header; - *tmp = 0; - - gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-HEADER-----" - "\n%s\n=> -----END-HTTP-HEADER-----\n", - h->header); - - while (line) { - if (!strncasecmp(line, "Content-length: ", 16)) { - h->body_size = atoi(line + 16); - } - line = strchr(line, '\n'); - if (line) - line++; - } - - if (h->body_size <= 0) { - gg_debug(GG_DEBUG_MISC, "=> http, content-length not found\n"); - h->body_size = left; - } - - if (h->body_size > GG_HTTP_MAX_LENGTH) { - gg_debug(GG_DEBUG_MISC, "=> http, content-length too big\n"); - h->body_size = GG_HTTP_MAX_LENGTH; - } - - if (left > h->body_size) { - gg_debug(GG_DEBUG_MISC, "=> http, oversized " - "reply (%d bytes needed, " - "%d bytes left)\n", h->body_size, left); - h->body_size = left; - } - - gg_debug(GG_DEBUG_MISC, "=> http, body_size=%d\n", h->body_size); - - if (!(h->body = malloc(h->body_size + 1))) { - gg_debug(GG_DEBUG_MISC, "=> http, not enough " - "memory (%d bytes for body_buf)\n", - h->body_size + 1); - free(h->header); - h->header = NULL; - gg_http_error(GG_ERROR_READING); - } - - if (left) { - memcpy(h->body, tmp + sep_len, left); - h->body_done = left; - } - - h->body[left] = 0; - - h->state = GG_STATE_READING_DATA; - h->check = GG_CHECK_READ; - h->timeout = GG_DEFAULT_TIMEOUT; - } - - return 0; - } - - if (h->state == GG_STATE_READING_DATA) { - char buf[1024]; - int res; - - res = recv(h->fd, buf, sizeof(buf), 0); - - if (res == -1 && errno != EINTR && errno != EAGAIN) { - gg_debug(GG_DEBUG_MISC, "=> http, reading body failed (errno=%d)\n", errno); - free(h->body); - h->body = NULL; - gg_http_error(GG_ERROR_READING); - } - - if (res == -1) { - gg_debug(GG_DEBUG_MISC, "=> http, non-critical " - "recv error (errno=%d, %s)\n", - errno, strerror(errno)); - return 0; - } - - if (res == 0) { - if (h->body_done >= h->body_size) { - gg_debug(GG_DEBUG_MISC, "=> http, we're done, closing socket\n"); - h->state = GG_STATE_PARSING; - close(h->fd); - h->fd = -1; - } else { - gg_debug(GG_DEBUG_MISC, "=> http, " - "connection closed while reading " - "(have %d, need %d)\n", - h->body_done, h->body_size); - free(h->body); - h->body = NULL; - gg_http_error(GG_ERROR_READING); - } - - return 0; - } - - gg_debug(GG_DEBUG_MISC, "=> http, read %d bytes of body\n", res); - - if (h->body_done + res > h->body_size) { - char *tmp; - - gg_debug(GG_DEBUG_MISC, "=> http, too much data " - "(%d bytes, %d needed), enlarging buffer\n", - h->body_done + res, h->body_size); - - if (!(tmp = realloc(h->body, h->body_done + res + 1))) { - gg_debug(GG_DEBUG_MISC, "=> http, not enough " - "memory for data (%d needed)\n", - h->body_done + res + 1); - free(h->body); - h->body = NULL; - gg_http_error(GG_ERROR_READING); - } - - h->body = tmp; - h->body_size = h->body_done + res; - } - - h->body[h->body_done + res] = 0; - memcpy(h->body + h->body_done, buf, res); - h->body_done += res; - - gg_debug(GG_DEBUG_MISC, "=> body_done=%d, body_size=%d\n", h->body_done, h->body_size); - - return 0; - } - - if (h->fd != -1) - close(h->fd); - - h->fd = -1; - h->state = GG_STATE_ERROR; - h->error = 0; - - return -1; -} - -/** - * Kończy asynchroniczne połączenie HTTP. - * - * Po zatrzymaniu należy zwolnić zasoby funkcją \c gg_http_free(). - * - * \param h Struktura połączenia - * - * \ingroup http - */ -void gg_http_stop(struct gg_http *h) -{ - if (!h) - return; - - if (h->state == GG_STATE_ERROR || h->state == GG_STATE_DONE) - return; - - h->resolver_cleanup(&h->resolver, 1); - - if (h->fd != -1) { - close(h->fd); - h->fd = -1; - } -} - -/** - * \internal Zwalnia pola struktury \c gg_http. - * - * Funkcja zwalnia same pola, nie zwalnia struktury. - * - * \param h Struktura połączenia - */ -void gg_http_free_fields(struct gg_http *h) -{ - if (h == NULL) - return; - - free(h->body); - h->body = NULL; - - free(h->query); - h->query = NULL; - - free(h->header); - h->header = NULL; -} - -/** - * Zwalnia zasoby po połączeniu HTTP. - * - * Jeśli połączenie nie zostało jeszcze zakończone, jest przerywane. - * - * \param h Struktura połączenia - * - * \ingroup http - */ -void gg_http_free(struct gg_http *h) -{ - if (h == NULL) - return; - - gg_http_stop(h); - gg_http_free_fields(h); - free(h); -} - -/* - * Local variables: - * c-indentation-style: k&r - * c-basic-offset: 8 - * indent-tabs-mode: notnil - * End: - * - * vim: shiftwidth=8: - */
--- a/libpurple/protocols/gg/lib/internal.h Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,266 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2009 Jakub Zawadzki <darkjames@darkjames.ath.cx> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef LIBGADU_INTERNAL_H -#define LIBGADU_INTERNAL_H - -#include "libgadu.h" - -#define GG_DEFAULT_CLIENT_VERSION_100 "10.1.0.11070" -#define GG_DEFAULT_CLIENT_VERSION_110 "11.3.45.10771" - -#ifdef _WIN32 -# ifdef __COVERITY__ -# define GG_SIZE_FMT "lu" -# define _GG_INT64_MODIFIER "ll" -# undef PRIu64 -# undef PRIx64 -# undef PRId64 -# else -# define GG_SIZE_FMT "Iu" -# define _GG_INT64_MODIFIER "I64" -# endif -#elif defined(_LP64) -# define GG_SIZE_FMT "zu" -# define _GG_INT64_MODIFIER "l" -#else -# define GG_SIZE_FMT "zu" -# define _GG_INT64_MODIFIER "ll" -#endif - -#ifndef PRIu64 -# define PRIu64 _GG_INT64_MODIFIER "u" -#endif -#ifndef PRIx64 -# define PRIx64 _GG_INT64_MODIFIER "x" -#endif -#ifndef PRId64 -# define PRId64 _GG_INT64_MODIFIER "d" -#endif - -#define GG_LOGIN_PARAMS_HAS_FIELD(glp, member) \ - (offsetof(struct gg_login_params, member) < (glp)->struct_size || \ - offsetof(struct gg_login_params, member) <= offsetof(struct gg_login_params, struct_size)) - -#ifdef __GNUC__ -# define GG_UNUSED __attribute__ ((unused)) -# define GG_NORETURN __attribute__ ((noreturn)) -# define GG_CDECL __attribute__ ((__cdecl__)) -#else -# define GG_UNUSED -# define GG_NORETURN -# define GG_CDECL -#endif - -#define GG_STATIC_ASSERT(condition, message) \ - { typedef char static_assertion_failed_ ## message \ - [(condition) ? 1 : -1]; static_assertion_failed_ ## message dummy; \ - (void)dummy; } - -#define GG_IMGOUT_WAITING_MAX 4 - -struct gg_dcc7_relay { - uint32_t addr; - uint16_t port; - uint8_t family; -}; - -typedef struct _gg_chat_list gg_chat_list_t; -struct _gg_chat_list { - uint64_t id; - uint32_t version; - uint32_t participants_count; - uin_t *participants; - - gg_chat_list_t *next; -}; - -typedef struct _gg_msg_list gg_msg_list_t; -struct _gg_msg_list { - int seq; - uin_t *recipients; - size_t recipients_count; - - gg_msg_list_t *next; -}; - -typedef struct _gg_eventqueue gg_eventqueue_t; -struct _gg_eventqueue { - struct gg_event *event; - - gg_eventqueue_t *next; -}; - -typedef struct _gg_imgout_queue_t gg_imgout_queue_t; -struct _gg_imgout_queue_t { - struct gg_send_msg msg_hdr; - char buf[1910]; - size_t buf_len; - - gg_imgout_queue_t *next; -}; - -struct gg_session_private { - gg_compat_t compatibility; - - gg_chat_list_t *chat_list; - gg_msg_list_t *sent_messages; - - gg_eventqueue_t *event_queue; - int check_after_queue; - int fd_after_queue; - - gg_imgout_queue_t *imgout_queue; - int imgout_waiting_ack; - - gg_socket_manager_type_t socket_manager_type; - gg_socket_manager_t socket_manager; - void *socket_handle; - int socket_next_state; - int socket_is_external; - enum gg_failure_t socket_failure; - - int time_diff; - - int dummyfds_created; - int dummyfds[2]; - - char **host_white_list; -}; - -typedef enum -{ - GG_COMPAT_FEATURE_ACK_EVENT, - GG_COMPAT_FEATURE_LEGACY_CONFER -} gg_compat_feature_t; - -typedef struct gg_dcc7_relay gg_dcc7_relay_t; - -void * gg_new0(size_t size); -int gg_required_proto(struct gg_session *gs, int protocol_version); -int gg_get_dummy_fd(struct gg_session *sess); - -int gg_compat_feature_is_enabled(struct gg_session *sess, gg_compat_feature_t feature); - -int gg_pubdir50_handle_reply_sess(struct gg_session *sess, struct gg_event *e, const char *packet, int length); - -int gg_resolve(int *fd, int *pid, const char *hostname); -int gg_resolve_pthread(int *fd, void **resolver, const char *hostname); -void gg_resolve_pthread_cleanup(void *resolver, int kill); - -int gg_login_hash_sha1_2(const char *password, uint32_t seed, uint8_t *result); - -int gg_chat_update(struct gg_session *sess, uint64_t id, uint32_t version, - const uin_t *participants, unsigned int participants_count); -gg_chat_list_t *gg_chat_find(struct gg_session *sess, uint64_t id); - -uin_t gg_str_to_uin(const char *str, int len); - -uint64_t gg_fix64(uint64_t x); -void gg_connection_failure(struct gg_session *gs, struct gg_event *ge, - enum gg_failure_t failure); - -time_t gg_server_time(struct gg_session *gs); - -int gg_session_init_ssl(struct gg_session *gs); -void gg_close(struct gg_session *gs); - -struct gg_event *gg_eventqueue_add(struct gg_session *sess); - -void gg_compat_message_ack(struct gg_session *sess, int seq); - -void gg_image_sendout(struct gg_session *sess); - -void gg_strarr_free(char **strarr); -char ** gg_strarr_dup(char **strarr); - -#ifdef _WIN32 - -#include <windows.h> - -typedef struct { - void (*fnc)(); -#ifdef _WIN64 - uint8_t trap[12]; - uint8_t original[12]; -#else - uint8_t trap[7]; - uint8_t original[7]; -#endif -} gg_win32_hook_data_t; - -#define gg_win32_hook(orig_func, hook_func, data) \ - gg_win32_hook_f((void (*)())(orig_func), (void (*)())(hook_func), (data)) - -static inline void -gg_win32_hook_f(void (*orig_func)(), void (*hook_func)(), gg_win32_hook_data_t *data) -{ - DWORD dPermission; - uint8_t trap[] = { -#ifdef _WIN64 - 0x48, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, /* mov rax, uint64_t */ - 0xff, 0xe0 /* jmp rax */ -#else - 0xB8, 0, 0, 0, 0, /* mov eax, uint32_t */ - 0xff, 0xe0 /* jmp eax */ -#endif - }; - -#ifdef _WIN64 - uint64_t addr = (uint64_t)hook_func; - memcpy(&trap[2], &addr, sizeof(addr)); -#else - uint32_t addr = (uint32_t)hook_func; - memcpy(&trap[1], &addr, sizeof(addr)); -#endif - - VirtualProtect(orig_func, sizeof(trap), - PAGE_EXECUTE_READWRITE, &dPermission); - if (data != NULL) { - data->fnc = orig_func; - memcpy(data->trap, trap, sizeof(trap)); - memcpy(data->original, orig_func, sizeof(trap)); - } - memcpy(orig_func, trap, sizeof(trap)); - VirtualProtect(orig_func, sizeof(trap), - dPermission, &dPermission); -} - -static inline void -gg_win32_hook_set_enabled(gg_win32_hook_data_t *data, int enabled) -{ - DWORD dPermission; - uint8_t *src; - - if (enabled) - src = data->trap; - else - src = data->original; - - VirtualProtect(data->fnc, sizeof(data->trap), - PAGE_EXECUTE_READWRITE, &dPermission); - memcpy(data->fnc, src, sizeof(data->trap)); - VirtualProtect(data->fnc, sizeof(data->trap), - dPermission, &dPermission); -} - -#endif /* _WIN32 */ - -#endif /* LIBGADU_INTERNAL_H */
--- a/libpurple/protocols/gg/lib/libgadu.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3082 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2001-2010 Wojtek Kaniewski <wojtekka@irc.pl> - * Robert J. Woźny <speedy@ziew.org> - * Arkadiusz Miśkiewicz <arekm@pld-linux.org> - * Tomasz Chiliński <chilek@chilan.com> - * Adam Wysocki <gophi@ekg.chmurka.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file libgadu.c - * - * \brief Główny moduł biblioteki - */ - -#include "strman.h" -#include "network.h" -#include "fileio.h" - -#include "libgadu.h" -#include "protocol.h" -#include "resolver.h" -#include "internal.h" -#include "encoding.h" -#include "debug.h" -#include "session.h" -#include "message.h" -#include "deflate.h" -#include "tvbuilder.h" -#include "protobuf.h" -#include "packets.pb-c.h" - -#include <errno.h> -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#ifdef GG_CONFIG_HAVE_GNUTLS -# include <gnutls/gnutls.h> -#endif -#ifdef GG_CONFIG_HAVE_OPENSSL -# include <openssl/err.h> -# include <openssl/rand.h> -#endif - -/** - * Port gniazda nasłuchującego dla połączeń bezpośrednich. - * - * \ingroup ip - */ -int gg_dcc_port = 0; - -/** - * Adres IP gniazda nasłuchującego dla połączeń bezpośrednich. - * - * \ingroup ip - */ -unsigned long gg_dcc_ip = 0; - -/** - * Adres lokalnego interfejsu IP, z którego wywoływane są wszystkie połączenia. - * - * \ingroup ip - */ -unsigned long gg_local_ip = 0; - -/** - * Flaga włączenia połączeń przez serwer pośredniczący. - * - * \ingroup proxy - */ -int gg_proxy_enabled = 0; - -/** - * Adres serwera pośredniczącego. - * - * \ingroup proxy - */ -char *gg_proxy_host = NULL; - -/** - * Port serwera pośredniczącego. - * - * \ingroup proxy - */ -int gg_proxy_port = 0; - -/** - * Flaga używania serwera pośredniczącego jedynie dla usług HTTP. - * - * \ingroup proxy - */ -int gg_proxy_http_only = 0; - -/** - * Nazwa użytkownika do autoryzacji serwera pośredniczącego. - * - * \ingroup proxy - */ -char *gg_proxy_username = NULL; - -/** - * Hasło użytkownika do autoryzacji serwera pośredniczącego. - * - * \ingroup proxy - */ -char *gg_proxy_password = NULL; - -#ifndef DOXYGEN - -#ifndef lint -static char rcsid[] GG_UNUSED = "$Id$"; -#endif - -#endif /* DOXYGEN */ - -static void gg_compat_message_sent(struct gg_session *sess, int seq, size_t recipients_count, uin_t *recipients); -static void gg_compat_message_cleanup(struct gg_session *sess); - -#ifdef GG_CONFIG_IS_GPL_COMPLIANT -/** - * Symbol zdefiniowany tylko dla libgadu zgodnego z licencją GPL. - * - * Zwracana wartość nie jest istotna, a ponadto może się zmienić w przyszłych - * wersjach biblioteki. Istotne jest tylko wywołanie tej funkcji w kodzie, który - * ma być zgodny z GPL, aby wymusić jej istnienie. - * - * \return Wartość 1. - * - * \ingroup version - */ -int gg_is_gpl_compliant(void) -{ - return 1; -} -#endif - -/** - * Zwraca wersję biblioteki. - * - * \return Wskaźnik na statyczny bufor z wersją biblioteki. - * - * \ingroup version - */ -const char *gg_libgadu_version(void) -{ - return GG_LIBGADU_VERSION; -} - -void * gg_new0(size_t size) -{ - void *ptr; - - ptr = malloc(size); - if (ptr == NULL) { - gg_debug(GG_DEBUG_MISC | GG_DEBUG_ERROR, - "//gg_new0(%" GG_SIZE_FMT - ") not enough memory\n", size); - return NULL; - } - - memset(ptr, 0, size); - return ptr; -} - -int -gg_required_proto(struct gg_session *gs, int protocol_version) -{ - if (gs->protocol_version >= protocol_version) - return 1; - - gg_debug_session(gs, GG_DEBUG_MISC | GG_DEBUG_ERROR, "// requested " - "feature requires protocol %#02x, but %#02x is selected\n", - protocol_version, gs->protocol_version); - return 0; -} - -int gg_get_dummy_fd(struct gg_session *sess) -{ - struct gg_session_private *p = sess->private_data; - - if (p->dummyfds_created) - return p->dummyfds[0]; - - if (socketpair(AF_LOCAL, SOCK_STREAM, 0, p->dummyfds) == -1) { - gg_debug(GG_DEBUG_MISC | GG_DEBUG_ERROR, "// gg_get_dummy_fd() " - "unable to create pipes (errno=%d, %s)\n", - errno, strerror(errno)); - return -1; - } - - p->dummyfds_created = 1; - return p->dummyfds[0]; -} - -/** - * \internal Liczy skrót z hasła i ziarna. - * - * \param password Hasło - * \param seed Ziarno podane przez serwer - * - * \return Wartość skrótu - */ -unsigned int gg_login_hash(const unsigned char *password, unsigned int seed) -{ - unsigned int x, y, z; - - y = seed; - - for (x = 0; *password; password++) { - x = (x & 0xffffff00) | *password; - y ^= x; - y += x; - x <<= 8; - y ^= x; - x <<= 8; - y -= x; - x <<= 8; - y ^= x; - - z = y & 0x1F; - y = (y << z) | (y >> (32 - z)); - } - - return y; -} - -/** - * \internal Odbiera od serwera dane binarne. - * - * Funkcja odbiera dane od serwera zajmując się SSL/TLS w razie konieczności. - * Obsługuje EINTR, więc użytkownik nie musi się przejmować przerwanymi - * wywołaniami systemowymi. - * - * \param sess Struktura sesji - * \param buf Bufor na danymi - * \param length Długość bufora - * - * \return To samo co funkcja systemowa \c read - */ -int gg_read(struct gg_session *sess, char *buf, int length) -{ - struct gg_session_private *p = sess->private_data; - int res; - -#ifdef GG_CONFIG_HAVE_GNUTLS - if (sess->ssl != NULL) { - for (;;) { - res = gnutls_record_recv(GG_SESSION_GNUTLS(sess), buf, length); - - if (res < 0) { - if (res == GNUTLS_E_AGAIN) - errno = EAGAIN; - else if (!gnutls_error_is_fatal(res) || res == GNUTLS_E_INTERRUPTED) - continue; - else - errno = EINVAL; - - return -1; - } - - return res; - } - } -#endif - -#ifdef GG_CONFIG_HAVE_OPENSSL - if (sess->ssl != NULL) { - for (;;) { - int err; - - res = SSL_read(sess->ssl, buf, length); - - if (res < 0) { - err = SSL_get_error(sess->ssl, res); - - if (err == SSL_ERROR_SYSCALL && errno == EINTR) - continue; - - if (err == SSL_ERROR_WANT_READ) - errno = EAGAIN; - else if (err != SSL_ERROR_SYSCALL) - errno = EINVAL; - - return -1; - } - - return res; - } - } -#endif - - if (p->socket_handle != NULL) { - if (p->socket_manager.read_cb == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR, - "// gg_read() socket_manager.read callback is " - "empty\n"); - errno = EINVAL; - return -1; - } - - do { - res = p->socket_manager.read_cb( - p->socket_manager.cb_data, p->socket_handle, - (unsigned char*)buf, length); - } while (res < 0 && errno == EINTR); - - if (res < 0) { - if (errno == EAGAIN) - return -1; - gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR, - "// gg_read() unexpected errno=%d\n", errno); - errno = EINVAL; - } - return res; - } - - for (;;) { - res = recv(sess->fd, buf, length, 0); - - if (res == -1 && errno == EINTR) - continue; - - return res; - } -} - -/** - * \internal Wysyła do serwera dane binarne. - * - * Funkcja wysyła dane do serwera zajmując się SSL/TLS w razie konieczności. - * Obsługuje EINTR, więc użytkownik nie musi się przejmować przerwanymi - * wywołaniami systemowymi. - * - * \note Funkcja nie zajmuje się buforowaniem wysyłanych danych (patrz - * gg_write()). - * - * \param sess Struktura sesji - * \param buf Bufor z danymi - * \param length Długość bufora - * - * \return To samo co funkcja systemowa \c write - */ -static int gg_write_common(struct gg_session *sess, const char *buf, int length) -{ - struct gg_session_private *p = sess->private_data; - int res; - -#ifdef GG_CONFIG_HAVE_GNUTLS - if (sess->ssl != NULL) { - for (;;) { - res = gnutls_record_send(GG_SESSION_GNUTLS(sess), buf, length); - - if (res < 0) { - if (!gnutls_error_is_fatal(res) || res == GNUTLS_E_INTERRUPTED) - continue; - - if (res == GNUTLS_E_AGAIN) - errno = EAGAIN; - else - errno = EINVAL; - - return -1; - } - - return res; - } - } -#endif - -#ifdef GG_CONFIG_HAVE_OPENSSL - if (sess->ssl != NULL) { - for (;;) { - int err; - - res = SSL_write(sess->ssl, buf, length); - - if (res < 0) { - err = SSL_get_error(sess->ssl, res); - - if (err == SSL_ERROR_SYSCALL && errno == EINTR) - continue; - - if (err == SSL_ERROR_WANT_WRITE) - errno = EAGAIN; - else if (err != SSL_ERROR_SYSCALL) - errno = EINVAL; - - return -1; - } - - return res; - } - } -#endif - - if (p->socket_handle != NULL) { - if (p->socket_manager.write_cb == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR, - "// gg_write_common() socket_manager.write " - "callback is empty\n"); - errno = EINVAL; - return -1; - } - - do { - res = p->socket_manager.write_cb( - p->socket_manager.cb_data, p->socket_handle, - (const unsigned char*)buf, length); - } while (res < 0 && errno == EINTR); - - if (res < 0) { - if (errno == EAGAIN) - return -1; - gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR, - "// gg_read() unexpected errno=%d\n", errno); - errno = EINVAL; - } - - return res; - } - - for (;;) { - res = send(sess->fd, buf, length, 0); - - if (res == -1 && errno == EINTR) - continue; - - return res; - } -} - -/** - * \internal Wysyła do serwera dane binarne. - * - * Funkcja wysyła dane do serwera zajmując się TLS w razie konieczności. - * - * \param sess Struktura sesji - * \param buf Bufor z danymi - * \param length Długość bufora - * - * \return To samo co funkcja systemowa \c write - */ -int gg_write(struct gg_session *sess, const char *buf, int length) -{ - int res = 0; - - if (!sess->async) { - int written = 0; - - while (written < length) { - res = gg_write_common(sess, buf + written, length - written); - - if (res == -1) - return -1; - - written += res; - res = written; - } - } else { - if (sess->send_buf == NULL) { - res = gg_write_common(sess, buf, length); - - if (res == -1 && errno == EAGAIN) - res = 0; - if (res == -1) - return -1; - } - - if (res < length) { - char *tmp; - - if (!(tmp = realloc(sess->send_buf, sess->send_left + length - res))) { - errno = ENOMEM; - return -1; - } - - sess->send_buf = tmp; - - memcpy(sess->send_buf + sess->send_left, buf + res, length - res); - - sess->send_left += length - res; - } - } - - return res; -} - -void gg_close(struct gg_session *sess) -{ - struct gg_session_private *p = sess->private_data; - int errno_copy; - - errno_copy = errno; - - if (!p->socket_is_external) { - if (sess->fd != -1) - close(sess->fd); - } else { - assert(p->socket_manager_type != - GG_SOCKET_MANAGER_TYPE_INTERNAL); - if (p->socket_handle != NULL) { - p->socket_manager.close_cb(p->socket_manager.cb_data, - p->socket_handle); - } - p->socket_is_external = 0; - } - sess->fd = -1; - p->socket_handle = NULL; - - while (p->event_queue) { - gg_eventqueue_t *next = p->event_queue->next; - gg_event_free(p->event_queue->event); - free(p->event_queue); - p->event_queue = next; - } - - while (p->imgout_queue) { - gg_imgout_queue_t *next = p->imgout_queue->next; - free(p->imgout_queue); - p->imgout_queue = next; - } - - if (p->dummyfds_created) { - close(p->dummyfds[0]); - close(p->dummyfds[1]); - p->dummyfds_created = 0; - } - - gg_compat_message_cleanup(sess); - - errno = errno_copy; -} - -/** - * \internal Odbiera pakiet od serwera. - * - * Funkcja odczytuje nagłówek pakietu, a następnie jego zawartość i zwraca - * w zaalokowanym buforze. - * - * Przy połączeniach asynchronicznych, funkcja może nie być w stanie - * skompletować całego pakietu -- w takim przypadku zwróci \c NULL, a kodem błędu - * będzie \c EAGAIN. - * - * \param sess Struktura sesji - * - * \return Wskaźnik do zaalokowanego bufora - */ -void *gg_recv_packet(struct gg_session *sess) -{ - struct gg_header *gh; - char *packet; - int res; - size_t len; - uint32_t ghlen = 0; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_recv_packet(%p);\n", sess); - - if (sess == NULL) { - errno = EFAULT; - return NULL; - } - - for (;;) { - if (sess->recv_buf == NULL && sess->recv_done == 0) { - sess->recv_buf = malloc(sizeof(struct gg_header) + 1); - - if (sess->recv_buf == NULL) { - gg_debug_session(sess, GG_DEBUG_ERROR, "// gg_recv_packet() out of memory\n"); - return NULL; - } - } - - gh = (struct gg_header*) sess->recv_buf; - - if ((size_t) sess->recv_done < sizeof(struct gg_header)) { - len = sizeof(struct gg_header) - sess->recv_done; - gg_debug_session(sess, GG_DEBUG_NET, - "// gg_recv_packet() header: %d done, " - "%" GG_SIZE_FMT " to go\n", - sess->recv_done, len); - } else { - ghlen = gh ? gg_fix32(gh->length) : 0; - - if (ghlen > 65535) { - gg_debug_session(sess, GG_DEBUG_ERROR, - "// gg_recv_packet() invalid packet " - "length (%d)\n", ghlen); - errno = ERANGE; - goto fail; - } - - if ((size_t) sess->recv_done >= sizeof(struct gg_header) + ghlen) { - gg_debug_session(sess, GG_DEBUG_NET, "// gg_recv_packet() and that's it\n"); - break; - } - - len = sizeof(struct gg_header) + ghlen - sess->recv_done; - - gg_debug_session(sess, GG_DEBUG_NET, - "// gg_recv_packet() payload: %d done, " - "%u length, %" GG_SIZE_FMT " to go\n", - sess->recv_done, ghlen, len); - } - - res = gg_read(sess, sess->recv_buf + sess->recv_done, len); - - if (res == 0) { - errno = ECONNRESET; - gg_debug_session(sess, GG_DEBUG_ERROR, "// gg_recv_packet() connection broken\n"); - goto fail; - } - - if (res == -1 && errno == EAGAIN) { - gg_debug_session(sess, GG_DEBUG_NET, "// gg_recv_packet() resource temporarily unavailable\n"); - goto eagain; - } - - if (res == -1) { - gg_debug_session(sess, GG_DEBUG_ERROR, - "// gg_recv_packet() read failed: errno=%d, " - "%s\n", errno, strerror(errno)); - goto fail; - } - - gg_debug_session(sess, GG_DEBUG_NET, "// gg_recv_packet() read %d bytes\n", res); - - if (sess->recv_done + res == sizeof(struct gg_header)) { - char *tmp; - ghlen = gh ? gg_fix32(gh->length) : 0; - - gg_debug_session(sess, GG_DEBUG_NET, - "// gg_recv_packet() header complete, " - "payload %d bytes\n", ghlen); - - if (ghlen == 0) - break; - - if (ghlen > 65535) { - gg_debug_session(sess, GG_DEBUG_ERROR, - "// gg_recv_packet() invalid packet " - "length (%d)\n", ghlen); - errno = ERANGE; - goto fail; - } - - tmp = realloc(sess->recv_buf, sizeof(struct gg_header) + ghlen + 1); - - if (tmp == NULL) { - gg_debug_session(sess, GG_DEBUG_ERROR, "// gg_recv_packet() out of memory\n"); - goto fail; - } - - sess->recv_buf = tmp; - } - - sess->recv_done += res; - } - - packet = sess->recv_buf; - sess->recv_buf = NULL; - sess->recv_done = 0; - - if (gh == NULL) - goto fail; - - /* Czasami zakładamy, że teksty w pakietach są zakończone zerem */ - packet[sizeof(struct gg_header) + ghlen] = 0; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet(type=0x%.2x, " - "length=%d)\n", gg_fix32(gh->type), ghlen); - gg_debug_dump(sess, GG_DEBUG_DUMP, packet, sizeof(struct gg_header) + ghlen); - - gh->type = gg_fix32(gh->type); - gh->length = ghlen; - - return packet; - -fail: - free(sess->recv_buf); - sess->recv_buf = NULL; - sess->recv_done = 0; - -eagain: - return NULL; -} - -/** - * \internal Wysyła pakiet do serwera. - * - * Funkcja konstruuje pakiet do wysłania z dowolnej liczby fragmentów. Jeśli - * rozmiar pakietu jest za duży, by móc go wysłać za jednym razem, pozostała - * część zostanie zakolejkowana i wysłana, gdy będzie to możliwe. - * - * \param sess Struktura sesji - * \param type Rodzaj pakietu - * \param ... Lista kolejnych części pakietu (wskaźnik na bufor i długość - * typu \c int) zakończona \c NULL - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -int gg_send_packet(struct gg_session *sess, int type, ...) -{ - struct gg_header *h; - char *tmp; - unsigned int tmp_length; - void *payload; - unsigned int payload_length; - va_list ap; - int res; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_send_packet(%p, 0x%.2x, ...);\n", sess, type); - - tmp_length = sizeof(struct gg_header); - - if (!(tmp = malloc(tmp_length))) { - gg_debug_session(sess, GG_DEBUG_ERROR, "// gg_send_packet() not enough memory for packet header\n"); - return -1; - } - - va_start(ap, type); - - payload = va_arg(ap, void *); - - while (payload) { - char *tmp2; - - payload_length = va_arg(ap, unsigned int); - - if (!(tmp2 = realloc(tmp, tmp_length + payload_length))) { - gg_debug_session(sess, GG_DEBUG_ERROR, "// gg_send_packet() not enough memory for payload\n"); - free(tmp); - va_end(ap); - return -1; - } - - tmp = tmp2; - - memcpy(tmp + tmp_length, payload, payload_length); - tmp_length += payload_length; - - payload = va_arg(ap, void *); - } - - va_end(ap); - - h = (struct gg_header*) tmp; - h->type = gg_fix32(type); - h->length = gg_fix32(tmp_length - sizeof(struct gg_header)); - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_send_packet(type=0x%.2x, " - "length=%d)\n", gg_fix32(h->type), gg_fix32(h->length)); - gg_debug_dump(sess, GG_DEBUG_DUMP, tmp, tmp_length); - - res = gg_write(sess, tmp, tmp_length); - - free(tmp); - - if (res == -1) { - gg_debug_session(sess, GG_DEBUG_ERROR, "// gg_send_packet() " - "write() failed. res = %d, errno = %d (%s)\n", - res, errno, strerror(errno)); - return -1; - } - - if (sess->async) { - gg_debug_session(sess, GG_DEBUG_NET, "// gg_send_packet() " - "partial write(), %d sent, %d left, %d total left\n", - res, tmp_length - res, sess->send_left); - } - - if (sess->send_buf) - sess->check |= GG_CHECK_WRITE; - - return 0; -} - -/** - * \internal Funkcja zwrotna sesji. - * - * Pole \c callback struktury \c gg_session zawiera wskaźnik do tej funkcji. - * Wywołuje ona \c gg_watch_fd i zachowuje wynik w polu \c event. - * - * \note Korzystanie z tej funkcjonalności nie jest już zalecane. - * - * \param sess Struktura sesji - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -static int gg_session_callback(struct gg_session *sess) -{ - if (!sess) { - errno = EFAULT; - return -1; - } - - return ((sess->event = gg_watch_fd(sess)) != NULL) ? 0 : -1; -} - -/** - * Łączy się z serwerem Gadu-Gadu. - * - * Przy połączeniu synchronicznym funkcja zakończy działanie po nawiązaniu - * połączenia lub gdy wystąpi błąd. Po udanym połączeniu należy wywoływać - * funkcję \c gg_watch_fd(), która odbiera informacje od serwera i zwraca - * informacje o zdarzeniach. - * - * Przy połączeniu asynchronicznym funkcja rozpocznie procedurę połączenia - * i zwróci zaalokowaną strukturę. Pole \c fd struktury \c gg_session zawiera - * deskryptor, który należy obserwować funkcją \c select, \c poll lub za - * pomocą mechanizmów użytej pętli zdarzeń (Glib, Qt itp.). Pole \c check - * jest maską bitową mówiącą, czy biblioteka chce być informowana o możliwości - * odczytu danych (\c GG_CHECK_READ) czy zapisu danych (\c GG_CHECK_WRITE). - * Po zaobserwowaniu zmian na deskryptorze należy wywołać funkcję - * \c gg_watch_fd(). Podczas korzystania z połączeń asynchronicznych, w trakcie - * połączenia może zostać stworzony dodatkowy proces rozwiązujący nazwę - * serwera -- z tego powodu program musi poprawnie obsłużyć sygnał SIGCHLD. - * - * \note Po nawiązaniu połączenia z serwerem należy wysłać listę kontaktów - * za pomocą funkcji \c gg_notify() lub \c gg_notify_ex(). - * - * \note Funkcja zwróci błąd ENOSYS jeśli połączenie SSL było wymagane, ale - * obsługa SSL nie jest wkompilowana. - * - * \param p Struktura opisująca parametry połączenia. Wymagane pola: uin, - * password, async. - * - * \return Wskaźnik do zaalokowanej struktury sesji \c gg_session lub NULL - * w przypadku błędu. - * - * \ingroup login - */ -struct gg_session *gg_login(const struct gg_login_params *p) -{ - struct gg_session *sess = NULL; - struct gg_session_private *sess_private = NULL; - - if (p == NULL) { - gg_debug(GG_DEBUG_FUNCTION, "** gg_login(%p);\n", p); - errno = EFAULT; - return NULL; - } - - gg_debug(GG_DEBUG_FUNCTION, "** gg_login(%p: [uin=%u, async=%d, ...]);\n", p, p->uin, p->async); - - sess = malloc(sizeof(struct gg_session)); - - if (sess == NULL) { - gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for session data\n"); - goto fail; - } - - memset(sess, 0, sizeof(struct gg_session)); - sess->fd = -1; - - sess_private = malloc(sizeof(struct gg_session_private)); - - if (sess_private == NULL) { - gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for session private data\n"); - goto fail; - } - - memset(sess_private, 0, sizeof(struct gg_session_private)); - sess->private_data = sess_private; - - if (p->password == NULL || p->uin == 0) { - gg_debug(GG_DEBUG_MISC, "// gg_login() invalid arguments. uin and password needed\n"); - errno = EFAULT; - goto fail; - } - - if (!(sess->password = strdup(p->password))) { - gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for password\n"); - goto fail; - } - - if (p->hash_type < 0 || p->hash_type > GG_LOGIN_HASH_SHA1) { - gg_debug(GG_DEBUG_MISC, "// gg_login() invalid arguments. unknown hash type (%d)\n", p->hash_type); - errno = EFAULT; - goto fail; - } - - sess->uin = p->uin; - sess->state = GG_STATE_RESOLVING; - sess->check = GG_CHECK_READ; - sess->timeout = GG_DEFAULT_TIMEOUT; - sess->async = p->async; - sess->type = GG_SESSION_GG; - sess->initial_status = p->status; - sess->callback = gg_session_callback; - sess->destroy = gg_free_session; - sess->port = p->server_port; - sess->server_addr = p->server_addr; - sess->external_port = p->external_port; - sess->external_addr = p->external_addr; - sess->client_addr = p->client_addr; - sess->client_port = p->client_port; - - if (GG_LOGIN_PARAMS_HAS_FIELD(p, compatibility)) - sess_private->compatibility = p->compatibility; - - if (GG_LOGIN_PARAMS_HAS_FIELD(p, connect_host) && p->connect_host != NULL) { - int port = 0; - char *colon; - - sess->connect_host = strdup(p->connect_host); - if (sess->connect_host == NULL) - goto fail; - - colon = strchr(sess->connect_host, ':'); - if (colon != NULL) { - colon[0] = '\0'; - port = atoi(colon + 1); - } - if (port > 0) - sess->port = port; - } - - if (GG_LOGIN_PARAMS_HAS_FIELD(p, socket_manager_type) && - GG_LOGIN_PARAMS_HAS_FIELD(p, socket_manager) && - p->socket_manager_type != GG_SOCKET_MANAGER_TYPE_INTERNAL) - { - if ((unsigned int)p->socket_manager_type > - GG_SOCKET_MANAGER_TYPE_TLS) - { - gg_debug(GG_DEBUG_MISC | GG_DEBUG_ERROR, "// gg_login()" - " invalid arguments. unknown socket manager " - "type (%d)\n", p->socket_manager_type); - errno = EFAULT; - goto fail; - } else { - sess_private->socket_manager_type = - p->socket_manager_type; - memcpy(&sess_private->socket_manager, - &p->socket_manager, - sizeof(gg_socket_manager_t)); - } - } else { - sess_private->socket_manager_type = - GG_SOCKET_MANAGER_TYPE_INTERNAL; - } - - if (GG_LOGIN_PARAMS_HAS_FIELD(p, host_white_list) && - p->host_white_list != NULL) - { - sess_private->host_white_list = - gg_strarr_dup(p->host_white_list); - if (sess_private->host_white_list == NULL) - goto fail; - } - - if (p->protocol_features == 0) { - sess->protocol_features = GG_FEATURE_MSG80 | - GG_FEATURE_STATUS80 | GG_FEATURE_DND_FFC | - GG_FEATURE_IMAGE_DESCR | GG_FEATURE_UNKNOWN_100 | - GG_FEATURE_USER_DATA | GG_FEATURE_MSG_ACK | - GG_FEATURE_TYPING_NOTIFICATION; - } else { - sess->protocol_features = (p->protocol_features & ~(GG_FEATURE_STATUS77 | GG_FEATURE_MSG77)); - - if (!(p->protocol_features & GG_FEATURE_STATUS77)) - sess->protocol_features |= GG_FEATURE_STATUS80; - - if (!(p->protocol_features & GG_FEATURE_MSG77)) - sess->protocol_features |= GG_FEATURE_MSG80; - } - - if (!(sess->status_flags = p->status_flags)) - sess->status_flags = GG_STATUS_FLAG_UNKNOWN | GG_STATUS_FLAG_SPAM; - - if (!p->protocol_version) - sess->protocol_version = GG_DEFAULT_PROTOCOL_VERSION; - else if (p->protocol_version < 0x2e) { - gg_debug(GG_DEBUG_MISC, "// gg_login() libgadu no longer support protocol < 0x2e\n"); - sess->protocol_version = 0x2e; - } else - sess->protocol_version = p->protocol_version; - - if (p->client_version && strcmp(p->client_version, "-") != 0) - sess->client_version = strdup(p->client_version); - sess->last_sysmsg = p->last_sysmsg; - sess->image_size = p->image_size; - sess->pid = -1; - sess->encoding = p->encoding; - - if (gg_session_set_resolver(sess, p->resolver) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_login() invalid arguments. " - "unsupported resolver type (%d)\n", p->resolver); - errno = EFAULT; - goto fail; - } - - if (p->status_descr) { - sess->initial_descr = gg_encoding_convert(p->status_descr, p->encoding, GG_ENCODING_UTF8, -1, -1); - - if (!sess->initial_descr) { - gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for status\n"); - goto fail; - } - - /* XXX pamiętać, żeby nie ciąć w środku znaku utf-8 */ - - if (strlen(sess->initial_descr) > GG_STATUS_DESCR_MAXSIZE) - sess->initial_descr[GG_STATUS_DESCR_MAXSIZE] = 0; - } - - if (p->tls != GG_SSL_DISABLED) { -#if !defined(GG_CONFIG_HAVE_GNUTLS) && !defined(GG_CONFIG_HAVE_OPENSSL) - gg_debug(GG_DEBUG_MISC, "// gg_login() client requested TLS but no support compiled in\n"); - - if (p->tls == GG_SSL_REQUIRED) { - errno = ENOSYS; - goto fail; - } -#else - sess->ssl_flag = p->tls; -#endif - } - - if (p->hash_type) - sess->hash_type = p->hash_type; - else - sess->hash_type = GG_LOGIN_HASH_SHA1; - - if (sess->server_addr == 0 && sess->connect_host == NULL) { - if (gg_proxy_enabled) { - sess->resolver_host = gg_proxy_host; - sess->proxy_port = gg_proxy_port; - sess->state = (sess->async) ? - GG_STATE_RESOLVE_PROXY_HUB_ASYNC : - GG_STATE_RESOLVE_PROXY_HUB_SYNC; - } else { - sess->resolver_host = GG_APPMSG_HOST; - sess->proxy_port = 0; - sess->state = (sess->async) ? GG_STATE_RESOLVE_HUB_ASYNC : GG_STATE_RESOLVE_HUB_SYNC; - } - } else { - if (sess->connect_host != NULL) - sess->server_addr = 0; - else { - /* XXX inet_ntoa i wielowątkowość */ - sess->connect_host = strdup(inet_ntoa(*(struct in_addr*) &sess->server_addr)); - if (sess->connect_host == NULL) - goto fail; - } - sess->connect_index = 0; - - if (gg_proxy_enabled) { - sess->resolver_host = gg_proxy_host; - sess->proxy_port = gg_proxy_port; - if (sess->port == 0) - sess->connect_port[0] = GG_HTTPS_PORT; - else - sess->connect_port[0] = sess->port; - sess->connect_port[1] = 0; - sess->state = (sess->async) ? GG_STATE_RESOLVE_PROXY_GG_ASYNC : GG_STATE_RESOLVE_PROXY_GG_SYNC; - } else { - sess->resolver_host = sess->connect_host; - if (sess->port == 0) { - if (sess->ssl_flag == GG_SSL_DISABLED) { - sess->connect_port[0] = GG_DEFAULT_PORT; - sess->connect_port[1] = GG_HTTPS_PORT; - } else { - sess->connect_port[0] = GG_HTTPS_PORT; - sess->connect_port[1] = 0; - } - } else { - sess->connect_port[0] = sess->port; - sess->connect_port[1] = 0; - } - sess->state = (sess->async) ? GG_STATE_RESOLVE_GG_ASYNC : GG_STATE_RESOLVE_GG_SYNC; - } - } - - /* XXX inaczej gg_watch_fd() wyjdzie z timeoutem */ - sess->timeout = GG_DEFAULT_TIMEOUT; - - if (!sess->async) { - while (!GG_SESSION_IS_CONNECTED(sess)) { - struct gg_event *ge; - - ge = gg_watch_fd(sess); - - if (ge == NULL) { - gg_debug(GG_DEBUG_MISC, "// gg_session_connect() critical error in gg_watch_fd()\n"); - goto fail; - } - - if (ge->type == GG_EVENT_CONN_FAILED) { - errno = EACCES; - gg_debug(GG_DEBUG_MISC, "// gg_session_connect() could not login\n"); - gg_event_free(ge); - goto fail; - } - - gg_event_free(ge); - } - } else { - struct gg_event *ge; - - ge = gg_watch_fd(sess); - - if (ge == NULL) { - gg_debug(GG_DEBUG_MISC, "// gg_session_connect() critical error in gg_watch_fd()\n"); - goto fail; - } - - gg_event_free(ge); - } - - return sess; - -fail: - gg_free_session(sess); - - return NULL; -} - -/** - * Wysyła do serwera pakiet utrzymania połączenia. - * - * Klient powinien regularnie co minutę wysyłać pakiet utrzymania połączenia, - * inaczej serwer uzna, że klient stracił łączność z siecią i zerwie - * połączenie. - * - * \param sess Struktura sesji - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup login - */ -int gg_ping(struct gg_session *sess) -{ - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_ping(%p);\n", sess); - - if (!sess) { - errno = EFAULT; - return -1; - } - - if (sess->state != GG_STATE_CONNECTED) { - errno = ENOTCONN; - return -1; - } - - return gg_send_packet(sess, GG_PING, NULL); -} - -/** - * Kończy połączenie z serwerem. - * - * Funkcja nie zwalnia zasobów, więc po jej wywołaniu należy użyć - * \c gg_free_session(). Jeśli chce się ustawić opis niedostępności, należy - * wcześniej wywołać funkcję \c gg_change_status_descr() lub - * \c gg_change_status_descr_time(). - * - * \note Jeśli w buforze nadawczym połączenia z serwerem znajdują się jeszcze - * dane (np. z powodu strat pakietów na łączu), prawdopodobnie zostaną one - * utracone przy zrywaniu połączenia. Aby mieć pewność, że opis statusu - * zostanie zachowany, należy ustawić stan \c GG_STATUS_NOT_AVAIL_DESCR - * za pomocą funkcji \c gg_change_status_descr() i poczekać na zdarzenie - * \c GG_EVENT_DISCONNECT_ACK. - * - * \param sess Struktura sesji - * - * \ingroup login - */ -void gg_logoff(struct gg_session *sess) -{ - if (!sess) - return; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_logoff(%p);\n", sess); - -#ifdef GG_CONFIG_HAVE_GNUTLS - if (sess->ssl != NULL) - gnutls_bye(GG_SESSION_GNUTLS(sess), GNUTLS_SHUT_RDWR); -#endif - -#ifdef GG_CONFIG_HAVE_OPENSSL - if (sess->ssl != NULL) - SSL_shutdown(sess->ssl); -#endif - - sess->resolver_cleanup(&sess->resolver, 1); - - gg_close(sess); - - if (sess->send_buf) { - free(sess->send_buf); - sess->send_buf = NULL; - sess->send_left = 0; - } -} - -/** - * Zwalnia zasoby używane przez połączenie z serwerem. Funkcję należy wywołać - * po zamknięciu połączenia z serwerem, by nie doprowadzić do wycieku zasobów - * systemowych. - * - * \param sess Struktura sesji - * - * \ingroup login - */ -void gg_free_session(struct gg_session *sess) -{ - struct gg_dcc7 *dcc; - gg_chat_list_t *chat; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_free_session(%p);\n", sess); - - if (sess == NULL) - return; - - /* XXX dopisać zwalnianie i zamykanie wszystkiego, co mogło zostać */ - - free(sess->resolver_result); - free(sess->connect_host); - free(sess->password); - free(sess->initial_descr); - free(sess->client_version); - free(sess->header_buf); - free(sess->recv_buf); - -#ifdef GG_CONFIG_HAVE_GNUTLS - if (sess->ssl != NULL) { - gg_session_gnutls_t *tmp; - - tmp = (gg_session_gnutls_t*) sess->ssl; - gnutls_deinit(tmp->session); - gnutls_certificate_free_credentials(tmp->xcred); - gnutls_global_deinit(); - free(sess->ssl); - } -#endif - -#ifdef GG_CONFIG_HAVE_OPENSSL - if (sess->ssl) - SSL_free(sess->ssl); - - if (sess->ssl_ctx) - SSL_CTX_free(sess->ssl_ctx); -#endif - - if (sess->resolver_cleanup != NULL) - sess->resolver_cleanup(&sess->resolver, 1); - - gg_close(sess); - - while (sess->images) { - struct gg_image_queue *next = sess->images->next; - - gg_image_queue_remove(sess, sess->images, 1); - - /* a fix for false-positive NULL-dereference */ - sess->images = next; - } - - free(sess->send_buf); - - for (dcc = sess->dcc7_list; dcc; dcc = dcc->next) - dcc->sess = NULL; - - chat = sess->private_data->chat_list; - while (chat != NULL) { - gg_chat_list_t *next = chat->next; - free(chat->participants); - free(chat); - chat = next; - } - - gg_strarr_free(sess->private_data->host_white_list); - - free(sess->private_data); - - free(sess); -} - -/** - * Zmienia status użytkownika. - * - * \param sess Struktura sesji - * \param status Nowy status użytkownika - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup status - */ -int gg_change_status(struct gg_session *sess, int status) -{ - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_change_status(%p, %d);\n", sess, status); - - return gg_change_status_descr(sess, status, NULL); -} - -/** - * Zmienia status użytkownika na status opisowy. - * - * \param sess Struktura sesji - * \param status Nowy status użytkownika - * \param descr Opis statusu użytkownika (lub \c NULL) - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup status - */ -int gg_change_status_descr(struct gg_session *sess, int status, const char *descr) -{ - struct gg_new_status80 p; - char *gen_descr = NULL; - int descr_len = 0; - int descr_null_len = 0; - int res; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_change_status_descr(%p, %d, \"%s\");\n", sess, status, descr); - - if (!sess) { - errno = EFAULT; - return -1; - } - - if (sess->state != GG_STATE_CONNECTED) { - errno = ENOTCONN; - return -1; - } - - sess->status = status; - - if (descr != NULL && sess->encoding != GG_ENCODING_UTF8) { - descr = gen_descr = gg_encoding_convert(descr, GG_ENCODING_CP1250, GG_ENCODING_UTF8, -1, -1); - - if (!gen_descr) - return -1; - } - - if (descr) { - descr_len = strlen(descr); - - if (descr_len > GG_STATUS_DESCR_MAXSIZE) - descr_len = GG_STATUS_DESCR_MAXSIZE; - - /* XXX pamiętać o tym, żeby nie ucinać w środku znaku utf-8 */ - } else { - descr = ""; - } - - p.status = gg_fix32(status); - p.flags = gg_fix32(sess->status_flags); - p.description_size = gg_fix32(descr_len); - - if (sess->protocol_version >= GG_PROTOCOL_VERSION_110) { - p.flags = gg_fix32(0x00000014); - descr_null_len = 1; - } - - res = gg_send_packet(sess, GG_NEW_STATUS80, - &p, sizeof(p), descr, descr_len, - "\x00", descr_null_len, NULL); - - free(gen_descr); - - if (GG_S_NA(status)) { - sess->state = GG_STATE_DISCONNECTING; - sess->timeout = GG_TIMEOUT_DISCONNECT; - } - - return res; -} - -/** - * Zmienia status użytkownika na status opisowy z podanym czasem powrotu. - * - * \param sess Struktura sesji - * \param status Nowy status użytkownika - * \param descr Opis statusu użytkownika - * \param ts Czas powrotu w postaci uniksowego znacznika czasu - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup status - */ -int gg_change_status_descr_time(struct gg_session *sess, int status, const char *descr, int ts) -{ - gg_debug_session(sess, GG_DEBUG_FUNCTION, - "** gg_change_status_descr_time(%p, %d, \"%s\", %d);\n", - sess, status, descr, ts); - - return gg_change_status_descr(sess, status, descr); -} - -/** - * Funkcja zmieniająca flagi statusu. - * - * \param sess Struktura sesji - * \param flags Nowe flagi statusu - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \note Aby zmiany weszły w życie, należy ponownie ustawić status za pomocą - * funkcji z rodziny \c gg_change_status(). - * - * \ingroup status - */ -int gg_change_status_flags(struct gg_session *sess, int flags) -{ - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_change_status_flags(%p, 0x%08x);\n", sess, flags); - - if (sess == NULL) { - errno = EFAULT; - return -1; - } - - sess->status_flags = flags; - - return 0; -} - -#ifndef DOXYGEN - -static int gg_send_message_110(struct gg_session *sess, - uin_t recipient, uint64_t chat_id, - const char *message, int is_html) -{ - GG110SendMessage msg = GG110_SEND_MESSAGE__INIT; - int packet_type = recipient ? GG_SEND_MSG110 : GG_CHAT_SEND_MSG; - int seq; - char *html_message_gen = NULL, *plain_message_gen = NULL; - const char *html_message, *plain_message; - int succ = 1; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, - "** gg_send_message_110(%p, %u, %" PRIu64 ", %p, %d);\n", - sess, recipient, chat_id, message, is_html); - - if (message == NULL) - return -1; - - if ((recipient == 0) == (chat_id == 0)) - return -1; - - if (is_html) { - html_message = message; - - if (sess->encoding != GG_ENCODING_UTF8) { - html_message = html_message_gen = gg_encoding_convert( - html_message, sess->encoding, GG_ENCODING_UTF8, - -1, -1); - if (html_message_gen == NULL) - return -1; - } - - plain_message = plain_message_gen = - gg_message_html_to_text_110(html_message); - if (plain_message_gen == NULL) { - free(html_message_gen); - return -1; - } - } else { - plain_message = message; - - if (sess->encoding != GG_ENCODING_UTF8) { - plain_message = plain_message_gen = gg_encoding_convert( - plain_message, sess->encoding, GG_ENCODING_UTF8, - -1, -1); - if (plain_message_gen == NULL) - return -1; - } - - html_message = html_message_gen = - gg_message_text_to_html_110(plain_message, -1); - if (html_message_gen == NULL) { - free(plain_message_gen); - return -1; - } - } - - seq = ++sess->seq; - - if (recipient) { - msg.has_recipient = 1; - gg_protobuf_set_uin(&msg.recipient, recipient, NULL); - } - - msg.seq = seq; - - /* rzutujemy z const, ale msg i tak nie będzie modyfikowany */ - msg.msg_plain = (char*)plain_message; - msg.msg_xhtml = (char*)html_message; - - if (chat_id) { - msg.dummy3 = ""; - msg.has_chat_id = 1; - msg.chat_id = chat_id; - } - - if (!GG_PROTOBUF_SEND(sess, NULL, packet_type, gg110_send_message, msg)) - succ = 0; - - free(html_message_gen); - free(plain_message_gen); - - return succ ? seq : -1; -} - -static char * -gg_message_legacy_text_to_html(const char *src, gg_encoding_t encoding, - const unsigned char *format, size_t format_len) -{ - size_t len; - char *dst; - - if (format == NULL || format_len <= 3) { - format = NULL; - format_len = 0; - } else { - format += 3; - format_len -= 3; - } - - len = gg_message_text_to_html(NULL, src, encoding, format, format_len); - - dst = malloc(len + 1); - if (dst == NULL) - return NULL; - - gg_message_text_to_html(dst, src, encoding, format, format_len); - - return dst; -} - -/** - * \internal Wysyła wiadomość. - * - * Zwraca losowy numer sekwencyjny, który można zignorować albo wykorzystać - * do potwierdzenia. - * - * \param sess Struktura sesji - * \param msgclass Klasa wiadomości - * \param recipients_count Liczba adresatów - * \param recipients Wskaźnik do tablicy z numerami adresatów - * \param message Treść wiadomości - * \param format Informacje o formatowaniu - * \param formatlen Długość informacji o formatowaniu - * \param html_message Treść wiadomości HTML - * - * \return Numer sekwencyjny wiadomości lub -1 w przypadku błędu. - * - * \ingroup messages - */ -static int gg_send_message_common(struct gg_session *sess, int msgclass, - int recipients_count, uin_t *recipients, const unsigned char *message, - const unsigned char *format, int formatlen, - const unsigned char *html_message) -{ - struct gg_send_msg80 s80; - const char *cp_msg = NULL, *utf_html_msg = NULL; - char *recoded_msg = NULL, *recoded_html_msg = NULL; - unsigned char *generated_format = NULL; - int seq_no = -1; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_send_message_common(" - "%p, %d, %d, %p, %p, %p, %d, %p);\n", sess, msgclass, - recipients_count, recipients, message, format, - formatlen, html_message); - - if (!sess) { - errno = EFAULT; - return -1; - } - - if (sess->state != GG_STATE_CONNECTED) { - errno = ENOTCONN; - return -1; - } - - if ((message == NULL && html_message == NULL) || - recipients_count <= 0 || recipients_count > 0xffff || - recipients == NULL || (format == NULL && formatlen != 0)) - { - errno = EINVAL; - return -1; - } - - if (sess->protocol_version >= GG_PROTOCOL_VERSION_110 && - recipients_count == 1) - { - int is_html = (html_message != NULL); - char *formatted_msg = NULL; - - if (formatlen > 3 && !is_html) { - gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_WARNING, - "// gg_send_message_common() using legacy " - "formatting with new protocol\n"); - formatted_msg = gg_message_legacy_text_to_html( - (const char *)message, sess->encoding, - format, formatlen); - if (formatted_msg == NULL) - goto cleanup; - html_message = (unsigned char*)formatted_msg; - is_html = 1; - } - - seq_no = gg_send_message_110(sess, recipients[0], 0, - (const char*)(is_html ? html_message : message), - is_html); - goto cleanup; - } - - if (sess->protocol_version >= GG_PROTOCOL_VERSION_110 && - !gg_compat_feature_is_enabled(sess, GG_COMPAT_FEATURE_LEGACY_CONFER)) - { - gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR, - "// gg_send_message_common() legacy conferences disabled\n"); - errno = EINVAL; - return -1; - } - - if (message == NULL) { - char *tmp_msg; - size_t len, fmt_len; - uint16_t fixed_fmt_len; - - len = gg_message_html_to_text(NULL, NULL, &fmt_len, (const char*) html_message, sess->encoding); - - tmp_msg = malloc(len + 1); - - if (tmp_msg == NULL) - goto cleanup; - - if (fmt_len != 0) { - generated_format = malloc(fmt_len + 3); - - if (generated_format == NULL) { - free(tmp_msg); - goto cleanup; - } - - generated_format[0] = '\x02'; - fixed_fmt_len = gg_fix16(fmt_len); - memcpy(generated_format + 1, &fixed_fmt_len, sizeof(fixed_fmt_len)); - gg_message_html_to_text(tmp_msg, generated_format + 3, - NULL, (const char*)html_message, sess->encoding); - - format = generated_format; - formatlen = fmt_len + 3; - } else { - gg_message_html_to_text(tmp_msg, NULL, NULL, (const char*) html_message, sess->encoding); - - format = NULL; - formatlen = 0; - } - - if (sess->encoding != GG_ENCODING_CP1250) { - cp_msg = recoded_msg = gg_encoding_convert(tmp_msg, sess->encoding, GG_ENCODING_CP1250, -1, -1); - free(tmp_msg); - - if (cp_msg == NULL) - goto cleanup; - } else { - cp_msg = recoded_msg = tmp_msg; - } - } else { - if (sess->encoding != GG_ENCODING_CP1250) { - cp_msg = recoded_msg = gg_encoding_convert( - (const char*)message, sess->encoding, - GG_ENCODING_CP1250, -1, -1); - - if (cp_msg == NULL) - goto cleanup; - } else { - cp_msg = (const char*) message; - } - } - - if (html_message == NULL) { - char *formatted_msg; - - formatted_msg = gg_message_legacy_text_to_html( - (const char*)message, sess->encoding, format, formatlen); - if (formatted_msg == NULL) - goto cleanup; - - if (sess->encoding == GG_ENCODING_UTF8) { - utf_html_msg = recoded_html_msg = formatted_msg; - } else { - utf_html_msg = recoded_html_msg = gg_encoding_convert( - formatted_msg, sess->encoding, - GG_ENCODING_UTF8, -1, -1); - free(formatted_msg); - - if (utf_html_msg == NULL) - goto cleanup; - } - } else { - if (sess->encoding == GG_ENCODING_UTF8) { - utf_html_msg = (const char*) html_message; - } else { - utf_html_msg = recoded_html_msg = gg_encoding_convert( - (const char*)html_message, sess->encoding, - GG_ENCODING_UTF8, -1, -1); - - if (utf_html_msg == NULL) - goto cleanup; - } - } - - /* Drobne odchylenie od protokołu. Jeśli wysyłamy kilka - * wiadomości w ciągu jednej sekundy, zwiększamy poprzednią - * wartość, żeby każda wiadomość miała unikalny numer. - */ - - seq_no = time(NULL); - - if (seq_no <= sess->seq) - seq_no = sess->seq + 1; - - sess->seq = seq_no; - - s80.seq = gg_fix32(seq_no); - s80.msgclass = gg_fix32(msgclass); - s80.offset_plain = gg_fix32(sizeof(s80) + strlen(utf_html_msg) + 1); - s80.offset_attr = gg_fix32(sizeof(s80) + strlen(utf_html_msg) + 1 + strlen(cp_msg) + 1); - - if (recipients_count > 1) { - struct gg_msg_recipients r; - int i, j, k; - uin_t *recps; - - r.flag = GG_MSG_OPTION_CONFERENCE; - r.count = gg_fix32(recipients_count - 1); - - recps = malloc(sizeof(uin_t) * (recipients_count - 1)); - - if (!recps) { - seq_no = -1; - goto cleanup; - } - - for (i = 0; i < recipients_count; i++) { - for (j = 0, k = 0; j < recipients_count; j++) { - if (j != i) { - recps[k] = gg_fix32(recipients[j]); - k++; - } - } - - s80.recipient = gg_fix32(recipients[i]); - - if (gg_send_packet(sess, GG_SEND_MSG80, &s80, - sizeof(s80), utf_html_msg, - strlen(utf_html_msg) + 1, cp_msg, - strlen(cp_msg) + 1, &r, sizeof(r), recps, - (recipients_count - 1) * sizeof(uin_t), format, - formatlen, NULL) == -1) - { - seq_no = -1; - } - } - - free(recps); - } else { - s80.recipient = gg_fix32(recipients[0]); - - if (gg_send_packet(sess, GG_SEND_MSG80, &s80, sizeof(s80), - utf_html_msg, strlen(utf_html_msg) + 1, cp_msg, - strlen(cp_msg) + 1, format, formatlen, NULL) == -1) - { - seq_no = -1; - } - } - -cleanup: - free(recoded_msg); - free(recoded_html_msg); - free(generated_format); - - if (seq_no >= 0) - gg_compat_message_sent(sess, seq_no, recipients_count, recipients); - - return seq_no; -} - -#endif /* DOXYGEN */ - -/** - * Wysyła wiadomość do użytkownika. - * - * Zwraca losowy numer sekwencyjny, który można zignorować albo wykorzystać - * do potwierdzenia. - * - * \param sess Struktura sesji - * \param msgclass Klasa wiadomości - * \param recipient Numer adresata - * \param message Treść wiadomości - * - * \return Numer sekwencyjny wiadomości lub -1 w przypadku błędu. - * - * \ingroup messages - */ -int gg_send_message(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message) -{ - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_send_message(%p, %d, " - "%u, %p)\n", sess, msgclass, recipient, message); - - if (sess->protocol_version >= GG_PROTOCOL_VERSION_110) { - int seq_no; - - seq_no = gg_send_message_110(sess, recipient, 0, (const char*)message, 0); - - if (seq_no >= 0) - gg_compat_message_sent(sess, seq_no, 1, &recipient); - - return seq_no; - } - - return gg_send_message_common(sess, msgclass, 1, &recipient, message, - (const unsigned char*)"\x02\x06\x00\x00\x00\x08\x00\x00\x00", - 9, NULL); -} - -/** - * Wysyła wiadomość formatowaną. - * - * Zwraca losowy numer sekwencyjny, który można zignorować albo wykorzystać - * do potwierdzenia. - * - * \param sess Struktura sesji - * \param msgclass Klasa wiadomości - * \param recipient Numer adresata - * \param message Treść wiadomości - * \param format Informacje o formatowaniu - * \param formatlen Długość informacji o formatowaniu - * - * \return Numer sekwencyjny wiadomości lub -1 w przypadku błędu. - * - * \ingroup messages - */ -int gg_send_message_richtext(struct gg_session *sess, int msgclass, - uin_t recipient, const unsigned char *message, - const unsigned char *format, int formatlen) -{ - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_send_message_richtext(" - "%p, %d, %u, %p, %p, %d);\n", sess, msgclass, recipient, - message, format, formatlen); - - return gg_send_message_common(sess, msgclass, 1, &recipient, message, format, formatlen, NULL); -} - -/** - * Wysyła formatowaną wiadomość HTML. - * - * Zwraca losowy numer sekwencyjny, który można zignorować albo wykorzystać - * do potwierdzenia. - * - * \param sess Struktura sesji - * \param msgclass Klasa wiadomości - * \param recipient Numer adresata - * \param html_message Treść wiadomości HTML - * - * \return Numer sekwencyjny wiadomości lub -1 w przypadku błędu. - * - * \ingroup messages - */ -int gg_send_message_html(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *html_message) -{ - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_send_message_html(%p, " - "%d, %u, %p);\n", sess, msgclass, recipient, html_message); - - return gg_send_message_common(sess, msgclass, 1, &recipient, NULL, NULL, 0, html_message); -} - -/** - * Wysyła wiadomość w ramach konferencji. - * - * Zwraca losowy numer sekwencyjny, który można zignorować albo wykorzystać - * do potwierdzenia. - * - * \param sess Struktura sesji - * \param msgclass Klasa wiadomości - * \param recipients_count Liczba adresatów - * \param recipients Wskaźnik do tablicy z numerami adresatów - * \param message Treść wiadomości - * - * \return Numer sekwencyjny wiadomości lub -1 w przypadku błędu. - * - * \ingroup messages - */ -int gg_send_message_confer(struct gg_session *sess, int msgclass, - int recipients_count, uin_t *recipients, const unsigned char *message) -{ - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_send_message_confer(" - "%p, %d, %d, %p, %p);\n", sess, msgclass, recipients_count, - recipients, message); - - return gg_send_message_common(sess, msgclass, recipients_count, - recipients, message, - (const unsigned char*)"\x02\x06\x00\x00\x00\x08\x00\x00\x00", - 9, NULL); -} - -/** - * Wysyła wiadomość formatowaną w ramach konferencji. - * - * Zwraca losowy numer sekwencyjny, który można zignorować albo wykorzystać - * do potwierdzenia. - * - * \param sess Struktura sesji - * \param msgclass Klasa wiadomości - * \param recipients_count Liczba adresatów - * \param recipients Wskaźnik do tablicy z numerami adresatów - * \param message Treść wiadomości - * \param format Informacje o formatowaniu - * \param formatlen Długość informacji o formatowaniu - * - * \return Numer sekwencyjny wiadomości lub -1 w przypadku błędu. - * - * \ingroup messages - */ -int gg_send_message_confer_richtext(struct gg_session *sess, int msgclass, - int recipients_count, uin_t *recipients, const unsigned char *message, - const unsigned char *format, int formatlen) -{ - gg_debug_session(sess, GG_DEBUG_FUNCTION, - "** gg_send_message_confer_richtext(%p, %d, %d, %p, %p, %p, " - "%d);\n", sess, msgclass, recipients_count, recipients, message, - format, formatlen); - - return gg_send_message_common(sess, msgclass, recipients_count, recipients, message, format, formatlen, NULL); -} - -/** - * Wysyła formatowaną wiadomość HTML w ramach konferencji. - * - * Zwraca losowy numer sekwencyjny, który można zignorować albo wykorzystać - * do potwierdzenia. - * - * \param sess Struktura sesji - * \param msgclass Klasa wiadomości - * \param recipients_count Liczba adresatów - * \param recipients Wskaźnik do tablicy z numerami adresatów - * \param html_message Treść wiadomości HTML - * - * \return Numer sekwencyjny wiadomości lub -1 w przypadku błędu. - * - * \ingroup messages - */ -int gg_send_message_confer_html(struct gg_session *sess, int msgclass, - int recipients_count, uin_t *recipients, - const unsigned char *html_message) -{ - gg_debug_session(sess, GG_DEBUG_FUNCTION, - "** gg_send_message_confer_html(%p, %d, %d, %p, %p);\n", sess, - msgclass, recipients_count, recipients, html_message); - - return gg_send_message_common(sess, msgclass, recipients_count, recipients, NULL, NULL, 0, html_message); -} - -/** - * Wysyła wiadomość binarną przeznaczoną dla klienta. - * - * Wiadomości między klientami przesyła się np. w celu wywołania zwrotnego - * połączenia bezpośredniego. Funkcja zwraca losowy numer sekwencyjny, - * który można zignorować albo wykorzystać do potwierdzenia. - * - * \param sess Struktura sesji - * \param msgclass Klasa wiadomości - * \param recipient Numer adresata - * \param message Treść wiadomości - * \param message_len Długość wiadomości - * - * \return Numer sekwencyjny wiadomości lub -1 w przypadku błędu. - * - * \ingroup messages - */ -int gg_send_message_ctcp(struct gg_session *sess, int msgclass, uin_t recipient, - const unsigned char *message, int message_len) -{ - struct gg_send_msg s; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_send_message_ctcp(%p, " - "%d, %u, ...);\n", sess, msgclass, recipient); - - if (!sess) { - errno = EFAULT; - return -1; - } - - if (sess->state != GG_STATE_CONNECTED) { - errno = ENOTCONN; - return -1; - } - - s.recipient = gg_fix32(recipient); - s.seq = gg_fix32(0); - s.msgclass = gg_fix32(msgclass); - - return gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), message, message_len, NULL); -} - -/** - * Wysyła żądanie obrazka o podanych parametrach. - * - * Wiadomości obrazkowe nie zawierają samych obrazków, a tylko ich rozmiary - * i sumy kontrolne. Odbiorca najpierw szuka obrazków w swojej pamięci - * podręcznej i dopiero gdy ich nie znajdzie, wysyła żądanie do nadawcy. - * Wynik zostanie przekazany zdarzeniem \c GG_EVENT_IMAGE_REPLY. - * - * \param sess Struktura sesji - * \param recipient Numer adresata - * \param size Rozmiar obrazka w bajtach - * \param crc32 Suma kontrola obrazka - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup messages - */ -int gg_image_request(struct gg_session *sess, uin_t recipient, int size, uint32_t crc32) -{ - struct gg_send_msg s; - struct gg_msg_image_request r; - char dummy = 0; - int res; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_image_request(%p, %d, " - "%u, 0x%.4x);\n", sess, recipient, size, crc32); - - if (!sess) { - errno = EFAULT; - return -1; - } - - if (sess->state != GG_STATE_CONNECTED) { - errno = ENOTCONN; - return -1; - } - - if (size < 0) { - errno = EINVAL; - return -1; - } - - s.recipient = gg_fix32(recipient); - s.seq = gg_fix32(0); - s.msgclass = gg_fix32(GG_CLASS_MSG); - - r.flag = GG_MSG_OPTION_IMAGE_REQUEST; - r.size = gg_fix32(size); - r.crc32 = gg_fix32(crc32); - - res = gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), &dummy, 1, &r, sizeof(r), NULL); - - if (!res) { - struct gg_image_queue *q = malloc(sizeof(*q)); - char *buf; - - if (!q) { - gg_debug_session(sess, GG_DEBUG_MISC, - "// gg_image_request() not enough memory for " - "image queue\n"); - return -1; - } - - buf = malloc(size); - if (size && !buf) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_image_request() not enough memory for image\n"); - free(q); - return -1; - } - - memset(q, 0, sizeof(*q)); - - q->sender = recipient; - q->size = size; - q->crc32 = crc32; - q->image = buf; - - if (!sess->images) - sess->images = q; - else { - struct gg_image_queue *qq; - - for (qq = sess->images; qq->next; qq = qq->next); - - qq->next = q; - } - } - - return res; -} - -/** - * Wysyła żądany obrazek. - * - * \param sess Struktura sesji - * \param recipient Numer adresata - * \param filename Nazwa pliku - * \param image Bufor z obrazkiem - * \param size Rozmiar obrazka - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup messages - */ -int gg_image_reply(struct gg_session *sess, uin_t recipient, const char *filename, const char *image, int size) -{ - struct gg_session_private *p; - struct gg_msg_image_reply *r; - struct gg_send_msg s; - const char *tmp; - char buf[1910]; - gg_imgout_queue_t *queue = NULL, *queue_end = NULL; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_image_reply(%p, %d, " - "\"%s\", %p, %d);\n", sess, recipient, filename, image, size); - - if (!sess || !filename || !image) { - errno = EFAULT; - return -1; - } - - p = sess->private_data; - - if (sess->state != GG_STATE_CONNECTED) { - errno = ENOTCONN; - return -1; - } - - if (size < 0) { - errno = EINVAL; - return -1; - } - - /* wytnij ścieżki, zostaw tylko nazwę pliku */ - while ((tmp = strrchr(filename, '/')) || (tmp = strrchr(filename, '\\'))) - filename = tmp + 1; - - if (strlen(filename) < 1 || strlen(filename) > 1024) { - errno = EINVAL; - return -1; - } - - s.recipient = gg_fix32(recipient); - s.seq = gg_fix32(0); - s.msgclass = gg_fix32(GG_CLASS_MSG); - - buf[0] = 0; - r = (void*) &buf[1]; - - r->flag = GG_MSG_OPTION_IMAGE_REPLY; - r->size = gg_fix32(size); - r->crc32 = gg_fix32(gg_crc32(0, (const unsigned char*) image, size)); - - while (size > 0) { - gg_imgout_queue_t *it; - size_t buflen, chunklen; - - /* \0 + struct gg_msg_image_reply */ - buflen = sizeof(struct gg_msg_image_reply) + 1; - - /* w pierwszym kawałku jest nazwa pliku */ - if (r->flag == GG_MSG_OPTION_IMAGE_REPLY) { - strcpy(buf + buflen, filename); - buflen += strlen(filename) + 1; - } - - chunklen = ((size_t) size >= sizeof(buf) - buflen) ? (sizeof(buf) - buflen) : (size_t) size; - - memcpy(buf + buflen, image, chunklen); - size -= chunklen; - image += chunklen; - - it = gg_new0(sizeof(gg_imgout_queue_t)); - if (!it) - break; - if (queue_end) { - queue_end->next = it; - queue_end = it; - } else { - queue = queue_end = it; - } - - memcpy(&it->msg_hdr, &s, sizeof(s)); - memcpy(it->buf, buf, buflen + chunklen); - it->buf_len = buflen + chunklen; - - r->flag = GG_MSG_OPTION_IMAGE_REPLY_MORE; - } - - if (p->imgout_queue) { - queue_end = p->imgout_queue; - while (queue_end->next) - queue_end = queue_end->next; - queue_end->next = queue; - } else { - p->imgout_queue = queue; - } - gg_image_sendout(sess); - - return 0; -} - -void gg_image_sendout(struct gg_session *sess) -{ - struct gg_session_private *p = sess->private_data; - - while (p->imgout_waiting_ack < GG_IMGOUT_WAITING_MAX && p->imgout_queue) { - gg_imgout_queue_t *it = p->imgout_queue; - int res; - - p->imgout_queue = p->imgout_queue->next; - p->imgout_waiting_ack++; - - res = gg_send_packet(sess, GG_SEND_MSG, - &it->msg_hdr, sizeof(it->msg_hdr), - it->buf, it->buf_len, - NULL); - - free(it); - - if (res == -1) - break; - } -} - -static int gg_notify105_ex(struct gg_session *sess, uin_t *userlist, char *types, int count) -{ - int i = 0; - - if (!userlist || !count) - return gg_send_packet(sess, GG_NOTIFY105_LIST_EMPTY, NULL); - - while (i < count) { - gg_tvbuilder_t *tvb = gg_tvbuilder_new(sess, NULL); - gg_tvbuilder_expected_size(tvb, 2100); - - while (i < count) { - size_t prev_size = gg_tvbuilder_get_size(tvb); - gg_tvbuilder_write_uin(tvb, userlist[i]); - gg_tvbuilder_write_uint8(tvb, - (types == NULL) ? GG_USER_NORMAL : types[i]); - - /* Oryginalny klient wysyła maksymalnie 2048 bajtów - * danych w każdym pakiecie tego typu. - */ - if (gg_tvbuilder_get_size(tvb) > 2048) { - gg_tvbuilder_strip(tvb, prev_size); - break; - } - i++; - } - - if (!gg_tvbuilder_send(tvb, (i < count) ? - GG_NOTIFY105_FIRST : GG_NOTIFY105_LAST)) - { - return -1; - } - } - - return 0; -} - -/** - * Wysyła do serwera listę kontaktów. - * - * Funkcja informuje serwer o liście kontaktów, których statusy będą - * obserwowane lub kontaktów, które bedą blokowane. Dla każdego z \c count - * kontaktów tablica \c userlist zawiera numer, a tablica \c types rodzaj - * kontaktu (\c GG_USER_NORMAL, \c GG_USER_OFFLINE, \c GG_USER_BLOCKED). - * - * Listę kontaktów należy \b zawsze wysyłać po połączeniu, nawet jeśli - * jest pusta. - * - * \param sess Struktura sesji - * \param userlist Wskaźnik do tablicy numerów kontaktów - * \param types Wskaźnik do tablicy rodzajów kontaktów. Jeżeli NULL, wszystkie kontakty są typu GG_USER_NORMAL. - * \param count Liczba kontaktów - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup contacts - */ -int gg_notify_ex(struct gg_session *sess, uin_t *userlist, char *types, int count) -{ - struct gg_notify *n; - int i, res = 0; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_notify_ex(%p, %p, %p, %d);\n", sess, userlist, types, count); - - if (!sess) { - errno = EFAULT; - return -1; - } - - if (sess->state != GG_STATE_CONNECTED) { - errno = ENOTCONN; - return -1; - } - - if (sess->protocol_version >= GG_PROTOCOL_VERSION_110) - return gg_notify105_ex(sess, userlist, types, count); - - if (!userlist || !count) - return gg_send_packet(sess, GG_LIST_EMPTY, NULL); - - while (count > 0) { - int part_count, packet_type; - - if (count > 400) { - part_count = 400; - packet_type = GG_NOTIFY_FIRST; - } else { - part_count = count; - packet_type = GG_NOTIFY_LAST; - } - - if (!(n = (struct gg_notify*) malloc(sizeof(*n) * part_count))) - return -1; - - for (i = 0; i < part_count; i++) { - n[i].uin = gg_fix32(userlist[i]); - if (types == NULL) - n[i].dunno1 = GG_USER_NORMAL; - else - n[i].dunno1 = types[i]; - } - - if (gg_send_packet(sess, packet_type, n, sizeof(*n) * part_count, NULL) == -1) { - free(n); - res = -1; - break; - } - - count -= part_count; - userlist += part_count; - if (types != NULL) - types += part_count; - - free(n); - } - - return res; -} - -/** - * Wysyła do serwera listę kontaktów. - * - * Funkcja jest odpowiednikiem \c gg_notify_ex(), gdzie wszystkie kontakty - * są rodzaju \c GG_USER_NORMAL. - * - * \param sess Struktura sesji - * \param userlist Wskaźnik do tablicy numerów kontaktów - * \param count Liczba kontaktów - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup contacts - */ -int gg_notify(struct gg_session *sess, uin_t *userlist, int count) -{ - return gg_notify_ex(sess, userlist, NULL, count); -} - -/** - * Dodaje kontakt. - * - * Dodaje do listy kontaktów dany numer w trakcie połączenia. Aby zmienić - * rodzaj kontaktu (np. z normalnego na zablokowany), należy najpierw usunąć - * poprzedni rodzaj, ponieważ serwer operuje na maskach bitowych. - * - * \param sess Struktura sesji - * \param uin Numer kontaktu - * \param type Rodzaj kontaktu - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup contacts - */ -int gg_add_notify_ex(struct gg_session *sess, uin_t uin, char type) -{ - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_add_notify_ex(%p, %u, %d);\n", sess, uin, type); - - if (!sess) { - errno = EFAULT; - return -1; - } - - if (sess->state != GG_STATE_CONNECTED) { - errno = ENOTCONN; - return -1; - } - - if (sess->protocol_version >= GG_PROTOCOL_VERSION_110) { - gg_tvbuilder_t *tvb = gg_tvbuilder_new(sess, NULL); - gg_tvbuilder_expected_size(tvb, 16); - - gg_tvbuilder_write_uin(tvb, uin); - gg_tvbuilder_write_uint8(tvb, type); - - if (!gg_tvbuilder_send(tvb, GG_ADD_NOTIFY105)) - return -1; - return 0; - } else { - struct gg_add_remove a; - - a.uin = gg_fix32(uin); - a.dunno1 = type; - - return gg_send_packet(sess, GG_ADD_NOTIFY, &a, sizeof(a), NULL); - } -} - -/** - * Dodaje kontakt. - * - * Funkcja jest odpowiednikiem \c gg_add_notify_ex(), gdzie rodzaj wszystkich - * kontaktów to \c GG_USER_NORMAL. - * - * \param sess Struktura sesji - * \param uin Numer kontaktu - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup contacts - */ -int gg_add_notify(struct gg_session *sess, uin_t uin) -{ - return gg_add_notify_ex(sess, uin, GG_USER_NORMAL); -} - -/** - * Usuwa kontakt. - * - * Usuwa z listy kontaktów dany numer w trakcie połączenia. - * - * \param sess Struktura sesji - * \param uin Numer kontaktu - * \param type Rodzaj kontaktu - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup contacts - */ -int gg_remove_notify_ex(struct gg_session *sess, uin_t uin, char type) -{ - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_remove_notify_ex(%p, %u, %d);\n", sess, uin, type); - - if (!sess) { - errno = EFAULT; - return -1; - } - - if (sess->state != GG_STATE_CONNECTED) { - errno = ENOTCONN; - return -1; - } - - if (sess->protocol_version >= GG_PROTOCOL_VERSION_110) { - gg_tvbuilder_t *tvb = gg_tvbuilder_new(sess, NULL); - gg_tvbuilder_expected_size(tvb, 16); - - gg_tvbuilder_write_uin(tvb, uin); - gg_tvbuilder_write_uint8(tvb, type); - - if (!gg_tvbuilder_send(tvb, GG_REMOVE_NOTIFY105)) - return -1; - return 0; - } else { - struct gg_add_remove a; - - a.uin = gg_fix32(uin); - a.dunno1 = type; - - return gg_send_packet(sess, GG_REMOVE_NOTIFY, &a, sizeof(a), NULL); - } -} - -/** - * Usuwa kontakt. - * - * Funkcja jest odpowiednikiem \c gg_add_notify_ex(), gdzie rodzaj wszystkich - * kontaktów to \c GG_USER_NORMAL. - * - * \param sess Struktura sesji - * \param uin Numer kontaktu - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup contacts - */ -int gg_remove_notify(struct gg_session *sess, uin_t uin) -{ - return gg_remove_notify_ex(sess, uin, GG_USER_NORMAL); -} - -/** - * Wysyła do serwera zapytanie dotyczące listy kontaktów. - * - * Funkcja służy do importu lub eksportu listy kontaktów do serwera. - * W odróżnieniu od funkcji \c gg_notify(), ta lista kontaktów jest przez - * serwer jedynie przechowywana i nie ma wpływu na połączenie. Format - * listy kontaktów jest ignorowany przez serwer, ale ze względu na - * kompatybilność z innymi klientami, należy przechowywać dane w tym samym - * formacie co oryginalny klient Gadu-Gadu. - * - * Program nie musi się przejmować fragmentacją listy kontaktów wynikającą - * z protokołu -- wysyła i odbiera kompletną listę. - * - * \param sess Struktura sesji - * \param type Rodzaj zapytania - * \param request Treść zapytania (może być równe NULL) - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup importexport - */ -int gg_userlist_request(struct gg_session *sess, char type, const char *request) -{ - int len; - - if (!sess) { - errno = EFAULT; - return -1; - } - - if (sess->state != GG_STATE_CONNECTED) { - errno = ENOTCONN; - return -1; - } - - if (!request) { - sess->userlist_blocks = 1; - return gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), NULL); - } - - len = strlen(request); - - sess->userlist_blocks = 0; - - while (len > 2047) { - sess->userlist_blocks++; - - if (gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), request, 2047, NULL) == -1) - return -1; - - if (type == GG_USERLIST_PUT) - type = GG_USERLIST_PUT_MORE; - - request += 2047; - len -= 2047; - } - - sess->userlist_blocks++; - - return gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), request, len, NULL); -} - -/** - * Wysyła do serwera zapytanie dotyczące listy kontaktów (10.0). - * - * Funkcja służy do importu lub eksportu listy kontaktów do serwera. - * W odróżnieniu od funkcji \c gg_notify(), ta lista kontaktów jest przez - * serwer jedynie przechowywana i nie ma wpływu na połączenie. Format - * listy kontaktów jest jednak weryfikowany przez serwer, który stara się - * synchronizować listę kontaktów zapisaną w formatach GG 7.0 oraz GG 10.0. - * Serwer przyjmuje listy kontaktów przysłane w formacie niezgodnym z podanym - * jako \c format_type, ale nie zachowuje ich, a przesłanie takiej listy jest - * równoznaczne z usunięciem listy kontaktów. - * - * Program nie musi się przejmować kompresją listy kontaktów zgodną - * z protokołem -- wysyła i odbiera kompletną listę zapisaną czystym tekstem. - * - * \param sess Struktura sesji - * \param type Rodzaj zapytania - * \param version Numer ostatniej znanej programowi wersji listy kontaktów lub 0 - * \param format_type Typ formatu listy kontaktów - * \param request Treść zapytania (może być równe NULL) - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup importexport - */ -int gg_userlist100_request(struct gg_session *sess, char type, - unsigned int version, char format_type, const char *request) -{ - struct gg_userlist100_request pkt; - unsigned char *zrequest; - size_t zrequest_len; - int ret; - - if (!sess) { - errno = EFAULT; - return -1; - } - - if (sess->state != GG_STATE_CONNECTED) { - errno = ENOTCONN; - return -1; - } - - pkt.type = type; - pkt.version = gg_fix32(version); - pkt.format_type = format_type; - pkt.unknown1 = 0x01; - - if (request == NULL) - return gg_send_packet(sess, GG_USERLIST100_REQUEST, &pkt, sizeof(pkt), NULL); - - zrequest = gg_deflate(request, &zrequest_len); - - if (zrequest == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_userlist100_request() gg_deflate() failed\n"); - return -1; - } - - ret = gg_send_packet(sess, GG_USERLIST100_REQUEST, &pkt, sizeof(pkt), zrequest, zrequest_len, NULL); - - free(zrequest); - - return ret; -} - -/** - * Informuje rozmówcę o pisaniu wiadomości. - * - * \param sess Struktura sesji - * \param recipient Numer adresata - * \param length Długość wiadomości lub 0 jeśli jest pusta - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup messages - */ -int gg_typing_notification(struct gg_session *sess, uin_t recipient, int length){ - struct gg_typing_notification pkt; - uin_t uin; - - pkt.length = gg_fix16(length); - uin = gg_fix32(recipient); - memcpy(&pkt.uin, &uin, sizeof(uin_t)); - - return gg_send_packet(sess, GG_TYPING_NOTIFICATION, &pkt, sizeof(pkt), NULL); -} - -/** - * Rozłącza inną sesję multilogowania. - * - * \param gs Struktura sesji - * \param conn_id Sesja do rozłączenia - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup login - */ -int gg_multilogon_disconnect(struct gg_session *gs, gg_multilogon_id_t conn_id) -{ - struct gg_multilogon_disconnect pkt; - - pkt.conn_id = conn_id; - - return gg_send_packet(gs, GG_MULTILOGON_DISCONNECT, &pkt, sizeof(pkt), NULL); -} - -/** - * Tworzy nową konferencję (11.0). - * - * \param gs Struktura sesji - * - * \return Numer sekwencyjny (ten sam, co w \c gg_event_chat_created), lub -1 - * w przypadku błędu - * - * \ingroup chat - */ -int gg_chat_create(struct gg_session *gs) -{ - struct gg_chat_create pkt; - int seq; - - if (!gg_required_proto(gs, GG_PROTOCOL_VERSION_110)) - return -1; - - seq = ++gs->seq; - - pkt.seq = gg_fix32(seq); - pkt.dummy = 0; - - if (gg_send_packet(gs, GG_CHAT_CREATE, &pkt, sizeof(pkt), NULL) == -1) - return -1; - - return seq; -} - -/** - * Zaprasza nowych użytkowników do konferencji (11.0). - * - * \param gs Struktura sesji - * \param id Identyfikator konferencji - * \param participants Lista użytkowników do zaproszenia - * \param participants_count Liczba użytkowników - * - * \return Numer sekwencyjny w przypadku powodzenia (ten sam, co w - * \c gg_event_chat_invite_ack), lub -1 w przypadku błędu - * - * \ingroup chat - */ -int gg_chat_invite(struct gg_session *gs, uint64_t id, uin_t *participants, - unsigned int participants_count) -{ - struct gg_chat_invite pkt; - int seq, ret; - unsigned int i; - struct gg_chat_participant - { - uint32_t uin; - uint32_t dummy; - } GG_PACKED; - struct gg_chat_participant *participants_list; - size_t participants_list_size; - - if (!gg_required_proto(gs, GG_PROTOCOL_VERSION_110)) - return -1; - - if (participants_count == 0 || participants_count >= - ~(unsigned int)0 / sizeof(struct gg_chat_participant)) - { - return -1; - } - - participants_list_size = sizeof(struct gg_chat_participant) * - participants_count; - participants_list = malloc(participants_list_size); - if (participants_list == NULL) - return -1; - - seq = ++gs->seq; - pkt.id = gg_fix64(id); - pkt.seq = gg_fix32(seq); - pkt.participants_count = gg_fix32(participants_count); - - for (i = 0; i < participants_count; i++) { - participants_list[i].uin = gg_fix32(participants[i]); - participants_list[i].dummy = gg_fix32(0x1e); - } - - ret = gg_send_packet(gs, GG_CHAT_INVITE, - &pkt, sizeof(pkt), - participants_list, participants_list_size, - NULL); - free(participants_list); - - if (ret == -1) - return -1; - return seq; -} - -/** - * Opuszcza konferencję (11.0). - * - * \param gs Struktura sesji - * \param id Identyfikator konferencji - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup chat - */ -int gg_chat_leave(struct gg_session *gs, uint64_t id) -{ - struct gg_chat_leave pkt; - int seq; - - if (!gg_required_proto(gs, GG_PROTOCOL_VERSION_110)) - return -1; - - seq = ++gs->seq; - pkt.id = gg_fix64(id); - pkt.seq = gg_fix32(seq); - - if (gg_send_packet(gs, GG_CHAT_LEAVE, &pkt, sizeof(pkt), NULL) == -1) - return -1; - - return seq; -} - -/** - * Wysyła wiadomość w ramach konferencji (11.0). - * - * \param gs Struktura sesji - * \param id Identyfikator konferencji - * \param message Wiadomość - * \param is_html 1, jeżeli wiadomość jest zapisana jako HTML, 0 w p.p. - * - * \return Numer sekwencyjny (taki sam, jak w \c gg_event_chat_send_msg_ack) - * jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup chat - */ -int gg_chat_send_message(struct gg_session *gs, uint64_t id, const char *message, int is_html) -{ - if (!gg_required_proto(gs, GG_PROTOCOL_VERSION_110)) - return -1; - - return gg_send_message_110(gs, 0, id, message, is_html); -} - -/* @} */ - -/** - * Sprawdza czy biblioteka obsługuje daną funkcję. - * - * \param feature Identyfikator funkcji. - * - * \return Wartość niezerowa jeśli funkcja jest obsłgiwana. - * - * \ingroup version - */ -int gg_libgadu_check_feature(gg_libgadu_feature_t feature) -{ - switch (feature) - { - case GG_LIBGADU_FEATURE_SSL: -#if defined(GG_CONFIG_HAVE_OPENSSL) || defined(GG_CONFIG_HAVE_GNUTLS) - return 1; -#else - return 0; -#endif - - case GG_LIBGADU_FEATURE_PTHREAD: -#ifdef GG_CONFIG_HAVE_PTHREAD - return 1; -#else - return 0; -#endif - - case GG_LIBGADU_FEATURE_USERLIST100: -#ifdef GG_CONFIG_HAVE_ZLIB - return 1; -#else - return 0; -#endif - - /* Celowo nie ma default, żeby kompilator wyłapał brakujące funkcje */ - - } - - return 0; -} - -static void gg_socket_manager_error(struct gg_session *sess, enum gg_failure_t failure) -{ - int pipes[2]; - uint8_t dummy = 0; - struct gg_session_private *p = sess->private_data; - - p->socket_failure = failure; - - if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipes) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_socket_manager_error() unable to" - " create pipes (errno=%d, %s)\n", errno, - strerror(errno)); - return; - } - - p->socket_is_external = 0; - sess->fd = pipes[1]; - sess->check = GG_CHECK_READ; - sess->state = GG_STATE_ERROR; - if (send(pipes[0], &dummy, sizeof(dummy), 0) != sizeof(dummy)) { - gg_debug(GG_DEBUG_MISC, "// gg_socket_manager_error() unable to" - " send via pipe (errno=%d, %s)\n", errno, - strerror(errno)); - return; - } - close(pipes[0]); -} - -int gg_compat_feature_is_enabled(struct gg_session *sess, gg_compat_feature_t feature) -{ - gg_compat_t level; - - if (sess == NULL) - return 0; - - level = sess->private_data->compatibility; - - switch (feature) { - case GG_COMPAT_FEATURE_ACK_EVENT: - case GG_COMPAT_FEATURE_LEGACY_CONFER: - return (level < GG_COMPAT_1_12_0); - } - - return 0; -} - -static gg_msg_list_t * gg_compat_find_sent_message(struct gg_session *sess, int seq, int remove) -{ - struct gg_session_private *p = sess->private_data; - gg_msg_list_t *it, *previous = NULL; - - for (it = p->sent_messages; it; it = it->next) { - if (it->seq == seq) - break; - else - previous = it; - } - - if (remove && it) { - if (previous == NULL) - p->sent_messages = it->next; - else - previous->next = it->next; - } - - return it; -} - -static void gg_compat_message_cleanup(struct gg_session *sess) -{ - struct gg_session_private *p = sess->private_data; - - while (p->sent_messages) { - gg_msg_list_t *next = p->sent_messages->next; - free(p->sent_messages->recipients); - free(p->sent_messages); - p->sent_messages = next; - } -} - -static void gg_compat_message_sent(struct gg_session *sess, int seq, size_t recipients_count, uin_t *recipients) -{ - struct gg_session_private *p = sess->private_data; - gg_msg_list_t *sm; - uin_t *new_recipients; - size_t old_count, i; - - if (sess->protocol_version < GG_PROTOCOL_VERSION_110) - return; - - if (!gg_compat_feature_is_enabled(sess, GG_COMPAT_FEATURE_ACK_EVENT)) - return; - - sm = gg_compat_find_sent_message(sess, seq, 0); - if (!sm) { - sm = gg_new0(sizeof(gg_msg_list_t)); - if (!sm) - return; - sm->next = p->sent_messages; - p->sent_messages = sm; - } - - sm->seq = seq; - old_count = sm->recipients_count; - sm->recipients_count += recipients_count; - - new_recipients = realloc(sm->recipients, sizeof(uin_t) * sm->recipients_count); - if (new_recipients == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR, - "// gg_compat_message_sent() not enough memory\n"); - return; - } - sm->recipients = new_recipients; - - for (i = 0; i < recipients_count; i++) - sm->recipients[old_count + i] = recipients[i]; -} - -void gg_compat_message_ack(struct gg_session *sess, int seq) -{ - gg_msg_list_t *sm; - size_t i; - - if (sess->protocol_version < GG_PROTOCOL_VERSION_110) - return; - - if (!gg_compat_feature_is_enabled(sess, GG_COMPAT_FEATURE_ACK_EVENT)) - return; - - sm = gg_compat_find_sent_message(sess, seq, 1); - if (!sm) - return; - - for (i = 0; i < sm->recipients_count; i++) { - struct gg_event *qev; - - qev = gg_eventqueue_add(sess); - - qev->type = GG_EVENT_ACK; - qev->event.ack.status = GG_ACK_DELIVERED; - qev->event.ack.recipient = sm->recipients[i]; - qev->event.ack.seq = seq; - } - - free(sm->recipients); - free(sm); -} - -/** - * Odbiera nowo utworzone gniazdo TCP/TLS. - * - * Po wywołaniu tej funkcji należy zacząć obserwować deskryptor sesji (nawet - * w przypadku niepowodzenia). - * - * Jeżeli gniazdo nie zostanie obsłużone, należy je zniszczyć. - * - * \param handle Uchwyt gniazda - * \param priv Dane prywatne biblioteki libgadu - * \param fd Deskryptor nowo utworzonego gniazda, lub -1 w przypadku błędu - * - * \return Wartość różna od zera, jeżeli gniazdo zostało obsłużone, 0 w przeciwnym przypadku - * - * \ingroup socketmanager - */ -int gg_socket_manager_connected(void *handle, void *priv, int fd) -{ - struct gg_session *sess = priv; - struct gg_session_private *p = sess->private_data; - - if (p->socket_handle != handle) { - gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR, - "// gg_socket_manager_connected() invalid handle\n"); - return 0; - } - - sess->fd = -1; - - if (fd < 0) { - gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR, - "// gg_socket_manager_connected() connection error\n"); - p->socket_handle = NULL; - gg_socket_manager_error(sess, GG_FAILURE_CONNECTING); - return 0; - } - - if (p->socket_next_state == GG_STATE_TLS_NEGOTIATION) { - if (gg_session_init_ssl(sess) == -1) { - gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR, - "// gg_socket_manager_connected() couldn't " - "initialize ssl\n"); - p->socket_handle = NULL; - gg_socket_manager_error(sess, GG_FAILURE_TLS); - return 0; - } - } - - p->socket_is_external = 1; - sess->fd = fd; - sess->timeout = GG_DEFAULT_TIMEOUT; - sess->state = p->socket_next_state; - - gg_debug_session(sess, GG_DEBUG_MISC, "// next state=%s\n", - gg_debug_state(p->socket_next_state)); - - if (p->socket_next_state == GG_STATE_READING_KEY) - sess->check = GG_CHECK_READ; - else - sess->check = GG_CHECK_WRITE; - - return 1; -} - -/* - * Local variables: - * c-indentation-style: k&r - * c-basic-offset: 8 - * indent-tabs-mode: notnil - * End: - * - * vim: shiftwidth=8: - */
--- a/libpurple/protocols/gg/lib/libgadu.h Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2639 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2001-2009 Wojtek Kaniewski <wojtekka@irc.pl> - * Robert J. Woźny <speedy@ziew.org> - * Arkadiusz Miśkiewicz <arekm@pld-linux.org> - * Tomasz Chiliński <chilek@chilan.com> - * Piotr Wysocki <wysek@linux.bydg.org> - * Dawid Jarosz <dawjar@poczta.onet.pl> - * Jakub Zawadzki <darkjames@darkjames.ath.cx> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file libgadu.h - * - * \brief Główny plik nagłówkowy biblioteki - */ - -#ifndef LIBGADU_LIBGADU_H -#define LIBGADU_LIBGADU_H - -#ifdef _WIN32 -#pragma pack(push, 1) -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#include <sys/types.h> -#include <stdio.h> -#include <stdarg.h> - -/** \cond ignore */ - -/* Defined if libgadu was compiled for bigendian machine. */ -#undef GG_CONFIG_BIGENDIAN - -/* Defined if this machine has gethostbyname_r(). */ -#undef GG_CONFIG_HAVE_GETHOSTBYNAME_R - -/* Defined if libgadu was compiled and linked with fork support. */ -#undef GG_CONFIG_HAVE_FORK - -/* Defined if libgadu was compiled and linked with pthread support. */ -#undef GG_CONFIG_HAVE_PTHREAD - -/* Defined if pthread resolver is the default one. */ -#undef GG_CONFIG_PTHREAD_DEFAULT - -/* Defined if this machine has C99-compiliant vsnprintf(). */ -#undef GG_CONFIG_HAVE_C99_VSNPRINTF - -/* Defined if this machine has va_copy(). */ -#undef GG_CONFIG_HAVE_VA_COPY - -/* Defined if this machine has __va_copy(). */ -#undef GG_CONFIG_HAVE___VA_COPY - -/* Defined if this machine supports long long. */ -#undef GG_CONFIG_HAVE_LONG_LONG - -/* Defined if libgadu was compiled and linked with GnuTLS support. */ -#undef GG_CONFIG_HAVE_GNUTLS - -/* Defined if libgadu was compiled and linked with OpenSSL support. */ -#undef GG_CONFIG_HAVE_OPENSSL - -/* Defined if libgadu was compiled and linked with zlib support. */ -#undef GG_CONFIG_HAVE_ZLIB - -/* Defined if uintX_t types are defined in <stdint.h>. */ -#undef GG_CONFIG_HAVE_STDINT_H - -/* Defined if uintX_t types are defined in <inttypes.h>. */ -#undef GG_CONFIG_HAVE_INTTYPES_H - -/* Defined if uintX_t types are defined in <sys/inttypes.h>. */ -#undef GG_CONFIG_HAVE_SYS_INTTYPES_H - -/* Defined if uintX_t types are defined in <sys/int_types.h>. */ -#undef GG_CONFIG_HAVE_SYS_INT_TYPES_H - -/* Defined if uintX_t types are defined in <sys/types.h>. */ -#undef GG_CONFIG_HAVE_SYS_TYPES_H - -/* Defined if this machine has uint64_t. */ -#undef GG_CONFIG_HAVE_UINT64_T - -/* Defined if libgadu is GPL compliant (was not linked with OpenSSL or any - other non-GPL compliant library support). */ -#undef GG_CONFIG_IS_GPL_COMPLIANT - -#include "config.h" - -#ifdef GG_CONFIG_HAVE_OPENSSL -#include <openssl/ssl.h> -#endif - -#ifdef GG_CONFIG_HAVE_STDINT_H -#include <stdint.h> -#else -# ifdef GG_CONFIG_HAVE_INTTYPES_H -# include <inttypes.h> -# else -# ifdef GG_CONFIG_HAVE_SYS_INTTYPES_H -# include <sys/inttypes.h> -# else -# ifdef GG_CONFIG_HAVE_SYS_INT_TYPES_H -# include <sys/int_types.h> -# else -# ifdef GG_CONFIG_HAVE_SYS_TYPES_H -# include <sys/types.h> -# else - -/* ISO C 9X: 7.18 Integer types <stdint.h> */ - -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; - -# endif -# endif -# endif -# endif -#endif - -#ifndef GG_CONFIG_HAVE_UINT64_T -typedef unsigned long long uint64_t; -#endif - -#ifdef _MSC_VER -#include <BaseTsd.h> -typedef SSIZE_T ssize_t; -#endif - -#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)) -# define GG_GNUC_PRINTF(format_idx, arg_idx) \ - __attribute__((format (printf, (format_idx), (arg_idx)))) -#else -# define GG_GNUC_PRINTF(format_idx, arg_idx) -#endif - -/** \endcond */ - -/** - * Numer Gadu-Gadu. - */ -typedef uint32_t uin_t; - -/** - * Identyfikator połączenia bezpośredniego Gadu-Gadu 7.x. - */ -typedef struct { - uint8_t id[8]; -} gg_dcc7_id_t; - -/** - * Identyfikator sesji multilogowania. - */ -typedef struct { - uint8_t id[8]; -} gg_multilogon_id_t; - -/** - * Makro deklarujące pola wspólne dla struktur sesji. - */ -#define gg_common_head(x) \ - int fd; /**< Obserwowany deskryptor */ \ - int check; /**< Informacja o żądaniu odczytu/zapisu (patrz \ref gg_check_t) */ \ - int state; /**< Aktualny stan połączenia (patrz \ref gg_state_t) */ \ - int error; /**< Kod błędu dla \c GG_STATE_ERROR (patrz \ref gg_error_t) */ \ - int type; /**< Rodzaj sesji (patrz \ref gg_session_t) */ \ - int id; /**< Identyfikator sesji */ \ - int timeout; /**< Czas pozostały do zakończenia stanu */ \ - int (*callback)(x*); /**< Funkcja zwrotna */ \ - void (*destroy)(x*); /**< Funkcja zwalniania zasobów */ - -/** - * Struktura wspólna dla wszystkich sesji i połączeń. Pozwala na proste - * rzutowanie niezależne od rodzaju połączenia. - */ -struct gg_common { - gg_common_head(struct gg_common) -}; - -struct gg_image_queue; - -struct gg_dcc7; - -struct gg_dcc7_relay; - -struct gg_session_private; - -/** - * Sposób rozwiązywania nazw serwerów. - */ -typedef enum { - GG_RESOLVER_DEFAULT = 0, /**< Domyślny sposób rozwiązywania nazw (jeden z poniższych) */ - GG_RESOLVER_FORK, /**< Rozwiązywanie nazw bazujące na procesach */ - GG_RESOLVER_PTHREAD, /**< Rozwiązywanie nazw bazujące na wątkach */ - GG_RESOLVER_CUSTOM, /**< Funkcje rozwiązywania nazw dostarczone przed aplikację */ - GG_RESOLVER_WIN32, /**< Rozwiązywanie nazw bazujące na wątkach Win32 */ - GG_RESOLVER_INVALID = -1 /**< Nieprawidłowy sposób rozwiązywania nazw (wynik \c gg_session_get_resolver) */ -} gg_resolver_t; - -/** - * Rodzaj kodowania znaków. - */ -typedef enum { - GG_ENCODING_CP1250 = 0, /**< Kodowanie CP1250 */ - GG_ENCODING_UTF8, /**< Kodowanie UTF-8 */ - GG_ENCODING_INVALID = -1 /**< Nieprawidłowe kodowanie */ -} gg_encoding_t; - -/** - * Stopień kompatybilności ze starymi wersjami API. - */ -typedef enum { - GG_COMPAT_LEGACY = 0, /**< Całkowita kompatybilność (nie wyłącza żadnych funkcji) */ - GG_COMPAT_1_12_0 = 1 /**< Wyłącza: dostarczanie eventów GG_EVENT_ACK, stary format konferencji */ -} gg_compat_t; - -/** - * Flaga połączenia szyfrowanego. - * - * \ingroup login - */ -typedef enum { - GG_SSL_DISABLED = 0, /**< Połączenie SSL wyłączone */ - GG_SSL_ENABLED, /**< Połączenie SSL włączone gdy dostępne. Błędny certyfikat serwera nie powoduje odrzucenia połączenia. */ - GG_SSL_REQUIRED /**< Połączenie SSL wymagane. Błędny certyfikat serwera powoduje odrzucenie połączenia. */ -} gg_ssl_t; - -/** - * Sesja Gadu-Gadu. - * - * Tworzona przez funkcję \c gg_login(), zwalniana przez \c gg_free_session(). - * - * \ingroup login - */ -struct gg_session { - gg_common_head(struct gg_session) - - int async; /**< Flaga połączenia asynchronicznego */ - int pid; /**< Numer procesu rozwiązującego nazwę serwera */ - int port; /**< Port serwera */ - int seq; /**< Numer sekwencyjny ostatniej wiadomości */ - int last_pong; /**< Czas otrzymania ostatniej ramki utrzymaniowej */ - int last_event; /**< Czas otrzymania ostatniego pakietu */ - - struct gg_event *event; /**< Zdarzenie po wywołaniu \c callback */ - - uint32_t proxy_addr; /**< Adres serwera pośredniczącego */ - uint16_t proxy_port; /**< Port serwera pośredniczącego */ - - uint32_t hub_addr; /**< Adres huba po rozwiązaniu nazwy */ - uint32_t server_addr; /**< Adres serwera otrzymany od huba */ - - uint32_t client_addr; /**< Adres gniazda dla połączeń bezpośrednich */ - uint16_t client_port; /**< Port gniazda dla połączeń bezpośrednich */ - - uint32_t external_addr; /**< Publiczny adres dla połączeń bezpośrednich */ - uint16_t external_port; /**< Publiczny port dla połączeń bezpośrednich */ - - uin_t uin; /**< Własny numer Gadu-Gadu */ - char *password; /**< Hasło (zwalniane po użyciu) */ - - int initial_status; /**< Początkowy status */ - int status; /**< Aktualny status */ - - char *recv_buf; /**< Bufor na odbierane pakiety. Wskaźnik zawsze maksymalnie wyrównany, tak jak w wyniku działania \c malloc(). */ - int recv_done; /**< Liczba wczytanych bajtów pakietu */ - int recv_left; /**< Liczba pozostałych do wczytania bajtów pakietu */ - - int protocol_version; /**< Wersja protokołu (bez flag) */ - char *client_version; /**< Wersja klienta */ - int last_sysmsg; /**< Numer ostatniej wiadomości systemowej */ - - char *initial_descr; /**< Początkowy opis statusu */ - - void *resolver; /**< Dane prywatne procesu lub wątku rozwiązującego nazwę serwera */ - -#ifndef DOXYGEN - char *header_buf; /**< Bufor na początek nagłówka pakietu (nieaktualne) */ - unsigned int header_done; /**< Liczba wczytanych bajtów nagłówka pakietu (nieaktualne) */ -#endif - -#ifdef GG_CONFIG_HAVE_OPENSSL - SSL *ssl; /**< Struktura TLS */ - SSL_CTX *ssl_ctx; /**< Kontekst sesji TLS */ -#else - void *ssl; /**< Struktura TLS */ - void *ssl_ctx; /**< Kontekst sesji TLS */ -#endif - - int image_size; /**< Maksymalny rozmiar obsługiwanych obrazków w KiB */ - - char *userlist_reply; /**< Bufor z odbieraną listą kontaktów */ - - int userlist_blocks; /**< Liczba części listy kontaktów */ - - struct gg_image_queue *images; /**< Lista wczytywanych obrazków */ - - int hash_type; /**< Rodzaj funkcji skrótu hasła (\c GG_LOGIN_HASH_GG32 lub \c GG_LOGIN_HASH_SHA1) */ - - char *send_buf; /**< Bufor z danymi do wysłania */ - int send_left; /**< Liczba bajtów do wysłania */ - - struct gg_dcc7 *dcc7_list; /**< Lista połączeń bezpośrednich skojarzonych z sesją */ - - int soft_timeout; /**< Flaga mówiąca, że po przekroczeniu \c timeout należy wywołać \c gg_watch_fd() */ - - int protocol_flags; /**< Flagi protokołu */ - - gg_encoding_t encoding; /**< Rodzaj kodowania znaków */ - - gg_resolver_t resolver_type; /**< Sposób rozwiązywania nazw serwerów */ - int (*resolver_start)(int *fd, void **private_data, const char *hostname); /**< Funkcja rozpoczynająca rozwiązywanie nazwy */ - void (*resolver_cleanup)(void **private_data, int force); /**< Funkcja zwalniająca zasoby po rozwiązaniu nazwy */ - - int protocol_features; /**< Opcje protokołu */ - int status_flags; /**< Flagi statusu */ - int recv_msg_count; /**< Liczba odebranych wiadomości */ - - const char *resolver_host; /**< Nazwa do rozwiązania */ - struct in_addr *resolver_result; /**< Wynik rozwiązywania nazwy */ - unsigned int resolver_index; /**< Indeks aktualnie obsługiwanego wyniku rozwiązywania nazwy */ - unsigned int resolver_count; /**< Liczba wyników rozwiązywania nazwy */ - - uint16_t connect_port[2]; /**< Lista portów do połączenia */ - unsigned int connect_index; /**< Indeks aktualnie obsługiwanego portu */ - - char *connect_host; /**< Adres serwera Gadu-Gadu, z którym się łączymy */ - gg_ssl_t ssl_flag; /**< Flaga połączenia szyfrowanego */ - - struct gg_session_private *private_data; /**< Prywatne dane sesji, nie udostępnione w API */ -}; - -/** - * Połączenie HTTP. - * - * Tworzone przez \c gg_http_connect(), zwalniane przez \c gg_http_free(). - * - * \ingroup http - */ -struct gg_http { - gg_common_head(struct gg_http) - - int async; /**< Flaga połączenia asynchronicznego */ - int pid; /**< Identyfikator procesu rozwiązującego nazwę serwera */ - int port; /**< Port */ - - char *query; /**< Zapytanie HTTP */ - char *header; /**< Odebrany nagłówek */ - int header_size; /**< Rozmiar wczytanego nagłówka */ - char *body; /**< Odebrana strona */ - unsigned int body_size; /**< Rozmiar strony */ - - void *data; /**< Dane prywatne usługi HTTP */ - - char *user_data; /**< Dane prywatne użytkownika (nie są zwalniane) */ - - void *resolver; /**< Dane prywatne procesu lub wątku rozwiązującego nazwę */ - - unsigned int body_done; /**< Liczba odebranych bajtów strony */ - - gg_resolver_t resolver_type; /**< Sposób rozwiązywania nazw serwerów */ - int (*resolver_start)(int *fd, void **private_data, const char *hostname); /**< Funkcja rozpoczynająca rozwiązywanie nazwy */ - void (*resolver_cleanup)(void **private_data, int force); /**< Funkcja zwalniająca zasoby po rozwiązaniu nazwy */ -}; - -/** \cond ignore */ - -#ifdef __GNUC__ -#define GG_PACKED __attribute__ ((packed)) -#ifndef GG_IGNORE_DEPRECATED -#define GG_DEPRECATED __attribute__ ((deprecated)) -#else -#define GG_DEPRECATED -#endif -#else -#define GG_PACKED -#define GG_DEPRECATED -#endif - -/** \endcond */ - -#define GG_MAX_PATH 276 /**< Maksymalny rozmiar nazwy pliku w strukturze \c gg_file_info */ - -/** - * Odpowiednik struktury WIN32_FIND_DATA z API WIN32. - * - * Wykorzystywana przy połączeniach bezpośrednich do wersji Gadu-Gadu 6.x. - */ -struct gg_file_info { - uint32_t mode; /**< dwFileAttributes */ - uint32_t ctime[2]; /**< ftCreationTime */ - uint32_t atime[2]; /**< ftLastAccessTime */ - uint32_t mtime[2]; /**< ftLastWriteTime */ - uint32_t size_hi; /**< nFileSizeHigh */ - uint32_t size; /**< nFileSizeLow */ - uint32_t reserved0; /**< dwReserved0 */ - uint32_t reserved1; /**< dwReserved1 */ - unsigned char filename[GG_MAX_PATH - 14]; /**< cFileName */ - unsigned char short_filename[14]; /**< cAlternateFileName */ -} /** \cond ignore */ GG_PACKED /** \endcond */; - -/** - * Połączenie bezpośrednie do wersji Gadu-Gadu 6.x. - * - * Tworzone przez \c gg_dcc_socket_create(), \c gg_dcc_get_file(), - * \c gg_dcc_send_file() lub \c gg_dcc_voice_chat(), zwalniane przez - * \c gg_dcc_free(). - * - * \ingroup dcc6 - */ -struct gg_dcc { - gg_common_head(struct gg_dcc) - - struct gg_event *event; /**< Zdarzenie po wywołaniu \c callback */ - - int active; /**< Flaga połączenia aktywnego (nieużywana) */ - int port; /**< Port gniazda nasłuchującego */ - uin_t uin; /**< Własny numer Gadu-Gadu */ - uin_t peer_uin; /**< Numer Gadu-Gadu drugiej strony połączenia */ - int file_fd; /**< deskryptor pliku */ - unsigned int offset; /**< Położenie w pliku */ - unsigned int chunk_size; - /**< Rozmiar kawałka pliku */ - unsigned int chunk_offset; - /**< Położenie w aktualnym kawałku pliku */ - struct gg_file_info file_info; - /**< Informacje o pliku */ - int established; /**< Flaga ustanowienia połączenia */ - char *voice_buf; /**< Bufor na pakiet połączenia głosowego */ - int incoming; /**< Flaga połączenia przychodzącego */ - char *chunk_buf; /**< Bufor na fragment danych */ - uint32_t remote_addr; /**< Adres drugiej strony */ - uint16_t remote_port; /**< Port drugiej strony */ -}; - -#define GG_DCC7_HASH_LEN 20 /**< Maksymalny rozmiar skrótu pliku w połączeniach bezpośrenich */ -#define GG_DCC7_FILENAME_LEN 255 /**< Maksymalny rozmiar nazwy pliku w połączeniach bezpośrednich */ -#define GG_DCC7_INFO_LEN 32 /**< Maksymalny rozmiar informacji o połączeniach bezpośrednich */ -#define GG_DCC7_INFO_HASH_LEN 32 /**< Maksymalny rozmiar skrótu ip informacji o połączeniach bezpośrednich */ - -/** - * Połączenie bezpośrednie od wersji Gadu-Gadu 7.x. - * - * \ingroup dcc7 - */ -struct gg_dcc7 { - gg_common_head(struct gg_dcc7) - - gg_dcc7_id_t cid; /**< Identyfikator połączenia */ - - struct gg_event *event; /**< Struktura zdarzenia */ - - uin_t uin; /**< Własny numer Gadu-Gadu */ - uin_t peer_uin; /**< Numer Gadu-Gadu drugiej strony połączenia */ - - int file_fd; /**< Deskryptor przesyłanego pliku */ - unsigned int offset; /**< Aktualne położenie w przesyłanym pliku */ - unsigned int size; /**< Rozmiar przesyłanego pliku */ - unsigned char filename[GG_DCC7_FILENAME_LEN + 1]; - /**< Nazwa przesyłanego pliku */ - unsigned char hash[GG_DCC7_HASH_LEN]; - /**< Skrót SHA1 przesyłanego pliku */ - - int dcc_type; /**< Rodzaj połączenia bezpośredniego */ - int established; /**< Flaga ustanowienia połączenia */ - int incoming; /**< Flaga połączenia przychodzącego */ - int reverse; /**< Flaga połączenia zwrotnego */ - - uint32_t local_addr; /**< Adres lokalny */ - uint16_t local_port; /**< Port lokalny */ - - uint32_t remote_addr; /**< Adres drugiej strony */ - uint16_t remote_port; /**< Port drugiej strony */ - - struct gg_session *sess; - /**< Sesja do której przypisano połączenie */ - struct gg_dcc7 *next; /**< Następne połączenie w liście */ - - int soft_timeout; /**< Flaga mówiąca, że po przekroczeniu \c timeout należy wywołać \c gg_dcc7_watch_fd() */ - int seek; /**< Flaga mówiąca, że można zmieniać położenie w wysyłanym pliku */ - - void *resolver; /**< Dane prywatne procesu lub wątku rozwiązującego nazwę serwera */ - - int relay; /**< Flaga mówiąca, że laczymy sie przez serwer */ - int relay_index; /**< Numer serwera pośredniczącego, do którego się łączymy */ - int relay_count; /**< Rozmiar listy serwerów pośredniczących */ - struct gg_dcc7_relay *relay_list; /**< Lista serwerów pośredniczących */ -}; - -/** - * Rodzaj sesji. - */ -enum gg_session_t { - GG_SESSION_GG = 1, /**< Połączenie z serwerem Gadu-Gadu */ - GG_SESSION_HTTP, /**< Połączenie HTTP */ - GG_SESSION_SEARCH, /**< Wyszukiwanie w katalogu publicznym (nieaktualne) */ - GG_SESSION_REGISTER, /**< Rejestracja nowego konta */ - GG_SESSION_REMIND, /**< Przypominanie hasła */ - GG_SESSION_PASSWD, /**< Zmiana hasła */ - GG_SESSION_CHANGE, /**< Zmiana informacji w katalogu publicznym (nieaktualne) */ - GG_SESSION_DCC, /**< Połączenie bezpośrednie (do wersji 6.x) */ - GG_SESSION_DCC_SOCKET, /**< Gniazdo nasłuchujące (do wersji 6.x) */ - GG_SESSION_DCC_SEND, /**< Wysyłanie pliku (do wersji 6.x) */ - GG_SESSION_DCC_GET, /**< Odbieranie pliku (do wersji 6.x) */ - GG_SESSION_DCC_VOICE, /**< Rozmowa głosowa (do wersji 6.x) */ - GG_SESSION_USERLIST_GET, /**< Import listy kontaktów z serwera (nieaktualne) */ - GG_SESSION_USERLIST_PUT, /**< Eksport listy kontaktów do serwera (nieaktualne) */ - GG_SESSION_UNREGISTER, /**< Usuwanie konta */ - GG_SESSION_USERLIST_REMOVE, /**< Usuwanie listy kontaktów z serwera (nieaktualne) */ - GG_SESSION_TOKEN, /**< Pobieranie tokenu */ - GG_SESSION_DCC7_SOCKET, /**< Gniazdo nasłuchujące (od wersji 7.x) */ - GG_SESSION_DCC7_SEND, /**< Wysyłanie pliku (od wersji 7.x) */ - GG_SESSION_DCC7_GET, /**< Odbieranie pliku (od wersji 7.x) */ - GG_SESSION_DCC7_VOICE, /**< Rozmowa głosowa (od wersji 7.x) */ - - GG_SESSION_USER0 = 256, /**< Rodzaj zadeklarowany dla użytkownika */ - GG_SESSION_USER1, /**< Rodzaj zadeklarowany dla użytkownika */ - GG_SESSION_USER2, /**< Rodzaj zadeklarowany dla użytkownika */ - GG_SESSION_USER3, /**< Rodzaj zadeklarowany dla użytkownika */ - GG_SESSION_USER4, /**< Rodzaj zadeklarowany dla użytkownika */ - GG_SESSION_USER5, /**< Rodzaj zadeklarowany dla użytkownika */ - GG_SESSION_USER6, /**< Rodzaj zadeklarowany dla użytkownika */ - GG_SESSION_USER7 /**< Rodzaj zadeklarowany dla użytkownika */ -}; - -/** - * Aktualny stan sesji. - */ -enum gg_state_t { - /* wspólne */ - GG_STATE_IDLE = 0, /**< Nie dzieje się nic */ - GG_STATE_RESOLVING, /**< Oczekiwanie na rozwiązanie nazwy serwera */ - GG_STATE_CONNECTING, /**< Oczekiwanie na połączenie */ - GG_STATE_READING_DATA, /**< Oczekiwanie na dane */ - GG_STATE_ERROR, /**< Kod błędu w polu \c error */ - - /* gg_session */ - GG_STATE_CONNECTING_HUB, /**< Oczekiwanie na połączenie z hubem */ - GG_STATE_CONNECTING_GG, /**< Oczekiwanie na połączenie z serwerem */ - GG_STATE_READING_KEY, /**< Oczekiwanie na klucz */ - GG_STATE_READING_REPLY, /**< Oczekiwanie na odpowiedź serwera */ - GG_STATE_CONNECTED, /**< Połączono z serwerem */ - - /* gg_http */ - GG_STATE_SENDING_QUERY, /**< Wysłano zapytanie HTTP */ - GG_STATE_READING_HEADER, /**< Oczekiwanie na nagłówek HTTP */ - GG_STATE_PARSING, /**< Przetwarzanie danych */ - GG_STATE_DONE, /**< Połączenie zakończone */ - - /* gg_dcc */ - GG_STATE_LISTENING, /* czeka na połączenia */ - GG_STATE_READING_UIN_1, /* czeka na uin peera */ - GG_STATE_READING_UIN_2, /* czeka na swój uin */ - GG_STATE_SENDING_ACK, /* wysyła potwierdzenie dcc */ - GG_STATE_READING_ACK, /* czeka na potwierdzenie dcc */ - GG_STATE_READING_REQUEST, /* czeka na komendę */ - GG_STATE_SENDING_REQUEST, /* wysyła komendę */ - GG_STATE_SENDING_FILE_INFO, /* wysyła informacje o pliku */ - GG_STATE_READING_PRE_FILE_INFO, /* czeka na pakiet przed file_info */ - GG_STATE_READING_FILE_INFO, /* czeka na informacje o pliku */ - GG_STATE_SENDING_FILE_ACK, /* wysyła potwierdzenie pliku */ - GG_STATE_READING_FILE_ACK, /* czeka na potwierdzenie pliku */ - GG_STATE_SENDING_FILE_HEADER, /* wysyła nagłówek pliku */ - GG_STATE_READING_FILE_HEADER, /* czeka na nagłówek */ - GG_STATE_GETTING_FILE, /* odbiera plik */ - GG_STATE_SENDING_FILE, /* wysyła plik */ - GG_STATE_READING_VOICE_ACK, /* czeka na potwierdzenie voip */ - GG_STATE_READING_VOICE_HEADER, /* czeka na rodzaj bloku voip */ - GG_STATE_READING_VOICE_SIZE, /* czeka na rozmiar bloku voip */ - GG_STATE_READING_VOICE_DATA, /* czeka na dane voip */ - GG_STATE_SENDING_VOICE_ACK, /* wysyła potwierdzenie voip */ - GG_STATE_SENDING_VOICE_REQUEST, /* wysyła żądanie voip */ - GG_STATE_READING_TYPE, /* czeka na typ połączenia */ - - /* nowe. bez sensu jest to API. */ - GG_STATE_TLS_NEGOTIATION, /**< Negocjacja połączenia szyfrowanego */ - - GG_STATE_REQUESTING_ID, /**< Oczekiwanie na nadanie identyfikatora połączenia bezpośredniego */ - GG_STATE_WAITING_FOR_ACCEPT, /**< Oczekiwanie na potwierdzenie lub odrzucenie połączenia bezpośredniego */ - GG_STATE_WAITING_FOR_INFO, /**< Oczekiwanie na informacje o połączeniu bezpośrednim */ - - GG_STATE_READING_ID, /**< Odebranie identyfikatora połączenia bezpośredniego */ - GG_STATE_SENDING_ID, /**< Wysłano identyfikator połączenia bezpośredniego */ - GG_STATE_RESOLVING_GG, /**< Oczekiwanie na rozwiązanie nazwy serwera Gadu-Gadu */ - - GG_STATE_RESOLVING_RELAY, /**< Oczekiwanie na rozwiązanie nazwy serwera pośredniczącego */ - GG_STATE_CONNECTING_RELAY, /**< Oczekiwanie na połączenie z serwerem pośredniczącym */ - GG_STATE_READING_RELAY, /**< Odbieranie danych */ - - GG_STATE_DISCONNECTING, /**< Oczekiwanie na potwierdzenie rozłączenia */ - - GG_STATE_CONNECT_HUB, /**< Nawiązanie połączenia z hubem */ - GG_STATE_CONNECT_PROXY_HUB, - GG_STATE_CONNECT_GG, /**< Nawiązanie połączenia z serwerem */ - GG_STATE_CONNECT_PROXY_GG, - GG_STATE_CONNECTING_PROXY_HUB, - GG_STATE_CONNECTING_PROXY_GG, - GG_STATE_RESOLVE_HUB_SYNC, - GG_STATE_RESOLVE_HUB_ASYNC, - GG_STATE_RESOLVE_PROXY_HUB_SYNC, - GG_STATE_RESOLVE_PROXY_HUB_ASYNC, - GG_STATE_RESOLVE_PROXY_GG_SYNC, - GG_STATE_RESOLVE_PROXY_GG_ASYNC, - GG_STATE_RESOLVE_GG_SYNC, - GG_STATE_RESOLVE_GG_ASYNC, - GG_STATE_RESOLVING_HUB, - GG_STATE_RESOLVING_PROXY_HUB, - GG_STATE_RESOLVING_PROXY_GG, - GG_STATE_SEND_HUB, - GG_STATE_SEND_PROXY_HUB, - GG_STATE_SEND_PROXY_GG, - GG_STATE_SENDING_HUB, - GG_STATE_SENDING_PROXY_HUB, - GG_STATE_SENDING_PROXY_GG, - GG_STATE_READING_HUB, - GG_STATE_READING_PROXY_HUB, - GG_STATE_READING_PROXY_GG, -}; - -/** - * Informacja o tym, czy biblioteka chce zapisywać i/lub czytać - * z deskryptora. Maska bitowa. - * - * \ingroup events - */ -enum gg_check_t { - GG_CHECK_NONE = 0, /**< Nie sprawdzaj niczego */ - GG_CHECK_WRITE = 1, /**< Sprawdź możliwość zapisu */ - GG_CHECK_READ = 2 /**< Sprawdź możliwość odczytu */ -}; - -/** - * Metody nawiązywania połączeń TCP/TLS. - * - * \ingroup socketmanager - */ -typedef enum { - GG_SOCKET_MANAGER_TYPE_INTERNAL = 0, /**< Wewnętrzna obsługa gniazd (domyślne). */ - GG_SOCKET_MANAGER_TYPE_TCP, /**< Dostarczona przez aplikację - tylko obsługa TCP. */ - GG_SOCKET_MANAGER_TYPE_TLS /**< Dostarczona przez aplikację - obsługa zarówno TCP, jak i TLS. */ -} gg_socket_manager_type_t; - -/** - * Funkcja dostarczona przez aplikację, tworząca nowe gniazdo TCP/TLS. - * - * Po nawiązaniu połączenia aplikacja musi wywołać gg_socket_manager_connected. - * Jeżeli połączenie jest asynchroniczne, wywołanie musi nastąpić po wyjściu z - * kontekstu tej funkcji. Dla połączeń synchronicznych z kolei, musi nastąpić - * jeszcze przed wyjściem z kontekstu. - * - * \param cb_data Dane prywatne aplikacji - * \param host Nazwa hosta - * \param port Numer portu - * \param is_tls Flaga określająca, czy ma zostać nawiązane połączenie TLS - * \param is_async Flaga określająca połączenie asynchroniczne (patrz szczegóły powyżej) - * \param priv Dane prywatne biblioteki libgadu (do przekazania do gg_socket_manager_connected) - * - * \return Uchwyt gniazda - * - * \ingroup socketmanager - */ -typedef void* (*gg_socket_manager_connect_cb_t)(void *cb_data, const char *host, int port, int is_tls, int is_async, void *priv); - -/** - * Niszczy gniazdo i zwalnia wszystkie powiązane z nim zasoby. - * - * \param cb_data Dane prywatne aplikacji - * \param handle Uchwyt gniazda - * - * \ingroup socketmanager - */ -typedef void (*gg_socket_manager_close_cb_t)(void *cb_data, void *handle); - -/** - * Odbiera z gniazda dane binarne. - * - * Funkcja powinna zajmować się obsługą TLS, jeżeli gniazdo jest w takim trybie. - * - * \param cb_data Dane prywatne aplikacji - * \param handle Uchwyt gniazda - * \param buffer Bufor do zapisu danych - * \param bufsize Rozmiar bufora - * - * \return Ilość zapisanych danych, lub -1 (oraz ustawiony errno) w przypadku niepowodzenia - * - * \ingroup socketmanager - */ -typedef ssize_t (*gg_socket_manager_read_cb_t)(void *cb_data, void *handle, unsigned char *buffer, size_t bufsize); - -/** - * Wysyła przez gniazdo dane binarne. - * - * Funkcja powinna zajmować się obsługą TLS, jeżeli gniazdo jest w takim trybie. - * - * \param cb_data Dane prywatne aplikacji - * \param handle Uchwyt gniazda - * \param data Dane do wysłania - * \param length Rozmiar danych - * - * \return Ilość wysłanych danych, lub -1 (oraz ustawiony errno) w przypadku niepowodzenia - * - * \ingroup socketmanager - */ -typedef ssize_t (*gg_socket_manager_write_cb_t)(void *cb_data, void *handle, const unsigned char *data, size_t length); - -/** - * Struktura opisująca funkcje zarządzające gniazdami, jeżeli aplikacja sama je - * obsługuje. - * - * \ingroup socketmanager - */ -typedef struct { - void *cb_data; /**< Dane prywatne aplikacji */ - gg_socket_manager_connect_cb_t connect_cb; /**< Funkcja tworząca nowe gniazdo */ - gg_socket_manager_close_cb_t close_cb; /**< Funkcja niszcząca gniazdo */ - gg_socket_manager_read_cb_t read_cb; /**< Funkcja odczytująca dane z gniazda */ - gg_socket_manager_write_cb_t write_cb; /**< Funkcja wysyłająca dane przez gniazdo */ -#ifndef DOXYGEN - void *reserved1; - void *reserved2; - void *reserved3; - void *reserved4; -#endif -} gg_socket_manager_t; - -int gg_socket_manager_connected(void *handle, void *priv, int fd); - -/** - * Parametry połączenia z serwerem Gadu-Gadu. Parametry zostały przeniesione - * do struktury, by uniknąć zmian API po rozszerzeniu protokołu i dodaniu - * kolejnych opcji połączenia. Część parametrów, które nie są już aktualne - * lub nie mają znaczenia, została usunięta z dokumentacji. - * - * \ingroup login - */ -struct gg_login_params { - uin_t uin; /**< Numer Gadu-Gadu */ - char *password; /**< Hasło */ - int async; /**< Flaga asynchronicznego połączenia (domyślnie nie) */ - int status; /**< Początkowy status użytkownika (domyślnie \c GG_STATUS_AVAIL) */ - char *status_descr; /**< Początkowy opis użytkownika (domyślnie brak) */ - uint32_t server_addr; /**< Adres serwera Gadu-Gadu (domyślnie pobierany automatycznie) */ - uint16_t server_port; /**< Port serwera Gadu-Gadu (domyślnie pobierany automatycznie) */ - uint32_t client_addr; /**< Adres połączeń bezpośrednich (domyślnie dobierany automatycznie) */ - uint16_t client_port; /**< Port połączeń bezpośrednich (domyślnie dobierany automatycznie) */ - int protocol_version; /**< Wersja protokołu wysyłana do serwera (domyślnie najnowsza obsługiwana) */ - char *client_version; /**< Wersja klienta wysyłana do serwera (domyślnie najnowsza znana) */ - int has_audio; /**< Flaga obsługi połączeń głosowych */ - int last_sysmsg; /**< Numer ostatnio odebranej wiadomości systemowej */ - uint32_t external_addr; /**< Adres publiczny dla połączeń bezpośrednich (domyślnie dobierany automatycznie) */ - uint16_t external_port; /**< Port publiczny dla połączeń bezpośrednich (domyślnie dobierany automatycznie) */ - int tls; /**< Flaga połączenia szyfrowanego (patrz \ref gg_ssl_t) */ - int image_size; /**< Maksymalny rozmiar obsługiwanych obrazków w kilobajtach */ -#ifndef DOXYGEN - int era_omnix; /**< Flaga udawania klienta Era Omnix (nieaktualna) */ -#endif - int hash_type; /**< Rodzaj skrótu hasła (\c GG_LOGIN_HASH_GG32 lub \c GG_LOGIN_HASH_SHA1, domyślnie SHA1) */ - gg_encoding_t encoding; /**< Rodzaj kodowania używanego w sesji (domyślnie CP1250) */ - gg_resolver_t resolver; /**< Sposób rozwiązywania nazw (patrz \ref build-resolver) */ - int protocol_features; /**< Opcje protokołu (flagi GG_FEATURE_*). */ - int status_flags; /**< Flagi statusu (flagi GG_STATUS_FLAG_*, patrz \ref status). */ - - unsigned int struct_size; /**< Rozmiar struktury. To pole powinno być inicjowane wartością sizeof(struct gg_login_params) - w przeciwnym przypadku pola za nim nie będą obsługiwane. Pozwala na rozszerzanie struktury bez łamania ABI. */ - - gg_compat_t compatibility; /**< Stopień kompatybilności ze starym API. */ - - char *connect_host; /**< Nazwa hosta (oraz opcjonalnie port, podany po dwukropku) serwera Gadu-Gadu (domyślnie pobierany automatycznie) (patrz pole struct_size). */ - - gg_socket_manager_type_t socket_manager_type; /**< Wybrana metoda nawiązywania połączeń TCP/TLS (domyślnie wewnętrzna) */ - gg_socket_manager_t socket_manager; /**< Jeżeli wybrano metodę zewnętrzną - konfiguracja jej */ - - char **host_white_list; /**< Lista zakończona wskaźnikiem NULL, domen akceptowanych w odpowiedziach od huba (domyślnie wszystkie do tej pory znane). Używane tylko przy GG_SSL_REQUIRED. Pusta lista wyłącza sprawdzanie. */ -}; - -#ifdef GG_CONFIG_IS_GPL_COMPLIANT -int gg_is_gpl_compliant(void); -#endif -struct gg_session *gg_login(const struct gg_login_params *p); -void gg_free_session(struct gg_session *sess); -void gg_logoff(struct gg_session *sess); -int gg_change_status(struct gg_session *sess, int status); -int gg_change_status_descr(struct gg_session *sess, int status, const char *descr); -int gg_change_status_descr_time(struct gg_session *sess, int status, const char *descr, int time); -int gg_change_status_flags(struct gg_session *sess, int flags); -int gg_send_message(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message); -int gg_send_message_richtext(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message, const unsigned char *format, int formatlen); -int gg_send_message_html(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *html_message); -int gg_send_message_confer(struct gg_session *sess, int msgclass, int recipients_count, uin_t *recipients, const unsigned char *message); -int gg_send_message_confer_richtext(struct gg_session *sess, int msgclass, int recipients_count, uin_t *recipients, const unsigned char *message, const unsigned char *format, int formatlen); -int gg_send_message_confer_html(struct gg_session *sess, int msgclass, int recipients_count, uin_t *recipients, const unsigned char *html_message); -int gg_send_message_ctcp(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message, int message_len); -int gg_ping(struct gg_session *sess); -int gg_userlist_request(struct gg_session *sess, char type, const char *request); -int gg_userlist100_request(struct gg_session *sess, char type, unsigned int version, char format_type, const char *request); -int gg_image_request(struct gg_session *sess, uin_t recipient, int size, uint32_t crc32); -int gg_image_reply(struct gg_session *sess, uin_t recipient, const char *filename, const char *image, int size); -int gg_typing_notification(struct gg_session *sess, uin_t recipient, int length); - -uint32_t gg_crc32(uint32_t crc, const unsigned char *buf, int len); - -int gg_session_set_resolver(struct gg_session *gs, gg_resolver_t type); -gg_resolver_t gg_session_get_resolver(struct gg_session *gs); -int gg_session_set_custom_resolver(struct gg_session *gs, int (*resolver_start)(int*, void**, const char*), void (*resolver_cleanup)(void**, int)); - -int gg_http_set_resolver(struct gg_http *gh, gg_resolver_t type); -gg_resolver_t gg_http_get_resolver(struct gg_http *gh); -int gg_http_set_custom_resolver(struct gg_http *gh, int (*resolver_start)(int*, void**, const char*), void (*resolver_cleanup)(void**, int)); - -int gg_global_set_resolver(gg_resolver_t type); -gg_resolver_t gg_global_get_resolver(void); -int gg_global_set_custom_resolver(int (*resolver_start)(int*, void**, const char*), void (*resolver_cleanup)(void**, int)); - -int gg_multilogon_disconnect(struct gg_session *gs, gg_multilogon_id_t conn_id); - -int gg_chat_create(struct gg_session *gs); -int gg_chat_invite(struct gg_session *gs, uint64_t id, uin_t *participants, unsigned int participants_count); -int gg_chat_leave(struct gg_session *gs, uint64_t id); -int gg_chat_send_message(struct gg_session *gs, uint64_t id, const char *message, int is_html); - -/** - * Rodzaj zdarzenia. - * - * \ingroup events - */ -enum gg_event_t { - GG_EVENT_NONE = 0, /**< Nie wydarzyło się nic wartego uwagi */ - GG_EVENT_MSG, /**< \brief Otrzymano wiadomość. Przekazuje również wiadomości systemowe od numeru 0. */ - GG_EVENT_NOTIFY, /**< \brief Informacja o statusach osób z listy kontaktów (przed 6.0). Zdarzenie należy obsługiwać, jeśli planuje się używać protokołu w wersji starszej niż domyślna. Ostatni element tablicy zawiera uin równy 0, a pozostałe pola są niezainicjowane. */ - GG_EVENT_NOTIFY_DESCR, /**< \brief Informacja o statusie opisowym osoby z listy kontaktów (przed 6.0). Zdarzenie należy obsługiwać, jeśli planuje się używać protokołu w wersji starszej niż domyślna. */ - GG_EVENT_STATUS, /**< \brief Zmiana statusu osoby z listy kontaktów (przed 6.0). Zdarzenie należy obsługiwać, jeśli planuje się używać protokołu w wersji starszej niż domyślna. */ - GG_EVENT_ACK, /**< Potwierdzenie doręczenia wiadomości */ - GG_EVENT_PONG, /**< \brief Utrzymanie połączenia. Obecnie serwer nie wysyła już do klienta ramek utrzymania połączenia, polega wyłącznie na wysyłaniu ramek przez klienta. */ - GG_EVENT_CONN_FAILED, /**< \brief Nie udało się połączyć */ - GG_EVENT_CONN_SUCCESS, /**< \brief Połączono z serwerem. Pierwszą rzeczą, jaką należy zrobić jest wysłanie listy kontaktów. */ - GG_EVENT_DISCONNECT, /**< \brief Serwer zrywa połączenie. Zdarza się, gdy równolegle do serwera podłączy się druga sesja i trzeba zerwać połączenie z pierwszą. */ - - GG_EVENT_DCC_NEW, /**< Nowe połączenie bezpośrednie (6.x) */ - GG_EVENT_DCC_ERROR, /**< Błąd połączenia bezpośredniego (6.x) */ - GG_EVENT_DCC_DONE, /**< Zakończono połączenie bezpośrednie (6.x) */ - GG_EVENT_DCC_CLIENT_ACCEPT, /**< Moment akceptacji klienta w połączeniu bezpośrednim (6.x) */ - GG_EVENT_DCC_CALLBACK, /**< Zwrotne połączenie bezpośrednie (6.x) */ - GG_EVENT_DCC_NEED_FILE_INFO, /**< Należy wypełnić \c file_info dla połączenia bezpośredniego (6.x) */ - GG_EVENT_DCC_NEED_FILE_ACK, /**< Czeka na potwierdzenie pliku w połączeniu bezpośrednim (6.x) */ - GG_EVENT_DCC_NEED_VOICE_ACK, /**< Czeka na potwierdzenie rozmowy w połączeniu bezpośrednim (6.x) */ - GG_EVENT_DCC_VOICE_DATA, /**< Dane bezpośredniego połączenia głosowego (6.x) */ - - GG_EVENT_PUBDIR50_SEARCH_REPLY, /**< Odpowiedź katalogu publicznego */ - GG_EVENT_PUBDIR50_READ, /**< Odczytano własne dane z katalogu publicznego */ - GG_EVENT_PUBDIR50_WRITE, /**< Zmieniono własne dane w katalogu publicznym */ - - GG_EVENT_STATUS60, /**< Zmiana statusu osoby z listy kontaktów */ - GG_EVENT_NOTIFY60, /**< Informacja o statusach osób z listy kontaktów. Ostatni element tablicy zawiera uin równy 0, a pozostałe pola są niezainicjowane. */ - GG_EVENT_USERLIST, /**< Wynik importu lub eksportu listy kontaktów */ - GG_EVENT_IMAGE_REQUEST, /**< Żądanie przesłania obrazka z wiadomości */ - GG_EVENT_IMAGE_REPLY, /**< Przysłano obrazek z wiadomości */ - GG_EVENT_DCC_ACK, /**< Potwierdzenie transmisji w połączeniu bezpośrednim (6.x) */ - - GG_EVENT_DCC7_NEW, /**< Nowe połączenie bezpośrednie (7.x) */ - GG_EVENT_DCC7_ACCEPT, /**< Zaakceptowano połączenie bezpośrednie (7.x), nowy deskryptor */ - GG_EVENT_DCC7_REJECT, /**< Odrzucono połączenie bezpośrednie (7.x) */ - GG_EVENT_DCC7_CONNECTED, /**< Zestawiono połączenie bezpośrednie (7.x), nowy deskryptor */ - GG_EVENT_DCC7_ERROR, /**< Błąd połączenia bezpośredniego (7.x) */ - GG_EVENT_DCC7_DONE, /**< Zakończono połączenie bezpośrednie (7.x) */ - GG_EVENT_DCC7_PENDING, /**< Trwa próba połączenia bezpośredniego (7.x), nowy deskryptor */ - - GG_EVENT_XML_EVENT, /**< Otrzymano komunikat systemowy (7.7) */ - GG_EVENT_DISCONNECT_ACK, /**< \brief Potwierdzenie zakończenia sesji. Informuje o tym, że zmiana stanu na niedostępny z opisem dotarła do serwera i można zakończyć połączenie TCP. */ - GG_EVENT_TYPING_NOTIFICATION, /**< Powiadomienie o pisaniu */ - GG_EVENT_USER_DATA, /**< Informacja o kontaktach */ - GG_EVENT_MULTILOGON_MSG, /**< Wiadomość wysłana z innej sesji multilogowania */ - GG_EVENT_MULTILOGON_INFO, /**< Informacja o innych sesjach multilogowania */ - - GG_EVENT_USERLIST100_VERSION, /**< Otrzymano numer wersji listy kontaktów na serwerze (10.0) */ - GG_EVENT_USERLIST100_REPLY, /**< Wynik importu lub eksportu listy kontaktów (10.0) */ - - GG_EVENT_IMTOKEN, /**< Otrzymano ciąg IMTOKEN (11.0) */ - GG_EVENT_PONG110, /**< \brief Utrzymanie połączenia (11.0). Może służyć do synchronizacji czasu z serwerem. */ - GG_EVENT_JSON_EVENT, /**< Otrzymano komunikat systemowy (11.0) */ - GG_EVENT_ACK110, /**< Potwierdzenie wysłania wiadomości (11.0) */ - - GG_EVENT_CHAT_INFO, /**< Otrzymano informację o konferencji (11.0). */ - GG_EVENT_CHAT_INFO_GOT_ALL, /**< \brief Informacje o wszystkich konferencjach zostały już wysłane (11.0). Otrzymywany po ostatnim pakiecie \c GG_EVENT_CHAT_INFO */ - GG_EVENT_CHAT_INFO_UPDATE, /**< \brief Aktualizacja informacji o konferencji (11.0). Dodanie, usunięcie jednego z uczestników. */ - GG_EVENT_CHAT_CREATED, /**< Potwierdzenie utworzenia konferencji (11.0) */ - GG_EVENT_CHAT_INVITE_ACK, /**< Potwierdzenie wysłania zaproszenia do konferencji (11.0) */ -}; - -#define GG_EVENT_SEARCH50_REPLY GG_EVENT_PUBDIR50_SEARCH_REPLY - -/** - * Powód nieudanego połączenia. - */ -enum gg_failure_t { - GG_FAILURE_RESOLVING = 1, /**< Nie znaleziono serwera */ - GG_FAILURE_CONNECTING, /**< Błąd połączenia */ - GG_FAILURE_INVALID, /**< Serwer zwrócił nieprawidłowe dane */ - GG_FAILURE_READING, /**< Zerwano połączenie podczas odczytu */ - GG_FAILURE_WRITING, /**< Zerwano połączenie podczas zapisu */ - GG_FAILURE_PASSWORD, /**< Nieprawidłowe hasło */ - GG_FAILURE_404, /**< Nieużywane */ - GG_FAILURE_TLS, /**< Błąd negocjacji szyfrowanego połączenia */ - GG_FAILURE_NEED_EMAIL, /**< Serwer rozłączył nas z prośbą o zmianę adresu e-mail */ - GG_FAILURE_INTRUDER, /**< Zbyt wiele prób połączenia z nieprawidłowym hasłem */ - GG_FAILURE_UNAVAILABLE, /**< Serwery są wyłączone */ - GG_FAILURE_PROXY, /**< Błąd serwera pośredniczącego */ - GG_FAILURE_HUB, /**< Błąd połączenia z hubem */ - GG_FAILURE_INTERNAL, /**< Błąd wewnętrzny */ -}; - -/** - * Kod błędu danej operacji. - * - * Nie zawiera przesadnie szczegółowych informacji o powodach błędów, by nie - * komplikować ich obsługi. Jeśli wymagana jest większa dokładność, należy - * sprawdzić zawartość zmiennej systemowej \c errno. - */ -enum gg_error_t { - GG_ERROR_RESOLVING = 1, /**< Nie znaleziono hosta */ - GG_ERROR_CONNECTING, /**< Błąd połączenia */ - GG_ERROR_READING, /**< Błąd odczytu/odbierania */ - GG_ERROR_WRITING, /**< Błąd zapisu/wysyłania */ - - GG_ERROR_DCC_HANDSHAKE, /**< Błąd negocjacji */ - GG_ERROR_DCC_FILE, /**< Błąd odczytu/zapisu pliku */ - GG_ERROR_DCC_EOF, /**< Przedwczesny koniec pliku */ - GG_ERROR_DCC_NET, /**< Błąd wysyłania/odbierania */ - GG_ERROR_DCC_REFUSED, /**< Połączenie odrzucone */ - - GG_ERROR_DCC7_HANDSHAKE, /**< Błąd negocjacji */ - GG_ERROR_DCC7_FILE, /**< Błąd odczytu/zapisu pliku */ - GG_ERROR_DCC7_EOF, /**< Przedwczesny koniec pliku */ - GG_ERROR_DCC7_NET, /**< Błąd wysyłania/odbierania */ - GG_ERROR_DCC7_REFUSED, /**< Połączenie odrzucone */ - GG_ERROR_DCC7_RELAY, /**< Problem z serwerem pośredniczącym */ -}; - -/** - * Pole zapytania lub odpowiedzi katalogu publicznego. - */ -struct gg_pubdir50_entry { - int num; /**< Numer wyniku */ - char *field; /**< Nazwa pola */ - char *value; /**< Wartość pola */ -} /* GG_DEPRECATED */; - -/** - * Zapytanie lub odpowiedź katalogu publicznego. - * - * Patrz \c gg_pubdir50_t. - */ -struct gg_pubdir50_s { - int count; /**< Liczba wyników odpowiedzi */ - uin_t next; /**< Numer początkowy następnego zapytania */ - int type; /**< Rodzaj zapytania */ - uint32_t seq; /**< Numer sekwencyjny */ - struct gg_pubdir50_entry *entries; /**< Pola zapytania lub odpowiedzi */ - int entries_count; /**< Liczba pól */ -} /* GG_DEPRECATED */; - -/** - * Zapytanie lub odpowiedź katalogu publicznego. - * - * Do pól nie należy się odwoływać bezpośrednio -- wszystkie niezbędne - * informacje są dostępne za pomocą funkcji \c gg_pubdir50_* - */ -typedef struct gg_pubdir50_s *gg_pubdir50_t; - -/** - * Opis zdarzeń \c GG_EVENT_MSG i \c GG_EVENT_MULTILOGON_MSG. - */ -struct gg_event_msg { - uin_t sender; /**< Numer nadawcy/odbiorcy */ - int msgclass; /**< Klasa wiadomości */ -#ifndef _WIN32 - time_t time; /**< Czas nadania */ -#else - uint32_t time; /**< Czas nadania */ -#endif - unsigned char *message; /**< Treść wiadomości */ - - int recipients_count; /**< Liczba odbiorców konferencji */ - uin_t *recipients; /**< Odbiorcy konferencji */ - - int formats_length; /**< Długość informacji o formatowaniu tekstu */ - void *formats; /**< Informacje o formatowaniu tekstu */ - uint32_t seq; /**< Numer sekwencyjny wiadomości */ - - char *xhtml_message; /**< Treść wiadomości w formacie XHTML */ - - uint64_t chat_id; /**< Identyfikator konferencji lub 0, jeżeli jest to zwykła wiadomość (11.0) */ - uint64_t flags; /**< Flagi wiadomości (11.0) */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_NOTIFY_DESCR. - */ -struct gg_event_notify_descr { - struct gg_notify_reply *notify; /**< Informacje o liście kontaktów */ - char *descr; /**< Opis status */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_STATUS. - */ -struct gg_event_status { - uin_t uin; /**< Numer Gadu-Gadu */ - uint32_t status; /**< Nowy status */ - char *descr; /**< Opis */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_STATUS60. - */ -struct gg_event_status60 { - uin_t uin; /**< Numer Gadu-Gadu */ - int status; /**< Nowy status */ - uint32_t remote_ip; /**< Adres IP dla połączeń bezpośrednich */ - uint16_t remote_port; /**< Port dla połączeń bezpośrednich */ - int version; /**< Wersja protokołu */ - int image_size; /**< Maksymalny rozmiar obsługiwanych obrazków w KiB */ - char *descr; /**< Opis statusu */ -#ifndef _WIN32 - time_t time; /**< Czas powrotu */ -#else - uint32_t time; /**< Czas powrotu */ -#endif -}; - -/** - * Opis zdarzenia \c GG_EVENT_NOTIFY_REPLY60. - */ -struct gg_event_notify60 { - uin_t uin; /**< Numer Gadu-Gadu. W ostatnim elemencie jest równy 0, a pozostałe pola są niezainicjowane. */ - int status; /**< Nowy status */ - uint32_t remote_ip; /**< Adres IP dla połączeń bezpośrednich */ - uint16_t remote_port; /**< Port dla połączeń bezpośrednich */ - int version; /**< Wersja protokołu */ - int image_size; /**< Maksymalny rozmiar obsługiwanych obrazków w KiB */ - char *descr; /**< Opis statusu */ -#ifndef _WIN32 - time_t time; /**< Czas powrotu */ -#else - uint32_t time; /**< Czas powrotu */ -#endif -}; - -/** - * Opis zdarzenia \c GG_EVENT_ACK. - */ -struct gg_event_ack { - uin_t recipient; /**< Numer odbiorcy */ - int status; /**< Status doręczenia */ - int seq; /**< Numer sekwencyjny wiadomości */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_ACK110. - */ -struct gg_event_ack110 { - uint8_t msg_type; /**< Rodzaj wiadomości (0x01 - zwykła, 0x02 - konferencja) */ - uint32_t seq; /**< Numer sekwencyjny */ - uint32_t time; /**< Czas zdarzenia */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_USERLIST. - */ -struct gg_event_userlist { - char type; /**< Rodzaj odpowiedzi */ - char *reply; /**< Treść odpowiedzi */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_DCC_VOICE_DATA. - */ -struct gg_event_dcc_voice_data { - uint8_t *data; /**< Dane dźwiękowe */ - int length; /**< Rozmiar danych dźwiękowych */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_IMAGE_REQUEST. - */ -struct gg_event_image_request { - uin_t sender; /**< Nadawca żądania */ - uint32_t size; /**< Rozmiar obrazka */ - uint32_t crc32; /**< Suma kontrolna CRC32 */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_IMAGE_REPLY. - */ -struct gg_event_image_reply { - uin_t sender; /**< Nadawca obrazka */ - uint32_t size; /**< Rozmiar obrazka */ - uint32_t crc32; /**< Suma kontrolna CRC32 */ - char *filename; /**< Nazwa pliku */ - char *image; /**< Bufor z obrazkiem */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_XML_EVENT. - */ -struct gg_event_xml_event { - char *data; /**< Bufor z komunikatem */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_JSON_EVENT. - */ -struct gg_event_json_event { - char *data; /**< Bufor z komunikatem */ - char *type; /**< Bufor z typem komunikatu */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_DCC7_CONNECTED. - */ -struct gg_event_dcc7_connected { - struct gg_dcc7 *dcc7; /**< Struktura połączenia */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_DCC7_PENDING. - */ -struct gg_event_dcc7_pending { - struct gg_dcc7 *dcc7; /**< Struktura połączenia */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_DCC7_REJECT. - */ -struct gg_event_dcc7_reject { - struct gg_dcc7 *dcc7; /**< Struktura połączenia */ - int reason; /**< powód odrzucenia */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_DCC7_ACCEPT. - */ -struct gg_event_dcc7_accept { - struct gg_dcc7 *dcc7; /**< Struktura połączenia */ - int type; /**< Sposób połączenia (P2P, przez serwer) */ - uint32_t remote_ip; /**< Adres zdalnego klienta */ - uint16_t remote_port; /**< Port zdalnego klienta */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_DCC7_DONE. - */ -struct gg_event_dcc7_done { - struct gg_dcc7 *dcc7; /**< Struktura połączenia */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_TYPING_NOTIFICATION. - */ -struct gg_event_typing_notification { - uin_t uin; /**< Numer rozmówcy */ - int length; /**< Długość tekstu */ -}; - -/** - * Atrybut użytkownika. - */ -struct gg_event_user_data_attr { - int type; /**< Typ atrybutu */ - char *key; /**< Klucz */ - char *value; /**< Wartość */ -}; - -/** - * Struktura opisująca kontakt w zdarzeniu GG_EVENT_USER_DATA. - */ -struct gg_event_user_data_user { - uin_t uin; /**< Numer kontaktu */ - size_t attr_count; /**< Liczba atrybutów */ - struct gg_event_user_data_attr *attrs; /**< Lista atrybutów */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_USER_DATA. - */ -struct gg_event_user_data { - int type; /**< Rodzaj informacji o kontaktach */ - size_t user_count; /**< Liczba kontaktów */ - struct gg_event_user_data_user *users; /**< Lista kontaktów */ -}; - -/** - * Struktura opisująca sesję multilogowania. - */ -struct gg_multilogon_session { - gg_multilogon_id_t id; /**< Identyfikator sesji */ - char *name; /**< Nazwa sesji (podana w \c gg_login_params.client_version) */ - uint32_t remote_addr; /**< Adres sesji */ - int status_flags; /**< Flagi statusu sesji */ - int protocol_features; /**< Opcje protokolu sesji */ -#ifndef _WIN32 - time_t logon_time; /**< Czas zalogowania */ -#else - uint32_t logon_time; /**< Czas zalogowania */ -#endif -}; - -/** - * Opis zdarzenia \c GG_EVENT_MULTILOGON_INFO. - */ -struct gg_event_multilogon_info { - int count; /**< Liczba sesji */ - struct gg_multilogon_session *sessions; /** Lista sesji */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_USERLIST100_VERSION. - */ -struct gg_event_userlist100_version { - uint32_t version; /**< Numer wersji listy kontaktów na serwerze */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_USERLIST100_REPLY. - */ -struct gg_event_userlist100_reply { - char type; /**< Rodzaj odpowiedzi */ - uint32_t version; /**< Aktualna wersja listy kontaktów na serwerze */ - char format_type; /**< Typ formatu listy kontaktów (żądany w \c gg_userlist100_request.format_type) */ - char *reply; /**< Treść listy kontaktów w przesyłanej wersji i formacie */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_IMTOKEN. - */ -struct gg_event_imtoken { - char *imtoken; /**< Wartość IMTOKEN */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_PONG110. - */ -struct gg_event_pong110 { -#ifndef _WIN32 - time_t time; /**< Aktualny czas na serwerze */ -#else - uint32_t time; /**< Aktualny czas na serwerze */ -#endif -}; - -/** - * Opis zdarzenia \c GG_EVENT_CHAT_INFO. - */ -struct gg_event_chat_info { - uint64_t id; /**< Identyfikator konferencji */ - uint32_t version; /**< Wersja informacji o konferencji */ - uint32_t participants_count; /**< Ilość uczestników */ - uin_t *participants; /**< Lista uczestników */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_CHAT_INFO_UPDATE. - */ -struct gg_event_chat_info_update { - uint64_t id; /**< Identyfikator konferencji */ - uint32_t type; /**< Typ aktualizacji (\c GG_CHAT_INFO_UPDATE_*) */ - uin_t participant; /**< Uczestnik, którego dotyczy aktualizacja */ - uin_t inviter; /**< Uczestnik inicjujący aktualizację (zapraszający) */ - uint32_t version; /**< Wersja informacji o konferencji */ - uint32_t time; /**< Czas zdarzenia */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_CHAT_CREATED. - */ -struct gg_event_chat_created { - uint64_t id; /**< Identyfikator konferencji */ - uint32_t seq; /**< Numer sekwencyjny */ -}; - -/** - * Opis zdarzenia \c GG_EVENT_CHAT_INVITE_ACK. - */ -struct gg_event_chat_invite_ack { - uint64_t id; /**< Identyfikator konferencji */ - uint32_t seq; /**< Numer sekwencyjny */ -}; - -/** - * Unia wszystkich zdarzeń zwracanych przez funkcje \c gg_watch_fd(), - * \c gg_dcc_watch_fd() i \c gg_dcc7_watch_fd(). - * - * \ingroup events - */ -union gg_event_union { - enum gg_failure_t failure; /**< Błąd połączenia (\c GG_EVENT_CONN_FAILED) */ - struct gg_notify_reply *notify; /**< Zmiana statusu kontaktów (\c GG_EVENT_NOTIFY) */ - struct gg_event_notify_descr notify_descr; /**< Zmiana statusu kontaktów (\c GG_EVENT_NOTIFY_DESCR) */ - struct gg_event_status status; /**< Zmiana statusu kontaktów (\c GG_EVENT_STATUS) */ - struct gg_event_status60 status60; /**< Zmiana statusu kontaktów (\c GG_EVENT_STATUS60) */ - struct gg_event_notify60 *notify60; /**< Zmiana statusu kontaktów (\c GG_EVENT_NOTIFY60) */ - struct gg_event_msg msg; /**< Otrzymano wiadomość (\c GG_EVENT_MSG) */ - struct gg_event_ack ack; /**< Potwierdzenie wiadomości (\c GG_EVENT_ACK) */ - struct gg_event_ack110 ack110; /**< Potwierdzenie wysłania wiadomości (11.0) (\c GG_EVENT_ACK110) */ - struct gg_event_image_request image_request; /**< Żądanie wysłania obrazka (\c GG_EVENT_IMAGE_REQUEST) */ - struct gg_event_image_reply image_reply; /**< Odpowiedź z obrazkiem (\c GG_EVENT_IMAGE_REPLY) */ - struct gg_event_userlist userlist; /**< Odpowiedź listy kontaktów (\c GG_EVENT_USERLIST) */ - gg_pubdir50_t pubdir50; /**< Odpowiedź katalogu publicznego (\c GG_EVENT_PUBDIR50_*) */ - struct gg_event_xml_event xml_event; /**< Zdarzenie systemowe (\c GG_EVENT_XML_EVENT) */ - struct gg_event_json_event json_event; /**< Zdarzenie systemowe (\c GG_EVENT_JSON_EVENT) */ - struct gg_dcc *dcc_new; /**< Nowe połączenie bezpośrednie (\c GG_EVENT_DCC_NEW) */ - enum gg_error_t dcc_error; /**< Błąd połączenia bezpośredniego (\c GG_EVENT_DCC_ERROR) */ - struct gg_event_dcc_voice_data dcc_voice_data; /**< Dane połączenia głosowego (\c GG_EVENT_DCC_VOICE_DATA) */ - struct gg_dcc7 *dcc7_new; /**< Nowe połączenie bezpośrednie (\c GG_EVENT_DCC7_NEW) */ - enum gg_error_t dcc7_error; /**< Błąd połączenia bezpośredniego (\c GG_EVENT_DCC7_ERROR) */ - struct gg_event_dcc7_connected dcc7_connected; /**< Informacja o zestawieniu połączenia bezpośredniego (\c GG_EVENT_DCC7_CONNECTED) */ - struct gg_event_dcc7_pending dcc7_pending; /**< Trwa próba połączenia bezpośredniego (\c GG_EVENT_DCC7_PENDING) */ - struct gg_event_dcc7_reject dcc7_reject; /**< Odrzucono połączenia bezpośredniego (\c GG_EVENT_DCC7_REJECT) */ - struct gg_event_dcc7_accept dcc7_accept; /**< Zaakceptowano połączenie bezpośrednie (\c GG_EVENT_DCC7_ACCEPT) */ - struct gg_event_dcc7_done dcc7_done; /**< Zakończono połączenie bezpośrednie (\c GG_EVENT_DCC7_DONE) */ - struct gg_event_typing_notification typing_notification; /**< Powiadomienie o pisaniu */ - struct gg_event_user_data user_data; /**< Informacje o kontaktach */ - struct gg_event_msg multilogon_msg; /**< Inna sesja wysłała wiadomość (\c GG_EVENT_MULTILOGON_MSG) */ - struct gg_event_multilogon_info multilogon_info; /**< Informacja o innych sesjach multilogowania (\c GG_EVENT_MULTILOGON_INFO) */ - struct gg_event_userlist100_version userlist100_version; /**< Informacja o numerze wersji listy kontaktów na serwerze (\c GG_EVENT_USERLIST100_VERSION) */ - struct gg_event_userlist100_reply userlist100_reply; /**< Odpowiedź listy kontaktów (10.0) (\c GG_EVENT_USERLIST100_REPLY) */ - struct gg_event_imtoken imtoken; /**< Ciąg IMTOKEN (11.0) (\c GG_EVENT_IMTOKEN) */ - struct gg_event_pong110 pong110; /**< Utrzymanie połączenia (11.0) (\c GG_EVENT_PONG110) */ - struct gg_event_chat_info chat_info; /**< Informacje o konferencji (11.0) (\c GG_EVENT_CHAT_INFO) */ - struct gg_event_chat_info_update chat_info_update; /**< Aktualizacja informacji o konferencji (11.0) (\c GG_EVENT_CHAT_INFO_UPDATE) */ - struct gg_event_chat_created chat_created; /**< Potwierdzenie utworzenia konferencji (11.0) (\c GG_EVENT_CHAT_CREATED) */ - struct gg_event_chat_invite_ack chat_invite_ack; /**< Potwierdzenie wysłania zaproszenia do konferencji (11.0) (\c GG_EVENT_CHAT_INVITE_ACK) */ -}; - -/** - * Opis zdarzenia. - * - * Zwracany przez funkcje \c gg_watch_fd(), \c gg_dcc_watch_fd() - * i \c gg_dcc7_watch_fd(). Po przeanalizowaniu należy zwolnić - * za pomocą \c gg_event_free(). - * - * \ingroup events - */ -struct gg_event { - int type; /**< Rodzaj zdarzenia */ - union gg_event_union event; /**< Informacja o zdarzeniu */ -}; - -struct gg_event *gg_watch_fd(struct gg_session *sess); -void gg_event_free(struct gg_event *e); - -int gg_notify_ex(struct gg_session *sess, uin_t *userlist, char *types, int count); -int gg_notify(struct gg_session *sess, uin_t *userlist, int count); -int gg_add_notify_ex(struct gg_session *sess, uin_t uin, char type); -int gg_add_notify(struct gg_session *sess, uin_t uin); -int gg_remove_notify_ex(struct gg_session *sess, uin_t uin, char type); -int gg_remove_notify(struct gg_session *sess, uin_t uin); - -struct gg_http *gg_http_connect(const char *hostname, int port, int async, const char *method, const char *path, const char *header); -int gg_http_watch_fd(struct gg_http *h); -void gg_http_stop(struct gg_http *h); -void gg_http_free(struct gg_http *h); - -uint32_t gg_pubdir50(struct gg_session *sess, gg_pubdir50_t req); -gg_pubdir50_t gg_pubdir50_new(int type); -int gg_pubdir50_add(gg_pubdir50_t req, const char *field, const char *value); -int gg_pubdir50_seq_set(gg_pubdir50_t req, uint32_t seq); -const char *gg_pubdir50_get(gg_pubdir50_t res, int num, const char *field); -int gg_pubdir50_type(gg_pubdir50_t res); -int gg_pubdir50_count(gg_pubdir50_t res); -uin_t gg_pubdir50_next(gg_pubdir50_t res); -uint32_t gg_pubdir50_seq(gg_pubdir50_t res); -void gg_pubdir50_free(gg_pubdir50_t res); - -#ifndef DOXYGEN - -#define GG_PUBDIR50_UIN "FmNumber" -#define GG_PUBDIR50_STATUS "FmStatus" -#define GG_PUBDIR50_FIRSTNAME "firstname" -#define GG_PUBDIR50_LASTNAME "lastname" -#define GG_PUBDIR50_NICKNAME "nickname" -#define GG_PUBDIR50_BIRTHYEAR "birthyear" -#define GG_PUBDIR50_CITY "city" -#define GG_PUBDIR50_GENDER "gender" -#define GG_PUBDIR50_GENDER_FEMALE "1" -#define GG_PUBDIR50_GENDER_MALE "2" -#define GG_PUBDIR50_GENDER_SET_FEMALE "2" -#define GG_PUBDIR50_GENDER_SET_MALE "1" -#define GG_PUBDIR50_ACTIVE "ActiveOnly" -#define GG_PUBDIR50_ACTIVE_TRUE "1" -#define GG_PUBDIR50_START "fmstart" -#define GG_PUBDIR50_FAMILYNAME "familyname" -#define GG_PUBDIR50_FAMILYCITY "familycity" - -#else - -/** - * \ingroup pubdir50 - * - * Rodzaj pola zapytania. - */ -enum { - GG_PUBDIR50_UIN, /**< Numer Gadu-Gadu */ - GG_PUBDIR50_STATUS, /**< Status (tylko wynik wyszukiwania) */ - GG_PUBDIR50_FIRSTNAME, /**< Imię */ - GG_PUBDIR50_LASTNAME, /**< Nazwisko */ - GG_PUBDIR50_NICKNAME, /**< Pseudonim */ - GG_PUBDIR50_BIRTHYEAR, /**< Rok urodzenia lub przedział lat oddzielony spacją */ - GG_PUBDIR50_CITY, /**< Miejscowość */ - GG_PUBDIR50_GENDER, /**< Płeć */ - GG_PUBDIR50_ACTIVE, /**< Osoba dostępna (tylko wyszukiwanie) */ - GG_PUBDIR50_START, /**< Numer początkowy wyszukiwania (tylko wyszukiwanie) */ - GG_PUBDIR50_FAMILYNAME, /**< Nazwisko rodowe (tylko wysyłanie informacji o sobie) */ - GG_PUBDIR50_FAMILYCITY, /**< Miejscowość pochodzenia (tylko wysyłanie informacji o sobie) */ -}; - -/** - * \ingroup pubdir50 - * - * Wartość pola GG_PUBDIR50_GENDER przy wyszukiwaniu. Brak pola oznacza dowolną płeć. - */ -enum { - GG_PUBDIR50_GENDER_FEMALE, /**< Kobieta */ - GG_PUBDIR50_GENDER_MALE, /**< Mężczyzna */ -}; - -/** - * \ingroup pubdir50 - * - * Wartość pola GG_PUBDIR50_GENDER przy wysyłaniu informacji o sobie. - */ -enum { - GG_PUBDIR50_GENDER_SET_FEMALE, /**< Kobieta */ - GG_PUBDIR50_GENDER_SET_MALE, /**< Mężczyzna */ -}; - -/** - * \ingroup pubdir50 - * - * Wartość pola GG_PUBDIR50_ACTIVE. - */ -enum { - GG_PUBDIR50_ACTIVE_TRUE, /**< Wyszukaj tylko osoby dostępne */ -}; - -#endif /* DOXYGEN */ - -/** - * Powód błędu operacji na katalogu publicznym. - * - * \ingroup http - */ -typedef enum { - GG_PUBDIR_ERROR_NONE = 0, /**< Brak błędu */ - GG_PUBDIR_ERROR_OTHER, /**< Nieznany błąd */ - GG_PUBDIR_ERROR_TOKEN, /**< Błędny token */ - GG_PUBDIR_ERROR_OLD_PASSWORD, /**< Niepoprawne stare hasło */ - GG_PUBDIR_ERROR_NEW_PASSWORD, /**< Niepoprawne nowe hasło */ -} gg_pubdir_error_t; - -/** - * Wynik operacji na katalogu publicznym. - * - * \ingroup http - */ -struct gg_pubdir { - int success; /**< Flaga powodzenia operacji */ - uin_t uin; /**< Otrzymany numer lub 0 w przypadku błędu */ - gg_pubdir_error_t error; /**< Powód błędu */ -}; - -int gg_pubdir_watch_fd(struct gg_http *f); -void gg_pubdir_free(struct gg_http *f); - -/** - * Token autoryzacji niektórych operacji HTTP. - * - * \ingroup token - */ -struct gg_token { - int width; /**< Szerokość obrazka */ - int height; /**< Wysokość obrazka */ - int length; /**< Liczba znaków w tokenie */ - char *tokenid; /**< Identyfikator tokenu */ -}; - -struct gg_http *gg_token(int async); -int gg_token_watch_fd(struct gg_http *h); -void gg_token_free(struct gg_http *h); - -struct gg_http *gg_register3(const char *email, const char *password, const char *tokenid, const char *tokenval, int async); -#ifndef DOXYGEN -#define gg_register_watch_fd gg_pubdir_watch_fd -#define gg_register_free gg_pubdir_free -#endif - -struct gg_http *gg_unregister3(uin_t uin, const char *password, const char *tokenid, const char *tokenval, int async); -#ifndef DOXYGEN -#define gg_unregister_watch_fd gg_pubdir_watch_fd -#define gg_unregister_free gg_pubdir_free -#endif - -struct gg_http *gg_remind_passwd3(uin_t uin, const char *email, const char *tokenid, const char *tokenval, int async); -#ifndef DOXYGEN -#define gg_remind_passwd_watch_fd gg_pubdir_watch_fd -#define gg_remind_passwd_free gg_pubdir_free -#endif - -struct gg_http *gg_change_passwd4(uin_t uin, const char *email, const char *passwd, const char *newpasswd, const char *tokenid, const char *tokenval, int async); -#ifndef DOXYGEN -#define gg_change_passwd_watch_fd gg_pubdir_watch_fd -#define gg_change_passwd_free gg_pubdir_free -#endif - -extern int gg_dcc_port; -extern unsigned long gg_dcc_ip; - -int gg_dcc_request(struct gg_session *sess, uin_t uin); - -struct gg_dcc *gg_dcc_send_file(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin); -struct gg_dcc *gg_dcc_get_file(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin); -struct gg_dcc *gg_dcc_voice_chat(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin); -void gg_dcc_set_type(struct gg_dcc *d, int type); -int gg_dcc_fill_file_info(struct gg_dcc *d, const char *filename); -int gg_dcc_fill_file_info2(struct gg_dcc *d, const char *filename, const char *local_filename); -int gg_dcc_voice_send(struct gg_dcc *d, char *buf, int length); - -#define GG_DCC_VOICE_FRAME_LENGTH 195 /**< Rozmiar pakietu głosowego przed wersją Gadu-Gadu 5.0.5 */ -#define GG_DCC_VOICE_FRAME_LENGTH_505 326 /**< Rozmiar pakietu głosowego od wersji Gadu-Gadu 5.0.5 */ - -struct gg_dcc *gg_dcc_socket_create(uin_t uin, uint16_t port); -#ifndef DOXYGEN -#define gg_dcc_socket_free gg_dcc_free -#define gg_dcc_socket_watch_fd gg_dcc_watch_fd -#endif - -struct gg_event *gg_dcc_watch_fd(struct gg_dcc *d); - -void gg_dcc_free(struct gg_dcc *c); - -struct gg_event *gg_dcc7_watch_fd(struct gg_dcc7 *d); -struct gg_dcc7 *gg_dcc7_send_file(struct gg_session *sess, uin_t rcpt, const char *filename, const char *filename1250, const char *hash); -struct gg_dcc7 *gg_dcc7_send_file_fd(struct gg_session *sess, uin_t rcpt, int fd, size_t size, const char *filename1250, const char *hash); -int gg_dcc7_accept(struct gg_dcc7 *dcc, unsigned int offset); -int gg_dcc7_reject(struct gg_dcc7 *dcc, int reason); -void gg_dcc7_free(struct gg_dcc7 *d); - -extern int gg_debug_level; - -extern void (*gg_debug_handler)(int level, const char *format, va_list ap); -extern void (*gg_debug_handler_session)(struct gg_session *sess, int level, const char *format, va_list ap); - -extern FILE *gg_debug_file; - -/** - * \ingroup debug - * @{ - */ -#define GG_DEBUG_NET 1 /**< Rejestracja zdarzeń związanych z siecią */ -#define GG_DEBUG_TRAFFIC 2 /**< Rejestracja ruchu sieciowego */ -#define GG_DEBUG_DUMP 4 /**< Rejestracja zawartości pakietów */ -#define GG_DEBUG_FUNCTION 8 /**< Rejestracja wywołań funkcji */ -#define GG_DEBUG_MISC 16 /**< Rejestracja różnych informacji */ -#define GG_DEBUG_VERBOSE 32 /**< Rejestracja informacji szczegółowych */ -#define GG_DEBUG_WARNING 64 /**< Rejestracja ostrzeżeń */ -#define GG_DEBUG_ERROR 128 /**< Rejestracja błędów krytycznych */ -/** @} */ - -const char *gg_debug_state(enum gg_state_t state); -const char *gg_debug_event(enum gg_event_t event); - -#ifdef GG_DEBUG_DISABLE -#define gg_debug(...) do { } while (0) -#define gg_debug_session(...) do { } while (0) -#else -void gg_debug(int level, const char *format, ...) GG_GNUC_PRINTF(2, 3); -void gg_debug_session(struct gg_session *sess, int level, const char *format, ...) GG_GNUC_PRINTF(3, 4); -#endif - -const char *gg_libgadu_version(void); - -/** - * Lista funkcji biblioteki, które zależą od zewnętrznych bibliotek. - * - * \ingroup version - */ -typedef enum { - GG_LIBGADU_FEATURE_SSL, /**< Biblioteka obsługuje połączenia szyfrowane */ - GG_LIBGADU_FEATURE_PTHREAD, /**< Biblioteka obsługuje rozwiązywanie nazw za pomocą wątków */ - GG_LIBGADU_FEATURE_USERLIST100, /**< Biblioteka obsługuje listę kontaktów zgodną z Gadu-Gadu 10 */ -} gg_libgadu_feature_t; - -int gg_libgadu_check_feature(gg_libgadu_feature_t feature); - -extern int gg_proxy_enabled; -extern char *gg_proxy_host; -extern int gg_proxy_port; -extern char *gg_proxy_username; -extern char *gg_proxy_password; -extern int gg_proxy_http_only; - -extern unsigned long gg_local_ip; - -#define GG_LOGIN_HASH_GG32 0x01 /**< Algorytm Gadu-Gadu */ -#define GG_LOGIN_HASH_SHA1 0x02 /**< Algorytm SHA1 */ - -#ifndef DOXYGEN - -#define GG_PUBDIR50_WRITE 0x01 -#define GG_PUBDIR50_READ 0x02 -#define GG_PUBDIR50_SEARCH 0x03 -#define GG_PUBDIR50_SEARCH_REQUEST GG_PUBDIR50_SEARCH -#define GG_PUBDIR50_SEARCH_REPLY 0x05 - -#else - -/** - * \ingroup pubdir50 - * - * Rodzaj zapytania lub odpowiedzi katalogu publicznego. - */ -enum { - GG_PUBDIR50_WRITE, /**< Wysłanie do serwera informacji o sobie */ - GG_PUBDIR50_READ, /**< Pobranie z serwera informacji o sobie */ - GG_PUBDIR50_SEARCH, /**< Wyszukiwanie w katalogu publicznym */ - GG_PUBDIR50_SEARCH_REPLY, /**< Wynik wyszukiwania w katalogu publicznym */ -}; - -#endif /* DOXYGEN */ - -/** \cond obsolete */ - -#define gg_free_event gg_event_free -#define gg_free_http gg_http_free -#define gg_free_pubdir gg_pubdir_free -#define gg_free_register gg_pubdir_free -#define gg_free_remind_passwd gg_pubdir_free -#define gg_free_dcc gg_dcc_free -#define gg_free_change_passwd gg_pubdir_free - -struct gg_search_request { - int active; - unsigned int start; - char *nickname; - char *first_name; - char *last_name; - char *city; - int gender; - int min_birth; - int max_birth; - char *email; - char *phone; - uin_t uin; -} /* GG_DEPRECATED */; - -struct gg_search { - int count; - struct gg_search_result *results; -} GG_DEPRECATED; - -struct gg_search_result { - uin_t uin; - char *first_name; - char *last_name; - char *nickname; - int born; - int gender; - char *city; - int active; -} GG_DEPRECATED; - -#define GG_GENDER_NONE 0 -#define GG_GENDER_FEMALE 1 -#define GG_GENDER_MALE 2 - -struct gg_http *gg_search(const struct gg_search_request *r, int async) GG_DEPRECATED; -int gg_search_watch_fd(struct gg_http *f) GG_DEPRECATED; -void gg_free_search(struct gg_http *f) GG_DEPRECATED; -#define gg_search_free gg_free_search - -const struct gg_search_request *gg_search_request_mode_0(char *nickname, char *first_name, char *last_name, char *city, int gender, int min_birth, int max_birth, int active, int start) GG_DEPRECATED; -const struct gg_search_request *gg_search_request_mode_1(char *email, int active, int start) GG_DEPRECATED; -const struct gg_search_request *gg_search_request_mode_2(char *phone, int active, int start) GG_DEPRECATED; -const struct gg_search_request *gg_search_request_mode_3(uin_t uin, int active, int start) GG_DEPRECATED; -void gg_search_request_free(struct gg_search_request *r) GG_DEPRECATED; - -struct gg_http *gg_register(const char *email, const char *password, int async) GG_DEPRECATED; -struct gg_http *gg_register2(const char *email, const char *password, const char *qa, int async) GG_DEPRECATED; - -struct gg_http *gg_unregister(uin_t uin, const char *password, const char *email, int async) GG_DEPRECATED; -struct gg_http *gg_unregister2(uin_t uin, const char *password, const char *qa, int async) GG_DEPRECATED; - -struct gg_http *gg_remind_passwd(uin_t uin, int async) GG_DEPRECATED; -struct gg_http *gg_remind_passwd2(uin_t uin, const char *tokenid, const char *tokenval, int async) GG_DEPRECATED; - -struct gg_http *gg_change_passwd(uin_t uin, const char *passwd, const char *newpasswd, const char *newemail, int async) GG_DEPRECATED; -struct gg_http *gg_change_passwd2(uin_t uin, const char *passwd, const char *newpasswd, const char *email, const char *newemail, int async) GG_DEPRECATED; -struct gg_http *gg_change_passwd3(uin_t uin, const char *passwd, const char *newpasswd, const char *qa, int async) GG_DEPRECATED; - -struct gg_change_info_request { - char *first_name; - char *last_name; - char *nickname; - char *email; - int born; - int gender; - char *city; -} /* GG_DEPRECATED */; - -struct gg_change_info_request *gg_change_info_request_new(const char *first_name, const char *last_name, const char *nickname, const char *email, int born, int gender, const char *city) GG_DEPRECATED; -void gg_change_info_request_free(struct gg_change_info_request *r) GG_DEPRECATED; - -struct gg_http *gg_change_info(uin_t uin, const char *passwd, const struct gg_change_info_request *request, int async) GG_DEPRECATED; -#define gg_change_pubdir_watch_fd gg_pubdir_watch_fd -#define gg_change_pubdir_free gg_pubdir_free -#define gg_free_change_pubdir gg_pubdir_free - -struct gg_http *gg_userlist_get(uin_t uin, const char *password, int async) GG_DEPRECATED; -int gg_userlist_get_watch_fd(struct gg_http *f) GG_DEPRECATED; -void gg_userlist_get_free(struct gg_http *f) GG_DEPRECATED; - -struct gg_http *gg_userlist_put(uin_t uin, const char *password, const char *contacts, int async) GG_DEPRECATED; -int gg_userlist_put_watch_fd(struct gg_http *f) GG_DEPRECATED; -void gg_userlist_put_free(struct gg_http *f) GG_DEPRECATED; - -struct gg_http *gg_userlist_remove(uin_t uin, const char *password, int async) GG_DEPRECATED; -int gg_userlist_remove_watch_fd(struct gg_http *f) GG_DEPRECATED; -void gg_userlist_remove_free(struct gg_http *f) GG_DEPRECATED; - -int gg_pubdir50_handle_reply(struct gg_event *e, const char *packet, int length) GG_DEPRECATED; - -/** \endcond */ - -int gg_file_hash_sha1(int fd, uint8_t *result) GG_DEPRECATED; - -char *gg_saprintf(const char *format, ...) GG_GNUC_PRINTF(1, 2) GG_DEPRECATED; -char *gg_vsaprintf(const char *format, va_list ap) GG_DEPRECATED; - -#define gg_alloc_sprintf gg_saprintf - -char *gg_get_line(char **ptr) GG_DEPRECATED; - -int gg_connect(void *addr, int port, int async) GG_DEPRECATED; -struct in_addr *gg_gethostbyname(const char *hostname) GG_DEPRECATED; -char *gg_read_line(int sock, char *buf, int length) GG_DEPRECATED; -void gg_chomp(char *line) GG_DEPRECATED; -char *gg_urlencode(const char *str) GG_DEPRECATED; -int gg_http_hash(const char *format, ...) GG_DEPRECATED; -void gg_http_free_fields(struct gg_http *h) GG_DEPRECATED; -int gg_read(struct gg_session *sess, char *buf, int length) GG_DEPRECATED; -int gg_write(struct gg_session *sess, const char *buf, int length) GG_DEPRECATED; -void *gg_recv_packet(struct gg_session *sess) GG_DEPRECATED; -int gg_send_packet(struct gg_session *sess, int type, ...) GG_DEPRECATED; -unsigned int gg_login_hash(const unsigned char *password, unsigned int seed) GG_DEPRECATED; -void gg_login_hash_sha1(const char *password, uint32_t seed, uint8_t *result) GG_DEPRECATED; -uint32_t gg_fix32(uint32_t x); -uint16_t gg_fix16(uint16_t x); -#define fix16 gg_fix16 -#define fix32 gg_fix32 -char *gg_proxy_auth(void) GG_DEPRECATED; -char *gg_base64_encode(const char *buf) GG_DEPRECATED; -char *gg_base64_decode(const char *buf) GG_DEPRECATED; -int gg_image_queue_remove(struct gg_session *s, struct gg_image_queue *q, int freeq) GG_DEPRECATED; - -/** - * Kolejka odbieranych obrazków. - */ -struct gg_image_queue { - uin_t sender; /**< Nadawca obrazka */ - uint32_t size; /**< Rozmiar obrazka */ - uint32_t crc32; /**< Suma kontrolna CRC32 */ - char *filename; /**< Nazwa pliku */ - char *image; /**< Bufor z odebranymi danymi */ - uint32_t done; /**< Rozmiar odebranych danych */ - - struct gg_image_queue *next; /**< Kolejny element listy */ - - uint32_t packet_type; /**< \brief Rodzaj odbieranych pakietów. W niektórych przypadkach (przy multilogowaniu) serwer wysyła nam dwie kopie obrazka jako dwa różne typy pakietów */ -} GG_DEPRECATED; - -int gg_dcc7_handle_id(struct gg_session *sess, struct gg_event *e, const void *payload, int len) GG_DEPRECATED; -int gg_dcc7_handle_new(struct gg_session *sess, struct gg_event *e, const void *payload, int len) GG_DEPRECATED; -int gg_dcc7_handle_info(struct gg_session *sess, struct gg_event *e, const void *payload, int len) GG_DEPRECATED; -int gg_dcc7_handle_accept(struct gg_session *sess, struct gg_event *e, const void *payload, int len) GG_DEPRECATED; -int gg_dcc7_handle_reject(struct gg_session *sess, struct gg_event *e, const void *payload, int len) GG_DEPRECATED; - -#define GG_APPMSG_HOST "appmsg.gadu-gadu.pl" -#define GG_APPMSG_PORT 80 -#define GG_PUBDIR_HOST "pubdir.gadu-gadu.pl" -#define GG_PUBDIR_PORT 80 -#define GG_REGISTER_HOST "register.gadu-gadu.pl" -#define GG_REGISTER_PORT 80 -#define GG_REMIND_HOST "retr.gadu-gadu.pl" -#define GG_REMIND_PORT 80 -#define GG_RELAY_HOST "relay.gadu-gadu.pl" -#define GG_RELAY_PORT 80 - -#define GG_DEFAULT_PORT 8074 -#define GG_HTTPS_PORT 443 -#define GG_HTTP_USERAGENT "Mozilla/4.7 [en] (Win98; I)" - -#define GG_PROTOCOL_VERSION_100 0x2e -#define GG_PROTOCOL_VERSION_110 0x40 - -/* GG_DEPRECATED */ -#define GG_DEFAULT_CLIENT_VERSION "-" - -#define GG_DEFAULT_PROTOCOL_VERSION GG_PROTOCOL_VERSION_110 -#define GG_DEFAULT_TIMEOUT 30 -#define GG_HAS_AUDIO_MASK 0x40000000 -#define GG_HAS_AUDIO7_MASK 0x20000000 -#define GG_ERA_OMNIX_MASK 0x04000000 -#undef GG_LIBGADU_VERSION - -#ifndef DOXYGEN - -#define GG_FEATURE_MSG77 0x0001 -#define GG_FEATURE_STATUS77 0x0002 -#define GG_FEATURE_UNKNOWN_4 0x0004 -#define GG_FEATURE_UNKNOWN_8 0x0008 -#define GG_FEATURE_DND_FFC 0x0010 -#define GG_FEATURE_IMAGE_DESCR 0x0020 -#define GG_FEATURE_UNKNOWN_40 0x0040 -#define GG_FEATURE_UNKNOWN_80 0x0080 -#define GG_FEATURE_UNKNOWN_100 0x0100 -#define GG_FEATURE_USER_DATA 0x0200 -#define GG_FEATURE_MSG_ACK 0x0400 -#define GG_FEATURE_UNKNOWN_800 0x0800 -#define GG_FEATURE_UNKNOWN_1000 0x1000 -#define GG_FEATURE_TYPING_NOTIFICATION 0x2000 -#define GG_FEATURE_MULTILOGON 0x4000 - -/* Poniższe makra zostały zachowane dla zgodności API */ -#define GG_FEATURE_MSG80 0 -#define GG_FEATURE_STATUS80 0 -#define GG_FEATURE_STATUS80BETA 0 - -#define GG_FEATURE_ALL (GG_FEATURE_MSG80 | GG_FEATURE_STATUS80 | GG_FEATURE_DND_FFC | GG_FEATURE_IMAGE_DESCR | GG_FEATURE_UNKNOWN_100 | GG_FEATURE_USER_DATA | GG_FEATURE_MSG_ACK | GG_FEATURE_TYPING_NOTIFICATION) - -#else - -/** - * \ingroup login - * - * Flagi opcji protokołu. - */ -enum { - GG_FEATURE_MSG77, /**< Klient życzy sobie otrzymywać wiadomości zgodnie z protokołem 7.7 */ - GG_FEATURE_STATUS77, /**< Klient życzy sobie otrzymywać zmiany stanu zgodnie z protokołem 7.7 */ - GG_FEATURE_DND_FFC, /**< Klient obsługuje statusy "nie przeszkadzać" i "poGGadaj ze mną" */ - GG_FEATURE_IMAGE_DESCR, /**< Klient obsługuje opisy graficzne oraz flagę \c GG_STATUS80_DESCR_MASK */ -}; - - -#endif - -#define GG_DEFAULT_DCC_PORT 1550 - -struct gg_header { - uint32_t type; /* typ pakietu */ - uint32_t length; /* długość reszty pakietu */ -} GG_PACKED; - -#define GG_WELCOME 0x0001 -#define GG_NEED_EMAIL 0x0014 - -struct gg_welcome { - uint32_t key; /* klucz szyfrowania hasła */ -} GG_PACKED; - -#define GG_LOGIN 0x000c - -struct gg_login { - uint32_t uin; /* mój numerek */ - uint32_t hash; /* hash hasła */ - uint32_t status; /* status na dzień dobry */ - uint32_t version; /* moja wersja klienta */ - uint32_t local_ip; /* mój adres ip */ - uint16_t local_port; /* port, na którym słucham */ -} GG_PACKED; - -#define GG_LOGIN_EXT 0x0013 - -struct gg_login_ext { - uint32_t uin; /* mój numerek */ - uint32_t hash; /* hash hasła */ - uint32_t status; /* status na dzień dobry */ - uint32_t version; /* moja wersja klienta */ - uint32_t local_ip; /* mój adres ip */ - uint16_t local_port; /* port, na którym słucham */ - uint32_t external_ip; /* zewnętrzny adres ip */ - uint16_t external_port; /* zewnętrzny port */ -} GG_PACKED; - -#define GG_LOGIN60 0x0015 - -struct gg_login60 { - uint32_t uin; /* mój numerek */ - uint32_t hash; /* hash hasła */ - uint32_t status; /* status na dzień dobry */ - uint32_t version; /* moja wersja klienta */ - uint8_t dunno1; /* 0x00 */ - uint32_t local_ip; /* mój adres ip */ - uint16_t local_port; /* port, na którym słucham */ - uint32_t external_ip; /* zewnętrzny adres ip */ - uint16_t external_port; /* zewnętrzny port */ - uint8_t image_size; /* maksymalny rozmiar grafiki w KiB */ - uint8_t dunno2; /* 0xbe */ -} GG_PACKED; - -#define GG_LOGIN70 0x0019 - -struct gg_login70 { - uint32_t uin; /* mój numerek */ - uint8_t hash_type; /* rodzaj hashowania hasła */ - uint8_t hash[64]; /* hash hasła dopełniony zerami */ - uint32_t status; /* status na dzień dobry */ - uint32_t version; /* moja wersja klienta */ - uint8_t dunno1; /* 0x00 */ - uint32_t local_ip; /* mój adres ip */ - uint16_t local_port; /* port, na którym słucham */ - uint32_t external_ip; /* zewnętrzny adres ip (???) */ - uint16_t external_port; /* zewnętrzny port (???) */ - uint8_t image_size; /* maksymalny rozmiar grafiki w KiB */ - uint8_t dunno2; /* 0xbe */ -} GG_PACKED; - -#define GG_LOGIN_OK 0x0003 - -#define GG_LOGIN_FAILED 0x0009 - -#define GG_PUBDIR50_REQUEST 0x0014 - -struct gg_pubdir50_request { - uint8_t type; /* GG_PUBDIR50_* */ - uint32_t seq; /* czas wysłania zapytania */ -} GG_PACKED; - -#define GG_PUBDIR50_REPLY 0x000e - -struct gg_pubdir50_reply { - uint8_t type; /* GG_PUBDIR50_* */ - uint32_t seq; /* czas wysłania zapytania */ -} GG_PACKED; - -#define GG_NEW_STATUS 0x0002 - -#ifndef DOXYGEN - -#define GG_STATUS_NOT_AVAIL 0x0001 -#define GG_STATUS_NOT_AVAIL_DESCR 0x0015 -#define GG_STATUS_FFC 0x0017 -#define GG_STATUS_FFC_DESCR 0x0018 -#define GG_STATUS_AVAIL 0x0002 -#define GG_STATUS_AVAIL_DESCR 0x0004 -#define GG_STATUS_BUSY 0x0003 -#define GG_STATUS_BUSY_DESCR 0x0005 -#define GG_STATUS_DND 0x0021 -#define GG_STATUS_DND_DESCR 0x0022 -#define GG_STATUS_INVISIBLE 0x0014 -#define GG_STATUS_INVISIBLE_DESCR 0x0016 -#define GG_STATUS_BLOCKED 0x0006 - -#define GG_STATUS_GGPLUS 0x0020 -#define GG_STATUS_NOT_SET 0x0023 -#define GG_STATUS_UNKNOWN 0x0025 - -#define GG_STATUS_IMAGE_MASK 0x0100 -#define GG_STATUS_DESCR_MASK 0x4000 -#define GG_STATUS_FRIENDS_MASK 0x8000 - -#define GG_STATUS_FLAG_UNKNOWN 0x00000001 -#define GG_STATUS_FLAG_VIDEO 0x00000002 -#define GG_STATUS_FLAG_INHERIT 0x00000020 -#define GG_STATUS_FLAG_MOBILE 0x00100000 -#define GG_STATUS_FLAG_SPAM 0x00800000 - -#else - -/** - * Rodzaje statusów użytkownika. - * - * \ingroup status - */ -enum { - GG_STATUS_NOT_AVAIL, /**< Niedostępny */ - GG_STATUS_NOT_AVAIL_DESCR, /**< Niedostępny z opisem */ - GG_STATUS_FFC, /**< PoGGadaj ze mną */ - GG_STATUS_FFC_DESCR, /**< PoGGadaj ze mną z opisem */ - GG_STATUS_AVAIL, /**< Dostępny */ - GG_STATUS_AVAIL_DESCR, /**< Dostępny z opisem */ - GG_STATUS_BUSY, /**< Zajęty */ - GG_STATUS_BUSY_DESCR, /**< Zajęty z opisem */ - GG_STATUS_DND, /**< Nie przeszkadzać */ - GG_STATUS_DND_DESCR, /**< Nie przeszakdzać z opisem */ - GG_STATUS_INVISIBLE, /**< Niewidoczny (tylko własny status) */ - GG_STATUS_INVISIBLE_DESCR, /**< Niewidoczny z opisem (tylko własny status) */ - GG_STATUS_BLOCKED, /**< Zablokowany (tylko status innych) */ - GG_STATUS_GGPLUS, /**< Status "Korzystam z GG Plus" */ - GG_STATUS_NOT_SET, /**< Status nie ustawiony (przy logowaniu się do sieci) */ - GG_STATUS_IMAGE_MASK, /**< Flaga bitowa oznaczająca opis graficzny (tylko jeśli wybrano \c GG_FEATURE_IMAGE_DESCR) */ - GG_STATUS_DESCR_MASK, /**< Flaga bitowa oznaczająca status z opisem (tylko jeśli wybrano \c GG_FEATURE_IMAGE_DESCR) */ - GG_STATUS_FRIENDS_MASK, /**< Flaga bitowa dostępności tylko dla znajomych */ -}; - -/** - * Rodzaje statusów użytkownika. Mapa bitowa. - * - * \ingroup status - */ -enum { - GG_STATUS_FLAG_UNKNOWN, /**< Przeznaczenie nieznane, ale występuje zawsze */ - GG_STATUS_FLAG_VIDEO, /**< Klient obsługuje wideorozmowy */ - GG_STATUS_FLAG_INHERIT, /**< Synchronizacja statusu do innych klientów (przy logowaniu się do sieci) */ - GG_STATUS_FLAG_MOBILE, /**< Klient mobilny (ikona telefonu komórkowego) */ - GG_STATUS_FLAG_SPAM, /**< Klient chce otrzymywać linki od nieznajomych */ -}; - -#endif /* DOXYGEN */ - -/** - * \ingroup status - * - * Flaga bitowa dostepnosci informujaca ze mozemy voipowac - */ - -#define GG_STATUS_VOICE_MASK 0x20000 /**< czy ma wlaczone audio (7.7) */ - -/** - * \ingroup status - * - * Maksymalna długośc opisu. - */ -#define GG_STATUS_DESCR_MAXSIZE 255 -#define GG_STATUS_DESCR_MAXSIZE_PRE_8_0 70 - -#define GG_STATUS_MASK 0xff - -/* GG_S_F() tryb tylko dla znajomych */ -#define GG_S_F(x) (((x) & GG_STATUS_FRIENDS_MASK) != 0) - -/* GG_S() stan bez uwzględnienia dodatkowych flag */ -#define GG_S(x) ((x) & GG_STATUS_MASK) - - -/* GG_S_FF() chętny do rozmowy */ -#define GG_S_FF(x) (GG_S(x) == GG_STATUS_FFC || GG_S(x) == GG_STATUS_FFC_DESCR) - -/* GG_S_AV() dostępny */ -#define GG_S_AV(x) (GG_S(x) == GG_STATUS_AVAIL || GG_S(x) == GG_STATUS_AVAIL_DESCR) - -/* GG_S_AW() zaraz wracam */ -#define GG_S_AW(x) (GG_S(x) == GG_STATUS_BUSY || GG_S(x) == GG_STATUS_BUSY_DESCR) - -/* GG_S_DD() nie przeszkadzać */ -#define GG_S_DD(x) (GG_S(x) == GG_STATUS_DND || GG_S(x) == GG_STATUS_DND_DESCR) - -/* GG_S_NA() niedostępny */ -#define GG_S_NA(x) (GG_S(x) == GG_STATUS_NOT_AVAIL || GG_S(x) == GG_STATUS_NOT_AVAIL_DESCR) - -/* GG_S_I() niewidoczny */ -#define GG_S_I(x) (GG_S(x) == GG_STATUS_INVISIBLE || GG_S(x) == GG_STATUS_INVISIBLE_DESCR) - - -/* GG_S_A() dostępny lub chętny do rozmowy */ -#define GG_S_A(x) (GG_S_FF(x) || GG_S_AV(x)) - -/* GG_S_B() zajęty lub nie przeszkadzać */ -#define GG_S_B(x) (GG_S_AW(x) || GG_S_DD(x)) - - -/* GG_S_D() stan opisowy */ -#define GG_S_D(x) (GG_S(x) == GG_STATUS_NOT_AVAIL_DESCR || \ - GG_S(x) == GG_STATUS_FFC_DESCR || \ - GG_S(x) == GG_STATUS_AVAIL_DESCR || \ - GG_S(x) == GG_STATUS_BUSY_DESCR || \ - GG_S(x) == GG_STATUS_DND_DESCR || \ - GG_S(x) == GG_STATUS_INVISIBLE_DESCR) - -/* GG_S_BL() blokowany lub blokujący */ -#define GG_S_BL(x) (GG_S(x) == GG_STATUS_BLOCKED) - -/** - * Zmiana statusu (pakiet \c GG_NEW_STATUS i \c GG_NEW_STATUS80BETA) - */ -struct gg_new_status { - uint32_t status; /**< Nowy status */ -} GG_PACKED; - -#define GG_NOTIFY_FIRST 0x000f -#define GG_NOTIFY_LAST 0x0010 - -#define GG_NOTIFY 0x0010 - -struct gg_notify { - uint32_t uin; /* numerek danej osoby */ - uint8_t dunno1; /* rodzaj wpisu w liście */ -} GG_PACKED; - -#ifndef DOXYGEN - -#define GG_USER_OFFLINE 0x01 -#define GG_USER_NORMAL 0x03 -#define GG_USER_BLOCKED 0x04 - -#else - -/** - * \ingroup contacts - * - * Rodzaj kontaktu. - */ -enum { - GG_USER_NORMAL, /**< Zwykły kontakt */ - GG_USER_BLOCKED, /**< Zablokowany */ - GG_USER_OFFLINE, /**< Niewidoczny dla kontaktu */ -}; - -#endif /* DOXYGEN */ - -#define GG_LIST_EMPTY 0x0012 - -#define GG_NOTIFY_REPLY 0x000c /* tak, to samo co GG_LOGIN */ - -struct gg_notify_reply { - uint32_t uin; /* numerek */ - uint32_t status; /* status danej osoby */ - uint32_t remote_ip; /* adres ip delikwenta */ - uint16_t remote_port; /* port, na którym słucha klient */ - uint32_t version; /* wersja klienta */ - uint16_t dunno2; /* znowu port? */ -} GG_PACKED; - -#define GG_NOTIFY_REPLY60 0x0011 - -struct gg_notify_reply60 { - uint32_t uin; /* numerek plus flagi w MSB */ - uint8_t status; /* status danej osoby */ - uint32_t remote_ip; /* adres ip delikwenta */ - uint16_t remote_port; /* port, na którym słucha klient */ - uint8_t version; /* wersja klienta */ - uint8_t image_size; /* maksymalny rozmiar grafiki w KiB */ - uint8_t dunno1; /* 0x00 */ -} GG_PACKED; - -#define GG_STATUS60 0x000f - -struct gg_status60 { - uint32_t uin; /* numerek plus flagi w MSB */ - uint8_t status; /* status danej osoby */ - uint32_t remote_ip; /* adres ip delikwenta */ - uint16_t remote_port; /* port, na którym słucha klient */ - uint8_t version; /* wersja klienta */ - uint8_t image_size; /* maksymalny rozmiar grafiki w KiB */ - uint8_t dunno1; /* 0x00 */ -} GG_PACKED; - -#define GG_NOTIFY_REPLY77 0x0018 - -struct gg_notify_reply77 { - uint32_t uin; /* numerek plus flagi w MSB */ - uint8_t status; /* status danej osoby */ - uint32_t remote_ip; /* adres ip delikwenta */ - uint16_t remote_port; /* port, na którym słucha klient */ - uint8_t version; /* wersja klienta */ - uint8_t image_size; /* maksymalny rozmiar grafiki w KiB */ - uint8_t dunno1; /* 0x00 */ - uint32_t dunno2; /* ? */ -} GG_PACKED; - -#define GG_STATUS77 0x0017 - -struct gg_status77 { - uint32_t uin; /* numerek plus flagi w MSB */ - uint8_t status; /* status danej osoby */ - uint32_t remote_ip; /* adres ip delikwenta */ - uint16_t remote_port; /* port, na którym słucha klient */ - uint8_t version; /* wersja klienta */ - uint8_t image_size; /* maksymalny rozmiar grafiki w KiB */ - uint8_t dunno1; /* 0x00 */ - uint32_t dunno2; /* ? */ -} GG_PACKED; - -#define GG_ADD_NOTIFY 0x000d -#define GG_REMOVE_NOTIFY 0x000e - -struct gg_add_remove { - uint32_t uin; /* numerek */ - uint8_t dunno1; /* bitmapa */ -} GG_PACKED; - -#define GG_STATUS 0x0002 - -struct gg_status { - uint32_t uin; /* numerek */ - uint32_t status; /* nowy stan */ -} GG_PACKED; - -#define GG_SEND_MSG 0x000b - -#ifndef DOXYGEN - -#define GG_CLASS_QUEUED 0x0001 -#define GG_CLASS_OFFLINE GG_CLASS_QUEUED -#define GG_CLASS_MSG 0x0004 -#define GG_CLASS_CHAT 0x0008 -#define GG_CLASS_CTCP 0x0010 -#define GG_CLASS_ACK 0x0020 -#define GG_CLASS_EXT GG_CLASS_ACK /**< Dla kompatybilności wstecz */ - -#else - -/** - * Klasy wiadomości. Wartości są maskami bitowymi, które w większości - * przypadków można łączyć (połączenie \c GG_CLASS_MSG i \c GG_CLASS_CHAT - * nie ma sensu). - * - * \ingroup messages - */ -enum { - GG_CLASS_MSG, /**< Wiadomość ma pojawić się w osobnym oknie */ - GG_CLASS_CHAT, /**< Wiadomość ma pojawić się w oknie rozmowy */ - GG_CLASS_CTCP, /**< Wiadomość przeznaczona dla klienta Gadu-Gadu */ - GG_CLASS_ACK, /**< Klient nie życzy sobie potwierdzenia */ - GG_CLASS_QUEUED, /**< Wiadomość zakolejkowana na serwerze (tylko przy odbieraniu) */ -}; - -#endif /* DOXYGEN */ - -/** - * Maksymalna długość wiadomości. - * - * \ingroup messages - */ -#define GG_MSG_MAXSIZE 1989 - -struct gg_send_msg { - uint32_t recipient; - uint32_t seq; - uint32_t msgclass; -} GG_PACKED; - -struct gg_msg_richtext { - uint8_t flag; - uint16_t length; -} GG_PACKED; - -/** - * Struktura opisująca formatowanie tekstu. W zależności od wartości pola - * \c font, zaraz za tą strukturą może wystąpić \c gg_msg_richtext_color - * lub \c gg_msg_richtext_image. - * - * \ingroup messages - */ -struct gg_msg_richtext_format { - uint16_t position; /**< Początkowy znak formatowania (liczony od 0) */ - uint8_t font; /**< Atrybuty formatowania */ -} GG_PACKED; - -#ifndef DOXYGEN - -#define GG_FONT_BOLD 0x01 -#define GG_FONT_ITALIC 0x02 -#define GG_FONT_UNDERLINE 0x04 -#define GG_FONT_COLOR 0x08 -#define GG_FONT_IMAGE 0x80 - -#else - -/** - * Atrybuty formatowania wiadomości. - * - * \ingroup messages - */ -enum { - GG_FONT_BOLD, - GG_FONT_ITALIC, - GG_FONT_UNDERLINE, - GG_FONT_COLOR, - GG_FONT_IMAGE -}; - -#endif /* DOXYGEN */ - -/** - * Struktura opisującą kolor tekstu dla atrybutu \c GG_FONT_COLOR. - * - * \ingroup messages - */ -struct gg_msg_richtext_color { - uint8_t red; /**< Składowa czerwona koloru */ - uint8_t green; /**< Składowa zielona koloru */ - uint8_t blue; /**< Składowa niebieska koloru */ -} GG_PACKED; - -/** - * Strukturya opisująca obrazek wstawiony do wiadomości dla atrubutu - * \c GG_FONT_IMAGE. - * - * \ingroup messages - */ -struct gg_msg_richtext_image { - uint16_t unknown1; /**< Nieznane pole o wartości 0x0109 */ - uint32_t size; /**< Rozmiar obrazka */ - uint32_t crc32; /**< Suma kontrolna CRC32 obrazka */ -} GG_PACKED; - -struct gg_msg_recipients { - uint8_t flag; - uint32_t count; -} GG_PACKED; - -struct gg_msg_image_request { - uint8_t flag; - uint32_t size; - uint32_t crc32; -} GG_PACKED; - -struct gg_msg_image_reply { - uint8_t flag; - uint32_t size; - uint32_t crc32; - /* char filename[]; */ - /* char image[]; */ -} GG_PACKED; - -#define GG_SEND_MSG_ACK 0x0005 - -#ifndef DOXYGEN - -#define GG_ACK_BLOCKED 0x0001 -#define GG_ACK_DELIVERED 0x0002 -#define GG_ACK_QUEUED 0x0003 -#define GG_ACK_MBOXFULL 0x0004 -#define GG_ACK_NOT_DELIVERED 0x0006 - -#else - -/** - * Status doręczenia wiadomości. - * - * \ingroup messages - */ -enum -{ - GG_ACK_DELIVERED, /**< Wiadomość dostarczono. */ - GG_ACK_QUEUED, /**< Wiadomość zakolejkowano z powodu niedostępności odbiorcy. */ - GG_ACK_BLOCKED, /**< Wiadomość zablokowana przez serwer (spam, świąteczne ograniczenia itd.) */ - GG_ACK_MBOXFULL, /**< Wiadomości nie dostarczono z powodu zapełnionej kolejki wiadomości odbiorcy. */ - GG_ACK_NOT_DELIVERED /**< Wiadomości nie dostarczono (tylko dla \c GG_CLASS_CTCP). */ -}; - -#endif /* DOXYGEN */ - -struct gg_send_msg_ack { - uint32_t status; - uint32_t recipient; - uint32_t seq; -} GG_PACKED; - -#define GG_RECV_MSG 0x000a - -struct gg_recv_msg { - uint32_t sender; - uint32_t seq; - uint32_t time; - uint32_t msgclass; -} GG_PACKED; - -#define GG_PING 0x0008 - -#define GG_PONG 0x0007 - -#define GG_DISCONNECTING 0x000b - -#define GG_USERLIST_REQUEST 0x0016 - -#define GG_XML_EVENT 0x0027 - -#ifndef DOXYGEN - -#define GG_USERLIST_PUT 0x00 -#define GG_USERLIST_PUT_MORE 0x01 -#define GG_USERLIST_GET 0x02 - -#else - -/** - * \ingroup importexport - * - * Rodzaj zapytania. - */ -enum { - GG_USERLIST_PUT, /**< Eksport listy kontaktów. */ - GG_USERLIST_GET, /**< Import listy kontaktów. */ -}; - -#endif /* DOXYGEN */ - -struct gg_userlist_request { - uint8_t type; -} GG_PACKED; - -#define GG_USERLIST_REPLY 0x0010 - -#ifndef DOXYGEN - -#define GG_USERLIST_PUT_REPLY 0x00 -#define GG_USERLIST_PUT_MORE_REPLY 0x02 -#define GG_USERLIST_GET_REPLY 0x06 -#define GG_USERLIST_GET_MORE_REPLY 0x04 - -#else - -/** - * \ingroup importexport - * - * Rodzaj odpowiedzi. - */ -enum { - GG_USERLIST_PUT_REPLY, /**< Wyeksportowano listy kontaktów. */ - GG_USERLIST_GET_REPLY, /**< Zaimportowano listę kontaktów. */ -}; - -#endif /* DOXYGEN */ - -struct gg_userlist_reply { - uint8_t type; -} GG_PACKED; - -#ifndef DOXYGEN - -#define GG_USERLIST100_PUT 0x00 -#define GG_USERLIST100_GET 0x02 - -#else - -/** - * \ingroup importexport - * - * Rodzaj zapytania (10.0). - */ -enum { - GG_USERLIST100_PUT, /**< Eksport listy kontaktów. */ - GG_USERLIST100_GET, /**< Import listy kontaktów. */ -}; - -#endif /* DOXYGEN */ - -#ifndef DOXYGEN - -#define GG_USERLIST100_FORMAT_TYPE_NONE 0x00 -#define GG_USERLIST100_FORMAT_TYPE_GG70 0x01 -#define GG_USERLIST100_FORMAT_TYPE_GG100 0x02 - -#else - -/** - * \ingroup importexport - * - * Typ formatu listy kontaktów (10.0). - */ -enum { - GG_USERLIST100_FORMAT_TYPE_NONE, /**< Brak treści listy kontaktów. */ - GG_USERLIST100_FORMAT_TYPE_GG70, /**< Format listy kontaktów zgodny z Gadu-Gadu 7.0. */ - GG_USERLIST100_FORMAT_TYPE_GG100, /**< Format listy kontaktów zgodny z Gadu-Gadu 10.0. */ -}; - -#endif /* DOXYGEN */ - -#ifndef DOXYGEN - -#define GG_USERLIST100_REPLY_LIST 0x00 -#define GG_USERLIST100_REPLY_UPTODATE 0x01 -#define GG_USERLIST100_REPLY_ACK 0x10 -#define GG_USERLIST100_REPLY_REJECT 0x12 - -#else - -/** - * \ingroup importexport - * - * Typ odpowiedzi listy kontaktów (10.0). - */ -enum { - GG_USERLIST100_REPLY_LIST, /**< W odpowiedzi znajduje się aktualna lista kontaktów na serwerze. */ - GG_USERLIST100_REPLY_UPTODATE, /**< Komunikat o tym, że lista kontaktów jest już zsynchronizowana. */ - GG_USERLIST100_REPLY_ACK, /**< Potwierdzenie odebrania nowej wersji listy kontaktów. W polu \c gg_userlist100_reply.version znajduje się numer nowej wersji listy kontaktów. */ - GG_USERLIST100_REPLY_REJECT, /**< Odmowa przyjęcia nowej wersji listy kontaktów. W polu \c gg_userlist100_reply.version znajduje się numer wersji listy kontaktów aktualnie przechowywanej przez serwer. */ -}; - -#endif /* DOXYGEN */ - -struct gg_dcc_tiny_packet { - uint8_t type; /* rodzaj pakietu */ -} GG_PACKED; - -struct gg_dcc_small_packet { - uint32_t type; /* rodzaj pakietu */ -} GG_PACKED; - -struct gg_dcc_big_packet { - uint32_t type; /* rodzaj pakietu */ - uint32_t dunno1; /* niewiadoma */ - uint32_t dunno2; /* niewiadoma */ -} GG_PACKED; - -/* - * póki co, nie znamy dokładnie protokołu. nie wiemy, co czemu odpowiada. - * nazwy są niepoważne i tymczasowe. - */ -#define GG_DCC_WANT_FILE 0x0003 /* peer chce plik */ -#define GG_DCC_HAVE_FILE 0x0001 /* więc mu damy */ -#define GG_DCC_HAVE_FILEINFO 0x0003 /* niech ma informacje o pliku */ -#define GG_DCC_GIMME_FILE 0x0006 /* peer jest pewny */ -#define GG_DCC_CATCH_FILE 0x0002 /* wysyłamy plik */ - -#define GG_DCC_FILEATTR_READONLY 0x0020 - -#define GG_DCC_TIMEOUT_SEND 1800 /* 30 minut */ -#define GG_DCC_TIMEOUT_GET 1800 /* 30 minut */ -#define GG_DCC_TIMEOUT_FILE_ACK 300 /* 5 minut */ -#define GG_DCC_TIMEOUT_VOICE_ACK 300 /* 5 minut */ - -#define GG_DCC7_INFO 0x1f - -struct gg_dcc7_info { - uint32_t uin; /* numer nadawcy */ - uint32_t type; /* sposób połączenia */ - gg_dcc7_id_t id; /* identyfikator połączenia */ - char info[GG_DCC7_INFO_LEN]; /* informacje o połączeniu "ip port" */ - char hash[GG_DCC7_INFO_HASH_LEN];/* skrót "ip" */ -} GG_PACKED; - -#define GG_DCC7_NEW 0x20 - -struct gg_dcc7_new { - gg_dcc7_id_t id; /* identyfikator połączenia */ - uint32_t uin_from; /* numer nadawcy */ - uint32_t uin_to; /* numer odbiorcy */ - uint32_t type; /* rodzaj transmisji */ - unsigned char filename[GG_DCC7_FILENAME_LEN]; /* nazwa pliku */ - uint32_t size; /* rozmiar pliku */ - uint32_t size_hi; /* rozmiar pliku (starsze bajty) */ - unsigned char hash[GG_DCC7_HASH_LEN]; /* hash SHA1 */ -} GG_PACKED; - -#define GG_DCC7_ACCEPT 0x21 - -struct gg_dcc7_accept { - uint32_t uin; /* numer przyjmującego połączenie */ - gg_dcc7_id_t id; /* identyfikator połączenia */ - uint32_t offset; /* offset przy wznawianiu transmisji */ - uint32_t dunno1; /* 0x00000000 */ -} GG_PACKED; - -/* XXX API */ -#define GG_DCC7_TYPE_P2P 0x00000001 /**< Połączenie bezpośrednie */ -#define GG_DCC7_TYPE_SERVER 0x00000002 /**< Połączenie przez serwer */ - -#define GG_DCC7_REJECT 0x22 - -struct gg_dcc7_reject { - uint32_t uin; /**< Numer odrzucającego połączenie */ - gg_dcc7_id_t id; /**< Identyfikator połączenia */ - uint32_t reason; /**< Powód rozłączenia */ -} GG_PACKED; - -/* XXX API */ -#define GG_DCC7_REJECT_BUSY 0x00000001 /**< Połączenie bezpośrednie już trwa, nie umiem obsłużyć więcej */ -#define GG_DCC7_REJECT_USER 0x00000002 /**< Użytkownik odrzucił połączenie */ -#define GG_DCC7_REJECT_VERSION 0x00000006 /**< Druga strona ma wersję klienta nieobsługującą połączeń bezpośrednich tego typu */ - -#define GG_DCC7_ID_REQUEST 0x23 - -struct gg_dcc7_id_request { - uint32_t type; /**< Rodzaj tranmisji */ -} GG_PACKED; - -/* XXX API */ -#define GG_DCC7_TYPE_VOICE 0x00000001 /**< Transmisja głosu */ -#define GG_DCC7_TYPE_FILE 0x00000004 /**< transmisja pliku */ - -#define GG_DCC7_ID_REPLY 0x23 - -struct gg_dcc7_id_reply { - uint32_t type; /** Rodzaj transmisji */ - gg_dcc7_id_t id; /** Przyznany identyfikator */ -} GG_PACKED; - -#define GG_DCC7_DUNNO1 0x24 - -#define GG_DCC7_TIMEOUT_CONNECT 10 /* 10 sekund */ -#define GG_DCC7_TIMEOUT_SEND 1800 /* 30 minut */ -#define GG_DCC7_TIMEOUT_GET 1800 /* 30 minut */ -#define GG_DCC7_TIMEOUT_FILE_ACK 300 /* 5 minut */ -#define GG_DCC7_TIMEOUT_VOICE_ACK 300 /* 5 minut */ - -#define GG_CHAT_INFO_UPDATE_ENTERED 0x01 -#define GG_CHAT_INFO_UPDATE_EXITED 0x03 - -#ifdef __cplusplus -} -#endif - -#ifdef _WIN32 -#pragma pack(pop) -#endif - -#endif /* LIBGADU_LIBGADU_H */ - -/* - * Local variables: - * c-indentation-style: k&r - * c-basic-offset: 8 - * indent-tabs-mode: notnil - * End: - * - * vim: shiftwidth=8: - */
--- a/libpurple/protocols/gg/lib/message.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1016 +0,0 @@ -/* - * (C) Copyright 2001-2010 Wojtek Kaniewski <wojtekka@irc.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file message.c - * - * \brief Obsługa wiadomości - * - * Plik zawiera funkcje dotyczące obsługi "klasy" gg_message_t, które - * w przyszłości zostaną dołączone do API. Obecnie używane są funkcje - * konwersji między tekstem z atrybutami i HTML. - */ - -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <limits.h> -#include <ctype.h> -#include <assert.h> - -#include "message.h" - -#if 0 - -gg_message_t *gg_message_new(void) -{ - gg_message_t *gm; - - gm = malloc(sizeof(gg_message_t)); - - if (gm == NULL) - return NULL; - - memset(gm, 0, sizeof(gg_message_t)); - - gm->msgclass = GG_CLASS_CHAT; - gm->seq = (uint32_t) -1; - - return gm; -} - -int gg_message_init(gg_message_t *gm, int msgclass, int seq, uin_t *recipients, - size_t recipient_count, char *text, char *html, char *attributes, - size_t attributes_length, int auto_convert) -{ - GG_MESSAGE_CHECK(gm, -1); - - memset(gm, 0, sizeof(gg_message_t)); - gm->recipients = recipients; - gm->recipient_count = recipient_count; - gm->text = text; - gm->html = html; - gm->attributes = attributes; - gm->attributes_length = attributes_length; - gm->msgclass = msgclass; - gm->seq = seq; - gm->auto_convert = auto_convert; - - return 0; -} - -void gg_message_free(gg_message_t *gm) -{ - if (gm == NULL) { - errno = EINVAL; - return; - } - - free(gm->text); - free(gm->text_converted); - free(gm->html); - free(gm->html_converted); - free(gm->recipients); - free(gm->attributes); - - free(gm); -} - -int gg_message_set_auto_convert(gg_message_t *gm, int auto_convert) -{ - GG_MESSAGE_CHECK(gm, -1); - - gm->auto_convert = !!auto_convert; - - if (!gm->auto_convert) { - free(gm->text_converted); - free(gm->html_converted); - gm->text_converted = NULL; - gm->html_converted = NULL; - } - - return 0; -} - -int gg_message_get_auto_convert(gg_message_t *gm) -{ - GG_MESSAGE_CHECK(gm, -1); - - return gm->auto_convert; -} - -int gg_message_set_recipients(gg_message_t *gm, const uin_t *recipients, size_t recipient_count) -{ - GG_MESSAGE_CHECK(gm, -1); - - if (recipient_count >= INT_MAX / sizeof(uin_t)) { - errno = EINVAL; - return -1; - } - - if ((recipients == NULL) || (recipient_count == 0)) { - free(gm->recipients); - gm->recipients = NULL; - gm->recipient_count = 0; - } else { - uin_t *tmp; - - tmp = realloc(gm->recipients, recipient_count * sizeof(uin_t)); - - if (tmp == NULL) - return -1; - - memcpy(tmp, recipients, recipient_count * sizeof(uin_t)); - - gm->recipients = tmp; - gm->recipient_count = recipient_count; - } - - return 0; -} - -int gg_message_set_recipient(gg_message_t *gm, uin_t recipient) -{ - return gg_message_set_recipients(gm, &recipient, 1); -} - -int gg_message_get_recipients(gg_message_t *gm, const uin_t **recipients, size_t *recipient_count) -{ - GG_MESSAGE_CHECK(gm, -1); - - if (recipients != NULL) - *recipients = gm->recipients; - - if (recipient_count != NULL) - *recipient_count = gm->recipient_count; - - return 0; -} - -uin_t gg_message_get_recipient(gg_message_t *gm) -{ - GG_MESSAGE_CHECK(gm, (uin_t) -1); - - if ((gm->recipients == NULL) || (gm->recipient_count < 1)) { - /* errno = XXX; */ - return (uin_t) -1; - } - - return gm->recipients[0]; -} - -int gg_message_set_class(gg_message_t *gm, uint32_t msgclass) -{ - GG_MESSAGE_CHECK(gm, -1); - - gm->msgclass = msgclass; - - return 0; -} - -uint32_t gg_message_get_class(gg_message_t *gm) -{ - GG_MESSAGE_CHECK(gm, (uint32_t) -1); - - return gm->msgclass; -} - -int gg_message_set_seq(gg_message_t *gm, uint32_t seq) -{ - GG_MESSAGE_CHECK(gm, -1); - - gm->seq = seq; - - return 0; -} - -uint32_t gg_message_get_seq(gg_message_t *gm) -{ - GG_MESSAGE_CHECK(gm, (uint32_t) -1); - - return gm->seq; -} - -int gg_message_set_text(gg_message_t *gm, const char *text) -{ - GG_MESSAGE_CHECK(gm, -1); - - if (text == NULL) { - free(gm->text); - gm->text = NULL; - } else { - char *tmp; - - tmp = strdup(text); - - if (tmp == NULL) - return -1; - - free(gm->text); - gm->text = tmp; - } - - free(gm->html_converted); - gm->html_converted = NULL; - - return 0; -} - -const char *gg_message_get_text(gg_message_t *gm) -{ - GG_MESSAGE_CHECK(gm, NULL); - - if (gm->text_converted != NULL) - return gm->text_converted; - - if (gm->text == NULL && gm->html != NULL && gm->auto_convert) { - size_t len; - - free(gm->text_converted); - - len = gg_message_html_to_text(NULL, gm->html); - - gm->text_converted = malloc(len + 1); - - if (gm->text_converted == NULL) - return NULL; - - gg_message_html_to_text(gm->text_converted, gm->html); - - return gm->text_converted; - } - - return gm->text; -} - -int gg_message_set_html(gg_message_t *gm, const char *html) -{ - GG_MESSAGE_CHECK(gm, -1); - - if (html == NULL) { - free(gm->html); - gm->html = NULL; - } else { - char *tmp; - - tmp = strdup(html); - - if (tmp == NULL) - return -1; - - free(gm->html); - gm->html = tmp; - } - - free(gm->text_converted); - gm->text_converted = NULL; - - return 0; -} - -const char *gg_message_get_html(gg_message_t *gm) -{ - GG_MESSAGE_CHECK(gm, NULL); - - if (gm->html_converted != NULL) - return gm->html_converted; - - if (gm->html == NULL && gm->text != NULL && gm->auto_convert) { - size_t len; - - free(gm->html_converted); - - len = gg_message_text_to_html(NULL, gm->text, GG_ENCODING_UTF8, gm->attributes, gm->attributes_length); - - gm->html_converted = malloc(len + 1); - - if (gm->html_converted == NULL) - return NULL; - - gg_message_text_to_html(gm->html_converted, gm->text, - GG_ENCODING_UTF8, gm->attributes, gm->attributes_length); - - return gm->html_converted; - } - - return gm->html; -} - -int gg_message_set_attributes(gg_message_t *gm, const char *attributes, size_t length) -{ - GG_MESSAGE_CHECK(gm, -1); - - if (length > 0xfffd) { - /* errno = XXX; */ - return -1; - } - - if ((attributes == NULL) || (length == 0)) { - free(gm->attributes); - gm->attributes = NULL; - gm->attributes_length = 0; - } else { - char *tmp; - - tmp = realloc(gm->attributes, length); - - if (tmp == NULL) - return -1; - - gm->attributes = tmp; - gm->attributes_length = length; - } - - free(gm->html_converted); - gm->html_converted = NULL; - - return 0; -} - -int gg_message_get_attributes(gg_message_t *gm, const char **attributes, size_t *attributes_length) -{ - GG_MESSAGE_CHECK(gm, -1); - - if (attributes != NULL) - *attributes = gm->attributes; - - if (attributes_length != NULL) - *attributes_length = gm->attributes_length; - - return 0; -} - -#endif - -/** - * \internal Dodaje tekst na koniec bufora. - * - * \param dst Wskaźnik na bufor roboczy - * \param pos Wskaźnik na aktualne położenie w buforze roboczym - * \param src Dodawany tekst - * \param len Długość dodawanego tekstu - */ -static void gg_append(char *dst, size_t *pos, const void *src, size_t len) -{ - if (dst != NULL) - memcpy(&dst[*pos], src, len); - - *pos += len; -} - -/** - * \internal Zamienia tekst z formatowaniem Gadu-Gadu na HTML. - * - * \param dst Bufor wynikowy (może być \c NULL) - * \param src Tekst źródłowy - * \param encoding Kodowanie tekstu źródłowego oraz wynikowego - * \param format Atrybuty tekstu źródłowego - * \param format_len Długość bloku atrybutów tekstu źródłowego - * - * \note Wynikowy tekst nie jest idealnym kodem HTML, ponieważ ma jak - * dokładniej odzwierciedlać to, co wygenerowałby oryginalny klient. - * - * \note Dokleja \c \\0 na końcu bufora wynikowego. - * - * \return Długość tekstu wynikowego bez \c \\0 (nawet jeśli \c dst to \c NULL). - */ -size_t gg_message_text_to_html(char *dst, const char *src, - gg_encoding_t encoding, const unsigned char *format, size_t format_len) -{ - const char span_fmt[] = "<span style=\"color:#%02x%02x%02x; font-family:'MS Shell Dlg 2'; font-size:9pt; \">"; - const size_t span_len = 75; - const char img_fmt[] = "<img name=\"%02x%02x%02x%02x%02x%02x%02x%02x\">"; - const size_t img_len = 29; - size_t char_pos = 0; - unsigned char old_attr = 0; - const unsigned char default_color[] = {'\x00', '\x00', '\x00'}; - const unsigned char *old_color = NULL; - int in_span = 0; - unsigned int i; - size_t len = 0; - - if (format == NULL) - format_len = 0; - - /* Pętla przechodzi też przez kończące \0, żeby móc dokleić obrazek - * na końcu tekstu. */ - - for (i = 0; ; i++) { - int in_char = 0; - size_t format_idx = 0; - - /* Sprawdź, czy bajt jest kontynuacją znaku UTF-8. */ - if (encoding == GG_ENCODING_UTF8 && (src[i] & 0xc0) == 0x80) - in_char = 1; - - /* GG_FONT_IMAGE powinno dotyczyć tylko jednego znaku, więc czyścimy stary atrybut */ - - if (!in_char && (old_attr & GG_FONT_IMAGE) != 0) - old_attr &= ~GG_FONT_IMAGE; - - /* Analizuj wszystkie atrybuty dotyczące aktualnego znaku. */ - for (;;) { - unsigned char attr; - size_t attr_pos; - - /* Nie wstawiamy niczego wewnątrz wielobajtowego znaku UTF-8. */ - if (in_char) - break; - - if (format_idx + 3 > format_len) - break; - - /* (format_idx + 3 <= format_len) && (format_idx > 0) - * 3 < format_len - * 0 != format_len - * format != NULL - */ - assert(format != NULL); - - attr_pos = format[format_idx] | (format[format_idx + 1] << 8); - attr = format[format_idx + 2]; - - /* Nie doklejaj atrybutów na końcu, co najwyżej obrazki. */ - - if (src[i] == 0) - attr &= ~(GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR); - - format_idx += 3; - - if (attr_pos != char_pos) { - if ((attr & GG_FONT_COLOR) != 0) - format_idx += 3; - if ((attr & GG_FONT_IMAGE) != 0) - format_idx += 10; - - continue; - } - - if ((old_attr & GG_FONT_UNDERLINE) != 0) - gg_append(dst, &len, "</u>", 4); - - if ((old_attr & GG_FONT_ITALIC) != 0) - gg_append(dst, &len, "</i>", 4); - - if ((old_attr & GG_FONT_BOLD) != 0) - gg_append(dst, &len, "</b>", 4); - - if ((attr & (GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR)) != 0) { - const unsigned char *color; - - if (((attr & GG_FONT_COLOR) != 0) && (format_idx + 3 <= format_len)) { - color = &format[format_idx]; - format_idx += 3; - } else { - color = default_color; - } - - if (old_color == NULL || memcmp(color, old_color, 3) != 0) { - if (in_span) { - gg_append(dst, &len, "</span>", 7); - in_span = 0; - } - - if (src[i] != 0) { - if (dst != NULL) - sprintf(&dst[len], span_fmt, color[0], color[1], color[2]); - - len += span_len; - in_span = 1; - old_color = color; - } - } - } - - if ((attr & GG_FONT_BOLD) != 0) - gg_append(dst, &len, "<b>", 3); - - if ((attr & GG_FONT_ITALIC) != 0) - gg_append(dst, &len, "<i>", 3); - - if ((attr & GG_FONT_UNDERLINE) != 0) - gg_append(dst, &len, "<u>", 3); - - if (((attr & GG_FONT_IMAGE) != 0) && (format_idx + 10 <= format_len)) { - if (dst != NULL) { - sprintf(&dst[len], img_fmt, - format[format_idx + 9], - format[format_idx + 8], - format[format_idx + 7], - format[format_idx + 6], - format[format_idx + 5], - format[format_idx + 4], - format[format_idx + 3], - format[format_idx + 2]); - } - - len += img_len; - format_idx += 10; - } - - old_attr = attr; - } - - if (src[i] == 0) - break; - - /* Znaki oznaczone jako GG_FONT_IMAGE nie są częścią wiadomości. */ - - if ((old_attr & GG_FONT_IMAGE) != 0) { - if (!in_char) - char_pos++; - - continue; - } - - /* Jesteśmy na początku tekstu i choć nie było atrybutów dla pierwszego - * znaku, ponieważ tekst nie jest pusty, trzeba otworzyć <span>. */ - - if (!in_span) { - if (dst != NULL) - sprintf(&dst[len], span_fmt, default_color[0], default_color[1], default_color[2]); - - len += span_len; - in_span = 1; - old_color = default_color; - } - - /* Doklej znak zachowując htmlowe escapowanie. */ - - switch (src[i]) { - case '&': - gg_append(dst, &len, "&", 5); - break; - case '<': - gg_append(dst, &len, "<", 4); - break; - case '>': - gg_append(dst, &len, ">", 4); - break; - case '\'': - gg_append(dst, &len, "'", 6); - break; - case '\"': - gg_append(dst, &len, """, 6); - break; - case '\n': - gg_append(dst, &len, "<br>", 4); - break; - case '\r': - break; - default: - if (dst != NULL) - dst[len] = src[i]; - len++; - } - - if (!in_char) - char_pos++; - } - - /* Zamknij tagi. */ - - if ((old_attr & GG_FONT_UNDERLINE) != 0) - gg_append(dst, &len, "</u>", 4); - - if ((old_attr & GG_FONT_ITALIC) != 0) - gg_append(dst, &len, "</i>", 4); - - if ((old_attr & GG_FONT_BOLD) != 0) - gg_append(dst, &len, "</b>", 4); - - if (in_span) - gg_append(dst, &len, "</span>", 7); - - if (dst != NULL) - dst[len] = 0; - - return len; -} - -/** - * \internal Dokleja nowe atrybuty formatowania, jeśli konieczne, oraz inkrementuje pozycję znaku w tekście. - * - * \param pos Wskaźnik na zmienną przechowującą pozycję znaku w tekście - * \param attr_flag Aktualna flaga atrybutu formatowania - * \param old_attr_flag Wskaźnik na poprzednią flagę atrybutu formatowania - * \param color Wskaźnik na tablicę z aktualnym kolorem RGB (jeśli \p attr_flag - * nie zawiera flagi \c GG_FONT_COLOR, ignorowane) - * \param old_color Wskaźnik na tablicę z poprzednim kolorem RGB - * \param imgs_size Rozmiar atrybutów formatowania obrazków znajdujących się - * obecnie w tablicy atrybutów formatowania, w bajtach - * \param format Wskaźnik na wskaźnik do tablicy atrybutów formatowania - * \param format_len Wskaźnik na zmienną zawierającą długość tablicy atrybutów - * formatowania, w bajtach (może być \c NULL) - */ -static void gg_after_append_formatted_char(uint16_t *pos, - unsigned char attr_flag, unsigned char *old_attr_flag, - const unsigned char *color, unsigned char *old_color, size_t imgs_size, - unsigned char **format, size_t *format_len) -{ - const size_t color_size = 3; - int has_color = 0; - - if ((attr_flag & GG_FONT_COLOR) != 0) - has_color = 1; - - if (*old_attr_flag != attr_flag || (has_color && memcmp(old_color, color, color_size) != 0)) { - size_t attr_size = sizeof(*pos) + sizeof(attr_flag) + (has_color ? color_size : 0); - - if (*format != NULL) { - /* Staramy się naśladować oryginalnego klienta i atrybuty obrazków trzymamy na końcu */ - - *format -= imgs_size; - memmove(*format + attr_size, *format, imgs_size); - - **format = (unsigned char) (*pos & (uint16_t) 0x00ffU); - *format += 1; - **format = (unsigned char) ((*pos & (uint16_t) 0xff00U) >> 8); - *format += 1; - - **format = attr_flag; - *format += 1; - - if (has_color) { - memcpy(*format, color, color_size); - *format += color_size; - } - - *format += imgs_size; - } - - if (format_len != NULL) - *format_len += attr_size; - - *old_attr_flag = attr_flag; - if (has_color) - memcpy(old_color, color, color_size); - } - - *pos += 1; -} - -/** - * \internal Zamienia tekst w formacie HTML na czysty tekst. - * - * \param dst Bufor wynikowy (może być \c NULL) - * \param format Bufor wynikowy z atrybutami formatowania (może być \c NULL) - * \param format_len Wskaźnik na zmienną, do której zostanie zapisana potrzebna - * wielkość bufora wynikowego z atrybutami formatowania, - * w bajtach (może być \c NULL) - * \param html Tekst źródłowy - * \param encoding Kodowanie tekstu źródłowego oraz wynikowego - * - * \note Dokleja \c \\0 na końcu bufora wynikowego. - * - * \return Długość bufora wynikowego bez \c \\0 (nawet jeśli \c dst to \c NULL). - */ -size_t gg_message_html_to_text(char *dst, unsigned char *format, - size_t *format_len, const char *html, gg_encoding_t encoding) -{ - const char *src, *entity = NULL, *tag = NULL; - int in_tag = 0, in_entity = 0, in_bold = 0, in_italic = 0, in_underline = 0; - unsigned char color[3] = { 0 }, old_color[3] = { 0 }; - unsigned char attr_flag = 0, old_attr_flag = 0; - uint16_t pos = 0; - size_t len = 0, imgs_size = 0; - - if (format_len != NULL) - *format_len = 0; - - for (src = html; *src != 0; src++) { - if (in_entity && !(isalnum(*src) || *src == '#' || *src == ';')) { - int first = 1; - size_t i, append_len = src - entity; - - gg_append(dst, &len, entity, append_len); - for (i = 0; i < append_len; i++) { - if (encoding != GG_ENCODING_UTF8 || (entity[i] & 0xc0) != 0x80) { - if (first) { - gg_after_append_formatted_char(&pos, attr_flag, - &old_attr_flag, color, old_color, imgs_size, - &format, format_len); - first = 0; - } else { - pos++; - } - } - } - - in_entity = 0; - } - - if (*src == '<') { - tag = src; - in_tag = 1; - continue; - } - - if (in_tag && (*src == '>')) { - if (strncmp(tag, "<br", 3) == 0) { - if (dst != NULL) - dst[len] = '\n'; - len++; - - gg_after_append_formatted_char(&pos, attr_flag, - &old_attr_flag, color, old_color, - imgs_size, &format, format_len); - } else if (strncmp(tag, "<img name=\"", 11) == 0 || strncmp(tag, "<img name=\'", 11) == 0) { - tag += 11; - - /* 17 bo jeszcze cudzysłów musi być zamknięty */ - if (tag + 17 <= src) { - int i, ok = 1; - - for (i = 0; i < 16; i++) { - if (!isxdigit(tag[i])) { - ok = 0; - break; - } - } - - if (ok) { - unsigned char img_attr[13]; - - if (format != NULL) { - char buf[3] = { 0 }; - - img_attr[0] = (unsigned char) (pos & (uint16_t) 0x00ffU); - img_attr[1] = (unsigned char) ((pos & (uint16_t) 0xff00U) >> 8); - img_attr[2] = GG_FONT_IMAGE; - img_attr[3] = '\x09'; - img_attr[4] = '\x01'; - for (i = 0; i < 16; i += 2) { - buf[0] = tag[i]; - buf[1] = tag[i + 1]; - /* buf[2] to '\0' */ - img_attr[12 - i / 2] = - (unsigned char)strtoul(buf, NULL, 16); - } - - memcpy(format, img_attr, sizeof(img_attr)); - format += sizeof(img_attr); - } - - if (format_len != NULL) - *format_len += sizeof(img_attr); - imgs_size += sizeof(img_attr); - - if (dst != NULL) { - if (encoding == GG_ENCODING_UTF8) - dst[len++] = '\xc2'; - dst[len++] = '\xa0'; - } else { - len += 2; - } - - /* Nie używamy tutaj gg_after_append_formatted_char(). - * Po pierwsze to praktycznie niczego by nie - * zmieniło, a po drugie nie wszystkim klientom - * mogłaby się spodobać redefinicja atrybutów - * formatowania dla jednego znaku (bo np. najpierw - * byśmy zdefiniowali bolda od znaku 10, a potem - * by się okazało, że znak 10 to obrazek). - */ - - pos++; - - /* Resetujemy atrybuty, aby je w razie czego - * redefiniować od następnego znaku, co by sobie - * nikt przypadkiem nie pomyślał, że GG_FONT_IMAGE - * dotyczy więcej, niż jednego znaku. - * Tak samo robi oryginalny klient. - */ - - old_attr_flag = -1; - } - } - } else if (strncmp(tag, "<b>", 3) == 0) { - in_bold++; - attr_flag |= GG_FONT_BOLD; - } else if (strncmp(tag, "</b>", 4) == 0) { - if (in_bold > 0) { - in_bold--; - if (in_bold == 0) - attr_flag &= ~GG_FONT_BOLD; - } - } else if (strncmp(tag, "<i>", 3) == 0) { - in_italic++; - attr_flag |= GG_FONT_ITALIC; - } else if (strncmp(tag, "</i>", 4) == 0) { - if (in_italic > 0) { - in_italic--; - if (in_italic == 0) - attr_flag &= ~GG_FONT_ITALIC; - } - } else if (strncmp(tag, "<u>", 3) == 0) { - in_underline++; - attr_flag |= GG_FONT_UNDERLINE; - } else if (strncmp(tag, "</u>", 4) == 0) { - if (in_underline > 0) { - in_underline--; - if (in_underline == 0) - attr_flag &= ~GG_FONT_UNDERLINE; - } - } else if (strncmp(tag, "<span ", 6) == 0) { - for (tag += 6; tag < src - 8; tag++) { - if (*tag == '\"' || *tag == '\'' || *tag == ' ') { - if (strncmp(tag + 1, "color:#", 7) == 0) { - int i, ok = 1; - char buf[3] = { 0 }; - - tag += 8; - if (tag + 6 > src) - break; - - for (i = 0; i < 6; i++) { - if (!isxdigit(tag[i])) { - ok = 0; - break; - } - } - - if (!ok) - break; - - for (i = 0; i < 6; i += 2) { - buf[0] = tag[i]; - buf[1] = tag[i + 1]; - /* buf[2] to '\0' */ - color[i / 2] = (unsigned char) strtoul(buf, NULL, 16); - } - - attr_flag |= GG_FONT_COLOR; - } - } - } - } else if (strncmp(tag, "</span", 6) == 0) { - /* Można by trzymać kolory na stosie i tutaj - * przywracać poprzedni, ale to raczej zbędne */ - - attr_flag &= ~GG_FONT_COLOR; - } - - tag = NULL; - in_tag = 0; - continue; - } - - if (in_tag) - continue; - - if (*src == '&') { - in_entity = 1; - entity = src; - continue; - } - - if (in_entity && *src == ';') { - in_entity = 0; - - if (dst != NULL) { - if (strncmp(entity, "<", 4) == 0) - dst[len++] = '<'; - else if (strncmp(entity, ">", 4) == 0) - dst[len++] = '>'; - else if (strncmp(entity, """, 6) == 0) - dst[len++] = '"'; - else if (strncmp(entity, "'", 6) == 0) - dst[len++] = '\''; - else if (strncmp(entity, "&", 5) == 0) - dst[len++] = '&'; - else if (strncmp(entity, " ", 6) == 0) { - if (encoding == GG_ENCODING_UTF8) - dst[len++] = '\xc2'; - dst[len++] = '\xa0'; - } else - dst[len++] = '?'; - } else { - if (strncmp(entity, " ", 6) == 0) - len += 2; - else - len++; - } - - gg_after_append_formatted_char(&pos, attr_flag, - &old_attr_flag, color, old_color, imgs_size, - &format, format_len); - - continue; - } - - if (in_entity && !(isalnum(*src) || *src == '#')) - in_entity = 0; - - if (in_entity) - continue; - - if (dst != NULL) - dst[len] = *src; - len++; - - if (encoding != GG_ENCODING_UTF8 || (*src & 0xc0) != 0x80) { - gg_after_append_formatted_char(&pos, attr_flag, - &old_attr_flag, color, old_color, imgs_size, - &format, format_len); - } - } - - if (dst != NULL) - dst[len] = '\0'; - - return len; -} - -static size_t gg_message_html_to_text_110_buff(char *dst, const char *html) -{ - return gg_message_html_to_text(dst, NULL, NULL, html, GG_ENCODING_UTF8); -} - -static size_t gg_message_text_to_html_110_buff(char *dst, const char *text, - ssize_t text_len) -{ - size_t i, dst_len; - - if (text_len == -1) - text_len = strlen(text); - dst_len = 0; - - gg_append(dst, &dst_len, "<span>", 6); - - for (i = 0; i < (size_t)text_len; i++) { - char c = text[i]; - if (c == '<') - gg_append(dst, &dst_len, "<", 4); - else if (c == '>') - gg_append(dst, &dst_len, ">", 4); - else if (c == '&') - gg_append(dst, &dst_len, "&", 5); - else if (c == '"') - gg_append(dst, &dst_len, """, 6); - else if (c == '\'') - gg_append(dst, &dst_len, "'", 6); - else if (c == '\n') - gg_append(dst, &dst_len, "<br>", 4); - else if (c == '\r') - continue; - else if (c == '\xc2' && text[i + 1] == '\xa0') { - gg_append(dst, &dst_len, " ", 6); - i++; - } else { - if (dst) - dst[dst_len] = c; - dst_len++; - } - } - - gg_append(dst, &dst_len, "</span>", 7); - - if (dst) - dst[dst_len] = '\0'; - - return dst_len; -} - -char *gg_message_html_to_text_110(const char *html) -{ - size_t dst_len; - char *dst; - - dst_len = gg_message_html_to_text_110_buff(NULL, html) + 1; - dst = malloc(dst_len); - if (!dst) - return NULL; - gg_message_html_to_text_110_buff(dst, html); - - return dst; -} - -char *gg_message_text_to_html_110(const char *text, ssize_t text_len) -{ - size_t dst_len; - char *dst; - - dst_len = gg_message_text_to_html_110_buff(NULL, text, text_len) + 1; - dst = malloc(dst_len); - if (!dst) - return NULL; - gg_message_text_to_html_110_buff(dst, text, text_len); - - return dst; -}
--- a/libpurple/protocols/gg/lib/message.h Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * (C) Copyright 2009 Wojtek Kaniewski <wojtekka@irc.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef LIBGADU_MESSAGE_H -#define LIBGADU_MESSAGE_H - -#include <sys/types.h> -#include "libgadu.h" - -#if 0 - -struct gg_message { - uin_t *recipients; - size_t recipient_count; - char *text; - char *html; - char *attributes; - size_t attributes_length; - uint32_t msgclass; - uint32_t seq; - - int auto_convert; - char *text_converted; - char *html_converted; -}; - -#define GG_MESSAGE_CHECK(gm, result) \ - if ((gm) == NULL) { \ - errno = EINVAL; \ - return (result); \ - } - -int gg_message_init(gg_message_t *gm, int msgclass, int seq, uin_t *recipients, - size_t recipient_count, char *text, char *xhtml, char *attributes, - size_t attributes_length, int auto_convert); - -#endif - -size_t gg_message_html_to_text(char *dst, unsigned char *format, - size_t *format_len, const char *html, gg_encoding_t encoding); -size_t gg_message_text_to_html(char *dst, const char *src, - gg_encoding_t encoding, const unsigned char *format, size_t format_len); - -char * gg_message_html_to_text_110(const char *html); -char * gg_message_text_to_html_110(const char *text, ssize_t text_len); - -#endif /* LIBGADU_MESSAGE_H */
--- a/libpurple/protocols/gg/lib/network.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,310 +0,0 @@ -/* - * (C) Copyright 2011 Wojtek Kaniewski <wojtekka@irc.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#include "network.h" -#include <stdlib.h> -#include <string.h> - -#ifdef _WIN32 - -/* Code losely based on sockerpair implementation by Nathan C. Meyrs. - * The original copyright notice follows: */ - -/* socketpair.c - * Copyright 2007, 2010 by Nathan C. Myers <ncm@cantrip.org> - * This code is Free Software. It may be copied freely, in original or - * modified form, subject only to the restrictions that (1) the author is - * relieved from all responsibilities for any use for any purpose, and (2) - * this copyright notice must be retained, unchanged, in its entirety. If - * for any reason the author might be held responsible for any consequences - * of copying or use, license is withheld. - */ - -int gg_win32_socketpair(int sv[2]) -{ - struct sockaddr_in sin; - socklen_t sin_len = sizeof(sin); - int server = -1; - int tmp = 1; - int errno_copy; - - server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - - sv[0] = -1; - sv[1] = -1; - - if (server == -1) - goto fail; - - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - sin.sin_port = 0; - - if (setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)) == -1) - goto fail; - - if (bind(server, (struct sockaddr*) &sin, sin_len) == -1) - goto fail; - - if (listen(server, 1) == -1) - goto fail; - - if (getsockname(server, (struct sockaddr*) &sin, &sin_len) == -1) - goto fail; - - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - - sv[0] = socket(AF_INET, SOCK_STREAM, 0); - - if (sv[0] == -1) - goto fail; - - if (connect(sv[0], (struct sockaddr*) &sin, sin_len) == -1) - goto fail; - - sv[1] = accept(server, NULL, NULL); - - if (sv[1] == -1) - goto fail; - - close(server); - - return 0; - -fail: - errno_copy = errno; - close(server); - close(sv[0]); - close(sv[1]); - errno = errno_copy; - - return -1; -} - -static int gg_win32_map_wsa_error_to_errno(int wsaewouldblock_map) -{ - int wsa_error; - - wsa_error = WSAGetLastError(); - - /* Tutaj powinny być tłumaczone wszystkie typy błędów sprawdzane przez - * kod libgadu. Dla spójność są również tłumaczone typy błędów ustawiane - * przez libgadu. - * Ponadto gdyby okazało się, że jakaś aplikacja na Win32 chce móc - * polegać jeszcze na innych wartościach errno, można tutaj dodać - * ich tłumaczenie. Najpierw jednak zawsze trzeba porównać dokumentacje, - * aby upewnić się co do poprawności tłumaczenia (patrz WSAEWOULDBLOCK, - * które można tłumaczyć na EWOULDBLOCK lub EAGAIN, a nawet na - * EINPROGRESS w przypadku connect()). - */ - switch (wsa_error) - { - /* Typy błędów sprawdzane przez libgadu. */ - case WSAEINTR: - return EINTR; - case WSAEWOULDBLOCK: - return wsaewouldblock_map; - /* Typy błędów ustawiane przez libgadu. */ - case WSAECONNRESET: - return ECONNRESET; - case WSAEFAULT: - return EFAULT; - case WSAEINVAL: - return EINVAL; - case WSAENOTCONN: - return ENOTCONN; - case WSAETIMEDOUT: - return ETIMEDOUT; - default: - /* Najlepiej zwrócić oryginalny kod błędu. I tak będzie co najwyżej - * wyświetlony w komunikacie debugowym, a tym sposobem będzie łatwiej - * dojść przyczyny problemu. */ - return wsa_error; - } -} - -#undef accept -int gg_win32_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) -{ - int res; - - res = accept(sockfd, addr, addrlen); - - if (res == -1) - errno = gg_win32_map_wsa_error_to_errno(EAGAIN); - - return res; -} - -#undef bind -int gg_win32_bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) -{ - int res; - - res = bind(sockfd, addr, addrlen); - - if (res == -1) - errno = gg_win32_map_wsa_error_to_errno(EAGAIN); - - return res; -} - -int gg_win32_close(int sockfd) -{ - int res; - - res = closesocket(sockfd); - - if (res == -1) - errno = gg_win32_map_wsa_error_to_errno(EAGAIN); - - return res; -} - -#undef connect -int gg_win32_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) -{ - int res; - - res = connect(sockfd, addr, addrlen); - - if (res == -1) - errno = gg_win32_map_wsa_error_to_errno(EINPROGRESS); - - return res; -} - -#undef gethostbyname -struct hostent *gg_win32_gethostbyname(const char *name) -{ - struct hostent *res; - - res = gethostbyname(name); - - if (res == NULL) - errno = gg_win32_map_wsa_error_to_errno(EAGAIN); - - return res; -} - -#undef getsockname -int gg_win32_getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen) -{ - int res; - - res = getsockname(sockfd, addr, addrlen); - - if (res == -1) - errno = gg_win32_map_wsa_error_to_errno(EAGAIN); - - return res; -} - -#undef getsockopt -int gg_win32_getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen) -{ - int res; - - res = getsockopt(sockfd, level, optname, optval, optlen); - - if (res == -1) - errno = gg_win32_map_wsa_error_to_errno(EAGAIN); - - return res; -} - -int gg_win32_ioctl(int d, int request, int *argp) -{ - int res; - - res = ioctlsocket(d, request, (u_long *)argp); - - if (res == -1) - errno = gg_win32_map_wsa_error_to_errno(EAGAIN); - - return res; -} - -#undef listen -int gg_win32_listen(int sockfd, int backlog) -{ - int res; - - res = listen(sockfd, backlog); - - if (res == -1) - errno = gg_win32_map_wsa_error_to_errno(EAGAIN); - - return res; -} - -#undef recv -int gg_win32_recv(int sockfd, void *buf, size_t len, int flags) -{ - int res; - - res = recv(sockfd, buf, len, flags); - - if (res == -1) - errno = gg_win32_map_wsa_error_to_errno(EAGAIN); - - return res; -} - -#undef send -int gg_win32_send(int sockfd, const void *buf, size_t len, int flags) -{ - int res; - - res = send(sockfd, buf, len, flags); - - if (res == -1) - errno = gg_win32_map_wsa_error_to_errno(EAGAIN); - - return res; -} - -#undef setsockopt -int gg_win32_setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) -{ - int res; - - res = setsockopt(sockfd, level, optname, optval, optlen); - - if (res == -1) - errno = gg_win32_map_wsa_error_to_errno(EAGAIN); - - return res; -} - -#undef socket -int gg_win32_socket(int domain, int type, int protocol) -{ - int res; - - res = socket(domain, type, protocol); - - if (res == -1) - errno = gg_win32_map_wsa_error_to_errno(EAGAIN); - - return res; -} - -#endif /* _WIN32 */
--- a/libpurple/protocols/gg/lib/network.h Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl> - * Robert J. Woźny <speedy@ziew.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file network.h - * - * \brief Makra zapewniające kompatybilność API do obsługi sieci na różnych systemach - */ - -#ifndef LIBGADU_NETWORK_H -#define LIBGADU_NETWORK_H - -#ifdef _WIN32 -# include <ws2tcpip.h> -# include <winsock2.h> -# include <stdlib.h> -# include <stdio.h> -# include <errno.h> -/* Obecnie na Win32 tylko MSVC definiuje te typy błędów. Na wypadek, gdyby - * jednak Cygwin bądź MinGW zaczęły je definiować, używamy bardziej ogólnych - * ifdefów. */ -# ifndef ECONNRESET -# define ECONNRESET WSAECONNRESET -# endif -# ifndef EINPROGRESS -# define EINPROGRESS WSAEINPROGRESS -# endif -# ifndef ENOTCONN -# define ENOTCONN WSAENOTCONN -# endif -# ifndef ETIMEDOUT -# define ETIMEDOUT WSAETIMEDOUT -# endif -# define accept gg_win32_accept -# define bind gg_win32_bind -# define close gg_win32_close -# define connect gg_win32_connect -# define gethostbyname gg_win32_gethostbyname -# define getsockname gg_win32_getsockname -# define getsockopt gg_win32_getsockopt -# define ioctl gg_win32_ioctl -# define listen gg_win32_listen -# define recv gg_win32_recv -# define send gg_win32_send -# define setsockopt gg_win32_setsockopt -# define socket gg_win32_socket -# define socketpair(a, b, c, d) gg_win32_socketpair(d) -int gg_win32_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); -int gg_win32_bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); -int gg_win32_close(int sockfd); -int gg_win32_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); -struct hostent *gg_win32_gethostbyname(const char *name); -int gg_win32_getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen); -int gg_win32_getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); -int gg_win32_ioctl(int d, int request, int *argp); -int gg_win32_listen(int sockfd, int backlog); -int gg_win32_recv(int sockfd, void *buf, size_t len, int flags); -int gg_win32_send(int sockfd, const void *buf, size_t len, int flags); -int gg_win32_setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); -int gg_win32_socket(int domain, int type, int protocol); -int gg_win32_socketpair(int sv[2]); - -static inline void gg_win32_init_network(void) -{ - WSADATA wsaData; - - if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { - perror("WSAStartup"); - exit(1); - } -} - -#else -# include <sys/ioctl.h> -# include <sys/types.h> -# include <sys/socket.h> -# include <netinet/in.h> -# include <arpa/inet.h> -# include <netdb.h> -# include <unistd.h> -# ifndef FIONBIO -# include <fcntl.h> -# endif -#endif - -#ifndef INADDR_NONE -# define INADDR_NONE ((in_addr_t) 0xffffffff) -#endif - -#ifndef AF_LOCAL -# define AF_LOCAL AF_UNIX -#endif - -static inline int gg_fd_set_nonblocking(int fd) -{ - int success; -#ifdef FIONBIO - int one = 1; - success = (ioctl(fd, FIONBIO, &one) == 0); -#else - success = (fcntl(fd, F_SETFL, O_NONBLOCK) == 0); -#endif - - return success; -} - -#endif /* LIBGADU_NETWORK_H */
--- a/libpurple/protocols/gg/lib/obsolete.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,250 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2001-2003 Wojtek Kaniewski <wojtekka@irc.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file obsolete.c - * - * \brief Nieaktualne funkcje - * - * Plik zawiera definicje funkcji, które są już nieaktualne ze względu - * na zmiany w protokole. Programy konsolidowane ze starszych wersjami - * bibliotek powinny nadal mieć możliwość działania, mimo ograniczonej - * funkcjonalności. - */ - -/** \cond obsolete */ - -#include <errno.h> -#include <string.h> - -#include "libgadu.h" -#include "internal.h" - -struct gg_http *gg_userlist_get(uin_t uin, const char *passwd, int async) -{ - gg_debug(GG_DEBUG_MISC, "// gg_userlist_get() is obsolete. use gg_userlist_request() instead!\n"); - errno = EINVAL; - return NULL; -} - -int gg_userlist_get_watch_fd(struct gg_http *h) -{ - errno = EINVAL; - return -1; -} - -void gg_userlist_get_free(struct gg_http *h) -{ - -} - -struct gg_http *gg_userlist_put(uin_t uin, const char *password, const char *contacts, int async) -{ - gg_debug(GG_DEBUG_MISC, "// gg_userlist_put() is obsolete. use gg_userlist_request() instead!\n"); - errno = EINVAL; - return NULL; -} - -int gg_userlist_put_watch_fd(struct gg_http *h) -{ - errno = EINVAL; - return -1; -} - -void gg_userlist_put_free(struct gg_http *h) -{ - -} - -struct gg_http *gg_userlist_remove(uin_t uin, const char *passwd, int async) -{ - gg_debug(GG_DEBUG_MISC, "// gg_userlist_remove() is obsolete. use gg_userlist_request() instead!\n"); - errno = EINVAL; - return NULL; -} - -int gg_userlist_remove_watch_fd(struct gg_http *h) -{ - errno = EINVAL; - return -1; -} - -void gg_userlist_remove_free(struct gg_http *h) -{ - -} - -struct gg_http *gg_search(const struct gg_search_request *r, int async) -{ - gg_debug(GG_DEBUG_MISC, "// gg_search() is obsolete. use gg_search50() instead!\n"); - errno = EINVAL; - return NULL; -} - -int gg_search_watch_fd(struct gg_http *h) -{ - errno = EINVAL; - return -1; -} - -void gg_search_free(struct gg_http *h) -{ - -} - -const struct gg_search_request *gg_search_request_mode_0(char *nickname, - char *first_name, char *last_name, char *city, int gender, - int min_birth, int max_birth, int active, int start) -{ - return NULL; -} - -const struct gg_search_request *gg_search_request_mode_1(char *email, int active, int start) -{ - return NULL; -} - -const struct gg_search_request *gg_search_request_mode_2(char *phone, int active, int start) -{ - return NULL; -} - -const struct gg_search_request *gg_search_request_mode_3(uin_t uin, int active, int start) -{ - return NULL; -} - -void gg_search_request_free(struct gg_search_request *r) -{ - -} - -struct gg_http *gg_register(const char *email, const char *password, int async) -{ - gg_debug(GG_DEBUG_MISC, "// gg_register() is obsolete. use gg_register3() instead!\n"); - errno = EINVAL; - return NULL; -} - -struct gg_http *gg_register2(const char *email, const char *password, const char *qa, int async) -{ - gg_debug(GG_DEBUG_MISC, "// gg_register2() is obsolete. use gg_register3() instead!\n"); - errno = EINVAL; - return NULL; -} - -struct gg_http *gg_unregister(uin_t uin, const char *password, const char *email, int async) -{ - gg_debug(GG_DEBUG_MISC, "// gg_unregister() is obsolete. use gg_unregister3() instead!\n"); - errno = EINVAL; - return NULL; -} - -struct gg_http *gg_unregister2(uin_t uin, const char *password, const char *qa, int async) -{ - gg_debug(GG_DEBUG_MISC, "// gg_unregister2() is obsolete. use gg_unregister3() instead!\n"); - errno = EINVAL; - return NULL; -} - - -struct gg_http *gg_change_passwd(uin_t uin, const char *passwd, const char *newpasswd, const char *newemail, int async) -{ - gg_debug(GG_DEBUG_MISC, "// gg_change_passwd() is obsolete. use gg_change_passwd4() instead!\n"); - errno = EINVAL; - return NULL; -} - -struct gg_http *gg_change_passwd2(uin_t uin, const char *passwd, - const char *newpasswd, const char *email, const char *newemail, - int async) -{ - gg_debug(GG_DEBUG_MISC, "// gg_change_passwd2() is obsolete. use gg_change_passwd4() instead!\n"); - errno = EINVAL; - return NULL; -} - -struct gg_http *gg_change_passwd3(uin_t uin, const char *passwd, const char *newpasswd, const char *qa, int async) -{ - gg_debug(GG_DEBUG_MISC, "// gg_change_passwd3() is obsolete. use gg_change_passwd4() instead!\n"); - errno = EINVAL; - return NULL; -} - -struct gg_http *gg_remind_passwd(uin_t uin, int async) -{ - gg_debug(GG_DEBUG_MISC, "// gg_remind_passwd() is obsolete. use gg_remind_passwd3() instead!\n"); - errno = EINVAL; - return NULL; -} - -struct gg_http *gg_remind_passwd2(uin_t uin, const char *tokenid, const char *tokenval, int async) -{ - gg_debug(GG_DEBUG_MISC, "// gg_remind_passwd2() is obsolete. use gg_remind_passwd3() instead!\n"); - errno = EINVAL; - return NULL; -} - -struct gg_http *gg_change_info(uin_t uin, const char *passwd, const struct gg_change_info_request *request, int async) -{ - gg_debug(GG_DEBUG_MISC, "// gg_change_info() is obsolete. use gg_pubdir50() instead\n"); - errno = EINVAL; - return NULL; -} - -struct gg_change_info_request *gg_change_info_request_new( - const char *first_name, const char *last_name, const char *nickname, - const char *email, int born, int gender, const char *city) -{ - return NULL; -} - -void gg_change_info_request_free(struct gg_change_info_request *r) -{ - -} - -int gg_resolve(int *fd, int *pid, const char *hostname) -{ - return -1; -} - -void gg_resolve_pthread_cleanup(void *arg, int kill) -{ - -} - -int gg_resolve_pthread(int *fd, void **resolver, const char *hostname) -{ - return -1; -} - -int gg_pubdir50_handle_reply(struct gg_event *e, const char *packet, int length) -{ - return -1; -} - -void gg_login_hash_sha1(const char *password, uint32_t seed, uint8_t *result) -{ - if (gg_login_hash_sha1_2(password, seed, result) != 0) - memset(result, 0, 20); -} - -/** \endcond */
--- a/libpurple/protocols/gg/lib/packets.pb-c.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2603 +0,0 @@ -/* Generated by the protocol buffer compiler. DO NOT EDIT! */ -/* Generated from: packets.proto */ - -/* Do not generate deprecated warnings for self */ -#ifndef PROTOBUF_C__NO_DEPRECATED -#define PROTOBUF_C__NO_DEPRECATED -#endif - -#include "packets.pb-c.h" -void gg110_login_ok__init - (GG110LoginOK *message) -{ - static GG110LoginOK init_value = GG110_LOGIN_OK__INIT; - *message = init_value; -} -size_t gg110_login_ok__get_packed_size - (const GG110LoginOK *message) -{ - assert(message->base.descriptor == &gg110_login_ok__descriptor); - return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); -} -size_t gg110_login_ok__pack - (const GG110LoginOK *message, - uint8_t *out) -{ - assert(message->base.descriptor == &gg110_login_ok__descriptor); - return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); -} -size_t gg110_login_ok__pack_to_buffer - (const GG110LoginOK *message, - ProtobufCBuffer *buffer) -{ - assert(message->base.descriptor == &gg110_login_ok__descriptor); - return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); -} -GG110LoginOK * - gg110_login_ok__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data) -{ - return (GG110LoginOK *) - protobuf_c_message_unpack (&gg110_login_ok__descriptor, - allocator, len, data); -} -void gg110_login_ok__free_unpacked - (GG110LoginOK *message, - ProtobufCAllocator *allocator) -{ - assert(message->base.descriptor == &gg110_login_ok__descriptor); - protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); -} -void gg110_pong__init - (GG110Pong *message) -{ - static GG110Pong init_value = GG110_PONG__INIT; - *message = init_value; -} -size_t gg110_pong__get_packed_size - (const GG110Pong *message) -{ - assert(message->base.descriptor == &gg110_pong__descriptor); - return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); -} -size_t gg110_pong__pack - (const GG110Pong *message, - uint8_t *out) -{ - assert(message->base.descriptor == &gg110_pong__descriptor); - return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); -} -size_t gg110_pong__pack_to_buffer - (const GG110Pong *message, - ProtobufCBuffer *buffer) -{ - assert(message->base.descriptor == &gg110_pong__descriptor); - return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); -} -GG110Pong * - gg110_pong__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data) -{ - return (GG110Pong *) - protobuf_c_message_unpack (&gg110_pong__descriptor, - allocator, len, data); -} -void gg110_pong__free_unpacked - (GG110Pong *message, - ProtobufCAllocator *allocator) -{ - assert(message->base.descriptor == &gg110_pong__descriptor); - protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); -} -void gg110_ack__init - (GG110Ack *message) -{ - static GG110Ack init_value = GG110_ACK__INIT; - *message = init_value; -} -size_t gg110_ack__get_packed_size - (const GG110Ack *message) -{ - assert(message->base.descriptor == &gg110_ack__descriptor); - return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); -} -size_t gg110_ack__pack - (const GG110Ack *message, - uint8_t *out) -{ - assert(message->base.descriptor == &gg110_ack__descriptor); - return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); -} -size_t gg110_ack__pack_to_buffer - (const GG110Ack *message, - ProtobufCBuffer *buffer) -{ - assert(message->base.descriptor == &gg110_ack__descriptor); - return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); -} -GG110Ack * - gg110_ack__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data) -{ - return (GG110Ack *) - protobuf_c_message_unpack (&gg110_ack__descriptor, - allocator, len, data); -} -void gg110_ack__free_unpacked - (GG110Ack *message, - ProtobufCAllocator *allocator) -{ - assert(message->base.descriptor == &gg110_ack__descriptor); - protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); -} -void gg105_login__init - (GG105Login *message) -{ - static GG105Login init_value = GG105_LOGIN__INIT; - *message = init_value; -} -size_t gg105_login__get_packed_size - (const GG105Login *message) -{ - assert(message->base.descriptor == &gg105_login__descriptor); - return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); -} -size_t gg105_login__pack - (const GG105Login *message, - uint8_t *out) -{ - assert(message->base.descriptor == &gg105_login__descriptor); - return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); -} -size_t gg105_login__pack_to_buffer - (const GG105Login *message, - ProtobufCBuffer *buffer) -{ - assert(message->base.descriptor == &gg105_login__descriptor); - return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); -} -GG105Login * - gg105_login__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data) -{ - return (GG105Login *) - protobuf_c_message_unpack (&gg105_login__descriptor, - allocator, len, data); -} -void gg105_login__free_unpacked - (GG105Login *message, - ProtobufCAllocator *allocator) -{ - assert(message->base.descriptor == &gg105_login__descriptor); - protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); -} -void gg110_message_ack_link__init - (GG110MessageAckLink *message) -{ - static GG110MessageAckLink init_value = GG110_MESSAGE_ACK_LINK__INIT; - *message = init_value; -} -size_t gg110_message_ack_link__get_packed_size - (const GG110MessageAckLink *message) -{ - assert(message->base.descriptor == &gg110_message_ack_link__descriptor); - return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); -} -size_t gg110_message_ack_link__pack - (const GG110MessageAckLink *message, - uint8_t *out) -{ - assert(message->base.descriptor == &gg110_message_ack_link__descriptor); - return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); -} -size_t gg110_message_ack_link__pack_to_buffer - (const GG110MessageAckLink *message, - ProtobufCBuffer *buffer) -{ - assert(message->base.descriptor == &gg110_message_ack_link__descriptor); - return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); -} -GG110MessageAckLink * - gg110_message_ack_link__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data) -{ - return (GG110MessageAckLink *) - protobuf_c_message_unpack (&gg110_message_ack_link__descriptor, - allocator, len, data); -} -void gg110_message_ack_link__free_unpacked - (GG110MessageAckLink *message, - ProtobufCAllocator *allocator) -{ - assert(message->base.descriptor == &gg110_message_ack_link__descriptor); - protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); -} -void gg110_message_ack__init - (GG110MessageAck *message) -{ - static GG110MessageAck init_value = GG110_MESSAGE_ACK__INIT; - *message = init_value; -} -size_t gg110_message_ack__get_packed_size - (const GG110MessageAck *message) -{ - assert(message->base.descriptor == &gg110_message_ack__descriptor); - return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); -} -size_t gg110_message_ack__pack - (const GG110MessageAck *message, - uint8_t *out) -{ - assert(message->base.descriptor == &gg110_message_ack__descriptor); - return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); -} -size_t gg110_message_ack__pack_to_buffer - (const GG110MessageAck *message, - ProtobufCBuffer *buffer) -{ - assert(message->base.descriptor == &gg110_message_ack__descriptor); - return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); -} -GG110MessageAck * - gg110_message_ack__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data) -{ - return (GG110MessageAck *) - protobuf_c_message_unpack (&gg110_message_ack__descriptor, - allocator, len, data); -} -void gg110_message_ack__free_unpacked - (GG110MessageAck *message, - ProtobufCAllocator *allocator) -{ - assert(message->base.descriptor == &gg110_message_ack__descriptor); - protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); -} -void gg110_event__init - (GG110Event *message) -{ - static GG110Event init_value = GG110_EVENT__INIT; - *message = init_value; -} -size_t gg110_event__get_packed_size - (const GG110Event *message) -{ - assert(message->base.descriptor == &gg110_event__descriptor); - return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); -} -size_t gg110_event__pack - (const GG110Event *message, - uint8_t *out) -{ - assert(message->base.descriptor == &gg110_event__descriptor); - return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); -} -size_t gg110_event__pack_to_buffer - (const GG110Event *message, - ProtobufCBuffer *buffer) -{ - assert(message->base.descriptor == &gg110_event__descriptor); - return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); -} -GG110Event * - gg110_event__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data) -{ - return (GG110Event *) - protobuf_c_message_unpack (&gg110_event__descriptor, - allocator, len, data); -} -void gg110_event__free_unpacked - (GG110Event *message, - ProtobufCAllocator *allocator) -{ - assert(message->base.descriptor == &gg110_event__descriptor); - protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); -} -void gg110_recv_message__init - (GG110RecvMessage *message) -{ - static GG110RecvMessage init_value = GG110_RECV_MESSAGE__INIT; - *message = init_value; -} -size_t gg110_recv_message__get_packed_size - (const GG110RecvMessage *message) -{ - assert(message->base.descriptor == &gg110_recv_message__descriptor); - return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); -} -size_t gg110_recv_message__pack - (const GG110RecvMessage *message, - uint8_t *out) -{ - assert(message->base.descriptor == &gg110_recv_message__descriptor); - return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); -} -size_t gg110_recv_message__pack_to_buffer - (const GG110RecvMessage *message, - ProtobufCBuffer *buffer) -{ - assert(message->base.descriptor == &gg110_recv_message__descriptor); - return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); -} -GG110RecvMessage * - gg110_recv_message__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data) -{ - return (GG110RecvMessage *) - protobuf_c_message_unpack (&gg110_recv_message__descriptor, - allocator, len, data); -} -void gg110_recv_message__free_unpacked - (GG110RecvMessage *message, - ProtobufCAllocator *allocator) -{ - assert(message->base.descriptor == &gg110_recv_message__descriptor); - protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); -} -void gg110_send_message__init - (GG110SendMessage *message) -{ - static GG110SendMessage init_value = GG110_SEND_MESSAGE__INIT; - *message = init_value; -} -size_t gg110_send_message__get_packed_size - (const GG110SendMessage *message) -{ - assert(message->base.descriptor == &gg110_send_message__descriptor); - return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); -} -size_t gg110_send_message__pack - (const GG110SendMessage *message, - uint8_t *out) -{ - assert(message->base.descriptor == &gg110_send_message__descriptor); - return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); -} -size_t gg110_send_message__pack_to_buffer - (const GG110SendMessage *message, - ProtobufCBuffer *buffer) -{ - assert(message->base.descriptor == &gg110_send_message__descriptor); - return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); -} -GG110SendMessage * - gg110_send_message__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data) -{ - return (GG110SendMessage *) - protobuf_c_message_unpack (&gg110_send_message__descriptor, - allocator, len, data); -} -void gg110_send_message__free_unpacked - (GG110SendMessage *message, - ProtobufCAllocator *allocator) -{ - assert(message->base.descriptor == &gg110_send_message__descriptor); - protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); -} -void gg110_imtoken__init - (GG110Imtoken *message) -{ - static GG110Imtoken init_value = GG110_IMTOKEN__INIT; - *message = init_value; -} -size_t gg110_imtoken__get_packed_size - (const GG110Imtoken *message) -{ - assert(message->base.descriptor == &gg110_imtoken__descriptor); - return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); -} -size_t gg110_imtoken__pack - (const GG110Imtoken *message, - uint8_t *out) -{ - assert(message->base.descriptor == &gg110_imtoken__descriptor); - return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); -} -size_t gg110_imtoken__pack_to_buffer - (const GG110Imtoken *message, - ProtobufCBuffer *buffer) -{ - assert(message->base.descriptor == &gg110_imtoken__descriptor); - return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); -} -GG110Imtoken * - gg110_imtoken__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data) -{ - return (GG110Imtoken *) - protobuf_c_message_unpack (&gg110_imtoken__descriptor, - allocator, len, data); -} -void gg110_imtoken__free_unpacked - (GG110Imtoken *message, - ProtobufCAllocator *allocator) -{ - assert(message->base.descriptor == &gg110_imtoken__descriptor); - protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); -} -void gg110_chat_info_update__init - (GG110ChatInfoUpdate *message) -{ - static GG110ChatInfoUpdate init_value = GG110_CHAT_INFO_UPDATE__INIT; - *message = init_value; -} -size_t gg110_chat_info_update__get_packed_size - (const GG110ChatInfoUpdate *message) -{ - assert(message->base.descriptor == &gg110_chat_info_update__descriptor); - return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); -} -size_t gg110_chat_info_update__pack - (const GG110ChatInfoUpdate *message, - uint8_t *out) -{ - assert(message->base.descriptor == &gg110_chat_info_update__descriptor); - return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); -} -size_t gg110_chat_info_update__pack_to_buffer - (const GG110ChatInfoUpdate *message, - ProtobufCBuffer *buffer) -{ - assert(message->base.descriptor == &gg110_chat_info_update__descriptor); - return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); -} -GG110ChatInfoUpdate * - gg110_chat_info_update__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data) -{ - return (GG110ChatInfoUpdate *) - protobuf_c_message_unpack (&gg110_chat_info_update__descriptor, - allocator, len, data); -} -void gg110_chat_info_update__free_unpacked - (GG110ChatInfoUpdate *message, - ProtobufCAllocator *allocator) -{ - assert(message->base.descriptor == &gg110_chat_info_update__descriptor); - protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); -} -void protobuf_kvp__init - (ProtobufKVP *message) -{ - static ProtobufKVP init_value = PROTOBUF_KVP__INIT; - *message = init_value; -} -size_t protobuf_kvp__get_packed_size - (const ProtobufKVP *message) -{ - assert(message->base.descriptor == &protobuf_kvp__descriptor); - return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); -} -size_t protobuf_kvp__pack - (const ProtobufKVP *message, - uint8_t *out) -{ - assert(message->base.descriptor == &protobuf_kvp__descriptor); - return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); -} -size_t protobuf_kvp__pack_to_buffer - (const ProtobufKVP *message, - ProtobufCBuffer *buffer) -{ - assert(message->base.descriptor == &protobuf_kvp__descriptor); - return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); -} -ProtobufKVP * - protobuf_kvp__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data) -{ - return (ProtobufKVP *) - protobuf_c_message_unpack (&protobuf_kvp__descriptor, - allocator, len, data); -} -void protobuf_kvp__free_unpacked - (ProtobufKVP *message, - ProtobufCAllocator *allocator) -{ - assert(message->base.descriptor == &protobuf_kvp__descriptor); - protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); -} -void gg110_options__init - (GG110Options *message) -{ - static GG110Options init_value = GG110_OPTIONS__INIT; - *message = init_value; -} -size_t gg110_options__get_packed_size - (const GG110Options *message) -{ - assert(message->base.descriptor == &gg110_options__descriptor); - return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); -} -size_t gg110_options__pack - (const GG110Options *message, - uint8_t *out) -{ - assert(message->base.descriptor == &gg110_options__descriptor); - return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); -} -size_t gg110_options__pack_to_buffer - (const GG110Options *message, - ProtobufCBuffer *buffer) -{ - assert(message->base.descriptor == &gg110_options__descriptor); - return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); -} -GG110Options * - gg110_options__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data) -{ - return (GG110Options *) - protobuf_c_message_unpack (&gg110_options__descriptor, - allocator, len, data); -} -void gg110_options__free_unpacked - (GG110Options *message, - ProtobufCAllocator *allocator) -{ - assert(message->base.descriptor == &gg110_options__descriptor); - protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); -} -void gg110_access_info__init - (GG110AccessInfo *message) -{ - static GG110AccessInfo init_value = GG110_ACCESS_INFO__INIT; - *message = init_value; -} -size_t gg110_access_info__get_packed_size - (const GG110AccessInfo *message) -{ - assert(message->base.descriptor == &gg110_access_info__descriptor); - return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); -} -size_t gg110_access_info__pack - (const GG110AccessInfo *message, - uint8_t *out) -{ - assert(message->base.descriptor == &gg110_access_info__descriptor); - return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); -} -size_t gg110_access_info__pack_to_buffer - (const GG110AccessInfo *message, - ProtobufCBuffer *buffer) -{ - assert(message->base.descriptor == &gg110_access_info__descriptor); - return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); -} -GG110AccessInfo * - gg110_access_info__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data) -{ - return (GG110AccessInfo *) - protobuf_c_message_unpack (&gg110_access_info__descriptor, - allocator, len, data); -} -void gg110_access_info__free_unpacked - (GG110AccessInfo *message, - ProtobufCAllocator *allocator) -{ - assert(message->base.descriptor == &gg110_access_info__descriptor); - protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); -} -void gg112_transfer_info_uin__init - (GG112TransferInfoUin *message) -{ - static GG112TransferInfoUin init_value = GG112_TRANSFER_INFO_UIN__INIT; - *message = init_value; -} -size_t gg112_transfer_info_uin__get_packed_size - (const GG112TransferInfoUin *message) -{ - assert(message->base.descriptor == &gg112_transfer_info_uin__descriptor); - return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); -} -size_t gg112_transfer_info_uin__pack - (const GG112TransferInfoUin *message, - uint8_t *out) -{ - assert(message->base.descriptor == &gg112_transfer_info_uin__descriptor); - return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); -} -size_t gg112_transfer_info_uin__pack_to_buffer - (const GG112TransferInfoUin *message, - ProtobufCBuffer *buffer) -{ - assert(message->base.descriptor == &gg112_transfer_info_uin__descriptor); - return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); -} -GG112TransferInfoUin * - gg112_transfer_info_uin__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data) -{ - return (GG112TransferInfoUin *) - protobuf_c_message_unpack (&gg112_transfer_info_uin__descriptor, - allocator, len, data); -} -void gg112_transfer_info_uin__free_unpacked - (GG112TransferInfoUin *message, - ProtobufCAllocator *allocator) -{ - assert(message->base.descriptor == &gg112_transfer_info_uin__descriptor); - protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); -} -void gg112_transfer_info_file__init - (GG112TransferInfoFile *message) -{ - static GG112TransferInfoFile init_value = GG112_TRANSFER_INFO_FILE__INIT; - *message = init_value; -} -size_t gg112_transfer_info_file__get_packed_size - (const GG112TransferInfoFile *message) -{ - assert(message->base.descriptor == &gg112_transfer_info_file__descriptor); - return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); -} -size_t gg112_transfer_info_file__pack - (const GG112TransferInfoFile *message, - uint8_t *out) -{ - assert(message->base.descriptor == &gg112_transfer_info_file__descriptor); - return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); -} -size_t gg112_transfer_info_file__pack_to_buffer - (const GG112TransferInfoFile *message, - ProtobufCBuffer *buffer) -{ - assert(message->base.descriptor == &gg112_transfer_info_file__descriptor); - return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); -} -GG112TransferInfoFile * - gg112_transfer_info_file__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data) -{ - return (GG112TransferInfoFile *) - protobuf_c_message_unpack (&gg112_transfer_info_file__descriptor, - allocator, len, data); -} -void gg112_transfer_info_file__free_unpacked - (GG112TransferInfoFile *message, - ProtobufCAllocator *allocator) -{ - assert(message->base.descriptor == &gg112_transfer_info_file__descriptor); - protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); -} -void gg112_transfer_info__init - (GG112TransferInfo *message) -{ - static GG112TransferInfo init_value = GG112_TRANSFER_INFO__INIT; - *message = init_value; -} -size_t gg112_transfer_info__get_packed_size - (const GG112TransferInfo *message) -{ - assert(message->base.descriptor == &gg112_transfer_info__descriptor); - return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); -} -size_t gg112_transfer_info__pack - (const GG112TransferInfo *message, - uint8_t *out) -{ - assert(message->base.descriptor == &gg112_transfer_info__descriptor); - return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); -} -size_t gg112_transfer_info__pack_to_buffer - (const GG112TransferInfo *message, - ProtobufCBuffer *buffer) -{ - assert(message->base.descriptor == &gg112_transfer_info__descriptor); - return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); -} -GG112TransferInfo * - gg112_transfer_info__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data) -{ - return (GG112TransferInfo *) - protobuf_c_message_unpack (&gg112_transfer_info__descriptor, - allocator, len, data); -} -void gg112_transfer_info__free_unpacked - (GG112TransferInfo *message, - ProtobufCAllocator *allocator) -{ - assert(message->base.descriptor == &gg112_transfer_info__descriptor); - protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); -} -void gg110_magic_notification__init - (GG110MagicNotification *message) -{ - static GG110MagicNotification init_value = GG110_MAGIC_NOTIFICATION__INIT; - *message = init_value; -} -size_t gg110_magic_notification__get_packed_size - (const GG110MagicNotification *message) -{ - assert(message->base.descriptor == &gg110_magic_notification__descriptor); - return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); -} -size_t gg110_magic_notification__pack - (const GG110MagicNotification *message, - uint8_t *out) -{ - assert(message->base.descriptor == &gg110_magic_notification__descriptor); - return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); -} -size_t gg110_magic_notification__pack_to_buffer - (const GG110MagicNotification *message, - ProtobufCBuffer *buffer) -{ - assert(message->base.descriptor == &gg110_magic_notification__descriptor); - return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); -} -GG110MagicNotification * - gg110_magic_notification__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data) -{ - return (GG110MagicNotification *) - protobuf_c_message_unpack (&gg110_magic_notification__descriptor, - allocator, len, data); -} -void gg110_magic_notification__free_unpacked - (GG110MagicNotification *message, - ProtobufCAllocator *allocator) -{ - assert(message->base.descriptor == &gg110_magic_notification__descriptor); - protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); -} -static const int32_t gg110_login_ok__dummy1__default_value = 1; -static const ProtobufCFieldDescriptor gg110_login_ok__field_descriptors[4] = -{ - { - "dummy1", - 1, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_INT32, - 0, /* quantifier_offset */ - offsetof(GG110LoginOK, dummy1), - NULL, - &gg110_login_ok__dummy1__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "dummyhash", - 2, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(GG110LoginOK, dummyhash), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "uin", - 3, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG110LoginOK, uin), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "server_time", - 4, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED32, - 0, /* quantifier_offset */ - offsetof(GG110LoginOK, server_time), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, -}; -static const unsigned gg110_login_ok__field_indices_by_name[] = { - 0, /* field[0] = dummy1 */ - 1, /* field[1] = dummyhash */ - 3, /* field[3] = server_time */ - 2, /* field[2] = uin */ -}; -static const ProtobufCIntRange gg110_login_ok__number_ranges[1 + 1] = -{ - { 1, 0 }, - { 0, 4 } -}; -const ProtobufCMessageDescriptor gg110_login_ok__descriptor = -{ - PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "GG110LoginOK", - "GG110LoginOK", - "GG110LoginOK", - "", - sizeof(GG110LoginOK), - 4, - gg110_login_ok__field_descriptors, - gg110_login_ok__field_indices_by_name, - 1, gg110_login_ok__number_ranges, - (ProtobufCMessageInit) gg110_login_ok__init, - NULL,NULL,NULL /* reserved[123] */ -}; -static const ProtobufCFieldDescriptor gg110_pong__field_descriptors[1] = -{ - { - "server_time", - 1, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED32, - 0, /* quantifier_offset */ - offsetof(GG110Pong, server_time), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, -}; -static const unsigned gg110_pong__field_indices_by_name[] = { - 0, /* field[0] = server_time */ -}; -static const ProtobufCIntRange gg110_pong__number_ranges[1 + 1] = -{ - { 1, 0 }, - { 0, 1 } -}; -const ProtobufCMessageDescriptor gg110_pong__descriptor = -{ - PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "GG110Pong", - "GG110Pong", - "GG110Pong", - "", - sizeof(GG110Pong), - 1, - gg110_pong__field_descriptors, - gg110_pong__field_indices_by_name, - 1, gg110_pong__number_ranges, - (ProtobufCMessageInit) gg110_pong__init, - NULL,NULL,NULL /* reserved[123] */ -}; -const ProtobufCEnumValue gg110_ack__type__enum_values_by_number[6] = -{ - { "MSG", "GG110_ACK__TYPE__MSG", 1 }, - { "CHAT", "GG110_ACK__TYPE__CHAT", 2 }, - { "CHAT_INFO", "GG110_ACK__TYPE__CHAT_INFO", 3 }, - { "MAGIC_NOTIFICATION", "GG110_ACK__TYPE__MAGIC_NOTIFICATION", 5 }, - { "MPA", "GG110_ACK__TYPE__MPA", 6 }, - { "TRANSFER_INFO", "GG110_ACK__TYPE__TRANSFER_INFO", 7 }, -}; -static const ProtobufCIntRange gg110_ack__type__value_ranges[] = { -{1, 0},{5, 3},{0, 6} -}; -const ProtobufCEnumValueIndex gg110_ack__type__enum_values_by_name[6] = -{ - { "CHAT", 1 }, - { "CHAT_INFO", 2 }, - { "MAGIC_NOTIFICATION", 3 }, - { "MPA", 4 }, - { "MSG", 0 }, - { "TRANSFER_INFO", 5 }, -}; -const ProtobufCEnumDescriptor gg110_ack__type__descriptor = -{ - PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC, - "GG110Ack.Type", - "Type", - "GG110Ack__Type", - "", - 6, - gg110_ack__type__enum_values_by_number, - 6, - gg110_ack__type__enum_values_by_name, - 2, - gg110_ack__type__value_ranges, - NULL,NULL,NULL,NULL /* reserved[1234] */ -}; -static const uint32_t gg110_ack__dummy1__default_value = 1u; -static const ProtobufCFieldDescriptor gg110_ack__field_descriptors[3] = -{ - { - "type", - 1, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_ENUM, - 0, /* quantifier_offset */ - offsetof(GG110Ack, type), - &gg110_ack__type__descriptor, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "seq", - 2, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG110Ack, seq), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "dummy1", - 3, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG110Ack, dummy1), - NULL, - &gg110_ack__dummy1__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, -}; -static const unsigned gg110_ack__field_indices_by_name[] = { - 2, /* field[2] = dummy1 */ - 1, /* field[1] = seq */ - 0, /* field[0] = type */ -}; -static const ProtobufCIntRange gg110_ack__number_ranges[1 + 1] = -{ - { 1, 0 }, - { 0, 3 } -}; -const ProtobufCMessageDescriptor gg110_ack__descriptor = -{ - PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "GG110Ack", - "GG110Ack", - "GG110Ack", - "", - sizeof(GG110Ack), - 3, - gg110_ack__field_descriptors, - gg110_ack__field_indices_by_name, - 1, gg110_ack__number_ranges, - (ProtobufCMessageInit) gg110_ack__init, - NULL,NULL,NULL /* reserved[123] */ -}; -char gg105_login__initial_descr__default_value[] = ""; -static const uint32_t gg105_login__initial_status__default_value = 8227u; -static const int32_t gg105_login__dummy1__default_value = 4; -static const uint32_t gg105_login__dummy2__default_value = 65994615u; -static const uint32_t gg105_login__dummy3__default_value = 198164u; -static const int32_t gg105_login__dummy5__default_value = 255; -static const int32_t gg105_login__dummy6__default_value = 100; -static const uint32_t gg105_login__dummy7__default_value = 127u; -static const int32_t gg105_login__dummy8__default_value = 0; -static const uint32_t gg105_login__dummy10__default_value = 0u; -static const ProtobufCFieldDescriptor gg105_login__field_descriptors[16] = -{ - { - "lang", - 1, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(GG105Login, lang), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "uin", - 2, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_BYTES, - 0, /* quantifier_offset */ - offsetof(GG105Login, uin), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "hash", - 3, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_BYTES, - 0, /* quantifier_offset */ - offsetof(GG105Login, hash), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "dummy1", - 4, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_INT32, - 0, /* quantifier_offset */ - offsetof(GG105Login, dummy1), - NULL, - &gg105_login__dummy1__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "dummy2", - 5, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED32, - 0, /* quantifier_offset */ - offsetof(GG105Login, dummy2), - NULL, - &gg105_login__dummy2__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "dummy3", - 6, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED32, - 0, /* quantifier_offset */ - offsetof(GG105Login, dummy3), - NULL, - &gg105_login__dummy3__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "client", - 7, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(GG105Login, client), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "initial_status", - 8, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED32, - 0, /* quantifier_offset */ - offsetof(GG105Login, initial_status), - NULL, - &gg105_login__initial_status__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "initial_descr", - 9, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(GG105Login, initial_descr), - NULL, - &gg105_login__initial_descr__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "dummy4", - 10, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_BYTES, - 0, /* quantifier_offset */ - offsetof(GG105Login, dummy4), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "supported_features", - 11, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(GG105Login, supported_features), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "dummy5", - 12, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_INT32, - 0, /* quantifier_offset */ - offsetof(GG105Login, dummy5), - NULL, - &gg105_login__dummy5__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "dummy6", - 13, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_INT32, - 0, /* quantifier_offset */ - offsetof(GG105Login, dummy6), - NULL, - &gg105_login__dummy6__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "dummy7", - 14, - PROTOBUF_C_LABEL_OPTIONAL, - PROTOBUF_C_TYPE_FIXED32, - offsetof(GG105Login, has_dummy7), - offsetof(GG105Login, dummy7), - NULL, - &gg105_login__dummy7__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "dummy8", - 15, - PROTOBUF_C_LABEL_OPTIONAL, - PROTOBUF_C_TYPE_INT32, - offsetof(GG105Login, has_dummy8), - offsetof(GG105Login, dummy8), - NULL, - &gg105_login__dummy8__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "dummy10", - 17, - PROTOBUF_C_LABEL_OPTIONAL, - PROTOBUF_C_TYPE_UINT32, - offsetof(GG105Login, has_dummy10), - offsetof(GG105Login, dummy10), - NULL, - &gg105_login__dummy10__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, -}; -static const unsigned gg105_login__field_indices_by_name[] = { - 6, /* field[6] = client */ - 3, /* field[3] = dummy1 */ - 15, /* field[15] = dummy10 */ - 4, /* field[4] = dummy2 */ - 5, /* field[5] = dummy3 */ - 9, /* field[9] = dummy4 */ - 11, /* field[11] = dummy5 */ - 12, /* field[12] = dummy6 */ - 13, /* field[13] = dummy7 */ - 14, /* field[14] = dummy8 */ - 2, /* field[2] = hash */ - 8, /* field[8] = initial_descr */ - 7, /* field[7] = initial_status */ - 0, /* field[0] = lang */ - 10, /* field[10] = supported_features */ - 1, /* field[1] = uin */ -}; -static const ProtobufCIntRange gg105_login__number_ranges[2 + 1] = -{ - { 1, 0 }, - { 17, 15 }, - { 0, 16 } -}; -const ProtobufCMessageDescriptor gg105_login__descriptor = -{ - PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "GG105Login", - "GG105Login", - "GG105Login", - "", - sizeof(GG105Login), - 16, - gg105_login__field_descriptors, - gg105_login__field_indices_by_name, - 2, gg105_login__number_ranges, - (ProtobufCMessageInit) gg105_login__init, - NULL,NULL,NULL /* reserved[123] */ -}; -static const ProtobufCFieldDescriptor gg110_message_ack_link__field_descriptors[2] = -{ - { - "id", - 1, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED64, - 0, /* quantifier_offset */ - offsetof(GG110MessageAckLink, id), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "url", - 2, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(GG110MessageAckLink, url), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, -}; -static const unsigned gg110_message_ack_link__field_indices_by_name[] = { - 0, /* field[0] = id */ - 1, /* field[1] = url */ -}; -static const ProtobufCIntRange gg110_message_ack_link__number_ranges[1 + 1] = -{ - { 1, 0 }, - { 0, 2 } -}; -const ProtobufCMessageDescriptor gg110_message_ack_link__descriptor = -{ - PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "GG110MessageAckLink", - "GG110MessageAckLink", - "GG110MessageAckLink", - "", - sizeof(GG110MessageAckLink), - 2, - gg110_message_ack_link__field_descriptors, - gg110_message_ack_link__field_indices_by_name, - 1, gg110_message_ack_link__number_ranges, - (ProtobufCMessageInit) gg110_message_ack_link__init, - NULL,NULL,NULL /* reserved[123] */ -}; -static const uint32_t gg110_message_ack__dummy1__default_value = 0u; -static const ProtobufCFieldDescriptor gg110_message_ack__field_descriptors[7] = -{ - { - "msg_type", - 1, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG110MessageAck, msg_type), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "seq", - 2, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG110MessageAck, seq), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "time", - 3, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED32, - 0, /* quantifier_offset */ - offsetof(GG110MessageAck, time), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "msg_id", - 4, - PROTOBUF_C_LABEL_OPTIONAL, - PROTOBUF_C_TYPE_FIXED64, - offsetof(GG110MessageAck, has_msg_id), - offsetof(GG110MessageAck, msg_id), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "conv_id", - 5, - PROTOBUF_C_LABEL_OPTIONAL, - PROTOBUF_C_TYPE_FIXED64, - offsetof(GG110MessageAck, has_conv_id), - offsetof(GG110MessageAck, conv_id), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "links", - 6, - PROTOBUF_C_LABEL_REPEATED, - PROTOBUF_C_TYPE_MESSAGE, - offsetof(GG110MessageAck, n_links), - offsetof(GG110MessageAck, links), - &gg110_message_ack_link__descriptor, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "dummy1", - 7, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG110MessageAck, dummy1), - NULL, - &gg110_message_ack__dummy1__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, -}; -static const unsigned gg110_message_ack__field_indices_by_name[] = { - 4, /* field[4] = conv_id */ - 6, /* field[6] = dummy1 */ - 5, /* field[5] = links */ - 3, /* field[3] = msg_id */ - 0, /* field[0] = msg_type */ - 1, /* field[1] = seq */ - 2, /* field[2] = time */ -}; -static const ProtobufCIntRange gg110_message_ack__number_ranges[1 + 1] = -{ - { 1, 0 }, - { 0, 7 } -}; -const ProtobufCMessageDescriptor gg110_message_ack__descriptor = -{ - PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "GG110MessageAck", - "GG110MessageAck", - "GG110MessageAck", - "", - sizeof(GG110MessageAck), - 7, - gg110_message_ack__field_descriptors, - gg110_message_ack__field_indices_by_name, - 1, gg110_message_ack__number_ranges, - (ProtobufCMessageInit) gg110_message_ack__init, - NULL,NULL,NULL /* reserved[123] */ -}; -const ProtobufCEnumValue gg110_event__type__enum_values_by_number[2] = -{ - { "XML", "GG110_EVENT__TYPE__XML", 0 }, - { "JSON", "GG110_EVENT__TYPE__JSON", 2 }, -}; -static const ProtobufCIntRange gg110_event__type__value_ranges[] = { -{0, 0},{2, 1},{0, 2} -}; -const ProtobufCEnumValueIndex gg110_event__type__enum_values_by_name[2] = -{ - { "JSON", 1 }, - { "XML", 0 }, -}; -const ProtobufCEnumDescriptor gg110_event__type__descriptor = -{ - PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC, - "GG110Event.Type", - "Type", - "GG110Event__Type", - "", - 2, - gg110_event__type__enum_values_by_number, - 2, - gg110_event__type__enum_values_by_name, - 2, - gg110_event__type__value_ranges, - NULL,NULL,NULL,NULL /* reserved[1234] */ -}; -static const ProtobufCFieldDescriptor gg110_event__field_descriptors[5] = -{ - { - "type", - 1, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_ENUM, - 0, /* quantifier_offset */ - offsetof(GG110Event, type), - &gg110_event__type__descriptor, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "seq", - 2, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG110Event, seq), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "data", - 3, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(GG110Event, data), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "subtype", - 4, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(GG110Event, subtype), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "id", - 5, - PROTOBUF_C_LABEL_OPTIONAL, - PROTOBUF_C_TYPE_UINT64, - offsetof(GG110Event, has_id), - offsetof(GG110Event, id), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, -}; -static const unsigned gg110_event__field_indices_by_name[] = { - 2, /* field[2] = data */ - 4, /* field[4] = id */ - 1, /* field[1] = seq */ - 3, /* field[3] = subtype */ - 0, /* field[0] = type */ -}; -static const ProtobufCIntRange gg110_event__number_ranges[1 + 1] = -{ - { 1, 0 }, - { 0, 5 } -}; -const ProtobufCMessageDescriptor gg110_event__descriptor = -{ - PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "GG110Event", - "GG110Event", - "GG110Event", - "", - sizeof(GG110Event), - 5, - gg110_event__field_descriptors, - gg110_event__field_indices_by_name, - 1, gg110_event__number_ranges, - (ProtobufCMessageInit) gg110_event__init, - NULL,NULL,NULL /* reserved[123] */ -}; -char gg110_recv_message__msg_plain__default_value[] = ""; -static const ProtobufCFieldDescriptor gg110_recv_message__field_descriptors[10] = -{ - { - "sender", - 1, - PROTOBUF_C_LABEL_OPTIONAL, - PROTOBUF_C_TYPE_BYTES, - offsetof(GG110RecvMessage, has_sender), - offsetof(GG110RecvMessage, sender), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "flags", - 2, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG110RecvMessage, flags), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "seq", - 3, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG110RecvMessage, seq), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "time", - 4, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED32, - 0, /* quantifier_offset */ - offsetof(GG110RecvMessage, time), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "msg_plain", - 5, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(GG110RecvMessage, msg_plain), - NULL, - &gg110_recv_message__msg_plain__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "msg_xhtml", - 6, - PROTOBUF_C_LABEL_OPTIONAL, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(GG110RecvMessage, msg_xhtml), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "data", - 7, - PROTOBUF_C_LABEL_OPTIONAL, - PROTOBUF_C_TYPE_BYTES, - offsetof(GG110RecvMessage, has_data), - offsetof(GG110RecvMessage, data), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "msg_id", - 9, - PROTOBUF_C_LABEL_OPTIONAL, - PROTOBUF_C_TYPE_FIXED64, - offsetof(GG110RecvMessage, has_msg_id), - offsetof(GG110RecvMessage, msg_id), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "chat_id", - 10, - PROTOBUF_C_LABEL_OPTIONAL, - PROTOBUF_C_TYPE_FIXED64, - offsetof(GG110RecvMessage, has_chat_id), - offsetof(GG110RecvMessage, chat_id), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "conv_id", - 11, - PROTOBUF_C_LABEL_OPTIONAL, - PROTOBUF_C_TYPE_FIXED64, - offsetof(GG110RecvMessage, has_conv_id), - offsetof(GG110RecvMessage, conv_id), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, -}; -static const unsigned gg110_recv_message__field_indices_by_name[] = { - 8, /* field[8] = chat_id */ - 9, /* field[9] = conv_id */ - 6, /* field[6] = data */ - 1, /* field[1] = flags */ - 7, /* field[7] = msg_id */ - 4, /* field[4] = msg_plain */ - 5, /* field[5] = msg_xhtml */ - 0, /* field[0] = sender */ - 2, /* field[2] = seq */ - 3, /* field[3] = time */ -}; -static const ProtobufCIntRange gg110_recv_message__number_ranges[2 + 1] = -{ - { 1, 0 }, - { 9, 7 }, - { 0, 10 } -}; -const ProtobufCMessageDescriptor gg110_recv_message__descriptor = -{ - PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "GG110RecvMessage", - "GG110RecvMessage", - "GG110RecvMessage", - "", - sizeof(GG110RecvMessage), - 10, - gg110_recv_message__field_descriptors, - gg110_recv_message__field_indices_by_name, - 2, gg110_recv_message__number_ranges, - (ProtobufCMessageInit) gg110_recv_message__init, - NULL,NULL,NULL /* reserved[123] */ -}; -char gg110_send_message__dummy3__default_value[] = ""; -static const uint32_t gg110_send_message__dummy1__default_value = 8u; -static const ProtobufCFieldDescriptor gg110_send_message__field_descriptors[7] = -{ - { - "recipient", - 1, - PROTOBUF_C_LABEL_OPTIONAL, - PROTOBUF_C_TYPE_BYTES, - offsetof(GG110SendMessage, has_recipient), - offsetof(GG110SendMessage, recipient), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "dummy1", - 2, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG110SendMessage, dummy1), - NULL, - &gg110_send_message__dummy1__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "seq", - 3, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG110SendMessage, seq), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "msg_plain", - 5, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(GG110SendMessage, msg_plain), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "msg_xhtml", - 6, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(GG110SendMessage, msg_xhtml), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "dummy3", - 7, - PROTOBUF_C_LABEL_OPTIONAL, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(GG110SendMessage, dummy3), - NULL, - &gg110_send_message__dummy3__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "chat_id", - 10, - PROTOBUF_C_LABEL_OPTIONAL, - PROTOBUF_C_TYPE_FIXED64, - offsetof(GG110SendMessage, has_chat_id), - offsetof(GG110SendMessage, chat_id), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, -}; -static const unsigned gg110_send_message__field_indices_by_name[] = { - 6, /* field[6] = chat_id */ - 1, /* field[1] = dummy1 */ - 5, /* field[5] = dummy3 */ - 3, /* field[3] = msg_plain */ - 4, /* field[4] = msg_xhtml */ - 0, /* field[0] = recipient */ - 2, /* field[2] = seq */ -}; -static const ProtobufCIntRange gg110_send_message__number_ranges[3 + 1] = -{ - { 1, 0 }, - { 5, 3 }, - { 10, 6 }, - { 0, 7 } -}; -const ProtobufCMessageDescriptor gg110_send_message__descriptor = -{ - PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "GG110SendMessage", - "GG110SendMessage", - "GG110SendMessage", - "", - sizeof(GG110SendMessage), - 7, - gg110_send_message__field_descriptors, - gg110_send_message__field_indices_by_name, - 3, gg110_send_message__number_ranges, - (ProtobufCMessageInit) gg110_send_message__init, - NULL,NULL,NULL /* reserved[123] */ -}; -static const ProtobufCFieldDescriptor gg110_imtoken__field_descriptors[1] = -{ - { - "imtoken", - 1, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(GG110Imtoken, imtoken), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, -}; -static const unsigned gg110_imtoken__field_indices_by_name[] = { - 0, /* field[0] = imtoken */ -}; -static const ProtobufCIntRange gg110_imtoken__number_ranges[1 + 1] = -{ - { 1, 0 }, - { 0, 1 } -}; -const ProtobufCMessageDescriptor gg110_imtoken__descriptor = -{ - PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "GG110Imtoken", - "GG110Imtoken", - "GG110Imtoken", - "", - sizeof(GG110Imtoken), - 1, - gg110_imtoken__field_descriptors, - gg110_imtoken__field_indices_by_name, - 1, gg110_imtoken__number_ranges, - (ProtobufCMessageInit) gg110_imtoken__init, - NULL,NULL,NULL /* reserved[123] */ -}; -static const ProtobufCFieldDescriptor gg110_chat_info_update__field_descriptors[10] = -{ - { - "participant", - 1, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_BYTES, - 0, /* quantifier_offset */ - offsetof(GG110ChatInfoUpdate, participant), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "inviter", - 2, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_BYTES, - 0, /* quantifier_offset */ - offsetof(GG110ChatInfoUpdate, inviter), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "update_type", - 3, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED32, - 0, /* quantifier_offset */ - offsetof(GG110ChatInfoUpdate, update_type), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "time", - 4, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED32, - 0, /* quantifier_offset */ - offsetof(GG110ChatInfoUpdate, time), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "dummy1", - 5, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED32, - 0, /* quantifier_offset */ - offsetof(GG110ChatInfoUpdate, dummy1), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "version", - 6, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG110ChatInfoUpdate, version), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "dummy2", - 7, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG110ChatInfoUpdate, dummy2), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "msg_id", - 9, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED64, - 0, /* quantifier_offset */ - offsetof(GG110ChatInfoUpdate, msg_id), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "chat_id", - 10, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED64, - 0, /* quantifier_offset */ - offsetof(GG110ChatInfoUpdate, chat_id), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "conv_id", - 11, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED64, - 0, /* quantifier_offset */ - offsetof(GG110ChatInfoUpdate, conv_id), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, -}; -static const unsigned gg110_chat_info_update__field_indices_by_name[] = { - 8, /* field[8] = chat_id */ - 9, /* field[9] = conv_id */ - 4, /* field[4] = dummy1 */ - 6, /* field[6] = dummy2 */ - 1, /* field[1] = inviter */ - 7, /* field[7] = msg_id */ - 0, /* field[0] = participant */ - 3, /* field[3] = time */ - 2, /* field[2] = update_type */ - 5, /* field[5] = version */ -}; -static const ProtobufCIntRange gg110_chat_info_update__number_ranges[2 + 1] = -{ - { 1, 0 }, - { 9, 7 }, - { 0, 10 } -}; -const ProtobufCMessageDescriptor gg110_chat_info_update__descriptor = -{ - PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "GG110ChatInfoUpdate", - "GG110ChatInfoUpdate", - "GG110ChatInfoUpdate", - "", - sizeof(GG110ChatInfoUpdate), - 10, - gg110_chat_info_update__field_descriptors, - gg110_chat_info_update__field_indices_by_name, - 2, gg110_chat_info_update__number_ranges, - (ProtobufCMessageInit) gg110_chat_info_update__init, - NULL,NULL,NULL /* reserved[123] */ -}; -static const ProtobufCFieldDescriptor protobuf_kvp__field_descriptors[2] = -{ - { - "key", - 1, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(ProtobufKVP, key), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "value", - 2, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(ProtobufKVP, value), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, -}; -static const unsigned protobuf_kvp__field_indices_by_name[] = { - 0, /* field[0] = key */ - 1, /* field[1] = value */ -}; -static const ProtobufCIntRange protobuf_kvp__number_ranges[1 + 1] = -{ - { 1, 0 }, - { 0, 2 } -}; -const ProtobufCMessageDescriptor protobuf_kvp__descriptor = -{ - PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "ProtobufKVP", - "ProtobufKVP", - "ProtobufKVP", - "", - sizeof(ProtobufKVP), - 2, - protobuf_kvp__field_descriptors, - protobuf_kvp__field_indices_by_name, - 1, protobuf_kvp__number_ranges, - (ProtobufCMessageInit) protobuf_kvp__init, - NULL,NULL,NULL /* reserved[123] */ -}; -static const uint32_t gg110_options__dummy1__default_value = 0u; -static const ProtobufCFieldDescriptor gg110_options__field_descriptors[2] = -{ - { - "options", - 1, - PROTOBUF_C_LABEL_REPEATED, - PROTOBUF_C_TYPE_MESSAGE, - offsetof(GG110Options, n_options), - offsetof(GG110Options, options), - &protobuf_kvp__descriptor, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "dummy1", - 2, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG110Options, dummy1), - NULL, - &gg110_options__dummy1__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, -}; -static const unsigned gg110_options__field_indices_by_name[] = { - 1, /* field[1] = dummy1 */ - 0, /* field[0] = options */ -}; -static const ProtobufCIntRange gg110_options__number_ranges[1 + 1] = -{ - { 1, 0 }, - { 0, 2 } -}; -const ProtobufCMessageDescriptor gg110_options__descriptor = -{ - PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "GG110Options", - "GG110Options", - "GG110Options", - "", - sizeof(GG110Options), - 2, - gg110_options__field_descriptors, - gg110_options__field_indices_by_name, - 1, gg110_options__number_ranges, - (ProtobufCMessageInit) gg110_options__init, - NULL,NULL,NULL /* reserved[123] */ -}; -static const uint32_t gg110_access_info__dummy1__default_value = 1u; -static const ProtobufCFieldDescriptor gg110_access_info__field_descriptors[5] = -{ - { - "dummy1", - 1, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG110AccessInfo, dummy1), - NULL, - &gg110_access_info__dummy1__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "dummy2", - 2, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG110AccessInfo, dummy2), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "last_message", - 3, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG110AccessInfo, last_message), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "last_file_transfer", - 4, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG110AccessInfo, last_file_transfer), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "last_conference_ch", - 5, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG110AccessInfo, last_conference_ch), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, -}; -static const unsigned gg110_access_info__field_indices_by_name[] = { - 0, /* field[0] = dummy1 */ - 1, /* field[1] = dummy2 */ - 4, /* field[4] = last_conference_ch */ - 3, /* field[3] = last_file_transfer */ - 2, /* field[2] = last_message */ -}; -static const ProtobufCIntRange gg110_access_info__number_ranges[1 + 1] = -{ - { 1, 0 }, - { 0, 5 } -}; -const ProtobufCMessageDescriptor gg110_access_info__descriptor = -{ - PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "GG110AccessInfo", - "GG110AccessInfo", - "GG110AccessInfo", - "", - sizeof(GG110AccessInfo), - 5, - gg110_access_info__field_descriptors, - gg110_access_info__field_indices_by_name, - 1, gg110_access_info__number_ranges, - (ProtobufCMessageInit) gg110_access_info__init, - NULL,NULL,NULL /* reserved[123] */ -}; -static const uint32_t gg112_transfer_info_uin__dummy1__default_value = 1u; -static const ProtobufCFieldDescriptor gg112_transfer_info_uin__field_descriptors[2] = -{ - { - "dummy1", - 1, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG112TransferInfoUin, dummy1), - NULL, - &gg112_transfer_info_uin__dummy1__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "uin", - 2, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_BYTES, - 0, /* quantifier_offset */ - offsetof(GG112TransferInfoUin, uin), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, -}; -static const unsigned gg112_transfer_info_uin__field_indices_by_name[] = { - 0, /* field[0] = dummy1 */ - 1, /* field[1] = uin */ -}; -static const ProtobufCIntRange gg112_transfer_info_uin__number_ranges[1 + 1] = -{ - { 1, 0 }, - { 0, 2 } -}; -const ProtobufCMessageDescriptor gg112_transfer_info_uin__descriptor = -{ - PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "GG112TransferInfoUin", - "GG112TransferInfoUin", - "GG112TransferInfoUin", - "", - sizeof(GG112TransferInfoUin), - 2, - gg112_transfer_info_uin__field_descriptors, - gg112_transfer_info_uin__field_indices_by_name, - 1, gg112_transfer_info_uin__number_ranges, - (ProtobufCMessageInit) gg112_transfer_info_uin__init, - NULL,NULL,NULL /* reserved[123] */ -}; -char gg112_transfer_info_file__type__default_value[] = "other"; -static const ProtobufCFieldDescriptor gg112_transfer_info_file__field_descriptors[6] = -{ - { - "type", - 1, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(GG112TransferInfoFile, type), - NULL, - &gg112_transfer_info_file__type__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "url", - 2, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(GG112TransferInfoFile, url), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "content_type", - 6, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(GG112TransferInfoFile, content_type), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "filename", - 7, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(GG112TransferInfoFile, filename), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "filesize", - 8, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG112TransferInfoFile, filesize), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "msg_id", - 1001, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED64, - 0, /* quantifier_offset */ - offsetof(GG112TransferInfoFile, msg_id), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, -}; -static const unsigned gg112_transfer_info_file__field_indices_by_name[] = { - 2, /* field[2] = content_type */ - 3, /* field[3] = filename */ - 4, /* field[4] = filesize */ - 5, /* field[5] = msg_id */ - 0, /* field[0] = type */ - 1, /* field[1] = url */ -}; -static const ProtobufCIntRange gg112_transfer_info_file__number_ranges[3 + 1] = -{ - { 1, 0 }, - { 6, 2 }, - { 1001, 5 }, - { 0, 6 } -}; -const ProtobufCMessageDescriptor gg112_transfer_info_file__descriptor = -{ - PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "GG112TransferInfoFile", - "GG112TransferInfoFile", - "GG112TransferInfoFile", - "", - sizeof(GG112TransferInfoFile), - 6, - gg112_transfer_info_file__field_descriptors, - gg112_transfer_info_file__field_indices_by_name, - 3, gg112_transfer_info_file__number_ranges, - (ProtobufCMessageInit) gg112_transfer_info_file__init, - NULL,NULL,NULL /* reserved[123] */ -}; -static const ProtobufCFieldDescriptor gg112_transfer_info__field_descriptors[9] = -{ - { - "dummy1", - 1, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG112TransferInfo, dummy1), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "peer", - 2, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_MESSAGE, - 0, /* quantifier_offset */ - offsetof(GG112TransferInfo, peer), - &gg112_transfer_info_uin__descriptor, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "time", - 3, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED32, - 0, /* quantifier_offset */ - offsetof(GG112TransferInfo, time), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "sender", - 4, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_MESSAGE, - 0, /* quantifier_offset */ - offsetof(GG112TransferInfo, sender), - &gg112_transfer_info_uin__descriptor, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "data", - 5, - PROTOBUF_C_LABEL_REPEATED, - PROTOBUF_C_TYPE_MESSAGE, - offsetof(GG112TransferInfo, n_data), - offsetof(GG112TransferInfo, data), - &protobuf_kvp__descriptor, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "file", - 6, - PROTOBUF_C_LABEL_OPTIONAL, - PROTOBUF_C_TYPE_MESSAGE, - 0, /* quantifier_offset */ - offsetof(GG112TransferInfo, file), - &gg112_transfer_info_file__descriptor, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "seq", - 7, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_UINT32, - 0, /* quantifier_offset */ - offsetof(GG112TransferInfo, seq), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "msg_id", - 1001, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED64, - 0, /* quantifier_offset */ - offsetof(GG112TransferInfo, msg_id), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "conv_id", - 1002, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED64, - 0, /* quantifier_offset */ - offsetof(GG112TransferInfo, conv_id), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, -}; -static const unsigned gg112_transfer_info__field_indices_by_name[] = { - 8, /* field[8] = conv_id */ - 4, /* field[4] = data */ - 0, /* field[0] = dummy1 */ - 5, /* field[5] = file */ - 7, /* field[7] = msg_id */ - 1, /* field[1] = peer */ - 3, /* field[3] = sender */ - 6, /* field[6] = seq */ - 2, /* field[2] = time */ -}; -static const ProtobufCIntRange gg112_transfer_info__number_ranges[2 + 1] = -{ - { 1, 0 }, - { 1001, 7 }, - { 0, 9 } -}; -const ProtobufCMessageDescriptor gg112_transfer_info__descriptor = -{ - PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "GG112TransferInfo", - "GG112TransferInfo", - "GG112TransferInfo", - "", - sizeof(GG112TransferInfo), - 9, - gg112_transfer_info__field_descriptors, - gg112_transfer_info__field_indices_by_name, - 2, gg112_transfer_info__number_ranges, - (ProtobufCMessageInit) gg112_transfer_info__init, - NULL,NULL,NULL /* reserved[123] */ -}; -char gg110_magic_notification__dummy4__default_value[] = ""; -static const int32_t gg110_magic_notification__dummy1__default_value = 2; -static const int32_t gg110_magic_notification__dummy2__default_value = 1; -static const int32_t gg110_magic_notification__dummy3__default_value = 1; -static const ProtobufCFieldDescriptor gg110_magic_notification__field_descriptors[6] = -{ - { - "dummy1", - 1, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_INT32, - 0, /* quantifier_offset */ - offsetof(GG110MagicNotification, dummy1), - NULL, - &gg110_magic_notification__dummy1__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "seq", - 2, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_INT32, - 0, /* quantifier_offset */ - offsetof(GG110MagicNotification, seq), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "dummy2", - 3, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_INT32, - 0, /* quantifier_offset */ - offsetof(GG110MagicNotification, dummy2), - NULL, - &gg110_magic_notification__dummy2__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "dummy3", - 4, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_INT32, - 0, /* quantifier_offset */ - offsetof(GG110MagicNotification, dummy3), - NULL, - &gg110_magic_notification__dummy3__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "uin", - 5, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_BYTES, - 0, /* quantifier_offset */ - offsetof(GG110MagicNotification, uin), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "dummy4", - 6, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(GG110MagicNotification, dummy4), - NULL, - &gg110_magic_notification__dummy4__default_value, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, -}; -static const unsigned gg110_magic_notification__field_indices_by_name[] = { - 0, /* field[0] = dummy1 */ - 2, /* field[2] = dummy2 */ - 3, /* field[3] = dummy3 */ - 5, /* field[5] = dummy4 */ - 1, /* field[1] = seq */ - 4, /* field[4] = uin */ -}; -static const ProtobufCIntRange gg110_magic_notification__number_ranges[1 + 1] = -{ - { 1, 0 }, - { 0, 6 } -}; -const ProtobufCMessageDescriptor gg110_magic_notification__descriptor = -{ - PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "GG110MagicNotification", - "GG110MagicNotification", - "GG110MagicNotification", - "", - sizeof(GG110MagicNotification), - 6, - gg110_magic_notification__field_descriptors, - gg110_magic_notification__field_indices_by_name, - 1, gg110_magic_notification__number_ranges, - (ProtobufCMessageInit) gg110_magic_notification__init, - NULL,NULL,NULL /* reserved[123] */ -};
--- a/libpurple/protocols/gg/lib/packets.pb-c.h Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,766 +0,0 @@ -/* Generated by the protocol buffer compiler. DO NOT EDIT! */ -/* Generated from: packets.proto */ - -#ifndef PROTOBUF_C_packets_2eproto__INCLUDED -#define PROTOBUF_C_packets_2eproto__INCLUDED - -#include "protobuf.h" - -PROTOBUF_C__BEGIN_DECLS - -#if PROTOBUF_C_VERSION_NUMBER < 1000000 -# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. -#elif 1000002 < PROTOBUF_C_MIN_COMPILER_VERSION -# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. -#endif - - -typedef struct _GG110LoginOK GG110LoginOK; -typedef struct _GG110Pong GG110Pong; -typedef struct _GG110Ack GG110Ack; -typedef struct _GG105Login GG105Login; -typedef struct _GG110MessageAckLink GG110MessageAckLink; -typedef struct _GG110MessageAck GG110MessageAck; -typedef struct _GG110Event GG110Event; -typedef struct _GG110RecvMessage GG110RecvMessage; -typedef struct _GG110SendMessage GG110SendMessage; -typedef struct _GG110Imtoken GG110Imtoken; -typedef struct _GG110ChatInfoUpdate GG110ChatInfoUpdate; -typedef struct _ProtobufKVP ProtobufKVP; -typedef struct _GG110Options GG110Options; -typedef struct _GG110AccessInfo GG110AccessInfo; -typedef struct _GG112TransferInfoUin GG112TransferInfoUin; -typedef struct _GG112TransferInfoFile GG112TransferInfoFile; -typedef struct _GG112TransferInfo GG112TransferInfo; -typedef struct _GG110MagicNotification GG110MagicNotification; - - -/* --- enums --- */ - -typedef enum _GG110Ack__Type { - GG110_ACK__TYPE__MSG = 1, - GG110_ACK__TYPE__CHAT = 2, - GG110_ACK__TYPE__CHAT_INFO = 3, - GG110_ACK__TYPE__MAGIC_NOTIFICATION = 5, - GG110_ACK__TYPE__MPA = 6, - GG110_ACK__TYPE__TRANSFER_INFO = 7 - PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(GG110_ACK__TYPE) -} GG110Ack__Type; -typedef enum _GG110Event__Type { - GG110_EVENT__TYPE__XML = 0, - GG110_EVENT__TYPE__JSON = 2 - PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(GG110_EVENT__TYPE) -} GG110Event__Type; - -/* --- messages --- */ - -struct _GG110LoginOK -{ - ProtobufCMessage base; - int32_t dummy1; - char *dummyhash; - uint32_t uin; - uint32_t server_time; -}; -#define GG110_LOGIN_OK__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&gg110_login_ok__descriptor) \ - , 1, NULL, 0, 0 } - - -struct _GG110Pong -{ - ProtobufCMessage base; - uint32_t server_time; -}; -#define GG110_PONG__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&gg110_pong__descriptor) \ - , 0 } - - -struct _GG110Ack -{ - ProtobufCMessage base; - GG110Ack__Type type; - uint32_t seq; - uint32_t dummy1; -}; -#define GG110_ACK__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&gg110_ack__descriptor) \ - , 0, 0, 1u } - - -struct _GG105Login -{ - ProtobufCMessage base; - char *lang; - ProtobufCBinaryData uin; - ProtobufCBinaryData hash; - char *client; - uint32_t initial_status; - char *initial_descr; - char *supported_features; - int32_t dummy1; - uint32_t dummy2; - uint32_t dummy3; - ProtobufCBinaryData dummy4; - int32_t dummy5; - int32_t dummy6; - protobuf_c_boolean has_dummy7; - uint32_t dummy7; - protobuf_c_boolean has_dummy8; - int32_t dummy8; - protobuf_c_boolean has_dummy10; - uint32_t dummy10; -}; -extern char gg105_login__initial_descr__default_value[]; -#define GG105_LOGIN__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&gg105_login__descriptor) \ - , NULL, {0,NULL}, {0,NULL}, NULL, 8227u, gg105_login__initial_descr__default_value, NULL, 4, 65994615u, 198164u, {0,NULL}, 255, 100, 0,127u, 0,0, 0,0u } - - -struct _GG110MessageAckLink -{ - ProtobufCMessage base; - uint64_t id; - char *url; -}; -#define GG110_MESSAGE_ACK_LINK__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&gg110_message_ack_link__descriptor) \ - , 0, NULL } - - -struct _GG110MessageAck -{ - ProtobufCMessage base; - uint32_t msg_type; - uint32_t seq; - uint32_t time; - protobuf_c_boolean has_msg_id; - uint64_t msg_id; - protobuf_c_boolean has_conv_id; - uint64_t conv_id; - size_t n_links; - GG110MessageAckLink **links; - uint32_t dummy1; -}; -#define GG110_MESSAGE_ACK__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&gg110_message_ack__descriptor) \ - , 0, 0, 0, 0,0, 0,0, 0,NULL, 0u } - - -struct _GG110Event -{ - ProtobufCMessage base; - GG110Event__Type type; - uint32_t seq; - char *data; - char *subtype; - protobuf_c_boolean has_id; - uint64_t id; -}; -#define GG110_EVENT__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&gg110_event__descriptor) \ - , 0, 0, NULL, NULL, 0,0 } - - -struct _GG110RecvMessage -{ - ProtobufCMessage base; - protobuf_c_boolean has_sender; - ProtobufCBinaryData sender; - uint32_t flags; - uint32_t seq; - uint32_t time; - char *msg_plain; - char *msg_xhtml; - protobuf_c_boolean has_data; - ProtobufCBinaryData data; - protobuf_c_boolean has_msg_id; - uint64_t msg_id; - protobuf_c_boolean has_chat_id; - uint64_t chat_id; - protobuf_c_boolean has_conv_id; - uint64_t conv_id; -}; -extern char gg110_recv_message__msg_plain__default_value[]; -#define GG110_RECV_MESSAGE__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&gg110_recv_message__descriptor) \ - , 0,{0,NULL}, 0, 0, 0, gg110_recv_message__msg_plain__default_value, NULL, 0,{0,NULL}, 0,0, 0,0, 0,0 } - - -struct _GG110SendMessage -{ - ProtobufCMessage base; - protobuf_c_boolean has_recipient; - ProtobufCBinaryData recipient; - uint32_t dummy1; - uint32_t seq; - char *msg_plain; - char *msg_xhtml; - char *dummy3; - protobuf_c_boolean has_chat_id; - uint64_t chat_id; -}; -extern char gg110_send_message__dummy3__default_value[]; -#define GG110_SEND_MESSAGE__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&gg110_send_message__descriptor) \ - , 0,{0,NULL}, 8u, 0, NULL, NULL, gg110_send_message__dummy3__default_value, 0,0 } - - -struct _GG110Imtoken -{ - ProtobufCMessage base; - char *imtoken; -}; -#define GG110_IMTOKEN__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&gg110_imtoken__descriptor) \ - , NULL } - - -struct _GG110ChatInfoUpdate -{ - ProtobufCMessage base; - ProtobufCBinaryData participant; - ProtobufCBinaryData inviter; - uint32_t update_type; - uint32_t time; - uint32_t dummy1; - uint32_t version; - uint32_t dummy2; - uint64_t msg_id; - uint64_t chat_id; - uint64_t conv_id; -}; -#define GG110_CHAT_INFO_UPDATE__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&gg110_chat_info_update__descriptor) \ - , {0,NULL}, {0,NULL}, 0, 0, 0, 0, 0, 0, 0, 0 } - - -struct _ProtobufKVP -{ - ProtobufCMessage base; - char *key; - char *value; -}; -#define PROTOBUF_KVP__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&protobuf_kvp__descriptor) \ - , NULL, NULL } - - -struct _GG110Options -{ - ProtobufCMessage base; - size_t n_options; - ProtobufKVP **options; - uint32_t dummy1; -}; -#define GG110_OPTIONS__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&gg110_options__descriptor) \ - , 0,NULL, 0u } - - -struct _GG110AccessInfo -{ - ProtobufCMessage base; - uint32_t dummy1; - uint32_t dummy2; - uint32_t last_message; - uint32_t last_file_transfer; - uint32_t last_conference_ch; -}; -#define GG110_ACCESS_INFO__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&gg110_access_info__descriptor) \ - , 1u, 0, 0, 0, 0 } - - -struct _GG112TransferInfoUin -{ - ProtobufCMessage base; - uint32_t dummy1; - ProtobufCBinaryData uin; -}; -#define GG112_TRANSFER_INFO_UIN__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&gg112_transfer_info_uin__descriptor) \ - , 1u, {0,NULL} } - - -struct _GG112TransferInfoFile -{ - ProtobufCMessage base; - char *type; - char *url; - char *content_type; - char *filename; - uint32_t filesize; - uint64_t msg_id; -}; -extern char gg112_transfer_info_file__type__default_value[]; -#define GG112_TRANSFER_INFO_FILE__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&gg112_transfer_info_file__descriptor) \ - , gg112_transfer_info_file__type__default_value, NULL, NULL, NULL, 0, 0 } - - -struct _GG112TransferInfo -{ - ProtobufCMessage base; - uint32_t dummy1; - GG112TransferInfoUin *peer; - GG112TransferInfoUin *sender; - uint32_t time; - size_t n_data; - ProtobufKVP **data; - GG112TransferInfoFile *file; - uint32_t seq; - uint64_t msg_id; - uint64_t conv_id; -}; -#define GG112_TRANSFER_INFO__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&gg112_transfer_info__descriptor) \ - , 0, NULL, NULL, 0, 0,NULL, NULL, 0, 0, 0 } - - -struct _GG110MagicNotification -{ - ProtobufCMessage base; - int32_t dummy1; - int32_t seq; - int32_t dummy2; - int32_t dummy3; - ProtobufCBinaryData uin; - char *dummy4; -}; -extern char gg110_magic_notification__dummy4__default_value[]; -#define GG110_MAGIC_NOTIFICATION__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&gg110_magic_notification__descriptor) \ - , 2, 0, 1, 1, {0,NULL}, gg110_magic_notification__dummy4__default_value } - - -/* GG110LoginOK methods */ -void gg110_login_ok__init - (GG110LoginOK *message); -size_t gg110_login_ok__get_packed_size - (const GG110LoginOK *message); -size_t gg110_login_ok__pack - (const GG110LoginOK *message, - uint8_t *out); -size_t gg110_login_ok__pack_to_buffer - (const GG110LoginOK *message, - ProtobufCBuffer *buffer); -GG110LoginOK * - gg110_login_ok__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -void gg110_login_ok__free_unpacked - (GG110LoginOK *message, - ProtobufCAllocator *allocator); -/* GG110Pong methods */ -void gg110_pong__init - (GG110Pong *message); -size_t gg110_pong__get_packed_size - (const GG110Pong *message); -size_t gg110_pong__pack - (const GG110Pong *message, - uint8_t *out); -size_t gg110_pong__pack_to_buffer - (const GG110Pong *message, - ProtobufCBuffer *buffer); -GG110Pong * - gg110_pong__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -void gg110_pong__free_unpacked - (GG110Pong *message, - ProtobufCAllocator *allocator); -/* GG110Ack methods */ -void gg110_ack__init - (GG110Ack *message); -size_t gg110_ack__get_packed_size - (const GG110Ack *message); -size_t gg110_ack__pack - (const GG110Ack *message, - uint8_t *out); -size_t gg110_ack__pack_to_buffer - (const GG110Ack *message, - ProtobufCBuffer *buffer); -GG110Ack * - gg110_ack__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -void gg110_ack__free_unpacked - (GG110Ack *message, - ProtobufCAllocator *allocator); -/* GG105Login methods */ -void gg105_login__init - (GG105Login *message); -size_t gg105_login__get_packed_size - (const GG105Login *message); -size_t gg105_login__pack - (const GG105Login *message, - uint8_t *out); -size_t gg105_login__pack_to_buffer - (const GG105Login *message, - ProtobufCBuffer *buffer); -GG105Login * - gg105_login__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -void gg105_login__free_unpacked - (GG105Login *message, - ProtobufCAllocator *allocator); -/* GG110MessageAckLink methods */ -void gg110_message_ack_link__init - (GG110MessageAckLink *message); -size_t gg110_message_ack_link__get_packed_size - (const GG110MessageAckLink *message); -size_t gg110_message_ack_link__pack - (const GG110MessageAckLink *message, - uint8_t *out); -size_t gg110_message_ack_link__pack_to_buffer - (const GG110MessageAckLink *message, - ProtobufCBuffer *buffer); -GG110MessageAckLink * - gg110_message_ack_link__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -void gg110_message_ack_link__free_unpacked - (GG110MessageAckLink *message, - ProtobufCAllocator *allocator); -/* GG110MessageAck methods */ -void gg110_message_ack__init - (GG110MessageAck *message); -size_t gg110_message_ack__get_packed_size - (const GG110MessageAck *message); -size_t gg110_message_ack__pack - (const GG110MessageAck *message, - uint8_t *out); -size_t gg110_message_ack__pack_to_buffer - (const GG110MessageAck *message, - ProtobufCBuffer *buffer); -GG110MessageAck * - gg110_message_ack__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -void gg110_message_ack__free_unpacked - (GG110MessageAck *message, - ProtobufCAllocator *allocator); -/* GG110Event methods */ -void gg110_event__init - (GG110Event *message); -size_t gg110_event__get_packed_size - (const GG110Event *message); -size_t gg110_event__pack - (const GG110Event *message, - uint8_t *out); -size_t gg110_event__pack_to_buffer - (const GG110Event *message, - ProtobufCBuffer *buffer); -GG110Event * - gg110_event__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -void gg110_event__free_unpacked - (GG110Event *message, - ProtobufCAllocator *allocator); -/* GG110RecvMessage methods */ -void gg110_recv_message__init - (GG110RecvMessage *message); -size_t gg110_recv_message__get_packed_size - (const GG110RecvMessage *message); -size_t gg110_recv_message__pack - (const GG110RecvMessage *message, - uint8_t *out); -size_t gg110_recv_message__pack_to_buffer - (const GG110RecvMessage *message, - ProtobufCBuffer *buffer); -GG110RecvMessage * - gg110_recv_message__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -void gg110_recv_message__free_unpacked - (GG110RecvMessage *message, - ProtobufCAllocator *allocator); -/* GG110SendMessage methods */ -void gg110_send_message__init - (GG110SendMessage *message); -size_t gg110_send_message__get_packed_size - (const GG110SendMessage *message); -size_t gg110_send_message__pack - (const GG110SendMessage *message, - uint8_t *out); -size_t gg110_send_message__pack_to_buffer - (const GG110SendMessage *message, - ProtobufCBuffer *buffer); -GG110SendMessage * - gg110_send_message__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -void gg110_send_message__free_unpacked - (GG110SendMessage *message, - ProtobufCAllocator *allocator); -/* GG110Imtoken methods */ -void gg110_imtoken__init - (GG110Imtoken *message); -size_t gg110_imtoken__get_packed_size - (const GG110Imtoken *message); -size_t gg110_imtoken__pack - (const GG110Imtoken *message, - uint8_t *out); -size_t gg110_imtoken__pack_to_buffer - (const GG110Imtoken *message, - ProtobufCBuffer *buffer); -GG110Imtoken * - gg110_imtoken__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -void gg110_imtoken__free_unpacked - (GG110Imtoken *message, - ProtobufCAllocator *allocator); -/* GG110ChatInfoUpdate methods */ -void gg110_chat_info_update__init - (GG110ChatInfoUpdate *message); -size_t gg110_chat_info_update__get_packed_size - (const GG110ChatInfoUpdate *message); -size_t gg110_chat_info_update__pack - (const GG110ChatInfoUpdate *message, - uint8_t *out); -size_t gg110_chat_info_update__pack_to_buffer - (const GG110ChatInfoUpdate *message, - ProtobufCBuffer *buffer); -GG110ChatInfoUpdate * - gg110_chat_info_update__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -void gg110_chat_info_update__free_unpacked - (GG110ChatInfoUpdate *message, - ProtobufCAllocator *allocator); -/* ProtobufKVP methods */ -void protobuf_kvp__init - (ProtobufKVP *message); -size_t protobuf_kvp__get_packed_size - (const ProtobufKVP *message); -size_t protobuf_kvp__pack - (const ProtobufKVP *message, - uint8_t *out); -size_t protobuf_kvp__pack_to_buffer - (const ProtobufKVP *message, - ProtobufCBuffer *buffer); -ProtobufKVP * - protobuf_kvp__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -void protobuf_kvp__free_unpacked - (ProtobufKVP *message, - ProtobufCAllocator *allocator); -/* GG110Options methods */ -void gg110_options__init - (GG110Options *message); -size_t gg110_options__get_packed_size - (const GG110Options *message); -size_t gg110_options__pack - (const GG110Options *message, - uint8_t *out); -size_t gg110_options__pack_to_buffer - (const GG110Options *message, - ProtobufCBuffer *buffer); -GG110Options * - gg110_options__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -void gg110_options__free_unpacked - (GG110Options *message, - ProtobufCAllocator *allocator); -/* GG110AccessInfo methods */ -void gg110_access_info__init - (GG110AccessInfo *message); -size_t gg110_access_info__get_packed_size - (const GG110AccessInfo *message); -size_t gg110_access_info__pack - (const GG110AccessInfo *message, - uint8_t *out); -size_t gg110_access_info__pack_to_buffer - (const GG110AccessInfo *message, - ProtobufCBuffer *buffer); -GG110AccessInfo * - gg110_access_info__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -void gg110_access_info__free_unpacked - (GG110AccessInfo *message, - ProtobufCAllocator *allocator); -/* GG112TransferInfoUin methods */ -void gg112_transfer_info_uin__init - (GG112TransferInfoUin *message); -size_t gg112_transfer_info_uin__get_packed_size - (const GG112TransferInfoUin *message); -size_t gg112_transfer_info_uin__pack - (const GG112TransferInfoUin *message, - uint8_t *out); -size_t gg112_transfer_info_uin__pack_to_buffer - (const GG112TransferInfoUin *message, - ProtobufCBuffer *buffer); -GG112TransferInfoUin * - gg112_transfer_info_uin__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -void gg112_transfer_info_uin__free_unpacked - (GG112TransferInfoUin *message, - ProtobufCAllocator *allocator); -/* GG112TransferInfoFile methods */ -void gg112_transfer_info_file__init - (GG112TransferInfoFile *message); -size_t gg112_transfer_info_file__get_packed_size - (const GG112TransferInfoFile *message); -size_t gg112_transfer_info_file__pack - (const GG112TransferInfoFile *message, - uint8_t *out); -size_t gg112_transfer_info_file__pack_to_buffer - (const GG112TransferInfoFile *message, - ProtobufCBuffer *buffer); -GG112TransferInfoFile * - gg112_transfer_info_file__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -void gg112_transfer_info_file__free_unpacked - (GG112TransferInfoFile *message, - ProtobufCAllocator *allocator); -/* GG112TransferInfo methods */ -void gg112_transfer_info__init - (GG112TransferInfo *message); -size_t gg112_transfer_info__get_packed_size - (const GG112TransferInfo *message); -size_t gg112_transfer_info__pack - (const GG112TransferInfo *message, - uint8_t *out); -size_t gg112_transfer_info__pack_to_buffer - (const GG112TransferInfo *message, - ProtobufCBuffer *buffer); -GG112TransferInfo * - gg112_transfer_info__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -void gg112_transfer_info__free_unpacked - (GG112TransferInfo *message, - ProtobufCAllocator *allocator); -/* GG110MagicNotification methods */ -void gg110_magic_notification__init - (GG110MagicNotification *message); -size_t gg110_magic_notification__get_packed_size - (const GG110MagicNotification *message); -size_t gg110_magic_notification__pack - (const GG110MagicNotification *message, - uint8_t *out); -size_t gg110_magic_notification__pack_to_buffer - (const GG110MagicNotification *message, - ProtobufCBuffer *buffer); -GG110MagicNotification * - gg110_magic_notification__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -void gg110_magic_notification__free_unpacked - (GG110MagicNotification *message, - ProtobufCAllocator *allocator); -/* --- per-message closures --- */ - -typedef void (*GG110LoginOK_Closure) - (const GG110LoginOK *message, - void *closure_data); -typedef void (*GG110Pong_Closure) - (const GG110Pong *message, - void *closure_data); -typedef void (*GG110Ack_Closure) - (const GG110Ack *message, - void *closure_data); -typedef void (*GG105Login_Closure) - (const GG105Login *message, - void *closure_data); -typedef void (*GG110MessageAckLink_Closure) - (const GG110MessageAckLink *message, - void *closure_data); -typedef void (*GG110MessageAck_Closure) - (const GG110MessageAck *message, - void *closure_data); -typedef void (*GG110Event_Closure) - (const GG110Event *message, - void *closure_data); -typedef void (*GG110RecvMessage_Closure) - (const GG110RecvMessage *message, - void *closure_data); -typedef void (*GG110SendMessage_Closure) - (const GG110SendMessage *message, - void *closure_data); -typedef void (*GG110Imtoken_Closure) - (const GG110Imtoken *message, - void *closure_data); -typedef void (*GG110ChatInfoUpdate_Closure) - (const GG110ChatInfoUpdate *message, - void *closure_data); -typedef void (*ProtobufKVP_Closure) - (const ProtobufKVP *message, - void *closure_data); -typedef void (*GG110Options_Closure) - (const GG110Options *message, - void *closure_data); -typedef void (*GG110AccessInfo_Closure) - (const GG110AccessInfo *message, - void *closure_data); -typedef void (*GG112TransferInfoUin_Closure) - (const GG112TransferInfoUin *message, - void *closure_data); -typedef void (*GG112TransferInfoFile_Closure) - (const GG112TransferInfoFile *message, - void *closure_data); -typedef void (*GG112TransferInfo_Closure) - (const GG112TransferInfo *message, - void *closure_data); -typedef void (*GG110MagicNotification_Closure) - (const GG110MagicNotification *message, - void *closure_data); - -/* --- services --- */ - - -/* --- descriptors --- */ - -extern const ProtobufCMessageDescriptor gg110_login_ok__descriptor; -extern const ProtobufCMessageDescriptor gg110_pong__descriptor; -extern const ProtobufCMessageDescriptor gg110_ack__descriptor; -extern const ProtobufCEnumDescriptor gg110_ack__type__descriptor; -extern const ProtobufCMessageDescriptor gg105_login__descriptor; -extern const ProtobufCMessageDescriptor gg110_message_ack_link__descriptor; -extern const ProtobufCMessageDescriptor gg110_message_ack__descriptor; -extern const ProtobufCMessageDescriptor gg110_event__descriptor; -extern const ProtobufCEnumDescriptor gg110_event__type__descriptor; -extern const ProtobufCMessageDescriptor gg110_recv_message__descriptor; -extern const ProtobufCMessageDescriptor gg110_send_message__descriptor; -extern const ProtobufCMessageDescriptor gg110_imtoken__descriptor; -extern const ProtobufCMessageDescriptor gg110_chat_info_update__descriptor; -extern const ProtobufCMessageDescriptor protobuf_kvp__descriptor; -extern const ProtobufCMessageDescriptor gg110_options__descriptor; -extern const ProtobufCMessageDescriptor gg110_access_info__descriptor; -extern const ProtobufCMessageDescriptor gg112_transfer_info_uin__descriptor; -extern const ProtobufCMessageDescriptor gg112_transfer_info_file__descriptor; -extern const ProtobufCMessageDescriptor gg112_transfer_info__descriptor; -extern const ProtobufCMessageDescriptor gg110_magic_notification__descriptor; - -PROTOBUF_C__END_DECLS - - -#endif /* PROTOBUF_C_packets_2eproto__INCLUDED */
--- a/libpurple/protocols/gg/lib/protobuf-c.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3288 +0,0 @@ -/* - * Copyright (c) 2008-2014, Dave Benson and the protobuf-c authors. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/*! \file - * Support library for `protoc-c` generated code. - * - * This file implements the public API used by the code generated - * by `protoc-c`. - * - * \authors Dave Benson and the protobuf-c authors - * - * \copyright 2008-2014. Licensed under the terms of the [BSD-2-Clause] license. - */ - -/** - * \todo 64-BIT OPTIMIZATION: certain implementations use 32-bit math - * even on 64-bit platforms (uint64_size, uint64_pack, parse_uint64). - * - * \todo Use size_t consistently. - */ - -#include <stdlib.h> /* for malloc, free */ -#include <string.h> /* for strcmp, strlen, memcpy, memmove, memset */ - -/* Pull WORDS_BIGENDIAN etc */ -#include "config.h" - -#include "protobuf-c.h" - -#define TRUE 1 -#define FALSE 0 - -#define PROTOBUF_C__ASSERT_NOT_REACHED() assert(0) - -/* Workaround for Microsoft compilers. */ -#ifdef _MSC_VER -# define inline __inline -#endif - -/** - * \defgroup internal Internal functions and macros - * - * These are not exported by the library but are useful to developers working - * on `libprotobuf-c` itself. - */ - -/** - * \defgroup macros Utility macros for manipulating structures - * - * Macros and constants used to manipulate the base "classes" generated by - * `protobuf-c`. They also define limits and check correctness. - * - * \ingroup internal - * @{ - */ - -/** The maximum length of a 64-bit integer in varint encoding. */ -#define MAX_UINT64_ENCODED_SIZE 10 - -#ifndef PROTOBUF_C_UNPACK_ERROR -# define PROTOBUF_C_UNPACK_ERROR(...) -#endif - -/** - * Internal `ProtobufCMessage` manipulation macro. - * - * Base macro for manipulating a `ProtobufCMessage`. Used by STRUCT_MEMBER() and - * STRUCT_MEMBER_PTR(). - */ -#define STRUCT_MEMBER_P(struct_p, struct_offset) \ - ((void *) ((uint8_t *) (struct_p) + (struct_offset))) - -/** - * Return field in a `ProtobufCMessage` based on offset. - * - * Take a pointer to a `ProtobufCMessage` and find the field at the offset. - * Cast it to the passed type. - */ -#define STRUCT_MEMBER(member_type, struct_p, struct_offset) \ - (*(member_type *) STRUCT_MEMBER_P((struct_p), (struct_offset))) - -/** - * Return field in a `ProtobufCMessage` based on offset. - * - * Take a pointer to a `ProtobufCMessage` and find the field at the offset. Cast - * it to a pointer to the passed type. - */ -#define STRUCT_MEMBER_PTR(member_type, struct_p, struct_offset) \ - ((member_type *) STRUCT_MEMBER_P((struct_p), (struct_offset))) - -/* Assertions for magic numbers. */ - -#define ASSERT_IS_ENUM_DESCRIPTOR(desc) \ - assert((desc)->magic == PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC) - -#define ASSERT_IS_MESSAGE_DESCRIPTOR(desc) \ - assert((desc)->magic == PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) - -#define ASSERT_IS_MESSAGE(message) \ - ASSERT_IS_MESSAGE_DESCRIPTOR((message)->descriptor) - -#define ASSERT_IS_SERVICE_DESCRIPTOR(desc) \ - assert((desc)->magic == PROTOBUF_C__SERVICE_DESCRIPTOR_MAGIC) - -/**@}*/ - -/* --- version --- */ - -const char * -protobuf_c_version(void) -{ - return PROTOBUF_C_VERSION; -} - -uint32_t -protobuf_c_version_number(void) -{ - return PROTOBUF_C_VERSION_NUMBER; -} - -/* --- allocator --- */ - -static void * -system_alloc(void *allocator_data, size_t size) -{ - return malloc(size); -} - -static void -system_free(void *allocator_data, void *data) -{ - free(data); -} - -static inline void * -do_alloc(ProtobufCAllocator *allocator, size_t size) -{ - return allocator->alloc(allocator->allocator_data, size); -} - -static inline void -do_free(ProtobufCAllocator *allocator, void *data) -{ - if (data != NULL) - allocator->free(allocator->allocator_data, data); -} - -/* - * This allocator uses the system's malloc() and free(). It is the default - * allocator used if NULL is passed as the ProtobufCAllocator to an exported - * function. - */ -static ProtobufCAllocator protobuf_c__allocator = { - .alloc = &system_alloc, - .free = &system_free, - .allocator_data = NULL, -}; - -/* === buffer-simple === */ - -void -protobuf_c_buffer_simple_append(ProtobufCBuffer *buffer, - size_t len, const uint8_t *data) -{ - ProtobufCBufferSimple *simp = (ProtobufCBufferSimple *) buffer; - size_t new_len = simp->len + len; - - if (new_len > simp->alloced) { - ProtobufCAllocator *allocator = simp->allocator; - size_t new_alloced = simp->alloced * 2; - uint8_t *new_data; - - if (allocator == NULL) - allocator = &protobuf_c__allocator; - while (new_alloced < new_len) - new_alloced += new_alloced; - new_data = do_alloc(allocator, new_alloced); - if (!new_data) - return; - memcpy(new_data, simp->data, simp->len); - if (simp->must_free_data) - do_free(allocator, simp->data); - else - simp->must_free_data = TRUE; - simp->data = new_data; - simp->alloced = new_alloced; - } - memcpy(simp->data + simp->len, data, len); - simp->len = new_len; -} - -/** - * \defgroup packedsz protobuf_c_message_get_packed_size() implementation - * - * Routines mainly used by protobuf_c_message_get_packed_size(). - * - * \ingroup internal - * @{ - */ - -/** - * Return the number of bytes required to store the tag for the field. Includes - * 3 bits for the wire-type, and a single bit that denotes the end-of-tag. - * - * \param number - * Field tag to encode. - * \return - * Number of bytes required. - */ -static inline size_t -get_tag_size(unsigned number) -{ - if (number < (1 << 4)) { - return 1; - } else if (number < (1 << 11)) { - return 2; - } else if (number < (1 << 18)) { - return 3; - } else if (number < (1 << 25)) { - return 4; - } else { - return 5; - } -} - -/** - * Return the number of bytes required to store a variable-length unsigned - * 32-bit integer in base-128 varint encoding. - * - * \param v - * Value to encode. - * \return - * Number of bytes required. - */ -static inline size_t -uint32_size(uint32_t v) -{ - if (v < (1 << 7)) { - return 1; - } else if (v < (1 << 14)) { - return 2; - } else if (v < (1 << 21)) { - return 3; - } else if (v < (1 << 28)) { - return 4; - } else { - return 5; - } -} - -/** - * Return the number of bytes required to store a variable-length signed 32-bit - * integer in base-128 varint encoding. - * - * \param v - * Value to encode. - * \return - * Number of bytes required. - */ -static inline size_t -int32_size(int32_t v) -{ - if (v < 0) { - return 10; - } else if (v < (1 << 7)) { - return 1; - } else if (v < (1 << 14)) { - return 2; - } else if (v < (1 << 21)) { - return 3; - } else if (v < (1 << 28)) { - return 4; - } else { - return 5; - } -} - -/** - * Return the ZigZag-encoded 32-bit unsigned integer form of a 32-bit signed - * integer. - * - * \param v - * Value to encode. - * \return - * ZigZag encoded integer. - */ -static inline uint32_t -zigzag32(int32_t v) -{ - if (v < 0) - return ((uint32_t) (-v)) * 2 - 1; - else - return v * 2; -} - -/** - * Return the number of bytes required to store a signed 32-bit integer, - * converted to an unsigned 32-bit integer with ZigZag encoding, using base-128 - * varint encoding. - * - * \param v - * Value to encode. - * \return - * Number of bytes required. - */ -static inline size_t -sint32_size(int32_t v) -{ - return uint32_size(zigzag32(v)); -} - -/** - * Return the number of bytes required to store a 64-bit unsigned integer in - * base-128 varint encoding. - * - * \param v - * Value to encode. - * \return - * Number of bytes required. - */ -static inline size_t -uint64_size(uint64_t v) -{ - uint32_t upper_v = (uint32_t) (v >> 32); - - if (upper_v == 0) { - return uint32_size((uint32_t) v); - } else if (upper_v < (1 << 3)) { - return 5; - } else if (upper_v < (1 << 10)) { - return 6; - } else if (upper_v < (1 << 17)) { - return 7; - } else if (upper_v < (1 << 24)) { - return 8; - } else if (upper_v < (1U << 31)) { - return 9; - } else { - return 10; - } -} - -/** - * Return the ZigZag-encoded 64-bit unsigned integer form of a 64-bit signed - * integer. - * - * \param v - * Value to encode. - * \return - * ZigZag encoded integer. - */ -static inline uint64_t -zigzag64(int64_t v) -{ - if (v < 0) - return ((uint64_t) (-v)) * 2 - 1; - else - return v * 2; -} - -/** - * Return the number of bytes required to store a signed 64-bit integer, - * converted to an unsigned 64-bit integer with ZigZag encoding, using base-128 - * varint encoding. - * - * \param v - * Value to encode. - * \return - * Number of bytes required. - */ -static inline size_t -sint64_size(int64_t v) -{ - return uint64_size(zigzag64(v)); -} - -/** - * Calculate the serialized size of a single required message field, including - * the space needed by the preceding tag. - * - * \param field - * Field descriptor for member. - * \param member - * Field to encode. - * \return - * Number of bytes required. - */ -static size_t -required_field_get_packed_size(const ProtobufCFieldDescriptor *field, - const void *member) -{ - size_t rv = get_tag_size(field->id); - - switch (field->type) { - case PROTOBUF_C_TYPE_SINT32: - return rv + sint32_size(*(const int32_t *) member); - case PROTOBUF_C_TYPE_INT32: - return rv + int32_size(*(const uint32_t *) member); - case PROTOBUF_C_TYPE_UINT32: - return rv + uint32_size(*(const uint32_t *) member); - case PROTOBUF_C_TYPE_SINT64: - return rv + sint64_size(*(const int64_t *) member); - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_UINT64: - return rv + uint64_size(*(const uint64_t *) member); - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - return rv + 4; - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - return rv + 8; - case PROTOBUF_C_TYPE_BOOL: - return rv + 1; - case PROTOBUF_C_TYPE_FLOAT: - return rv + 4; - case PROTOBUF_C_TYPE_DOUBLE: - return rv + 8; - case PROTOBUF_C_TYPE_ENUM: - /* \todo Is this correct for negative-valued enums? */ - return rv + uint32_size(*(const uint32_t *) member); - case PROTOBUF_C_TYPE_STRING: { - const char *str = *(char * const *) member; - size_t len = str ? strlen(str) : 0; - return rv + uint32_size(len) + len; - } - case PROTOBUF_C_TYPE_BYTES: { - size_t len = ((const ProtobufCBinaryData *) member)->len; - return rv + uint32_size(len) + len; - } - case PROTOBUF_C_TYPE_MESSAGE: { - const ProtobufCMessage *msg = *(ProtobufCMessage * const *) member; - size_t subrv = msg ? protobuf_c_message_get_packed_size(msg) : 0; - return rv + uint32_size(subrv) + subrv; - } - } - PROTOBUF_C__ASSERT_NOT_REACHED(); - return 0; -} - -/** - * Calculate the serialized size of a single optional message field, including - * the space needed by the preceding tag. Returns 0 if the optional field isn't - * set. - * - * \param field - * Field descriptor for member. - * \param has - * True if the field exists, false if not. - * \param member - * Field to encode. - * \return - * Number of bytes required. - */ -static size_t -optional_field_get_packed_size(const ProtobufCFieldDescriptor *field, - const protobuf_c_boolean *has, - const void *member) -{ - if (field->type == PROTOBUF_C_TYPE_MESSAGE || - field->type == PROTOBUF_C_TYPE_STRING) - { - const void *ptr = *(const void * const *) member; - if (ptr == NULL || ptr == field->default_value) - return 0; - } else { - if (!*has) - return 0; - } - return required_field_get_packed_size(field, member); -} - -/** - * Calculate the serialized size of repeated message fields, which may consist - * of any number of values (including 0). Includes the space needed by the - * preceding tags (as needed). - * - * \param field - * Field descriptor for member. - * \param count - * Number of repeated field members. - * \param member - * Field to encode. - * \return - * Number of bytes required. - */ -static size_t -repeated_field_get_packed_size(const ProtobufCFieldDescriptor *field, - size_t count, const void *member) -{ - size_t header_size; - size_t rv = 0; - unsigned i; - void *array = *(void * const *) member; - - if (count == 0) - return 0; - header_size = get_tag_size(field->id); - if (0 == (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) - header_size *= count; - - switch (field->type) { - case PROTOBUF_C_TYPE_SINT32: - for (i = 0; i < count; i++) - rv += sint32_size(((int32_t *) array)[i]); - break; - case PROTOBUF_C_TYPE_INT32: - for (i = 0; i < count; i++) - rv += int32_size(((uint32_t *) array)[i]); - break; - case PROTOBUF_C_TYPE_UINT32: - case PROTOBUF_C_TYPE_ENUM: - for (i = 0; i < count; i++) - rv += uint32_size(((uint32_t *) array)[i]); - break; - case PROTOBUF_C_TYPE_SINT64: - for (i = 0; i < count; i++) - rv += sint64_size(((int64_t *) array)[i]); - break; - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_UINT64: - for (i = 0; i < count; i++) - rv += uint64_size(((uint64_t *) array)[i]); - break; - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: - rv += 4 * count; - break; - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: - rv += 8 * count; - break; - case PROTOBUF_C_TYPE_BOOL: - rv += count; - break; - case PROTOBUF_C_TYPE_STRING: - for (i = 0; i < count; i++) { - size_t len = strlen(((char **) array)[i]); - rv += uint32_size(len) + len; - } - break; - case PROTOBUF_C_TYPE_BYTES: - for (i = 0; i < count; i++) { - size_t len = ((ProtobufCBinaryData *) array)[i].len; - rv += uint32_size(len) + len; - } - break; - case PROTOBUF_C_TYPE_MESSAGE: - for (i = 0; i < count; i++) { - size_t len = protobuf_c_message_get_packed_size( - ((ProtobufCMessage **) array)[i]); - rv += uint32_size(len) + len; - } - break; - } - - if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) - header_size += uint32_size(rv); - return header_size + rv; -} - -/** - * Calculate the serialized size of an unknown field, i.e. one that is passed - * through mostly uninterpreted. This is required for forward compatibility if - * new fields are added to the message descriptor. - * - * \param field - * Unknown field type. - * \return - * Number of bytes required. - */ -static inline size_t -unknown_field_get_packed_size(const ProtobufCMessageUnknownField *field) -{ - return get_tag_size(field->tag) + field->len; -} - -/**@}*/ - -/* - * Calculate the serialized size of the message. - */ -size_t protobuf_c_message_get_packed_size(const ProtobufCMessage *message) -{ - unsigned i; - size_t rv = 0; - - ASSERT_IS_MESSAGE(message); - for (i = 0; i < message->descriptor->n_fields; i++) { - const ProtobufCFieldDescriptor *field = - message->descriptor->fields + i; - const void *member = - ((const char *) message) + field->offset; - const void *qmember = - ((const char *) message) + field->quantifier_offset; - - if (field->label == PROTOBUF_C_LABEL_REQUIRED) { - rv += required_field_get_packed_size(field, member); - } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) { - rv += optional_field_get_packed_size(field, qmember, member); - } else { - rv += repeated_field_get_packed_size( - field, - *(const size_t *) qmember, - member - ); - } - } - for (i = 0; i < message->n_unknown_fields; i++) - rv += unknown_field_get_packed_size(&message->unknown_fields[i]); - return rv; -} - -/** - * \defgroup pack protobuf_c_message_pack() implementation - * - * Routines mainly used by protobuf_c_message_pack(). - * - * \ingroup internal - * @{ - */ - -/** - * Pack an unsigned 32-bit integer in base-128 varint encoding and return the - * number of bytes written, which must be 5 or less. - * - * \param value - * Value to encode. - * \param[out] out - * Packed value. - * \return - * Number of bytes written to `out`. - */ -static inline size_t -uint32_pack(uint32_t value, uint8_t *out) -{ - unsigned rv = 0; - - if (value >= 0x80) { - out[rv++] = value | 0x80; - value >>= 7; - if (value >= 0x80) { - out[rv++] = value | 0x80; - value >>= 7; - if (value >= 0x80) { - out[rv++] = value | 0x80; - value >>= 7; - if (value >= 0x80) { - out[rv++] = value | 0x80; - value >>= 7; - } - } - } - } - /* assert: value<128 */ - out[rv++] = value; - return rv; -} - -/** - * Pack a signed 32-bit integer and return the number of bytes written. - * Negative numbers are encoded as two's complement 64-bit integers. - * - * \param value - * Value to encode. - * \param[out] out - * Packed value. - * \return - * Number of bytes written to `out`. - */ -static inline size_t -int32_pack(int32_t value, uint8_t *out) -{ - if (value < 0) { - out[0] = value | 0x80; - out[1] = (value >> 7) | 0x80; - out[2] = (value >> 14) | 0x80; - out[3] = (value >> 21) | 0x80; - out[4] = (value >> 28) | 0x80; - out[5] = out[6] = out[7] = out[8] = 0xff; - out[9] = 0x01; - return 10; - } else { - return uint32_pack(value, out); - } -} - -/** - * Pack a signed 32-bit integer using ZigZag encoding and return the number of - * bytes written. - * - * \param value - * Value to encode. - * \param[out] out - * Packed value. - * \return - * Number of bytes written to `out`. - */ -static inline size_t -sint32_pack(int32_t value, uint8_t *out) -{ - return uint32_pack(zigzag32(value), out); -} - -/** - * Pack a 64-bit unsigned integer using base-128 varint encoding and return the - * number of bytes written. - * - * \param value - * Value to encode. - * \param[out] out - * Packed value. - * \return - * Number of bytes written to `out`. - */ -static size_t -uint64_pack(uint64_t value, uint8_t *out) -{ - uint32_t hi = (uint32_t) (value >> 32); - uint32_t lo = (uint32_t) value; - unsigned rv; - - if (hi == 0) - return uint32_pack((uint32_t) lo, out); - out[0] = (lo) | 0x80; - out[1] = (lo >> 7) | 0x80; - out[2] = (lo >> 14) | 0x80; - out[3] = (lo >> 21) | 0x80; - if (hi < 8) { - out[4] = (hi << 4) | (lo >> 28); - return 5; - } else { - out[4] = ((hi & 7) << 4) | (lo >> 28) | 0x80; - hi >>= 3; - } - rv = 5; - while (hi >= 128) { - out[rv++] = hi | 0x80; - hi >>= 7; - } - out[rv++] = hi; - return rv; -} - -/** - * Pack a 64-bit signed integer in ZigZag encoding and return the number of - * bytes written. - * - * \param value - * Value to encode. - * \param[out] out - * Packed value. - * \return - * Number of bytes written to `out`. - */ -static inline size_t -sint64_pack(int64_t value, uint8_t *out) -{ - return uint64_pack(zigzag64(value), out); -} - -/** - * Pack a 32-bit quantity in little-endian byte order. Used for protobuf wire - * types fixed32, sfixed32, float. Similar to "htole32". - * - * \param value - * Value to encode. - * \param[out] out - * Packed value. - * \return - * Number of bytes written to `out`. - */ -static inline size_t -fixed32_pack(uint32_t value, void *out) -{ -#if !defined(WORDS_BIGENDIAN) - memcpy(out, &value, 4); -#else - uint8_t *buf = out; - - buf[0] = value; - buf[1] = value >> 8; - buf[2] = value >> 16; - buf[3] = value >> 24; -#endif - return 4; -} - -/** - * Pack a 64-bit quantity in little-endian byte order. Used for protobuf wire - * types fixed64, sfixed64, double. Similar to "htole64". - * - * \todo The big-endian impl is really only good for 32-bit machines, a 64-bit - * version would be appreciated, plus a way to decide to use 64-bit math where - * convenient. - * - * \param value - * Value to encode. - * \param[out] out - * Packed value. - * \return - * Number of bytes written to `out`. - */ -static inline size_t -fixed64_pack(uint64_t value, void *out) -{ -#if !defined(WORDS_BIGENDIAN) - memcpy(out, &value, 8); -#else - fixed32_pack(value, out); - fixed32_pack(value >> 32, ((char *) out) + 4); -#endif - return 8; -} - -/** - * Pack a boolean value as an integer and return the number of bytes written. - * - * \todo Perhaps on some platforms *out = !!value would be a better impl, b/c - * that is idiomatic C++ in some STL implementations. - * - * \param value - * Value to encode. - * \param[out] out - * Packed value. - * \return - * Number of bytes written to `out`. - */ -static inline size_t -boolean_pack(protobuf_c_boolean value, uint8_t *out) -{ - *out = value ? TRUE : FALSE; - return 1; -} - -/** - * Pack a NUL-terminated C string and return the number of bytes written. The - * output includes a length delimiter. - * - * The NULL pointer is treated as an empty string. This isn't really necessary, - * but it allows people to leave required strings blank. (See Issue #13 in the - * bug tracker for a little more explanation). - * - * \param str - * String to encode. - * \param[out] out - * Packed value. - * \return - * Number of bytes written to `out`. - */ -static inline size_t -string_pack(const char *str, uint8_t *out) -{ - if (str == NULL) { - out[0] = 0; - return 1; - } else { - size_t len = strlen(str); - size_t rv = uint32_pack(len, out); - memcpy(out + rv, str, len); - return rv + len; - } -} - -/** - * Pack a ProtobufCBinaryData and return the number of bytes written. The output - * includes a length delimiter. - * - * \param bd - * ProtobufCBinaryData to encode. - * \param[out] out - * Packed value. - * \return - * Number of bytes written to `out`. - */ -static inline size_t -binary_data_pack(const ProtobufCBinaryData *bd, uint8_t *out) -{ - size_t len = bd->len; - size_t rv = uint32_pack(len, out); - memcpy(out + rv, bd->data, len); - return rv + len; -} - -/** - * Pack a ProtobufCMessage and return the number of bytes written. The output - * includes a length delimiter. - * - * \param message - * ProtobufCMessage object to pack. - * \param[out] out - * Packed message. - * \return - * Number of bytes written to `out`. - */ -static inline size_t -prefixed_message_pack(const ProtobufCMessage *message, uint8_t *out) -{ - if (message == NULL) { - out[0] = 0; - return 1; - } else { - size_t rv = protobuf_c_message_pack(message, out + 1); - uint32_t rv_packed_size = uint32_size(rv); - if (rv_packed_size != 1) - memmove(out + rv_packed_size, out + 1, rv); - return uint32_pack(rv, out) + rv; - } -} - -/** - * Pack a field tag. - * - * Wire-type will be added in required_field_pack(). - * - * \todo Just call uint64_pack on 64-bit platforms. - * - * \param id - * Tag value to encode. - * \param[out] out - * Packed value. - * \return - * Number of bytes written to `out`. - */ -static size_t -tag_pack(uint32_t id, uint8_t *out) -{ - if (id < (1 << (32 - 3))) - return uint32_pack(id << 3, out); - else - return uint64_pack(((uint64_t) id) << 3, out); -} - -/** - * Pack a required field and return the number of bytes written. - * - * \param field - * Field descriptor. - * \param member - * The field member. - * \param[out] out - * Packed value. - * \return - * Number of bytes written to `out`. - */ -static size_t -required_field_pack(const ProtobufCFieldDescriptor *field, - const void *member, uint8_t *out) -{ - size_t rv = tag_pack(field->id, out); - - switch (field->type) { - case PROTOBUF_C_TYPE_SINT32: - out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - return rv + sint32_pack(*(const int32_t *) member, out + rv); - case PROTOBUF_C_TYPE_INT32: - out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - return rv + int32_pack(*(const uint32_t *) member, out + rv); - case PROTOBUF_C_TYPE_UINT32: - case PROTOBUF_C_TYPE_ENUM: - out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - return rv + uint32_pack(*(const uint32_t *) member, out + rv); - case PROTOBUF_C_TYPE_SINT64: - out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - return rv + sint64_pack(*(const int64_t *) member, out + rv); - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_UINT64: - out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - return rv + uint64_pack(*(const uint64_t *) member, out + rv); - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: - out[0] |= PROTOBUF_C_WIRE_TYPE_32BIT; - return rv + fixed32_pack(*(const uint32_t *) member, out + rv); - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: - out[0] |= PROTOBUF_C_WIRE_TYPE_64BIT; - return rv + fixed64_pack(*(const uint64_t *) member, out + rv); - case PROTOBUF_C_TYPE_BOOL: - out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - return rv + boolean_pack(*(const protobuf_c_boolean *) member, out + rv); - case PROTOBUF_C_TYPE_STRING: - out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; - return rv + string_pack(*(char *const *) member, out + rv); - case PROTOBUF_C_TYPE_BYTES: - out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; - return rv + binary_data_pack((const ProtobufCBinaryData *) member, out + rv); - case PROTOBUF_C_TYPE_MESSAGE: - out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; - return rv + prefixed_message_pack(*(ProtobufCMessage * const *) member, out + rv); - } - PROTOBUF_C__ASSERT_NOT_REACHED(); - return 0; -} - -/** - * Pack an optional field and return the number of bytes written. - * - * \param field - * Field descriptor. - * \param has - * Whether the field is set. - * \param member - * The field member. - * \param[out] out - * Packed value. - * \return - * Number of bytes written to `out`. - */ -static size_t -optional_field_pack(const ProtobufCFieldDescriptor *field, - const protobuf_c_boolean *has, - const void *member, uint8_t *out) -{ - if (field->type == PROTOBUF_C_TYPE_MESSAGE || - field->type == PROTOBUF_C_TYPE_STRING) - { - const void *ptr = *(const void * const *) member; - if (ptr == NULL || ptr == field->default_value) - return 0; - } else { - if (!*has) - return 0; - } - return required_field_pack(field, member, out); -} - -/** - * Given a field type, return the in-memory size. - * - * \todo Implement as a table lookup. - * - * \param type - * Field type. - * \return - * Size of the field. - */ -static inline size_t -sizeof_elt_in_repeated_array(ProtobufCType type) -{ - switch (type) { - case PROTOBUF_C_TYPE_SINT32: - case PROTOBUF_C_TYPE_INT32: - case PROTOBUF_C_TYPE_UINT32: - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: - case PROTOBUF_C_TYPE_ENUM: - return 4; - case PROTOBUF_C_TYPE_SINT64: - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_UINT64: - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: - return 8; - case PROTOBUF_C_TYPE_BOOL: - return sizeof(protobuf_c_boolean); - case PROTOBUF_C_TYPE_STRING: - case PROTOBUF_C_TYPE_MESSAGE: - return sizeof(void *); - case PROTOBUF_C_TYPE_BYTES: - return sizeof(ProtobufCBinaryData); - } - PROTOBUF_C__ASSERT_NOT_REACHED(); - return 0; -} - -/** - * Pack an array of 32-bit quantities. - * - * \param[out] out - * Destination. - * \param[in] in - * Source. - * \param[in] n - * Number of elements in the source array. - */ -static void -copy_to_little_endian_32(void *out, const void *in, const unsigned n) -{ -#if !defined(WORDS_BIGENDIAN) - memcpy(out, in, n * 4); -#else - unsigned i; - const uint32_t *ini = in; - for (i = 0; i < n; i++) - fixed32_pack(ini[i], (uint32_t *) out + i); -#endif -} - -/** - * Pack an array of 64-bit quantities. - * - * \param[out] out - * Destination. - * \param[in] in - * Source. - * \param[in] n - * Number of elements in the source array. - */ -static void -copy_to_little_endian_64(void *out, const void *in, const unsigned n) -{ -#if !defined(WORDS_BIGENDIAN) - memcpy(out, in, n * 8); -#else - unsigned i; - const uint64_t *ini = in; - for (i = 0; i < n; i++) - fixed64_pack(ini[i], (uint64_t *) out + i); -#endif -} - -/** - * Get the minimum number of bytes required to pack a field value of a - * particular type. - * - * \param type - * Field type. - * \return - * Number of bytes. - */ -static unsigned -get_type_min_size(ProtobufCType type) -{ - if (type == PROTOBUF_C_TYPE_SFIXED32 || - type == PROTOBUF_C_TYPE_FIXED32 || - type == PROTOBUF_C_TYPE_FLOAT) - { - return 4; - } - if (type == PROTOBUF_C_TYPE_SFIXED64 || - type == PROTOBUF_C_TYPE_FIXED64 || - type == PROTOBUF_C_TYPE_DOUBLE) - { - return 8; - } - return 1; -} - -/** - * Packs the elements of a repeated field and returns the serialised field and - * its length. - * - * \param field - * Field descriptor. - * \param count - * Number of elements in the repeated field array. - * \param member - * Pointer to the elements for this repeated field. - * \param[out] out - * Serialised representation of the repeated field. - * \return - * Number of bytes serialised to `out`. - */ -static size_t -repeated_field_pack(const ProtobufCFieldDescriptor *field, - size_t count, const void *member, uint8_t *out) -{ - void *array = *(void * const *) member; - unsigned i; - - if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) { - unsigned header_len; - unsigned len_start; - unsigned min_length; - unsigned payload_len; - unsigned length_size_min; - unsigned actual_length_size; - uint8_t *payload_at; - - if (count == 0) - return 0; - header_len = tag_pack(field->id, out); - out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; - len_start = header_len; - min_length = get_type_min_size(field->type) * count; - length_size_min = uint32_size(min_length); - header_len += length_size_min; - payload_at = out + header_len; - - switch (field->type) { - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: - copy_to_little_endian_32(payload_at, array, count); - payload_at += count * 4; - break; - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: - copy_to_little_endian_64(payload_at, array, count); - payload_at += count * 8; - break; - case PROTOBUF_C_TYPE_INT32: { - const int32_t *arr = (const int32_t *) array; - for (i = 0; i < count; i++) - payload_at += int32_pack(arr[i], payload_at); - break; - } - case PROTOBUF_C_TYPE_SINT32: { - const int32_t *arr = (const int32_t *) array; - for (i = 0; i < count; i++) - payload_at += sint32_pack(arr[i], payload_at); - break; - } - case PROTOBUF_C_TYPE_SINT64: { - const int64_t *arr = (const int64_t *) array; - for (i = 0; i < count; i++) - payload_at += sint64_pack(arr[i], payload_at); - break; - } - case PROTOBUF_C_TYPE_ENUM: - case PROTOBUF_C_TYPE_UINT32: { - const uint32_t *arr = (const uint32_t *) array; - for (i = 0; i < count; i++) - payload_at += uint32_pack(arr[i], payload_at); - break; - } - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_UINT64: { - const uint64_t *arr = (const uint64_t *) array; - for (i = 0; i < count; i++) - payload_at += uint64_pack(arr[i], payload_at); - break; - } - case PROTOBUF_C_TYPE_BOOL: { - const protobuf_c_boolean *arr = (const protobuf_c_boolean *) array; - for (i = 0; i < count; i++) - payload_at += boolean_pack(arr[i], payload_at); - break; - } - default: - PROTOBUF_C__ASSERT_NOT_REACHED(); - } - - payload_len = payload_at - (out + header_len); - actual_length_size = uint32_size(payload_len); - if (length_size_min != actual_length_size) { - assert(actual_length_size == length_size_min + 1); - memmove(out + header_len + 1, out + header_len, - payload_len); - header_len++; - } - uint32_pack(payload_len, out + len_start); - return header_len + payload_len; - } else { - /* not "packed" cased */ - /* CONSIDER: optimize this case a bit (by putting the loop inside the switch) */ - size_t rv = 0; - unsigned siz = sizeof_elt_in_repeated_array(field->type); - - for (i = 0; i < count; i++) { - rv += required_field_pack(field, array, out + rv); - array = (char *)array + siz; - } - return rv; - } -} - -static size_t -unknown_field_pack(const ProtobufCMessageUnknownField *field, uint8_t *out) -{ - size_t rv = tag_pack(field->tag, out); - out[0] |= field->wire_type; - memcpy(out + rv, field->data, field->len); - return rv + field->len; -} - -/**@}*/ - -size_t -protobuf_c_message_pack(const ProtobufCMessage *message, uint8_t *out) -{ - unsigned i; - size_t rv = 0; - - ASSERT_IS_MESSAGE(message); - for (i = 0; i < message->descriptor->n_fields; i++) { - const ProtobufCFieldDescriptor *field = - message->descriptor->fields + i; - const void *member = ((const char *) message) + field->offset; - - /* - * It doesn't hurt to compute qmember (a pointer to the - * quantifier field of the structure), but the pointer is only - * valid if the field is: - * - a repeated field, or - * - an optional field that isn't a pointer type - * (Meaning: not a message or a string). - */ - const void *qmember = - ((const char *) message) + field->quantifier_offset; - - if (field->label == PROTOBUF_C_LABEL_REQUIRED) { - rv += required_field_pack(field, member, out + rv); - } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) { - /* - * Note that qmember is bogus for strings and messages, - * but it isn't used. - */ - rv += optional_field_pack(field, qmember, member, out + rv); - } else { - rv += repeated_field_pack(field, *(const size_t *) qmember, - member, out + rv); - } - } - for (i = 0; i < message->n_unknown_fields; i++) - rv += unknown_field_pack(&message->unknown_fields[i], out + rv); - return rv; -} - -/** - * \defgroup packbuf protobuf_c_message_pack_to_buffer() implementation - * - * Routines mainly used by protobuf_c_message_pack_to_buffer(). - * - * \ingroup internal - * @{ - */ - -/** - * Pack a required field to a virtual buffer. - * - * \param field - * Field descriptor. - * \param member - * The element to be packed. - * \param[out] buffer - * Virtual buffer to append data to. - * \return - * Number of bytes packed. - */ -static size_t -required_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, - const void *member, ProtobufCBuffer *buffer) -{ - size_t rv; - uint8_t scratch[MAX_UINT64_ENCODED_SIZE * 2]; - - rv = tag_pack(field->id, scratch); - switch (field->type) { - case PROTOBUF_C_TYPE_SINT32: - scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - rv += sint32_pack(*(const int32_t *) member, scratch + rv); - buffer->append(buffer, rv, scratch); - break; - case PROTOBUF_C_TYPE_INT32: - scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - rv += int32_pack(*(const uint32_t *) member, scratch + rv); - buffer->append(buffer, rv, scratch); - break; - case PROTOBUF_C_TYPE_UINT32: - case PROTOBUF_C_TYPE_ENUM: - scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - rv += uint32_pack(*(const uint32_t *) member, scratch + rv); - buffer->append(buffer, rv, scratch); - break; - case PROTOBUF_C_TYPE_SINT64: - scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - rv += sint64_pack(*(const int64_t *) member, scratch + rv); - buffer->append(buffer, rv, scratch); - break; - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_UINT64: - scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - rv += uint64_pack(*(const uint64_t *) member, scratch + rv); - buffer->append(buffer, rv, scratch); - break; - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: - scratch[0] |= PROTOBUF_C_WIRE_TYPE_32BIT; - rv += fixed32_pack(*(const uint32_t *) member, scratch + rv); - buffer->append(buffer, rv, scratch); - break; - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: - scratch[0] |= PROTOBUF_C_WIRE_TYPE_64BIT; - rv += fixed64_pack(*(const uint64_t *) member, scratch + rv); - buffer->append(buffer, rv, scratch); - break; - case PROTOBUF_C_TYPE_BOOL: - scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - rv += boolean_pack(*(const protobuf_c_boolean *) member, scratch + rv); - buffer->append(buffer, rv, scratch); - break; - case PROTOBUF_C_TYPE_STRING: { - const char *str = *(char *const *) member; - size_t sublen = str ? strlen(str) : 0; - - scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; - rv += uint32_pack(sublen, scratch + rv); - buffer->append(buffer, rv, scratch); - buffer->append(buffer, sublen, (const uint8_t *) str); - rv += sublen; - break; - } - case PROTOBUF_C_TYPE_BYTES: { - const ProtobufCBinaryData *bd = ((const ProtobufCBinaryData *) member); - size_t sublen = bd->len; - - scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; - rv += uint32_pack(sublen, scratch + rv); - buffer->append(buffer, rv, scratch); - buffer->append(buffer, sublen, bd->data); - rv += sublen; - break; - } - case PROTOBUF_C_TYPE_MESSAGE: { - uint8_t simple_buffer_scratch[256]; - size_t sublen; - const ProtobufCMessage *msg = *(ProtobufCMessage * const *) member; - ProtobufCBufferSimple simple_buffer = - PROTOBUF_C_BUFFER_SIMPLE_INIT(simple_buffer_scratch); - - scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; - if (msg == NULL) - sublen = 0; - else - sublen = protobuf_c_message_pack_to_buffer(msg, &simple_buffer.base); - rv += uint32_pack(sublen, scratch + rv); - buffer->append(buffer, rv, scratch); - buffer->append(buffer, sublen, simple_buffer.data); - rv += sublen; - PROTOBUF_C_BUFFER_SIMPLE_CLEAR(&simple_buffer); - break; - } - default: - PROTOBUF_C__ASSERT_NOT_REACHED(); - } - return rv; -} - -/** - * Pack an optional field to a buffer. - * - * \param field - * Field descriptor. - * \param has - * Whether the field is set. - * \param member - * The element to be packed. - * \param[out] buffer - * Virtual buffer to append data to. - * \return - * Number of bytes serialised to `buffer`. - */ -static size_t -optional_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, - const protobuf_c_boolean *has, - const void *member, ProtobufCBuffer *buffer) -{ - if (field->type == PROTOBUF_C_TYPE_MESSAGE || - field->type == PROTOBUF_C_TYPE_STRING) - { - const void *ptr = *(const void *const *) member; - if (ptr == NULL || ptr == field->default_value) - return 0; - } else { - if (!*has) - return 0; - } - return required_field_pack_to_buffer(field, member, buffer); -} - -/** - * Get the packed size of an array of same field type. - * - * \param field - * Field descriptor. - * \param count - * Number of elements of this type. - * \param array - * The elements to get the size of. - * \return - * Number of bytes required. - */ -static size_t -get_packed_payload_length(const ProtobufCFieldDescriptor *field, - unsigned count, const void *array) -{ - unsigned rv = 0; - unsigned i; - - switch (field->type) { - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: - return count * 4; - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: - return count * 8; - case PROTOBUF_C_TYPE_INT32: { - const int32_t *arr = (const int32_t *) array; - for (i = 0; i < count; i++) - rv += int32_size(arr[i]); - break; - } - case PROTOBUF_C_TYPE_SINT32: { - const int32_t *arr = (const int32_t *) array; - for (i = 0; i < count; i++) - rv += sint32_size(arr[i]); - break; - } - case PROTOBUF_C_TYPE_ENUM: - case PROTOBUF_C_TYPE_UINT32: { - const uint32_t *arr = (const uint32_t *) array; - for (i = 0; i < count; i++) - rv += uint32_size(arr[i]); - break; - } - case PROTOBUF_C_TYPE_SINT64: { - const int64_t *arr = (const int64_t *) array; - for (i = 0; i < count; i++) - rv += sint64_size(arr[i]); - break; - } - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_UINT64: { - const uint64_t *arr = (const uint64_t *) array; - for (i = 0; i < count; i++) - rv += uint64_size(arr[i]); - break; - } - case PROTOBUF_C_TYPE_BOOL: - return count; - default: - PROTOBUF_C__ASSERT_NOT_REACHED(); - } - return rv; -} - -/** - * Pack an array of same field type to a virtual buffer. - * - * \param field - * Field descriptor. - * \param count - * Number of elements of this type. - * \param array - * The elements to get the size of. - * \param[out] buffer - * Virtual buffer to append data to. - * \return - * Number of bytes packed. - */ -static size_t -pack_buffer_packed_payload(const ProtobufCFieldDescriptor *field, - unsigned count, const void *array, - ProtobufCBuffer *buffer) -{ - uint8_t scratch[16]; - size_t rv = 0; - unsigned i; - - switch (field->type) { - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: -#if !defined(WORDS_BIGENDIAN) - rv = count * 4; - goto no_packing_needed; -#else - for (i = 0; i < count; i++) { - unsigned len = fixed32_pack(((uint32_t *) array)[i], scratch); - buffer->append(buffer, len, scratch); - rv += len; - } - break; -#endif - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: -#if !defined(WORDS_BIGENDIAN) - rv = count * 8; - goto no_packing_needed; -#else - for (i = 0; i < count; i++) { - unsigned len = fixed64_pack(((uint64_t *) array)[i], scratch); - buffer->append(buffer, len, scratch); - rv += len; - } - break; -#endif - case PROTOBUF_C_TYPE_INT32: - for (i = 0; i < count; i++) { - unsigned len = int32_pack(((int32_t *) array)[i], scratch); - buffer->append(buffer, len, scratch); - rv += len; - } - break; - case PROTOBUF_C_TYPE_SINT32: - for (i = 0; i < count; i++) { - unsigned len = sint32_pack(((int32_t *) array)[i], scratch); - buffer->append(buffer, len, scratch); - rv += len; - } - break; - case PROTOBUF_C_TYPE_ENUM: - case PROTOBUF_C_TYPE_UINT32: - for (i = 0; i < count; i++) { - unsigned len = uint32_pack(((uint32_t *) array)[i], scratch); - buffer->append(buffer, len, scratch); - rv += len; - } - break; - case PROTOBUF_C_TYPE_SINT64: - for (i = 0; i < count; i++) { - unsigned len = sint64_pack(((int64_t *) array)[i], scratch); - buffer->append(buffer, len, scratch); - rv += len; - } - break; - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_UINT64: - for (i = 0; i < count; i++) { - unsigned len = uint64_pack(((uint64_t *) array)[i], scratch); - buffer->append(buffer, len, scratch); - rv += len; - } - break; - case PROTOBUF_C_TYPE_BOOL: - for (i = 0; i < count; i++) { - unsigned len = boolean_pack(((protobuf_c_boolean *) array)[i], scratch); - buffer->append(buffer, len, scratch); - rv += len; - } - return count; - default: - PROTOBUF_C__ASSERT_NOT_REACHED(); - } - return rv; - -#if !defined(WORDS_BIGENDIAN) -no_packing_needed: - buffer->append(buffer, rv, array); - return rv; -#endif -} - -static size_t -repeated_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, - unsigned count, const void *member, - ProtobufCBuffer *buffer) -{ - char *array = *(char * const *) member; - - if (count == 0) - return 0; - if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) { - uint8_t scratch[MAX_UINT64_ENCODED_SIZE * 2]; - size_t rv = tag_pack(field->id, scratch); - size_t payload_len = get_packed_payload_length(field, count, array); - size_t tmp; - - scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; - rv += uint32_pack(payload_len, scratch + rv); - buffer->append(buffer, rv, scratch); - tmp = pack_buffer_packed_payload(field, count, array, buffer); - assert(tmp == payload_len); - return rv + payload_len; - } else { - size_t siz; - unsigned i; - /* CONSIDER: optimize this case a bit (by putting the loop inside the switch) */ - unsigned rv = 0; - - siz = sizeof_elt_in_repeated_array(field->type); - for (i = 0; i < count; i++) { - rv += required_field_pack_to_buffer(field, array, buffer); - array = ((char*)array) + siz; - } - return rv; - } -} - -static size_t -unknown_field_pack_to_buffer(const ProtobufCMessageUnknownField *field, - ProtobufCBuffer *buffer) -{ - uint8_t header[MAX_UINT64_ENCODED_SIZE]; - size_t rv = tag_pack(field->tag, header); - - header[0] |= field->wire_type; - buffer->append(buffer, rv, header); - buffer->append(buffer, field->len, field->data); - return rv + field->len; -} - -/**@}*/ - -size_t -protobuf_c_message_pack_to_buffer(const ProtobufCMessage *message, - ProtobufCBuffer *buffer) -{ - unsigned i; - size_t rv = 0; - - ASSERT_IS_MESSAGE(message); - for (i = 0; i < message->descriptor->n_fields; i++) { - const ProtobufCFieldDescriptor *field = - message->descriptor->fields + i; - const void *member = - ((const char *) message) + field->offset; - const void *qmember = - ((const char *) message) + field->quantifier_offset; - - if (field->label == PROTOBUF_C_LABEL_REQUIRED) { - rv += required_field_pack_to_buffer(field, member, buffer); - } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) { - rv += optional_field_pack_to_buffer( - field, - qmember, - member, - buffer - ); - } else { - rv += repeated_field_pack_to_buffer( - field, - *(const size_t *) qmember, - member, - buffer - ); - } - } - for (i = 0; i < message->n_unknown_fields; i++) - rv += unknown_field_pack_to_buffer(&message->unknown_fields[i], buffer); - - return rv; -} - -/** - * \defgroup unpack unpacking implementation - * - * Routines mainly used by the unpacking functions. - * - * \ingroup internal - * @{ - */ - -static inline int -int_range_lookup(unsigned n_ranges, const ProtobufCIntRange *ranges, int value) -{ - unsigned n; - unsigned start; - - if (n_ranges == 0) - return -1; - start = 0; - n = n_ranges; - while (n > 1) { - unsigned mid = start + n / 2; - - if (value < ranges[mid].start_value) { - n = mid - start; - } else if (value >= ranges[mid].start_value + - (int) (ranges[mid + 1].orig_index - - ranges[mid].orig_index)) - { - unsigned new_start = mid + 1; - n = start + n - new_start; - start = new_start; - } else - return (value - ranges[mid].start_value) + - ranges[mid].orig_index; - } - if (n > 0) { - unsigned start_orig_index = ranges[start].orig_index; - unsigned range_size = - ranges[start + 1].orig_index - start_orig_index; - - if (ranges[start].start_value <= value && - value < (int) (ranges[start].start_value + range_size)) - { - return (value - ranges[start].start_value) + - start_orig_index; - } - } - return -1; -} - -static size_t -parse_tag_and_wiretype(size_t len, - const uint8_t *data, - uint32_t *tag_out, - ProtobufCWireType *wiretype_out) -{ - unsigned max_rv = len > 5 ? 5 : len; - uint32_t tag = (data[0] & 0x7f) >> 3; - unsigned shift = 4; - unsigned rv; - - *wiretype_out = data[0] & 7; - if ((data[0] & 0x80) == 0) { - *tag_out = tag; - return 1; - } - for (rv = 1; rv < max_rv; rv++) { - if (data[rv] & 0x80) { - tag |= (data[rv] & 0x7f) << shift; - shift += 7; - } else { - tag |= data[rv] << shift; - *tag_out = tag; - return rv + 1; - } - } - return 0; /* error: bad header */ -} - -/* sizeof(ScannedMember) must be <= (1<<BOUND_SIZEOF_SCANNED_MEMBER_LOG2) */ -#define BOUND_SIZEOF_SCANNED_MEMBER_LOG2 5 -typedef struct _ScannedMember ScannedMember; -/** Field as it's being read. */ -struct _ScannedMember { - uint32_t tag; /**< Field tag. */ - uint8_t wire_type; /**< Field type. */ - uint8_t length_prefix_len; /**< Prefix length. */ - const ProtobufCFieldDescriptor *field; /**< Field descriptor. */ - size_t len; /**< Field length. */ - const uint8_t *data; /**< Pointer to field data. */ -}; - -static inline uint32_t -scan_length_prefixed_data(size_t len, const uint8_t *data, - size_t *prefix_len_out) -{ - unsigned hdr_max = len < 5 ? len : 5; - unsigned hdr_len; - uint32_t val = 0; - unsigned i; - unsigned shift = 0; - - for (i = 0; i < hdr_max; i++) { - val |= (data[i] & 0x7f) << shift; - shift += 7; - if ((data[i] & 0x80) == 0) - break; - } - if (i == hdr_max) { - PROTOBUF_C_UNPACK_ERROR("error parsing length for length-prefixed data"); - return 0; - } - hdr_len = i + 1; - *prefix_len_out = hdr_len; - if (hdr_len + val > len) { - PROTOBUF_C_UNPACK_ERROR("data too short after length-prefix of %u", val); - return 0; - } - return hdr_len + val; -} - -static size_t -max_b128_numbers(size_t len, const uint8_t *data) -{ - size_t rv = 0; - while (len--) - if ((*data++ & 0x80) == 0) - ++rv; - return rv; -} - -/**@}*/ - -/** - * Merge earlier message into a latter message. - * - * For numeric types and strings, if the same value appears multiple - * times, the parser accepts the last value it sees. For embedded - * message fields, the parser merges multiple instances of the same - * field. That is, all singular scalar fields in the latter instance - * replace those in the former, singular embedded messages are merged, - * and repeated fields are concatenated. - * - * The earlier message should be freed after calling this function, as - * some of its fields may have been reused and changed to their default - * values during the merge. - */ -static protobuf_c_boolean -merge_messages(ProtobufCMessage *earlier_msg, - ProtobufCMessage *latter_msg, - ProtobufCAllocator *allocator) -{ - unsigned i; - const ProtobufCFieldDescriptor *fields = - earlier_msg->descriptor->fields; - for (i = 0; i < latter_msg->descriptor->n_fields; i++) { - if (fields[i].label == PROTOBUF_C_LABEL_REPEATED) { - size_t *n_earlier = - STRUCT_MEMBER_PTR(size_t, earlier_msg, - fields[i].quantifier_offset); - uint8_t **p_earlier = - STRUCT_MEMBER_PTR(uint8_t *, earlier_msg, - fields[i].offset); - size_t *n_latter = - STRUCT_MEMBER_PTR(size_t, latter_msg, - fields[i].quantifier_offset); - uint8_t **p_latter = - STRUCT_MEMBER_PTR(uint8_t *, latter_msg, - fields[i].offset); - - if (*n_earlier > 0) { - if (*n_latter > 0) { - /* Concatenate the repeated field */ - size_t el_size = - sizeof_elt_in_repeated_array(fields[i].type); - uint8_t *new_field; - - new_field = do_alloc(allocator, - (*n_earlier + *n_latter) * el_size); - if (!new_field) - return FALSE; - - memcpy(new_field, *p_earlier, - *n_earlier * el_size); - memcpy(new_field + - *n_earlier * el_size, - *p_latter, - *n_latter * el_size); - - do_free(allocator, *p_latter); - do_free(allocator, *p_earlier); - *p_latter = new_field; - *n_latter = *n_earlier + *n_latter; - } else { - /* Zero copy the repeated field from the earlier message */ - *n_latter = *n_earlier; - *p_latter = *p_earlier; - } - /* Make sure the field does not get double freed */ - *n_earlier = 0; - *p_earlier = 0; - } - } else if (fields[i].type == PROTOBUF_C_TYPE_MESSAGE) { - ProtobufCMessage **em = - STRUCT_MEMBER_PTR(ProtobufCMessage *, - earlier_msg, - fields[i].offset); - ProtobufCMessage **lm = - STRUCT_MEMBER_PTR(ProtobufCMessage *, - latter_msg, - fields[i].offset); - if (*em != NULL) { - if (*lm != NULL) { - if (!merge_messages - (*em, *lm, allocator)) - return FALSE; - } else { - /* Zero copy the optional message */ - assert(fields[i].label == - PROTOBUF_C_LABEL_OPTIONAL); - *lm = *em; - *em = NULL; - } - } - } else if (fields[i].label == PROTOBUF_C_LABEL_OPTIONAL) { - size_t el_size = 0; - protobuf_c_boolean need_to_merge = FALSE; - void *earlier_elem = - STRUCT_MEMBER_P(earlier_msg, fields[i].offset); - void *latter_elem = - STRUCT_MEMBER_P(latter_msg, fields[i].offset); - const void *def_val = fields[i].default_value; - - switch (fields[i].type) { - case PROTOBUF_C_TYPE_BYTES: { - uint8_t *e_data = - ((ProtobufCBinaryData *) earlier_elem)->data; - uint8_t *l_data = - ((ProtobufCBinaryData *) latter_elem)->data; - const ProtobufCBinaryData *d_bd = - (ProtobufCBinaryData *) def_val; - - el_size = sizeof(ProtobufCBinaryData); - need_to_merge = - (e_data != NULL && - (d_bd != NULL && - e_data != d_bd->data)) && - (l_data == NULL || - (d_bd != NULL && - l_data == d_bd->data)); - break; - } - case PROTOBUF_C_TYPE_STRING: { - char *e_str = *(char **) earlier_elem; - char *l_str = *(char **) latter_elem; - const char *d_str = def_val; - - el_size = sizeof(char *); - need_to_merge = e_str != d_str && l_str == d_str; - break; - } - default: { - el_size = sizeof_elt_in_repeated_array(fields[i].type); - - need_to_merge = - STRUCT_MEMBER(protobuf_c_boolean, - earlier_msg, - fields[i].quantifier_offset) && - !STRUCT_MEMBER(protobuf_c_boolean, - latter_msg, - fields[i].quantifier_offset); - break; - } - } - - if (need_to_merge) { - memcpy(latter_elem, earlier_elem, el_size); - /* - * Reset the element from the old message to 0 - * to make sure earlier message deallocation - * doesn't corrupt zero-copied data in the new - * message, earlier message will be freed after - * this function is called anyway - */ - memset(earlier_elem, 0, el_size); - - if (fields[i].quantifier_offset != 0) { - /* Set the has field, if applicable */ - STRUCT_MEMBER(protobuf_c_boolean, - latter_msg, - fields[i]. - quantifier_offset) = TRUE; - STRUCT_MEMBER(protobuf_c_boolean, - earlier_msg, - fields[i]. - quantifier_offset) = FALSE; - } - } - } - } - return TRUE; -} - -/** - * Count packed elements. - * - * Given a raw slab of packed-repeated values, determine the number of - * elements. This function detects certain kinds of errors but not - * others; the remaining error checking is done by - * parse_packed_repeated_member(). - */ -static protobuf_c_boolean -count_packed_elements(ProtobufCType type, - size_t len, const uint8_t *data, size_t *count_out) -{ - switch (type) { - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: - if (len % 4 != 0) { - PROTOBUF_C_UNPACK_ERROR("length must be a multiple of 4 for fixed-length 32-bit types"); - return FALSE; - } - *count_out = len / 4; - return TRUE; - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: - if (len % 8 != 0) { - PROTOBUF_C_UNPACK_ERROR("length must be a multiple of 8 for fixed-length 64-bit types"); - return FALSE; - } - *count_out = len / 8; - return TRUE; - case PROTOBUF_C_TYPE_INT32: - case PROTOBUF_C_TYPE_SINT32: - case PROTOBUF_C_TYPE_ENUM: - case PROTOBUF_C_TYPE_UINT32: - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_SINT64: - case PROTOBUF_C_TYPE_UINT64: - *count_out = max_b128_numbers(len, data); - return TRUE; - case PROTOBUF_C_TYPE_BOOL: - *count_out = len; - return TRUE; - case PROTOBUF_C_TYPE_STRING: - case PROTOBUF_C_TYPE_BYTES: - case PROTOBUF_C_TYPE_MESSAGE: - default: - PROTOBUF_C_UNPACK_ERROR("bad protobuf-c type %u for packed-repeated", type); - return FALSE; - } -} - -static inline uint32_t -parse_uint32(unsigned len, const uint8_t *data) -{ - uint32_t rv = data[0] & 0x7f; - if (len > 1) { - rv |= ((uint32_t) (data[1] & 0x7f) << 7); - if (len > 2) { - rv |= ((uint32_t) (data[2] & 0x7f) << 14); - if (len > 3) { - rv |= ((uint32_t) (data[3] & 0x7f) << 21); - if (len > 4) - rv |= ((uint32_t) (data[4]) << 28); - } - } - } - return rv; -} - -static inline uint32_t -parse_int32(unsigned len, const uint8_t *data) -{ - return parse_uint32(len, data); -} - -static inline int32_t -unzigzag32(uint32_t v) -{ - if (v & 1) - return -(v >> 1) - 1; - else - return v >> 1; -} - -static inline uint32_t -parse_fixed_uint32(const uint8_t *data) -{ -#if !defined(WORDS_BIGENDIAN) - uint32_t t; - memcpy(&t, data, 4); - return t; -#else - return data[0] | - ((uint32_t) (data[1]) << 8) | - ((uint32_t) (data[2]) << 16) | - ((uint32_t) (data[3]) << 24); -#endif -} - -static uint64_t -parse_uint64(unsigned len, const uint8_t *data) -{ - unsigned shift, i; - uint64_t rv; - - if (len < 5) - return parse_uint32(len, data); - rv = ((uint64_t) (data[0] & 0x7f)) | - ((uint64_t) (data[1] & 0x7f) << 7) | - ((uint64_t) (data[2] & 0x7f) << 14) | - ((uint64_t) (data[3] & 0x7f) << 21); - shift = 28; - for (i = 4; i < len; i++) { - rv |= (((uint64_t) (data[i] & 0x7f)) << shift); - shift += 7; - } - return rv; -} - -static inline int64_t -unzigzag64(uint64_t v) -{ - if (v & 1) - return -(v >> 1) - 1; - else - return v >> 1; -} - -static inline uint64_t -parse_fixed_uint64(const uint8_t *data) -{ -#if !defined(WORDS_BIGENDIAN) - uint64_t t; - memcpy(&t, data, 8); - return t; -#else - return (uint64_t) parse_fixed_uint32(data) | - (((uint64_t) parse_fixed_uint32(data + 4)) << 32); -#endif -} - -static protobuf_c_boolean -parse_boolean(unsigned len, const uint8_t *data) -{ - unsigned i; - for (i = 0; i < len; i++) - if (data[i] & 0x7f) - return TRUE; - return FALSE; -} - -static protobuf_c_boolean -parse_required_member(ScannedMember *scanned_member, - void *member, - ProtobufCAllocator *allocator, - protobuf_c_boolean maybe_clear) -{ - unsigned len = scanned_member->len; - const uint8_t *data = scanned_member->data; - ProtobufCWireType wire_type = scanned_member->wire_type; - - switch (scanned_member->field->type) { - case PROTOBUF_C_TYPE_INT32: - if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) - return FALSE; - *(uint32_t *) member = parse_int32(len, data); - return TRUE; - case PROTOBUF_C_TYPE_UINT32: - if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) - return FALSE; - *(uint32_t *) member = parse_uint32(len, data); - return TRUE; - case PROTOBUF_C_TYPE_SINT32: - if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) - return FALSE; - *(int32_t *) member = unzigzag32(parse_uint32(len, data)); - return TRUE; - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: - if (wire_type != PROTOBUF_C_WIRE_TYPE_32BIT) - return FALSE; - *(uint32_t *) member = parse_fixed_uint32(data); - return TRUE; - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_UINT64: - if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) - return FALSE; - *(uint64_t *) member = parse_uint64(len, data); - return TRUE; - case PROTOBUF_C_TYPE_SINT64: - if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) - return FALSE; - *(int64_t *) member = unzigzag64(parse_uint64(len, data)); - return TRUE; - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: - if (wire_type != PROTOBUF_C_WIRE_TYPE_64BIT) - return FALSE; - *(uint64_t *) member = parse_fixed_uint64(data); - return TRUE; - case PROTOBUF_C_TYPE_BOOL: - *(protobuf_c_boolean *) member = parse_boolean(len, data); - return TRUE; - case PROTOBUF_C_TYPE_ENUM: - if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) - return FALSE; - *(uint32_t *) member = parse_uint32(len, data); - return TRUE; - case PROTOBUF_C_TYPE_STRING: { - char **pstr = member; - unsigned pref_len = scanned_member->length_prefix_len; - - if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) - return FALSE; - - if (maybe_clear && *pstr != NULL) { - const char *def = scanned_member->field->default_value; - if (*pstr != NULL && *pstr != def) - do_free(allocator, *pstr); - } - *pstr = do_alloc(allocator, len - pref_len + 1); - if (*pstr == NULL) - return FALSE; - memcpy(*pstr, data + pref_len, len - pref_len); - (*pstr)[len - pref_len] = 0; - return TRUE; - } - case PROTOBUF_C_TYPE_BYTES: { - ProtobufCBinaryData *bd = member; - const ProtobufCBinaryData *def_bd; - unsigned pref_len = scanned_member->length_prefix_len; - - if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) - return FALSE; - - def_bd = scanned_member->field->default_value; - if (maybe_clear && - bd->data != NULL && - (def_bd == NULL || bd->data != def_bd->data)) - { - do_free(allocator, bd->data); - } - if (len - pref_len > 0) { - bd->data = do_alloc(allocator, len - pref_len); - if (bd->data == NULL) - return FALSE; - memcpy(bd->data, data + pref_len, len - pref_len); - } else { - bd->data = NULL; - } - bd->len = len - pref_len; - return TRUE; - } - case PROTOBUF_C_TYPE_MESSAGE: { - ProtobufCMessage **pmessage = member; - ProtobufCMessage *subm; - const ProtobufCMessage *def_mess; - protobuf_c_boolean merge_successful = TRUE; - unsigned pref_len = scanned_member->length_prefix_len; - - if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) - return FALSE; - - def_mess = scanned_member->field->default_value; - subm = protobuf_c_message_unpack(scanned_member->field->descriptor, - allocator, - len - pref_len, - data + pref_len); - - if (maybe_clear && - *pmessage != NULL && - *pmessage != def_mess) - { - if (subm != NULL) - merge_successful = merge_messages(*pmessage, subm, allocator); - /* Delete the previous message */ - protobuf_c_message_free_unpacked(*pmessage, allocator); - } - *pmessage = subm; - if (subm == NULL || !merge_successful) - return FALSE; - return TRUE; - } - } - return FALSE; -} - -static protobuf_c_boolean -parse_optional_member(ScannedMember *scanned_member, - void *member, - ProtobufCMessage *message, - ProtobufCAllocator *allocator) -{ - if (!parse_required_member(scanned_member, member, allocator, TRUE)) - return FALSE; - if (scanned_member->field->quantifier_offset != 0) - STRUCT_MEMBER(protobuf_c_boolean, - message, - scanned_member->field->quantifier_offset) = TRUE; - return TRUE; -} - -static protobuf_c_boolean -parse_repeated_member(ScannedMember *scanned_member, - void *member, - ProtobufCMessage *message, - ProtobufCAllocator *allocator) -{ - const ProtobufCFieldDescriptor *field = scanned_member->field; - size_t *p_n = STRUCT_MEMBER_PTR(size_t, message, field->quantifier_offset); - size_t siz = sizeof_elt_in_repeated_array(field->type); - char *array = *(char **) member; - - if (!parse_required_member(scanned_member, array + siz * (*p_n), - allocator, FALSE)) - { - return FALSE; - } - *p_n += 1; - return TRUE; -} - -static unsigned -scan_varint(unsigned len, const uint8_t *data) -{ - unsigned i; - if (len > 10) - len = 10; - for (i = 0; i < len; i++) - if ((data[i] & 0x80) == 0) - break; - if (i == len) - return 0; - return i + 1; -} - -static protobuf_c_boolean -parse_packed_repeated_member(ScannedMember *scanned_member, - void *member, - ProtobufCMessage *message) -{ - const ProtobufCFieldDescriptor *field = scanned_member->field; - size_t *p_n = STRUCT_MEMBER_PTR(size_t, message, field->quantifier_offset); - size_t siz = sizeof_elt_in_repeated_array(field->type); - void *array = *(char **) member + siz * (*p_n); - const uint8_t *at = scanned_member->data + scanned_member->length_prefix_len; - size_t rem = scanned_member->len - scanned_member->length_prefix_len; - size_t count = 0; - unsigned i; - - switch (field->type) { - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: - count = (scanned_member->len - scanned_member->length_prefix_len) / 4; -#if !defined(WORDS_BIGENDIAN) - goto no_unpacking_needed; -#else - for (i = 0; i < count; i++) { - ((uint32_t *) array)[i] = parse_fixed_uint32(at); - at += 4; - } - break; -#endif - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: - count = (scanned_member->len - scanned_member->length_prefix_len) / 8; -#if !defined(WORDS_BIGENDIAN) - goto no_unpacking_needed; -#else - for (i = 0; i < count; i++) { - ((uint64_t *) array)[i] = parse_fixed_uint64(at); - at += 8; - } - break; -#endif - case PROTOBUF_C_TYPE_INT32: - while (rem > 0) { - unsigned s = scan_varint(rem, at); - if (s == 0) { - PROTOBUF_C_UNPACK_ERROR("bad packed-repeated int32 value"); - return FALSE; - } - ((int32_t *) array)[count++] = parse_int32(s, at); - at += s; - rem -= s; - } - break; - case PROTOBUF_C_TYPE_SINT32: - while (rem > 0) { - unsigned s = scan_varint(rem, at); - if (s == 0) { - PROTOBUF_C_UNPACK_ERROR("bad packed-repeated sint32 value"); - return FALSE; - } - ((int32_t *) array)[count++] = unzigzag32(parse_uint32(s, at)); - at += s; - rem -= s; - } - break; - case PROTOBUF_C_TYPE_ENUM: - case PROTOBUF_C_TYPE_UINT32: - while (rem > 0) { - unsigned s = scan_varint(rem, at); - if (s == 0) { - PROTOBUF_C_UNPACK_ERROR("bad packed-repeated enum or uint32 value"); - return FALSE; - } - ((uint32_t *) array)[count++] = parse_uint32(s, at); - at += s; - rem -= s; - } - break; - - case PROTOBUF_C_TYPE_SINT64: - while (rem > 0) { - unsigned s = scan_varint(rem, at); - if (s == 0) { - PROTOBUF_C_UNPACK_ERROR("bad packed-repeated sint64 value"); - return FALSE; - } - ((int64_t *) array)[count++] = unzigzag64(parse_uint64(s, at)); - at += s; - rem -= s; - } - break; - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_UINT64: - while (rem > 0) { - unsigned s = scan_varint(rem, at); - if (s == 0) { - PROTOBUF_C_UNPACK_ERROR("bad packed-repeated int64/uint64 value"); - return FALSE; - } - ((int64_t *) array)[count++] = parse_uint64(s, at); - at += s; - rem -= s; - } - break; - case PROTOBUF_C_TYPE_BOOL: - count = rem; - for (i = 0; i < count; i++) { - if (at[i] > 1) { - PROTOBUF_C_UNPACK_ERROR("bad packed-repeated boolean value"); - return FALSE; - } - ((protobuf_c_boolean *) array)[i] = at[i]; - } - break; - default: - PROTOBUF_C__ASSERT_NOT_REACHED(); - } - *p_n += count; - return TRUE; - -#if !defined(WORDS_BIGENDIAN) -no_unpacking_needed: - memcpy(array, at, count * siz); - *p_n += count; - return TRUE; -#endif -} - -static protobuf_c_boolean -is_packable_type(ProtobufCType type) -{ - return - type != PROTOBUF_C_TYPE_STRING && - type != PROTOBUF_C_TYPE_BYTES && - type != PROTOBUF_C_TYPE_MESSAGE; -} - -static protobuf_c_boolean -parse_member(ScannedMember *scanned_member, - ProtobufCMessage *message, - ProtobufCAllocator *allocator) -{ - const ProtobufCFieldDescriptor *field = scanned_member->field; - void *member; - - if (field == NULL) { - ProtobufCMessageUnknownField *ufield = - message->unknown_fields + - (message->n_unknown_fields++); - ufield->tag = scanned_member->tag; - ufield->wire_type = scanned_member->wire_type; - ufield->len = scanned_member->len; - ufield->data = do_alloc(allocator, scanned_member->len); - if (ufield->data == NULL) - return FALSE; - memcpy(ufield->data, scanned_member->data, ufield->len); - return TRUE; - } - member = (char *) message + field->offset; - switch (field->label) { - case PROTOBUF_C_LABEL_REQUIRED: - return parse_required_member(scanned_member, member, - allocator, TRUE); - case PROTOBUF_C_LABEL_OPTIONAL: - return parse_optional_member(scanned_member, member, - message, allocator); - case PROTOBUF_C_LABEL_REPEATED: - if (scanned_member->wire_type == - PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED && - (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED) || - is_packable_type(field->type))) - { - return parse_packed_repeated_member(scanned_member, - member, message); - } else { - return parse_repeated_member(scanned_member, - member, message, - allocator); - } - } - PROTOBUF_C__ASSERT_NOT_REACHED(); - return 0; -} - -/** - * Initialise messages generated by old code. - * - * This function is used if desc->message_init == NULL (which occurs - * for old code, and which would be useful to support allocating - * descriptors dynamically). - */ -static void -message_init_generic(const ProtobufCMessageDescriptor *desc, - ProtobufCMessage *message) -{ - unsigned i; - - memset(message, 0, desc->sizeof_message); - message->descriptor = desc; - for (i = 0; i < desc->n_fields; i++) { - if (desc->fields[i].default_value != NULL && - desc->fields[i].label != PROTOBUF_C_LABEL_REPEATED) - { - void *field = - STRUCT_MEMBER_P(message, desc->fields[i].offset); - const void *dv = desc->fields[i].default_value; - - switch (desc->fields[i].type) { - case PROTOBUF_C_TYPE_INT32: - case PROTOBUF_C_TYPE_SINT32: - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_UINT32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: - case PROTOBUF_C_TYPE_ENUM: - memcpy(field, dv, 4); - break; - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_SINT64: - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_UINT64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: - memcpy(field, dv, 8); - break; - case PROTOBUF_C_TYPE_BOOL: - memcpy(field, dv, sizeof(protobuf_c_boolean)); - break; - case PROTOBUF_C_TYPE_BYTES: - memcpy(field, dv, sizeof(ProtobufCBinaryData)); - break; - - case PROTOBUF_C_TYPE_STRING: - case PROTOBUF_C_TYPE_MESSAGE: - /* - * The next line essentially implements a cast - * from const, which is totally unavoidable. - */ - *(const void **) field = dv; - break; - } - } - } -} - -/**@}*/ - -/* - * ScannedMember slabs (an unpacking implementation detail). Before doing real - * unpacking, we first scan through the elements to see how many there are (for - * repeated fields), and which field to use (for non-repeated fields given - * twice). - * - * In order to avoid allocations for small messages, we keep a stack-allocated - * slab of ScannedMembers of size FIRST_SCANNED_MEMBER_SLAB_SIZE (16). After we - * fill that up, we allocate each slab twice as large as the previous one. - */ -#define FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2 4 - -/* - * The number of slabs, including the stack-allocated ones; choose the number so - * that we would overflow if we needed a slab larger than provided. - */ -#define MAX_SCANNED_MEMBER_SLAB \ - (sizeof(unsigned int)*8 - 1 \ - - BOUND_SIZEOF_SCANNED_MEMBER_LOG2 \ - - FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2) - -#define REQUIRED_FIELD_BITMAP_SET(index) \ - (required_fields_bitmap[(index)/8] |= (1<<((index)%8))) - -#define REQUIRED_FIELD_BITMAP_IS_SET(index) \ - (required_fields_bitmap[(index)/8] & (1<<((index)%8))) - -ProtobufCMessage * -protobuf_c_message_unpack(const ProtobufCMessageDescriptor *desc, - ProtobufCAllocator *allocator, - size_t len, const uint8_t *data) -{ - ProtobufCMessage *rv; - size_t rem = len; - const uint8_t *at = data; - const ProtobufCFieldDescriptor *last_field = desc->fields + 0; - ScannedMember first_member_slab[1 << - FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2]; - - /* - * scanned_member_slabs[i] is an array of arrays of ScannedMember. - * The first slab (scanned_member_slabs[0] is just a pointer to - * first_member_slab), above. All subsequent slabs will be allocated - * using the allocator. - */ - ScannedMember *scanned_member_slabs[MAX_SCANNED_MEMBER_SLAB + 1]; - unsigned which_slab = 0; /* the slab we are currently populating */ - unsigned in_slab_index = 0; /* number of members in the slab */ - size_t n_unknown = 0; - unsigned f; - unsigned j; - unsigned i_slab; - unsigned last_field_index = 0; - unsigned required_fields_bitmap_len; - unsigned char required_fields_bitmap_stack[16]; - unsigned char *required_fields_bitmap = required_fields_bitmap_stack; - protobuf_c_boolean required_fields_bitmap_alloced = FALSE; - - ASSERT_IS_MESSAGE_DESCRIPTOR(desc); - - if (allocator == NULL) - allocator = &protobuf_c__allocator; - - rv = do_alloc(allocator, desc->sizeof_message); - if (!rv) - return (NULL); - scanned_member_slabs[0] = first_member_slab; - - required_fields_bitmap_len = (desc->n_fields + 7) / 8; - if (required_fields_bitmap_len > sizeof(required_fields_bitmap_stack)) { - required_fields_bitmap = do_alloc(allocator, required_fields_bitmap_len); - if (!required_fields_bitmap) { - do_free(allocator, rv); - return (NULL); - } - required_fields_bitmap_alloced = TRUE; - } - memset(required_fields_bitmap, 0, required_fields_bitmap_len); - - /* - * Generated code always defines "message_init". However, we provide a - * fallback for (1) users of old protobuf-c generated-code that do not - * provide the function, and (2) descriptors constructed from some other - * source (most likely, direct construction from the .proto file). - */ - if (desc->message_init != NULL) - protobuf_c_message_init(desc, rv); - else - message_init_generic(desc, rv); - - while (rem > 0) { - uint32_t tag; - ProtobufCWireType wire_type; - size_t used = parse_tag_and_wiretype(rem, at, &tag, &wire_type); - const ProtobufCFieldDescriptor *field; - ScannedMember tmp; - - memset(&tmp, 0, sizeof(ScannedMember)); - - if (used == 0) { - PROTOBUF_C_UNPACK_ERROR("error parsing tag/wiretype at offset %u", - (unsigned) (at - data)); - goto error_cleanup_during_scan; - } - /* - * \todo Consider optimizing for field[1].id == tag, if field[1] - * exists! - */ - if (last_field == NULL || last_field->id != tag) { - /* lookup field */ - int field_index = - int_range_lookup(desc->n_field_ranges, - desc->field_ranges, - tag); - if (field_index < 0) { - field = NULL; - n_unknown++; - } else { - field = desc->fields + field_index; - last_field = field; - last_field_index = field_index; - } - } else { - field = last_field; - } - - if (field != NULL && field->label == PROTOBUF_C_LABEL_REQUIRED) - REQUIRED_FIELD_BITMAP_SET(last_field_index); - - at += used; - rem -= used; - tmp.tag = tag; - tmp.wire_type = wire_type; - tmp.field = field; - tmp.data = at; - tmp.length_prefix_len = 0; - - switch (wire_type) { - case PROTOBUF_C_WIRE_TYPE_VARINT: { - unsigned max_len = rem < 10 ? rem : 10; - unsigned i; - - for (i = 0; i < max_len; i++) - if ((at[i] & 0x80) == 0) - break; - if (i == max_len) { - PROTOBUF_C_UNPACK_ERROR("unterminated varint at offset %u", - (unsigned) (at - data)); - goto error_cleanup_during_scan; - } - tmp.len = i + 1; - break; - } - case PROTOBUF_C_WIRE_TYPE_64BIT: - if (rem < 8) { - PROTOBUF_C_UNPACK_ERROR("too short after 64bit wiretype at offset %u", - (unsigned) (at - data)); - goto error_cleanup_during_scan; - } - tmp.len = 8; - break; - case PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED: { - size_t pref_len; - - tmp.len = scan_length_prefixed_data(rem, at, &pref_len); - if (tmp.len == 0) { - /* NOTE: scan_length_prefixed_data calls UNPACK_ERROR */ - goto error_cleanup_during_scan; - } - tmp.length_prefix_len = pref_len; - break; - } - case PROTOBUF_C_WIRE_TYPE_32BIT: - if (rem < 4) { - PROTOBUF_C_UNPACK_ERROR("too short after 32bit wiretype at offset %u", - (unsigned) (at - data)); - goto error_cleanup_during_scan; - } - tmp.len = 4; - break; - default: - PROTOBUF_C_UNPACK_ERROR("unsupported tag %u at offset %u", - wire_type, (unsigned) (at - data)); - goto error_cleanup_during_scan; - } - - if (in_slab_index == (1U << - (which_slab + FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2))) - { - size_t size; - - in_slab_index = 0; - if (which_slab == MAX_SCANNED_MEMBER_SLAB) { - PROTOBUF_C_UNPACK_ERROR("too many fields"); - goto error_cleanup_during_scan; - } - which_slab++; - size = sizeof(ScannedMember) - << (which_slab + FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2); - scanned_member_slabs[which_slab] = do_alloc(allocator, size); - if (scanned_member_slabs[which_slab] == NULL) - goto error_cleanup_during_scan; - } - scanned_member_slabs[which_slab][in_slab_index++] = tmp; - - if (field != NULL && field->label == PROTOBUF_C_LABEL_REPEATED) { - size_t *n = STRUCT_MEMBER_PTR(size_t, rv, - field->quantifier_offset); - if (wire_type == PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED && - (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED) || - is_packable_type(field->type))) - { - size_t count; - if (!count_packed_elements(field->type, - tmp.len - - tmp.length_prefix_len, - tmp.data + - tmp.length_prefix_len, - &count)) - { - PROTOBUF_C_UNPACK_ERROR("counting packed elements"); - goto error_cleanup_during_scan; - } - *n += count; - } else { - *n += 1; - } - } - - at += tmp.len; - rem -= tmp.len; - } - - /* allocate space for repeated fields, also check that all required fields have been set */ - for (f = 0; f < desc->n_fields; f++) { - const ProtobufCFieldDescriptor *field = desc->fields + f; - if (field->label == PROTOBUF_C_LABEL_REPEATED) { - size_t siz = - sizeof_elt_in_repeated_array(field->type); - size_t *n_ptr = - STRUCT_MEMBER_PTR(size_t, rv, - field->quantifier_offset); - if (*n_ptr != 0) { - unsigned n = *n_ptr; - void *a; - *n_ptr = 0; - assert(rv->descriptor != NULL); -#define CLEAR_REMAINING_N_PTRS() \ - for(f++;f < desc->n_fields; f++) \ - { \ - field = desc->fields + f; \ - if (field->label == PROTOBUF_C_LABEL_REPEATED) \ - STRUCT_MEMBER (size_t, rv, field->quantifier_offset) = 0; \ - } - a = do_alloc(allocator, siz * n); - if (!a) { - CLEAR_REMAINING_N_PTRS(); - goto error_cleanup; - } - STRUCT_MEMBER(void *, rv, field->offset) = a; - } - } else if (field->label == PROTOBUF_C_LABEL_REQUIRED) { - if (field->default_value == NULL && - !REQUIRED_FIELD_BITMAP_IS_SET(f)) - { - CLEAR_REMAINING_N_PTRS(); - PROTOBUF_C_UNPACK_ERROR("message '%s': missing required field '%s'", - desc->name, field->name); - goto error_cleanup; - } - } - } -#undef CLEAR_REMAINING_N_PTRS - - /* allocate space for unknown fields */ - if (n_unknown) { - rv->unknown_fields = do_alloc(allocator, - n_unknown * sizeof(ProtobufCMessageUnknownField)); - if (rv->unknown_fields == NULL) - goto error_cleanup; - } - - /* do real parsing */ - for (i_slab = 0; i_slab <= which_slab; i_slab++) { - unsigned max = (i_slab == which_slab) ? - in_slab_index : (1U << (i_slab + 4)); - ScannedMember *slab = scanned_member_slabs[i_slab]; - unsigned j; - - for (j = 0; j < max; j++) { - if (!parse_member(slab + j, rv, allocator)) { - PROTOBUF_C_UNPACK_ERROR("error parsing member %s of %s", - slab->field ? slab->field->name : "*unknown-field*", - desc->name); - goto error_cleanup; - } - } - } - - /* cleanup */ - for (j = 1; j <= which_slab; j++) - do_free(allocator, scanned_member_slabs[j]); - if (required_fields_bitmap_alloced) - do_free(allocator, required_fields_bitmap); - return rv; - -error_cleanup: - protobuf_c_message_free_unpacked(rv, allocator); - for (j = 1; j <= which_slab; j++) - do_free(allocator, scanned_member_slabs[j]); - if (required_fields_bitmap_alloced) - do_free(allocator, required_fields_bitmap); - return NULL; - -error_cleanup_during_scan: - do_free(allocator, rv); - for (j = 1; j <= which_slab; j++) - do_free(allocator, scanned_member_slabs[j]); - if (required_fields_bitmap_alloced) - do_free(allocator, required_fields_bitmap); - return NULL; -} - -void -protobuf_c_message_free_unpacked(ProtobufCMessage *message, - ProtobufCAllocator *allocator) -{ - const ProtobufCMessageDescriptor *desc = message->descriptor; - unsigned f; - - ASSERT_IS_MESSAGE(message); - if (allocator == NULL) - allocator = &protobuf_c__allocator; - message->descriptor = NULL; - for (f = 0; f < desc->n_fields; f++) { - if (desc->fields[f].label == PROTOBUF_C_LABEL_REPEATED) { - size_t n = STRUCT_MEMBER(size_t, - message, - desc->fields[f].quantifier_offset); - void *arr = STRUCT_MEMBER(void *, - message, - desc->fields[f].offset); - - if (desc->fields[f].type == PROTOBUF_C_TYPE_STRING) { - unsigned i; - for (i = 0; i < n; i++) - do_free(allocator, ((char **) arr)[i]); - } else if (desc->fields[f].type == PROTOBUF_C_TYPE_BYTES) { - unsigned i; - for (i = 0; i < n; i++) - do_free(allocator, ((ProtobufCBinaryData *) arr)[i].data); - } else if (desc->fields[f].type == PROTOBUF_C_TYPE_MESSAGE) { - unsigned i; - for (i = 0; i < n; i++) - protobuf_c_message_free_unpacked( - ((ProtobufCMessage **) arr)[i], - allocator - ); - } - if (arr != NULL) - do_free(allocator, arr); - } else if (desc->fields[f].type == PROTOBUF_C_TYPE_STRING) { - char *str = STRUCT_MEMBER(char *, message, - desc->fields[f].offset); - - if (str && str != desc->fields[f].default_value) - do_free(allocator, str); - } else if (desc->fields[f].type == PROTOBUF_C_TYPE_BYTES) { - void *data = STRUCT_MEMBER(ProtobufCBinaryData, message, - desc->fields[f].offset).data; - const ProtobufCBinaryData *default_bd; - - default_bd = desc->fields[f].default_value; - if (data != NULL && - (default_bd == NULL || - default_bd->data != data)) - { - do_free(allocator, data); - } - } else if (desc->fields[f].type == PROTOBUF_C_TYPE_MESSAGE) { - ProtobufCMessage *sm; - - sm = STRUCT_MEMBER(ProtobufCMessage *, message, - desc->fields[f].offset); - if (sm && sm != desc->fields[f].default_value) - protobuf_c_message_free_unpacked(sm, allocator); - } - } - - for (f = 0; f < message->n_unknown_fields; f++) - do_free(allocator, message->unknown_fields[f].data); - if (message->unknown_fields != NULL) - do_free(allocator, message->unknown_fields); - - do_free(allocator, message); -} - -void -protobuf_c_message_init(const ProtobufCMessageDescriptor * descriptor, - void *message) -{ - descriptor->message_init((ProtobufCMessage *) (message)); -} - -protobuf_c_boolean -protobuf_c_message_check(const ProtobufCMessage *message) -{ - unsigned i; - - if (!message || - !message->descriptor || - message->descriptor->magic != PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) - { - return FALSE; - } - - for (i = 0; i < message->descriptor->n_fields; i++) { - const ProtobufCFieldDescriptor *f = message->descriptor->fields + i; - ProtobufCType type = f->type; - ProtobufCLabel label = f->label; - void *field = STRUCT_MEMBER_P (message, f->offset); - - if (label == PROTOBUF_C_LABEL_REPEATED) { - size_t *quantity = STRUCT_MEMBER_P (message, f->quantifier_offset); - - if (*quantity > 0 && *(void **) field == NULL) { - return FALSE; - } - - if (type == PROTOBUF_C_TYPE_MESSAGE) { - ProtobufCMessage **submessage = *(ProtobufCMessage ***) field; - unsigned j; - for (j = 0; j < *quantity; j++) { - if (!protobuf_c_message_check(submessage[j])) - return FALSE; - } - } else if (type == PROTOBUF_C_TYPE_STRING) { - char **string = *(char ***) field; - unsigned j; - for (j = 0; j < *quantity; j++) { - if (!string[j]) - return FALSE; - } - } else if (type == PROTOBUF_C_TYPE_BYTES) { - ProtobufCBinaryData *bd = *(ProtobufCBinaryData **) field; - unsigned j; - for (j = 0; j < *quantity; j++) { - if (bd[j].len > 0 && bd[j].data == NULL) - return FALSE; - } - } - - } else { /* PROTOBUF_C_LABEL_REQUIRED or PROTOBUF_C_LABEL_OPTIONAL */ - - if (type == PROTOBUF_C_TYPE_MESSAGE) { - ProtobufCMessage *submessage = *(ProtobufCMessage **) field; - if (label == PROTOBUF_C_LABEL_REQUIRED || submessage != NULL) { - if (!protobuf_c_message_check(submessage)) - return FALSE; - } - } else if (type == PROTOBUF_C_TYPE_STRING) { - char *string = *(char **) field; - if (label == PROTOBUF_C_LABEL_REQUIRED && string == NULL) - return FALSE; - } else if (type == PROTOBUF_C_TYPE_BYTES) { - protobuf_c_boolean *has = STRUCT_MEMBER_P (message, f->quantifier_offset); - ProtobufCBinaryData *bd = field; - if (label == PROTOBUF_C_LABEL_REQUIRED || *has == TRUE) { - if (bd->len > 0 && bd->data == NULL) - return FALSE; - } - } - } - } - - return TRUE; -} - -/* === services === */ - -typedef void (*GenericHandler) (void *service, - const ProtobufCMessage *input, - ProtobufCClosure closure, - void *closure_data); -void -protobuf_c_service_invoke_internal(ProtobufCService *service, - unsigned method_index, - const ProtobufCMessage *input, - ProtobufCClosure closure, - void *closure_data) -{ - GenericHandler *handlers; - GenericHandler handler; - - /* - * Verify that method_index is within range. If this fails, you are - * likely invoking a newly added method on an old service. (Although - * other memory corruption bugs can cause this assertion too.) - */ - assert(method_index < service->descriptor->n_methods); - - /* - * Get the array of virtual methods (which are enumerated by the - * generated code). - */ - handlers = (GenericHandler *) (service + 1); - - /* - * Get our method and invoke it. - * \todo Seems like handler == NULL is a situation that needs handling. - */ - handler = handlers[method_index]; - (*handler)(service, input, closure, closure_data); -} - -void -protobuf_c_service_generated_init(ProtobufCService *service, - const ProtobufCServiceDescriptor *descriptor, - ProtobufCServiceDestroy destroy) -{ - ASSERT_IS_SERVICE_DESCRIPTOR(descriptor); - service->descriptor = descriptor; - service->destroy = destroy; - service->invoke = protobuf_c_service_invoke_internal; - memset(service + 1, 0, descriptor->n_methods * sizeof(GenericHandler)); -} - -void protobuf_c_service_destroy(ProtobufCService *service) -{ - service->destroy(service); -} - -/* --- querying the descriptors --- */ - -const ProtobufCEnumValue * -protobuf_c_enum_descriptor_get_value_by_name(const ProtobufCEnumDescriptor *desc, - const char *name) -{ - unsigned start = 0; - unsigned count = desc->n_value_names; - - while (count > 1) { - unsigned mid = start + count / 2; - int rv = strcmp(desc->values_by_name[mid].name, name); - if (rv == 0) - return desc->values + desc->values_by_name[mid].index; - else if (rv < 0) { - count = start + count - (mid + 1); - start = mid + 1; - } else - count = mid - start; - } - if (count == 0) - return NULL; - if (strcmp(desc->values_by_name[start].name, name) == 0) - return desc->values + desc->values_by_name[start].index; - return NULL; -} - -const ProtobufCEnumValue * -protobuf_c_enum_descriptor_get_value(const ProtobufCEnumDescriptor *desc, - int value) -{ - int rv = int_range_lookup(desc->n_value_ranges, desc->value_ranges, value); - if (rv < 0) - return NULL; - return desc->values + rv; -} - -const ProtobufCFieldDescriptor * -protobuf_c_message_descriptor_get_field_by_name(const ProtobufCMessageDescriptor *desc, - const char *name) -{ - unsigned start = 0; - unsigned count = desc->n_fields; - const ProtobufCFieldDescriptor *field; - - while (count > 1) { - unsigned mid = start + count / 2; - int rv; - field = desc->fields + desc->fields_sorted_by_name[mid]; - rv = strcmp(field->name, name); - if (rv == 0) - return field; - else if (rv < 0) { - count = start + count - (mid + 1); - start = mid + 1; - } else - count = mid - start; - } - if (count == 0) - return NULL; - field = desc->fields + desc->fields_sorted_by_name[start]; - if (strcmp(field->name, name) == 0) - return field; - return NULL; -} - -const ProtobufCFieldDescriptor * -protobuf_c_message_descriptor_get_field(const ProtobufCMessageDescriptor *desc, - unsigned value) -{ - int rv = int_range_lookup(desc->n_field_ranges,desc->field_ranges, value); - if (rv < 0) - return NULL; - return desc->fields + rv; -} - -const ProtobufCMethodDescriptor * -protobuf_c_service_descriptor_get_method_by_name(const ProtobufCServiceDescriptor *desc, - const char *name) -{ - unsigned start = 0; - unsigned count = desc->n_methods; - - while (count > 1) { - unsigned mid = start + count / 2; - unsigned mid_index = desc->method_indices_by_name[mid]; - const char *mid_name = desc->methods[mid_index].name; - int rv = strcmp(mid_name, name); - - if (rv == 0) - return desc->methods + desc->method_indices_by_name[mid]; - if (rv < 0) { - count = start + count - (mid + 1); - start = mid + 1; - } else { - count = mid - start; - } - } - if (count == 0) - return NULL; - if (strcmp(desc->methods[desc->method_indices_by_name[start]].name, name) == 0) - return desc->methods + desc->method_indices_by_name[start]; - return NULL; -}
--- a/libpurple/protocols/gg/lib/protobuf-c.h Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1078 +0,0 @@ -/* - * Copyright (c) 2008-2014, Dave Benson and the protobuf-c authors. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/*! \file - * \mainpage Introduction - * - * This is [protobuf-c], a C implementation of [Protocol Buffers]. - * - * This file defines the public API for the `libprotobuf-c` support library. - * This API includes interfaces that can be used directly by client code as well - * as the interfaces used by the code generated by the `protoc-c` compiler. - * - * The `libprotobuf-c` support library performs the actual serialization and - * deserialization of Protocol Buffers messages. It interacts with structures, - * definitions, and metadata generated by the `protoc-c` compiler from .proto - * files. - * - * \authors Dave Benson and the `protobuf-c` authors. - * - * \copyright 2008-2014. Licensed under the terms of the [BSD-2-Clause] license. - * - * [protobuf-c]: https://github.com/protobuf-c/protobuf-c - * [Protocol Buffers]: https://developers.google.com/protocol-buffers/ - * [BSD-2-Clause]: http://opensource.org/licenses/BSD-2-Clause - * - * \page gencode Generated Code - * - * For each enum, we generate a C enum. For each message, we generate a C - * structure which can be cast to a `ProtobufCMessage`. - * - * For each enum and message, we generate a descriptor object that allows us to - * implement a kind of reflection on the structures. - * - * First, some naming conventions: - * - * - The name of the type for enums and messages and services is camel case - * (meaning WordsAreCrammedTogether) except that double underscores are used - * to delimit scopes. For example, the following `.proto` file: - * -~~~{.proto} - package foo.bar; - message BazBah { - optional int32 val = 1; - } -~~~ - * - * would generate a C type `Foo__Bar__BazBah`. - * - * - Identifiers for functions and globals are all lowercase, with camel case - * words separated by single underscores. For example, one of the function - * prototypes generated by `protoc-c` for the above example: - * -~~~{.c} -Foo__Bar__BazBah * - foo__bar__baz_bah__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -~~~ - * - * - Identifiers for enum values contain an uppercase prefix which embeds the - * package name and the enum type name. - * - * - A double underscore is used to separate further components of identifier - * names. - * - * For example, in the name of the unpack function above, the package name - * `foo.bar` has become `foo__bar`, the message name BazBah has become - * `baz_bah`, and the method name is `unpack`. These are all joined with double - * underscores to form the C identifier `foo__bar__baz_bah__unpack`. - * - * We also generate descriptor objects for messages and enums. These are - * declared in the `.pb-c.h` files: - * -~~~{.c} -extern const ProtobufCMessageDescriptor foo__bar__baz_bah__descriptor; -~~~ - * - * The message structures all begin with `ProtobufCMessageDescriptor *` which is - * sufficient to allow them to be cast to `ProtobufCMessage`. - * - * For each message defined in a `.proto` file, we generate a number of - * functions. Each function name contains a prefix based on the package name and - * message name in order to make it a unique C identifier. - * - * - `unpack()`. Unpacks data for a particular message format. Note that the - * `allocator` parameter is usually `NULL` to indicate that the system's - * `malloc()` and `free()` functions should be used for dynamically allocating - * memory. - * -~~~{.c} -Foo__Bar__BazBah * - foo__bar__baz_bah__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -~~~ - * - * - `free_unpacked()`. Frees a message object obtained with the `unpack()` - * method. - * -~~~{.c} -void foo__bar__baz_bah__free_unpacked - (Foo__Bar__BazBah *message, - ProtobufCAllocator *allocator); -~~~ - * - * - `get_packed_size()`. Calculates the length in bytes of the serialized - * representation of the message object. - * -~~~{.c} -size_t foo__bar__baz_bah__get_packed_size - (const Foo__Bar__BazBah *message); -~~~ - * - * - `pack()`. Pack a message object into a preallocated buffer. Assumes that - * the buffer is large enough. (Use `get_packed_size()` first.) - * -~~~{.c} -size_t foo__bar__baz_bah__pack - (const Foo__Bar__BazBah *message, - uint8_t *out); -~~~ - * - * - `pack_to_buffer()`. Packs a message into a "virtual buffer". This is an - * object which defines an "append bytes" callback to consume data as it is - * serialized. - * -~~~{.c} -size_t foo__bar__baz_bah__pack_to_buffer - (const Foo__Bar__BazBah *message, - ProtobufCBuffer *buffer); -~~~ - * - * \page pack Packing and unpacking messages - * - * To pack a message, first compute the packed size of the message with - * protobuf_c_message_get_packed_size(), then allocate a buffer of at least - * that size, then call protobuf_c_message_pack(). - * - * Alternatively, a message can be serialized without calculating the final size - * first. Use the protobuf_c_message_pack_to_buffer() function and provide a - * ProtobufCBuffer object which implements an "append" method that consumes - * data. - * - * To unpack a message, call the protobuf_c_message_unpack() function. The - * result can be cast to an object of the type that matches the descriptor for - * the message. - * - * The result of unpacking a message should be freed with - * protobuf_c_message_free_unpacked(). - */ - -#ifndef PROTOBUF_C_H -#define PROTOBUF_C_H - -#include <assert.h> -#include <limits.h> -#include <stddef.h> -#include <stdint.h> - -#ifdef __cplusplus -# define PROTOBUF_C__BEGIN_DECLS extern "C" { -# define PROTOBUF_C__END_DECLS } -#else -# define PROTOBUF_C__BEGIN_DECLS -# define PROTOBUF_C__END_DECLS -#endif - -PROTOBUF_C__BEGIN_DECLS - -#if defined(_WIN32) && defined(PROTOBUF_C_USE_SHARED_LIB) -# ifdef PROTOBUF_C_EXPORT -# define PROTOBUF_C__API __declspec(dllexport) -# else -# define PROTOBUF_C__API __declspec(dllimport) -# endif -#else -# define PROTOBUF_C__API -#endif - -#if !defined(PROTOBUF_C__NO_DEPRECATED) && \ - ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) -# define PROTOBUF_C__DEPRECATED __attribute__((__deprecated__)) -#else -# define PROTOBUF_C__DEPRECATED -#endif - -#ifndef PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE - #define PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(enum_name) \ - , _##enum_name##_IS_INT_SIZE = INT_MAX -#endif - -#define PROTOBUF_C__SERVICE_DESCRIPTOR_MAGIC 0x14159bc3 -#define PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC 0x28aaeef9 -#define PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC 0x114315af - -/** - * \defgroup api Public API - * - * This is the public API for `libprotobuf-c`. These interfaces are stable and - * subject to Semantic Versioning guarantees. - * - * @{ - */ - -/** - * Values for the `flags` word in `ProtobufCFieldDescriptor`. - */ -typedef enum { - /** Set if the field is repeated and marked with the `packed` option. */ - PROTOBUF_C_FIELD_FLAG_PACKED = (1 << 0), - - /** Set if the field is marked with the `deprecated` option. */ - PROTOBUF_C_FIELD_FLAG_DEPRECATED = (1 << 1), -} ProtobufCFieldFlag; - -/** - * Message field rules. - * - * \see [Defining A Message Type] in the Protocol Buffers documentation. - * - * [Defining A Message Type]: - * https://developers.google.com/protocol-buffers/docs/proto#simple - */ -typedef enum { - /** A well-formed message must have exactly one of this field. */ - PROTOBUF_C_LABEL_REQUIRED, - - /** - * A well-formed message can have zero or one of this field (but not - * more than one). - */ - PROTOBUF_C_LABEL_OPTIONAL, - - /** - * This field can be repeated any number of times (including zero) in a - * well-formed message. The order of the repeated values will be - * preserved. - */ - PROTOBUF_C_LABEL_REPEATED, -} ProtobufCLabel; - -/** - * Field value types. - * - * \see [Scalar Value Types] in the Protocol Buffers documentation. - * - * [Scalar Value Types]: - * https://developers.google.com/protocol-buffers/docs/proto#scalar - */ -typedef enum { - PROTOBUF_C_TYPE_INT32, /**< int32 */ - PROTOBUF_C_TYPE_SINT32, /**< signed int32 */ - PROTOBUF_C_TYPE_SFIXED32, /**< signed int32 (4 bytes) */ - PROTOBUF_C_TYPE_INT64, /**< int64 */ - PROTOBUF_C_TYPE_SINT64, /**< signed int64 */ - PROTOBUF_C_TYPE_SFIXED64, /**< signed int64 (8 bytes) */ - PROTOBUF_C_TYPE_UINT32, /**< unsigned int32 */ - PROTOBUF_C_TYPE_FIXED32, /**< unsigned int32 (4 bytes) */ - PROTOBUF_C_TYPE_UINT64, /**< unsigned int64 */ - PROTOBUF_C_TYPE_FIXED64, /**< unsigned int64 (8 bytes) */ - PROTOBUF_C_TYPE_FLOAT, /**< float */ - PROTOBUF_C_TYPE_DOUBLE, /**< double */ - PROTOBUF_C_TYPE_BOOL, /**< boolean */ - PROTOBUF_C_TYPE_ENUM, /**< enumerated type */ - PROTOBUF_C_TYPE_STRING, /**< UTF-8 or ASCII string */ - PROTOBUF_C_TYPE_BYTES, /**< arbitrary byte sequence */ - PROTOBUF_C_TYPE_MESSAGE, /**< nested message */ -} ProtobufCType; - -/** - * Field wire types. - * - * \see [Message Structure] in the Protocol Buffers documentation. - * - * [Message Structure]: - * https://developers.google.com/protocol-buffers/docs/encoding#structure - */ -typedef enum { - PROTOBUF_C_WIRE_TYPE_VARINT = 0, - PROTOBUF_C_WIRE_TYPE_64BIT = 1, - PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED = 2, - /* "Start group" and "end group" wire types are unsupported. */ - PROTOBUF_C_WIRE_TYPE_32BIT = 5, -} ProtobufCWireType; - -struct ProtobufCAllocator; -struct ProtobufCBinaryData; -struct ProtobufCBuffer; -struct ProtobufCBufferSimple; -struct ProtobufCEnumDescriptor; -struct ProtobufCEnumValue; -struct ProtobufCEnumValueIndex; -struct ProtobufCFieldDescriptor; -struct ProtobufCIntRange; -struct ProtobufCMessage; -struct ProtobufCMessageDescriptor; -struct ProtobufCMessageUnknownField; -struct ProtobufCMethodDescriptor; -struct ProtobufCService; -struct ProtobufCServiceDescriptor; - -typedef struct ProtobufCAllocator ProtobufCAllocator; -typedef struct ProtobufCBinaryData ProtobufCBinaryData; -typedef struct ProtobufCBuffer ProtobufCBuffer; -typedef struct ProtobufCBufferSimple ProtobufCBufferSimple; -typedef struct ProtobufCEnumDescriptor ProtobufCEnumDescriptor; -typedef struct ProtobufCEnumValue ProtobufCEnumValue; -typedef struct ProtobufCEnumValueIndex ProtobufCEnumValueIndex; -typedef struct ProtobufCFieldDescriptor ProtobufCFieldDescriptor; -typedef struct ProtobufCIntRange ProtobufCIntRange; -typedef struct ProtobufCMessage ProtobufCMessage; -typedef struct ProtobufCMessageDescriptor ProtobufCMessageDescriptor; -typedef struct ProtobufCMessageUnknownField ProtobufCMessageUnknownField; -typedef struct ProtobufCMethodDescriptor ProtobufCMethodDescriptor; -typedef struct ProtobufCService ProtobufCService; -typedef struct ProtobufCServiceDescriptor ProtobufCServiceDescriptor; - -/** Boolean type. */ -typedef int protobuf_c_boolean; - -typedef void (*ProtobufCClosure)(const ProtobufCMessage *, void *closure_data); -typedef void (*ProtobufCMessageInit)(ProtobufCMessage *); -typedef void (*ProtobufCServiceDestroy)(ProtobufCService *); - -/** - * Structure for defining a custom memory allocator. - */ -struct ProtobufCAllocator { - /** Function to allocate memory. */ - void *(*alloc)(void *allocator_data, size_t size); - - /** Function to free memory. */ - void (*free)(void *allocator_data, void *pointer); - - /** Opaque pointer passed to `alloc` and `free` functions. */ - void *allocator_data; -}; - -/** - * Structure for the protobuf `bytes` scalar type. - * - * The data contained in a `ProtobufCBinaryData` is an arbitrary sequence of - * bytes. It may contain embedded `NUL` characters and is not required to be - * `NUL`-terminated. - */ -struct ProtobufCBinaryData { - size_t len; /**< Number of bytes in the `data` field. */ - uint8_t *data; /**< Data bytes. */ -}; - -/** - * Structure for defining a virtual append-only buffer. Used by - * protobuf_c_message_pack_to_buffer() to abstract the consumption of serialized - * bytes. - * - * `ProtobufCBuffer` "subclasses" may be defined on the stack. For example, to - * write to a `FILE` object: - * -~~~{.c} -typedef struct { - ProtobufCBuffer base; - FILE *fp; -} BufferAppendToFile; - -static void -my_buffer_file_append(ProtobufCBuffer *buffer, - size_t len, - const uint8_t *data) -{ - BufferAppendToFile *file_buf = (BufferAppendToFile *) buffer; - fwrite(data, len, 1, file_buf->fp); // XXX: No error handling! -} -~~~ - * - * To use this new type of ProtobufCBuffer, it could be called as follows: - * -~~~{.c} -... -BufferAppendToFile tmp = {0}; -tmp.base.append = my_buffer_file_append; -tmp.fp = fp; -protobuf_c_message_pack_to_buffer(&message, &tmp); -... -~~~ - */ -struct ProtobufCBuffer { - /** Append function. Consumes the `len` bytes stored at `data`. */ - void (*append)(ProtobufCBuffer *buffer, - size_t len, - const uint8_t *data); -}; - -/** - * Simple buffer "subclass" of `ProtobufCBuffer`. - * - * A `ProtobufCBufferSimple` object is declared on the stack and uses a - * scratch buffer provided by the user for the initial allocation. It performs - * exponential resizing, using dynamically allocated memory. A - * `ProtobufCBufferSimple` object can be created and used as follows: - * -~~~{.c} -uint8_t pad[128]; -ProtobufCBufferSimple simple = PROTOBUF_C_BUFFER_SIMPLE_INIT(pad); -ProtobufCBuffer *buffer = (ProtobufCBuffer *) &simple; -~~~ - * - * `buffer` can now be used with `protobuf_c_message_pack_to_buffer()`. Once a - * message has been serialized to a `ProtobufCBufferSimple` object, the - * serialized data bytes can be accessed from the `.data` field. - * - * To free the memory allocated by a `ProtobufCBufferSimple` object, if any, - * call PROTOBUF_C_BUFFER_SIMPLE_CLEAR() on the object, for example: - * -~~~{.c} -PROTOBUF_C_BUFFER_SIMPLE_CLEAR(&simple); -~~~ - * - * \see PROTOBUF_C_BUFFER_SIMPLE_INIT - * \see PROTOBUF_C_BUFFER_SIMPLE_CLEAR - */ -struct ProtobufCBufferSimple { - /** "Base class". */ - ProtobufCBuffer base; - /** Number of bytes allocated in `data`. */ - size_t alloced; - /** Number of bytes currently stored in `data`. */ - size_t len; - /** Data bytes. */ - uint8_t *data; - /** Whether `data` must be freed. */ - protobuf_c_boolean must_free_data; - /** Allocator to use. May be NULL to indicate the system allocator. */ - ProtobufCAllocator *allocator; -}; - -/** - * Describes an enumeration as a whole, with all of its values. - */ -struct ProtobufCEnumDescriptor { - /** Magic value checked to ensure that the API is used correctly. */ - uint32_t magic; - - /** The qualified name (e.g., "namespace.Type"). */ - const char *name; - /** The unqualified name as given in the .proto file (e.g., "Type"). */ - const char *short_name; - /** Identifier used in generated C code. */ - const char *c_name; - /** The dot-separated namespace. */ - const char *package_name; - - /** Number elements in `values`. */ - unsigned n_values; - /** Array of distinct values, sorted by numeric value. */ - const ProtobufCEnumValue *values; - - /** Number of elements in `values_by_name`. */ - unsigned n_value_names; - /** Array of named values, including aliases, sorted by name. */ - const ProtobufCEnumValueIndex *values_by_name; - - /** Number of elements in `value_ranges`. */ - unsigned n_value_ranges; - /** Value ranges, for faster lookups by numeric value. */ - const ProtobufCIntRange *value_ranges; - - /** Reserved for future use. */ - void *reserved1; - /** Reserved for future use. */ - void *reserved2; - /** Reserved for future use. */ - void *reserved3; - /** Reserved for future use. */ - void *reserved4; -}; - -/** - * Represents a single value of an enumeration. - */ -struct ProtobufCEnumValue { - /** The string identifying this value in the .proto file. */ - const char *name; - - /** The string identifying this value in generated C code. */ - const char *c_name; - - /** The numeric value assigned in the .proto file. */ - int value; -}; - -/** - * Used by `ProtobufCEnumDescriptor` to look up enum values. - */ -struct ProtobufCEnumValueIndex { - /** Name of the enum value. */ - const char *name; - /** Index into values[] array. */ - unsigned index; -}; - -/** - * Describes a single field in a message. - */ -struct ProtobufCFieldDescriptor { - /** Name of the field as given in the .proto file. */ - const char *name; - - /** Tag value of the field as given in the .proto file. */ - uint32_t id; - - /** Whether the field is `REQUIRED`, `OPTIONAL`, or `REPEATED`. */ - ProtobufCLabel label; - - /** The type of the field. */ - ProtobufCType type; - - /** - * The offset in bytes of the message's C structure's quantifier field - * (the `has_MEMBER` field for optional members or the `n_MEMBER` field - * for repeated members. - */ - unsigned quantifier_offset; - - /** - * The offset in bytes into the message's C structure for the member - * itself. - */ - unsigned offset; - - /** - * A type-specific descriptor. - * - * If `type` is `PROTOBUF_C_TYPE_ENUM`, then `descriptor` points to the - * corresponding `ProtobufCEnumDescriptor`. - * - * If `type` is `PROTOBUF_C_TYPE_MESSAGE`, then `descriptor` points to - * the corresponding `ProtobufCMessageDescriptor`. - * - * Otherwise this field is NULL. - */ - const void *descriptor; /* for MESSAGE and ENUM types */ - - /** The default value for this field, if defined. May be NULL. */ - const void *default_value; - - /** - * A flag word. Zero or more of the bits defined in the - * `ProtobufCFieldFlag` enum may be set. - */ - uint32_t flags; - - /** Reserved for future use. */ - unsigned reserved_flags; - /** Reserved for future use. */ - void *reserved2; - /** Reserved for future use. */ - void *reserved3; -}; - -/** - * Helper structure for optimizing int => index lookups in the case - * where the keys are mostly consecutive values, as they presumably are for - * enums and fields. - * - * The data structures requires that the values in the original array are - * sorted. - */ -struct ProtobufCIntRange { - int start_value; - unsigned orig_index; - /* - * NOTE: the number of values in the range can be inferred by looking - * at the next element's orig_index. A dummy element is added to make - * this simple. - */ -}; - -/** - * An instance of a message. - * - * `ProtobufCMessage` is a light-weight "base class" for all messages. - * - * In particular, `ProtobufCMessage` doesn't have any allocation policy - * associated with it. That's because it's common to create `ProtobufCMessage` - * objects on the stack. In fact, that's what we recommend for sending messages. - * If the object is allocated from the stack, you can't really have a memory - * leak. - * - * This means that calls to functions like protobuf_c_message_unpack() which - * return a `ProtobufCMessage` must be paired with a call to a free function, - * like protobuf_c_message_free_unpacked(). - */ -struct ProtobufCMessage { - /** The descriptor for this message type. */ - const ProtobufCMessageDescriptor *descriptor; - /** The number of elements in `unknown_fields`. */ - unsigned n_unknown_fields; - /** The fields that weren't recognized by the parser. */ - ProtobufCMessageUnknownField *unknown_fields; -}; - -/** - * Describes a message. - */ -struct ProtobufCMessageDescriptor { - /** Magic value checked to ensure that the API is used correctly. */ - uint32_t magic; - - /** The qualified name (e.g., "namespace.Type"). */ - const char *name; - /** The unqualified name as given in the .proto file (e.g., "Type"). */ - const char *short_name; - /** Identifier used in generated C code. */ - const char *c_name; - /** The dot-separated namespace. */ - const char *package_name; - - /** - * Size in bytes of the C structure representing an instance of this - * type of message. - */ - size_t sizeof_message; - - /** Number of elements in `fields`. */ - unsigned n_fields; - /** Field descriptors, sorted by tag number. */ - const ProtobufCFieldDescriptor *fields; - /** Used for looking up fields by name. */ - const unsigned *fields_sorted_by_name; - - /** Number of elements in `field_ranges`. */ - unsigned n_field_ranges; - /** Used for looking up fields by id. */ - const ProtobufCIntRange *field_ranges; - - /** Message initialisation function. */ - ProtobufCMessageInit message_init; - - /** Reserved for future use. */ - void *reserved1; - /** Reserved for future use. */ - void *reserved2; - /** Reserved for future use. */ - void *reserved3; -}; - -/** - * An unknown message field. - */ -struct ProtobufCMessageUnknownField { - /** The tag number. */ - uint32_t tag; - /** The wire type of the field. */ - ProtobufCWireType wire_type; - /** Number of bytes in `data`. */ - size_t len; - /** Field data. */ - uint8_t *data; -}; - -/** - * Method descriptor. - */ -struct ProtobufCMethodDescriptor { - /** Method name. */ - const char *name; - /** Input message descriptor. */ - const ProtobufCMessageDescriptor *input; - /** Output message descriptor. */ - const ProtobufCMessageDescriptor *output; -}; - -/** - * Service. - */ -struct ProtobufCService { - /** Service descriptor. */ - const ProtobufCServiceDescriptor *descriptor; - /** Function to invoke the service. */ - void (*invoke)(ProtobufCService *service, - unsigned method_index, - const ProtobufCMessage *input, - ProtobufCClosure closure, - void *closure_data); - /** Function to destroy the service. */ - void (*destroy)(ProtobufCService *service); -}; - -/** - * Service descriptor. - */ -struct ProtobufCServiceDescriptor { - /** Magic value checked to ensure that the API is used correctly. */ - uint32_t magic; - - /** Service name. */ - const char *name; - /** Short version of service name. */ - const char *short_name; - /** C identifier for the service name. */ - const char *c_name; - /** Package name. */ - const char *package; - /** Number of elements in `methods`. */ - unsigned n_methods; - /** Method descriptors, in the order defined in the .proto file. */ - const ProtobufCMethodDescriptor *methods; - /** Sort index of methods. */ - const unsigned *method_indices_by_name; -}; - -/** - * Get the version of the protobuf-c library. Note that this is the version of - * the library linked against, not the version of the headers compiled against. - * - * \return A string containing the version number of protobuf-c. - */ -PROTOBUF_C__API -const char * -protobuf_c_version(void); - -/** - * Get the version of the protobuf-c library. Note that this is the version of - * the library linked against, not the version of the headers compiled against. - * - * \return A 32 bit unsigned integer containing the version number of - * protobuf-c, represented in base-10 as (MAJOR*1E6) + (MINOR*1E3) + PATCH. - */ -PROTOBUF_C__API -uint32_t -protobuf_c_version_number(void); - -/** - * The version of the protobuf-c headers, represented as a string using the same - * format as protobuf_c_version(). - */ -#define PROTOBUF_C_VERSION "1.0.2" - -/** - * The version of the protobuf-c headers, represented as an integer using the - * same format as protobuf_c_version_number(). - */ -#define PROTOBUF_C_VERSION_NUMBER 1000002 - -/** - * The minimum protoc-c version which works with the current version of the - * protobuf-c headers. - */ -#define PROTOBUF_C_MIN_COMPILER_VERSION 1000000 - -/** - * Look up a `ProtobufCEnumValue` from a `ProtobufCEnumDescriptor` by name. - * - * \param desc - * The `ProtobufCEnumDescriptor` object. - * \param name - * The `name` field from the corresponding `ProtobufCEnumValue` object to - * match. - * \return - * A `ProtobufCEnumValue` object. - * \retval NULL - * If not found. - */ -PROTOBUF_C__API -const ProtobufCEnumValue * -protobuf_c_enum_descriptor_get_value_by_name( - const ProtobufCEnumDescriptor *desc, - const char *name); - -/** - * Look up a `ProtobufCEnumValue` from a `ProtobufCEnumDescriptor` by numeric - * value. - * - * \param desc - * The `ProtobufCEnumDescriptor` object. - * \param value - * The `value` field from the corresponding `ProtobufCEnumValue` object to - * match. - * - * \return - * A `ProtobufCEnumValue` object. - * \retval NULL - * If not found. - */ -PROTOBUF_C__API -const ProtobufCEnumValue * -protobuf_c_enum_descriptor_get_value( - const ProtobufCEnumDescriptor *desc, - int value); - -/** - * Look up a `ProtobufCFieldDescriptor` from a `ProtobufCMessageDescriptor` by - * the name of the field. - * - * \param desc - * The `ProtobufCMessageDescriptor` object. - * \param name - * The name of the field. - * \return - * A `ProtobufCFieldDescriptor` object. - * \retval NULL - * If not found. - */ -PROTOBUF_C__API -const ProtobufCFieldDescriptor * -protobuf_c_message_descriptor_get_field_by_name( - const ProtobufCMessageDescriptor *desc, - const char *name); - -/** - * Look up a `ProtobufCFieldDescriptor` from a `ProtobufCMessageDescriptor` by - * the tag value of the field. - * - * \param desc - * The `ProtobufCMessageDescriptor` object. - * \param value - * The tag value of the field. - * \return - * A `ProtobufCFieldDescriptor` object. - * \retval NULL - * If not found. - */ -PROTOBUF_C__API -const ProtobufCFieldDescriptor * -protobuf_c_message_descriptor_get_field( - const ProtobufCMessageDescriptor *desc, - unsigned value); - -/** - * Determine the number of bytes required to store the serialised message. - * - * \param message - * The message object to serialise. - * \return - * Number of bytes. - */ -PROTOBUF_C__API -size_t -protobuf_c_message_get_packed_size(const ProtobufCMessage *message); - -/** - * Serialise a message from its in-memory representation. - * - * This function stores the serialised bytes of the message in a pre-allocated - * buffer. - * - * \param message - * The message object to serialise. - * \param[out] out - * Buffer to store the bytes of the serialised message. This buffer must - * have enough space to store the packed message. Use - * protobuf_c_message_get_packed_size() to determine the number of bytes - * required. - * \return - * Number of bytes stored in `out`. - */ -PROTOBUF_C__API -size_t -protobuf_c_message_pack(const ProtobufCMessage *message, uint8_t *out); - -/** - * Serialise a message from its in-memory representation to a virtual buffer. - * - * This function calls the `append` method of a `ProtobufCBuffer` object to - * consume the bytes generated by the serialiser. - * - * \param message - * The message object to serialise. - * \param buffer - * The virtual buffer object. - * \return - * Number of bytes passed to the virtual buffer. - */ -PROTOBUF_C__API -size_t -protobuf_c_message_pack_to_buffer( - const ProtobufCMessage *message, - ProtobufCBuffer *buffer); - -/** - * Unpack a serialised message into an in-memory representation. - * - * \param descriptor - * The message descriptor. - * \param allocator - * `ProtobufCAllocator` to use for memory allocation. May be NULL to - * specify the default allocator. - * \param len - * Length in bytes of the serialised message. - * \param data - * Pointer to the serialised message. - * \return - * An unpacked message object. - * \retval NULL - * If an error occurred during unpacking. - */ -PROTOBUF_C__API -ProtobufCMessage * -protobuf_c_message_unpack( - const ProtobufCMessageDescriptor *descriptor, - ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); - -/** - * Free an unpacked message object. - * - * This function should be used to deallocate the memory used by a call to - * protobuf_c_message_unpack(). - * - * \param message - * The message object to free. - * \param allocator - * `ProtobufCAllocator` to use for memory deallocation. May be NULL to - * specify the default allocator. - */ -PROTOBUF_C__API -void -protobuf_c_message_free_unpacked( - ProtobufCMessage *message, - ProtobufCAllocator *allocator); - -/** - * Check the validity of a message object. - * - * Makes sure all required fields (`PROTOBUF_C_LABEL_REQUIRED`) are present. - * Recursively checks nested messages. - * - * \retval TRUE - * Message is valid. - * \retval FALSE - * Message is invalid. - */ -PROTOBUF_C__API -protobuf_c_boolean -protobuf_c_message_check(const ProtobufCMessage *); - -/** Message initialiser. */ -#define PROTOBUF_C_MESSAGE_INIT(descriptor) { descriptor, 0, NULL } - -/** - * Initialise a message object from a message descriptor. - * - * \param descriptor - * Message descriptor. - * \param message - * Allocated block of memory of size `descriptor->sizeof_message`. - */ -PROTOBUF_C__API -void -protobuf_c_message_init( - const ProtobufCMessageDescriptor *descriptor, - void *message); - -/** - * Free a service. - * - * \param service - * The service object to free. - */ -PROTOBUF_C__API -void -protobuf_c_service_destroy(ProtobufCService *service); - -/** - * Look up a `ProtobufCMethodDescriptor` by name. - * - * \param desc - * Service descriptor. - * \param name - * Name of the method. - * - * \return - * A `ProtobufCMethodDescriptor` object. - * \retval NULL - * If not found. - */ -PROTOBUF_C__API -const ProtobufCMethodDescriptor * -protobuf_c_service_descriptor_get_method_by_name( - const ProtobufCServiceDescriptor *desc, - const char *name); - -/** - * Initialise a `ProtobufCBufferSimple` object. - */ -#define PROTOBUF_C_BUFFER_SIMPLE_INIT(array_of_bytes) \ -{ \ - { protobuf_c_buffer_simple_append }, \ - sizeof(array_of_bytes), \ - 0, \ - (array_of_bytes), \ - 0, \ - NULL \ -} - -/** - * Clear a `ProtobufCBufferSimple` object, freeing any allocated memory. - */ -#define PROTOBUF_C_BUFFER_SIMPLE_CLEAR(simp_buf) \ -do { \ - if ((simp_buf)->must_free_data) { \ - if ((simp_buf)->allocator != NULL) \ - (simp_buf)->allocator->free( \ - (simp_buf)->allocator, \ - (simp_buf)->data); \ - else \ - free((simp_buf)->data); \ - } \ -} while (0) - -/** - * The `append` method for `ProtobufCBufferSimple`. - * - * \param buffer - * The buffer object to append to. Must actually be a - * `ProtobufCBufferSimple` object. - * \param len - * Number of bytes in `data`. - * \param data - * Data to append. - */ -PROTOBUF_C__API -void -protobuf_c_buffer_simple_append( - ProtobufCBuffer *buffer, - size_t len, - const unsigned char *data); - -PROTOBUF_C__API -void -protobuf_c_service_generated_init( - ProtobufCService *service, - const ProtobufCServiceDescriptor *descriptor, - ProtobufCServiceDestroy destroy); - -PROTOBUF_C__API -void -protobuf_c_service_invoke_internal( - ProtobufCService *service, - unsigned method_index, - const ProtobufCMessage *input, - ProtobufCClosure closure, - void *closure_data); - -/**@}*/ - -PROTOBUF_C__END_DECLS - -#endif /* PROTOBUF_C_H */
--- a/libpurple/protocols/gg/lib/protobuf.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,153 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2012 Tomek Wasilczyk <www.wasilczyk.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file protobuf.c - * - * \brief Funkcje pomocnicze do obsługi formatu protocol buffers - */ - -#include "protobuf.h" - -#define GG_PROTOBUFF_UIN_MAXLEN 15 -struct _gg_protobuf_uin_buff -{ - char data[GG_PROTOBUFF_UIN_MAXLEN + 1 + 2]; -}; - -void gg_protobuf_expected(struct gg_session *gs, const char *field_name, - uint32_t value, uint32_t expected) -{ - if (value == expected) { - return; - } - gg_debug_session(gs, GG_DEBUG_WARNING, "// gg_packet: field %s was " - "expected to be %#x, but its value was %#x\n", - field_name, expected, value); -} - -int gg_protobuf_valid_chknull(struct gg_session *gs, const char *msg_name, - int isNull) -{ - if (isNull) { - gg_debug_session(gs, GG_DEBUG_ERROR, "// gg_protobuf: couldn't " - "unpack %s message\n", msg_name); - } - return !isNull; -} - -int gg_protobuf_valid_chkunknown(struct gg_session *gs, const char *msg_name, - ProtobufCMessage *base) -{ - if (base->n_unknown_fields > 0) { - gg_debug_session(gs, GG_DEBUG_WARNING, "// gg_protobuf: message" - " %s had %d unknown field(s)\n", - msg_name, base->n_unknown_fields); - } - return 1; -} - -int gg_protobuf_send_ex(struct gg_session *gs, struct gg_event *ge, int type, - void *msg, gg_protobuf_size_cb_t size_cb, - gg_protobuf_pack_cb_t pack_cb) -{ - void *buffer; - size_t len; - int succ = 1; - enum gg_failure_t failure; - - len = size_cb(msg); - buffer = malloc(len); - if (buffer == NULL) { - gg_debug_session(gs, GG_DEBUG_ERROR, "// gg_protobuf_send: out " - "of memory - tried to allocate %" GG_SIZE_FMT - " bytes for %#x packet\n", len, type); - succ = 0; - failure = GG_FAILURE_INTERNAL; - } else { - pack_cb(msg, buffer); - succ = (-1 != gg_send_packet(gs, type, buffer, len, NULL)); - free(buffer); - buffer = NULL; - if (!succ) { - failure = GG_FAILURE_WRITING; - gg_debug_session(gs, GG_DEBUG_ERROR, - "// gg_protobuf_send: sending packet %#x " - "failed. (errno=%d, %s)\n", type, errno, - strerror(errno)); - } - } - - if (!succ) { - gg_connection_failure(gs, ge, failure); - } - - return succ; -} - -void gg_protobuf_set_uin(ProtobufCBinaryData *dst, uin_t uin, gg_protobuf_uin_buff_t *buff) -{ - char *uin_str; - int uin_len; - static gg_protobuf_uin_buff_t static_buffer; - - if (buff == NULL) { - buff = &static_buffer; - } - - uin_str = buff->data + 2; - uin_len = snprintf(uin_str, GG_PROTOBUFF_UIN_MAXLEN + 1, "%u", uin); - - buff->data[0] = 0x01; /* magic: 0x00 lub 0x01 */ - buff->data[1] = uin_len; - - dst->len = uin_len + 2; - dst->data = (uint8_t*)&buff->data; -} - -uin_t gg_protobuf_get_uin(ProtobufCBinaryData uin_data) -{ - uint8_t magic; - size_t uin_len; - const char *uin_str; - uin_t uin; - - magic = (uin_data.len > 0) ? uin_data.data[0] : 0; - uin_len = (uin_data.len > 1) ? uin_data.data[1] : 0; - - if (uin_data.len != uin_len + 2 || uin_len > 10) { - gg_debug(GG_DEBUG_ERROR, "// gg_protobuf_get_uin: " - "invalid length\n"); - return 0; - } - if (magic != 0) { - gg_debug(GG_DEBUG_WARNING, "// gg_protobuf_get_uin: " - "unexpected magic value=%#x\n", magic); - } - - uin_str = (char*)(uin_data.data + 2); - uin = gg_str_to_uin(uin_str, uin_len); - - if (uin == 0) { - gg_debug(GG_DEBUG_ERROR, "// gg_protobuf_get_uin: " - "invalid uin\n"); - } - return uin; -}
--- a/libpurple/protocols/gg/lib/protobuf.h Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2012 Tomek Wasilczyk <www.wasilczyk.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef LIBGADU_PROTOBUF_H -#define LIBGADU_PROTOBUF_H - -#include <stdlib.h> -#include <errno.h> -#include <string.h> - -#include "config.h" -#ifdef GG_CONFIG_HAVE_PROTOBUF_C -#include <protobuf-c/protobuf-c.h> -#else -#include "protobuf-c.h" -#endif - -#include "internal.h" -#include "fileio.h" - -typedef size_t (*gg_protobuf_size_cb_t)(const void *message); -typedef size_t (*gg_protobuf_pack_cb_t)(const void *message, uint8_t *out); - -typedef struct _gg_protobuf_uin_buff gg_protobuf_uin_buff_t; - -/* Ostatni warunek (msg != NULL) jest tylko po to, żeby uciszyć analizę - * statyczną (zawiera się w pierwszym). */ -#define GG_PROTOBUF_VALID(gs, name, msg) \ - (gg_protobuf_valid_chknull(gs, name, msg == NULL) && \ - gg_protobuf_valid_chkunknown(gs, name, &msg->base) && \ - msg != NULL) - -#define GG_PROTOBUF_SEND(gs, ge, packet_type, msg_type, msg) \ - gg_protobuf_send_ex(gs, ge, packet_type, &msg, \ - (gg_protobuf_size_cb_t) msg_type ## __get_packed_size, \ - (gg_protobuf_pack_cb_t) msg_type ## __pack) - -void gg_protobuf_expected(struct gg_session *gs, const char *field_name, - uint32_t value, uint32_t expected); - -int gg_protobuf_valid_chknull(struct gg_session *gs, const char *msg_name, - int isNull); -int gg_protobuf_valid_chkunknown(struct gg_session *gs, const char *msg_name, - ProtobufCMessage *base); - -int gg_protobuf_send_ex(struct gg_session *gs, struct gg_event *ge, int type, - void *msg, gg_protobuf_size_cb_t size_cb, - gg_protobuf_pack_cb_t pack_cb); - -void gg_protobuf_set_uin(ProtobufCBinaryData *dst, uin_t uin, gg_protobuf_uin_buff_t *buff); -uin_t gg_protobuf_get_uin(ProtobufCBinaryData uin_data); - -#endif /* LIBGADU_PROTOBUF_H */
--- a/libpurple/protocols/gg/lib/protocol.h Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,411 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2009-2010 Jakub Zawadzki <darkjames@darkjames.ath.cx> - * Bartłomiej Zimoń <uzi18@o2.pl> - * Wojtek Kaniewski <wojtekka@irc.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef LIBGADU_PROTOCOL_H -#define LIBGADU_PROTOCOL_H - -#include "libgadu.h" - -#ifdef _WIN32 -#pragma pack(push, 1) -#endif - -#define GG_LOGIN80BETA 0x0029 - -#define GG_LOGIN80 0x0031 - -#define GG_LOGIN105 0x0083 - -#undef GG_FEATURE_STATUS80BETA -#undef GG_FEATURE_MSG80 -#undef GG_FEATURE_STATUS80 -#define GG_FEATURE_STATUS80BETA 0x01 -#define GG_FEATURE_MSG80 0x02 -#define GG_FEATURE_STATUS80 0x05 - -#define GG_DEFAULT_HOST_WHITE_LIST { "gadu-gadu.pl", "gg.pl", NULL } - -#define GG8_LANG "pl" -#define GG8_VERSION "Gadu-Gadu Client Build " - -#define GG11_VERSION "GG-Phoenix/" -#define GG11_TARGET " (BUILD;WINNT_x86-msvc;rv:11.0,pl;release;standard) (OS;Windows;Windows NT 6.1)" - -struct gg_login80 { - uint32_t uin; /* mój numerek */ - uint8_t language[2]; /* język: GG8_LANG */ - uint8_t hash_type; /* rodzaj hashowania hasła */ - uint8_t hash[64]; /* hash hasła dopełniony zerami */ - uint32_t status; /* status na dzień dobry */ - uint32_t flags; /* flagi (przeznaczenie nieznane) */ - uint32_t features; /* opcje protokołu (GG8_FEATURES) */ - uint32_t local_ip; /* mój adres ip */ - uint16_t local_port; /* port, na którym słucham */ - uint32_t external_ip; /* zewnętrzny adres ip (???) */ - uint16_t external_port; /* zewnętrzny port (???) */ - uint8_t image_size; /* maksymalny rozmiar grafiki w KiB */ - uint8_t dunno2; /* 0x64 */ -} GG_PACKED; - -#define GG_LOGIN_HASH_TYPE_INVALID 0x0016 - -#define GG_LOGIN80_OK 0x0035 - -#define GG_LOGIN110_OK 0x009d - -/** - * Logowanie powiodło się (pakiet \c GG_LOGIN80_OK) - */ -struct gg_login80_ok { - uint32_t unknown1; /* 0x00000001 */ -} GG_PACKED; - -/** - * Logowanie nie powiodło się (pakiet \c GG_LOGIN80_FAILED) - */ -#define GG_LOGIN80_FAILED 0x0043 - -struct gg_login80_failed { - uint32_t unknown1; /* 0x00000001 */ -} GG_PACKED; - -#define GG_NEW_STATUS80BETA 0x0028 - -#define GG_NEW_STATUS80 0x0038 - -/** - * Zmiana stanu (pakiet \c GG_NEW_STATUS80) - */ -struct gg_new_status80 { - uint32_t status; /**< Nowy status */ - uint32_t flags; /**< flagi (nieznane przeznaczenie) */ - uint32_t description_size; /**< rozmiar opisu */ -} GG_PACKED; - -#define GG_NEW_STATUS105 0x0063 - -#define GG_STATUS80BETA 0x002a -#define GG_NOTIFY_REPLY80BETA 0x002b - -#define GG_STATUS80 0x0036 -#define GG_NOTIFY_REPLY80 0x0037 - -struct gg_notify_reply80 { - uint32_t uin; /* numerek plus flagi w najstarszym bajcie */ - uint32_t status; /* status danej osoby */ - uint32_t features; /* opcje protokołu */ - uint32_t remote_ip; /* adres IP bezpośrednich połączeń */ - uint16_t remote_port; /* port bezpośrednich połączeń */ - uint8_t image_size; /* maksymalny rozmiar obrazków w KB */ - uint8_t unknown1; /* 0x00 */ - uint32_t flags; /* flagi połączenia */ - uint32_t descr_len; /* rozmiar opisu */ -} GG_PACKED; - -#define GG_SEND_MSG80 0x002d - -struct gg_send_msg80 { - uint32_t recipient; - uint32_t seq; - uint32_t msgclass; - uint32_t offset_plain; - uint32_t offset_attr; -} GG_PACKED; - -#define GG_RECV_MSG80 0x002e - -struct gg_recv_msg80 { - uint32_t sender; - uint32_t seq; - uint32_t time; - uint32_t msgclass; - uint32_t offset_plain; - uint32_t offset_attr; -} GG_PACKED; - -#define GG_DISCONNECT_ACK 0x000d - -#define GG_RECV_MSG_ACK 0x0046 - -struct gg_recv_msg_ack { - uint32_t seq; -} GG_PACKED; - -#define GG_USER_DATA 0x0044 - -struct gg_user_data { - uint32_t type; - uint32_t user_count; -} GG_PACKED; - -struct gg_user_data_user { - uint32_t uin; - uint32_t attr_count; -} GG_PACKED; - -#define GG_TYPING_NOTIFICATION 0x0059 - -struct gg_typing_notification { - uint16_t length; - uint32_t uin; -} GG_PACKED; - -#define GG_XML_ACTION 0x002c - -#define GG_RECV_OWN_MSG 0x005a - -#define GG_MULTILOGON_INFO 0x005b - -struct gg_multilogon_info { - uint32_t count; -} GG_PACKED; - -struct gg_multilogon_info_item { - uint32_t addr; - uint32_t flags; - uint32_t features; - uint32_t logon_time; - gg_multilogon_id_t conn_id; - uint32_t unknown1; - uint32_t name_size; -} GG_PACKED; - -#define GG_MULTILOGON_DISCONNECT 0x0062 - -struct gg_multilogon_disconnect { - gg_multilogon_id_t conn_id; -} GG_PACKED; - -#define GG_MSG_CALLBACK 0x02 /**< Żądanie zwrotnego połączenia bezpośredniego */ - -#define GG_MSG_OPTION_CONFERENCE 0x01 -#define GG_MSG_OPTION_ATTRIBUTES 0x02 -#define GG_MSG_OPTION_IMAGE_REQUEST 0x04 -#define GG_MSG_OPTION_IMAGE_REPLY 0x05 -#define GG_MSG_OPTION_IMAGE_REPLY_MORE 0x06 - -#define GG_DCC7_ABORT 0x0025 - -struct gg_dcc7_abort { - gg_dcc7_id_t id; /* identyfikator połączenia */ - uint32_t uin_from; /* numer nadawcy */ - uint32_t uin_to; /* numer odbiorcy */ -} GG_PACKED; - -#define GG_DCC7_ABORTED 0x0025 - -struct gg_dcc7_aborted { - gg_dcc7_id_t id; /* identyfikator połączenia */ -} GG_PACKED; - -#define GG_DCC7_VOICE_RETRIES 0x11 /* 17 powtorzen */ - -#define GG_DCC7_RESERVED1 0xdeadc0de -#define GG_DCC7_RESERVED2 0xdeadbeaf - -struct gg_dcc7_voice_auth { - uint8_t type; /* 0x00 -> wysylanie ID - * 0x01 -> potwierdzenie ID - */ - gg_dcc7_id_t id; /* identyfikator połączenia */ - uint32_t reserved1; /* GG_DCC7_RESERVED1 */ - uint32_t reserved2; /* GG_DCC7_RESERVED2 */ -} GG_PACKED; - -/* Wyciszony mikrofon. Ten pakiet jest wysylany co 1s (jesli chcemy podtrzymac - * polaczenie). - */ -struct gg_dcc7_voice_nodata { - uint8_t type; /* 0x02 */ - gg_dcc7_id_t id; /* identyfikator połączenia */ - uint32_t reserved1; /* GG_DCC7_RESERVED1 */ - uint32_t reserved2; /* GG_DCC7_RESERVED2 */ -} GG_PACKED; - -struct gg_dcc7_voice_data { - uint8_t type; /* 0x03 */ - uint32_t did; /* XXX: co ile zwieksza sie u nas id pakietu [uzywac 0x28] */ - uint32_t len; /* rozmiar strukturki - 1 (sizeof(type)) */ - uint32_t packet_id; /* numerek pakietu */ - uint32_t datalen; /* rozmiar danych */ - /* char data[]; */ /* ramki: albo gsm, albo speex, albo melp, albo inne. */ -} GG_PACKED; - -struct gg_dcc7_voice_init { - uint8_t type; /* 0x04 */ - uint32_t id; /* nr kroku [0x1 - 0x5] */ - uint32_t protocol; /* XXX: wersja protokolu (0x29, 0x2a, 0x2b) */ - uint32_t len; /* rozmiar sizeof(protocol)+sizeof(len)+ - * sizeof(data) = 0x08 + sizeof(data) */ - /* char data[]; */ /* reszta danych */ -} GG_PACKED; - -struct gg_dcc7_voice_init_confirm { - uint8_t type; /* 0x05 */ - uint32_t id; /* id tego co potwierdzamy [0x1 - 0x5] */ -} GG_PACKED; - -#define GG_DCC7_RELAY_TYPE_SERVER 0x01 /* adres serwera, na który spytać o proxy */ -#define GG_DCC7_RELAY_TYPE_PROXY 0x08 /* adresy proxy, na które sie łączyć */ - -#define GG_DCC7_RELAY_DUNNO1 0x02 - -#define GG_DCC7_RELAY_REQUEST 0x0a - -struct gg_dcc7_relay_req { - uint32_t magic; /* 0x0a */ - uint32_t len; /* długość całego pakietu */ - gg_dcc7_id_t id; /* identyfikator połączenia */ - uint16_t type; /* typ zapytania */ - uint16_t dunno1; /* 0x02 */ -} GG_PACKED; - -#define GG_DCC7_RELAY_REPLY_RCOUNT 0x02 - -#define GG_DCC7_RELAY_REPLY 0x0b - -struct gg_dcc7_relay_reply { - uint32_t magic; /* 0x0b */ - uint32_t len; /* długość całego pakietu */ - uint32_t rcount; /* ilość serwerów */ -} GG_PACKED; - -struct gg_dcc7_relay_reply_server { - uint32_t addr; /* adres ip serwera */ - uint16_t port; /* port serwera */ - uint8_t family; /* rodzina adresów (na końcu?!) AF_INET=2 */ -} GG_PACKED; - -#define GG_DCC7_WELCOME_SERVER 0xc0debabe - -struct gg_dcc7_welcome_server { - uint32_t magic; /* 0xc0debabe */ - gg_dcc7_id_t id; /* identyfikator połączenia */ -} GG_PACKED; - -struct gg_dcc7_welcome_p2p { - gg_dcc7_id_t id; /* identyfikator połączenia */ -} GG_PACKED; - -#define GG_TIMEOUT_DISCONNECT 5 /**< Maksymalny czas oczekiwania na rozłączenie */ - -#define GG_USERLIST100_VERSION 0x5c - -struct gg_userlist100_version { - uint32_t version; /* numer wersji listy kontaktów */ -} GG_PACKED; - -#define GG_USERLIST100_REQUEST 0x0040 - -struct gg_userlist100_request { - uint8_t type; /* rodzaj żądania */ - uint32_t version; /* numer ostatniej znanej wersji listy kontaktów bądź 0 */ - uint8_t format_type; /* rodzaj żądanego typu formatu listy kontaktów */ - uint8_t unknown1; /* 0x01 */ - /* char request[]; */ -} GG_PACKED; - -#define GG_USERLIST100_REPLY 0x41 - -struct gg_userlist100_reply { - uint8_t type; /* rodzaj odpowiedzi */ - uint32_t version; /* numer wersji listy kontaktów aktualnie przechowywanej przez serwer */ - uint8_t format_type; /* rodzaj przesyłanego typu formatu listy kontaktów */ - uint8_t unknown1; /* 0x01 */ - /* char reply[]; */ -} GG_PACKED; - -struct gg_chat_create { - uint32_t seq; - uint32_t dummy; -} GG_PACKED; - -struct gg_chat_invite { - uint64_t id; - uint32_t seq; - uint32_t participants_count; - /* struct { - uint32_t uin; - uint32_t dummy; (0x1e) - } participants[]; */ -} GG_PACKED; - -struct gg_chat_leave { - uint64_t id; - uint32_t seq; -} GG_PACKED; - -struct gg_chat_created { - uint64_t id; - uint32_t seq; -} GG_PACKED; - -struct gg_chat_invite_ack { - uint64_t id; - uint32_t seq; - uint32_t unknown1; /* 0x00 */ - uint32_t unknown2; /* 0x10 */ -} GG_PACKED; - -struct gg_chat_left { - uint64_t id; - uint32_t uin; -} GG_PACKED; - -#define GG_ADD_NOTIFY105 0x007b -#define GG_REMOVE_NOTIFY105 0x007c -#define GG_EVENT110 0x0084 -#define GG_IMTOKEN 0x008c -#define GG_ACCESS_INFO 0x008f -#define GG_NOTIFY105_FIRST 0x0077 -#define GG_NOTIFY105_LAST 0x0078 -#define GG_NOTIFY105_LIST_EMPTY 0x0079 -#define GG_PONG110 0x00a1 -#define GG_OPTIONS 0x009b - -#define GG_SEND_MSG110 0x007d -#define GG_RECV_MSG110 0x007e -#define GG_RECV_OWN_MSG110 0x0082 -#define GG_ACK110 0x0086 -#define GG_SEND_MSG_ACK110 0x0087 - -#define GG_CHAT_INFO 0x0093 -#define GG_CHAT_INFO_UPDATE 0x009e -#define GG_CHAT_CREATED 0x0045 -#define GG_CHAT_INVITE_ACK 0x0047 -#define GG_CHAT_RECV_MSG 0x0088 -#define GG_CHAT_RECV_OWN_MSG 0x008e -#define GG_CHAT_CREATE 0x0047 -#define GG_CHAT_INVITE 0x0090 -#define GG_CHAT_LEAVE 0x0052 -#define GG_CHAT_LEFT 0x0066 -#define GG_CHAT_SEND_MSG 0x008d - -#define GG_UIN_INFO 0x007a -#define GG_TRANSFER_INFO 0x00a0 -#define GG_MAGIC_NOTIFICATION 0x009f - -#ifdef _WIN32 -#pragma pack(pop) -#endif - -#endif /* LIBGADU_PROTOCOL_H */
--- a/libpurple/protocols/gg/lib/pubdir.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,888 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2001-2006 Wojtek Kaniewski <wojtekka@irc.pl> - * Dawid Jarosz <dawjar@poczta.onet.pl> - * Adam Wysocki <gophi@ekg.chmurka.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file pubdir.c - * - * \brief Obsługa katalogu publicznego - */ - -#include "network.h" -#include <ctype.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> - -#include "libgadu.h" - -/** - * Rejestruje nowego użytkownika. - * - * Wymaga wcześniejszego pobrania tokenu za pomocą \c gg_token(). - * - * \param email Adres e-mail - * \param password Hasło - * \param tokenid Identyfikator tokenu - * \param tokenval Zawartość tokenu - * \param async Flaga połączenia asynchronicznego - * - * \return Struktura \c gg_http lub \c NULL w przypadku błędu - * - * \ingroup register - */ -struct gg_http *gg_register3(const char *email, const char *password, - const char *tokenid, const char *tokenval, int async) -{ - struct gg_http *h; - char *__pwd, *__email, *__tokenid, *__tokenval, *form, *query; - - if (!email || !password || !tokenid || !tokenval) { - gg_debug(GG_DEBUG_MISC, "=> register, NULL parameter\n"); - errno = EFAULT; - return NULL; - } - - __pwd = gg_urlencode(password); - __email = gg_urlencode(email); - __tokenid = gg_urlencode(tokenid); - __tokenval = gg_urlencode(tokenval); - - if (!__pwd || !__email || !__tokenid || !__tokenval) { - gg_debug(GG_DEBUG_MISC, "=> register, not enough memory for form fields\n"); - free(__pwd); - free(__email); - free(__tokenid); - free(__tokenval); - return NULL; - } - - form = gg_saprintf("pwd=%s&email=%s&tokenid=%s&tokenval=%s&code=%u", - __pwd, __email, __tokenid, __tokenval, - gg_http_hash("ss", email, password)); - - free(__pwd); - free(__email); - free(__tokenid); - free(__tokenval); - - if (!form) { - gg_debug(GG_DEBUG_MISC, "=> register, not enough memory for form query\n"); - return NULL; - } - - gg_debug(GG_DEBUG_MISC, "=> register, %s\n", form); - - query = gg_saprintf( - "Host: " GG_REGISTER_HOST "\r\n" - "Content-Type: application/x-www-form-urlencoded\r\n" - "User-Agent: " GG_HTTP_USERAGENT "\r\n" - "Content-Length: %d\r\n" - "Pragma: no-cache\r\n" - "\r\n" - "%s", - (int) strlen(form), form); - - free(form); - - if (!query) { - gg_debug(GG_DEBUG_MISC, "=> register, not enough memory for query\n"); - return NULL; - } - - if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, - "POST", "/appsvc/fmregister3.asp", query))) - { - gg_debug(GG_DEBUG_MISC, "=> register, gg_http_connect() failed mysteriously\n"); - free(query); - return NULL; - } - - h->type = GG_SESSION_REGISTER; - - free(query); - - h->callback = gg_pubdir_watch_fd; - h->destroy = gg_pubdir_free; - - if (!async) - gg_pubdir_watch_fd(h); - - return h; -} - -#ifdef DOXYGEN - -/** - * Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze połączenia. - * - * Operacja będzie zakończona, gdy pole \c state będzie równe \c GG_STATE_DONE. - * Jeśli wystąpi błąd, \c state będzie równe \c GG_STATE_ERROR, a kod błędu - * znajdzie się w polu \c error. - * - * \note W rzeczywistości funkcja jest makrem rozwijanym do - * \c gg_pubdir_watch_fd(). - * - * \param h Struktura połączenia - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup register - */ -int gg_register_watch_fd(struct gg_httpd *h) -{ - return gg_pubdir_watch_fd(h); -} - -/** - * Zwalnia zasoby po operacji. - * - * \note W rzeczywistości funkcja jest makrem rozwijanym do \c gg_pubdir_free(). - * - * \param h Struktura połączenia - * - * \ingroup register - */ -void gg_register_free(struct gg_http *h) -{ - return gg_pubdir_free(h); -} - -#endif /* DOXYGEN */ - -/** - * Usuwa użytkownika. - * - * Wymaga wcześniejszego pobrania tokenu za pomocą \c gg_token(). - * - * \param uin Numer Gadu-Gadu - * \param password Hasło - * \param tokenid Identyfikator tokenu - * \param tokenval Zawartość tokenu - * \param async Flaga połączenia asynchronicznego - * - * \return Struktura \c gg_http lub \c NULL w przypadku błędu - * - * \ingroup unregister - */ -struct gg_http *gg_unregister3(uin_t uin, const char *password, const char *tokenid, const char *tokenval, int async) -{ - struct gg_http *h; - char *__fmpwd, *__pwd, *__tokenid, *__tokenval, *form, *query; - - if (!password || !tokenid || !tokenval) { - gg_debug(GG_DEBUG_MISC, "=> unregister, NULL parameter\n"); - errno = EFAULT; - return NULL; - } - - __pwd = gg_saprintf("%d", rand()); - __fmpwd = gg_urlencode(password); - __tokenid = gg_urlencode(tokenid); - __tokenval = gg_urlencode(tokenval); - - if (!__fmpwd || !__pwd || !__tokenid || !__tokenval) { - gg_debug(GG_DEBUG_MISC, "=> unregister, not enough memory for form fields\n"); - free(__pwd); - free(__fmpwd); - free(__tokenid); - free(__tokenval); - return NULL; - } - - form = gg_saprintf("fmnumber=%d&fmpwd=%s&delete=1&pwd=%s&" - "email=deletedaccount@gadu-gadu.pl&tokenid=%s&tokenval=%s&" - "code=%u", uin, __fmpwd, __pwd, __tokenid, __tokenval, - gg_http_hash("ss", "deletedaccount@gadu-gadu.pl", __pwd)); - - free(__fmpwd); - free(__pwd); - free(__tokenid); - free(__tokenval); - - if (!form) { - gg_debug(GG_DEBUG_MISC, "=> unregister, not enough memory for form query\n"); - return NULL; - } - - gg_debug(GG_DEBUG_MISC, "=> unregister, %s\n", form); - - query = gg_saprintf( - "Host: " GG_REGISTER_HOST "\r\n" - "Content-Type: application/x-www-form-urlencoded\r\n" - "User-Agent: " GG_HTTP_USERAGENT "\r\n" - "Content-Length: %d\r\n" - "Pragma: no-cache\r\n" - "\r\n" - "%s", - (int) strlen(form), form); - - free(form); - - if (!query) { - gg_debug(GG_DEBUG_MISC, "=> unregister, not enough memory for query\n"); - return NULL; - } - - if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, - "POST", "/appsvc/fmregister3.asp", query))) - { - gg_debug(GG_DEBUG_MISC, "=> unregister, gg_http_connect() failed mysteriously\n"); - free(query); - return NULL; - } - - h->type = GG_SESSION_UNREGISTER; - - free(query); - - h->callback = gg_pubdir_watch_fd; - h->destroy = gg_pubdir_free; - - if (!async) - gg_pubdir_watch_fd(h); - - return h; -} - -#ifdef DOXYGEN - -/** - * Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze połączenia. - * - * Operacja będzie zakończona, gdy pole \c state będzie równe \c GG_STATE_DONE. - * Jeśli wystąpi błąd, \c state będzie równe \c GG_STATE_ERROR, a kod błędu - * znajdzie się w polu \c error. - * - * \note W rzeczywistości funkcja jest makrem rozwijanym do - * \c gg_pubdir_watch_fd(). - * - * \param h Struktura połączenia - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup unregister - */ -int gg_unregister_watch_fd(struct gg_httpd *h) -{ - return gg_pubdir_watch_fd(h); -} - -/** - * Zwalnia zasoby po operacji. - * - * \note W rzeczywistości funkcja jest makrem rozwijanym do \c gg_pubdir_free(). - * - * \param h Struktura połączenia - * - * \ingroup unregister - */ -void gg_unregister_free(struct gg_http *h) -{ - return gg_pubdir_free(h); -} - -#endif /* DOXYGEN */ - -/** - * Zmienia hasło użytkownika. - * - * Wymaga wcześniejszego pobrania tokenu za pomocą \c gg_token(). - * - * \param uin Numer Gadu-Gadu - * \param email Adres e-mail - * \param passwd Obecne hasło - * \param newpasswd Nowe hasło - * \param tokenid Identyfikator tokenu - * \param tokenval Zawartość tokenu - * \param async Flaga połączenia asynchronicznego - * - * \return Struktura \c gg_http lub \c NULL w przypadku błędu - * - * \ingroup passwd - */ -struct gg_http *gg_change_passwd4(uin_t uin, const char *email, - const char *passwd, const char *newpasswd, const char *tokenid, - const char *tokenval, int async) -{ - struct gg_http *h; - char *form, *query, *__email, *__fmpwd, *__pwd, *__tokenid, *__tokenval; - - if (!uin || !email || !passwd || !newpasswd || !tokenid || !tokenval) { - gg_debug(GG_DEBUG_MISC, "=> change, NULL parameter\n"); - errno = EFAULT; - return NULL; - } - - __fmpwd = gg_urlencode(passwd); - __pwd = gg_urlencode(newpasswd); - __email = gg_urlencode(email); - __tokenid = gg_urlencode(tokenid); - __tokenval = gg_urlencode(tokenval); - - if (!__fmpwd || !__pwd || !__email || !__tokenid || !__tokenval) { - gg_debug(GG_DEBUG_MISC, "=> change, not enough memory for form fields\n"); - free(__fmpwd); - free(__pwd); - free(__email); - free(__tokenid); - free(__tokenval); - return NULL; - } - - if (!(form = gg_saprintf("fmnumber=%d&fmpwd=%s&pwd=%s&email=%s&" - "tokenid=%s&tokenval=%s&code=%u", uin, __fmpwd, __pwd, __email, - __tokenid, __tokenval, gg_http_hash("ss", email, newpasswd)))) - { - gg_debug(GG_DEBUG_MISC, "=> change, not enough memory for form fields\n"); - free(__fmpwd); - free(__pwd); - free(__email); - free(__tokenid); - free(__tokenval); - - return NULL; - } - - free(__fmpwd); - free(__pwd); - free(__email); - free(__tokenid); - free(__tokenval); - - gg_debug(GG_DEBUG_MISC, "=> change, %s\n", form); - - query = gg_saprintf( - "Host: " GG_REGISTER_HOST "\r\n" - "Content-Type: application/x-www-form-urlencoded\r\n" - "User-Agent: " GG_HTTP_USERAGENT "\r\n" - "Content-Length: %d\r\n" - "Pragma: no-cache\r\n" - "\r\n" - "%s", - (int) strlen(form), form); - - free(form); - - if (!query) { - gg_debug(GG_DEBUG_MISC, "=> change, not enough memory for query\n"); - return NULL; - } - - if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, - "POST", "/appsvc/fmregister3.asp", query))) - { - gg_debug(GG_DEBUG_MISC, "=> change, gg_http_connect() failed mysteriously\n"); - free(query); - return NULL; - } - - h->type = GG_SESSION_PASSWD; - - free(query); - - h->callback = gg_pubdir_watch_fd; - h->destroy = gg_pubdir_free; - - if (!async) - gg_pubdir_watch_fd(h); - - return h; -} - -#ifdef DOXYGEN - -/** - * Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze połączenia. - * - * Operacja będzie zakończona, gdy pole \c state będzie równe \c GG_STATE_DONE. - * Jeśli wystąpi błąd, \c state będzie równe \c GG_STATE_ERROR, a kod błędu - * znajdzie się w polu \c error. - * - * \note W rzeczywistości funkcja jest makrem rozwijanym do - * \c gg_pubdir_watch_fd(). - * - * \param h Struktura połączenia - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup passwd - */ -int gg_change_passwd_watch_fd(struct gg_httpd *h) -{ - return gg_pubdir_watch_fd(h); -} - -/** - * Zwalnia zasoby po operacji. - * - * \note W rzeczywistości funkcja jest makrem rozwijanym do \c gg_pubdir_free(). - * - * \param h Struktura połączenia - * - * \ingroup passwd - */ -void gg_change_passwd_free(struct gg_http *h) -{ - return gg_pubdir_free(h); -} - -#endif /* DOXYGEN */ - -/** - * Wysyła hasło użytkownika na e-mail. - * - * Wymaga wcześniejszego pobrania tokenu za pomocą \c gg_token(). - * - * \param uin Numer Gadu-Gadu - * \param email Adres e-mail (podany przy rejestracji) - * \param tokenid Identyfikator tokenu - * \param tokenval Zawartość tokenu - * \param async Flaga połączenia asynchronicznego - * - * \return Struktura \c gg_http lub \c NULL w przypadku błędu - * - * \ingroup remind - */ -struct gg_http *gg_remind_passwd3(uin_t uin, const char *email, const char *tokenid, const char *tokenval, int async) -{ - struct gg_http *h; - char *form, *query, *__tokenid, *__tokenval, *__email; - - if (!tokenid || !tokenval || !email) { - gg_debug(GG_DEBUG_MISC, "=> remind, NULL parameter\n"); - errno = EFAULT; - return NULL; - } - - __tokenid = gg_urlencode(tokenid); - __tokenval = gg_urlencode(tokenval); - __email = gg_urlencode(email); - - if (!__tokenid || !__tokenval || !__email) { - gg_debug(GG_DEBUG_MISC, "=> remind, not enough memory for form fields\n"); - free(__tokenid); - free(__tokenval); - free(__email); - return NULL; - } - - if (!(form = gg_saprintf("userid=%d&code=%u&tokenid=%s&tokenval=%s&" - "email=%s", uin, gg_http_hash("u", uin), __tokenid, __tokenval, - __email))) - { - gg_debug(GG_DEBUG_MISC, "=> remind, not enough memory for form fields\n"); - free(__tokenid); - free(__tokenval); - free(__email); - return NULL; - } - - free(__tokenid); - free(__tokenval); - free(__email); - - gg_debug(GG_DEBUG_MISC, "=> remind, %s\n", form); - - query = gg_saprintf( - "Host: " GG_REMIND_HOST "\r\n" - "Content-Type: application/x-www-form-urlencoded\r\n" - "User-Agent: " GG_HTTP_USERAGENT "\r\n" - "Content-Length: %d\r\n" - "Pragma: no-cache\r\n" - "\r\n" - "%s", - (int) strlen(form), form); - - free(form); - - if (!query) { - gg_debug(GG_DEBUG_MISC, "=> remind, not enough memory for query\n"); - return NULL; - } - - if (!(h = gg_http_connect(GG_REMIND_HOST, GG_REMIND_PORT, async, "POST", "/appsvc/fmsendpwd3.asp", query))) { - gg_debug(GG_DEBUG_MISC, "=> remind, gg_http_connect() failed mysteriously\n"); - free(query); - return NULL; - } - - h->type = GG_SESSION_REMIND; - - free(query); - - h->callback = gg_pubdir_watch_fd; - h->destroy = gg_pubdir_free; - - if (!async) - gg_pubdir_watch_fd(h); - - return h; -} - -#ifdef DOXYGEN - -/** - * Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze połączenia. - * - * Operacja będzie zakończona, gdy pole \c state będzie równe \c GG_STATE_DONE. - * Jeśli wystąpi błąd, \c state będzie równe \c GG_STATE_ERROR, a kod błędu - * znajdzie się w polu \c error. - * - * \note W rzeczywistości funkcja jest makrem rozwijanym do - * \c gg_pubdir_watch_fd(). - * - * \param h Struktura połączenia - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup remind - */ -int gg_remind_watch_fd(struct gg_httpd *h) -{ - return gg_pubdir_watch_fd(h); -} - -/** - * Zwalnia zasoby po operacji. - * - * \note W rzeczywistości funkcja jest makrem rozwijanym do \c gg_pubdir_free(). - * - * \param h Struktura połączenia - * - * \ingroup remind - */ -void gg_remind_free(struct gg_http *h) -{ - return gg_pubdir_free(h); -} - -#endif /* DOXYGEN */ - -/** - * Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze połączenia. - * - * Operacja będzie zakończona, gdy pole \c state będzie równe \c GG_STATE_DONE. - * Jeśli wystąpi błąd, \c state będzie równe \c GG_STATE_ERROR, a kod błędu - * znajdzie się w polu \c error. - * - * \param h Struktura połączenia - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -int gg_pubdir_watch_fd(struct gg_http *h) -{ - struct gg_pubdir *p; - char *tmp; - - if (!h) { - errno = EFAULT; - return -1; - } - - if (h->state == GG_STATE_ERROR) { - gg_debug(GG_DEBUG_MISC, "=> pubdir, watch_fd issued on failed session\n"); - errno = EINVAL; - return -1; - } - - if (h->state != GG_STATE_PARSING) { - if (gg_http_watch_fd(h) == -1) { - gg_debug(GG_DEBUG_MISC, "=> pubdir, http failure\n"); - errno = EINVAL; - return -1; - } - } - - if (h->state != GG_STATE_PARSING) - return 0; - - h->state = GG_STATE_DONE; - - if (!(h->data = p = malloc(sizeof(struct gg_pubdir)))) { - gg_debug(GG_DEBUG_MISC, "=> pubdir, not enough memory for results\n"); - return -1; - } - - p->success = 0; - p->uin = 0; - - gg_debug(GG_DEBUG_MISC, "=> pubdir, let's parse \"%s\"\n", h->body); - - if ((tmp = strstr(h->body, "Tokens okregisterreply_packet.reg.dwUserId="))) { - p->success = 1; - p->uin = strtol(tmp + sizeof("Tokens okregisterreply_packet.reg.dwUserId=") - 1, NULL, 0); - p->error = GG_PUBDIR_ERROR_NONE; - gg_debug(GG_DEBUG_MISC, "=> pubdir, success (okregisterreply, uin=%d)\n", p->uin); - } else if ((tmp = strstr(h->body, "success")) || (tmp = strstr(h->body, "results"))) { - p->success = 1; - if (tmp[7] == ':') - p->uin = strtol(tmp + 8, NULL, 0); - p->error = GG_PUBDIR_ERROR_NONE; - gg_debug(GG_DEBUG_MISC, "=> pubdir, success (uin=%d)\n", p->uin); - } else if (strncmp(h->body, "error1", 6) == 0 || strncmp(h->body, "error3", 6) == 0) { - p->error = GG_PUBDIR_ERROR_NEW_PASSWORD; - gg_debug(GG_DEBUG_MISC, "=> pubdir, invalid new password\n"); - } else if (strncmp(h->body, "not authenticated", 17) == 0) { - p->error = GG_PUBDIR_ERROR_OLD_PASSWORD; - gg_debug(GG_DEBUG_MISC, "=> pubdir, invalid old password\n"); - } else if (strncmp(h->body, "bad_tokenval", 12) == 0) { - p->error = GG_PUBDIR_ERROR_TOKEN; - gg_debug(GG_DEBUG_MISC, "=> pubdir, invalid token\n"); - } else { - p->error = GG_PUBDIR_ERROR_OTHER; - gg_debug(GG_DEBUG_MISC, "=> pubdir, unknown error\n"); - } - - return 0; -} - -/** - * Zwalnia zasoby po operacji na katalogu publicznym. - * - * \param h Struktura połączenia - */ -void gg_pubdir_free(struct gg_http *h) -{ - if (!h) - return; - - free(h->data); - gg_http_free(h); -} - -/** - * Pobiera token do autoryzacji operacji na katalogu publicznym. - * - * Token jest niezbędny do tworzenia nowego i usuwania użytkownika, - * zmiany hasła itd. - * - * \param async Flaga połączenia asynchronicznego - * - * \return Struktura \c gg_http lub \c NULL w przypadku błędu - * - * \ingroup token - */ -struct gg_http *gg_token(int async) -{ - struct gg_http *h; - const char *query; - - query = "Host: " GG_REGISTER_HOST "\r\n" - "Content-Type: application/x-www-form-urlencoded\r\n" - "User-Agent: " GG_HTTP_USERAGENT "\r\n" - "Content-Length: 0\r\n" - "Pragma: no-cache\r\n" - "\r\n"; - - if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, "POST", "/appsvc/regtoken.asp", query))) { - gg_debug(GG_DEBUG_MISC, "=> token, gg_http_connect() failed mysteriously\n"); - return NULL; - } - - h->type = GG_SESSION_TOKEN; - - h->callback = gg_token_watch_fd; - h->destroy = gg_token_free; - - if (!async) - gg_token_watch_fd(h); - - return h; -} - -/** - * Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze połączenia. - * - * Operacja będzie zakończona, gdy pole \c state będzie równe \c GG_STATE_DONE. - * Jeśli wystąpi błąd, \c state będzie równe \c GG_STATE_ERROR, a kod błędu - * znajdzie się w polu \c error. - * - * \param h Struktura połączenia - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup token - */ -int gg_token_watch_fd(struct gg_http *h) -{ - if (!h) { - errno = EFAULT; - return -1; - } - - if (h->state == GG_STATE_ERROR) { - gg_debug(GG_DEBUG_MISC, "=> token, watch_fd issued on failed session\n"); - errno = EINVAL; - return -1; - } - - if (h->state != GG_STATE_PARSING) { - if (gg_http_watch_fd(h) == -1) { - gg_debug(GG_DEBUG_MISC, "=> token, http failure\n"); - errno = EINVAL; - return -1; - } - } - - if (h->state != GG_STATE_PARSING) - return 0; - - /* jeśli h->data jest puste, to ściągaliśmy tokenid i url do niego, - * ale jeśli coś tam jest, to znaczy, że mamy drugi etap polegający - * na pobieraniu tokenu. */ - if (!h->data) { - int width, height, length; - char *url = NULL, *tokenid = NULL, *path, *headers; - const char *host; - struct gg_http *h2; - struct gg_token *t; - size_t results_len; - - gg_debug(GG_DEBUG_MISC, "=> token body \"%s\"\n", h->body); - - results_len = h->body ? strlen(h->body) : 0; - - if (h->body && (!(url = malloc(results_len)) || !(tokenid = malloc(results_len)))) { - gg_debug(GG_DEBUG_MISC, "=> token, not enough memory for results\n"); - free(url); - return -1; - } - - if (!h->body || sscanf(h->body, "%d %d %d\r\n%s\r\n%s", &width, &height, &length, tokenid, url) != 5) { - gg_debug(GG_DEBUG_MISC, "=> token, parsing failed\n"); - free(url); - free(tokenid); - errno = EINVAL; - return -1; - } - - /* dostaliśmy tokenid i wszystkie niezbędne informacje, - * więc pobierzmy obrazek z tokenem */ - - if (strncmp(url, "http://", 7)) { - path = gg_saprintf("%s?tokenid=%s", url, tokenid); - host = GG_REGISTER_HOST; - } else { - char *slash = strchr(url + 7, '/'); - - if (slash) { - path = gg_saprintf("%s?tokenid=%s", slash, tokenid); - *slash = 0; - host = url + 7; - } else { - gg_debug(GG_DEBUG_MISC, "=> token, url parsing failed\n"); - free(url); - free(tokenid); - errno = EINVAL; - return -1; - } - } - - if (!path) { - gg_debug(GG_DEBUG_MISC, "=> token, not enough memory for token url\n"); - free(url); - free(tokenid); - return -1; - } - - if (!(headers = gg_saprintf("Host: %s\r\nUser-Agent: " GG_HTTP_USERAGENT "\r\n\r\n", host))) { - gg_debug(GG_DEBUG_MISC, "=> token, not enough memory for token url\n"); - free(path); - free(url); - free(tokenid); - return -1; - } - - if (!(h2 = gg_http_connect(host, GG_REGISTER_PORT, h->async, "GET", path, headers))) { - gg_debug(GG_DEBUG_MISC, "=> token, gg_http_connect() failed mysteriously\n"); - free(headers); - free(url); - free(path); - free(tokenid); - return -1; - } - - free(headers); - free(path); - free(url); - - gg_http_free_fields(h); - - memcpy(h, h2, sizeof(struct gg_http)); - free(h2); - - h->type = GG_SESSION_TOKEN; - - h->callback = gg_token_watch_fd; - h->destroy = gg_token_free; - - if (!h->async) - gg_token_watch_fd(h); - - if (!(h->data = t = malloc(sizeof(struct gg_token)))) { - gg_debug(GG_DEBUG_MISC, "=> token, not enough memory for token data\n"); - free(tokenid); - return -1; - } - - t->width = width; - t->height = height; - t->length = length; - t->tokenid = tokenid; - } else { - /* obrazek mamy w h->body */ - h->state = GG_STATE_DONE; - } - - return 0; -} - -/** - * Zwalnia zasoby po operacji pobierania tokenu. - * - * \param h Struktura połączenia - * - * \ingroup token - */ -void gg_token_free(struct gg_http *h) -{ - struct gg_token *t; - - if (!h) - return; - - if ((t = h->data)) - free(t->tokenid); - - free(h->data); - gg_http_free(h); -} - -/* - * Local variables: - * c-indentation-style: k&r - * c-basic-offset: 8 - * indent-tabs-mode: notnil - * End: - * - * vim: shiftwidth=8: - */
--- a/libpurple/protocols/gg/lib/pubdir50.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,555 +0,0 @@ -/* - * (C) Copyright 2003 Wojtek Kaniewski <wojtekka@irc.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file pubdir50.c - * - * \brief Obsługa katalogu publicznego od wersji Gadu-Gadu 5.x - * - * \todo Zoptymalizować konwersję CP1250<->UTF8. Obecnie robiona jest - * testowa konwersja, żeby poznać długość tekstu wynikowego. - */ - -#include "network.h" -#include "strman.h" -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#include "libgadu.h" -#include "internal.h" -#include "encoding.h" - -/** - * Tworzy nowe zapytanie katalogu publicznego. - * - * \param type Rodzaj zapytania - * - * \return Zmienna \c gg_pubdir50_t lub \c NULL w przypadku błędu. - * - * \ingroup pubdir50 - */ -gg_pubdir50_t gg_pubdir50_new(int type) -{ - gg_pubdir50_t res = malloc(sizeof(struct gg_pubdir50_s)); - - gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_new(%d);\n", type); - - if (!res) { - gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_new() out of memory\n"); - return NULL; - } - - memset(res, 0, sizeof(struct gg_pubdir50_s)); - - res->type = type; - - return res; -} - -/** - * \internal Dodaje lub zastępuje pole zapytania lub odpowiedzi katalogu - * publicznego. - * - * \param req Zapytanie lub odpowiedź - * \param num Numer wyniku odpowiedzi (0 dla zapytania) - * \param field Nazwa pola - * \param value Wartość pola - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -static int gg_pubdir50_add_n(gg_pubdir50_t req, int num, const char *field, const char *value) -{ - struct gg_pubdir50_entry *tmp = NULL, *entry; - char *dupfield, *dupvalue; - int i; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_add_n(%p, %d, \"%s\", \"%s\");\n", req, num, field, value); - - if (!(dupvalue = strdup(value))) { - gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_add_n() out of memory\n"); - return -1; - } - - for (i = 0; i < req->entries_count; i++) { - if (req->entries[i].num != num || strcmp(req->entries[i].field, field)) - continue; - - free(req->entries[i].value); - req->entries[i].value = dupvalue; - - return 0; - } - - if (!(dupfield = strdup(field))) { - gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_add_n() out of memory\n"); - free(dupvalue); - return -1; - } - - if (!(tmp = realloc(req->entries, sizeof(struct gg_pubdir50_entry) * (req->entries_count + 1)))) { - gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_add_n() out of memory\n"); - free(dupfield); - free(dupvalue); - return -1; - } - - req->entries = tmp; - - entry = &req->entries[req->entries_count]; - entry->num = num; - entry->field = dupfield; - entry->value = dupvalue; - - req->entries_count++; - - return 0; -} - -/** - * Dodaje pole zapytania. - * - * \param req Zapytanie - * \param field Nazwa pola - * \param value Wartość pola - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup pubdir50 - */ -int gg_pubdir50_add(gg_pubdir50_t req, const char *field, const char *value) -{ - return gg_pubdir50_add_n(req, 0, field, value); -} - -/** - * Ustawia numer sekwencyjny zapytania. - * - * \param req Zapytanie - * \param seq Numer sekwencyjny - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - * - * \ingroup pubdir50 - */ -int gg_pubdir50_seq_set(gg_pubdir50_t req, uint32_t seq) -{ - gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_seq_set(%p, %d);\n", req, seq); - - if (!req) { - gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_seq_set() invalid arguments\n"); - errno = EFAULT; - return -1; - } - - req->seq = seq; - - return 0; -} - -/** - * Zwalnia zasoby po zapytaniu lub odpowiedzi katalogu publicznego. - * - * \param s Zapytanie lub odpowiedź - * - * \ingroup pubdir50 - */ -void gg_pubdir50_free(gg_pubdir50_t s) -{ - int i; - - if (!s) - return; - - for (i = 0; i < s->entries_count; i++) { - free(s->entries[i].field); - free(s->entries[i].value); - } - - free(s->entries); - free(s); -} - -/** - * Wysyła zapytanie katalogu publicznego do serwera. - * - * \param sess Struktura sesji - * \param req Zapytanie - * - * \return Numer sekwencyjny zapytania lub 0 w przypadku błędu - * - * \ingroup pubdir50 - */ -uint32_t gg_pubdir50(struct gg_session *sess, gg_pubdir50_t req) -{ - int i, size = 5; - uint32_t res; - char *buf, *p; - struct gg_pubdir50_request *r; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_pubdir50(%p, %p);\n", sess, req); - - if (!sess || !req) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_pubdir50() invalid arguments\n"); - errno = EFAULT; - return 0; - } - - if (sess->state != GG_STATE_CONNECTED) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_pubdir50() not connected\n"); - errno = ENOTCONN; - return 0; - } - - for (i = 0; i < req->entries_count; i++) { - /* wyszukiwanie bierze tylko pierwszy wpis */ - if (req->entries[i].num) - continue; - - if (sess->encoding == GG_ENCODING_CP1250) { - size += strlen(req->entries[i].field) + 1; - size += strlen(req->entries[i].value) + 1; - } else { - char *tmp; - - /* XXX \todo zoptymalizować */ - tmp = gg_encoding_convert(req->entries[i].field, sess->encoding, GG_ENCODING_CP1250, -1, -1); - - if (tmp == NULL) - return -1; - - size += strlen(tmp) + 1; - - free(tmp); - - /* XXX \todo zoptymalizować */ - tmp = gg_encoding_convert(req->entries[i].value, sess->encoding, GG_ENCODING_CP1250, -1, -1); - - if (tmp == NULL) - return -1; - - size += strlen(tmp) + 1; - - free(tmp); - } - } - - if (!(buf = malloc(size))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_pubdir50() out of memory (%d bytes)\n", size); - return 0; - } - - if (!req->seq) - req->seq = time(NULL); - - res = req->seq; - - r = (struct gg_pubdir50_request*) buf; - r->type = req->type; - r->seq = gg_fix32(req->seq); - - for (i = 0, p = buf + 5; i < req->entries_count; i++) { - if (req->entries[i].num) - continue; - - if (sess->encoding == GG_ENCODING_CP1250) { - strcpy(p, req->entries[i].field); - p += strlen(p) + 1; - - strcpy(p, req->entries[i].value); - p += strlen(p) + 1; - } else { - char *tmp; - - /* XXX \todo zoptymalizować */ - tmp = gg_encoding_convert(req->entries[i].field, sess->encoding, GG_ENCODING_CP1250, -1, -1); - - if (tmp == NULL) { - free(buf); - return -1; - } - - strcpy(p, tmp); - p += strlen(tmp) + 1; - free(tmp); - - /* XXX \todo zoptymalizować */ - tmp = gg_encoding_convert(req->entries[i].value, sess->encoding, GG_ENCODING_CP1250, -1, -1); - - - if (tmp == NULL) { - free(buf); - return -1; - } - - strcpy(p, tmp); - p += strlen(tmp) + 1; - free(tmp); - } - } - - if (gg_send_packet(sess, GG_PUBDIR50_REQUEST, buf, size, NULL, 0) == -1) - res = 0; - - free(buf); - - return res; -} - -/* - * \internal Analizuje przychodzący pakiet odpowiedzi i zapisuje wynik - * w strukturze \c gg_event. - * - * \param sess Struktura sesji - * \param e Struktura zdarzenia - * \param packet Pakiet odpowiedzi - * \param length Długość pakietu odpowiedzi - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -int gg_pubdir50_handle_reply_sess(struct gg_session *sess, struct gg_event *e, const char *packet, int length) -{ - const char *end = packet + length, *p; - const struct gg_pubdir50_reply *r = (const struct gg_pubdir50_reply*) packet; - gg_pubdir50_t res; - int num = 0; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_handle_reply_sess(%p, %p, %p, %d);\n", sess, e, packet, length); - - if (!sess || !e || !packet) { - gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_handle_reply() invalid arguments\n"); - errno = EFAULT; - return -1; - } - - if (length < 5) { - gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_handle_reply() packet too short\n"); - errno = EINVAL; - return -1; - } - - if (!(res = gg_pubdir50_new(r->type))) { - gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_handle_reply() unable to allocate reply\n"); - return -1; - } - - e->event.pubdir50 = res; - - res->seq = gg_fix32(r->seq); - - switch (res->type) { - case GG_PUBDIR50_READ: - e->type = GG_EVENT_PUBDIR50_READ; - break; - - case GG_PUBDIR50_WRITE: - e->type = GG_EVENT_PUBDIR50_WRITE; - break; - - default: - e->type = GG_EVENT_PUBDIR50_SEARCH_REPLY; - break; - } - - /* brak wyników? */ - if (length == 5) - return 0; - - /* pomiń początek odpowiedzi */ - p = packet + 5; - - while (p < end) { - const char *field, *value; - - field = p; - - /* sprawdź, czy nie mamy podziału na kolejne pole */ - if (!*field) { - num++; - field++; - } - - value = NULL; - - for (p = field; p < end; p++) { - /* jeśli mamy koniec tekstu... */ - if (!*p) { - /* ...i jeszcze nie mieliśmy wartości pola to - * wiemy, że po tym zerze jest wartość... */ - if (!value) - value = p + 1; - else - /* ...w przeciwym wypadku koniec - * wartości i możemy wychodzić - * grzecznie z pętli */ - break; - } - } - - /* sprawdźmy, czy pole nie wychodzi poza pakiet, żeby nie - * mieć segfaultów, jeśli serwer przestanie zakańczać pakietów - * przez \0 */ - - if (p == end) { - gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_handle_reply() premature end of packet\n"); - goto failure; - } - - p++; - - /* jeśli dostaliśmy namier na następne wyniki, to znaczy że - * mamy koniec wyników i nie jest to kolejna osoba. */ - if (!strcasecmp(field, "nextstart")) { - res->next = value ? atoi(value) : 0; - num--; - } else { - if (sess->encoding == GG_ENCODING_CP1250) { - if (gg_pubdir50_add_n(res, num, field, value) == -1) - goto failure; - } else { - char *tmp; - - tmp = gg_encoding_convert(value, GG_ENCODING_CP1250, sess->encoding, -1, -1); - - if (tmp == NULL) - goto failure; - - if (gg_pubdir50_add_n(res, num, field, tmp) == -1) { - free(tmp); - goto failure; - } - - free(tmp); - } - } - } - - res->count = num + 1; - - return 0; - -failure: - gg_pubdir50_free(res); - return -1; -} - -/** - * Pobiera pole z odpowiedzi katalogu publicznego. - * - * \param res Odpowiedź - * \param num Numer wyniku odpowiedzi - * \param field Nazwa pola (wielkość liter nie ma znaczenia) - * - * \return Wartość pola lub \c NULL jeśli nie znaleziono - * - * \ingroup pubdir50 - */ -const char *gg_pubdir50_get(gg_pubdir50_t res, int num, const char *field) -{ - char *value = NULL; - int i; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_get(%p, %d, \"%s\");\n", res, num, field); - - if (!res || num < 0 || !field) { - gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_get() invalid arguments\n"); - errno = EINVAL; - return NULL; - } - - for (i = 0; i < res->entries_count; i++) { - if (res->entries[i].num == num && !strcasecmp(res->entries[i].field, field)) { - value = res->entries[i].value; - break; - } - } - - return value; -} - -/** - * Zwraca liczbę wyników odpowiedzi. - * - * \param res Odpowiedź - * - * \return Liczba wyników lub -1 w przypadku błędu - * - * \ingroup pubdir50 - */ -int gg_pubdir50_count(gg_pubdir50_t res) -{ - return (!res) ? -1 : res->count; -} - -/** - * Zwraca rodzaj zapytania lub odpowiedzi. - * - * \param res Zapytanie lub odpowiedź - * - * \return Rodzaj lub -1 w przypadku błędu - * - * \ingroup pubdir50 - */ -int gg_pubdir50_type(gg_pubdir50_t res) -{ - return (!res) ? -1 : res->type; -} - -/** - * Zwraca numer, od którego należy rozpocząc kolejne wyszukiwanie. - * - * Dłuższe odpowiedzi katalogu publicznego są wysyłane przez serwer - * w mniejszych paczkach. Po otrzymaniu odpowiedzi, jeśli numer kolejnego - * wyszukiwania jest większy od zera, dalsze wyniki można otrzymać przez - * wywołanie kolejnego zapytania z określonym numerem początkowym. - * - * \param res Odpowiedź - * - * \return Numer lub -1 w przypadku błędu - * - * \ingroup pubdir50 - */ -uin_t gg_pubdir50_next(gg_pubdir50_t res) -{ - return (!res) ? (unsigned) -1 : res->next; -} - -/** - * Zwraca numer sekwencyjny zapytania lub odpowiedzi. - * - * \param res Zapytanie lub odpowiedź - * - * \return Numer sekwencyjny lub -1 w przypadku błędu - * - * \ingroup pubdir50 - */ -uint32_t gg_pubdir50_seq(gg_pubdir50_t res) -{ - return (!res) ? (unsigned) -1 : res->seq; -} - -/* - * Local variables: - * c-indentation-style: k&r - * c-basic-offset: 8 - * indent-tabs-mode: notnil - * End: - * - * vim: shiftwidth=8: - */
--- a/libpurple/protocols/gg/lib/resolver.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1132 +0,0 @@ -/* - * (C) Copyright 2001-2009 Wojtek Kaniewski <wojtekka@irc.pl> - * Robert J. Woźny <speedy@ziew.org> - * Arkadiusz Miśkiewicz <arekm@pld-linux.org> - * Tomasz Chiliński <chilek@chilan.com> - * Adam Wysocki <gophi@ekg.chmurka.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file resolver.c - * - * \brief Funkcje rozwiązywania nazw - */ - -#include <errno.h> -#include <stdlib.h> -#include <string.h> - -#include "strman.h" -#include "network.h" -#include "config.h" -#include "libgadu.h" -#include "resolver.h" -#include "session.h" - -#ifdef GG_CONFIG_HAVE_FORK -#include <sys/wait.h> -#include <signal.h> -#endif - -/** Sposób rozwiązywania nazw serwerów */ -static gg_resolver_t gg_global_resolver_type = GG_RESOLVER_DEFAULT; - -/** Funkcja rozpoczynająca rozwiązywanie nazwy */ -static int (*gg_global_resolver_start)(int *fd, void **private_data, const char *hostname); - -/** Funkcja zwalniająca zasoby po rozwiązaniu nazwy */ -static void (*gg_global_resolver_cleanup)(void **private_data, int force); - -#ifdef GG_CONFIG_HAVE_PTHREAD - -#include <pthread.h> - -/** - * \internal Funkcja pomocnicza zwalniająca zasoby po rozwiązywaniu nazwy - * w wątku. - * - * \note Funkcja nie powinna być statyczna, ponieważ zostanie potraktowana - * jako inline i kompilator może "zoptymalizować" jej wywołanie w funkcji - * pthread_cleanup_pop(). - * - * \param data Wskaźnik na wskaźnik bufora zaalokowanego w wątku - */ -void gg_resolver_cleaner(void *data) -{ - void **buf_ptr = (void **) data; - - if (buf_ptr != NULL) { - free(*buf_ptr); - *buf_ptr = NULL; - } -} - -#endif /* GG_CONFIG_HAVE_PTHREAD */ - -/** - * \internal Odpowiednik \c gethostbyname zapewniający współbieżność. - * - * Jeśli dany system dostarcza \c gethostbyname_r, używa się tej wersji, jeśli - * nie, to zwykłej \c gethostbyname. Wynikiem jest tablica adresów zakończona - * wartością INADDR_NONE, którą należy zwolnić po użyciu. - * - * \param hostname Nazwa serwera - * \param result Wskaźnik na wskaźnik z tablicą adresów zakończoną INADDR_NONE - * \param count Wskaźnik na zmienną, do ktorej zapisze się liczbę wyników - * \param pthread Flaga blokowania unicestwiania wątku podczas alokacji pamięci - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -int gg_gethostbyname_real(const char *hostname, struct in_addr **result, unsigned int *count, int pthread) -{ -#ifdef GG_CONFIG_HAVE_GETHOSTBYNAME_R - char *buf = NULL; - char *new_buf = NULL; - struct hostent he; - struct hostent *he_ptr = NULL; - size_t buf_len = 1024; - int res = -1; - int h_errnop; - int ret = 0; -#ifdef GG_CONFIG_HAVE_PTHREAD - int old_state; -#endif - - if (result == NULL) { - errno = EINVAL; - return -1; - } - -#ifdef GG_CONFIG_HAVE_PTHREAD - pthread_cleanup_push(gg_resolver_cleaner, &buf); - - if (pthread) - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state); -#endif - - buf = malloc(buf_len); - -#ifdef GG_CONFIG_HAVE_PTHREAD - if (pthread) - pthread_setcancelstate(old_state, NULL); -#endif - - if (buf != NULL) { - while (1) { -#ifndef sun - ret = gethostbyname_r(hostname, &he, buf, buf_len, &he_ptr, &h_errnop); - if (ret != ERANGE) - break; -#else - he_ptr = gethostbyname_r(hostname, &he, buf, buf_len, &h_errnop); - if (he_ptr != NULL || errno != ERANGE) - break; -#endif - - buf_len *= 2; - -#ifdef GG_CONFIG_HAVE_PTHREAD - if (pthread) - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state); -#endif - - new_buf = realloc(buf, buf_len); - - if (new_buf != NULL) - buf = new_buf; - -#ifdef GG_CONFIG_HAVE_PTHREAD - if (pthread) - pthread_setcancelstate(old_state, NULL); -#endif - - if (new_buf == NULL) { - ret = ENOMEM; - break; - } - } - - if (ret == 0 && he_ptr != NULL && he_ptr->h_addr_list[0] != NULL) { - int i; - - /* Policz liczbę adresów */ - - for (i = 0; he_ptr->h_addr_list[i] != NULL; i++); - - /* Zaalokuj */ - -#ifdef GG_CONFIG_HAVE_PTHREAD - if (pthread) - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state); -#endif - - *result = malloc((i + 1) * sizeof(struct in_addr)); - -#ifdef GG_CONFIG_HAVE_PTHREAD - if (pthread) - pthread_setcancelstate(old_state, NULL); -#endif - - if (*result != NULL) { - /* Kopiuj */ - - for (i = 0; he_ptr->h_addr_list[i] != NULL; i++) - memcpy(&((*result)[i]), he_ptr->h_addr_list[i], sizeof(struct in_addr)); - - (*result)[i].s_addr = INADDR_NONE; - - *count = i; - - res = 0; - } else - res = -1; - } - -#ifdef GG_CONFIG_HAVE_PTHREAD - if (pthread) - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state); -#endif - - free(buf); - buf = NULL; - -#ifdef GG_CONFIG_HAVE_PTHREAD - if (pthread) - pthread_setcancelstate(old_state, NULL); -#endif - } - -#ifdef GG_CONFIG_HAVE_PTHREAD - pthread_cleanup_pop(0); -#endif - - return res; -#else /* GG_CONFIG_HAVE_GETHOSTBYNAME_R */ - struct hostent *he; - int i; -#ifdef GG_CONFIG_HAVE_PTHREAD - int old_state; -#endif - - if (result == NULL || count == NULL) { - errno = EINVAL; - return -1; - } - - he = gethostbyname(hostname); - - if (he == NULL || he->h_addr_list[0] == NULL) - return -1; - - /* Policz liczbę adresów */ - - for (i = 0; he->h_addr_list[i] != NULL; i++); - - /* Zaalokuj */ - -#ifdef GG_CONFIG_HAVE_PTHREAD - if (pthread) - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state); -#endif - - *result = malloc((i + 1) * sizeof(struct in_addr)); - -#ifdef GG_CONFIG_HAVE_PTHREAD - if (pthread) - pthread_setcancelstate(old_state, NULL); -#endif - - if (*result == NULL) - return -1; - - /* Kopiuj */ - - for (i = 0; he->h_addr_list[i] != NULL; i++) - memcpy(&((*result)[i]), he->h_addr_list[i], sizeof(struct in_addr)); - - (*result)[i].s_addr = INADDR_NONE; - - *count = i; - - return 0; -#endif /* GG_CONFIG_HAVE_GETHOSTBYNAME_R */ -} - -/** - * \internal Rozwiązuje nazwę i zapisuje wynik do podanego gniazda. - * - * \note Użycie logowania w tej funkcji może mieć negatywny wpływ na - * aplikacje jednowątkowe korzystające. - * - * \param fd Deskryptor gniazda - * \param hostname Nazwa serwera - * \param pthread Flaga blokowania unicestwiania wątku podczas alokacji pamięci - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -static int gg_resolver_run(int fd, const char *hostname, int pthread) -{ - struct in_addr addr_ip[2], *addr_list = NULL; - unsigned int addr_count; - int res = 0; -#ifdef GG_CONFIG_HAVE_PTHREAD - int old_state; -#endif - -#ifdef GG_CONFIG_HAVE_PTHREAD - pthread_cleanup_push(gg_resolver_cleaner, &addr_list); -#endif - - if ((addr_ip[0].s_addr = inet_addr(hostname)) == INADDR_NONE) { - if (gg_gethostbyname_real(hostname, &addr_list, &addr_count, pthread) == -1) { -#ifdef GG_CONFIG_HAVE_PTHREAD - if (pthread) - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state); -#endif - - free(addr_list); - addr_list = NULL; - -#ifdef GG_CONFIG_HAVE_PTHREAD - if (pthread) - pthread_setcancelstate(old_state, NULL); -#endif - - addr_count = 0; - /* addr_ip[0] już zawiera INADDR_NONE */ - } - } else { - addr_ip[1].s_addr = INADDR_NONE; - addr_count = 1; - } - - if (send(fd, addr_list != NULL ? addr_list : addr_ip, - (addr_count + 1) * sizeof(struct in_addr), 0) != - (int)((addr_count + 1) * sizeof(struct in_addr))) - { - res = -1; - } - -#ifdef GG_CONFIG_HAVE_PTHREAD - if (pthread) - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state); -#endif - - free(addr_list); - addr_list = NULL; - -#ifdef GG_CONFIG_HAVE_PTHREAD - if (pthread) - pthread_setcancelstate(old_state, NULL); - - pthread_cleanup_pop(0); -#endif - - return res; -} - -/** - * \internal Odpowiednik \c gethostbyname zapewniający współbieżność. - * - * Jeśli dany system dostarcza \c gethostbyname_r, używa się tej wersji, jeśli - * nie, to zwykłej \c gethostbyname. Funkcja służy do zachowania zgodności - * ABI i służy do pobierania tylko pierwszego adresu -- pozostałe mogą - * zostać zignorowane przez aplikację. - * - * \param hostname Nazwa serwera - * - * \return Zaalokowana struktura \c in_addr lub NULL w przypadku błędu. - */ -struct in_addr *gg_gethostbyname(const char *hostname) -{ - struct in_addr *result; - unsigned int count; - - if (gg_gethostbyname_real(hostname, &result, &count, 0) == -1) - return NULL; - - return result; -} - -#ifdef GG_CONFIG_HAVE_FORK - -/** - * \internal Struktura przekazywana do wątku rozwiązującego nazwę. - */ -struct gg_resolver_fork_data { - int pid; /*< Identyfikator procesu */ -}; - -/** - * \internal Rozwiązuje nazwę serwera w osobnym procesie. - * - * Połączenia asynchroniczne nie mogą blokować procesu w trakcie rozwiązywania - * nazwy serwera. W tym celu tworzona jest para gniazd, nowy proces i dopiero - * w nim przeprowadzane jest rozwiązywanie nazwy. Deskryptor gniazda do odczytu - * zapisuje się w strukturze sieci i czeka na dane w postaci struktury - * \c in_addr. Jeśli nie znaleziono nazwy, zwracana jest \c INADDR_NONE. - * - * \param fd Wskaźnik na zmienną, gdzie zostanie umieszczony deskryptor gniazda - * \param priv_data Wskaźnik na zmienną, gdzie zostanie umieszczony wskaźnik - * do numeru procesu potomnego rozwiązującego nazwę - * \param hostname Nazwa serwera do rozwiązania - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -static int gg_resolver_fork_start(int *fd, void **priv_data, const char *hostname) -{ - struct gg_resolver_fork_data *data = NULL; - int pipes[2], new_errno; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_resolver_fork_start(%p, %p, \"%s\");\n", fd, priv_data, hostname); - - if (fd == NULL || priv_data == NULL || hostname == NULL) { - gg_debug(GG_DEBUG_MISC, "// gg_resolver_fork_start() invalid arguments\n"); - errno = EFAULT; - return -1; - } - - data = malloc(sizeof(struct gg_resolver_fork_data)); - - if (data == NULL) { - gg_debug(GG_DEBUG_MISC, "// gg_resolver_fork_start() out of memory for resolver data\n"); - return -1; - } - - if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipes) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_resolver_fork_start() unable " - "to create pipes (errno=%d, %s)\n", - errno, strerror(errno)); - free(data); - return -1; - } - - data->pid = fork(); - - if (data->pid == -1) { - new_errno = errno; - goto cleanup; - } - - if (data->pid == 0) { - int status; - - close(pipes[0]); - - status = (gg_resolver_run(pipes[1], hostname, 0) == -1) ? 1 : 0; - -#ifdef HAVE__EXIT - _exit(status); -#else - exit(status); -#endif - } - - close(pipes[1]); - - gg_debug(GG_DEBUG_MISC, "// gg_resolver_fork_start() %p\n", data); - - *fd = pipes[0]; - *priv_data = data; - - return 0; - -cleanup: - free(data); - close(pipes[0]); - close(pipes[1]); - - errno = new_errno; - - return -1; -} - -/** - * \internal Usuwanie zasobów po procesie rozwiązywaniu nazwy. - * - * Funkcja wywoływana po zakończeniu rozwiązanywania nazwy lub przy zwalnianiu - * zasobów sesji podczas rozwiązywania nazwy. - * - * \param priv_data Wskaźnik na zmienną przechowującą wskaźnik do prywatnych - * danych - * \param force Flaga usuwania zasobów przed zakończeniem działania - */ -static void gg_resolver_fork_cleanup(void **priv_data, int force) -{ - struct gg_resolver_fork_data *data; - - if (priv_data == NULL || *priv_data == NULL) - return; - - data = (struct gg_resolver_fork_data*) *priv_data; - *priv_data = NULL; - - if (force) - kill(data->pid, SIGKILL); - - /* we don't care about child's exit status, just want to clean it up */ - (void)waitpid(data->pid, NULL, WNOHANG); - - free(data); -} - -#endif /* GG_CONFIG_HAVE_FORK */ - -#ifdef GG_CONFIG_HAVE_PTHREAD - -/** - * \internal Struktura przekazywana do wątku rozwiązującego nazwę. - */ -struct gg_resolver_pthread_data { - pthread_t thread; /*< Identyfikator wątku */ - char *hostname; /*< Nazwa serwera */ - int wfd; /*< Deskryptor do zapisu */ -}; - -/** - * \internal Usuwanie zasobów po wątku rozwiązywaniu nazwy. - * - * Funkcja wywoływana po zakończeniu rozwiązanywania nazwy lub przy zwalnianiu - * zasobów sesji podczas rozwiązywania nazwy. - * - * \param priv_data Wskaźnik na zmienną przechowującą wskaźnik do prywatnych - * danych - * \param force Flaga usuwania zasobów przed zakończeniem działania - */ -static void gg_resolver_pthread_cleanup(void **priv_data, int force) -{ - struct gg_resolver_pthread_data *data; - - if (priv_data == NULL || *priv_data == NULL) - return; - - data = (struct gg_resolver_pthread_data *) *priv_data; - *priv_data = NULL; - - if (force) - pthread_cancel(data->thread); - - pthread_join(data->thread, NULL); - - close(data->wfd); - free(data->hostname); - free(data); -} - -/** - * \internal Wątek rozwiązujący nazwę. - * - * \param arg Wskaźnik na strukturę \c gg_resolver_pthread_data - */ -static void *gg_resolver_pthread_thread(void *arg) -{ - struct gg_resolver_pthread_data *data = arg; - - if (gg_resolver_run(data->wfd, data->hostname, 1) == -1) - pthread_exit((void*) -1); - else - pthread_exit(NULL); - - return NULL; /* żeby kompilator nie marudził */ -} - -/** - * \internal Rozwiązuje nazwę serwera w osobnym wątku. - * - * Funkcja działa analogicznie do \c gg_resolver_fork_start(), z tą różnicą, - * że działa na wątkach, nie procesach. Jest dostępna wyłącznie gdy podczas - * kompilacji włączono odpowiednią opcję. - * - * \param fd Wskaźnik na zmienną, gdzie zostanie umieszczony deskryptor gniazda - * \param priv_data Wskaźnik na zmienną, gdzie zostanie umieszczony wskaźnik - * do prywatnych danych wątku rozwiązującego nazwę - * \param hostname Nazwa serwera do rozwiązania - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -static int gg_resolver_pthread_start(int *fd, void **priv_data, const char *hostname) -{ - struct gg_resolver_pthread_data *data = NULL; - int pipes[2], new_errno; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_resolver_pthread_start(%p, %p, \"%s\");\n", fd, priv_data, hostname); - - if (fd == NULL || priv_data == NULL || hostname == NULL) { - gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() invalid arguments\n"); - errno = EFAULT; - return -1; - } - - data = malloc(sizeof(struct gg_resolver_pthread_data)); - - if (data == NULL) { - gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() out of memory for resolver data\n"); - return -1; - } - - if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipes) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() unable " - "to create pipes (errno=%d, %s)\n", - errno, strerror(errno)); - free(data); - return -1; - } - - data->hostname = strdup(hostname); - - if (data->hostname == NULL) { - gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() out of memory\n"); - new_errno = errno; - goto cleanup; - } - - data->wfd = pipes[1]; - - if (pthread_create(&data->thread, NULL, gg_resolver_pthread_thread, data)) { - gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() unable to create thread\n"); - new_errno = errno; - goto cleanup; - } - - gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() %p\n", data); - - *fd = pipes[0]; - *priv_data = data; - - return 0; - -cleanup: - if (data != NULL) - free(data->hostname); - - free(data); - - close(pipes[0]); - close(pipes[1]); - - errno = new_errno; - - return -1; -} - -#endif /* GG_CONFIG_HAVE_PTHREAD */ - -#ifdef _WIN32 - -/** - * \internal Struktura przekazywana do wątku rozwiązującego nazwę. - */ -struct gg_resolver_win32_data { - HANDLE thread; /*< Uchwyt wątku */ - CRITICAL_SECTION mutex; /*< Semafor wątku */ - char *hostname; /*< Nazwa serwera */ - int wfd; /*< Deskryptor do zapisu */ - int orphan; /*< Wątek powinien sam po sobie posprzątać */ - int finished; /*< Wątek już skończył pracę */ -}; - -/** - * \internal Wątek rozwiązujący nazwę. - * - * \param arg Wskaźnik na strukturę \c gg_resolver_win32_data - */ -static DWORD WINAPI gg_resolver_win32_thread(void *arg) -{ - struct gg_resolver_win32_data *data = arg; - int result, is_orphan; - - result = gg_resolver_run(data->wfd, data->hostname, 0); - - EnterCriticalSection(&data->mutex); - is_orphan = data->orphan; - data->finished = 1; - LeaveCriticalSection(&data->mutex); - - if (is_orphan) { - CloseHandle(data->thread); - DeleteCriticalSection(&data->mutex); - close(data->wfd); - free(data->hostname); - free(data); - } - - ExitThread(result); - return 0; /* żeby kompilator nie marudził */ -} - -/** - * \internal Rozwiązuje nazwę serwera w osobnym wątku. - * - * Funkcja działa analogicznie do \c gg_resolver_pthread_start(), z tą różnicą, - * że działa na wątkach Win32. Jest dostępna wyłącznie przy kompilacji dla - * systemu Windows. - * - * \param fd Wskaźnik na zmienną, gdzie zostanie umieszczony deskryptor gniazda - * \param priv_data Wskaźnik na zmienną, gdzie zostanie umieszczony wskaźnik - * do prywatnych danych wątku rozwiązującego nazwę - * \param hostname Nazwa serwera do rozwiązania - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -static int gg_resolver_win32_start(int *fd, void **priv_data, const char *hostname) -{ - struct gg_resolver_win32_data *data = NULL; - int pipes[2], new_errno; - CRITICAL_SECTION *mutex = NULL; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_resolver_win32_start(%p, %p, \"%s\");\n", fd, priv_data, hostname); - - if (fd == NULL || priv_data == NULL || hostname == NULL) { - gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() invalid arguments\n"); - errno = EFAULT; - return -1; - } - - data = malloc(sizeof(struct gg_resolver_win32_data)); - - if (data == NULL) { - gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() out of memory for resolver data\n"); - return -1; - } - - data->orphan = 0; - data->finished = 0; - - if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipes) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() unable to " - "create pipes (errno=%d, %s)\n", - errno, strerror(errno)); - free(data); - return -1; - } - - data->hostname = strdup(hostname); - - if (data->hostname == NULL) { - gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() out of memory\n"); - new_errno = errno; - goto cleanup; - } - - data->wfd = pipes[1]; - - mutex = &data->mutex; - InitializeCriticalSection(mutex); - - data->thread = CreateThread(NULL, 0, gg_resolver_win32_thread, data, 0, NULL); - if (!data->thread) { - gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() unable to create thread\n"); - new_errno = errno; - goto cleanup; - } - - gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() %p\n", data); - - *fd = pipes[0]; - *priv_data = data; - - return 0; - -cleanup: - if (data) { - free(data->hostname); - free(data); - } - - close(pipes[0]); - close(pipes[1]); - - if (mutex) - DeleteCriticalSection(mutex); - - errno = new_errno; - - return -1; -} - -/** - * \internal Usuwanie zasobów po wątku rozwiązywaniu nazwy. - * - * Funkcja wywoływana po zakończeniu rozwiązanywania nazwy lub przy zwalnianiu - * zasobów sesji podczas rozwiązywania nazwy. - * - * \param priv_data Wskaźnik na zmienną przechowującą wskaźnik do prywatnych - * danych - * \param force Flaga usuwania zasobów przed zakończeniem działania - */ -static void gg_resolver_win32_cleanup(void **priv_data, int force) -{ - struct gg_resolver_win32_data *data; - - if (priv_data == NULL || *priv_data == NULL) - return; - - data = (struct gg_resolver_win32_data *) *priv_data; - *priv_data = NULL; - - if (WaitForSingleObject(data->thread, 0) == WAIT_TIMEOUT) { - int finished; - /* We cannot call TerminateThread here - it doesn't - * release critical section locks (see MSDN docs). - * if (force) TerminateThread(data->thread, 0); - */ - EnterCriticalSection(&data->mutex); - finished = data->finished; - if (!finished) - data->orphan = 1; - LeaveCriticalSection(&data->mutex); - if (!finished) - return; - } - - CloseHandle(data->thread); - DeleteCriticalSection(&data->mutex); - close(data->wfd); - free(data->hostname); - free(data); -} - -#endif /* _WIN32 */ - -/** - * Ustawia sposób rozwiązywania nazw w sesji. - * - * \param gs Struktura sesji - * \param type Sposób rozwiązywania nazw (patrz \ref build-resolver) - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -int gg_session_set_resolver(struct gg_session *gs, gg_resolver_t type) -{ - GG_SESSION_CHECK(gs, -1); - - if (type == GG_RESOLVER_DEFAULT) { - if (gg_global_resolver_type != GG_RESOLVER_DEFAULT) { - gs->resolver_type = gg_global_resolver_type; - gs->resolver_start = gg_global_resolver_start; - gs->resolver_cleanup = gg_global_resolver_cleanup; - return 0; - } - -#ifdef GG_CONFIG_HAVE_PTHREAD - type = GG_RESOLVER_PTHREAD; -#elif defined(_WIN32) - type = GG_RESOLVER_WIN32; -#elif defined(GG_CONFIG_HAVE_FORK) - type = GG_RESOLVER_FORK; -#endif - } - - switch (type) { -#ifdef GG_CONFIG_HAVE_FORK - case GG_RESOLVER_FORK: - gs->resolver_type = type; - gs->resolver_start = gg_resolver_fork_start; - gs->resolver_cleanup = gg_resolver_fork_cleanup; - return 0; -#endif - -#ifdef GG_CONFIG_HAVE_PTHREAD - case GG_RESOLVER_PTHREAD: - gs->resolver_type = type; - gs->resolver_start = gg_resolver_pthread_start; - gs->resolver_cleanup = gg_resolver_pthread_cleanup; - return 0; -#endif - -#ifdef _WIN32 - case GG_RESOLVER_WIN32: - gs->resolver_type = type; - gs->resolver_start = gg_resolver_win32_start; - gs->resolver_cleanup = gg_resolver_win32_cleanup; - return 0; -#endif - - default: - errno = EINVAL; - return -1; - } -} - -/** - * Zwraca sposób rozwiązywania nazw w sesji. - * - * \param gs Struktura sesji - * - * \return Sposób rozwiązywania nazw - */ -gg_resolver_t gg_session_get_resolver(struct gg_session *gs) -{ - GG_SESSION_CHECK(gs, (gg_resolver_t) -1); - - return gs->resolver_type; -} - -/** - * Ustawia własny sposób rozwiązywania nazw w sesji. - * - * \param gs Struktura sesji - * \param resolver_start Funkcja rozpoczynająca rozwiązywanie nazwy - * \param resolver_cleanup Funkcja zwalniająca zasoby - * - * Parametry funkcji rozpoczynającej rozwiązywanie nazwy wyglądają następująco: - * - \c "int *fd" — wskaźnik na zmienną, gdzie zostanie umieszczony deskryptor gniazda - * - \c "void **priv_data" — wskaźnik na zmienną, gdzie można umieścić - * wskaźnik do prywatnych danych na potrzeby rozwiązywania nazwy - * - \c "const char *name" — nazwa serwera do rozwiązania - * - * Parametry funkcji zwalniającej zasoby wyglądają następująco: - * - \c "void **priv_data" — wskaźnik na zmienną przechowującą wskaźnik - * do prywatnych danych, należy go ustawić na \c NULL po zakończeniu - * - \c "int force" — flaga mówiąca o tym, że zasoby są zwalniane przed - * zakończeniem rozwiązywania nazwy, np. z powodu zamknięcia sesji. - * - * Własny kod rozwiązywania nazwy powinien stworzyć potok, parę gniazd lub - * inny deskryptor pozwalający na co najmniej odbiór danych i przekazać go - * w parametrze \c fd. Na platformie Windows możliwe jest przekazanie jedynie - * deskryptora gniazda. Po zakończeniu rozwiązywania nazwy powinien wysłać - * otrzymany adres IP w postaci sieciowej (big-endian) do deskryptora. Jeśli - * rozwiązywanie nazwy się nie powiedzie, należy wysłać \c INADDR_NONE. - * Następnie zostanie wywołana funkcja zwalniająca zasoby z parametrem - * \c force równym \c 0. Gdyby sesja została zakończona przed rozwiązaniem - * nazwy, np. za pomocą funkcji \c gg_logoff(), funkcja zwalniająca zasoby - * zostanie wywołana z parametrem \c force równym \c 1. - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -int gg_session_set_custom_resolver(struct gg_session *gs, - int (*resolver_start)(int*, void**, const char*), - void (*resolver_cleanup)(void**, int)) -{ - GG_SESSION_CHECK(gs, -1); - - if (resolver_start == NULL || resolver_cleanup == NULL) { - errno = EINVAL; - return -1; - } - - gs->resolver_type = GG_RESOLVER_CUSTOM; - gs->resolver_start = resolver_start; - gs->resolver_cleanup = resolver_cleanup; - - return 0; -} - -/** - * Ustawia sposób rozwiązywania nazw połączenia HTTP. - * - * \param gh Struktura połączenia - * \param type Sposób rozwiązywania nazw (patrz \ref build-resolver) - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -int gg_http_set_resolver(struct gg_http *gh, gg_resolver_t type) -{ - if (gh == NULL) { - errno = EINVAL; - return -1; - } - - if (type == GG_RESOLVER_DEFAULT) { - if (gg_global_resolver_type != GG_RESOLVER_DEFAULT) { - gh->resolver_type = gg_global_resolver_type; - gh->resolver_start = gg_global_resolver_start; - gh->resolver_cleanup = gg_global_resolver_cleanup; - return 0; - } - -#ifdef GG_CONFIG_HAVE_PTHREAD - type = GG_RESOLVER_PTHREAD; -#elif defined(_WIN32) - type = GG_RESOLVER_WIN32; -#elif defined(GG_CONFIG_HAVE_FORK) - type = GG_RESOLVER_FORK; -#endif - } - - switch (type) { -#ifdef GG_CONFIG_HAVE_FORK - case GG_RESOLVER_FORK: - gh->resolver_type = type; - gh->resolver_start = gg_resolver_fork_start; - gh->resolver_cleanup = gg_resolver_fork_cleanup; - return 0; -#endif - -#ifdef GG_CONFIG_HAVE_PTHREAD - case GG_RESOLVER_PTHREAD: - gh->resolver_type = type; - gh->resolver_start = gg_resolver_pthread_start; - gh->resolver_cleanup = gg_resolver_pthread_cleanup; - return 0; -#endif - -#ifdef _WIN32 - case GG_RESOLVER_WIN32: - gh->resolver_type = type; - gh->resolver_start = gg_resolver_win32_start; - gh->resolver_cleanup = gg_resolver_win32_cleanup; - return 0; -#endif - - default: - errno = EINVAL; - return -1; - } -} - -/** - * Zwraca sposób rozwiązywania nazw połączenia HTTP. - * - * \param gh Struktura połączenia - * - * \return Sposób rozwiązywania nazw - */ -gg_resolver_t gg_http_get_resolver(struct gg_http *gh) -{ - if (gh == NULL) { - errno = EINVAL; - return GG_RESOLVER_INVALID; - } - - return gh->resolver_type; -} - -/** - * Ustawia własny sposób rozwiązywania nazw połączenia HTTP. - * - * \param gh Struktura sesji - * \param resolver_start Funkcja rozpoczynająca rozwiązywanie nazwy - * \param resolver_cleanup Funkcja zwalniająca zasoby - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -int gg_http_set_custom_resolver(struct gg_http *gh, - int (*resolver_start)(int*, void**, const char*), - void (*resolver_cleanup)(void**, int)) -{ - if (gh == NULL || resolver_start == NULL || resolver_cleanup == NULL) { - errno = EINVAL; - return -1; - } - - gh->resolver_type = GG_RESOLVER_CUSTOM; - gh->resolver_start = resolver_start; - gh->resolver_cleanup = resolver_cleanup; - - return 0; -} - -/** - * Ustawia sposób rozwiązywania nazw globalnie dla biblioteki. - * - * \param type Sposób rozwiązywania nazw (patrz \ref build-resolver) - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -int gg_global_set_resolver(gg_resolver_t type) -{ - switch (type) { - case GG_RESOLVER_DEFAULT: - gg_global_resolver_type = type; - gg_global_resolver_start = NULL; - gg_global_resolver_cleanup = NULL; - return 0; - -#ifdef GG_CONFIG_HAVE_FORK - case GG_RESOLVER_FORK: - gg_global_resolver_type = type; - gg_global_resolver_start = gg_resolver_fork_start; - gg_global_resolver_cleanup = gg_resolver_fork_cleanup; - return 0; -#endif - -#ifdef GG_CONFIG_HAVE_PTHREAD - case GG_RESOLVER_PTHREAD: - gg_global_resolver_type = type; - gg_global_resolver_start = gg_resolver_pthread_start; - gg_global_resolver_cleanup = gg_resolver_pthread_cleanup; - return 0; -#endif - -#ifdef _WIN32 - case GG_RESOLVER_WIN32: - gg_global_resolver_type = type; - gg_global_resolver_start = gg_resolver_win32_start; - gg_global_resolver_cleanup = gg_resolver_win32_cleanup; - return 0; -#endif - - default: - errno = EINVAL; - return -1; - } -} - -/** - * Zwraca sposób rozwiązywania nazw globalnie dla biblioteki. - * - * \return Sposób rozwiązywania nazw - */ -gg_resolver_t gg_global_get_resolver(void) -{ - return gg_global_resolver_type; -} - -/** - * Ustawia własny sposób rozwiązywania nazw globalnie dla biblioteki. - * - * \param resolver_start Funkcja rozpoczynająca rozwiązywanie nazwy - * \param resolver_cleanup Funkcja zwalniająca zasoby - * - * Patrz \ref gg_session_set_custom_resolver. - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -int gg_global_set_custom_resolver( - int (*resolver_start)(int*, void**, const char*), - void (*resolver_cleanup)(void**, int)) -{ - if (resolver_start == NULL || resolver_cleanup == NULL) { - errno = EINVAL; - return -1; - } - - gg_global_resolver_type = GG_RESOLVER_CUSTOM; - gg_global_resolver_start = resolver_start; - gg_global_resolver_cleanup = resolver_cleanup; - - return 0; -} - -/** - * Odczytuje dane z procesu/wątku rozwiązywania nazw. - * - * \param fd Deskryptor - * \param buf Wskaźnik na bufor - * \param len Długość bufora - * - * \return Patrz recv() i read(). - */ -int gg_resolver_recv(int fd, void *buf, size_t len) -{ -#ifndef _WIN32 - return read(fd, buf, len); -#else - return recv(fd, buf, len, 0); -#endif -}
--- a/libpurple/protocols/gg/lib/resolver.h Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -/* - * (C) Copyright 2008 Wojtek Kaniewski <wojtekka@irc.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef LIBGADU_RESOLVER_H -#define LIBGADU_RESOLVER_H - -#include "network.h" - -int gg_gethostbyname_real(const char *hostname, struct in_addr **result, unsigned int *count, int pthread); -int gg_resolver_recv(int fd, void *buf, size_t len); -void gg_resolver_cleaner(void *data); - -#endif /* LIBGADU_RESOLVER_H */
--- a/libpurple/protocols/gg/lib/session.h Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* - * (C) Copyright 2008-2010 Wojtek Kaniewski <wojtekka@irc.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef LIBGADU_SESSION_H -#define LIBGADU_SESSION_H - -#ifdef GG_CONFIG_HAVE_GNUTLS -# include <gnutls/gnutls.h> -#endif - -#define GG_SESSION_CHECK(gs, result) \ - do { \ - if ((gs) == NULL) { \ - errno = EINVAL; \ - return (result); \ - } \ - } while (0) - -#define GG_SESSION_CHECK_CONNECTED(gs, result) \ - do { \ - GG_SESSION_CHECK(gs, result); \ - \ - if (!GG_SESSION_IS_CONNECTED(gs)) { \ - errno = ENOTCONN; \ - return (result); \ - } \ - } while (0) - -#define GG_SESSION_IS_IDLE(gs) ((gs)->state == GG_STATE_IDLE) -#define GG_SESSION_IS_CONNECTING(gs) ((gs)->state != GG_STATE_IDLE && (gs)->state != GG_STATE_CONNECTED) -#define GG_SESSION_IS_CONNECTED(gs) ((gs)->state == GG_STATE_CONNECTED) - -#ifdef GG_CONFIG_HAVE_GNUTLS - -typedef struct { - gnutls_session_t session; - gnutls_certificate_credentials_t xcred; -} gg_session_gnutls_t; - -#define GG_SESSION_GNUTLS(gs) ((gg_session_gnutls_t*) (gs)->ssl)->session - -#endif /* GG_CONFIG_HAVE_GNUTLS */ - -#ifdef GG_CONFIG_HAVE_OPENSSL - -#define GG_SESSION_OPENSSL(gs) ((SSL*) (gs)->ssl) - -#endif /* GG_CONFIG_HAVE_OPENSSL */ - -int gg_session_handle_packet(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge); - -#endif /* LIBGADU_SESSION_H */
--- a/libpurple/protocols/gg/lib/sha1.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,382 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2007 Wojtek Kaniewski <wojtekka@irc.pl> - * - * Public domain SHA-1 implementation by Steve Reid <steve@edmweb.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file sha1.c - * - * \brief Funkcje wyznaczania skrótu SHA1 - */ - -#include <errno.h> -#include <string.h> - -#include "libgadu.h" -#include "internal.h" -#include "fileio.h" -#include "config.h" - -/** \cond ignore */ - -#ifdef GG_CONFIG_HAVE_OPENSSL - -#include <openssl/sha.h> - -#elif defined(GG_CONFIG_HAVE_GNUTLS) - -#include <gnutls/gnutls.h> -#include <gnutls/crypto.h> - -#define SHA_CTX gnutls_hash_hd_t -#define SHA1_Init(ctx) (gnutls_hash_init((ctx), GNUTLS_DIG_SHA1) == 0 ? 1 : 0) -#define SHA1_Update(ctx, ptr, len) (gnutls_hash(*(ctx), (ptr), (len)) == 0 ? 1 : 0) -#define SHA1_Final(digest, ctx) (gnutls_hash_deinit(*(ctx), (digest)), 1) - -#else - -/* -SHA-1 in C -By Steve Reid <steve@edmweb.com> -100% Public Domain - -Modified by Wojtek Kaniewski <wojtekka@toxygen.net> for compatibility -with libgadu and OpenSSL API. - -Test Vectors (from FIPS PUB 180-1) -"abc" - A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D -"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" - 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 -A million repetitions of "a" - 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F -*/ - -/* #define LITTLE_ENDIAN * This should be #define'd if true. */ -/* #define SHA1HANDSOFF * Copies data before messing with it. */ - -typedef struct { - uint32_t state[5]; - uint32_t count[2]; - unsigned char buffer[64]; -} SHA_CTX; - -static void SHA1_Transform(uint32_t state[5], const unsigned char buffer[64]); -static int SHA1_Init(SHA_CTX* context); -static int SHA1_Update(SHA_CTX* context, const unsigned char* data, unsigned int len); -static int SHA1_Final(unsigned char digest[20], SHA_CTX* context); - -#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) - -/* blk0() and blk() perform the initial expand. */ -/* I got the idea of expanding during the round function from SSLeay */ -#ifndef GG_CONFIG_BIGENDIAN -#define blk0(i) (block.l[i] = (rol(block.l[i], 24) & 0xFF00FF00) \ - |(rol(block.l[i], 8) & 0x00FF00FF)) -#else -#define blk0(i) block.l[i] -#endif -#define blk(i) (block.l[i&15] = rol(block.l[(i+13)&15]^block.l[(i+8)&15] \ - ^block.l[(i+2)&15]^block.l[i&15], 1)) - -/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -/* style:comma:start-ignore */ -#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); -#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); -#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); -/* style:comma:end-ignore */ - - -/* Hash a single 512-bit block. This is the core of the algorithm. */ - -static void SHA1_Transform(uint32_t state[5], const unsigned char buffer[64]) -{ -uint32_t a, b, c, d, e; -typedef union { - unsigned char c[64]; - uint32_t l[16]; -} CHAR64LONG16; - CHAR64LONG16 block; - memcpy(&block, buffer, sizeof(block)); - /* Copy context->state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - /* 4 rounds of 20 operations each. Loop unrolled. */ - /* style:comma:start-ignore */ - R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); - R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); - R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); - R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); - R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); - R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); - R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); - R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); - R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); - R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); - R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); - R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); - R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); - R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); - R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); - /* style:comma:end-ignore */ - /* Add the working vars back into context.state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - /* Wipe variables */ - memset(&a, 0, sizeof(a)); - memset(&b, 0, sizeof(b)); - memset(&c, 0, sizeof(c)); - memset(&d, 0, sizeof(d)); - memset(&e, 0, sizeof(e)); -} - - -/* SHA1_Init - Initialize new context */ - -static int SHA1_Init(SHA_CTX* context) -{ - /* SHA1 initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; - - return 1; -} - - -/* Run your data through this. */ - -static int SHA1_Update(SHA_CTX* context, const unsigned char* data, unsigned int len) -{ -unsigned int i, j; - - j = (context->count[0] >> 3) & 63; - if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; - context->count[1] += (len >> 29); - if ((j + len) > 63) { - memcpy(&context->buffer[j], data, (i = 64-j)); - SHA1_Transform(context->state, context->buffer); - for ( ; i + 63 < len; i += 64) { - SHA1_Transform(context->state, &data[i]); - } - j = 0; - } - else i = 0; - memcpy(&context->buffer[j], &data[i], len - i); - - return 1; -} - - -/* Add padding and return the message digest. */ - -static int SHA1_Final(unsigned char digest[20], SHA_CTX* context) -{ -uint32_t i; -unsigned char finalcount[8]; - - for (i = 0; i < 8; i++) { - finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] - >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ - } - SHA1_Update(context, (const unsigned char *)"\200", 1); - while ((context->count[0] & 504) != 448) { - SHA1_Update(context, (const unsigned char *)"\0", 1); - } - SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */ - for (i = 0; i < 20; i++) { - digest[i] = (unsigned char) - ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); - } - /* Wipe variables */ - memset(context->buffer, 0, 64); - memset(context->state, 0, 20); - memset(context->count, 0, 8); - memset(&finalcount, 0, 8); -#ifdef SHA1HANDSOFF /* make SHA1_Transform overwrite it's own static vars */ - SHA1_Transform(context->state, context->buffer); -#endif - - return 1; -} - -#endif /* GG_CONFIG_HAVE_OPENSSL */ - -/** \endcond */ - -/** \cond internal */ - -/** - * \internal Liczy skrót SHA1 z ziarna i hasła. - * - * \param password Hasło - * \param seed Ziarno - * \param result Bufor na wynik funkcji skrótu (20 bajtów) - * - * \return 0 lub -1 - */ -int gg_login_hash_sha1_2(const char *password, uint32_t seed, uint8_t *result) -{ - SHA_CTX ctx; - - if (!SHA1_Init(&ctx)) - return -1; - - if (!SHA1_Update(&ctx, (const unsigned char*) password, strlen(password))) - goto fail; - - seed = gg_fix32(seed); - if (!SHA1_Update(&ctx, (uint8_t*) &seed, 4)) - goto fail; - - if (!SHA1_Final(result, &ctx)) - return -1; - - return 0; - -fail: - /* Zwolnij zasoby. Tylko GnuTLS przyjęłoby NULL zamiast result, więc przekaż result. */ - (void)SHA1_Final(result, &ctx); - return -1; -} - -/** - * \internal Liczy skrót SHA1 z fragmentu pliku. - * - * \param fd Deskryptor pliku - * \param ctx Kontekst SHA-1 - * \param pos Położenie fragmentu pliku - * \param len Długość fragmentu pliku - * - * \return 0 lub -1 - */ -static int gg_file_hash_sha1_part(int fd, SHA_CTX *ctx, off_t pos, size_t len) -{ - unsigned char buf[4096]; - size_t chunk_len; - int res = 0; - - while (len > 0) { - if (lseek(fd, pos, SEEK_SET) == (off_t) -1) { - res = -1; - break; - } - - chunk_len = len; - - if (chunk_len > sizeof(buf)) - chunk_len = sizeof(buf); - - res = read(fd, buf, chunk_len); - - if (res == -1 && errno != EINTR) - break; - - if (res == 0) - break; - - if (res != -1) { - if (!SHA1_Update(ctx, buf, res)) { - res = -1; - break; - } - - pos += res; - len -= res; - } - } - - return res; -} - -/** - * \internal Liczy skrót SHA1 z pliku. - * - * Dla plików poniżej 10MB liczony jest skrót z całego pliku, dla plików - * powyżej 10MB liczy się 9 jednomegabajtowych fragmentów. - * - * \param fd Deskryptor pliku - * \param result Bufor na wynik funkcji skrótu (20 bajtów) - * - * \return 0 lub -1 - */ -int gg_file_hash_sha1(int fd, uint8_t *result) -{ - SHA_CTX ctx; - off_t pos, len; - int res; - const size_t part_len = 1048576; - - if ((pos = lseek(fd, 0, SEEK_CUR)) == (off_t) -1) - return -1; - - if ((len = lseek(fd, 0, SEEK_END)) == (off_t) -1) - return -1; - - if (lseek(fd, 0, SEEK_SET) == (off_t) -1) - return -1; - - if (!SHA1_Init(&ctx)) - return -1; - - if (len <= (off_t)part_len * 10) { - res = gg_file_hash_sha1_part(fd, &ctx, 0, len); - } else { - unsigned int i; - - for (i = 0; i < 9; i++) { - off_t part_pos = (len - part_len) / 9 * i; - - res = gg_file_hash_sha1_part(fd, &ctx, part_pos, part_len); - - if (res == -1) - break; - } - } - - if (!SHA1_Final(result, &ctx)) - return -1; - - if (res == -1) - return -1; - - if (lseek(fd, pos, SEEK_SET) == (off_t) -1) - return -1; - - return 0; -} - -/** \endcond */
--- a/libpurple/protocols/gg/lib/strman.h Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2011 Bartosz Brachaczek <b.brachaczek@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file strman.h - * - * \brief Makra zapewniające kompatybilność API do obsługi operacji na stringach na różnych systemach - */ - -#ifndef LIBGADU_STRMAN_H -#define LIBGADU_STRMAN_H - -#include <stdio.h> -#include <stdarg.h> -#include <string.h> -#ifndef _MSC_VER -# include <strings.h> -#else -# define snprintf(str, size, format, ...) _snprintf_s(str, size, _TRUNCATE, format, __VA_ARGS__) -# define vsnprintf(str, size, format, ap) vsnprintf_s(str, size, _TRUNCATE, format, ap) -# define strdup _strdup -# define strcasecmp _stricmp -# define strncasecmp _strnicmp -#endif - -#endif /* LIBGADU_STRMAN_H */
--- a/libpurple/protocols/gg/lib/tvbuff.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,607 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2012 Tomek Wasilczyk <www.wasilczyk.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file tvbuff.c - * - * \brief Bufor wspierający obsługę pakietów typu Type-Value(s) - */ - -#include <stdlib.h> -#include <string.h> - -#include "tvbuff.h" - -#include "internal.h" - -struct gg_tvbuff -{ - const char *buffer; - size_t length; - size_t offset; - int valid; -}; - -/** - * \internal Tworzy nową instancję bufora. - * - * \param buffer Bufor źródłowy; nie może być modyfikowany (w szczególności - * zwalniany) przez cały okres korzystania z jego opakowanej wersji. - * \param length Długość bufora źródłowego. - * - * \return Zaalokowane opakowanie bufora - musi być zwolnione przez free lub - * gg_tvbuff_close. - */ -gg_tvbuff_t *gg_tvbuff_new(const char *buffer, size_t length) -{ - gg_tvbuff_t *tvb; - - tvb = malloc(sizeof(gg_tvbuff_t)); - if (tvb == NULL) - return NULL; - memset(tvb, 0, sizeof(gg_tvbuff_t)); - - if (buffer == NULL && length > 0) { - gg_debug(GG_DEBUG_ERROR, "// gg_tvbuff_new() " - "invalid arguments\n"); - tvb->valid = 0; - return tvb; - } - - tvb->buffer = buffer; - tvb->length = length; - tvb->offset = 0; - tvb->valid = 1; - - return tvb; -} - -/** - * \internal Zwalnia opakowanie bufora. Przed zwolnieniem sprawdza, czy - * przeczytano go do końca. - * - * \param tvb Bufor. - * - * \return Wartość różna od 0, jeżeli bufor tuż przed zwolnieniem był oznaczony - * jako prawidłowy - */ -int gg_tvbuff_close(gg_tvbuff_t *tvb) -{ - int valid; - - gg_tvbuff_expected_eob(tvb); - valid = gg_tvbuff_is_valid(tvb); - free(tvb); - - return valid; -} - -/** - * \internal Sprawdza, czy wszystkie odczyty z bufora były prawidłowe. - * - * \param tvb Bufor. - * - * \return Wartość różna od 0, jeżeli wszystkie odczyty były prawidłowe. - */ -int gg_tvbuff_is_valid(const gg_tvbuff_t *tvb) -{ - if (tvb == NULL) - return 0; - return tvb->valid; -} - -/** - * \internal Zwraca pozostałą do odczytania liczbę bajtów w buforze. - * - * \param tvb Bufor. - * - * \return Pozostała liczba bajtów do odczytania. - */ -size_t gg_tvbuff_get_remaining(const gg_tvbuff_t *tvb) -{ - if (!gg_tvbuff_is_valid(tvb)) - return 0; - - return tvb->length - tvb->offset; -} - -/** - * \internal Sprawdza, czy w buforze pozostała określona liczba bajtów do - * odczytania. Jeżeli nie została - oznacza bufor jako nieprawidłowy. - * - * \param tvb Bufor. - * \param length Ilość bajtów do odczytania. - * - * \return Wartość różna od 0, jeżeli można odczytać podaną liczbę bajtów. - */ -int gg_tvbuff_have_remaining(gg_tvbuff_t *tvb, size_t length) -{ - if (!gg_tvbuff_is_valid(tvb)) - return 0; - - if (gg_tvbuff_get_remaining(tvb) >= length) - return 1; - - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_have_remaining() failed " - "(%" GG_SIZE_FMT " < %" GG_SIZE_FMT ")\n", - gg_tvbuff_get_remaining(tvb), length); - tvb->valid = 0; - return 0; -} - -/** - * \internal Pomija określoną liczbę bajtów w buforze. Jeżeli w wyniku ich - * pominięcia wyjdzie poza zakres, oznacza bufor jako nieprawidłowy. - * - * \param tvb Bufor - * \param amount Liczba bajtów do pominięcia - */ -void gg_tvbuff_skip(gg_tvbuff_t *tvb, size_t amount) -{ - if (!gg_tvbuff_is_valid(tvb)) - return; - - if (tvb->offset + amount > tvb->length) { - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_skip() failed\n"); - tvb->valid = 0; - return; - } - - tvb->offset += amount; -} - -/** - * \internal Cofa się o określoną liczbę bajtów w buforze. Jeżeli cofnie przed - * pierwszy znak, oznacza bufor jako nieprawidłowy. - * - * \param tvb Bufor - * \param amount Liczba bajtów do cofnięcia - */ -void gg_tvbuff_rewind(gg_tvbuff_t *tvb, size_t amount) -{ - if (!gg_tvbuff_is_valid(tvb)) - return; - - if (tvb->offset < amount) { - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_rewind() failed\n"); - tvb->valid = 0; - return; - } - - tvb->offset -= amount; -} - -/** - * \internal Sprawdza, czy pod aktualną pozycją w buforze występuje podana - * wartość. Jeżeli tak, przesuwa aktualną pozycję do przodu. - * - * \param tvb Bufor. - * \param value Wartość do sprawdzenia - * - * \return Wartość różna od 0, jeżeli znaleziono podaną wartość. - */ -int gg_tvbuff_match(gg_tvbuff_t *tvb, uint8_t value) -{ - if (!gg_tvbuff_is_valid(tvb)) - return 0; - - if (!gg_tvbuff_have_remaining(tvb, 1)) { - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_match() failed\n"); - return 0; - } - - if (tvb->buffer[tvb->offset] != value) - return 0; - - tvb->offset++; - return 1; -} - -/** - * \internal Odczytuje z bufora liczbę 8-bitową. - * - * \param tvb Bufor - * - * \return Odczytana liczba - */ -uint8_t gg_tvbuff_read_uint8(gg_tvbuff_t *tvb) -{ - if (!gg_tvbuff_is_valid(tvb)) - return 0; - - if (!gg_tvbuff_have_remaining(tvb, 1)) { - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_read_uint8() " - "failed at %" GG_SIZE_FMT "\n", tvb->offset); - return 0; - } - - return tvb->buffer[tvb->offset++]; -} - -/** - * \internal Odczytuje z bufora liczbę 32-bitową. - * - * \param tvb Bufor - * - * \return Odczytana liczba - */ -uint32_t gg_tvbuff_read_uint32(gg_tvbuff_t *tvb) -{ - uint32_t val; - - if (!gg_tvbuff_is_valid(tvb)) - return 0; - - if (!gg_tvbuff_have_remaining(tvb, 4)) { - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_read_uint32() " - "failed at %" GG_SIZE_FMT "\n", tvb->offset); - return 0; - } - - memcpy(&val, tvb->buffer + tvb->offset, 4); - tvb->offset += 4; - - return gg_fix32(val); -} - -/** - * \internal Odczytuje z bufora liczbę 64-bitową. - * - * \param tvb Bufor - * - * \return Odczytana liczba - */ -uint64_t gg_tvbuff_read_uint64(gg_tvbuff_t *tvb) -{ - uint64_t val; - - if (!gg_tvbuff_is_valid(tvb)) - return 0; - - if (!gg_tvbuff_have_remaining(tvb, 8)) { - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_read_uint64() " - "failed at %" GG_SIZE_FMT "\n", tvb->offset); - return 0; - } - - memcpy(&val, tvb->buffer + tvb->offset, 8); - tvb->offset += 8; - - return gg_fix64(val); -} - -/** - * \internal Odczytuje z bufora skompresowaną liczbę całkowitą. - * Liczba taka może być zapisana w buforze na 1-9 bajtach, w zależności - * od jej wartości. - * - * Skompresowana liczba jest zapisywana od najmłodszego bajtu do najstarszego - * niezerowego. W każdym bajcie zapisuje się bit sterujący (równy 0, jeżeli jest - * to ostatni bajt do przeczytania, lub 1 w p.p.) oraz 7 kolejnych bitów z - * kompresowanej liczby. - * - * Przykładowo, liczby mniejsze od 128 (1000.0000b) są zapisywane dokładnie tak, - * jak uint8_t; a np. 12345 (0011.0000.0011.1001b) zostanie zapisana jako 0x60B9 - * (0110.0000.1011.1001b). - * - * \param tvb Bufor. - * - * \return Odczytana liczba. - */ -uint64_t gg_tvbuff_read_packed_uint(gg_tvbuff_t *tvb) -{ - uint64_t val = 0; - int i, val_len = 0; - - if (!gg_tvbuff_is_valid(tvb)) - return 0; - - while (gg_tvbuff_have_remaining(tvb, 1)) { - val_len++; - if (!(gg_tvbuff_read_uint8(tvb) & 0x80)) - break; - } - - if (!gg_tvbuff_is_valid(tvb)) { - gg_debug(GG_DEBUG_WARNING, - "// gg_tvbuff_read_packed_uint() failed\n"); - return 0; - } - - if (val_len > 9) { - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_read_packed_uint() " - "packed uint size too big: %d\n", val_len); - tvb->valid = 0; - return 0; - } - - for (i = 1; i <= val_len; i++) { - uint64_t old_val = val; - val <<= 7; - if (old_val != (val >> 7)) { - gg_debug(GG_DEBUG_WARNING, - "// gg_tvbuff_read_packed_uint() overflow\n"); - tvb->valid = 0; - return 0; - } - val |= (uint8_t)(tvb->buffer[tvb->offset - i] & ~0x80); - } - - return val; -} - -/** - * \internal Odczytuje z bufora podciąg bez kopiowania danych. - * - * \param tvb Bufor źródłowy - * \param length Ilość bajtów do odczytania - * - * \return Wskaźnik na początek odczytanych danych, lub NULL w przypadku - * niepowodzenia - */ -const char *gg_tvbuff_read_buff(gg_tvbuff_t *tvb, size_t length) -{ - const char *buff; - - if (!gg_tvbuff_is_valid(tvb)) - return NULL; - - if (!gg_tvbuff_have_remaining(tvb, length)) { - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_get_buff() " - "failed at %" GG_SIZE_FMT ":%" GG_SIZE_FMT "\n", - tvb->offset, length); - return NULL; - } - - buff = tvb->buffer + tvb->offset; - tvb->offset += length; - return buff; -} - -/** - * \internal Odczytuje z bufora podciąg kopiując go do nowego obszaru pamięci. - * - * \param tvb Bufor źródłowy - * \param buffer Bufor docelowy - * \param length Ilość bajtów do odczytania - */ -void gg_tvbuff_read_buff_cpy(gg_tvbuff_t *tvb, char *buffer, size_t length) -{ - if (!gg_tvbuff_is_valid(tvb)) - return; - - if (!gg_tvbuff_have_remaining(tvb, length)) { - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_read_buff() " - "failed at %" GG_SIZE_FMT ":%" GG_SIZE_FMT "\n", - tvb->offset, length); - return; - } - - if (buffer == NULL && length > 0) { - gg_debug(GG_DEBUG_ERROR, "// gg_tvbuff_new() " - "invalid arguments\n"); - tvb->valid = 0; - return; - } - - memcpy(buffer, tvb->buffer + tvb->offset, length); - tvb->offset += length; -} - -/** - * \internal Odczytuje z bufora ciąg tekstowy (mogący zawierać dowolne znaki, - * również \0) bez kopiowania danych. - * - * \param tvb Bufor źródłowy - * \param length Zmienna, do której zostanie zapisana długość odczytanego ciągu - * - * \return Wskaźnik na początek odczytanych danych, lub NULL w przypadku - * niepowodzenia - */ -const char *gg_tvbuff_read_str(gg_tvbuff_t *tvb, size_t *length) -{ - size_t offset; - uint32_t str_len; - const char *str; - - if (!gg_tvbuff_is_valid(tvb)) - return NULL; - - offset = tvb->offset; - str_len = gg_tvbuff_read_packed_uint(tvb); - if (!gg_tvbuff_is_valid(tvb) || - !gg_tvbuff_have_remaining(tvb, str_len)) - { - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_read_str() failed at " - "%" GG_SIZE_FMT ":%d\n", offset, str_len); - return NULL; - } - - str = gg_tvbuff_read_buff(tvb, str_len); - - if (!gg_tvbuff_is_valid(tvb)) - return NULL; - - if (length != NULL) - *length = str_len; - if (str_len == 0) - return NULL; - return str; -} - -/** - * \internal Odczytuje z bufora ciąg tekstowy (mogący zawierać dowolne znaki, - * również \0) kopiując go do nowego obszaru pamięci. Zwrócony ciąg będzie - * zawsze zakończony znakiem \0. - * - * \param tvb Bufor źródłowy - * \param dst Zmienna, do której zostanie zapisany wskaźnik na odczytany ciąg. - * Po użyciu, blok ten powinien zostać zwolniony za pomocą \c free() - * - * \return Wskaźnik na początek odczytanych danych, lub NULL w przypadku - * niepowodzenia - */ -void gg_tvbuff_read_str_dup(gg_tvbuff_t *tvb, char **dst) -{ - size_t offset; - uint32_t str_len; - char *str; - - if (!gg_tvbuff_is_valid(tvb)) - return; - - offset = tvb->offset; - str_len = gg_tvbuff_read_packed_uint(tvb); - if (!gg_tvbuff_is_valid(tvb) || - !gg_tvbuff_have_remaining(tvb, str_len)) - { - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_read_str_dup() failed " - "at %" GG_SIZE_FMT ":%d\n", offset, str_len); - return; - } - - str = malloc(str_len + 1); - if (str == NULL) { - gg_debug(GG_DEBUG_ERROR, "// gg_tvbuff_read_str_dup() " - "not enough free memory: %d + 1\n", str_len); - tvb->valid = 0; - return; - } - - gg_tvbuff_read_buff_cpy(tvb, str, str_len); - str[str_len] = '\0'; - - if (*dst != NULL) { - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_read_str_dup() " - "destination already filled, freeing it...\n"); - free(*dst); - } - *dst = str; -} - -/** - * \internal Odczytuje z bufora identyfikator użytkownika. - * - * \param tvb Bufor - * - * \return Identyfikator użytkownika, lub 0 w przypadku niepowodzenia - */ -uin_t gg_tvbuff_read_uin(gg_tvbuff_t *tvb) -{ - uin_t uin = 0; - uint32_t uin_len, full_len; - uint8_t uin_type; - const char *raw; - - if (!gg_tvbuff_is_valid(tvb)) - return 0; - - full_len = gg_tvbuff_read_packed_uint(tvb); - uin_type = gg_tvbuff_read_uint8(tvb); - uin_len = gg_tvbuff_read_uint8(tvb); - - if (!gg_tvbuff_is_valid(tvb)) - return 0; - - if (full_len != uin_len + 2 || - uin_type != 0 || - uin_len > 10) - { - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_read_uin() failed (1)\n"); - tvb->valid = 0; - return 0; - } - - raw = gg_tvbuff_read_buff(tvb, uin_len); - if (raw) - uin = gg_str_to_uin(raw, uin_len); - - if (uin == 0) { - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_read_uin() failed (2)\n"); - tvb->valid = 0; - return 0; - } - - return uin; -} - -/** - * \internal Odczytuje z bufora liczbę 8-bitową i porównuje z podaną. Jeżeli te - * się różnią, zostaje wygenerowane ostrzeżenie. - * - * \param tvb Bufor - * \param value Oczekiwana wartość - */ -void gg_tvbuff_expected_uint8(gg_tvbuff_t *tvb, uint8_t value) -{ - uint8_t got; - size_t offset; - - offset = tvb->offset; - got = gg_tvbuff_read_uint8(tvb); - if (!gg_tvbuff_is_valid(tvb)) - return; - - if (got != value) - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_expected_uint8() " - "expected %#02x, but %#02x found at %" GG_SIZE_FMT "\n", - value, got, offset); -} - -/** - * \internal Odczytuje z bufora liczbę 32-bitową i porównuje z podaną. Jeżeli te - * się różnią, zostaje wygenerowane ostrzeżenie. - * - * \param tvb Bufor - * \param value Oczekiwana wartość - */ -void gg_tvbuff_expected_uint32(gg_tvbuff_t *tvb, uint32_t value) -{ - uint32_t got; - size_t offset; - - offset = tvb->offset; - got = gg_tvbuff_read_uint32(tvb); - if (!gg_tvbuff_is_valid(tvb)) - return; - - if (got != value) - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_expected_uint32() " - "expected %#08x, but %#08x found at %" GG_SIZE_FMT "\n", - value, got, offset); -} - -/** - * \internal Oczekuje końca bufora. Jeżeli w buforze są jeszcze dane do - * przeczytania, generuje ostrzeżenie. - * - * \param tvb Bufor. - */ -void gg_tvbuff_expected_eob(const gg_tvbuff_t *tvb) -{ - if (!gg_tvbuff_is_valid(tvb)) - return; - - if (gg_tvbuff_get_remaining(tvb) != 0) - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_expected_eob() " - "unexpected %" GG_SIZE_FMT " bytes, first=%#02x\n", - gg_tvbuff_get_remaining(tvb), - tvb->buffer[tvb->offset]); -}
--- a/libpurple/protocols/gg/lib/tvbuff.h Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2012 Tomek Wasilczyk <www.wasilczyk.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef LIBGADU_TVBUFF_H -#define LIBGADU_TVBUFF_H - -#include "libgadu.h" - -typedef struct gg_tvbuff gg_tvbuff_t; - -gg_tvbuff_t * gg_tvbuff_new(const char *buffer, size_t length); -int gg_tvbuff_close(gg_tvbuff_t *tvb); - -int gg_tvbuff_is_valid(const gg_tvbuff_t *tvb); - -size_t gg_tvbuff_get_remaining(const gg_tvbuff_t *tvb); - -int gg_tvbuff_have_remaining(gg_tvbuff_t *tvb, size_t length); - -void gg_tvbuff_skip(gg_tvbuff_t *tvb, size_t amount); -void gg_tvbuff_rewind(gg_tvbuff_t *tvb, size_t amount); - -int gg_tvbuff_match(gg_tvbuff_t *tvb, uint8_t value); - -uint8_t gg_tvbuff_read_uint8(gg_tvbuff_t *tvb); -uint32_t gg_tvbuff_read_uint32(gg_tvbuff_t *tvb); -uint64_t gg_tvbuff_read_uint64(gg_tvbuff_t *tvb); - -uint64_t gg_tvbuff_read_packed_uint(gg_tvbuff_t *tvb); - -const char * gg_tvbuff_read_buff(gg_tvbuff_t *tvb, size_t length); -void gg_tvbuff_read_buff_cpy(gg_tvbuff_t *tvb, char *buffer, size_t length); -const char * gg_tvbuff_read_str(gg_tvbuff_t *tvb, size_t *length); -void gg_tvbuff_read_str_dup(gg_tvbuff_t *tvb, char **dst); - -uin_t gg_tvbuff_read_uin(gg_tvbuff_t *tvb); - -void gg_tvbuff_expected_uint8(gg_tvbuff_t *tvb, uint8_t value); -void gg_tvbuff_expected_uint32(gg_tvbuff_t *tvb, uint32_t value); -void gg_tvbuff_expected_eob(const gg_tvbuff_t *tvb); - -#endif /* LIBGADU_TVBUFF_H */
--- a/libpurple/protocols/gg/lib/tvbuilder.c Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,426 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2012 Tomek Wasilczyk <www.wasilczyk.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -/** - * \file tvbuilder.c - * - * \brief Bufor wspierający budowanie pakietów typu Type-Value(s) - */ - -#include <stdlib.h> -#include <string.h> - -#include "tvbuilder.h" - -#include "internal.h" -#include "fileio.h" - -#include <errno.h> - -struct gg_tvbuilder -{ - char *buffer; - size_t length; - size_t alloc_length; - int valid; - - struct gg_session *gs; - struct gg_event *ge; -}; - -static char *gg_tvbuilder_extend(gg_tvbuilder_t *tvb, size_t length); - -/** - * \internal Tworzy nową instancję bufora. - * - * \param gs Struktura sesji - * \param ge Struktura zdarzenia - * - * \return Zaalokowany bufor - musi być zwolniony przez gg_tvbuilder_free, - * gg_tvbuilder_fail lub gg_tvbuilder_send. - */ -gg_tvbuilder_t *gg_tvbuilder_new(struct gg_session *gs, struct gg_event *ge) -{ - gg_tvbuilder_t *tvb; - - tvb = malloc(sizeof(gg_tvbuilder_t)); - if (tvb == NULL) - return NULL; - memset(tvb, 0, sizeof(gg_tvbuilder_t)); - - if (gs == NULL) { - gg_debug(GG_DEBUG_ERROR, "// gg_tvbuilder_new() " - "invalid arguments\n"); - tvb->valid = 0; - return tvb; - } - - tvb->buffer = NULL; - tvb->length = 0; - tvb->alloc_length = 0; - tvb->valid = 1; - - tvb->gs = gs; - tvb->ge = ge; - - return tvb; -} - -/** - * \internal Zwalnia bufor. - * - * \param tvb Bufor - */ -void gg_tvbuilder_free(gg_tvbuilder_t *tvb) -{ - if (tvb == NULL) - return; - - free(tvb->buffer); - free(tvb); -} - -/** - * \internal Zwalnia bufor i generuje błąd połączenia. - * - * \param tvb Bufor - * \param failure Powód błędu - */ -void gg_tvbuilder_fail(gg_tvbuilder_t *tvb, enum gg_failure_t failure) -{ - int errno_copy; - - if (tvb == NULL) { - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuilder_fail() " - "NULL tvbuilder\n"); - return; - } - - errno_copy = errno; - close(tvb->gs->fd); - tvb->gs->fd = -1; - errno = errno_copy; - - if (tvb->ge) { - tvb->ge->type = GG_EVENT_CONN_FAILED; - tvb->ge->event.failure = failure; - } - tvb->gs->state = GG_STATE_IDLE; - - gg_tvbuilder_free(tvb); -} - -/** - * \internal Próbuje wysłać zawartość bufora i go zwalnia. - * - * \param tvb Bufor - * \param type Typ pakietu - * - * \return 1 jeśli się powiodło, 0 w p.p. - */ -int gg_tvbuilder_send(gg_tvbuilder_t *tvb, int type) -{ - int ret; - enum gg_failure_t failure; - - if (tvb == NULL) { - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuilder_send() " - "NULL tvbuilder\n"); - return 0; - } - - if (!gg_tvbuilder_is_valid(tvb)) { - gg_debug_session(tvb->gs, GG_DEBUG_ERROR, "// gg_tvbuilder_send() " - "invalid buffer\n"); - ret = -1; - failure = GG_FAILURE_INTERNAL; - } else { - const char *buffer = (tvb->length > 0) ? tvb->buffer : ""; - ret = gg_send_packet(tvb->gs, type, buffer, tvb->length, NULL); - if (ret == -1) { - failure = GG_FAILURE_WRITING; - gg_debug_session(tvb->gs, GG_DEBUG_ERROR, - "// gg_tvbuilder_send() " - "sending packet %#x failed. (errno=%d, %s)\n", - type, errno, strerror(errno)); - } - } - - if (ret == -1) { - gg_tvbuilder_fail(tvb, failure); - return 0; - } - - gg_tvbuilder_free(tvb); - return 1; -} - -/** - * \internal Sprawdza, czy wszystkie zapisy do bufora były prawidłowe. - * - * \param tvb Builder. - * - * \return Wartość różna od 0, jeżeli wszystkie zapisy były prawidłowe. - */ -int gg_tvbuilder_is_valid(const gg_tvbuilder_t *tvb) -{ - if (tvb == NULL) - return 0; - return tvb->valid; -} - -/** - * \internal Sprawdza rozmiar bufora. - * - * \param tvb Bufor - * - * \return Rozmiar bufora - */ -size_t gg_tvbuilder_get_size(const gg_tvbuilder_t *tvb) -{ - if (!gg_tvbuilder_is_valid(tvb)) - return 0; - - return tvb->length; -} - -/** - * \internal Określa oczekiwaną liczbę bajtów, o którą zostanie rozszerzony - * bufor. - * - * Funkcja powoduje jedynie wzrost wydajności poprzez zmniejszenie ilości - * realokacji. - * - * \param tvb Builder. - * \param length Oczekiwana liczba bajtów. - */ -void gg_tvbuilder_expected_size(gg_tvbuilder_t *tvb, size_t length) -{ - size_t length_new; - char *buff_new; - - if (!gg_tvbuilder_is_valid(tvb) || length == 0) - return; - - length_new = tvb->length + length; - - if (length_new <= tvb->alloc_length) - return; - - if (tvb->alloc_length > 0) { - gg_debug(GG_DEBUG_MISC, "// gg_tvbuilder_expected_size(%p, %" - GG_SIZE_FMT ") realloc from %" GG_SIZE_FMT " to %" - GG_SIZE_FMT "\n", - tvb, length, tvb->alloc_length, length_new); - } - - buff_new = realloc(tvb->buffer, length_new); - if (buff_new != NULL) { - tvb->buffer = buff_new; - tvb->alloc_length = length_new; - return; - } - - gg_debug(GG_DEBUG_ERROR, "// gg_tvbuilder_expected_size(%p, %" - GG_SIZE_FMT ") out of memory (new length: %" GG_SIZE_FMT - ")\n", tvb, length, length_new); - free(tvb->buffer); - tvb->buffer = NULL; - tvb->length = 0; - tvb->alloc_length = 0; - tvb->valid = 0; -} - -/** - * \internal Poszerza bufor o podaną liczbę bajtów. - * - * \param tvb Bufor - * \param length Liczba bajtów do dodania - * - * \return Początek nowo dodanego bloku bufora - */ -static char * gg_tvbuilder_extend(gg_tvbuilder_t *tvb, size_t length) -{ - size_t length_old; - - gg_tvbuilder_expected_size(tvb, length); - if (!gg_tvbuilder_is_valid(tvb)) - return NULL; - - length_old = tvb->length; - tvb->length += length; - - return tvb->buffer + length_old; -} - -/** - * \internal Skraca bufor o podaną liczbę bajtów - * - * \param tvb Bufor - * \param length Ilość bajtów do skrócenia - */ -void gg_tvbuilder_strip(gg_tvbuilder_t *tvb, size_t length) -{ - if (!gg_tvbuilder_is_valid(tvb)) - return; - - if (length > tvb->length) { - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuilder_strip() " - "out of range\n"); - tvb->valid = 0; - return; - } - - tvb->length = length; -} - -/** - * \internal Zapisuje do bufora liczbę 8-bitową. - * - * \param tvb Bufor - * \param value Wartość do zapisania - */ -void gg_tvbuilder_write_uint8(gg_tvbuilder_t *tvb, uint8_t value) -{ - gg_tvbuilder_write_buff(tvb, (const char *)&value, 1); -} - -/** - * \internal Zapisuje do bufora liczbę 32-bitową. - * - * \param tvb Bufor - * \param value Wartość do zapisania - */ -void gg_tvbuilder_write_uint32(gg_tvbuilder_t *tvb, uint32_t value) -{ - value = gg_fix32(value); - gg_tvbuilder_write_buff(tvb, (const char *)&value, 4); -} - -/** - * \internal Zapisuje do bufora liczbę 64-bitową. - * - * \param tvb Bufor - * \param value Wartość do zapisania - */ -void gg_tvbuilder_write_uint64(gg_tvbuilder_t *tvb, uint64_t value) -{ - value = gg_fix64(value); - gg_tvbuilder_write_buff(tvb, (const char *)&value, 8); -} - -/** - * \internal Zapisuje do bufora liczbę 1-9 bajtową. - * - * \param tvb Bufor - * \param value Wartość do zapisania - * - * \see gg_tvbuff_read_packed_uint - */ -void gg_tvbuilder_write_packed_uint(gg_tvbuilder_t *tvb, uint64_t value) -{ - uint8_t buff[9]; - uint64_t val_curr; - int i, val_len = 0; - - if (!gg_tvbuilder_is_valid(tvb)) - return; - - val_curr = value; - while (val_curr > 0) { - val_curr >>= 7; - val_len++; - } - if (val_len == 0) - val_len = 1; - - if (val_len > 9) { - gg_debug(GG_DEBUG_WARNING, "// gg_tvbuilder_write_packed_uint() " - "int size too big (%d): %" PRIu64 "\n", val_len, value); - tvb->valid = 0; - return; - } - - val_curr = value; - for (i = 0; i < val_len; i++) { - uint8_t raw = val_curr & 0x7F; - val_curr >>= 7; - if (i + 1 < val_len) - raw |= 0x80; - buff[i] = raw; - } - - gg_tvbuilder_write_buff(tvb, (const char*)buff, val_len); -} - -/** - * \internal Zapisuje do bufora zawartość innego bufora. - * - * \param tvb Bufor docelowy - * \param buffer Bufor źródłowy - * \param length Ilość danych do skopiowania - */ -void gg_tvbuilder_write_buff(gg_tvbuilder_t *tvb, const char *buffer, - size_t length) -{ - char *buff = gg_tvbuilder_extend(tvb, length); - if (!buff) - return; - - memcpy(buff, buffer, length); -} - -/** - * \internal Zapisuje do bufora ciąg tekstowy (mogący zawierać znaki \0). - * - * \param tvb Bufor docelowy - * \param buffer Bufor źródłowy - * \param length Długość tekstu, lub -1, jeżeli ma zostać wyliczona - * automatycznie (do pierwszego znaku \0) - */ -void gg_tvbuilder_write_str(gg_tvbuilder_t *tvb, const char *buffer, - ssize_t length) -{ - if (!gg_tvbuilder_is_valid(tvb)) - return; - - if (length == -1) - length = strlen(buffer); - - gg_tvbuilder_write_packed_uint(tvb, length); - gg_tvbuilder_write_buff(tvb, buffer, length); -} - -/** - * \internal Zapisuje do bufora identyfikator użytkownika. - * - * \param tvb Bufor - * \param uin Identyfikator użytkownika - */ -void gg_tvbuilder_write_uin(gg_tvbuilder_t *tvb, uin_t uin) -{ - char uin_str[16]; - int uin_len; - - uin_len = snprintf(uin_str, sizeof(uin_str), "%u", uin); - - gg_tvbuilder_write_uint8(tvb, 0x00); - gg_tvbuilder_write_str(tvb, uin_str, uin_len); -}
--- a/libpurple/protocols/gg/lib/tvbuilder.h Wed Sep 28 09:32:19 2016 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* $Id$ */ - -/* - * (C) Copyright 2012 Tomek Wasilczyk <www.wasilczyk.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License Version - * 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef LIBGADU_TVBUILDER_H -#define LIBGADU_TVBUILDER_H - -#include "libgadu.h" - -typedef struct gg_tvbuilder gg_tvbuilder_t; - -gg_tvbuilder_t * gg_tvbuilder_new(struct gg_session *gs, struct gg_event *ge); -void gg_tvbuilder_free(gg_tvbuilder_t *tvb); -void gg_tvbuilder_fail(gg_tvbuilder_t *tvb, enum gg_failure_t failure); -int gg_tvbuilder_send(gg_tvbuilder_t *tvb, int type); - -int gg_tvbuilder_is_valid(const gg_tvbuilder_t *tvb); - -size_t gg_tvbuilder_get_size(const gg_tvbuilder_t *tvb); -void gg_tvbuilder_expected_size(gg_tvbuilder_t *tvb, size_t length); -void gg_tvbuilder_strip(gg_tvbuilder_t *tvb, size_t length); - -void gg_tvbuilder_write_uint8(gg_tvbuilder_t *tvb, uint8_t value); -void gg_tvbuilder_write_uint32(gg_tvbuilder_t *tvb, uint32_t value); -void gg_tvbuilder_write_uint64(gg_tvbuilder_t *tvb, uint64_t value); - -void gg_tvbuilder_write_packed_uint(gg_tvbuilder_t *tvb, uint64_t value); - -void gg_tvbuilder_write_buff(gg_tvbuilder_t *tvb, const char *buffer, size_t length); -void gg_tvbuilder_write_str(gg_tvbuilder_t *tvb, const char *buffer, ssize_t length); - -void gg_tvbuilder_write_uin(gg_tvbuilder_t *tvb, uin_t uin); - -#endif /* LIBGADU_TVBUILDER_H */