diff options
author | Vadim Dashevskiy <watcherhd@gmail.com> | 2012-10-12 14:18:20 +0000 |
---|---|---|
committer | Vadim Dashevskiy <watcherhd@gmail.com> | 2012-10-12 14:18:20 +0000 |
commit | 0ecadfc45326fce5fc4ba28b27a0a7ad484e5b84 (patch) | |
tree | fef68e6433f39bd8d51e0718f0de8ea425e52be3 /protocols/Gadu-Gadu/libgadu | |
parent | ef1f6f8fac28594a151c4cd811d1590cfc7ff81d (diff) |
Gadu-Gadu: folders restructurization
git-svn-id: http://svn.miranda-ng.org/main/trunk@1888 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'protocols/Gadu-Gadu/libgadu')
21 files changed, 0 insertions, 15968 deletions
diff --git a/protocols/Gadu-Gadu/libgadu/COPYING b/protocols/Gadu-Gadu/libgadu/COPYING deleted file mode 100644 index 6e816402b7..0000000000 --- a/protocols/Gadu-Gadu/libgadu/COPYING +++ /dev/null @@ -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!
-
-
diff --git a/protocols/Gadu-Gadu/libgadu/common.c b/protocols/Gadu-Gadu/libgadu/common.c deleted file mode 100644 index b9b41c0547..0000000000 --- a/protocols/Gadu-Gadu/libgadu/common.c +++ /dev/null @@ -1,975 +0,0 @@ -/* coding: UTF-8 */
-/* $Id: common.c 13762 2011-08-09 12:35:16Z dezred $ */
-
-/*
- * (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.
- */
-
-/*
- * Funkcje konwersji między UTF-8 i CP1250 są oparte o kod biblioteki iconv.
- * Informacje o prawach autorskich oryginalnego kodu zamieszczono poniżej:
- *
- * Copyright (C) 1999-2001, 2004 Free Software Foundation, Inc.
- * This file is part of the GNU LIBICONV Library.
- *
- * The GNU LIBICONV Library is free software; you can redistribute it
- * and/or modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * The GNU LIBICONV Library is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with the GNU LIBICONV Library; see the file COPYING.LIB.
- * If not, write to the Free Software Foundation, Inc., 51 Franklin Street,
- * Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/**
- * \file common.c
- *
- * \brief Funkcje wykorzystywane przez różne moduły biblioteki
- */
-#include <sys/types.h>
-#ifdef _WIN32
-#include "win32.h"
-#else
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#ifdef sun
-# include <sys/filio.h>
-#endif
-#endif /* _WIN32 */
-
-#include <errno.h>
-#include <fcntl.h>
-#ifndef _WIN32
-#include <netdb.h>
-#endif /* _WIN32 */
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifndef _WIN32
-#include <unistd.h>
-#endif /* _WIN32 */
-
-#include "libgadu.h"
-#include "internal.h"
-
-/**
- * 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)
- */
-static void gg_debug_common(struct gg_session *sess, int level, const char *format, va_list ap)
-{
- if (gg_debug_handler_session)
- (*gg_debug_handler_session)(sess, level, format, ap);
- else if (gg_debug_handler)
- (*gg_debug_handler)(level, format, ap);
- else if (gg_debug_level & level)
- 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 sess 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 *sess, int level, const char *format, ...)
-{
- va_list ap;
- int old_errno = errno;
- va_start(ap, format);
- gg_debug_common(sess, level, format, ap);
- va_end(ap);
- errno = old_errno;
-}
-
-/**
- * \internal Przekazuje informację odpluskwiania związane z zawartością pamięci.
- *
- * \param sess Struktura sesji
- * \param buf Adres w pamięci
- * \param buf_length Ilość danych do wyświetlenia
- * \param format Format wiadomości (zgodny z \c printf)
- *
- * \ingroup debug
- */
-void gg_debug_dump_session(struct gg_session *sess, const void *buf, unsigned int buf_length, const char *format, ...)
-{
- va_list ap;
-
- if ((gg_debug_level & GG_DEBUG_DUMP)) {
- unsigned int i;
-
- va_start(ap, format);
- gg_debug_common(sess, GG_DEBUG_DUMP, format, ap);
- for (i = 0; i < buf_length; ++i)
- gg_debug_session(sess, GG_DEBUG_DUMP, " %.2x", ((unsigned char*) buf)[i]);
- gg_debug_session(sess, GG_DEBUG_DUMP, "\n");
- va_end(ap);
- }
-}
-
-#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 = 0;
- char *buf = NULL;
-
-#ifdef GG_CONFIG_HAVE_VA_COPY
- va_list aq;
-
- va_copy(aq, ap);
-#else
-# ifdef GG_CONFIG_HAVE___VA_COPY
- va_list aq;
-
- __va_copy(aq, ap);
-# endif
-#endif
-
-#ifndef GG_CONFIG_HAVE_C99_VSNPRINTF
- {
- int res;
- char *tmp;
-
- size = 128;
- do {
- size *= 2;
- if (!(tmp = realloc(buf, size))) {
- free(buf);
- return NULL;
- }
- buf = tmp;
- res = vsnprintf(buf, size, format, ap);
- } while (res == size - 1 || res == -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, ap);
- if (!(buf = malloc(size + 1)))
- return NULL;
- }
-#endif
-
-#ifdef GG_CONFIG_HAVE_VA_COPY
- vsnprintf(buf, size + 1, format, aq);
- va_end(aq);
-#else
-# ifdef GG_CONFIG_HAVE___VA_COPY
- vsnprintf(buf, size + 1, format, aq);
- va_end(aq);
-# else
- vsnprintf(buf, size + 1, format, ap);
-# endif
-#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
- *
- * \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.
- *
- * \param sock Deskryptor gniazda
- * \param buf Wskaźnik do bufora
- * \param length Długość bufora
- *
- * \return Zwraca \c buf jeśli się powiodło, lub \c NULL w przypadku błędu.
- */
-char *gg_read_line(SOCKET sock, char *buf, int length)
-{
- int ret;
-
- if (!buf || length < 0)
- return NULL;
-
- for (; length > 1; buf++, length--) {
- do {
- if ((ret = gg_sock_read(sock, buf, 1)) == -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
- */
-#ifdef GG_CONFIG_MIRANDA -SOCKET gg_connect_internal(void *addr, int port, int async, SOCKET *gg_sock)
-#else
-SOCKET gg_connect(void *addr, int port, int async)
-#endif
-{
- SOCKET sock;
- int one = 1, 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;
- gg_sock_close(sock);
- errno = errno2;
- return -1;
- }
-
-#ifdef GG_CONFIG_MIRANDA - if (gg_sock) *gg_sock = sock; -#endif
-
- if (async) {
-#ifdef FIONBIO
- if (ioctl(sock, FIONBIO, &one) == -1) {
-#else
- if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
-#endif
- gg_debug(GG_DEBUG_MISC, "// gg_connect() ioctl() failed (errno=%d, %s)\n", errno, strerror(errno));
- errno2 = errno;
- gg_sock_close(sock);
- errno = errno2;
- return -1;
- }
- }
-
- sin.sin_port = htons((uint16_t)port);
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = a->s_addr;
-
- errno = 0;
- 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;
- gg_sock_close(sock);
- errno = errno2;
- return -1;
- }
- gg_debug(GG_DEBUG_MISC, "// gg_connect() connect() in progress\n");
- }
-
- return sock;
-}
-
-#ifdef GG_CONFIG_MIRANDA -SOCKET gg_connect(void *addr, int port, int async)
-{
- return gg_connect_internal(addr, port, async, 0);
-}
-#endif
-
-/**
- * \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)
-{
- size_t 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, 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++) {
- char *arg, 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 = (unsigned int)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 index = 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 = strchr(gg_base64_charset, *buf)))
- foo = gg_base64_charset;
- val = (int)(foo - gg_base64_charset);
- buf++;
- switch (index) {
- 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;
- }
- index++;
- index %= 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()
-{
- char *tmp, *enc, *out;
- size_t tmp_size;
-
- if (!gg_proxy_enabled || !gg_proxy_username || !gg_proxy_password)
- return NULL;
-
- if (!(tmp = malloc((tmp_size = strlen(gg_proxy_username) + strlen(gg_proxy_password) + 2))))
- return NULL;
-
- snprintf(tmp, tmp_size, "%s:%s", gg_proxy_username, gg_proxy_password);
-
- if (!(enc = gg_base64_encode(tmp))) {
- free(tmp);
- return NULL;
- }
-
- free(tmp);
-
- if (!(out = malloc(strlen(enc) + 40))) {
- 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 uint32_t gg_crc32_table[256];
-
-/**
- * \internal Flaga wypełnienia tablicy pomocniczej do wyznaczania sumy
- * kontrolnej.
- */
-static int gg_crc32_initialized = 0;
-
-/**
- * \internal Tworzy tablicę pomocniczą do wyznaczania sumy kontrolnej.
- */
-static void gg_crc32_make_table(void)
-{
- uint32_t h = 1;
- unsigned int i, j;
-
- memset(gg_crc32_table, 0, sizeof(gg_crc32_table));
-
- for (i = 128; i; i >>= 1) {
- h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
-
- for (j = 0; j < 256; j += 2 * i)
- gg_crc32_table[i + j] = gg_crc32_table[j] ^ h;
- }
-
- gg_crc32_initialized = 1;
-}
-
-/**
- * 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 (!gg_crc32_initialized)
- gg_crc32_make_table();
-
- if (!buf || len < 0)
- return crc;
-
- crc ^= 0xffffffffL;
-
- while (len--)
- crc = (crc >> 8) ^ gg_crc32_table[(crc ^ *buf++) & 0xff];
-
- return crc ^ 0xffffffffL;
-}
-
-/**
- * \internal Tablica konwersji między CP1250 a UTF-8.
- */
-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 b Tekst źródłowy w CP1250.
- *
- * \return Zaalokowany bufor z tekstem w UTF-8.
- */
-char *gg_cp_to_utf8(const char *b)
-{
- unsigned char *buf = (unsigned char *) b;
- char *newbuf;
- int newlen = 0;
- int i, j;
-
- for (i = 0; buf[i]; i++) {
- uint16_t znak = (buf[i] < 0x80) ? buf[i] : table_cp1250[buf[i]-0x80];
-
- if (znak < 0x80) newlen += 1;
- else if (znak < 0x800) newlen += 2;
- else newlen += 3;
- }
-
- if (!(newbuf = malloc(newlen+1))) {
- gg_debug(GG_DEBUG_MISC, "// gg_cp_to_utf8() not enough memory\n");
- return NULL;
- }
-
- for (i = 0, j = 0; buf[i]; i++) {
- uint16_t znak = (buf[i] < 0x80) ? buf[i] : table_cp1250[buf[i]-0x80];
- int count;
-
- if (znak < 0x80) count = 1;
- else if (znak < 0x800) count = 2;
- else count = 3;
-
- switch (count) {
- case 3: newbuf[j+2] = 0x80 | (znak & 0x3f); znak = znak >> 6; znak |= 0x800;
- case 2: newbuf[j+1] = 0x80 | (znak & 0x3f); znak = znak >> 6; znak |= 0xc0;
- case 1: newbuf[j] = (char)znak;
- }
- j += count;
- }
- newbuf[j] = '\0';
-
- return newbuf;
-}
-
-/**
- * \internal Dekoduje jeden znak UTF-8.
- *
- * \note Funkcja nie jest kompletną implementacją UTF-8, a wersją uproszczoną
- * do potrzeb kodowania CP1250.
- *
- * \param s Tekst źródłowy.
- * \param n Długość tekstu źródłowego.
- * \param ch Wskaźnik na wynik dekodowania.
- *
- * \return Długość zdekodowanej sekwencji w bajtach lub wartość mniejsza
- * od zera w przypadku błędu.
- */
-static int gg_utf8_helper(unsigned char *s, int n, uint16_t *ch)
-{
- unsigned char c = s[0];
-
- if (c < 0x80) {
- *ch = c;
- return 1;
- }
-
- if (c < 0xc2)
- return -1;
-
- if (c < 0xe0) {
- if (n < 2)
- return -2;
- if (!((s[1] ^ 0x80) < 0x40))
- return -1;
- *ch = ((uint16_t) (c & 0x1f) << 6) | (uint16_t) (s[1] ^ 0x80);
- return 2;
- }
-
- if (c < 0xf0) {
- if (n < 3)
- return -2;
- if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (c >= 0xe1 || s[1] >= 0xa0)))
- return -1;
- *ch = ((uint16_t) (c & 0x0f) << 12) | ((uint16_t) (s[1] ^ 0x80) << 6) | (uint16_t) (s[2] ^ 0x80);
- return 3;
- }
-
- return -1;
-}
-
-/**
- * \internal Zamienia tekst kodowany UTF-8 na CP1250.
- *
- * \param b Tekst źródłowy w UTF-8.
- *
- * \return Zaalokowany bufor z tekstem w CP1250.
- */
-char *gg_utf8_to_cp(const char *b)
-{
- unsigned char *buf = (unsigned char *) b;
- char *newbuf;
- int newlen = 0;
- int len;
- int i, j;
-
- len = (int)strlen(b);
-
- for (i = 0; i < len; newlen++) {
- uint16_t discard;
- int ret;
-
- ret = gg_utf8_helper(&buf[i], len - i, &discard);
-
- if (ret > 0)
- i += ret;
- else
- i++;
- }
-
- if (!(newbuf = malloc(newlen+1))) {
- gg_debug(GG_DEBUG_MISC, "// gg_utf8_to_cp() not enough memory\n");
- return NULL;
- }
-
- for (i = 0, j = 0; buf[i]; j++) {
- uint16_t znak;
- int ret, k;
-
- ret = gg_utf8_helper(&buf[i], len - i, &znak);
-
- if (ret > 0) {
- i += ret;
- } else {
- znak = '?';
- i++;
- }
-
- if (znak < 0x80) {
- newbuf[j] = (char)znak;
- continue;
- }
-
- newbuf[j] = '?';
-
- for (k = 0; k < (sizeof(table_cp1250)/sizeof(table_cp1250[0])); k++) {
- if (table_cp1250[k] == znak) {
- newbuf[j] = (0x80 | k);
- break;
- }
- }
- }
- newbuf[j] = '\0';
-
- return newbuf;
-}
-
-/*
- * Local variables:
- * c-indentation-style: k&r
- * c-basic-offset: 8
- * indent-tabs-mode: notnil
- * End:
- *
- * vim: shiftwidth=8:
- */
diff --git a/protocols/Gadu-Gadu/libgadu/compat.h b/protocols/Gadu-Gadu/libgadu/compat.h deleted file mode 100644 index 1aa17d1e4a..0000000000 --- a/protocols/Gadu-Gadu/libgadu/compat.h +++ /dev/null @@ -1,36 +0,0 @@ -/* coding: UTF-8 */
-/* $Id: compat.h 11075 2009-12-20 15:01:43Z dezred $ */
-
-/*
- * (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 compat.h
- *
- * \brief Makra zapewniające kompatybilność API na różnych systemach
- */
-
-#ifndef __COMPAT_H
-#define __COMPAT_H
-
-#ifdef sun
-# define INADDR_NONE ((in_addr_t) 0xffffffff)
-#endif
-
-#endif
diff --git a/protocols/Gadu-Gadu/libgadu/dcc.c b/protocols/Gadu-Gadu/libgadu/dcc.c deleted file mode 100644 index 2fbe1b430c..0000000000 --- a/protocols/Gadu-Gadu/libgadu/dcc.c +++ /dev/null @@ -1,1363 +0,0 @@ -/* coding: UTF-8 */
-/* $Id: dcc.c 12145 2010-07-07 23:49:04Z dezred $ */
-
-/*
- * (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
- */
-
-#ifndef _WIN64
-#define _USE_32BIT_TIME_T
-#endif
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#ifdef _WIN32
-#include "win32.h"
-#else
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#ifdef sun
-# include <sys/filio.h>
-#endif
-#endif /* _WIN32 */
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#ifndef _WIN32
-#include <unistd.h>
-#endif
-
-#include "compat.h"
-#include "libgadu.h"
-
-#ifdef _WIN32
-#undef small
-#endif
-
-#ifndef GG_DEBUG_DISABLE
-
-/**
- * \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, SOCKET fd, const void *buf, unsigned int size)
-{
- unsigned int i;
-
- gg_debug(GG_DEBUG_MISC, "++ gg_dcc %s (fd=%d,len=%d)", prefix, fd, size);
-
- for (i = 0; i < size; i++)
- gg_debug(GG_DEBUG_MISC, " %.2x", ((unsigned char*) buf)[i]);
-
- gg_debug(GG_DEBUG_MISC, "\n");
-}
-#else
-#define gg_dcc_debug_data(a,b,c,d) do { } while (0)
-#endif
-
-/**
- * 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, (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(time_t ut, uint32_t *ft)
-{
-#ifdef GG_CONFIG_HAVE_LONG_LONG
- unsigned long long tmp;
-
- tmp = ut;
- tmp += 11644473600LL;
- tmp *= 10000000LL;
-
-#ifndef GG_CONFIG_BIGENDIAN
- ft[0] = (uint32_t) tmp;
- ft[1] = (uint32_t) (tmp >> 32);
-#else
- ft[0] = gg_fix32((uint32_t) (tmp >> 32));
- ft[1] = gg_fix32((uint32_t) tmp);
-#endif
-
-#endif
-}
-
-/**
- * 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 (stat(local_filename, &st) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() stat() failed (%s)\n", strerror(errno));
- 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;
- return -1;
- }
-
- if ((d->file_fd = open(local_filename, O_RDONLY | O_BINARY)) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() open() failed (%s)\n", strerror(errno));
- 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 */
-
-#ifdef _WIN32
- if (!(name = strrchr(filename, '\\')))
-#else
- if (!(name = strrchr(filename, '/')))
-#endif
- 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, %ld, %ld, %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_watch_fd() i zachowuje wynik w polu \c event.
- *
- * \note Funkcjonalność funkcjo 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)
- *
- * \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;
- struct sockaddr_in sin;
- SOCKET sock;
- int 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 == -1)
- port = GG_DEFAULT_DCC_PORT;
-
- while (!bound) {
- 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");
- gg_sock_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;
- gg_sock_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");
- gg_sock_close(sock);
- return NULL;
- }
- memset(c, 0, sizeof(*c));
-
- c->port = c->id = port;
- c->fd = sock;
- 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 (gg_sock_write(d->fd, &packet, sizeof(packet)) < (signed)sizeof(packet)) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_voice_send() write() failed\n");
- return -1;
- }
- gg_dcc_debug_data("write", d->fd, &packet, sizeof(packet));
-
- if (gg_sock_write(d->fd, buf, length) < length) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_voice_send() write() 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 = gg_sock_read(fd, buf, size); \
- \
- if (tmp < (int) size) { \
- if (tmp == -1) { \
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed (errno=%d, %s)\n", errno, strerror(errno)); \
- } else if (tmp == 0) { \
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed, connection broken\n"); \
- } else { \
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed (%d bytes, %d 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 tmp; \
- gg_dcc_debug_data("write", fd, buf, size); \
- tmp = gg_sock_write(fd, buf, size); \
- if (tmp < (int) size) { \
- if (tmp == -1) { \
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() write() failed (errno=%d, %s)\n", errno, strerror(errno)); \
- } else { \
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() write() failed (%d needed, %d done)\n", size, tmp); \
- } \
- 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;
- SOCKET fd;
- int one = 1;
- unsigned int 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));
-
-#ifdef FIONBIO
- if (ioctl(fd, FIONBIO, &one) == -1) {
-#else
- if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
-#endif
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() can't set nonblocking (errno=%d, %s)\n", errno, strerror(errno));
- gg_sock_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);
- gg_sock_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;
- struct gg_dcc_small_packet small;
- struct gg_dcc_big_packet big;
- int size, tmp, res;
- unsigned int utmp, res_size = sizeof(res);
- char buf[1024], ack[] = "UDAG";
-
- 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, 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, sizeof(small));
-
- small.type = gg_fix32(small.type);
-
- switch (small.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 %ld\n", small.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, sizeof(small));
-
- small.type = gg_fix32(small.type);
-
- switch (small.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 %ld\n", small.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.type = gg_fix32(0x0006); /* XXX */
- big.dunno1 = gg_fix32(h->offset);
- big.dunno2 = 0;
-
- gg_dcc_write(h->fd, &big, sizeof(big));
-
- h->state = GG_STATE_READING_FILE_HEADER;
- h->chunk_size = sizeof(big);
- h->chunk_offset = 0;
- if (!(h->chunk_buf = malloc(sizeof(big)))) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() out of memory\n");
- free(e);
- return NULL;
- }
- 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.type = 0x01; /* XXX */
-
- gg_dcc_write(h->fd, &tiny, sizeof(tiny));
-
- 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 = gg_sock_read(h->fd, h->chunk_buf + h->chunk_offset, h->chunk_size - h->chunk_offset);
-
- if (tmp == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() read() 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, h->chunk_buf, sizeof(big));
- free(h->chunk_buf);
- h->chunk_buf = NULL;
-
- big.type = gg_fix32(big.type);
- h->chunk_size = gg_fix32(big.dunno1);
- h->chunk_offset = 0;
-
- if (big.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, sizeof(tiny));
-
- switch (tiny.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.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, sizeof(small));
-
- small.type = gg_fix32(small.type);
-
- if (small.type < 16 || small.type > sizeof(buf)) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() invalid voice frame size (%d)\n", small.type);
- e->type = GG_EVENT_DCC_ERROR;
- e->event.dcc_error = GG_ERROR_DCC_NET;
-
- return e;
- }
-
- h->chunk_size = small.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 = gg_sock_read(h->fd, h->voice_buf + h->chunk_offset, h->chunk_size - h->chunk_offset);
- if (tmp < 1) {
- if (tmp == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed (errno=%d, %s)\n", errno, strerror(errno));
- } else {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() 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 = gg_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, 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.type = gg_fix32(0x0003);
-
- gg_dcc_write(h->fd, &small, sizeof(small));
-
- 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.type = (h->type == GG_SESSION_DCC_GET) ? gg_fix32(0x0003) : gg_fix32(0x0002); /* XXX */
-
- gg_dcc_write(h->fd, &small, sizeof(small));
-
- 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.type = gg_fix32(0x0001); /* XXX */
-
- gg_dcc_write(h->fd, &small, sizeof(small));
-
- 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, sizeof(big));
-
- /* XXX sprawdzać wynik */
- h->offset = gg_fix32(big.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, sizeof(tiny));
-
- if (tiny.type != 0x01) {
- gg_debug(GG_DEBUG_MISC, "// invalid reply (%.2x), connection refused\n", tiny.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.type = gg_fix32(0x0003); /* XXX */
- } else
- big.type = gg_fix32(0x0002); /* XXX */
-
- big.dunno1 = gg_fix32(h->chunk_size);
- big.dunno2 = 0;
-
- gg_dcc_write(h->fd, &big, sizeof(big));
-
- 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;
- }
-
- lseek(h->file_fd, h->offset, SEEK_SET);
-
- 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 = gg_sock_write(h->fd, buf, size);
-
- if (tmp == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() write() 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() write() 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 = gg_sock_read(h->fd, buf, utmp);
-
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() ofs=%d, size=%d, read()=%d\n", h->offset, h->file_info.size, size);
-
- /* 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_NET;
-
- return e;
- }
-
- /* koniec? */
- 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;
- }
-
- 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);
- if (!(h->chunk_buf = malloc(sizeof(big)))) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() out of memory\n");
- free(e);
- return NULL;
- }
- } 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)
- gg_sock_close(d->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:
- */
diff --git a/protocols/Gadu-Gadu/libgadu/dcc7.c b/protocols/Gadu-Gadu/libgadu/dcc7.c deleted file mode 100644 index f3813e6e83..0000000000 --- a/protocols/Gadu-Gadu/libgadu/dcc7.c +++ /dev/null @@ -1,1655 +0,0 @@ -/* coding: UTF-8 */
-/* $Id: dcc7.c,v 1.2 2007-07-20 23:00:49 wojtekka Exp $ */
-
-/*
- * (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
- */
-
-#ifndef _WIN64
-#define _USE_32BIT_TIME_T
-#endif
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#ifdef _WIN32
-#include "win32.h"
-#else
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#ifdef sun
-# include <sys/filio.h>
-#endif
-#endif /* _WIN32 */
-#include <time.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#ifndef _WIN32
-#include <unistd.h>
-#endif
-
-#include "compat.h"
-#include "libgadu.h"
-#include "protocol.h"
-#include "resolver.h"
-#include "internal.h"
-
-/**
- * \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_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_FUNCTION, "** gg_dcc7_get_relay_addr(%p)\n", dcc);
-
- if (dcc == NULL || dcc->sess == NULL) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, 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_session((dcc) ? (dcc)->sess : NULL, 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_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_FUNCTION, "** gg_dcc7_connect(%p)\n", dcc);
-
- if (dcc == NULL) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, 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_session((dcc) ? (dcc)->sess : NULL, 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 port Preferowany port (jeśli równy 0 lub -1, próbuje się domyślnego)
- *
- * \return 0 jeśli się powiodło, -1 w przypadku błędu
- */
-static int gg_dcc7_listen(struct gg_dcc7 *dcc, uint16_t port)
-{
- struct sockaddr_in sin;
- SOCKET fd;
-
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_FUNCTION, "** gg_dcc7_listen(%p, %d)\n", dcc, port);
-
- if (!dcc) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, 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_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_listen() can't create socket (%s)\n", strerror(errno));
- return -1;
- }
-
- // XXX losować porty?
-
- if (!port)
- port = GG_DEFAULT_DCC_PORT;
-
- while (1) {
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = INADDR_ANY;
- sin.sin_port = htons(port);
-
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_listen() trying port %d\n", port);
-
- if (!bind(fd, (struct sockaddr*) &sin, sizeof(sin)))
- break;
-
- if (port++ == 65535) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_listen() no free port found\n");
- gg_sock_close(fd);
- errno = ENOENT;
- return -1;
- }
- }
-
- if (listen(fd, 1)) {
- int errsv = errno;
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_listen() unable to listen (%s)\n", strerror(errno));
- gg_sock_close(fd);
- errno = errsv;
- return -1;
- }
-
- dcc->fd = fd;
- dcc->local_port = port;
-
- dcc->state = GG_STATE_LISTENING;
- dcc->check = GG_CHECK_READ;
- dcc->timeout = GG_DCC7_TIMEOUT_FILE_ACK;
-
- return 0;
-}
-
-/**
- * \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;
- uint16_t local_port;
- uint32_t count;
-
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_FUNCTION, "** gg_dcc7_listen_and_send_info(%p)\n", dcc);
-
- if (!dcc->sess->client_port)
- local_port = dcc->sess->external_port;
- else
- local_port = dcc->sess->client_port;
-
- if (gg_dcc7_listen(dcc, local_port) == -1)
- return -1;
-
- if (!dcc->sess->external_port || dcc->local_port != local_port)
- external_port = dcc->local_port;
- else
- external_port = dcc->sess->external_port;
-
- if (!dcc->sess->external_addr || dcc->local_port != local_port)
- dcc->local_addr = dcc->sess->client_addr;
- else
- dcc->local_addr = dcc->sess->external_addr;
-
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// dcc7_listen_and_send_info() sending IP address %s and port %d\n", inet_ntoa(*((struct in_addr*) &dcc->local_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(*((struct in_addr*) &dcc->local_addr)), external_port);
- // TODO: implement hash count
- // we MUST fill hash to recive from server request for server connection
- //snprintf((char*) pkt.hash, sizeof(pkt.hash), "0");
- count = dcc->local_addr + external_port * rand();
- snprintf((char*) pkt.hash, sizeof(pkt.hash), "%d", count);
-
- 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_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_FUNCTION, "** gg_dcc7_reverse_connect(%p)\n", dcc);
-
- if (dcc->reverse) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_reverse_connect() already reverse connection\n");
- return -1;
- }
-
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_reverse_connect() timeout, trying reverse connection\n");
- gg_sock_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 = (unsigned int)size;
- dcc->seek = seek;
-
- strncpy((char*) dcc->filename, filename1250, GG_DCC7_FILENAME_LEN - 1);
- 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 (stat(filename, &st) == -1) {
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_send_file() stat() 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 ((fd = open(filename, O_RDONLY | O_BINARY)) == -1) {
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_send_file() open() failed (%s)\n", strerror(errno));
- goto fail;
- }
-
- if (!hash) {
- if (gg_file_hash_sha1(fd, (uint8_t*) hash_buf) == -1)
- goto fail;
-
- hash = hash_buf;
- }
-
-#ifdef _WIN32
- if ((tmp = strrchr(filename1250, '\\')))
-#else
- if ((tmp = strrchr(filename1250, '/')))
-#endif
- 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;
- 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, %u, \"%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_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_FUNCTION, "** gg_dcc7_accept(%p, %d)\n", dcc, offset);
-
- if (!dcc || !dcc->sess) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, 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_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_FUNCTION, "** gg_dcc7_reject(%p, %d)\n", dcc, reason);
-
- if (!dcc || !dcc->sess) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, 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);
-}
-
-/**
- * Przerwanie żądania przesłania pliku.
- *
- * \param dcc Struktura połączenia
- *
- * \return 0 jeśli się powiodło, -1 w przypadku błędu
- *
- * \ingroup dcc7
- */
-int gg_dcc7_abort(struct gg_dcc7 *dcc)
-{
- struct gg_dcc7_abort pkt;
-
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_FUNCTION, "** gg_dcc7_abort(%p)\n", dcc);
-
- if (!dcc || !dcc->sess) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_abort() invalid parameters\n");
- errno = EFAULT;
- return -1;
- }
-
- memset(&pkt, 0, sizeof(pkt));
- pkt.id = dcc->cid;
- pkt.uin_from = gg_fix32(dcc->uin);
- pkt.uin_to = gg_fix32(dcc->peer_uin);
-
- return gg_send_packet(dcc->sess, GG_DCC7_ABORT, &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, void *payload, int len)
-{
- 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);
-
- strncpy((char*) s.filename, (char*) tmp->filename, GG_DCC7_FILENAME_LEN);
-
- 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, void *payload, int len)
-{
- 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;
- e->event.dcc7_error_ex.dcc7 = dcc;
- 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;
- e->event.dcc7_error_ex.dcc7 = dcc;
- 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, void *payload, int len)
-{
- 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;
- e->event.dcc7_error_ex.dcc7 = dcc;
- 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;
- e->event.dcc7_error_ex.dcc7 = dcc;
- return 0;
- }
-
- if (dcc->state == GG_STATE_WAITING_FOR_INFO) {
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() wainting for info so send one\n");
- gg_dcc7_listen_and_send_info(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;
- e->event.dcc7_error_ex.dcc7 = dcc;
- return 0;
- }
-
-#if defined(GG_CONFIG_HAVE_UINT64_T) && defined(GG_CONFIG_HAVE_STRTOULL)
- {
- uint64_t cid;
-
- cid = strtoull(tmp + 2, NULL, 0);
-
- 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;
- e->event.dcc7_error_ex.dcc7 = dcc;
- return 0;
- }
- }
-#endif
-
- if (gg_dcc7_get_relay_addr(dcc) == -1) {
- gg_debug_session(sess, 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;
- e->event.dcc7_error_ex.dcc7 = dcc;
- 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);
-
- break;
-
- 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;
- e->event.dcc7_error_ex.dcc7 = dcc;
- return 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;
-// e->event.dcc7_error_ex.dcc7 = dcc;
-// return 0;
-// }
-
- if (dcc->state == GG_STATE_LISTENING) {
- gg_sock_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 (dcc->state == GG_STATE_RESOLVING_RELAY)
- return 0;
-
- 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;
- e->event.dcc7_error_ex.dcc7 = dcc;
- 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, void *payload, int len)
-{
- 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;
- e->event.dcc7_error_ex.dcc7 = dcc;
- 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 przerwania żądania 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_abort(struct gg_session *sess, struct gg_event *e, void *payload, int len)
-{
- struct gg_dcc7_aborted *p = payload;
- struct gg_dcc7 *dcc;
-
- gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_handle_abort(%p, %p, %p, %d)\n", sess, e, payload, len);
-
- if (!(dcc = gg_dcc7_session_find(sess, p->id, gg_fix32(0)))) {
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_abort() unknown dcc session\n");
- return 0;
- }
-
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_abort() state %d\n", dcc->state);
-
- if (dcc->state != GG_STATE_IDLE) {
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_abort() invalid state\n");
- e->type = GG_EVENT_DCC7_ERROR;
- e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE;
- e->event.dcc7_error_ex.dcc7 = dcc;
- return 0;
- }
-
- e->type = GG_EVENT_DCC7_REJECT;
- e->event.dcc7_reject.dcc7 = dcc;
- e->event.dcc7_reject.reason = gg_fix32(GG_DCC7_REJECT_USER);
-
- // 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, void *payload, int len)
-{
- 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 - 1);
- 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 %ld\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_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_FUNCTION, "** gg_dcc7_postauth_fixup(%p)\n", dcc);
-
- if (!dcc) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, 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_session((dcc) ? (dcc)->sess : NULL, 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_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() invalid parameters\n");
- errno = EINVAL;
- return NULL;
- }
-
- if (!(e = malloc(sizeof(struct gg_event)))) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, 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;
- SOCKET fd;
- int one = 1;
- unsigned int sin_len = sizeof(sin);
-
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_LISTENING\n");
-
- if ((fd = accept(dcc->fd, (struct sockaddr*) &sin, &sin_len)) == -1) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() accept() failed (%s)\n", strerror(errno));
- return e;
- }
-
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() connection from %s:%d\n", inet_ntoa(sin.sin_addr), htons(sin.sin_port));
-
-#ifdef FIONBIO
- if (ioctl(fd, FIONBIO, &one) == -1) {
-#else
- if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
-#endif
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() can't set nonblocking (%s)\n", strerror(errno));
- gg_sock_close(fd);
- e->type = GG_EVENT_DCC7_ERROR;
- e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE;
- e->event.dcc7_error_ex.dcc7 = dcc;
- return e;
- }
-
- gg_sock_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;
- unsigned int error_size = sizeof(error);
-
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_CONNECTING\n");
-
- dcc->soft_timeout = 0;
-
- if (dcc->timeout == 0)
- error = ETIMEDOUT;
-
- if (error || (res = gg_getsockopt(dcc->fd, SOL_SOCKET, SO_ERROR, &error, &error_size)) == -1 || error != 0) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, 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_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() no relay available");
- e->type = GG_EVENT_DCC7_ERROR;
- e->event.dcc7_error = GG_ERROR_DCC7_RELAY;
- e->event.dcc7_error_ex.dcc7 = dcc;
- 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.dcc7_error = GG_ERROR_DCC7_NET;
- e->event.dcc7_error_ex.dcc7 = dcc;
- }
-
- return e;
- }
- }
-
- gg_debug_session((dcc) ? (dcc)->sess : NULL, 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_session((dcc) ? (dcc)->sess : NULL, 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 = gg_sock_read(dcc->fd, &welcome, sizeof(welcome))) != sizeof(welcome)) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() read() failed (%d, %s)\n", res, strerror(errno));
- e->type = GG_EVENT_DCC7_ERROR;
- e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE;
- e->event.dcc7_error_ex.dcc7 = dcc;
- return e;
- }
-
- if (memcmp(&welcome, &welcome_ok, sizeof(welcome))) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() invalid id\n");
- e->type = GG_EVENT_DCC7_ERROR;
- e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE;
- e->event.dcc7_error_ex.dcc7 = dcc;
- 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 = gg_sock_read(dcc->fd, &welcome, sizeof(welcome))) != sizeof(welcome)) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() read() failed (%d, %s)\n", res, strerror(errno));
- e->type = GG_EVENT_DCC7_ERROR;
- e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE;
- e->event.dcc7_error_ex.dcc7 = dcc;
- return e;
- }
-
- if (memcmp(&welcome, &welcome_ok, sizeof(welcome)) != 0) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() invalid id\n");
- e->type = GG_EVENT_DCC7_ERROR;
- e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE;
- e->event.dcc7_error_ex.dcc7 = dcc;
- 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_session((dcc) ? (dcc)->sess : NULL, 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 = gg_sock_write(dcc->fd, &welcome, sizeof(welcome))) != sizeof(welcome)) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() write() failed (%d, %s)", res, strerror(errno));
- e->type = GG_EVENT_DCC7_ERROR;
- e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE;
- e->event.dcc7_error_ex.dcc7 = dcc;
- return e;
- }
- } else {
- struct gg_dcc7_welcome_server welcome;
-
- welcome.magic = gg_fix32(GG_DCC7_WELCOME_SERVER);
- welcome.id = dcc->cid;
-
- if ((res = gg_sock_write(dcc->fd, &welcome, sizeof(welcome))) != sizeof(welcome)) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() write() failed (%d, %s)\n", res, strerror(errno));
- e->type = GG_EVENT_DCC7_ERROR;
- e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE;
- e->event.dcc7_error_ex.dcc7 = dcc;
- 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];
- int chunk, res;
-
- gg_debug_session((dcc) ? (dcc)->sess : NULL, 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_session((dcc) ? (dcc)->sess : NULL, 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_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() lseek() failed (%s)\n", strerror(errno));
- e->type = GG_EVENT_DCC7_ERROR;
- e->event.dcc7_error = GG_ERROR_DCC7_FILE;
- e->event.dcc7_error_ex.dcc7 = dcc;
- return e;
- }
-
- if ((chunk = dcc->size - dcc->offset) > sizeof(buf))
- chunk = sizeof(buf);
-
- if ((res = read(dcc->file_fd, buf, chunk)) < 1) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() read() failed (res=%d, %s)\n", res, strerror(errno));
- e->type = GG_EVENT_DCC7_ERROR;
- e->event.dcc7_error = (res == -1) ? GG_ERROR_DCC7_FILE : GG_ERROR_DCC7_EOF;
- e->event.dcc7_error_ex.dcc7 = dcc;
- return e;
- }
-
- if ((res = gg_sock_write(dcc->fd, buf, res)) == -1) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() write() failed (%s)\n", strerror(errno));
- e->type = GG_EVENT_DCC7_ERROR;
- e->event.dcc7_error = GG_ERROR_DCC7_NET;
- e->event.dcc7_error_ex.dcc7 = dcc;
- return e;
- }
-
- dcc->offset += res;
-
- if (dcc->offset >= dcc->size) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, 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_session((dcc) ? (dcc)->sess : NULL, 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_session((dcc) ? (dcc)->sess : NULL, 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 = gg_sock_read(dcc->fd, buf, sizeof(buf))) < 1) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() read() failed (fd=%d, res=%d, %s)\n", dcc->fd, res, strerror(errno));
- e->type = GG_EVENT_DCC7_ERROR;
- e->event.dcc7_error = (res == -1) ? GG_ERROR_DCC7_NET : GG_ERROR_DCC7_EOF;
- e->event.dcc7_error_ex.dcc7 = dcc;
- return e;
- }
-
- // XXX zapisywać do skutku?
-
- if ((wres = write(dcc->file_fd, buf, res)) < res) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, 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.dcc7_error = GG_ERROR_DCC7_FILE;
- e->event.dcc7_error_ex.dcc7 = dcc;
- return e;
- }
-
- dcc->offset += res;
-
- if (dcc->offset >= dcc->size) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, 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;
-
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_RESOLVING_RELAY\n");
-
- if (gg_sock_read(dcc->fd, &addr, sizeof(addr)) < sizeof(addr) || addr.s_addr == INADDR_NONE) {
- int errno_save = errno;
-
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() resolving failed\n");
- gg_sock_close(dcc->fd);
- dcc->fd = -1;
- dcc->sess->resolver_cleanup(&dcc->resolver, 0);
- errno = errno_save;
- e->type = GG_EVENT_DCC7_ERROR;
- e->event.dcc7_error = GG_ERROR_DCC7_RELAY;
- e->event.dcc7_error_ex.dcc7 = dcc;
- return e;
- }
-
- gg_debug_session((dcc) ? (dcc)->sess : NULL, 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_session((dcc) ? (dcc)->sess : NULL, 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.dcc7_error = GG_ERROR_DCC7_RELAY;
- e->event.dcc7_error_ex.dcc7 = dcc;
- return e;
- }
-
- dcc->state = GG_STATE_CONNECTING_RELAY;
- dcc->check = GG_CHECK_WRITE;
- dcc->timeout = GG_DEFAULT_TIMEOUT;
-
- return e;
- }
-
- case GG_STATE_CONNECTING_RELAY:
- {
- int res;
- unsigned int res_size = sizeof(res);
- struct gg_dcc7_relay_req pkt;
-
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_CONNECTING_RELAY\n");
-
- if (gg_getsockopt(dcc->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) != 0 || res != 0) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() connection failed (errno=%d, %s)\n", res, strerror(res));
- e->type = GG_EVENT_DCC7_ERROR;
- e->event.dcc7_error = GG_ERROR_DCC7_RELAY;
- e->event.dcc7_error_ex.dcc7 = dcc;
- 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_dump_session((dcc) ? (dcc)->sess : NULL, &pkt, sizeof(pkt), "// gg_dcc7_watch_fd() send pkt(0x%.2x)\n", gg_fix32(pkt.magic));
-
- if ((res = gg_sock_write(dcc->fd, &pkt, sizeof(pkt))) != sizeof(pkt)) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() sending failed\n");
- e->type = GG_EVENT_DCC7_ERROR;
- e->event.dcc7_error = GG_ERROR_DCC7_RELAY;
- e->event.dcc7_error_ex.dcc7 = dcc;
- 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;
- int res;
- int i;
-
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_READING_RELAY\n");
-
- if ((res = gg_sock_read(dcc->fd, buf, sizeof(buf))) < sizeof(*pkt)) {
- if (res == 0)
- errno = ECONNRESET;
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() read() failed (%d, %s)\n", res, strerror(errno));
- e->type = GG_EVENT_DCC7_ERROR;
- e->event.dcc7_error = GG_ERROR_DCC7_RELAY;
- e->event.dcc7_error_ex.dcc7 = dcc;
- 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_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_wathc_fd() invalid reply\n");
- errno = EINVAL;
- e->type = GG_EVENT_DCC7_ERROR;
- e->event.dcc7_error = GG_ERROR_DCC7_RELAY;
- e->event.dcc7_error_ex.dcc7 = dcc;
- return e;
- }
-
- gg_debug_dump_session((dcc) ? (dcc)->sess : NULL, buf, res, "// gg_dcc7_get_relay() read pkt(0x%.2x)\n", gg_fix32(pkt->magic));
-
- free(dcc->relay_list);
-
- dcc->relay_index = 0;
- dcc->relay_count = gg_fix32(pkt->rcount);
- dcc->relay_list = malloc(dcc->relay_count * sizeof(gg_dcc7_relay_t));
-
- if (dcc->relay_list == NULL) {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() not enough memory");
- 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_session((dcc) ? (dcc)->sess : NULL, 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_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() no relay available");
- e->type = GG_EVENT_DCC7_ERROR;
- e->event.dcc7_error = GG_ERROR_DCC7_RELAY;
- e->event.dcc7_error_ex.dcc7 = dcc;
- return e;
- }
-
- return e;
- }
-
- default:
- {
- gg_debug_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_???\n");
- e->type = GG_EVENT_DCC7_ERROR;
- e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE;
- e->event.dcc7_error_ex.dcc7 = dcc;
-
- 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_session((dcc) ? (dcc)->sess : NULL, GG_DEBUG_FUNCTION, "** gg_dcc7_free(%p)\n", dcc);
-
- if (!dcc)
- return;
-
- if (dcc->fd != -1)
- gg_sock_close(dcc->fd);
-
- if (dcc->file_fd != -1)
- close(dcc->file_fd);
-
- if (dcc->sess)
- gg_dcc7_session_remove(dcc->sess, dcc);
-
- free(dcc->relay_list);
-
- free(dcc);
-}
-
diff --git a/protocols/Gadu-Gadu/libgadu/events.c b/protocols/Gadu-Gadu/libgadu/events.c deleted file mode 100644 index a730e9d620..0000000000 --- a/protocols/Gadu-Gadu/libgadu/events.c +++ /dev/null @@ -1,2864 +0,0 @@ -/* coding: UTF-8 */ -/* $Id: events.c 13583 2011-04-12 12:51:18Z dezred $ */ - -/* - * (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ń - */ - -#ifndef _WIN64 -#define _USE_32BIT_TIME_T -#endif - -#include <sys/types.h> -#ifdef _WIN32 -#include "win32.h" -#else -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#endif /* _WIN32 */ - -#include "compat.h" -#include "libgadu.h" -#include "protocol.h" -#include "internal.h" - -#include <errno.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <time.h> -#ifndef _WIN32 -#include <unistd.h> -#include <ctype.h> -#endif /* _WIN32 */ -#ifndef GG_CONFIG_MIRANDA -#ifdef GG_CONFIG_HAVE_OPENSSL -# include <openssl/err.h> -# include <openssl/x509.h> -#endif -#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_XML_ACTION: - free(e->event.xml_action.data); - break; - - case GG_EVENT_USER_DATA: - { - unsigned 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; - } - } - - 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; -} - -/** - * \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 size Rozmiar pliku (z nagłówka) - * \param crc32 Suma kontrolna (z nagłówka) - */ -static void gg_image_queue_parse(struct gg_event *e, char *p, unsigned int len, struct gg_session *sess, uin_t sender, uint32_t size, uint32_t crc32) -{ - struct gg_image_queue *q, *qq; - - if (!p || !sess || !e) { - errno = EFAULT; - return; - } - - /* znajdź dany obrazek w kolejce danej sesji */ - - for (qq = sess->images, q = NULL; qq; qq = qq->next) { - if (sender == qq->sender && size == qq->size && crc32 == qq->crc32) { - q = qq; - break; - } - } - - if (!q) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_image_queue_parse() unknown image from %d, size=%d, crc32=%.8x\n", sender, size, crc32); - return; - } - - if (p[0] == 0x05) { - 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_MISC, "// gg_image_queue_parse() malformed packet from %d, unlimited filename\n", sender); - return; - } - - if (!(q->filename = strdup(p))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_image_queue_parse() not enough memory for filename\n"); - return; - } - - len -= (unsigned int)strlen(p) + 1; - p += strlen(p) + 1; - } else { - len -= sizeof(struct gg_msg_image_reply); - p += sizeof(struct gg_msg_image_reply); - } - - if (q->done + len > q->size) - len = q->size - q->done; - - memcpy(q->image + q->done, p, len); - q->done += len; - - /* jeśli skończono odbierać obrazek, wygeneruj zdarzenie */ - - if (q->done >= q->size) { - 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. - * - * \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, char *p, char *packet_end) -{ - while (p < packet_end) { - switch (*p) { - case 0x01: /* konferencja */ - { - struct gg_msg_recipients *m = (void*) p; - uint32_t i, count; - - if (p + sizeof(*m) > packet_end) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg_options() packet out of bounds (1)\n"); - goto malformed; - } - - memcpy(&count, &m->count, sizeof(count)); - count = gg_fix32(count); - p += sizeof(*m); - - 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 0x02: /* richtext */ - { - 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 0x04: /* image_request */ - { - struct gg_msg_image_request *i = (void*) p; - - if (p + sizeof(*i) > packet_end) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg_options() packet out of bounds (3.5)\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; - } - - memcpy(&e->event.image_request.size, &i->size, sizeof(i->size)); - memcpy(&e->event.image_request.crc32, &i->crc32, sizeof(i->crc32)); - - e->event.image_request.sender = sender; - e->event.image_request.size = gg_fix32(e->event.image_request.size); - e->event.image_request.crc32 = gg_fix32(e->event.image_request.crc32); - - e->type = GG_EVENT_IMAGE_REQUEST; - - goto handled; - } - - case 0x05: /* image_reply */ - case 0x06: - { - struct gg_msg_image_reply *rep = (void*) p; - uint32_t size; - uint32_t crc32; - - 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) + 1 > packet_end) { - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg_options() packet out of bounds (4)\n"); - goto malformed; - } - - memcpy(&size, &rep->size, sizeof(size)); - memcpy(&crc32, &rep->crc32, sizeof(crc32)); - size = gg_fix32(size); - crc32 = gg_fix32(crc32); - - 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 = crc32; - e->event.image_reply.filename = NULL; - e->event.image_reply.image = NULL; - goto handled; - - } - - gg_image_queue_parse(e, p, (unsigned int)(packet_end - p), sess, sender, size, crc32); - - goto handled; - } - - default: - { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg_options() unknown payload 0x%.2x\n", *p); - p = packet_end; - } - } - } - - return 0; - -handled: - return -1; - -fail: - return -2; - -malformed: - return -3; -} - -/** - * \internal Analizuje przychodzący pakiet z wiadomością. - * - * Rozbija pakiet na poszczególne składniki -- tekst, informacje - * o konferencjach, formatowani itd. - * - * \param h Wskaźnik do odebranego pakietu - * \param e Struktura zdarzenia - * \param sess Struktura sesji - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -static int gg_handle_recv_msg(struct gg_header *h, struct gg_event *e, struct gg_session *sess) -{ - struct gg_recv_msg *r = (struct gg_recv_msg*) ((char*) h + sizeof(struct gg_header)); - char *p, *packet_end = (char*) r + h->length; - int ctcp = 0; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_handle_recv_msg(%p, %p);\n", h, e); - - if (!r->seq && !r->msgclass) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() oops, silently ignoring the bait\n"); - e->type = GG_EVENT_NONE; - return 0; - } - - /* znajdź \0 */ - for (p = (char*) r + sizeof(*r); ; p++) { - if (p >= packet_end) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() malformed packet, message out of bounds (0)\n"); - goto malformed; - } - - if (*p == 0x02 && p == packet_end - 1) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() received ctcp packet\n"); - ctcp = 1; - break; - } - - if (!*p) - break; - } - - p++; - - switch (gg_handle_recv_msg_options(sess, e, gg_fix32(r->sender), p, packet_end)) { - case -1: // handled - 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); - if (ctcp) - e->event.msg.message = (unsigned char*) strdup("\x02"); - else - e->event.msg.message = (unsigned char*) strdup((char*) r + sizeof(*r)); - - - return 0; - -malformed: - e->type = GG_EVENT_NONE; - free(e->event.msg.message); - free(e->event.msg.recipients); - free(e->event.msg.formats); - - return 0; - -fail: - free(e->event.msg.message); - free(e->event.msg.recipients); - free(e->event.msg.formats); - return -1; -} - -/** - * \internal Zamienia tekst w formacie HTML na czysty tekst. - * - * \param dst Bufor wynikowy (może być \c NULL) - * \param html Tekst źródłowy - * - * \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). - */ -static int gg_convert_from_html(char *dst, const char *html) -{ - const char *src, *entity, *tag; - int len, in_tag, in_entity; - - len = 0; - in_tag = 0; - tag = NULL; - in_entity = 0; - entity = NULL; - - for (src = html; *src != 0; src++) { - 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++; - } - 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 - dst[len] = '?'; - } - len++; - continue; - } - - if (in_entity && !(isalnum(*src) || *src == '#')) - in_entity = 0; - - if (in_entity) - continue; - - if (dst != NULL) - dst[len] = *src; - - len++; - } - - if (dst != NULL) - dst[len] = 0; - - return len; -} - -/** - * \internal Analizuje przychodzący pakiet z wiadomością protokołu Gadu-Gadu 8.0. - * - * Rozbija pakiet na poszczególne składniki -- tekst, informacje - * o konferencjach, formatowani itd. - * - * \param h Wskaźnik do odebranego pakietu - * \param e Struktura zdarzenia - * \param sess Struktura sesji - * \param event Typ zdarzenia - * - * \return 0 jeśli się powiodło, -1 w przypadku błędu - */ -static int gg_handle_recv_msg80(struct gg_header *h, struct gg_event *e, struct gg_session *sess, int event) -{ - char *packet = (char*) h + sizeof(struct gg_header); - struct gg_recv_msg80 *r = (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, %p);\n", h, e); - - if (!r->seq && !r->msgclass) { - 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 >= h->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 > h->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. */ - /* goto ignore; */ - } - - /* Normalna sytuacja, więc nie podpada pod powyższy warunek. */ - if (offset_attr == h->length) - offset_attr = 0; - - if (memchr(packet + offset_plain, 0, h->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 = event; - 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 + h->length)) { - case -1: // handled - 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); - } else { - if (offset_plain > sizeof(struct gg_recv_msg80)) { - int len; - - len = gg_convert_from_html(NULL, packet + sizeof(struct gg_recv_msg80)); - - e->event.msg.message = malloc(len + 1); - - if (e->event.msg.message == NULL) - goto fail; - - gg_convert_from_html((char*) e->event.msg.message, packet + sizeof(struct gg_recv_msg80)); - } else { - e->event.msg.message = (unsigned char*) gg_cp_to_utf8(packet + offset_plain); - } - } - - if (offset_plain > sizeof(struct gg_recv_msg80)) { - if (sess->encoding == GG_ENCODING_UTF8) - e->event.msg.xhtml_message = strdup(packet + sizeof(struct gg_recv_msg80)); - else - e->event.msg.xhtml_message = gg_utf8_to_cp(packet + sizeof(struct gg_recv_msg80)); - } else { - e->event.msg.xhtml_message = NULL; - } - - 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); - return 0; -} - -/** - * \internal Wysyła potwierdzenie odebrania wiadomości. - * - * \param sess Struktura sesji - * - * \return 0 jeśli się powiodło, -1 jeśli wystąpił błąd - */ -static int gg_handle_recv_msg_ack(struct gg_header *h, struct gg_session *sess) -{ - char *packet = (char*) h + sizeof(struct gg_header); - struct gg_recv_msg80 *r = (struct gg_recv_msg80*) packet; - struct gg_recv_msg_ack pkt; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_handle_recv_msg_ack(%p);\n", sess); - - if ((sess->protocol_features & GG_FEATURE_MSG_ACK) == 0) - return 0; - - pkt.seq = gg_fix32(r->seq); - - return gg_send_packet(sess, GG_RECV_MSG_ACK, &pkt, sizeof(pkt), NULL); -} - -/** - * \internal Analizuje przychodzący pakiet z danymi kontaktów. - * - * \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 - */ -static int gg_handle_user_data(struct gg_session *sess, struct gg_event *e, void *packet, size_t len) -{ - struct gg_user_data d; - char *p = (char*) packet; - char *packet_end = (char*) packet + len; - struct gg_event_user_data_user *users; - unsigned i, j; - int res = 0; - - gg_debug_session(sess, GG_DEBUG_MISC, "** gg_handle_user_data(%p, %p, %p, %d);\n", sess, e, packet, len); - - e->event.user_data.user_count = 0; - e->event.user_data.users = NULL; - - if (p + 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(sess, GG_DEBUG_MISC, "// gg_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(sess, GG_DEBUG_MISC, "// gg_handle_user_data() out of memory (%d*%d)\n", d.user_count, sizeof(struct gg_event_user_data_user)); - goto fail; - } - } else { - users = NULL; - } - - e->type = GG_EVENT_USER_DATA; - e->event.user_data.type = d.type; - e->event.user_data.user_count = d.user_count; - e->event.user_data.users = users; - - gg_debug_session(sess, 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(sess, GG_DEBUG_MISC, "// gg_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(sess, GG_DEBUG_MISC, "// gg_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(sess, GG_DEBUG_MISC, "// gg_handle_user_data() out of memory (%d*%d)\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(sess, 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(sess, GG_DEBUG_MISC, "// gg_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(sess, GG_DEBUG_MISC, "// gg_handle_user_data() malformed packet (3)\n"); - goto malformed; - } - - key = malloc(key_size + 1); - - if (key == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_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(sess, GG_DEBUG_MISC, "// gg_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(sess, GG_DEBUG_MISC, "// gg_handle_user_data() malformed packet (5)\n"); - goto malformed; - } - - value = malloc(value_size + 1); - - if (value == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_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(sess, GG_DEBUG_DUMP, " key=\"%s\", type=%d, value=\"%s\"\n", key, attr_type, value); - } - } - - return 0; - -fail: - res = -1; - -malformed: - e->type = GG_EVENT_NONE; - - 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); - - return res; -} - -/** - * \internal Analizuje przychodzący pakiet z listą sesji multilogowania. - * - * \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 - */ -static int gg_handle_multilogon_info(struct gg_session *sess, struct gg_event *e, void *packet, size_t len) -{ - char *packet_end = (char*) packet + len; - struct gg_multilogon_info *info = (struct gg_multilogon_info*) packet; - char *p = (char*) packet + sizeof(*info); - struct gg_multilogon_session *sessions = NULL; - size_t count; - size_t i; - int res = 0; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_handle_multilogon_info(%p, %p, %p, %d);\n", sess, e, packet, len); - - count = gg_fix32(info->count); - - if (count > 0xffff) { - gg_debug_session(sess, 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(sess, GG_DEBUG_MISC, "// gg_handle_multilogon_info() out of memory (%d*%d)\n", count, sizeof(struct gg_multilogon_session)); - return -1; - } - - e->type = GG_EVENT_MULTILOGON_INFO; - e->event.multilogon_info.count = (int)count; - e->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(sess, 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(sess, 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(sess, GG_DEBUG_MISC, "// gg_handle_multilogon_info() out of memory (%d)\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: - e->type = GG_EVENT_NONE; - - for (i = 0; i < (size_t)e->event.multilogon_info.count; i++) - free(e->event.multilogon_info.sessions[i].name); - - free(e->event.multilogon_info.sessions); - - return res; -} - -/** - * \internal Odbiera pakiet od serwera. - * - * Analizuje pakiet i wypełnia strukturę zdarzenia. - * - * \param sess Struktura sesji - * \param e Struktura zdarzenia - * - * \return 0 jeśli się powiodło, -1 jeśli wystąpił błąd - */ -static int gg_watch_fd_connected(struct gg_session *sess, struct gg_event *e) -{ - struct gg_header *h = NULL; - char *p; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_watch_fd_connected(%p, %p);\n", sess, e); - - if (!sess) { - errno = EFAULT; - return -1; - } - - if (!(h = gg_recv_packet(sess))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() gg_recv_packet failed (errno=%d, %s)\n", errno, strerror(errno)); - goto fail; - } - - p = (char*) h + sizeof(struct gg_header); - - switch (h->type) { - case GG_RECV_MSG: - { - if (h->length >= sizeof(struct gg_recv_msg)) { - if (gg_handle_recv_msg(h, e, sess) != -1) - gg_handle_recv_msg_ack(h, sess); - else - goto fail; - } - - break; - } - - case GG_RECV_MSG80: - { - if (h->length >= sizeof(struct gg_recv_msg80)) { - if (gg_handle_recv_msg80(h, e, sess, GG_EVENT_MSG) != -1) - gg_handle_recv_msg_ack(h, sess); - else - goto fail; - } - - break; - } - - case GG_RECV_OWN_MSG: - { - if (h->length >= sizeof(struct gg_recv_msg80)) { - if (gg_handle_recv_msg80(h, e, sess, GG_EVENT_MULTILOGON_MSG) == -1) - goto fail; - } - - break; - } - - case GG_NOTIFY_REPLY: - { - struct gg_notify_reply *n = (void*) p; - unsigned int count, i; - char *tmp; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n"); - - if (h->length < sizeof(*n)) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() incomplete packet\n"); - errno = EINVAL; - goto fail; - } - - 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) { - e->type = GG_EVENT_NOTIFY_DESCR; - - if (!(e->event.notify_descr.notify = (void*) malloc(sizeof(*n) * 2))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); - goto fail; - } - e->event.notify_descr.notify[1].uin = 0; - memcpy(e->event.notify_descr.notify, p, sizeof(*n)); - e->event.notify_descr.notify[0].uin = gg_fix32(e->event.notify_descr.notify[0].uin); - e->event.notify_descr.notify[0].status = gg_fix32(e->event.notify_descr.notify[0].status); - e->event.notify_descr.notify[0].remote_port = gg_fix16(e->event.notify_descr.notify[0].remote_port); - e->event.notify_descr.notify[0].version = gg_fix32(e->event.notify_descr.notify[0].version); - - count = h->length - sizeof(*n); - if (!(tmp = malloc(count + 1))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); - goto fail; - } - memcpy(tmp, p + sizeof(*n), count); - tmp[count] = 0; - e->event.notify_descr.descr = tmp; - - } else { - e->type = GG_EVENT_NOTIFY; - - if (!(e->event.notify = (void*) malloc(h->length + 2 * sizeof(*n)))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); - goto fail; - } - - memcpy(e->event.notify, p, h->length); - count = h->length / sizeof(*n); - e->event.notify[count].uin = 0; - - for (i = 0; i < count; i++) { - e->event.notify[i].uin = gg_fix32(e->event.notify[i].uin); - e->event.notify[i].status = gg_fix32(e->event.notify[i].status); - e->event.notify[i].remote_port = gg_fix16(e->event.notify[i].remote_port); - e->event.notify[i].version = gg_fix32(e->event.notify[i].version); - } - } - - break; - } - - case GG_STATUS: - { - struct gg_status *s = (void*) p; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a status change\n"); - - if (h->length >= sizeof(*s)) { - e->type = GG_EVENT_STATUS; - memcpy(&e->event.status, p, sizeof(*s)); - e->event.status.uin = gg_fix32(e->event.status.uin); - e->event.status.status = gg_fix32(e->event.status.status); - if (h->length > sizeof(*s)) { - int len = h->length - sizeof(*s); - char *buf = malloc(len + 1); - if (buf) { - memcpy(buf, p + sizeof(*s), len); - buf[len] = 0; - } - e->event.status.descr = buf; - } else - e->event.status.descr = NULL; - } - - break; - } - - case GG_NOTIFY_REPLY77: - case GG_NOTIFY_REPLY80BETA: - { - struct gg_notify_reply77 *n = (void*) p; - unsigned int length = h->length, i = 0; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n"); - - e->type = GG_EVENT_NOTIFY60; - e->event.notify60 = malloc(sizeof(*e->event.notify60)); - - if (!e->event.notify60) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); - goto fail; - } - - e->event.notify60[0].uin = 0; - - while (length >= sizeof(struct gg_notify_reply77)) { - uin_t uin = gg_fix32(n->uin); - char *tmp; - - e->event.notify60[i].uin = uin & 0x00ffffff; - e->event.notify60[i].status = n->status; - e->event.notify60[i].remote_ip = n->remote_ip; - e->event.notify60[i].remote_port = gg_fix16(n->remote_port); - e->event.notify60[i].version = n->version; - e->event.notify60[i].image_size = n->image_size; - e->event.notify60[i].descr = NULL; - e->event.notify60[i].time = 0; - - if (uin & 0x40000000) - e->event.notify60[i].version |= GG_HAS_AUDIO_MASK; - if (uin & 0x20000000) - e->event.notify60[i].version |= GG_HAS_AUDIO7_MASK; - if (uin & 0x08000000) - e->event.notify60[i].version |= GG_ERA_OMNIX_MASK; - - if (GG_S_D(n->status)) { - unsigned char descr_len = *((char*) n + sizeof(struct gg_notify_reply77)); - - if (sizeof(struct gg_notify_reply77) + descr_len <= length) { - char *descr; - - if (!(descr = malloc(descr_len + 1))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); - goto fail; - } - - memcpy(descr, (char*) n + sizeof(struct gg_notify_reply77) + 1, descr_len); - descr[descr_len] = 0; - - if (h->type == GG_NOTIFY_REPLY80BETA && sess->encoding != GG_ENCODING_UTF8) { - char *cp_descr = gg_utf8_to_cp(descr); - - if (!cp_descr) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); - free(descr); - goto fail; - } - - free(descr); - descr = cp_descr; - } - - e->event.notify60[i].descr = descr; - - /* XXX czas */ - - length -= sizeof(struct gg_notify_reply77) + descr_len + 1; - n = (void*) ((char*) n + sizeof(struct gg_notify_reply77) + descr_len + 1); - } else { - length = 0; - } - - } else { - length -= sizeof(struct gg_notify_reply77); - n = (void*) ((char*) n + sizeof(struct gg_notify_reply77)); - } - - if (!(tmp = realloc(e->event.notify60, (i + 2) * sizeof(*e->event.notify60)))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); - free(e->event.notify60); - goto fail; - } - - e->event.notify60 = (void*) tmp; - e->event.notify60[++i].uin = 0; - } - - break; - } - - case GG_STATUS77: - case GG_STATUS80BETA: - { - struct gg_status77 *s = (void*) p; - uint32_t uin; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a status change\n"); - - if (h->length < sizeof(*s)) - break; - - uin = gg_fix32(s->uin); - - e->type = GG_EVENT_STATUS60; - e->event.status60.uin = uin & 0x00ffffff; - e->event.status60.status = s->status; - e->event.status60.remote_ip = s->remote_ip; - e->event.status60.remote_port = gg_fix16(s->remote_port); - e->event.status60.version = s->version; - e->event.status60.image_size = s->image_size; - e->event.status60.descr = NULL; - e->event.status60.time = 0; - - if (uin & 0x40000000) - e->event.status60.version |= GG_HAS_AUDIO_MASK; - if (uin & 0x20000000) - e->event.status60.version |= GG_HAS_AUDIO7_MASK; - if (uin & 0x08000000) - e->event.status60.version |= GG_ERA_OMNIX_MASK; - - if (h->length > sizeof(*s)) { - int len = h->length - sizeof(*s); - char *buf = malloc(len + 1); - - /* XXX, jesli malloc() sie nie uda to robic tak samo jak przy GG_NOTIFY_REPLY* ? - * - goto fail; (?) - */ - if (buf) { - memcpy(buf, (char*) p + sizeof(*s), len); - buf[len] = 0; - - if (h->type == GG_STATUS80BETA && sess->encoding != GG_ENCODING_UTF8) { - char *cp_buf = gg_utf8_to_cp(buf); - free(buf); - buf = cp_buf; - } - } - - e->event.status60.descr = buf; - - if (len > 4 && p[h->length - 5] == 0) { - uint32_t t; - memcpy(&t, p + h->length - 4, sizeof(uint32_t)); - e->event.status60.time = gg_fix32(t); - } - } - - break; - } - - case GG_NOTIFY_REPLY60: - { - struct gg_notify_reply60 *n = (void*) p; - unsigned int length = h->length, i = 0; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n"); - - e->type = GG_EVENT_NOTIFY60; - e->event.notify60 = malloc(sizeof(*e->event.notify60)); - - if (!e->event.notify60) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); - goto fail; - } - - e->event.notify60[0].uin = 0; - - while (length >= sizeof(struct gg_notify_reply60)) { - uin_t uin = gg_fix32(n->uin); - char *tmp; - - e->event.notify60[i].uin = uin & 0x00ffffff; - e->event.notify60[i].status = n->status; - e->event.notify60[i].remote_ip = n->remote_ip; - e->event.notify60[i].remote_port = gg_fix16(n->remote_port); - e->event.notify60[i].version = n->version; - e->event.notify60[i].image_size = n->image_size; - e->event.notify60[i].descr = NULL; - e->event.notify60[i].time = 0; - - if (uin & 0x40000000) - e->event.notify60[i].version |= GG_HAS_AUDIO_MASK; - if (uin & 0x08000000) - e->event.notify60[i].version |= GG_ERA_OMNIX_MASK; - - if (GG_S_D(n->status)) { - unsigned char descr_len = *((char*) n + sizeof(struct gg_notify_reply60)); - - if (sizeof(struct gg_notify_reply60) + descr_len <= length) { - if (!(e->event.notify60[i].descr = malloc(descr_len + 1))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); - goto fail; - } - - memcpy(e->event.notify60[i].descr, (char*) n + sizeof(struct gg_notify_reply60) + 1, descr_len); - e->event.notify60[i].descr[descr_len] = 0; - - /* XXX czas */ - - length -= sizeof(struct gg_notify_reply60) + descr_len + 1; - n = (void*) ((char*) n + sizeof(struct gg_notify_reply60) + descr_len + 1); - } else { - length = 0; - } - - } else { - length -= sizeof(struct gg_notify_reply60); - n = (void*) ((char*) n + sizeof(struct gg_notify_reply60)); - } - - if (!(tmp = realloc(e->event.notify60, (i + 2) * sizeof(*e->event.notify60)))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); - free(e->event.notify60); - goto fail; - } - - e->event.notify60 = (void*) tmp; - e->event.notify60[++i].uin = 0; - } - - break; - } - - case GG_STATUS60: - { - struct gg_status60 *s = (void*) p; - uint32_t uin; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a status change\n"); - - if (h->length < sizeof(*s)) - break; - - uin = gg_fix32(s->uin); - - e->type = GG_EVENT_STATUS60; - e->event.status60.uin = uin & 0x00ffffff; - e->event.status60.status = s->status; - e->event.status60.remote_ip = s->remote_ip; - e->event.status60.remote_port = gg_fix16(s->remote_port); - e->event.status60.version = s->version; - e->event.status60.image_size = s->image_size; - e->event.status60.descr = NULL; - e->event.status60.time = 0; - - if (uin & 0x40000000) - e->event.status60.version |= GG_HAS_AUDIO_MASK; - if (uin & 0x08000000) - e->event.status60.version |= GG_ERA_OMNIX_MASK; - - if (h->length > sizeof(*s)) { - int len = h->length - sizeof(*s); - char *buf = malloc(len + 1); - - if (buf) { - memcpy(buf, (char*) p + sizeof(*s), len); - buf[len] = 0; - } - - e->event.status60.descr = buf; - - if (len > 4 && p[h->length - 5] == 0) { - uint32_t t; - memcpy(&t, p + h->length - 4, sizeof(uint32_t)); - e->event.status60.time = gg_fix32(t); - } - } - - break; - } - - case GG_STATUS80: - { - struct gg_notify_reply80 *s = (void*) p; - uint32_t descr_len; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a status change\n"); - - if (h->length < sizeof(*s)) - break; - - e->type = GG_EVENT_STATUS60; - e->event.status60.uin = gg_fix32(s->uin); - e->event.status60.status = gg_fix32(s->status); - e->event.status60.remote_ip = s->remote_ip; - e->event.status60.remote_port = gg_fix16(s->remote_port); - e->event.status60.image_size = s->image_size; - e->event.status60.descr = NULL; - e->event.status60.version = 0x00; /* not-supported */ - e->event.status60.time = 0; /* not-supported */ - - descr_len = gg_fix32(s->descr_len); - - if (descr_len > 0 && h->length-sizeof(*s) >= descr_len) { - char *buf = malloc(descr_len + 1); - - if (buf) { - memcpy(buf, (char*) p + sizeof(*s), descr_len); - buf[descr_len] = 0; - - if (sess->encoding != GG_ENCODING_UTF8) { - char *cp_buf = gg_utf8_to_cp(buf); - free(buf); - buf = cp_buf; - } - } - - e->event.status60.descr = buf; - } - break; - } - - case GG_NOTIFY_REPLY80: - { - struct gg_notify_reply80 *n = (void*) p; - unsigned int length = h->length, i = 0; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n"); - - e->type = GG_EVENT_NOTIFY60; - e->event.notify60 = malloc(sizeof(*e->event.notify60)); - - if (!e->event.notify60) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); - goto fail; - } - - e->event.notify60[0].uin = 0; - - while (length >= sizeof(struct gg_notify_reply80)) { - uint32_t descr_len; - char *tmp; - - e->event.notify60[i].uin = gg_fix32(n->uin); - e->event.notify60[i].status = gg_fix32(n->status); - e->event.notify60[i].remote_ip = n->remote_ip; - e->event.notify60[i].remote_port= gg_fix16(n->remote_port); - e->event.notify60[i].image_size = n->image_size; - e->event.notify60[i].descr = NULL; - e->event.notify60[i].version = 0x00; /* not-supported */ - e->event.notify60[i].time = 0; /* not-supported */ - - descr_len = gg_fix32(n->descr_len); - - length -= sizeof(struct gg_notify_reply80); - n = (void*) ((char*) n + sizeof(struct gg_notify_reply80)); - - if (descr_len) { - if (length >= descr_len) { - /* XXX, GG_S_D(n->status) */ - char *descr; - - if (!(descr = malloc(descr_len + 1))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); - goto fail; - } - - memcpy(descr, n, descr_len); - descr[descr_len] = 0; - - if (sess->encoding != GG_ENCODING_UTF8) { - char *cp_descr = gg_utf8_to_cp(descr); - - if (!cp_descr) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); - free(descr); - goto fail; - } - - free(descr); - descr = cp_descr; - } - e->event.notify60[i].descr = descr; - - length -= descr_len; - n = (void*) ((char*) n + descr_len); - } else - length = 0; - } - - if (!(tmp = realloc(e->event.notify60, (i + 2) * sizeof(*e->event.notify60)))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); - free(e->event.notify60); - goto fail; - } - - e->event.notify60 = (void*) tmp; - e->event.notify60[++i].uin = 0; - } - break; - } - - case GG_SEND_MSG_ACK: - { - struct gg_send_msg_ack *s = (void*) p; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a message ack\n"); - - if (h->length < sizeof(*s)) - break; - - e->type = GG_EVENT_ACK; - e->event.ack.status = gg_fix32(s->status); - e->event.ack.recipient = gg_fix32(s->recipient); - e->event.ack.seq = gg_fix32(s->seq); - - break; - } - - case GG_PONG: - { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a pong\n"); - - e->type = GG_EVENT_PONG; - sess->last_pong = (int)time(NULL); - - break; - } - - case GG_DISCONNECTING: - { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received disconnection warning\n"); - e->type = GG_EVENT_DISCONNECT; - break; - } - - case GG_DISCONNECT_ACK: - { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received disconnection acknowledge\n"); - e->type = GG_EVENT_DISCONNECT_ACK; - break; - } - - case GG_XML_EVENT: - { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received XML event\n"); - e->type = GG_EVENT_XML_EVENT; - if (!(e->event.xml_event.data = (char *) malloc(h->length + 1))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for XML event data\n"); - goto fail; - } - memcpy(e->event.xml_event.data, p, h->length); - e->event.xml_event.data[h->length] = 0; - break; - } - - case GG_XML_ACTION: - { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received XML action\n"); - e->type = GG_EVENT_XML_ACTION; - if (!(e->event.xml_action.data = (char *) malloc(h->length + 1))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for XML action data\n"); - goto fail; - } - memcpy(e->event.xml_action.data, p, h->length); - e->event.xml_action.data[h->length] = 0; - break; - } - - case GG_PUBDIR50_REPLY: - { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received pubdir/search reply\n"); - if (gg_pubdir50_handle_reply_sess(sess, e, p, h->length) == -1) - goto fail; - break; - } - - case GG_USERLIST_REPLY: - { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received userlist reply\n"); - - if (h->length < 1) - break; - - /* jeśli odpowiedź na eksport, wywołaj zdarzenie tylko - * gdy otrzymano wszystkie odpowiedzi */ - if (p[0] == GG_USERLIST_PUT_REPLY || p[0] == GG_USERLIST_PUT_MORE_REPLY) { - if (--sess->userlist_blocks) - break; - - p[0] = GG_USERLIST_PUT_REPLY; - } - - if (h->length > 1) { - char *tmp; - unsigned int len = (sess->userlist_reply) ? (unsigned int)strlen(sess->userlist_reply) : 0; - - gg_debug_session(sess, GG_DEBUG_MISC, "userlist_reply=%p, len=%d\n", sess->userlist_reply, len); - - if (!(tmp = realloc(sess->userlist_reply, len + h->length))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for userlist reply\n"); - free(sess->userlist_reply); - sess->userlist_reply = NULL; - goto fail; - } - - sess->userlist_reply = tmp; - sess->userlist_reply[len + h->length - 1] = 0; - memcpy(sess->userlist_reply + len, p + 1, h->length - 1); - } - - if (p[0] == GG_USERLIST_GET_MORE_REPLY) - break; - - e->type = GG_EVENT_USERLIST; - e->event.userlist.type = p[0]; - e->event.userlist.reply = sess->userlist_reply; - sess->userlist_reply = NULL; - - break; - } - - case GG_DCC7_ID_REPLY: - { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received dcc7 id packet\n"); - - if (h->length < sizeof(struct gg_dcc7_id_reply)) - break; - - if (gg_dcc7_handle_id(sess, e, p, h->length) == -1) - goto fail; - - break; - } - - case GG_DCC7_ACCEPT: - { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received dcc7 accept\n"); - - if (h->length < sizeof(struct gg_dcc7_accept)) - break; - - if (gg_dcc7_handle_accept(sess, e, p, h->length) == -1) - goto fail; - - break; - } - - case GG_DCC7_NEW: - { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received dcc7 request\n"); - - if (h->length < sizeof(struct gg_dcc7_new)) - break; - - if (gg_dcc7_handle_new(sess, e, p, h->length) == -1) - goto fail; - - break; - } - - case GG_DCC7_REJECT: - { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received dcc7 reject\n"); - - if (h->length < sizeof(struct gg_dcc7_reject)) - break; - - if (gg_dcc7_handle_reject(sess, e, p, h->length) == -1) - goto fail; - - break; - } - - case GG_DCC7_ABORT: - { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received dcc7 abort\n"); - - if (h->length < sizeof(struct gg_dcc7_aborted)) - break; - - if (gg_dcc7_handle_abort(sess, e, p, h->length) == -1) - goto fail; - - break; - } - - case GG_DCC7_INFO: - { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received dcc7 info\n"); - - if (h->length < sizeof(struct gg_dcc7_info)) - break; - - if (gg_dcc7_handle_info(sess, e, p, h->length) == -1) - goto fail; - - break; - } - - case GG_USER_DATA: - { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received user data\n"); - - if (h->length < sizeof(struct gg_user_data)) - break; - - if (gg_handle_user_data(sess, e, p, h->length) == -1) - goto fail; - - break; - } - - case GG_TYPING_NOTIFICATION: - { - struct gg_typing_notification *n = (void*) p; - uin_t uin; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received typing notification\n"); - - if (h->length < sizeof(*n)) - break; - - memcpy(&uin, &n->uin, sizeof(uin_t)); - - e->type = GG_EVENT_TYPING_NOTIFICATION; - e->event.typing_notification.uin = gg_fix32(uin); - e->event.typing_notification.length = gg_fix16(n->length); - - break; - } - - case GG_MULTILOGON_INFO: - { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received multilogon info\n"); - - if (h->length < sizeof(struct gg_multilogon_info)) - break; - - if (gg_handle_multilogon_info(sess, e, p, h->length) == -1) - goto fail; - - break; - } - - default: - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received unknown packet 0x%.2x\n", h->type); - } - - free(h); - return 0; - -fail: - free(h); - return -1; -} - -/** \endcond */ - -/** - * 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 *e; - int res = 0; - int port = 0; - int errno2 = 0; - - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_watch_fd(%p);\n", sess); - - if (!sess) { - errno = EFAULT; - return NULL; - } - - if (!(e = (void*) calloc(1, sizeof(*e)))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() not enough memory for event data\n"); - return NULL; - } - - e->type = GG_EVENT_NONE; - - if (sess->send_buf && (sess->state == GG_STATE_READING_REPLY || sess->state == GG_STATE_CONNECTED)) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() sending %d bytes of queued data\n", sess->send_left); - - res = gg_sock_write(sess->fd, sess->send_buf, sess->send_left); - - if (res == -1 && errno != EAGAIN) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() write() failed (errno=%d, %s)\n", errno, strerror(errno)); - - if (sess->state == GG_STATE_READING_REPLY) - goto fail_connecting; - else - goto done; - } - - 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; - } - - res = 0; - } - - switch (sess->state) { - case GG_STATE_RESOLVING: - { - struct in_addr addr; - int failed = 0; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_RESOLVING\n"); - - if (gg_sock_read(sess->fd, &addr, sizeof(addr)) < (signed)sizeof(addr) || addr.s_addr == INADDR_NONE) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() resolving failed\n"); - failed = 1; - errno2 = errno; - } - - gg_sock_close(sess->fd); - sess->fd = -1; - - sess->resolver_cleanup(&sess->resolver, 0); - - if (failed) { - errno = errno2; - goto fail_resolving; - } - - /* jeśli jesteśmy w resolverze i mamy ustawiony port - * proxy, znaczy, że resolvowaliśmy proxy. zatem - * wpiszmy jego adres. */ - if (sess->proxy_port) - sess->proxy_addr = addr.s_addr; - - /* zapiszmy sobie adres huba i adres serwera (do - * bezpośredniego połączenia, jeśli hub leży) - * z resolvera. */ - if (sess->proxy_addr && sess->proxy_port) - port = sess->proxy_port; - else { - sess->server_addr = sess->hub_addr = addr.s_addr; - port = GG_APPMSG_PORT; - } - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() resolved, connecting to %s:%d\n", inet_ntoa(addr), port); - - /* łączymy się albo z hubem, albo z proxy, zależnie - * od tego, co resolvowaliśmy. */ - if ((sess->fd = gg_connect(&addr, port, sess->async)) == -1) { - /* jeśli w trybie asynchronicznym gg_connect() - * zwróci błąd, nie ma sensu próbować dalej. */ - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), critical\n", errno, strerror(errno)); - goto fail_connecting; - } - - /* jeśli podano serwer i łączmy się przez proxy, - * jest to bezpośrednie połączenie, inaczej jest - * do huba. */ - - if (sess->proxy_addr && sess->proxy_port && sess->server_addr) { - sess->state = GG_STATE_CONNECTING_GG; - sess->soft_timeout = 1; - } else - sess->state = GG_STATE_CONNECTING_HUB; - - sess->check = GG_CHECK_WRITE; - sess->timeout = GG_DEFAULT_TIMEOUT; - - break; - } - - case GG_STATE_CONNECTING_HUB: - { - char buf[1024], *client, *auth; - int res = 0; - unsigned int res_size = sizeof(res); - const char *host; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_CONNECTING_HUB\n"); - - /* jeśli asynchroniczne, sprawdzamy, czy nie wystąpił - * przypadkiem jakiś błąd. */ - if (sess->async && (gg_getsockopt(sess->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) { - if (sess->proxy_addr && sess->proxy_port) - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", res, strerror(res)); - else - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection to hub failed (errno=%d, %s)\n", res, strerror(res)); - - goto fail_connecting; - } - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connected to hub, sending query\n"); - - if (!(client = gg_urlencode((sess->client_version) ? sess->client_version : GG_DEFAULT_CLIENT_VERSION))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() out of memory for client version\n"); - goto fail_connecting; - } - - if (!gg_proxy_http_only && sess->proxy_addr && sess->proxy_port) - host = "http://" GG_APPMSG_HOST; - else - host = ""; - - auth = gg_proxy_auth(); - -#ifdef GG_CONFIG_MIRANDA - if (sess->tls) { - snprintf(buf, sizeof(buf) - 1, - "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 -#elif GG_CONFIG_HAVE_OPENSSL - if (sess->ssl != NULL) { - snprintf(buf, sizeof(buf) - 1, - "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 -#endif - { - snprintf(buf, sizeof(buf) - 1, - "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); - - /* zwolnij pamięć po wersji klienta. */ - if (sess->client_version) { - free(sess->client_version); - sess->client_version = NULL; - } - - gg_debug_session(sess, GG_DEBUG_MISC, "=> -----BEGIN-HTTP-QUERY-----\n%s\n=> -----END-HTTP-QUERY-----\n", buf); - - /* zapytanie jest krótkie, więc zawsze zmieści się - * do bufora gniazda. jeśli write() zwróci mniej, - * stało się coś złego. */ - if (gg_sock_write(sess->fd, buf, (int)strlen(buf)) < (signed)strlen(buf)) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() sending query failed\n"); - - e->type = GG_EVENT_CONN_FAILED; - e->event.failure = GG_FAILURE_WRITING; - sess->state = GG_STATE_IDLE; - gg_sock_close(sess->fd); - sess->fd = -1; - break; - } - - sess->state = GG_STATE_READING_DATA; - sess->check = GG_CHECK_READ; - sess->timeout = GG_DEFAULT_TIMEOUT; - - break; - } - - case GG_STATE_READING_DATA: - { - char buf[1024], *tmp, *host; - int port = GG_DEFAULT_PORT; - struct in_addr addr; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_READING_DATA\n"); - - /* czytamy linię z gniazda i obcinamy \r\n. */ - gg_read_line(sess->fd, buf, sizeof(buf) - 1); - gg_chomp(buf); - gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// gg_watch_fd() received http header (%s)\n", buf); - - /* sprawdzamy, czy wszystko w porządku. */ - if (strncmp(buf, "HTTP/1.", 7) || strncmp(buf + 9, "200", 3)) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() invalid http reply, connection failed\n"); - goto fail_connecting; - } - - /* ignorujemy resztę nagłówka. */ - while (strcmp(buf, "\r\n") && strcmp(buf, "")) - gg_read_line(sess->fd, buf, sizeof(buf) - 1); - - /* czytamy pierwszą linię danych. */ - gg_read_line(sess->fd, buf, sizeof(buf) - 1); - gg_chomp(buf); - - /* jeśli pierwsza liczba w linii nie jest równa zeru, - * oznacza to, że mamy wiadomość systemową. */ - if (atoi(buf)) { - char tmp[1024], *foo, *sysmsg_buf = NULL; - int len = 0; - - while (gg_read_line(sess->fd, tmp, sizeof(tmp) - 1)) { - if (!(foo = realloc(sysmsg_buf, len + strlen(tmp) + 2))) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() out of memory for system message, ignoring\n"); - break; - } - - sysmsg_buf = foo; - - if (!len) - strcpy(sysmsg_buf, tmp); - else - strcat(sysmsg_buf, tmp); - - len += (int)strlen(tmp); - } - - e->type = GG_EVENT_MSG; - e->event.msg.msgclass = atoi(buf); - e->event.msg.sender = 0; - e->event.msg.message = (unsigned char*) sysmsg_buf; - } - - gg_sock_close(sess->fd); - - gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// gg_watch_fd() received http data (%s)\n", buf); - - /* analizujemy otrzymane dane. */ - tmp = buf; - - while (*tmp && *tmp != ' ') - tmp++; - while (*tmp && *tmp == ' ') - tmp++; - while (*tmp && *tmp != ' ') - tmp++; - while (*tmp && *tmp == ' ') - tmp++; - host = tmp; - while (*tmp && *tmp != ' ') - tmp++; - *tmp = 0; - - if ((tmp = strchr(host, ':'))) { - *tmp = 0; - port = atoi(tmp + 1); - } - - if (!strcmp(host, "notoperating")) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() service unavailable\n", errno, strerror(errno)); - sess->fd = -1; - goto fail_unavailable; - } - - addr.s_addr = inet_addr(host); - sess->server_addr = addr.s_addr; - - if (!gg_proxy_http_only && sess->proxy_addr && sess->proxy_port) { - /* jeśli mamy proxy, łączymy się z nim. */ - if ((sess->fd = gg_connect(&sess->proxy_addr, sess->proxy_port, sess->async)) == -1) { - /* nie wyszło? trudno. */ - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", errno, strerror(errno)); - goto fail_connecting; - } - - sess->state = GG_STATE_CONNECTING_GG; - sess->check = GG_CHECK_WRITE; - sess->timeout = GG_DEFAULT_TIMEOUT; - sess->soft_timeout = 1; - break; - } - - sess->port = port; - - /* Jeśli podano nazwę, nie adres serwera... */ - if (sess->server_addr == INADDR_NONE) { - if (sess->resolver_start(&sess->fd, &sess->resolver, host) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_login() resolving failed (errno=%d, %s)\n", errno, strerror(errno)); - goto fail_resolving; - } - - sess->state = GG_STATE_RESOLVING_GG; - sess->check = GG_CHECK_READ; - sess->timeout = GG_DEFAULT_TIMEOUT; - break; - } - - /* łączymy się z właściwym serwerem. */ - if ((sess->fd = gg_connect(&addr, sess->port, sess->async)) == -1) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), trying https\n", errno, strerror(errno)); - - sess->port = GG_HTTPS_PORT; - - /* nie wyszło? próbujemy portu 443. */ - if ((sess->fd = gg_connect(&addr, GG_HTTPS_PORT, sess->async)) == -1) { - /* ostatnia deska ratunku zawiodła? - * w takim razie zwijamy manatki. */ - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno)); - goto fail_connecting; - } - } - - sess->state = GG_STATE_CONNECTING_GG; - sess->check = GG_CHECK_WRITE; - sess->timeout = GG_DEFAULT_TIMEOUT; - sess->soft_timeout = 1; - - break; - } - - case GG_STATE_RESOLVING_GG: - { - struct in_addr addr; - int failed = 0; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_RESOLVING_GG\n"); - - if (gg_sock_read(sess->fd, &addr, sizeof(addr)) < (signed)sizeof(addr) || addr.s_addr == INADDR_NONE) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() resolving failed\n"); - failed = 1; - errno2 = errno; - } - - gg_sock_close(sess->fd); - sess->fd = -1; - - sess->resolver_cleanup(&sess->resolver, 0); - - if (failed) { - errno = errno2; - goto fail_resolving; - } - - sess->server_addr = addr.s_addr; - - /* łączymy się z właściwym serwerem. */ - if ((sess->fd = gg_connect(&addr, sess->port, sess->async)) == -1) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), trying https\n", errno, strerror(errno)); - - sess->port = GG_HTTPS_PORT; - - /* nie wyszło? próbujemy portu 443. */ - if ((sess->fd = gg_connect(&addr, GG_HTTPS_PORT, sess->async)) == -1) { - /* ostatnia deska ratunku zawiodła? - * w takim razie zwijamy manatki. */ - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno)); - goto fail_connecting; - } - } - - sess->state = GG_STATE_CONNECTING_GG; - sess->check = GG_CHECK_WRITE; - sess->timeout = GG_DEFAULT_TIMEOUT; - sess->soft_timeout = 1; - - break; - } - - case GG_STATE_CONNECTING_GG: - { - int res = 0; - unsigned int res_size = sizeof(res); - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_CONNECTING_GG\n"); - - sess->soft_timeout = 0; - - /* jeśli wystąpił błąd podczas łączenia się... */ - if (sess->async && (sess->timeout == 0 || gg_getsockopt(sess->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) { - /* jeśli nie udało się połączenie z proxy, - * nie mamy czego próbować więcej. */ - if (sess->proxy_addr && sess->proxy_port) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", res, strerror(res)); - goto fail_connecting; - } - - gg_sock_close(sess->fd); - sess->fd = -1; - -#ifdef ETIMEDOUT - if (sess->timeout == 0) - errno = ETIMEDOUT; -#endif - -#ifdef GG_CONFIG_HAVE_OPENSSL - /* jeśli logujemy się po TLS, nie próbujemy - * się łączyć już z niczym innym w przypadku - * błędu. nie dość, że nie ma sensu, to i - * trzeba by się bawić w tworzenie na nowo - * SSL i SSL_CTX. */ - - if (sess->ssl) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", res, strerror(res)); - goto fail_connecting; - } -#endif - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), trying https\n", res, strerror(res)); - - if (sess->port == GG_HTTPS_PORT) - goto fail_connecting; - - sess->port = GG_HTTPS_PORT; - - /* próbujemy na port 443. */ - if ((sess->fd = gg_connect(&sess->server_addr, sess->port, sess->async)) == -1) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno)); - goto fail_connecting; - } - - sess->state = GG_STATE_CONNECTING_GG; - sess->check = GG_CHECK_WRITE; - sess->timeout = GG_DEFAULT_TIMEOUT; - sess->soft_timeout = 1; - - break; - } - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connected\n"); - - if (gg_proxy_http_only) - sess->proxy_port = 0; - - /* jeśli mamy proxy, wyślijmy zapytanie. */ - if (sess->proxy_addr && sess->proxy_port) { - char buf[100], *auth = gg_proxy_auth(); - struct in_addr addr; - - if (sess->server_addr) - addr.s_addr = sess->server_addr; - else - addr.s_addr = sess->hub_addr; - - snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.0\r\n", inet_ntoa(addr), sess->port); - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() proxy request:\n// %s", buf); - - /* wysyłamy zapytanie. jest ono na tyle krótkie, - * że musi się zmieścić w buforze gniazda. jeśli - * write() zawiedzie, stało się coś złego. */ - if (gg_sock_write(sess->fd, buf, (int)strlen(buf)) < (signed)strlen(buf)) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n"); - free(auth); - goto fail_connecting; - } - - if (auth) { - gg_debug_session(sess, GG_DEBUG_MISC, "// %s", auth); - if (gg_sock_write(sess->fd, auth, (int)strlen(auth)) < (signed)strlen(auth)) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n"); - free(auth); - goto fail_connecting; - } - - free(auth); - } - - if (gg_sock_write(sess->fd, "\r\n", 2) < 2) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n"); - goto fail_connecting; - } - } - -#ifdef GG_CONFIG_MIRANDA - if (sess->tls) { - sess->state = GG_STATE_TLS_NEGOTIATION; - sess->check = GG_CHECK_WRITE; - sess->timeout = GG_DEFAULT_TIMEOUT; - - break; - } -#elif GG_CONFIG_HAVE_OPENSSL - if (sess->ssl != NULL) { - SSL_set_fd(sess->ssl, (int)sess->fd); - - sess->state = GG_STATE_TLS_NEGOTIATION; - sess->check = GG_CHECK_WRITE; - sess->timeout = GG_DEFAULT_TIMEOUT; - - break; - } -#endif - - sess->state = GG_STATE_READING_KEY; - sess->check = GG_CHECK_READ; - sess->timeout = GG_DEFAULT_TIMEOUT; - - break; - } - -#ifdef GG_CONFIG_MIRANDA - case GG_STATE_TLS_NEGOTIATION: - { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_TLS_NEGOTIATION\n"); - - sess->ssl = si.connect(sess->fd, 0, 0); - - if (sess->ssl == NULL) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() TLS negotiation failed\n"); - - e->type = GG_EVENT_CONN_FAILED; - e->event.failure = GG_FAILURE_TLS; - sess->state = GG_STATE_IDLE; - gg_sock_close(sess->fd); - sess->fd = -1; - break; - } - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() TLS negotiation succeded\n"); - - sess->state = GG_STATE_READING_KEY; - sess->check = GG_CHECK_READ; - sess->timeout = GG_DEFAULT_TIMEOUT; - - break; - } -#elif GG_CONFIG_HAVE_OPENSSL - case GG_STATE_TLS_NEGOTIATION: - { - int res; - X509 *peer; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_TLS_NEGOTIATION\n"); - - if ((res = SSL_connect(sess->ssl)) <= 0) { - int err = SSL_get_error(sess->ssl, res); - - if (res == 0) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() disconnected during TLS negotiation\n"); - - e->type = GG_EVENT_CONN_FAILED; - e->event.failure = GG_FAILURE_TLS; - sess->state = GG_STATE_IDLE; - gg_sock_close(sess->fd); - sess->fd = -1; - break; - } - - if (err == SSL_ERROR_WANT_READ) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() wants to read\n"); - - sess->state = GG_STATE_TLS_NEGOTIATION; - sess->check = GG_CHECK_READ; - sess->timeout = GG_DEFAULT_TIMEOUT; - - break; - } else if (err == SSL_ERROR_WANT_WRITE) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() wants to write\n"); - - sess->state = GG_STATE_TLS_NEGOTIATION; - sess->check = GG_CHECK_WRITE; - sess->timeout = GG_DEFAULT_TIMEOUT; - - break; - } 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->type = GG_EVENT_CONN_FAILED; - e->event.failure = GG_FAILURE_TLS; - sess->state = GG_STATE_IDLE; - gg_sock_close(sess->fd); - sess->fd = -1; - break; - } - } - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() TLS negotiation succeded:\n// cipher: %s\n", SSL_get_cipher_name(sess->ssl)); - - peer = SSL_get_peer_certificate(sess->ssl); - - if (!peer) - gg_debug_session(sess, GG_DEBUG_MISC, "// WARNING! unable to get peer certificate!\n"); - else { - char buf[256]; - - 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); - } - - sess->state = GG_STATE_READING_KEY; - sess->check = GG_CHECK_READ; - sess->timeout = GG_DEFAULT_TIMEOUT; - - break; - } -#endif - - case GG_STATE_READING_KEY: - { - struct gg_header *h; - struct gg_welcome *w; - unsigned char *password = (unsigned char*) sess->password; - int ret; - uint8_t login_hash[64]; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_READING_KEY\n"); - - memset(login_hash, 0, sizeof(login_hash)); - - /* XXX bardzo, bardzo, bardzo głupi pomysł na pozbycie - * się tekstu wrzucanego przez proxy. */ - if (sess->proxy_addr && sess->proxy_port) { - char buf[100]; - - strcpy(buf, ""); - gg_read_line(sess->fd, buf, sizeof(buf) - 1); - gg_chomp(buf); - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() proxy response:\n// %s\n", buf); - - while (strcmp(buf, "")) { - gg_read_line(sess->fd, buf, sizeof(buf) - 1); - gg_chomp(buf); - if (strcmp(buf, "")) - gg_debug_session(sess, GG_DEBUG_MISC, "// %s\n", buf); - } - - /* XXX niech czeka jeszcze raz w tej samej - * fazie. głupio, ale działa. */ - sess->proxy_port = 0; - - break; - } - - /* czytaj pierwszy pakiet. */ - if (!(h = gg_recv_packet(sess))) { - if (errno == EAGAIN) { - sess->check = GG_CHECK_READ; - break; - } - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() didn't receive packet (errno=%d, %s)\n", errno, strerror(errno)); - - e->type = GG_EVENT_CONN_FAILED; - e->event.failure = GG_FAILURE_READING; - sess->state = GG_STATE_IDLE; - errno2 = errno; - gg_sock_close(sess->fd); - errno = errno2; - sess->fd = -1; - break; - } - - if (h->type != GG_WELCOME) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() invalid packet received\n"); - free(h); - gg_sock_close(sess->fd); - sess->fd = -1; - errno = EINVAL; - e->type = GG_EVENT_CONN_FAILED; - e->event.failure = GG_FAILURE_INVALID; - sess->state = GG_STATE_IDLE; - break; - } - - w = (struct gg_welcome*) ((char*) h + sizeof(struct gg_header)); - w->key = gg_fix32(w->key); - - switch (sess->hash_type) { - case GG_LOGIN_HASH_GG32: - { - unsigned int hash; - - hash = gg_fix32(gg_login_hash(password, w->key)); - gg_debug_session(sess, GG_DEBUG_DUMP, "// gg_watch_fd() challenge %.4x --> GG32 hash %.8x\n", w->key, hash); - memcpy(login_hash, &hash, sizeof(hash)); - - break; - } - - case GG_LOGIN_HASH_SHA1: - { - char tmp[41]; - int i; - - gg_login_hash_sha1((char*) password, w->key, login_hash); - for (i = 0; i < 40; i += 2) - snprintf(tmp + i, sizeof(tmp) - i, "%02x", login_hash[i / 2]); - - gg_debug_session(sess, GG_DEBUG_DUMP, "// gg_watch_fd() challenge %.4x --> SHA1 hash: %s\n", w->key, tmp); - - break; - } - } - - free(h); - free(sess->password); - sess->password = NULL; - - if (gg_dcc_ip == (unsigned long) inet_addr("255.255.255.255")) { - struct sockaddr_in sin; - unsigned int sin_len = sizeof(sin); - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() detecting address\n"); - - if (!getsockname(sess->fd, (struct sockaddr*) &sin, &sin_len)) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() detected address to %s\n", inet_ntoa(sin.sin_addr)); - sess->client_addr = sin.sin_addr.s_addr; - } else { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() unable to detect address\n"); - sess->client_addr = 0; - } - } else - sess->client_addr = gg_dcc_ip; - - if (sess->protocol_version >= 0x2e) { - struct gg_login80 l; - const char *version = (sess->client_version) ? sess->client_version : GG_DEFAULT_CLIENT_VERSION; - uint32_t tmp_version_len = gg_fix32((uint32_t)strlen(GG8_VERSION) + (uint32_t)strlen(version)); - uint32_t tmp_descr_len = gg_fix32((sess->initial_descr) ? (uint32_t)strlen(sess->initial_descr) : 0); - - memset(&l, 0, sizeof(l)); - l.uin = gg_fix32(sess->uin); - memcpy(l.language, GG8_LANG, sizeof(l.language)); - l.hash_type = sess->hash_type; - memcpy(l.hash, login_hash, sizeof(login_hash)); - l.status = gg_fix32(sess->initial_status ? sess->initial_status : GG_STATUS_AVAIL); - l.flags = gg_fix32(sess->status_flags); - l.features = gg_fix32(sess->protocol_features); - l.image_size = sess->image_size; - l.dunno2 = 0x64; - - gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// gg_watch_fd() sending GG_LOGIN80 packet\n"); - ret = gg_send_packet(sess, GG_LOGIN80, - &l, sizeof(l), - &tmp_version_len, sizeof(uint32_t), GG8_VERSION, strlen(GG8_VERSION), version, strlen(version), - &tmp_descr_len, sizeof(uint32_t), sess->initial_descr, (sess->initial_descr) ? strlen(sess->initial_descr) : 0, - NULL); - - } else if (sess->protocol_version == 0x2d) { - struct gg_login70 l; - - memset(&l, 0, sizeof(l)); - l.uin = gg_fix32(sess->uin); - l.local_ip = (sess->external_addr) ? sess->external_addr : sess->client_addr; - l.local_port = gg_fix16((uint16_t)((sess->external_port > 1023) ? sess->external_port : gg_dcc_port)); - l.hash_type = sess->hash_type; - memcpy(l.hash, login_hash, sizeof(login_hash)); - l.image_size = sess->image_size; - l.dunno2 = 0x64; - l.status = gg_fix32(sess->initial_status ? sess->initial_status : GG_STATUS_AVAIL); - l.version = gg_fix32(sess->protocol_version | sess->protocol_flags); - - gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// gg_watch_fd() sending GG_LOGIN80BETA packet\n"); - ret = gg_send_packet(sess, GG_LOGIN80BETA, - &l, sizeof(l), - sess->initial_descr, (sess->initial_descr) ? strlen(sess->initial_descr) : 0, - (sess->initial_descr) ? "\0" : NULL, (sess->initial_descr) ? 1 : 0, - NULL); - } else { - struct gg_login70 l; - - memset(&l, 0, sizeof(l)); - l.local_ip = (sess->external_addr) ? sess->external_addr : sess->client_addr; - l.uin = gg_fix32(sess->uin); - l.local_port = gg_fix16((uint16_t)((sess->external_port > 1023) ? sess->external_port : gg_dcc_port)); - l.hash_type = sess->hash_type; - memcpy(l.hash, login_hash, sizeof(login_hash)); - l.image_size = sess->image_size; - l.dunno2 = 0xbe; - l.status = gg_fix32(sess->initial_status ? sess->initial_status : GG_STATUS_AVAIL); - l.version = gg_fix32(sess->protocol_version | sess->protocol_flags); - - gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// gg_watch_fd() sending GG_LOGIN70 packet\n"); - ret = gg_send_packet(sess, GG_LOGIN70, - &l, sizeof(l), - sess->initial_descr, (sess->initial_descr) ? strlen(sess->initial_descr) : 0, - NULL); - } - - free(sess->initial_descr); - sess->initial_descr = NULL; - - if (ret == -1) { - gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// gg_watch_fd() sending packet failed. (errno=%d, %s)\n", errno, strerror(errno)); - errno2 = errno; - gg_sock_close(sess->fd); - errno = errno2; - sess->fd = -1; - e->type = GG_EVENT_CONN_FAILED; - e->event.failure = GG_FAILURE_WRITING; - sess->state = GG_STATE_IDLE; - break; - } - - sess->state = GG_STATE_READING_REPLY; - sess->check = GG_CHECK_READ; - - break; - } - - case GG_STATE_READING_REPLY: - { - struct gg_header *h; - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_READING_REPLY\n"); - - if (!(h = gg_recv_packet(sess))) { - if (errno == EAGAIN) { - sess->check = GG_CHECK_READ; - break; - } - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() didn't receive packet (errno=%d, %s)\n", errno, strerror(errno)); - e->type = GG_EVENT_CONN_FAILED; - e->event.failure = GG_FAILURE_READING; - sess->state = GG_STATE_IDLE; - errno2 = errno; - gg_sock_close(sess->fd); - errno = errno2; - sess->fd = -1; - break; - } - - if (h->type == GG_LOGIN_OK || h->type == GG_NEED_EMAIL || h->type == GG_LOGIN80_OK) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() login succeded\n"); - e->type = GG_EVENT_CONN_SUCCESS; - sess->state = GG_STATE_CONNECTED; - sess->check = GG_CHECK_READ; - sess->timeout = -1; - sess->status = (sess->initial_status) ? sess->initial_status : GG_STATUS_AVAIL; - free(h); - break; - } - - if (h->type == GG_LOGIN_FAILED || h->type == GG_LOGIN80_FAILED) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() login failed\n"); - e->event.failure = GG_FAILURE_PASSWORD; - errno = EACCES; - } else if (h->type == GG_DISCONNECTING) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() too many incorrect password attempts\n"); - e->event.failure = GG_FAILURE_INTRUDER; - errno = EACCES; - } else { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() invalid packet\n"); - e->event.failure = GG_FAILURE_INVALID; - errno = EINVAL; - } - - e->type = GG_EVENT_CONN_FAILED; - sess->state = GG_STATE_IDLE; - errno2 = errno; - gg_sock_close(sess->fd); - errno = errno2; - sess->fd = -1; - free(h); - - break; - } - - case GG_STATE_CONNECTED: - { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_CONNECTED\n"); - - sess->last_event = (int)time(NULL); - - if ((res = gg_watch_fd_connected(sess, e)) == -1) { - - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() watch_fd_connected failed (errno=%d, %s)\n", errno, strerror(errno)); - - if (errno == EAGAIN) { - e->type = GG_EVENT_NONE; - res = 0; - } else - res = -1; - } - - sess->check = GG_CHECK_READ; - - break; - } - } - -done: - if (res == -1) { - free(e); - e = NULL; - } else { - if (sess->send_buf && (sess->state == GG_STATE_READING_REPLY || sess->state == GG_STATE_CONNECTED)) - sess->check |= GG_CHECK_WRITE; - } - - return e; - -fail_connecting: - if (sess->fd != -1) { - errno2 = errno; - gg_sock_close(sess->fd); - errno = errno2; - sess->fd = -1; - } - e->type = GG_EVENT_CONN_FAILED; - e->event.failure = GG_FAILURE_CONNECTING; - sess->state = GG_STATE_IDLE; - goto done; - -fail_resolving: - e->type = GG_EVENT_CONN_FAILED; - e->event.failure = GG_FAILURE_RESOLVING; - sess->state = GG_STATE_IDLE; - goto done; - -fail_unavailable: - e->type = GG_EVENT_CONN_FAILED; - e->event.failure = GG_FAILURE_UNAVAILABLE; - sess->state = GG_STATE_IDLE; - goto done; -} - -/* - * Local variables: - * c-indentation-style: k&r - * c-basic-offset: 8 - * indent-tabs-mode: notnil - * End: - * - * vim: shiftwidth=8: - */ diff --git a/protocols/Gadu-Gadu/libgadu/http.c b/protocols/Gadu-Gadu/libgadu/http.c deleted file mode 100644 index c070b3ee53..0000000000 --- a/protocols/Gadu-Gadu/libgadu/http.c +++ /dev/null @@ -1,544 +0,0 @@ -/* coding: UTF-8 */
-/* $Id: http.c 11370 2010-03-13 16:17:54Z dezred $ */
-
-/*
- * (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 <sys/types.h>
-#ifdef _WIN32
-#include "win32.h"
-#else
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#endif /* _WIN32 */
-
-#include "compat.h"
-#include "libgadu.h"
-#include "resolver.h"
-
-#include <ctype.h>
-#include <errno.h>
-#ifndef _WIN32
-#include <netdb.h>
-#endif /* _WIN32 */
-#include <signal.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifndef _WIN32
-#include <unistd.h>
-#endif /* _WIN32 */
-
-/**
- * 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) {
- 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;
-
- if (gg_gethostbyname_real(hostname, &addr, 0) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_http_connect() host not found\n");
- gg_http_free(h);
- errno = ENOENT;
- return NULL;
- }
-
- if ((h->fd = gg_connect(&addr, port, 0)) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_http_connect() connection failed (errno=%d, %s)\n", errno, strerror(errno));
- gg_http_free(h);
- return NULL;
- }
-
- 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) \
- gg_sock_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) {
- 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 a;
-
- gg_debug(GG_DEBUG_MISC, "=> http, resolving done\n");
-
- if (gg_sock_read(h->fd, &a, sizeof(a)) < (signed)sizeof(a) || a.s_addr == INADDR_NONE) {
- gg_debug(GG_DEBUG_MISC, "=> http, resolver thread failed\n");
- gg_http_error(GG_ERROR_RESOLVING);
- }
-
- gg_sock_close(h->fd);
- h->fd = -1;
-
- h->resolver_cleanup(&h->resolver, 0);
-
- gg_debug(GG_DEBUG_MISC, "=> http, connecting to %s:%d\n", inet_ntoa(a), h->port);
-
- if ((h->fd = gg_connect(&a, h->port, h->async)) == -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;
- unsigned int res_size = sizeof(res);
-
- if (h->async && (gg_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));
- gg_sock_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;
-
- if ((res = gg_sock_write(h->fd, h->query, (int)strlen(h->query))) < 1) {
- gg_debug(GG_DEBUG_MISC, "=> http, write() failed (len=%d, res=%d, errno=%d)\n", strlen(h->query), res, errno);
- gg_http_error(GG_ERROR_WRITING);
- }
-
- if (res < (int)strlen(h->query)) {
- gg_debug(GG_DEBUG_MISC, "=> http, partial header sent (led=%d, 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=%d)\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;
-
- if ((res = gg_sock_read(h->fd, buf, sizeof(buf))) == -1) {
- gg_debug(GG_DEBUG_MISC, "=> http, reading header failed (errno=%d)\n", errno);
- if (h->header) {
- free(h->header);
- h->header = NULL;
- }
- gg_http_error(GG_ERROR_READING);
- }
-
- if (!res) {
- gg_debug(GG_DEBUG_MISC, "=> http, connection reset by peer\n");
- if (h->header) {
- 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);
-
- if (!(tmp = realloc(h->header, h->header_size + res + 1))) {
- 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 - ((long)(tmp) - (long)(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 (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;
-
- if ((res = gg_sock_read(h->fd, buf, sizeof(buf))) == -1) {
- gg_debug(GG_DEBUG_MISC, "=> http, reading body failed (errno=%d)\n", errno);
- if (h->body) {
- free(h->body);
- h->body = NULL;
- }
- gg_http_error(GG_ERROR_READING);
- }
-
- if (!res) {
- if (h->body_done >= h->body_size) {
- gg_debug(GG_DEBUG_MISC, "=> http, we're done, closing socket\n");
- h->state = GG_STATE_PARSING;
- gg_sock_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);
- if (h->body) {
- 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)
- gg_sock_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;
-
- if (h->fd != -1) {
- gg_sock_close(h->fd);
- h->fd = -1;
- }
-
- h->resolver_cleanup(&h->resolver, 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)
- return;
-
- if (h->body) {
- free(h->body);
- h->body = NULL;
- }
-
- if (h->query) {
- free(h->query);
- h->query = NULL;
- }
-
- if (h->header) {
- 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)
- 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:
- */
diff --git a/protocols/Gadu-Gadu/libgadu/internal.h b/protocols/Gadu-Gadu/libgadu/internal.h deleted file mode 100644 index 0ffd39fdd5..0000000000 --- a/protocols/Gadu-Gadu/libgadu/internal.h +++ /dev/null @@ -1,48 +0,0 @@ -/* coding: UTF-8 */ -/* $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" - -struct gg_dcc7_relay {
- uint32_t addr;
- uint16_t port;
- uint8_t family;
-};
-
-typedef struct gg_dcc7_relay gg_dcc7_relay_t; - -char *gg_cp_to_utf8(const char *b); -char *gg_utf8_to_cp(const char *b); -int gg_pubdir50_handle_reply_sess(struct gg_session *sess, struct gg_event *e, const char *packet, int length); -void gg_debug_dump_session(struct gg_session *sess, const void *buf, unsigned int buf_length, const char *format, ...); - -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); - -#ifdef GG_CONFIG_HAVE_UINT64_T
-uint64_t gg_fix64(uint64_t x);
-#endif - -#endif /* LIBGADU_INTERNAL_H */ diff --git a/protocols/Gadu-Gadu/libgadu/libgadu.c b/protocols/Gadu-Gadu/libgadu/libgadu.c deleted file mode 100644 index f06f8a5b84..0000000000 --- a/protocols/Gadu-Gadu/libgadu/libgadu.c +++ /dev/null @@ -1,2353 +0,0 @@ -/* coding: UTF-8 */
-/* $Id: libgadu.c 13762 2011-08-09 12:35:16Z dezred $ */
-
-/*
- * (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
- */
-
-#ifndef _WIN64
-#define _USE_32BIT_TIME_T
-#endif
-
-#include <sys/types.h>
-#ifdef _WIN32
-#include "win32.h"
-#else
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#ifdef sun
-# include <sys/filio.h>
-#endif
-#endif /* _WIN32 */
-
-#include "compat.h"
-#include "libgadu.h"
-#include "protocol.h"
-#include "resolver.h"
-#include "internal.h"
-
-#include <errno.h>
-#ifndef _WIN32
-#include <netdb.h>
-#endif /* _WIN32 */
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <signal.h>
-#include <time.h>
-#ifndef _WIN32
-#include <unistd.h>
-#endif /* _WIN32 */
-#if !defined(GG_CONFIG_MIRANDA) && defined(GG_CONFIG_HAVE_OPENSSL)
-# include <openssl/err.h>
-# include <openssl/rand.h>
-#endif
-
-/**
- * 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;
-
-/**
- * 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[]
-#ifdef __GNUC__
-__attribute__ ((unused))
-#endif
-= "$Id: libgadu.c 13762 2011-08-09 12:35:16Z dezred $";
-#endif
-
-#endif /* DOXYGEN */
-
-/**
- * Zwraca wersję biblioteki.
- *
- * \return Wskaźnik na statyczny bufor z wersją biblioteki.
- *
- * \ingroup version
- */
-const char *gg_libgadu_version()
-{
- return GG_LIBGADU_VERSION;
-}
-
-#ifdef GG_CONFIG_HAVE_UINT64_T
-/**
- * \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
-}
-#endif /* GG_CONFIG_HAVE_UINT64_T */
-
-/**
- * \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
-}
-
-/**
- * \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)
-{
-#ifdef GG_CONFIG_MIRANDA
- if (sess->ssl != NULL)
- return si.read(sess->ssl, buf, length, 0);
-#elif GG_CONFIG_HAVE_OPENSSL
- if (sess->ssl != NULL) {
- for (;;) {
- int res, 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
-
- return gg_sock_read(sess->fd, buf, length);
-}
-
-/**
- * \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)
-{
-#ifdef GG_CONFIG_MIRANDA
- if (sess->ssl != NULL)
- return si.write(sess->ssl, buf, length);
-#elif GG_CONFIG_HAVE_OPENSSL
- if (sess->ssl != NULL) {
- for (;;) {
- int res, err;
-
- res = SSL_write(sess->ssl, (void *)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
-
- return gg_sock_write(sess->fd, buf, length);
-}
-
-
-
-/**
- * \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 {
- res = 0;
-
- if (sess->send_buf == NULL) {
- res = gg_write_common(sess, buf, length);
-
- 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;
-}
-
-/**
- * \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 -1, 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 h;
- char *buf = NULL;
- int ret = 0;
- unsigned int offset, size = 0;
-
- gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_recv_packet(%p);\n", sess);
-
- if (!sess) {
- errno = EFAULT;
- return NULL;
- }
-
- if (sess->recv_left < 1) {
- if (sess->header_buf) {
- memcpy(&h, sess->header_buf, sess->header_done);
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv: resuming last read (%d bytes left)\n", sizeof(h) - sess->header_done);
- free(sess->header_buf);
- sess->header_buf = NULL;
- } else
- sess->header_done = 0;
-
- while (sess->header_done < sizeof(h)) {
- ret = gg_read(sess, (char*) &h + sess->header_done, sizeof(h) - sess->header_done);
-
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv(%d,%p,%d) = %d\n", sess->fd, &h + sess->header_done, sizeof(h) - sess->header_done, ret);
-
- if (!ret) {
- errno = ECONNRESET;
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: connection broken\n");
- return NULL;
- }
-
- if (ret == -1) {
- if (errno == EAGAIN) {
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv() incomplete header received\n");
-
- if (!(sess->header_buf = malloc(sess->header_done))) {
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv() not enough memory\n");
- return NULL;
- }
-
- memcpy(sess->header_buf, &h, sess->header_done);
-
- errno = EAGAIN;
-
- return NULL;
- }
-
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: errno=%d, %s\n", errno, strerror(errno));
-
- return NULL;
- }
-
- sess->header_done += ret;
-
- }
-
- h.type = gg_fix32(h.type);
- h.length = gg_fix32(h.length);
- } else
- memcpy(&h, sess->recv_buf, sizeof(h));
-
- /* jakieś sensowne limity na rozmiar pakietu */
- if (h.length > 65535) {
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() invalid packet length (%d)\n", h.length);
- errno = ERANGE;
- return NULL;
- }
-
- if (sess->recv_left > 0) {
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() resuming last gg_recv_packet()\n");
- size = sess->recv_left;
- offset = sess->recv_done;
- buf = sess->recv_buf;
- } else {
- if (!(buf = malloc(sizeof(h) + h.length + 1))) {
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() not enough memory for packet data\n");
- return NULL;
- }
-
- memcpy(buf, &h, sizeof(h));
-
- offset = 0;
- size = h.length;
- }
-
- while (size > 0) {
- ret = gg_read(sess, buf + sizeof(h) + offset, size);
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() body recv(%d,%p,%d) = %d\n", sess->fd, buf + sizeof(h) + offset, size, ret);
- if (!ret) {
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed: connection broken\n");
- errno = ECONNRESET;
- return NULL;
- }
- if (ret > -1 && ret <= (int)size) {
- offset += ret;
- size -= ret;
- } else if (ret == -1) {
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed (errno=%d, %s)\n", errno, strerror(errno));
-
- if (errno == EAGAIN) {
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() %d bytes received, %d left\n", offset, size);
- sess->recv_buf = buf;
- sess->recv_left = size;
- sess->recv_done = offset;
- return NULL;
- }
-
- free(buf);
- return NULL;
- }
- }
-
- sess->recv_left = 0;
-
- gg_debug_dump_session(sess, buf, sizeof(h) + h.length, "// gg_recv_packet(0x%.2x)", h.type);
-
- return buf;
-}
-
-/**
- * \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_MISC, "// 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_MISC, "// 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_dump_session(sess, tmp, tmp_length, "// gg_send_packet(0x%.2x)", gg_fix32(h->type));
-
- res = gg_write(sess, tmp, tmp_length);
-
- free(tmp);
-
- if (res == -1) {
- gg_debug_session(sess, GG_DEBUG_MISC, "// 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_MISC, "// 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().
- *
- * \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
- */
-#ifdef GG_CONFIG_MIRANDA -struct gg_session *gg_login(const struct gg_login_params *p, SOCKET *gg_sock, int *gg_failno) -#else -struct gg_session *gg_login(const struct gg_login_params *p)
-#endif
-{
- struct gg_session *sess = NULL;
- char *hostname;
- int port;
-
- if (!p) {
- 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);
-
- if (!(sess = malloc(sizeof(struct gg_session)))) {
- gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for session data\n");
- goto fail;
- }
-
- memset(sess, 0, sizeof(struct gg_session));
-
- if (!p->password || !p->uin) {
- 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) ? p->server_port : ((gg_proxy_enabled) ? GG_HTTPS_PORT : GG_DEFAULT_PORT);
- sess->server_addr = p->server_addr;
- sess->external_port = p->external_port;
- sess->external_addr = p->external_addr;
- sess->client_port = p->client_port;
-
- 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;
-
- sess->protocol_version = (p->protocol_version) ? p->protocol_version : GG_DEFAULT_PROTOCOL_VERSION;
-
- if (p->era_omnix)
- sess->protocol_flags |= GG_ERA_OMNIX_MASK;
- if (p->has_audio)
- sess->protocol_flags |= GG_HAS_AUDIO_MASK;
- sess->client_version = (p->client_version) ? strdup(p->client_version) : NULL;
- 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) {
- int max_length;
-
- if (sess->protocol_version >= 0x2d)
- max_length = GG_STATUS_DESCR_MAXSIZE;
- else
- max_length = GG_STATUS_DESCR_MAXSIZE_PRE_8_0;
-
- if (sess->protocol_version >= 0x2d && p->encoding != GG_ENCODING_UTF8)
- sess->initial_descr = gg_cp_to_utf8(p->status_descr);
- else
- sess->initial_descr = strdup(p->status_descr);
-
- 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 ((signed)strlen(sess->initial_descr) > max_length)
- sess->initial_descr[max_length] = 0;
- }
-
-#ifdef GG_CONFIG_MIRANDA
- sess->tls = p->tls;
-#endif
- if (p->tls == 1) {
-#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));
- }
-
- sess->ssl_ctx = SSL_CTX_new(SSLv3_client_method());
-
- if (!sess->ssl_ctx) {
- ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
- gg_debug(GG_DEBUG_MISC, "// gg_login() SSL_CTX_new() failed: %s\n", buf);
- goto fail;
- }
-
- SSL_CTX_set_verify(sess->ssl_ctx, SSL_VERIFY_NONE, NULL);
-
- sess->ssl = SSL_new(sess->ssl_ctx);
-
- if (!sess->ssl) {
- ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
- gg_debug(GG_DEBUG_MISC, "// gg_login() SSL_new() failed: %s\n", buf);
- goto fail;
- }
-#elif !defined(GG_CONFIG_MIRANDA)
- gg_debug(GG_DEBUG_MISC, "// gg_login() client requested TLS but no support compiled in\n");
-#endif
- }
-
- if (gg_proxy_enabled) {
- hostname = gg_proxy_host;
- sess->proxy_port = port = gg_proxy_port;
- } else {
- hostname = GG_APPMSG_HOST;
- port = GG_APPMSG_PORT;
- }
-
- if (p->hash_type)
- sess->hash_type = p->hash_type;
- else
- sess->hash_type = GG_LOGIN_HASH_SHA1;
-
- if (!p->async) {
- struct in_addr addr;
-
- if (!sess->server_addr) {
- if ((addr.s_addr = inet_addr(hostname)) == INADDR_NONE) {
- if (gg_gethostbyname_real(hostname, &addr, 0) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_login() host \"%s\" not found\n", hostname);
-#ifdef GG_CONFIG_MIRANDA
- errno = EACCES;
- *gg_failno = GG_FAILURE_RESOLVING;
-#endif
- goto fail;
- }
- }
- } else {
- addr.s_addr = sess->server_addr;
- port = sess->port;
- }
-
- sess->hub_addr = addr.s_addr;
-
- if (gg_proxy_enabled)
- sess->proxy_addr = addr.s_addr;
-
-#ifdef GG_CONFIG_MIRANDA
- if ((sess->fd = gg_connect_internal(&addr, port, 0, gg_sock)) == -1) {
-#else
- if ((sess->fd = gg_connect(&addr, port, 0)) == -1) {
-#endif
- gg_debug(GG_DEBUG_MISC, "// gg_login() connection failed (errno=%d, %s)\n", errno, strerror(errno));
-
- /* nie wyszło? próbujemy portu 443. */
- if (sess->server_addr) {
- sess->port = GG_HTTPS_PORT;
-
-#ifdef GG_CONFIG_MIRANDA
- if ((sess->fd = gg_connect_internal(&addr, GG_HTTPS_PORT, 0, gg_sock)) == -1) {
-#else
- if ((sess->fd = gg_connect(&addr, GG_HTTPS_PORT, 0)) == -1) {
-#endif
- /* ostatnia deska ratunku zawiodła?
- * w takim razie zwijamy manatki. */
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_login() connection failed (errno=%d, %s)\n", errno, strerror(errno));
- goto fail;
- }
- } else {
- goto fail;
- }
- }
-
- if (sess->server_addr)
- sess->state = GG_STATE_CONNECTING_GG;
- else
- sess->state = GG_STATE_CONNECTING_HUB;
-
- while (sess->state != GG_STATE_CONNECTED) {
- struct gg_event *e;
-
- if (!(e = gg_watch_fd(sess))) {
- gg_debug(GG_DEBUG_MISC, "// gg_login() critical error in gg_watch_fd()\n");
- goto fail;
- }
-
- if (e->type == GG_EVENT_CONN_FAILED) {
- errno = EACCES;
-#ifdef GG_CONFIG_MIRANDA
- *gg_failno = e->event.failure;
-#endif
- gg_debug(GG_DEBUG_MISC, "// gg_login() could not login\n");
- gg_event_free(e);
- goto fail;
- }
-
- gg_event_free(e);
- }
-
- return sess;
- }
-
- if (!sess->server_addr || gg_proxy_enabled) {
- if (sess->resolver_start(&sess->fd, &sess->resolver, hostname) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_login() resolving failed (errno=%d, %s)\n", errno, strerror(errno));
- goto fail;
- }
- } else {
- if ((sess->fd = gg_connect(&sess->server_addr, sess->port, sess->async)) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_login() direct connection failed (errno=%d, %s)\n", errno, strerror(errno));
- goto fail;
- }
- sess->state = GG_STATE_CONNECTING_GG;
- sess->check = GG_CHECK_WRITE;
- sess->soft_timeout = 1;
- }
-
- 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_MIRANDA
- if (sess->ssl != NULL)
- si.shutdown(sess->ssl);
-#elif GG_CONFIG_HAVE_OPENSSL
- if (sess->ssl != NULL)
- SSL_shutdown(sess->ssl);
-#endif
-
- sess->resolver_cleanup(&sess->resolver, 1);
-
- if (sess->fd != -1) {
- shutdown(sess->fd, SHUT_RDWR);
- gg_sock_close(sess->fd);
- sess->fd = -1;
- }
-
- 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;
-
- if (!sess)
- return;
-
- /* XXX dopisać zwalnianie i zamykanie wszystkiego, co mogło zostać */
-
- free(sess->password);
- free(sess->initial_descr);
- free(sess->client_version);
- free(sess->header_buf);
-
-#ifdef GG_CONFIG_MIRANDA
- if (sess->ssl != NULL)
- si.sfree(sess->ssl);
-#elif GG_CONFIG_HAVE_OPENSSL
- if (sess->ssl != NULL)
- SSL_free(sess->ssl);
-
- if (sess->ssl_ctx)
- SSL_CTX_free(sess->ssl_ctx);
-#endif
-
- sess->resolver_cleanup(&sess->resolver, 1);
-
- if (sess->fd != -1)
- gg_sock_close(sess->fd);
-
- while (sess->images)
- gg_image_queue_remove(sess, sess->images, 1);
-
- free(sess->send_buf);
-
- for (dcc = sess->dcc7_list; dcc; dcc = dcc->next)
- dcc->sess = NULL;
-
- free(sess);
-}
-
-#ifndef DOXYGEN
-
-/**
- * \internal Funkcja wysyłająca pakiet zmiany statusu użytkownika.
- *
- * \param sess Struktura sesji
- * \param status Nowy status użytkownika
- * \param descr Opis statusu użytkownika (lub \c NULL)
- * \param time Czas powrotu w postaci uniksowego znacznika czasu (lub 0)
- *
- * \return 0 jeśli się powiodło, -1 w przypadku błędu
- *
- * \ingroup status
- */
-static int gg_change_status_common(struct gg_session *sess, int status, const char *descr, int time)
-{
- char *new_descr = NULL;
- uint32_t new_time;
- int descr_len = 0;
- int descr_len_max;
- int packet_type;
- int append_null = 0;
- int res;
-
- if (!sess) {
- errno = EFAULT;
- return -1;
- }
-
- if (sess->state != GG_STATE_CONNECTED) {
- errno = ENOTCONN;
- return -1;
- }
-
- /* XXX, obcinać stany których stary protokół niezna (czyt. dnd->aw; ffc->av) */
-
- /* dodaj flagę obsługi połączeń głosowych zgodną z GG 7.x */
- if ((sess->protocol_version >= 0x2a) && (sess->protocol_version < 0x2d /* ? */ ) && (sess->protocol_flags & GG_HAS_AUDIO_MASK) && !GG_S_I(status))
- status |= GG_STATUS_VOICE_MASK;
-
- sess->status = status;
-
- if (sess->protocol_version >= 0x2d) {
- if (descr != NULL && sess->encoding != GG_ENCODING_UTF8) {
- new_descr = gg_cp_to_utf8(descr);
-
- if (!new_descr)
- return -1;
- }
-
- if (sess->protocol_version >= 0x2e)
- packet_type = GG_NEW_STATUS80;
- else /* sess->protocol_version == 0x2d */
- packet_type = GG_NEW_STATUS80BETA;
- descr_len_max = GG_STATUS_DESCR_MAXSIZE;
- append_null = 1;
-
- } else {
- packet_type = GG_NEW_STATUS;
- descr_len_max = GG_STATUS_DESCR_MAXSIZE_PRE_8_0;
-
- if (time != 0)
- append_null = 1;
- }
-
- if (descr) {
- descr_len = (int)strlen((new_descr) ? new_descr : descr);
-
- if (descr_len > descr_len_max)
- descr_len = descr_len_max;
-
- // XXX pamiętać o tym, żeby nie ucinać w środku znaku utf-8
- }
-
- if (time)
- new_time = gg_fix32(time);
-
- if (packet_type == GG_NEW_STATUS80) {
- struct gg_new_status80 p;
-
- p.status = gg_fix32(status);
- p.flags = gg_fix32(sess->status_flags);
- p.description_size = gg_fix32(descr_len);
- res = gg_send_packet(sess,
- packet_type,
- &p,
- sizeof(p),
- (new_descr) ? new_descr : descr,
- descr_len,
- NULL);
-
- } else {
- struct gg_new_status p;
-
- p.status = gg_fix32(status);
- res = gg_send_packet(sess,
- packet_type,
- &p,
- sizeof(p),
- (new_descr) ? new_descr : descr,
- descr_len,
- (append_null) ? "\0" : NULL,
- (append_null) ? 1 : 0,
- (time) ? &new_time : NULL,
- (time) ? sizeof(new_time) : 0,
- NULL);
- }
-
- free(new_descr);
- return res;
-}
-
-#endif /* DOXYGEN */
-
-/**
- * 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_common(sess, status, NULL, 0);
-}
-
-/**
- * Zmienia status użytkownika na status opisowy.
- *
- * \param sess Struktura sesji
- * \param status Nowy status użytkownika
- * \param descr Opis statusu użytkownika
- *
- * \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)
-{
- gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_change_status_descr(%p, %d, \"%s\");\n", sess, status, descr);
-
- return gg_change_status_common(sess, status, descr, 0);
-}
-
-/**
- * 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 time 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 time)
-{
- gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_change_status_descr_time(%p, %d, \"%s\", %d);\n", sess, status, descr, time);
-
- return gg_change_status_common(sess, status, descr, time);
-}
-
-/**
- * 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;
-}
-
-/**
- * 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);
-
- return gg_send_message_confer_richtext(sess, msgclass, 1, &recipient, message, NULL, 0);
-}
-
-/**
- * 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_confer_richtext(sess, msgclass, 1, &recipient, message, format, formatlen);
-}
-
-/**
- * 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_confer_richtext(sess, msgclass, recipients_count, recipients, message, NULL, 0);
-}
-
-/**
- * \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, int *pos, const void *src, int 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 w UTF-8
- * \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).
- */
-static int gg_convert_to_html(char *dst, const char *src, const unsigned char *format, int format_len)
-{
- const char span_fmt[] = "<span style=\"color:#%02x%02x%02x; font-family:'MS Shell Dlg 2'; font-size:9pt; \">";
- const int span_len = 75;
- const char img_fmt[] = "<img name=\"%02x%02x%02x%02x%02x%02x%02x%02x\">";
- const int img_len = 29;
- int char_pos = 0;
- int format_idx = 0;
- unsigned char old_attr = 0;
- const unsigned char *color = (const unsigned char*) "\x00\x00\x00";
- int len, i;
- const unsigned char *format_ = (const unsigned char*) format;
-
- len = 0;
-
- /* Nie mamy atrybutów dla pierwsze znaku, a tekst nie jest pusty, więc
- * tak czy inaczej trzeba otworzyć <span>. */
-
- if (src[0] != 0 && (format_idx + 3 > format_len || (format_[format_idx] | (format_[format_idx + 1] << 8)) != 0)) {
- if (dst != NULL)
- sprintf(&dst[len], span_fmt, 0, 0, 0);
-
- len += span_len;
- }
-
- /* Pętla przechodzi też przez kończące \0, żeby móc dokleić obrazek
- * na końcu tekstu. */
-
- for (i = 0; ; i++) {
- /* Analizuj atrybuty tak długo jak dotyczą aktualnego znaku. */
- for (;;) {
- unsigned char attr;
- int attr_pos;
-
- if (format_idx + 3 > format_len)
- break;
-
- attr_pos = format_[format_idx] | (format_[format_idx + 1] << 8);
-
- if (attr_pos != char_pos)
- break;
-
- 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 & (GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR)) != 0 || (attr == 0 && old_attr != 0)) {
- if (char_pos != 0) {
- 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 (src[i] != 0)
- gg_append(dst, &len, "</span>", 7);
- }
-
- if (((attr & GG_FONT_COLOR) != 0) && (format_idx + 3 <= format_len)) {
- color = &format_[format_idx];
- format_idx += 3;
- } else {
- color = (unsigned char*) "\x00\x00\x00";
- }
-
- if (src[i] != 0) {
- if (dst != NULL)
- sprintf(&dst[len], span_fmt, color[0], color[1], color[2]);
- len += span_len;
- }
- } else if (char_pos == 0 && src[0] != 0) {
- if (dst != NULL)
- sprintf(&dst[len], span_fmt, 0, 0, 0);
- len += span_len;
- }
-
- 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;
- }
-
- /* 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':
- case 0:
- break;
- default:
- if (dst != NULL)
- dst[len] = src[i];
- len++;
- }
-
- /* Sprawdź, czy bajt nie jest kontynuacją znaku unikodowego. */
-
- if ((src[i] & 0xc0) != 0xc0)
- char_pos++;
-
- if (src[i] == 0)
- break;
- }
-
- /* 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 (src[0] != 0)
- gg_append(dst, &len, "</span>", 7);
-
- if (dst != NULL)
- dst[len] = 0;
-
- return len;
-}
-
-/**
- * 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)
-{
- struct gg_send_msg s;
- struct gg_send_msg80 s80;
- struct gg_msg_recipients r;
- char *cp_msg = NULL;
- char *utf_msg = NULL;
- char *html_msg = NULL;
- int seq_no;
- int i, j, k;
- uin_t *recps;
-
- 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);
-
- if (!sess) {
- errno = EFAULT;
- return -1;
- }
-
- if (sess->state != GG_STATE_CONNECTED) {
- errno = ENOTCONN;
- return -1;
- }
-
- if (message == NULL || recipients_count <= 0 || recipients_count > 0xffff || (recipients_count != 1 && recipients == NULL)) {
- errno = EINVAL;
- return -1;
- }
-
- if (sess->encoding == GG_ENCODING_UTF8) {
- if (!(cp_msg = gg_utf8_to_cp((const char *) message)))
- return -1;
-
- utf_msg = (char*) message;
- } else {
- if (sess->protocol_version >= 0x2d) {
- if (!(utf_msg = gg_cp_to_utf8((const char *) message)))
- return -1;
- }
-
- cp_msg = (char*) message;
- }
-
- if (sess->protocol_version < 0x2d) {
- if (!sess->seq)
- sess->seq = 0x01740000 | (rand() & 0xffff);
- seq_no = sess->seq;
- sess->seq += (rand() % 0x300) + 0x300;
-
- s.msgclass = gg_fix32(msgclass);
- s.seq = gg_fix32(seq_no);
- } else {
- int len;
-
- // 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 = (int)time(NULL);
-
- if (seq_no <= sess->seq)
- seq_no = sess->seq + 1;
-
- sess->seq = seq_no;
-
- if (format == NULL || formatlen < 3) {
- format = (unsigned char*) "\x02\x06\x00\x00\x00\x08\x00\x00\x00";
- formatlen = 9;
- }
-
- len = gg_convert_to_html(NULL, utf_msg, format + 3, formatlen - 3);
-
- html_msg = malloc(len + 1);
-
- if (html_msg == NULL) {
- seq_no = -1;
- goto cleanup;
- }
-
- gg_convert_to_html(html_msg, utf_msg, format + 3, formatlen - 3);
-
- s80.seq = gg_fix32(seq_no);
- s80.msgclass = gg_fix32(msgclass);
- s80.offset_plain = gg_fix32(sizeof(s80) + (uint32_t)strlen(html_msg) + 1);
- s80.offset_attr = gg_fix32(sizeof(s80) + (uint32_t)strlen(html_msg) + 1 + (uint32_t)strlen(cp_msg) + 1);
- }
-
- if (recipients_count > 1) {
- r.flag = 0x01;
- r.count = gg_fix32(recipients_count - 1);
-
- recps = malloc(sizeof(uin_t) * recipients_count);
-
- if (!recps) {
- seq_no = -1;
- goto cleanup;
- }
-
- for (i = 0; i < recipients_count; i++) {
- for (j = 0, k = 0; j < recipients_count; j++) {
- if (recipients[j] != recipients[i]) {
- recps[k] = gg_fix32(recipients[j]);
- k++;
- }
- }
-
- if (sess->protocol_version < 0x2d) {
- s.recipient = gg_fix32(recipients[i]);
-
- if (gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), cp_msg, strlen(cp_msg) + 1, &r, sizeof(r), recps, (recipients_count - 1) * sizeof(uin_t), format, formatlen, NULL) == -1)
- seq_no = -1;
- } else {
- s80.recipient = gg_fix32(recipients[i]);
-
- if (gg_send_packet(sess, GG_SEND_MSG80, &s80, sizeof(s80), html_msg, strlen(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 {
- if (sess->protocol_version < 0x2d) {
- s.recipient = gg_fix32(recipients[0]);
-
- if (gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), cp_msg, strlen(cp_msg) + 1, format, formatlen, NULL) == -1)
- seq_no = -1;
- } else {
- s80.recipient = gg_fix32(recipients[0]);
-
- if (gg_send_packet(sess, GG_SEND_MSG80, &s80, sizeof(s80), html_msg, strlen(html_msg) + 1, cp_msg, strlen(cp_msg) + 1, format, formatlen, NULL) == -1)
- seq_no = -1;
- }
- }
-
-cleanup:
- if (cp_msg != (char*) message)
- free(cp_msg);
-
- if (utf_msg != (char*) message)
- free(utf_msg);
-
- free(html_msg);
-
- return seq_no;
-}
-
-/**
- * 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 = 0x04;
- 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_msg_image_reply *r;
- struct gg_send_msg s;
- const char *tmp;
- char buf[1910];
- int res = -1;
-
- 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;
- }
-
- 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 = 0x05;
- r->size = gg_fix32(size);
- r->crc32 = gg_fix32(gg_crc32(0, (unsigned char*) image, size));
-
- while (size > 0) {
- int 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 == 0x05) {
- strcpy(buf + buflen, filename);
- buflen += (int)strlen(filename) + 1;
- }
-
- chunklen = (size >= (int)sizeof(buf) - buflen) ? ((int)sizeof(buf) - buflen) : size;
-
- memcpy(buf + buflen, image, chunklen);
- size -= chunklen;
- image += chunklen;
-
- res = gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), buf, buflen + chunklen, NULL);
-
- if (res == -1)
- break;
-
- r->flag = 0x06;
- }
-
- return res;
-}
-
-/**
- * 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
- * \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;
- uin_t *u;
- char *t;
- 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 (!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 (u = userlist, t = types, i = 0; i < part_count; u++, t++, i++) {
- n[i].uin = gg_fix32(*u);
- n[i].dunno1 = *t;
- }
-
- 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;
- 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)
-{
- struct gg_notify *n;
- uin_t *u;
- int i, res = 0;
-
- gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_notify(%p, %p, %d);\n", sess, userlist, count);
-
- if (!sess) {
- errno = EFAULT;
- return -1;
- }
-
- if (sess->state != GG_STATE_CONNECTED) {
- errno = ENOTCONN;
- return -1;
- }
-
- 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 (u = userlist, i = 0; i < part_count; u++, i++) {
- n[i].uin = gg_fix32(*u);
- n[i].dunno1 = GG_USER_NORMAL;
- }
-
- if (gg_send_packet(sess, packet_type, n, sizeof(*n) * part_count, NULL) == -1) {
- res = -1;
- free(n);
- break;
- }
-
- free(n);
-
- userlist += part_count;
- count -= part_count;
- }
-
- return res;
-}
-
-/**
- * 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)
-{
- struct gg_add_remove a;
-
- 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;
- }
-
- 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)
-{
- struct gg_add_remove a;
-
- 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;
- }
-
- 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 = (int)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);
-}
-
-/**
- * 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((uint16_t)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);
-}
-
-/* @} */
-
-/*
- * Local variables:
- * c-indentation-style: k&r
- * c-basic-offset: 8
- * indent-tabs-mode: notnil
- * End:
- *
- * vim: shiftwidth=8:
- */
diff --git a/protocols/Gadu-Gadu/libgadu/libgadu.h b/protocols/Gadu-Gadu/libgadu/libgadu.h deleted file mode 100644 index d273d998e1..0000000000 --- a/protocols/Gadu-Gadu/libgadu/libgadu.h +++ /dev/null @@ -1,2311 +0,0 @@ -/* coding: UTF-8 */ -/* $Id: libgadu.h 13762 2011-08-09 12:35:16Z dezred $ */ - -/* - * (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 __GG_LIBGADU_H -#define __GG_LIBGADU_H - -/* Defined if libgadu should be compatible with Miranda. */ -#define GG_CONFIG_MIRANDA - -#ifdef GG_CONFIG_MIRANDA -#include <m_ssl.h> -#endif - -#if defined(__cplusplus) || defined(_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 pthread support. */ -#define GG_CONFIG_HAVE_PTHREAD - -/* Defined if pthread resolver is the default one. */ -#define 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. */ -/* Visual C++ 6.0 has no long long */ -#if !defined(_MSC_VER) || (_MSC_VER >= 1300) -#define GG_CONFIG_HAVE_LONG_LONG -#endif - -/* Defined if libgadu was compiled and linked with OpenSSL support. */ -#undef GG_CONFIG_HAVE_OPENSSL - -/* 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 - -/* MSC have no va_copy */ -#ifndef _MSC_VER -#define GG_CONFIG_HAVE_VA_COPY -#define GG_CONFIG_HAVE___VA_COPY -#endif - -#if defined(GG_CONFIG_HAVE_OPENSSL) && !defined(GG_CONFIG_MIRANDA)
-#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 - -#ifndef __AC_STDINT_H -#define __AC_STDINT_H - -/* ISO C 9X: 7.18 Integer types <stdint.h> */ - -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -#ifdef GG_CONFIG_HAVE_LONG_LONG
-typedef unsigned long long uint64_t;
-#define GG_CONFIG_HAVE_UINT64_T
-#endif - -#ifndef __CYGWIN__ -#define __int8_t_defined -typedef signed char int8_t; -typedef signed short int16_t; -typedef signed int int32_t; -#endif - -#endif /* __AC_STDINT_H */ - -# endif -# endif -# endif -# endif -#endif - -#ifdef _WIN32 -# define kill(pid,sig) -# ifdef _MSC_VER -# define vsnprintf _vsnprintf -# define stat _stat -# ifndef strdup -# define strdup _strdup -# endif -# define strncasecmp _strnicmp -# define vsnprintf _vsnprintf -# define snprintf _snprintf -# define strcasecmp _stricmp -# define GG_CONFIG_HAVE_STRTOULL -# define strtoull _strtoui64 -# endif -# define gg_sock_write(sock,buf,len) send(sock,(void *)(buf),len,0) -# define gg_sock_read(sock,buf,len) recv(sock,(void *)(buf),len,0) -# define gg_sock_close(sock) closesocket(sock) -# define gg_getsockopt(sock,level,name,val,len) getsockopt(sock,level,name,(char *)val,len) -#else - typedef int SOCKET; -# define gg_sock_write write -# define gg_sock_read read -# define gg_sock_close close -# define gg_getsockopt getsockopt -#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) \ - SOCKET 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;
- -/** - * 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_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; - -/** - * 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 do wersji Gadu-Gadu 6.x */ - uint16_t client_port; /**< Port gniazda dla połączeń bezpośrednich do wersji Gadu-Gadu 6.x */ - - uint32_t external_addr; /**< Publiczny adres dla połączeń bezpośrednich do wersji Gadu-Gadu 6.x */ - uint16_t external_port; /**< Publiczny port dla połączeń bezpośrednich do wersji Gadu-Gadu 6.x */ - - 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 odbierany pakiety */ - 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 */ - - char *header_buf; /**< Bufor na początek nagłówka pakietu */ - unsigned int header_done; /**< Liczba wczytanych bajtów nagłówka pakietu */ - -#ifdef GG_CONFIG_MIRANDA - HSSL ssl; - int tls; /**< Flaga połączenia szyfrowanego */ -#elif 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)(SOCKET *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 */ -}; - -/** - * 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)(SOCKET *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 */ - -#ifdef GG_CONFIG_MIRANDA - void *contact; - char *folder; - uint32_t tick; -#endif -}; - -#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 */
- -#ifdef GG_CONFIG_MIRANDA - void *contact; - char *folder; - uint32_t tick; -#endif -}; - -/** - * 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 */ -}; - -/** - * 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 */ -}; - -/** - * 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) */ -#ifndef DOXYGEN - uint32_t client_addr; /**< Adres połączeń bezpośrednich (nieaktualne) */ - uint16_t client_port; /**< Port połączeń bezpośrednich (nieaktualne) */ -#endif - 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 (6.x) */ - uint16_t external_port; /**< Port publiczny dla połączeń bezpośrednich (6.x) */ -#ifndef DOXYGEN - int tls; /**< Flaga połączenia szyfrowanego (nieaktualna) */ -#endif - 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). */ - -#ifndef DOXYGEN - char dummy[1 * sizeof(int)]; /**< \internal Miejsce na kilka kolejnych - parametrów, żeby wraz z dodawaniem kolejnych - parametrów nie zmieniał się rozmiar struktury */ -#endif - -}; - -#ifdef GG_CONFIG_MIRANDA -struct gg_session *gg_login(const struct gg_login_params *p, SOCKET *gg_sock, int *gg_failno); -#else -struct gg_session *gg_login(const struct gg_login_params *p); -#endif -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_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_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_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 TCHAR *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)(SOCKET*, 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)(SOCKET*, 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)(SOCKET*, void**, const char*), void (*resolver_cleanup)(void**, int)); - -int gg_multilogon_disconnect(struct gg_session *gs, gg_multilogon_id_t conn_id);
- -/** - * 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_XML_ACTION, - 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 */
-}; - -#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 */ -}; - -/** - * 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 */ - time_t time; /**< Czas nadania */ - 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 (może być równe \c NULL, jeśli wiadomość nie zawiera treści XHTML) */ -}; - -/** - * 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 */ - time_t time; /**< Czas powrotu */ -}; - -/** - * 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 */ - time_t time; /**< Czas powrotu */ -}; - -/** - * 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_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_XML_ACTION. - */ -struct gg_event_xml_action { - char *data; /**< Bufor z komunikatem */ -}; - -/** - * 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_DCC7_ERROR. - * - * \note Odwrotna kolejność pól ma na celu zachowanie ABI. - */ -struct gg_event_dcc7_error { - enum gg_error_t error; /**< Kod błędu */ - 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 */
- time_t logon_time; /**< Czas zalogowania */
-};
-
-/**
- * Opis zdarzenia \c GG_EVENT_MULTILOGON_INFO.
- */
-struct gg_event_multilogon_info {
- int count; /**< Liczba sesji */
- struct gg_multilogon_session *sessions; /** Lista sesji */
-};
- -/** - * 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_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_xml_action xml_action; /**< Zdarzenie XML (\c GG_EVENT_XML_ACTION) */ - 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_error dcc7_error_ex; /**< Błąd połączenia bezpośredniego ze wskaźnikiem na strukturę połączenia (\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 (\c GG_EVENT_TYPING_NOTIFICATION) */ - 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) */
-}; - -/** - * 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 */ - -/** - * 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 */ -}; - -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); -int gg_dcc7_abort(struct gg_dcc7 *dcc); -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 */ -/** @} */ - -#ifdef GG_DEBUG_DISABLE -#define gg_debug(x, y...) do { } while(0) -#define gg_debug_session(z, x, y...) do { } while(0) -#else -void gg_debug(int level, const char *format, ...); -void gg_debug_session(struct gg_session *sess, int level, const char *format, ...); -#endif - -const char *gg_libgadu_version(void); - -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; - -#ifdef __GNUC__ -char *gg_saprintf(const char *format, ...) __attribute__ ((format (printf, 1, 2))) GG_DEPRECATED; -#else -char *gg_saprintf(const char *format, ...) GG_DEPRECATED; -#endif - -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; - -SOCKET gg_connect(void *addr, int port, int async) GG_DEPRECATED; -#ifdef GG_CONFIG_MIRANDA -SOCKET gg_connect_internal(void *addr, int port, int async, SOCKET *gg_sock);
-#endif -struct in_addr *gg_gethostbyname(const char *hostname) GG_DEPRECATED; -char *gg_read_line(SOCKET 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 */ -} GG_DEPRECATED; - -int gg_dcc7_handle_id(struct gg_session *sess, struct gg_event *e, void *payload, int len) GG_DEPRECATED; -int gg_dcc7_handle_new(struct gg_session *sess, struct gg_event *e, void *payload, int len) GG_DEPRECATED; -int gg_dcc7_handle_info(struct gg_session *sess, struct gg_event *e, void *payload, int len) GG_DEPRECATED; -int gg_dcc7_handle_accept(struct gg_session *sess, struct gg_event *e, void *payload, int len) GG_DEPRECATED; -int gg_dcc7_handle_reject(struct gg_session *sess, struct gg_event *e, void *payload, int len) GG_DEPRECATED; -int gg_dcc7_handle_abort(struct gg_session *sess, struct gg_event *e, 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_DEFAULT_CLIENT_VERSION "10.1.0.11070" -#define GG_DEFAULT_PROTOCOL_VERSION 0x2e -#define GG_DEFAULT_TIMEOUT 30 -#define GG_HAS_AUDIO_MASK 0x40000000 -#define GG_HAS_AUDIO7_MASK 0x20000000 -#define GG_ERA_OMNIX_MASK 0x04000000 -#define GG_LIBGADU_VERSION "1.10.0" - -#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_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_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_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_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; - -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_HIDDEN 0x00000003 /* użytkownik ojest ukryty i nie możesz mu wysłać pliku */ -#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 - -struct gg_dcc7_dunno1 { - // XXX -} GG_PACKED; -*/ - -#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; - -struct gg_dcc7_aborted { - gg_dcc7_id_t id; /* identyfikator połączenia */
-} GG_PACKED; - -#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 */ - -#ifdef __cplusplus -} -#endif - -#if defined(__cplusplus) || defined(_WIN32) -#ifdef _WIN32 -#pragma pack(pop) -#endif -#endif - -#endif /* __GG_LIBGADU_H */ - -/* - * Local variables: - * c-indentation-style: k&r - * c-basic-offset: 8 - * indent-tabs-mode: notnil - * End: - * - * vim: shiftwidth=8: - */ diff --git a/protocols/Gadu-Gadu/libgadu/obsolete.c b/protocols/Gadu-Gadu/libgadu/obsolete.c deleted file mode 100644 index f8fe4dc5de..0000000000 --- a/protocols/Gadu-Gadu/libgadu/obsolete.c +++ /dev/null @@ -1,238 +0,0 @@ -/* coding: UTF-8 */
-/* $Id: obsolete.c 854 2009-10-12 21:06:28Z wojtekka $ */
-
-/*
- * (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 "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;
-}
-
-/** \endcond */
diff --git a/protocols/Gadu-Gadu/libgadu/protocol.h b/protocols/Gadu-Gadu/libgadu/protocol.h deleted file mode 100644 index 5b4895c260..0000000000 --- a/protocols/Gadu-Gadu/libgadu/protocol.h +++ /dev/null @@ -1,277 +0,0 @@ -/* coding: UTF-8 */ -/* $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 - -#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 GG8_LANG "pl" -#define GG8_VERSION "Gadu-Gadu Client Build " - -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 - -/** - * 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_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_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; - -struct gg_dcc7_voice_nodata { /* wyciszony mikrofon, ten pakiet jest wysylany co 1s (jesli chcemy podtrzymac polaczenie) */ - 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; - -#ifdef _WIN32 -#pragma pack(pop) -#endif - -#endif /* LIBGADU_PROTOCOL_H */ diff --git a/protocols/Gadu-Gadu/libgadu/pthread.c b/protocols/Gadu-Gadu/libgadu/pthread.c deleted file mode 100644 index 9a8988a358..0000000000 --- a/protocols/Gadu-Gadu/libgadu/pthread.c +++ /dev/null @@ -1,78 +0,0 @@ -/*
-AOL Instant Messenger Plugin for Miranda IM
-
-Copyright (c) 2003-2006 Robert Rainwater
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
-
-#include "pthread.h"
-#include <process.h>
-#include <newpluginapi.h>
-#include <m_system.h>
-
-/****************************************/
-/* Portable pthread code for Miranda IM */
-
-/* create thread */
-int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void *(__stdcall * thread_start) (void *), void *param)
-{
- tid->hThread = (HANDLE)mir_forkthreadex((pThreadFuncEx)*(void**)&thread_start, param, (unsigned *)&tid->dwThreadId);
-
- return 0;
-}
-
-/* detach a thread */
-int pthread_detach(pthread_t *tid)
-{
- CloseHandle(tid->hThread);
- return 0;
-}
-
-/* wait for thread termination */
-int pthread_join(pthread_t *tid, void **value_ptr)
-{
- if (tid->dwThreadId == GetCurrentThreadId())
- return 35 /*EDEADLK*/;
-
- WaitForSingleObject(tid->hThread, INFINITE);
- return 0;
-}
-
-/* get calling thread's ID */
-pthread_t *pthread_self(void)
-{
- static int poolId = 0;
- static pthread_t tidPool[32];
- /* mark & round pool to 32 items */
- pthread_t *tid = &tidPool[poolId ++];
- poolId %= 32;
-
- tid->hThread = GetCurrentThread();
- tid->dwThreadId = GetCurrentThreadId();
- return tid;
-}
-
-/* cancel execution of a thread */
-int pthread_cancel(pthread_t *thread)
-{
- return TerminateThread(thread->hThread, 0) ? 0 : 3 /*ESRCH*/;
-}
-
-/* terminate thread */
-void pthread_exit(void *value_ptr)
-{
-// _endthreadex((unsigned)value_ptr);
-}
diff --git a/protocols/Gadu-Gadu/libgadu/pthread.h b/protocols/Gadu-Gadu/libgadu/pthread.h deleted file mode 100644 index 4de1053e0e..0000000000 --- a/protocols/Gadu-Gadu/libgadu/pthread.h +++ /dev/null @@ -1,56 +0,0 @@ -/*
-pthread Portable implementation
-
-Copyright (c) 2003 Robert Rainwater
-Copyright (c) 2003-2005 Adam Strzelecki
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
-
-#ifndef PTHREAD_H
-#define PTHREAD_H
-
-#include <windows.h>
-
-// Minipthread code from Miranda IM source
-typedef struct
-{
- HANDLE hThread;
- DWORD dwThreadId;
-}
-pthread_t;
-
-typedef int pthread_attr_t;
-typedef CRITICAL_SECTION pthread_mutex_t;
-
-/* create thread */
-int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void *(__stdcall *thread_start) (void *), void *param);
-/* wait for thread termination */
-int pthread_join(pthread_t *tid, void **value_ptr);
-/* detach a thread */
-int pthread_detach(pthread_t *tid);
-/* get calling thread's ID */
-pthread_t *pthread_self(void);
-/* cancel execution of a thread */
-int pthread_cancel(pthread_t *thread);
-/* terminate thread */
-void pthread_exit(void *value_ptr);
-
-#define pthread_mutex_init(pmutex, pattr) InitializeCriticalSection(pmutex)
-#define pthread_mutex_destroy(pmutex) DeleteCriticalSection(pmutex)
-#define pthread_mutex_lock(pmutex) EnterCriticalSection(pmutex)
-#define pthread_mutex_unlock(pmutex) LeaveCriticalSection(pmutex)
-
-#endif
diff --git a/protocols/Gadu-Gadu/libgadu/pubdir.c b/protocols/Gadu-Gadu/libgadu/pubdir.c deleted file mode 100644 index f9d656dfe3..0000000000 --- a/protocols/Gadu-Gadu/libgadu/pubdir.c +++ /dev/null @@ -1,862 +0,0 @@ -/* coding: UTF-8 */
-/* $Id: pubdir.c 11370 2010-03-13 16:17:54Z dezred $ */
-
-/*
- * (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 <ctype.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef _WIN32
-#include "win32.h"
-#define random() rand()
-#else
-#include <unistd.h>
-#endif
-
-#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("%ld", random());
- __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);
- 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);
- gg_debug(GG_DEBUG_MISC, "=> pubdir, success (uin=%d)\n", p->uin);
- } else
- gg_debug(GG_DEBUG_MISC, "=> pubdir, 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;
-
- gg_debug(GG_DEBUG_MISC, "=> token body \"%s\"\n", h->body);
-
- if (h->body && (!(url = malloc(strlen(h->body))) || !(tokenid = malloc(strlen(h->body))))) {
- 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:
- */
diff --git a/protocols/Gadu-Gadu/libgadu/pubdir50.c b/protocols/Gadu-Gadu/libgadu/pubdir50.c deleted file mode 100644 index 6914cbd01a..0000000000 --- a/protocols/Gadu-Gadu/libgadu/pubdir50.c +++ /dev/null @@ -1,557 +0,0 @@ -/* coding: UTF-8 */
-/* $Id: pubdir50.c 11370 2010-03-13 16:17:54Z dezred $ */
-
-/*
- * (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
- */
-
-#ifndef _WIN64
-#define _USE_32BIT_TIME_T
-#endif
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#ifdef _WIN32
-#include "win32.h"
-#undef small
-#endif
-
-#include "libgadu.h"
-#include "internal.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)
-{
- size_t size = 5;
- int i;
- 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;
-
- tmp = gg_utf8_to_cp(req->entries[i].field);
-
- if (tmp == NULL)
- return -1;
-
- size += strlen(tmp) + 1;
-
- free(tmp);
-
- tmp = gg_utf8_to_cp(req->entries[i].value);
-
- 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 = (uint32_t)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;
-
- tmp = gg_utf8_to_cp(req->entries[i].field);
-
- if (tmp == NULL) {
- free(buf);
- return -1;
- }
-
- strcpy(p, tmp);
- p += strlen(tmp) + 1;
- free(tmp);
-
- tmp = gg_utf8_to_cp(req->entries[i].value);
-
- 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;
- struct gg_pubdir50_reply *r = (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 = atoi(value);
- 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_cp_to_utf8(value);
-
- 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:
- */
diff --git a/protocols/Gadu-Gadu/libgadu/resolver.c b/protocols/Gadu-Gadu/libgadu/resolver.c deleted file mode 100644 index 1adef3ef9d..0000000000 --- a/protocols/Gadu-Gadu/libgadu/resolver.c +++ /dev/null @@ -1,766 +0,0 @@ -/* coding: UTF-8 */ -/* $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> - * 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 - */ - -#ifdef _WIN32 -#include "win32.h" -#else -#include <sys/wait.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#endif /* _WIN32 */ - -#ifndef _WIN32 -#include <netdb.h> -#endif -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#ifndef _WIN32 -#include <unistd.h> -#endif -#include <signal.h> - -#include "libgadu.h" -#include "resolver.h" -#include "compat.h" - -/** 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)(SOCKET *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> - -#ifdef GG_CONFIG_HAVE_GETHOSTBYNAME_R -/** - * \internal Funkcja pomocnicza zwalniająca zasoby po rozwiązywaniu nazwy - * w wątku. - * - * \param data Wskaźnik na wskaźnik bufora zaalokowanego w wątku - */ -static void gg_gethostbyname_cleaner(void *data) -{ - char **buf_ptr = (char**) data; - - if (buf_ptr != NULL) { - free(*buf_ptr); - *buf_ptr = NULL; - } -} -#endif -#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. - * - * \param hostname Nazwa serwera - * \param addr Wskaźnik na rezultat rozwiązywania nazwy - * \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 *addr, 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 result = -1; - int h_errnop; - int ret = 0; -#ifdef GG_CONFIG_HAVE_PTHREAD - int old_state; -#endif - -#ifdef GG_CONFIG_HAVE_PTHREAD - pthread_cleanup_push(gg_gethostbyname_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) { -#ifndef sun - while ((ret = gethostbyname_r(hostname, &he, buf, buf_len, &he_ptr, &h_errnop)) == ERANGE) { -#else - while (((he_ptr = gethostbyname_r(hostname, &he, buf, buf_len, &h_errnop)) == NULL) && (errno == ERANGE)) { -#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) { - memcpy(addr, he_ptr->h_addr, sizeof(struct in_addr)); - result = 0; - } - -#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(1); -#endif - - return result; -#else - struct hostent *he; - - he = gethostbyname(hostname); - - if (he == NULL) - return -1; - - memcpy(addr, he->h_addr, sizeof(struct in_addr)); - - return 0; -#endif /* GG_CONFIG_HAVE_GETHOSTBYNAME_R */ -} - -/** - * \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. - * - * \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 *addr; - - if (!(addr = malloc(sizeof(struct in_addr)))) - return NULL; - - if (gg_gethostbyname_real(hostname, addr, 0)) { - free(addr); - return NULL; - } - return addr; -} - -/** - * \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 tworzony jest potok, nowy proces i dopiero w nim - * przeprowadzane jest rozwiązywanie nazwy. Deskryptor strony 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 - * potoku - * \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(SOCKET *fd, void **priv_data, const char *hostname) -{ - struct gg_resolver_fork_data *data = NULL; - struct in_addr addr; - int new_errno; - SOCKET pipes[2]; - - 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 (pipe(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) { - gg_sock_close(pipes[0]); - - if ((addr.s_addr = inet_addr(hostname)) == INADDR_NONE) { - /* W przypadku błędu gg_gethostbyname_real() zwróci -1 - * i nie zmieni &addr. Tam jest już INADDR_NONE, - * więc nie musimy robić nic więcej. */ - gg_gethostbyname_real(hostname, &addr, 0); - } - - if (gg_sock_write(pipes[1], &addr, sizeof(addr)) != sizeof(addr)) - exit(1); - - exit(0); - } - - gg_sock_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); - gg_sock_close(pipes[0]); - gg_sock_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); - - waitpid(data->pid, NULL, WNOHANG); - - free(data); -} - -#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 */ - SOCKET rfd; /*< Deskryptor do odczytu */ - SOCKET 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); - } - - free(data->hostname); - data->hostname = NULL; - - if (data->wfd != -1) { - gg_sock_close(data->wfd); - data->wfd = -1; - } - - free(data); -} - -/** - * \internal Wątek rozwiązujący nazwę. - * - * \param arg Wskaźnik na strukturę \c gg_resolver_pthread_data - */ -static void *__stdcall gg_resolver_pthread_thread(void *arg) -{ - struct gg_resolver_pthread_data *data = arg; - struct in_addr addr; - - pthread_detach(pthread_self()); - - if ((addr.s_addr = inet_addr(data->hostname)) == INADDR_NONE) { - /* W przypadku błędu gg_gethostbyname_real() zwróci -1 - * i nie zmieni &addr. Tam jest już INADDR_NONE, - * więc nie musimy robić nic więcej. */ - gg_gethostbyname_real(data->hostname, &addr, 1); - } - - if (gg_sock_write(data->wfd, &addr, sizeof(addr)) == sizeof(addr)) - pthread_exit(NULL); - else - pthread_exit((void*) -1); - - 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 - * potoku - * \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(SOCKET *fd, void **priv_data, const char *hostname) -{ - struct gg_resolver_pthread_data *data = NULL; - int new_errno; - SOCKET pipes[2]; - - 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 (pipe(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->rfd = pipes[0]; - 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) { - free(data->hostname); - free(data); - } - - gg_sock_close(pipes[0]); - gg_sock_close(pipes[1]); - - errno = new_errno; - - return -1; -} - -#endif /* GG_CONFIG_HAVE_PTHREAD */ - -/** - * 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) -{ - if (gs == NULL) { - errno = EINVAL; - return -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; - } - -#if !defined(GG_CONFIG_HAVE_PTHREAD) || !defined(GG_CONFIG_PTHREAD_DEFAULT) - type = GG_RESOLVER_FORK; -#else - type = GG_RESOLVER_PTHREAD; -#endif - } - - switch (type) { - case GG_RESOLVER_FORK: - gs->resolver_type = type; - gs->resolver_start = gg_resolver_fork_start; - gs->resolver_cleanup = gg_resolver_fork_cleanup; - return 0; - -#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 - - 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) -{ - if (gs == NULL) { - errno = EINVAL; - return GG_RESOLVER_INVALID; - } - - 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 - * - * \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)(SOCKET*, void**, const char*), void (*resolver_cleanup)(void**, int)) -{ - if (gs == NULL || 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; - } - -#if !defined(GG_CONFIG_HAVE_PTHREAD) || !defined(GG_CONFIG_PTHREAD_DEFAULT) - type = GG_RESOLVER_FORK; -#else - type = GG_RESOLVER_PTHREAD; -#endif - } - - switch (type) { - case GG_RESOLVER_FORK: - gh->resolver_type = type; - gh->resolver_start = gg_resolver_fork_start; - gh->resolver_cleanup = gg_resolver_fork_cleanup; - return 0; - -#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 - - 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)(SOCKET*, 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; - - 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; - -#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 - - 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 - * - * Parametry funkcji rozpoczynającej rozwiązywanie nazwy wyglądają następująco: - * - \c "SOCKET *fd" — wskaźnik na zmienną, gdzie zostanie umieszczony deskryptor potoku - * - \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 jednostronną komunikację i - * przekazać go w parametrze \c fd. 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_global_set_custom_resolver(int (*resolver_start)(SOCKET*, 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; -} - diff --git a/protocols/Gadu-Gadu/libgadu/resolver.h b/protocols/Gadu-Gadu/libgadu/resolver.h deleted file mode 100644 index 145c5178a4..0000000000 --- a/protocols/Gadu-Gadu/libgadu/resolver.h +++ /dev/null @@ -1,33 +0,0 @@ -/* coding: UTF-8 */
-/* $Id$ */
-
-/*
- * (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
-
-#ifdef _WIN32
-#include "win32.h"
-#else
-#include <arpa/inet.h>
-#endif /* _WIN32 */
-
-int gg_gethostbyname_real(const char *hostname, struct in_addr *result, int pthread);
-
-#endif /* LIBGADU_RESOLVER_H */
diff --git a/protocols/Gadu-Gadu/libgadu/sha1.c b/protocols/Gadu-Gadu/libgadu/sha1.c deleted file mode 100644 index 124a1cffaa..0000000000 --- a/protocols/Gadu-Gadu/libgadu/sha1.c +++ /dev/null @@ -1,308 +0,0 @@ -/* coding: UTF-8 */
-/* $Id: sha1.c,v 1.4 2007-07-20 23:00:50 wojtekka Exp $ */
-
-/*
- * (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 <string.h>
-#include <sys/types.h>
-#ifdef _WIN32
-#include "win32.h"
-#else
-#include <unistd.h>
-#endif
-
-#include "libgadu.h"
-
-/** \cond ignore */
-
-#if defined(GG_CONFIG_HAVE_OPENSSL) && !defined(GG_CONFIG_MIRANDA)
-
-#include <openssl/sha.h>
-
-#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. */
-
-#include <string.h>
-
-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 void SHA1_Init(SHA_CTX* context);
-static void SHA1_Update(SHA_CTX* context, const unsigned char* data, unsigned int len);
-static void 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 */
-#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);
-
-
-/* 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;
-static unsigned char workspace[64];
- block = (CHAR64LONG16*)workspace;
- memcpy(block, buffer, 64);
- /* 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. */
- 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);
- /* 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 */
- a = b = c = d = e = 0;
-}
-
-
-/* SHA1_Init - Initialize new context */
-
-static void 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;
-}
-
-
-/* Run your data through this. */
-
-static void 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);
-}
-
-
-/* Add padding and return the message digest. */
-
-static void SHA1_Final(unsigned char digest[20], SHA_CTX* context)
-{
-uint32_t i, j;
-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, (unsigned char *)"\200", 1);
- while ((context->count[0] & 504) != 448) {
- SHA1_Update(context, (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 */
- i = j = 0;
- 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
-}
-
-#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)
- */
-void gg_login_hash_sha1(const char *password, uint32_t seed, uint8_t *result)
-{
- SHA_CTX ctx;
-
- SHA1_Init(&ctx);
- SHA1_Update(&ctx, (const unsigned char*) password, (unsigned int)strlen(password));
- seed = gg_fix32(seed);
- SHA1_Update(&ctx, (uint8_t*) &seed, 4);
-
- SHA1_Final(result, &ctx);
-}
-
-/**
- * \internal Liczy skrĂłt SHA1 z pliku.
- *
- * \param fd Deskryptor pliku
- * \param result WskaĹşnik na skrĂłt
- *
- * \return 0 lub -1
- */
-int gg_file_hash_sha1(int fd, uint8_t *result)
-{
- unsigned char buf[4096];
- SHA_CTX ctx;
- off_t pos, len;
- int res;
-
- 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;
-
- SHA1_Init(&ctx);
-
- if (len <= 10485760) {
- while ((res = read(fd, buf, sizeof(buf))) > 0)
- SHA1_Update(&ctx, buf, res);
- } else {
- int i;
-
- for (i = 0; i < 9; i++) {
- int j;
-
- if (lseek(fd, (len - 1048576) / 9 * i, SEEK_SET) == (off_t) - 1)
- return -1;
-
- for (j = 0; j < 1048576 / sizeof(buf); j++) {
- if ((res = read(fd, buf, sizeof(buf))) != sizeof(buf)) {
- res = -1;
- break;
- }
-
- SHA1_Update(&ctx, buf, res);
- }
-
- if (res == -1)
- break;
- }
- }
-
- if (res == -1)
- return -1;
-
- SHA1_Final(result, &ctx);
-
- if (lseek(fd, pos, SEEK_SET) == (off_t) -1)
- return -1;
-
- return 0;
-}
-
-/** \endcond */
diff --git a/protocols/Gadu-Gadu/libgadu/win32.c b/protocols/Gadu-Gadu/libgadu/win32.c deleted file mode 100644 index 4f5ad3ff5d..0000000000 --- a/protocols/Gadu-Gadu/libgadu/win32.c +++ /dev/null @@ -1,65 +0,0 @@ -////////////////////////////////////////////////////////////////////////////////
-// Gadu-Gadu Plugin for Miranda IM
-//
-// Copyright (c) 2003-2009 Adam Strzelecki <ono+miranda@java.pl>
-// Copyright (c) 2009-2010 Bartosz Biaek
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-////////////////////////////////////////////////////////////////////////////////
-
-#ifdef _WIN32
-#include "win32.h"
-
-int sockpipe(SOCKET filedes[2])
-{
- SOCKET sock;
- struct sockaddr_in sin;
- unsigned int len = sizeof(sin);
-
- filedes[0] = filedes[1] = INVALID_SOCKET;
-
- if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
- return -1;
-
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_port = htons(0);
- sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
- if (bind(sock, (SOCKADDR *)&sin, len) == SOCKET_ERROR ||
- listen(sock, 1) == SOCKET_ERROR ||
- getsockname(sock, (SOCKADDR *)&sin, &len) == SOCKET_ERROR) {
- closesocket(sock);
- return -1;
- }
-
- if ((filedes[1] = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET ||
- connect(filedes[1], (SOCKADDR *)&sin, len) == SOCKET_ERROR) {
- closesocket(sock);
- return -1;
- }
-
- if ((filedes[0] = accept(sock, (SOCKADDR *)&sin, &len)) == INVALID_SOCKET) {
- closesocket(filedes[1]);
- filedes[1] = INVALID_SOCKET;
- closesocket(sock);
- return -1;
- }
-
- closesocket(sock);
- return 0;
-}
-
-#endif /* _WIN32 */
diff --git a/protocols/Gadu-Gadu/libgadu/win32.h b/protocols/Gadu-Gadu/libgadu/win32.h deleted file mode 100644 index d432a359ac..0000000000 --- a/protocols/Gadu-Gadu/libgadu/win32.h +++ /dev/null @@ -1,75 +0,0 @@ -////////////////////////////////////////////////////////////////////////////////
-// Gadu-Gadu Plugin for Miranda IM
-//
-// Copyright (c) 2003-2009 Adam Strzelecki <ono+miranda@java.pl>
-// Copyright (c) 2009-2010 Bartosz Biaek
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-////////////////////////////////////////////////////////////////////////////////
-
-/* Windows wrappers for missing POSIX functions */
-
-#ifndef __GG_WIN32_H
-#define __GG_WIN32_H
-
-#include <winsock2.h>
-#include <io.h>
-
-/* Some Visual C++ overrides having no problems with MinGW */
-#ifdef _MSC_VER
-#define S_IWUSR 0x0080
-/* Make sure we included errno before that */
-#include <errno.h>
-#endif
-
-#ifdef EINPROGRESS
-# undef EINPROGRESS
-#endif
-#ifdef ENOTCONN
-# undef ENOTCONN
-#endif
-#ifdef EINTR
-# undef EINTR
-#endif
-#ifdef ECONNRESET
-# undef ECONNRESET
-#endif
-#ifdef ETIMEDOUT
-# undef ETIMEDOUT
-#endif
-
-#define EINPROGRESS WSAEINPROGRESS
-#define ENOTCONN WSAENOTCONN
-#define EINTR WSAEINTR
-#define ECONNRESET WSAECONNRESET
-#define ETIMEDOUT WSAETIMEDOUT
-
-#define WNOHANG WHOHANG
-#define SHUT_RDWR 2
-
-/* Defined in gg.c custom error reporting function */
-#ifdef GG_CONFIG_MIRANDA
-char *ws_strerror(int code);
-#define strerror(x) ws_strerror(x)
-#endif
-
-#define fork() (-1)
-int sockpipe(SOCKET filedes[2]);
-#define pipe(filedes) sockpipe(filedes)
-#define wait(x) (-1)
-#define waitpid(x,y,z) (-1)
-#define ioctl(fd,request,val) ioctlsocket(fd,request,(unsigned long *)val)
-
-#endif /* __GG_WIN32_H */
|