Merged in kill-oscar-prpl (pull request #609)

Fri, 25 Oct 2019 07:52:44 +0000

author
Gary Kramlich <grim@reaperworld.com>
date
Fri, 25 Oct 2019 07:52:44 +0000
changeset 40072
67e558b6711b
parent 40065
3b61e89f42bd (current diff)
parent 40071
148d89dee247 (diff)
child 40076
432bd1f3748f

Merged in kill-oscar-prpl (pull request #609)

Kill oscar prpl

Approved-by: Elliott Sales de Andrade
Approved-by: Gary Kramlich
Approved-by: Eion Robb

doc/oscar/On_Sending_Files_via_OSCAR.odt file | annotate | diff | comparison | revisions
doc/oscar/On_Sending_Files_via_OSCAR.pdf file | annotate | diff | comparison | revisions
doc/oscar/Receive_Codepaths.odg file | annotate | diff | comparison | revisions
doc/oscar/Send_Codepaths.odg file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/AUTHORS file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/COPYING file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/aim.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/aim.h file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/authorization.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/bstream.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/clientlogin.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/encoding.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/encoding.h file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/family_admin.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/family_alert.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/family_auth.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/family_bart.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/family_bos.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/family_buddy.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/family_chat.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/family_chatnav.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/family_feedbag.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/family_icbm.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/family_icq.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/family_locate.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/family_oservice.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/family_popup.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/family_stats.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/family_userlookup.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/flap_connection.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/icq.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/icq.h file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/kerberos.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/meson.build file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/misc.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/msgcookie.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/odc.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/oft.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/oscar.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/oscar.h file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/oscar_data.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/oscarcommon.h file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/peer.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/peer.h file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/peer_proxy.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/rxhandlers.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/snac.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/snactypes.h file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/tests/meson.build file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/tests/test_oscar_util.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/tlv.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/userinfo.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/util.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/visibility.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/visibility.h file | annotate | diff | comparison | revisions
Binary file doc/oscar/On_Sending_Files_via_OSCAR.odt has changed
Binary file doc/oscar/On_Sending_Files_via_OSCAR.pdf has changed
Binary file doc/oscar/Receive_Codepaths.odg has changed
Binary file doc/oscar/Send_Codepaths.odg has changed
--- a/libpurple/protocols/meson.build	Sun Oct 20 00:24:28 2019 +0300
+++ b/libpurple/protocols/meson.build	Fri Oct 25 07:52:44 2019 +0000
@@ -5,7 +5,6 @@
 subdir('jabber')
 subdir('novell')
 subdir('null')
-subdir('oscar')
 subdir('sametime')
 subdir('silc')
 subdir('simple')
--- a/libpurple/protocols/oscar/AUTHORS	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-
-N: ComBOTS Product GmbH (htfv)
-T: 2007
-E: foss@combots.com
-
-N: Jonathan Clark
-T: 2005-2006
-E: ardentlygnarley a.t users d.o.t sourceforge d.o.t net
-
-N: Mark Doliner
-T: 2001-2006
-H: markdoliner
-E: thekingant a.t users d.o.t sourceforge d.o.t net
-W: http://kingant.net/
-
-N: Adam Fritzler
-T: 1998-2001
-H: mid
-E: mid a.t auk d.o.t cx
-W: http://www.auk.cx/~mid,http://www.auk.cx/faim
-D: Wrote most of the wap of crap that you see before you.
-
-N: Josh Myer
-T: 1998-2001
-E: josh a.t joshisanerd d.o.t com
-D: OFT/ODC (not quite finished yet..), random little things, Munger-At-Large, compile-time warnings.
-
-N: Daniel M. Pomerantz
-H: dmprantz
-D: Made initial versions cross platform
-
-N: Daniel Reed
-T: 1998-2001
-H: n, linuxkitty
-E: n a.t ml d.o.t org
-W: http://users.n.ml.org/n/
-D: Fixed aim_snac.c
-
-N: Eric Warmenhoven
-T: 1998-2001
-E: warmenhoven a.t linux d.o.t com
-D: Some OFT info, initial author of the libpurple-side of the oscar protocol plugin
-
-N: Brock Wilcox
-T: 1998-2001
-H: awwaiid
-E: awwaiid a.t auk d.o.t cx
-D: Figured out original password roasting
-
--- a/libpurple/protocols/oscar/COPYING	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,504 +0,0 @@
-		  GNU LESSER GENERAL PUBLIC LICENSE
-		       Version 2.1, February 1999
-
- Copyright (C) 1991, 1999 Free Software Foundation, Inc.
-     51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-
-Also add information on how to contact you by electronic and paper mail.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the library, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the
-  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
-
-  <signature of Ty Coon>, 1 April 1990
-  Ty Coon, President of Vice
-
-That's all there is to it!
-
-
--- a/libpurple/protocols/oscar/aim.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-/* purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- *
- */
-
-#include "aim.h"
-
-#include "core.h"
-#include "plugins.h"
-#include "signals.h"
-
-#include "oscarcommon.h"
-
-static void
-aim_protocol_init(AIMProtocol *self)
-{
-	PurpleProtocol *protocol = PURPLE_PROTOCOL(self);
-
-	protocol->id   = "prpl-aim";
-	protocol->name = "AIM";
-
-	oscar_init_account_options(protocol, FALSE);
-}
-
-static void
-aim_protocol_class_init(AIMProtocolClass *klass)
-{
-	PurpleProtocolClass *protocol_class = PURPLE_PROTOCOL_CLASS(klass);
-
-	protocol_class->list_icon = oscar_list_icon_aim;
-}
-
-static void
-aim_protocol_class_finalize(G_GNUC_UNUSED AIMProtocolClass *klass)
-{
-}
-
-static void
-aim_protocol_client_iface_init(PurpleProtocolClientInterface *client_iface)
-{
-	client_iface->get_max_message_size = oscar_get_max_message_size;
-}
-
-static void
-aim_protocol_privacy_iface_init(PurpleProtocolPrivacyInterface *privacy_iface)
-{
-	privacy_iface->add_permit      = oscar_add_permit;
-	privacy_iface->rem_permit      = oscar_rem_permit;
-	privacy_iface->set_permit_deny = oscar_set_aim_permdeny;
-}
-
-G_DEFINE_DYNAMIC_TYPE_EXTENDED(
-        AIMProtocol, aim_protocol, OSCAR_TYPE_PROTOCOL, 0,
-
-        G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_CLIENT,
-                                      aim_protocol_client_iface_init)
-
-        G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_PRIVACY,
-                                      aim_protocol_privacy_iface_init));
-
-/* This exists solely because the above macro makes aim_protocol_register_type
- * static. */
-void
-aim_protocol_register(PurplePlugin *plugin)
-{
-	aim_protocol_register_type(G_TYPE_MODULE(plugin));
-}
--- a/libpurple/protocols/oscar/aim.h	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/* purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- *
- */
-
-#ifndef PURPLE_OSCAR_AIM_H
-#define PURPLE_OSCAR_AIM_H
-
-#include "oscar.h"
-
-#define AIM_TYPE_PROTOCOL             (aim_protocol_get_type())
-#define AIM_PROTOCOL(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), AIM_TYPE_PROTOCOL, AIMProtocol))
-#define AIM_PROTOCOL_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), AIM_TYPE_PROTOCOL, AIMProtocolClass))
-#define AIM_IS_PROTOCOL(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), AIM_TYPE_PROTOCOL))
-#define AIM_IS_PROTOCOL_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), AIM_TYPE_PROTOCOL))
-#define AIM_PROTOCOL_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), AIM_TYPE_PROTOCOL, AIMProtocolClass))
-
-typedef struct
-{
-	OscarProtocol parent;
-} AIMProtocol;
-
-typedef struct
-{
-	OscarProtocolClass parent_class;
-} AIMProtocolClass;
-
-/**
- * Registers the AIMProtocol type in the type system.
- */
-G_GNUC_INTERNAL
-void aim_protocol_register(PurplePlugin *plugin);
-
-/**
- * Returns the GType for the AIMProtocol object.
- */
-G_MODULE_EXPORT GType aim_protocol_get_type(void);
-
-#endif /* PURPLE_OSCAR_AIM_H */
--- a/libpurple/protocols/oscar/authorization.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,120 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Everything related to OSCAR authorization requests.
- */
-
-#include "oscar.h"
-#include "request.h"
-
-/* When you ask other people for authorization */
-void
-oscar_auth_sendrequest(PurpleConnection *gc, const char *bname, const char *msg)
-{
-	OscarData *od;
-	PurpleAccount *account;
-	PurpleBuddy *buddy;
-	PurpleGroup *group;
-	const char *gname;
-
-	od = purple_connection_get_protocol_data(gc);
-	account = purple_connection_get_account(gc);
-	buddy = purple_blist_find_buddy(account, bname);
-	if (buddy != NULL)
-		group = purple_buddy_get_group(buddy);
-	else
-		group = NULL;
-
-	if (group != NULL)
-	{
-		gname = purple_group_get_name(group);
-		purple_debug_info("oscar", "ssi: adding buddy %s to group %s\n",
-				   bname, gname);
-		aim_ssi_sendauthrequest(od, bname, msg ? msg : _("Please authorize me so I can add you to my buddy list."));
-		if (!aim_ssi_itemlist_finditem(&od->ssi.local, gname, bname, AIM_SSI_TYPE_BUDDY))
-		{
-			aim_ssi_addbuddy(od, bname, gname, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, TRUE);
-
-			/* Mobile users should always be online */
-			if (bname[0] == '+') {
-				purple_protocol_got_user_status(account,
-						purple_buddy_get_name(buddy),
-						OSCAR_STATUS_ID_AVAILABLE, NULL);
-				purple_protocol_got_user_status(account,
-						purple_buddy_get_name(buddy),
-						OSCAR_STATUS_ID_MOBILE, NULL);
-			}
-		}
-	}
-}
-
-static void
-oscar_auth_grant(const char *message, gpointer cbdata)
-{
-	struct name_data *data = cbdata;
-	PurpleConnection *gc = data->gc;
-	OscarData *od = purple_connection_get_protocol_data(gc);
-
-	aim_ssi_sendauthreply(od, data->name, 0x01, NULL);
-
-	oscar_free_name_data(data);
-}
-
-static void
-oscar_auth_dontgrant(const char *msg, gpointer cbdata)
-{
-	struct name_data *data = cbdata;
-	PurpleConnection *gc = data->gc;
-	OscarData *od = purple_connection_get_protocol_data(gc);
-
-	aim_ssi_sendauthreply(od, data->name, 0x00, msg ? msg : _("No reason given."));
-
-	oscar_free_name_data(data);
-}
-
-void
-oscar_auth_sendrequest_menu(PurpleBlistNode *node, gpointer ignored)
-{
-	PurpleBuddy *buddy;
-	PurpleConnection *gc;
-
-	g_return_if_fail(PURPLE_IS_BUDDY(node));
-
-	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
-	oscar_auth_sendrequest(gc, purple_buddy_get_name(buddy), NULL);
-}
-
-/* When other people ask you for authorization */
-void
-oscar_auth_recvrequest(PurpleConnection *gc, gchar *name, gchar *nick, gchar *reason)
-{
-	PurpleAccount* account = purple_connection_get_account(gc);
-	struct name_data *data = g_new(struct name_data, 1);
-
-	data->gc = gc;
-	data->name = name;
-	data->nick = nick;
-
-	purple_account_request_authorization(account, data->name, NULL, data->nick,
-		reason, purple_blist_find_buddy(account, data->name) != NULL,
-		oscar_auth_grant, oscar_auth_dontgrant, data);
-}
--- a/libpurple/protocols/oscar/bstream.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,291 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * This file contains all functions needed to use bstreams.
- */
-
-#include "oscar.h"
-
-int byte_stream_new(ByteStream *bs, size_t len)
-{
-	if (bs == NULL)
-		return -1;
-
-	return byte_stream_init(bs, g_malloc(len), len);
-}
-
-int byte_stream_init(ByteStream *bs, guint8 *data, size_t len)
-{
-	if (bs == NULL)
-		return -1;
-
-	bs->data = data;
-	bs->len = len;
-	bs->offset = 0;
-
-	return 0;
-}
-
-void byte_stream_destroy(ByteStream *bs)
-{
-	g_free(bs->data);
-}
-
-size_t byte_stream_bytes_left(ByteStream *bs)
-{
-	g_return_val_if_fail(bs != NULL, 0);
-	g_return_val_if_fail(bs->len >= bs->offset, 0);
-
-	return bs->len - bs->offset;
-}
-
-int byte_stream_curpos(ByteStream *bs)
-{
-	return bs->offset;
-}
-
-int byte_stream_setpos(ByteStream *bs, size_t off)
-{
-	g_return_val_if_fail(off <= bs->len, -1);
-
-	bs->offset = off;
-	return off;
-}
-
-void byte_stream_rewind(ByteStream *bs)
-{
-	byte_stream_setpos(bs, 0);
-}
-
-/*
- * N can be negative, which can be used for going backwards
- * in a bstream.
- */
-int byte_stream_advance(ByteStream *bs, int n)
-{
-	g_return_val_if_fail(byte_stream_curpos(bs) + n >= 0, 0);
-	g_return_val_if_fail((gsize)n <= byte_stream_bytes_left(bs), 0);
-
-	bs->offset += n;
-	return n;
-}
-
-guint8 byte_stream_get8(ByteStream *bs)
-{
-	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 1, 0);
-
-	bs->offset++;
-	return aimutil_get8(bs->data + bs->offset - 1);
-}
-
-guint16 byte_stream_get16(ByteStream *bs)
-{
-	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 2, 0);
-
-	bs->offset += 2;
-	return aimutil_get16(bs->data + bs->offset - 2);
-}
-
-guint32 byte_stream_get32(ByteStream *bs)
-{
-	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 4, 0);
-
-	bs->offset += 4;
-	return aimutil_get32(bs->data + bs->offset - 4);
-}
-
-guint8 byte_stream_getle8(ByteStream *bs)
-{
-	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 1, 0);
-
-	bs->offset++;
-	return aimutil_getle8(bs->data + bs->offset - 1);
-}
-
-guint16 byte_stream_getle16(ByteStream *bs)
-{
-	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 2, 0);
-
-	bs->offset += 2;
-	return aimutil_getle16(bs->data + bs->offset - 2);
-}
-
-guint32 byte_stream_getle32(ByteStream *bs)
-{
-	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 4, 0);
-
-	bs->offset += 4;
-	return aimutil_getle32(bs->data + bs->offset - 4);
-}
-
-static void byte_stream_getrawbuf_nocheck(ByteStream *bs, guint8 *buf, size_t len)
-{
-	memcpy(buf, bs->data + bs->offset, len);
-	bs->offset += len;
-}
-
-int byte_stream_getrawbuf(ByteStream *bs, guint8 *buf, size_t len)
-{
-	g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, 0);
-
-	byte_stream_getrawbuf_nocheck(bs, buf, len);
-	return len;
-}
-
-guint8 *byte_stream_getraw(ByteStream *bs, size_t len)
-{
-	guint8 *ob;
-
-	g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, NULL);
-
-	ob = g_malloc(len);
-	byte_stream_getrawbuf_nocheck(bs, ob, len);
-	return ob;
-}
-
-char *byte_stream_getstr(ByteStream *bs, size_t len)
-{
-	char *ob;
-
-	g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, NULL);
-
-	ob = g_malloc(len + 1);
-	byte_stream_getrawbuf_nocheck(bs, (guint8 *)ob, len);
-	ob[len] = '\0';
-	return ob;
-}
-
-int byte_stream_put8(ByteStream *bs, guint8 v)
-{
-	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 1, 0);
-
-	bs->offset += aimutil_put8(bs->data + bs->offset, v);
-	return 1;
-}
-
-int byte_stream_put16(ByteStream *bs, guint16 v)
-{
-	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 2, 0);
-
-	bs->offset += aimutil_put16(bs->data + bs->offset, v);
-	return 2;
-}
-
-int byte_stream_put32(ByteStream *bs, guint32 v)
-{
-	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 4, 0);
-
-	bs->offset += aimutil_put32(bs->data + bs->offset, v);
-	return 1;
-}
-
-int byte_stream_putle8(ByteStream *bs, guint8 v)
-{
-	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 1, 0);
-
-	bs->offset += aimutil_putle8(bs->data + bs->offset, v);
-	return 1;
-}
-
-int byte_stream_putle16(ByteStream *bs, guint16 v)
-{
-	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 2, 0);
-
-	bs->offset += aimutil_putle16(bs->data + bs->offset, v);
-	return 2;
-}
-
-int byte_stream_putle32(ByteStream *bs, guint32 v)
-{
-	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 4, 0);
-
-	bs->offset += aimutil_putle32(bs->data + bs->offset, v);
-	return 1;
-}
-
-
-int byte_stream_putraw(ByteStream *bs, const guint8 *v, size_t len)
-{
-	g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, 0);
-
-	memcpy(bs->data + bs->offset, v, len);
-	bs->offset += len;
-	return len;
-}
-
-int byte_stream_putstr(ByteStream *bs, const char *str)
-{
-	return byte_stream_putraw(bs, (guint8 *)str, strlen(str));
-}
-
-int byte_stream_putbs(ByteStream *bs, ByteStream *srcbs, size_t len)
-{
-	g_return_val_if_fail(byte_stream_bytes_left(srcbs) >= len, 0);
-	g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, 0);
-
-	memcpy(bs->data + bs->offset, srcbs->data + srcbs->offset, len);
-	bs->offset += len;
-	srcbs->offset += len;
-	return len;
-}
-
-int byte_stream_putuid(ByteStream *bs, OscarData *od)
-{
-	PurpleAccount *account;
-
-	account = purple_connection_get_account(od->gc);
-
-	return byte_stream_putle32(bs, atoi(purple_account_get_username(account)));
-}
-
-void byte_stream_put_bart_asset(ByteStream *bs, guint16 type, ByteStream *data)
-{
-	byte_stream_put16(bs, type);
-
-	if (data != NULL && data->len > 0) {
-		/* Flags. 0x04 means "this asset has data attached to it" */
-		byte_stream_put8(bs, 0x04); /* Flags */
-		byte_stream_put8(bs, data->len); /* Length */
-		byte_stream_rewind(data);
-		byte_stream_putbs(bs, data, data->len); /* Data */
-	} else {
-		byte_stream_put8(bs, 0x00); /* No flags */
-		byte_stream_put8(bs, 0x00); /* Length */
-		/* No data */
-	}
-}
-
-void byte_stream_put_bart_asset_str(ByteStream *bs, guint16 type, const char *datastr)
-{
-	ByteStream data;
-	size_t len = datastr != NULL ? strlen(datastr) : 0;
-
-	if (len > 0) {
-		byte_stream_new(&data, 2 + len + 2);
-		byte_stream_put16(&data, len); /* Length */
-		byte_stream_putstr(&data, datastr); /* String */
-		byte_stream_put16(&data, 0x0000); /* Unknown */
-		byte_stream_put_bart_asset(bs, type, &data);
-		byte_stream_destroy(&data);
-	} else {
-		byte_stream_put_bart_asset(bs, type, NULL);
-	}
-}
--- a/libpurple/protocols/oscar/clientlogin.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,634 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/**
- * This file implements AIM's clientLogin procedure for authenticating
- * users.  This replaces the older MD5-based and XOR-based
- * authentication methods that use SNAC family 0x0017.
- *
- * This doesn't use SNACs or FLAPs at all.  It makes http and https
- * POSTs to AOL to validate the user based on the password they
- * provided to us.  Upon successful authentication we request a
- * connection to the BOS server by calling startOSCARsession.  The
- * AOL server gives us the hostname and port number to use, as well
- * as the cookie to use to authenticate to the BOS server.  And then
- * everything else is the same as with BUCP.
- *
- * For details, see:
- * http://dev.aol.com/aim/oscar/#AUTH
- * http://dev.aol.com/authentication_for_clients
- */
-
-#include "oscar.h"
-#include "oscarcommon.h"
-#include "core.h"
-
-#define AIM_LOGIN_HOST "api.screenname.aol.com"
-#define ICQ_LOGIN_HOST "api.login.icq.net"
-
-#define AIM_API_HOST "api.oscar.aol.com"
-#define ICQ_API_HOST "api.icq.net"
-
-#define CLIENT_LOGIN_PAGE "/auth/clientLogin"
-#define START_OSCAR_SESSION_PAGE "/aim/startOSCARSession"
-
-#define HTTPS_FORMAT_URL(host, page) "https://" host page
-
-static const gchar *client_login_urls[] = {
-	HTTPS_FORMAT_URL(AIM_LOGIN_HOST, CLIENT_LOGIN_PAGE),
-	HTTPS_FORMAT_URL(ICQ_LOGIN_HOST, CLIENT_LOGIN_PAGE),
-};
-
-static const gchar *start_oscar_session_urls[] = {
-	HTTPS_FORMAT_URL(AIM_API_HOST, START_OSCAR_SESSION_PAGE),
-	HTTPS_FORMAT_URL(ICQ_API_HOST, START_OSCAR_SESSION_PAGE),
-};
-
-static const gchar *get_client_login_url(OscarData *od)
-{
-	return client_login_urls[od->icq ? 1 : 0];
-}
-
-static const gchar *get_start_oscar_session_url(OscarData *od)
-{
-	return start_oscar_session_urls[od->icq ? 1 : 0];
-}
-
-static const char *get_client_key(OscarData *od)
-{
-	return oscar_get_ui_info_string(
-			od->icq ? "prpl-icq-clientkey" : "prpl-aim-clientkey",
-			od->icq ? ICQ_DEFAULT_CLIENT_KEY : AIM_DEFAULT_CLIENT_KEY);
-}
-
-static gchar *generate_error_message(PurpleXmlNode *resp, const char *url)
-{
-	PurpleXmlNode *text;
-	PurpleXmlNode *status_code_node;
-	gboolean have_error_code = TRUE;
-	gchar *err = NULL;
-	gchar *details = NULL;
-
-	status_code_node = purple_xmlnode_get_child(resp, "statusCode");
-	if (status_code_node) {
-		gchar *status_code;
-
-		/* We can get 200 OK here if the server omitted something we think it shouldn't have (see #12783).
-		 * No point in showing the "Ok" string to the user.
-		 */
-		status_code = purple_xmlnode_get_data_unescaped(status_code_node);
-		if (purple_strequal(status_code, "200")) {
-			have_error_code = FALSE;
-		}
-	}
-	if (have_error_code && resp && (text = purple_xmlnode_get_child(resp, "statusText"))) {
-		details = purple_xmlnode_get_data(text);
-	}
-
-	if (details && *details) {
-		/* Translators: The first %s is a URL. The second is a brief error
-		   message. */
-		err = g_strdup_printf(_("Received unexpected response from %s: %s"), url, details);
-	} else {
-		/* Translators: %s in this string is a URL */
-		err = g_strdup_printf(_("Received unexpected response from %s"), url);
-	}
-
-	g_free(details);
-	return err;
-}
-
-/**
- * @return A null-terminated base64 encoded version of the HMAC
- *         calculated using the given key and data.
- */
-static gchar *hmac_sha256(const char *key, const char *message)
-{
-	GHmac *hmac;
-	guchar digest[32];
-	gsize digest_len = 32;
-
-	hmac = g_hmac_new(G_CHECKSUM_SHA256, (guchar *)key, strlen(key));
-	g_hmac_update(hmac, (guchar *)message, -1);
-	g_hmac_get_digest(hmac, digest, &digest_len);
-	g_hmac_unref(hmac);
-
-	return g_base64_encode(digest, sizeof(digest));
-}
-
-/**
- * @return A base-64 encoded HMAC-SHA256 signature created using the
- *         technique documented at
- *         http://dev.aol.com/authentication_for_clients#signing
- */
-static gchar *generate_signature(const char *method, const char *url, const char *parameters, const char *session_key)
-{
-	char *encoded_url, *signature_base_string, *signature;
-	const char *encoded_parameters;
-
-	encoded_url = g_strdup(purple_url_encode(url));
-	encoded_parameters = purple_url_encode(parameters);
-	signature_base_string = g_strdup_printf("%s&%s&%s",
-			method, encoded_url, encoded_parameters);
-	g_free(encoded_url);
-
-	signature = hmac_sha256(session_key, signature_base_string);
-	g_free(signature_base_string);
-
-	return signature;
-}
-
-static gboolean parse_start_oscar_session_response(PurpleConnection *gc, const gchar *response, gsize response_len, char **host, unsigned short *port, char **cookie, char **tls_certname)
-{
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	PurpleXmlNode *response_node, *tmp_node, *data_node;
-	PurpleXmlNode *host_node = NULL, *port_node = NULL, *cookie_node = NULL, *tls_node = NULL;
-	char *tmp;
-	guint code;
-	const gchar *encryption_type = purple_account_get_string(purple_connection_get_account(gc), "encryption", OSCAR_DEFAULT_ENCRYPTION);
-
-	/* Parse the response as XML */
-	response_node = purple_xmlnode_from_str(response, response_len);
-	if (response_node == NULL)
-	{
-		char *msg;
-		purple_debug_error("oscar", "startOSCARSession could not parse "
-				"response as XML: %s\n", response);
-		msg = generate_error_message(response_node,
-				get_start_oscar_session_url(od));
-		purple_connection_error(gc,
-				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
-		g_free(msg);
-		return FALSE;
-	}
-
-	/* Grab the necessary XML nodes */
-	tmp_node = purple_xmlnode_get_child(response_node, "statusCode");
-	data_node = purple_xmlnode_get_child(response_node, "data");
-	if (data_node != NULL) {
-		host_node = purple_xmlnode_get_child(data_node, "host");
-		port_node = purple_xmlnode_get_child(data_node, "port");
-		cookie_node = purple_xmlnode_get_child(data_node, "cookie");
-	}
-
-	/* Make sure we have a status code */
-	if (tmp_node == NULL || (tmp = purple_xmlnode_get_data_unescaped(tmp_node)) == NULL) {
-		char *msg;
-		purple_debug_error("oscar", "startOSCARSession response was "
-				"missing statusCode: %s\n", response);
-		msg = generate_error_message(response_node,
-				get_start_oscar_session_url(od));
-		purple_connection_error(gc,
-				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
-		g_free(msg);
-		purple_xmlnode_free(response_node);
-		return FALSE;
-	}
-
-	/* Make sure the status code was 200 */
-	code = atoi(tmp);
-	if (code != 200)
-	{
-		PurpleXmlNode *status_detail_node;
-		guint status_detail = 0;
-
-		status_detail_node = purple_xmlnode_get_child(response_node,
-		                                       "statusDetailCode");
-		if (status_detail_node) {
-			gchar *data = purple_xmlnode_get_data(status_detail_node);
-			if (data) {
-				status_detail = atoi(data);
-				g_free(data);
-			}
-		}
-
-		purple_debug_error("oscar", "startOSCARSession response statusCode "
-				"was %s: %s\n", tmp, response);
-
-		if ((code == 401 && status_detail != 1014) || code == 607)
-			purple_connection_error(gc,
-					PURPLE_CONNECTION_ERROR_OTHER_ERROR,
-					_("You have been connecting and disconnecting too "
-					  "frequently. Wait ten minutes and try again. If "
-					  "you continue to try, you will need to wait even "
-					  "longer."));
-		else {
-			char *msg;
-			msg = generate_error_message(response_node,
-					get_start_oscar_session_url(od));
-			purple_connection_error(gc,
-					PURPLE_CONNECTION_ERROR_OTHER_ERROR, msg);
-			g_free(msg);
-		}
-
-		g_free(tmp);
-		purple_xmlnode_free(response_node);
-		return FALSE;
-	}
-	g_free(tmp);
-
-	/* Make sure we have everything else */
-	if (data_node == NULL || host_node == NULL || port_node == NULL || cookie_node == NULL)
-	{
-		char *msg;
-		purple_debug_error("oscar", "startOSCARSession response was missing "
-				"something: %s\n", response);
-		msg = generate_error_message(response_node,
-				get_start_oscar_session_url(od));
-		purple_connection_error(gc,
-				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
-		g_free(msg);
-		purple_xmlnode_free(response_node);
-		return FALSE;
-	}
-
-	if (!purple_strequal(encryption_type, OSCAR_NO_ENCRYPTION)) {
-		tls_node = purple_xmlnode_get_child(data_node, "tlsCertName");
-		if (tls_node != NULL) {
-			*tls_certname = purple_xmlnode_get_data_unescaped(tls_node);
-		} else {
-			if (purple_strequal(encryption_type, OSCAR_OPPORTUNISTIC_ENCRYPTION)) {
-				purple_debug_warning("oscar", "We haven't received a tlsCertName to use. We will not do SSL to BOS.\n");
-			} else {
-				purple_debug_error("oscar", "startOSCARSession was missing tlsCertName: %s\n", response);
-				purple_connection_error(
-					gc,
-					PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT,
-					_("You required encryption in your account settings, but one of the servers doesn't support it."));
-				purple_xmlnode_free(response_node);
-				return FALSE;
-			}
-		}
-	}
-
-	/* Extract data from the XML */
-	*host = purple_xmlnode_get_data_unescaped(host_node);
-	tmp = purple_xmlnode_get_data_unescaped(port_node);
-	*cookie = purple_xmlnode_get_data_unescaped(cookie_node);
-
-	if (*host == NULL || **host == '\0' || tmp == NULL || *tmp == '\0' || *cookie == NULL || **cookie == '\0')
-	{
-		char *msg;
-		purple_debug_error("oscar", "startOSCARSession response was missing "
-				"something: %s\n", response);
-		msg = generate_error_message(response_node,
-				get_start_oscar_session_url(od));
-		purple_connection_error(gc,
-				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
-		g_free(msg);
-		g_free(*host);
-		g_free(tmp);
-		g_free(*cookie);
-		purple_xmlnode_free(response_node);
-		return FALSE;
-	}
-
-	*port = atoi(tmp);
-	g_free(tmp);
-
-	return TRUE;
-}
-
-static void
-start_oscar_session_cb(G_GNUC_UNUSED SoupSession *session, SoupMessage *msg,
-                       gpointer user_data)
-{
-	OscarData *od = user_data;
-	PurpleConnection *gc;
-	char *host, *cookie;
-	char *tls_certname = NULL;
-	unsigned short port;
-	guint8 *cookiedata;
-	gsize cookiedata_len = 0;
-
-	gc = od->gc;
-
-	g_clear_object(&od->http_conns);
-
-	if (!SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) {
-		gchar *tmp;
-		/* Translators: The first %s is a URL, the second is a brief error
-		   message. */
-		tmp = g_strdup_printf(_("Error requesting %s: %d %s"),
-		                      get_start_oscar_session_url(od), msg->status_code,
-		                      msg->reason_phrase);
-		purple_connection_error(gc,
-				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
-		g_free(tmp);
-		return;
-	}
-
-	if (!parse_start_oscar_session_response(gc, msg->response_body->data,
-	                                        msg->response_body->length, &host,
-	                                        &port, &cookie, &tls_certname)) {
-		return;
-	}
-
-	cookiedata = g_base64_decode(cookie, &cookiedata_len);
-	oscar_connect_to_bos(gc, od, host, port, cookiedata, cookiedata_len, tls_certname);
-	g_free(cookiedata);
-
-	g_free(host);
-	g_free(cookie);
-	g_free(tls_certname);
-}
-
-static void send_start_oscar_session(OscarData *od, const char *token, const char *session_key, time_t hosttime)
-{
-	gchar *query_string, *signature, *uri;
-	SoupMessage *msg;
-	PurpleAccount *account = purple_connection_get_account(od->gc);
-	const gchar *encryption_type = purple_account_get_string(account, "encryption", OSCAR_DEFAULT_ENCRYPTION);
-
-	/*
-	 * Construct the GET parameters.
-	 */
-	query_string = g_strdup_printf("a=%s"
-			"&distId=%d"
-			"&f=xml"
-			"&k=%s"
-			"&ts=%" G_GINT64_FORMAT
-			"&useTLS=%d",
-			purple_url_encode(token),
-			oscar_get_ui_info_int(od->icq ? "prpl-icq-distid" : "prpl-aim-distid",
-				od->icq ? ICQ_DEFAULT_DIST_ID : AIM_DEFAULT_DIST_ID),
-			get_client_key(od),
-			(gint64)hosttime,
-			!purple_strequal(encryption_type, OSCAR_NO_ENCRYPTION));
-	signature = generate_signature("GET", get_start_oscar_session_url(od),
-			query_string, session_key);
-
-	uri = g_strdup_printf("%s?%s&sig_sha256=%s",
-	                      get_start_oscar_session_url(od), query_string,
-	                      signature);
-
-	msg = soup_message_new("GET", uri);
-	soup_session_queue_message(od->http_conns, msg, start_oscar_session_cb, od);
-
-	g_free(query_string);
-	g_free(signature);
-	g_free(uri);
-}
-
-/**
- * This function parses the given response from a clientLogin request
- * and extracts the useful information.
- *
- * @param gc           The PurpleConnection.  If the response data does
- *                     not indicate then purple_connection_error()
- *                     will be called to close this connection.
- * @param response     The response data from the clientLogin request.
- * @param response_len The length of the above response, or -1 if
- *                     @response is NUL terminated.
- * @param token        If parsing was successful then this will be set to
- *                     a newly allocated string containing the token.  The
- *                     caller should g_free this string when it is finished
- *                     with it.  On failure this value will be untouched.
- * @param secret       If parsing was successful then this will be set to
- *                     a newly allocated string containing the secret.  The
- *                     caller should g_free this string when it is finished
- *                     with it.  On failure this value will be untouched.
- * @param hosttime     If parsing was successful then this will be set to
- *                     the time on the OpenAuth Server in seconds since the
- *                     Unix epoch.  On failure this value will be untouched.
- *
- * @return TRUE if the request was successful and we were able to
- *         extract all info we need.  Otherwise FALSE.
- */
-static gboolean parse_client_login_response(PurpleConnection *gc, const gchar *response, gsize response_len, char **token, char **secret, time_t *hosttime)
-{
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	PurpleXmlNode *response_node, *tmp_node, *data_node;
-	PurpleXmlNode *secret_node = NULL, *hosttime_node = NULL, *token_node = NULL, *tokena_node = NULL;
-	char *tmp;
-
-	/* Parse the response as XML */
-	response_node = purple_xmlnode_from_str(response, response_len);
-	if (response_node == NULL)
-	{
-		char *msg;
-		purple_debug_error("oscar", "clientLogin could not parse "
-				"response as XML: %s\n", response);
-		msg = generate_error_message(response_node,
-				get_client_login_url(od));
-		purple_connection_error(gc,
-				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
-		g_free(msg);
-		return FALSE;
-	}
-
-	/* Grab the necessary XML nodes */
-	tmp_node = purple_xmlnode_get_child(response_node, "statusCode");
-	data_node = purple_xmlnode_get_child(response_node, "data");
-	if (data_node != NULL) {
-		secret_node = purple_xmlnode_get_child(data_node, "sessionSecret");
-		hosttime_node = purple_xmlnode_get_child(data_node, "hostTime");
-		token_node = purple_xmlnode_get_child(data_node, "token");
-		if (token_node != NULL)
-			tokena_node = purple_xmlnode_get_child(token_node, "a");
-	}
-
-	/* Make sure we have a status code */
-	if (tmp_node == NULL || (tmp = purple_xmlnode_get_data_unescaped(tmp_node)) == NULL) {
-		char *msg;
-		purple_debug_error("oscar", "clientLogin response was "
-				"missing statusCode: %s\n", response);
-		msg = generate_error_message(response_node,
-				get_client_login_url(od));
-		purple_connection_error(gc,
-				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
-		g_free(msg);
-		purple_xmlnode_free(response_node);
-		return FALSE;
-	}
-
-	/* Make sure the status code was 200 */
-	if (!purple_strequal(tmp, "200"))
-	{
-		int status_code, status_detail_code = 0;
-
-		status_code = atoi(tmp);
-		g_free(tmp);
-		tmp_node = purple_xmlnode_get_child(response_node, "statusDetailCode");
-		if (tmp_node != NULL && (tmp = purple_xmlnode_get_data_unescaped(tmp_node)) != NULL) {
-			status_detail_code = atoi(tmp);
-			g_free(tmp);
-		}
-
-		purple_debug_error("oscar", "clientLogin response statusCode "
-				"was %d (%d): %s\n", status_code, status_detail_code, response);
-
-		if (status_code == 330 && status_detail_code == 3011) {
-			PurpleAccount *account = purple_connection_get_account(gc);
-			if (!purple_account_get_remember_password(account))
-				purple_account_set_password(account, NULL, NULL, NULL);
-			purple_connection_error(gc,
-					PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
-					_("Incorrect password"));
-		} else if (status_code == 330 && status_detail_code == 3015) {
-			purple_connection_error(gc,
-					PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
-					_("Server requested that you fill out a CAPTCHA in order to "
-					"sign in, but this client does not currently support CAPTCHAs."));
-		} else if (status_code == 401 && status_detail_code == 3019) {
-			purple_connection_error(gc,
-					PURPLE_CONNECTION_ERROR_OTHER_ERROR,
-					_("AOL does not allow your screen name to authenticate here"));
-		} else {
-			char *msg;
-			msg = generate_error_message(response_node,
-					get_client_login_url(od));
-			purple_connection_error(gc,
-					PURPLE_CONNECTION_ERROR_OTHER_ERROR, msg);
-			g_free(msg);
-		}
-
-		purple_xmlnode_free(response_node);
-		return FALSE;
-	}
-	g_free(tmp);
-
-	/* Make sure we have everything else */
-	if (data_node == NULL || secret_node == NULL ||
-		token_node == NULL || tokena_node == NULL)
-	{
-		char *msg;
-		purple_debug_error("oscar", "clientLogin response was missing "
-				"something: %s\n", response);
-		msg = generate_error_message(response_node,
-				get_client_login_url(od));
-		purple_connection_error(gc,
-				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
-		g_free(msg);
-		purple_xmlnode_free(response_node);
-		return FALSE;
-	}
-
-	/* Extract data from the XML */
-	*token = purple_xmlnode_get_data_unescaped(tokena_node);
-	*secret = purple_xmlnode_get_data_unescaped(secret_node);
-	tmp = purple_xmlnode_get_data_unescaped(hosttime_node);
-	if (*token == NULL || **token == '\0' || *secret == NULL || **secret == '\0' || tmp == NULL || *tmp == '\0')
-	{
-		char *msg;
-		purple_debug_error("oscar", "clientLogin response was missing "
-				"something: %s\n", response);
-		msg = generate_error_message(response_node,
-				get_client_login_url(od));
-		purple_connection_error(gc,
-				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
-		g_free(msg);
-		g_free(*token);
-		g_free(*secret);
-		g_free(tmp);
-		purple_xmlnode_free(response_node);
-		return FALSE;
-	}
-
-	*hosttime = strtol(tmp, NULL, 10);
-	g_free(tmp);
-
-	purple_xmlnode_free(response_node);
-
-	return TRUE;
-}
-
-static void
-client_login_cb(G_GNUC_UNUSED SoupSession *session, SoupMessage *msg,
-                gpointer user_data)
-{
-	OscarData *od = user_data;
-	PurpleConnection *gc;
-	char *token, *secret, *session_key;
-	time_t hosttime;
-	int password_len;
-	char *password;
-
-	gc = od->gc;
-
-	if (!SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) {
-		gchar *tmp;
-		tmp = g_strdup_printf(_("Error requesting %s: %d %s"),
-		                      get_client_login_url(od), msg->status_code,
-		                      msg->reason_phrase);
-		purple_connection_error(gc,
-				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
-		g_free(tmp);
-		return;
-	}
-
-	if (!parse_client_login_response(gc, msg->response_body->data,
-	                                 msg->response_body->length, &token,
-	                                 &secret, &hosttime)) {
-		return;
-	}
-
-	password_len = strlen(purple_connection_get_password(gc));
-	password = g_strdup_printf("%.*s",
-			od->icq ? MIN(password_len, MAXICQPASSLEN) : password_len,
-			purple_connection_get_password(gc));
-	session_key = hmac_sha256(password, secret);
-	g_free(password);
-	g_free(secret);
-
-	send_start_oscar_session(od, token, session_key, hosttime);
-
-	g_free(token);
-	g_free(session_key);
-}
-
-/**
- * This function sends a request to
- * https://api.screenname.aol.com/auth/clientLogin with the user's
- * username and password and receives the user's session key, which is
- * used to request a connection to the BOSS server.
- */
-void send_client_login(OscarData *od, const char *username)
-{
-	PurpleConnection *gc;
-	SoupMessage *msg;
-	const char *tmp;
-	char *password;
-	int password_len;
-
-	gc = od->gc;
-
-	/*
-	 * We truncate ICQ passwords to 8 characters.  There is probably a
-	 * limit for AIM passwords, too, but we really only need to do
-	 * this for ICQ because older ICQ clients let you enter a password
-	 * as long as you wanted and then they truncated it silently.
-	 *
-	 * And we can truncate based on the number of bytes and not the
-	 * number of characters because passwords for AIM and ICQ are
-	 * supposed to be plain ASCII (I don't know if this has always been
-	 * the case, though).
-	 */
-	tmp = purple_connection_get_password(gc);
-	password_len = strlen(tmp);
-	password = g_strndup(tmp, od->icq ? MIN(password_len, MAXICQPASSLEN) : password_len);
-
-	msg = soup_form_request_new("POST", get_client_login_url(od), "devId",
-	                            get_client_key(od), "f", "xml", "pwd", password,
-	                            "s", username, NULL);
-	soup_session_queue_message(od->http_conns, msg, client_login_cb, od);
-
-	g_free(password);
-}
--- a/libpurple/protocols/oscar/encoding.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,285 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-#include "encoding.h"
-
-static gchar *
-encoding_multi_convert_to_utf8(const gchar *text, gssize textlen, const gchar *encodings, GError **error, gboolean fallback)
-{
-	gchar *utf8 = NULL;
-	const gchar *begin = encodings;
-	const gchar *end = NULL;
-	gchar *curr_encoding = NULL; /* allocated buffer for encoding name */
-	const gchar *curr_encoding_ro = NULL; /* read-only encoding name */
-
-	if (!encodings) {
-		purple_debug_error("oscar", "encodings is NULL");
-		return NULL;
-	}
-
-	for (;;)
-	{
-		/* extract next encoding */
-		end = strchr(begin, ',');
-		if (!end) {
-			curr_encoding_ro = begin;
-		}	else { /* allocate buffer for encoding */
-			curr_encoding = g_strndup(begin, end - begin);
-			if (!curr_encoding) {
-				purple_debug_error("oscar", "Error allocating memory for encoding");
-				break;
-			}
-			curr_encoding_ro = curr_encoding;
-		}
-
-		if (!g_ascii_strcasecmp(curr_encoding_ro, "utf-8") && g_utf8_validate(text, textlen, NULL)) {
-			break;
-		}
-
-		utf8 = g_convert(text, textlen, "UTF-8", curr_encoding_ro, NULL, NULL, NULL);
-
-		if (!end) /* last occurence. do not free curr_encoding: buffer was'nt allocated */
-			break;
-
-		g_free(curr_encoding); /* free allocated buffer for encoding here */
-
-		if (utf8) /* text was successfully converted */
-			break;
-
-		begin = end + 1;
-	}
-
-	if (!utf8 && fallback)
-	{ /* "begin" points to last encoding */
-		utf8 = g_convert_with_fallback(text, textlen, "UTF-8", begin, "?", NULL, NULL, error);
-	}
-
-	return utf8;
-}
-
-static gchar *
-encoding_extract(const char *encoding)
-{
-	char *begin, *end;
-
-	if (encoding == NULL) {
-		return NULL;
-	}
-
-	if (!g_str_has_prefix(encoding, "text/aolrtf; charset=") &&
-		!g_str_has_prefix(encoding, "text/x-aolrtf; charset=") &&
-		!g_str_has_prefix(encoding, "text/plain; charset=")) {
-		return g_strdup(encoding);
-	}
-
-	begin = strchr(encoding, '"');
-	end = strrchr(encoding, '"');
-
-	if ((begin == NULL) || (end == NULL) || (begin >= end)) {
-		return g_strdup(encoding);
-	}
-
-	return g_strndup(begin+1, (end-1) - begin);
-}
-
-gchar *
-oscar_encoding_to_utf8(const char *encoding, const char *text, int textlen)
-{
-	gchar *utf8 = NULL;
-	const gchar *glib_encoding = NULL;
-	gchar *extracted_encoding = encoding_extract(encoding);
-
-	if (extracted_encoding == NULL || *extracted_encoding == '\0') {
-		purple_debug_info("oscar", "Empty encoding, assuming UTF-8\n");
-	} else if (!g_ascii_strcasecmp(extracted_encoding, "iso-8859-1")) {
-		glib_encoding = "iso-8859-1";
-	} else if (!g_ascii_strcasecmp(extracted_encoding, "ISO-8859-1-Windows-3.1-Latin-1") || !g_ascii_strcasecmp(extracted_encoding, "us-ascii")) {
-		glib_encoding = "Windows-1252";
-	} else if (!g_ascii_strcasecmp(extracted_encoding, "unicode-2-0")) {
-		glib_encoding = "UTF-16BE";
-	} else if (g_ascii_strcasecmp(extracted_encoding, "utf-8")) {
-		glib_encoding = extracted_encoding;
-	}
-
-	if (glib_encoding != NULL) {
-		utf8 = encoding_multi_convert_to_utf8(text, textlen, glib_encoding, NULL, FALSE);
-	}
-
-	/*
-	 * If utf8 is still NULL then either the encoding is utf-8 or
-	 * we have been unable to convert the text to utf-8 from the encoding
-	 * that was specified.  So we check if the text is valid utf-8 then
-	 * just copy it.
-	 */
-	if (utf8 == NULL) {
-		if (textlen != 0 && *text != '\0' && !g_utf8_validate(text, textlen, NULL))
-			utf8 = g_strdup(_("(There was an error receiving this message.  The buddy you are speaking with is probably using a different encoding than expected.  If you know what encoding he is using, you can specify it in the advanced account options for your AIM/ICQ account.)"));
-		else
-			utf8 = g_strndup(text, textlen);
-	}
-
-	g_free(extracted_encoding);
-	return utf8;
-}
-
-gchar *
-oscar_utf8_try_convert(PurpleAccount *account, OscarData *od, const gchar *msg)
-{
-	const char *charset = NULL;
-	char *ret = NULL;
-
-	if (msg == NULL)
-		return NULL;
-
-	if (g_utf8_validate(msg, -1, NULL))
-		return g_strdup(msg);
-
-	if (od->icq)
-		charset = purple_account_get_string(account, "encoding", NULL);
-
-	if(charset && *charset)
-		ret = encoding_multi_convert_to_utf8(msg, -1, charset, NULL, FALSE);
-
-	if(!ret)
-		ret = purple_utf8_try_convert(msg);
-
-	return ret;
-}
-
-static gchar *
-oscar_convert_to_utf8(const gchar *data, gsize datalen, const char *charsetstr, gboolean fallback)
-{
-	gchar *ret = NULL;
-	GError *err = NULL;
-
-	if ((charsetstr == NULL) || (*charsetstr == '\0'))
-		return NULL;
-
-	if (g_ascii_strcasecmp("UTF-8", charsetstr)) {
-		ret = encoding_multi_convert_to_utf8(data, datalen, charsetstr, &err, fallback);
-		if (err != NULL) {
-			purple_debug_warning("oscar", "Conversion from %s failed: %s.\n",
-							   charsetstr, err->message);
-			g_error_free(err);
-		}
-	} else {
-		if (g_utf8_validate(data, datalen, NULL))
-			ret = g_strndup(data, datalen);
-		else
-			purple_debug_warning("oscar", "String is not valid UTF-8.\n");
-	}
-
-	return ret;
-}
-
-gchar *
-oscar_decode_im(PurpleAccount *account, const char *sourcebn, guint16 charset, const gchar *data, gsize datalen)
-{
-	gchar *ret = NULL;
-	/* charsetstr1 is always set to what the correct encoding should be. */
-	const gchar *charsetstr1, *charsetstr2, *charsetstr3 = NULL;
-
-	if ((datalen == 0) || (data == NULL))
-		return NULL;
-
-	if (charset == AIM_CHARSET_UNICODE) {
-		charsetstr1 = "UTF-16BE";
-		charsetstr2 = "UTF-8";
-	} else if (charset == AIM_CHARSET_LATIN_1) {
-		if ((sourcebn != NULL) && oscar_util_valid_name_icq(sourcebn))
-			charsetstr1 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
-		else
-			charsetstr1 = "ISO-8859-1";
-		charsetstr2 = "UTF-8";
-	} else if (charset == AIM_CHARSET_ASCII) {
-		/* Should just be "ASCII" */
-		charsetstr1 = "ASCII";
-		charsetstr2 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
-	} else if (charset == 0x000d) {
-		/* iChat sending unicode over a Direct IM connection = UTF-8 */
-		/* Mobile AIM client on multiple devices (including Blackberry Tour, Nokia 3100, and LG VX6000) = ISO-8859-1 */
-		charsetstr1 = "UTF-8";
-		charsetstr2 = "ISO-8859-1";
-		charsetstr3 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
-	} else {
-		/* Unknown, hope for valid UTF-8... */
-		charsetstr1 = "UTF-8";
-		charsetstr2 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
-	}
-
-	purple_debug_info("oscar", "Parsing IM, charset=0x%04hx, datalen=%" G_GSIZE_FORMAT ", choice1=%s, choice2=%s, choice3=%s\n",
-					  charset, datalen, charsetstr1, charsetstr2, (charsetstr3 ? charsetstr3 : ""));
-
-	ret = oscar_convert_to_utf8(data, datalen, charsetstr1, FALSE);
-	if (ret == NULL) {
-		if (charsetstr3 != NULL) {
-			/* Try charsetstr2 without allowing substitutions, then fall through to charsetstr3 if needed */
-			ret = oscar_convert_to_utf8(data, datalen, charsetstr2, FALSE);
-			if (ret == NULL)
-				ret = oscar_convert_to_utf8(data, datalen, charsetstr3, TRUE);
-		} else {
-			/* Try charsetstr2, allowing substitutions */
-			ret = oscar_convert_to_utf8(data, datalen, charsetstr2, TRUE);
-		}
-	}
-	if (ret == NULL) {
-		char *str, *salvage, *tmp;
-
-		str = g_malloc(datalen + 1);
-		strncpy(str, data, datalen);
-		str[datalen] = '\0';
-		salvage = purple_utf8_salvage(str);
-		tmp = g_strdup_printf(_("(There was an error receiving this message.  Either you and %s have different encodings selected, or %s has a buggy client.)"),
-					  sourcebn, sourcebn);
-		ret = g_strdup_printf("%s %s", salvage, tmp);
-		g_free(tmp);
-		g_free(str);
-		g_free(salvage);
-	}
-
-	return ret;
-}
-
-static guint16
-get_simplest_charset(const char *utf8)
-{
-	while (*utf8)
-	{
-		if ((unsigned char)(*utf8) > 0x7f) {
-			/* not ASCII! */
-			return AIM_CHARSET_UNICODE;
-		}
-		utf8++;
-	}
-	return AIM_CHARSET_ASCII;
-}
-
-gchar *
-oscar_encode_im(const gchar *msg, gsize *result_len, guint16 *charset, gchar **charsetstr)
-{
-	guint16 msg_charset = get_simplest_charset(msg);
-	if (charset != NULL) {
-		*charset = msg_charset;
-	}
-	if (charsetstr != NULL) {
-		*charsetstr = msg_charset == AIM_CHARSET_ASCII ? "us-ascii" : "unicode-2-0";
-	}
-	return g_convert(msg, -1, msg_charset == AIM_CHARSET_ASCII ? "ASCII" : "UTF-16BE", "UTF-8", NULL, result_len, NULL);
-}
--- a/libpurple/protocols/oscar/encoding.h	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-#ifndef PURPLE_OSCAR_ENCODING_H
-#define PURPLE_OSCAR_ENCODING_H
-
-#include "oscar.h"
-#include "oscarcommon.h"
-
-gchar * oscar_encoding_to_utf8(const char *encoding, const char *text, int textlen);
-gchar * oscar_utf8_try_convert(PurpleAccount *account, OscarData *od, const gchar *msg);
-
-/**
- * This attemps to decode an incoming IM into a UTF8 string.
- *
- * We try decoding using two different character sets.  The charset
- * specified in the IM determines the order in which we attempt to
- * decode.  We do this because there are lots of broken ICQ clients
- * that don't correctly send non-ASCII messages.  And if Purple isn't
- * able to deal with that crap, then people complain like banshees.
- */
-gchar * oscar_decode_im(PurpleAccount *account, const char *sourcebn, guint16 charset, const gchar *data, gsize datalen);
-
-/**
- * Figure out what encoding to use when sending a given outgoing message.
- */
-gchar * oscar_encode_im(const gchar *msg, gsize *result_len, guint16 *charset, gchar **charsetstr);
-
-#endif /* PURPLE_OSCAR_ENCODING_H */
--- a/libpurple/protocols/oscar/family_admin.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,246 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Family 0x0007 - Account Administration.
- *
- * Used for stuff like changing the formating of your username, changing your
- * email address, requesting an account confirmation email, getting account info,
- */
-
-#include "oscar.h"
-
-/**
- * Subtype 0x0002 - Request a bit of account info.
- *
- * Info should be one of the following:
- * 0x0001 - Username formatting
- * 0x0011 - Email address
- * 0x0013 - Unknown
- */
-void
-aim_admin_getinfo(OscarData *od, FlapConnection *conn, guint16 info)
-{
-	ByteStream bs;
-	aim_snacid_t snacid;
-
-	byte_stream_new(&bs, 4);
-
-	byte_stream_put16(&bs, info);
-	byte_stream_put16(&bs, 0x0000);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ADMIN, 0x0002, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0002, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-}
-
-/**
- * Subtypes 0x0003 and 0x0005 - Parse account info.
- *
- * Called in reply to both an information request (subtype 0x0002) and
- * an information change (subtype 0x0004).
- */
-static void
-infochange(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	aim_rxcallback_t userfunc;
-	char *url=NULL, *sn=NULL, *email=NULL;
-	guint16 perms, tlvcount, err=0;
-
-	perms = byte_stream_get16(bs);
-	tlvcount = byte_stream_get16(bs);
-
-	while (tlvcount && byte_stream_bytes_left(bs)) {
-		guint16 type, length;
-
-		type = byte_stream_get16(bs);
-		length = byte_stream_get16(bs);
-
-		switch (type) {
-			case 0x0001: {
-				g_free(sn);
-				sn = byte_stream_getstr(bs, length);
-			} break;
-
-			case 0x0004: {
-				g_free(url);
-				url = byte_stream_getstr(bs, length);
-			} break;
-
-			case 0x0008: {
-				err = byte_stream_get16(bs);
-			} break;
-
-			case 0x0011: {
-				g_free(email);
-				if (length == 0)
-					email = g_strdup("*suppressed");
-				else
-					email = byte_stream_getstr(bs, length);
-			} break;
-		}
-
-		tlvcount--;
-	}
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		userfunc(od, conn, frame, (snac->subtype == 0x0005) ? 1 : 0, perms, err, url, sn, email);
-
-	g_free(sn);
-	g_free(url);
-	g_free(email);
-}
-
-/**
- * Subtype 0x0004 - Set the formatting of username (change spaces and capitalization).
- */
-void
-aim_admin_setnick(OscarData *od, FlapConnection *conn, const char *newnick)
-{
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *tlvlist = NULL;
-
-	byte_stream_new(&bs, 2+2+strlen(newnick));
-
-	aim_tlvlist_add_str(&tlvlist, 0x0001, newnick);
-
-	aim_tlvlist_write(&bs, &tlvlist);
-	aim_tlvlist_free(tlvlist);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-}
-
-/**
- * Subtype 0x0004 - Change password.
- */
-void
-aim_admin_changepasswd(OscarData *od, FlapConnection *conn, const char *newpw, const char *curpw)
-{
-	ByteStream bs;
-	GSList *tlvlist = NULL;
-	aim_snacid_t snacid;
-
-	byte_stream_new(&bs, 4+strlen(curpw)+4+strlen(newpw));
-
-	/* new password TLV t(0002) */
-	aim_tlvlist_add_str(&tlvlist, 0x0002, newpw);
-
-	/* current password TLV t(0012) */
-	aim_tlvlist_add_str(&tlvlist, 0x0012, curpw);
-
-	aim_tlvlist_write(&bs, &tlvlist);
-	aim_tlvlist_free(tlvlist);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-}
-
-/**
- * Subtype 0x0004 - Change email address.
- */
-void
-aim_admin_setemail(OscarData *od, FlapConnection *conn, const char *newemail)
-{
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *tlvlist = NULL;
-
-	byte_stream_new(&bs, 2+2+strlen(newemail));
-
-	aim_tlvlist_add_str(&tlvlist, 0x0011, newemail);
-
-	aim_tlvlist_write(&bs, &tlvlist);
-	aim_tlvlist_free(tlvlist);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-}
-
-/*
- * Subtype 0x0006 - Request account confirmation.
- *
- * This will cause an email to be sent to the address associated with
- * the account.  By following the instructions in the mail, you can
- * get the TRIAL flag removed from your account.
- *
- */
-void
-aim_admin_reqconfirm(OscarData *od, FlapConnection *conn)
-{
-	aim_genericreq_n(od, conn, SNAC_FAMILY_ADMIN, 0x0006);
-}
-
-/**
- * Subtype SNAC_FAMILY_ADMIN - Account confirmation request acknowledgement.
- */
-static int
-accountconfirm(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	guint16 status;
-	/* GSList *tlvlist; */
-
-	status = byte_stream_get16(bs);
-	/* Status is 0x0013 if unable to confirm at this time */
-
-	/* tlvlist = aim_tlvlist_read(bs); */
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, status);
-
-	/* aim_tlvlist_free(tlvlist); */
-
-	return ret;
-}
-
-static int
-snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	if ((snac->subtype == 0x0003) || (snac->subtype == 0x0005)) {
-		infochange(od, conn, mod, frame, snac, bs);
-		return 1;
-	} else if (snac->subtype == SNAC_FAMILY_ADMIN)
-		return accountconfirm(od, conn, mod, frame, snac, bs);
-
-	return 0;
-}
-
-int admin_modfirst(OscarData *od, aim_module_t *mod)
-{
-	mod->family = SNAC_FAMILY_ADMIN;
-	mod->version = 0x0001;
-	mod->toolid = 0x0010;
-	mod->toolversion = 0x0629;
-	mod->flags = 0;
-	strncpy(mod->name, "admin", sizeof(mod->name));
-	mod->snachandler = snachandler;
-
-	return 0;
-}
--- a/libpurple/protocols/oscar/family_alert.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,238 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Family 0x0018 - Email notification
- *
- * Used for being alerted when the email address(es) associated with
- * your username get new electronic-m.  For normal AIM accounts, you
- * get the email address username@netscape.net.  AOL accounts have
- * username@aol.com, and can also activate a netscape.net account.
- * Note: This information might be out of date.
- */
-
-#include "oscar.h"
-
-/**
- * Subtype 0x0006 - Request information about your email account
- *
- * @param od The oscar session.
- * @param conn The email connection for this session.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int
-aim_email_sendcookies(OscarData *od)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ALERT)))
-		return -EINVAL;
-
-	byte_stream_new(&bs, 2+16+16);
-
-	/* Number of cookies to follow */
-	byte_stream_put16(&bs, 0x0002);
-
-	/* Cookie */
-	byte_stream_put16(&bs, 0x5d5e);
-	byte_stream_put16(&bs, 0x1708);
-	byte_stream_put16(&bs, 0x55aa);
-	byte_stream_put16(&bs, 0x11d3);
-	byte_stream_put16(&bs, 0xb143);
-	byte_stream_put16(&bs, 0x0060);
-	byte_stream_put16(&bs, 0xb0fb);
-	byte_stream_put16(&bs, 0x1ecb);
-
-	/* Cookie */
-	byte_stream_put16(&bs, 0xb380);
-	byte_stream_put16(&bs, 0x9ad8);
-	byte_stream_put16(&bs, 0x0dba);
-	byte_stream_put16(&bs, 0x11d5);
-	byte_stream_put16(&bs, 0x9f8a);
-	byte_stream_put16(&bs, 0x0060);
-	byte_stream_put16(&bs, 0xb0ee);
-	byte_stream_put16(&bs, 0x0631);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ALERT, 0x0006, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ALERT, 0x0006, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-
-/**
- * Subtype 0x0007 - Receive information about your email account
- *
- * So I don't even know if you can have multiple 16 byte keys,
- * but this is coded so it will handle that, and handle it well.
- * This tells you if you have unread mail or not, the URL you
- * should use to access that mail, and the domain name for the
- * email account (username@domainname.com).  If this is the
- * first 0x0007 SNAC you've received since you signed on, or if
- * this is just a periodic status update, this will also contain
- * the number of unread emails that you have.
- */
-static int
-parseinfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	struct aim_emailinfo *new;
-	GSList *tlvlist;
-	guint8 *cookie8, *cookie16;
-	int tmp, havenewmail = 0; /* Used to tell the client we have _new_ mail */
-
-	char *alertitle = NULL, *alerturl = NULL;
-
-	cookie8 = byte_stream_getraw(bs, 8); /* Possibly the code used to log you in to mail? */
-	cookie16 = byte_stream_getraw(bs, 16); /* Mail cookie sent above */
-
-	/* See if we already have some info associated with this cookie */
-	for (new = od->emailinfo; (new && memcmp(cookie16, new->cookie16, 16)); new = new->next);
-	if (new) {
-		/* Free some of the old info, if it exists */
-		g_free(new->cookie8);
-		g_free(new->cookie16);
-		g_free(new->url);
-		g_free(new->domain);
-	} else {
-		/* We don't already have info, so create a new struct for it */
-		new = g_new0(struct aim_emailinfo, 1);
-		new->next = od->emailinfo;
-		od->emailinfo = new;
-	}
-
-	new->cookie8 = cookie8;
-	new->cookie16 = cookie16;
-
-	tlvlist = aim_tlvlist_readnum(bs, byte_stream_get16(bs));
-
-	tmp = aim_tlv_get16(tlvlist, 0x0080, 1);
-	if (tmp) {
-		if (new->nummsgs < tmp)
-			havenewmail = 1;
-		new->nummsgs = tmp;
-	} else {
-		/* If they don't send a 0x0080 TLV, it means we definitely have new mail */
-		/* (ie. this is not just another status update) */
-		havenewmail = 1;
-		new->nummsgs++; /* We know we have at least 1 new email */
-	}
-	new->url = aim_tlv_getstr(tlvlist, 0x0007, 1);
-	if (!(new->unread = aim_tlv_get8(tlvlist, 0x0081, 1))) {
-		havenewmail = 0;
-		new->nummsgs = 0;
-	}
-	new->domain = aim_tlv_getstr(tlvlist, 0x0082, 1);
-	new->flag = aim_tlv_get16(tlvlist, 0x0084, 1);
-
-	alertitle = aim_tlv_getstr(tlvlist, 0x0005, 1);
-	alerturl  = aim_tlv_getstr(tlvlist, 0x000d, 1);
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, new, havenewmail, alertitle, (alerturl ? alerturl + 2 : NULL));
-
-	aim_tlvlist_free(tlvlist);
-
-	g_free(alertitle);
-	g_free(alerturl);
-
-	return ret;
-}
-
-/**
- * Subtype 0x0016 - Send something or other
- *
- * @param od The oscar session.
- * @param conn The email connection for this session.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int
-aim_email_activate(OscarData *od)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ALERT)))
-		return -EINVAL;
-
-	byte_stream_new(&bs, 1+16);
-
-	/* I would guess this tells AIM that you want updates for your mail accounts */
-	/* ...but I really have no idea */
-	byte_stream_put8(&bs, 0x02);
-	byte_stream_put32(&bs, 0x04000000);
-	byte_stream_put32(&bs, 0x04000000);
-	byte_stream_put32(&bs, 0x04000000);
-	byte_stream_put32(&bs, 0x00000000);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ALERT, 0x0016, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ALERT, 0x0006, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-static int
-snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	if (snac->subtype == 0x0007)
-		return parseinfo(od, conn, mod, frame, snac, bs);
-
-	return 0;
-}
-
-static void
-email_shutdown(OscarData *od, aim_module_t *mod)
-{
-	while (od->emailinfo)
-	{
-		struct aim_emailinfo *tmp = od->emailinfo;
-		od->emailinfo = od->emailinfo->next;
-		g_free(tmp->cookie16);
-		g_free(tmp->cookie8);
-		g_free(tmp->url);
-		g_free(tmp->domain);
-		g_free(tmp);
-	}
-
-	return;
-}
-
-int
-email_modfirst(OscarData *od, aim_module_t *mod)
-{
-	mod->family = SNAC_FAMILY_ALERT;
-	mod->version = 0x0001;
-	mod->toolid = 0x0010;
-	mod->toolversion = 0x0629;
-	mod->flags = 0;
-	strncpy(mod->name, "alert", sizeof(mod->name));
-	mod->snachandler = snachandler;
-	mod->shutdown = email_shutdown;
-
-	return 0;
-}
--- a/libpurple/protocols/oscar/family_auth.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,647 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Family 0x0017 - Authentication.
- *
- * Deals with the authorizer for SNAC-based login, and also old-style
- * non-SNAC login.
- *
- */
-
-#include "oscar.h"
-#include "oscarcommon.h"
-
-#include <ctype.h>
-
-/* #define USE_XOR_FOR_ICQ */
-
-#ifdef USE_XOR_FOR_ICQ
-/**
- * Encode a password using old XOR method
- *
- * This takes a const pointer to a (null terminated) string
- * containing the unencoded password.  It also gets passed
- * an already allocated buffer to store the encoded password.
- * This buffer should be the exact length of the password without
- * the null.  The encoded password buffer /is not %NULL terminated/.
- *
- * The encoding_table seems to be a fixed set of values.  We'll
- * hope it doesn't change over time!
- *
- * This is only used for the XOR method, not the better MD5 method.
- *
- * @param password Incoming password.
- * @param encoded Buffer to put encoded password.
- */
-static int
-aim_encode_password(const char *password, guint8 *encoded)
-{
-	guint8 encoding_table[] = {
-		0xf3, 0x26, 0x81, 0xc4,
-		0x39, 0x86, 0xdb, 0x92,
-		0x71, 0xa3, 0xb9, 0xe6,
-		0x53, 0x7a, 0x95, 0x7c
-	};
-	unsigned int i;
-
-	for (i = 0; i < strlen(password); i++)
-		encoded[i] = (password[i] ^ encoding_table[i]);
-
-	return 0;
-}
-#endif
-
-#ifdef USE_OLD_MD5
-static int
-aim_encode_password_md5(const char *password, size_t password_len, const char *key, guint8 *digest)
-{
-	GChecksum *hash;
-	gsize digest_len = 16;
-
-	hash = g_checksum_new(G_CHECKSUM_MD5);
-	g_checksum_update(hash, (const guchar *)key, -1);
-	g_checksum_update(hash, (const guchar *)password, password_len);
-	g_checksum_update(hash, (const guchar *)AIM_MD5_STRING, -1);
-	g_checksum_get_digest(hash, digest, &digest_len);
-	g_checksum_free(hash);
-
-	return 0;
-}
-#else
-static int
-aim_encode_password_md5(const char *password, size_t password_len, const char *key, guint8 *digest)
-{
-	GChecksum *hash;
-	guchar passdigest[16];
-	gsize digest_len = 16;
-
-	hash = g_checksum_new(G_CHECKSUM_MD5);
-	g_checksum_update(hash, (const guchar *)password, password_len);
-	g_checksum_get_digest(hash, passdigest, &digest_len);
-	g_checksum_reset(hash);
-
-	g_checksum_update(hash, (const guchar *)key, -1);
-	g_checksum_update(hash, passdigest, digest_len);
-	g_checksum_update(hash, (const guchar *)AIM_MD5_STRING, -1);
-	g_checksum_get_digest(hash, digest, &digest_len);
-	g_checksum_free(hash);
-
-	return 0;
-}
-#endif
-
-#ifdef USE_XOR_FOR_ICQ
-/*
- * Part two of the ICQ hack.  Note the ignoring of the key.
- */
-static int
-goddamnicq2(OscarData *od, FlapConnection *conn, const char *sn, const char *password, ClientInfo *ci)
-{
-	FlapFrame *frame;
-	GSList *tlvlist = NULL;
-	int passwdlen;
-	guint8 *password_encoded;
-	guint32 distrib;
-
-	passwdlen = strlen(password);
-	password_encoded = (guint8 *)g_malloc(passwdlen+1);
-	if (passwdlen > MAXICQPASSLEN)
-		passwdlen = MAXICQPASSLEN;
-
-	frame = flap_frame_new(od, 0x01, 1152);
-
-	aim_encode_password(password, password_encoded);
-
-	distrib = oscar_get_ui_info_int(
-			od->icq ? "prpl-icq-distid" : "prpl-aim-distid",
-			ci->distrib);
-
-	byte_stream_put32(&frame->data, 0x00000001); /* FLAP Version */
-	aim_tlvlist_add_str(&tlvlist, 0x0001, sn);
-	aim_tlvlist_add_raw(&tlvlist, 0x0002, passwdlen, password_encoded);
-
-	if (ci->clientstring != NULL)
-		aim_tlvlist_add_str(&tlvlist, 0x0003, ci->clientstring);
-	else {
-		gchar *clientstring = oscar_get_clientstring();
-		aim_tlvlist_add_str(&tlvlist, 0x0003, clientstring);
-		g_free(clientstring);
-	}
-	aim_tlvlist_add_16(&tlvlist, 0x0016, (guint16)ci->clientid);
-	aim_tlvlist_add_16(&tlvlist, 0x0017, (guint16)ci->major);
-	aim_tlvlist_add_16(&tlvlist, 0x0018, (guint16)ci->minor);
-	aim_tlvlist_add_16(&tlvlist, 0x0019, (guint16)ci->point);
-	aim_tlvlist_add_16(&tlvlist, 0x001a, (guint16)ci->build);
-	aim_tlvlist_add_32(&tlvlist, 0x0014, distrib); /* distribution chan */
-	aim_tlvlist_add_str(&tlvlist, 0x000f, ci->lang);
-	aim_tlvlist_add_str(&tlvlist, 0x000e, ci->country);
-
-	aim_tlvlist_write(&frame->data, &tlvlist);
-
-	g_free(password_encoded);
-	aim_tlvlist_free(tlvlist);
-
-	flap_connection_send(conn, frame);
-
-	return 0;
-}
-#endif
-
-/*
- * Subtype 0x0002
- *
- * This is the initial login request packet.
- *
- * NOTE!! If you want/need to make use of the aim_sendmemblock() function,
- * then the client information you send here must exactly match the
- * executable that you're pulling the data from.
- *
- * Java AIM 1.1.19:
- *   clientstring = "AOL Instant Messenger (TM) version 1.1.19 for Java built 03/24/98, freeMem 215871 totalMem 1048567, i686, Linus, #2 SMP Sun Feb 11 03:41:17 UTC 2001 2.4.1-ac9, IBM Corporation, 1.1.8, 45.3, Tue Mar 27 12:09:17 PST 2001"
- *   clientid = 0x0001
- *   major  = 0x0001
- *   minor  = 0x0001
- *   point = (not sent)
- *   build  = 0x0013
- *   unknown= (not sent)
- *
- * AIM for Linux 1.1.112:
- *   clientstring = "AOL Instant Messenger (SM)"
- *   clientid = 0x1d09
- *   major  = 0x0001
- *   minor  = 0x0001
- *   point = 0x0001
- *   build  = 0x0070
- *   unknown= 0x0000008b
- *   serverstore = 0x01
- *
- * @param truncate_pass Truncate the password to 8 characters.  This
- *        usually happens for AOL accounts.  We are told that we
- *        should truncate it if the 0x0017/0x0007 SNAC contains
- *        a TLV of type 0x0026 with data 0x0000.
- * @param allow_multiple_logins Allow multiple logins? If TRUE, the AIM
- *        server will prompt the user when multiple logins occur. If
- *        FALSE, existing connections (on other clients) will be
- *        disconnected automatically as we connect.
- */
-int
-aim_send_login(OscarData *od, FlapConnection *conn, const char *sn, const char *password, gboolean truncate_pass, ClientInfo *ci, const char *key, gboolean allow_multiple_logins)
-{
-	FlapFrame *frame;
-	GSList *tlvlist = NULL;
-	guint8 digest[16];
-	aim_snacid_t snacid;
-	size_t password_len;
-	guint32 distrib;
-
-	if (!ci || !sn || !password)
-		return -EINVAL;
-
-#ifdef USE_XOR_FOR_ICQ
-	/* If we're signing on an ICQ account then use the older, XOR login method */
-	if (aim_snvalid_icq(sn))
-		return goddamnicq2(od, conn, sn, password, ci);
-#endif
-
-	frame = flap_frame_new(od, 0x02, 1152);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_AUTH, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, 0x0002, snacid);
-
-	aim_tlvlist_add_str(&tlvlist, 0x0001, sn);
-
-	/* Truncate ICQ and AOL passwords, if necessary */
-	password_len = strlen(password);
-	if (oscar_util_valid_name_icq(sn) && (password_len > MAXICQPASSLEN))
-		password_len = MAXICQPASSLEN;
-	else if (truncate_pass && password_len > 8)
-		password_len = 8;
-
-	aim_encode_password_md5(password, password_len, key, digest);
-
-	distrib = oscar_get_ui_info_int(
-			od->icq ? "prpl-icq-distid" : "prpl-aim-distid",
-			ci->distrib);
-
-	aim_tlvlist_add_raw(&tlvlist, 0x0025, 16, digest);
-
-#ifndef USE_OLD_MD5
-	aim_tlvlist_add_noval(&tlvlist, 0x004c);
-#endif
-
-	if (ci->clientstring != NULL)
-		aim_tlvlist_add_str(&tlvlist, 0x0003, ci->clientstring);
-	else {
-		gchar *clientstring = oscar_get_clientstring();
-		aim_tlvlist_add_str(&tlvlist, 0x0003, clientstring);
-		g_free(clientstring);
-	}
-	aim_tlvlist_add_16(&tlvlist, 0x0016, (guint16)ci->clientid);
-	aim_tlvlist_add_16(&tlvlist, 0x0017, (guint16)ci->major);
-	aim_tlvlist_add_16(&tlvlist, 0x0018, (guint16)ci->minor);
-	aim_tlvlist_add_16(&tlvlist, 0x0019, (guint16)ci->point);
-	aim_tlvlist_add_16(&tlvlist, 0x001a, (guint16)ci->build);
-	aim_tlvlist_add_32(&tlvlist, 0x0014, distrib);
-	aim_tlvlist_add_str(&tlvlist, 0x000f, ci->lang);
-	aim_tlvlist_add_str(&tlvlist, 0x000e, ci->country);
-
-	/*
-	 * If set, old-fashioned buddy lists will not work. You will need
-	 * to use SSI.
-	 */
-	aim_tlvlist_add_8(&tlvlist, 0x004a, (allow_multiple_logins ? 0x01 : 0x03));
-
-	aim_tlvlist_write(&frame->data, &tlvlist);
-
-	aim_tlvlist_free(tlvlist);
-
-	flap_connection_send(conn, frame);
-
-	return 0;
-}
-
-/*
- * This is sent back as a general response to the login command.
- * It can be either an error or a success, depending on the
- * presence of certain TLVs.
- *
- * The client should check the value passed as errorcode. If
- * its nonzero, there was an error.
- */
-static int
-parse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	GSList *tlvlist;
-	aim_rxcallback_t userfunc;
-	struct aim_authresp_info *info;
-	int ret = 0;
-
-	info = g_new0(struct aim_authresp_info, 1);
-
-	/*
-	 * Read block of TLVs.  All further data is derived
-	 * from what is parsed here.
-	 */
-	tlvlist = aim_tlvlist_read(bs);
-
-	/*
-	 * No matter what, we should have a username.
-	 */
-	if (aim_tlv_gettlv(tlvlist, 0x0001, 1)) {
-		info->bn = aim_tlv_getstr(tlvlist, 0x0001, 1);
-		purple_connection_set_display_name(od->gc, info->bn);
-	}
-
-	/*
-	 * Check for an error code.  If so, we should also
-	 * have an error url.
-	 */
-	if (aim_tlv_gettlv(tlvlist, 0x0008, 1))
-		info->errorcode = aim_tlv_get16(tlvlist, 0x0008, 1);
-	if (aim_tlv_gettlv(tlvlist, 0x0004, 1))
-		info->errorurl = aim_tlv_getstr(tlvlist, 0x0004, 1);
-
-	/*
-	 * BOS server address.
-	 */
-	if (aim_tlv_gettlv(tlvlist, 0x0005, 1))
-		info->bosip = aim_tlv_getstr(tlvlist, 0x0005, 1);
-
-	/*
-	 * Authorization cookie.
-	 */
-	if (aim_tlv_gettlv(tlvlist, 0x0006, 1)) {
-		aim_tlv_t *tmptlv;
-
-		tmptlv = aim_tlv_gettlv(tlvlist, 0x0006, 1);
-		if (tmptlv != NULL)
-		{
-			info->cookielen = tmptlv->length;
-			info->cookie = tmptlv->value;
-		}
-	}
-
-	/*
-	 * The email address attached to this account
-	 *   Not available for ICQ or @mac.com logins.
-	 *   If you receive this TLV, then you are allowed to use
-	 *   family 0x0018 to check the status of your email.
-	 * XXX - Not really true!
-	 */
-	if (aim_tlv_gettlv(tlvlist, 0x0011, 1))
-		info->email = aim_tlv_getstr(tlvlist, 0x0011, 1);
-
-	/*
-	 * The registration status.  (Not real sure what it means.)
-	 *   Not available for ICQ or @mac.com logins.
-	 *
-	 *   1 = No disclosure
-	 *   2 = Limited disclosure
-	 *   3 = Full disclosure
-	 *
-	 * This has to do with whether your email address is available
-	 * to other users or not.  AFAIK, this feature is no longer used.
-	 *
-	 * Means you can use the admin family? (0x0007)
-	 *
-	 */
-	if (aim_tlv_gettlv(tlvlist, 0x0013, 1))
-		info->regstatus = aim_tlv_get16(tlvlist, 0x0013, 1);
-
-	if (aim_tlv_gettlv(tlvlist, 0x0040, 1))
-		info->latestbeta.build = aim_tlv_get32(tlvlist, 0x0040, 1);
-	if (aim_tlv_gettlv(tlvlist, 0x0041, 1))
-		info->latestbeta.url = aim_tlv_getstr(tlvlist, 0x0041, 1);
-	if (aim_tlv_gettlv(tlvlist, 0x0042, 1))
-		info->latestbeta.info = aim_tlv_getstr(tlvlist, 0x0042, 1);
-	if (aim_tlv_gettlv(tlvlist, 0x0043, 1))
-		info->latestbeta.name = aim_tlv_getstr(tlvlist, 0x0043, 1);
-
-	if (aim_tlv_gettlv(tlvlist, 0x0044, 1))
-		info->latestrelease.build = aim_tlv_get32(tlvlist, 0x0044, 1);
-	if (aim_tlv_gettlv(tlvlist, 0x0045, 1))
-		info->latestrelease.url = aim_tlv_getstr(tlvlist, 0x0045, 1);
-	if (aim_tlv_gettlv(tlvlist, 0x0046, 1))
-		info->latestrelease.info = aim_tlv_getstr(tlvlist, 0x0046, 1);
-	if (aim_tlv_gettlv(tlvlist, 0x0047, 1))
-		info->latestrelease.name = aim_tlv_getstr(tlvlist, 0x0047, 1);
-
-	/*
-	 * URL to change password.
-	 */
-	if (aim_tlv_gettlv(tlvlist, 0x0054, 1))
-		info->chpassurl = aim_tlv_getstr(tlvlist, 0x0054, 1);
-
-	od->authinfo = info;
-
-	if ((userfunc = aim_callhandler(od, snac ? snac->family : SNAC_FAMILY_AUTH, snac ? snac->subtype : 0x0003)))
-		ret = userfunc(od, conn, frame, info);
-
-	aim_tlvlist_free(tlvlist);
-
-	return ret;
-}
-
-#ifdef USE_XOR_FOR_ICQ
-/*
- * Subtype 0x0007 (kind of) - Send a fake type 0x0007 SNAC to the client
- *
- * This is a bit confusing.
- *
- * Normal SNAC login goes like this:
- *   - connect
- *   - server sends flap version
- *   - client sends flap version
- *   - client sends username (17/6)
- *   - server sends hash key (17/7)
- *   - client sends auth request (17/2 -- aim_send_login)
- *   - server yells
- *
- * XOR login (for ICQ) goes like this:
- *   - connect
- *   - server sends flap version
- *   - client sends auth request which contains flap version (aim_send_login)
- *   - server yells
- *
- * For the client API, we make them implement the most complicated version,
- * and for the simpler version, we fake it and make it look like the more
- * complicated process.
- *
- * This is done by giving the client a faked key, just so we can convince
- * them to call aim_send_login right away, which will detect the session
- * flag that says this is XOR login and ignore the key, sending an ICQ
- * login request instead of the normal SNAC one.
- *
- * As soon as AOL makes ICQ log in the same way as AIM, this is /gone/.
- */
-static int
-goddamnicq(OscarData *od, FlapConnection *conn, const char *sn)
-{
-	FlapFrame frame;
-	aim_rxcallback_t userfunc;
-
-	if ((userfunc = aim_callhandler(od, SNAC_FAMILY_AUTH, 0x0007)))
-		userfunc(od, conn, &frame, "");
-
-	return 0;
-}
-#endif
-
-/*
- * Subtype 0x0006
- *
- * In AIM 3.5 protocol, the first stage of login is to request login from the
- * Authorizer, passing it the username for verification.  If the name is
- * invalid, a 0017/0003 is spit back, with the standard error contents.  If
- * valid, a 0017/0007 comes back, which is the signal to send it the main
- * login command (0017/0002).
- *
- */
-int
-aim_request_login(OscarData *od, FlapConnection *conn, const char *sn)
-{
-	FlapFrame *frame;
-	aim_snacid_t snacid;
-	GSList *tlvlist = NULL;
-
-	if (!od || !conn || !sn)
-		return -EINVAL;
-
-#ifdef USE_XOR_FOR_ICQ
-	if (aim_snvalid_icq(sn))
-		return goddamnicq(od, conn, sn);
-#endif
-
-	frame = flap_frame_new(od, 0x02, 10+2+2+strlen(sn)+8);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_AUTH, 0x0006, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, 0x0006, snacid);
-
-	aim_tlvlist_add_str(&tlvlist, 0x0001, sn);
-
-	/* Tell the server we support SecurID logins. */
-	aim_tlvlist_add_noval(&tlvlist, 0x004b);
-
-	/* Unknown.  Sent in recent WinAIM clients.*/
-	aim_tlvlist_add_noval(&tlvlist, 0x005a);
-
-	aim_tlvlist_write(&frame->data, &tlvlist);
-	aim_tlvlist_free(tlvlist);
-
-	flap_connection_send(conn, frame);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0007
- *
- * Middle handler for 0017/0007 SNACs.  Contains the auth key prefixed
- * by only its length in a two byte word.
- *
- * Calls the client, which should then use the value to call aim_send_login.
- *
- */
-static int
-keyparse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int keylen;
-	char *keystr;
-	GSList *tlvlist;
-	gboolean truncate_pass;
-	PurpleConnection *gc;
-	PurpleAccount *account;
-	ClientInfo aiminfo = CLIENTINFO_PURPLE_AIM;
-	ClientInfo icqinfo = CLIENTINFO_PURPLE_ICQ;
-
-	gc = od->gc;
-	account = purple_connection_get_account(gc);
-
-	keylen = byte_stream_get16(bs);
-	keystr = byte_stream_getstr(bs, keylen);
-	if (!g_utf8_validate(keystr, -1, NULL)) {
-		purple_debug_warning("oscar", "Received SNAC %04hx/%04hx with "
-				"invalid UTF-8 keystr.\n", snac->family, snac->subtype);
-		purple_connection_error(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
-				_("Received unexpected response from server"));
-		g_free(keystr);
-		return 1;
-	}
-
-	tlvlist = aim_tlvlist_read(bs);
-
-	/*
-	 * If the truncate_pass TLV exists then we should truncate the
-	 * user's password to 8 characters.  This flag is sent to us
-	 * when logging in with an AOL user's username.
-	 */
-	truncate_pass = aim_tlv_gettlv(tlvlist, 0x0026, 1) != NULL;
-
-	/* XXX - When GiantGrayPanda signed on AIM I got a thing asking me to register
-	 * for the netscape network.  This SNAC had a type 0x0058 TLV with length 10.
-	 * Data is 0x0007 0004 3e19 ae1e 0006 0004 0000 0005 */
-
-	aim_send_login(od, conn, purple_account_get_username(account),
-			purple_connection_get_password(gc), truncate_pass,
-			od->icq ? &icqinfo : &aiminfo, keystr,
-			purple_account_get_bool(account, "allow_multiple_logins", OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS));
-
-	purple_connection_update_progress(gc,
-			_("Password sent"), 2, OSCAR_CONNECT_STEPS);
-
-	g_free(keystr);
-	aim_tlvlist_free(tlvlist);
-
-	return 1;
-}
-
-/**
- * Subtype 0x000a
- *
- * Receive SecurID request.
- */
-static int
-got_securid_request(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame);
-
-	return ret;
-}
-
-/**
- * Subtype 0x000b
- *
- * Send SecurID response.
- */
-int
-aim_auth_securid_send(OscarData *od, const char *securid)
-{
-	FlapConnection *conn;
-	FlapFrame *frame;
-	int len;
-
-	if (!od || !(conn = flap_connection_getbytype_all(od, SNAC_FAMILY_AUTH)) || !securid)
-		return -EINVAL;
-
-	len = strlen(securid);
-
-	frame = flap_frame_new(od, 0x02, 10+2+len);
-
-	/* aim_snacid_t snacid = */ aim_cachesnac(od, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_RESPONSE, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_RESPONSE, 0);
-
-	byte_stream_put16(&frame->data, len);
-	byte_stream_putstr(&frame->data, securid);
-
-	flap_connection_send(conn, frame);
-
-	return 0;
-}
-
-static void
-auth_shutdown(OscarData *od, aim_module_t *mod)
-{
-	if (od->authinfo != NULL)
-	{
-		g_free(od->authinfo->bn);
-		g_free(od->authinfo->bosip);
-		g_free(od->authinfo->errorurl);
-		g_free(od->authinfo->email);
-		g_free(od->authinfo->chpassurl);
-		g_free(od->authinfo->latestrelease.name);
-		g_free(od->authinfo->latestrelease.url);
-		g_free(od->authinfo->latestrelease.info);
-		g_free(od->authinfo->latestbeta.name);
-		g_free(od->authinfo->latestbeta.url);
-		g_free(od->authinfo->latestbeta.info);
-		g_free(od->authinfo);
-	}
-}
-
-static int
-snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	if (snac->subtype == 0x0003)
-		return parse(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x0007)
-		return keyparse(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x000a)
-		return got_securid_request(od, conn, mod, frame, snac, bs);
-
-	return 0;
-}
-
-int
-auth_modfirst(OscarData *od, aim_module_t *mod)
-{
-	mod->family = SNAC_FAMILY_AUTH;
-	mod->version = 0x0000;
-	mod->flags = 0;
-	strncpy(mod->name, "auth", sizeof(mod->name));
-	mod->snachandler = snachandler;
-	mod->shutdown = auth_shutdown;
-
-	return 0;
-}
--- a/libpurple/protocols/oscar/family_bart.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,190 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Family 0x0010 - Server stored buddy art
- *
- * Used for storing and retrieving your cute little buddy icon
- * from the AIM servers.
- *
- */
-
-#include "oscar.h"
-
-/**
- * Subtype 0x0002 - Upload your icon.
- *
- * @param od The oscar session.
- * @param icon The raw data of the icon image file.
- * @param iconlen Length of the raw data of the icon image file.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int
-aim_bart_upload(OscarData *od, const guint8 *icon, guint16 iconlen)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_BART)) || !icon || !iconlen)
-		return -EINVAL;
-
-	byte_stream_new(&bs, 2 + 2 + iconlen);
-
-	/* The reference number for the icon */
-	byte_stream_put16(&bs, 1);
-
-	/* The icon */
-	byte_stream_put16(&bs, iconlen);
-	byte_stream_putraw(&bs, icon, iconlen);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_BART, 0x0002, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_BART, 0x0002, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/**
- * Subtype 0x0003 - Acknowledgement for uploading a buddy icon.
- *
- * You get this honky after you upload a buddy icon.
- */
-static int
-uploadack(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-
-	byte_stream_get16(bs);
-	byte_stream_get16(bs);
-	byte_stream_get8(bs);
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame);
-
-	return ret;
-}
-
-/**
- * Subtype 0x0004 - Request someone's icon.
- *
- * @param od The oscar session.
- * @param bn The name of the buddy whose icon you are requesting.
- * @param iconcsum The MD5 checksum of the icon you are requesting.
- * @param iconcsumlen Length of the MD5 checksum given above.  Should be 10 bytes.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int
-aim_bart_request(OscarData *od, const char *bn, guint8 iconcsumtype, const guint8 *iconcsum, guint16 iconcsumlen)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_BART)) || !bn || *bn == '\0' || !iconcsum || !iconcsumlen)
-		return -EINVAL;
-
-	byte_stream_new(&bs, 1+strlen(bn) + 4 + 1+iconcsumlen);
-
-	/* Buddy name */
-	byte_stream_put8(&bs, strlen(bn));
-	byte_stream_putstr(&bs, bn);
-
-	/* Some numbers.  You like numbers, right? */
-	byte_stream_put8(&bs, 0x01);
-	byte_stream_put16(&bs, 0x0001);
-	byte_stream_put8(&bs, iconcsumtype);
-
-	/* Icon string */
-	byte_stream_put8(&bs, iconcsumlen);
-	byte_stream_putraw(&bs, iconcsum, iconcsumlen);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_BART, 0x0004, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_BART, 0x0004, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/**
- * Subtype 0x0005 - Receive a buddy icon.
- *
- * This is sent in response to a buddy icon request.
- */
-static int
-parseicon(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	char *bn;
-	guint16 iconlen;
-	guint8 iconcsumtype, iconcsumlen, *iconcsum, *icon;
-
-	bn = byte_stream_getstr(bs, byte_stream_get8(bs));
-	if (!g_utf8_validate(bn, -1, NULL)) {
-		purple_debug_warning("oscar", "Received SNAC %04hx/%04hx with "
-				"invalid UTF-8 buddy name.\n", snac->family, snac->subtype);
-		g_free(bn);
-		return 1;
-	}
-	byte_stream_get16(bs); /* flags */
-	iconcsumtype = byte_stream_get8(bs);
-	iconcsumlen = byte_stream_get8(bs);
-	iconcsum = byte_stream_getraw(bs, iconcsumlen);
-	iconlen = byte_stream_get16(bs);
-	icon = byte_stream_getraw(bs, iconlen);
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, bn, iconcsumtype, iconcsum, iconcsumlen, icon, iconlen);
-
-	g_free(bn);
-	g_free(iconcsum);
-	g_free(icon);
-
-	return ret;
-}
-
-static int
-snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	if (snac->subtype == 0x0003)
-		return uploadack(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x0005)
-		return parseicon(od, conn, mod, frame, snac, bs);
-
-	return 0;
-}
-
-int
-bart_modfirst(OscarData *od, aim_module_t *mod)
-{
-	mod->family = SNAC_FAMILY_BART;
-	mod->version = 0x0001;
-	mod->toolid = 0x0010;
-	mod->toolversion = 0x0629;
-	mod->flags = 0;
-	strncpy(mod->name, "bart", sizeof(mod->name));
-	mod->snachandler = snachandler;
-
-	return 0;
-}
--- a/libpurple/protocols/oscar/family_bos.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Family 0x0009 - Basic Oscar Service.
- *
- * The functionality of this family has been replaced by SSI.
- */
-
-#include "oscar.h"
-
-#include <string.h>
-
-/* Subtype 0x0002 - Request BOS rights. */
-void
-aim_bos_reqrights(OscarData *od, FlapConnection *conn)
-{
-	aim_genericreq_n_snacid(od, conn, SNAC_FAMILY_BOS, 0x0002);
-}
-
-/* Subtype 0x0003 - BOS Rights. */
-static int rights(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	aim_rxcallback_t userfunc;
-	GSList *tlvlist;
-	guint16 maxpermits = 0, maxdenies = 0;
-	int ret = 0;
-
-	/*
-	 * TLVs follow
-	 */
-	tlvlist = aim_tlvlist_read(bs);
-
-	/*
-	 * TLV type 0x0001: Maximum number of buddies on permit list.
-	 */
-	if (aim_tlv_gettlv(tlvlist, 0x0001, 1))
-		maxpermits = aim_tlv_get16(tlvlist, 0x0001, 1);
-
-	/*
-	 * TLV type 0x0002: Maximum number of buddies on deny list.
-	 */
-	if (aim_tlv_gettlv(tlvlist, 0x0002, 1))
-		maxdenies = aim_tlv_get16(tlvlist, 0x0002, 1);
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, maxpermits, maxdenies);
-
-	aim_tlvlist_free(tlvlist);
-
-	return ret;
-}
-
-static int
-snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	if (snac->subtype == 0x0003)
-		return rights(od, conn, mod, frame, snac, bs);
-
-	return 0;
-}
-
-int
-bos_modfirst(OscarData *od, aim_module_t *mod)
-{
-	mod->family = SNAC_FAMILY_BOS;
-	mod->version = 0x0001;
-	mod->toolid = 0x0110;
-	mod->toolversion = 0x0629;
-	mod->flags = 0;
-	strncpy(mod->name, "bos", sizeof(mod->name));
-	mod->snachandler = snachandler;
-
-	return 0;
-}
--- a/libpurple/protocols/oscar/family_buddy.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,153 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Family 0x0003 (SNAC_FAMILY_BUDDY) - Old-style Buddylist Management (non-SSI).
- *
- */
-
-#include "oscar.h"
-
-#include <string.h>
-
-/*
- * Subtype 0x0002 - Request rights.
- *
- * Request Buddy List rights.
- *
- */
-void
-aim_buddylist_reqrights(OscarData *od, FlapConnection *conn)
-{
-	aim_genericreq_n_snacid(od, conn, SNAC_FAMILY_BUDDY, SNAC_SUBTYPE_BUDDY_REQRIGHTS);
-}
-
-/*
- * Subtype 0x0003 - Rights.
- *
- */
-static int
-rights(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	aim_rxcallback_t userfunc;
-	GSList *tlvlist;
-	guint16 maxbuddies = 0, maxwatchers = 0;
-	int ret = 0;
-
-	/*
-	 * TLVs follow
-	 */
-	tlvlist = aim_tlvlist_read(bs);
-
-	/*
-	 * TLV type 0x0001: Maximum number of buddies.
-	 */
-	if (aim_tlv_gettlv(tlvlist, 0x0001, 1))
-		maxbuddies = aim_tlv_get16(tlvlist, 0x0001, 1);
-
-	/*
-	 * TLV type 0x0002: Maximum number of watchers.
-	 *
-	 * Watchers are other users who have you on their buddy
-	 * list.  (This is called the "reverse list" by a certain
-	 * other IM protocol.)
-	 *
-	 */
-	if (aim_tlv_gettlv(tlvlist, 0x0002, 1))
-		maxwatchers = aim_tlv_get16(tlvlist, 0x0002, 1);
-
-	/*
-	 * TLV type 0x0003: Unknown.
-	 *
-	 * ICQ only?
-	 */
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, maxbuddies, maxwatchers);
-
-	aim_tlvlist_free(tlvlist);
-
-	return ret;
-}
-
-/*
- * Subtypes 0x000b (SNAC_SUBTYPE_BUDDY_ONCOMING) and 0x000c (SNAC_SUBTYPE_BUDDY_OFFGOING) - Change in buddy status
- *
- * Oncoming Buddy notifications contain a subset of the
- * user information structure.  It's close enough to run
- * through aim_info_extract() however.
- *
- * Although the offgoing notification contains no information,
- * it is still in a format parsable by aim_info_extract().
- *
- */
-static int
-buddychange(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_userinfo_t userinfo;
-	aim_rxcallback_t userfunc;
-
-	aim_info_extract(od, bs, &userinfo);
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, &userinfo);
-
-	if (snac->subtype == SNAC_SUBTYPE_BUDDY_ONCOMING &&
-	    userinfo.capabilities & OSCAR_CAPABILITY_XTRAZ) {
-		PurpleAccount *account = purple_connection_get_account(od->gc);
-		PurpleBuddy *buddy = purple_blist_find_buddy(account, userinfo.bn);
-
-		if (buddy) {
-			PurplePresence *presence = purple_buddy_get_presence(buddy);
-
-			if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_MOOD))
-				icq_im_xstatus_request(od, userinfo.bn);
-		}
-	}
-	aim_info_free(&userinfo);
-
-	return ret;
-}
-
-static int
-snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	if (snac->subtype == SNAC_SUBTYPE_BUDDY_RIGHTSINFO)
-		return rights(od, conn, mod, frame, snac, bs);
-	else if ((snac->subtype == SNAC_SUBTYPE_BUDDY_ONCOMING) || (snac->subtype == SNAC_SUBTYPE_BUDDY_OFFGOING))
-		return buddychange(od, conn, mod, frame, snac, bs);
-
-	return 0;
-}
-
-int
-buddylist_modfirst(OscarData *od, aim_module_t *mod)
-{
-	mod->family = SNAC_FAMILY_BUDDY;
-	mod->version = 0x0001;
-	mod->toolid = 0x0110;
-	mod->toolversion = 0x0629;
-	mod->flags = 0;
-	strncpy(mod->name, "buddy", sizeof(mod->name));
-	mod->snachandler = snachandler;
-
-	return 0;
-}
--- a/libpurple/protocols/oscar/family_chat.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,403 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Family 0x000e - Routines for the Chat service.
- *
- */
-
-#include "oscar.h"
-
-#include <string.h>
-
-/* Stored in the ->internal of chat connections */
-struct chatconnpriv
-{
-	guint16 exchange;
-	char *name;
-	guint16 instance;
-};
-
-void
-flap_connection_destroy_chat(OscarData *od, FlapConnection *conn)
-{
-	struct chatconnpriv *ccp = (struct chatconnpriv *)conn->internal;
-
-	if (ccp)
-		g_free(ccp->name);
-	g_free(ccp);
-
-	return;
-}
-
-int
-aim_chat_readroominfo(ByteStream *bs, struct aim_chat_roominfo *outinfo)
-{
-	if (!outinfo)
-		return 0;
-
-	outinfo->exchange = byte_stream_get16(bs);
-	outinfo->namelen = byte_stream_get8(bs);
-	outinfo->name = (char *)byte_stream_getraw(bs, outinfo->namelen);
-	outinfo->instance = byte_stream_get16(bs);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0002 - General room information.  Lots of stuff.
- *
- * Values I know are in here but I haven't attached
- * them to any of the 'Unknown's:
- *	- Language (English)
- *
- */
-static int
-infoupdate(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	aim_rxcallback_t userfunc;
-	int ret = 0;
-	guint8 detaillevel = 0;
-	struct aim_chat_roominfo roominfo;
-	GSList *tlvlist;
-	guint16 maxmsglen, maxvisiblemsglen;
-
-	aim_chat_readroominfo(bs, &roominfo);
-
-	detaillevel = byte_stream_get8(bs);
-
-	if (detaillevel != 0x02) {
-		purple_debug_misc("oscar", "faim: chat_roomupdateinfo: detail level %d not supported\n", detaillevel);
-		return 1;
-	}
-
-	byte_stream_get16(bs); /* skip the TLV count */
-
-	/*
-	 * Everything else are TLVs.
-	 */
-	tlvlist = aim_tlvlist_read(bs);
-
-	/*
-	 * Type 0x00d1: Maximum Message Length
-	 */
-	maxmsglen = aim_tlv_get16(tlvlist, 0x00d1, 1);
-
-	/*
-	 * Type 0x00da: Maximum visible message length
-	 */
-	maxvisiblemsglen = aim_tlv_get16(tlvlist, 0x00da, 1);
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) {
-		ret = userfunc(od, conn, frame, maxmsglen, maxvisiblemsglen);
-	}
-
-	g_free(roominfo.name);
-
-	aim_tlvlist_free(tlvlist);
-
-	return ret;
-}
-
-/* Subtypes 0x0003 and 0x0004 */
-static int
-userlistchange(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	aim_userinfo_t *userinfo = NULL;
-	aim_rxcallback_t userfunc;
-	int curcount = 0, ret = 0;
-
-	while (byte_stream_bytes_left(bs)) {
-		curcount++;
-		userinfo = g_realloc(userinfo, curcount * sizeof(aim_userinfo_t));
-		aim_info_extract(od, bs, &userinfo[curcount-1]);
-	}
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, curcount, userinfo);
-
-	aim_info_free(userinfo);
-	g_free(userinfo);
-
-	return ret;
-}
-
-/*
- * Subtype 0x0005 - Send a Chat Message.
- *
- * Possible flags:
- *   AIM_CHATFLAGS_NOREFLECT   --  Unset the flag that requests messages
- *                                 should be sent to their sender.
- *   AIM_CHATFLAGS_AWAY        --  Mark the message as an autoresponse
- *                                 (Note that WinAIM does not honor this,
- *                                 and displays the message as normal.)
- *
- * XXX convert this to use tlvchains
- */
-int
-aim_chat_send_im(OscarData *od, FlapConnection *conn, guint16 flags, const gchar *msg, int msglen, const char *encoding, const char *language)
-{
-	int i;
-	ByteStream bs;
-	IcbmCookie *cookie;
-	aim_snacid_t snacid;
-	guint8 ckstr[8];
-	GSList *tlvlist = NULL, *inner_tlvlist = NULL;
-
-	if (!od || !conn || !msg || (msglen <= 0))
-		return 0;
-
-	byte_stream_new(&bs, 1142);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_CHAT, 0x0005, 0x0000, NULL, 0);
-
-	/*
-	 * Cookie
-	 *
-	 * XXX mkcookie should generate the cookie and cache it in one
-	 * operation to preserve uniqueness.
-	 */
-	for (i = 0; i < 8; i += 4) {
-		gint32 rnd = g_random_int();
-		ckstr[i] = (guint8)((rnd & 0xFF000000) >> 24);
-		ckstr[i+1] = (guint8)((rnd & 0xFF0000) >> 16);
-		ckstr[i+2] = (guint8)((rnd & 0xFF00) >> 8);
-		ckstr[i+3] = (guint8)(rnd & 0xFF);
-	}
-
-	cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_CHAT, NULL);
-	cookie->data = NULL; /* XXX store something useful here */
-
-	aim_cachecookie(od, cookie);
-
-	/* ICBM Header */
-	byte_stream_putraw(&bs, ckstr, 8); /* Cookie */
-	byte_stream_put16(&bs, 0x0003); /* Channel */
-
-	/*
-	 * Type 1: Flag meaning this message is destined to the room.
-	 */
-	aim_tlvlist_add_noval(&tlvlist, 0x0001);
-
-	/*
-	 * Type 6: Reflect
-	 */
-	if (!(flags & AIM_CHATFLAGS_NOREFLECT))
-		aim_tlvlist_add_noval(&tlvlist, 0x0006);
-
-	/*
-	 * Type 7: Autoresponse
-	 */
-	if (flags & AIM_CHATFLAGS_AWAY)
-		aim_tlvlist_add_noval(&tlvlist, 0x0007);
-
-	/*
-	 * SubTLV: Type 1: Message
-	 */
-	aim_tlvlist_add_raw(&inner_tlvlist, 0x0001, msglen, (guchar *)msg);
-
-	/*
-	 * SubTLV: Type 2: Encoding
-	 */
-	if (encoding != NULL)
-		aim_tlvlist_add_str(&inner_tlvlist, 0x0002, encoding);
-
-	/*
-	 * SubTLV: Type 3: Language
-	 */
-	if (language != NULL)
-		aim_tlvlist_add_str(&inner_tlvlist, 0x0003, language);
-
-	/*
-	 * Type 5: Message block.  Contains more TLVs.
-	 *
-	 * This could include other information... We just
-	 * put in a message TLV however.
-	 *
-	 */
-	aim_tlvlist_add_frozentlvlist(&tlvlist, 0x0005, &inner_tlvlist);
-
-	aim_tlvlist_write(&bs, &tlvlist);
-
-	aim_tlvlist_free(inner_tlvlist);
-	aim_tlvlist_free(tlvlist);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_CHAT, 0x0005, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0006
- *
- * We could probably include this in the normal ICBM parsing
- * code as channel 0x0003, however, since only the start
- * would be the same, we might as well do it here.
- *
- * General outline of this SNAC:
- *   snac
- *   cookie
- *   channel id
- *   tlvlist
- *     unknown
- *     source user info
- *       name
- *       evility
- *       userinfo tlvs
- *         online time
- *         etc
- *     message metatlv
- *       message tlv
- *         message string
- *       possibly others
- *
- */
-static int
-incomingim_ch3(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0, i;
-	aim_rxcallback_t userfunc;
-	aim_userinfo_t userinfo;
-	guint8 cookie[8];
-	guint16 channel;
-	GSList *tlvlist;
-	char *msg = NULL;
-	int len = 0;
-	char *encoding = NULL, *language = NULL;
-	IcbmCookie *ck;
-	aim_tlv_t *tlv;
-	ByteStream tbs;
-
-	memset(&userinfo, 0, sizeof(aim_userinfo_t));
-
-	/*
-	 * Read ICBM Cookie.
-	 */
-	for (i = 0; i < 8; i++)
-		cookie[i] = byte_stream_get8(bs);
-
-	if ((ck = aim_uncachecookie(od, cookie, AIM_COOKIETYPE_CHAT))) {
-		g_free(ck->data);
-		g_free(ck);
-	}
-
-	/*
-	 * Channel ID
-	 *
-	 * Channel 0x0003 is used for chat messages.
-	 *
-	 */
-	channel = byte_stream_get16(bs);
-
-	if (channel != 0x0003) {
-		purple_debug_misc("oscar", "faim: chat_incoming: unknown channel! (0x%04x)\n", channel);
-		return 0;
-	}
-
-	/*
-	 * Start parsing TLVs right away.
-	 */
-	tlvlist = aim_tlvlist_read(bs);
-
-	/*
-	 * Type 0x0003: Source User Information
-	 */
-	tlv = aim_tlv_gettlv(tlvlist, 0x0003, 1);
-	if (tlv != NULL)
-	{
-		byte_stream_init(&tbs, tlv->value, tlv->length);
-		aim_info_extract(od, &tbs, &userinfo);
-	}
-
-	/*
-	 * Type 0x0005: Message Block.  Conains more TLVs.
-	 */
-	tlv = aim_tlv_gettlv(tlvlist, 0x0005, 1);
-	if (tlv != NULL)
-	{
-		GSList *inner_tlvlist;
-		aim_tlv_t *inner_tlv;
-
-		byte_stream_init(&tbs, tlv->value, tlv->length);
-		inner_tlvlist = aim_tlvlist_read(&tbs);
-
-		/*
-		 * Type 0x0001: Message.
-		 */
-		inner_tlv = aim_tlv_gettlv(inner_tlvlist, 0x0001, 1);
-		if (inner_tlv != NULL)
-		{
-			len = inner_tlv->length;
-			msg = aim_tlv_getvalue_as_string(inner_tlv);
-		}
-
-		/*
-		 * Type 0x0002: Encoding.
-		 */
-		encoding = aim_tlv_getstr(inner_tlvlist, 0x0002, 1);
-
-		/*
-		 * Type 0x0003: Language.
-		 */
-		language = aim_tlv_getstr(inner_tlvlist, 0x0003, 1);
-
-		aim_tlvlist_free(inner_tlvlist);
-	}
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, &userinfo, len, msg, encoding, language);
-
-	aim_info_free(&userinfo);
-	g_free(msg);
-	g_free(encoding);
-	g_free(language);
-	aim_tlvlist_free(tlvlist);
-
-	return ret;
-}
-
-static int
-snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	if (snac->subtype == 0x0002)
-		return infoupdate(od, conn, mod, frame, snac, bs);
-	else if ((snac->subtype == 0x0003) || (snac->subtype == 0x0004))
-		return userlistchange(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x0006)
-		return incomingim_ch3(od, conn, mod, frame, snac, bs);
-
-	return 0;
-}
-
-int
-chat_modfirst(OscarData *od, aim_module_t *mod)
-{
-	mod->family = SNAC_FAMILY_CHAT;
-	mod->version = 0x0001;
-	mod->toolid = 0x0010;
-	mod->toolversion = 0x0629;
-	mod->flags = 0;
-	strncpy(mod->name, "chat", sizeof(mod->name));
-	mod->snachandler = snachandler;
-
-	return 0;
-}
--- a/libpurple/protocols/oscar/family_chatnav.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,446 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Family 0x000d - Handle ChatNav.
- *
- * The ChatNav(igation) service does various things to keep chat
- * alive.  It provides room information, room searching and creating,
- * as well as giving users the right ("permission") to use chat.
- *
- */
-
-#include "oscar.h"
-
-static int
-error(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_snac_t *snac2;
-	guint16 error, chatnav_error;
-	GSList *tlvlist;
-
-	snac2 = aim_remsnac(od, snac->id);
-	if (!snac2) {
-		purple_debug_warning("oscar", "chatnav error: received response to unknown request (%08x)\n", snac->id);
-		return 0;
-	}
-
-	if (snac2->family != SNAC_FAMILY_CHATNAV) {
-		purple_debug_warning("oscar", "chatnav error: received response that maps to corrupt request (fam=%04x)\n", snac2->family);
-		g_free(snac2->data);
-		g_free(snac2);
-		return 0;
-	}
-
-	/*
-	 * We now know what the original SNAC subtype was.
-	 */
-	if (snac2->type == 0x0008) /* create room */
-	{
-		error = byte_stream_get16(bs);
-		tlvlist = aim_tlvlist_read(bs);
-		chatnav_error = aim_tlv_get16(tlvlist, 0x0008, 1);
-
-		purple_debug_warning("oscar",
-				"Could not join room, error=0x%04hx, chatnav_error=0x%04hx\n",
-				error, chatnav_error);
-		purple_notify_error(od->gc, NULL, _("Could not join chat room"),
-			chatnav_error == 0x0033 ? _("Invalid chat room name") :
-				_("Unknown error"),
-			purple_request_cpar_from_connection(od->gc));
-
-		ret = 1;
-	}
-
-	g_free(snac2->data);
-	g_free(snac2);
-
-	return ret;
-}
-
-/*
- * Subtype 0x0002
- *
- * conn must be a chatnav connection!
- *
- */
-void aim_chatnav_reqrights(OscarData *od, FlapConnection *conn)
-{
-	aim_genericreq_n_snacid(od, conn, SNAC_FAMILY_CHATNAV, 0x0002);
-}
-
-/*
- * Subtype 0x0008
- */
-int aim_chatnav_createroom(OscarData *od, FlapConnection *conn, const char *name, guint16 exchange)
-{
-	static const char ck[] = {"create"};
-	static const char lang[] = {"en"};
-	static const char charset[] = {"us-ascii"};
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *tlvlist = NULL;
-
-	byte_stream_new(&bs, 1142);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_CHATNAV, 0x0008, 0x0000, NULL, 0);
-
-	/* exchange */
-	byte_stream_put16(&bs, exchange);
-
-	/*
-	 * This looks to be a big hack.  You'll note that this entire
-	 * SNAC is just a room info structure, but the hard room name,
-	 * here, is set to "create".
-	 *
-	 * Either this goes on the "list of questions concerning
-	 * why-the-hell-did-you-do-that", or this value is completely
-	 * ignored.  Without experimental evidence, but a good knowledge of
-	 * AOL style, I'm going to guess that it is the latter, and that
-	 * the value of the room name in create requests is ignored.
-	 */
-	byte_stream_put8(&bs, strlen(ck));
-	byte_stream_putstr(&bs, ck);
-
-	/*
-	 * instance
-	 *
-	 * Setting this to 0xffff apparently assigns the last instance.
-	 *
-	 */
-	byte_stream_put16(&bs, 0xffff);
-
-	/* detail level */
-	byte_stream_put8(&bs, 0x01);
-
-	aim_tlvlist_add_str(&tlvlist, 0x00d3, name);
-	aim_tlvlist_add_str(&tlvlist, 0x00d6, charset);
-	aim_tlvlist_add_str(&tlvlist, 0x00d7, lang);
-
-	/* tlvcount */
-	byte_stream_put16(&bs, aim_tlvlist_count(tlvlist));
-	aim_tlvlist_write(&bs, &tlvlist);
-
-	aim_tlvlist_free(tlvlist);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_CHATNAV, 0x0008, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-static int
-parseinfo_perms(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs, aim_snac_t *snac2)
-{
-	aim_rxcallback_t userfunc;
-	int ret = 0;
-	struct aim_chat_exchangeinfo *exchanges = NULL;
-	int curexchange;
-	aim_tlv_t *exchangetlv;
-	guint8 maxrooms = 0;
-	GSList *tlvlist, *innerlist;
-
-	tlvlist = aim_tlvlist_read(bs);
-
-	/*
-	 * Type 0x0002: Maximum concurrent rooms.
-	 */
-	if (aim_tlv_gettlv(tlvlist, 0x0002, 1))
-		maxrooms = aim_tlv_get8(tlvlist, 0x0002, 1);
-
-	/*
-	 * Type 0x0003: Exchange information
-	 *
-	 * There can be any number of these, each one
-	 * representing another exchange.
-	 *
-	 */
-	for (curexchange = 0; ((exchangetlv = aim_tlv_gettlv(tlvlist, 0x0003, curexchange+1))); ) {
-		ByteStream tbs;
-
-		byte_stream_init(&tbs, exchangetlv->value, exchangetlv->length);
-
-		curexchange++;
-
-		exchanges = g_realloc(exchanges, curexchange * sizeof(struct aim_chat_exchangeinfo));
-
-		/* exchange number */
-		exchanges[curexchange-1].number = byte_stream_get16(&tbs);
-		innerlist = aim_tlvlist_read(&tbs);
-
-		/*
-		 * Type 0x0002: Unknown
-		 */
-		if (aim_tlv_gettlv(innerlist, 0x0002, 1)) {
-			guint16 classperms;
-
-			classperms = aim_tlv_get16(innerlist, 0x0002, 1);
-
-			purple_debug_misc("oscar", "faim: class permissions %x\n", classperms);
-		}
-
-		/*
-		 * Type 0x00c9: Flags
-		 *
-		 * 1 Evilable
-		 * 2 Nav Only
-		 * 4 Instancing Allowed
-		 * 8 Occupant Peek Allowed
-		 *
-		 */
-		if (aim_tlv_gettlv(innerlist, 0x00c9, 1))
-			exchanges[curexchange-1].flags = aim_tlv_get16(innerlist, 0x00c9, 1);
-
-		/*
-		 * Type 0x00d3: Exchange Description
-		 */
-		if (aim_tlv_gettlv(innerlist, 0x00d3, 1))
-			exchanges[curexchange-1].name = aim_tlv_getstr(innerlist, 0x00d3, 1);
-		else
-			exchanges[curexchange-1].name = NULL;
-
-		/*
-		 * Type 0x00d5: Creation Permissions
-		 *
-		 * 0  Creation not allowed
-		 * 1  Room creation allowed
-		 * 2  Exchange creation allowed
-		 *
-		 */
-		if (aim_tlv_gettlv(innerlist, 0x00d5, 1))
-			aim_tlv_get8(innerlist, 0x00d5, 1); /* createperms */
-
-		/*
-		 * Type 0x00d6: Character Set (First Time)
-		 */
-		if (aim_tlv_gettlv(innerlist, 0x00d6, 1))
-			exchanges[curexchange-1].charset1 = aim_tlv_getstr(innerlist, 0x00d6, 1);
-		else
-			exchanges[curexchange-1].charset1 = NULL;
-
-		/*
-		 * Type 0x00d7: Language (First Time)
-		 */
-		if (aim_tlv_gettlv(innerlist, 0x00d7, 1))
-			exchanges[curexchange-1].lang1 = aim_tlv_getstr(innerlist, 0x00d7, 1);
-		else
-			exchanges[curexchange-1].lang1 = NULL;
-
-		/*
-		 * Type 0x00d8: Character Set (Second Time)
-		 */
-		if (aim_tlv_gettlv(innerlist, 0x00d8, 1))
-			exchanges[curexchange-1].charset2 = aim_tlv_getstr(innerlist, 0x00d8, 1);
-		else
-			exchanges[curexchange-1].charset2 = NULL;
-
-		/*
-		 * Type 0x00d9: Language (Second Time)
-		 */
-		if (aim_tlv_gettlv(innerlist, 0x00d9, 1))
-			exchanges[curexchange-1].lang2 = aim_tlv_getstr(innerlist, 0x00d9, 1);
-		else
-			exchanges[curexchange-1].lang2 = NULL;
-
-		aim_tlvlist_free(innerlist);
-	}
-
-	/*
-	 * Call client.
-	 */
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, snac2->type, maxrooms, curexchange, exchanges);
-
-	for (curexchange--; curexchange >= 0; curexchange--) {
-		g_free(exchanges[curexchange].name);
-		g_free(exchanges[curexchange].charset1);
-		g_free(exchanges[curexchange].lang1);
-		g_free(exchanges[curexchange].charset2);
-		g_free(exchanges[curexchange].lang2);
-	}
-	g_free(exchanges);
-	aim_tlvlist_free(tlvlist);
-
-	return ret;
-}
-
-static int
-parseinfo_create(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs, aim_snac_t *snac2)
-{
-	aim_rxcallback_t userfunc;
-	GSList *tlvlist, *innerlist;
-	char *ck = NULL, *fqcn = NULL, *name = NULL;
-	guint16 exchange = 0, instance = 0, unknown = 0, flags = 0, maxmsglen = 0, maxoccupancy = 0;
-	guint32 createtime = 0;
-	guint8 createperms = 0, detaillevel;
-	int cklen;
-	aim_tlv_t *bigblock;
-	int ret = 0;
-	ByteStream bbbs;
-
-	tlvlist = aim_tlvlist_read(bs);
-
-	if (!(bigblock = aim_tlv_gettlv(tlvlist, 0x0004, 1))) {
-		purple_debug_misc("oscar", "no bigblock in top tlv in create room response\n");
-		aim_tlvlist_free(tlvlist);
-		return 0;
-	}
-
-	byte_stream_init(&bbbs, bigblock->value, bigblock->length);
-
-	exchange = byte_stream_get16(&bbbs);
-	cklen = byte_stream_get8(&bbbs);
-	ck = byte_stream_getstr(&bbbs, cklen);
-	instance = byte_stream_get16(&bbbs);
-	detaillevel = byte_stream_get8(&bbbs);
-
-	if (detaillevel != 0x02) {
-		purple_debug_misc("oscar", "unknown detaillevel in create room response (0x%02x)\n", detaillevel);
-		aim_tlvlist_free(tlvlist);
-		g_free(ck);
-		return 0;
-	}
-
-	unknown = byte_stream_get16(&bbbs);
-
-	innerlist = aim_tlvlist_read(&bbbs);
-
-	if (aim_tlv_gettlv(innerlist, 0x006a, 1))
-		fqcn = aim_tlv_getstr(innerlist, 0x006a, 1);
-
-	if (aim_tlv_gettlv(innerlist, 0x00c9, 1))
-		flags = aim_tlv_get16(innerlist, 0x00c9, 1);
-
-	if (aim_tlv_gettlv(innerlist, 0x00ca, 1))
-		createtime = aim_tlv_get32(innerlist, 0x00ca, 1);
-
-	if (aim_tlv_gettlv(innerlist, 0x00d1, 1))
-		maxmsglen = aim_tlv_get16(innerlist, 0x00d1, 1);
-
-	if (aim_tlv_gettlv(innerlist, 0x00d2, 1))
-		maxoccupancy = aim_tlv_get16(innerlist, 0x00d2, 1);
-
-	if (aim_tlv_gettlv(innerlist, 0x00d3, 1))
-		name = aim_tlv_getstr(innerlist, 0x00d3, 1);
-
-	if (aim_tlv_gettlv(innerlist, 0x00d5, 1))
-		createperms = aim_tlv_get8(innerlist, 0x00d5, 1);
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) {
-		ret = userfunc(od, conn, frame, snac2->type, fqcn, instance, exchange, flags, createtime, maxmsglen, maxoccupancy, createperms, unknown, name, ck);
-	}
-
-	g_free(ck);
-	g_free(name);
-	g_free(fqcn);
-	aim_tlvlist_free(innerlist);
-	aim_tlvlist_free(tlvlist);
-
-	return ret;
-}
-
-/*
- * Subtype 0x0009
- *
- * Since multiple things can trigger this callback, we must lookup the
- * snacid to determine the original snac subtype that was called.
- *
- * XXX This isn't really how this works.  But this is:  Every d/9 response
- * has a 16bit value at the beginning. That matches to:
- *    Short Desc = 1
- *    Full Desc = 2
- *    Instance Info = 4
- *    Nav Short Desc = 8
- *    Nav Instance Info = 16
- * And then everything is really asynchronous.  There is no specific
- * attachment of a response to a create room request, for example.  Creating
- * the room yields no different a response than requesting the room's info.
- *
- */
-static int
-parseinfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	aim_snac_t *snac2;
-	int ret = 0;
-
-	if (!(snac2 = aim_remsnac(od, snac->id))) {
-		purple_debug_misc("oscar", "faim: chatnav_parse_info: received response to unknown request! (%08x)\n", snac->id);
-		return 0;
-	}
-
-	if (snac2->family != SNAC_FAMILY_CHATNAV) {
-		purple_debug_misc("oscar", "faim: chatnav_parse_info: received response that maps to corrupt request! (fam=%04x)\n", snac2->family);
-		g_free(snac2->data);
-		g_free(snac2);
-		return 0;
-	}
-
-	/*
-	 * We now know what the original SNAC subtype was.
-	 */
-	if (snac2->type == 0x0002) /* request chat rights */
-		ret = parseinfo_perms(od, conn, mod, frame, snac, bs, snac2);
-	else if (snac2->type == 0x0003) /* request exchange info */
-		purple_debug_misc("oscar", "chatnav_parse_info: response to exchange info\n");
-	else if (snac2->type == 0x0004) /* request room info */
-		purple_debug_misc("oscar", "chatnav_parse_info: response to room info\n");
-	else if (snac2->type == 0x0005) /* request more room info */
-		purple_debug_misc("oscar", "chatnav_parse_info: response to more room info\n");
-	else if (snac2->type == 0x0006) /* request occupant list */
-		purple_debug_misc("oscar", "chatnav_parse_info: response to occupant info\n");
-	else if (snac2->type == 0x0007) /* search for a room */
-		purple_debug_misc("oscar", "chatnav_parse_info: search results\n");
-	else if (snac2->type == 0x0008) /* create room */
-		ret = parseinfo_create(od, conn, mod, frame, snac, bs, snac2);
-	else
-		purple_debug_misc("oscar", "chatnav_parse_info: unknown request subtype (%04x)\n", snac2->type);
-
-	g_free(snac2->data);
-	g_free(snac2);
-
-	return ret;
-}
-
-static int
-snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	if (snac->subtype == 0x0001)
-		return error(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x0009)
-		return parseinfo(od, conn, mod, frame, snac, bs);
-
-	return 0;
-}
-
-int
-chatnav_modfirst(OscarData *od, aim_module_t *mod)
-{
-	mod->family = SNAC_FAMILY_CHATNAV;
-	mod->version = 0x0001;
-	mod->toolid = 0x0010;
-	mod->toolversion = 0x0629;
-	mod->flags = 0;
-	strncpy(mod->name, "chatnav", sizeof(mod->name));
-	mod->snachandler = snachandler;
-
-	return 0;
-}
--- a/libpurple/protocols/oscar/family_feedbag.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2065 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Family 0x0013 - Server-Side/Stored Information.
- *
- * Deals with storing certain types of information, such as a user's buddy
- * list, permit/deny list, and permit/deny preferences, on the server, so
- * that they can be accessed from any client.
- *
- * We keep 2 copies of SSI data:
- * 1) An exact copy of what is stored on the AIM servers.
- * 2) A local copy that we make changes to, and then send diffs
- *    between this and the exact copy to keep them in sync.
- *
- * All the "aim_ssi_itemlist_bleh" functions near the top just modify the list
- * that is given to them (i.e. they don't send SNACs).
- *
- * The SNAC sending and receiving functions are lower down in the file, and
- * they're simpler.  They are in the order of the subtypes they deal with,
- * starting with the request rights function (subtype 0x0002), then parse
- * rights (subtype 0x0003), then--well, you get the idea.
- *
- * This is entirely too complicated.
- * You don't know the half of it.
- */
-
-#include "oscar.h"
-#include "oscarcommon.h"
-#include "debug.h"
-
-static int aim_ssi_addmoddel(OscarData *od);
-
-static void aim_ssi_item_free(struct aim_ssi_item *item)
-{
-	g_free(item->name);
-	aim_tlvlist_free(item->data);
-	g_free(item);
-}
-
-static void aim_ssi_item_set_name(struct aim_ssi_itemlist *list, struct aim_ssi_item *item, const char *name)
-{
-	gchar key[3000];
-
-	if (item->name) {
-		/* Remove old name from hash table */
-		snprintf(key, sizeof(key), "%hx%s", item->type, oscar_normalize(NULL, item->name));
-		g_hash_table_remove(list->idx_all_named_items, key);
-	}
-
-	g_free(item->name);
-	item->name = g_strdup(name);
-
-	if (name) {
-		/* Add new name to hash table */
-		snprintf(key, sizeof(key), "%hx%s", item->type, oscar_normalize(NULL, item->name));
-		g_hash_table_insert(list->idx_all_named_items, g_strdup(key), item);
-	}
-}
-
-/**
- * List types based on http://dev.aol.com/aim/oscar/#FEEDBAG (archive.org)
- * and http://iserverd.khstu.ru/oscar/ssi_item.html
- *
- * @param type The type of a list item as integer number, as provided by an aim_ssi_item struct.
- * @return Returns the name of the item type as a character string.
- */
-static const gchar*
-aim_ssi_type_to_string(guint16 type)
-{
-	struct TypeStringPair
-	{
-		guint16 type;
-		const gchar *string;
-	};
-	static const struct TypeStringPair type_strings[] = {
-		{ 0x0000, "Buddy" },
-		{ 0x0001, "Group" },
-		{ 0x0002, "Permit/Visible" },
-		{ 0x0003, "Deny/Invisible" },
-		{ 0x0004, "PDInfo" },
-		{ 0x0005, "PresencePrefs" }, 
-		{ 0x0006, "Non-Buddy Info" },
-		{ 0x0009, "ClientPrefs" },
-		{ 0x000e, "ICQDeny/Ignore" },
-		{ 0x0014, "Buddy Icon" }, 
-		{ 0x0015, "Recent Buddies" },
-		{ 0x0019, "Non-Buddy" },
-		{ 0x001d, "Vanity Info" },
-		{ 0x0020, "ICQ-MDir" },
-		{ 0x0029, "Facebook" },
-	};
-	size_t i;
-	for (i = 0; i < G_N_ELEMENTS(type_strings); i++) {
-		if (type_strings[i].type == type) {
-			return type_strings[i].string;
-		}
-	}
-	return "unknown";
-}
-
-/** For debug log output: Appends a line containing information about a given list item to a string.
- *
- * @param str String to which the line will be appended.
- * @param prefix A string which will be prepended to the line.
- * @param item List item from which information is extracted.
- */
-static void
-aim_ssi_item_debug_append(GString *str, char *prefix, struct aim_ssi_item *item)
-{
-	g_string_append_printf(str, 
-		"%s gid=0x%04hx, bid=0x%04hx, list_type=0x%04hx [%s], name=%s.\n",
-		prefix, item->gid, item->bid, item->type, aim_ssi_type_to_string(item->type),
-		item->name ? item->name : "(null)");
-}
-
-/**
- * Locally rebuild the 0x00c8 TLV in the additional data of the given group.
- *
- * @param list A pointer to a pointer to the current list of items.
- * @param name A null terminated string containing the group name, or NULL
- *        if you want to modify the master group.
- * @return Return a pointer to the modified item.
- */
-static void
-aim_ssi_itemlist_rebuildgroup(struct aim_ssi_itemlist *list, const char *name)
-{
-	int newlen;
-	struct aim_ssi_item *cur, *group;
-
-	/* Find the group */
-	if (!(group = aim_ssi_itemlist_finditem(list, name, NULL, AIM_SSI_TYPE_GROUP)))
-		return;
-
-	/* Find the length for the new additional data */
-	newlen = 0;
-	if (group->gid == 0x0000) {
-		for (cur=list->data; cur; cur=cur->next)
-			if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid != 0x0000))
-				newlen += 2;
-	} else {
-		for (cur=list->data; cur; cur=cur->next)
-			if ((cur->gid == group->gid) && (cur->type == AIM_SSI_TYPE_BUDDY))
-				newlen += 2;
-	}
-
-	/* Build the new TLV list */
-	if (newlen > 0) {
-		guint8 *newdata;
-
-		newdata = g_new(guint8, newlen);
-		newlen = 0;
-		if (group->gid == 0x0000) {
-			for (cur=list->data; cur; cur=cur->next)
-				if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid != 0x0000))
-						newlen += aimutil_put16(newdata+newlen, cur->gid);
-		} else {
-			for (cur=list->data; cur; cur=cur->next)
-				if ((cur->gid == group->gid) && (cur->type == AIM_SSI_TYPE_BUDDY))
-						newlen += aimutil_put16(newdata+newlen, cur->bid);
-		}
-		aim_tlvlist_replace_raw(&group->data, 0x00c8, newlen, newdata);
-
-		g_free(newdata);
-	}
-}
-
-/**
- * Locally add a new item to the given item list.
- *
- * @param list A pointer to a pointer to the current list of items.
- * @param name A null terminated string of the name of the new item, or NULL if the
- *        item should have no name.
- * @param gid The group ID# you want the new item to have, or 0xFFFF if we should pick something.
- * @param bid The buddy ID# you want the new item to have, or 0xFFFF if we should pick something.
- * @param type The type of the item, 0x0000 for a contact, 0x0001 for a group, etc.
- * @param data The additional data for the new item.
- * @return A pointer to the newly created item.
- */
-static struct aim_ssi_item *aim_ssi_itemlist_add(struct aim_ssi_itemlist *list, const char *name, guint16 gid, guint16 bid, guint16 type, GSList *data)
-{
-	gboolean exists;
-	struct aim_ssi_item *cur, *new;
-
-	new = g_new0(struct aim_ssi_item, 1);
-
-	/* Set the group ID# and buddy ID# */
-	new->gid = gid;
-	new->bid = bid;
-	if (type == AIM_SSI_TYPE_GROUP) {
-		if ((new->gid == 0xFFFF) && name) {
-			do {
-				new->gid += 0x0001;
-				exists = FALSE;
-				for (cur = list->data; cur != NULL; cur = cur->next)
-					if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid == new->gid)) {
-						exists = TRUE;
-						break;
-					}
-			} while (exists);
-		}
-	} else if (new->gid == 0x0000) {
-		/*
-		 * This is weird, but apparently items in the root group can't
-		 * have a buddy ID equal to any group ID.  You'll get error
-		 * 0x0003 when trying to add, which is "item already exists"
-		 */
-		if (new->bid == 0xFFFF) {
-			do {
-				new->bid += 0x0001;
-				exists = FALSE;
-				for (cur = list->data; cur != NULL; cur = cur->next)
-					if (cur->bid == new->bid || cur->gid == new->bid) {
-						exists = TRUE;
-						break;
-					}
-			} while (exists);
-		}
-	} else {
-		if (new->bid == 0xFFFF) {
-			do {
-				new->bid += 0x0001;
-				exists = FALSE;
-				for (cur = list->data; cur != NULL; cur = cur->next)
-					if (cur->bid == new->bid && cur->gid == new->gid) {
-						exists = TRUE;
-						break;
-					}
-			} while (exists);
-		}
-	}
-
-	/* Set the type */
-	new->type = type;
-
-	/* Add it to the gid+bid hashtable */
-	g_hash_table_insert(list->idx_gid_bid, GINT_TO_POINTER((new->gid << 16) + new->bid), new);
-
-	/* Set the name - do this *AFTER* setting the type because type is used for the key */
-	aim_ssi_item_set_name(list, new, name);
-
-	/* Set the TLV list */
-	new->data = aim_tlvlist_copy(data);
-
-	/* Add the item to the list in the correct numerical position.  Fancy, eh? */
-	if (list->data) {
-		if ((new->gid < list->data->gid) || ((new->gid == list->data->gid) && (new->bid < list->data->bid))) {
-			new->next = list->data;
-			list->data = new;
-		} else {
-			struct aim_ssi_item *prev;
-			for ((prev=list->data, cur=list->data->next); (cur && ((new->gid > cur->gid) || ((new->gid == cur->gid) && (new->bid > cur->bid)))); prev=cur, cur=cur->next);
-			new->next = prev->next;
-			prev->next = new;
-		}
-	} else {
-		new->next = list->data;
-		list->data = new;
-	}
-
-	return new;
-}
-
-/**
- * Locally delete an item from the given item list.
- *
- * @param list A pointer to a pointer to the current list of items.
- * @param del A pointer to the item you want to remove from the list.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-static int aim_ssi_itemlist_del(struct aim_ssi_itemlist *list, struct aim_ssi_item *del)
-{
-	gchar key[3000];
-
-	if (!(list->data) || !del)
-		return -EINVAL;
-
-	/* Remove the item from the list */
-	if (list->data == del) {
-		list->data = list->data->next;
-	} else {
-		struct aim_ssi_item *cur;
-		for (cur=list->data; (cur->next && (cur->next!=del)); cur=cur->next);
-		if (cur->next)
-			cur->next = del->next;
-	}
-
-	/* Remove from the hashtables */
-	g_hash_table_remove(list->idx_gid_bid, GINT_TO_POINTER((del->gid << 16) + del->bid));
-
-	snprintf(key, sizeof(key), "%hx%s", del->type, oscar_normalize(NULL, del->name));
-	g_hash_table_remove(list->idx_all_named_items, key);
-
-	/* Free the removed item */
-	aim_ssi_item_free(del);
-
-	return 0;
-}
-
-/**
- * Compare two items to see if they have the same data.
- *
- * @param cur1 A pointer to a pointer to the first item.
- * @param cur2 A pointer to a pointer to the second item.
- * @return Return 0 if no differences, or a number if there are differences.
- */
-static int aim_ssi_itemlist_cmp(struct aim_ssi_item *cur1, struct aim_ssi_item *cur2)
-{
-	if (!cur1 || !cur2)
-		return 1;
-
-	if (cur1->data && !cur2->data)
-		return 2;
-
-	if (!cur1->data && cur2->data)
-		return 3;
-
-	if ((cur1->data && cur2->data) && (aim_tlvlist_cmp(cur1->data, cur2->data)))
-		return 4;
-
-	if (cur1->name && !cur2->name)
-		return 5;
-
-	if (!cur1->name && cur2->name)
-		return 6;
-
-	if (cur1->name && cur2->name && oscar_util_name_compare(cur1->name, cur2->name))
-		return 7;
-
-	if (cur1->gid != cur2->gid)
-		return 8;
-
-	if (cur1->bid != cur2->bid)
-		return 9;
-
-	if (cur1->type != cur2->type)
-		return 10;
-
-	return 0;
-}
-
-static gboolean aim_ssi_itemlist_valid(struct aim_ssi_itemlist *list, struct aim_ssi_item *item)
-{
-	struct aim_ssi_item *cur;
-	for (cur=list->data; cur; cur=cur->next)
-		if (cur == item)
-			return TRUE;
-	return FALSE;
-}
-
-/**
- * Locally find an item given a group ID# and a buddy ID#.
- *
- * @param list A pointer to the current list of items.
- * @param gid The group ID# of the desired item.
- * @param bid The buddy ID# of the desired item.
- * @return Return a pointer to the item if found, else return NULL;
- */
-struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_itemlist *list, guint16 gid, guint16 bid)
-{
-	guint32 id_key = (gid << 16) + bid;
-	return g_hash_table_lookup(list->idx_gid_bid, GINT_TO_POINTER(id_key));
-}
-
-/**
- * Locally find an item given a group name, buddy name, and type.  If group name
- * and buddy name are null, then just return the first item of the given type.
- *
- * @param list A pointer to the current list of items.
- * @param gn The group name of the desired item.
- * @param bn The buddy name of the desired item.
- * @param type The type of the desired item.
- * @return Return a pointer to the item if found, else return NULL.
- */
-struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_itemlist *list, const char *gn, const char *bn, guint16 type)
-{
-	struct aim_ssi_item *cur;
-	gchar key[3000];
-
-	if (!list->data)
-		return NULL;
-
-	if (gn && bn) { /* For finding buddies in groups */
-		g_return_val_if_fail(type == AIM_SSI_TYPE_BUDDY, NULL);
-		for (cur=list->data; cur; cur=cur->next)
-			if ((cur->type == type) && (cur->name) && !(oscar_util_name_compare(cur->name, bn))) {
-				struct aim_ssi_item *curg;
-				for (curg=list->data; curg; curg=curg->next)
-					if ((curg->type == AIM_SSI_TYPE_GROUP) && (curg->gid == cur->gid) && (curg->name) && !(oscar_util_name_compare(curg->name, gn)))
-						return cur;
-			}
-
-	} else if (gn || bn) { /* For finding groups, permits, denies and ignores */
-		snprintf(key, sizeof(key), "%hx%s", type, oscar_normalize(NULL, gn ? gn : bn));
-		return g_hash_table_lookup(list->idx_all_named_items, key);
-
-	/* For stuff without names--permit deny setting, visibility mask, etc. */
-	} else for (cur=list->data; cur; cur=cur->next) {
-		if ((cur->type == type) && (!cur->name))
-			return cur;
-	}
-
-	return NULL;
-}
-
-/**
- * Check if the given buddy exists in any group in the buddy list.
- *
- * @param list A pointer to the current list of items.
- * @param bn The group name of the desired item.
- * @return Return a pointer to the name of the item if found, else return NULL;
- */
-struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_itemlist *list, const char *bn)
-{
-	if (!bn)
-		return NULL;
-	return aim_ssi_itemlist_finditem(list, NULL, bn, AIM_SSI_TYPE_BUDDY);
-}
-
-/**
- * Locally find the parent item of the given buddy name.
- *
- * @param list A pointer to the current list of items.
- * @param bn The buddy name of the desired item.
- * @return Return a pointer to the name of the item if found, else return NULL;
- */
-char *aim_ssi_itemlist_findparentname(struct aim_ssi_itemlist *list, const char *bn)
-{
-	struct aim_ssi_item *cur, *curg;
-	if (!list->data || !bn)
-		return NULL;
-	if (!(cur = aim_ssi_itemlist_exists(list, bn)))
-		return NULL;
-	if (!(curg = aim_ssi_itemlist_find(list, cur->gid, 0x0000)))
-		return NULL;
-	return curg->name;
-}
-
-/**
- * Locally find the permit/deny setting item, and return the setting.
- *
- * @param list A pointer to the current list of items.
- * @return Return the current SSI permit deny setting, or 0 if no setting was found.
- */
-int aim_ssi_getpermdeny(struct aim_ssi_itemlist *list)
-{
-	struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PDINFO);
-	if (cur) {
-		aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x00ca, 1);
-		if (tlv && tlv->value)
-			return aimutil_get8(tlv->value);
-	}
-	return 0;
-}
-
-/**
- * Locally find the presence flag item, and return the setting.  The returned setting is a
- * bitmask of the preferences.  See the AIM_SSI_PRESENCE_FLAG_* #defines in oscar.h.
- *
- * @param list A pointer to the current list of items.
- * @return Return the current set of preferences.
- */
-guint32 aim_ssi_getpresence(struct aim_ssi_itemlist *list)
-{
-	struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS);
-	if (cur) {
-		aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x00c9, 1);
-		if (tlv && tlv->length)
-			return aimutil_get32(tlv->value);
-	}
-	return 0xFFFFFFFF;
-}
-
-/**
- * Locally find the alias of the given buddy.
- *
- * @param list A pointer to the current list of items.
- * @param gn The group of the buddy.
- * @param bn The name of the buddy.
- * @return A pointer to a NULL terminated string that is the buddy's
- *         alias, or NULL if the buddy has no alias.  You should free
- *         this returned value!
- */
-char *aim_ssi_getalias(struct aim_ssi_itemlist *list, const char *gn, const char *bn)
-{
-	struct aim_ssi_item *item = aim_ssi_itemlist_finditem(list, gn, bn, AIM_SSI_TYPE_BUDDY);
-	if (item) {
-		return aim_ssi_getalias_from_item(item);
-	}
-	return NULL;
-}
-
-char *aim_ssi_getalias_from_item(struct aim_ssi_item *item)
-{
-	aim_tlv_t *tlv = aim_tlv_gettlv(item->data, 0x0131, 1);
-	if (tlv && tlv->length)
-		return g_strndup((const gchar *)tlv->value, tlv->length);
-	return NULL;
-}
-
-/**
- * Locally find the comment of the given buddy.
- *
- * @param list A pointer to the current list of items.
- * @param gn The group of the buddy.
- * @param bn The name of the buddy.
- * @return A pointer to a NULL terminated string that is the buddy's
- *         comment, or NULL if the buddy has no comment.  You should free
- *         this returned value!
- */
-char *aim_ssi_getcomment(struct aim_ssi_itemlist *list, const char *gn, const char *bn)
-{
-	struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, bn, AIM_SSI_TYPE_BUDDY);
-	if (cur) {
-		aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x013c, 1);
-		if (tlv && tlv->length) {
-			return g_strndup((const gchar *)tlv->value, tlv->length);
-		}
-	}
-	return NULL;
-}
-
-/**
- * Locally find if you are waiting for authorization for a buddy.
- *
- * @param list A pointer to the current list of items.
- * @param gn The group of the buddy.
- * @param bn The name of the buddy.
- * @return 1 if you are waiting for authorization; 0 if you are not
- */
-gboolean aim_ssi_waitingforauth(struct aim_ssi_itemlist *list, const char *gn, const char *bn)
-{
-	struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, bn, AIM_SSI_TYPE_BUDDY);
-	if (cur) {
-		if (aim_tlv_gettlv(cur->data, 0x0066, 1))
-			return TRUE;
-	}
-	return FALSE;
-}
-
-/**
- * If there are changes, then create temporary items and
- * call addmoddel.
- *
- * @param od The oscar session.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-static int aim_ssi_sync(OscarData *od)
-{
-	struct aim_ssi_item *cur1, *cur2;
-	struct aim_ssi_tmp *cur, *new;
-	int n = 0;
-	GString *debugstr;
-
-	/*
-	 * The variable "n" is used to limit the number of addmoddel's that
-	 * are performed in a single SNAC.  It will hopefully keep the size
-	 * of the SNAC below the maximum SNAC size.
-	 */
-
-	if (!od)
-		return -EINVAL;
-
-	/* If we're waiting for an ack, we shouldn't do anything else */
-	if (od->ssi.waiting_for_ack)
-		return 0;
-
-	/*
-	 * Compare the 2 lists and create an aim_ssi_tmp for each difference.
-	 * We should only send either additions, modifications, or deletions
-	 * before waiting for an acknowledgement.  So first do deletions, then
-	 * additions, then modifications.  Also, both the official and the local
-	 * list should be in ascending numerical order for the group ID#s and the
-	 * buddy ID#s, which makes things more efficient.  I think.
-	 */
-	debugstr = g_string_new("");
-
-	/* Deletions */
-	if (!od->ssi.pending) {
-		for (cur1=od->ssi.official.data; cur1 && (n < 15); cur1=cur1->next) {
-			if (!aim_ssi_itemlist_find(&od->ssi.local, cur1->gid, cur1->bid)) {
-				n++;
-				new = g_new(struct aim_ssi_tmp, 1);
-				new->action = SNAC_SUBTYPE_FEEDBAG_DEL;
-				new->ack = 0xffff;
-				new->name = NULL;
-				new->item = cur1;
-				new->next = NULL;
-				if (od->ssi.pending) {
-					for (cur=od->ssi.pending; cur->next; cur=cur->next);
-					cur->next = new;
-				} else {
-					od->ssi.pending = new;
-				}
-				aim_ssi_item_debug_append(debugstr, "Deleting item ", cur1);
-			}
-		}
-	}
-
-	/* Additions */
-	if (!od->ssi.pending) {
-		for (cur1=od->ssi.local.data; cur1 && (n < 15); cur1=cur1->next) {
-			if (!aim_ssi_itemlist_find(&od->ssi.official, cur1->gid, cur1->bid)) {
-				n++;
-				new = g_new(struct aim_ssi_tmp, 1);
-				new->action = SNAC_SUBTYPE_FEEDBAG_ADD;
-				new->ack = 0xffff;
-				new->name = NULL;
-				new->item = cur1;
-				new->next = NULL;
-				if (od->ssi.pending) {
-					for (cur=od->ssi.pending; cur->next; cur=cur->next);
-					cur->next = new;
-				} else {
-					od->ssi.pending = new;
-				}
-				aim_ssi_item_debug_append(debugstr, "Adding item ", cur1);
-			}
-		}
-	}
-
-	/* Modifications */
-	if (!od->ssi.pending) {
-		for (cur1=od->ssi.local.data; cur1 && (n < 15); cur1=cur1->next) {
-			cur2 = aim_ssi_itemlist_find(&od->ssi.official, cur1->gid, cur1->bid);
-			if (cur2 && (aim_ssi_itemlist_cmp(cur1, cur2))) {
-				n++;
-				new = g_new(struct aim_ssi_tmp, 1);
-				new->action = SNAC_SUBTYPE_FEEDBAG_MOD;
-				new->ack = 0xffff;
-				new->name = NULL;
-				new->item = cur1;
-				new->next = NULL;
-				if (od->ssi.pending) {
-					for (cur=od->ssi.pending; cur->next; cur=cur->next);
-					cur->next = new;
-				} else {
-					od->ssi.pending = new;
-				}
-				aim_ssi_item_debug_append(debugstr, "Modifying item ", cur1);
-			}
-		}
-	}
-	if (debugstr->len > 0) {
-		purple_debug_info("oscar", "%s", debugstr->str);
-		if (purple_debug_is_verbose()) {
-			PurpleAccount *account = purple_connection_get_account(od->gc);
-			g_string_truncate(debugstr, 0);
-			for (cur1 = od->ssi.local.data; cur1; cur1 = cur1->next) {
-				aim_ssi_item_debug_append(debugstr, "\t", cur1);
-			}
-			purple_debug_misc("oscar", "Dumping item list of account %s:\n%s",
-					purple_account_get_username(account), debugstr->str);
-		}
-	}
-	g_string_free(debugstr, TRUE);
-
-	/* We're out of stuff to do, so tell the AIM servers we're done and exit */
-	if (!od->ssi.pending) {
-		if (od->ssi.in_transaction) {
-			aim_ssi_modend(od);
-			od->ssi.in_transaction = FALSE;
-		}
-		return 0;
-	}
-
-	/* If this is the first in a series of add/mod/del
-	 * requests then send the "begin transaction" message. */
-	if (!od->ssi.in_transaction)
-	{
-		aim_ssi_modbegin(od);
-		od->ssi.in_transaction = TRUE;
-	}
-
-	/* Make sure we don't send anything else between now
-	 * and when we receive the ack for the following operation */
-	od->ssi.waiting_for_ack = TRUE;
-
-	/* Now go mail off our data and wait 4 to 6 weeks */
-	return aim_ssi_addmoddel(od);;
-}
-
-/**
- * Free all SSI data.
- *
- * This doesn't remove it from the server, that's different.
- *
- * @param od The oscar odion.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-static void
-aim_ssi_freelist(OscarData *od)
-{
-	struct aim_ssi_item *cur, *del;
-	struct aim_ssi_tmp *curtmp, *deltmp;
-
-	cur = od->ssi.official.data;
-	while (cur) {
-		del = cur;
-		cur = cur->next;
-		aim_ssi_item_free(del);
-	}
-
-	cur = od->ssi.local.data;
-	while (cur) {
-		del = cur;
-		cur = cur->next;
-		aim_ssi_item_free(del);
-	}
-
-	curtmp = od->ssi.pending;
-	while (curtmp) {
-		deltmp = curtmp;
-		curtmp = curtmp->next;
-		g_free(deltmp);
-	}
-
-	od->ssi.numitems = 0;
-	od->ssi.official.data = NULL;
-	od->ssi.local.data = NULL;
-	od->ssi.pending = NULL;
-	od->ssi.timestamp = (time_t)0;
-}
-
-/**
- * Look up the given TLV type in the item's data.  If the value of
- * the TLV is not a valid UTF-8 string then use purple_utf8_salvage()
- * to replace invalid bytes with question marks.
- */
-static void cleanlist_ensure_utf8_data(struct aim_ssi_item *item, guint16 tlvtype)
-{
-	aim_tlv_t *tlv;
-	gchar *value, *salvaged;
-
-	tlv = aim_tlv_gettlv(item->data, tlvtype, 1);
-	if (tlv && tlv->length && !g_utf8_validate((const gchar *)tlv->value, tlv->length, NULL)) {
-		purple_debug_warning("oscar", "cleanlist found invalid UTF-8 "
-				"for 0x%04hx field of 0x%04hx item with name %s.  "
-				"Attempting to repair.\n",
-				tlvtype, item->type, item->name ? item->name : "(null)");
-		value = g_strndup((const gchar *)tlv->value, tlv->length);
-		salvaged = purple_utf8_salvage(value);
-		g_free(value);
-		if (*salvaged)
-			aim_tlvlist_replace_str(&item->data, tlvtype, salvaged);
-		else
-			aim_tlvlist_remove(&item->data, tlvtype);
-		g_free(salvaged);
-	}
-}
-
-/**
- * This "cleans" the ssi list.  It does things like:
- * - Makes sure all buddies, permits, and denies have names
- * - Makes sure all buddies are in a group that exist
- * - Makes sure strings are valid UTF-8
- *
- * @param od The oscar odion.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-static int aim_ssi_cleanlist(OscarData *od)
-{
-	struct aim_ssi_item *cur, *next;
-
-	if (!od)
-		return -EINVAL;
-
-	/* Delete any buddies, permits, or denies with empty names. */
-	/* If there are any buddies directly in the master group, add them to a real group. */
-	/* DESTROY any buddies that are directly in the master group. */
-	/* Do the same for buddies that are in a non-existant group. */
-	/* This will kind of mess up if you hit the item limit, but this function isn't too critical */
-	cur = od->ssi.local.data;
-	while (cur) {
-		next = cur->next;
-		if (!cur->name) {
-			if (cur->type == AIM_SSI_TYPE_BUDDY)
-				aim_ssi_delbuddy(od, NULL, NULL);
-			else if (cur->type == AIM_SSI_TYPE_PERMIT || cur->type == AIM_SSI_TYPE_DENY || cur->type == AIM_SSI_TYPE_ICQDENY)
-				aim_ssi_del_from_private_list(od, NULL, cur->type);
-		} else if ((cur->type == AIM_SSI_TYPE_BUDDY) && ((cur->gid == 0x0000) || (!aim_ssi_itemlist_find(&od->ssi.local, cur->gid, 0x0000)))) {
-			char *alias = aim_ssi_getalias(&od->ssi.local, NULL, cur->name);
-			aim_ssi_addbuddy(od, cur->name, PURPLE_BLIST_DEFAULT_GROUP_NAME,
-				NULL, alias, NULL, NULL, FALSE);
-			aim_ssi_delbuddy(od, cur->name, NULL);
-			g_free(alias);
-		}
-		cur = next;
-	}
-
-	cur = od->ssi.local.data;
-	while (cur) {
-		if ((cur->type == AIM_SSI_TYPE_BUDDY) || (cur->type == AIM_SSI_TYPE_PERMIT) || (cur->type == AIM_SSI_TYPE_DENY))
-		{
-			struct aim_ssi_item *cur2, *next2;
-
-			/* Make sure there aren't any duplicate permits or denies, or
-			   duplicate buddies within a group */
-			cur2 = cur->next;
-			while (cur2) {
-				next2 = cur2->next;
-				if (cur->type == cur2->type
-						&& cur->gid == cur2->gid
-						&& cur->name
-						&& cur2->name
-						&& !oscar_util_name_compare(cur->name, cur2->name))
-				{
-					aim_ssi_itemlist_del(&od->ssi.local, cur2);
-				}
-				cur2 = next2;
-			}
-
-			/* Make sure alias is valid UTF-8 */
-			cleanlist_ensure_utf8_data(cur, 0x0131);
-
-			/* Make sure comment is valid UTF-8 */
-			cleanlist_ensure_utf8_data(cur, 0x013c);
-		}
-		cur = cur->next;
-	}
-
-	/* If we've made any changes then sync our list with the server's */
-	return aim_ssi_sync(od);
-}
-
-/**
- * Add a buddy to the list.
- *
- * @param od The oscar odion.
- * @param name The name of the item.
- * @param group The group of the item.
- * @param data A TLV list to use as the additional data for this item.
- * @param alias The alias/nickname of the item, or NULL.
- * @param comment The buddy comment for the item, or NULL.
- * @param smsnum The locally assigned SMS number, or NULL.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_addbuddy(OscarData *od, const char *name, const char *group, GSList *data, const char *alias, const char *comment, const char *smsnum, gboolean needauth)
-{
-	struct aim_ssi_item *parent;
-
-	if (!od || !name || !group)
-		return -EINVAL;
-
-	/* Find the parent */
-	if (!(parent = aim_ssi_itemlist_finditem(&od->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP))) {
-		/* Find the parent's parent (the master group) */
-		if (aim_ssi_itemlist_find(&od->ssi.local, 0x0000, 0x0000) == NULL)
-			aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL);
-
-		/* Add the parent */
-		parent = aim_ssi_itemlist_add(&od->ssi.local, group, 0xFFFF, 0x0000, AIM_SSI_TYPE_GROUP, NULL);
-
-		/* Modify the parent's parent (the master group) */
-		aim_ssi_itemlist_rebuildgroup(&od->ssi.local, NULL);
-	}
-
-	/* Create a TLV list for the new buddy */
-	if (needauth)
-		aim_tlvlist_add_noval(&data, 0x0066);
-	if (alias != NULL)
-		aim_tlvlist_add_str(&data, 0x0131, alias);
-	if (smsnum != NULL)
-		aim_tlvlist_add_str(&data, 0x013a, smsnum);
-	if (comment != NULL)
-		aim_tlvlist_add_str(&data, 0x013c, comment);
-
-	/* Add that bad boy */
-	aim_ssi_itemlist_add(&od->ssi.local, name, parent->gid, 0xFFFF, AIM_SSI_TYPE_BUDDY, data);
-	aim_tlvlist_free(data);
-
-	/* Modify the parent group */
-	aim_ssi_itemlist_rebuildgroup(&od->ssi.local, group);
-
-	/* Sync our local list with the server list */
-	return aim_ssi_sync(od);
-}
-
-int
-aim_ssi_add_to_private_list(OscarData *od, const char* name, guint16 list_type)
-{
-	if (!od || !name || !od->ssi.received_data)
-		return -EINVAL;
-
-	if (aim_ssi_itemlist_find(&od->ssi.local, 0x0000, 0x0000) == NULL)
-		aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL);
-
-	aim_ssi_itemlist_add(&od->ssi.local, name, 0x0000, 0xFFFF, list_type, NULL);
-	return aim_ssi_sync(od);
-}
-
-int
-aim_ssi_del_from_private_list(OscarData* od, const char* name, guint16 list_type)
-{
-	struct aim_ssi_item *del;
-
-	if (!od)
-		return -EINVAL;
-
-	if (!(del = aim_ssi_itemlist_finditem(&od->ssi.local, NULL, name, list_type)))
-		return -EINVAL;
-
-	aim_ssi_itemlist_del(&od->ssi.local, del);
-	return aim_ssi_sync(od);
-}
-
-/**
- * Deletes a buddy from the list.
- *
- * @param od The oscar odion.
- * @param name The name of the item, or NULL.
- * @param group The group of the item, or NULL.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_delbuddy(OscarData *od, const char *name, const char *group)
-{
-	struct aim_ssi_item *del;
-
-	if (!od)
-		return -EINVAL;
-
-	/* Find the buddy */
-	if (!(del = aim_ssi_itemlist_finditem(&od->ssi.local, group, name, AIM_SSI_TYPE_BUDDY)))
-		return -EINVAL;
-
-	/* Remove the item from the list */
-	aim_ssi_itemlist_del(&od->ssi.local, del);
-
-	/* Modify the parent group */
-	aim_ssi_itemlist_rebuildgroup(&od->ssi.local, group);
-
-	/* Sync our local list with the server list */
-	return aim_ssi_sync(od);
-}
-
-/**
- * Deletes a group from the list.
- *
- * @param od The oscar odion.
- * @param group The name of the group.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_delgroup(OscarData *od, const char *group)
-{
-	struct aim_ssi_item *del;
-	aim_tlv_t *tlv;
-
-	if (!od)
-		return -EINVAL;
-
-	/* Find the group */
-	if (!(del = aim_ssi_itemlist_finditem(&od->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP)))
-		return -EINVAL;
-
-	/* Don't delete the group if it's not empty */
-	tlv = aim_tlv_gettlv(del->data, 0x00c8, 1);
-	if (tlv && tlv->length > 0)
-		return -EINVAL;
-
-	/* Remove the item from the list */
-	aim_ssi_itemlist_del(&od->ssi.local, del);
-
-	/* Modify the parent group */
-	aim_ssi_itemlist_rebuildgroup(&od->ssi.local, NULL);
-
-	/* Sync our local list with the server list */
-	return aim_ssi_sync(od);
-}
-
-/**
- * Move a buddy from one group to another group.  This basically just deletes the
- * buddy and re-adds it.
- *
- * @param od The oscar odion.
- * @param oldgn The group that the buddy is currently in.
- * @param newgn The group that the buddy should be moved in to.
- * @param bn The name of the buddy to be moved.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_movebuddy(OscarData *od, const char *oldgn, const char *newgn, const char *bn)
-{
-	struct aim_ssi_item *buddy;
-	GSList *data;
-
-	/* Find the buddy */
-	buddy = aim_ssi_itemlist_finditem(&od->ssi.local, oldgn, bn, AIM_SSI_TYPE_BUDDY);
-	if (buddy == NULL)
-		return -EINVAL;
-
-	/* Make a copy of the buddy's TLV list */
-	data = aim_tlvlist_copy(buddy->data);
-
-	/* Delete the old item */
-	aim_ssi_delbuddy(od, bn, oldgn);
-
-	/* Add the new item using the EXACT SAME TLV list */
-	aim_ssi_addbuddy(od, bn, newgn, data, NULL, NULL, NULL, FALSE);
-
-	return 0;
-}
-
-/**
- * Change the alias stored on the server for a given buddy.
- *
- * @param od The oscar odion.
- * @param gn The group that the buddy is currently in.
- * @param bn The name of the buddy.
- * @param alias The new alias for the buddy, or NULL if you want to remove
- *        a buddy's comment.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_aliasbuddy(OscarData *od, const char *gn, const char *bn, const char *alias)
-{
-	struct aim_ssi_item *tmp;
-
-	if (!od || !gn || !bn)
-		return -EINVAL;
-
-	if (!(tmp = aim_ssi_itemlist_finditem(&od->ssi.local, gn, bn, AIM_SSI_TYPE_BUDDY)))
-		return -EINVAL;
-
-	/* Either add or remove the 0x0131 TLV from the TLV chain */
-	if (alias && *alias)
-		aim_tlvlist_replace_str(&tmp->data, 0x0131, alias);
-	else
-		aim_tlvlist_remove(&tmp->data, 0x0131);
-
-	/* Sync our local list with the server list */
-	return aim_ssi_sync(od);
-}
-
-/**
- * Change the comment stored on the server for a given buddy.
- *
- * @param od The oscar odion.
- * @param gn The group that the buddy is currently in.
- * @param bn The name of the buddy.
- * @param alias The new comment for the buddy, or NULL if you want to remove
- *        a buddy's comment.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_editcomment(OscarData *od, const char *gn, const char *bn, const char *comment)
-{
-	struct aim_ssi_item *tmp;
-
-	if (!od || !gn || !bn)
-		return -EINVAL;
-
-	if (!(tmp = aim_ssi_itemlist_finditem(&od->ssi.local, gn, bn, AIM_SSI_TYPE_BUDDY)))
-		return -EINVAL;
-
-	/* Either add or remove the 0x0131 TLV from the TLV chain */
-	if (comment && *comment)
-		aim_tlvlist_replace_str(&tmp->data, 0x013c, comment);
-	else
-		aim_tlvlist_remove(&tmp->data, 0x013c);
-
-	/* Sync our local list with the server list */
-	return aim_ssi_sync(od);
-}
-
-/**
- * Rename a group.
- *
- * @param od The oscar odion.
- * @param oldgn The old group name.
- * @param newgn The new group name.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_rename_group(OscarData *od, const char *oldgn, const char *newgn)
-{
-	struct aim_ssi_item *group;
-
-	if (!od || !oldgn || !newgn)
-		return -EINVAL;
-
-	if (!(group = aim_ssi_itemlist_finditem(&od->ssi.local, oldgn, NULL, AIM_SSI_TYPE_GROUP)))
-		return -EINVAL;
-
-	aim_ssi_item_set_name(&od->ssi.local, group, newgn);
-
-	/* Sync our local list with the server list */
-	return aim_ssi_sync(od);
-}
-
-/**
- * Stores your permit/deny setting on the server, and starts using it.
- *
- * @param od The oscar odion.
- * @param permdeny Your permit/deny setting. For ICQ accounts, it actually affects your visibility
- *        and has nothing to do with blocking. Can be one of the following:
- *        1 - Allow all users
- *        2 - Block all users
- *        3 - Allow only the users below
- *        4 - Block only the users below
- *        5 - Allow only users on my buddy list
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_setpermdeny(OscarData *od, guint8 permdeny)
-{
-	struct aim_ssi_item *tmp;
-
-	if (!od || !od->ssi.received_data)
-		return -EINVAL;
-
-	/* Find the PDINFO item, or add it if it does not exist */
-	if (!(tmp = aim_ssi_itemlist_finditem(&od->ssi.local, NULL, NULL, AIM_SSI_TYPE_PDINFO))) {
-		/* Make sure the master group exists */
-		if (aim_ssi_itemlist_find(&od->ssi.local, 0x0000, 0x0000) == NULL)
-			aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL);
-
-		tmp = aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PDINFO, NULL);
-	}
-
-	/* Need to add the 0x00ca TLV to the TLV chain */
-	aim_tlvlist_replace_8(&tmp->data, 0x00ca, permdeny);
-
-	/* Sync our local list with the server list */
-	return aim_ssi_sync(od);
-}
-
-/**
- * Set buddy icon information
- *
- * @param od The oscar odion.
- * @param iconcsum The MD5 checksum of the icon you are using.
- * @param iconcsumlen Length of the MD5 checksum given above.  Should be 0x10 bytes.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_seticon(OscarData *od, const guint8 *iconsum, guint8 iconsumlen)
-{
-	struct aim_ssi_item *tmp;
-	guint8 *csumdata;
-
-	if (!od || !iconsum || !iconsumlen || !od->ssi.received_data)
-		return -EINVAL;
-
-	/* Find the ICONINFO item, or add it if it does not exist */
-	if (!(tmp = aim_ssi_itemlist_finditem(&od->ssi.local, NULL, "1", AIM_SSI_TYPE_ICONINFO))) {
-		/* Make sure the master group exists */
-		if (aim_ssi_itemlist_find(&od->ssi.local, 0x0000, 0x0000) == NULL)
-			aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL);
-
-		tmp = aim_ssi_itemlist_add(&od->ssi.local, "1", 0x0000, 0xFFFF, AIM_SSI_TYPE_ICONINFO, NULL);
-	}
-
-	/* Need to add the 0x00d5 TLV to the TLV chain */
-	csumdata = (guint8 *)g_malloc((iconsumlen+2)*sizeof(guint8));
-	(void)aimutil_put8(&csumdata[0], 0x00);
-	(void)aimutil_put8(&csumdata[1], iconsumlen);
-	memcpy(&csumdata[2], iconsum, iconsumlen);
-	aim_tlvlist_replace_raw(&tmp->data, 0x00d5, (iconsumlen+2) * sizeof(guint8), csumdata);
-	g_free(csumdata);
-
-	/* Need to add the 0x0131 TLV to the TLV chain, used to cache the icon */
-	aim_tlvlist_replace_noval(&tmp->data, 0x0131);
-
-	/* Sync our local list with the server list */
-	aim_ssi_sync(od);
-	return 0;
-}
-
-/**
- * Remove a reference to a server stored buddy icon.  This will make your
- * icon stop showing up to other people.
- *
- * Really this function just sets the icon to a dummy value.  It's weird...
- * but I think the dummy value basically means "I don't have an icon!"
- *
- * @param od The oscar session.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_delicon(OscarData *od)
-{
-	const guint8 csumdata[] = {0x02, 0x01, 0xd2, 0x04, 0x72};
-
-	return aim_ssi_seticon(od, csumdata, 5);
-}
-
-/**
- * Stores your setting for various SSI settings.  Whether you
- * should show up as idle or not, etc.
- *
- * @param od The oscar odion.
- * @param presence A bitmask of the first 32 entries [0-31] from
- *        http://dev.aol.com/aim/oscar/#FEEDBAG__BUDDY_PREFS
- *        0x00000002 - Hide "eBuddy group" (whatever that is)
- *        0x00000400 - Allow others to see your idle time
- *        0x00020000 - Don't show Recent Buddies
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_setpresence(OscarData *od, guint32 presence) {
-	struct aim_ssi_item *tmp;
-
-	if (!od || !od->ssi.received_data)
-		return -EINVAL;
-
-	/* Find the PRESENCEPREFS item, or add it if it does not exist */
-	if (!(tmp = aim_ssi_itemlist_finditem(&od->ssi.local, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS))) {
-		/* Make sure the master group exists */
-		if (aim_ssi_itemlist_find(&od->ssi.local, 0x0000, 0x0000) == NULL)
-			aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL);
-
-		tmp = aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PRESENCEPREFS, NULL);
-	}
-
-	/* Need to add the x00c9 TLV to the TLV chain */
-	aim_tlvlist_replace_32(&tmp->data, 0x00c9, presence);
-
-	/* Sync our local list with the server list */
-	return aim_ssi_sync(od);
-}
-
-/*
- * Subtype 0x0002 - Request SSI Rights.
- */
-int aim_ssi_reqrights(OscarData *od)
-{
-	FlapConnection *conn;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)))
-		return -EINVAL;
-
-	aim_genericreq_n_snacid(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_REQRIGHTS);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0003 - SSI Rights Information.
- */
-static int parserights(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0, i;
-	aim_rxcallback_t userfunc;
-	GSList *tlvlist;
-	aim_tlv_t *tlv;
-	ByteStream bstream;
-	guint16 *maxitems;
-
-	/* This SNAC is made up of a bunch of TLVs */
-	tlvlist = aim_tlvlist_read(bs);
-
-	/* TLV 0x0004 contains the maximum number of each item */
-	if (!(tlv = aim_tlv_gettlv(tlvlist, 0x0004, 1))) {
-		aim_tlvlist_free(tlvlist);
-		return 0;
-	}
-
-	byte_stream_init(&bstream, tlv->value, tlv->length);
-
-	maxitems = (guint16 *)g_malloc((tlv->length/2)*sizeof(guint16));
-
-	for (i=0; i<(tlv->length/2); i++)
-		maxitems[i] = byte_stream_get16(&bstream);
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, tlv->length/2, maxitems);
-
-	aim_tlvlist_free(tlvlist);
-	g_free(maxitems);
-
-	return ret;
-}
-
-/*
- * Subtype 0x0004 - Request SSI Data when you don't have a timestamp and
- * revision number.
- *
- */
-int aim_ssi_reqdata(OscarData *od)
-{
-	FlapConnection *conn;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)))
-		return -EINVAL;
-
-	/* Free any current data, just in case */
-	aim_ssi_freelist(od);
-
-	aim_genericreq_n_snacid(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_REQDATA);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0006 - SSI Data.
- */
-static int parsedata(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	guint8 fmtver; /* guess */
-	guint16 namelen, gid, bid, type;
-	char *name;
-	GSList *data;
-	GString *debugstr = g_string_new("");
-
-	fmtver = byte_stream_get8(bs); /* Version of ssi data.  Should be 0x00 */
-	od->ssi.numitems += byte_stream_get16(bs); /* # of items in this SSI SNAC */
-
-	/* Read in the list */
-	while (byte_stream_bytes_left(bs) > 4) { /* last four bytes are timestamp */
-		if ((namelen = byte_stream_get16(bs)))
-			name = byte_stream_getstr(bs, namelen);
-		else
-			name = NULL;
-		gid = byte_stream_get16(bs);
-		bid = byte_stream_get16(bs);
-		type = byte_stream_get16(bs);
-		data = aim_tlvlist_readlen(bs, byte_stream_get16(bs));
-		aim_ssi_item_debug_append(debugstr, "\t", aim_ssi_itemlist_add(&od->ssi.official, name, gid, bid, type, data));
-		g_free(name);
-		aim_tlvlist_free(data);
-	}
-	purple_debug_misc("oscar", "Reading items from tlvlist for account %s:\n%s",
-		purple_account_get_username(purple_connection_get_account(od->gc)), debugstr->str);
-	g_string_free(debugstr, TRUE);
-
-	/* Read in the timestamp */
-	od->ssi.timestamp = byte_stream_get32(bs);
-
-	if (!(snac->flags & 0x0001)) {
-		/* Make a copy of the list */
-		struct aim_ssi_item *cur;
-		for (cur=od->ssi.official.data; cur; cur=cur->next)
-			aim_ssi_itemlist_add(&od->ssi.local, cur->name, cur->gid, cur->bid, cur->type, cur->data);
-
-		/* Clean the buddy list */
-		aim_ssi_cleanlist(od);
-
-		od->ssi.received_data = TRUE;
-
-		if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-			ret = userfunc(od, conn, frame, fmtver, od->ssi.numitems, od->ssi.timestamp);
-	}
-
-	return ret;
-}
-
-/*
- * Subtype 0x0007 - SSI Activate Data.
- *
- * Should be sent after receiving 13/6 or 13/f to tell the server you
- * are ready to begin using the list.  It will promptly give you the
- * presence information for everyone in your list and put your permit/deny
- * settings into effect.
- *
- */
-int aim_ssi_enable(OscarData *od)
-{
-	FlapConnection *conn;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)))
-		return -EINVAL;
-
-	aim_genericreq_n(od, conn, SNAC_FAMILY_FEEDBAG, 0x0007);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0008/0x0009/0x000a - SSI Add/Mod/Del Item(s).
- *
- * Sends the SNAC to add, modify, or delete items from the server-stored
- * information.  These 3 SNACs all have an identical structure.  The only
- * difference is the subtype that is set for the SNAC.
- *
- */
-static int aim_ssi_addmoddel(OscarData *od)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	int bslen;
-	struct aim_ssi_tmp *cur;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)) || !od->ssi.pending || !od->ssi.pending->item)
-		return -EINVAL;
-
-	/* Calculate total SNAC size */
-	bslen = 0;
-	for (cur=od->ssi.pending; cur; cur=cur->next) {
-		bslen += 10; /* For length, GID, BID, type, and length */
-		if (cur->item->name)
-			bslen += strlen(cur->item->name);
-		if (cur->item->data)
-			bslen += aim_tlvlist_size(cur->item->data);
-	}
-
-	byte_stream_new(&bs, bslen);
-
-	for (cur=od->ssi.pending; cur; cur=cur->next) {
-		byte_stream_put16(&bs, cur->item->name ? strlen(cur->item->name) : 0);
-		if (cur->item->name)
-			byte_stream_putstr(&bs, cur->item->name);
-		byte_stream_put16(&bs, cur->item->gid);
-		byte_stream_put16(&bs, cur->item->bid);
-		byte_stream_put16(&bs, cur->item->type);
-		byte_stream_put16(&bs, cur->item->data ? aim_tlvlist_size(cur->item->data) : 0);
-		if (cur->item->data)
-			aim_tlvlist_write(&bs, &cur->item->data);
-	}
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, od->ssi.pending->action, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, od->ssi.pending->action, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0008 - Incoming SSI add.
- *
- * Sent by the server, for example, when someone is added to
- * your "Recent Buddies" group.
- */
-static int parseadd(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	char *name;
-	guint16 len, gid, bid, type;
-	GSList *data;
-
-	while (byte_stream_bytes_left(bs)) {
-		if ((len = byte_stream_get16(bs)))
-			name = byte_stream_getstr(bs, len);
-		else
-			name = NULL;
-		gid = byte_stream_get16(bs);
-		bid = byte_stream_get16(bs);
-		type = byte_stream_get16(bs);
-		if ((len = byte_stream_get16(bs)))
-			data = aim_tlvlist_readlen(bs, len);
-		else
-			data = NULL;
-
-		aim_ssi_itemlist_add(&od->ssi.local, name, gid, bid, type, data);
-		aim_ssi_itemlist_add(&od->ssi.official, name, gid, bid, type, data);
-		aim_tlvlist_free(data);
-
-		if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-			ret = userfunc(od, conn, frame, snac->subtype, type, name);
-
-		g_free(name);
-	}
-
-	return ret;
-}
-
-/*
- * Subtype 0x0009 - Incoming SSI mod.
- */
-static int parsemod(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	char *name;
-	guint16 len, gid, bid, type;
-	GSList *data;
-	struct aim_ssi_item *item;
-
-	while (byte_stream_bytes_left(bs)) {
-		if ((len = byte_stream_get16(bs)))
-			name = byte_stream_getstr(bs, len);
-		else
-			name = NULL;
-		gid = byte_stream_get16(bs);
-		bid = byte_stream_get16(bs);
-		type = byte_stream_get16(bs);
-		if ((len = byte_stream_get16(bs)))
-			data = aim_tlvlist_readlen(bs, len);
-		else
-			data = NULL;
-
-		/* Replace the 2 local items with the given one */
-		if ((item = aim_ssi_itemlist_find(&od->ssi.local, gid, bid))) {
-			item->type = type;
-			aim_ssi_item_set_name(&od->ssi.local, item, name);
-			aim_tlvlist_free(item->data);
-			item->data = aim_tlvlist_copy(data);
-		}
-
-		if ((item = aim_ssi_itemlist_find(&od->ssi.official, gid, bid))) {
-			item->type = type;
-			aim_ssi_item_set_name(&od->ssi.official, item, name);
-			aim_tlvlist_free(item->data);
-			item->data = aim_tlvlist_copy(data);
-		}
-
-		if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-			ret = userfunc(od, conn, frame, snac->subtype, type, name);
-
-		g_free(name);
-		aim_tlvlist_free(data);
-	}
-
-	return ret;
-}
-
-/*
- * Subtype 0x000a - Incoming SSI del.
- *
- * XXX - It would probably be good for the client to actually do something when it gets this.
- */
-static int parsedel(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	guint16 gid, bid;
-	struct aim_ssi_item *del;
-
-	while (byte_stream_bytes_left(bs)) {
-		byte_stream_advance(bs, byte_stream_get16(bs));
-		gid = byte_stream_get16(bs);
-		bid = byte_stream_get16(bs);
-		byte_stream_get16(bs);
-		byte_stream_advance(bs, byte_stream_get16(bs));
-
-		if ((del = aim_ssi_itemlist_find(&od->ssi.local, gid, bid)))
-			aim_ssi_itemlist_del(&od->ssi.local, del);
-		if ((del = aim_ssi_itemlist_find(&od->ssi.official, gid, bid)))
-			aim_ssi_itemlist_del(&od->ssi.official, del);
-
-		if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-			ret = userfunc(od, conn, frame);
-	}
-
-	return ret;
-}
-
-/*
- * Subtype 0x000e - SSI Add/Mod/Del Ack.
- *
- * Response to add, modify, or delete SNAC (sent with aim_ssi_addmoddel).
- *
- */
-static int parseack(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	struct aim_ssi_tmp *cur, *del;
-
-	/* Read in the success/failure flags from the ack SNAC */
-	cur = od->ssi.pending;
-	while (cur && (byte_stream_bytes_left(bs)>0)) {
-		cur->ack = byte_stream_get16(bs);
-		cur = cur->next;
-	}
-
-	/*
-	 * If outcome is 0, then add the item to the item list, or replace the other item,
-	 * or remove the old item.  If outcome is non-zero, then remove the item from the
-	 * local list, or unmodify it, or add it.
-	 */
-	for (cur=od->ssi.pending; (cur && (cur->ack != 0xffff)); cur=cur->next) {
-	if (cur->item) {
-		if (cur->ack) {
-			/* Our action was unsuccessful, so change the local list back to how it was */
-			if (cur->action == SNAC_SUBTYPE_FEEDBAG_ADD) {
-				/* Remove the item from the local list */
-				/* Make sure cur->item is still valid memory */
-				/* TODO: "Still valid memory"?  That's bad form. */
-				if (aim_ssi_itemlist_valid(&od->ssi.local, cur->item)) {
-					cur->name = g_strdup(cur->item->name);
-					aim_ssi_itemlist_del(&od->ssi.local, cur->item);
-				}
-				cur->item = NULL;
-
-			} else if (cur->action == SNAC_SUBTYPE_FEEDBAG_MOD) {
-				/* Replace the local item with the item from the official list */
-				if (aim_ssi_itemlist_valid(&od->ssi.local, cur->item)) {
-					struct aim_ssi_item *cur1;
-					if ((cur1 = aim_ssi_itemlist_find(&od->ssi.official, cur->item->gid, cur->item->bid))) {
-						aim_ssi_item_set_name(&od->ssi.official, cur->item, cur1->name);
-						aim_tlvlist_free(cur->item->data);
-						cur->item->data = aim_tlvlist_copy(cur1->data);
-					}
-				} else
-					cur->item = NULL;
-
-			} else if (cur->action == SNAC_SUBTYPE_FEEDBAG_DEL) {
-				/* Add the item back into the local list */
-				if (aim_ssi_itemlist_valid(&od->ssi.official, cur->item)) {
-					aim_ssi_itemlist_add(&od->ssi.local, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data);
-				} else
-					cur->item = NULL;
-			}
-
-		} else {
-			/* Do the exact opposite */
-			if (cur->action == SNAC_SUBTYPE_FEEDBAG_ADD) {
-			/* Add the local item to the official list */
-				if (aim_ssi_itemlist_valid(&od->ssi.local, cur->item)) {
-					aim_ssi_itemlist_add(&od->ssi.official, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data);
-				} else
-					cur->item = NULL;
-
-			} else if (cur->action == SNAC_SUBTYPE_FEEDBAG_MOD) {
-				/* Replace the official item with the item from the local list */
-				if (aim_ssi_itemlist_valid(&od->ssi.local, cur->item)) {
-					struct aim_ssi_item *cur1;
-					if ((cur1 = aim_ssi_itemlist_find(&od->ssi.official, cur->item->gid, cur->item->bid))) {
-						aim_ssi_item_set_name(&od->ssi.official, cur1, cur->item->name);
-						aim_tlvlist_free(cur1->data);
-						cur1->data = aim_tlvlist_copy(cur->item->data);
-					}
-				} else
-					cur->item = NULL;
-
-			} else if (cur->action == SNAC_SUBTYPE_FEEDBAG_DEL) {
-				/* Remove the item from the official list */
-				if (aim_ssi_itemlist_valid(&od->ssi.official, cur->item))
-					aim_ssi_itemlist_del(&od->ssi.official, cur->item);
-				cur->item = NULL;
-			}
-
-		}
-	} /* End if (cur->item) */
-	} /* End for loop */
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, od->ssi.pending);
-
-	/* Free all aim_ssi_tmp's with an outcome */
-	cur = od->ssi.pending;
-	while (cur && (cur->ack != 0xffff)) {
-		del = cur;
-		cur = cur->next;
-		g_free(del->name);
-		g_free(del);
-	}
-	od->ssi.pending = cur;
-
-	/* If we're not waiting for any more acks, then send more SNACs */
-	if (!od->ssi.pending) {
-		od->ssi.waiting_for_ack = FALSE;
-		aim_ssi_sync(od);
-	}
-
-	return ret;
-}
-
-/*
- * Subtype 0x000f - SSI Data Unchanged.
- *
- * Response to aim_ssi_reqifchanged() if the server-side data is not newer than
- * posted local stamp/revision.
- *
- */
-static int parsedataunchanged(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-
-	od->ssi.received_data = TRUE;
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame);
-
-	return ret;
-}
-
-/*
- * Subtype 0x0011 - SSI Begin Data Modification.
- *
- * Tell the server you're going to start modifying data.  This marks
- * the beginning of a transaction.
- */
-int aim_ssi_modbegin(OscarData *od)
-{
-	FlapConnection *conn;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)))
-		return -EINVAL;
-
-	aim_genericreq_n(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_EDITSTART);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0012 - SSI End Data Modification.
- *
- * Tell the server you're finished modifying data.  The marks the end
- * of a transaction.
- */
-int aim_ssi_modend(OscarData *od)
-{
-	FlapConnection *conn;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)))
-		return -EINVAL;
-
-	aim_genericreq_n(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_EDITSTOP);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0015 - Receive an authorization grant
- */
-static int receiveauthgrant(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	guint16 tmp;
-	char *bn, *msg, *tmpstr;
-
-	/* Read buddy name */
-	tmp = byte_stream_get8(bs);
-	if (!tmp) {
-		purple_debug_warning("oscar", "Dropping auth grant SNAC "
-				"because username was empty\n");
-		return 0;
-	}
-	bn = byte_stream_getstr(bs, tmp);
-	if (!g_utf8_validate(bn, -1, NULL)) {
-		purple_debug_warning("oscar", "Dropping auth grant SNAC "
-				"because the username was not valid UTF-8\n");
-		g_free(bn);
-		return 0;
-	}
-
-	/* Read message */
-	tmp = byte_stream_get16(bs);
-	if (tmp) {
-		msg = byte_stream_getstr(bs, tmp);
-		if (!g_utf8_validate(msg, -1, NULL)) {
-			/* Ugh, msg isn't UTF8.  Let's salvage. */
-			purple_debug_warning("oscar", "Got non-UTF8 message in auth "
-					"grant from %s\n", bn);
-			tmpstr = purple_utf8_salvage(msg);
-			g_free(msg);
-			msg = tmpstr;
-		}
-	} else
-		msg = NULL;
-
-	/* Unknown */
-	tmp = byte_stream_get16(bs);
-	if (!tmp)
-		purple_debug_warning("oscar", "unknown field missing");
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, bn, msg);
-
-	g_free(bn);
-	g_free(msg);
-
-	return ret;
-}
-
-/*
- * Subtype 0x0018 - Send authorization request
- *
- * Sends a request for authorization to the given contact.  The request will either be
- * granted, denied, or dropped.
- *
- */
-int aim_ssi_sendauthrequest(OscarData *od, const char *bn, const char *msg)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)) || !bn)
-		return -EINVAL;
-
-	byte_stream_new(&bs, 1+strlen(bn) + 2+(msg ? strlen(msg)+1 : 0) + 2);
-
-	/* Username */
-	byte_stream_put8(&bs, strlen(bn));
-	byte_stream_putstr(&bs, bn);
-
-	/* Message (null terminated) */
-	byte_stream_put16(&bs, msg ? strlen(msg) : 0);
-	if (msg) {
-		byte_stream_putstr(&bs, msg);
-		byte_stream_put8(&bs, 0x00);
-	}
-
-	/* Unknown */
-	byte_stream_put16(&bs, 0x0000);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREQ, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREQ, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0019 - Receive an authorization request
- */
-static int receiveauthrequest(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	guint16 tmp;
-	char *bn, *msg, *tmpstr;
-
-	/* Read buddy name */
-	tmp = byte_stream_get8(bs);
-	if (!tmp) {
-		purple_debug_warning("oscar", "Dropping auth request SNAC "
-				"because username was empty\n");
-		return 0;
-	}
-	bn = byte_stream_getstr(bs, tmp);
-	if (!g_utf8_validate(bn, -1, NULL)) {
-		purple_debug_warning("oscar", "Dropping auth request SNAC "
-				"because the username was not valid UTF-8\n");
-		g_free(bn);
-		return 0;
-	}
-
-	/* Read message */
-	tmp = byte_stream_get16(bs);
-	if (tmp) {
-		msg = byte_stream_getstr(bs, tmp);
-		if (!g_utf8_validate(msg, -1, NULL)) {
-			/* Ugh, msg isn't UTF8.  Let's salvage. */
-			purple_debug_warning("oscar", "Got non-UTF8 message in auth "
-					"request from %s\n", bn);
-			tmpstr = purple_utf8_salvage(msg);
-			g_free(msg);
-			msg = tmpstr;
-		}
-	} else
-		msg = NULL;
-
-	/* Unknown */
-	tmp = byte_stream_get16(bs);
-	if (!tmp)
-		purple_debug_warning("oscar", "unknown field missing");
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, bn, msg);
-
-	g_free(bn);
-	g_free(msg);
-
-	return ret;
-}
-
-/*
- * Subtype 0x001a - Send authorization reply
- *
- * Sends a reply to a request for authorization.  The reply can either
- * grant authorization or deny authorization.
- *
- * if reply=0x00 then deny
- * if reply=0x01 then grant
- *
- */
-int aim_ssi_sendauthreply(OscarData *od, const char *bn, guint8 reply, const char *msg)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)) || !bn)
-		return -EINVAL;
-
-	byte_stream_new(&bs, 1+strlen(bn) + 1 + 2+(msg ? (strlen(msg)+1) : 0) + 2);
-
-	/* Username */
-	byte_stream_put8(&bs, strlen(bn));
-	byte_stream_putstr(&bs, bn);
-
-	/* Grant or deny */
-	byte_stream_put8(&bs, reply);
-
-	/* Message (null terminated) */
-	byte_stream_put16(&bs, msg ? (strlen(msg)+1) : 0);
-	if (msg) {
-		byte_stream_putstr(&bs, msg);
-		byte_stream_put8(&bs, 0x00);
-	}
-
-	/* Unknown */
-	byte_stream_put16(&bs, 0x0000);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREP, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREP, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/*
- * Subtype 0x001b - Receive an authorization reply
- *
- * You get this bad boy when other people respond to the authorization
- * request that you have previously sent them.
- */
-static int receiveauthreply(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	guint16 tmp;
-	guint8 reply;
-	char *bn, *msg, *tmpstr;
-
-	/* Read buddy name */
-	tmp = byte_stream_get8(bs);
-	if (!tmp) {
-		purple_debug_warning("oscar", "Dropping auth reply SNAC "
-				"because username was empty\n");
-		return 0;
-	}
-	bn = byte_stream_getstr(bs, tmp);
-	if (!g_utf8_validate(bn, -1, NULL)) {
-		purple_debug_warning("oscar", "Dropping auth reply SNAC "
-				"because the username was not valid UTF-8\n");
-		g_free(bn);
-		return 0;
-	}
-
-	/* Read reply */
-	reply = byte_stream_get8(bs);
-
-	/* Read message */
-	tmp = byte_stream_get16(bs);
-	if (tmp) {
-		msg = byte_stream_getstr(bs, tmp);
-		if (!g_utf8_validate(msg, -1, NULL)) {
-			/* Ugh, msg isn't UTF8.  Let's salvage. */
-			purple_debug_warning("oscar", "Got non-UTF8 message in auth "
-					"reply from %s\n", bn);
-			tmpstr = purple_utf8_salvage(msg);
-			g_free(msg);
-			msg = tmpstr;
-		}
-	} else
-		msg = NULL;
-
-	/* Unknown */
-	tmp = byte_stream_get16(bs);
-	if (!tmp)
-		purple_debug_warning("oscar", "unknown field missing");
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, bn, reply, msg);
-
-	g_free(bn);
-	g_free(msg);
-
-	return ret;
-}
-
-/*
- * Subtype 0x001c - Receive a message telling you someone added you to their list.
- */
-static int receiveadded(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	guint16 tmp;
-	char *bn;
-
-	/* Read buddy name */
-	tmp = byte_stream_get8(bs);
-	if (!tmp) {
-		purple_debug_warning("oscar", "Dropping 'you were added' SNAC "
-				"because username was empty\n");
-		return 0;
-	}
-	bn = byte_stream_getstr(bs, tmp);
-	if (!g_utf8_validate(bn, -1, NULL)) {
-		purple_debug_warning("oscar", "Dropping 'you were added' SNAC "
-				"because the username was not valid UTF-8\n");
-		g_free(bn);
-		return 0;
-	}
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, bn);
-
-	g_free(bn);
-
-	return ret;
-}
-
-/*
- * If we're on ICQ, then AIM_SSI_TYPE_DENY is used for the "permanently invisible" list.
- * AIM_SSI_TYPE_ICQDENY is used for blocking users instead.
- */
-guint16
-aim_ssi_getdenyentrytype(OscarData* od)
-{
-	return od->icq ? AIM_SSI_TYPE_ICQDENY : AIM_SSI_TYPE_DENY;
-}
-
-static int
-snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_RIGHTSINFO)
-		return parserights(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_LIST)
-		return parsedata(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_ADD)
-		return parseadd(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_MOD)
-		return parsemod(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_DEL)
-		return parsedel(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_SRVACK)
-		return parseack(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_NOLIST)
-		return parsedataunchanged(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_RECVAUTH)
-		return receiveauthgrant(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_RECVAUTHREQ)
-		return receiveauthrequest(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_RECVAUTHREP)
-		return receiveauthreply(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_ADDED)
-		return receiveadded(od, conn, mod, frame, snac, bs);
-
-	return 0;
-}
-
-static void
-ssi_shutdown(OscarData *od, aim_module_t *mod)
-{
-	aim_ssi_freelist(od);
-}
-
-int
-ssi_modfirst(OscarData *od, aim_module_t *mod)
-{
-	mod->family = SNAC_FAMILY_FEEDBAG;
-	mod->version = 0x0004;
-	mod->toolid = 0x0110;
-	mod->toolversion = 0x0629;
-	mod->flags = 0;
-	strncpy(mod->name, "feedbag", sizeof(mod->name));
-	mod->snachandler = snachandler;
-	mod->shutdown = ssi_shutdown;
-
-	return 0;
-}
--- a/libpurple/protocols/oscar/family_icbm.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2149 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Family 0x0004 - Routines for sending/receiving Instant Messages.
- *
- * Note the term ICBM (Inter-Client Basic Message) which blankets
- * all types of generically routed through-server messages.  Within
- * the ICBM types (family 4), a channel is defined.  Each channel
- * represents a different type of message.  Channel 1 is used for
- * what would commonly be called an "instant message".  Channel 2
- * is used for negotiating "rendezvous".  These transactions end in
- * something more complex happening, such as a chat invitation, or
- * a file transfer.  Channel 3 is used for chat messages (not in
- * the same family as these channels).  Channel 4 is used for
- * various ICQ messages.  Examples are normal messages, URLs, and
- * old-style authorization.
- *
- * In addition to the channel, every ICBM contains a cookie.  For
- * standard IMs, these are only used for error messages.  However,
- * the more complex rendezvous messages make suitably more complex
- * use of this field.
- *
- * TODO: Split this up into an im.c file an an icbm.c file.  It
- *       will be beautiful, you'll see.
- *
- *       Make sure flap_connection_findbygroup is used by all functions.
- */
-
-#include "encoding.h"
-#include "oscar.h"
-#include "peer.h"
-
-#include "util.h"
-
-static const char * const errcodereason[] = {
-	N_("Invalid error"),
-	N_("Not logged in"),
-	N_("Cannot receive IM due to parental controls"),
-	N_("Cannot send SMS without accepting terms"),
-	N_("Cannot send SMS"), /* SMS_WITHOUT_DISCLAIMER is weird */
-	N_("Cannot send SMS to this country"),
-	N_("Unknown error"), /* Undocumented */
-	N_("Unknown error"), /* Undocumented */
-	N_("Cannot send SMS to unknown country"),
-	N_("Bot accounts cannot initiate IMs"),
-	N_("Bot account cannot IM this user"),
-	N_("Bot account reached IM limit"),
-	N_("Bot account reached daily IM limit"),
-	N_("Bot account reached monthly IM limit"),
-	N_("Unable to receive offline messages"),
-	N_("Offline message store full")
-};
-static const int errcodereasonlen = G_N_ELEMENTS(errcodereason);
-
-/**
- * Add a standard ICBM header to the given bstream with the given
- * information.
- *
- * @param bs The bstream to write the ICBM header to.
- * @param c c is for cookie, and cookie is for me.
- * @param channel The ICBM channel (1 through 4).
- * @param bn Null-terminated scrizeen nizame.
- * @return The number of bytes written.  It's really not useful.
- */
-static int aim_im_puticbm(ByteStream *bs, const guchar *c, guint16 channel, const char *bn)
-{
-	byte_stream_putraw(bs, c, 8);
-	byte_stream_put16(bs, channel);
-	byte_stream_put8(bs, strlen(bn));
-	byte_stream_putstr(bs, bn);
-	return 8+2+1+strlen(bn);
-}
-
-/**
- * Generates a random ICBM cookie in a character array of length 8
- * and copies it into the variable passed as cookie
- * TODO: Maybe we should stop limiting our characters to the visible range?
- */
-void aim_icbm_makecookie(guchar *cookie)
-{
-	int i;
-
-	/* Should be like "21CBF95" and null terminated */
-	for (i = 0; i < 7; i++)
-		cookie[i] = 0x30 + ((guchar)g_random_int() % 10);
-	cookie[7] = '\0';
-}
-
-/*
- * Subtype 0x0001 - Error
- */
-static int
-error(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	aim_snac_t *snac2;
-	guint16 reason, errcode = 0;
-	const char *bn;
-	GSList *tlvlist;
-	PurpleConnection *gc = od->gc;
-#ifdef TODOFT
-	PurpleXfer *xfer;
-#endif
-	const char *reason_str;
-	char *buf;
-
-	snac2 = aim_remsnac(od, snac->id);
-	if (!snac2) {
-		purple_debug_misc("oscar", "icbm error: received response from unknown request!\n");
-		return 1;
-	}
-
-	if (snac2->family != SNAC_FAMILY_ICBM) {
-		purple_debug_misc("oscar", "icbm error: received response from invalid request! %d\n", snac2->family);
-		g_free(snac2->data);
-		g_free(snac2);
-		return 1;
-	}
-
-	/* Data is assumed to be the destination bn */
-	bn = snac2->data;
-	if (!bn || bn[0] == '\0') {
-		purple_debug_misc("oscar", "icbm error: received response from request without a buddy name!\n");
-		g_free(snac2->data);
-		g_free(snac2);
-		return 1;
-	}
-
-	reason = byte_stream_get16(bs);
-
-	tlvlist = aim_tlvlist_read(bs);
-	if (aim_tlv_gettlv(tlvlist, 0x0008, 1))
-		errcode = aim_tlv_get16(tlvlist, 0x0008, 1);
-	aim_tlvlist_free(tlvlist);
-
-	purple_debug_error("oscar",
-			   "Message error with bn %s and reason %hu and errcode %hu\n",
-				bn, reason, errcode);
-
-#ifdef TODOFT
-	/* If this was a file transfer request, bn is a cookie */
-	if ((xfer = oscar_find_xfer_by_cookie(od->file_transfers, bn))) {
-		purple_xfer_cancel_remote(xfer);
-		return 1;
-	}
-#endif
-
-	/* Notify the user that the message wasn't delivered */
-	reason_str = oscar_get_msgerr_reason(reason);
-	if (errcode != 0 && errcode < errcodereasonlen)
-		buf = g_strdup_printf(_("Unable to send message: %s (%s)"), reason_str,
-		                      _(errcodereason[errcode]));
-	else
-		buf = g_strdup_printf(_("Unable to send message: %s"), reason_str);
-
-	if (!purple_conversation_present_error(bn, purple_connection_get_account(gc), buf)) {
-		g_free(buf);
-		if (errcode != 0 && errcode < errcodereasonlen) {
-			buf = g_strdup_printf(_("Unable to send message to %s: %s (%s)"),
-			                      bn, reason_str, _(errcodereason[errcode]));
-		} else {
-			buf = g_strdup_printf(_("Unable to send message to %s: %s"), bn,
-			                      reason_str);
-		}
-		purple_notify_error(od->gc, NULL, buf, reason_str,
-			purple_request_cpar_from_connection(od->gc));
-	}
-	g_free(buf);
-
-	g_free(snac2->data);
-	g_free(snac2);
-
-	return 1;
-}
-
-/**
- * Subtype 0x0002 - Set ICBM parameters.
- *
- * I definitely recommend sending this.  If you don't, you'll be stuck
- * with the rather unreasonable defaults.
- *
- */
-int aim_im_setparams(OscarData *od, struct aim_icbmparameters *params)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM)))
-		return -EINVAL;
-
-	if (!params)
-		return -EINVAL;
-
-	byte_stream_new(&bs, 16);
-
-	/* This is read-only (see Parameter Reply). Must be set to zero here. */
-	byte_stream_put16(&bs, 0x0000);
-
-	/* These are all read-write */
-	byte_stream_put32(&bs, params->flags);
-	byte_stream_put16(&bs, params->maxmsglen);
-	byte_stream_put16(&bs, params->maxsenderwarn);
-	byte_stream_put16(&bs, params->maxrecverwarn);
-	byte_stream_put32(&bs, params->minmsginterval);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0002, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0002, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/**
- * Subtype 0x0004 - Request ICBM parameter information.
- *
- */
-int aim_im_reqparams(OscarData *od)
-{
-	FlapConnection *conn;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM)))
-		return -EINVAL;
-
-	aim_genericreq_n_snacid(od, conn, SNAC_FAMILY_ICBM, 0x0004);
-
-	return 0;
-}
-
-/**
- * Subtype 0x0005 - Receive parameter information.
- *
- */
-static int aim_im_paraminfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	struct aim_icbmparameters params;
-
-	params.maxchan = byte_stream_get16(bs);
-	params.flags = byte_stream_get32(bs);
-	params.maxmsglen = byte_stream_get16(bs);
-	params.maxsenderwarn = byte_stream_get16(bs);
-	params.maxrecverwarn = byte_stream_get16(bs);
-	params.minmsginterval = byte_stream_get32(bs);
-
-	params.flags = AIM_IMPARAM_FLAG_CHANNEL_MSGS_ALLOWED
-			| AIM_IMPARAM_FLAG_MISSED_CALLS_ENABLED
-			| AIM_IMPARAM_FLAG_EVENTS_ALLOWED
-			| AIM_IMPARAM_FLAG_SMS_SUPPORTED
-			| AIM_IMPARAM_FLAG_OFFLINE_MSGS_ALLOWED
-			| AIM_IMPARAM_FLAG_USE_HTML_FOR_ICQ;
-	params.maxmsglen = 8000;
-	params.minmsginterval = 0;
-
-	aim_im_setparams(od, &params);
-
-	return 0;
-}
-
-/**
- * Subtype 0x0006 - Send an ICBM (instant message).
- *
- *
- * Possible flags:
- *   AIM_IMFLAGS_AWAY  -- Marks the message as an autoresponse
- *   AIM_IMFLAGS_OFFLINE--If destination is offline, store it until they are
- *                        online (probably ICQ only).
- *
- * Implementation note:  Since this is one of the most-used functions
- * in all of libfaim, it is written with performance in mind.  As such,
- * it is not as clear as it could be in respect to how this message is
- * supposed to be layed out. Most obviously, tlvlists should be used
- * instead of writing out the bytes manually.
- */
-int aim_im_sendch1_ext(OscarData *od, struct aim_sendimext_args *args)
-{
-	FlapConnection *conn;
-	aim_snacid_t snacid;
-	ByteStream data;
-	guchar cookie[8];
-	int msgtlvlen;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM)))
-		return -EINVAL;
-
-	if (!args)
-		return -EINVAL;
-
-	if (!args->msg || (args->msglen <= 0))
-		return -EINVAL;
-
-	if (args->msglen > MAXMSGLEN)
-		return -E2BIG;
-
-	/* Painfully calculate the size of the message TLV */
-	msgtlvlen = 1 + 1; /* 0501 */
-	msgtlvlen += 2 + args->featureslen;
-	msgtlvlen += 2 /* 0101 */ + 2 /* block len */;
-	msgtlvlen += 4 /* charset */ + args->msglen;
-
-	byte_stream_new(&data, msgtlvlen + 128);
-
-	/* Generate an ICBM cookie */
-	aim_icbm_makecookie(cookie);
-
-	/* ICBM header */
-	aim_im_puticbm(&data, cookie, 0x0001, args->destbn);
-
-	/* Message TLV (type 0x0002) */
-	byte_stream_put16(&data, 0x0002);
-	byte_stream_put16(&data, msgtlvlen);
-
-	/* Features TLV (type 0x0501) */
-	byte_stream_put16(&data, 0x0501);
-	byte_stream_put16(&data, args->featureslen);
-	byte_stream_putraw(&data, args->features, args->featureslen);
-
-	/* Insert message text in a TLV (type 0x0101) */
-	byte_stream_put16(&data, 0x0101);
-
-	/* Message block length */
-	byte_stream_put16(&data, args->msglen + 0x04);
-
-	/* Character set */
-	byte_stream_put16(&data, args->charset);
-	/* Character subset -- we always use 0 here */
-	byte_stream_put16(&data, 0x0);
-
-	/* Message.  Not terminated */
-	byte_stream_putraw(&data, (guchar *)args->msg, args->msglen);
-
-	/* Set the Autoresponse flag */
-	if (args->flags & AIM_IMFLAGS_AWAY) {
-		byte_stream_put16(&data, 0x0004);
-		byte_stream_put16(&data, 0x0000);
-	} else {
-		/* Set the Request Acknowledge flag */
-		byte_stream_put16(&data, 0x0003);
-		byte_stream_put16(&data, 0x0000);
-
-		if (args->flags & AIM_IMFLAGS_OFFLINE) {
-			/* Allow this message to be queued as an offline message */
-			byte_stream_put16(&data, 0x0006);
-			byte_stream_put16(&data, 0x0000);
-		}
-	}
-
-	/*
-	 * Set the I HAVE A REALLY PURTY ICON flag.
-	 * XXX - This should really only be sent on initial
-	 * IMs and when you change your icon.
-	 */
-	if (args->flags & AIM_IMFLAGS_HASICON) {
-		byte_stream_put16(&data, 0x0008);
-		byte_stream_put16(&data, 0x000c);
-		byte_stream_put32(&data, args->iconlen);
-		byte_stream_put16(&data, 0x0001);
-		byte_stream_put16(&data, args->iconsum);
-		byte_stream_put32(&data, args->iconstamp);
-	}
-
-	/*
-	 * Set the Buddy Icon Requested flag.
-	 * XXX - Every time?  Surely not...
-	 */
-	if (args->flags & AIM_IMFLAGS_BUDDYREQ) {
-		byte_stream_put16(&data, 0x0009);
-		byte_stream_put16(&data, 0x0000);
-	}
-
-	/* XXX - should be optional */
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, args->destbn, strlen(args->destbn)+1);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &data);
-	byte_stream_destroy(&data);
-
-	/* clean out SNACs over 60sec old */
-	aim_cleansnacs(od, 60);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0006 - Send a chat invitation.
- */
-int aim_im_sendch2_chatinvite(OscarData *od, const char *bn, const char *msg, guint16 exchange, const char *roomname, guint16 instance)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	IcbmCookie *msgcookie;
-	struct aim_invite_priv *priv;
-	guchar cookie[8];
-	GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL;
-	ByteStream hdrbs;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM)))
-		return -EINVAL;
-
-	if (!bn || !msg || !roomname)
-		return -EINVAL;
-
-	aim_icbm_makecookie(cookie);
-
-	byte_stream_new(&bs, 1142+strlen(bn)+strlen(roomname)+strlen(msg));
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, bn, strlen(bn)+1);
-
-	/* XXX should be uncached by an unwritten 'invite accept' handler */
-	priv = g_new0(struct aim_invite_priv, 1);
-	priv->bn = g_strdup(bn);
-	priv->roomname = g_strdup(roomname);
-	priv->exchange = exchange;
-	priv->instance = instance;
-
-	if ((msgcookie = aim_mkcookie(cookie, AIM_COOKIETYPE_INVITE, priv)))
-		aim_cachecookie(od, msgcookie);
-	else
-		g_free(priv);
-
-	/* ICBM Header */
-	aim_im_puticbm(&bs, cookie, 0x0002, bn);
-
-	/*
-	 * TLV t(0005)
-	 *
-	 * Everything else is inside this TLV.
-	 *
-	 * Sigh.  AOL was rather inconsistent right here.  So we have
-	 * to play some minor tricks.  Right inside the type 5 is some
-	 * raw data, followed by a series of TLVs.
-	 *
-	 */
-	byte_stream_new(&hdrbs, 2+8+16+6+4+4+strlen(msg)+4+2+1+strlen(roomname)+2);
-
-	byte_stream_put16(&hdrbs, 0x0000); /* Unknown! */
-	byte_stream_putraw(&hdrbs, cookie, sizeof(cookie)); /* I think... */
-	byte_stream_putcaps(&hdrbs, OSCAR_CAPABILITY_CHAT);
-
-	aim_tlvlist_add_16(&inner_tlvlist, 0x000a, 0x0001);
-	aim_tlvlist_add_noval(&inner_tlvlist, 0x000f);
-	aim_tlvlist_add_str(&inner_tlvlist, 0x000c, msg);
-	aim_tlvlist_add_chatroom(&inner_tlvlist, 0x2711, exchange, roomname, instance);
-	aim_tlvlist_write(&hdrbs, &inner_tlvlist);
-
-	aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data);
-	byte_stream_destroy(&hdrbs);
-
-	aim_tlvlist_write(&bs, &outer_tlvlist);
-
-	aim_tlvlist_free(inner_tlvlist);
-	aim_tlvlist_free(outer_tlvlist);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/**
- * Subtype 0x0006 - Send your icon to a given user.
- *
- * This is also performance sensitive. (If you can believe it...)
- *
- */
-int aim_im_sendch2_icon(OscarData *od, const char *bn, const guint8 *icon, int iconlen, time_t stamp, guint16 iconsum)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	guchar cookie[8];
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM)))
-		return -EINVAL;
-
-	if (!bn || !icon || (iconlen <= 0) || (iconlen >= MAXICONLEN))
-		return -EINVAL;
-
-	aim_icbm_makecookie(cookie);
-
-	byte_stream_new(&bs, 8+2+1+strlen(bn)+2+2+2+8+16+2+2+2+2+2+2+2+4+4+4+iconlen+strlen(AIM_ICONIDENT)+2+2);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
-
-	/* ICBM header */
-	aim_im_puticbm(&bs, cookie, 0x0002, bn);
-
-	/*
-	 * TLV t(0005)
-	 *
-	 * Encompasses everything below.
-	 */
-	byte_stream_put16(&bs, 0x0005);
-	byte_stream_put16(&bs, 2+8+16+6+4+4+iconlen+4+4+4+strlen(AIM_ICONIDENT));
-
-	byte_stream_put16(&bs, 0x0000);
-	byte_stream_putraw(&bs, cookie, 8);
-	byte_stream_putcaps(&bs, OSCAR_CAPABILITY_BUDDYICON);
-
-	/* TLV t(000a) */
-	byte_stream_put16(&bs, 0x000a);
-	byte_stream_put16(&bs, 0x0002);
-	byte_stream_put16(&bs, 0x0001);
-
-	/* TLV t(000f) */
-	byte_stream_put16(&bs, 0x000f);
-	byte_stream_put16(&bs, 0x0000);
-
-	/* TLV t(2711) */
-	byte_stream_put16(&bs, 0x2711);
-	byte_stream_put16(&bs, 4+4+4+iconlen+strlen(AIM_ICONIDENT));
-	byte_stream_put16(&bs, 0x0000);
-	byte_stream_put16(&bs, iconsum);
-	byte_stream_put32(&bs, iconlen);
-	byte_stream_put32(&bs, stamp);
-	byte_stream_putraw(&bs, icon, iconlen);
-	byte_stream_putstr(&bs, AIM_ICONIDENT);
-
-	/* TLV t(0003) */
-	byte_stream_put16(&bs, 0x0003);
-	byte_stream_put16(&bs, 0x0000);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/**
- * Cancel a rendezvous invitation.  It could be an invitation to
- * establish a direct connection, or a file-send, or a chat invite.
- */
-void
-aim_im_sendch2_cancel(PeerConnection *peer_conn)
-{
-	OscarData *od;
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL;
-	ByteStream hdrbs;
-
-	od = peer_conn->od;
-	conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM);
-	if (conn == NULL)
-		return;
-
-	byte_stream_new(&bs, 118+strlen(peer_conn->bn));
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
-
-	/* ICBM header */
-	aim_im_puticbm(&bs, peer_conn->cookie, 0x0002, peer_conn->bn);
-
-	aim_tlvlist_add_noval(&outer_tlvlist, 0x0003);
-
-	byte_stream_new(&hdrbs, 64);
-
-	byte_stream_put16(&hdrbs, AIM_RENDEZVOUS_CANCEL);
-	byte_stream_putraw(&hdrbs, peer_conn->cookie, 8);
-	byte_stream_putcaps(&hdrbs, peer_conn->type);
-
-	/* This TLV means "cancel!" */
-	aim_tlvlist_add_16(&inner_tlvlist, 0x000b, 0x0001);
-	aim_tlvlist_write(&hdrbs, &inner_tlvlist);
-
-	aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data);
-	byte_stream_destroy(&hdrbs);
-
-	aim_tlvlist_write(&bs, &outer_tlvlist);
-
-	aim_tlvlist_free(inner_tlvlist);
-	aim_tlvlist_free(outer_tlvlist);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-}
-
-/**
- * Subtype 0x0006 - Send an "I accept and I've connected to
- * you" message.
- */
-void
-aim_im_sendch2_connected(PeerConnection *peer_conn)
-{
-	OscarData *od;
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-
-	od = peer_conn->od;
-	conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM);
-	if (conn == NULL)
-		return;
-
-	byte_stream_new(&bs, 11+strlen(peer_conn->bn) + 4+2+8+16);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
-
-	/* ICBM header */
-	aim_im_puticbm(&bs, peer_conn->cookie, 0x0002, peer_conn->bn);
-
-	byte_stream_put16(&bs, 0x0005);
-	byte_stream_put16(&bs, 0x001a);
-	byte_stream_put16(&bs, AIM_RENDEZVOUS_CONNECTED);
-	byte_stream_putraw(&bs, peer_conn->cookie, 8);
-	byte_stream_putcaps(&bs, peer_conn->type);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-}
-
-/**
- * Subtype 0x0006 - Send a direct connect rendezvous ICBM.  This
- * could have a number of meanings, depending on the content:
- * "I want you to connect to me"
- * "I want to connect to you"
- * "I want to connect through a proxy server"
- */
-void
-aim_im_sendch2_odc_requestdirect(OscarData *od, guchar *cookie, const char *bn, const guint8 *ip, guint16 port, guint16 requestnumber)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL;
-	ByteStream hdrbs;
-
-	g_return_if_fail(bn != NULL);
-	g_return_if_fail(ip != NULL);
-
-	conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM);
-	if (conn == NULL)
-		return;
-
-	byte_stream_new(&bs, 246+strlen(bn));
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
-
-	/* ICBM header */
-	aim_im_puticbm(&bs, cookie, 0x0002, bn);
-
-	aim_tlvlist_add_noval(&outer_tlvlist, 0x0003);
-
-	byte_stream_new(&hdrbs, 128);
-
-	byte_stream_put16(&hdrbs, AIM_RENDEZVOUS_PROPOSE);
-	byte_stream_putraw(&hdrbs, cookie, 8);
-	byte_stream_putcaps(&hdrbs, OSCAR_CAPABILITY_DIRECTIM);
-
-	aim_tlvlist_add_raw(&inner_tlvlist, 0x0002, 4, ip);
-	aim_tlvlist_add_raw(&inner_tlvlist, 0x0003, 4, ip);
-	aim_tlvlist_add_16(&inner_tlvlist, 0x0005, port);
-	aim_tlvlist_add_16(&inner_tlvlist, 0x000a, requestnumber);
-	aim_tlvlist_add_noval(&inner_tlvlist, 0x000f);
-	aim_tlvlist_write(&hdrbs, &inner_tlvlist);
-
-	aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data);
-	byte_stream_destroy(&hdrbs);
-
-	aim_tlvlist_write(&bs, &outer_tlvlist);
-
-	aim_tlvlist_free(inner_tlvlist);
-	aim_tlvlist_free(outer_tlvlist);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-}
-
-/**
- * Subtype 0x0006 - Send a direct connect rendezvous ICBM asking the
- * remote user to connect to us via a proxy server.
- */
-void
-aim_im_sendch2_odc_requestproxy(OscarData *od, guchar *cookie, const char *bn, const guint8 *ip, guint16 pin, guint16 requestnumber)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL;
-	ByteStream hdrbs;
-	guint8 ip_comp[4];
-
-	conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM);
-	if (conn == NULL)
-		return;
-
-	byte_stream_new(&bs, 246+strlen(bn));
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
-
-	/* ICBM header */
-	aim_im_puticbm(&bs, cookie, 0x0002, bn);
-
-	aim_tlvlist_add_noval(&outer_tlvlist, 0x0003);
-
-	byte_stream_new(&hdrbs, 128);
-
-	byte_stream_put16(&hdrbs, AIM_RENDEZVOUS_PROPOSE);
-	byte_stream_putraw(&hdrbs, cookie, 8);
-	byte_stream_putcaps(&hdrbs, OSCAR_CAPABILITY_DIRECTIM);
-
-	aim_tlvlist_add_raw(&inner_tlvlist, 0x0002, 4, ip);
-	aim_tlvlist_add_raw(&inner_tlvlist, 0x0003, 4, ip);
-	aim_tlvlist_add_16(&inner_tlvlist, 0x0005, pin);
-	aim_tlvlist_add_16(&inner_tlvlist, 0x000a, requestnumber);
-	aim_tlvlist_add_noval(&inner_tlvlist, 0x000f);
-	aim_tlvlist_add_noval(&inner_tlvlist, 0x0010);
-
-	/* Send the bitwise complement of the port and ip.  As a check? */
-	ip_comp[0] = ~ip[0];
-	ip_comp[1] = ~ip[1];
-	ip_comp[2] = ~ip[2];
-	ip_comp[3] = ~ip[3];
-	aim_tlvlist_add_raw(&inner_tlvlist, 0x0016, 4, ip_comp);
-	aim_tlvlist_add_16(&inner_tlvlist, 0x0017, ~pin);
-
-	aim_tlvlist_write(&hdrbs, &inner_tlvlist);
-
-	aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data);
-	byte_stream_destroy(&hdrbs);
-
-	aim_tlvlist_write(&bs, &outer_tlvlist);
-
-	aim_tlvlist_free(inner_tlvlist);
-	aim_tlvlist_free(outer_tlvlist);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-}
-
-/**
- * Subtype 0x0006 - Send an "I want to send you this file" message
- *
- */
-void
-aim_im_sendch2_sendfile_requestdirect(OscarData *od, guchar *cookie, const char *bn, const guint8 *ip, guint16 port, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL;
-	ByteStream hdrbs;
-
-	g_return_if_fail(bn != NULL);
-	g_return_if_fail(ip != NULL);
-
-	conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM);
-	if (conn == NULL)
-		return;
-
-	byte_stream_new(&bs, 1014);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
-
-	/* ICBM header */
-	aim_im_puticbm(&bs, cookie, 0x0002, bn);
-
-	aim_tlvlist_add_noval(&outer_tlvlist, 0x0003);
-
-	byte_stream_new(&hdrbs, 512);
-
-	byte_stream_put16(&hdrbs, AIM_RENDEZVOUS_PROPOSE);
-	byte_stream_putraw(&hdrbs, cookie, 8);
-	byte_stream_putcaps(&hdrbs, OSCAR_CAPABILITY_SENDFILE);
-
-	aim_tlvlist_add_raw(&inner_tlvlist, 0x0002, 4, ip);
-	aim_tlvlist_add_raw(&inner_tlvlist, 0x0003, 4, ip);
-	aim_tlvlist_add_16(&inner_tlvlist, 0x0005, port);
-	aim_tlvlist_add_16(&inner_tlvlist, 0x000a, requestnumber);
-	aim_tlvlist_add_noval(&inner_tlvlist, 0x000f);
-	/* TODO: Send 0x0016 and 0x0017 */
-
-	if (filename != NULL)
-	{
-		ByteStream inner_bs;
-
-		/* Begin TLV t(2711) */
-		byte_stream_new(&inner_bs, 2+2+4+strlen(filename)+1);
-		byte_stream_put16(&inner_bs, (numfiles > 1) ? 0x0002 : 0x0001);
-		byte_stream_put16(&inner_bs, numfiles);
-		byte_stream_put32(&inner_bs, size);
-
-		/* Filename - NULL terminated, for some odd reason */
-		byte_stream_putstr(&inner_bs, filename);
-		byte_stream_put8(&inner_bs, 0x00);
-
-		aim_tlvlist_add_raw(&inner_tlvlist, 0x2711, inner_bs.len, inner_bs.data);
-		byte_stream_destroy(&inner_bs);
-		/* End TLV t(2711) */
-	}
-
-	aim_tlvlist_write(&hdrbs, &inner_tlvlist);
-	aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data);
-	byte_stream_destroy(&hdrbs);
-
-	aim_tlvlist_write(&bs, &outer_tlvlist);
-
-	aim_tlvlist_free(inner_tlvlist);
-	aim_tlvlist_free(outer_tlvlist);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-}
-
-/**
- * Subtype 0x0006 - Send a sendfile connect rendezvous ICBM asking the
- * remote user to connect to us via a proxy server.
- */
-void
-aim_im_sendch2_sendfile_requestproxy(OscarData *od, guchar *cookie, const char *bn, const guint8 *ip, guint16 pin, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL;
-	ByteStream hdrbs;
-	guint8 ip_comp[4];
-
-	conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM);
-	if (conn == NULL)
-		return;
-
-	byte_stream_new(&bs, 1014);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
-
-	/* ICBM header */
-	aim_im_puticbm(&bs, cookie, 0x0002, bn);
-
-	aim_tlvlist_add_noval(&outer_tlvlist, 0x0003);
-
-	byte_stream_new(&hdrbs, 512);
-
-	byte_stream_put16(&hdrbs, AIM_RENDEZVOUS_PROPOSE);
-	byte_stream_putraw(&hdrbs, cookie, 8);
-	byte_stream_putcaps(&hdrbs, OSCAR_CAPABILITY_SENDFILE);
-
-	aim_tlvlist_add_raw(&inner_tlvlist, 0x0002, 4, ip);
-	aim_tlvlist_add_raw(&inner_tlvlist, 0x0003, 4, ip);
-	aim_tlvlist_add_16(&inner_tlvlist, 0x0005, pin);
-	aim_tlvlist_add_16(&inner_tlvlist, 0x000a, requestnumber);
-	aim_tlvlist_add_noval(&inner_tlvlist, 0x000f);
-	aim_tlvlist_add_noval(&inner_tlvlist, 0x0010);
-
-	/* Send the bitwise complement of the port and ip.  As a check? */
-	ip_comp[0] = ~ip[0];
-	ip_comp[1] = ~ip[1];
-	ip_comp[2] = ~ip[2];
-	ip_comp[3] = ~ip[3];
-	aim_tlvlist_add_raw(&inner_tlvlist, 0x0016, 4, ip_comp);
-	aim_tlvlist_add_16(&inner_tlvlist, 0x0017, ~pin);
-
-	if (filename != NULL)
-	{
-		ByteStream filename_bs;
-
-		/* Begin TLV t(2711) */
-		byte_stream_new(&filename_bs, 2+2+4+strlen(filename)+1);
-		byte_stream_put16(&filename_bs, (numfiles > 1) ? 0x0002 : 0x0001);
-		byte_stream_put16(&filename_bs, numfiles);
-		byte_stream_put32(&filename_bs, size);
-
-		/* Filename - NULL terminated, for some odd reason */
-		byte_stream_putstr(&filename_bs, filename);
-		byte_stream_put8(&filename_bs, 0x00);
-
-		aim_tlvlist_add_raw(&inner_tlvlist, 0x2711, filename_bs.len, filename_bs.data);
-		byte_stream_destroy(&filename_bs);
-		/* End TLV t(2711) */
-	}
-
-	aim_tlvlist_write(&hdrbs, &inner_tlvlist);
-
-	aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data);
-	byte_stream_destroy(&hdrbs);
-
-	aim_tlvlist_write(&bs, &outer_tlvlist);
-
-	aim_tlvlist_free(inner_tlvlist);
-	aim_tlvlist_free(outer_tlvlist);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-}
-
-static void
-incomingim_ch1_parsemsg(OscarData *od, aim_userinfo_t *userinfo, ByteStream *message, struct aim_incomingim_ch1_args *args)
-{
-	PurpleAccount *account = purple_connection_get_account(od->gc);
-	/*
-	 * We're interested in the inner TLV 0x101, which contains precious, precious message.
-	 */
-	while (byte_stream_bytes_left(message) >= 4) {
-		guint16 type = byte_stream_get16(message);
-		guint16 length = byte_stream_get16(message);
-		if (type == 0x101) {
-			gchar *msg;
-			guint16 msglen = length - 4; /* charset + charsubset */
-			guint16 charset = byte_stream_get16(message);
-			byte_stream_advance(message, 2); /* charsubset */
-
-			msg = byte_stream_getstr(message, msglen);
-			args->msg = oscar_decode_im(account, userinfo->bn, charset, msg, msglen);
-			g_free(msg);
-		} else {
-			byte_stream_advance(message, length);
-		}
-	}
-}
-
-static int
-incomingim_ch1(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, ByteStream *bs, guint8 *cookie)
-{
-	guint16 type, length;
-	aim_rxcallback_t userfunc;
-	int ret = 0;
-	struct aim_incomingim_ch1_args args;
-	unsigned int endpos;
-
-	memset(&args, 0, sizeof(args));
-
-	/*
-	 * This used to be done using tlvchains.  For performance reasons,
-	 * I've changed it to process the TLVs in-place.  This avoids lots
-	 * of per-IM memory allocations.
-	 */
-	while (byte_stream_bytes_left(bs) >= 4)
-	{
-		type = byte_stream_get16(bs);
-		length = byte_stream_get16(bs);
-
-		if (length > byte_stream_bytes_left(bs))
-		{
-			purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s.  They are probably trying to do something malicious.\n", userinfo->bn);
-			break;
-		}
-
-		endpos = byte_stream_curpos(bs) + length;
-
-		if (type == 0x0002) { /* Message Block */
-			ByteStream tlv02;
-			byte_stream_init(&tlv02, bs->data + bs->offset, length);
-			incomingim_ch1_parsemsg(od, userinfo, &tlv02, &args);
-		} else if (type == 0x0003) { /* Server Ack Requested */
-			args.icbmflags |= AIM_IMFLAGS_ACK;
-		} else if (type == 0x0004) { /* Message is Auto Response */
-			args.icbmflags |= AIM_IMFLAGS_AWAY;
-		} else if (type == 0x0006) { /* Message was received offline. */
-			/*
-			 * This flag is set on incoming offline messages for both
-			 * AIM and ICQ accounts.
-			 */
-			args.icbmflags |= AIM_IMFLAGS_OFFLINE;
-		} else if (type == 0x0008) { /* I-HAVE-A-REALLY-PURTY-ICON Flag */
-			args.iconlen = byte_stream_get32(bs);
-			byte_stream_get16(bs); /* 0x0001 */
-			args.iconsum = byte_stream_get16(bs);
-			args.iconstamp = byte_stream_get32(bs);
-
-			/*
-			 * This looks to be a client bug.  MacAIM 4.3 will
-			 * send this tag, but with all zero values, in the
-			 * first message of a conversation. This makes no
-			 * sense whatsoever, so I'm going to say its a bug.
-			 *
-			 * You really shouldn't advertise a zero-length icon
-			 * anyway.
-			 *
-			 */
-			if (args.iconlen)
-				args.icbmflags |= AIM_IMFLAGS_HASICON;
-		} else if (type == 0x0009) {
-			args.icbmflags |= AIM_IMFLAGS_BUDDYREQ;
-		} else if (type == 0x000b) { /* Non-direct connect typing notification */
-			args.icbmflags |= AIM_IMFLAGS_TYPINGNOT;
-		} else if (type == 0x0016) {
-			/*
-			 * UTC timestamp for when the message was sent.  Only
-			 * provided for offline messages.
-			 */
-			args.timestamp = byte_stream_get32(bs);
-		}
-
-		/*
-		 * This is here to protect ourselves from ourselves.  That
-		 * is, if something above doesn't completely parse its value
-		 * section, or, worse, overparses it, this will set the
-		 * stream where it needs to be in order to land on the next
-		 * TLV when the loop continues.
-		 *
-		 */
-		byte_stream_setpos(bs, endpos);
-	}
-
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, channel, userinfo, &args);
-
-	g_free(args.msg);
-	return ret;
-}
-
-static void
-incomingim_ch2_buddylist(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, aim_userinfo_t *userinfo, IcbmArgsCh2 *args, ByteStream *servdata)
-{
-	/*
-	 * This goes like this...
-	 *
-	 *   group name length
-	 *   group name
-	 *     num of buddies in group
-	 *     buddy name length
-	 *     buddy name
-	 *     buddy name length
-	 *     buddy name
-	 *     ...
-	 *   group name length
-	 *   group name
-	 *     num of buddies in group
-	 *     buddy name length
-	 *     buddy name
-	 *     ...
-	 *   ...
-	 */
-	while (byte_stream_bytes_left(servdata))
-	{
-		guint16 gnlen, numb;
-		int i;
-		char *gn;
-
-		gnlen = byte_stream_get16(servdata);
-		gn = byte_stream_getstr(servdata, gnlen);
-		numb = byte_stream_get16(servdata);
-
-		for (i = 0; i < numb; i++) {
-			guint16 bnlen;
-			char *bn;
-
-			bnlen = byte_stream_get16(servdata);
-			bn = byte_stream_getstr(servdata, bnlen);
-
-			purple_debug_misc("oscar", "got a buddy list from %s: group %s, buddy %s\n", userinfo->bn, gn, bn);
-
-			g_free(bn);
-		}
-
-		g_free(gn);
-	}
-
-	return;
-}
-
-static void
-incomingim_ch2_buddyicon_free(OscarData *od, IcbmArgsCh2 *args)
-{
-	g_free(args->info.icon.icon);
-
-	return;
-}
-
-static void
-incomingim_ch2_buddyicon(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, aim_userinfo_t *userinfo, IcbmArgsCh2 *args, ByteStream *servdata)
-{
-	args->info.icon.checksum = byte_stream_get32(servdata);
-	args->info.icon.length = byte_stream_get32(servdata);
-	args->info.icon.timestamp = byte_stream_get32(servdata);
-	args->info.icon.icon = byte_stream_getraw(servdata, args->info.icon.length);
-
-	args->destructor = (void *)incomingim_ch2_buddyicon_free;
-
-	return;
-}
-
-static void
-incomingim_ch2_chat_free(OscarData *od, IcbmArgsCh2 *args)
-{
-	/* XXX - aim_chat_roominfo_free() */
-	g_free(args->info.chat.roominfo.name);
-
-	return;
-}
-
-static void
-incomingim_ch2_chat(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, aim_userinfo_t *userinfo, IcbmArgsCh2 *args, ByteStream *servdata)
-{
-	/*
-	 * Chat room info.
-	 */
-	aim_chat_readroominfo(servdata, &args->info.chat.roominfo);
-
-	args->destructor = (void *)incomingim_ch2_chat_free;
-}
-
-static void
-incomingim_ch2_icqserverrelay_free(OscarData *od, IcbmArgsCh2 *args)
-{
-	g_free((char *)args->info.rtfmsg.msg);
-}
-
-/*
- * The relationship between OSCAR_CAPABILITY_ICQSERVERRELAY and OSCAR_CAPABILITY_ICQRTF is
- * kind of odd. This sends the client ICQRTF since that is all that I've seen
- * SERVERRELAY used for.
- *
- * Note that this is all little-endian.  Cringe.
- *
- */
-static void
-incomingim_ch2_icqserverrelay(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, aim_userinfo_t *userinfo, IcbmArgsCh2 *args, ByteStream *servdata)
-{
-	guint16 hdrlen, msglen;
-
-	args->destructor = (void *)incomingim_ch2_icqserverrelay_free;
-
-#define SKIP_HEADER(expected_hdrlen) \
-	hdrlen = byte_stream_getle16(servdata); \
-	if (hdrlen != expected_hdrlen) { \
-		purple_debug_warning("oscar", "Expected to find a header with length " #expected_hdrlen "; ignoring message"); \
-		return; \
-	} \
-	byte_stream_advance(servdata, hdrlen);
-
-	SKIP_HEADER(0x001b);
-	SKIP_HEADER(0x000e);
-
-	args->info.rtfmsg.msgtype = byte_stream_get8(servdata);
-	/*
-	 * Copied from http://iserverd.khstu.ru/oscar/message.html:
-	 * xx      byte       message flags
-	 * xx xx   word (LE)  status code
-	 * xx xx   word (LE)  priority code
-	 *
-	 * We don't need any of these, so just skip them.
-	 */
-	byte_stream_advance(servdata, 1 + 2 + 2);
-
-	msglen = byte_stream_getle16(servdata);
-	args->info.rtfmsg.msg = byte_stream_getstr(servdata, msglen);
-}
-
-static void
-incomingim_ch2_sendfile_free(OscarData *od, IcbmArgsCh2 *args)
-{
-	g_free(args->info.sendfile.filename);
-}
-
-/* Someone is sending us a file */
-static void
-incomingim_ch2_sendfile(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, aim_userinfo_t *userinfo, IcbmArgsCh2 *args, ByteStream *servdata)
-{
-	int flen;
-
-	args->destructor = (void *)incomingim_ch2_sendfile_free;
-
-	/* Maybe there is a better way to tell what kind of sendfile
-	 * this is?  Maybe TLV t(000a)? */
-
-	/* subtype is one of AIM_OFT_SUBTYPE_* */
-	args->info.sendfile.subtype = byte_stream_get16(servdata);
-	args->info.sendfile.totfiles = byte_stream_get16(servdata);
-	args->info.sendfile.totsize = byte_stream_get32(servdata);
-
-	/*
-	 * I hope to God I'm right when I guess that there is a
-	 * 32 char max filename length for single files.  I think
-	 * OFT tends to do that.  Gotta love inconsistency.  I saw
-	 * a 26 byte filename?
-	 */
-	/* AAA - create an byte_stream_getnullstr function (don't anymore)(maybe) */
-	/* Use an inelegant way of getting the null-terminated filename,
-	 * since there's no easy bstream routine. */
-	for (flen = 0; byte_stream_get8(servdata); flen++);
-	byte_stream_advance(servdata, -flen -1);
-	args->info.sendfile.filename = byte_stream_getstr(servdata, flen);
-
-	/* There is sometimes more after the null-terminated filename,
-	 * but I'm unsure of its format. */
-	/* I don't believe him. */
-	/* There is sometimes a null byte inside a unicode filename,
-	 * but as far as I can tell the filename is the last
-	 * piece of data that will be in this message. --Jonathan */
-}
-
-typedef void (*ch2_args_destructor_t)(OscarData *od, IcbmArgsCh2 *args);
-
-static int incomingim_ch2(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, GSList *tlvlist, guint8 *cookie)
-{
-	aim_rxcallback_t userfunc;
-	aim_tlv_t *block1, *servdatatlv;
-	GSList *list2;
-	aim_tlv_t *tlv;
-	IcbmArgsCh2 args;
-	ByteStream bbs, sdbs, *sdbsptr = NULL;
-	guint8 *cookie2;
-	int ret = 0;
-
-	char proxyip[30] = {""};
-	char clientip[30] = {""};
-	char verifiedip[30] = {""};
-
-	memset(&args, 0, sizeof(args));
-
-	/*
-	 * There's another block of TLVs embedded in the type 5 here.
-	 */
-	block1 = aim_tlv_gettlv(tlvlist, 0x0005, 1);
-	if (block1 == NULL)
-	{
-		/* The server sent us ch2 ICBM without ch2 info?  Weird. */
-		return 1;
-	}
-	byte_stream_init(&bbs, block1->value, block1->length);
-
-	/*
-	 * First two bytes represent the status of the connection.
-	 * One of the AIM_RENDEZVOUS_ defines.
-	 *
-	 * 0 is a request, 1 is a cancel, 2 is an accept
-	 */
-	args.status = byte_stream_get16(&bbs);
-
-	/*
-	 * Next comes the cookie.  Should match the ICBM cookie.
-	 */
-	cookie2 = byte_stream_getraw(&bbs, 8);
-	if (memcmp(cookie, cookie2, 8) != 0)
-	{
-		purple_debug_warning("oscar",
-				"Cookies don't match in rendezvous ICBM, bailing out.\n");
-		g_free(cookie2);
-		return 1;
-	}
-	memcpy(args.cookie, cookie2, 8);
-	g_free(cookie2);
-
-	/*
-	 * The next 16bytes are a capability block so we can
-	 * identify what type of rendezvous this is.
-	 */
-	args.type = aim_locate_getcaps(od, &bbs, 0x10);
-
-	/*
-	 * What follows may be TLVs or nothing, depending on the
-	 * purpose of the message.
-	 *
-	 * Ack packets for instance have nothing more to them.
-	 */
-	list2 = aim_tlvlist_read(&bbs);
-
-	/*
-	 * IP address to proxy the file transfer through.
-	 *
-	 * TODO: I don't like this.  Maybe just read in an int?  Or inet_ntoa...
-	 */
-	tlv = aim_tlv_gettlv(list2, 0x0002, 1);
-	if ((tlv != NULL) && (tlv->length == 4))
-		snprintf(proxyip, sizeof(proxyip), "%hhu.%hhu.%hhu.%hhu",
-				tlv->value[0], tlv->value[1],
-				tlv->value[2], tlv->value[3]);
-
-	/*
-	 * IP address from the perspective of the client.
-	 */
-	tlv = aim_tlv_gettlv(list2, 0x0003, 1);
-	if ((tlv != NULL) && (tlv->length == 4))
-		snprintf(clientip, sizeof(clientip), "%hhu.%hhu.%hhu.%hhu",
-				tlv->value[0], tlv->value[1],
-				tlv->value[2], tlv->value[3]);
-
-	/*
-	 * Verified IP address (from the perspective of Oscar).
-	 *
-	 * This is added by the server.
-	 */
-	tlv = aim_tlv_gettlv(list2, 0x0004, 1);
-	if ((tlv != NULL) && (tlv->length == 4))
-		snprintf(verifiedip, sizeof(verifiedip), "%hhu.%hhu.%hhu.%hhu",
-				tlv->value[0], tlv->value[1],
-				tlv->value[2], tlv->value[3]);
-
-	/*
-	 * Port number for something.
-	 */
-	if (aim_tlv_gettlv(list2, 0x0005, 1))
-		args.port = aim_tlv_get16(list2, 0x0005, 1);
-
-	/*
-	 * File transfer "request number":
-	 * 0x0001 - Initial file transfer request for no proxy or stage 1 proxy
-	 * 0x0002 - "Reply request" for a stage 2 proxy (receiver wants to use proxy)
-	 * 0x0003 - A third request has been sent; applies only to stage 3 proxied transfers
-	 */
-	if (aim_tlv_gettlv(list2, 0x000a, 1))
-		args.requestnumber = aim_tlv_get16(list2, 0x000a, 1);
-
-	/*
-	 * Terminate connection/error code.  0x0001 means the other user
-	 * cancelled the connection.
-	 */
-	if (aim_tlv_gettlv(list2, 0x000b, 1))
-		args.errorcode = aim_tlv_get16(list2, 0x000b, 1);
-
-	/*
-	 * Invitation message / chat description.
-	 */
-	if (aim_tlv_gettlv(list2, 0x000c, 1)) {
-		args.msg = aim_tlv_getstr(list2, 0x000c, 1);
-		args.msglen = aim_tlv_getlength(list2, 0x000c, 1);
-	}
-
-	/*
-	 * Character set.
-	 */
-	if (aim_tlv_gettlv(list2, 0x000d, 1))
-		args.encoding = aim_tlv_getstr(list2, 0x000d, 1);
-
-	/*
-	 * Language.
-	 */
-	if (aim_tlv_gettlv(list2, 0x000e, 1))
-		args.language = aim_tlv_getstr(list2, 0x000e, 1);
-
-	/*
-	 * Flag meaning we should proxy the file transfer through an AIM server
-	 */
-	if (aim_tlv_gettlv(list2, 0x0010, 1))
-		args.use_proxy = TRUE;
-
-	if (*proxyip != '\0')
-		args.proxyip = (char *)proxyip;
-	if (*clientip != '\0')
-		args.clientip = (char *)clientip;
-	if (*verifiedip != '\0')
-		args.verifiedip = (char *)verifiedip;
-
-	/*
-	 * This must be present in PROPOSALs, but will probably not
-	 * exist in CANCELs and ACCEPTs.  Also exists in ICQ Lite
-	 * Beta 4.0 URLs (OSCAR_CAPABILITY_ICQSERVERRELAY).
-	 *
-	 * Service Data blocks are module-specific in format.
-	 */
-	if ((servdatatlv = aim_tlv_gettlv(list2, 0x2711 /* 10001 */, 1))) {
-
-		byte_stream_init(&sdbs, servdatatlv->value, servdatatlv->length);
-		sdbsptr = &sdbs;
-
-		/*
-		 * The rest of the handling depends on what type it is.
-		 *
-		 * Not all of them have special handling (yet).
-		 */
-		if (args.type & OSCAR_CAPABILITY_BUDDYICON)
-			incomingim_ch2_buddyicon(od, conn, mod, frame, snac, userinfo, &args, sdbsptr);
-		else if (args.type & OSCAR_CAPABILITY_SENDBUDDYLIST)
-			incomingim_ch2_buddylist(od, conn, mod, frame, snac, userinfo, &args, sdbsptr);
-		else if (args.type & OSCAR_CAPABILITY_CHAT)
-			incomingim_ch2_chat(od, conn, mod, frame, snac, userinfo, &args, sdbsptr);
-		else if (args.type & OSCAR_CAPABILITY_ICQSERVERRELAY)
-			incomingim_ch2_icqserverrelay(od, conn, mod, frame, snac, userinfo, &args, sdbsptr);
-		else if (args.type & OSCAR_CAPABILITY_SENDFILE)
-			incomingim_ch2_sendfile(od, conn, mod, frame, snac, userinfo, &args, sdbsptr);
-	}
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, channel, userinfo, &args);
-
-
-	if (args.destructor)
-		((ch2_args_destructor_t)args.destructor)(od, &args);
-
-	g_free((char *)args.msg);
-	g_free((char *)args.encoding);
-	g_free((char *)args.language);
-
-	aim_tlvlist_free(list2);
-
-	return ret;
-}
-
-static int incomingim_ch4(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, GSList *tlvlist, guint8 *cookie)
-{
-	ByteStream meat;
-	aim_rxcallback_t userfunc;
-	aim_tlv_t *block;
-	struct aim_incomingim_ch4_args args;
-	int ret = 0;
-
-	/*
-	 * Make a bstream for the meaty part.  Yum.  Meat.
-	 */
-	if (!(block = aim_tlv_gettlv(tlvlist, 0x0005, 1)))
-		return -1;
-	byte_stream_init(&meat, block->value, block->length);
-
-	args.uin = byte_stream_getle32(&meat);
-	args.type = byte_stream_getle8(&meat);
-	args.flags = byte_stream_getle8(&meat);
-	if (args.type == 0x1a)
-		/* There seems to be a problem with the length in SMS msgs from server, this fixed it */
-		args.msglen = block->length - 6;
-	else
-		args.msglen = byte_stream_getle16(&meat);
-	args.msg = (gchar *)byte_stream_getraw(&meat, args.msglen);
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, channel, userinfo, &args);
-
-	g_free(args.msg);
-
-	return ret;
-}
-
-/*
- * Subtype 0x0007
- *
- * It can easily be said that parsing ICBMs is THE single
- * most difficult thing to do in the in AIM protocol.  In
- * fact, I think I just did say that.
- *
- * Below is the best damned solution I've come up with
- * over the past sixteen months of battling with it. This
- * can parse both away and normal messages from every client
- * I have access to.  Its not fast, its not clean.  But it works.
- *
- */
-static int incomingim(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	guchar *cookie;
-	guint16 channel;
-	aim_userinfo_t userinfo;
-
-	memset(&userinfo, 0x00, sizeof(aim_userinfo_t));
-
-	/*
-	 * Read ICBM Cookie.
-	 */
-	cookie = byte_stream_getraw(bs, 8);
-
-	/*
-	 * Channel ID.
-	 *
-	 * Channel 0x0001 is the message channel.  It is
-	 * used to send basic ICBMs.
-	 *
-	 * Channel 0x0002 is the Rendezvous channel, which
-	 * is where Chat Invitiations and various client-client
-	 * connection negotiations come from.
-	 *
-	 * Channel 0x0003 is used for chat messages.
-	 *
-	 * Channel 0x0004 is used for ICQ authorization, or
-	 * possibly any system notice.
-	 *
-	 */
-	channel = byte_stream_get16(bs);
-
-	/*
-	 * Extract the standard user info block.
-	 *
-	 * Note that although this contains TLVs that appear contiguous
-	 * with the TLVs read below, they are two different pieces.  The
-	 * userinfo block contains the number of TLVs that contain user
-	 * information, the rest are not even though there is no separation.
-	 * You can start reading the message TLVs after aim_info_extract()
-	 * parses out the standard userinfo block.
-	 *
-	 * That also means that TLV types can be duplicated between the
-	 * userinfo block and the rest of the message, however there should
-	 * never be two TLVs of the same type in one block.
-	 *
-	 */
-	aim_info_extract(od, bs, &userinfo);
-
-	/*
-	 * From here on, its depends on what channel we're on.
-	 *
-	 * Technically all channels have a TLV list have this, however,
-	 * for the common channel 1 case, in-place parsing is used for
-	 * performance reasons (less memory allocation).
-	 */
-	if (channel == 1) {
-
-		ret = incomingim_ch1(od, conn, mod, frame, snac, channel, &userinfo, bs, cookie);
-
-	} else if (channel == 2) {
-		GSList *tlvlist;
-
-		/*
-		 * Read block of TLVs (not including the userinfo data).  All
-		 * further data is derived from what is parsed here.
-		 */
-		tlvlist = aim_tlvlist_read(bs);
-
-		ret = incomingim_ch2(od, conn, mod, frame, snac, channel, &userinfo, tlvlist, cookie);
-
-		aim_tlvlist_free(tlvlist);
-
-	} else if (channel == 4) {
-		GSList *tlvlist;
-
-		tlvlist = aim_tlvlist_read(bs);
-		ret = incomingim_ch4(od, conn, mod, frame, snac, channel, &userinfo, tlvlist, cookie);
-		aim_tlvlist_free(tlvlist);
-
-	} else {
-		purple_debug_misc("oscar", "icbm: ICBM received on an unsupported channel.  Ignoring.  (chan = %04x)\n", channel);
-	}
-
-	aim_info_free(&userinfo);
-	g_free(cookie);
-
-	return ret;
-}
-
-/* Subtype 0x000a */
-static int missedcall(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	guint16 channel, nummissed, reason;
-	aim_userinfo_t userinfo;
-
-	while (byte_stream_bytes_left(bs)) {
-
-		channel = byte_stream_get16(bs);
-		aim_info_extract(od, bs, &userinfo);
-		nummissed = byte_stream_get16(bs);
-		reason = byte_stream_get16(bs);
-
-		if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-			 ret = userfunc(od, conn, frame, channel, &userinfo, nummissed, reason);
-
-		aim_info_free(&userinfo);
-	}
-
-	return ret;
-}
-
-/*
- * Subtype 0x000b
- *
- * Possible codes:
- *    AIM_TRANSFER_DENY_DECLINE -- "client has declined transfer"
- *
- */
-int aim_im_denytransfer(OscarData *od, const char *bn, const guchar *cookie, guint16 code)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *tlvlist = NULL;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM)))
-		return -EINVAL;
-
-	byte_stream_new(&bs, 8+2+1+strlen(bn)+6);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x000b, 0x0000, NULL, 0);
-
-	byte_stream_putraw(&bs, cookie, 8);
-
-	byte_stream_put16(&bs, 0x0002); /* channel */
-	byte_stream_put8(&bs, strlen(bn));
-	byte_stream_putstr(&bs, bn);
-
-	aim_tlvlist_add_16(&tlvlist, 0x0003, code);
-	aim_tlvlist_write(&bs, &tlvlist);
-	aim_tlvlist_free(tlvlist);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x000b, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/*
- * Subtype 0x000b.
- * Send confirmation for a channel 2 message (Miranda wants it by default).
- */
-void
-aim_im_send_icq_confirmation(OscarData *od, const char *bn, const guchar *cookie)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	guint32 header_size, data_size;
-	guint16 cookie2 = (guint16)g_random_int();
-
-	purple_debug_misc("oscar", "Sending message ack to %s\n", bn);
-
-	header_size = 8 + 2 + 1 + strlen(bn) + 2;
-	data_size = 2 + 1 + 16 + 4*2 + 2*3 + 4*3 + 1*2 + 2*3 + 1;
-	byte_stream_new(&bs, header_size + data_size);
-
-	/* The message header. */
-	aim_im_puticbm(&bs, cookie, 0x0002, bn);
-	byte_stream_put16(&bs, 0x0003);	/* reason */
-
-	/* The actual message. */
-	byte_stream_putle16(&bs, 0x1b);	/* subheader #1 length */
-	byte_stream_put8(&bs, 0x08);	/* protocol version */
-	byte_stream_putcaps(&bs, OSCAR_CAPABILITY_EMPTY);
-	byte_stream_put32(&bs, 0x3);	/* client features */
-	byte_stream_put32(&bs, 0x0004);	/* DC type */
-	byte_stream_put16(&bs, cookie2);	/* a cookie, chosen by fair dice roll */
-	byte_stream_putle16(&bs, 0x0e);	/* header #2 len? */
-	byte_stream_put16(&bs, cookie2);	/* the same cookie again */
-	byte_stream_put32(&bs, 0);	/* unknown */
-	byte_stream_put32(&bs, 0);	/* unknown */
-	byte_stream_put32(&bs, 0);	/* unknown */
-	byte_stream_put8(&bs, 0x01);	/* plain text message */
-	byte_stream_put8(&bs, 0x00);	/* no message flags */
-	byte_stream_put16(&bs, 0x0000);	/* no icq status */
-	byte_stream_put16(&bs, 0x0100);	/* priority */
-	byte_stream_putle16(&bs, 1);	/* query message len */
-	byte_stream_put8(&bs, 0x00);	/* empty query message */
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x000b, 0x0000, NULL, 0);
-	conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM);
-	g_warn_if_fail(conn);
-	if (conn) {
-		flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x000b,
-			snacid, &bs);
-	}
-	byte_stream_destroy(&bs);
-}
-
-/*
- * Subtype 0x000b - Receive the response from an ICQ status message
- * request (in which case this contains the ICQ status message) or
- * a file transfer or direct IM request was declined.
- */
-static int clientautoresp(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	guint16 channel, reason;
-	char *bn;
-	guchar *cookie;
-	guint8 bnlen;
-	char *xml = NULL;
-	guint16 hdrlen;
-	int curpos;
-	guint16 num1, num2;
-	PurpleAccount *account;
-	PurpleBuddy *buddy;
-	PurplePresence *presence;
-	PurpleStatus *status;
-
-	cookie = byte_stream_getraw(bs, 8);
-	channel = byte_stream_get16(bs);
-	bnlen = byte_stream_get8(bs);
-	bn = byte_stream_getstr(bs, bnlen);
-	reason = byte_stream_get16(bs);
-
-	if (channel == 0x0002)
-	{
-		hdrlen = byte_stream_getle16(bs);
-		if (hdrlen == 27 && bs->len > (27 + 51)) {
-			byte_stream_advance(bs, 51);
-			num1 = byte_stream_getle16(bs);
-			num2 = byte_stream_getle16(bs);
-			purple_debug_misc("oscar", "X-Status: num1 %hu, num2 %hu\n", num1, num2);
-
-			if (num1 == 0x4f00 && num2 == 0x3b00) {
-				byte_stream_advance(bs, 86);
-				curpos = byte_stream_curpos(bs);
-				xml = byte_stream_getstr(bs, bs->len - curpos);
-				purple_debug_misc("oscar", "X-Status: Received XML reply\n");
-				if (xml) {
-					GString *xstatus;
-					char *tmp1, *tmp2, *unescaped_xstatus;
-
-					/* purple_debug_misc("oscar", "X-Status: XML reply: %s\n", xml); */
-
-					xstatus = g_string_new(NULL);
-
-					tmp1 = strstr(xml, "&lt;title&gt;");
-					if (tmp1 != NULL) {
-						tmp1 += 13;
-						tmp2 = strstr(tmp1, "&lt;/title&gt;");
-						if (tmp2 != NULL)
-							g_string_append_len(xstatus, tmp1, tmp2 - tmp1);
-					}
-					tmp1 = strstr(xml, "&lt;desc&gt;");
-					if (tmp1 != NULL) {
-						tmp1 += 12;
-						tmp2 = strstr(tmp1, "&lt;/desc&gt;");
-						if (tmp2 != NULL) {
-							if (xstatus->len > 0 && tmp2 > tmp1)
-								g_string_append(xstatus, " - ");
-							g_string_append_len(xstatus, tmp1, tmp2 - tmp1);
-						}
-					}
-					unescaped_xstatus = purple_unescape_text(xstatus->str);
-					g_string_free(xstatus, TRUE);
-					if (*unescaped_xstatus) {
-						purple_debug_misc("oscar", "X-Status reply: %s\n", unescaped_xstatus);
-						account = purple_connection_get_account(od->gc);
-						buddy = purple_blist_find_buddy(account, bn);
-						presence = purple_buddy_get_presence(buddy);
-						status = purple_presence_get_status(presence, "mood");
-						if (status) {
-							purple_protocol_got_user_status(account, bn,
-									"mood",
-									PURPLE_MOOD_NAME, purple_status_get_attr_string(status, PURPLE_MOOD_NAME),
-									PURPLE_MOOD_COMMENT, unescaped_xstatus, NULL);
-						}
-					}
-					g_free(unescaped_xstatus);
-				} else {
-					purple_debug_misc("oscar", "X-Status: Can't get XML reply string\n");
-				}
-			} else {
-				purple_debug_misc("oscar", "X-Status: 0x0004, 0x000b not an xstatus reply\n");
-			}
-
-		}
-
-	} else if (channel == 0x0004) { /* ICQ message */
-		switch (reason) {
-			case 0x0003: { /* ICQ status message.  Maybe other stuff too, you never know with these people. */
-				guint8 statusmsgtype, *msg;
-				guint16 len;
-				guint32 state;
-
-				len = byte_stream_getle16(bs); /* Should be 0x001b */
-				byte_stream_advance(bs, len); /* Unknown */
-
-				len = byte_stream_getle16(bs); /* Should be 0x000e */
-				byte_stream_advance(bs, len); /* Unknown */
-
-				statusmsgtype = byte_stream_getle8(bs);
-				switch (statusmsgtype) {
-					case 0xe8:
-						state = AIM_ICQ_STATE_AWAY;
-						break;
-					case 0xe9:
-						state = AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_BUSY;
-						break;
-					case 0xea:
-						state = AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_OUT;
-						break;
-					case 0xeb:
-						state = AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_DND | AIM_ICQ_STATE_BUSY;
-						break;
-					case 0xec:
-						state = AIM_ICQ_STATE_CHAT;
-						break;
-					default:
-						state = 0;
-						break;
-				}
-
-				byte_stream_getle8(bs); /* Unknown - 0x03 Maybe this means this is an auto-reply */
-				byte_stream_getle16(bs); /* Unknown - 0x0000 */
-				byte_stream_getle16(bs); /* Unknown - 0x0000 */
-
-				len = byte_stream_getle16(bs);
-				msg = byte_stream_getraw(bs, len);
-
-				if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-					ret = userfunc(od, conn, frame, channel, bn, reason, state, msg);
-
-				g_free(msg);
-			} break;
-
-			default: {
-				if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-					ret = userfunc(od, conn, frame, channel, bn, reason);
-			} break;
-		} /* end switch */
-	}
-
-	g_free(cookie);
-	g_free(bn);
-	g_free(xml);
-
-	return ret;
-}
-
-/*
- * Subtype 0x000c - Receive an ack after sending an ICBM. The ack contains the ICBM header of the message you sent.
- */
-static int msgack(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	guchar *cookie;
-	char *bn;
-	int ret = 0;
-
-	cookie = byte_stream_getraw(bs, 8);
-	byte_stream_get16(bs); /* ch */
-	bn = byte_stream_getstr(bs, byte_stream_get8(bs));
-
-	purple_debug_info("oscar", "Sent message to %s.\n", bn);
-
-	g_free(bn);
-	g_free(cookie);
-
-	return ret;
-}
-
-/*
- * Subtype 0x0010 - Request any offline messages that are waiting for
- * us.  This is the "new" way of handling offline messages which is
- * used for both AIM and ICQ.  The old way is to use the ugly
- * aim_icq_reqofflinemsgs() function, but that is no longer necessary.
- *
- * We set the 0x00000100 flag on the ICBM message parameters, which
- * tells the oscar servers that we support offline messages.  When we
- * set that flag the servers do not automatically send us offline
- * messages.  Instead we must request them using this function.  This
- * should happen after sending the 0x0001/0x0002 "client online" SNAC.
- */
-int aim_im_reqofflinemsgs(OscarData *od)
-{
-	FlapConnection *conn;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, 0x0002)))
-		return -EINVAL;
-
-	aim_genericreq_n(od, conn, SNAC_FAMILY_ICBM, 0x0010);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0014 - Send a mini typing notification (mtn) packet.
- *
- * This is supported by winaim5 and newer, MacAIM bleh and newer, iChat bleh and newer,
- * and Purple 0.60 and newer.
- *
- */
-int aim_im_sendmtn(OscarData *od, guint16 channel, const char *bn, guint16 event)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, 0x0002)))
-		return -EINVAL;
-
-	if (!bn)
-		return -EINVAL;
-
-	byte_stream_new(&bs, 11 + strlen(bn) + 2);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0014, 0x0000, NULL, 0);
-
-	/* ICBM cookie */
-	byte_stream_put32(&bs, 0x00000000);
-	byte_stream_put32(&bs, 0x00000000);
-
-	/*
-	 * Channel (should be 0x0001 for mtn)
-	 */
-	byte_stream_put16(&bs, channel);
-
-	/*
-	 * Dest buddy name
-	 */
-	byte_stream_put8(&bs, strlen(bn));
-	byte_stream_putstr(&bs, bn);
-
-	/*
-	 * Event (should be 0x0000, 0x0001, or 0x0002 for mtn)
-	 */
-	byte_stream_put16(&bs, event);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0014, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0006 - Send eXtra Status request
- */
-int icq_im_xstatus_request(OscarData *od, const char *sn)
-{
-	FlapConnection *conn;
-	aim_snacid_t snacid;
-	guchar cookie[8];
-	GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL;
-	ByteStream bs, header, plugindata;
-	PurpleAccount *account;
-	const char *fmt;
-	char *statxml;
-	int xmllen;
-
-	static const guint8 pluginid[] = {
-		0x09, 0x46, 0x13, 0x49, 0x4C, 0x7F, 0x11, 0xD1,
-		0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00
-	};
-
-	static const guint8 c_plugindata[] = {
-		0x1B, 0x00, 0x0A,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xD1, 0x0E, 0x00, 0xF9, 0xD1, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x01, 0x00,
-		0x01, 0x00, 0x00, 0x4F, 0x00, 0x3B, 0x60, 0xB3, 0xEF, 0xD8, 0x2A, 0x6C, 0x45, 0xA4, 0xE0, 0x9C,
-		0x5A, 0x5E, 0x67, 0xE8, 0x65, 0x08, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x53, 0x63, 0x72, 0x69, 0x70,
-		0x74, 0x20, 0x50, 0x6C, 0x75, 0x67, 0x2D, 0x69, 0x6E, 0x3A, 0x20, 0x52, 0x65, 0x6D, 0x6F, 0x74,
-		0x65, 0x20, 0x4E, 0x6F, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x41,
-		0x72, 0x72, 0x69, 0x76, 0x65, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00
-	};
-
-	if (!od || !(conn = flap_connection_findbygroup(od, 0x0004)))
-		return -EINVAL;
-
-	if (!sn)
-		return -EINVAL;
-
-	fmt = "<N><QUERY>&lt;Q&gt;&lt;PluginID&gt;srvMng&lt;/PluginID&gt;&lt;/Q&gt;</QUERY><NOTIFY>&lt;srv&gt;&lt;id&gt;cAwaySrv&lt;/id&gt;&lt;req&gt;&lt;id&gt;AwayStat&lt;/id&gt;&lt;trans&gt;2&lt;/trans&gt;&lt;senderId&gt;%s&lt;/senderId&gt;&lt;/req&gt;&lt;/srv&gt;</NOTIFY></N>\r\n";
-
-	account = purple_connection_get_account(od->gc);
-
-	statxml = g_strdup_printf(fmt, purple_account_get_username(account));
-	xmllen = strlen(statxml);
-
-	aim_icbm_makecookie(cookie);
-
-	byte_stream_new(&bs, 10 + 8 + 2 + 1 + strlen(sn) + 2
-					  + 2 + 2 + 8 + 16 + 2 + 2 + 2 + 2 + 2
-					  + 2 + 2 + sizeof(c_plugindata) + xmllen
-					  + 2 + 2);
-
-	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
-	aim_im_puticbm(&bs, cookie, 0x0002, sn);
-
-	byte_stream_new(&header, (7*2) + 16 + 8 + 2 + sizeof(c_plugindata) + xmllen); /* TLV 0x0005 Stream + Size */
-	byte_stream_put16(&header, 0x0000); /* Message Type: Request */
-	byte_stream_putraw(&header, cookie, sizeof(cookie)); /* Message ID */
-	byte_stream_putraw(&header, pluginid, sizeof(pluginid)); /* Plugin ID */
-
-	aim_tlvlist_add_16(&inner_tlvlist, 0x000a, 0x0001);
-	aim_tlvlist_add_noval(&inner_tlvlist, 0x000f);
-
-	/* Add Plugin Specific Data */
-	byte_stream_new(&plugindata, (sizeof(c_plugindata) + xmllen));
-	byte_stream_putraw(&plugindata, c_plugindata, sizeof(c_plugindata)); /* Content of TLV 0x2711 */
-	byte_stream_putraw(&plugindata, (const guint8*)statxml, xmllen);
-
-	aim_tlvlist_add_raw(&inner_tlvlist, 0x2711, (sizeof(c_plugindata) + xmllen), plugindata.data);
-
-	aim_tlvlist_write(&header, &inner_tlvlist);
-	aim_tlvlist_free(inner_tlvlist);
-
-	aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&header), header.data);
-	aim_tlvlist_add_noval(&outer_tlvlist, 0x0003); /* Empty TLV 0x0003 */
-
-	aim_tlvlist_write(&bs, &outer_tlvlist);
-
-	purple_debug_misc("oscar", "X-Status Request\n");
-	flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x0006, snacid, &bs, TRUE);
-
-	aim_tlvlist_free(outer_tlvlist);
-	byte_stream_destroy(&header);
-	byte_stream_destroy(&plugindata);
-	byte_stream_destroy(&bs);
-	g_free(statxml);
-
-	return 0;
-}
-
-int icq_relay_xstatus(OscarData *od, const char *sn, const guchar *cookie)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	PurpleAccount *account;
-	PurpleStatus *status;
-	const char *fmt;
-	const char *formatted_msg;
-	char *msg;
-	char *statxml;
-	const char *title;
-	int len;
-
-	static const guint8 plugindata[] = {
-		0x1B, 0x00,
-		0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x01, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xD1, 0x0E, 0x00, 0xF9, 0xD1,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x4F,
-		0x00, 0x3B, 0x60, 0xB3, 0xEF, 0xD8, 0x2A, 0x6C, 0x45, 0xA4, 0xE0,
-		0x9C, 0x5A, 0x5E, 0x67, 0xE8, 0x65, 0x08, 0x00, 0x2A, 0x00, 0x00,
-		0x00, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x20, 0x50, 0x6C, 0x75,
-		0x67, 0x2D, 0x69, 0x6E, 0x3A, 0x20, 0x52, 0x65, 0x6D, 0x6F, 0x74,
-		0x65, 0x20, 0x4E, 0x6F, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
-		0x69, 0x6F, 0x6E, 0x20, 0x41, 0x72, 0x72, 0x69, 0x76, 0x65, 0x00,
-		0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0xF3, 0x01, 0x00, 0x00, 0xEF, 0x01, 0x00, 0x00
-	};
-
-	fmt = "<NR><RES>&lt;ret event='OnRemoteNotification'&gt;&lt;srv&gt;&lt;id&gt;cAwaySrv&lt;/id&gt;&lt;val srv_id='cAwaySrv'&gt;&lt;Root&gt;&lt;CASXtraSetAwayMessage&gt;&lt;/CASXtraSetAwayMessage&gt;&l t;uin&gt;%s&lt;/uin&gt;&lt;index&gt;1&lt;/index&gt;&lt;title&gt;%s&lt;/title&gt;&lt;desc&gt;%s&lt;/desc&gt;&lt;/Root&gt;&lt;/val&gt;&lt;/srv&gt;&lt;srv&gt;&lt;id&gt;cRandomizerSrv&lt;/id&gt;&lt;val srv_id='cRandomizerSrv'&gt;undefined&lt;/val&gt;&lt;/srv&gt;&lt;/ret&gt;</RES></NR>\r\n";
-
-	if (!od || !(conn = flap_connection_findbygroup(od, 0x0002)))
-		return -EINVAL;
-
-	if (!sn)
-		return -EINVAL;
-
-	account = purple_connection_get_account(od->gc);
-	if (!account)
-		return -EINVAL;
-
-	/* if (purple_strequal(account->username, sn))
-		icq_im_xstatus_request(od, sn); */
-
-	status = purple_presence_get_active_status(purple_account_get_presence(account));
-	if (!status)
-		return -EINVAL;
-
-	title = purple_status_get_name(status);
-	if (!title)
-		return -EINVAL;
-
-	formatted_msg = purple_status_get_attr_string(status, "message");
-	if (!formatted_msg)
-		return -EINVAL;
-
-	msg = purple_markup_strip_html(formatted_msg);
-	if (!msg)
-		return -EINVAL;
-
-	statxml = g_strdup_printf(fmt, purple_account_get_username(account), title, msg);
-	len = strlen(statxml);
-
-	purple_debug_misc("oscar", "X-Status AutoReply: %s, %s\n", formatted_msg, msg);
-
-	byte_stream_new(&bs, 10 + 8 + 2 + 1 + strlen(sn) + 2 + sizeof(plugindata) + len); /* 16 extra */
-
-	snacid = aim_cachesnac(od, 0x0004, 0x000b, 0x0000, NULL, 0);
-	aim_im_puticbm(&bs, cookie, 0x0002, sn);
-	byte_stream_put16(&bs, 0x0003);
-	byte_stream_putraw(&bs, plugindata, sizeof(plugindata));
-	byte_stream_putraw(&bs, (const guint8*)statxml, len);
-
-	flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x000b, snacid, &bs, TRUE);
-
-	g_free(statxml);
-	g_free(msg);
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0014 - Receive a mini typing notification (mtn) packet.
- *
- * This is supported by winaim5 and newer, MacAIM bleh and newer, iChat bleh and newer,
- * and Purple 0.60 and newer.
- *
- */
-static int mtn_receive(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	char *bn;
-	guint8 bnlen;
-	guint16 channel, event;
-
-	byte_stream_advance(bs, 8); /* ICBM cookie */
-	channel = byte_stream_get16(bs);
-	bnlen = byte_stream_get8(bs);
-	bn = byte_stream_getstr(bs, bnlen);
-	if (!g_utf8_validate(bn, -1, NULL)) {
-		purple_debug_warning("oscar", "Received SNAC %04hx/%04hx with "
-				"invalid UTF-8 buddy name.\n", snac->family, snac->subtype);
-		g_free(bn);
-		return 1;
-	}
-	event = byte_stream_get16(bs);
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, channel, bn, event);
-
-	g_free(bn);
-
-	return ret;
-}
-
-static int
-snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	if (snac->subtype == 0x0001)
-		return error(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x0005)
-		return aim_im_paraminfo(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x0007)
-		return incomingim(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x000a)
-		return missedcall(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x000b)
-		return clientautoresp(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x000c)
-		return msgack(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x0014)
-		return mtn_receive(od, conn, mod, frame, snac, bs);
-
-	return 0;
-}
-
-int
-msg_modfirst(OscarData *od, aim_module_t *mod)
-{
-	mod->family = SNAC_FAMILY_ICBM;
-	mod->version = 0x0001;
-	mod->toolid = 0x0110;
-	mod->toolversion = 0x0629;
-	mod->flags = 0;
-	strncpy(mod->name, "messaging", sizeof(mod->name));
-	mod->snachandler = snachandler;
-
-	return 0;
-}
--- a/libpurple/protocols/oscar/family_icq.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,792 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Family 0x0015 - Encapsulated ICQ.
- *
- */
-
-#include "glibcompat.h"
-
-#include "encoding.h"
-#include "oscar.h"
-
-#define AIM_ICQ_INFO_REQUEST 0x04b2
-#define AIM_ICQ_ALIAS_REQUEST 0x04ba
-
-static
-int compare_icq_infos(gconstpointer a, gconstpointer b)
-{
-	const struct aim_icq_info* aa = a;
-	const guint16* bb = b;
-	return aa->reqid - *bb;
-}
-
-static void aim_icq_freeinfo(struct aim_icq_info *info) {
-	int i;
-
-	if (!info)
-		return;
-	g_free(info->nick);
-	g_free(info->first);
-	g_free(info->last);
-	g_free(info->email);
-	g_free(info->homecity);
-	g_free(info->homestate);
-	g_free(info->homephone);
-	g_free(info->homefax);
-	g_free(info->homeaddr);
-	g_free(info->mobile);
-	g_free(info->homezip);
-	g_free(info->personalwebpage);
-	if (info->email2)
-		for (i = 0; i < info->numaddresses; i++)
-			g_free(info->email2[i]);
-	g_free(info->email2);
-	g_free(info->workcity);
-	g_free(info->workstate);
-	g_free(info->workphone);
-	g_free(info->workfax);
-	g_free(info->workaddr);
-	g_free(info->workzip);
-	g_free(info->workcompany);
-	g_free(info->workdivision);
-	g_free(info->workposition);
-	g_free(info->workwebpage);
-	g_free(info->info);
-	g_free(info->status_note_title);
-	g_free(info->auth_request_reason);
-}
-
-static
-int error(OscarData *od, aim_modsnac_t *error_snac, ByteStream *bs)
-{
-	aim_snac_t *original_snac = aim_remsnac(od, error_snac->id);
-	guint16 *request_type;
-	GSList *original_info_ptr;
-	struct aim_icq_info *original_info;
-	guint16 reason;
-	gchar *uin;
-
-	if (!original_snac || (original_snac->family != SNAC_FAMILY_ICQ) || !original_snac->data) {
-		purple_debug_misc("oscar", "icq: the original snac for the error packet was not found");
-		g_free(original_snac);
-		return 0;
-	}
-
-	request_type = original_snac->data;
-	original_info_ptr = g_slist_find_custom(od->icq_info, &original_snac->id, compare_icq_infos);
-
-	if (!original_info_ptr) {
-		purple_debug_misc("oscar", "icq: the request info for the error packet was not found");
-		g_free(original_snac);
-		return 0;
-	}
-
-	original_info = original_info_ptr->data;
-
-	reason = byte_stream_get16(bs);
-	uin = g_strdup_printf("%u", original_info->uin);
-	switch (*request_type) {
-		case AIM_ICQ_INFO_REQUEST:
-			oscar_user_info_display_error(od, reason, uin);
-			break;
-		case AIM_ICQ_ALIAS_REQUEST:
-			/* Couldn't retrieve an alias for the buddy requesting authorization; have to make do with UIN only. */
-			if (original_info->for_auth_request)
-				oscar_auth_recvrequest(od->gc, uin, NULL, original_info->auth_request_reason);
-			break;
-		default:
-			purple_debug_misc("oscar", "icq: got an error packet with unknown request type %u", *request_type);
-			break;
-	}
-
-	aim_icq_freeinfo(original_info);
-	od->icq_info = g_slist_remove(od->icq_info, original_info_ptr);
-	g_free(original_snac->data);
-	g_free(original_snac);
-	return 1;
-}
-
-int
-aim_icq_setsecurity(OscarData *od, gboolean auth_required, gboolean webaware)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	int bslen;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
-		return -EINVAL;
-
-	bslen = 2+4+2+2+2+2+2+1+1+1+1+1+1;
-
-	byte_stream_new(&bs, 4 + bslen);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
-
-	/* For simplicity, don't bother using a tlvlist */
-	byte_stream_put16(&bs, 0x0001);
-	byte_stream_put16(&bs, bslen);
-
-	byte_stream_putle16(&bs, bslen - 2);
-	byte_stream_putuid(&bs, od);
-	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
-	byte_stream_putle16(&bs, snacid); /* eh. */
-	byte_stream_putle16(&bs, 0x0c3a); /* shrug. */
-	byte_stream_putle16(&bs, 0x030c);
-	byte_stream_putle16(&bs, 0x0001);
-	byte_stream_putle8(&bs, webaware);
-	byte_stream_putle8(&bs, 0xf8);
-	byte_stream_putle8(&bs, 0x02);
-	byte_stream_putle8(&bs, 0x01);
-	byte_stream_putle8(&bs, 0x00);
-	byte_stream_putle8(&bs, !auth_required);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/**
- * Change your ICQ password.
- *
- * @param od The oscar session
- * @param passwd The new password.  If this is longer than 8 characters it
- *        will be truncated.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_icq_changepasswd(OscarData *od, const char *passwd)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	int bslen, passwdlen;
-
-	if (!passwd)
-		return -EINVAL;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
-		return -EINVAL;
-
-	passwdlen = strlen(passwd);
-	if (passwdlen > MAXICQPASSLEN)
-		passwdlen = MAXICQPASSLEN;
-	bslen = 2+4+2+2+2+2+passwdlen+1;
-
-	byte_stream_new(&bs, 4 + bslen);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
-
-	/* For simplicity, don't bother using a tlvlist */
-	byte_stream_put16(&bs, 0x0001);
-	byte_stream_put16(&bs, bslen);
-
-	byte_stream_putle16(&bs, bslen - 2);
-	byte_stream_putuid(&bs, od);
-	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
-	byte_stream_putle16(&bs, snacid); /* eh. */
-	byte_stream_putle16(&bs, 0x042e); /* shrug. */
-	byte_stream_putle16(&bs, passwdlen+1);
-	byte_stream_putraw(&bs, (const guint8 *)passwd, passwdlen);
-	byte_stream_putle8(&bs, '\0');
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-int aim_icq_getallinfo(OscarData *od, const char *uin)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	int bslen;
-	struct aim_icq_info *info;
-	guint16 request_type = AIM_ICQ_INFO_REQUEST;
-
-	if (!uin || uin[0] < '0' || uin[0] > '9')
-		return -EINVAL;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
-		return -EINVAL;
-
-	bslen = 2 + 4 + 2 + 2 + 2 + 4;
-
-	byte_stream_new(&bs, 4 + bslen);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, &request_type, sizeof(request_type));
-
-	/* For simplicity, don't bother using a tlvlist */
-	byte_stream_put16(&bs, 0x0001);
-	byte_stream_put16(&bs, bslen);
-
-	byte_stream_putle16(&bs, bslen - 2);
-	byte_stream_putuid(&bs, od);
-	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
-	byte_stream_putle16(&bs, snacid); /* eh. */
-	byte_stream_putle16(&bs, request_type); /* shrug. */
-	byte_stream_putle32(&bs, atoi(uin));
-
-	flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs, FALSE);
-
-	byte_stream_destroy(&bs);
-
-	/* Keep track of this request and the ICQ number and request ID */
-	info = g_new0(struct aim_icq_info, 1);
-	info->reqid = snacid;
-	info->uin = atoi(uin);
-	od->icq_info = g_slist_prepend(od->icq_info, info);
-
-	return 0;
-}
-
-int aim_icq_getalias(OscarData *od, const char *uin, gboolean for_auth_request, char *auth_request_reason)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	int bslen;
-	struct aim_icq_info *info;
-	guint16 request_type = AIM_ICQ_ALIAS_REQUEST;
-
-	if (!uin || uin[0] < '0' || uin[0] > '9')
-		return -EINVAL;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
-		return -EINVAL;
-
-	purple_debug_info("oscar", "Requesting ICQ alias for %s\n", uin);
-
-	bslen = 2 + 4 + 2 + 2 + 2 + 4;
-
-	byte_stream_new(&bs, 4 + bslen);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, &request_type, sizeof(request_type));
-
-	/* For simplicity, don't bother using a tlvlist */
-	byte_stream_put16(&bs, 0x0001);
-	byte_stream_put16(&bs, bslen);
-
-	byte_stream_putle16(&bs, bslen - 2);
-	byte_stream_putuid(&bs, od);
-	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
-	byte_stream_putle16(&bs, snacid); /* eh. */
-	byte_stream_putle16(&bs, request_type); /* shrug. */
-	byte_stream_putle32(&bs, atoi(uin));
-
-	flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs, FALSE);
-
-	byte_stream_destroy(&bs);
-
-	/* Keep track of this request and the ICQ number and request ID */
-	info = g_new0(struct aim_icq_info, 1);
-	info->reqid = snacid;
-	info->uin = atoi(uin);
-	info->for_auth_request = for_auth_request;
-	info->auth_request_reason = g_strdup(auth_request_reason);
-	od->icq_info = g_slist_prepend(od->icq_info, info);
-
-	return 0;
-}
-
-/*
- * Send an SMS message.  This is the non-US way.  The US-way is to IM
- * their cell phone number (+19195551234).
- *
- * We basically construct and send an XML message.  The format is:
- * <icq_sms_message>
- *   <destination>full_phone_without_leading_+</destination>
- *   <text>message</text>
- *   <codepage>1252</codepage>
- *   <senders_UIN>self_uin</senders_UIN>
- *   <senders_name>self_name</senders_name>
- *   <delivery_receipt>Yes|No</delivery_receipt>
- *   <time>Wkd, DD Mmm YYYY HH:MM:SS TMZ</time>
- * </icq_sms_message>
- *
- * Yeah hi Peter, whaaaat's happening.  If there's any way to use
- * a codepage other than 1252 that would be great.  Thaaaanks.
- */
-int aim_icq_sendsms(OscarData *od, const char *name, const char *msg, const char *alias)
-{
-	FlapConnection *conn;
-	PurpleAccount *account;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	int bslen, xmllen;
-	char *xml;
-	const char *timestr, *username;
-	time_t t;
-	struct tm *tm;
-	gchar *stripped;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
-		return -EINVAL;
-
-	if (!name || !msg || !alias)
-		return -EINVAL;
-
-	account = purple_connection_get_account(od->gc);
-	username = purple_account_get_username(account);
-
-	time(&t);
-	tm = gmtime(&t);
-	timestr = purple_utf8_strftime("%a, %d %b %Y %T %Z", tm);
-
-	stripped = purple_markup_strip_html(msg);
-
-	/* The length of xml included the null terminating character */
-	xmllen = 209 + strlen(name) + strlen(stripped) + strlen(username) + strlen(alias) + strlen(timestr) + 1;
-
-	xml = g_new(char, xmllen);
-	snprintf(xml, xmllen, "<icq_sms_message>"
-		"<destination>%s</destination>"
-		"<text>%s</text>"
-		"<codepage>1252</codepage>"
-		"<senders_UIN>%s</senders_UIN>"
-		"<senders_name>%s</senders_name>"
-		"<delivery_receipt>Yes</delivery_receipt>"
-		"<time>%s</time>"
-		"</icq_sms_message>",
-		name, stripped, username, alias, timestr);
-
-	bslen = 36 + xmllen;
-
-	byte_stream_new(&bs, 4 + bslen);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
-
-	/* For simplicity, don't bother using a tlvlist */
-	byte_stream_put16(&bs, 0x0001);
-	byte_stream_put16(&bs, bslen);
-
-	byte_stream_putle16(&bs, bslen - 2);
-	byte_stream_putuid(&bs, od);
-	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
-	byte_stream_putle16(&bs, snacid); /* eh. */
-
-	/* From libicq200-0.3.2/src/SNAC-SRV.cpp */
-	byte_stream_putle16(&bs, 0x1482);
-	byte_stream_put16(&bs, 0x0001);
-	byte_stream_put16(&bs, 0x0016);
-	byte_stream_put32(&bs, 0x00000000);
-	byte_stream_put32(&bs, 0x00000000);
-	byte_stream_put32(&bs, 0x00000000);
-	byte_stream_put32(&bs, 0x00000000);
-
-	byte_stream_put16(&bs, 0x0000);
-	byte_stream_put16(&bs, xmllen);
-	byte_stream_putstr(&bs, xml);
-	byte_stream_put8(&bs, 0x00);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	g_free(xml);
-	g_free(stripped);
-
-	return 0;
-}
-
-static void
-gotalias(OscarData *od, struct aim_icq_info *info)
-{
-	PurpleConnection *gc = od->gc;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	PurpleBuddy *b;
-	gchar *utf8 = oscar_utf8_try_convert(account, od, info->nick);
-
-	if (info->for_auth_request) {
-		oscar_auth_recvrequest(gc, g_strdup_printf("%u", info->uin), utf8, info->auth_request_reason);
-	} else {
-		if (utf8 && *utf8) {
-			gchar who[16];
-			g_snprintf(who, sizeof(who), "%u", info->uin);
-			purple_serv_got_alias(gc, who, utf8);
-			if ((b = purple_blist_find_buddy(account, who))) {
-				purple_blist_node_set_string((PurpleBlistNode*)b, "servernick", utf8);
-			}
-		}
-		g_free(utf8);
-	}
-}
-
-/**
- * Subtype 0x0003 - Response to SNAC_FAMILY_ICQ/0x002, contains an ICQesque packet.
- */
-static int
-icqresponse(OscarData *od, aim_modsnac_t *snac, ByteStream *bs)
-{
-	GSList *tlvlist;
-	aim_tlv_t *datatlv;
-	ByteStream qbs;
-	guint32 ouruin;
-	guint16 cmdlen, cmd, reqid;
-
-	if (!(tlvlist = aim_tlvlist_read(bs)) || !(datatlv = aim_tlv_gettlv(tlvlist, 0x0001, 1))) {
-		aim_tlvlist_free(tlvlist);
-		purple_debug_misc("oscar", "corrupt ICQ response\n");
-		return 0;
-	}
-
-	byte_stream_init(&qbs, datatlv->value, datatlv->length);
-
-	cmdlen = byte_stream_getle16(&qbs);
-	ouruin = byte_stream_getle32(&qbs);
-	cmd = byte_stream_getle16(&qbs);
-	reqid = byte_stream_getle16(&qbs);
-
-	purple_debug_misc("oscar", "icq response: %d bytes, %u, 0x%04x, 0x%04x\n", cmdlen, ouruin, cmd, reqid);
-
-	if (cmd == 0x07da) { /* information */
-		guint16 subtype;
-		GSList *info_ptr;
-		struct aim_icq_info *info;
-
-		subtype = byte_stream_getle16(&qbs);
-		byte_stream_advance(&qbs, 1); /* 0x0a */
-
-		/* find other data from the same request */
-		info_ptr = g_slist_find_custom(od->icq_info, &reqid, compare_icq_infos);
-		if (!info_ptr) {
-			struct aim_icq_info *new_info = g_new0(struct aim_icq_info, 1);
-			new_info->reqid = reqid;
-			info_ptr = od->icq_info = g_slist_prepend(od->icq_info, new_info);
-		}
-
-		info = info_ptr->data;
-		switch (subtype) {
-		case 0x00a0: { /* hide ip status */
-			/* nothing */
-		} break;
-
-		case 0x00aa: { /* password change status */
-			/* nothing */
-		} break;
-
-		case 0x00c8: { /* general and "home" information */
-			info->nick = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->first = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->last = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->email = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->homecity = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->homestate = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->homephone = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->homefax = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->homeaddr = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->mobile = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->homezip = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->homecountry = byte_stream_getle16(&qbs);
-			/* 0x0a 00 02 00 */
-			/* 1 byte timezone? */
-			/* 1 byte hide email flag? */
-		} break;
-
-		case 0x00dc: { /* personal information */
-			info->age = byte_stream_getle8(&qbs);
-			info->unknown = byte_stream_getle8(&qbs);
-			info->gender = byte_stream_getle8(&qbs); /* Not specified=0x00, Female=0x01, Male=0x02 */
-			info->personalwebpage = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->birthyear = byte_stream_getle16(&qbs);
-			info->birthmonth = byte_stream_getle8(&qbs);
-			info->birthday = byte_stream_getle8(&qbs);
-			info->language1 = byte_stream_getle8(&qbs);
-			info->language2 = byte_stream_getle8(&qbs);
-			info->language3 = byte_stream_getle8(&qbs);
-			/* 0x00 00 01 00 00 01 00 00 00 00 00 */
-		} break;
-
-		case 0x00d2: { /* work information */
-			info->workcity = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->workstate = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->workphone = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->workfax = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->workaddr = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->workzip = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->workcountry = byte_stream_getle16(&qbs);
-			info->workcompany = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->workdivision = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->workposition = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			byte_stream_advance(&qbs, 2); /* 0x01 00 */
-			info->workwebpage = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-		} break;
-
-		case 0x00e6: { /* additional personal information */
-			info->info = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs)-1);
-		} break;
-
-		case 0x00eb: { /* email address(es) */
-			int i;
-			info->numaddresses = byte_stream_getle16(&qbs);
-			info->email2 = g_new0(char *, info->numaddresses);
-			for (i = 0; i < info->numaddresses; i++) {
-				info->email2[i] = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-				if (i+1 != info->numaddresses)
-					byte_stream_advance(&qbs, 1); /* 0x00 */
-			}
-		} break;
-
-		case 0x00f0: { /* personal interests */
-		} break;
-
-		case 0x00fa: { /* past background and current organizations */
-		} break;
-
-		case 0x0104: { /* alias info */
-			info->nick = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->first = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->last = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			byte_stream_advance(&qbs, byte_stream_getle16(&qbs)); /* email address? */
-			/* Then 0x00 02 00 */
-		} break;
-
-		case 0x010e: { /* unknown */
-			/* 0x00 00 */
-		} break;
-
-		case 0x019a: { /* simple info */
-			byte_stream_advance(&qbs, 2);
-			info->uin = byte_stream_getle32(&qbs);
-			info->nick = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->first = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->last = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			info->email = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
-			/* Then 0x00 02 00 00 00 00 00 */
-		} break;
-
-		/* status note title and send request for status note text */
-		case 0x0fb4: {
-			GSList *tlvlist;
-			aim_tlv_t *tlv;
-			FlapConnection *conn;
-			char *uin = NULL;
-			char *status_note_title = NULL;
-
-			conn = flap_connection_findbygroup(od, 0x0004);
-			if (conn == NULL)
-			{
-				purple_debug_misc("oscar", "icq/0x0fb4: flap connection was not found.\n");
-				break;
-			}
-
-			byte_stream_advance(&qbs, 0x02); /* length */
-			byte_stream_advance(&qbs, 0x2f); /* unknown stuff */
-
-			tlvlist = aim_tlvlist_read(&qbs);
-
-			tlv = aim_tlv_gettlv(tlvlist, 0x0032, 1);
-			if (tlv != NULL)
-				/* Get user number */
-				uin = aim_tlv_getvalue_as_string(tlv);
-
-			tlv = aim_tlv_gettlv(tlvlist, 0x0226, 1);
-			if (tlv != NULL)
-				/* Get status note title */
-				status_note_title = aim_tlv_getvalue_as_string(tlv);
-
-			aim_tlvlist_free(tlvlist);
-
-			if (uin == NULL || status_note_title == NULL)
-			{
-				purple_debug_misc("oscar", "icq/0x0fb4: uin or "
-						"status_note_title was not found\n");
-				g_free(uin);
-				g_free(status_note_title);
-				break;
-			}
-
-			if (status_note_title[0] == '\0')
-			{
-				PurpleAccount *account;
-				PurpleBuddy *buddy;
-				PurplePresence *presence;
-				PurpleStatus *status;
-
-				account = purple_connection_get_account(od->gc);
-				buddy = purple_blist_find_buddy(account, uin);
-				presence = purple_buddy_get_presence(buddy);
-				status = purple_presence_get_active_status(presence);
-
-				purple_protocol_got_user_status(account, uin,
-						purple_status_get_id(status),
-						"message", NULL, NULL);
-
-				g_free(status_note_title);
-			}
-			else
-			{
-				struct aim_icq_info *info;
-				ByteStream bs;
-				guint32 bslen;
-				aim_snacid_t snacid;
-				guchar cookie[8];
-
-				info = g_new0(struct aim_icq_info, 1);
-
-				bslen = 13 + strlen(uin) + 30 + 6 + 4 + 55 + 85 + 4;
-				byte_stream_new(&bs, 4 + bslen);
-
-				snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
-
-				aim_icbm_makecookie(cookie);
-
-				byte_stream_putraw(&bs, cookie, 8); /* ICBM cookie */
-				byte_stream_put16(&bs, 0x0002); /* message channel */
-				byte_stream_put8(&bs, strlen(uin)); /* uin */
-				byte_stream_putstr(&bs, uin);
-
-				byte_stream_put16(&bs, 0x0005); /* rendez vous data */
-				byte_stream_put16(&bs, 0x00b2);
-				byte_stream_put16(&bs, 0x0000); /* request */
-				byte_stream_putraw(&bs, cookie, 8); /* ICBM cookie */
-				byte_stream_put32(&bs, 0x09461349); /* ICQ server relaying */
-				byte_stream_put16(&bs, 0x4c7f);
-				byte_stream_put16(&bs, 0x11d1);
-				byte_stream_put32(&bs, 0x82224445);
-				byte_stream_put32(&bs, 0x53540000);
-
-				byte_stream_put16(&bs, 0x000a); /* unknown TLV */
-				byte_stream_put16(&bs, 0x0002);
-				byte_stream_put16(&bs, 0x0001);
-
-				byte_stream_put16(&bs, 0x000f); /* unknown TLV */
-				byte_stream_put16(&bs, 0x0000);
-
-				byte_stream_put16(&bs, 0x2711); /* extended data */
-				byte_stream_put16(&bs, 0x008a);
-				byte_stream_putle16(&bs, 0x001b); /* length */
-				byte_stream_putle16(&bs, 0x0009); /* version */
-				byte_stream_putle32(&bs, 0x00000000); /* plugin: none */
-				byte_stream_putle32(&bs, 0x00000000);
-				byte_stream_putle32(&bs, 0x00000000);
-				byte_stream_putle32(&bs, 0x00000000);
-				byte_stream_putle16(&bs, 0x0000); /* unknown */
-				byte_stream_putle32(&bs, 0x00000000); /* client capabilities flags */
-				byte_stream_put8(&bs, 0x00); /* unknown */
-				byte_stream_putle16(&bs, 0x0064); /* downcounter? */
-				byte_stream_putle16(&bs, 0x000e); /* length */
-				byte_stream_putle16(&bs, 0x0064); /* downcounter? */
-				byte_stream_putle32(&bs, 0x00000000); /* unknown */
-				byte_stream_putle32(&bs, 0x00000000);
-				byte_stream_putle32(&bs, 0x00000000);
-				byte_stream_put8(&bs, 0x1a); /* message type: plugin message descibed by text string */
-				byte_stream_put8(&bs, 0x00); /* message flags */
-				byte_stream_putle16(&bs, 0x0000); /* status code */
-				byte_stream_putle16(&bs, 0x0001); /* priority code */
-				byte_stream_putle16(&bs, 0x0000); /* text length */
-
-				byte_stream_put8(&bs, 0x3a); /* message dump */
-				byte_stream_put32(&bs, 0x00811a18);
-				byte_stream_put32(&bs, 0xbc0e6c18);
-				byte_stream_put32(&bs, 0x47a5916f);
-				byte_stream_put32(&bs, 0x18dcc76f);
-				byte_stream_put32(&bs, 0x1a010013);
-				byte_stream_put32(&bs, 0x00000041);
-				byte_stream_put32(&bs, 0x77617920);
-				byte_stream_put32(&bs, 0x53746174);
-				byte_stream_put32(&bs, 0x7573204d);
-				byte_stream_put32(&bs, 0x65737361);
-				byte_stream_put32(&bs, 0x67650100);
-				byte_stream_put32(&bs, 0x00000000);
-				byte_stream_put32(&bs, 0x00000000);
-				byte_stream_put32(&bs, 0x00000000);
-				byte_stream_put32(&bs, 0x00000015);
-				byte_stream_put32(&bs, 0x00000000);
-				byte_stream_put32(&bs, 0x0000000d);
-				byte_stream_put32(&bs, 0x00000074);
-				byte_stream_put32(&bs, 0x6578742f);
-				byte_stream_put32(&bs, 0x782d616f);
-				byte_stream_put32(&bs, 0x6c727466);
-
-				byte_stream_put16(&bs, 0x0003); /* server ACK requested */
-				byte_stream_put16(&bs, 0x0000);
-
-				info->uin = atoi(uin);
-				info->status_note_title = status_note_title;
-
-				memcpy(&info->icbm_cookie, cookie, 8);
-
-				od->icq_info = g_slist_prepend(od->icq_info, info);
-
-				flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x0006, snacid, &bs, FALSE);
-
-				byte_stream_destroy(&bs);
-			}
-
-			g_free(uin);
-
-		} break;
-
-		} /* End switch statement */
-
-		if (!(snac->flags & 0x0001)) {
-			if (subtype != 0x0104)
-				oscar_user_info_display_icq(od, info);
-
-			if (info->uin && info->nick)
-				gotalias(od, info);
-
-			aim_icq_freeinfo(info);
-			od->icq_info = g_slist_remove(od->icq_info, info);
-		}
-	}
-
-	aim_tlvlist_free(tlvlist);
-
-	return 1;
-}
-
-static int
-snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	if (snac->subtype == 0x0001)
-		return error(od, snac, bs);
-	else if (snac->subtype == 0x0003)
-		return icqresponse(od, snac, bs);
-
-	return 0;
-}
-
-static void
-icq_shutdown(OscarData *od, aim_module_t *mod)
-{
-	g_slist_free_full(od->icq_info, (GDestroyNotify)aim_icq_freeinfo);
-}
-
-int
-icq_modfirst(OscarData *od, aim_module_t *mod)
-{
-	mod->family = SNAC_FAMILY_ICQ;
-	mod->version = 0x0001;
-	mod->toolid = 0x0110;
-	mod->toolversion = 0x047c;
-	mod->flags = 0;
-	strncpy(mod->name, "icq", sizeof(mod->name));
-	mod->snachandler = snachandler;
-	mod->shutdown = icq_shutdown;
-
-	return 0;
-}
--- a/libpurple/protocols/oscar/family_locate.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1546 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Family 0x0002 - Locate.
- *
- * The functions here are responsible for requesting and parsing information-
- * gathering SNACs.  Or something like that.  This family contains the SNACs
- * for getting and setting info, away messages, directory profile thingy, etc.
- */
-
-#include "oscar.h"
-
-/* Define to log unknown TLVs */
-/* #define LOG_UNKNOWN_TLV */
-
-/*
- * Capability blocks.
- *
- * These are CLSIDs. They should actually be of the form:
- *
- * {0x0946134b, 0x4c7f, 0x11d1,
- *  {0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}},
- *
- * But, eh.
- */
-static const struct {
-	guint64 flag;
-	guint8 data[16];
-} aim_caps[] = {
-
-	/*
-	 * These are in ascending numerical order.
-	 */
-
-	/* Client understands short caps, a UUID of the form
-	 * 0946XXYY-4C7F-11D1-8222-444553540000 where XXYY is the short cap. */
-	{OSCAR_CAPABILITY_SHORTCAPS,
-	 {0x09, 0x46, 0x00, 0x00, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	{OSCAR_CAPABILITY_SECUREIM,
-	 {0x09, 0x46, 0x00, 0x01, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	/* OSCAR_CAPABILITY_XHTML_IM */
-	{OSCAR_CAPABILITY_GENERICUNKNOWN,
-	 {0x09, 0x46, 0x00, 0x02, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	{OSCAR_CAPABILITY_VIDEO,
-	 {0x09, 0x46, 0x01, 0x00, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	/* "Live Video" (SIP/RTC Video) support in Windows AIM 5.5.3501 and newer */
-	{OSCAR_CAPABILITY_LIVEVIDEO,
-	 {0x09, 0x46, 0x01, 0x01, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	/* "Camera" support in Windows AIM 5.5.3501 and newer */
-	{OSCAR_CAPABILITY_CAMERA,
-	 {0x09, 0x46, 0x01, 0x02, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	/* "Microphone" support in Windows AIM 5.5.3501 and newer */
-	/* OSCAR_CAPABILITY_MICROPHONE */
-	{OSCAR_CAPABILITY_GENERICUNKNOWN,
-	 {0x09, 0x46, 0x01, 0x03, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	/* Supports RTC Audio */
-	/* OSCAR_CAPABILITY_RTCAUDIO */
-	{OSCAR_CAPABILITY_GENERICUNKNOWN,
-	 {0x09, 0x46, 0x01, 0x04, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	/* In iChatAV (version numbers...?) */
-	{OSCAR_CAPABILITY_ICHATAV,
-	 {0x09, 0x46, 0x01, 0x05, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x45, 0x53, 0x54, 0x00}},
-
-	/* Supports "new status message features" (Who advertises this one?) */
-	/* OSCAR_CAPABILITY_HOST_STATUS_TEXT_AWARE */
-	{OSCAR_CAPABILITY_GENERICUNKNOWN,
-	 {0x09, 0x46, 0x01, 0x0a, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	/* Supports "see as I type" (Who advertises this one?) */
-	/* OSCAR_CAPABILITY_SEE_AS_I_TYPE */
-	{OSCAR_CAPABILITY_GENERICUNKNOWN,
-	 {0x09, 0x46, 0x01, 0x0b, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	/* Client only asserts caps for services in which it is participating */
-	/* OSCAR_CAPABILITY_SMARTCAPS */
-	{OSCAR_CAPABILITY_GENERICUNKNOWN,
-	 {0x09, 0x46, 0x01, 0xff, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	{OSCAR_CAPABILITY_HIPTOP,
-	 {0x09, 0x46, 0x13, 0x23, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	{OSCAR_CAPABILITY_TALK,
-	 {0x09, 0x46, 0x13, 0x41, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	{OSCAR_CAPABILITY_SENDFILE,
-	 {0x09, 0x46, 0x13, 0x43, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	{OSCAR_CAPABILITY_ICQ_DIRECT,
-	 {0x09, 0x46, 0x13, 0x44, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	{OSCAR_CAPABILITY_DIRECTIM,
-	 {0x09, 0x46, 0x13, 0x45, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	{OSCAR_CAPABILITY_BUDDYICON,
-	 {0x09, 0x46, 0x13, 0x46, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	{OSCAR_CAPABILITY_ADDINS,
-	 {0x09, 0x46, 0x13, 0x47, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	{OSCAR_CAPABILITY_GETFILE,
-	 {0x09, 0x46, 0x13, 0x48, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	{OSCAR_CAPABILITY_ICQSERVERRELAY,
-	 {0x09, 0x46, 0x13, 0x49, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	/*
-	 * Indeed, there are two of these.  The former appears to be correct,
-	 * but in some versions of winaim, the second one is set.  Either they
-	 * forgot to fix endianness, or they made a typo. It really doesn't
-	 * matter which.
-	 */
-	{OSCAR_CAPABILITY_GAMES,
-	 {0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-	{OSCAR_CAPABILITY_GAMES2,
-	 {0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x22, 0x82, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	/* New format of caps (xtraz icons) */
-	{OSCAR_CAPABILITY_NEWCAPS,
-	 {0x09, 0x46, 0x00, 0x00, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	/* Support xtraz statuses */
-	{OSCAR_CAPABILITY_XTRAZ,
-	 {0x1a, 0x09, 0x3c, 0x6c, 0xd7, 0xFD, 0x4e, 0xc5,
-	  0x9d, 0x51, 0xa6, 0x47, 0x4e, 0x34, 0xf5, 0xa0}},
-
-	{OSCAR_CAPABILITY_SENDBUDDYLIST,
-	 {0x09, 0x46, 0x13, 0x4b, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	/*
-	 * Setting this lets AIM users receive messages from ICQ users, and ICQ
-	 * users receive messages from AIM users.  It also lets ICQ users show
-	 * up in buddy lists for AIM users, and AIM users show up in buddy lists
-	 * for ICQ users.  And ICQ privacy/invisibility acts like AIM privacy,
-	 * in that if you add a user to your deny list, you will not be able to
-	 * see them as online (previous you could still see them, but they
-	 * couldn't see you.
-	 */
-	{OSCAR_CAPABILITY_INTEROPERATE,
-	 {0x09, 0x46, 0x13, 0x4d, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	{OSCAR_CAPABILITY_UNICODE,
-	 {0x09, 0x46, 0x13, 0x4e, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	{OSCAR_CAPABILITY_GENERICUNKNOWN,
-	 {0x09, 0x46, 0xf0, 0x03, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	{OSCAR_CAPABILITY_ICHAT_SCREENSHARE,
-	 {0x09, 0x46, 0xf0, 0x04, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	{OSCAR_CAPABILITY_GENERICUNKNOWN,
-	 {0x09, 0x46, 0xf0, 0x05, 0x4c, 0x7f, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	{OSCAR_CAPABILITY_UNICODEOLD,
-	 {0x2e, 0x7a, 0x64, 0x75, 0xfa, 0xdf, 0x4d, 0xc8,
-	  0x88, 0x6f, 0xea, 0x35, 0x95, 0xfd, 0xb6, 0xdf}},
-
-	{OSCAR_CAPABILITY_TYPING,
-	 {0x56, 0x3f, 0xc8, 0x09, 0x0b, 0x6f, 0x41, 0xbd,
-	  0x9f, 0x79, 0x42, 0x26, 0x09, 0xdf, 0xa2, 0xf3}},
-
-	/*
-	 * Chat is oddball.
-	 */
-	{OSCAR_CAPABILITY_CHAT,
-	 {0x74, 0x8f, 0x24, 0x20, 0x62, 0x87, 0x11, 0xd1,
-	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-
-	/* This is added by the servers and it only shows up for ourselves... */
-	{OSCAR_CAPABILITY_GENERICUNKNOWN,
-	 {0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34,
-	  0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x09}},
-
-	{OSCAR_CAPABILITY_ICQRTF,
-	 {0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34,
-	  0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x92}},
-
-	{OSCAR_CAPABILITY_APINFO,
-	 {0xaa, 0x4a, 0x32, 0xb5, 0xf8, 0x84, 0x48, 0xc6,
-	  0xa3, 0xd7, 0x8c, 0x50, 0x97, 0x19, 0xfd, 0x5b}},
-
-	{OSCAR_CAPABILITY_TRILLIANCRYPT,
-	 {0xf2, 0xe7, 0xc7, 0xf4, 0xfe, 0xad, 0x4d, 0xfb,
-	  0xb2, 0x35, 0x36, 0x79, 0x8b, 0xdf, 0x00, 0x00}},
-
-	{OSCAR_CAPABILITY_EMPTY,
-	 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
-
-	{OSCAR_CAPABILITY_HTML_MSGS,
-	 {0x01, 0x38, 0xca, 0x7b, 0x76, 0x9a, 0x49, 0x15,
-	  0x88, 0xf2, 0x13, 0xfc, 0x00, 0x97, 0x9e, 0xa8}},
-
-	{OSCAR_CAPABILITY_LAST,
-	 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
-};
-
-/* Keep this array synchronized with icq_purple_moods. */
-static const struct {
-	const char *mood;
-	guint8 data[16];
-} icq_custom_icons[] = {
-
-	{"thinking",
-	 {0x3f, 0xb0, 0xbd, 0x36, 0xaf, 0x3b, 0x4a, 0x60,
-	  0x9e, 0xef, 0xcf, 0x19, 0x0f, 0x6a, 0x5a, 0x7f}},
-
-	{"busy",
-	 {0x48, 0x8e, 0x14, 0x89, 0x8a, 0xca, 0x4a, 0x08,
-	  0x82, 0xaa, 0x77, 0xce, 0x7a, 0x16, 0x52, 0x08}},
-
-	{"shopping",
-	 {0x63, 0x62, 0x73, 0x37, 0xa0, 0x3f, 0x49, 0xff,
-	  0x80, 0xe5, 0xf7, 0x09, 0xcd, 0xe0, 0xa4, 0xee}},
-
-	/* This was in the original patch, but isn't what the official client
-	 * (ICQ 6) sets when you choose its typewriter icon. */
-	{"typing",
-	 {0x63, 0x4f, 0x6b, 0xd8 ,0xad, 0xd2, 0x4a, 0xa1,
-	  0xaa, 0xb9, 0x11, 0x5b, 0xc2, 0x6d, 0x05, 0xa1}},
-
-	{"question",
-	 {0x63, 0x14, 0x36, 0xff, 0x3f, 0x8a, 0x40, 0xd0,
-	  0xa5, 0xcb, 0x7b, 0x66, 0xe0, 0x51, 0xb3, 0x64}},
-
-	{"angry",
-	 {0x01, 0xd8, 0xd7, 0xee, 0xac, 0x3b, 0x49, 0x2a,
-	  0xa5, 0x8d, 0xd3, 0xd8, 0x77, 0xe6, 0x6b, 0x92}},
-
-	{"plate",
-	 {0xf8, 0xe8, 0xd7, 0xb2, 0x82, 0xc4, 0x41, 0x42,
-	  0x90, 0xf8, 0x10, 0xc6, 0xce, 0x0a, 0x89, 0xa6}},
-
-	{"cinema",
-	 {0x10, 0x7a, 0x9a, 0x18, 0x12, 0x32, 0x4d, 0xa4,
-	  0xb6, 0xcd, 0x08, 0x79, 0xdb, 0x78, 0x0f, 0x09}},
-
-	{"sick",
-	 {0x1f, 0x7a, 0x40, 0x71, 0xbf, 0x3b, 0x4e, 0x60,
-	  0xbc, 0x32, 0x4c, 0x57, 0x87, 0xb0, 0x4c, 0xf1}},
-
-	{"typing",
-	 {0x2c, 0xe0, 0xe4, 0xe5, 0x7c, 0x64, 0x43, 0x70,
-	  0x9c, 0x3a, 0x7a, 0x1c, 0xe8, 0x78, 0xa7, 0xdc}},
-
-	{"suit",
-	 {0xb7, 0x08, 0x67, 0xf5, 0x38, 0x25, 0x43, 0x27,
-	  0xa1, 0xff, 0xcf, 0x4c, 0xc1, 0x93, 0x97, 0x97}},
-
-	{"bathing",
-	 {0x5a, 0x58, 0x1e, 0xa1, 0xe5, 0x80, 0x43, 0x0c,
-	  0xa0, 0x6f, 0x61, 0x22, 0x98, 0xb7, 0xe4, 0xc7}},
-
-	{"tv",
-	 {0x80, 0x53, 0x7d, 0xe2, 0xa4, 0x67, 0x4a, 0x76,
-	  0xb3, 0x54, 0x6d, 0xfd, 0x07, 0x5f, 0x5e, 0xc6}},
-
-	{"excited",
-	 {0x6f, 0x49, 0x30, 0x98, 0x4f, 0x7c, 0x4a, 0xff,
-	  0xa2, 0x76, 0x34, 0xa0, 0x3b, 0xce, 0xae, 0xa7}},
-
-	{"sleeping",
-	 {0x78, 0x5e, 0x8c, 0x48, 0x40, 0xd3, 0x4c, 0x65,
-	  0x88, 0x6f, 0x04, 0xcf, 0x3f, 0x3f, 0x43, 0xdf}},
-
-	{"hiptop",
-	 {0x10, 0x11, 0x17, 0xc9, 0xa3, 0xb0, 0x40, 0xf9,
-	  0x81, 0xac, 0x49, 0xe1, 0x59, 0xfb, 0xd5, 0xd4}},
-
-	{"in_love",
-	 {0xdd, 0xcf, 0x0e, 0xa9, 0x71, 0x95, 0x40, 0x48,
-	  0xa9, 0xc6, 0x41, 0x32, 0x06, 0xd6, 0xf2, 0x80}},
-
-	{"sleepy",
-	 {0x83, 0xc9, 0xb7, 0x8e, 0x77, 0xe7, 0x43, 0x78,
-	  0xb2, 0xc5, 0xfb, 0x6c, 0xfc, 0xc3, 0x5b, 0xec}},
-
-	{"meeting",
-	 {0xf1, 0x8a, 0xb5, 0x2e, 0xdc, 0x57, 0x49, 0x1d,
-	  0x99, 0xdc, 0x64, 0x44, 0x50, 0x24, 0x57, 0xaf}},
-
-	{"phone",
-	 {0x12, 0x92, 0xe5, 0x50, 0x1b, 0x64, 0x4f, 0x66,
-	  0xb2, 0x06, 0xb2, 0x9a, 0xf3, 0x78, 0xe4, 0x8d}},
-
-	{"surfing",
-	 {0xa6, 0xed, 0x55, 0x7e, 0x6b, 0xf7, 0x44, 0xd4,
-	  0xa5, 0xd4, 0xd2, 0xe7, 0xd9, 0x5c, 0xe8, 0x1f}},
-
-	{"mobile",
-	 {0x16, 0x0c, 0x60, 0xbb, 0xdd, 0x44, 0x43, 0xf3,
-	  0x91, 0x40, 0x05, 0x0f, 0x00, 0xe6, 0xc0, 0x09}},
-
-	{"search",
-	 {0xd4, 0xe2, 0xb0, 0xba, 0x33, 0x4e, 0x4f, 0xa5,
-	  0x98, 0xd0, 0x11, 0x7d, 0xbf, 0x4d, 0x3c, 0xc8}},
-
-	{"party",
-	 {0xe6, 0x01, 0xe4, 0x1c, 0x33, 0x73, 0x4b, 0xd1,
-	  0xbc, 0x06, 0x81, 0x1d, 0x6c, 0x32, 0x3d, 0x81}},
-
-	{"coffee",
-	 {0x1b, 0x78, 0xae, 0x31, 0xfa, 0x0b, 0x4d, 0x38,
-	  0x93, 0xd1, 0x99, 0x7e, 0xee, 0xaf, 0xb2, 0x18}},
-
-	{"console",
-	 {0xd4, 0xa6, 0x11, 0xd0, 0x8f, 0x01, 0x4e, 0xc0,
-	  0x92, 0x23, 0xc5, 0xb6, 0xbe, 0xc6, 0xcc, 0xf0}},
-
-	{"internet",
-	 {0x12, 0xd0, 0x7e, 0x3e, 0xf8, 0x85, 0x48, 0x9e,
-	  0x8e, 0x97, 0xa7, 0x2a, 0x65, 0x51, 0xe5, 0x8d}},
-
-	{"cigarette",
-	 {0x64, 0x43, 0xc6, 0xaf, 0x22, 0x60, 0x45, 0x17,
-	  0xb5, 0x8c, 0xd7, 0xdf, 0x8e, 0x29, 0x03, 0x52}},
-
-	{"writing",
-	 {0x00, 0x72, 0xd9, 0x08, 0x4a, 0xd1, 0x43, 0xdd,
-	  0x91, 0x99, 0x6f, 0x02, 0x69, 0x66, 0x02, 0x6f}},
-
-	{"beer",
-	 {0x8c, 0x50, 0xdb, 0xae, 0x81, 0xed, 0x47, 0x86,
-	  0xac, 0xca, 0x16, 0xcc, 0x32, 0x13, 0xc7, 0xb7}},
-
-	{"music",
-	 {0x61, 0xbe, 0xe0, 0xdd, 0x8b, 0xdd, 0x47, 0x5d,
-	  0x8d, 0xee, 0x5f, 0x4b, 0xaa, 0xcf, 0x19, 0xa7}},
-
-	{"studying",
-	 {0x60, 0x9d, 0x52, 0xf8, 0xa2, 0x9a, 0x49, 0xa6,
-	  0xb2, 0xa0, 0x25, 0x24, 0xc5, 0xe9, 0xd2, 0x60}},
-
-	{"working",
-	 {0xba, 0x74, 0xdb, 0x3e, 0x9e, 0x24, 0x43, 0x4b,
-	  0x87, 0xb6, 0x2f, 0x6b, 0x8d, 0xfe, 0xe5, 0x0f}},
-
-	{"restroom",
-	 {0x16, 0xf5, 0xb7, 0x6f, 0xa9, 0xd2, 0x40, 0x35,
-	  0x8c, 0xc5, 0xc0, 0x84, 0x70, 0x3c, 0x98, 0xfa}},
-
-	{NULL,
-	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}
-};
-
-/* Keep this array synchronized with icq_custom_icons. */
-static PurpleMood icq_purple_moods[] = {
-	{"thinking", N_("Thinking"), NULL},
-	{"busy", N_("Busy"), NULL},
-	{"shopping", N_("Shopping"), NULL},
-	/* This was in the original patch, but isn't what the official client
-	 * (ICQ 6) sets when you choose its typewriter icon. */
-	{"typing", NULL, NULL},
-	{"question", N_("Questioning"), NULL},
-	{"angry", N_("Angry"), NULL},
-	{"plate", N_("Eating"), NULL},
-	{"cinema", N_("Watching a movie"), NULL},
-	{"sick", N_("Sick"), NULL},
-	{"typing", N_("Typing"), NULL},
-	{"suit", N_("At the office"), NULL},
-	{"bathing", N_("Taking a bath"), NULL},
-	{"tv", N_("Watching TV"), NULL},
-	{"excited", N_("Having fun"), NULL},
-	{"sleeping", N_("Sleeping"), NULL},
-	{"hiptop", N_("Using a PDA"), NULL},
-	{"in_love", N_("In love"), NULL},
-	/* Sleepy / Tired */
-	{"sleepy", N_("Sleepy"), NULL},
-	{"meeting", N_("Meeting friends"), NULL},
-	{"phone", N_("On the phone"), NULL},
-	{"surfing", N_("Surfing"), NULL},
-	/* "I am mobile." / "John is mobile." */
-	{"mobile", N_("Mobile"), NULL},
-	{"search", N_("Searching the web"), NULL},
-	{"party", N_("At a party"), NULL},
-	{"coffee", N_("Having Coffee"), NULL},
-	/* Playing video games */
-	{"console", N_("Gaming"), NULL},
-	{"internet", N_("Browsing the web"), NULL},
-	{"cigarette", N_("Smoking"), NULL},
-	{"writing", N_("Writing"), NULL},
-	/* Drinking [Alcohol] */
-	{"beer", N_("Drinking"), NULL},
-	{"music", N_("Listening to music"), NULL},
-	{"studying", N_("Studying"), NULL},
-	{"working", N_("Working"), NULL},
-	{"restroom", N_("In the restroom"), NULL},
-	/* Mark the last record. */
-	{NULL, NULL, NULL},
-};
-
-
-/*
- * Add the userinfo to our linked list.  If we already have userinfo
- * for this buddy, then just overwrite parts of the old data.
- *
- * @param userinfo Contains the new information for the buddy.
- */
-static void
-aim_locate_adduserinfo(OscarData *od, aim_userinfo_t *userinfo)
-{
-	aim_userinfo_t *cur;
-
-	cur = aim_locate_finduserinfo(od, userinfo->bn);
-
-	if (cur == NULL) {
-		cur = (aim_userinfo_t *)g_new0(aim_userinfo_t, 1);
-		cur->bn = g_strdup(userinfo->bn);
-		cur->next = od->locate.userinfo;
-		od->locate.userinfo = cur;
-	}
-
-	cur->warnlevel = userinfo->warnlevel;
-	cur->idletime = userinfo->idletime;
-	if (userinfo->flags != 0)
-		cur->flags = userinfo->flags;
-	if (userinfo->createtime != 0)
-		cur->createtime = userinfo->createtime;
-	if (userinfo->membersince != 0)
-		cur->membersince = userinfo->membersince;
-	if (userinfo->onlinesince != 0)
-		cur->onlinesince = userinfo->onlinesince;
-	if (userinfo->sessionlen != 0)
-		cur->sessionlen = userinfo->sessionlen;
-	if (userinfo->capabilities != 0)
-		cur->capabilities = userinfo->capabilities;
-
-	cur->present |= userinfo->present;
-
-	if (userinfo->iconcsumlen > 0) {
-		g_free(cur->iconcsum);
-		cur->iconcsum = (guint8 *)g_malloc(userinfo->iconcsumlen);
-		memcpy(cur->iconcsum, userinfo->iconcsum, userinfo->iconcsumlen);
-		cur->iconcsumlen = userinfo->iconcsumlen;
-	}
-
-	if (userinfo->info != NULL) {
-		g_free(cur->info);
-		g_free(cur->info_encoding);
-		if (userinfo->info_len > 0) {
-			cur->info = (char *)g_malloc(userinfo->info_len);
-			memcpy(cur->info, userinfo->info, userinfo->info_len);
-		} else
-			cur->info = NULL;
-		cur->info_encoding = g_strdup(userinfo->info_encoding);
-		cur->info_len = userinfo->info_len;
-	}
-
-	if (userinfo->status != NULL) {
-		g_free(cur->status);
-		g_free(cur->status_encoding);
-		if (userinfo->status_len > 0) {
-			cur->status = (char *)g_malloc(userinfo->status_len);
-			memcpy(cur->status, userinfo->status, userinfo->status_len);
-		} else
-			cur->status = NULL;
-		if (userinfo->status_encoding != NULL)
-			cur->status_encoding = g_strdup(userinfo->status_encoding);
-		else
-			cur->status_encoding = NULL;
-		cur->status_len = userinfo->status_len;
-	}
-
-	if (userinfo->itmsurl != NULL) {
-		g_free(cur->itmsurl);
-		g_free(cur->itmsurl_encoding);
-		if (userinfo->itmsurl_len > 0) {
-			cur->itmsurl = (char *)g_malloc(userinfo->itmsurl_len);
-			memcpy(cur->itmsurl, userinfo->itmsurl, userinfo->itmsurl_len);
-		} else
-			cur->itmsurl = NULL;
-		if (userinfo->itmsurl_encoding != NULL)
-			cur->itmsurl_encoding = g_strdup(userinfo->itmsurl_encoding);
-		else
-			cur->itmsurl_encoding = NULL;
-		cur->itmsurl_len = userinfo->itmsurl_len;
-	}
-
-	if (userinfo->away != NULL) {
-		g_free(cur->away);
-		g_free(cur->away_encoding);
-		if (userinfo->away_len > 0) {
-			cur->away = (char *)g_malloc(userinfo->away_len);
-			memcpy(cur->away, userinfo->away, userinfo->away_len);
-		} else
-			cur->away = NULL;
-		cur->away_encoding = g_strdup(userinfo->away_encoding);
-		cur->away_len = userinfo->away_len;
-
-	} else {
-		/*
-		 * We don't have an away message specified in this user_info
-		 * block, so clear any cached away message now.
-		 */
-		g_free(cur->away);
-		cur->away = NULL;
-		g_free(cur->away_encoding);
-		cur->away_encoding = NULL;
-		cur->away_len = 0;
-	}
-}
-
-aim_userinfo_t *aim_locate_finduserinfo(OscarData *od, const char *bn) {
-	aim_userinfo_t *cur = NULL;
-
-	if (bn == NULL)
-		return NULL;
-
-	cur = od->locate.userinfo;
-
-	while (cur != NULL) {
-		if (oscar_util_name_compare(cur->bn, bn) == 0)
-			return cur;
-		cur = cur->next;
-	}
-
-	return NULL;
-}
-
-guint64
-aim_locate_getcaps(OscarData *od, ByteStream *bs, int len)
-{
-	guint64 flags = 0;
-	int offset;
-
-	for (offset = 0; byte_stream_bytes_left(bs) && (offset < len); offset += 0x10) {
-		guint8 *cap;
-		int i, identified;
-
-		cap = byte_stream_getraw(bs, 0x10);
-
-		for (i = 0, identified = 0; !(aim_caps[i].flag & OSCAR_CAPABILITY_LAST); i++) {
-			if (memcmp(&aim_caps[i].data, cap, 0x10) == 0) {
-				flags |= aim_caps[i].flag;
-				identified++;
-				break; /* should only match once... */
-			}
-		}
-
-		if (!identified)
-			purple_debug_misc("oscar", "unknown capability: {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
-					cap[0], cap[1], cap[2], cap[3],
-					cap[4], cap[5],
-					cap[6], cap[7],
-					cap[8], cap[9],
-					cap[10], cap[11], cap[12], cap[13],
-					cap[14], cap[15]);
-		g_free(cap);
-	}
-
-	return flags;
-}
-
-static const char *
-aim_receive_custom_icon(OscarData *od, ByteStream *bs, int len)
-{
-	int offset;
-	const char *result = NULL;
-
-	for (offset = 0; byte_stream_bytes_left(bs) && (offset < len); offset += 0x10) {
-		/* check wheather this capability is a custom user icon */
-		guint8 *cap;
-		int i;
-
-		cap = byte_stream_getraw(bs, 0x10);
-
-		for (i = 0; icq_custom_icons[i].mood; i++) {
-			if (memcmp(&icq_custom_icons[i].data, cap, 0x10) == 0) {
-				purple_debug_misc("oscar", "Custom status icon: %s\n", icq_purple_moods[i].description);
-				result = icq_custom_icons[i].mood;
-				break; /* should only match once... */
-			}
-		}
-		g_free(cap);
-	}
-
-	return result;
-}
-
-guint64
-aim_locate_getcaps_short(OscarData *od, ByteStream *bs, int len)
-{
-	guint64 flags = 0;
-	int offset;
-
-	for (offset = 0; byte_stream_bytes_left(bs) && (offset < len); offset += 0x02) {
-		guint8 *cap;
-		int i, identified;
-
-		cap = byte_stream_getraw(bs, 0x02);
-
-		for (i = 0, identified = 0; !(aim_caps[i].flag & OSCAR_CAPABILITY_LAST); i++) {
-			if (memcmp(&aim_caps[i].data[2], cap, 0x02) == 0) {
-				flags |= aim_caps[i].flag;
-				identified++;
-				break; /* should only match once... */
-			}
-		}
-
-		if (!identified)
-			purple_debug_misc("oscar", "unknown short capability: {%02x%02x}\n", cap[0], cap[1]);
-
-		g_free(cap);
-	}
-
-	return flags;
-}
-
-int
-byte_stream_putcaps(ByteStream *bs, guint64 caps)
-{
-	int i;
-
-	if (!bs)
-		return -EINVAL;
-
-	for (i = 0; byte_stream_bytes_left(bs); i++) {
-		if (aim_caps[i].flag == OSCAR_CAPABILITY_LAST)
-			break;
-
-		if (caps & aim_caps[i].flag)
-			byte_stream_putraw(bs, aim_caps[i].data, 0x10);
-	}
-	return 0;
-}
-
-#ifdef LOG_UNKNOWN_TLV
-static void
-dumptlv(OscarData *od, guint16 type, ByteStream *bs, guint8 len)
-{
-	int i;
-
-	if (!od || !bs || !len)
-		return;
-
-	purple_debug_misc("oscar", "userinfo:   type  =0x%04x\n", type);
-	purple_debug_misc("oscar", "userinfo:   length=0x%04x\n", len);
-	purple_debug_misc("oscar", "userinfo:   value:\n");
-
-	for (i = 0; i < len; i++) {
-		if ((i % 8) == 0)
-			purple_debug_misc("oscar", "\nuserinfo:        ");
-		purple_debug_misc("oscar", "0x%2x ", byte_stream_get8(bs));
-	}
-
-	purple_debug_misc("oscar", "\n");
-
-	return;
-}
-#endif
-
-void
-aim_info_free(aim_userinfo_t *info)
-{
-	g_free(info->bn);
-	g_free(info->iconcsum);
-	g_free(info->info);
-	g_free(info->info_encoding);
-	g_free(info->status);
-	g_free(info->status_encoding);
-	g_free(info->itmsurl);
-	g_free(info->itmsurl_encoding);
-	g_free(info->away);
-	g_free(info->away_encoding);
-}
-
-static const struct {
-	char *icqmood;
-	const char *mood;
-} icqmoods[] = {
-	{"icqmood0",  "shopping"},
-	{"icqmood1",  "bathing"},
-	{"icqmood2",  "sleepy"},
-	{"icqmood3",  "party"},
-	{"icqmood4",  "beer"},
-	{"icqmood5",  "thinking"},
-	{"icqmood6",  "plate"},
-	{"icqmood7",  "tv"},
-	{"icqmood8",  "meeting"},
-	{"icqmood9",  "coffee"},
-	{"icqmood10", "music"},
-	{"icqmood11", "suit"},
-	{"icqmood12", "cinema"},
-	{"icqmood13", "smile-big"},
-	{"icqmood14", "phone"},
-	{"icqmood15", "console"},
-	{"icqmood16", "studying"},
-	{"icqmood17", "sick"},
-	{"icqmood18", "sleeping"},
-	{"icqmood19", "surfing"},
-	{"icqmood20", "internet"},
-	{"icqmood21", "working"},
-	{"icqmood22", "typing"},
-	{"icqmood23", "angry"},
-	{NULL, 0}
-
-};
-
-/*
- * AIM is fairly regular about providing user info.  This is a generic
- * routine to extract it in its standard form.
- */
-int
-aim_info_extract(OscarData *od, ByteStream *bs, aim_userinfo_t *outinfo)
-{
-	int curtlv, tlvcnt;
-	guint8 bnlen;
-
-	if (!bs || !outinfo)
-		return -EINVAL;
-
-	/* Clear out old data first */
-	memset(outinfo, 0x00, sizeof(aim_userinfo_t));
-
-	/*
-	 * Username.  Stored as an unterminated string prepended with a
-	 * byte containing its length.
-	 */
-	bnlen = byte_stream_get8(bs);
-	outinfo->bn = byte_stream_getstr(bs, bnlen);
-
-	/*
-	 * Warning Level.  Stored as an unsigned short.
-	 */
-	outinfo->warnlevel = byte_stream_get16(bs);
-
-	/*
-	 * TLV Count. Unsigned short representing the number of
-	 * Type-Length-Value triples that follow.
-	 */
-	tlvcnt = byte_stream_get16(bs);
-
-	/*
-	 * Parse out the Type-Length-Value triples as they're found.
-	 */
-	for (curtlv = 0; curtlv < tlvcnt; curtlv++) {
-		guint16 type, length;
-		int endpos;
-		int curpos;
-
-		type = byte_stream_get16(bs);
-		length = byte_stream_get16(bs);
-		curpos = byte_stream_curpos(bs);
-		endpos = curpos + MIN(length, byte_stream_bytes_left(bs));
-
-		if (type == 0x0001) {
-			/*
-			 * User flags
-			 *
-			 * Specified as any of the following ORed together:
-			 *      0x0001  Unconfirmed account
-			 *      0x0002  Unknown bit 2
-			 *      0x0004  AOL Main Service user
-			 *      0x0008  Unknown bit 4
-			 *      0x0010  Free (AIM) user
-			 *      0x0020  Away
-			 *      0x0040  ICQ user (AIM bit also set)
-			 *      0x0080  Mobile device
-			 *      0x0400  Bot (like ActiveBuddy)
-			 */
-			outinfo->flags = byte_stream_get16(bs);
-			outinfo->present |= AIM_USERINFO_PRESENT_FLAGS;
-
-		} else if (type == 0x0002) {
-			/*
-			 * Account creation time
-			 *
-			 * The time/date that the user originally registered for
-			 * the service, stored in time_t format.
-			 *
-			 * I'm not sure how this differs from type 5 ("member
-			 * since").
-			 *
-			 * Note: This is the field formerly known as "member
-			 * since".  All these years and I finally found out
-			 * that I got the name wrong.
-			 */
-			outinfo->createtime = byte_stream_get32(bs);
-			outinfo->present |= AIM_USERINFO_PRESENT_CREATETIME;
-
-		} else if (type == 0x0003) {
-			/*
-			 * On-Since date
-			 *
-			 * The time/date that the user started their current
-			 * session, stored in time_t format.
-			 */
-			outinfo->onlinesince = byte_stream_get32(bs);
-			outinfo->present |= AIM_USERINFO_PRESENT_ONLINESINCE;
-
-		} else if (type == 0x0004) {
-			/*
-			 * Idle time
-			 *
-			 * Number of minutes since the user actively used the
-			 * service.
-			 *
-			 * Note that the client tells the server when to start
-			 * counting idle times, so this may or may not be
-			 * related to reality.
-			 */
-			outinfo->idletime = byte_stream_get16(bs);
-			outinfo->present |= AIM_USERINFO_PRESENT_IDLE;
-
-		} else if (type == 0x0005) {
-			/*
-			 * Member since date
-			 *
-			 * The time/date that the user originally registered for
-			 * the service, stored in time_t format.
-			 *
-			 * This is sometimes sent instead of type 2 ("account
-			 * creation time"), particularly in the self-info.
-			 * And particularly for ICQ?
-			 */
-			outinfo->membersince = byte_stream_get32(bs);
-			outinfo->present |= AIM_USERINFO_PRESENT_MEMBERSINCE;
-
-		} else if (type == 0x0006) {
-			/*
-			 * ICQ Online Status
-			 *
-			 * ICQ's Away/DND/etc "enriched" status. Some decoding
-			 * of values done by Scott <darkagl@pcnet.com>
-			 */
-			byte_stream_get16(bs);
-			outinfo->icqinfo.status = byte_stream_get16(bs);
-			outinfo->present |= AIM_USERINFO_PRESENT_ICQEXTSTATUS;
-
-		} else if (type == 0x0008) {
-			/*
-			 * Client type, or some such.
-			 */
-
-		} else if (type == 0x000a) {
-			/*
-			 * ICQ User IP Address
-			 *
-			 * Ahh, the joy of ICQ security.
-			 */
-			outinfo->icqinfo.ipaddr = byte_stream_get32(bs);
-			outinfo->present |= AIM_USERINFO_PRESENT_ICQIPADDR;
-
-		} else if (type == 0x000c) {
-			/*
-			 * Random crap containing the IP address,
-			 * apparently a port number, and some Other Stuff.
-			 *
-			 * Format is:
-			 * 4 bytes - Our IP address, 0xc0 a8 01 2b for 192.168.1.43
-			 */
-			byte_stream_getrawbuf(bs, outinfo->icqinfo.crap, 0x25);
-			outinfo->present |= AIM_USERINFO_PRESENT_ICQDATA;
-
-		} else if (type == 0x000d) {
-			PurpleAccount *account = purple_connection_get_account(od->gc);
-			const char *mood;
-
-			/*
-			 * OSCAR Capability information
-			 */
-			outinfo->capabilities |= aim_locate_getcaps(od, bs, length);
-			outinfo->present |= AIM_USERINFO_PRESENT_CAPABILITIES;
-			byte_stream_setpos(bs, curpos);
-
-			mood = aim_receive_custom_icon(od, bs, length);
-			if (mood)
-				purple_protocol_got_user_status(account, outinfo->bn, "mood",
-						PURPLE_MOOD_NAME, mood,
-						NULL);
-			else
-				purple_protocol_got_user_status_deactive(account, outinfo->bn, "mood");
-
-		} else if (type == 0x000e) {
-			/*
-			 * AOL capability information
-			 */
-
-		} else if ((type == 0x000f) || (type == 0x0010)) {
-			/*
-			 * Type = 0x000f: Session Length. (AIM)
-			 * Type = 0x0010: Session Length. (AOL)
-			 *
-			 * The duration, in seconds, of the user's current
-			 * session.
-			 *
-			 * Which TLV type this comes in depends on the
-			 * service the user is using (AIM or AOL).
-			 */
-			outinfo->sessionlen = byte_stream_get32(bs);
-			outinfo->present |= AIM_USERINFO_PRESENT_SESSIONLEN;
-
-		} else if (type == 0x0014) {
-			/*
-			 * My instance number.
-			 */
-			byte_stream_get8(bs);
-
-		} else if (type == 0x0019) {
-			/*
-			 * OSCAR short capability information.  A shortened
-			 * form of the normal capabilities.
-			 */
-			outinfo->capabilities |= aim_locate_getcaps_short(od, bs, length);
-			outinfo->present |= AIM_USERINFO_PRESENT_CAPABILITIES;
-
-		} else if (type == 0x001a) {
-			/*
-			 * Type = 0x001a
-			 *
-			 * AOL short capability information.  A shortened
-			 * form of the normal capabilities.
-			 */
-
-		} else if (type == 0x001b) {
-			/*
-			 * Encryption certification MD5 checksum.
-			 */
-
-		} else if (type == 0x001d) {
-			/*
-			 * Buddy icon information and status/available messages.
-			 *
-			 * This almost seems like the AIM protocol guys gave
-			 * the iChat guys a Type, and the iChat guys tried to
-			 * cram as much cool shit into it as possible.  Then
-			 * the Windows AIM guys were like, "hey, that's
-			 * pretty neat, let's copy those prawns."
-			 *
-			 * In that spirit, this can contain a custom message,
-			 * kind of like an away message, but you're not away
-			 * (it's called an "available" message).  Or it can
-			 * contain information about the buddy icon the user
-			 * has stored on the server.
-			 */
-			guint16 type2;
-			guint8 number2, length2;
-			int endpos2;
-
-			/*
-			 * Continue looping as long as we're able to read type2,
-			 * number2, and length2.
-			 */
-			while (byte_stream_curpos(bs) + 4 <= endpos) {
-				type2 = byte_stream_get16(bs);
-				number2 = byte_stream_get8(bs);
-				length2 = byte_stream_get8(bs);
-
-				endpos2 = byte_stream_curpos(bs) + MIN(length2, byte_stream_bytes_left(bs));
-
-				switch (type2) {
-					case 0x0000: { /* This is an official buddy icon? */
-						/* This is always 5 bytes of "0x02 01 d2 04 72"? */
-					} break;
-
-					case 0x0001: { /* A buddy icon checksum */
-						if ((length2 > 0) && ((number2 == 0x00) || (number2 == 0x01))) {
-							g_free(outinfo->iconcsum);
-							outinfo->iconcsumtype = number2;
-							outinfo->iconcsum = byte_stream_getraw(bs, length2);
-							outinfo->iconcsumlen = length2;
-						}
-					} break;
-
-					case 0x0002: { /* A status/available message */
-						g_free(outinfo->status);
-						g_free(outinfo->status_encoding);
-						if (length2 >= 4) {
-							outinfo->status_len = byte_stream_get16(bs);
-							outinfo->status = byte_stream_getstr(bs, outinfo->status_len);
-							if (byte_stream_get16(bs) == 0x0001) { /* We have an encoding */
-								byte_stream_get16(bs);
-								outinfo->status_encoding = byte_stream_getstr(bs, byte_stream_get16(bs));
-							} else {
-								/* No explicit encoding, client should use UTF-8 */
-								outinfo->status_encoding = NULL;
-							}
-						} else {
-							byte_stream_advance(bs, length2);
-							outinfo->status_len = 0;
-							outinfo->status = g_strdup("");
-							outinfo->status_encoding = NULL;
-						}
-					} break;
-
-					case 0x0009: { /* An iTunes Music Store link */
-						g_free(outinfo->itmsurl);
-						g_free(outinfo->itmsurl_encoding);
-						if (length2 >= 4) {
-							outinfo->itmsurl_len = byte_stream_get16(bs);
-							outinfo->itmsurl = byte_stream_getstr(bs, outinfo->itmsurl_len);
-							if (byte_stream_get16(bs) == 0x0001) {
-								/* We have an encoding */
-								byte_stream_get16(bs);
-								outinfo->itmsurl_encoding = byte_stream_getstr(bs, byte_stream_get16(bs));
-							} else {
-								/* No explicit encoding, client should use UTF-8 */
-								outinfo->itmsurl_encoding = NULL;
-							}
-						} else {
-							byte_stream_advance(bs, length2);
-							outinfo->itmsurl_len = 0;
-							outinfo->itmsurl = g_strdup("");
-							outinfo->itmsurl_encoding = NULL;
-						}
-					} break;
-
-					case 0x000e: { /* ICQ mood */
-						PurpleAccount *account = purple_connection_get_account(od->gc);
-						char *icqmood;
-						gint32 i;
-						const char *mood = NULL;
-
-						icqmood = byte_stream_getstr(bs, length2);
-
-						/* icqmood = "" means X-Status
-						 * with no mood icon. */
-						if (*icqmood) {
-							for (i = 0; icqmoods[i].icqmood; i++) {
-								if (purple_strequal(icqmood, icqmoods[i].icqmood)) {
-									mood = icqmoods[i].mood;
-									break; /* should only match once... */
-								}
-							}
-
-							if (!mood)
-								purple_debug_warning("oscar", "Unknown icqmood: %s\n", icqmood);
-						}
-						g_free(icqmood);
-
-						if (mood)
-							purple_protocol_got_user_status(account, outinfo->bn, "mood",
-									PURPLE_MOOD_NAME, mood,
-									NULL);
-						else
-							purple_protocol_got_user_status_deactive(account, outinfo->bn, "mood");
-					} break;
-				}
-
-				/* Save ourselves. */
-				byte_stream_setpos(bs, endpos2);
-			}
-
-		} else if (type == 0x001e) {
-			/*
-			 * Always four bytes, but it doesn't look like an int.
-			 */
-
-		} else if (type == 0x001f) {
-			/*
-			 * Upper bytes of user flags.  Can be any size
-			 *
-			 * Seen on a buddy using DeadAIM.  Data was 4 bytes:
-			 * 0x00 00 00 10
-			 */
-
-		} else if (type == 0x0023) {
-			/*
-			 * Last Buddy Feed update time, in seconds since the epoch.
-			 */
-
-		} else if (type == 0x0026) {
-			/*
-			 * Time that the profile was set, in seconds since the epoch.
-			 */
-
-		} else if (type == 0x0027) {
-			/*
-			 * Time that the away message was set, in seconds since the epoch.
-			 */
-
-		} else if (type == 0x002a) {
-			/*
-			 * Country code based on GeoIP data.
-			 */
-
-		} else {
-
-			/*
-			 * Reaching here indicates that either AOL has
-			 * added yet another TLV for us to deal with,
-			 * or the parsing has gone Terribly Wrong.
-			 *
-			 * Either way, inform the owner and attempt
-			 * recovery.
-			 *
-			 */
-#ifdef LOG_UNKNOWN_TLV
-			purple_debug_misc("oscar", "userinfo: **warning: unexpected TLV:\n");
-			purple_debug_misc("oscar", "userinfo:   bn    =%s\n", outinfo->bn);
-			dumptlv(od, type, bs, length);
-#endif
-		}
-
-		/* Save ourselves. */
-		byte_stream_setpos(bs, endpos);
-	}
-
-	aim_locate_adduserinfo(od, outinfo);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0001
- */
-static int
-error(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	aim_snac_t *snac2;
-	guint16 reason;
-	char *bn;
-
-	snac2 = aim_remsnac(od, snac->id);
-	if (!snac2) {
-		purple_debug_misc("oscar", "locate error: received response from unknown request!\n");
-		return 0;
-	}
-
-	if ((snac2->family != SNAC_FAMILY_LOCATE) && (snac2->type != 0x0015)) {
-		purple_debug_misc("oscar", "locate error: received response from invalid request! %d\n", snac2->family);
-		g_free(snac2->data);
-		g_free(snac2);
-		return 0;
-	}
-
-	bn = snac2->data;
-	if (!bn) {
-		purple_debug_misc("oscar", "locate error: received response from request without a buddy name!\n");
-		g_free(snac2);
-		return 0;
-	}
-
-	reason = byte_stream_get16(bs);
-
-	oscar_user_info_display_error(od, reason, bn);
-
-	g_free(snac2->data);
-	g_free(snac2);
-
-	return 1;
-}
-
-/*
- * Subtype 0x0002
- *
- * Request Location services rights.
- *
- */
-int
-aim_locate_reqrights(OscarData *od)
-{
-	FlapConnection *conn;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
-		return -EINVAL;
-
-	aim_genericreq_n_snacid(od, conn, SNAC_FAMILY_LOCATE, SNAC_SUBTYPE_LOCATE_REQRIGHTS);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0003
- *
- * Normally contains:
- *   t(0001)  - short containing max profile length (value = 1024)
- *   t(0002)  - short - unknown (value = 16) [max MIME type length?]
- *   t(0003)  - short - unknown (value = 10)
- *   t(0004)  - short - unknown (value = 2048) [ICQ only?]
- */
-static int
-rights(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	GSList *tlvlist;
-	aim_rxcallback_t userfunc;
-	int ret = 0;
-	guint16 maxsiglen = 0;
-
-	tlvlist = aim_tlvlist_read(bs);
-
-	if (aim_tlv_gettlv(tlvlist, 0x0001, 1))
-		maxsiglen = aim_tlv_get16(tlvlist, 0x0001, 1);
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, maxsiglen);
-
-	aim_tlvlist_free(tlvlist);
-
-	return ret;
-}
-
-/*
- * Subtype 0x0004
- *
- * Gives BOS your profile.
- *
- * profile_encoding and awaymsg_encoding MUST be set if profile or
- * away are set, respectively, and their value may or may not be
- * restricted to a few choices.  I am currently aware of:
- *
- * us-ascii		Just that
- * unicode-2-0		UTF-16BE
- *
- * profile_len and awaymsg_len MUST be set similarly, and they MUST
- * be the length of their respective strings in bytes.
- *
- * To get the previous behavior of awaymsg == "" un-setting the away
- * message, set awaymsg non-NULL and awaymsg_len to 0 (this is the
- * obvious equivalent).
- *
- */
-int
-aim_locate_setprofile(OscarData *od,
-				  const char *profile_encoding, const gchar *profile, const int profile_len,
-				  const char *awaymsg_encoding, const gchar *awaymsg, const int awaymsg_len)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *tlvlist = NULL;
-	char *encoding;
-	static const char defencoding[] = {"text/aolrtf; charset=\"%s\""};
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
-		return -EINVAL;
-
-	if (!profile && !awaymsg)
-		return -EINVAL;
-
-	if ((profile && profile_encoding == NULL) || (awaymsg && awaymsg_len && awaymsg_encoding == NULL)) {
-		return -EINVAL;
-	}
-
-	/* Build the packet first to get real length */
-	if (profile) {
-		encoding = g_strdup_printf(defencoding, profile_encoding);
-		aim_tlvlist_add_str(&tlvlist, 0x0001, encoding);
-		aim_tlvlist_add_raw(&tlvlist, 0x0002, profile_len, (const guchar *)profile);
-		g_free(encoding);
-	}
-
-	/*
-	 * So here's how this works:
-	 *   - You are away when you have a non-zero-length type 4 TLV stored.
-	 *   - You become unaway when you clear the TLV with a zero-length
-	 *       type 4 TLV.
-	 *   - If you do not send the type 4 TLV, your status does not change
-	 *       (that is, if you were away, you'll remain away).
-	 */
-	if (awaymsg) {
-		if (awaymsg_len) {
-			encoding = g_strdup_printf(defencoding, awaymsg_encoding);
-			aim_tlvlist_add_str(&tlvlist, 0x0003, encoding);
-			aim_tlvlist_add_raw(&tlvlist, 0x0004, awaymsg_len, (const guchar *)awaymsg);
-			g_free(encoding);
-		} else
-			aim_tlvlist_add_noval(&tlvlist, 0x0004);
-	}
-
-	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0004, 0x0000, NULL, 0);
-
-	aim_tlvlist_write(&bs, &tlvlist);
-	aim_tlvlist_free(tlvlist);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0004, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0004 - Set your client's capabilities.
- */
-int
-aim_locate_setcaps(OscarData *od, guint64 caps)
-{
-	FlapConnection *conn;
-	PurpleAccount *account = purple_connection_get_account(od->gc);
-	PurplePresence *presence = purple_account_get_presence(account);
-	PurpleStatus *status = purple_presence_get_status(presence, "mood");
-	const char *mood = purple_status_get_attr_string(status, PURPLE_MOOD_NAME);
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *tlvlist = NULL;
-
-	if (!(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
-		return -EINVAL;
-
-	aim_tlvlist_add_caps(&tlvlist, 0x0005, caps, mood);
-
-	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0004, 0x0000, NULL, 0);
-
-	aim_tlvlist_write(&bs, &tlvlist);
-	aim_tlvlist_free(tlvlist);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0004, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/* Subtype 0x0006 */
-static int
-userinfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_userinfo_t *userinfo, *userinfo2;
-	GSList *tlvlist;
-	aim_tlv_t *tlv = NULL;
-
-	userinfo = g_new0(aim_userinfo_t, 1);
-	aim_info_extract(od, bs, userinfo);
-	tlvlist = aim_tlvlist_read(bs);
-
-	/* Profile will be 1 and 2 */
-	userinfo->info_encoding = aim_tlv_getstr(tlvlist, 0x0001, 1);
-	if ((tlv = aim_tlv_gettlv(tlvlist, 0x0002, 1))) {
-		userinfo->info = (char *)g_malloc(tlv->length);
-		memcpy(userinfo->info, tlv->value, tlv->length);
-		userinfo->info_len = tlv->length;
-	}
-
-	/* Away message will be 3 and 4 */
-	userinfo->away_encoding = aim_tlv_getstr(tlvlist, 0x0003, 1);
-	if ((tlv = aim_tlv_gettlv(tlvlist, 0x0004, 1))) {
-		userinfo->away = (char *)g_malloc(tlv->length);
-		memcpy(userinfo->away, tlv->value, tlv->length);
-		userinfo->away_len = tlv->length;
-	}
-
-	/* Caps will be 5 */
-	if ((tlv = aim_tlv_gettlv(tlvlist, 0x0005, 1))) {
-		ByteStream cbs;
-		PurpleAccount *account = purple_connection_get_account(od->gc);
-		const char *mood;
-
-		byte_stream_init(&cbs, tlv->value, tlv->length);
-		userinfo->capabilities = aim_locate_getcaps(od, &cbs, tlv->length);
-		byte_stream_rewind(&cbs);
-		userinfo->present = AIM_USERINFO_PRESENT_CAPABILITIES;
-
-		mood = aim_receive_custom_icon(od, &cbs, tlv->length);
-		if (mood)
-			purple_protocol_got_user_status(account, userinfo->bn, "mood",
-					PURPLE_MOOD_NAME, mood,
-					NULL);
-		else
-			purple_protocol_got_user_status_deactive(account, userinfo->bn, "mood");
-	}
-	aim_tlvlist_free(tlvlist);
-
-	aim_locate_adduserinfo(od, userinfo);
-	userinfo2 = aim_locate_finduserinfo(od, userinfo->bn);
-	aim_info_free(userinfo);
-	g_free(userinfo);
-
-	/* Show the info to the user */
-	oscar_user_info_display_aim(od, userinfo2);
-
-	return ret;
-}
-
-/*
- * Subtype 0x0015 - Request the info of a user using the short method.  This is
- * what iChat uses.  It normally is VERY leniently rate limited.
- *
- * @param bn The buddy name whose info you wish to request.
- * @param flags The bitmask which specifies the type of info you wish to request.
- *        0x00000001 - Info/profile.
- *        0x00000002 - Away message.
- *        0x00000004 - Capabilities.
- *        0x00000008 - Certification.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int
-aim_locate_getinfoshort(OscarData *od, const char *bn, guint32 flags)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !bn)
-		return -EINVAL;
-
-	byte_stream_new(&bs, 4 + 1 + strlen(bn));
-	byte_stream_put32(&bs, flags);
-	byte_stream_put8(&bs, strlen(bn));
-	byte_stream_putstr(&bs, bn);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0015, 0x0000, bn, strlen(bn)+1);
-	flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_LOCATE, 0x0015, snacid, &bs, FALSE);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-static int
-snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	if (snac->subtype == 0x0001)
-		return error(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x0003)
-		return rights(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x0006)
-		return userinfo(od, conn, mod, frame, snac, bs);
-
-	return 0;
-}
-
-static void
-locate_shutdown(OscarData *od, aim_module_t *mod)
-{
-	aim_userinfo_t *del;
-
-	while (od->locate.userinfo) {
-		del = od->locate.userinfo;
-		od->locate.userinfo = od->locate.userinfo->next;
-		aim_info_free(del);
-		g_free(del);
-	}
-}
-
-int
-locate_modfirst(OscarData *od, aim_module_t *mod)
-{
-	mod->family = SNAC_FAMILY_LOCATE;
-	mod->version = 0x0001;
-	mod->toolid = 0x0110;
-	mod->toolversion = 0x0629;
-	mod->flags = 0;
-	strncpy(mod->name, "locate", sizeof(mod->name));
-	mod->snachandler = snachandler;
-	mod->shutdown = locate_shutdown;
-
-	return 0;
-}
-
-const char*
-icq_get_custom_icon_description(const char *mood)
-{
-	int i;
-
-	if (!(mood && *mood))
-		return NULL;
-
-	for (i = 0; icq_custom_icons[i].mood; i++) {
-		/* We check that description is not NULL to exclude
-		 * duplicates, like the typing duplicate. */
-		if (icq_purple_moods[i].description &&
-		    purple_strequal(mood, icq_custom_icons[i].mood)) {
-			return icq_purple_moods[i].description;
-		}
-	}
-
-	return NULL;
-}
-
-guint8*
-icq_get_custom_icon_data(const char *mood)
-{
-	int i;
-
-	if (!(mood && *mood))
-		return NULL;
-
-	for (i = 0; icq_custom_icons[i].mood; i++) {
-		/* We check that description is not NULL to exclude
-		 * duplicates, like the typing duplicate. */
-		if (icq_purple_moods[i].description &&
-		    purple_strequal(mood, icq_custom_icons[i].mood)) {
-			return (guint8 *)icq_custom_icons[i].data;
-		}
-	}
-	return NULL;
-}
-
-PurpleMood*
-icq_get_purple_moods(PurpleAccount *account)
-{
-	return icq_purple_moods;
-}
--- a/libpurple/protocols/oscar/family_oservice.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,994 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Family 0x0001 - This is a very special group.  All connections support
- * this group, as it does some particularly good things (like rate limiting).
- */
-
-#include "oscar.h"
-
-/*
- * Each time we make a FLAP connection to an oscar server the server gives
- * us a list of rate classes.  Each rate class has different properties for
- * how frequently we can send SNACs in that rate class before we become
- * throttled or disconnected.
- *
- * The server also gives us a list of every available SNAC and tells us which
- * rate class it's in.  There are a lot of different SNACs, so this list can be
- * fairly large.  One important characteristic of these rate classes is that
- * currently (and since at least 2004) most SNACs are in the same rate class.
- *
- * One optimization we can do to save memory is to only keep track of SNACs
- * that are in classes other than this default rate class.  So if we try to
- * look up a SNAC and it's not in our hash table then we can assume that it's
- * in the default rate class.
- */
-#define OSCAR_DEFAULT_RATECLASS 1
-
-/* Subtype 0x0002 - Client Online */
-void
-aim_srv_clientready(OscarData *od, FlapConnection *conn)
-{
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *cur;
-
-	byte_stream_new(&bs, 1142);
-
-	/*
-	 * Send only the tool versions that the server cares about (that it
-	 * marked as supporting in the server ready SNAC).
-	 */
-	for (cur = conn->groups; cur != NULL; cur = cur->next)
-	{
-		aim_module_t *mod;
-
-		if ((mod = aim__findmodulebygroup(od, GPOINTER_TO_UINT(cur->data))))
-		{
-			byte_stream_put16(&bs, mod->family);
-			byte_stream_put16(&bs, mod->version);
-			byte_stream_put16(&bs, mod->toolid);
-			byte_stream_put16(&bs, mod->toolversion);
-		}
-	}
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0002, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0002, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-}
-
-/*
- * Subtype 0x0003 - Host Online
- *
- * See comments in conn.c about how the group associations are supposed
- * to work, and how they really work.
- *
- * This info probably doesn't even need to make it to the client.
- *
- * We don't actually call the client here.  This starts off the connection
- * initialization routine required by all AIM connections.  The next time
- * the client is called is the CONNINITDONE callback, which should be
- * shortly after the rate information is acknowledged.
- *
- */
-static int
-hostonline(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int group;
-
-	while (byte_stream_bytes_left(bs))
-	{
-		group = byte_stream_get16(bs);
-		conn->groups = g_slist_prepend(conn->groups, GUINT_TO_POINTER(group));
-	}
-
-	/*
-	 * Next step is in the Host Versions handler.
-	 *
-	 * Note that we must send this before we request rates, since
-	 * the format of the rate information depends on the versions we
-	 * give it.
-	 *
-	 */
-	aim_srv_setversions(od, conn);
-
-	return 1;
-}
-
-/* Subtype 0x0004 - Service request */
-void
-aim_srv_requestnew(OscarData *od, guint16 serviceid)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *tlvlist = NULL;
-
-	conn = flap_connection_findbygroup(od, SNAC_FAMILY_BOS);
-	if(!conn)
-		return;
-
-	byte_stream_new(&bs, 6);
-
-	byte_stream_put16(&bs, serviceid);
-
-	if (od->use_ssl)
-		/* Request SSL Connection */
-		aim_tlvlist_add_noval(&tlvlist, 0x008c);
-
-	aim_tlvlist_write(&bs, &tlvlist);
-	aim_tlvlist_free(tlvlist);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0004, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0004, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-}
-
-/*
- * Join a room of name roomname.  This is the first step to joining an
- * already created room.  It's basically a Service Request for
- * family 0x000e, with a little added on to specify the exchange and room
- * name.
- */
-int
-aim_chat_join(OscarData *od, guint16 exchange, const char *roomname, guint16 instance)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *tlvlist = NULL;
-	struct chatsnacinfo csi;
-
-	conn = flap_connection_findbygroup(od, SNAC_FAMILY_BOS);
-	if (!conn || !roomname || roomname[0] == '\0')
-		return -EINVAL;
-
-	byte_stream_new(&bs, 506);
-
-	memset(&csi, 0, sizeof(csi));
-	csi.exchange = exchange;
-	g_strlcpy(csi.name, roomname, sizeof(csi.name));
-	csi.instance = instance;
-
-	/*
-	 * Requesting service chat (0x000e)
-	 */
-	byte_stream_put16(&bs, 0x000e);
-
-	aim_tlvlist_add_chatroom(&tlvlist, 0x0001, exchange, roomname, instance);
-
-	if (od->use_ssl)
-		/* Request SSL Connection */
-		aim_tlvlist_add_noval(&tlvlist, 0x008c);
-
-	aim_tlvlist_write(&bs, &tlvlist);
-	aim_tlvlist_free(tlvlist);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0004, 0x0000, &csi, sizeof(csi));
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0004, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/* Subtype 0x0005 - Redirect */
-static int
-redirect(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	struct aim_redirect_data redir;
-	aim_rxcallback_t userfunc;
-	GSList *tlvlist;
-	aim_snac_t *origsnac = NULL;
-	int ret = 0;
-
-	memset(&redir, 0, sizeof(redir));
-
-	tlvlist = aim_tlvlist_read(bs);
-
-	if (!aim_tlv_gettlv(tlvlist, 0x000d, 1) ||
-			!aim_tlv_gettlv(tlvlist, 0x0005, 1) ||
-			!aim_tlv_gettlv(tlvlist, 0x0006, 1)) {
-		aim_tlvlist_free(tlvlist);
-		return 0;
-	}
-
-	redir.group = aim_tlv_get16(tlvlist, 0x000d, 1);
-	redir.ip = aim_tlv_getstr(tlvlist, 0x0005, 1);
-	redir.cookielen = aim_tlv_gettlv(tlvlist, 0x0006, 1)->length;
-	redir.cookie = (guchar *)aim_tlv_getstr(tlvlist, 0x0006, 1);
-	redir.ssl_cert_cn = aim_tlv_getstr(tlvlist, 0x008d, 1);
-	redir.use_ssl = aim_tlv_get8(tlvlist, 0x008e, 1);
-
-	/* Fetch original SNAC so we can get csi if needed */
-	origsnac = aim_remsnac(od, snac->id);
-
-	if ((redir.group == SNAC_FAMILY_CHAT) && origsnac) {
-		struct chatsnacinfo *csi = (struct chatsnacinfo *)origsnac->data;
-
-		redir.chat.exchange = csi->exchange;
-		redir.chat.room = csi->name;
-		redir.chat.instance = csi->instance;
-	}
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, &redir);
-
-	g_free((void *)redir.ip);
-	g_free((void *)redir.cookie);
-	g_free((void *)redir.ssl_cert_cn);
-
-	if (origsnac)
-		g_free(origsnac->data);
-	g_free(origsnac);
-
-	aim_tlvlist_free(tlvlist);
-
-	return ret;
-}
-
-/* Subtype 0x0006 - Request Rate Information. */
-void
-aim_srv_reqrates(OscarData *od, FlapConnection *conn)
-{
-	aim_genericreq_n_snacid(od, conn, SNAC_FAMILY_OSERVICE, 0x0006);
-}
-
-/*
- * OSCAR defines several 'rate classes'.  Each class has separate
- * rate limiting properties (limit level, alert level, disconnect
- * level, etc), and a set of SNAC family/type pairs associated with
- * it.  The rate classes, their limiting properties, and the definitions
- * of which SNACs belong to which class are defined in the
- * Rate Response packet at login to each host.
- *
- * Logically, all rate offenses within one class count against further
- * offenses for other SNACs in the same class (ie, sending messages
- * too fast will limit the number of user info requests you can send,
- * since those two SNACs are in the same rate class).
- *
- * Since the rate classes are defined dynamically at login, the values
- * below may change. But they seem to be fairly constant.
- *
- * Currently, BOS defines five rate classes, with the commonly used
- * members as follows...
- *
- *  Rate class 0x0001:
- *	- Everything thats not in any of the other classes
- *
- *  Rate class 0x0002:
- *	- Buddy list add/remove
- *	- Permit list add/remove
- *	- Deny list add/remove
- *
- *  Rate class 0x0003:
- *	- User information requests
- *	- Outgoing ICBMs
- *
- *  Rate class 0x0004:
- *	- A few unknowns: 2/9, 2/b, and f/2
- *
- *  Rate class 0x0005:
- *	- Chat room create
- *	- Outgoing chat ICBMs
- *
- * The only other thing of note is that class 5 (chat) has slightly looser
- * limiting properties than class 3 (normal messages).  But thats just a
- * small bit of trivia for you.
- *
- * The last thing that needs to be learned about the rate limiting
- * system is how the actual numbers relate to the passing of time.  This
- * seems to be a big mystery.
- *
- * See joscar's javadoc for the RateClassInfo class for a great
- * explanation.  You might be able to find it at
- * http://dscoder.com/RateClassInfo.html
- */
-
-static struct rateclass *
-rateclass_find(GSList *rateclasses, guint16 id)
-{
-	GSList *tmp;
-
-	for (tmp = rateclasses; tmp != NULL; tmp = tmp->next)
-	{
-		struct rateclass *rateclass;
-		rateclass = tmp->data;
-		if (rateclass->classid == id)
-			return rateclass;
-	}
-
-	return NULL;
-}
-
-/* Subtype 0x0007 - Rate Parameters */
-static int
-rateresp(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	guint16 numclasses, i;
-	aim_rxcallback_t userfunc;
-
-	/*
-	 * First are the parameters for each rate class.
-	 */
-	numclasses = byte_stream_get16(bs);
-	for (i = 0; i < numclasses; i++)
-	{
-		struct rateclass *rateclass;
-		guint32 delta;
-		struct timeval now;
-
-		gettimeofday(&now, NULL);
-		rateclass = g_new(struct rateclass, 1);
-
-		rateclass->classid = byte_stream_get16(bs);
-		rateclass->windowsize = byte_stream_get32(bs);
-		rateclass->clear = byte_stream_get32(bs);
-		rateclass->alert = byte_stream_get32(bs);
-		rateclass->limit = byte_stream_get32(bs);
-		rateclass->disconnect = byte_stream_get32(bs);
-		rateclass->current = byte_stream_get32(bs);
-		rateclass->max = byte_stream_get32(bs);
-		if (mod->version >= 3) {
-			delta = byte_stream_get32(bs);
-			rateclass->dropping_snacs = byte_stream_get8(bs);
-		} else {
-			delta = 0;
-			rateclass->dropping_snacs = 0;
-		}
-
-		rateclass->last.tv_sec = now.tv_sec - delta / 1000;
-		rateclass->last.tv_usec = now.tv_usec - (delta % 1000) * 1000;
-
-		conn->rateclasses = g_slist_prepend(conn->rateclasses, rateclass);
-
-		if (rateclass->classid == OSCAR_DEFAULT_RATECLASS)
-			conn->default_rateclass = rateclass;
-	}
-	conn->rateclasses = g_slist_reverse(conn->rateclasses);
-
-	/*
-	 * Then the members of each class.
-	 */
-	for (i = 0; i < numclasses; i++)
-	{
-		guint16 classid, count;
-		struct rateclass *rateclass;
-		int j;
-
-		classid = byte_stream_get16(bs);
-		count = byte_stream_get16(bs);
-
-		if (classid == OSCAR_DEFAULT_RATECLASS) {
-			/*
-			 * Don't bother adding these SNACs to the hash table.  See the
-			 * comment for OSCAR_DEFAULT_RATECLASS at the top of this file.
-			 */
-			byte_stream_advance(bs, 4 * count);
-			continue;
-		}
-
-		rateclass = rateclass_find(conn->rateclasses, classid);
-
-		for (j = 0; j < count; j++)
-		{
-			guint16 group, subtype;
-
-			group = byte_stream_get16(bs);
-			subtype = byte_stream_get16(bs);
-
-			if (rateclass != NULL)
-				g_hash_table_insert(conn->rateclass_members,
-						GUINT_TO_POINTER((group << 16) + subtype),
-						rateclass);
-		}
-	}
-
-	/*
-	 * We don't pass the rate information up to the client, as it really
-	 * doesn't care.  The information is stored in the connection, however
-	 * so that we can do rate limiting management when sending SNACs.
-	 */
-
-	/*
-	 * Subscribe to rate change information for all rate classes.
-	 */
-	aim_srv_rates_addparam(od, conn);
-
-	/*
-	 * Finally, tell the client it's ready to go...
-	 */
-	if ((userfunc = aim_callhandler(od, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE)))
-		userfunc(od, conn, frame);
-
-	return 1;
-}
-
-/* Subtype 0x0008 - Add Rate Parameter */
-void
-aim_srv_rates_addparam(OscarData *od, FlapConnection *conn)
-{
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *tmp;
-
-	byte_stream_new(&bs, 502);
-
-	for (tmp = conn->rateclasses; tmp != NULL; tmp = tmp->next)
-	{
-		struct rateclass *rateclass;
-		rateclass = tmp->data;
-		byte_stream_put16(&bs, rateclass->classid);
-	}
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0008, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0008, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-}
-
-/* Subtype 0x000a - Rate Change */
-static int
-ratechange(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	guint16 code, classid;
-	struct rateclass *rateclass;
-	guint32 delta;
-	struct timeval now;
-	static const char *codes[5] = {
-		"invalid",
-		"change",
-		"warning",
-		"limit",
-		"limit cleared",
-	};
-
-	gettimeofday(&now, NULL);
-	code = byte_stream_get16(bs);
-	classid = byte_stream_get16(bs);
-
-	rateclass = rateclass_find(conn->rateclasses, classid);
-	if (rateclass == NULL)
-		/* This should never really happen */
-		return 0;
-
-	rateclass->windowsize = byte_stream_get32(bs);
-	rateclass->clear = byte_stream_get32(bs);
-	rateclass->alert = byte_stream_get32(bs);
-	rateclass->limit = byte_stream_get32(bs);
-	rateclass->disconnect = byte_stream_get32(bs);
-	rateclass->current = byte_stream_get32(bs);
-	rateclass->max = byte_stream_get32(bs);
-	if (mod->version >= 3) {
-		delta = byte_stream_get32(bs);
-		rateclass->dropping_snacs = byte_stream_get8(bs);
-	} else {
-		delta = 0;
-		rateclass->dropping_snacs = 0;
-	}
-
-	rateclass->last.tv_sec = now.tv_sec - delta / 1000;
-	rateclass->last.tv_usec = now.tv_usec - (delta % 1000) * 1000;
-
-	purple_debug_misc("oscar", "rate %s (param ID 0x%04hx): curavg = %u, "
-			"maxavg = %u, alert at %u, clear warning at %u, limit at %u, "
-			"disconnect at %u, delta is %u, dropping is %u (window size = %u)\n",
-			(code < 5) ? codes[code] : codes[0], rateclass->classid,
-			rateclass->current, rateclass->max, rateclass->alert,
-			rateclass->clear, rateclass->limit, rateclass->disconnect,
-			delta, rateclass->dropping_snacs, rateclass->windowsize);
-
-	if (code == AIM_RATE_CODE_LIMIT) {
-		purple_debug_warning("oscar",  "The last action you attempted "
-				"could not be performed because you are over the rate "
-				"limit. Please wait 10 seconds and try again.\n");
-	}
-
-	return 1;
-}
-
-/*
- * How Migrations work.
- *
- * The server sends a Server Pause message, which the client should respond to
- * with a Server Pause Ack, which contains the families it needs on this
- * connection. The server will send a Migration Notice with an IP address, and
- * then disconnect. Next the client should open the connection and send the
- * cookie.  Repeat the normal login process and pretend this never happened.
- *
- * The Server Pause contains no data.
- *
- */
-
-/* Subtype 0x000b - Service Pause */
-static int
-serverpause(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame);
-
-	return ret;
-}
-
-/* Subtype 0x000d - Service Resume */
-static int
-serverresume(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame);
-
-	return ret;
-}
-
-/* Subtype 0x000e - Request self-info */
-void
-aim_srv_reqpersonalinfo(OscarData *od, FlapConnection *conn)
-{
-	aim_genericreq_n_snacid(od, conn, SNAC_FAMILY_OSERVICE, 0x000e);
-}
-
-/* Subtype 0x000f - Self User Info */
-static int
-selfinfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	aim_userinfo_t userinfo;
-
-	aim_info_extract(od, bs, &userinfo);
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, &userinfo);
-
-	aim_info_free(&userinfo);
-
-	return ret;
-}
-
-/* Subtype 0x0010 - Evil Notification */
-static int
-evilnotify(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	guint16 newevil;
-	aim_userinfo_t userinfo;
-
-	memset(&userinfo, 0, sizeof(aim_userinfo_t));
-
-	newevil = byte_stream_get16(bs);
-
-	if (byte_stream_bytes_left(bs))
-		aim_info_extract(od, bs, &userinfo);
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, newevil, &userinfo);
-
-	aim_info_free(&userinfo);
-
-	return ret;
-}
-
-/*
- * Subtype 0x0011 - Idle Notification
- *
- * Should set your current idle time in seconds.  Note that this should
- * never be called consecutively with a non-zero idle time.  That makes
- * OSCAR do funny things.  Instead, just set it once you go idle, and then
- * call it again with zero when you're back.
- *
- */
-void
-aim_srv_setidle(OscarData *od, guint32 idletime)
-{
-	FlapConnection *conn;
-
-	conn = flap_connection_findbygroup(od, SNAC_FAMILY_BOS);
-	if(!conn)
-		return;
-
-	aim_genericreq_l(od, conn, SNAC_FAMILY_OSERVICE, 0x0011, &idletime);
-}
-
-/*
- * Subtype 0x0012 - Service Migrate
- *
- * This is the final SNAC sent on the original connection during a migration.
- * It contains the IP and cookie used to connect to the new server, and
- * optionally a list of the SNAC groups being migrated.
- *
- */
-static int
-migrate(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	aim_rxcallback_t userfunc;
-	int ret = 0;
-	guint16 groupcount, i;
-	GSList *tlvlist;
-	char *ip = NULL;
-	aim_tlv_t *cktlv;
-
-	/*
-	 * Apparently there's some fun stuff that can happen right here. The
-	 * migration can actually be quite selective about what groups it
-	 * moves to the new server.  When not all the groups for a connection
-	 * are migrated, or they are all migrated but some groups are moved
-	 * to a different server than others, it is called a bifurcated
-	 * migration.
-	 *
-	 * Let's play dumb and not support that.
-	 *
-	 */
-	groupcount = byte_stream_get16(bs);
-	for (i = 0; i < groupcount; i++) {
-		guint16 group;
-
-		group = byte_stream_get16(bs);
-
-		purple_debug_misc("oscar", "bifurcated migration unsupported -- group 0x%04x\n", group);
-	}
-
-	tlvlist = aim_tlvlist_read(bs);
-
-	if (aim_tlv_gettlv(tlvlist, 0x0005, 1))
-		ip = aim_tlv_getstr(tlvlist, 0x0005, 1);
-
-	cktlv = aim_tlv_gettlv(tlvlist, 0x0006, 1);
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, ip, cktlv ? cktlv->value : NULL);
-
-	aim_tlvlist_free(tlvlist);
-	g_free(ip);
-
-	return ret;
-}
-
-/* Subtype 0x0013 - Message of the Day */
-static int
-motd(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	aim_rxcallback_t userfunc;
-	char *msg = NULL;
-	int ret = 0;
-	GSList *tlvlist;
-	guint16 id;
-
-	/*
-	 * Code.
-	 *
-	 * Valid values:
-	 *   1 Mandatory upgrade
-	 *   2 Advisory upgrade
-	 *   3 System bulletin
-	 *   4 Nothing's wrong ("top o the world" -- normal)
-	 *   5 Lets-break-something.
-	 *
-	 */
-	id = byte_stream_get16(bs);
-
-	/*
-	 * TLVs follow
-	 */
-	tlvlist = aim_tlvlist_read(bs);
-
-	msg = aim_tlv_getstr(tlvlist, 0x000b, 1);
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, id, msg);
-
-	g_free(msg);
-
-	aim_tlvlist_free(tlvlist);
-
-	return ret;
-}
-
-/*
- * Subtype 0x0017 - Set client versions
- *
- * If you've seen the clientonline/clientready SNAC you're probably
- * wondering what the point of this one is.  And that point seems to be
- * that the versions in the client online SNAC are sent too late for the
- * server to be able to use them to change the protocol for the earlier
- * login packets (client versions are sent right after Host Online is
- * received, but client online versions aren't sent until quite a bit later).
- * We can see them already making use of this by changing the format of
- * the rate information based on what version of group 1 we advertise here.
- *
- */
-void
-aim_srv_setversions(OscarData *od, FlapConnection *conn)
-{
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *cur;
-
-	byte_stream_new(&bs, 1142);
-
-	/*
-	 * Send only the versions that the server cares about (that it
-	 * marked as supporting in the server ready SNAC).
-	 */
-	for (cur = conn->groups; cur != NULL; cur = cur->next)
-	{
-		aim_module_t *mod;
-
-		if ((mod = aim__findmodulebygroup(od, GPOINTER_TO_UINT(cur->data))))
-		{
-			byte_stream_put16(&bs, mod->family);
-			byte_stream_put16(&bs, mod->version);
-		}
-	}
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0017, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0017, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-}
-
-/* Subtype 0x0018 - Host versions */
-static int
-hostversions(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int vercount;
-	guint8 *versions;
-
-	/* This is frivolous. (Thank you SmarterChild.) */
-	vercount = byte_stream_bytes_left(bs)/4;
-
-	/* XXX: vercount probably should be used for reading versions. */
-	(void)vercount;
-	versions = byte_stream_getraw(bs, byte_stream_bytes_left(bs));
-	g_free(versions);
-
-	/*
-	 * Now request rates.
-	 */
-	aim_srv_reqrates(od, conn);
-
-	return 1;
-}
-
-/**
- * Subtype 0x001e - Extended Status/Extra Info.
- *
- * These settings are transient, not server-stored (i.e. they only
- * apply to this session, and must be re-set the next time you sign
- * on).
- *
- * You can set your ICQ status (available, away, do not disturb,
- * etc.), or whether your IP address should be hidden or not, or
- * if your status is visible on ICQ web sites, and you can set
- * your IP address info and what not.
- *
- * You can also set your "available" message.  This is currently
- * only supported by iChat, Purple and other 3rd party clients.
- *
- * These are the same TLVs seen in user info.  You can
- * also set 0x0008 and 0x000c.
- */
-int
-aim_srv_setextrainfo(OscarData *od,
-		gboolean seticqstatus, guint32 icqstatus,
-		gboolean setstatusmsg, const char *statusmsg, const char *itmsurl)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *tlvlist = NULL;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM)))
-		return -EINVAL;
-
-	if (seticqstatus)
-	{
-		aim_tlvlist_add_32(&tlvlist, 0x0006, icqstatus |
-				AIM_ICQ_STATE_HIDEIP | AIM_ICQ_STATE_DIRECTREQUIREAUTH);
-	}
-
-	if (setstatusmsg)
-	{
-		size_t statusmsglen, itmsurllen;
-		ByteStream tmpbs;
-
-		statusmsglen = (statusmsg != NULL) ? strlen(statusmsg) : 0;
-		itmsurllen = (itmsurl != NULL) ? strlen(itmsurl) : 0;
-
-		byte_stream_new(&tmpbs, statusmsglen + 8 + itmsurllen + 8);
-		byte_stream_put_bart_asset_str(&tmpbs, 0x0002, statusmsg);
-		byte_stream_put_bart_asset_str(&tmpbs, 0x0009, itmsurl);
-
-		aim_tlvlist_add_raw(&tlvlist, 0x001d,
-				byte_stream_curpos(&tmpbs), tmpbs.data);
-		byte_stream_destroy(&tmpbs);
-	}
-
-	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
-
-	aim_tlvlist_write(&bs, &tlvlist);
-	aim_tlvlist_free(tlvlist);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x001e, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x001e, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/* Send dummy DC (direct connect) information to the server.
- * Direct connect is ICQ's counterpart for AIM's DirectIM,
- * as far as I can tell. Anyway, we don't support it;
- * the reason to send this packet is that some clients
- * (Miranda, QIP) won't send us channel 2 ICBM messages
- * unless we specify DC version >= 8.
- *
- * See #12044 for more information.
- */
-void
-aim_srv_set_dc_info(OscarData *od)
-{
-	FlapConnection *conn;
-
-	ByteStream bs, tlv0c;
-	aim_snacid_t snacid;
-	GSList *tlvlist = NULL;
-
-	/* http://iserverd.khstu.ru/oscar/snac_01_1e.html has a nice analysis of what goes in 0xc tlv.
-	 * Kopete sends a dummy DC info, too, so I just copied the values from them.
-	 */
-	byte_stream_new(&tlv0c, 4*2 + 1 + 2 + 4*6 + 2);
-	byte_stream_put32(&tlv0c, 0x0);
-	byte_stream_put32(&tlv0c, 0x0);
-	byte_stream_put8(&tlv0c, 0x0); /* We don't support DC */
-	byte_stream_put16(&tlv0c, 8); /* DC version */
-	byte_stream_put32(&tlv0c, 0x0);
-	byte_stream_put32(&tlv0c, 0x50);
-	byte_stream_put32(&tlv0c, 0x3);
-	byte_stream_put32(&tlv0c, 0x0);
-	byte_stream_put32(&tlv0c, 0x0);
-	byte_stream_put32(&tlv0c, 0x0);
-	byte_stream_put16(&tlv0c, 0x0);
-	aim_tlvlist_add_raw(&tlvlist, 0x000c, byte_stream_curpos(&tlv0c), tlv0c.data);
-	byte_stream_destroy(&tlv0c);
-
-	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
-	aim_tlvlist_write(&bs, &tlvlist);
-	aim_tlvlist_free(tlvlist);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x001e, 0x0000, NULL, 0);
-	conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM);
-	g_warn_if_fail(conn != NULL);
-	if (conn) {
-		flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE,
-			0x001e, snacid, &bs);
-	}
-
-	byte_stream_destroy(&bs);
-}
-
-/*
- * Subtype 0x0021 - Receive our extended status
- *
- * This is used for iChat's "available" messages, and maybe ICQ extended
- * status messages?  It's also used to tell the client whether or not it
- * needs to upload an SSI buddy icon... who engineers this stuff, anyway?
- */
-static int
-aim_parse_extstatus(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	guint16 type = byte_stream_get16(bs);
-	if (type == 0x0000 || type == 0x0001) {
-		/* buddy icon checksum */
-		/* not sure what the difference between 1 and 0 is */
-		guint8 flags = byte_stream_get8(bs);
-		guint8 length = byte_stream_get8(bs);
-		guint8 *md5 = byte_stream_getraw(bs, length);
-
-		if ((flags == 0x00) || (flags == 0x41)) {
-			if (!flap_connection_getbytype(od, SNAC_FAMILY_BART) && !od->iconconnecting) {
-				od->iconconnecting = TRUE;
-				od->set_icon = TRUE;
-				aim_srv_requestnew(od, SNAC_FAMILY_BART);
-			} else {
-				PurpleAccount *account = purple_connection_get_account(od->gc);
-				PurpleImage *img = purple_buddy_icons_find_account_icon(account);
-				if (img == NULL) {
-					aim_ssi_delicon(od);
-				} else {
-
-					purple_debug_info("oscar",
-									"Uploading icon to icon server\n");
-					aim_bart_upload(od,
-						purple_image_get_data(img),
-						purple_image_get_data_size(img));
-					g_object_unref(img);
-				}
-			}
-		} else if (flags == 0x81) {
-			PurpleAccount *account = purple_connection_get_account(od->gc);
-			PurpleImage *img = purple_buddy_icons_find_account_icon(account);
-			if (img == NULL)
-				aim_ssi_delicon(od);
-			else {
-				aim_ssi_seticon(od, md5, length);
-				g_object_unref(img);
-			}
-		}
-
-		g_free(md5);
-	}
-
-	return 0;
-}
-
-static int
-snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	if (snac->subtype == 0x0003)
-		return hostonline(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x0005)
-		return redirect(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x0007)
-		return rateresp(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x000a)
-		return ratechange(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x000b)
-		return serverpause(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x000d)
-		return serverresume(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x000f)
-		return selfinfo(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x0010)
-		return evilnotify(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x0012)
-		return migrate(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x0013)
-		return motd(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x0018)
-		return hostversions(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x0021)
-		return aim_parse_extstatus(od, conn, mod, frame, snac, bs);
-
-	return 0;
-}
-
-int service_modfirst(OscarData *od, aim_module_t *mod)
-{
-	mod->family = SNAC_FAMILY_OSERVICE;
-	mod->version = 0x0003;
-	mod->toolid = 0x0110;
-	mod->toolversion = 0x0629;
-	mod->flags = 0;
-	strncpy(mod->name, "oservice", sizeof(mod->name));
-	mod->snachandler = snachandler;
-
-	return 0;
-}
--- a/libpurple/protocols/oscar/family_popup.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Family 0x0008 - Popups.
- *
- * Popups are just what it sounds like.  They're a way for the server to
- * open up an informative box on the client's screen.
- */
-
-#include <oscar.h>
-
-/*
- * This is all there is to it.
- *
- * The message is probably HTML.
- *
- */
-static int
-parsepopup(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	aim_rxcallback_t userfunc;
-	GSList *tlvlist;
-	int ret = 0;
-	char *msg, *url;
-	guint16 width, height, delay;
-
-	tlvlist = aim_tlvlist_read(bs);
-
-	msg = aim_tlv_getstr(tlvlist, 0x0001, 1);
-	url = aim_tlv_getstr(tlvlist, 0x0002, 1);
-	width = aim_tlv_get16(tlvlist, 0x0003, 1);
-	height = aim_tlv_get16(tlvlist, 0x0004, 1);
-	delay = aim_tlv_get16(tlvlist, 0x0005, 1);
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, msg, url, width, height, delay);
-
-	aim_tlvlist_free(tlvlist);
-	g_free(msg);
-	g_free(url);
-
-	return ret;
-}
-
-static int
-snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	if (snac->subtype == 0x0002)
-		return parsepopup(od, conn, mod, frame, snac, bs);
-
-	return 0;
-}
-
-int
-popups_modfirst(OscarData *od, aim_module_t *mod)
-{
-	mod->family = SNAC_FAMILY_POPUP;
-	mod->version = 0x0001;
-	mod->toolid = 0x0104;
-	mod->toolversion = 0x0001;
-	mod->flags = 0;
-	strncpy(mod->name, "popup", sizeof(mod->name));
-	mod->snachandler = snachandler;
-
-	return 0;
-}
--- a/libpurple/protocols/oscar/family_stats.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Family 0x000b - Statistics.
- *
- */
-
-#include <oscar.h>
-
-static int
-reportinterval(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	guint16 interval;
-
-	interval = byte_stream_get16(bs);
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, interval);
-
-	return ret;
-}
-
-static int
-snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	if (snac->subtype == 0x0002)
-		return reportinterval(od, conn, mod, frame, snac, bs);
-
-	return 0;
-}
-
-int
-stats_modfirst(OscarData *od, aim_module_t *mod)
-{
-	mod->family = SNAC_FAMILY_STATS;
-	mod->version = 0x0001;
-	mod->toolid = 0x0104;
-	mod->toolversion = 0x0001;
-	mod->flags = 0;
-	strncpy(mod->name, "stats", sizeof(mod->name));
-	mod->snachandler = snachandler;
-
-	return 0;
-}
--- a/libpurple/protocols/oscar/family_userlookup.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,156 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Family 0x000a - User Search.
- *
- * TODO: Add aim_usersearch_name()
- *
- */
-
-#include "oscar.h"
-
-/*
- * Subtype 0x0001
- *
- * XXX can this be integrated with the rest of the error handling?
- */
-static int error(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	aim_snac_t *snac2;
-
-	/* XXX the modules interface should have already retrieved this for us */
-	if (!(snac2 = aim_remsnac(od, snac->id))) {
-		purple_debug_misc("oscar", "search error: couldn't get a snac for 0x%08x\n", snac->id);
-		return 0;
-	}
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, snac2->data /* address */);
-
-	/* XXX freesnac()? */
-	g_free(snac2->data);
-	g_free(snac2);
-
-	return ret;
-}
-
-/*
- * Subtype 0x0002
- *
- */
-int aim_search_address(OscarData *od, const char *address)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-
-	conn = flap_connection_findbygroup(od, SNAC_FAMILY_USERLOOKUP);
-
-	if (!conn || !address)
-		return -EINVAL;
-
-	byte_stream_new(&bs, strlen(address));
-
-	byte_stream_putstr(&bs, address);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_USERLOOKUP, 0x0002, 0x0000, address, strlen(address)+1);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_USERLOOKUP, 0x0002, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0003
- *
- */
-static int reply(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int j = 0, m, ret = 0;
-	GSList *tlvlist;
-	char *cur = NULL, *buf = NULL;
-	aim_rxcallback_t userfunc;
-	aim_snac_t *snac2;
-	const char *searchaddr = NULL;
-
-	if ((snac2 = aim_remsnac(od, snac->id)))
-		searchaddr = (const char *)snac2->data;
-
-	tlvlist = aim_tlvlist_read(bs);
-	m = aim_tlvlist_count(tlvlist);
-
-	/* XXX uhm.
-	 * This is the only place that uses something other than 1 for the 3rd
-	 * parameter to aim_tlv_gettlv_whatever().
-	 */
-	while ((cur = aim_tlv_getstr(tlvlist, 0x0001, j+1)) && j < m)
-	{
-		buf = g_realloc(buf, (j+1) * (MAXSNLEN+1));
-
-		strncpy(&buf[j * (MAXSNLEN+1)], cur, MAXSNLEN);
-		g_free(cur);
-
-		j++;
-	}
-	g_free(cur);
-
-	aim_tlvlist_free(tlvlist);
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, searchaddr, j, buf);
-
-	/* XXX freesnac()? */
-	if (snac2)
-		g_free(snac2->data);
-	g_free(snac2);
-
-	g_free(buf);
-
-	return ret;
-}
-
-static int
-snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	if (snac->subtype == 0x0001)
-		return error(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x0003)
-		return reply(od, conn, mod, frame, snac, bs);
-
-	return 0;
-}
-
-int
-search_modfirst(OscarData *od, aim_module_t *mod)
-{
-	mod->family = SNAC_FAMILY_USERLOOKUP;
-	mod->version = 0x0001;
-	mod->toolid = 0x0110;
-	mod->toolversion = 0x0629;
-	mod->flags = 0;
-	strncpy(mod->name, "userlookup", sizeof(mod->name));
-	mod->snachandler = snachandler;
-
-	return 0;
-}
--- a/libpurple/protocols/oscar/flap_connection.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1117 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-#include "oscar.h"
-
-#include "eventloop.h"
-#include "proxy.h"
-
-#ifndef _WIN32
-#include <netdb.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#endif
-
-/**
- * This sends a channel 1 SNAC containing the FLAP version.
- * The FLAP version is sent by itself at the beginning of every
- * connection to a FLAP server.  It is always the very first
- * packet sent by both the server and the client after the SYN,
- * SYN/ACK, ACK handshake.
- */
-void
-flap_connection_send_version(OscarData *od, FlapConnection *conn)
-{
-	FlapFrame *frame;
-
-	frame = flap_frame_new(od, 0x01, 4);
-	byte_stream_put32(&frame->data, 0x00000001); /* FLAP Version */
-	flap_connection_send(conn, frame);
-}
-
-/**
- * This sends a channel 1 FLAP containing the FLAP version and
- * the authentication cookie.  This is sent when connecting to
- * any FLAP server after the initial connection to the auth
- * server.  It is always the very first packet sent by both the
- * server and the client after the SYN, SYN/ACK, ACK handshake.
- */
-void
-flap_connection_send_version_with_cookie(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy)
-{
-	FlapFrame *frame;
-	GSList *tlvlist = NULL;
-
-	frame = flap_frame_new(od, 0x01, 4 + 2 + 2 + length);
-	byte_stream_put32(&frame->data, 0x00000001); /* FLAP Version */
-	aim_tlvlist_add_raw(&tlvlist, 0x0006, length, chipsahoy);
-	aim_tlvlist_write(&frame->data, &tlvlist);
-	aim_tlvlist_free(tlvlist);
-
-	flap_connection_send(conn, frame);
-}
-
-void
-flap_connection_send_version_with_cookie_and_clientinfo(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy, ClientInfo *ci, gboolean allow_multiple_logins)
-{
-	FlapFrame *frame;
-	GSList *tlvlist = NULL;
-
-	frame = flap_frame_new(od, 0x01, 1152 + length);
-
-	byte_stream_put32(&frame->data, 0x00000001); /* FLAP Version */
-	aim_tlvlist_add_raw(&tlvlist, 0x0006, length, chipsahoy);
-
-	if (ci->clientstring != NULL)
-		aim_tlvlist_add_str(&tlvlist, 0x0003, ci->clientstring);
-	else {
-		gchar *clientstring = oscar_get_clientstring();
-		aim_tlvlist_add_str(&tlvlist, 0x0003, clientstring);
-		g_free(clientstring);
-	}
-	aim_tlvlist_add_16(&tlvlist, 0x0017, (guint16)ci->major);
-	aim_tlvlist_add_16(&tlvlist, 0x0018, (guint16)ci->minor);
-	aim_tlvlist_add_16(&tlvlist, 0x0019, (guint16)ci->point);
-	aim_tlvlist_add_16(&tlvlist, 0x001a, (guint16)ci->build);
-	aim_tlvlist_add_8(&tlvlist, 0x004a, (allow_multiple_logins ? 0x01 : 0x03));
-
-	aim_tlvlist_write(&frame->data, &tlvlist);
-
-	aim_tlvlist_free(tlvlist);
-
-	flap_connection_send(conn, frame);
-}
-
-static struct rateclass *
-flap_connection_get_rateclass(FlapConnection *conn, guint16 family, guint16 subtype)
-{
-	gconstpointer key;
-	gpointer rateclass;
-
-	key = GUINT_TO_POINTER((family << 16) + subtype);
-	rateclass = g_hash_table_lookup(conn->rateclass_members, key);
-	if (rateclass != NULL)
-		return rateclass;
-
-	return conn->default_rateclass;
-}
-
-/*
- * Attempt to calculate what our new current average would be if we
- * were to send a SNAC in this rateclass at the given time.
- */
-static guint32
-rateclass_get_new_current(FlapConnection *conn, struct rateclass *rateclass, struct timeval *now)
-{
-	unsigned long timediff; /* In milliseconds */
-	guint32 current;
-
-	/* This formula is documented at http://dev.aol.com/aim/oscar/#RATELIMIT */
-	timediff = (now->tv_sec - rateclass->last.tv_sec) * 1000 + (now->tv_usec - rateclass->last.tv_usec) / 1000;
-	current = ((rateclass->current * (rateclass->windowsize - 1)) + timediff) / rateclass->windowsize;
-
-	return MIN(current, rateclass->max);
-}
-
-/*
- * Attempt to send the contents of a given queue
- *
- * @return TRUE if the queue was completely emptied or was initially
- *         empty; FALSE if rate limiting prevented it from being
- *         emptied.
- */
-static gboolean flap_connection_send_snac_queue(FlapConnection *conn, struct timeval now, GQueue *queue)
-{
-	while (!g_queue_is_empty(queue))
-	{
-		QueuedSnac *queued_snac;
-		struct rateclass *rateclass;
-
-		queued_snac = g_queue_peek_head(queue);
-
-		rateclass = flap_connection_get_rateclass(conn, queued_snac->family, queued_snac->subtype);
-		if (rateclass != NULL)
-		{
-			guint32 new_current;
-
-			new_current = rateclass_get_new_current(conn, rateclass, &now);
-
-			if (rateclass->dropping_snacs || new_current <= rateclass->alert)
-				/* Not ready to send this SNAC yet--keep waiting. */
-				return FALSE;
-
-			rateclass->current = new_current;
-			rateclass->last.tv_sec = now.tv_sec;
-			rateclass->last.tv_usec = now.tv_usec;
-		}
-
-		flap_connection_send(conn, queued_snac->frame);
-		g_free(queued_snac);
-		g_queue_pop_head(queue);
-	}
-
-	/* We emptied the queue */
-	return TRUE;
-}
-
-static gboolean flap_connection_send_queued(gpointer data)
-{
-	FlapConnection *conn;
-	struct timeval now;
-
-	conn = data;
-	gettimeofday(&now, NULL);
-
-	purple_debug_info("oscar", "Attempting to send %u queued SNACs and %u queued low-priority SNACs for %p\n",
-					  (conn->queued_snacs ? conn->queued_snacs->length : 0),
-					  (conn->queued_lowpriority_snacs ? conn->queued_lowpriority_snacs->length : 0),
-					  conn);
-	if (!conn->queued_snacs || flap_connection_send_snac_queue(conn, now, conn->queued_snacs)) {
-		if (!conn->queued_lowpriority_snacs || flap_connection_send_snac_queue(conn, now, conn->queued_lowpriority_snacs)) {
-			/* Both queues emptied. */
-			conn->queued_timeout = 0;
-			return FALSE;
-		}
-	}
-
-	/* We couldn't send all our SNACs. Keep trying */
-	return TRUE;
-}
-
-/**
- * This sends a channel 2 FLAP containing a SNAC.  The SNAC family and
- * subtype are looked up in the rate info for this connection, and if
- * sending this SNAC will induce rate limiting then we delay sending
- * of the SNAC by putting it into an outgoing holding queue.
- *
- * @param data The optional bytestream that makes up the data portion
- *        of this SNAC.  For empty SNACs this should be NULL.
- * @param high_priority If TRUE, the SNAC will be queued normally if
- *        needed. If FALSE, it will be queued separately, to be sent
- *        only if all high priority SNACs have been sent.
- */
-void
-flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, aim_snacid_t snacid, ByteStream *data, gboolean high_priority)
-{
-	FlapFrame *frame;
-	guint32 length;
-	gboolean enqueue = FALSE;
-	struct rateclass *rateclass;
-
-	length = data != NULL ? data->offset : 0;
-
-	frame = flap_frame_new(od, 0x02, 10 + length);
-	aim_putsnac(&frame->data, family, subtype, snacid);
-
-	if (length > 0)
-	{
-		byte_stream_rewind(data);
-		byte_stream_putbs(&frame->data, data, length);
-	}
-
-	if (conn->queued_timeout != 0)
-		enqueue = TRUE;
-	else if ((rateclass = flap_connection_get_rateclass(conn, family, subtype)) != NULL)
-	{
-		struct timeval now;
-		guint32 new_current;
-
-		gettimeofday(&now, NULL);
-		new_current = rateclass_get_new_current(conn, rateclass, &now);
-
-		if (rateclass->dropping_snacs || new_current <= rateclass->alert)
-		{
-			purple_debug_info("oscar", "Current rate for conn %p would be %u, but we alert at %u; enqueueing\n", conn, new_current, rateclass->alert);
-
-			enqueue = TRUE;
-		}
-		else
-		{
-			rateclass->current = new_current;
-			rateclass->last.tv_sec = now.tv_sec;
-			rateclass->last.tv_usec = now.tv_usec;
-		}
-	}
-
-	if (enqueue)
-	{
-		/* We've been sending too fast, so delay this message */
-		QueuedSnac *queued_snac;
-
-		queued_snac = g_new(QueuedSnac, 1);
-		queued_snac->family = family;
-		queued_snac->subtype = subtype;
-		queued_snac->frame = frame;
-
-		if (high_priority) {
-			if (!conn->queued_snacs)
-				conn->queued_snacs = g_queue_new();
-			g_queue_push_tail(conn->queued_snacs, queued_snac);
-		} else {
-			if (!conn->queued_lowpriority_snacs)
-				conn->queued_lowpriority_snacs = g_queue_new();
-			g_queue_push_tail(conn->queued_lowpriority_snacs, queued_snac);
-		}
-
-		if (conn->queued_timeout == 0)
-			conn->queued_timeout = g_timeout_add(500, flap_connection_send_queued, conn);
-
-		return;
-	}
-
-	flap_connection_send(conn, frame);
-}
-
-void
-flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, aim_snacid_t snacid, ByteStream *data)
-{
-	flap_connection_send_snac_with_priority(od, conn, family, subtype, snacid, data, TRUE);
-}
-
-/**
- * This sends an empty channel 4 FLAP.  This is sent to signify
- * that we're logging off.  This shouldn't really be necessary--
- * usually the AIM server will detect that the TCP connection has
- * been destroyed--but it's good practice.
- */
-static void
-flap_connection_send_close(OscarData *od, FlapConnection *conn)
-{
-	FlapFrame *frame;
-
-	frame = flap_frame_new(od, 0x04, 0);
-	flap_connection_send(conn, frame);
-}
-
-/**
- * This sends an empty channel 5 FLAP.  This is used as a keepalive
- * packet in FLAP connections.  WinAIM 4.x and higher send these
- * _every minute_ to keep the connection alive.
- */
-void
-flap_connection_send_keepalive(OscarData *od, FlapConnection *conn)
-{
-	FlapFrame *frame;
-
-	frame = flap_frame_new(od, 0x05, 0);
-	flap_connection_send(conn, frame);
-
-	/* clean out SNACs over 60sec old */
-	aim_cleansnacs(od, 60);
-}
-
-/**
- * Allocate a new empty connection structure.
- *
- * @param od The oscar session associated with this connection.
- * @param type Type of connection to create
- *
- * @return Returns the new connection structure.
- */
-FlapConnection *
-flap_connection_new(OscarData *od, int type)
-{
-	FlapConnection *conn;
-
-	conn = g_new0(FlapConnection, 1);
-	conn->od = od;
-	conn->buffer_outgoing = purple_circular_buffer_new(0);
-	conn->fd = -1;
-	conn->subtype = -1;
-	conn->type = type;
-	conn->rateclass_members = g_hash_table_new(g_direct_hash, g_direct_equal);
-
-	od->oscar_connections = g_slist_prepend(od->oscar_connections, conn);
-
-	return conn;
-}
-
-/**
- * Close (but not free) a connection.
- *
- * This cancels any currently pending connection attempt,
- * closes any open fd and frees the auth cookie.
- *
- * @param conn The connection to close.
- */
-void
-flap_connection_close(OscarData *od, FlapConnection *conn)
-{
-	if (conn->connect_data != NULL)
-	{
-		purple_proxy_connect_cancel(conn->connect_data);
-		conn->connect_data = NULL;
-	}
-
-	if (conn->gsc != NULL && conn->gsc->connect_data != NULL)
-	{
-		purple_ssl_close(conn->gsc);
-		conn->gsc = NULL;
-	}
-
-	if (conn->new_conn_data != NULL)
-	{
-		if (conn->type == SNAC_FAMILY_CHAT)
-		{
-			oscar_chat_destroy(conn->new_conn_data);
-			conn->new_conn_data = NULL;
-		}
-	}
-
-	if ((conn->fd >= 0 || conn->gsc != NULL)
-			&& conn->type == SNAC_FAMILY_LOCATE)
-		flap_connection_send_close(od, conn);
-
-	if (conn->watcher_incoming != 0)
-	{
-		purple_input_remove(conn->watcher_incoming);
-		conn->watcher_incoming = 0;
-	}
-
-	if (conn->watcher_outgoing != 0)
-	{
-		purple_input_remove(conn->watcher_outgoing);
-		conn->watcher_outgoing = 0;
-	}
-
-	if (conn->fd >= 0)
-	{
-		close(conn->fd);
-		conn->fd = -1;
-	}
-
-	if (conn->gsc != NULL)
-	{
-		purple_ssl_close(conn->gsc);
-		conn->gsc = NULL;
-	}
-
-	g_free(conn->buffer_incoming.data.data);
-	conn->buffer_incoming.data.data = NULL;
-
-	g_object_unref(G_OBJECT(conn->buffer_outgoing));
-	conn->buffer_outgoing = NULL;
-}
-
-/**
- * Free a FlapFrame
- *
- * @param frame The frame to free.
- */
-static void
-flap_frame_destroy(FlapFrame *frame)
-{
-	g_free(frame->data.data);
-	g_free(frame);
-}
-
-static gboolean
-flap_connection_destroy_cb(gpointer data)
-{
-	FlapConnection *conn;
-	OscarData *od;
-	PurpleAccount *account;
-	aim_rxcallback_t userfunc;
-
-	conn = data;
-	/* Explicitly added for debugging #5927.  Don't re-order this, only
-	 * consider removing it.
-	 */
-	purple_debug_info("oscar", "Destroying FLAP connection %p\n", conn);
-
-	od = conn->od;
-	account = purple_connection_get_account(od->gc);
-
-	purple_debug_info("oscar", "Destroying oscar connection (%p) of "
-			"type 0x%04hx.  Disconnect reason is %d\n", conn,
-			conn->type, conn->disconnect_reason);
-
-	od->oscar_connections = g_slist_remove(od->oscar_connections, conn);
-
-	if ((userfunc = aim_callhandler(od, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR)))
-		userfunc(od, conn, NULL, conn->disconnect_code, conn->error_message);
-
-	/*
-	 * TODO: If we don't have a SNAC_FAMILY_LOCATE connection then
-	 * we should try to request one instead of disconnecting.
-	 */
-	if (!purple_account_is_disconnecting(account) && ((od->oscar_connections == NULL)
-			|| (!flap_connection_getbytype(od, SNAC_FAMILY_LOCATE))))
-	{
-		/* No more FLAP connections!  Sign off this PurpleConnection! */
-		gchar *tmp;
-		PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
-
-		if (conn->disconnect_code == 0x0001) {
-			reason = PURPLE_CONNECTION_ERROR_NAME_IN_USE;
-			tmp = g_strdup(_("You have signed on from another location"));
-			if (!purple_account_get_remember_password(account))
-				purple_account_set_password(account, NULL, NULL, NULL);
-		} else if (conn->disconnect_reason == OSCAR_DISCONNECT_REMOTE_CLOSED)
-			tmp = g_strdup(_("Server closed the connection"));
-		else if (conn->disconnect_reason == OSCAR_DISCONNECT_LOST_CONNECTION)
-			tmp = g_strdup_printf(_("Lost connection with server: %s"),
-					conn->error_message);
-		else if (conn->disconnect_reason == OSCAR_DISCONNECT_INVALID_DATA)
-			tmp = g_strdup(_("Received invalid data on connection with server"));
-		else if (conn->disconnect_reason == OSCAR_DISCONNECT_COULD_NOT_CONNECT)
-			tmp = g_strdup_printf(_("Unable to connect: %s"),
-					conn->error_message);
-		else
-			/*
-			 * We shouldn't print a message for some disconnect_reasons.
-			 * Like OSCAR_DISCONNECT_LOCAL_CLOSED.
-			 */
-			tmp = NULL;
-
-		if (tmp != NULL)
-		{
-			purple_connection_error(od->gc, reason, tmp);
-			g_free(tmp);
-		}
-	}
-
-	flap_connection_close(od, conn);
-
-	g_free(conn->error_message);
-	g_free(conn->cookie);
-
-	/*
-	 * Free conn->internal, if necessary
-	 */
-	if (conn->type == SNAC_FAMILY_CHAT)
-		flap_connection_destroy_chat(od, conn);
-
-	g_slist_free(conn->groups);
-	g_slist_free_full(conn->rateclasses, g_free);
-
-	g_hash_table_destroy(conn->rateclass_members);
-
-	if (conn->queued_snacs) {
-		while (!g_queue_is_empty(conn->queued_snacs))
-		{
-			QueuedSnac *queued_snac;
-			queued_snac = g_queue_pop_head(conn->queued_snacs);
-			flap_frame_destroy(queued_snac->frame);
-			g_free(queued_snac);
-		}
-		g_queue_free(conn->queued_snacs);
-	}
-
-	if (conn->queued_lowpriority_snacs) {
-		while (!g_queue_is_empty(conn->queued_lowpriority_snacs))
-		{
-			QueuedSnac *queued_snac;
-			queued_snac = g_queue_pop_head(conn->queued_lowpriority_snacs);
-			flap_frame_destroy(queued_snac->frame);
-			g_free(queued_snac);
-		}
-		g_queue_free(conn->queued_lowpriority_snacs);
-	}
-
-	if (conn->queued_timeout > 0)
-		g_source_remove(conn->queued_timeout);
-
-	g_free(conn);
-
-	return FALSE;
-}
-
-/**
- * See the comments for the parameters of
- * flap_connection_schedule_destroy().
- */
-void
-flap_connection_destroy(FlapConnection *conn, OscarDisconnectReason reason, const gchar *error_message)
-{
-	if (conn->destroy_timeout != 0)
-		g_source_remove(conn->destroy_timeout);
-	conn->disconnect_reason = reason;
-	g_free(conn->error_message);
-	conn->error_message = g_strdup(error_message);
-	flap_connection_destroy_cb(conn);
-}
-
-/**
- * Schedule Purple to destroy the given FlapConnection as soon as we
- * return control back to the program's main loop.  We must do this
- * if we want to destroy the connection but we are still using it
- * for some reason.
- *
- * @param reason The reason for the disconnection.
- * @param error_message A brief error message that gives more detail
- *        regarding the reason for the disconnecting.  This should
- *        be NULL for everything except OSCAR_DISCONNECT_LOST_CONNECTION,
- *        in which case it should contain the value of g_strerror(errno),
- *        and OSCAR_DISCONNECT_COULD_NOT_CONNECT, in which case it
- *        should contain the error_message passed back from the call
- *        to purple_proxy_connect().
- */
-void
-flap_connection_schedule_destroy(FlapConnection *conn, OscarDisconnectReason reason, const gchar *error_message)
-{
-	if (conn->destroy_timeout != 0)
-		/* Already taken care of */
-		return;
-
-	purple_debug_info("oscar", "Scheduling destruction of FLAP "
-			"connection %p of type 0x%04hx\n", conn, conn->type);
-	conn->disconnect_reason = reason;
-	g_free(conn->error_message);
-	conn->error_message = g_strdup(error_message);
-	conn->destroy_timeout = g_timeout_add(0, flap_connection_destroy_cb, conn);
-}
-
-/**
- * In OSCAR, every connection has a set of SNAC groups associated
- * with it.  These are the groups that you can send over this connection
- * without being guaranteed a "Not supported" SNAC error.
- *
- * The grand theory of things says that these associations transcend
- * what libfaim calls "connection types" (conn->type).  You can probably
- * see the elegance here, but since I want to revel in it for a bit, you
- * get to hear it all spelled out.
- *
- * So let us say that you have your core BOS connection running.  One
- * of your modules has just given you a SNAC of the group 0x0004 to send
- * you.  Maybe an IM destined for some twit in Greenland.  So you start
- * at the top of your connection list, looking for a connection that
- * claims to support group 0x0004.  You find one.  Why, that neat BOS
- * connection of yours can do that.  So you send it on its way.
- *
- * Now, say, that fellow from Greenland has friends and they all want to
- * meet up with you in a lame chat room.  This has landed you a SNAC
- * in the family 0x000e and you have to admit you're a bit lost.  You've
- * searched your connection list for someone who wants to make your life
- * easy and deliver this SNAC for you, but there isn't one there.
- *
- * Here comes the good bit.  Without even letting anyone know, particularly
- * the module that decided to send this SNAC, and definitely not that twit
- * in Greenland, you send out a service request.  In this request, you have
- * marked the need for a connection supporting group 0x000e.  A few seconds
- * later, you receive a service redirect with an IP address and a cookie in
- * it.  Great, you say.  Now I have something to do.  Off you go, making
- * that connection.  One of the first things you get from this new server
- * is a message saying that indeed it does support the group you were looking
- * for.  So you continue and send rate confirmation and all that.
- *
- * Then you remember you had that SNAC to send, and now you have a means to
- * do it, and you do, and everyone is happy.  Except the Greenlander, who is
- * still stuck in the bitter cold.
- *
- * Oh, and this is useful for building the Migration SNACs, too.  In the
- * future, this may help convince me to implement rate limit mitigation
- * for real.  We'll see.
- *
- * Just to make me look better, I'll say that I've known about this great
- * scheme for quite some time now.  But I still haven't convinced myself
- * to make libfaim work that way.  It would take a fair amount of effort,
- * and probably some client API changes as well.  (Whenever I don't want
- * to do something, I just say it would change the client API.  Then I
- * instantly have a couple of supporters of not doing it.)
- *
- * Generally, addgroup is only called by the internal handling of the
- * server ready SNAC.  So if you want to do something before that, you'll
- * have to be more creative.  That is done rather early, though, so I don't
- * think you have to worry about it.  Unless you're me.  I care deeply
- * about such inane things.
- *
- */
-
-/**
- * Find a FlapConnection that supports the given oscar
- * family.
- */
-FlapConnection *
-flap_connection_findbygroup(OscarData *od, guint16 group)
-{
-	GSList *cur;
-
-	for (cur = od->oscar_connections; cur != NULL; cur = cur->next)
-	{
-		FlapConnection *conn;
-
-		conn = cur->data;
-
-		if (g_slist_find(conn->groups, GUINT_TO_POINTER(group)) != NULL) {
-			return conn;
-		}
-	}
-
-	return NULL;
-}
-
-/**
- * Locates a connection of the specified type in the
- * specified session.
- *
- * TODO: Use flap_connection_findbygroup everywhere and get rid of this.
- *
- * @param od The session to search.
- * @param type The type of connection to look for.
- *
- * @return Returns the first connection found of the given target type,
- *         or NULL if none could be found.
- */
-FlapConnection *
-flap_connection_getbytype(OscarData *od, int type)
-{
-	GSList *cur;
-
-	for (cur = od->oscar_connections; cur != NULL; cur = cur->next)
-	{
-		FlapConnection *conn;
-		conn = cur->data;
-		if ((conn->type == type) && (conn->connected))
-			return conn;
-	}
-
-	return NULL;
-}
-
-FlapConnection *
-flap_connection_getbytype_all(OscarData *od, int type)
-{
-	GSList *cur;
-
-	for (cur = od->oscar_connections; cur; cur = cur->next)
-	{
-		FlapConnection *conn;
-		conn = cur->data;
-		if (conn->type == type)
-			return conn;
-	}
-
-	return NULL;
-}
-
-/**
- * Allocate a new FLAP frame.
- *
- * @param channel The FLAP channel.  This is almost always 2.
- */
-FlapFrame *
-flap_frame_new(OscarData *od, guint16 channel, int datalen)
-{
-	FlapFrame *frame;
-
-	frame = g_new0(FlapFrame, 1);
-	frame->channel = channel;
-
-	if (datalen > 0)
-		byte_stream_new(&frame->data, datalen);
-
-	return frame;
-}
-
-static void
-parse_snac(OscarData *od, FlapConnection *conn, FlapFrame *frame)
-{
-	aim_module_t *cur;
-	aim_modsnac_t snac;
-
-	if (byte_stream_bytes_left(&frame->data) < 10)
-		return;
-
-	snac.family = byte_stream_get16(&frame->data);
-	snac.subtype = byte_stream_get16(&frame->data);
-	snac.flags = byte_stream_get16(&frame->data);
-	snac.id = byte_stream_get32(&frame->data);
-
-	/* SNAC flags are apparently uniform across all SNACs, so we handle them here */
-	if (snac.flags & 0x0001) {
-		/*
-		 * This means the SNAC will be followed by another SNAC with
-		 * related information.  We don't need to do anything about
-		 * this here.
-		 */
-	}
-	if (snac.flags & 0x8000) {
-		/*
-		 * This packet contains the version of the family that this SNAC is
-		 * in.  You get this when your SSI module is version 2 or higher.
-		 * For now we have no need for this, but you could always save
-		 * it as a part of aim_modnsac_t, or something.  The format is...
-		 * 2 byte length of total mini-header (which is 6 bytes), then TLV
-		 * of  type 0x0001, length 0x0002, value is the 2 byte version
-		 * number
-		 */
-		byte_stream_advance(&frame->data, byte_stream_get16(&frame->data));
-	}
-
-	for (cur = (aim_module_t *)od->modlistv; cur; cur = cur->next) {
-
-		if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
-				(cur->family != snac.family))
-			continue;
-
-		if (cur->snachandler(od, conn, cur, frame, &snac, &frame->data))
-			return;
-	}
-}
-
-static void
-parse_fakesnac(OscarData *od, FlapConnection *conn, FlapFrame *frame, guint16 family, guint16 subtype)
-{
-	aim_module_t *cur;
-	aim_modsnac_t snac;
-
-	snac.family = family;
-	snac.subtype = subtype;
-	snac.flags = snac.id = 0;
-
-	for (cur = (aim_module_t *)od->modlistv; cur; cur = cur->next) {
-
-		if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
-				(cur->family != snac.family))
-			continue;
-
-		if (cur->snachandler(od, conn, cur, frame, &snac, &frame->data))
-			return;
-	}
-}
-
-static void
-parse_flap_ch4(OscarData *od, FlapConnection *conn, FlapFrame *frame)
-{
-	GSList *tlvlist;
-	char *msg = NULL;
-
-	if (byte_stream_bytes_left(&frame->data) == 0) {
-		/* XXX should do something with this */
-		return;
-	}
-
-	/* An ICQ account is logging in */
-	if (conn->type == SNAC_FAMILY_AUTH)
-	{
-		parse_fakesnac(od, conn, frame, 0x0017, 0x0003);
-		return;
-	}
-
-	tlvlist = aim_tlvlist_read(&frame->data);
-
-	if (aim_tlv_gettlv(tlvlist, 0x0009, 1))
-		conn->disconnect_code = aim_tlv_get16(tlvlist, 0x0009, 1);
-
-	if (aim_tlv_gettlv(tlvlist, 0x000b, 1))
-		msg = aim_tlv_getstr(tlvlist, 0x000b, 1);
-
-	/*
-	 * The server ended this FLAP connnection, so let's be nice and
-	 * close the physical TCP connection
-	 */
-	flap_connection_schedule_destroy(conn,
-			OSCAR_DISCONNECT_REMOTE_CLOSED, msg);
-
-	aim_tlvlist_free(tlvlist);
-
-	g_free(msg);
-}
-
-/**
- * Takes a new incoming FLAP frame and sends it to the appropriate
- * handler function to be parsed.
- */
-static void
-parse_flap(OscarData *od, FlapConnection *conn, FlapFrame *frame)
-{
-	if (frame->channel == 0x01) {
-		guint32 flap_version = byte_stream_get32(&frame->data);
-		if (flap_version != 0x00000001)
-		{
-				/* Error! */
-				purple_debug_warning("oscar", "Expecting FLAP version "
-					"0x00000001 but received FLAP version %08x.  Closing connection.\n",
-					flap_version);
-				flap_connection_schedule_destroy(conn,
-						OSCAR_DISCONNECT_INVALID_DATA, NULL);
-		}
-		else
-			conn->connected = TRUE;
-
-	} else if (frame->channel == 0x02) {
-		parse_snac(od, conn, frame);
-
-	} else if (frame->channel == 0x04) {
-		parse_flap_ch4(od, conn, frame);
-
-	} else if (frame->channel == 0x05) {
-		/* TODO: Reset our keepalive watchdog? */
-
-	}
-}
-
-/**
- * Read in all available data on the socket for a given connection.
- * All complete FLAPs handled immedate after they're received.
- * Incomplete FLAP data is stored locally and appended to the next
- * time this callback is triggered.
- *
- * This is called by flap_connection_recv_cb and
- * flap_connection_recv_cb_ssl for unencrypted/encrypted connections.
- */
-static void
-flap_connection_recv(FlapConnection *conn)
-{
-	gpointer buf;
-	gsize buflen;
-	gssize read;
-
-	/* Read data until we run out of data and break out of the loop */
-	while (TRUE)
-	{
-		/* Start reading a new FLAP */
-		if (conn->buffer_incoming.data.data == NULL)
-		{
-			buf = conn->header + conn->header_received;
-			buflen = 6 - conn->header_received;
-
-			/* Read the first 6 bytes (the FLAP header) */
-			if (conn->gsc)
-				read = purple_ssl_read(conn->gsc, buf, buflen);
-			else
-				read = recv(conn->fd, buf, buflen, 0);
-
-			/* Check if the FLAP server closed the connection */
-			if (read == 0)
-			{
-				flap_connection_schedule_destroy(conn,
-						OSCAR_DISCONNECT_REMOTE_CLOSED, NULL);
-				break;
-			}
-
-			/* If there was an error then close the connection */
-			if (read < 0)
-			{
-				if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
-					/* No worries */
-					break;
-
-				/* Error! */
-				flap_connection_schedule_destroy(conn,
-						OSCAR_DISCONNECT_LOST_CONNECTION, g_strerror(errno));
-				break;
-			}
-			purple_connection_update_last_received(conn->od->gc);
-
-			/* If we don't even have a complete FLAP header then do nothing */
-			conn->header_received += read;
-			if (conn->header_received < 6)
-				break;
-
-			/* All FLAP frames must start with the byte 0x2a */
-			if (aimutil_get8(&conn->header[0]) != 0x2a)
-			{
-				flap_connection_schedule_destroy(conn,
-						OSCAR_DISCONNECT_INVALID_DATA, NULL);
-				break;
-			}
-
-			/* Initialize a new temporary FlapFrame for incoming data */
-			conn->buffer_incoming.channel = aimutil_get8(&conn->header[1]);
-			conn->buffer_incoming.seqnum = aimutil_get16(&conn->header[2]);
-			conn->buffer_incoming.data.len = aimutil_get16(&conn->header[4]);
-			conn->buffer_incoming.data.data = g_new(guint8, conn->buffer_incoming.data.len);
-			conn->buffer_incoming.data.offset = 0;
-		}
-
-		buflen = conn->buffer_incoming.data.len - conn->buffer_incoming.data.offset;
-		if (buflen)
-		{
-			buf = &conn->buffer_incoming.data.data[conn->buffer_incoming.data.offset];
-			/* Read data into the temporary FlapFrame until it is complete */
-			if (conn->gsc)
-				read = purple_ssl_read(conn->gsc, buf, buflen);
-			else
-				read = recv(conn->fd, buf, buflen, 0);
-
-			/* Check if the FLAP server closed the connection */
-			if (read == 0)
-			{
-				flap_connection_schedule_destroy(conn,
-						OSCAR_DISCONNECT_REMOTE_CLOSED, NULL);
-				break;
-			}
-
-			if (read < 0)
-			{
-				if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
-					/* No worries */
-					break;
-
-				/* Error! */
-				flap_connection_schedule_destroy(conn,
-						OSCAR_DISCONNECT_LOST_CONNECTION, g_strerror(errno));
-				break;
-			}
-
-			conn->buffer_incoming.data.offset += read;
-			if (conn->buffer_incoming.data.offset < conn->buffer_incoming.data.len)
-				/* Waiting for more data to arrive */
-				break;
-		}
-
-		/* We have a complete FLAP!  Handle it and continue reading */
-		byte_stream_rewind(&conn->buffer_incoming.data);
-		parse_flap(conn->od, conn, &conn->buffer_incoming);
-		conn->lastactivity = time(NULL);
-
-		g_free(conn->buffer_incoming.data.data);
-		conn->buffer_incoming.data.data = NULL;
-
-		conn->header_received = 0;
-	}
-}
-
-void
-flap_connection_recv_cb(gpointer data, gint source, PurpleInputCondition cond)
-{
-	FlapConnection *conn = data;
-
-	flap_connection_recv(conn);
-}
-
-void
-flap_connection_recv_cb_ssl(gpointer data, PurpleSslConnection *gsc, PurpleInputCondition cond)
-{
-	FlapConnection *conn = data;
-
-	flap_connection_recv(conn);
-}
-
-/**
- * @param source When this function is called as a callback source is
- *        set to the fd that triggered the callback.  But this function
- *        is also called directly from flap_connection_send_byte_stream(),
- *        in which case source will be -1.  So don't use source--use
- *        conn->gsc or conn->fd instead.
- */
-static void
-send_cb(gpointer data, gint source, PurpleInputCondition cond)
-{
-	FlapConnection *conn;
-	int writelen, ret;
-	const gchar *output = NULL;
-
-	conn = data;
-	writelen = purple_circular_buffer_get_max_read(conn->buffer_outgoing);
-	output = purple_circular_buffer_get_output(conn->buffer_outgoing);
-
-	if (writelen == 0)
-	{
-		purple_input_remove(conn->watcher_outgoing);
-		conn->watcher_outgoing = 0;
-		return;
-	}
-
-	if (conn->gsc)
-		ret = purple_ssl_write(conn->gsc, output, writelen);
-	else
-		ret = send(conn->fd, output, writelen, 0);
-	if (ret <= 0)
-	{
-		if (ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
-			/* No worries */
-			return;
-
-		/* Error! */
-		purple_input_remove(conn->watcher_outgoing);
-		conn->watcher_outgoing = 0;
-		if (conn->gsc) {
-			purple_ssl_close(conn->gsc);
-			conn->gsc = NULL;
-		} else {
-			close(conn->fd);
-			conn->fd = -1;
-		}
-		flap_connection_schedule_destroy(conn,
-				OSCAR_DISCONNECT_LOST_CONNECTION, g_strerror(errno));
-		return;
-	}
-
-	purple_circular_buffer_mark_read(conn->buffer_outgoing, ret);
-}
-
-static void
-flap_connection_send_byte_stream(ByteStream *bs, FlapConnection *conn, size_t count)
-{
-	if (conn == NULL)
-		return;
-
-	/* Make sure we don't send past the end of the bs */
-	if (count > byte_stream_bytes_left(bs))
-		count = byte_stream_bytes_left(bs); /* truncate to remaining space */
-
-	if (count == 0)
-		return;
-
-	/* Add everything to our outgoing buffer */
-	purple_circular_buffer_append(conn->buffer_outgoing, bs->data, count);
-
-	/* If we haven't already started writing stuff, then start the cycle */
-	if (conn->watcher_outgoing == 0)
-	{
-		if (conn->gsc) {
-			conn->watcher_outgoing = purple_input_add(conn->gsc->fd,
-					PURPLE_INPUT_WRITE, send_cb, conn);
-			send_cb(conn, -1, 0);
-		} else if (conn->fd >= 0) {
-			conn->watcher_outgoing = purple_input_add(conn->fd,
-					PURPLE_INPUT_WRITE, send_cb, conn);
-			send_cb(conn, -1, 0);
-		}
-	}
-}
-
-static void
-sendframe_flap(FlapConnection *conn, FlapFrame *frame)
-{
-	ByteStream bs;
-	int payloadlen, bslen;
-
-	payloadlen = byte_stream_curpos(&frame->data);
-
-	byte_stream_new(&bs, 6 + payloadlen);
-
-	/* FLAP header */
-	byte_stream_put8(&bs, 0x2a);
-	byte_stream_put8(&bs, frame->channel);
-	byte_stream_put16(&bs, frame->seqnum);
-	byte_stream_put16(&bs, payloadlen);
-
-	/* Payload */
-	byte_stream_rewind(&frame->data);
-	byte_stream_putbs(&bs, &frame->data, payloadlen);
-
-	bslen = byte_stream_curpos(&bs);
-	byte_stream_rewind(&bs);
-	flap_connection_send_byte_stream(&bs, conn, bslen);
-
-	byte_stream_destroy(&bs);
-}
-
-void
-flap_connection_send(FlapConnection *conn, FlapFrame *frame)
-{
-	frame->seqnum = ++(conn->seqnum_out);
-	sendframe_flap(conn, frame);
-	flap_frame_destroy(frame);
-}
--- a/libpurple/protocols/oscar/icq.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/* purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- *
- */
-
-#include "icq.h"
-
-#include "core.h"
-#include "plugins.h"
-#include "signals.h"
-
-#include "oscarcommon.h"
-
-static GHashTable *
-icq_get_account_text_table(PurpleAccount *account)
-{
-	GHashTable *table;
-	table = g_hash_table_new(g_str_hash, g_str_equal);
-	g_hash_table_insert(table, "login_label", (gpointer)_("ICQ UIN..."));
-	return table;
-}
-
-static gssize
-icq_get_max_message_size(PurpleConversation *conv)
-{
-	/* XXX: got from pidgin-otr - verify and document it */
-	return 2346;
-}
-
-static void
-icq_protocol_init(ICQProtocol *self)
-{
-	PurpleProtocol *protocol = PURPLE_PROTOCOL(self);
-
-	protocol->id   = "prpl-icq";
-	protocol->name = "ICQ";
-
-	oscar_init_account_options(protocol, TRUE);
-}
-
-static void
-icq_protocol_class_init(ICQProtocolClass *klass)
-{
-	PurpleProtocolClass *protocol_class = PURPLE_PROTOCOL_CLASS(klass);
-
-	protocol_class->list_icon = oscar_list_icon_icq;
-}
-
-static void
-icq_protocol_class_finalize(G_GNUC_UNUSED ICQProtocolClass *klass)
-{
-}
-
-static void
-icq_protocol_client_iface_init(PurpleProtocolClientInterface *client_iface)
-{
-	client_iface->get_account_text_table = icq_get_account_text_table;
-	client_iface->get_moods              = oscar_get_purple_moods;
-	client_iface->get_max_message_size   = icq_get_max_message_size;
-}
-
-G_DEFINE_DYNAMIC_TYPE_EXTENDED(
-        ICQProtocol, icq_protocol, OSCAR_TYPE_PROTOCOL, 0,
-
-        G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_CLIENT,
-                                      icq_protocol_client_iface_init));
-
-/* This exists solely because the above macro makes icq_protocol_register_type
- * static. */
-void
-icq_protocol_register(PurplePlugin *plugin)
-{
-	icq_protocol_register_type(G_TYPE_MODULE(plugin));
-}
--- a/libpurple/protocols/oscar/icq.h	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/* purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- *
- */
-
-#ifndef PURPLE_OSCAR_ICQ_H
-#define PURPLE_OSCAR_ICQ_H
-
-#include "oscar.h"
-
-#define ICQ_TYPE_PROTOCOL             (icq_protocol_get_type())
-#define ICQ_PROTOCOL(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), ICQ_TYPE_PROTOCOL, ICQProtocol))
-#define ICQ_PROTOCOL_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), ICQ_TYPE_PROTOCOL, ICQProtocolClass))
-#define ICQ_IS_PROTOCOL(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), ICQ_TYPE_PROTOCOL))
-#define ICQ_IS_PROTOCOL_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), ICQ_TYPE_PROTOCOL))
-#define ICQ_PROTOCOL_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), ICQ_TYPE_PROTOCOL, ICQProtocolClass))
-
-typedef struct
-{
-	OscarProtocol parent;
-} ICQProtocol;
-
-typedef struct
-{
-	OscarProtocolClass parent_class;
-} ICQProtocolClass;
-
-/**
- * Registers the ICQProtocol type in the type system.
- */
-G_GNUC_INTERNAL
-void icq_protocol_register(PurplePlugin *plugin);
-
-/**
- * Returns the GType for the ICQProtocol object.
- */
-G_MODULE_EXPORT GType icq_protocol_get_type(void);
-
-#endif /* PURPLE_OSCAR_ICQ_H */
--- a/libpurple/protocols/oscar/kerberos.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,425 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/**
- * This file implements AIM's kerberos procedure for authenticating
- * users.  This replaces the older MD5-based and XOR-based
- * authentication methods that use SNAC family 0x0017.
- *
- * This doesn't use SNACs or FLAPs at all.  It makes https
- * POSTs to AOL KDC server to validate the user based on the password they
- * provided to us.  Upon successful authentication we receive two tokens
- * in the response. One is assumed to be the kerberos ticket for authentication
- * on the various AOL websites, while the other contains BOSS information, such
- * as the hostname and port number to use, the TLS certificate name as well as
- * the cookie to use to authenticate to the BOS server.
- * And then everything else is the same as with BUCP.
- *
- */
-
-#include "oscar.h"
-#include "oscarcommon.h"
-#include "core.h"
-
-#define MAXAIMPASSLEN 16
-
-/*
- * Incomplete X-SNAC format taken from reverse engineering doen by digsby:
- * https://github.com/ifwe/digsby/blob/master/digsby/src/oscar/login2.py
- */
-typedef struct {
-	aim_tlv_t *main_tlv;
-	gchar *principal1;
-	gchar *service;
-	gchar *principal1_again;
-	gchar *principal2;
-	gchar unknown;
-	guint8 *footer;
-	struct {
-		guint32 unknown1;
-		guint32 unknown2;
-		guint32 epoch_now;
-		guint32 epoch_valid;
-		guint32 epoch_renew;
-		guint32 epoch_expire;
-		guint32 unknown3;
-		guint32 unknown4;
-		guint32 unknown5;
-	} dates;
-	GSList *tlvlist;
-} aim_xsnac_token_t;
-
-typedef struct {
-	guint16 family;
-	guint16 subtype;
-	guint8 flags[8];
-	guint16 request_id;
-	guint32 epoch;
-	guint32 unknown;
-	gchar *principal1;
-	gchar *principal2;
-	guint16 num_tokens;
-	aim_xsnac_token_t *tokens;
-	GSList *tlvlist;
-} aim_xsnac_t;
-
-static gchar *get_kdc_url(OscarData *od)
-{
-	PurpleAccount *account = purple_connection_get_account(od->gc);
-	const gchar *server;
-	gchar *url;
-	gchar *port_str = NULL;
-	gint port;
-
-	server = purple_account_get_string(account, "server", AIM_DEFAULT_KDC_SERVER);
-	port = purple_account_get_int(account, "port", AIM_DEFAULT_KDC_PORT);
-	if (port != 443)
-		port_str = g_strdup_printf(":%d", port);
-	url = g_strdup_printf("https://%s%s/", server, port_str ? port_str : "");
-	g_free(port_str);
-
-	return url;
-}
-
-static const char *get_client_key(OscarData *od)
-{
-	return oscar_get_ui_info_string(
-			od->icq ? "prpl-icq-clientkey" : "prpl-aim-clientkey",
-			od->icq ? ICQ_DEFAULT_CLIENT_KEY : AIM_DEFAULT_CLIENT_KEY);
-}
-
-static void
-aim_encode_password(const char *password, gchar *encoded)
-{
-	guint8 encoding_table[] = {
-		0x76, 0x91, 0xc5, 0xe7,
-		0xd0, 0xd9, 0x95, 0xdd,
-		0x9e, 0x2F, 0xea, 0xd8,
-		0x6B, 0x21, 0xc2, 0xbc,
-
-	};
-	guint i;
-
-	/*
-	 * We truncate AIM passwords to 16 characters since that's what
-	 * the official client does as well.
-	 */
-	for (i = 0; i < strlen(password) && i < MAXAIMPASSLEN; i++)
-		encoded[i] = (password[i] ^ encoding_table[i]);
-}
-
-static void
-aim_xsnac_free(aim_xsnac_t *xsnac)
-{
-	gint i;
-
-	g_free(xsnac->principal1);
-	g_free(xsnac->principal2);
-	aim_tlvlist_free(xsnac->tlvlist);
-
-	for (i = 0; i < xsnac->num_tokens; i++) {
-		g_free(xsnac->tokens[i].main_tlv->value);
-		g_free(xsnac->tokens[i].main_tlv);
-		g_free(xsnac->tokens[i].principal1);
-		g_free(xsnac->tokens[i].service);
-		g_free(xsnac->tokens[i].principal1_again);
-		g_free(xsnac->tokens[i].principal2);
-		g_free(xsnac->tokens[i].footer);
-		aim_tlvlist_free(xsnac->tokens[i].tlvlist);
-	}
-	g_free(xsnac->tokens);
-}
-
-static void
-kerberos_login_cb(G_GNUC_UNUSED SoupSession *session, SoupMessage *msg,
-                  gpointer user_data)
-{
-	OscarData *od = user_data;
-	PurpleConnection *gc;
-	ByteStream bs;
-	aim_xsnac_t xsnac = {0};
-	guint16 len;
-	gchar *bosip = NULL;
-	gchar *tlsCertName = NULL;
-	guint8 *cookie = NULL;
-	guint32 cookie_len = 0;
-	char *host; int port;
-	gsize i;
-
-	gc = od->gc;
-
-	g_clear_object(&od->http_conns);
-
-	if (!SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) {
-		gchar *tmp;
-		gchar *url;
-
-		url = get_kdc_url(od);
-		tmp = g_strdup_printf(_("Error requesting %s: %d %s"), url,
-		                      msg->status_code, msg->reason_phrase);
-		purple_connection_error(gc,
-				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
-		g_free(tmp);
-		g_free(url);
-		return;
-	}
-
-	purple_debug_info("oscar",
-	                  "Received kerberos login HTTP response %" G_GOFFSET_FORMAT
-	                  " : ",
-	                  msg->response_body->length);
-
-	byte_stream_init(&bs, (guint8 *)msg->response_body->data,
-	                 msg->response_body->length);
-
-	xsnac.family = byte_stream_get16(&bs);
-	xsnac.subtype = byte_stream_get16(&bs);
-	byte_stream_getrawbuf(&bs, (guint8 *) xsnac.flags, 8);
-
-	if (xsnac.family == 0x50C && xsnac.subtype == 0x0005) {
-		purple_connection_error(gc,
-			PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
-			_("Incorrect password"));
-		return;
-	}
-	if (xsnac.family != 0x50C || xsnac.subtype != 0x0003) {
-		purple_connection_error(gc,
-				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-			_("Error parsing response from authentication server"));
-		return;
-	}
-	xsnac.request_id = byte_stream_get16(&bs);
-	xsnac.epoch = byte_stream_get32(&bs);
-	xsnac.unknown = byte_stream_get32(&bs);
-	len = byte_stream_get16(&bs);
-	xsnac.principal1 = byte_stream_getstr(&bs, len);
-	len = byte_stream_get16(&bs);
-	xsnac.principal2 = byte_stream_getstr(&bs, len);
-	xsnac.num_tokens = byte_stream_get16(&bs);
-
-	purple_debug_info("oscar", "KDC: %d tokens between '%s' and '%s'\n",
-		xsnac.num_tokens, xsnac.principal1, xsnac.principal2);
-	xsnac.tokens = g_new0(aim_xsnac_token_t, xsnac.num_tokens);
-	for (i = 0; i < xsnac.num_tokens; i++) {
-		GSList *tlv;
-
-		tlv = aim_tlvlist_readnum(&bs, 1);
-		if (tlv)
-			xsnac.tokens[i].main_tlv = tlv->data;
-		g_slist_free(tlv);
-
-		len = byte_stream_get16(&bs);
-		xsnac.tokens[i].principal1 = byte_stream_getstr(&bs, len);
-		len = byte_stream_get16(&bs);
-		xsnac.tokens[i].service = byte_stream_getstr(&bs, len);
-		len = byte_stream_get16(&bs);
-		xsnac.tokens[i].principal1_again = byte_stream_getstr(&bs, len);
-		len = byte_stream_get16(&bs);
-		xsnac.tokens[i].principal2 = byte_stream_getstr(&bs, len);
-		xsnac.tokens[i].unknown = byte_stream_get8(&bs);
-		len = byte_stream_get16(&bs);
-		xsnac.tokens[i].footer = byte_stream_getraw(&bs, len);
-
-		xsnac.tokens[i].dates.unknown1 = byte_stream_get32(&bs);
-		xsnac.tokens[i].dates.unknown2 = byte_stream_get32(&bs);
-		xsnac.tokens[i].dates.epoch_now = byte_stream_get32(&bs);
-		xsnac.tokens[i].dates.epoch_valid = byte_stream_get32(&bs);
-		xsnac.tokens[i].dates.epoch_renew = byte_stream_get32(&bs);
-		xsnac.tokens[i].dates.epoch_expire = byte_stream_get32(&bs);
-		xsnac.tokens[i].dates.unknown3 = byte_stream_get32(&bs);
-		xsnac.tokens[i].dates.unknown4 = byte_stream_get32(&bs);
-		xsnac.tokens[i].dates.unknown5 = byte_stream_get32(&bs);
-
-		len = byte_stream_get16(&bs);
-		xsnac.tokens[i].tlvlist = aim_tlvlist_readnum(&bs, len);
-
-		purple_debug_info("oscar",
-		                  "Token %" G_GSIZE_FORMAT
-		                  " has %d TLVs for service '%s'\n",
-		                  i, len, xsnac.tokens[i].service);
-	}
-	len = byte_stream_get16(&bs);
-	xsnac.tlvlist = aim_tlvlist_readnum(&bs, len);
-
-	for (i = 0; i < xsnac.num_tokens; i++) {
-		if (purple_strequal(xsnac.tokens[i].service, "im/boss")) {
-			aim_tlv_t *tlv;
-			GSList *tlvlist;
-			ByteStream tbs;
-
-			tlv = aim_tlv_gettlv(xsnac.tokens[i].tlvlist, 0x0003, 1);
-			if (tlv != NULL) {
-				byte_stream_init(&tbs, tlv->value, tlv->length);
-				byte_stream_get32(&tbs);
-				tlvlist =  aim_tlvlist_read(&tbs);
-				if (aim_tlv_gettlv(tlvlist, 0x0005, 1))
-					bosip = aim_tlv_getstr(tlvlist, 0x0005, 1);
-				if (aim_tlv_gettlv(tlvlist, 0x0005, 1))
-					tlsCertName = aim_tlv_getstr(tlvlist, 0x008D, 1);
-				tlv = aim_tlv_gettlv(tlvlist, 0x0006, 1);
-				if (tlv) {
-					cookie_len = tlv->length;
-					cookie = tlv->value;
-				}
-			}
-			break;
-		}
-	}
-	if (bosip && cookie) {
-		port = AIM_DEFAULT_KDC_PORT;
-		for (i = 0; i < strlen(bosip); i++) {
-			if (bosip[i] == ':') {
-				port = atoi(&(bosip[i+1]));
-				break;
-			}
-		}
-		host = g_strndup(bosip, i);
-		oscar_connect_to_bos(gc, od, host, port, cookie, cookie_len, tlsCertName);
-		g_free(host);
-	} else {
-		purple_connection_error(gc,
-			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-			_("Unknown error during authentication"));
-	}
-	aim_xsnac_free(&xsnac);
-	g_free(tlsCertName);
-	g_free(bosip);
-}
-
-/**
- * This function sends a binary blob request to the Kerberos KDC server
- * https://kdc.uas.aol.com with the user's username and password and
- * receives the IM cookie, which is used to request a connection to the
- * BOSS server.
- * The binary data below is what AIM 8.0.8.1 sends in order to authenticate
- * to the KDC server. It is an 'X-SNAC' packet, which is relatively similar
- * to SNAC packets but somehow different.
- * The header starts with the 0x50C family follow by 0x0002 subtype, then
- * some fixed length data and TLVs. The string "COOL" appears in there for
- * some reason followed by the 'US' and 'en' strings.
- * Then the 'imApp key=<client key>' comes after that, and then the username
- * and the string "im/boss" which seems to represent the service we are
- * requesting the authentication for. Changing that will lead to a
- * 'unknown service' error. The client key is then added again (without the
- * 'imApp key' string prepended to it) then a XOR-ed version of the password.
- * The meaning of the header/footer/in-between bytes is not known but never
- * seems to change so there is no need to reverse engineer their meaning at
- * this point.
- */
-void send_kerberos_login(OscarData *od, const char *username)
-{
-	PurpleConnection *gc;
-	SoupMessage *msg;
-	gchar *url;
-	const gchar *password;
-	gchar password_xored[MAXAIMPASSLEN];
-	const gchar *client_key;
-	gchar *imapp_key;
-	GString *body;
-	guint16 len_be;
-	guint16 reqid;
-	const gchar header[] = {
-		0x05, 0x0C, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
-		0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x05,
-		0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05,
-		0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x18, 0x99,
-		0x00, 0x05, 0x00, 0x04, 0x43, 0x4F, 0x4F, 0x4C,
-		0x00, 0x0A, 0x00, 0x02, 0x00, 0x01, 0x00, 0x0B,
-		0x00, 0x04, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00,
-		0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
-		0x55, 0x53, 0x00, 0x02, 0x65, 0x6E, 0x00, 0x04,
-		0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0D,
-		0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04,
-		0x00, 0x05};
-	const gchar pre_username[] = {
-		0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x01, 0x8B,
-		0x01, 0x00, 0x00, 0x00, 0x00};
-	const gchar post_username[] = {
-		0x00, 0x07, 0x69, 0x6D, 0x2F, 0x62, 0x6F, 0x73,
-		0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x04, 0x00, 0x02};
-	const gchar pre_password[] = {
-		0x40, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01,
-		0x00, 0x00};
-	const gchar post_password[] = {0x00, 0x00, 0x00, 0x1D};
-	const gchar footer[] = {
-		0x00, 0x21, 0x00, 0x32, 0x00, 0x01, 0x10, 0x03,
-		0x00, 0x2C, 0x00, 0x07, 0x00, 0x14, 0x00, 0x04,
-		0x00, 0x00, 0x01, 0x8B, 0x00, 0x16, 0x00, 0x02,
-		0x00, 0x26, 0x00, 0x17, 0x00, 0x02, 0x00, 0x07,
-		0x00, 0x18, 0x00, 0x02, 0x00, 0x00, 0x00, 0x19,
-		0x00, 0x02, 0x00, 0x0D, 0x00, 0x1A, 0x00, 0x02,
-		0x00, 0x04, 0x00, 0xAB, 0x00, 0x00, 0x00, 0x28,
-		0x00, 0x00};
-
-	gc = od->gc;
-
-	password = purple_connection_get_password(gc);
-	aim_encode_password(password, password_xored);
-
-	client_key = get_client_key(od);
-	imapp_key = g_strdup_printf("imApp key=%s", client_key);
-
-	/* Construct the body of the HTTP POST request */
-	body = g_string_new(NULL);
-	g_string_append_len(body, header, sizeof(header));
-	reqid = (guint16) g_random_int();
-	g_string_overwrite_len(body, 0xC, (void *)&reqid, sizeof(guint16));
-
-	len_be = GUINT16_TO_BE(strlen(imapp_key));
-	g_string_append_len(body, (void *)&len_be, sizeof(guint16));
-	g_string_append(body, imapp_key);
-
-	len_be = GUINT16_TO_BE(strlen(username));
-	g_string_append_len(body, pre_username, sizeof(pre_username));
-	g_string_append_len(body, (void *)&len_be, sizeof(guint16));
-	g_string_append(body, username);
-	g_string_append_len(body, post_username, sizeof(post_username));
-
-	len_be = GUINT16_TO_BE(strlen(password) + 0x10);
-	g_string_append_len(body, (void *)&len_be, sizeof(guint16));
-	g_string_append_len(body, pre_password, sizeof(pre_password));
-	len_be = GUINT16_TO_BE(strlen(password) + 4);
-	g_string_append_len(body, (void *)&len_be, sizeof(guint16));
-	len_be = GUINT16_TO_BE(strlen(password));
-	g_string_append_len(body, (void *)&len_be, sizeof(guint16));
-	g_string_append_len(body, password_xored, strlen(password));
-	g_string_append_len(body, post_password, sizeof(post_password));
-
-	len_be = GUINT16_TO_BE(strlen(client_key));
-	g_string_append_len(body, (void *)&len_be, sizeof(guint16));
-	g_string_append(body, client_key);
-	g_string_append_len(body, footer, sizeof(footer));
-
-	g_free(imapp_key);
-
-	url = get_kdc_url(od);
-	msg = soup_message_new("POST", url);
-	soup_message_set_request(msg, "application/x-snac", SOUP_MEMORY_TAKE,
-	                         body->str, body->len);
-	soup_message_headers_replace(msg->request_headers, "Accept",
-	                             "application/x-snac");
-	soup_session_queue_message(od->http_conns, msg, kerberos_login_cb, od);
-
-	g_string_free(body, FALSE);
-	g_free(url);
-}
--- a/libpurple/protocols/oscar/meson.build	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-OSCARSOURCES = [
-	'authorization.c',
-	'aim.c',
-	'aim.h',
-	'bstream.c',
-	'clientlogin.c',
-	'kerberos.c',
-	'encoding.c',
-	'encoding.h',
-	'family_admin.c',
-	'family_alert.c',
-	'family_auth.c',
-	'family_bart.c',
-	'family_bos.c',
-	'family_buddy.c',
-	'family_chat.c',
-	'family_chatnav.c',
-	'family_icq.c',
-	'family_icbm.c',
-	'family_locate.c',
-	'family_oservice.c',
-	'family_popup.c',
-	'family_feedbag.c',
-	'family_stats.c',
-	'family_userlookup.c',
-	'flap_connection.c',
-	'icq.c',
-	'icq.h',
-	'misc.c',
-	'msgcookie.c',
-	'odc.c',
-	'oft.c',
-	'oscar.c',
-	'oscar.h',
-	'oscarcommon.h',
-	'oscar_data.c',
-	'peer.c',
-	'peer.h',
-	'peer_proxy.c',
-	'rxhandlers.c',
-	'snac.c',
-	'snactypes.h',
-	'tlv.c',
-	'userinfo.c',
-	'util.c',
-	'visibility.c',
-	'visibility.h'
-]
-
-if IS_WIN32
-	oscar_link_args = ['-Wl,--export-all-symbols']
-else
-	oscar_link_args = []
-endif
-
-if DYNAMIC_OSCAR
-	oscar_prpl = shared_library('oscar', OSCARSOURCES,
-	    link_args : oscar_link_args,
-	    dependencies : [libpurple_dep, glib, libsoup, ws2_32],
-	    install : true, install_dir : PURPLE_PLUGINDIR)
-
-	subdir('tests')
-endif
--- a/libpurple/protocols/oscar/misc.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,133 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Random stuff.  Basically just a few functions for sending
- * simple SNACs, and then the generic error handler.
- */
-
-#include "oscar.h"
-
-/*
- * Generic routine for sending commands.
- *
- * I know I can do this in a smarter way...but I'm not thinking straight
- * right now...
- *
- * I had one big function that handled all three cases, but then it broke
- * and I split it up into three.  But then I fixed it.  I just never went
- * back to the single.  I don't see any advantage to doing it either way.
- *
- */
-void
-aim_genericreq_n(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype)
-{
-	aim_snacid_t snacid = 0x00000000;
-
-	flap_connection_send_snac(od, conn, family, subtype, snacid, NULL);
-}
-
-void
-aim_genericreq_n_snacid(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype)
-{
-	aim_snacid_t snacid;
-
-	snacid = aim_cachesnac(od, family, subtype, 0x0000, NULL, 0);
-
-	flap_connection_send_snac(od, conn, family, subtype, snacid, NULL);
-}
-
-void
-aim_genericreq_l(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype, guint32 *longdata)
-{
-	ByteStream bs;
-	aim_snacid_t snacid;
-
-	if (!longdata)
-	{
-		aim_genericreq_n(od, conn, family, subtype);
-		return;
-	}
-
-	byte_stream_new(&bs, 4);
-
-	snacid = aim_cachesnac(od, family, subtype, 0x0000, NULL, 0);
-
-	byte_stream_put32(&bs, *longdata);
-
-	flap_connection_send_snac(od, conn, family, subtype, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-}
-
-/*
- * Should be generic enough to handle the errors for all groups.
- *
- */
-static int
-generror(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	int error = 0;
-	aim_rxcallback_t userfunc;
-	aim_snac_t *snac2;
-
-	snac2 = aim_remsnac(od, snac->id);
-
-	if (byte_stream_bytes_left(bs))
-		error = byte_stream_get16(bs);
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, error, snac2 ? snac2->data : NULL);
-
-	if (snac2) {
-		g_free(snac2->data);
-		g_free(snac2);
-	}
-
-	return ret;
-}
-
-static int
-snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	if (snac->subtype == 0x0001)
-		return generror(od, conn, mod, frame, snac, bs);
-	else if ((snac->family == 0xffff) && (snac->subtype == 0xffff)) {
-		aim_rxcallback_t userfunc;
-
-		if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-			return userfunc(od, conn, frame);
-	}
-
-	return 0;
-}
-
-int
-misc_modfirst(OscarData *od, aim_module_t *mod)
-{
-	mod->family = 0xffff;
-	mod->version = 0x0000;
-	mod->flags = AIM_MODFLAG_MULTIFAMILY;
-	strncpy(mod->name, "misc", sizeof(mod->name));
-	mod->snachandler = snachandler;
-
-	return 0;
-}
--- a/libpurple/protocols/oscar/msgcookie.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,179 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Cookie Caching stuff. Adam wrote this, apparently just some
- * derivatives of n's SNAC work. I cleaned it up, added comments.
- *
- */
-
-/*
- * I'm assuming that cookies are type-specific. that is, we can have
- * "1234578" for type 1 and type 2 concurrently. if i'm wrong, then we
- * lose some error checking. if we assume cookies are not type-specific and are
- * wrong, we get quirky behavior when cookies step on each others' toes.
- */
-
-#include "oscar.h"
-
-/**
- * aim_cachecookie - appends a cookie to the cookie list
- *
- * if cookie->cookie for type cookie->type is found, updates the
- * ->addtime of the found structure; otherwise adds the given cookie
- * to the cache
- *
- * @param od session to add to
- * @param cookie pointer to struct to append
- * @return returns -1 on error, 0 on append, 1 on update.  the cookie you pass
- *         in may be free'd, so don't count on its value after calling this!
- */
-int aim_cachecookie(OscarData *od, IcbmCookie *cookie)
-{
-	IcbmCookie *newcook;
-
-	if (!od || !cookie)
-		return -EINVAL;
-
-	newcook = aim_checkcookie(od, cookie->cookie, cookie->type);
-
-	if (newcook == cookie) {
-		newcook->addtime = time(NULL);
-		return 1;
-	} else if (newcook)
-		aim_cookie_free(od, newcook);
-
-	cookie->addtime = time(NULL);
-
-	cookie->next = od->msgcookies;
-	od->msgcookies = cookie;
-
-	return 0;
-}
-
-/**
- * aim_uncachecookie - grabs a cookie from the cookie cache (removes it from the list)
- *
- * takes a cookie string and a cookie type and finds the cookie struct associated with that duple, removing it from the cookie list ikn the process.
- *
- * @param od session to grab cookie from
- * @param cookie cookie string to look for
- * @param type cookie type to look for
- * @return if found, returns the struct; if none found (or on error), returns NULL:
- */
-IcbmCookie *aim_uncachecookie(OscarData *od, guint8 *cookie, int type)
-{
-	IcbmCookie *cur, **prev;
-
-	if (!cookie || !od->msgcookies)
-		return NULL;
-
-	for (prev = &od->msgcookies; (cur = *prev); ) {
-		if ((cur->type == type) &&
-				(memcmp(cur->cookie, cookie, 8) == 0)) {
-			*prev = cur->next;
-			return cur;
-		}
-		prev = &cur->next;
-	}
-
-	return NULL;
-}
-
-/**
- * aim_mkcookie - generate an IcbmCookie *struct from a cookie string, a type, and a data pointer.
- *
- * @param c pointer to the cookie string array
- * @param type cookie type to use
- * @param data data to be cached with the cookie
- * @return returns NULL on error, a pointer to the newly-allocated
- *         cookie on success.
- */
-IcbmCookie *aim_mkcookie(guint8 *c, int type, void *data)
-{
-	IcbmCookie *cookie;
-
-	if (!c)
-		return NULL;
-
-	cookie = g_new0(IcbmCookie, 1);
-
-	cookie->data = data;
-	cookie->type = type;
-	memcpy(cookie->cookie, c, 8);
-
-	return cookie;
-}
-
-/**
- * aim_checkcookie - check to see if a cookietuple has been cached
- *
- * @param od session to check for the cookie in
- * @param cookie pointer to the cookie string array
- * @param type type of the cookie to look for
- * @return returns a pointer to the cookie struct (still in the list)
- *         on success; returns NULL on error/not found
- */
-
-IcbmCookie *aim_checkcookie(OscarData *od, const guint8 *cookie, const int type)
-{
-	IcbmCookie *cur;
-
-	for (cur = od->msgcookies; cur; cur = cur->next) {
-		if ((cur->type == type) &&
-				(memcmp(cur->cookie, cookie, 8) == 0))
-			return cur;
-	}
-
-	return NULL;
-}
-
-/**
- * aim_cookie_free - free an IcbmCookie struct
- *
- * this function removes the cookie *cookie from the list of cookies
- * in od, and then frees all memory associated with it. including
- * its data! if you want to use the private data after calling this,
- * make sure you copy it first.
- *
- * @param od session to remove the cookie from
- * @param cookie the address of a pointer to the cookie struct to remove
- * @return returns -1 on error, 0 on success.
- *
- */
-int aim_cookie_free(OscarData *od, IcbmCookie *cookie)
-{
-	IcbmCookie *cur, **prev;
-
-	if (!od || !cookie)
-		return -EINVAL;
-
-	for (prev = &od->msgcookies; (cur = *prev); ) {
-		if (cur == cookie)
-			*prev = cur->next;
-		else
-			prev = &cur->next;
-	}
-
-	g_free(cookie->data);
-	g_free(cookie);
-
-	return 0;
-}
--- a/libpurple/protocols/oscar/odc.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,626 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/* From the oscar PRPL */
-#include "encoding.h"
-#include "oscar.h"
-#include "peer.h"
-
-/* From Purple */
-#include "conversation.h"
-#include "image-store.h"
-#include "util.h"
-
-#define DIRECTIM_MAX_FILESIZE 52428800
-
-/**
- * Free any ODC related data and print a message to the conversation
- * window based on conn->disconnect_reason.
- */
-void
-peer_odc_close(PeerConnection *conn)
-{
-	gchar *tmp;
-
-	if (conn->disconnect_reason == OSCAR_DISCONNECT_REMOTE_CLOSED)
-		tmp = g_strdup(_("The remote user has closed the connection."));
-	else if (conn->disconnect_reason == OSCAR_DISCONNECT_REMOTE_REFUSED)
-		tmp = g_strdup(_("The remote user has declined your request."));
-	else if (conn->disconnect_reason == OSCAR_DISCONNECT_LOST_CONNECTION)
-		tmp = g_strdup_printf(_("Lost connection with the remote user:<br>%s"),
-				conn->error_message);
-	else if (conn->disconnect_reason == OSCAR_DISCONNECT_INVALID_DATA)
-		tmp = g_strdup(_("Received invalid data on connection with remote user."));
-	else if (conn->disconnect_reason == OSCAR_DISCONNECT_COULD_NOT_CONNECT)
-		tmp = g_strdup(_("Unable to establish a connection with the remote user."));
-	else
-		/*
-		 * We shouldn't print a message for some disconnect_reasons.
-		 * Like OSCAR_DISCONNECT_LOCAL_CLOSED.
-		 */
-		tmp = NULL;
-
-	if (tmp != NULL)
-	{
-		PurpleAccount *account;
-		PurpleIMConversation *im;
-
-		account = purple_connection_get_account(conn->od->gc);
-		im = purple_im_conversation_new(account, conn->bn);
-		purple_conversation_write_system_message(
-			PURPLE_CONVERSATION(im), tmp, 0);
-		g_free(tmp);
-	}
-
-	if (conn->frame != NULL)
-	{
-		OdcFrame *frame;
-		frame = conn->frame;
-		g_free(frame->payload.data);
-		g_free(frame);
-	}
-}
-
-/**
- * Write the given OdcFrame to a ByteStream and send it out
- * on the established PeerConnection.
- */
-static void
-peer_odc_send(PeerConnection *conn, OdcFrame *frame)
-{
-	PurpleAccount *account;
-	const char *username;
-	size_t length;
-	ByteStream bs;
-
-	purple_debug_info("oscar", "Outgoing ODC frame to %s with "
-		"type=0x%04x, flags=0x%04x, payload length=%" G_GSIZE_FORMAT "\n",
-		conn->bn, frame->type, frame->flags, frame->payload.len);
-
-	account = purple_connection_get_account(conn->od->gc);
-	username = purple_account_get_username(account);
-	memcpy(frame->bn, username, strlen(username));
-	memcpy(frame->cookie, conn->cookie, 8);
-
-	length = 76;
-	byte_stream_new(&bs, length + frame->payload.len);
-	byte_stream_putraw(&bs, conn->magic, 4);
-	byte_stream_put16(&bs, length);
-	byte_stream_put16(&bs, frame->type);
-	byte_stream_put16(&bs, frame->subtype);
-	byte_stream_put16(&bs, 0x0000);
-	byte_stream_putraw(&bs, frame->cookie, 8);
-	byte_stream_put16(&bs, 0x0000);
-	byte_stream_put16(&bs, 0x0000);
-	byte_stream_put16(&bs, 0x0000);
-	byte_stream_put16(&bs, 0x0000);
-	byte_stream_put32(&bs, frame->payload.len);
-	byte_stream_put16(&bs, frame->encoding);
-	byte_stream_put16(&bs, 0x0000);
-	byte_stream_put16(&bs, 0x0000);
-	byte_stream_put16(&bs, frame->flags);
-	byte_stream_put16(&bs, 0x0000);
-	byte_stream_put16(&bs, 0x0000);
-	byte_stream_putraw(&bs, frame->bn, 32);
-	byte_stream_putraw(&bs, frame->payload.data, frame->payload.len);
-
-	peer_connection_send(conn, &bs);
-
-	byte_stream_destroy(&bs);
-}
-
-/**
- * Send a very basic ODC frame (which contains the cookie) so that the
- * remote user can verify that we are the person they were expecting.
- * If we made an outgoing connection to then remote user, then we send
- * this immediately.  If the remote user connected to us, then we wait
- * for the other person to send this to us, then we send one to them.
- */
-void
-peer_odc_send_cookie(PeerConnection *conn)
-{
-	OdcFrame frame;
-
-	memset(&frame, 0, sizeof(OdcFrame));
-	frame.type = 0x0001;
-	frame.subtype = 0x0006;
-	frame.flags = 0x0060; /* Maybe this means "we're sending the cookie"? */
-
-	peer_odc_send(conn, &frame);
-}
-
-/**
- * Send client-to-client typing notification over an established direct connection.
- */
-void
-peer_odc_send_typing(PeerConnection *conn, PurpleIMTypingState typing)
-{
-	OdcFrame frame;
-
-	memset(&frame, 0, sizeof(OdcFrame));
-	frame.type = 0x0001;
-	frame.subtype = 0x0006;
-	if (typing == PURPLE_IM_TYPING)
-		frame.flags = 0x0002 | 0x0008;
-	else if (typing == PURPLE_IM_TYPED)
-		frame.flags = 0x0002 | 0x0004;
-	else
-		frame.flags = 0x0002;
-
-	peer_odc_send(conn, &frame);
-}
-
-/**
- * Send client-to-client IM over an established direct connection.
- * To send a direct IM, call this just like you would aim_send_im.
- *
- * @param conn The already-connected ODC connection.
- * @param msg Null-terminated string to send.
- * @param len The length of the message to send, including binary data.
- * @param encoding See the AIM_CHARSET_* defines in oscar.h
- * @param autoreply TRUE if this is any auto-reply.
- */
-void
-peer_odc_send_im(PeerConnection *conn, const char *msg, int len, int encoding, gboolean autoreply)
-{
-	OdcFrame frame;
-
-	g_return_if_fail(msg != NULL);
-	g_return_if_fail(len > 0);
-
-	memset(&frame, 0, sizeof(OdcFrame));
-	frame.type = 0x0001;
-	frame.subtype = 0x0006;
-	frame.payload.len = len;
-	frame.encoding = encoding;
-	frame.flags = autoreply;
-	byte_stream_new(&frame.payload, len);
-	byte_stream_putraw(&frame.payload, (guint8 *)msg, len);
-
-	peer_odc_send(conn, &frame);
-
-	g_free(frame.payload.data);
-}
-
-struct embedded_data
-{
-	size_t size;
-	const guint8 *data;
-};
-
-/**
- * This is called after a direct IM has been received in its entirety.  This
- * function is passed a long chunk of data which contains the IM with any
- * data chunks (images) appended to it.
- *
- * This function rips out all the data chunks and creates a PurpleImage (?) for
- * each one.  In order to do this, it first goes through the IM and takes
- * out all the IMG tags.  When doing so, it rewrites the original IMG tag
- * with one compatible with the PurpleImage (?) code. For each one, we
- * then read in chunks of data from the end of the message and actually
- * create the img store using the given data.
- *
- * For somewhat easy reference, here's a sample message
- * (with added whitespace):
- *
- * <HTML><BODY BGCOLOR="#ffffff">
- *     <FONT LANG="0">
- *     This is a really stupid picture:<BR>
- *     <IMG SRC="Sample.jpg" ID="1" WIDTH="283" HEIGHT="212" DATASIZE="9894"><BR>
- *     Yeah it is<BR>
- *     Here is another one:<BR>
- *     <IMG SRC="Soap Bubbles.bmp" ID="2" WIDTH="256" HEIGHT="256" DATASIZE="65978">
- *     </FONT>
- * </BODY></HTML>
- * <BINARY>
- *     <DATA ID="1" SIZE="9894">datadatadatadata</DATA>
- *     <DATA ID="2" SIZE="65978">datadatadatadata</DATA>
- * </BINARY>
- */
-static void
-peer_odc_handle_payload(PeerConnection *conn, const char *msg, size_t len, int encoding, gboolean autoreply)
-{
-	PurpleConnection *gc;
-	PurpleAccount *account;
-	const char *msgend, *binary_start, *dataend;
-	const char *tmp, *start, *end, *idstr, *src, *sizestr;
-	GData *attributes;
-	GHashTable *embedded_datas;
-	struct embedded_data *embedded_data;
-	gboolean any_images = FALSE;
-	gchar *utf8;
-	GString *newmsg;
-	PurpleMessageFlags imflags;
-
-	gc = conn->od->gc;
-	account = purple_connection_get_account(gc);
-
-	dataend = msg + len;
-
-	/*
-	 * Create a hash table containing references to each embedded
-	 * data chunk.  The key is the "ID" and the value is an
-	 * embedded_data struct.
-	 */
-	embedded_datas = g_hash_table_new_full(g_direct_hash,
-			g_direct_equal, NULL, g_free);
-
-	/*
-	 * Create an index of any binary chunks.  If we run into any
-	 * problems while parsing the binary data section then we stop
-	 * parsing it, and the local user will see broken image icons.
-	 */
-	binary_start = purple_strcasestr(msg, "<binary>");
-	if (binary_start == NULL)
-		msgend = dataend;
-	else
-	{
-		msgend = binary_start;
-
-		/* Move our pointer to immediately after the <binary> tag */
-		tmp = binary_start + 8;
-
-		/* The embedded binary markup has a mimimum length of 29 bytes */
-		while ((tmp + 29 <= dataend) &&
-				purple_markup_find_tag("data", tmp, &start, &tmp, &attributes))
-		{
-			unsigned int id;
-			size_t size;
-
-			/* Move the binary pointer from ">" to the start of the data */
-			tmp++;
-
-			/* Get the ID */
-			idstr = g_datalist_get_data(&attributes, "id");
-			if (idstr == NULL)
-			{
-				g_datalist_clear(&attributes);
-				break;
-			}
-			id = atoi(idstr);
-
-			/* Get the size */
-			sizestr = g_datalist_get_data(&attributes, "size");
-			if (sizestr == NULL)
-			{
-				g_datalist_clear(&attributes);
-				break;
-			}
-			size = atol(sizestr);
-
-			g_datalist_clear(&attributes);
-
-			if ((size > 0) && (tmp + size > dataend))
-				break;
-
-			embedded_data = g_new(struct embedded_data, 1);
-			embedded_data->size = size;
-			embedded_data->data = (const guint8 *)tmp;
-			tmp += size;
-
-			/* Skip past the closing </data> tag */
-			if (g_ascii_strncasecmp(tmp, "</data>", 7))
-			{
-				g_free(embedded_data);
-				break;
-			}
-			tmp += 7;
-
-			g_hash_table_insert(embedded_datas,
-					GINT_TO_POINTER(id), embedded_data);
-		}
-	}
-
-	/*
-	 * Loop through the message, replacing OSCAR img tags with the
-	 * equivalent Purple img tag.
-	 */
-	newmsg = g_string_new("");
-	tmp = msg;
-	while (purple_markup_find_tag("img", tmp, &start, &end, &attributes))
-	{
-		PurpleImage *image = NULL;
-
-		idstr   = g_datalist_get_data(&attributes, "id");
-		src     = g_datalist_get_data(&attributes, "src");
-		sizestr = g_datalist_get_data(&attributes, "datasize");
-
-		if ((idstr != NULL) && (src != NULL) && (sizestr!= NULL))
-		{
-			unsigned int id;
-			size_t size;
-
-			id = atoi(idstr);
-			size = atol(sizestr);
-			embedded_data = g_hash_table_lookup(embedded_datas,
-					GINT_TO_POINTER(id));
-
-			if ((embedded_data != NULL) && (embedded_data->size == size))
-			{
-				image = purple_image_new_from_data(
-					embedded_data->data,
-					size);
-				purple_image_set_friendly_filename(image, src);
-			}
-		}
-
-		/* Delete the attribute list */
-		g_datalist_clear(&attributes);
-
-		/* Append the message up to the tag */
-		utf8 = oscar_decode_im(account, conn->bn, encoding, tmp, start - tmp);
-		if (utf8 != NULL) {
-			g_string_append(newmsg, utf8);
-			g_free(utf8);
-		}
-
-		if (image)
-		{
-			guint img_id;
-
-			img_id = purple_image_store_add_temporary(image);
-			g_object_unref(image);
-			any_images = TRUE;
-
-			/* Write the new image tag */
-			g_string_append_printf(newmsg, "<img src=\""
-				PURPLE_IMAGE_STORE_PROTOCOL "%u\">", img_id);
-		}
-
-		/* Continue from the end of the tag */
-		tmp = end + 1;
-	}
-
-	/* Append any remaining message data */
-	if (tmp <= msgend)
-	{
-		utf8 = oscar_decode_im(account, conn->bn, encoding, tmp, msgend - tmp);
-		if (utf8 != NULL) {
-			g_string_append(newmsg, utf8);
-			g_free(utf8);
-		}
-	}
-
-	/* Display the message we received */
-	imflags = 0;
-	if (any_images)
-		imflags |= PURPLE_MESSAGE_IMAGES;
-	if (autoreply)
-		imflags |= PURPLE_MESSAGE_AUTO_RESP;
-	purple_serv_got_im(gc, conn->bn, newmsg->str, imflags, time(NULL));
-	g_string_free(newmsg, TRUE);
-
-	/* Delete our list of pointers to embedded images */
-	g_hash_table_destroy(embedded_datas);
-}
-
-/**
- * This is a purple_input_add() watcher callback function for reading
- * direct IM payload data.  "Payload data" is always an IM and
- * maybe some embedded images or files or something.  The actual
- * ODC frame is read using peer_connection_recv_cb().  We temporarily
- * switch to this watcher callback ONLY to read the payload, and we
- * switch back once we're done.
- */
-static void
-peer_odc_recv_cb(gpointer data, gint source, PurpleInputCondition cond)
-{
-	PeerConnection *conn;
-	OdcFrame *frame;
-	ByteStream *bs;
-	gssize read;
-
-	conn = data;
-	frame = conn->frame;
-	bs = &frame->payload;
-
-	/* Read data into the temporary buffer until it is complete */
-	read = recv(conn->fd,
-				&bs->data[bs->offset],
-				bs->len - bs->offset,
-				0);
-
-	/* Check if the remote user closed the connection */
-	if (read == 0)
-	{
-		peer_connection_destroy(conn, OSCAR_DISCONNECT_REMOTE_CLOSED, NULL);
-		return;
-	}
-
-	if (read < 0)
-	{
-		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
-			/* No worries */
-			return;
-
-		peer_connection_destroy(conn,
-				OSCAR_DISCONNECT_LOST_CONNECTION, g_strerror(errno));
-		return;
-	}
-
-	bs->offset += read;
-	if (bs->offset < bs->len)
-		/* Waiting for more data to arrive */
-		return;
-	/* TODO: Instead of null-terminating this, it would be better if we just
-	   respected the length of the buffer when parsing it.  But it doesn't
-	   really matter and this is easy. */
-	bs->data[bs->len] = '\0';
-
-	/* We have a complete ODC/OFT frame!  Handle it and continue reading */
-	byte_stream_rewind(bs);
-	peer_odc_handle_payload(conn, (const char *)bs->data,
-			bs->len, frame->encoding, frame->flags & 0x0001);
-	g_free(bs->data);
-	bs->data = NULL;
-	g_free(frame);
-	conn->frame = NULL;
-
-	purple_input_remove(conn->watcher_incoming);
-	conn->watcher_incoming = purple_input_add(conn->fd,
-			PURPLE_INPUT_READ, peer_connection_recv_cb, conn);
-}
-
-/**
- * Handle an incoming OdcFrame.  If there is a payload associated
- * with this frame, then we remove the old watcher and add the
- * ODC watcher to read in the payload.
- */
-void
-peer_odc_recv_frame(PeerConnection *conn, ByteStream *bs)
-{
-	PurpleConnection *gc;
-	OdcFrame *frame;
-
-	gc = conn->od->gc;
-
-	frame = g_new0(OdcFrame, 1);
-	frame->type = byte_stream_get16(bs);
-	frame->subtype = byte_stream_get16(bs);
-	byte_stream_advance(bs, 2);
-	byte_stream_getrawbuf(bs, frame->cookie, 8);
-	byte_stream_advance(bs, 8);
-	frame->payload.len = byte_stream_get32(bs);
-	frame->encoding = byte_stream_get16(bs);
-	byte_stream_advance(bs, 4);
-	frame->flags = byte_stream_get16(bs);
-	byte_stream_advance(bs, 4);
-	byte_stream_getrawbuf(bs, frame->bn, 32);
-
-	purple_debug_info("oscar", "Incoming ODC frame from %s with "
-			"type=0x%04x, flags=0x%04x, payload length=%" G_GSIZE_FORMAT "\n",
-			frame->bn, frame->type, frame->flags, frame->payload.len);
-
-	if (!conn->ready)
-	{
-		/*
-		 * We need to verify the cookie so that we know we are
-		 * connected to our friend and not a malicious middle man.
-		 */
-
-		PurpleAccount *account;
-		PurpleIMConversation *im;
-
-		if (conn->flags & PEER_CONNECTION_FLAG_IS_INCOMING)
-		{
-			if (memcmp(conn->cookie, frame->cookie, 8))
-			{
-				/*
-				 * Oh no!  The user that connected to us did not send
-				 * the correct cookie!  They are not our friend.  Go try
-				 * to accept another connection?
-				 */
-				purple_debug_info("oscar", "Received an incorrect cookie.  "
-					"Closing connection.\n");
-				peer_connection_destroy(conn,
-						OSCAR_DISCONNECT_INVALID_DATA, NULL);
-				g_free(frame);
-				return;
-			}
-
-			/*
-			 * Ok, we know they are legit.  Now be courteous and
-			 * send them our cookie.  Note: This doesn't seem
-			 * to be necessary, but it also doesn't seem to hurt.
-			 */
-			peer_odc_send_cookie(conn);
-		}
-
-		conn->ready = TRUE;
-
-		/*
-		 * If they connected to us then close the listener socket
-		 * and send them our cookie.
-		 */
-		if (conn->listenerfd != -1)
-		{
-			close(conn->listenerfd);
-			conn->listenerfd = -1;
-		}
-
-		/* Tell the local user that we are connected */
-		account = purple_connection_get_account(gc);
-		im = purple_im_conversation_new(account, conn->bn);
-		purple_conversation_write_system_message(
-			PURPLE_CONVERSATION(im), _("Direct IM established"), 0);
-	}
-
-	if ((frame->type != 0x0001) && (frame->subtype != 0x0006))
-	{
-		purple_debug_info("oscar", "Unknown ODC frame type 0x%04hx, "
-				"subtype 0x%04hx.\n", frame->type, frame->subtype);
-		g_free(frame);
-		return;
-	}
-
-	if (frame->flags & 0x0008)
-	{
-		/* I had to leave this. It's just too funny. It reminds me of my sister. */
-		purple_debug_info("oscar", "ohmigod! %s has started typing "
-			"(DirectIM). He's going to send you a message! "
-			"*squeal*\n", conn->bn);
-		purple_serv_got_typing(gc, conn->bn, 0, PURPLE_IM_TYPING);
-	}
-	else if (frame->flags & 0x0004)
-	{
-		purple_serv_got_typing(gc, conn->bn, 0, PURPLE_IM_TYPED);
-	}
-	else
-	{
-		purple_serv_got_typing_stopped(gc, conn->bn);
-	}
-
-	if (frame->payload.len > 0)
-	{
-		if (frame->payload.len > DIRECTIM_MAX_FILESIZE)
-		{
-			gchar *tmp, *size1, *size2;
-			PurpleAccount *account;
-			PurpleIMConversation *im;
-
-			size1 = g_format_size(frame->payload.len);
-			size2 = g_format_size(DIRECTIM_MAX_FILESIZE);
-			tmp = g_strdup_printf(_("%s tried to send you a %s file, but we only allow files up to %s over Direct IM.  Try using file transfer instead.\n"), conn->bn, size1, size2);
-			g_free(size1);
-			g_free(size2);
-
-			account = purple_connection_get_account(conn->od->gc);
-			im = purple_im_conversation_new(account, conn->bn);
-			purple_conversation_write_system_message(
-				PURPLE_CONVERSATION(im), tmp, 0);
-			g_free(tmp);
-
-			peer_connection_destroy(conn, OSCAR_DISCONNECT_LOCAL_CLOSED, NULL);
-			g_free(frame);
-			return;
-		}
-
-		/* We have payload data!  Switch to the ODC watcher to read it. */
-		frame->payload.data = g_new(guint8, frame->payload.len + 1);
-		frame->payload.offset = 0;
-		conn->frame = frame;
-		purple_input_remove(conn->watcher_incoming);
-		conn->watcher_incoming = purple_input_add(conn->fd,
-				PURPLE_INPUT_READ, peer_odc_recv_cb, conn);
-		return;
-	}
-
-	g_free(frame);
-}
--- a/libpurple/protocols/oscar/oft.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,823 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * I feel like this is a good place to explain OFT, so I'm going to
- * do just that.  Each OFT packet has a header type.  I guess this
- * is pretty similar to the subtype of a SNAC packet.  The type
- * basically tells the other client the meaning of the OFT packet.
- * There are two distinct types of file transfer, which I usually
- * call "sendfile" and "getfile."  Sendfile is when you send a file
- * to another AIM user.  Getfile is when you share a group of files,
- * and other users request that you send them the files.
- *
- * A typical sendfile file transfer goes like this:
- *   1) Sender sends a channel 2 ICBM telling the other user that
- *      we want to send them a file.  At the same time, we open a
- *      listener socket (this should be done before sending the
- *      ICBM) on some port, and wait for them to connect to us.
- *      The ICBM we sent should contain our IP address and the port
- *      number that we're listening on.
- *   2) The receiver connects to the sender on the given IP address
- *      and port.  After the connection is established, the receiver
- *      sends an ICBM signifying that we are ready and waiting.
- *   3) The sender sends an OFT PROMPT message over the OFT
- *      connection.
- *   4) The receiver of the file sends back an exact copy of this
- *      OFT packet, except the cookie is filled in with the cookie
- *      from the ICBM.  I think this might be an attempt to verify
- *      that the user that is connected is actually the guy that
- *      we sent the ICBM to.  Oh, I've been calling this the ACK.
- *   5) The sender starts sending raw data across the connection
- *      until the entire file has been sent.
- *   6) The receiver knows the file is finished because the sender
- *      sent the file size in an earlier OFT packet.  So then the
- *      receiver sends the DONE thingy (after filling in the
- *      "received" checksum and size) and closes the connection.
- */
-
-#include "oscar.h"
-#include "peer.h"
-
-#include "util.h"
-
-#define CHECKSUM_BUFFER_SIZE 256 * 1024
-
-struct _ChecksumData
-{
-	PeerConnection *conn;
-	PurpleXfer *xfer;
-	GSourceFunc callback;
-	size_t size;
-	guint32 checksum;
-	size_t total;
-	FILE *file;
-	guint8 buffer[CHECKSUM_BUFFER_SIZE];
-	guint timer;
-};
-
-void
-peer_oft_checksum_destroy(ChecksumData *checksum_data)
-{
-	checksum_data->conn->checksum_data = NULL;
-	fclose(checksum_data->file);
-	if (checksum_data->timer > 0)
-		g_source_remove(checksum_data->timer);
-	g_free(checksum_data);
-}
-
-/**
- * Calculate oft checksum of buffer
- *
- * Prevcheck should be 0xFFFF0000 when starting a checksum of a file.  The
- * checksum is kind of a rolling checksum thing, so each time you get bytes
- * of a file you just call this puppy and it updates the checksum.  You can
- * calculate the checksum of an entire file by calling this in a while or a
- * for loop, or something.
- *
- * Thanks to Graham Booker for providing this improved checksum routine,
- * which is simpler and should be more accurate than Josh Myer's original
- * code. -- wtm
- *
- * This algorithm works every time I have tried it.  The other fails
- * sometimes.  So, AOL who thought this up?  It has got to be the weirdest
- * checksum I have ever seen.
- *
- * @param buffer Buffer of data to checksum.  Man I'd like to buff her...
- * @param bufsize Size of buffer.
- * @param prevchecksum Previous checksum.
- * @param odd Whether an odd number of bytes have been processed before this call
- */
-static guint32
-peer_oft_checksum_chunk(const guint8 *buffer, int bufferlen, guint32 prevchecksum, int odd)
-{
-	guint32 checksum, oldchecksum;
-	int i = 0;
-	unsigned short val;
-
-	checksum = (prevchecksum >> 16) & 0xffff;
-	if (odd)
-	{
-		/*
-		 * This is one hell of a hack, but it should always work.
-		 * Essentially, I am reindexing the array so that index 1
-		 * is the first element.  Since the odd and even bytes are
-		 * detected by the index number.
-		 */
-		i = 1;
-		bufferlen++;
-		buffer--;
-	}
-	for (; i < bufferlen; i++)
-	{
-		oldchecksum = checksum;
-		if (i & 1)
-			val = buffer[i];
-		else
-			val = buffer[i] << 8;
-		checksum -= val;
-		/*
-		 * The following appears to be necessary.... It happens
-		 * every once in a while and the checksum doesn't fail.
-		 */
-		if (checksum > oldchecksum)
-			checksum--;
-	}
-	checksum = ((checksum & 0x0000ffff) + (checksum >> 16));
-	checksum = ((checksum & 0x0000ffff) + (checksum >> 16));
-	return checksum << 16;
-}
-
-static gboolean
-peer_oft_checksum_file_piece(gpointer data)
-{
-	ChecksumData *checksum_data;
-	gboolean repeat;
-
-	checksum_data = data;
-	repeat = FALSE;
-
-	if (checksum_data->total < checksum_data->size)
-	{
-		size_t bytes = MIN(CHECKSUM_BUFFER_SIZE,
-				checksum_data->size - checksum_data->total);
-
-		bytes = fread(checksum_data->buffer, 1, bytes, checksum_data->file);
-		if (bytes != 0)
-		{
-			checksum_data->checksum = peer_oft_checksum_chunk(checksum_data->buffer, bytes, checksum_data->checksum, checksum_data->total & 1);
-			checksum_data->total += bytes;
-			repeat = TRUE;
-		}
-	}
-
-	if (!repeat)
-	{
-		purple_debug_info("oscar", "Checksum of %s calculated\n",
-				purple_xfer_get_local_filename(checksum_data->xfer));
-		if (checksum_data->callback != NULL)
-			checksum_data->callback(checksum_data);
-		peer_oft_checksum_destroy(checksum_data);
-	}
-
-	return repeat;
-}
-
-/**
- * Calculate oft checksum of a file in a series of calls to
- * peer_oft_checksum_file_piece().  We do it this way because
- * calculating the checksum on large files can take a long time,
- * and we want to return control to the UI so that the application
- * doesn't appear completely frozen.
- *
- * @param conn The connection used for this file transfer.
- * @param xfer The file transfer needing this checksum.
- * @param callback The function to call upon calculation of the checksum.
- * @param size The maximum size to check.
- */
-
-static void
-peer_oft_checksum_file(PeerConnection *conn, PurpleXfer *xfer, GSourceFunc callback, size_t size)
-{
-	ChecksumData *checksum_data;
-
-	purple_debug_info("oscar", "Calculating checksum of %s\n",
-			purple_xfer_get_local_filename(xfer));
-
-	checksum_data = g_malloc0(sizeof(ChecksumData));
-	checksum_data->conn = conn;
-	checksum_data->xfer = xfer;
-	checksum_data->callback = callback;
-	checksum_data->size = size;
-	checksum_data->checksum = 0xffff0000;
-	checksum_data->file = g_fopen(purple_xfer_get_local_filename(xfer), "rb");
-
-	if (checksum_data->file == NULL)
-	{
-		purple_debug_error("oscar", "Unable to open %s for checksumming: %s\n",
-				purple_xfer_get_local_filename(xfer), g_strerror(errno));
-		callback(checksum_data);
-		g_free(checksum_data);
-	}
-	else
-	{
-		checksum_data->timer = g_timeout_add(10,
-				peer_oft_checksum_file_piece, checksum_data);
-		conn->checksum_data = checksum_data;
-	}
-}
-
-static void
-peer_oft_copy_xfer_data(PeerConnection *conn, OftFrame *frame)
-{
-	g_free(conn->xferdata.name);
-
-	memcpy(&(conn->xferdata), frame, sizeof(OftFrame));
-	conn->xferdata.name = g_memdup(frame->name, frame->name_length);
-}
-
-/**
- * Free any OFT related data.
- */
-void
-peer_oft_close(PeerConnection *conn)
-{
-	/*
-	 * If cancelled by local user, and we're receiving a file, and
-	 * we're not connected/ready then send an ICBM cancel message.
-	 */
-	if ((purple_xfer_get_status(conn->xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL) &&
-		!conn->ready)
-	{
-		aim_im_sendch2_cancel(conn);
-	}
-
-	if (conn->sending_data_timer != 0)
-	{
-		g_source_remove(conn->sending_data_timer);
-		conn->sending_data_timer = 0;
-	}
-}
-
-/**
- * Write the given OftFrame to a ByteStream and send it out
- * on the established PeerConnection.
- */
-static void
-peer_oft_send(PeerConnection *conn, OftFrame *frame)
-{
-	size_t length;
-	ByteStream bs;
-
-	length = 192 + frame->name_length;
-	byte_stream_new(&bs, length);
-	byte_stream_putraw(&bs, conn->magic, 4);
-	byte_stream_put16(&bs, length);
-	byte_stream_put16(&bs, frame->type);
-	byte_stream_putraw(&bs, frame->cookie, 8);
-	byte_stream_put16(&bs, frame->encrypt);
-	byte_stream_put16(&bs, frame->compress);
-	byte_stream_put16(&bs, frame->totfiles);
-	byte_stream_put16(&bs, frame->filesleft);
-	byte_stream_put16(&bs, frame->totparts);
-	byte_stream_put16(&bs, frame->partsleft);
-	byte_stream_put32(&bs, frame->totsize);
-	byte_stream_put32(&bs, frame->size);
-	byte_stream_put32(&bs, frame->modtime);
-	byte_stream_put32(&bs, frame->checksum);
-	byte_stream_put32(&bs, frame->rfrcsum);
-	byte_stream_put32(&bs, frame->rfsize);
-	byte_stream_put32(&bs, frame->cretime);
-	byte_stream_put32(&bs, frame->rfcsum);
-	byte_stream_put32(&bs, frame->nrecvd);
-	byte_stream_put32(&bs, frame->recvcsum);
-	byte_stream_putraw(&bs, frame->idstring, 32);
-	byte_stream_put8(&bs, frame->flags);
-	byte_stream_put8(&bs, frame->lnameoffset);
-	byte_stream_put8(&bs, frame->lsizeoffset);
-	byte_stream_putraw(&bs, frame->dummy, 69);
-	byte_stream_putraw(&bs, frame->macfileinfo, 16);
-	byte_stream_put16(&bs, frame->nencode);
-	byte_stream_put16(&bs, frame->nlanguage);
-	/*
-	 * The name can be more than 64 characters, but if it is less than
-	 * 64 characters it is padded with NULLs.
-	 */
-	byte_stream_putraw(&bs, frame->name, frame->name_length);
-
-	peer_connection_send(conn, &bs);
-
-	byte_stream_destroy(&bs);
-}
-
-void
-peer_oft_send_prompt(PeerConnection *conn)
-{
-	conn->xferdata.type = PEER_TYPE_PROMPT;
-	peer_oft_send(conn, &conn->xferdata);
-}
-
-static void
-peer_oft_send_ack(PeerConnection *conn)
-{
-	conn->xferdata.type = PEER_TYPE_ACK;
-
-	/* Fill in the cookie */
-	memcpy(conn->xferdata.cookie, conn->cookie, 8);
-
-	peer_oft_send(conn, &conn->xferdata);
-}
-
-static void
-peer_oft_send_resume_accept(PeerConnection *conn)
-{
-	conn->xferdata.type = PEER_TYPE_RESUMEACCEPT;
-
-	/* Fill in the cookie */
-	memcpy(conn->xferdata.cookie, conn->cookie, 8);
-
-	peer_oft_send(conn, &conn->xferdata);
-}
-
-static void
-peer_oft_send_done(PeerConnection *conn)
-{
-	conn->xferdata.type = PEER_TYPE_DONE;
-	conn->xferdata.rfrcsum = 0xffff0000;
-	conn->xferdata.nrecvd = purple_xfer_get_bytes_sent(conn->xfer);
-	peer_oft_send(conn, &conn->xferdata);
-}
-
-/**
- * This function exists so that we don't remove the outgoing
- * data watcher while we're still sending data.  In most cases
- * any data we're sending will be instantly wisked away to a TCP
- * buffer maintained by our operating system... but we want to
- * make sure the core doesn't start sending file data while
- * we're still sending OFT frame data.  That would be bad.
- */
-static gboolean
-start_transfer_when_done_sending_data(gpointer data)
-{
-	PeerConnection *conn;
-
-	conn = data;
-
-	if (purple_circular_buffer_get_max_read(conn->buffer_outgoing) == 0)
-	{
-		int fd = conn->fd;
-		conn->sending_data_timer = 0;
-		conn->fd = -1;
-		purple_xfer_start(conn->xfer, fd, NULL, 0);
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-/**
- * This function is similar to the above function, except instead
- * of starting the xfer it will destroy the connection.  This is
- * used when you want to send one final message across the peer
- * connection, and then close everything.
- */
-static gboolean
-destroy_connection_when_done_sending_data(gpointer data)
-{
-	PeerConnection *conn;
-
-	conn = data;
-
-	if (purple_circular_buffer_get_max_read(conn->buffer_outgoing) == 0)
-	{
-		conn->sending_data_timer = 0;
-		peer_connection_destroy(conn, conn->disconnect_reason, NULL);
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-/*
- * This is called when a buddy sends us some file info.  This happens when they
- * are sending a file to you, and you have just established a connection to them.
- * You should send them the exact same info except use the real cookie.  We also
- * get like totally ready to like, receive the file, kay?
- */
-static void
-peer_oft_recv_frame_prompt(PeerConnection *conn, OftFrame *frame)
-{
-	/* Record the file information and send an ack */
-	peer_oft_copy_xfer_data(conn, frame);
-	peer_oft_send_ack(conn);
-
-	/* Remove our watchers and use the file transfer watchers in the core */
-	purple_input_remove(conn->watcher_incoming);
-	conn->watcher_incoming = 0;
-	conn->sending_data_timer = g_timeout_add(100,
-			start_transfer_when_done_sending_data, conn);
-}
-
-/**
- * We are sending a file to someone else.  They have just acknowledged our
- * prompt, so we want to start sending data like there's no tomorrow.
- */
-static void
-peer_oft_recv_frame_ack(PeerConnection *conn, OftFrame *frame)
-{
-	if (memcmp(conn->cookie, frame->cookie, 8) != 0)
-	{
-		purple_debug_info("oscar", "Received an incorrect cookie.  "
-				"Closing connection.\n");
-		peer_connection_destroy(conn, OSCAR_DISCONNECT_INVALID_DATA, NULL);
-		return;
-	}
-
-	/* Remove our watchers and use the file transfer watchers in the core */
-	purple_input_remove(conn->watcher_incoming);
-	conn->watcher_incoming = 0;
-	conn->sending_data_timer = g_timeout_add(100,
-			start_transfer_when_done_sending_data, conn);
-}
-
-static gboolean
-peer_oft_recv_frame_resume_checksum_calculated_cb(gpointer data)
-{
-	ChecksumData *checksum_data;
-	PeerConnection *conn;
-
-	checksum_data = data;
-	conn = checksum_data->conn;
-
-	/* Check the checksums here.  If not match, don't allow resume */
-	if (checksum_data->checksum != conn->xferdata.recvcsum || checksum_data->total != conn->xferdata.nrecvd)
-	{
-		/* Reset internal structure */
-		conn->xferdata.recvcsum = 0xffff0000;
-		conn->xferdata.rfrcsum = 0xffff0000;
-		conn->xferdata.nrecvd = 0;
-	}
-	else
-		/* Accept the change */
-		purple_xfer_set_bytes_sent(checksum_data->xfer, conn->xferdata.nrecvd);
-
-	peer_oft_send_resume_accept(conn);
-
-	return FALSE;
-}
-
-/**
- * We are sending a file to someone else.  They have just acknowledged our
- * prompt and are asking to resume, so we accept their resume and await
- * a resume ack.
- */
-static void
-peer_oft_recv_frame_resume(PeerConnection *conn, OftFrame *frame)
-{
-	if (memcmp(conn->cookie, frame->cookie, 8) != 0)
-	{
-		purple_debug_info("oscar", "Received an incorrect cookie.  "
-				"Closing connection.\n");
-		peer_connection_destroy(conn, OSCAR_DISCONNECT_INVALID_DATA, NULL);
-		return;
-	}
-
-	/* Copy resume data into internal structure */
-	conn->xferdata.recvcsum = frame->recvcsum;
-	conn->xferdata.rfrcsum = frame->rfrcsum;
-	conn->xferdata.nrecvd = frame->nrecvd;
-
-	peer_oft_checksum_file(conn, conn->xfer,
-			peer_oft_recv_frame_resume_checksum_calculated_cb,
-			frame->nrecvd);
-}
-
-/*
- * We just sent a file to someone.  They said they got it and everything,
- * so we can close our direct connection and what not.
- */
-static void
-peer_oft_recv_frame_done(PeerConnection *conn, OftFrame *frame)
-{
-	/*
-	 * The core ft code sets the xfer to completed automatically if we've
-	 * sent all bytes to the other user.  But this function can be called
-	 * even if we haven't sent all bytes to the other user (in the case
-	 * where the user already has this file on their computer and the
-	 * checksum matches).
-	 */
-	if (!purple_xfer_is_completed(conn->xfer))
-		purple_xfer_set_completed(conn->xfer, TRUE);
-
-	purple_input_remove(conn->watcher_incoming);
-	conn->watcher_incoming = 0;
-	purple_xfer_set_fd(conn->xfer, conn->fd);
-	conn->fd = -1;
-	conn->disconnect_reason = OSCAR_DISCONNECT_DONE;
-	peer_connection_schedule_destroy(conn, conn->disconnect_reason, NULL);
-}
-
-/**
- * Handle an incoming OftFrame.  If there is a payload associated
- * with this frame, then we remove the old watcher and add the
- * OFT watcher to read in the payload.
- */
-void
-peer_oft_recv_frame(PeerConnection *conn, ByteStream *bs)
-{
-	OftFrame frame;
-
-	frame.type = byte_stream_get16(bs);
-	byte_stream_getrawbuf(bs, frame.cookie, 8);
-	frame.encrypt = byte_stream_get16(bs);
-	frame.compress = byte_stream_get16(bs);
-	frame.totfiles = byte_stream_get16(bs);
-	frame.filesleft = byte_stream_get16(bs);
-	frame.totparts = byte_stream_get16(bs);
-	frame.partsleft = byte_stream_get16(bs);
-	frame.totsize = byte_stream_get32(bs);
-	frame.size = byte_stream_get32(bs);
-	frame.modtime = byte_stream_get32(bs);
-	frame.checksum = byte_stream_get32(bs);
-	frame.rfrcsum = byte_stream_get32(bs);
-	frame.rfsize = byte_stream_get32(bs);
-	frame.cretime = byte_stream_get32(bs);
-	frame.rfcsum = byte_stream_get32(bs);
-	frame.nrecvd = byte_stream_get32(bs);
-	frame.recvcsum = byte_stream_get32(bs);
-	byte_stream_getrawbuf(bs, frame.idstring, 32);
-	frame.flags = byte_stream_get8(bs);
-	frame.lnameoffset = byte_stream_get8(bs);
-	frame.lsizeoffset = byte_stream_get8(bs);
-	byte_stream_getrawbuf(bs, frame.dummy, 69);
-	byte_stream_getrawbuf(bs, frame.macfileinfo, 16);
-	frame.nencode = byte_stream_get16(bs);
-	frame.nlanguage = byte_stream_get16(bs);
-	frame.name_length = bs->len - 186;
-	frame.name = byte_stream_getraw(bs, frame.name_length);
-
-	purple_debug_info("oscar", "Incoming OFT frame from %s with "
-			"type=0x%04x\n", conn->bn, frame.type);
-
-	/* TODOFT: peer_oft_dirconvert_fromstupid(frame->name); */
-
-	switch(frame.type)
-	{
-		case PEER_TYPE_PROMPT:
-			peer_oft_recv_frame_prompt(conn, &frame);
-			break;
-		case PEER_TYPE_ACK:
-		case PEER_TYPE_RESUMEACK:
-			peer_oft_recv_frame_ack(conn, &frame);
-			break;
-		case PEER_TYPE_RESUME:
-			peer_oft_recv_frame_resume(conn, &frame);
-			break;
-		case PEER_TYPE_DONE:
-			peer_oft_recv_frame_done(conn, &frame);
-			break;
-		default:
-			break;
-	}
-
-	g_free(frame.name);
-}
-
-/*******************************************************************/
-/* Begin PurpleXfer callbacks for use when receiving a file          */
-/*******************************************************************/
-
-void
-peer_oft_recvcb_init(PurpleXfer *xfer)
-{
-	PeerConnection *conn;
-
-	conn = oscar_xfer_get_peer_connection(OSCAR_XFER(xfer));
-	conn->flags |= PEER_CONNECTION_FLAG_APPROVED;
-	peer_connection_trynext(conn);
-}
-
-void
-peer_oft_recvcb_end(PurpleXfer *xfer)
-{
-	PeerConnection *conn;
-
-	conn = oscar_xfer_get_peer_connection(OSCAR_XFER(xfer));
-
-	/* Tell the other person that we've received everything */
-	conn->fd = purple_xfer_get_fd(conn->xfer);
-	purple_xfer_set_fd(conn->xfer, -1);
-	peer_oft_send_done(conn);
-
-	conn->disconnect_reason = OSCAR_DISCONNECT_DONE;
-	conn->sending_data_timer = g_timeout_add(100,
-			destroy_connection_when_done_sending_data, conn);
-}
-
-void
-peer_oft_recvcb_ack_recv(PurpleXfer *xfer, const guchar *buffer, size_t size)
-{
-	PeerConnection *conn;
-
-	/* Update our rolling checksum.  Like Walmart, yo. */
-	conn = oscar_xfer_get_peer_connection(OSCAR_XFER(xfer));
-	conn->xferdata.recvcsum = peer_oft_checksum_chunk(buffer,
-			size, conn->xferdata.recvcsum, purple_xfer_get_bytes_sent(xfer) & 1);
-}
-
-/*******************************************************************/
-/* End PurpleXfer callbacks for use when receiving a file            */
-/*******************************************************************/
-
-/*******************************************************************/
-/* Begin PurpleXfer callbacks for use when sending a file            */
-/*******************************************************************/
-
-static gboolean
-peer_oft_checksum_calculated_cb(gpointer data)
-{
-	ChecksumData *checksum_data;
-	PeerConnection *conn;
-
-	checksum_data = data;
-	conn = checksum_data->conn;
-
-	conn->xferdata.checksum = checksum_data->checksum;
-
-	/* Start the connection process */
-	peer_connection_trynext(checksum_data->conn);
-
-	return FALSE;
-}
-
-void
-peer_oft_sendcb_init(PurpleXfer *xfer)
-{
-	PeerConnection *conn;
-	goffset size;
-
-	conn = oscar_xfer_get_peer_connection(OSCAR_XFER(xfer));
-	conn->flags |= PEER_CONNECTION_FLAG_APPROVED;
-
-	/* Make sure the file size can be represented in 32 bits */
-	size = purple_xfer_get_size(xfer);
-	if (size > G_MAXUINT32)
-	{
-		gchar *tmp, *size1, *size2;
-		size1 = g_format_size(size);
-		size2 = g_format_size(G_MAXUINT32);
-		tmp = g_strdup_printf(_("File %s is %s, which is larger than "
-				"the maximum size of %s."),
-				purple_xfer_get_local_filename(xfer), size1, size2);
-		purple_xfer_error(purple_xfer_get_xfer_type(xfer),
-				purple_xfer_get_account(xfer), purple_xfer_get_remote_user(xfer), tmp);
-		g_free(size1);
-		g_free(size2);
-		g_free(tmp);
-		peer_connection_destroy(conn, OSCAR_DISCONNECT_LOCAL_CLOSED, NULL);
-		return;
-	}
-
-	/* Keep track of file transfer info */
-	conn->xferdata.totfiles = 1;
-	conn->xferdata.filesleft = 1;
-	conn->xferdata.totparts = 1;
-	conn->xferdata.partsleft = 1;
-	conn->xferdata.totsize = size;
-	conn->xferdata.size = size;
-	conn->xferdata.checksum = 0xffff0000;
-	conn->xferdata.rfrcsum = 0xffff0000;
-	conn->xferdata.rfcsum = 0xffff0000;
-	conn->xferdata.recvcsum = 0xffff0000;
-	strncpy((gchar *)conn->xferdata.idstring, "Cool FileXfer", 31);
-	conn->xferdata.modtime = 0;
-	conn->xferdata.cretime = 0;
-	purple_xfer_set_filename(xfer, g_path_get_basename(purple_xfer_get_local_filename(xfer)));
-	conn->xferdata.name_length = MAX(64, strlen(purple_xfer_get_filename(xfer)) + 1);
-	conn->xferdata.name = (guchar *)g_strndup(purple_xfer_get_filename(xfer), conn->xferdata.name_length - 1);
-
-	peer_oft_checksum_file(conn, xfer,
-			peer_oft_checksum_calculated_cb, G_MAXUINT32);
-}
-
-/*
- * AIM file transfers aren't really meant to be thought
- * of as a transferring just a single file.  The rendezvous
- * establishes a connection between two computers, and then
- * those computers can use the same connection for transferring
- * multiple files.  So we don't want the Purple core up and closing
- * the socket all willy-nilly.  We want to do that in the oscar
- * protocol, whenever one side or the other says they're finished
- * using the connection.  There might be a better way to intercept
- * the socket from the core...
- */
-void
-peer_oft_sendcb_ack(PurpleXfer *xfer, const guchar *buffer, size_t size)
-{
-	PeerConnection *conn;
-
-	conn = oscar_xfer_get_peer_connection(OSCAR_XFER(xfer));
-
-	/*
-	 * If we're done sending, intercept the socket from the core ft code
-	 * and wait for the other guy to send the "done" OFT packet.
-	 */
-	if (purple_xfer_get_bytes_remaining(xfer) <= 0)
-	{
-		purple_input_remove(purple_xfer_get_watcher(xfer));
-		conn->fd = purple_xfer_get_fd(xfer);
-		purple_xfer_set_fd(xfer, -1);
-		conn->watcher_incoming = purple_input_add(conn->fd,
-				PURPLE_INPUT_READ, peer_connection_recv_cb, conn);
-	}
-}
-
-/*******************************************************************/
-/* End PurpleXfer callbacks for use when sending a file              */
-/*******************************************************************/
-
-/*******************************************************************/
-/* Begin PurpleXfer callbacks for use when sending and receiving     */
-/*******************************************************************/
-
-void
-peer_oft_cb_generic_cancel(PurpleXfer *xfer)
-{
-	PeerConnection *conn;
-
-	conn = oscar_xfer_get_peer_connection(OSCAR_XFER(xfer));
-
-	if (conn == NULL)
-		return;
-
-	peer_connection_destroy(conn, OSCAR_DISCONNECT_LOCAL_CLOSED, NULL);
-}
-
-/*******************************************************************/
-/* End PurpleXfer callbacks for use when sending and receiving       */
-/*******************************************************************/
-
-#ifdef TODOFT
-/*
- * This little area in oscar.c is the nexus of file transfer code,
- * so I wrote a little explanation of what happens.  I am such a
- * ninja.
- *
- * The series of events for a file send is:
- *  -Create xfer and call purple_xfer_request (this happens in oscar_ask_sendfile)
- *  -User chooses a file and oscar_xfer_init is called.  It establishes a
- *   listening socket, then asks the remote user to connect to us (and
- *   gives them the file name, port, IP, etc.)
- *  -They connect to us and we send them an PEER_TYPE_PROMPT (this happens
- *   in peer_oft_recv_frame_established)
- *  -They send us an PEER_TYPE_ACK and then we start sending data
- *  -When we finish, they send us an PEER_TYPE_DONE and they close the
- *   connection.
- *  -We get drunk because file transfer kicks ass.
- *
- * The series of events for a file receive is:
- *  -Create xfer and call purple_xfer request (this happens in incomingim_chan2)
- *  -Purple user selects file to name and location to save file to and
- *   oscar_xfer_init is called
- *  -It connects to the remote user using the IP they gave us earlier
- *  -After connecting, they send us an PEER_TYPE_PROMPT.  In reply, we send
- *   them an PEER_TYPE_ACK.
- *  -They begin to send us lots of raw data.
- *  -When they finish sending data we send an PEER_TYPE_DONE and then close
- *   the connection.
- *
- * Update August 2005:
- * The series of events for transfers has been seriously complicated by the addition
- * of transfer redirects and proxied connections. I could throw a whole lot of words
- * at trying to explain things here, but it probably wouldn't do much good. To get
- * a better idea of what happens, take a look at the diagrams and documentation
- * from my Summer of Code project. -- Jonathan Clark
- */
-
-/**
- * Convert the directory separator from / (0x2f) to ^A (0x01)
- *
- * @param name The filename to convert.
- */
-static void
-peer_oft_dirconvert_tostupid(char *name)
-{
-	while (name[0]) {
-		if (name[0] == 0x01)
-			name[0] = G_DIR_SEPARATOR;
-		name++;
-	}
-}
-
-/**
- * Convert the directory separator from ^A (0x01) to / (0x2f)
- *
- * @param name The filename to convert.
- */
-static void
-peer_oft_dirconvert_fromstupid(char *name)
-{
-	while (name[0]) {
-		if (name[0] == G_DIR_SEPARATOR)
-			name[0] = 0x01;
-		name++;
-	}
-}
-#endif
--- a/libpurple/protocols/oscar/oscar.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5839 +0,0 @@
-/*
- * purple
- *
- * Some code copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
- * Some code copyright (C) 1999-2001, Eric Warmenhoven
- * Some code copyright (C) 2001-2003, Sean Egan
- * Some code copyright (C) 2001-2007, Mark Doliner <thekingant@users.sourceforge.net>
- * Some code copyright (C) 2005, Jonathan Clark <ardentlygnarly@users.sourceforge.net>
- * Some code copyright (C) 2007, ComBOTS Product GmbH (htfv) <foss@combots.com>
- * Some code copyright (C) 2008, Aman Gupta
- *
- * Most libfaim code copyright (C) 1998-2001 Adam Fritzler <afritz@auk.cx>
- * Some libfaim code copyright (C) 2001-2004 Mark Doliner <thekingant@users.sourceforge.net>
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- *
- */
-
-#include "internal.h"
-
-#include "account.h"
-#include "buddyicon.h"
-#include "conversation.h"
-#include "core.h"
-#include "debug.h"
-#include "encoding.h"
-#include "image-store.h"
-#include "network.h"
-#include "notify.h"
-#include "protocol.h"
-#include "proxy.h"
-#include "purpleaccountoption.h"
-#include "request.h"
-#include "util.h"
-#include "version.h"
-#include "visibility.h"
-
-#include "aim.h"
-#include "icq.h"
-#include "oscarcommon.h"
-#include "oscar.h"
-#include "peer.h"
-
-static PurpleProtocol *aim_protocol = NULL;
-static PurpleProtocol *icq_protocol = NULL;
-
-static guint64 purple_caps =
-	OSCAR_CAPABILITY_CHAT
-		| OSCAR_CAPABILITY_BUDDYICON
-		| OSCAR_CAPABILITY_DIRECTIM
-		| OSCAR_CAPABILITY_SENDFILE
-		| OSCAR_CAPABILITY_UNICODE
-		| OSCAR_CAPABILITY_INTEROPERATE
-		| OSCAR_CAPABILITY_SHORTCAPS
-		| OSCAR_CAPABILITY_TYPING
-		| OSCAR_CAPABILITY_ICQSERVERRELAY
-		| OSCAR_CAPABILITY_NEWCAPS
-		| OSCAR_CAPABILITY_XTRAZ
-		| OSCAR_CAPABILITY_HTML_MSGS;
-
-static guint8 features_aim[] = {0x01, 0x01, 0x01, 0x02};
-static guint8 features_icq[] = {0x01};
-
-struct create_room {
-	char *name;
-	int exchange;
-};
-
-struct oscar_ask_directim_data
-{
-	OscarData *od;
-	char *who;
-};
-
-/* All the libfaim->purple callback functions */
-
-/* Only used when connecting with the old-style BUCP login */
-static int purple_parse_auth_resp  (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_auth_securid_request(OscarData *, FlapConnection *, FlapFrame *, ...);
-
-static int purple_handle_redirect  (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_info_change      (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_account_confirm  (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_oncoming   (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_offgoing   (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_incoming_im(OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_misses     (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_clientauto (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_motd       (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_chatnav_info     (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_chat_conversation_join (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_chat_conversation_left (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_chat_conversation_info_update (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_chat_conversation_incoming_msg(OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_email_parseupdate(OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_icon_parseicon   (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_searcherror(OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_searchreply(OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_bosrights        (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_connerr          (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_mtn        (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_locaterights(OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_buddyrights(OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_genericerr (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_selfinfo         (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_popup            (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_ssi_parseerr     (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_ssi_parserights  (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_ssi_parselist    (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_ssi_parseack     (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_ssi_parseaddmod  (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_ssi_authgiven    (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_ssi_authrequest  (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_ssi_authreply    (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_ssi_gotadded     (OscarData *, FlapConnection *, FlapFrame *, ...);
-
-static void purple_icons_fetch(PurpleConnection *gc);
-
-void oscar_set_info(PurpleConnection *gc, const char *info);
-static void oscar_set_info_and_status(PurpleAccount *account, gboolean setinfo, const char *rawinfo, gboolean setstatus, PurpleStatus *status);
-static void oscar_set_extended_status(PurpleConnection *gc);
-static gboolean purple_ssi_rerequestdata(gpointer data);
-
-void oscar_free_name_data(struct name_data *data) {
-	g_free(data->name);
-	g_free(data->nick);
-	g_free(data);
-}
-
-#ifdef _WIN32
-const char *oscar_get_locale_charset(void) {
-	static const char *charset = NULL;
-	if (charset == NULL)
-		g_get_charset(&charset);
-	return charset;
-}
-#endif
-
-static char *oscar_icqstatus(int state) {
-	/* Make a cute little string that shows the status of the dude or dudet */
-	if (state & AIM_ICQ_STATE_CHAT)
-		return g_strdup(_("Free For Chat"));
-	else if (state & AIM_ICQ_STATE_DND)
-		return g_strdup(_("Do Not Disturb"));
-	else if (state & AIM_ICQ_STATE_OUT)
-		return g_strdup(_("Not Available"));
-	else if (state & AIM_ICQ_STATE_BUSY)
-		return g_strdup(_("Occupied"));
-	else if (state & AIM_ICQ_STATE_AWAY)
-		return g_strdup(_("Away"));
-	else if (state & AIM_ICQ_STATE_WEBAWARE)
-		return g_strdup(_("Web Aware"));
-	else if (state & AIM_ICQ_STATE_INVISIBLE)
-		return g_strdup(_("Invisible"));
-	else if (state & AIM_ICQ_STATE_EVIL)
-		return g_strdup(_("Evil"));
-	else if (state & AIM_ICQ_STATE_DEPRESSION)
-		return g_strdup(_("Depression"));
-	else if (state & AIM_ICQ_STATE_ATHOME)
-		return g_strdup(_("At home"));
-	else if (state & AIM_ICQ_STATE_ATWORK)
-		return g_strdup(_("At work"));
-	else if (state & AIM_ICQ_STATE_LUNCH)
-		return g_strdup(_("At lunch"));
-	else
-		return g_strdup(_("Online"));
-}
-
-static char *extract_name(const char *name) {
-	char *tmp, *x;
-	int i, j;
-
-	if (!name)
-		return NULL;
-
-	x = strchr(name, '-');
-	if (!x)
-		return NULL;
-
-	x = strchr(x + 1, '-');
-	if (!x)
-		return NULL;
-
-	tmp = g_strdup(++x);
-
-	for (i = 0, j = 0; x[i]; i++) {
-		char hex[3];
-		if (x[i] != '%') {
-			tmp[j++] = x[i];
-			continue;
-		}
-		strncpy(hex, x + ++i, 2);
-		hex[2] = 0;
-		i++;
-		tmp[j++] = strtol(hex, NULL, 16);
-	}
-
-	tmp[j] = 0;
-	return tmp;
-}
-
-static struct chat_connection *
-find_oscar_chat(PurpleConnection *gc, int id)
-{
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	GSList *cur;
-	struct chat_connection *cc;
-
-	for (cur = od->oscar_chats; cur != NULL; cur = cur->next)
-	{
-		cc = (struct chat_connection *)cur->data;
-		if (cc->id == id)
-			return cc;
-	}
-
-	return NULL;
-}
-
-static struct chat_connection *
-find_oscar_chat_by_conn(PurpleConnection *gc, FlapConnection *conn)
-{
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	GSList *cur;
-	struct chat_connection *cc;
-
-	for (cur = od->oscar_chats; cur != NULL; cur = cur->next)
-	{
-		cc = (struct chat_connection *)cur->data;
-		if (cc->conn == conn)
-			return cc;
-	}
-
-	return NULL;
-}
-
-static struct chat_connection *
-find_oscar_chat_by_conv(PurpleConnection *gc, PurpleChatConversation *conv)
-{
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	GSList *cur;
-	struct chat_connection *cc;
-
-	for (cur = od->oscar_chats; cur != NULL; cur = cur->next)
-	{
-		cc = (struct chat_connection *)cur->data;
-		if (cc->conv == conv)
-			return cc;
-	}
-
-	return NULL;
-}
-
-void
-oscar_chat_destroy(struct chat_connection *cc)
-{
-	g_free(cc->name);
-	g_free(cc->show);
-	g_free(cc);
-}
-
-static void
-oscar_chat_kill(PurpleConnection *gc, struct chat_connection *cc)
-{
-	OscarData *od = purple_connection_get_protocol_data(gc);
-
-	/* Notify the conversation window that we've left the chat */
-	purple_serv_got_chat_left(gc, purple_chat_conversation_get_id(cc->conv));
-
-	/* Destroy the chat_connection */
-	od->oscar_chats = g_slist_remove(od->oscar_chats, cc);
-	oscar_chat_destroy(cc);
-}
-
-/**
- * This is called from the callback functions for establishing
- * a TCP connection with an oscar host if an error occurred.
- */
-static void
-connection_common_error_cb(FlapConnection *conn, const gchar *error_message)
-{
-	OscarData *od;
-	PurpleConnection *gc;
-
-	od = conn->od;
-	gc = od->gc;
-
-	purple_debug_error("oscar", "unable to connect to FLAP "
-			"server of type 0x%04hx\n", conn->type);
-
-	if (conn->type == SNAC_FAMILY_AUTH)
-	{
-		/* This only happens when connecting with the old-style BUCP login */
-		gchar *msg;
-		msg = g_strdup_printf(_("Unable to connect to authentication server: %s"),
-				error_message);
-		purple_connection_error(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
-		g_free(msg);
-	}
-	else if (conn->type == SNAC_FAMILY_LOCATE)
-	{
-		gchar *msg;
-		msg = g_strdup_printf(_("Unable to connect to BOS server: %s"),
-				error_message);
-		purple_connection_error(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
-		g_free(msg);
-	}
-	else
-	{
-		/* Maybe we should call this for BOS connections, too? */
-		flap_connection_schedule_destroy(conn,
-				OSCAR_DISCONNECT_COULD_NOT_CONNECT, error_message);
-	}
-}
-
-/**
- * This is called from the callback functions for establishing
- * a TCP connection with an oscar host. Depending on the type
- * of host, we do a few different things here.
- */
-static void
-connection_common_established_cb(FlapConnection *conn)
-{
-	OscarData *od;
-	PurpleConnection *gc;
-	PurpleAccount *account;
-
-	od = conn->od;
-	gc = od->gc;
-	account = purple_connection_get_account(gc);
-
-	purple_debug_info("oscar", "connected to FLAP server of type 0x%04hx\n",
-			conn->type);
-
-	if (conn->cookie == NULL)
-		flap_connection_send_version(od, conn);
-	else
-	{
-		const gchar *login_type = purple_account_get_string(account, "login_type", OSCAR_DEFAULT_LOGIN);
-
-		if (!purple_strequal(login_type, OSCAR_MD5_LOGIN))
-		{
-			ClientInfo aiminfo = CLIENTINFO_PURPLE_AIM;
-			ClientInfo icqinfo = CLIENTINFO_PURPLE_ICQ;
-			flap_connection_send_version_with_cookie_and_clientinfo(od,
-					conn, conn->cookielen, conn->cookie,
-					od->icq ? &icqinfo : &aiminfo,
-					purple_account_get_bool(account, "allow_multiple_logins", OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS));
-		} else {
-			flap_connection_send_version_with_cookie(od, conn,
-					conn->cookielen, conn->cookie);
-		}
-
-
-		g_free(conn->cookie);
-		conn->cookie = NULL;
-	}
-
-	if (conn->type == SNAC_FAMILY_AUTH)
-	{
-		/* This only happens when connecting with the old-style BUCP login */
-		aim_request_login(od, conn, purple_account_get_username(account));
-		purple_debug_info("oscar", "Username sent, waiting for response\n");
-		purple_connection_update_progress(gc, _("Username sent"), 1, OSCAR_CONNECT_STEPS);
-	}
-	else if (conn->type == SNAC_FAMILY_LOCATE)
-	{
-		purple_connection_update_progress(gc, _("Connection established, cookie sent"), 4, OSCAR_CONNECT_STEPS);
-	}
-	else if (conn->type == SNAC_FAMILY_CHAT)
-	{
-		od->oscar_chats = g_slist_prepend(od->oscar_chats, conn->new_conn_data);
-		conn->new_conn_data = NULL;
-	}
-}
-
-static void
-connection_established_cb(gpointer data, gint source, const gchar *error_message)
-{
-	FlapConnection *conn;
-
-	conn = data;
-
-	conn->connect_data = NULL;
-	conn->fd = source;
-
-	if (source < 0)
-	{
-		connection_common_error_cb(conn, error_message);
-		return;
-	}
-
-	conn->watcher_incoming = purple_input_add(conn->fd,
-			PURPLE_INPUT_READ, flap_connection_recv_cb, conn);
-	connection_common_established_cb(conn);
-}
-
-static void
-ssl_connection_established_cb(gpointer data, PurpleSslConnection *gsc,
-		PurpleInputCondition cond)
-{
-	FlapConnection *conn;
-
-	conn = data;
-
-	purple_ssl_input_add(gsc, flap_connection_recv_cb_ssl, conn);
-	connection_common_established_cb(conn);
-}
-
-static void
-ssl_connection_error_cb(PurpleSslConnection *gsc, PurpleSslErrorType error,
-		gpointer data)
-{
-	FlapConnection *conn;
-
-	conn = data;
-
-	if (conn->watcher_outgoing)
-	{
-		purple_input_remove(conn->watcher_outgoing);
-		conn->watcher_outgoing = 0;
-	}
-
-	/* sslconn frees the connection on error */
-	conn->gsc = NULL;
-
-	connection_common_error_cb(conn, purple_ssl_strerror(error));
-}
-
-static void
-flap_connection_established_bos(OscarData *od, FlapConnection *conn)
-{
-	PurpleConnection *gc = od->gc;
-
-	aim_srv_reqpersonalinfo(od, conn);
-
-	purple_debug_info("oscar", "ssi: requesting rights and list\n");
-	aim_ssi_reqrights(od);
-	aim_ssi_reqdata(od);
-	if (od->getblisttimer > 0)
-		g_source_remove(od->getblisttimer);
-	od->getblisttimer = g_timeout_add_seconds(30, purple_ssi_rerequestdata, od);
-
-	aim_locate_reqrights(od);
-	aim_buddylist_reqrights(od, conn);
-	aim_im_reqparams(od);
-	aim_bos_reqrights(od, conn); /* TODO: Don't call this with ssi */
-
-	purple_connection_update_progress(gc, _("Finalizing connection"), 5, OSCAR_CONNECT_STEPS);
-}
-
-static void
-flap_connection_established_admin(OscarData *od, FlapConnection *conn)
-{
-	aim_srv_clientready(od, conn);
-	purple_debug_info("oscar", "connected to admin\n");
-
-	if (od->chpass) {
-		purple_debug_info("oscar", "changing password\n");
-		aim_admin_changepasswd(od, conn, od->newp, od->oldp);
-		g_free(od->oldp);
-		od->oldp = NULL;
-		g_free(od->newp);
-		od->newp = NULL;
-		od->chpass = FALSE;
-	}
-	if (od->setnick) {
-		purple_debug_info("oscar", "formatting username\n");
-		aim_admin_setnick(od, conn, od->newformatting);
-		g_free(od->newformatting);
-		od->newformatting = NULL;
-		od->setnick = FALSE;
-	}
-	if (od->conf) {
-		purple_debug_info("oscar", "confirming account\n");
-		aim_admin_reqconfirm(od, conn);
-		od->conf = FALSE;
-	}
-	if (od->reqemail) {
-		purple_debug_info("oscar", "requesting email address\n");
-		aim_admin_getinfo(od, conn, 0x0011);
-		od->reqemail = FALSE;
-	}
-	if (od->setemail) {
-		purple_debug_info("oscar", "setting email address\n");
-		aim_admin_setemail(od, conn, od->email);
-		g_free(od->email);
-		od->email = NULL;
-		od->setemail = FALSE;
-	}
-}
-
-static void
-flap_connection_established_chat(OscarData *od, FlapConnection *conn)
-{
-	PurpleConnection *gc = od->gc;
-	struct chat_connection *chatcon;
-	static int id = 1;
-
-	aim_srv_clientready(od, conn);
-
-	chatcon = find_oscar_chat_by_conn(gc, conn);
-	if (chatcon) {
-		chatcon->id = id;
-		chatcon->conv = purple_serv_got_joined_chat(gc, id++, chatcon->show);
-	}
-}
-
-static void
-flap_connection_established_chatnav(OscarData *od, FlapConnection *conn)
-{
-	aim_srv_clientready(od, conn);
-	aim_chatnav_reqrights(od, conn);
-}
-
-static void
-flap_connection_established_alert(OscarData *od, FlapConnection *conn)
-{
-	aim_email_sendcookies(od);
-	aim_email_activate(od);
-	aim_srv_clientready(od, conn);
-}
-
-static void
-flap_connection_established_bart(OscarData *od, FlapConnection *conn)
-{
-	PurpleConnection *gc = od->gc;
-
-	aim_srv_clientready(od, conn);
-
-	od->iconconnecting = FALSE;
-
-	purple_icons_fetch(gc);
-}
-
-static int
-flap_connection_established(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
-{
-	conn->connected = TRUE;
-	purple_debug_info("oscar", "FLAP connection of type 0x%04hx is "
-			"now fully connected\n", conn->type);
-	if (conn->type == SNAC_FAMILY_LOCATE)
-		flap_connection_established_bos(od, conn);
-	else if (conn->type == SNAC_FAMILY_ADMIN)
-		flap_connection_established_admin(od, conn);
-	else if (conn->type == SNAC_FAMILY_CHAT)
-		flap_connection_established_chat(od, conn);
-	else if (conn->type == SNAC_FAMILY_CHATNAV)
-		flap_connection_established_chatnav(od, conn);
-	else if (conn->type == SNAC_FAMILY_ALERT)
-		flap_connection_established_alert(od, conn);
-	else if (conn->type == SNAC_FAMILY_BART)
-		flap_connection_established_bart(od, conn);
-
-	return 1;
-}
-
-static void
-idle_reporting_pref_cb(const char *name, PurplePrefType type,
-		gconstpointer value, gpointer data)
-{
-	PurpleConnection *gc;
-	OscarData *od;
-	gboolean report_idle;
-	guint32 presence;
-
-	gc = data;
-	od = purple_connection_get_protocol_data(gc);
-	report_idle = !purple_strequal((const char *)value, "none");
-	presence = aim_ssi_getpresence(&od->ssi.local);
-
-	if (report_idle)
-		aim_ssi_setpresence(od, presence | AIM_SSI_PRESENCE_FLAG_SHOWIDLE);
-	else
-		aim_ssi_setpresence(od, presence & ~AIM_SSI_PRESENCE_FLAG_SHOWIDLE);
-}
-
-/**
- * Should probably make a "Use recent buddies group" account preference
- * so that this option is surfaced to the user.
- */
-static void
-recent_buddies_pref_cb(const char *name, PurplePrefType type,
-		gconstpointer value, gpointer data)
-{
-	PurpleConnection *gc;
-	OscarData *od;
-	guint32 presence;
-
-	gc = data;
-	od = purple_connection_get_protocol_data(gc);
-	presence = aim_ssi_getpresence(&od->ssi.local);
-
-	if (value)
-		aim_ssi_setpresence(od, presence & ~AIM_SSI_PRESENCE_FLAG_NORECENTBUDDIES);
-	else
-		aim_ssi_setpresence(od, presence | AIM_SSI_PRESENCE_FLAG_NORECENTBUDDIES);
-}
-
-static const gchar *login_servers[] = {
-	AIM_DEFAULT_LOGIN_SERVER,
-	AIM_DEFAULT_SSL_LOGIN_SERVER,
-	ICQ_DEFAULT_LOGIN_SERVER,
-	ICQ_DEFAULT_SSL_LOGIN_SERVER,
-};
-
-const gchar *
-oscar_get_login_server(gboolean is_icq, gboolean use_ssl)
-{
-	return login_servers[(is_icq ? 2 : 0) + (use_ssl ? 1 : 0)];
-}
-
-static gint
-compare_handlers(gconstpointer a, gconstpointer b)
-{
-	guint aa = GPOINTER_TO_UINT(a);
-	guint bb = GPOINTER_TO_UINT(b);
-	guint family1 = aa >> 16;
-	guint family2 = bb >> 16;
-	guint subtype1 = aa & 0xFFFF;
-	guint subtype2 = bb & 0xFFFF;
-	if (family1 != family2) {
-		return family1 - family2;
-	}
-	return subtype1 - subtype2;
-}
-
-void
-oscar_login(PurpleAccount *account)
-{
-	PurpleConnection *gc;
-	OscarData *od;
-	const gchar *encryption_type;
-	const gchar *login_type;
-	GList *handlers;
-	GList *sorted_handlers;
-	GList *cur;
-	GString *msg = g_string_new("");
-	PurpleConnectionFlags flags;
-
-	gc = purple_account_get_connection(account);
-	od = oscar_data_new();
-	od->gc = gc;
-	purple_connection_set_protocol_data(gc, od);
-
-	oscar_data_addhandler(od, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, purple_connerr, 0);
-	oscar_data_addhandler(od, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, flap_connection_established, 0);
-
-	oscar_data_addhandler(od, SNAC_FAMILY_ADMIN, 0x0003, purple_info_change, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_ADMIN, 0x0005, purple_info_change, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_ADMIN, 0x0007, purple_account_confirm, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_ALERT, 0x0001, purple_parse_genericerr, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_ALERT, SNAC_SUBTYPE_ALERT_MAILSTATUS, purple_email_parseupdate, 0);
-
-	/* These are only needed when connecting with the old-style BUCP login */
-	oscar_data_addhandler(od, SNAC_FAMILY_AUTH, 0x0003, purple_parse_auth_resp, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_REQUEST, purple_parse_auth_securid_request, 0);
-
-	oscar_data_addhandler(od, SNAC_FAMILY_BART, SNAC_SUBTYPE_BART_RESPONSE, purple_icon_parseicon, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_BOS, 0x0001, purple_parse_genericerr, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_BOS, 0x0003, purple_bosrights, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_BUDDY, 0x0001, purple_parse_genericerr, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_BUDDY, SNAC_SUBTYPE_BUDDY_RIGHTSINFO, purple_parse_buddyrights, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_BUDDY, SNAC_SUBTYPE_BUDDY_ONCOMING, purple_parse_oncoming, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_BUDDY, SNAC_SUBTYPE_BUDDY_OFFGOING, purple_parse_offgoing, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_CHAT, 0x0001, purple_parse_genericerr, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_CHAT, SNAC_SUBTYPE_CHAT_USERJOIN, purple_chat_conversation_join, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_CHAT, SNAC_SUBTYPE_CHAT_USERLEAVE, purple_chat_conversation_left, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_CHAT, SNAC_SUBTYPE_CHAT_ROOMINFOUPDATE, purple_chat_conversation_info_update, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_CHAT, SNAC_SUBTYPE_CHAT_INCOMINGMSG, purple_chat_conversation_incoming_msg, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_CHATNAV, 0x0001, purple_parse_genericerr, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_CHATNAV, SNAC_SUBTYPE_CHATNAV_INFO, purple_chatnav_info, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_ERROR, purple_ssi_parseerr, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_RIGHTSINFO, purple_ssi_parserights, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_LIST, purple_ssi_parselist, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SRVACK, purple_ssi_parseack, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_ADD, purple_ssi_parseaddmod, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_MOD, purple_ssi_parseaddmod, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_RECVAUTH, purple_ssi_authgiven, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_RECVAUTHREQ, purple_ssi_authrequest, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_RECVAUTHREP, purple_ssi_authreply, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_ADDED, purple_ssi_gotadded, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_INCOMING, purple_parse_incoming_im, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_MISSEDCALL, purple_parse_misses, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_CLIENTAUTORESP, purple_parse_clientauto, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_MTN, purple_parse_mtn, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_LOCATE, SNAC_SUBTYPE_LOCATE_RIGHTSINFO, purple_parse_locaterights, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, 0x0001, purple_parse_genericerr, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, 0x000f, purple_selfinfo, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, SNAC_SUBTYPE_OSERVICE_REDIRECT, purple_handle_redirect, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, SNAC_SUBTYPE_OSERVICE_MOTD, purple_parse_motd, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_POPUP, 0x0002, purple_popup, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_USERLOOKUP, SNAC_SUBTYPE_USERLOOKUP_ERROR, purple_parse_searcherror, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_USERLOOKUP, 0x0003, purple_parse_searchreply, 0);
-
-	g_string_append(msg, "Registered handlers: ");
-	handlers = g_hash_table_get_keys(od->handlerlist);
-	sorted_handlers = g_list_sort(g_list_copy(handlers), compare_handlers);
-	for (cur = sorted_handlers; cur; cur = cur->next) {
-		guint x = GPOINTER_TO_UINT(cur->data);
-		g_string_append_printf(msg, "%04x/%04x, ", x >> 16, x & 0xFFFF);
-	}
-	g_list_free(sorted_handlers);
-	g_list_free(handlers);
-	purple_debug_misc("oscar", "%s\n", msg->str);
-	g_string_free(msg, TRUE);
-
-	purple_debug_misc("oscar", "oscar_login: gc = %p\n", gc);
-
-	if (!oscar_util_valid_name(purple_account_get_username(account))) {
-		gchar *buf;
-		buf = g_strdup_printf(_("Unable to sign on as %s because the username is invalid.  Usernames must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers."), purple_account_get_username(account));
-		purple_connection_error(gc, PURPLE_CONNECTION_ERROR_INVALID_SETTINGS, buf);
-		g_free(buf);
-		return;
-	}
-
-	flags = PURPLE_CONNECTION_FLAG_HTML;
-	if (purple_strequal(purple_account_get_protocol_id(account), "prpl-icq")) {
-		od->icq = TRUE;
-	} else {
-		flags |= PURPLE_CONNECTION_FLAG_AUTO_RESP;
-	}
-
-	/* Set this flag based on the protocol_id rather than the username,
-	   because that is what's tied to the get_moods protocol callback. */
-	if (purple_strequal(purple_account_get_protocol_id(account), "prpl-icq"))
-		flags |= PURPLE_CONNECTION_FLAG_SUPPORT_MOODS;
-
-	purple_connection_set_flags(gc, flags);
-
-	od->default_port = purple_account_get_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT);
-
-	login_type = purple_account_get_string(account, "login_type", OSCAR_DEFAULT_LOGIN);
-	encryption_type = purple_account_get_string(account, "encryption", OSCAR_DEFAULT_ENCRYPTION);
-	od->use_ssl = purple_strequal(encryption_type, OSCAR_NO_ENCRYPTION) == FALSE;
-
-	/* Connect to core Purple signals */
-	purple_prefs_connect_callback(purple_connection_get_protocol(gc), "/purple/away/idle_reporting", idle_reporting_pref_cb, gc);
-	purple_prefs_connect_callback(purple_connection_get_protocol(gc), "/plugins/prpl/oscar/recent_buddies", recent_buddies_pref_cb, gc);
-
-	if (purple_strequal(login_type, OSCAR_CLIENT_LOGIN) ||
-	    purple_strequal(login_type, OSCAR_KERBEROS_LOGIN)) {
-		/* Create a SoupSession to be used for HTTP login requests. */
-		GProxyResolver *resolver;
-		GError *error;
-
-		resolver = purple_proxy_get_proxy_resolver(account, &error);
-		if (resolver == NULL) {
-			purple_debug_error("oscar",
-			                   "Unable to get account proxy resolver: %s",
-			                   error->message);
-			purple_connection_g_error(gc, error);
-			return;
-		}
-
-		od->http_conns = soup_session_new_with_options(
-		        SOUP_SESSION_PROXY_RESOLVER, resolver, NULL);
-		g_object_unref(resolver);
-	}
-
-	/*
-	 * On 2008-03-05 AOL released some documentation on the OSCAR protocol
-	 * which includes a new login method called clientLogin.  It is similar
-	 * (though not the same?) as what the AIM 6.0 series uses to
-	 * authenticate.
-	 *
-	 * AIM 5.9 and lower use an MD5-based login procedure called "BUCP".
-	 * This authentication method is used for both ICQ and AIM when
-	 * clientLogin is not enabled.
-	 */
-	if (purple_strequal(login_type, OSCAR_CLIENT_LOGIN)) {
-		/* Note: Actual server/port configuration is ignored here */
-		send_client_login(od, purple_account_get_username(account));
-	} else if (purple_strequal(login_type, OSCAR_KERBEROS_LOGIN)) {
-		const char *server;
-
-		if (!od->use_ssl) {
-			purple_connection_error(
-				gc,
-				PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT,
-				_("You required Kerberos authentication but encryption is disabled in your account settings."));
-			return;
-		}
-		server = purple_account_get_string(account, "server", AIM_DEFAULT_KDC_SERVER);
-		/*
-		 * If the account's server is what the oscar protocol has offered as
-		 * the default login server through the vast eons (all two of
-		 * said default options, AFAIK) and the user wants KDC, we'll
-		 * do what we know is best for them and change the setting out
-		 * from under them to the KDC login server.
-		 */
-		if (purple_strequal(server, oscar_get_login_server(od->icq, FALSE)) ||
-			purple_strequal(server, oscar_get_login_server(od->icq, TRUE)) ||
-			purple_strequal(server, AIM_ALT_LOGIN_SERVER) ||
-			purple_strequal(server, "")) {
-			purple_debug_info("oscar", "Account uses Kerberos auth, so changing server to default KDC server\n");
-			purple_account_set_string(account, "server", AIM_DEFAULT_KDC_SERVER);
-			purple_account_set_int(account, "port", AIM_DEFAULT_KDC_PORT);
-		}
-		send_kerberos_login(od, purple_account_get_username(account));
-	} else {
-		FlapConnection *newconn;
-		const char *server;
-
-		newconn = flap_connection_new(od, SNAC_FAMILY_AUTH);
-
-		if (od->use_ssl) {
-			server = purple_account_get_string(account, "server", oscar_get_login_server(od->icq, TRUE));
-
-			/*
-			 * If the account's server is what the oscar protocol has offered as
-			 * the default login server through the vast eons (all two of
-			 * said default options, AFAIK) and the user wants SSL, we'll
-			 * do what we know is best for them and change the setting out
-			 * from under them to the SSL login server.
-			 */
-			if (purple_strequal(server, oscar_get_login_server(od->icq, FALSE)) ||
-				purple_strequal(server, AIM_ALT_LOGIN_SERVER) ||
-				purple_strequal(server, AIM_DEFAULT_KDC_SERVER) ||
-				purple_strequal(server, "")) {
-				purple_debug_info("oscar", "Account uses SSL, so changing server to default SSL server\n");
-				purple_account_set_string(account, "server", oscar_get_login_server(od->icq, TRUE));
-				purple_account_set_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT),
-				server = oscar_get_login_server(od->icq, TRUE);
-			}
-
-			newconn->gsc = purple_ssl_connect(account, server,
-					purple_account_get_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT),
-					ssl_connection_established_cb, ssl_connection_error_cb, newconn);
-		} else {
-			server = purple_account_get_string(account, "server", oscar_get_login_server(od->icq, FALSE));
-
-			/*
-			 * See the comment above. We do the reverse here. If they don't want
-			 * SSL but their server is set to OSCAR_DEFAULT_SSL_LOGIN_SERVER,
-			 * set it back to the default.
-			 */
-			if (purple_strequal(server, oscar_get_login_server(od->icq, TRUE)) ||
-				purple_strequal(server, AIM_DEFAULT_KDC_SERVER) ||
-				purple_strequal(server, "")) {
-				purple_debug_info("oscar", "Account does not use SSL, so changing server back to non-SSL\n");
-				purple_account_set_string(account, "server", oscar_get_login_server(od->icq, FALSE));
-				purple_account_set_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT),
-				server = oscar_get_login_server(od->icq, FALSE);
-			}
-
-			newconn->connect_data = purple_proxy_connect(NULL, account, server,
-					purple_account_get_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT),
-					connection_established_cb, newconn);
-		}
-
-		if (newconn->gsc == NULL && newconn->connect_data == NULL) {
-			purple_connection_error(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-					_("Unable to connect"));
-			return;
-		}
-	}
-
-	purple_connection_update_progress(gc, _("Connecting"), 0, OSCAR_CONNECT_STEPS);
-}
-
-void
-oscar_close(PurpleConnection *gc)
-{
-	OscarData *od;
-
-	od = purple_connection_get_protocol_data(gc);
-
-	g_slist_free_full(od->oscar_chats, (GDestroyNotify)oscar_chat_destroy);
-	while (od->create_rooms)
-	{
-		struct create_room *cr = od->create_rooms->data;
-		g_free(cr->name);
-		od->create_rooms = g_slist_remove(od->create_rooms, cr);
-		g_free(cr);
-	}
-	oscar_data_destroy(od);
-	purple_connection_set_protocol_data(gc, NULL);
-
-	purple_prefs_disconnect_by_handle(gc);
-
-	purple_debug_info("oscar", "Signed off.\n");
-}
-
-int oscar_connect_to_bos(PurpleConnection *gc, OscarData *od, const char *host, guint16 port, guint8 *cookie, guint16 cookielen, const char *tls_certname)
-{
-	PurpleAccount *account;
-	FlapConnection *conn;
-
-	account = purple_connection_get_account(gc);
-
-	conn = flap_connection_new(od, SNAC_FAMILY_LOCATE);
-	conn->cookielen = cookielen;
-	conn->cookie = g_memdup(cookie, cookielen);
-
-	/*
-	 * Use TLS only if the server provided us with a tls_certname. The server might not specify a tls_certname even if we requested to use TLS,
-	 * and that is something we should be prepared to.
-	 */
-	if (tls_certname)
-	{
-		conn->gsc = purple_ssl_connect_with_ssl_cn(account, host, port,
-				ssl_connection_established_cb, ssl_connection_error_cb,
-				tls_certname, conn);
-	}
-	else
-	{
-		conn->connect_data = purple_proxy_connect(NULL,
-				account, host, port,
-				connection_established_cb, conn);
-	}
-
-	if (conn->gsc == NULL && conn->connect_data == NULL)
-	{
-		purple_connection_error(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to connect"));
-		return 0;
-	}
-
-	od->default_port = port;
-
-	purple_connection_update_progress(gc, _("Received authorization"), 3, OSCAR_CONNECT_STEPS);
-
-	return 1;
-}
-
-/**
- * Only used when connecting with the old-style BUCP login.
- */
-static int
-purple_parse_auth_resp(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
-{
-	PurpleConnection *gc = od->gc;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	char *host; int port;
-	gsize i;
-	FlapConnection *newconn;
-	va_list ap;
-	struct aim_authresp_info *info;
-
-	port = purple_account_get_int(account, "port", od->default_port);
-
-	va_start(ap, fr);
-	info = va_arg(ap, struct aim_authresp_info *);
-	va_end(ap);
-
-	purple_debug_info("oscar",
-			   "inside auth_resp (Username: %s)\n", info->bn);
-
-	if (info->errorcode || !info->bosip || !info->cookielen || !info->cookie) {
-		char buf[256];
-		switch (info->errorcode) {
-		case 0x01:
-			/* Unregistered username */
-			purple_connection_error(gc, PURPLE_CONNECTION_ERROR_INVALID_USERNAME, _("Username does not exist"));
-			break;
-		case 0x05:
-			/* Incorrect password */
-			if (!purple_account_get_remember_password(account))
-				purple_account_set_password(account, NULL, NULL, NULL);
-			purple_connection_error(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("Incorrect password"));
-			break;
-		case 0x11:
-			/* Suspended account */
-			purple_connection_error(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("Your account is currently suspended"));
-			break;
-		case 0x02:
-		case 0x14:
-			/* service temporarily unavailable */
-			purple_connection_error(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("The AOL Instant Messenger service is temporarily unavailable."));
-			break;
-		case 0x18:
-			/* username connecting too frequently */
-			purple_connection_error(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("Your username has been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer."));
-			break;
-		case 0x1c:
-		{
-			/* client too old */
-			g_snprintf(buf, sizeof(buf), _("The client version you are using is too old. Please upgrade at %s"),
-					oscar_get_ui_info_string("website", PURPLE_WEBSITE));
-			purple_connection_error(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, buf);
-			break;
-		}
-		case 0x1d:
-			/* IP address connecting too frequently */
-			purple_connection_error(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("Your IP address has been connecting and disconnecting too frequently. Wait a minute and try again. If you continue to try, you will need to wait even longer."));
-			break;
-		default:
-			purple_connection_error(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("Unknown reason"));
-			break;
-		}
-		purple_debug_info("oscar", "Login Error Code 0x%04hx\n", info->errorcode);
-		purple_debug_info("oscar", "Error URL: %s\n", info->errorurl ? info->errorurl : "");
-		return 1;
-	}
-
-	purple_debug_misc("oscar",
-	                  "Reg status: %hu\n"
-	                  "Email: %s\n"
-	                  "BOSIP: %s\n",
-	                  info->regstatus, info->email ? info->email : "null",
-	                  info->bosip);
-	purple_debug_info("oscar", "Closing auth connection...\n");
-	flap_connection_schedule_destroy(conn, OSCAR_DISCONNECT_DONE, NULL);
-
-	for (i = 0; i < strlen(info->bosip); i++) {
-		if (info->bosip[i] == ':') {
-			port = atoi(&(info->bosip[i+1]));
-			break;
-		}
-	}
-	host = g_strndup(info->bosip, i);
-	newconn = flap_connection_new(od, SNAC_FAMILY_LOCATE);
-	newconn->cookielen = info->cookielen;
-	newconn->cookie = g_memdup(info->cookie, info->cookielen);
-
-	if (od->use_ssl)
-	{
-		/*
-		 * This shouldn't be hardcoded to "bos.oscar.aol.com" except that
-		 * the server isn't sending us a name to use for comparing the
-		 * certificate common name.
-		 */
-		newconn->gsc = purple_ssl_connect_with_ssl_cn(account, host, port,
-				ssl_connection_established_cb, ssl_connection_error_cb,
-				"bos.oscar.aol.com", newconn);
-	}
-	else
-	{
-		newconn->connect_data = purple_proxy_connect(NULL, account, host, port,
-				connection_established_cb, newconn);
-	}
-
-	g_free(host);
-	if (newconn->gsc == NULL && newconn->connect_data == NULL)
-	{
-		purple_connection_error(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to connect"));
-		return 0;
-	}
-
-	purple_connection_update_progress(gc, _("Received authorization"), 3, OSCAR_CONNECT_STEPS);
-
-	return 1;
-}
-
-/**
- * Only used when connecting with the old-style BUCP login.
- */
-static void
-purple_parse_auth_securid_request_yes_cb(gpointer user_data, const char *msg)
-{
-	PurpleConnection *gc = user_data;
-	OscarData *od = purple_connection_get_protocol_data(gc);
-
-	aim_auth_securid_send(od, msg);
-}
-
-/**
- * Only used when connecting with the old-style BUCP login.
- */
-static void
-purple_parse_auth_securid_request_no_cb(gpointer user_data, const char *value)
-{
-	PurpleConnection *gc = user_data;
-
-	/* Disconnect */
-	purple_connection_error(gc,
-		PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
-		_("The SecurID key entered is invalid"));
-}
-
-/**
- * Only used when connecting with the old-style BUCP login.
- */
-static int
-purple_parse_auth_securid_request(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
-{
-	PurpleConnection *gc = od->gc;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	gchar *primary;
-
-	purple_debug_info("oscar", "Got SecurID request\n");
-
-	primary = g_strdup_printf("Enter the SecurID key for %s.", purple_account_get_username(account));
-	purple_request_input(gc, NULL, _("Enter SecurID"), primary,
-					   _("Enter the 6 digit number from the digital display."),
-					   FALSE, FALSE, NULL,
-					   _("_OK"), G_CALLBACK(purple_parse_auth_securid_request_yes_cb),
-					   _("_Cancel"), G_CALLBACK(purple_parse_auth_securid_request_no_cb),
-					   purple_request_cpar_from_connection(gc),
-					   gc);
-	g_free(primary);
-
-	return 1;
-}
-
-static int
-purple_handle_redirect(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
-{
-	PurpleConnection *gc = od->gc;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	char *host, *separator;
-	int port;
-	FlapConnection *newconn;
-	va_list ap;
-	struct aim_redirect_data *redir;
-
-	va_start(ap, fr);
-	redir = va_arg(ap, struct aim_redirect_data *);
-	va_end(ap);
-
-	port = od->default_port;
-	separator = strchr(redir->ip, ':');
-	if (separator != NULL)
-	{
-		host = g_strndup(redir->ip, separator - redir->ip);
-		port = atoi(separator + 1);
-	}
-	else
-		host = g_strdup(redir->ip);
-
-	if (!redir->use_ssl) {
-		const gchar *encryption_type = purple_account_get_string(account, "encryption", OSCAR_DEFAULT_ENCRYPTION);
-		if (purple_strequal(encryption_type, OSCAR_OPPORTUNISTIC_ENCRYPTION)) {
-			purple_debug_warning("oscar", "We won't use SSL for FLAP type 0x%04hx.\n", redir->group);
-		} else if (purple_strequal(encryption_type, OSCAR_REQUIRE_ENCRYPTION)) {
-			purple_debug_error("oscar", "FLAP server %s:%d of type 0x%04hx doesn't support encryption.\n", host, port, redir->group);
-			purple_connection_error(
-				gc,
-				PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT,
-				_("You required encryption in your account settings, but one of the servers doesn't support it."));
-			return 0;
-		}
-	}
-
-	/*
-	 * These FLAP servers advertise SSL (type "0x02"), but SSL connections to these hosts
-	 * die a painful death. iChat and Miranda, when using SSL, still do these in plaintext.
-	 */
-	if (redir->use_ssl && (redir->group == SNAC_FAMILY_ADMIN ||
-	                       redir->group == SNAC_FAMILY_BART))
-	{
-		purple_debug_info("oscar", "Ignoring broken SSL for FLAP type 0x%04hx.\n", redir->group);
-		redir->use_ssl = 0;
-	}
-
-	purple_debug_info("oscar", "Connecting to FLAP server %s:%d of type 0x%04hx\n", host, port, redir->group);
-
-	newconn = flap_connection_new(od, redir->group);
-	newconn->cookielen = redir->cookielen;
-	newconn->cookie = g_memdup(redir->cookie, redir->cookielen);
-	if (newconn->type == SNAC_FAMILY_CHAT)
-	{
-		struct chat_connection *cc;
-		cc = g_new0(struct chat_connection, 1);
-		cc->conn = newconn;
-		cc->gc = gc;
-		cc->name = g_strdup(redir->chat.room);
-		cc->exchange = redir->chat.exchange;
-		cc->instance = redir->chat.instance;
-		cc->show = extract_name(redir->chat.room);
-		newconn->new_conn_data = cc;
-		purple_debug_info("oscar", "Connecting to chat room %s exchange %hu\n", cc->name, cc->exchange);
-	}
-
-
-	if (redir->use_ssl)
-	{
-		newconn->gsc = purple_ssl_connect_with_ssl_cn(account, host, port,
-				ssl_connection_established_cb, ssl_connection_error_cb,
-				redir->ssl_cert_cn, newconn);
-	}
-	else
-	{
-		newconn->connect_data = purple_proxy_connect(NULL, account, host, port,
-				connection_established_cb, newconn);
-	}
-
-	if (newconn->gsc == NULL && newconn->connect_data == NULL)
-	{
-		flap_connection_schedule_destroy(newconn,
-				OSCAR_DISCONNECT_COULD_NOT_CONNECT,
-				_("Unable to initialize connection"));
-		purple_debug_error("oscar", "Unable to connect to FLAP server "
-				"of type 0x%04hx\n", redir->group);
-	}
-	g_free(host);
-
-	return 1;
-}
-
-
-static int purple_parse_oncoming(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
-{
-	PurpleConnection *gc;
-	PurpleAccount *account;
-	PurpleBuddy *buddy = NULL;
-	PurpleStatus *previous_status = NULL;
-	struct buddyinfo *bi;
-	time_t time_idle = 0, signon = 0;
-	int type = 0;
-	gboolean buddy_is_away = FALSE;
-	const char *status_id;
-	va_list ap;
-	aim_userinfo_t *info;
-	char *message;
-	char *itmsurl = NULL;
-
-	gc = od->gc;
-	account = purple_connection_get_account(gc);
-
-	va_start(ap, fr);
-	info = va_arg(ap, aim_userinfo_t *);
-	va_end(ap);
-
-	g_return_val_if_fail(info != NULL, 1);
-	g_return_val_if_fail(info->bn != NULL, 1);
-
-	buddy = purple_blist_find_buddy(account, info->bn);
-	if (buddy) {
-		previous_status = purple_presence_get_active_status(purple_buddy_get_presence(buddy));
-	}
-
-	/*
-	 * If this is an AIM buddy and their name has formatting, set their
-	 * server alias.
-	 */
-	if (!oscar_util_valid_name_icq(info->bn)) {
-		gboolean bn_has_formatting = FALSE;
-		char *c;
-		for (c = info->bn; *c != '\0'; c++) {
-			if (!islower(*c)) {
-				bn_has_formatting = TRUE;
-				break;
-			}
-		}
-		purple_serv_got_alias(gc, info->bn,
-				bn_has_formatting ? info->bn : NULL);
-	}
-
-	if (info->present & AIM_USERINFO_PRESENT_FLAGS) {
-		if (info->flags & AIM_FLAG_AWAY)
-			buddy_is_away = TRUE;
-	}
-	if (info->present & AIM_USERINFO_PRESENT_ICQEXTSTATUS) {
-		type = info->icqinfo.status;
-		if (!(info->icqinfo.status & AIM_ICQ_STATE_CHAT) &&
-		      (info->icqinfo.status != AIM_ICQ_STATE_NORMAL)) {
-			buddy_is_away = TRUE;
-		}
-	}
-
-	if (oscar_util_valid_name_icq(info->bn)) {
-		if (type & AIM_ICQ_STATE_CHAT)
-			status_id = OSCAR_STATUS_ID_FREE4CHAT;
-		else if (type & AIM_ICQ_STATE_DND)
-			status_id = OSCAR_STATUS_ID_DND;
-		else if (type & AIM_ICQ_STATE_OUT)
-			status_id = OSCAR_STATUS_ID_NA;
-		else if (type & AIM_ICQ_STATE_BUSY)
-			status_id = OSCAR_STATUS_ID_OCCUPIED;
-		else if (type & AIM_ICQ_STATE_AWAY)
-			status_id = OSCAR_STATUS_ID_AWAY;
-		else if (type & AIM_ICQ_STATE_INVISIBLE)
-			status_id = OSCAR_STATUS_ID_INVISIBLE;
-		else if (type & AIM_ICQ_STATE_EVIL)
-			status_id = OSCAR_STATUS_ID_EVIL;
-		else if (type & AIM_ICQ_STATE_DEPRESSION)
-			status_id = OSCAR_STATUS_ID_DEPRESSION;
-		else if (type & AIM_ICQ_STATE_ATHOME)
-			status_id = OSCAR_STATUS_ID_ATHOME;
-		else if (type & AIM_ICQ_STATE_ATWORK)
-			status_id = OSCAR_STATUS_ID_ATWORK;
-		else if (type & AIM_ICQ_STATE_LUNCH)
-			status_id = OSCAR_STATUS_ID_LUNCH;
-		else
-			status_id = OSCAR_STATUS_ID_AVAILABLE;
-	} else {
-		if (type & AIM_ICQ_STATE_INVISIBLE)
-			status_id = OSCAR_STATUS_ID_INVISIBLE;
-		else if (buddy_is_away)
-			status_id = OSCAR_STATUS_ID_AWAY;
-		else
-			status_id = OSCAR_STATUS_ID_AVAILABLE;
-	}
-
-	if (info->flags & AIM_FLAG_WIRELESS) {
-		purple_protocol_got_user_status(account, info->bn, OSCAR_STATUS_ID_MOBILE, NULL);
-	} else {
-		purple_protocol_got_user_status_deactive(account, info->bn, OSCAR_STATUS_ID_MOBILE);
-	}
-
-	message = (info->status && info->status_len > 0)
-			? oscar_encoding_to_utf8(info->status_encoding, info->status, info->status_len)
-			: NULL;
-
-	if (purple_strequal(status_id, OSCAR_STATUS_ID_AVAILABLE)) {
-		/* TODO: If itmsurl is NULL, does that mean the URL has been
-		   cleared?  Or does it mean the URL should remain unchanged? */
-		if (info->itmsurl != NULL) {
-			itmsurl = (info->itmsurl_len > 0) ? oscar_encoding_to_utf8(info->itmsurl_encoding, info->itmsurl, info->itmsurl_len) : NULL;
-		} else if (previous_status != NULL && purple_status_is_available(previous_status)) {
-			itmsurl = g_strdup(purple_status_get_attr_string(previous_status, "itmsurl"));
-		}
-		purple_debug_info("oscar", "Activating status '%s' for buddy %s, message = '%s', itmsurl = '%s'\n", status_id, info->bn, message ? message : "(null)", itmsurl ? itmsurl : "(null)");
-		purple_protocol_got_user_status(account, info->bn, status_id, "message", message, "itmsurl", itmsurl, NULL);
-	} else {
-		purple_debug_info("oscar", "Activating status '%s' for buddy %s, message = '%s'\n", status_id, info->bn, message ? message : "(null)");
-		purple_protocol_got_user_status(account, info->bn, status_id, "message", message, NULL);
-	}
-
-	g_free(message);
-	g_free(itmsurl);
-
-	/* Login time stuff */
-	if (info->present & AIM_USERINFO_PRESENT_ONLINESINCE)
-		signon = info->onlinesince;
-	else if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN)
-		signon = time(NULL) - info->sessionlen;
-	purple_protocol_got_user_login_time(account, info->bn, signon);
-
-	/* Idle time stuff */
-	/* info->idletime is the number of minutes that this user has been idle */
-	if (info->present & AIM_USERINFO_PRESENT_IDLE)
-		time_idle = time(NULL) - info->idletime * 60;
-
-	if (time_idle > 0)
-		purple_protocol_got_user_idle(account, info->bn, TRUE, time_idle);
-	else
-		purple_protocol_got_user_idle(account, info->bn, FALSE, 0);
-
-	/* Server stored icon stuff */
-	bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, info->bn));
-	if (!bi) {
-		bi = g_new0(struct buddyinfo, 1);
-		g_hash_table_insert(od->buddyinfo, g_strdup(purple_normalize(account, info->bn)), bi);
-	}
-	bi->typingnot = FALSE;
-	bi->ico_informed = FALSE;
-	bi->ipaddr = info->icqinfo.ipaddr;
-
-	if (info->iconcsumlen) {
-		const char *saved_b16 = NULL;
-		char *b16 = NULL;
-		PurpleBuddy *b = NULL;
-
-		b16 = purple_base16_encode(info->iconcsum, info->iconcsumlen);
-		b = purple_blist_find_buddy(account, info->bn);
-		if (b != NULL)
-			saved_b16 = purple_buddy_icons_get_checksum_for_user(b);
-
-		if (!b16 || !saved_b16 || !purple_strequal(b16, saved_b16)) {
-			/* Invalidate the old icon for this user */
-			purple_buddy_icons_set_for_user(account, info->bn, NULL, 0, NULL);
-
-			/* Fetch the new icon (if we're not already doing so) */
-			if (g_slist_find_custom(od->requesticon, info->bn,
-					(GCompareFunc)oscar_util_name_compare) == NULL)
-			{
-				od->requesticon = g_slist_prepend(od->requesticon,
-						g_strdup(purple_normalize(account, info->bn)));
-				purple_icons_fetch(gc);
-			}
-		}
-		g_free(b16);
-	}
-
-	return 1;
-}
-
-static int purple_parse_offgoing(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	PurpleConnection *gc = od->gc;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	va_list ap;
-	aim_userinfo_t *info;
-
-	va_start(ap, fr);
-	info = va_arg(ap, aim_userinfo_t *);
-	va_end(ap);
-
-	purple_protocol_got_user_status(account, info->bn, OSCAR_STATUS_ID_OFFLINE, NULL);
-	purple_protocol_got_user_status_deactive(account, info->bn, OSCAR_STATUS_ID_MOBILE);
-	g_hash_table_remove(od->buddyinfo, purple_normalize(purple_connection_get_account(gc), info->bn));
-
-	return 1;
-}
-
-static int incomingim_chan1(OscarData *od, FlapConnection *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch1_args *args) {
-	PurpleConnection *gc = od->gc;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	PurpleMessageFlags flags = 0;
-	struct buddyinfo *bi;
-	PurpleImage *img;
-	gchar *tmp;
-	const char *start, *end;
-	GData *attribs;
-
-	purple_debug_misc("oscar", "Received IM from %s\n", userinfo->bn);
-
-	bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, userinfo->bn));
-	if (!bi) {
-		bi = g_new0(struct buddyinfo, 1);
-		g_hash_table_insert(od->buddyinfo, g_strdup(purple_normalize(account, userinfo->bn)), bi);
-	}
-
-	if (args->icbmflags & AIM_IMFLAGS_AWAY)
-		flags |= PURPLE_MESSAGE_AUTO_RESP;
-
-	if (args->icbmflags & AIM_IMFLAGS_TYPINGNOT)
-		bi->typingnot = TRUE;
-	else
-		bi->typingnot = FALSE;
-
-	if ((args->icbmflags & AIM_IMFLAGS_HASICON) && (args->iconlen) && (args->iconsum) && (args->iconstamp)) {
-		purple_debug_misc("oscar", "%s has an icon\n", userinfo->bn);
-		if ((args->iconlen != bi->ico_len) || (args->iconsum != bi->ico_csum) || (args->iconstamp != bi->ico_time)) {
-			bi->ico_need = TRUE;
-			bi->ico_len = args->iconlen;
-			bi->ico_csum = args->iconsum;
-			bi->ico_time = args->iconstamp;
-		}
-	}
-
-	img = purple_buddy_icons_find_account_icon(account);
-	if ((img != NULL) &&
-	    (args->icbmflags & AIM_IMFLAGS_BUDDYREQ) && !bi->ico_sent && bi->ico_informed) {
-		gconstpointer data = purple_image_get_data(img);
-		size_t len = purple_image_get_data_size(img);
-		purple_debug_info("oscar",
-				"Sending buddy icon to %s (%" G_GSIZE_FORMAT " bytes)\n",
-				userinfo->bn, len);
-		aim_im_sendch2_icon(od, userinfo->bn, data, len,
-			purple_buddy_icons_get_account_icon_timestamp(account),
-			aimutil_iconsum(data, len));
-	}
-	g_object_unref(img);
-
-	tmp = g_strdup(args->msg);
-
-	/*
-	 * Convert iChat color tags to normal font tags.
-	 */
-	if (purple_markup_find_tag("body", tmp, &start, &end, &attribs))
-	{
-		int len;
-		char *tmp2, *body;
-		const char *ichattextcolor, *ichatballooncolor;
-		const char *slash_body_start, *slash_body_end = NULL; /* </body> */
-		GData *unused;
-
-		/*
-		 * Find the ending </body> so we can strip off the outer <html/>
-		 * and <body/>
-		 */
-		if (purple_markup_find_tag("/body", end + 1, &slash_body_start, &slash_body_end, &unused))
-		{
-			body = g_strndup(start, slash_body_end - start + 1);
-			g_datalist_clear(&unused);
-		}
-		else
-		{
-			purple_debug_warning("oscar", "Broken message contains <body> but not </body>!\n");
-			/* Take everything after <body> */
-			body = g_strdup(start);
-		}
-
-		ichattextcolor = g_datalist_get_data(&attribs, "ichattextcolor");
-		if (ichattextcolor != NULL)
-		{
-			tmp2 = g_strdup_printf("<font color=\"%s\">%s</font>", ichattextcolor, body);
-			g_free(body);
-			body = tmp2;
-		}
-
-		ichatballooncolor = g_datalist_get_data(&attribs, "ichatballooncolor");
-		if (ichatballooncolor != NULL)
-		{
-			tmp2 = g_strdup_printf("<font back=\"%s\">%s</font>", ichatballooncolor, body);
-			g_free(body);
-			body = tmp2;
-		}
-
-		g_datalist_clear(&attribs);
-
-		len = start - tmp;
-		tmp2 = g_strdup_printf("%.*s%s%s", len, tmp, body, slash_body_end ? slash_body_end + 1: "</body>");
-		g_free(tmp);
-		g_free(body);
-
-		tmp = tmp2;
-	}
-
-	/*
-	 * Are there <html/> surrounding tags? If so, strip them out, too.
-	 */
-	if (purple_markup_find_tag("html", tmp, &start, &end, &attribs))
-	{
-		gchar *tmp2;
-		int len;
-
-		g_datalist_clear(&attribs);
-
-		len = start - tmp;
-		tmp2 = g_strdup_printf("%.*s%s", len, tmp, end + 1);
-		g_free(tmp);
-		tmp = tmp2;
-	}
-
-	if (purple_markup_find_tag("/html", tmp, &start, &end, &attribs))
-	{
-		gchar *tmp2;
-		int len;
-
-		g_datalist_clear(&attribs);
-
-		len = start - tmp;
-		tmp2 = g_strdup_printf("%.*s%s", len, tmp, end + 1);
-		g_free(tmp);
-		tmp = tmp2;
-	}
-
-	purple_serv_got_im(gc, userinfo->bn, tmp, flags, (args->icbmflags & AIM_IMFLAGS_OFFLINE) ? args->timestamp : time(NULL));
-	g_free(tmp);
-
-	return 1;
-}
-
-static int
-incomingim_chan2(OscarData *od, FlapConnection *conn, aim_userinfo_t *userinfo, IcbmArgsCh2 *args)
-{
-	PurpleConnection *gc;
-	PurpleAccount *account;
-	PurpleMessageFlags flags = 0;
-	char *message = NULL;
-
-	g_return_val_if_fail(od != NULL, 0);
-	g_return_val_if_fail(od->gc != NULL, 0);
-
-	gc = od->gc;
-	account = purple_connection_get_account(gc);
-	od = purple_connection_get_protocol_data(gc);
-
-	if (args == NULL)
-		return 0;
-
-	purple_debug_misc("oscar", "Incoming rendezvous message of type %"
-			G_GUINT64_FORMAT ", user %s, status %hu\n",
-			args->type, userinfo->bn, args->status);
-
-	if (args->msg != NULL) {
-		message = oscar_encoding_to_utf8(args->encoding, args->msg, args->msglen);
-	}
-
-	if (args->type & OSCAR_CAPABILITY_CHAT)
-	{
-		char *utf8name, *tmp;
-		GHashTable *components;
-
-		if (!args->info.chat.roominfo.name || !args->info.chat.roominfo.exchange) {
-			g_free(message);
-			return 1;
-		}
-		utf8name = oscar_encoding_to_utf8(args->encoding, args->info.chat.roominfo.name, args->info.chat.roominfo.namelen);
-
-		tmp = extract_name(utf8name);
-		if (tmp != NULL)
-		{
-			g_free(utf8name);
-			utf8name = tmp;
-		}
-
-		components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
-				g_free);
-		g_hash_table_replace(components, g_strdup("room"), utf8name);
-		g_hash_table_replace(components, g_strdup("exchange"),
-				g_strdup_printf("%d", args->info.chat.roominfo.exchange));
-		purple_serv_got_chat_invite(gc,
-				     utf8name,
-				     userinfo->bn,
-				     message,
-				     components);
-	}
-
-	else if ((args->type & OSCAR_CAPABILITY_SENDFILE) || (args->type & OSCAR_CAPABILITY_DIRECTIM))
-	{
-		if (args->status == AIM_RENDEZVOUS_PROPOSE)
-		{
-			peer_connection_got_proposition(od, userinfo->bn, message, args);
-		}
-		else if (args->status == AIM_RENDEZVOUS_CANCEL)
-		{
-			/* The other user cancelled a peer request */
-			PeerConnection *conn;
-
-			conn = peer_connection_find_by_cookie(od, userinfo->bn, args->cookie);
-			/*
-			 * If conn is NULL it means we haven't tried to create
-			 * a connection with that user.  They may be trying to
-			 * do something malicious.
-			 */
-			if (conn != NULL)
-			{
-				peer_connection_destroy(conn, OSCAR_DISCONNECT_REMOTE_CLOSED, NULL);
-			}
-		}
-		else if (args->status == AIM_RENDEZVOUS_CONNECTED)
-		{
-			/*
-			 * Remote user has accepted our peer request.  If we
-			 * wanted to we could look up the PeerConnection using
-			 * args->cookie, but we don't need to do anything here.
-			 */
-		}
-	}
-
-	else if (args->type & OSCAR_CAPABILITY_GETFILE)
-	{
-	}
-
-	else if (args->type & OSCAR_CAPABILITY_TALK)
-	{
-	}
-
-	else if (args->type & OSCAR_CAPABILITY_BUDDYICON)
-	{
-		purple_buddy_icons_set_for_user(account, userinfo->bn,
-									  g_memdup(args->info.icon.icon, args->info.icon.length),
-									  args->info.icon.length,
-									  NULL);
-	}
-
-	else if (args->type & OSCAR_CAPABILITY_ICQSERVERRELAY)
-	{
-		purple_debug_info("oscar", "Got an ICQ Server Relay message of "
-				"type %d\n", args->info.rtfmsg.msgtype);
-
-		if (args->info.rtfmsg.msgtype == 1) {
-			if (args->info.rtfmsg.msg != NULL) {
-				char *rtfmsg;
-				const char *encoding = args->encoding;
-				size_t len = strlen(args->info.rtfmsg.msg);
-				char *tmp, *tmp2;
-
-				if (encoding == NULL && !g_utf8_validate(args->info.rtfmsg.msg, len, NULL)) {
-					/* Yet another wonderful Miranda-related hack. If their user disables the "Send Unicode messages" setting,
-					 * Miranda sends us ch2 messages in whatever Windows codepage is set as default on their user's system (instead of UTF-8).
-					 * Of course, they don't bother to specify that codepage. Let's just fallback to the encoding OUR users can
-					 * specify in account options as a last resort.
-					 */
-					encoding = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
-					purple_debug_info("oscar", "Miranda, is that you? Using '%s' as encoding\n", encoding);
-				}
-
-				rtfmsg = oscar_encoding_to_utf8(encoding, args->info.rtfmsg.msg, len);
-
-				/* Channel 2 messages are supposed to be plain-text (never mind the name "rtfmsg", even
-				 * the official client doesn't parse them as RTF). Therefore, we should escape them before
-				 * showing to the user. */
-				tmp = g_markup_escape_text(rtfmsg, -1);
-				g_free(rtfmsg);
-				tmp2 = purple_strreplace(tmp, "\r\n", "<br>");
-				g_free(tmp);
-
-				purple_serv_got_im(gc, userinfo->bn, tmp2, flags, time(NULL));
-				aim_im_send_icq_confirmation(od, userinfo->bn, args->cookie);
-				g_free(tmp2);
-			}
-		} else if (args->info.rtfmsg.msgtype == 26) {
-			purple_debug_info("oscar", "Sending X-Status Reply\n");
-			icq_relay_xstatus(od, userinfo->bn, args->cookie);
-		}
-	}
-	else
-	{
-		purple_debug_error("oscar", "Unknown request class %"
-				G_GUINT64_FORMAT "\n", args->type);
-	}
-
-	g_free(message);
-
-	return 1;
-}
-
-/* When someone sends you buddies */
-static void
-purple_icq_buddyadd(struct name_data *data)
-{
-	PurpleConnection *gc = data->gc;
-
-	purple_blist_request_add_buddy(purple_connection_get_account(gc), data->name, NULL, data->nick);
-
-	oscar_free_name_data(data);
-}
-
-static int
-incomingim_chan4(OscarData *od, FlapConnection *conn, aim_userinfo_t *userinfo,
-		struct aim_incomingim_ch4_args *args)
-{
-	PurpleConnection *gc = od->gc;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	gchar **msg1, **msg2;
-	int i, numtoks;
-
-	if (!args->type || !args->msg || !args->uin)
-		return 1;
-
-	purple_debug_info("oscar",
-		"Received a channel 4 message of type 0x%02hx.",
-		(guint16)args->type);
-
-	/*
-	 * Split up the message at the delimeter character, then convert each
-	 * string to UTF-8.  Unless, of course, this is a type 1 message.  If
-	 * this is a type 1 message, then the delimiter 0xfe could be a valid
-	 * character in whatever encoding the message was sent in.  Type 1
-	 * messages are always made up of only one part, so we can easily account
-	 * for this suck-ass part of the protocol by splitting the string into at
-	 * most 1 baby string.
-	 */
-	msg1 = g_strsplit(args->msg, "\376", (args->type == 0x01 ? 1 : 0));
-	for (numtoks=0; msg1[numtoks]; numtoks++);
-	msg2 = (gchar **)g_malloc((numtoks+1)*sizeof(gchar *));
-	for (i=0; msg1[i]; i++) {
-		gchar *uin = g_strdup_printf("%u", args->uin);
-
-		purple_str_strip_char(msg1[i], '\r');
-		/* TODO: Should use an encoding other than ASCII? */
-		msg2[i] = oscar_decode_im(account, uin, AIM_CHARSET_ASCII, msg1[i], strlen(msg1[i]));
-		g_free(uin);
-	}
-	msg2[i] = NULL;
-
-	switch (args->type) {
-		case 0x01: { /* MacICQ message or basic offline message */
-			if (i >= 1) {
-				gchar *uin = g_strdup_printf("%u", args->uin);
-				gchar *tmp;
-
-				/* If the message came from an ICQ user then escape any HTML */
-				tmp = g_markup_escape_text(msg2[0], -1);
-
-				purple_serv_got_im(gc, uin, tmp, 0, time(NULL));
-
-				g_free(uin);
-				g_free(tmp);
-			}
-		} break;
-
-		case 0x04: { /* Someone sent you a URL */
-			if (i >= 2) {
-				if (msg2[1] != NULL) {
-					gchar *uin = g_strdup_printf("%u", args->uin);
-					gchar *message = g_strdup_printf("<A HREF=\"%s\">%s</A>",
-													 msg2[1],
-													 (msg2[0] && msg2[0][0]) ? msg2[0] : msg2[1]);
-					purple_serv_got_im(gc, uin, message, 0, time(NULL));
-					g_free(uin);
-					g_free(message);
-				}
-			}
-		} break;
-
-		case 0x06: { /* Someone requested authorization */
-			if (i >= 6) {
-				gchar *bn = g_strdup_printf("%u", args->uin);
-				gchar *reason = NULL;
-
-				if (msg2[5] != NULL)
-					reason = oscar_decode_im(account, bn, AIM_CHARSET_LATIN_1, msg2[5], strlen(msg2[5]));
-
-				purple_debug_info("oscar",
-						   "Received an authorization request from UIN %u\n",
-						   args->uin);
-				aim_icq_getalias(od, bn, TRUE, reason);
-				g_free(bn);
-				g_free(reason);
-			}
-		} break;
-
-		case 0x07: { /* Someone has denied you authorization */
-			if (i >= 1) {
-				gchar *dialog_msg = g_strdup_printf(_("The user %u has denied your request to add them to your buddy list for the following reason:\n%s"), args->uin, msg2[0] ? msg2[0] : _("No reason given."));
-				purple_notify_info(gc, NULL, _("ICQ authorization denied."), dialog_msg, purple_request_cpar_from_connection(gc));
-				g_free(dialog_msg);
-			}
-		} break;
-
-		case 0x08: { /* Someone has granted you authorization */
-			gchar *dialog_msg = g_strdup_printf(_("The user %u has granted your request to add them to your buddy list."), args->uin);
-			purple_notify_info(gc, NULL, "ICQ authorization accepted.", dialog_msg, purple_request_cpar_from_connection(gc));
-			g_free(dialog_msg);
-		} break;
-
-		case 0x09: { /* Message from the Godly ICQ server itself, I think */
-			if (i >= 5) {
-				gchar *dialog_msg = g_strdup_printf(_("You have received a special message\n\nFrom: %s [%s]\n%s"), msg2[0], msg2[3], msg2[5]);
-				purple_notify_info(gc, NULL, "ICQ Server Message", dialog_msg, purple_request_cpar_from_connection(gc));
-				g_free(dialog_msg);
-			}
-		} break;
-
-		case 0x0d: { /* Someone has sent you a pager message from http://www.icq.com/your_uin */
-			if (i >= 6) {
-				gchar *dialog_msg = g_strdup_printf(_("You have received an ICQ page\n\nFrom: %s [%s]\n%s"), msg2[0], msg2[3], msg2[5]);
-				purple_notify_info(gc, NULL, "ICQ Page", dialog_msg, purple_request_cpar_from_connection(gc));
-				g_free(dialog_msg);
-			}
-		} break;
-
-		case 0x0e: { /* Someone has emailed you at your_uin@pager.icq.com */
-			if (i >= 6) {
-				gchar *dialog_msg = g_strdup_printf(_("You have received an ICQ email from %s [%s]\n\nMessage is:\n%s"), msg2[0], msg2[3], msg2[5]);
-				purple_notify_info(gc, NULL, "ICQ Email", dialog_msg, purple_request_cpar_from_connection(gc));
-				g_free(dialog_msg);
-			}
-		} break;
-
-		case 0x12: {
-			/* Ack for authorizing/denying someone.  Or possibly an ack for sending any system notice */
-			/* Someone added you to their buddy list? */
-		} break;
-
-		case 0x13: { /* Someone has sent you some ICQ buddies */
-			guint i, num;
-			gchar **text;
-			text = g_strsplit(args->msg, "\376", 0);
-			if (text) {
-				/* Read the number of contacts that we were sent */
-				errno = 0;
-				num = text[0] ? strtoul(text[0], NULL, 10) : 0;
-
-				if (num > 0 && errno == 0) {
-					for (i=0; i<num; i++) {
-						struct name_data *data;
-						gchar *message;
-
-						if (!text[i*2 + 1] || !text[i*2 + 2]) {
-							/* We're missing the contact name or nickname.  Bail out. */
-							gchar *tmp = g_strescape(args->msg, NULL);
-							purple_debug_error("oscar", "Unknown syntax parsing "
-									"ICQ buddies.  args->msg=%s\n", tmp);
-							g_free(tmp);
-							break;
-						}
-
-						message = g_strdup_printf(_("ICQ user %u has sent you a buddy: %s (%s)"), args->uin, text[i*2+2], text[i*2+1]);
-
-						data = g_new(struct name_data, 1);
-						data->gc = gc;
-						data->name = g_strdup(text[i*2+1]);
-						data->nick = g_strdup(text[i*2+2]);
-
-						purple_request_action(gc, NULL, message,
-								_("Do you want to add this buddy "
-								  "to your buddy list?"),
-								PURPLE_DEFAULT_ACTION_NONE,
-								purple_request_cpar_from_connection(gc),
-								data, 2,
-								_("_Add"), G_CALLBACK(purple_icq_buddyadd),
-								_("_Decline"), G_CALLBACK(oscar_free_name_data));
-						g_free(message);
-					}
-				} else {
-					gchar *tmp = g_strescape(args->msg, NULL);
-					purple_debug_error("oscar", "Unknown syntax parsing "
-							"ICQ buddies.  args->msg=%s\n", tmp);
-					g_free(tmp);
-				}
-				g_strfreev(text);
-			}
-		} break;
-
-		case 0x1a: { /* Handle SMS or someone has sent you a greeting card or requested buddies? */
-			ByteStream qbs;
-			guint16 smstype;
-			guint32 taglen, smslen;
-			char *tagstr = NULL, *smsmsg = NULL;
-			PurpleXmlNode *xmlroot = NULL, *xmltmp = NULL;
-			gchar *uin = NULL, *message = NULL;
-
-			/* From libicq2000-0.3.2/src/ICQ.cpp */
-			byte_stream_init(&qbs, (guint8 *)args->msg, args->msglen);
-			byte_stream_advance(&qbs, 21);
-			/* expected:	01 00 00 20 00 0e 28 f6 00 11 e7 d3 11 bc f3 00 04 ac 96 9d c2 | 00 00 | 06 00 00 00 | 49 43 51 53 43 53 ...*/
-			/* unexpected:	00 00 26 00 81 1a 18 bc 0e 6c 18 47 a5 91 6f 18 dc c7 6f 1a | 00 00 | 0d 00 00 00 | 49 43 51 57 65 62 4d 65 73 73 61 67 65 ... */
-			smstype = byte_stream_getle16(&qbs);
-			if (smstype != 0)
-				break;
-			taglen = byte_stream_getle32(&qbs);
-			if (taglen > 2000) {
-				/* Avoid trying to allocate large amounts of memory, in
-				   case we get something unexpected. */
-				break;
-			}
-			tagstr = byte_stream_getstr(&qbs, taglen);
-			if (tagstr == NULL)
-				break;
-			byte_stream_advance(&qbs, 3);
-			byte_stream_advance(&qbs, 4);
-			smslen = byte_stream_getle32(&qbs);
-			if (smslen > 2000) {
-				/* Avoid trying to allocate large amounts of memory, in
-				   case we get something unexpected. */
-				g_free(tagstr);
-				break;
-			}
-			smsmsg = byte_stream_getstr(&qbs, smslen);
-
-			/* Check if this is an SMS being sent from server */
-			if (purple_strequal(tagstr, "ICQSMS") && smsmsg != NULL) {
-				xmlroot = purple_xmlnode_from_str(smsmsg, -1);
-				if (xmlroot != NULL)
-				{
-					xmltmp = purple_xmlnode_get_child(xmlroot, "sender");
-					if (xmltmp != NULL)
-						uin = purple_xmlnode_get_data(xmltmp);
-
-					xmltmp = purple_xmlnode_get_child(xmlroot, "text");
-					if (xmltmp != NULL)
-						message = purple_xmlnode_get_data(xmltmp);
-
-					if ((uin != NULL) && (message != NULL))
-							purple_serv_got_im(gc, uin, message, 0, time(NULL));
-
-					g_free(uin);
-					g_free(message);
-					purple_xmlnode_free(xmlroot);
-				}
-			}
-			g_free(tagstr);
-			g_free(smsmsg);
-		} break;
-
-		default: {
-			purple_debug_info("oscar",
-					   "Received a channel 4 message of unknown type "
-					   "(type 0x%02x).\n", args->type & 0xFF);
-		} break;
-	}
-
-	g_strfreev(msg1);
-	g_strfreev(msg2);
-
-	return 1;
-}
-
-static int purple_parse_incoming_im(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	guint16 channel;
-	int ret = 0;
-	aim_userinfo_t *userinfo;
-	va_list ap;
-
-	va_start(ap, fr);
-	channel = (guint16)va_arg(ap, unsigned int);
-	userinfo = va_arg(ap, aim_userinfo_t *);
-
-	switch (channel) {
-		case 1: { /* standard message */
-			struct aim_incomingim_ch1_args *args;
-			args = va_arg(ap, struct aim_incomingim_ch1_args *);
-			ret = incomingim_chan1(od, conn, userinfo, args);
-		} break;
-
-		case 2: { /* rendezvous */
-			IcbmArgsCh2 *args;
-			args = va_arg(ap, IcbmArgsCh2 *);
-			ret = incomingim_chan2(od, conn, userinfo, args);
-		} break;
-
-		case 4: { /* ICQ */
-			struct aim_incomingim_ch4_args *args;
-			args = va_arg(ap, struct aim_incomingim_ch4_args *);
-			ret = incomingim_chan4(od, conn, userinfo, args);
-		} break;
-
-		default: {
-			purple_debug_warning("oscar",
-					   "ICBM received on unsupported channel (channel "
-					   "0x%04hx).", channel);
-		} break;
-	}
-
-	va_end(ap);
-
-	return ret;
-}
-
-static int purple_parse_misses(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	PurpleConnection *gc = od->gc;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	char *buf;
-	va_list ap;
-	guint16 nummissed, reason;
-	aim_userinfo_t *userinfo;
-
-	va_start(ap, fr);
-	va_arg(ap, unsigned int); /* guint16 chan */
-	userinfo = va_arg(ap, aim_userinfo_t *);
-	nummissed = (guint16)va_arg(ap, unsigned int);
-	reason = (guint16)va_arg(ap, unsigned int);
-	va_end(ap);
-
-	switch(reason) {
-		case 0: /* Invalid (0) */
-			buf = g_strdup_printf(
-				   dngettext(PACKAGE,
-				   "You missed %hu message from %s because it was invalid.",
-				   "You missed %hu messages from %s because they were invalid.",
-				   nummissed),
-				   nummissed,
-				   userinfo->bn);
-			break;
-		case 1: /* Message too large */
-			buf = g_strdup_printf(
-				   dngettext(PACKAGE,
-				   "You missed %hu message from %s because it was too large.",
-				   "You missed %hu messages from %s because they were too large.",
-				   nummissed),
-				   nummissed,
-				   userinfo->bn);
-			break;
-		case 2: /* Rate exceeded */
-			buf = g_strdup_printf(
-				   dngettext(PACKAGE,
-				   "You missed %hu message from %s because the rate limit has been exceeded.",
-				   "You missed %hu messages from %s because the rate limit has been exceeded.",
-				   nummissed),
-				   nummissed,
-				   userinfo->bn);
-			break;
-		case 3: /* Evil Sender */
-			buf = g_strdup_printf(
-				   dngettext(PACKAGE,
-				   "You missed %hu message from %s because his/her warning level is too high.",
-				   "You missed %hu messages from %s because his/her warning level is too high.",
-				   nummissed),
-				   nummissed,
-				   userinfo->bn);
-			break;
-		case 4: /* Evil Receiver */
-			buf = g_strdup_printf(
-				   dngettext(PACKAGE,
-				   "You missed %hu message from %s because your warning level is too high.",
-				   "You missed %hu messages from %s because your warning level is too high.",
-				   nummissed),
-				   nummissed,
-				   userinfo->bn);
-			break;
-		default:
-			buf = g_strdup_printf(
-				   dngettext(PACKAGE,
-				   "You missed %hu message from %s for an unknown reason.",
-				   "You missed %hu messages from %s for an unknown reason.",
-				   nummissed),
-				   nummissed,
-				   userinfo->bn);
-			break;
-	}
-
-	if (!purple_conversation_present_error(userinfo->bn, account, buf)) {
-		purple_notify_error(od->gc, NULL, buf, NULL,
-			purple_request_cpar_from_connection(od->gc));
-	}
-	g_free(buf);
-
-	return 1;
-}
-
-static int
-purple_parse_clientauto_ch2(OscarData *od, const char *who, guint16 reason, const guchar *cookie)
-{
-	if (reason == 0x0003)
-	{
-		/* Rendezvous was refused. */
-		PeerConnection *conn;
-
-		conn = peer_connection_find_by_cookie(od, who, cookie);
-
-		if (conn == NULL)
-		{
-			purple_debug_info("oscar", "Received a rendezvous cancel message "
-					"for a nonexistant connection from %s.\n", who);
-		}
-		else
-		{
-			peer_connection_destroy(conn, OSCAR_DISCONNECT_REMOTE_REFUSED, NULL);
-		}
-	}
-	else
-	{
-		purple_debug_warning("oscar", "Received an unknown rendezvous "
-				"message from %s.  Type 0x%04hx\n", who, reason);
-	}
-
-	return 0;
-}
-
-static int purple_parse_clientauto_ch4(OscarData *od, const char *who, guint16 reason, guint32 state, char *msg) {
-	PurpleConnection *gc = od->gc;
-
-	switch(reason) {
-		/* Reply from an ICQ status message request */
-		case 0x0003:
-		case 0x0006: {
-			char *statusmsg, **splitmsg;
-			PurpleNotifyUserInfo *user_info;
-
-			statusmsg = oscar_icqstatus(state);
-
-			/* Split at (carriage return/newline)'s, then rejoin later with BRs between. */
-			/* TODO: Don't we need to escape each piece? */
-			splitmsg = g_strsplit(msg, "\r\n", 0);
-
-			user_info = purple_notify_user_info_new();
-
-			purple_notify_user_info_add_pair_plaintext(user_info, _("UIN"), who);
-			/* TODO: Check whether it's correct to call add_pair_html,
-			         or if we should be using add_pair_plaintext */
-			purple_notify_user_info_add_pair_html(user_info, _("Status"), statusmsg);
-			purple_notify_user_info_add_section_break(user_info);
-			purple_notify_user_info_add_pair_html(user_info, NULL, g_strjoinv("<BR>", splitmsg));
-
-			g_free(statusmsg);
-			g_strfreev(splitmsg);
-
-			purple_notify_userinfo(gc, who, user_info, NULL, NULL);
-			purple_notify_user_info_destroy(user_info);
-
-		} break;
-
-		default: {
-			purple_debug_warning("oscar",
-					   "Received an unknown client auto-response from %s.  "
-					   "Type 0x%04hx\n", who, reason);
-		} break;
-	} /* end of switch */
-
-	return 0;
-}
-
-static int purple_parse_clientauto(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	va_list ap;
-	guint16 chan, reason;
-	char *who;
-	int ret = 1;
-
-	va_start(ap, fr);
-	chan = (guint16)va_arg(ap, unsigned int);
-	who = va_arg(ap, char *);
-	reason = (guint16)va_arg(ap, unsigned int);
-
-	if (chan == 0x0002) { /* File transfer declined */
-		guchar *cookie = va_arg(ap, guchar *);
-		ret = purple_parse_clientauto_ch2(od, who, reason, cookie);
-	} else if (chan == 0x0004) { /* ICQ message */
-		guint32 state = 0;
-		char *msg = NULL;
-		if (reason == 0x0003) {
-			state = va_arg(ap, guint32);
-			msg = va_arg(ap, char *);
-		}
-		ret = purple_parse_clientauto_ch4(od, who, reason, state, msg);
-	}
-
-	va_end(ap);
-
-	return ret;
-}
-
-static int purple_parse_genericerr(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	va_list ap;
-	guint16 reason;
-
-	va_start(ap, fr);
-	reason = (guint16) va_arg(ap, unsigned int);
-	va_end(ap);
-
-	purple_debug_error("oscar", "snac threw error (reason 0x%04hx: %s)\n",
-			reason, oscar_get_msgerr_reason(reason));
-	return 1;
-}
-
-static int purple_parse_mtn(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	PurpleConnection *gc = od->gc;
-	va_list ap;
-	guint16 channel, event;
-	char *bn;
-
-	va_start(ap, fr);
-	channel = (guint16) va_arg(ap, unsigned int);
-	bn = va_arg(ap, char *);
-	event = (guint16) va_arg(ap, unsigned int);
-	va_end(ap);
-
-	switch (event) {
-		case 0x0000: /* Text has been cleared */
-		case 0x000f: /* Closed IM window */
-			purple_serv_got_typing_stopped(gc, bn);
-			break;
-
-		case 0x0001: /* Paused typing */
-			purple_serv_got_typing(gc, bn, 0, PURPLE_IM_TYPED);
-			break;
-
-		case 0x0002: /* Typing */
-			purple_serv_got_typing(gc, bn, 0, PURPLE_IM_TYPING);
-			break;
-
-		default:
-			purple_debug_info("oscar", "Received unknown typing "
-					"notification message from %s.  Channel is 0x%04x "
-					"and event is 0x%04hx.\n", bn, channel, event);
-			break;
-	}
-
-	return 1;
-}
-
-static int purple_parse_motd(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
-{
-	char *msg;
-	guint16 id;
-	va_list ap;
-
-	va_start(ap, fr);
-	id  = (guint16) va_arg(ap, unsigned int);
-	msg = va_arg(ap, char *);
-	va_end(ap);
-
-	purple_debug_misc("oscar",
-			   "MOTD: %s (%hu)\n", msg ? msg : "Unknown", id);
-	if (id < 4) {
-		purple_notify_warning(od->gc, NULL,
-			_("Your AIM connection may be lost."), NULL,
-			purple_request_cpar_from_connection(od->gc));
-	}
-
-	return 1;
-}
-
-static int purple_chatnav_info(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	va_list ap;
-	guint16 type;
-
-	va_start(ap, fr);
-	type = (guint16) va_arg(ap, unsigned int);
-
-	switch(type) {
-		case 0x0002: {
-			GString *msg = g_string_new("");
-			guint8 maxrooms;
-			struct aim_chat_exchangeinfo *exchanges;
-			int exchangecount, i;
-
-			maxrooms = (guint8) va_arg(ap, unsigned int);
-			exchangecount = va_arg(ap, int);
-			exchanges = va_arg(ap, struct aim_chat_exchangeinfo *);
-
-			g_string_append_printf(msg, "chat info: Max Concurrent Rooms: %d, Exchange List (%d total): ", (int)maxrooms, exchangecount);
-			for (i = 0; i < exchangecount; i++) {
-				g_string_append_printf(msg, "%hu", exchanges[i].number);
-				if (exchanges[i].name) {
-					g_string_append_printf(msg, " %s", exchanges[i].name);
-				}
-				g_string_append(msg, ", ");
-			}
-			purple_debug_misc("oscar", "%s\n", msg->str);
-			g_string_free(msg, TRUE);
-
-			while (od->create_rooms) {
-				struct create_room *cr = od->create_rooms->data;
-				purple_debug_info("oscar",
-						   "creating room %s\n", cr->name);
-				aim_chatnav_createroom(od, conn, cr->name, cr->exchange);
-				g_free(cr->name);
-				od->create_rooms = g_slist_remove(od->create_rooms, cr);
-				g_free(cr);
-			}
-			}
-			break;
-		case 0x0008: {
-			char *fqcn, *name, *ck;
-			guint16 instance, flags, maxmsglen, maxoccupancy, unknown, exchange;
-			guint8 createperms;
-			guint32 createtime;
-
-			fqcn = va_arg(ap, char *);
-			instance = (guint16)va_arg(ap, unsigned int);
-			exchange = (guint16)va_arg(ap, unsigned int);
-			flags = (guint16)va_arg(ap, unsigned int);
-			createtime = va_arg(ap, guint32);
-			maxmsglen = (guint16)va_arg(ap, unsigned int);
-			maxoccupancy = (guint16)va_arg(ap, unsigned int);
-			createperms = (guint8)va_arg(ap, unsigned int);
-			unknown = (guint16)va_arg(ap, unsigned int);
-			name = va_arg(ap, char *);
-			ck = va_arg(ap, char *);
-
-			purple_debug_misc("oscar",
-					"created room: %s %hu %hu %hu %u %hu %hu %u %hu %s %s\n",
-					fqcn ? fqcn : "(null)", exchange, instance, flags, createtime,
-					maxmsglen, maxoccupancy, (guint)createperms, unknown,
-					name ? name : "(null)", ck);
-			aim_chat_join(od, exchange, ck, instance);
-			}
-			break;
-		default:
-			purple_debug_warning("oscar",
-					   "chatnav info: unknown type (%04hx)\n", type);
-			break;
-	}
-
-	va_end(ap);
-
-	return 1;
-}
-
-static int purple_chat_conversation_join(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	va_list ap;
-	int count, i;
-	aim_userinfo_t *info;
-	PurpleConnection *gc = od->gc;
-
-	struct chat_connection *c = NULL;
-
-	va_start(ap, fr);
-	count = va_arg(ap, int);
-	info  = va_arg(ap, aim_userinfo_t *);
-	va_end(ap);
-
-	c = find_oscar_chat_by_conn(gc, conn);
-	if (!c)
-		return 1;
-
-	for (i = 0; i < count; i++)
-		purple_chat_conversation_add_user(c->conv, info[i].bn, NULL, PURPLE_CHAT_USER_NONE, TRUE);
-
-	return 1;
-}
-
-static int purple_chat_conversation_left(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	va_list ap;
-	int count, i;
-	aim_userinfo_t *info;
-	PurpleConnection *gc = od->gc;
-
-	struct chat_connection *c = NULL;
-
-	va_start(ap, fr);
-	count = va_arg(ap, int);
-	info  = va_arg(ap, aim_userinfo_t *);
-	va_end(ap);
-
-	c = find_oscar_chat_by_conn(gc, conn);
-	if (!c)
-		return 1;
-
-	for (i = 0; i < count; i++)
-		purple_chat_conversation_remove_user(c->conv, info[i].bn, NULL);
-
-	return 1;
-}
-
-static int purple_chat_conversation_info_update(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	va_list ap;
-	guint16 maxmsglen, maxvisiblemsglen;
-	PurpleConnection *gc = od->gc;
-	struct chat_connection *ccon = find_oscar_chat_by_conn(gc, conn);
-
-	if (!ccon)
-		return 1;
-
-	va_start(ap, fr);
-	maxmsglen = (guint16)va_arg(ap, unsigned int);
-	maxvisiblemsglen = (guint16)va_arg(ap, unsigned int);
-	va_end(ap);
-
-	purple_debug_misc("oscar",
-			   "inside chat_info_update (maxmsglen = %hu, maxvislen = %hu)\n",
-			   maxmsglen, maxvisiblemsglen);
-
-	ccon->maxlen = maxmsglen;
-	ccon->maxvis = maxvisiblemsglen;
-
-	return 1;
-}
-
-static int purple_chat_conversation_incoming_msg(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	PurpleConnection *gc = od->gc;
-	struct chat_connection *ccon = find_oscar_chat_by_conn(gc, conn);
-	gchar *utf8;
-	va_list ap;
-	aim_userinfo_t *info;
-	int len;
-	char *msg;
-	char *charset;
-
-	if (!ccon)
-		return 1;
-
-	va_start(ap, fr);
-	info = va_arg(ap, aim_userinfo_t *);
-	len = va_arg(ap, int);
-	msg = va_arg(ap, char *);
-	charset = va_arg(ap, char *);
-	va_end(ap);
-
-	utf8 = oscar_encoding_to_utf8(charset, msg, len);
-	purple_serv_got_chat_in(gc, ccon->id, info->bn,
-		PURPLE_MESSAGE_RECV, utf8, time(NULL));
-	g_free(utf8);
-
-	return 1;
-}
-
-static int purple_email_parseupdate(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	va_list ap;
-	PurpleConnection *gc;
-	PurpleAccount *account;
-	struct aim_emailinfo *emailinfo;
-	int havenewmail;
-	char *alertitle, *alerturl;
-
-	gc = od->gc;
-	account = purple_connection_get_account(gc);
-
-	va_start(ap, fr);
-	emailinfo = va_arg(ap, struct aim_emailinfo *);
-	havenewmail = va_arg(ap, int);
-	alertitle = va_arg(ap, char *);
-	alerturl  = va_arg(ap, char *);
-	va_end(ap);
-
-	if (account != NULL && emailinfo != NULL && purple_account_get_check_mail(account) &&
-			emailinfo->unread && havenewmail) {
-		gchar *to = g_strdup_printf("%s%s%s",
-				purple_account_get_username(account),
-				emailinfo->domain ? "@" : "",
-				emailinfo->domain ? emailinfo->domain : "");
-		const char *tos[2] = { to };
-		const char *urls[2] = { emailinfo->url };
-		purple_notify_emails(gc, emailinfo->nummsgs, FALSE, NULL, NULL,
-				tos, urls, NULL, NULL);
-		g_free(to);
-	}
-
-	if (alertitle)
-		purple_debug_misc("oscar", "Got an alert '%s' %s\n", alertitle, alerturl ? alerturl : "");
-
-	return 1;
-}
-
-static int purple_icon_parseicon(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	PurpleConnection *gc = od->gc;
-	va_list ap;
-	char *bn;
-	guint8 *iconcsum, *icon;
-	guint16 iconcsumlen, iconlen;
-
-	va_start(ap, fr);
-	bn = va_arg(ap, char *);
-	va_arg(ap, int); /* iconsumtype */
-	iconcsum = va_arg(ap, guint8 *);
-	iconcsumlen = va_arg(ap, int);
-	icon = va_arg(ap, guint8 *);
-	iconlen = va_arg(ap, int);
-	va_end(ap);
-
-	/*
-	 * Some AIM clients will send a blank GIF image with iconlen 90 when
-	 * no icon is set.  Ignore these.
-	 */
-	if ((iconlen > 0) && (iconlen != 90)) {
-		char *b16 = purple_base16_encode(iconcsum, iconcsumlen);
-		purple_buddy_icons_set_for_user(purple_connection_get_account(gc),
-									  bn, g_memdup(icon, iconlen), iconlen, b16);
-		g_free(b16);
-	}
-
-	return 1;
-}
-
-static void
-purple_icons_fetch(PurpleConnection *gc)
-{
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	aim_userinfo_t *userinfo;
-	FlapConnection *conn;
-
-	conn = flap_connection_getbytype(od, SNAC_FAMILY_BART);
-	if (!conn) {
-		if (!od->iconconnecting) {
-			aim_srv_requestnew(od, SNAC_FAMILY_BART);
-			od->iconconnecting = TRUE;
-		}
-		return;
-	}
-
-	if (od->set_icon) {
-		PurpleAccount *account = purple_connection_get_account(gc);
-		PurpleImage *img = purple_buddy_icons_find_account_icon(account);
-		if (img == NULL) {
-			aim_ssi_delicon(od);
-		} else {
-			purple_debug_info("oscar",
-				"Uploading icon to icon server");
-			aim_bart_upload(od, purple_image_get_data(img),
-				purple_image_get_data_size(img));
-			g_object_unref(img);
-		}
-		od->set_icon = FALSE;
-	}
-
-	while (od->requesticon != NULL)
-	{
-		userinfo = aim_locate_finduserinfo(od, (char *)od->requesticon->data);
-		if ((userinfo != NULL) && (userinfo->iconcsumlen > 0))
-			aim_bart_request(od, od->requesticon->data, userinfo->iconcsumtype, userinfo->iconcsum, userinfo->iconcsumlen);
-
-		g_free(od->requesticon->data);
-		od->requesticon = g_slist_delete_link(od->requesticon, od->requesticon);
-	}
-
-	purple_debug_misc("oscar", "no more icons to request\n");
-}
-
-static int purple_selfinfo(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	va_list ap;
-	aim_userinfo_t *info;
-
-	va_start(ap, fr);
-	info = va_arg(ap, aim_userinfo_t *);
-	va_end(ap);
-
-	purple_connection_set_display_name(od->gc, info->bn);
-
-	return 1;
-}
-
-static int purple_connerr(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	PurpleConnection *gc = od->gc;
-	va_list ap;
-	guint16 code;
-	char *msg;
-
-	va_start(ap, fr);
-	code = (guint16)va_arg(ap, int);
-	msg = va_arg(ap, char *);
-	va_end(ap);
-
-	purple_debug_info("oscar", "Disconnected.  Code is 0x%04x and msg is %s\n",
-					code, (msg != NULL ? msg : ""));
-
-	g_return_val_if_fail(conn != NULL, 1);
-
-	if (conn->type == SNAC_FAMILY_CHAT) {
-		struct chat_connection *cc;
-		PurpleChatConversation *chat = NULL;
-
-		cc = find_oscar_chat_by_conn(gc, conn);
-		if (cc != NULL)
-		{
-			chat = purple_conversations_find_chat(gc, cc->id);
-
-			if (chat != NULL)
-			{
-				/*
-				 * TOOD: Have flap_connection_destroy_cb() send us the
-				 *       error message stored in 'tmp', which should be
-				 *       human-friendly, and print that to the chat room.
-				 */
-				gchar *buf;
-				buf = g_strdup_printf(_("You have been disconnected from chat "
-										"room %s."), cc->name);
-				purple_conversation_write_system_message(
-					PURPLE_CONVERSATION(chat), buf,
-					PURPLE_MESSAGE_ERROR);
-				g_free(buf);
-			}
-			oscar_chat_kill(gc, cc);
-		}
-	}
-
-	return 1;
-}
-
-static int purple_parse_locaterights(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
-{
-	PurpleConnection *gc = od->gc;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	va_list ap;
-	guint16 maxsiglen;
-
-	va_start(ap, fr);
-	maxsiglen = (guint16) va_arg(ap, int);
-	va_end(ap);
-
-	purple_debug_misc("oscar",
-			   "locate rights: max sig len = %d\n", maxsiglen);
-
-	od->rights.maxsiglen = od->rights.maxawaymsglen = (guint)maxsiglen;
-
-	aim_locate_setcaps(od, purple_caps);
-	oscar_set_info_and_status(account, TRUE, purple_account_get_user_info(account), TRUE,
-							  purple_account_get_active_status(account));
-
-	return 1;
-}
-
-static int purple_parse_buddyrights(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	va_list ap;
-	guint16 maxbuddies, maxwatchers;
-
-	va_start(ap, fr);
-	maxbuddies = (guint16) va_arg(ap, unsigned int);
-	maxwatchers = (guint16) va_arg(ap, unsigned int);
-	va_end(ap);
-
-	purple_debug_misc("oscar",
-			   "buddy list rights: Max buddies = %hu / Max watchers = %hu\n", maxbuddies, maxwatchers);
-
-	od->rights.maxbuddies = (guint)maxbuddies;
-	od->rights.maxwatchers = (guint)maxwatchers;
-
-	return 1;
-}
-
-static void oscar_format_username(PurpleConnection *gc, const char *new_display_name)
-{
-	OscarData *od;
-	const char *old_display_name, *username;
-	char *tmp, *at_sign;
-
-	old_display_name = purple_connection_get_display_name(gc);
-	if (old_display_name && strchr(old_display_name, '@')) {
-		purple_debug_info("oscar", "Cowardly refusing to attempt to format "
-				"screen name because the current formatting according to "
-				"the server (%s) appears to be an email address\n",
-				old_display_name);
-		return;
-	}
-
-	username = purple_account_get_username(purple_connection_get_account(gc));
-	if (oscar_util_name_compare(username, new_display_name)) {
-		purple_notify_error(gc, NULL, _("The new formatting is invalid."),
-						  _("Username formatting can change only capitalization and whitespace."),
-			purple_request_cpar_from_connection(gc));
-		return;
-	}
-
-	tmp = g_strdup(new_display_name);
-
-	/*
-	 * If our local username is an email address then strip off the domain.
-	 * This allows formatting to work if the user entered their username as
-	 * 'something@aim.com' or possibly other AOL-owned domains.
-	 */
-	at_sign = strchr(tmp, '@');
-	if (at_sign)
-		at_sign[0] = '\0';
-
-	od = purple_connection_get_protocol_data(gc);
-	if (!flap_connection_getbytype(od, SNAC_FAMILY_ADMIN)) {
-		/* We don't have a connection to an "admin" server.  Make one. */
-		od->setnick = TRUE;
-		g_free(od->newformatting);
-		od->newformatting = tmp;
-		aim_srv_requestnew(od, SNAC_FAMILY_ADMIN);
-	} else {
-		aim_admin_setnick(od, flap_connection_getbytype(od, SNAC_FAMILY_ADMIN), tmp);
-		g_free(tmp);
-	}
-}
-
-static int purple_bosrights(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	PurpleConnection *gc;
-	PurpleAccount *account;
-	PurpleStatus *status;
-	gboolean is_available;
-	PurplePresence *presence;
-	const char *username, *message, *itmsurl;
-	char *tmp;
-	va_list ap;
-	guint16 maxpermits, maxdenies;
-
-	gc = od->gc;
-	od = purple_connection_get_protocol_data(gc);
-	account = purple_connection_get_account(gc);
-
-	va_start(ap, fr);
-	maxpermits = (guint16) va_arg(ap, unsigned int);
-	maxdenies = (guint16) va_arg(ap, unsigned int);
-	va_end(ap);
-
-	purple_debug_misc("oscar",
-			   "BOS rights: Max permit = %hu / Max deny = %hu\n", maxpermits, maxdenies);
-
-	od->rights.maxpermits = (guint)maxpermits;
-	od->rights.maxdenies = (guint)maxdenies;
-
-	purple_debug_info("oscar", "buddy list loaded\n");
-
-	if (purple_account_get_user_info(account) != NULL)
-		purple_serv_set_info(gc, purple_account_get_user_info(account));
-
-	username = purple_account_get_username(account);
-	if (!od->icq && !purple_strequal(username, purple_connection_get_display_name(gc))) {
-		/*
-		 * Format the username for AIM accounts if it's different
-		 * than what's currently set.
-		 */
-		oscar_format_username(gc, username);
-	}
-
-	/* Set our available message based on the current status */
-	status = purple_account_get_active_status(account);
-	is_available = purple_status_is_available(status);
-	if (is_available)
-		message = purple_status_get_attr_string(status, "message");
-	else
-		message = NULL;
-	tmp = purple_markup_strip_html(message);
-	itmsurl = purple_status_get_attr_string(status, "itmsurl");
-	aim_srv_setextrainfo(od, FALSE, 0, is_available, tmp, itmsurl);
-	aim_srv_set_dc_info(od);
-	g_free(tmp);
-
-	presence = purple_status_get_presence(status);
-	aim_srv_setidle(od, !purple_presence_is_idle(presence) ? 0 : time(NULL) - purple_presence_get_idle_time(presence));
-
-	if (od->icq) {
-		oscar_set_extended_status(gc);
-		aim_icq_setsecurity(od,
-			purple_account_get_bool(account, "authorization", OSCAR_DEFAULT_AUTHORIZATION),
-			purple_account_get_bool(account, "web_aware", OSCAR_DEFAULT_WEB_AWARE));
-	}
-
-	aim_srv_requestnew(od, SNAC_FAMILY_ALERT);
-	aim_srv_requestnew(od, SNAC_FAMILY_CHATNAV);
-
-	od->bos.have_rights = TRUE;
-
-	/*
-	 * If we've already received our feedbag data then we're not waiting on
-	 * anything else, so send the server clientready.
-	 *
-	 * Normally we get bos rights before we get our feedbag data, so this
-	 * rarely (never?) happens.  And I'm not sure it actually matters if we
-	 * wait for bos rights before calling clientready.  But it seems safer
-	 * to do it this way.
-	 */
-	if (od->ssi.received_data) {
-		aim_srv_clientready(od, conn);
-
-		/* Request offline messages for AIM and ICQ */
-		aim_im_reqofflinemsgs(od);
-
-		purple_connection_set_state(gc, PURPLE_CONNECTION_CONNECTED);
-	}
-
-	return 1;
-}
-
-static int purple_popup(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
-{
-	PurpleConnection *gc = od->gc;
-	gchar *text;
-	va_list ap;
-	char *msg, *url;
-
-	va_start(ap, fr);
-	msg = va_arg(ap, char *);
-	url = va_arg(ap, char *);
-	va_arg(ap, int); /* guint16 wid */
-	va_arg(ap, int); /* guint16 hei */
-	va_arg(ap, int); /* guint16 delay */
-	va_end(ap);
-
-	text = g_strdup_printf("%s<br><a href=\"%s\">%s</a>", msg, url, url);
-	purple_notify_formatted(gc, NULL, _("Pop-Up Message"), NULL, text, NULL, NULL);
-	g_free(text);
-
-	return 1;
-}
-
-static void oscar_searchresults_add_buddy_cb(PurpleConnection *gc, GList *row, void *user_data)
-{
-	purple_blist_request_add_buddy(purple_connection_get_account(gc),
-								 g_list_nth_data(row, 0), NULL, NULL);
-}
-
-static int purple_parse_searchreply(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
-{
-	PurpleConnection *gc = od->gc;
-	PurpleNotifySearchResults *results;
-	PurpleNotifySearchColumn *column;
-	gchar *secondary;
-	int i, num;
-	va_list ap;
-	char *email, *usernames;
-
-	va_start(ap, fr);
-	email = va_arg(ap, char *);
-	num = va_arg(ap, int);
-	usernames = va_arg(ap, char *);
-	va_end(ap);
-
-	results = purple_notify_searchresults_new();
-
-	if (results == NULL) {
-		purple_debug_error("oscar", "purple_parse_searchreply: "
-						 "Unable to display the search results.\n");
-		purple_notify_error(gc, NULL, _("Unable to display the search "
-			"results."), NULL,
-			purple_request_cpar_from_connection(gc));
-		return 1;
-	}
-
-	secondary = g_strdup_printf(
-					dngettext(PACKAGE, "The following username is associated with %s",
-						 "The following usernames are associated with %s",
-						 num),
-					email);
-
-	column = purple_notify_searchresults_column_new(_("Username"));
-	purple_notify_searchresults_column_add(results, column);
-
-	for (i = 0; i < num; i++) {
-		GList *row;
-		row = g_list_append(NULL, g_strdup(&usernames[i * (MAXSNLEN + 1)]));
-		purple_notify_searchresults_row_add(results, row);
-	}
-	purple_notify_searchresults_button_add(results, PURPLE_NOTIFY_BUTTON_ADD,
-										 oscar_searchresults_add_buddy_cb);
-	purple_notify_searchresults(gc, NULL, NULL, secondary, results, NULL, NULL);
-
-	g_free(secondary);
-
-	return 1;
-}
-
-static int purple_parse_searcherror(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	va_list ap;
-	char *email;
-	char *buf;
-
-	va_start(ap, fr);
-	email = va_arg(ap, char *);
-	va_end(ap);
-
-	buf = g_strdup_printf(_("No results found for email address %s"), email);
-	purple_notify_error(od->gc, NULL, buf, NULL,
-		purple_request_cpar_from_connection(od->gc));
-	g_free(buf);
-
-	return 1;
-}
-
-static int purple_account_confirm(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	PurpleConnection *gc = od->gc;
-	guint16 status;
-	va_list ap;
-	char msg[256];
-
-	va_start(ap, fr);
-	status = (guint16) va_arg(ap, unsigned int); /* status code of confirmation request */
-	va_end(ap);
-
-	purple_debug_info("oscar",
-			   "account confirmation returned status 0x%04x (%s)\n", status,
-			status ? "unknown" : "email sent");
-	if (!status) {
-		g_snprintf(msg, sizeof(msg), _("You should receive an email asking to confirm %s."),
-				purple_account_get_username(purple_connection_get_account(gc)));
-		purple_notify_info(gc, NULL, _("Account Confirmation Requested"),
-			msg, purple_request_cpar_from_connection(gc));
-	}
-
-	return 1;
-}
-
-static int purple_info_change(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	PurpleConnection *gc = od->gc;
-	va_list ap;
-	guint16 perms, err;
-	char *url, *bn, *email;
-	int change;
-
-	va_start(ap, fr);
-	change = va_arg(ap, int);
-	perms = (guint16) va_arg(ap, unsigned int);
-	err = (guint16) va_arg(ap, unsigned int);
-	url = va_arg(ap, char *);
-	bn = va_arg(ap, char *);
-	email = va_arg(ap, char *);
-	va_end(ap);
-
-	purple_debug_misc("oscar",
-					"account info: because of %s, perms=0x%04x, err=0x%04x, url=%s, bn=%s, email=%s\n",
-					change ? "change" : "request", perms, err,
-					(url != NULL) ? url : "(null)",
-					(bn != NULL) ? bn : "(null)",
-					(email != NULL) ? email : "(null)");
-
-	if ((err > 0) && (url != NULL)) {
-		char *dialog_msg;
-
-		if (err == 0x0001)
-			dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to format username because the requested name differs from the original."), err);
-		else if (err == 0x0006)
-			dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to format username because it is invalid."), err);
-		else if (err == 0x00b)
-			dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to format username because the requested name is too long."), err);
-		else if (err == 0x001d)
-			dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to change email address because there is already a request pending for this username."), err);
-		else if (err == 0x0021)
-			dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to change email address because the given address has too many usernames associated with it."), err);
-		else if (err == 0x0023)
-			dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to change email address because the given address is invalid."), err);
-		else
-			dialog_msg = g_strdup_printf(_("Error 0x%04x: Unknown error."), err);
-		purple_notify_error(gc, NULL, _("Error Changing Account Info"),
-			dialog_msg, purple_request_cpar_from_connection(gc));
-		g_free(dialog_msg);
-		return 1;
-	}
-
-	if (email != NULL) {
-		char *dialog_msg = g_strdup_printf(_("The email address for %s is %s"),
-						   purple_account_get_username(purple_connection_get_account(gc)), email);
-		purple_notify_info(gc, NULL, _("Account Info"), dialog_msg,
-			purple_request_cpar_from_connection(gc));
-		g_free(dialog_msg);
-	}
-
-	return 1;
-}
-
-void
-oscar_keepalive(PurpleConnection *gc)
-{
-	OscarData *od;
-	GSList *l;
-
-	od = purple_connection_get_protocol_data(gc);
-	for (l = od->oscar_connections; l; l = l->next) {
-		flap_connection_send_keepalive(od, l->data);
-	}
-}
-
-unsigned int
-oscar_send_typing(PurpleConnection *gc, const char *name, PurpleIMTypingState state)
-{
-	OscarData *od;
-	PeerConnection *conn;
-
-	od = purple_connection_get_protocol_data(gc);
-	conn = peer_connection_find_by_type(od, name, OSCAR_CAPABILITY_DIRECTIM);
-
-	if ((conn != NULL) && (conn->ready))
-	{
-		peer_odc_send_typing(conn, state);
-	}
-	else {
-		/* Don't send if this turkey is in our deny list */
-		PurpleAccount *account = purple_connection_get_account(gc);
-		GSList *list = purple_account_privacy_get_denied(account);
-
-		if (!g_slist_find_custom(list, name, (GCompareFunc)oscar_util_name_compare)) {
-			struct buddyinfo *bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, name));
-			if (bi && bi->typingnot) {
-				if (state == PURPLE_IM_TYPING)
-					aim_im_sendmtn(od, 0x0001, name, 0x0002);
-				else if (state == PURPLE_IM_TYPED)
-					aim_im_sendmtn(od, 0x0001, name, 0x0001);
-				else
-					aim_im_sendmtn(od, 0x0001, name, 0x0000);
-			}
-		}
-	}
-	return 0;
-}
-
-/* TODO: Move this into odc.c! */
-static void
-purple_odc_send_im(PeerConnection *conn, const char *message, PurpleMessageFlags imflags)
-{
-	GString *msg;
-	GString *data;
-	gchar *tmp;
-	gsize tmplen;
-	guint16 charset;
-	GData *attribs;
-	const char *start, *end, *last;
-	int oscar_id = 0;
-
-	msg = g_string_new("<HTML><BODY>");
-	data = g_string_new("<BINARY>");
-	last = message;
-
-	/* for each valid IMG tag... */
-	while (last && *last && purple_markup_find_tag("img", last, &start, &end, &attribs))
-	{
-		PurpleImage *image = NULL;
-		const gchar *src;
-
-		if (start - last) {
-			g_string_append_len(msg, last, start - last);
-		}
-
-		src = g_datalist_get_data(&attribs, "src");
-		if (src)
-			image = purple_image_store_get_from_uri(src);
-
-		/* ... if it refers to a valid purple image ... */
-		if (image) {
-			/* ... append the message from start to the tag ... */
-			unsigned long size = purple_image_get_data_size(image);
-			const gchar *filename = purple_image_get_friendly_filename(image);
-			gconstpointer imgdata = purple_image_get_data(image);
-
-			oscar_id++;
-
-			/* ... insert a new img tag with the oscar id ... */
-			if (filename)
-				g_string_append_printf(msg,
-					"<IMG SRC=\"%s\" ID=\"%d\" DATASIZE=\"%lu\">",
-					filename, oscar_id, size);
-			else
-				g_string_append_printf(msg,
-					"<IMG ID=\"%d\" DATASIZE=\"%lu\">",
-					oscar_id, size);
-
-			/* ... and append the data to the binary section ... */
-			g_string_append_printf(data, "<DATA ID=\"%d\" SIZE=\"%lu\">",
-				oscar_id, size);
-			g_string_append_len(data, imgdata, size);
-			g_string_append(data, "</DATA>");
-		}
-			/* If the tag is invalid, skip it, thus no else here */
-
-		g_datalist_clear(&attribs);
-
-		/* continue from the end of the tag */
-		last = end + 1;
-	}
-
-	/* append any remaining message data */
-	if (last && *last)
-		g_string_append(msg, last);
-
-	g_string_append(msg, "</BODY></HTML>");
-
-	/* Convert the message to a good encoding */
-	tmp = oscar_encode_im(msg->str, &tmplen, &charset, NULL);
-	g_string_free(msg, TRUE);
-	msg = g_string_new_len(tmp, tmplen);
-	g_free(tmp);
-
-	/* Append any binary data that we may have */
-	if (oscar_id) {
-		msg = g_string_append_len(msg, data->str, data->len);
-		msg = g_string_append(msg, "</BINARY>");
-	}
-	g_string_free(data, TRUE);
-
-	purple_debug_info("oscar", "sending direct IM %s using charset %i", msg->str, charset);
-
-	peer_odc_send_im(conn, msg->str, msg->len, charset,
-			imflags & PURPLE_MESSAGE_AUTO_RESP);
-	g_string_free(msg, TRUE);
-}
-
-int
-oscar_send_im(PurpleConnection *gc, PurpleMessage *msg)
-{
-	OscarData *od;
-	PurpleAccount *account;
-	PeerConnection *conn;
-	int ret;
-	char *tmp1, *tmp2;
-	gboolean is_sms, is_html;
-	const gchar *name, *message;
-	PurpleMessageFlags imflags;
-
-	name = purple_message_get_recipient(msg);
-	message = purple_message_get_contents(msg);
-	imflags = purple_message_get_flags(msg);
-	od = purple_connection_get_protocol_data(gc);
-	account = purple_connection_get_account(gc);
-	ret = 0;
-
-	is_sms = oscar_util_valid_name_sms(name);
-
-	if (od->icq && is_sms) {
-		/*
-		 * We're sending to a phone number and this is ICQ,
-		 * so send the message as an SMS using aim_icq_sendsms()
-		 */
-		int ret;
-		purple_debug_info("oscar", "Sending SMS to %s.\n", name);
-		ret = aim_icq_sendsms(od, name, message, purple_account_get_username(account));
-		return (ret >= 0 ? 1 : ret);
-	}
-
-	if (imflags & PURPLE_MESSAGE_AUTO_RESP)
-		tmp1 = oscar_util_format_string(message, name);
-	else
-		tmp1 = g_strdup(message);
-
-	conn = peer_connection_find_by_type(od, name, OSCAR_CAPABILITY_DIRECTIM);
-	if ((conn != NULL) && (conn->ready))
-	{
-		/* If we're directly connected, send a direct IM */
-		purple_debug_info("oscar", "Sending direct IM with flags %i\n", imflags);
-		purple_odc_send_im(conn, tmp1, imflags);
-	} else {
-		struct buddyinfo *bi;
-		struct aim_sendimext_args args;
-		PurpleIMConversation *im;
-		PurpleImage *img;
-		PurpleBuddy *buddy;
-
-		im = purple_conversations_find_im_with_account(name, account);
-
-		if (strstr(tmp1, "<img "))
-			purple_conversation_write_system_message(PURPLE_CONVERSATION(im),
-				_("Your IM Image was not sent. "
-				"You must be Direct Connected to send IM Images."),
-				PURPLE_MESSAGE_ERROR);
-
-		buddy = purple_blist_find_buddy(account, name);
-
-		bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, name));
-		if (!bi) {
-			bi = g_new0(struct buddyinfo, 1);
-			g_hash_table_insert(od->buddyinfo, g_strdup(purple_normalize(account, name)), bi);
-		}
-
-		args.flags = 0;
-
-		if (!is_sms && (!buddy || !PURPLE_BUDDY_IS_ONLINE(buddy)))
-			args.flags |= AIM_IMFLAGS_OFFLINE;
-
-		if (od->icq) {
-			args.features = features_icq;
-			args.featureslen = sizeof(features_icq);
-		} else {
-			args.features = features_aim;
-			args.featureslen = sizeof(features_aim);
-
-			if (imflags & PURPLE_MESSAGE_AUTO_RESP)
-				args.flags |= AIM_IMFLAGS_AWAY;
-		}
-
-		if (bi->ico_need) {
-			purple_debug_info("oscar",
-					   "Sending buddy icon request with message\n");
-			args.flags |= AIM_IMFLAGS_BUDDYREQ;
-			bi->ico_need = FALSE;
-		}
-
-		img = purple_buddy_icons_find_account_icon(account);
-		if (img) {
-			gconstpointer data = purple_image_get_data(img);
-			args.iconlen = purple_image_get_data_size(img);
-			args.iconsum = aimutil_iconsum(data, args.iconlen);
-			args.iconstamp = purple_buddy_icons_get_account_icon_timestamp(account);
-
-			if ((args.iconlen != bi->ico_me_len) || (args.iconsum != bi->ico_me_csum) || (args.iconstamp != bi->ico_me_time)) {
-				bi->ico_informed = FALSE;
-				bi->ico_sent     = FALSE;
-			}
-
-			/*
-			 * TODO:
-			 * For some reason sending our icon to people only works
-			 * when we're the ones who initiated the conversation.  If
-			 * the other person sends the first IM then they never get
-			 * the icon.  We should fix that.
-			 */
-			if (!bi->ico_informed) {
-				purple_debug_info("oscar",
-						   "Claiming to have a buddy icon\n");
-				args.flags |= AIM_IMFLAGS_HASICON;
-				bi->ico_me_len = args.iconlen;
-				bi->ico_me_csum = args.iconsum;
-				bi->ico_me_time = args.iconstamp;
-				bi->ico_informed = TRUE;
-			}
-
-			g_object_unref(img);
-		}
-
-		args.destbn = name;
-
-		if (oscar_util_valid_name_sms(name)) {
-			/* Messaging an SMS (mobile) user--strip HTML */
-			tmp2 = purple_markup_strip_html(tmp1);
-			is_html = FALSE;
-		} else {
-			/* ICQ 6 wants its HTML wrapped in these tags. Oblige it. */
-			tmp2 = g_strdup_printf("<HTML><BODY>%s</BODY></HTML>", tmp1);
-			is_html = TRUE;
-		}
-		g_free(tmp1);
-		tmp1 = tmp2;
-
-		args.msg = oscar_encode_im(tmp1, &args.msglen, &args.charset, NULL);
-		if (is_html && (args.msglen > MAXMSGLEN)) {
-			/* If the length was too long, try stripping the HTML and then running it back through
-			* purple_strdup_withhtml() and the encoding process. The result may be shorter. */
-			g_free((char *)args.msg);
-
-			tmp2 = purple_markup_strip_html(tmp1);
-			g_free(tmp1);
-
-			/* re-escape the entities */
-			tmp1 = g_markup_escape_text(tmp2, -1);
-			g_free(tmp2);
-
-			tmp2 = purple_strdup_withhtml(tmp1);
-			g_free(tmp1);
-			tmp1 = tmp2;
-
-			args.msg = oscar_encode_im(tmp1, &args.msglen, &args.charset, NULL);
-			purple_debug_info("oscar", "Sending %s as %s because the original was too long.\n",
-								  message, (char *)args.msg);
-		}
-
-		purple_debug_info("oscar", "Sending IM, charset=0x%04hx, length=%" G_GSIZE_FORMAT "\n", args.charset, args.msglen);
-		ret = aim_im_sendch1_ext(od, &args);
-		g_free((char *)args.msg);
-	}
-
-	g_free(tmp1);
-
-	if (ret >= 0)
-		return 1;
-
-	return ret;
-}
-
-/*
- * As of 26 June 2006, ICQ users can request AIM info from
- * everyone, and can request ICQ info from ICQ users, and
- * AIM users can only request AIM info.
- */
-void oscar_get_info(PurpleConnection *gc, const char *name) {
-	OscarData *od = purple_connection_get_protocol_data(gc);
-
-	if (od->icq && oscar_util_valid_name_icq(name))
-		aim_icq_getallinfo(od, name);
-	else
-		aim_locate_getinfoshort(od, name, 0x00000003);
-}
-
-void oscar_set_idle(PurpleConnection *gc, int time) {
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	aim_srv_setidle(od, time);
-}
-
-void
-oscar_set_info(PurpleConnection *gc, const char *rawinfo)
-{
-	PurpleAccount *account;
-	PurpleStatus *status;
-
-	account = purple_connection_get_account(gc);
-	status = purple_account_get_active_status(account);
-	oscar_set_info_and_status(account, TRUE, rawinfo, FALSE, status);
-}
-
-static guint32
-oscar_get_extended_status(PurpleConnection *gc)
-{
-	PurpleAccount *account;
-	PurpleStatus *status;
-	const gchar *status_id;
-	guint32 data = 0x00000000;
-
-	account = purple_connection_get_account(gc);
-	status = purple_account_get_active_status(account);
-	status_id = purple_status_get_id(status);
-
-	data |= AIM_ICQ_STATE_HIDEIP;
-	if (purple_account_get_bool(account, "web_aware", OSCAR_DEFAULT_WEB_AWARE))
-		data |= AIM_ICQ_STATE_WEBAWARE;
-
-	if (purple_strequal(status_id, OSCAR_STATUS_ID_AVAILABLE))
-		data |= AIM_ICQ_STATE_NORMAL;
-	else if (purple_strequal(status_id, OSCAR_STATUS_ID_AWAY))
-		data |= AIM_ICQ_STATE_AWAY;
-	else if (purple_strequal(status_id, OSCAR_STATUS_ID_DND))
-		data |= AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_DND | AIM_ICQ_STATE_BUSY;
-	else if (purple_strequal(status_id, OSCAR_STATUS_ID_NA))
-		data |= AIM_ICQ_STATE_OUT | AIM_ICQ_STATE_AWAY;
-	else if (purple_strequal(status_id, OSCAR_STATUS_ID_OCCUPIED))
-		data |= AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_BUSY;
-	else if (purple_strequal(status_id, OSCAR_STATUS_ID_FREE4CHAT))
-		data |= AIM_ICQ_STATE_CHAT;
-	else if (purple_strequal(status_id, OSCAR_STATUS_ID_INVISIBLE))
-		data |= AIM_ICQ_STATE_INVISIBLE;
-	else if (purple_strequal(status_id, OSCAR_STATUS_ID_EVIL))
-		data |= AIM_ICQ_STATE_EVIL;
-	else if (purple_strequal(status_id, OSCAR_STATUS_ID_DEPRESSION))
-		data |= AIM_ICQ_STATE_DEPRESSION;
-	else if (purple_strequal(status_id, OSCAR_STATUS_ID_ATWORK))
-		data |= AIM_ICQ_STATE_ATWORK;
-	else if (purple_strequal(status_id, OSCAR_STATUS_ID_ATHOME))
-		data |= AIM_ICQ_STATE_ATHOME;
-	else if (purple_strequal(status_id, OSCAR_STATUS_ID_LUNCH))
-		data |= AIM_ICQ_STATE_LUNCH;
-	else if (purple_strequal(status_id, OSCAR_STATUS_ID_CUSTOM))
-		data |= AIM_ICQ_STATE_OUT | AIM_ICQ_STATE_AWAY;
-
-	return data;
-}
-
-static void
-oscar_set_extended_status(PurpleConnection *gc)
-{
-	aim_srv_setextrainfo(purple_connection_get_protocol_data(gc), TRUE, oscar_get_extended_status(gc), FALSE, NULL, NULL);
-}
-
-static void
-oscar_set_info_and_status(PurpleAccount *account, gboolean setinfo, const char *rawinfo,
-						  gboolean setstatus, PurpleStatus *status)
-{
-	PurpleConnection *gc = purple_account_get_connection(account);
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	PurpleStatusType *status_type;
-	PurpleStatusPrimitive primitive;
-
-	char *info_encoding = NULL;
-	char *info = NULL;
-	gsize infolen = 0;
-
-	char *away_encoding = NULL;
-	char *away = NULL;
-	gsize awaylen = 0;
-
-	char *status_text = NULL;
-	const char *itmsurl = NULL;
-
-	status_type = purple_status_get_status_type(status);
-	primitive = purple_status_type_get_primitive(status_type);
-
-	if (!setinfo)
-	{
-		/* Do nothing! */
-	}
-	else if (od->rights.maxsiglen == 0)
-	{
-		purple_notify_warning(gc, NULL, _("Unable to set AIM profile."),
-							_("You have probably requested to set your "
-							  "profile before the login procedure completed.  "
-							  "Your profile remains unset; try setting it "
-							  "again when you are fully connected."),
-			purple_request_cpar_from_connection(gc));
-	}
-	else if (rawinfo != NULL)
-	{
-		char *htmlinfo = purple_strdup_withhtml(rawinfo);
-		info = oscar_encode_im(htmlinfo, &infolen, NULL, &info_encoding);
-		g_free(htmlinfo);
-
-		if (infolen > od->rights.maxsiglen)
-		{
-			gchar *errstr;
-			errstr = g_strdup_printf(dngettext(PACKAGE, "The maximum profile length of %d byte "
-									 "has been exceeded.  It has been truncated for you.",
-									 "The maximum profile length of %d bytes "
-									 "has been exceeded.  It has been truncated for you.",
-									 od->rights.maxsiglen), od->rights.maxsiglen);
-			purple_notify_warning(gc, NULL, _("Profile too long."),
-				errstr, purple_request_cpar_from_connection(gc));
-			g_free(errstr);
-		}
-	}
-
-	if (setstatus)
-	{
-		const char *status_html;
-
-		status_html = purple_status_get_attr_string(status, "message");
-
-		if (status_html == NULL || primitive == PURPLE_STATUS_AVAILABLE || primitive == PURPLE_STATUS_INVISIBLE)
-		{
-			/* This is needed for us to un-set any previous away message. */
-			away = g_strdup("");
-		}
-		else
-		{
-			gchar *linkified;
-
-			/* We do this for icq too so that they work for old third party clients */
-			linkified = purple_markup_linkify(status_html);
-			away = oscar_encode_im(linkified, &awaylen, NULL, &away_encoding);
-			g_free(linkified);
-
-			if (awaylen > od->rights.maxawaymsglen)
-			{
-				gchar *errstr;
-
-				errstr = g_strdup_printf(dngettext(PACKAGE, "The maximum away message length of %d byte "
-										 "has been exceeded.  It has been truncated for you.",
-										 "The maximum away message length of %d bytes "
-										 "has been exceeded.  It has been truncated for you.",
-										 od->rights.maxawaymsglen), od->rights.maxawaymsglen);
-				purple_notify_warning(gc, NULL,
-					_("Away message too long."), errstr,
-					purple_request_cpar_from_connection(gc));
-				g_free(errstr);
-			}
-		}
-	}
-
-	aim_locate_setprofile(od,
-			info_encoding, info, MIN(infolen, od->rights.maxsiglen),
-			away_encoding, away, MIN(awaylen, od->rights.maxawaymsglen));
-	g_free(info);
-	g_free(away);
-
-	if (setstatus)
-	{
-		const char *status_html;
-
-		status_html = purple_status_get_attr_string(status, "message");
-		if (status_html != NULL)
-		{
-			status_text = purple_markup_strip_html(status_html);
-			/* If the status_text is longer than 251 characters then truncate it */
-			if (strlen(status_text) > MAXAVAILMSGLEN)
-			{
-				char *tmp = g_utf8_find_prev_char(status_text, &status_text[MAXAVAILMSGLEN - 2]);
-				strcpy(tmp, "...");
-			}
-		}
-
-		itmsurl = purple_status_get_attr_string(status, "itmsurl");
-
-		aim_srv_setextrainfo(od, TRUE, oscar_get_extended_status(gc), TRUE, status_text, itmsurl);
-		g_free(status_text);
-	}
-}
-
-static void
-oscar_set_icq_permdeny(PurpleAccount *account)
-{
-	PurpleConnection *gc = purple_account_get_connection(account);
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	gboolean invisible = purple_account_is_status_active(account, OSCAR_STATUS_ID_INVISIBLE);
-
-	/*
-	 * For ICQ the permit/deny setting controls who can see you
-	 * online. Mimicking the official client's behavior, we use PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS
-	 * when our status is "invisible" and PURPLE_ACCOUNT_PRIVACY_DENY_USERS otherwise.
-	 * In the former case, we are visible only to buddies on our "permanently visible" list.
-	 * In the latter, we are invisible only to buddies on our "permanently invisible" list.
-	 */
-	aim_ssi_setpermdeny(od, invisible ? PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS : PURPLE_ACCOUNT_PRIVACY_DENY_USERS);
-}
-
-void
-oscar_set_status(PurpleAccount *account, PurpleStatus *status)
-{
-	PurpleConnection *pc;
-	OscarData *od;
-
-	purple_debug_info("oscar", "Set status to %s\n", purple_status_get_name(status));
-
-	/* Either setting a new status active or setting a status inactive.
-	 * (Only possible for independent status (i.e. X-Status moods.) */
-	if (!purple_status_is_active(status) && !purple_status_is_independent(status))
-		return;
-
-	if (!purple_account_is_connected(account))
-		return;
-
-	pc = purple_account_get_connection(account);
-	od = purple_connection_get_protocol_data(pc);
-
-	/* There's no need to do the stuff below for mood updates. */
-	if (purple_status_type_get_primitive(purple_status_get_status_type(status)) == PURPLE_STATUS_MOOD) {
-		aim_locate_setcaps(od, purple_caps);
-		return;
-	}
-
-	if (od->icq) {
-		/* Set visibility */
-		oscar_set_icq_permdeny(account);
-	}
-
-	/* Set the AIM-style away message for both AIM and ICQ accounts */
-	oscar_set_info_and_status(account, FALSE, NULL, TRUE, status);
-}
-
-void
-oscar_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group, const char *msg)
-{
-	OscarData *od;
-	PurpleAccount *account;
-	const char *bname, *gname;
-
-	od = purple_connection_get_protocol_data(gc);
-	account = purple_connection_get_account(gc);
-	bname = purple_buddy_get_name(buddy);
-	gname = purple_group_get_name(group);
-
-	if (!oscar_util_valid_name(bname)) {
-		gchar *buf;
-		buf = g_strdup_printf(_("Unable to add the buddy %s because the username is invalid.  Usernames must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers."), bname);
-		if (!purple_conversation_present_error(bname, account, buf))
-			purple_notify_error(gc, NULL, _("Unable to Add"), buf, purple_request_cpar_from_connection(gc));
-		g_free(buf);
-
-		/* Remove from local list */
-		purple_blist_remove_buddy(buddy);
-
-		return;
-	}
-
-	if (od->ssi.received_data) {
-		if (!aim_ssi_itemlist_finditem(&od->ssi.local, gname, bname, AIM_SSI_TYPE_BUDDY)) {
-			purple_debug_info("oscar",
-					   "ssi: adding buddy %s to group %s\n", bname, gname);
-			aim_ssi_addbuddy(od, bname, gname, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, 0);
-
-			/* Mobile users should always be online */
-			if (bname[0] == '+') {
-				purple_protocol_got_user_status(account, bname,
-						OSCAR_STATUS_ID_AVAILABLE, NULL);
-				purple_protocol_got_user_status(account, bname,
-						OSCAR_STATUS_ID_MOBILE, NULL);
-			}
-		} else if (aim_ssi_waitingforauth(&od->ssi.local,
-		                                  aim_ssi_itemlist_findparentname(&od->ssi.local, bname),
-		                                  bname)) {
-			/* Not authorized -- Re-request authorization */
-			oscar_auth_sendrequest(gc, bname, msg);
-		}
-	}
-
-	/* XXX - Should this be done from AIM accounts, as well? */
-	if (od->icq)
-		aim_icq_getalias(od, bname, FALSE, NULL);
-}
-
-void oscar_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) {
-	OscarData *od = purple_connection_get_protocol_data(gc);
-
-	if (od->ssi.received_data) {
-		const char *gname = purple_group_get_name(group);
-		const char *bname = purple_buddy_get_name(buddy);
-		purple_debug_info("oscar",
-				   "ssi: deleting buddy %s from group %s\n", bname, gname);
-		aim_ssi_delbuddy(od, bname, gname);
-	}
-}
-
-void oscar_move_buddy(PurpleConnection *gc, const char *name, const char *old_group, const char *new_group) {
-	OscarData *od = purple_connection_get_protocol_data(gc);
-
-	if (od->ssi.received_data && !purple_strequal(old_group, new_group)) {
-		purple_debug_info("oscar",
-				   "ssi: moving buddy %s from group %s to group %s\n", name, old_group, new_group);
-		aim_ssi_movebuddy(od, old_group, new_group, name);
-	}
-}
-
-void oscar_alias_buddy(PurpleConnection *gc, const char *name, const char *alias) {
-	OscarData *od = purple_connection_get_protocol_data(gc);
-
-	if (od->ssi.received_data) {
-		char *gname = aim_ssi_itemlist_findparentname(&od->ssi.local, name);
-		if (gname) {
-			purple_debug_info("oscar",
-					   "ssi: changing the alias for buddy %s to %s\n", name, alias ? alias : "(none)");
-			aim_ssi_aliasbuddy(od, gname, name, alias);
-		}
-	}
-}
-
-/*
- * FYI, the OSCAR SSI code removes empty groups automatically.
- */
-void oscar_rename_group(PurpleConnection *gc, const char *old_name, PurpleGroup *group, GList *moved_buddies) {
-	OscarData *od = purple_connection_get_protocol_data(gc);
-
-	if (od->ssi.received_data) {
-		const char *gname = purple_group_get_name(group);
-		if (aim_ssi_itemlist_finditem(&od->ssi.local, gname, NULL, AIM_SSI_TYPE_GROUP)) {
-			GList *cur, *groups = NULL;
-			PurpleAccount *account = purple_connection_get_account(gc);
-
-			/* Make a list of what the groups each buddy is in */
-			for (cur = moved_buddies; cur != NULL; cur = cur->next) {
-				PurpleBlistNode *node = cur->data;
-				/* node is PurpleBuddy, parent is a PurpleContact.
-				 * We must go two levels up to get the Group */
-				groups = g_list_append(groups,
-						purple_buddy_get_group((PurpleBuddy*)node));
-			}
-
-			purple_account_remove_buddies(account, moved_buddies, groups);
-			purple_account_add_buddies(account, moved_buddies, NULL);
-			g_list_free(groups);
-			purple_debug_info("oscar",
-					   "ssi: moved all buddies from group %s to %s\n", old_name, gname);
-		} else {
-			aim_ssi_rename_group(od, old_name, gname);
-			purple_debug_info("oscar",
-					   "ssi: renamed group %s to %s\n", old_name, gname);
-		}
-	}
-}
-
-void oscar_remove_group(PurpleConnection *gc, PurpleGroup *group)
-{
-	aim_ssi_delgroup(purple_connection_get_protocol_data(gc), purple_group_get_name(group));
-}
-
-static gboolean purple_ssi_rerequestdata(gpointer data) {
-	OscarData *od = data;
-
-	aim_ssi_reqdata(od);
-
-	return TRUE;
-}
-
-static int purple_ssi_parseerr(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	PurpleConnection *gc = od->gc;
-	va_list ap;
-	guint16 reason;
-
-	va_start(ap, fr);
-	reason = (guint16)va_arg(ap, unsigned int);
-	va_end(ap);
-
-	purple_debug_error("oscar", "ssi: SNAC error %hu\n", reason);
-
-	if (reason == 0x0005) {
-		if (od->getblisttimer > 0)
-			g_source_remove(od->getblisttimer);
-		else
-			/* We only show this error the first time it happens */
-			purple_notify_error(gc, NULL,
-					_("Unable to Retrieve Buddy List"),
-					_("The AIM servers were temporarily unable to send "
-					"your buddy list.  Your buddy list is not lost, and "
-					"will probably become available in a few minutes."),
-					purple_request_cpar_from_connection(gc));
-		od->getblisttimer = g_timeout_add_seconds(30, purple_ssi_rerequestdata, od);
-		return 1;
-	}
-
-	return 1;
-}
-
-static int purple_ssi_parserights(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	int i;
-	va_list ap;
-	int numtypes;
-	guint16 *maxitems;
-	GString *msg;
-
-	va_start(ap, fr);
-	numtypes = va_arg(ap, int);
-	maxitems = va_arg(ap, guint16 *);
-	va_end(ap);
-
-	msg = g_string_new("ssi rights:");
-	for (i=0; i<numtypes; i++)
-		g_string_append_printf(msg, " max type 0x%04x=%hd,", i, maxitems[i]);
-	g_string_append(msg, "\n");
-	purple_debug_misc("oscar", "%s", msg->str);
-	g_string_free(msg, TRUE);
-
-	if (numtypes >= 0)
-		od->rights.maxbuddies = maxitems[0];
-	if (numtypes >= 1)
-		od->rights.maxgroups = maxitems[1];
-	if (numtypes >= 2)
-		od->rights.maxpermits = maxitems[2];
-	if (numtypes >= 3)
-		od->rights.maxdenies = maxitems[3];
-
-	return 1;
-}
-
-static int purple_ssi_parselist(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
-{
-	PurpleConnection *gc;
-	PurpleAccount *account;
-	PurpleGroup *g;
-	PurpleBuddy *b;
-	GSList *cur, *next, *buddies;
-	struct aim_ssi_item *curitem;
-	guint32 tmp;
-	PurpleImage *img;
-	va_list ap;
-	guint16 deny_entry_type = aim_ssi_getdenyentrytype(od);
-
-	gc = od->gc;
-	od = purple_connection_get_protocol_data(gc);
-	account = purple_connection_get_account(gc);
-
-	va_start(ap, fr);
-	va_arg(ap, int); /* guint16 fmtver */
-	va_arg(ap, int); /* guint16 numitems */
-	va_arg(ap, guint32); /* timestamp */
-	va_end(ap);
-
-	/* Don't attempt to re-request our buddy list later */
-	if (od->getblisttimer != 0) {
-		g_source_remove(od->getblisttimer);
-		od->getblisttimer = 0;
-	}
-
-	purple_debug_info("oscar", "ssi: syncing local list and server list\n");
-
-	/*** Begin code for pruning buddies from local list if they're not in server list ***/
-
-	/* Buddies */
-	cur = NULL;
-	for (buddies = purple_blist_find_buddies(account, NULL);
-			buddies;
-			buddies = g_slist_delete_link(buddies, buddies))
-	{
-		PurpleGroup *g;
-		const char *gname;
-		const char *bname;
-
-		b = buddies->data;
-		g = purple_buddy_get_group(b);
-		gname = purple_group_get_name(g);
-		bname = purple_buddy_get_name(b);
-
-		if (aim_ssi_itemlist_exists(&od->ssi.local, bname)) {
-			/* If the buddy is an ICQ user then load his nickname */
-			const char *servernick = purple_blist_node_get_string((PurpleBlistNode*)b, "servernick");
-			char *alias;
-			const char *balias;
-			if (servernick)
-				purple_serv_got_alias(gc, bname, servernick);
-
-			/* Store local alias on server */
-			alias = aim_ssi_getalias(&od->ssi.local, gname, bname);
-			balias = purple_buddy_get_local_alias(b);
-			if (!alias && balias && *balias)
-				aim_ssi_aliasbuddy(od, gname, bname, balias);
-			g_free(alias);
-		} else {
-			purple_debug_info("oscar",
-					"ssi: removing buddy %s from local list\n", bname);
-			/* Queue the buddy for removal from the local list */
-			cur = g_slist_prepend(cur, b);
-		}
-	}
-	g_slist_free_full(cur, (GDestroyNotify)purple_blist_remove_buddy);
-
-	/* Permit list (ICQ doesn't have one) */
-	if (!od->icq) {
-		next = purple_account_privacy_get_permitted(account);
-		while (next != NULL) {
-			cur = next;
-			next = next->next;
-			if (!aim_ssi_itemlist_finditem(&od->ssi.local, NULL, cur->data, AIM_SSI_TYPE_PERMIT)) {
-				purple_debug_info("oscar",
-						"ssi: removing permit %s from local list\n", (const char *)cur->data);
-				purple_account_privacy_permit_remove(account, cur->data, TRUE);
-			}
-		}
-	}
-
-	/* Deny list */
-	next = purple_account_privacy_get_denied(account);
-	while (next != NULL) {
-		cur = next;
-		next = next->next;
-		if (!aim_ssi_itemlist_finditem(&od->ssi.local, NULL, cur->data, deny_entry_type)) {
-			purple_debug_info("oscar",
-					"ssi: removing deny %s from local list\n", (const char *)cur->data);
-			purple_account_privacy_deny_remove(account, cur->data, TRUE);
-		}
-	}
-
-	/* Presence settings (idle time visibility) */
-	tmp = aim_ssi_getpresence(&od->ssi.local);
-	if (tmp != 0xFFFFFFFF) {
-		const char *idle_reporting_pref;
-		gboolean report_idle;
-
-		idle_reporting_pref = purple_prefs_get_string("/purple/away/idle_reporting");
-		report_idle = !purple_strequal(idle_reporting_pref, "none");
-
-		if (report_idle)
-			aim_ssi_setpresence(od, tmp | AIM_SSI_PRESENCE_FLAG_SHOWIDLE);
-		else
-			aim_ssi_setpresence(od, tmp & ~AIM_SSI_PRESENCE_FLAG_SHOWIDLE);
-	}
-
-	/*** End code for pruning buddies from local list ***/
-
-	/*** Begin code for adding from server list to local list ***/
-
-	for (curitem=od->ssi.local.data; curitem; curitem=curitem->next) {
-		if (curitem->name && !g_utf8_validate(curitem->name, -1, NULL)) {
-			/* Got node with invalid UTF-8 in the name.  Skip it. */
-			purple_debug_warning("oscar", "ssi: server list contains item of "
-					"type 0x%04hx with a non-utf8 name\n", curitem->type);
-			continue;
-		}
-
-		switch (curitem->type) {
-			case AIM_SSI_TYPE_BUDDY: { /* Buddy */
-				if (curitem->name) {
-					struct aim_ssi_item *groupitem;
-					char *gname, *gname_utf8, *alias, *alias_utf8;
-
-					groupitem = aim_ssi_itemlist_find(&od->ssi.local, curitem->gid, 0x0000);
-					gname = groupitem ? groupitem->name : NULL;
-					gname_utf8 = oscar_utf8_try_convert(account, od, gname);
-
-					g = purple_blist_find_group(gname_utf8);
-					if (g == NULL) {
-						g = purple_group_new(gname_utf8);
-						purple_blist_add_group(g, NULL);
-					}
-
-					alias = aim_ssi_getalias_from_item(curitem);
-					alias_utf8 = oscar_utf8_try_convert(account, od, alias);
-
-					b = purple_blist_find_buddy_in_group(account, curitem->name, g);
-					if (b) {
-						/* Get server stored alias */
-						purple_buddy_set_local_alias(b, alias_utf8);
-					} else {
-						b = purple_buddy_new(account, curitem->name, alias_utf8);
-
-						purple_debug_info("oscar",
-								   "ssi: adding buddy %s to group %s to local list\n", curitem->name, gname);
-						purple_blist_add_buddy(b, NULL, g, NULL);
-					}
-
-					/* Mobile users should always be online */
-					if (curitem->name[0] == '+') {
-						purple_protocol_got_user_status(account,
-								purple_buddy_get_name(b),
-								OSCAR_STATUS_ID_AVAILABLE, NULL);
-						purple_protocol_got_user_status(account,
-								purple_buddy_get_name(b),
-								OSCAR_STATUS_ID_MOBILE, NULL);
-					}
-
-					g_free(gname_utf8);
-					g_free(alias);
-					g_free(alias_utf8);
-				}
-			} break;
-
-			case AIM_SSI_TYPE_GROUP: { /* Group */
-				if (curitem->name != NULL && purple_blist_find_group(curitem->name) == NULL) {
-					g = purple_group_new(curitem->name);
-					purple_blist_add_group(g, NULL);
-				}
-			} break;
-
-			case AIM_SSI_TYPE_PERMIT: { /* Permit buddy (unless we're on ICQ) */
-				if (!od->icq && curitem->name) {
-					cur = purple_account_privacy_get_permitted(account);
-					if (!g_slist_find_custom(cur, curitem->name, (GCompareFunc)oscar_util_name_compare)) {
-						purple_debug_info("oscar",
-								   "ssi: adding permit buddy %s to local list\n", curitem->name);
-						purple_account_privacy_permit_add(account, curitem->name, TRUE);
-					}
-				}
-			} break;
-
-			case AIM_SSI_TYPE_ICQDENY:
-			case AIM_SSI_TYPE_DENY: { /* Deny buddy */
-				if (curitem->type == deny_entry_type && curitem->name) {
-					cur = purple_account_privacy_get_denied(account);
-					if (!g_slist_find_custom(cur, curitem->name, (GCompareFunc)oscar_util_name_compare)) {
-						purple_debug_info("oscar",
-								   "ssi: adding deny buddy %s to local list\n", curitem->name);
-						purple_account_privacy_deny_add(account, curitem->name, TRUE);
-					}
-				}
-			} break;
-
-			case AIM_SSI_TYPE_PDINFO: { /* Permit/deny setting */
-				/*
-				 * We don't inherit the permit/deny setting from the server
-				 * for ICQ because, for ICQ, this setting controls who can
-				 * see your online status when you are invisible.  Thus it is
-				 * a part of your status and not really related to blocking.
-				 */
-				if (!od->icq && curitem->data) {
-					guint8 perm_deny = aim_ssi_getpermdeny(&od->ssi.local);
-					if (perm_deny != 0 && perm_deny != purple_account_get_privacy_type(account))
-					{
-						purple_debug_info("oscar",
-								   "ssi: changing permdeny from %d to %u\n", purple_account_get_privacy_type(account), (guint)perm_deny);
-						purple_account_set_privacy_type(account, perm_deny);
-					}
-				}
-			} break;
-
-			case AIM_SSI_TYPE_PRESENCEPREFS: { /* Presence setting */
-				/* We don't want to change Purple's setting because it applies to all accounts */
-			} break;
-		} /* End of switch on curitem->type */
-	} /* End of for loop */
-
-	/*** End code for adding from server list to local list ***/
-
-	if (od->icq) {
-		oscar_set_icq_permdeny(account);
-	} else {
-		oscar_set_aim_permdeny(gc);
-	}
-
-	/* Activate SSI */
-	/* Sending the enable causes other people to be able to see you, and you to see them */
-	/* Make sure your privacy setting/invisibility is set how you want it before this! */
-	purple_debug_info("oscar",
-			   "ssi: activating server-stored buddy list\n");
-	aim_ssi_enable(od);
-
-	/*
-	 * Make sure our server-stored icon is updated correctly in
-	 * the event that the local user set a new icon while this
-	 * account was offline.
-	 */
-	img = purple_buddy_icons_find_account_icon(account);
-	oscar_set_icon(gc, img);
-	g_object_unref(img);
-
-	/*
-	 * If we've already received our bos rights then we're not waiting on
-	 * anything else, so send the server clientready.
-	 */
-	if (od->bos.have_rights) {
-		aim_srv_clientready(od, conn);
-
-		/* Request offline messages for AIM and ICQ */
-		aim_im_reqofflinemsgs(od);
-
-		purple_connection_set_state(gc, PURPLE_CONNECTION_CONNECTED);
-	}
-
-	return 1;
-}
-
-static int purple_ssi_parseack(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	PurpleConnection *gc = od->gc;
-	va_list ap;
-	struct aim_ssi_tmp *retval;
-
-	va_start(ap, fr);
-	retval = va_arg(ap, struct aim_ssi_tmp *);
-	va_end(ap);
-
-	while (retval) {
-		purple_debug_misc("oscar",
-				   "ssi: status is 0x%04hx for a 0x%04hx action with name %s\n", retval->ack,  retval->action, retval->item ? (retval->item->name ? retval->item->name : "no name") : "no item");
-
-		if (retval->ack != 0xffff)
-		switch (retval->ack) {
-			case 0x0000: { /* added successfully */
-			} break;
-
-			case 0x000c: { /* you are over the limit, the cheat is to the limit, come on fhqwhgads */
-				gchar *buf;
-				buf = g_strdup_printf(_("Unable to add the buddy %s because you have too many buddies in your buddy list.  Please remove one and try again."), (retval->name ? retval->name : _("(no name)")));
-				if ((retval->name != NULL) && !purple_conversation_present_error(retval->name, purple_connection_get_account(gc), buf))
-					purple_notify_error(gc, NULL, _("Unable to Add"), buf, purple_request_cpar_from_connection(gc));
-				g_free(buf);
-			} break;
-
-			case 0x000e: { /* buddy requires authorization */
-				if ((retval->action == SNAC_SUBTYPE_FEEDBAG_ADD) && (retval->name))
-					oscar_auth_sendrequest(gc, retval->name, NULL);
-			} break;
-
-			default: { /* La la la */
-				gchar *buf;
-				purple_debug_error("oscar", "ssi: Action 0x%04hx was unsuccessful with error 0x%04hx\n", retval->action, retval->ack);
-				buf = g_strdup_printf(_("Unable to add the buddy %s for an unknown reason."),
-						(retval->name ? retval->name : _("(no name)")));
-				if ((retval->name != NULL) && !purple_conversation_present_error(retval->name, purple_connection_get_account(gc), buf))
-					purple_notify_error(gc, NULL, _("Unable to Add"), buf, purple_request_cpar_from_connection(gc));
-				g_free(buf);
-			} break;
-		}
-
-		retval = retval->next;
-	}
-
-	return 1;
-}
-
-static int
-purple_ssi_parseaddmod(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
-{
-	PurpleConnection *gc;
-	PurpleAccount *account;
-	char *gname, *gname_utf8, *alias, *alias_utf8;
-	PurpleBuddy *b;
-	PurpleGroup *g;
-	struct aim_ssi_item *ssi_item;
-	va_list ap;
-	guint16 snac_subtype, type;
-	const char *name;
-
-	gc = od->gc;
-	account = purple_connection_get_account(gc);
-
-	va_start(ap, fr);
-	snac_subtype = (guint16)va_arg(ap, int);
-	type = (guint16)va_arg(ap, int);
-	name = va_arg(ap, char *);
-	va_end(ap);
-
-	if ((type != 0x0000) || (name == NULL))
-		return 1;
-
-	gname = aim_ssi_itemlist_findparentname(&od->ssi.local, name);
-	gname_utf8 = gname ? oscar_utf8_try_convert(account, od, gname) : NULL;
-
-	alias = aim_ssi_getalias(&od->ssi.local, gname, name);
-	alias_utf8 = oscar_utf8_try_convert(account, od, alias);
-	g_free(alias);
-
-	b = purple_blist_find_buddy(account, name);
-	if (b) {
-		/*
-		 * You're logged in somewhere else and you aliased one
-		 * of your buddies, so update our local buddy list with
-		 * the person's new alias.
-		 */
-		purple_buddy_set_local_alias(b, alias_utf8);
-	} else if (snac_subtype == 0x0008) {
-		/*
-		 * You're logged in somewhere else and you added a buddy to
-		 * your server list, so add them to your local buddy list.
-		 */
-		b = purple_buddy_new(account, name, alias_utf8);
-
-		if (!(g = purple_blist_find_group(gname_utf8))) {
-			g = purple_group_new(gname_utf8);
-			purple_blist_add_group(g, NULL);
-		}
-
-		purple_debug_info("oscar", "ssi: adding buddy %s to group %s to"
-			" local list", name, gname_utf8 ? gname_utf8 : "(default)");
-		purple_blist_add_buddy(b, NULL, g, NULL);
-
-		/* Mobile users should always be online */
-		if (name[0] == '+') {
-			purple_protocol_got_user_status(account,
-					name, OSCAR_STATUS_ID_AVAILABLE, NULL);
-			purple_protocol_got_user_status(account,
-					name, OSCAR_STATUS_ID_MOBILE, NULL);
-		}
-
-	}
-
-	ssi_item = aim_ssi_itemlist_finditem(&od->ssi.local,
-			gname, name, AIM_SSI_TYPE_BUDDY);
-	if (ssi_item == NULL)
-	{
-		purple_debug_error("oscar", "purple_ssi_parseaddmod: "
-				"Could not find ssi item for oncoming buddy %s, "
-				"group %s\n", name, gname);
-	}
-
-	g_free(gname_utf8);
-	g_free(alias_utf8);
-
-	return 1;
-}
-
-static int purple_ssi_authgiven(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	PurpleConnection *gc = od->gc;
-	va_list ap;
-	char *bn;
-	gchar *dialog_msg, *nombre;
-	struct name_data *data;
-	PurpleBuddy *buddy;
-
-	va_start(ap, fr);
-	bn = va_arg(ap, char *);
-	va_arg(ap, char *); /* msg */
-	va_end(ap);
-
-	purple_debug_info("oscar",
-			   "ssi: %s has given you permission to add him to your buddy list\n", bn);
-
-	buddy = purple_blist_find_buddy(purple_connection_get_account(gc), bn);
-	if (buddy && (purple_buddy_get_alias_only(buddy)))
-		nombre = g_strdup_printf("%s (%s)", bn, purple_buddy_get_alias_only(buddy));
-	else
-		nombre = g_strdup(bn);
-
-	dialog_msg = g_strdup_printf(_("The user %s has given you permission to add him or her to your buddy list.  Do you want to add this user?"), nombre);
-	g_free(nombre);
-
-	data = g_new(struct name_data, 1);
-	data->gc = gc;
-	data->name = g_strdup(bn);
-	data->nick = (buddy ? g_strdup(purple_buddy_get_alias_only(buddy)) : NULL);
-
-	purple_request_yes_no(gc, NULL, _("Authorization Given"), dialog_msg,
-						PURPLE_DEFAULT_ACTION_NONE,
-						purple_request_cpar_from_connection(gc),
-						data,
-						G_CALLBACK(purple_icq_buddyadd),
-						G_CALLBACK(oscar_free_name_data));
-	g_free(dialog_msg);
-
-	return 1;
-}
-
-static int purple_ssi_authrequest(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
-{
-	va_list ap;
-	const char *bn;
-	char *msg;
-
-	va_start(ap, fr);
-	bn = va_arg(ap, const char *);
-	msg = va_arg(ap, char *);
-	va_end(ap);
-
-	purple_debug_info("oscar",
-			"ssi: received authorization request from %s\n", bn);
-
-	if (!msg) {
-		purple_debug_warning("oscar", "Received auth request from %s with "
-				"empty message\n", bn);
-	} else if (!g_utf8_validate(msg, -1, NULL)) {
-		purple_debug_warning("oscar", "Received auth request from %s with "
-				"invalid UTF-8 message\n", bn);
-		msg = NULL;
-	}
-
-	aim_icq_getalias(od, bn, TRUE, msg);
-	return 1;
-}
-
-static int purple_ssi_authreply(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	PurpleConnection *gc = od->gc;
-	va_list ap;
-	char *bn, *msg;
-	gchar *dialog_msg, *nombre;
-	guint8 reply;
-	PurpleBuddy *buddy;
-
-	va_start(ap, fr);
-	bn = va_arg(ap, char *);
-	reply = (guint8)va_arg(ap, int);
-	msg = va_arg(ap, char *);
-	va_end(ap);
-
-	purple_debug_info("oscar",
-			   "ssi: received authorization reply from %s.  Reply is 0x%02hx\n", bn, (guint16)reply);
-
-	buddy = purple_blist_find_buddy(purple_connection_get_account(gc), bn);
-	if (buddy && (purple_buddy_get_alias_only(buddy)))
-		nombre = g_strdup_printf("%s (%s)", bn, purple_buddy_get_alias_only(buddy));
-	else
-		nombre = g_strdup(bn);
-
-	if (reply) {
-		/* Granted */
-		dialog_msg = g_strdup_printf(_("The user %s has granted your request to add them to your buddy list."), nombre);
-		purple_notify_info(gc, NULL, _("Authorization Granted"),
-			dialog_msg, purple_request_cpar_from_connection(gc));
-	} else {
-		/* Denied */
-		dialog_msg = g_strdup_printf(_("The user %s has denied your request to add them to your buddy list for the following reason:\n%s"), nombre, msg ? msg : _("No reason given."));
-		purple_notify_info(gc, NULL, _("Authorization Denied"),
-			dialog_msg, purple_request_cpar_from_connection(gc));
-	}
-	g_free(dialog_msg);
-	g_free(nombre);
-
-	return 1;
-}
-
-static int purple_ssi_gotadded(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	PurpleConnection *gc = od->gc;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	va_list ap;
-	char *bn;
-	PurpleBuddy *buddy;
-
-	va_start(ap, fr);
-	bn = va_arg(ap, char *);
-	va_end(ap);
-
-	buddy = purple_blist_find_buddy(account, bn);
-	purple_debug_info("oscar", "ssi: %s added you to their buddy list\n", bn);
-	purple_account_notify_added(account, bn, NULL,
-			(buddy ? purple_buddy_get_alias_only(buddy) : NULL), NULL);
-
-	return 1;
-}
-
-GList *oscar_chat_info(PurpleConnection *gc) {
-	GList *m = NULL;
-	PurpleProtocolChatEntry *pce;
-
-	pce = g_new0(PurpleProtocolChatEntry, 1);
-	pce->label = _("_Room:");
-	pce->identifier = "room";
-	pce->required = TRUE;
-	m = g_list_append(m, pce);
-
-	pce = g_new0(PurpleProtocolChatEntry, 1);
-	pce->label = _("_Exchange:");
-	pce->identifier = "exchange";
-	pce->required = TRUE;
-	pce->is_int = TRUE;
-	pce->min = 4;
-	pce->max = 20;
-	m = g_list_append(m, pce);
-
-	return m;
-}
-
-GHashTable *oscar_chat_info_defaults(PurpleConnection *gc, const char *chat_name)
-{
-	GHashTable *defaults;
-
-	defaults = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
-
-	if (chat_name != NULL)
-		g_hash_table_insert(defaults, "room", g_strdup(chat_name));
-	g_hash_table_insert(defaults, "exchange", g_strdup("4"));
-
-	return defaults;
-}
-
-char *
-oscar_get_chat_name(GHashTable *data)
-{
-	return g_strdup(g_hash_table_lookup(data, "room"));
-}
-
-void
-oscar_join_chat(PurpleConnection *gc, GHashTable *data)
-{
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	FlapConnection *conn;
-	char *name, *exchange;
-	int exchange_int;
-
-	name = g_hash_table_lookup(data, "room");
-	exchange = g_hash_table_lookup(data, "exchange");
-
-	g_return_if_fail(name != NULL && *name != '\0');
-	g_return_if_fail(exchange != NULL);
-
-	errno = 0;
-	exchange_int = strtol(exchange, NULL, 10);
-	g_return_if_fail(errno == 0);
-
-	purple_debug_info("oscar", "Attempting to join chat room %s.\n", name);
-
-	if ((conn = flap_connection_getbytype(od, SNAC_FAMILY_CHATNAV)))
-	{
-		purple_debug_info("oscar", "chatnav exists, creating room\n");
-		aim_chatnav_createroom(od, conn, name, exchange_int);
-	} else {
-		/* this gets tricky */
-		struct create_room *cr = g_new0(struct create_room, 1);
-		purple_debug_info("oscar", "chatnav does not exist, opening chatnav\n");
-		cr->exchange = exchange_int;
-		cr->name = g_strdup(name);
-		od->create_rooms = g_slist_prepend(od->create_rooms, cr);
-		aim_srv_requestnew(od, SNAC_FAMILY_CHATNAV);
-	}
-}
-
-void
-oscar_chat_invite(PurpleConnection *gc, int id, const char *message, const char *name)
-{
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	struct chat_connection *ccon = find_oscar_chat(gc, id);
-
-	if (ccon == NULL)
-		return;
-
-	aim_im_sendch2_chatinvite(od, name, message ? message : "",
-			ccon->exchange, ccon->name, 0x0);
-}
-
-void
-oscar_chat_leave(PurpleConnection *gc, int id)
-{
-	PurpleChatConversation *conv;
-	struct chat_connection *cc;
-
-	conv = purple_conversations_find_chat(gc, id);
-
-	g_return_if_fail(conv != NULL);
-
-	purple_debug_info("oscar", "Leaving chat room %s\n",
-			purple_conversation_get_name(PURPLE_CONVERSATION(conv)));
-
-	cc = find_oscar_chat(gc, purple_chat_conversation_get_id(conv));
-	flap_connection_schedule_destroy(cc->conn, OSCAR_DISCONNECT_DONE, NULL);
-	oscar_chat_kill(gc, cc);
-}
-
-int oscar_send_chat(PurpleConnection *gc, int id, PurpleMessage *msg)
-{
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	PurpleChatConversation *conv = NULL;
-	struct chat_connection *c = NULL;
-	char *buf, *buf2, *buf3;
-	guint16 charset;
-	char *charsetstr;
-	gsize len;
-	const gchar *message = purple_message_get_contents(msg);
-
-	if (!(conv = purple_conversations_find_chat(gc, id)))
-		return -EINVAL;
-
-	if (!(c = find_oscar_chat_by_conv(gc, conv)))
-		return -EINVAL;
-
-	buf = purple_strdup_withhtml(message);
-
-	if (strstr(buf, "<img ")) {
-		purple_conversation_write_system_message(PURPLE_CONVERSATION(conv),
-			_("Your IM Image was not sent. "
-			  "You cannot send IM Images in AIM chats."),
-			PURPLE_MESSAGE_ERROR);
-	}
-
-	buf2 = oscar_encode_im(buf, &len, &charset, &charsetstr);
-	/*
-	 * Evan S. suggested that maxvis really does mean "number of
-	 * visible characters" and not "number of bytes"
-	 */
-	if ((len > c->maxlen) || (len > c->maxvis)) {
-		/* If the length was too long, try stripping the HTML and then running it back through
-		 * purple_strdup_withhtml() and the encoding process. The result may be shorter. */
-		g_free(buf2);
-
-		buf3 = purple_markup_strip_html(buf);
-		g_free(buf);
-
-		buf = purple_strdup_withhtml(buf3);
-		g_free(buf3);
-
-		buf2 = oscar_encode_im(buf, &len, &charset, &charsetstr);
-
-		if ((len > c->maxlen) || (len > c->maxvis)) {
-			purple_debug_warning("oscar",
-					"Could not send %s because (%" G_GSIZE_FORMAT " > maxlen %i) or (%" G_GSIZE_FORMAT " > maxvis %i)\n",
-					buf2, len, c->maxlen, len, c->maxvis);
-			g_free(buf);
-			g_free(buf2);
-			return -E2BIG;
-		}
-
-		purple_debug_info("oscar", "Sending %s as %s because the original was too long.\n",
-				message, buf2);
-	}
-
-	aim_chat_send_im(od, c->conn, 0, buf2, len, charsetstr, "en");
-	g_free(buf2);
-	g_free(buf);
-
-	return 0;
-}
-
-PurpleMood* oscar_get_purple_moods(PurpleAccount *account)
-{
-	return icq_get_purple_moods(account);
-}
-
-const char *oscar_list_icon_icq(PurpleAccount *a, PurpleBuddy *b)
-{
-	const char *name = b ? purple_buddy_get_name(b) : NULL;
-	if (name && !oscar_util_valid_name_sms(name) && oscar_util_valid_name_icq(name))
-		return "icq";
-
-	return "icq";
-}
-
-const char *oscar_list_icon_aim(PurpleAccount *a, PurpleBuddy *b)
-{
-	const char *name = b ? purple_buddy_get_name(b) : NULL;
-	if (name && !oscar_util_valid_name_sms(name) && oscar_util_valid_name_icq(name))
-		return "icq";
-
-	return "aim";
-}
-
-const char *oscar_list_emblem(PurpleBuddy *b)
-{
-	PurpleConnection *gc = NULL;
-	OscarData *od = NULL;
-	PurpleAccount *account = NULL;
-	PurplePresence *presence;
-	aim_userinfo_t *userinfo = NULL;
-	const char *name;
-
-	account = purple_buddy_get_account(b);
-	name = purple_buddy_get_name(b);
-	if (account != NULL)
-		gc = purple_account_get_connection(account);
-	if (gc != NULL)
-		od = purple_connection_get_protocol_data(gc);
-	if (od != NULL)
-		userinfo = aim_locate_finduserinfo(od, name);
-
-	presence = purple_buddy_get_presence(b);
-
-	if (purple_presence_is_online(presence) == FALSE) {
-		char *gname;
-		if ((name) && (od) && (od->ssi.received_data) &&
-			(gname = aim_ssi_itemlist_findparentname(&od->ssi.local, name)) &&
-			(aim_ssi_waitingforauth(&od->ssi.local, gname, name))) {
-			return "not-authorized";
-		}
-	}
-
-	if (userinfo != NULL ) {
-		if (userinfo->flags & AIM_FLAG_ADMINISTRATOR)
-			return "admin";
-		if (userinfo->flags & AIM_FLAG_ACTIVEBUDDY)
-			return "bot";
-		if (userinfo->capabilities & OSCAR_CAPABILITY_SECUREIM)
-			return "secure";
-		if (userinfo->icqinfo.status & AIM_ICQ_STATE_BIRTHDAY)
-			return "birthday";
-
-		/* Make the mood icon override anything below this. */
-		if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_MOOD))
-			return NULL;
-
-		if (userinfo->capabilities & OSCAR_CAPABILITY_HIPTOP)
-			return "hiptop";
-	}
-	return NULL;
-}
-
-void oscar_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full)
-{
-	PurpleConnection *gc;
-	PurpleAccount *account;
-	OscarData *od;
-	aim_userinfo_t *userinfo;
-
-	if (!PURPLE_BUDDY_IS_ONLINE(b))
-		return;
-
-	account = purple_buddy_get_account(b);
-	gc = purple_account_get_connection(account);
-	od = purple_connection_get_protocol_data(gc);
-	userinfo = aim_locate_finduserinfo(od, purple_buddy_get_name(b));
-
-	oscar_user_info_append_status(gc, user_info, b, userinfo, /* use_html_status */ FALSE);
-
-	if (full)
-		oscar_user_info_append_extra_info(gc, user_info, b, userinfo);
-}
-
-char *oscar_status_text(PurpleBuddy *b)
-{
-	PurpleConnection *gc;
-	PurpleAccount *account;
-	OscarData *od;
-	PurplePresence *presence;
-	PurpleStatus *status;
-	const char *message;
-	gchar *ret = NULL;
-
-	gc = purple_account_get_connection(purple_buddy_get_account(b));
-	account = purple_connection_get_account(gc);
-	od = purple_connection_get_protocol_data(gc);
-	presence = purple_buddy_get_presence(b);
-	status = purple_presence_get_active_status(presence);
-
-	if ((od != NULL) && !purple_presence_is_online(presence))
-	{
-		const char *name = purple_buddy_get_name(b);
-		char *gname = aim_ssi_itemlist_findparentname(&od->ssi.local, name);
-		if (aim_ssi_waitingforauth(&od->ssi.local, gname, name))
-			ret = g_strdup(_("Not Authorized"));
-		else
-			ret = g_strdup(_("Offline"));
-	}
-	else
-	{
-		message = purple_status_get_attr_string(status, "message");
-		if (message != NULL)
-		{
-			gchar *tmp = oscar_util_format_string(message, purple_account_get_username(account));
-			ret = purple_markup_escape_text(tmp, -1);
-			g_free(tmp);
-		}
-		else if (purple_status_is_available(status))
-		{
-			/* Don't show "Available" as status message in case buddy doesn't have a status message */
-		}
-		else
-		{
-			ret = g_strdup(purple_status_get_name(status));
-		}
-	}
-
-	return ret;
-}
-
-void oscar_set_aim_permdeny(PurpleConnection *gc) {
-	PurpleAccount *account = purple_connection_get_account(gc);
-	OscarData *od = purple_connection_get_protocol_data(gc);
-
-	/*
-	 * Conveniently there is a one-to-one mapping between the
-	 * values of libpurple's PurplePrivacyType and the values used
-	 * by the oscar protocol.
-	 */
-	aim_ssi_setpermdeny(od, purple_account_get_privacy_type(account));
-}
-
-void oscar_add_permit(PurpleConnection *gc, const char *who) {
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	purple_debug_info("oscar", "ssi: About to add a permit\n");
-	aim_ssi_add_to_private_list(od, who, AIM_SSI_TYPE_PERMIT);
-}
-
-void oscar_add_deny(PurpleConnection *gc, const char *who) {
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	purple_debug_info("oscar", "ssi: About to add a deny\n");
-	aim_ssi_add_to_private_list(od, who, aim_ssi_getdenyentrytype(od));
-}
-
-void oscar_rem_permit(PurpleConnection *gc, const char *who) {
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	purple_debug_info("oscar", "ssi: About to delete a permit\n");
-	aim_ssi_del_from_private_list(od, who, AIM_SSI_TYPE_PERMIT);
-}
-
-void oscar_rem_deny(PurpleConnection *gc, const char *who) {
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	purple_debug_info("oscar", "ssi: About to delete a deny\n");
-	aim_ssi_del_from_private_list(od, who, aim_ssi_getdenyentrytype(od));
-}
-
-GList *
-oscar_status_types(PurpleAccount *account)
-{
-	gboolean is_icq;
-	GList *status_types = NULL;
-	PurpleStatusType *type;
-
-	g_return_val_if_fail(account != NULL, NULL);
-
-	/* Used to flag some statuses as "user settable" or not */
-	is_icq = oscar_util_valid_name_icq(purple_account_get_username(account));
-
-	/* Common status types */
-	/* Really the available message should only be settable for AIM accounts */
-	type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
-										   OSCAR_STATUS_ID_AVAILABLE,
-										   NULL, TRUE, TRUE, FALSE,
-										   "message", _("Message"),
-										   purple_value_new(G_TYPE_STRING),
-										   "itmsurl", _("iTunes Music Store Link"),
-										   purple_value_new(G_TYPE_STRING), NULL);
-	status_types = g_list_prepend(status_types, type);
-
-	type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
-									 OSCAR_STATUS_ID_FREE4CHAT,
-									 _("Free For Chat"), TRUE, is_icq, FALSE,
-									 "message", _("Message"),
-				purple_value_new(G_TYPE_STRING), NULL);
-
-	status_types = g_list_prepend(status_types, type);
-
-	type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
-									 OSCAR_STATUS_ID_EVIL,
-									 _("Evil"), TRUE, is_icq, FALSE,
-				 "message", _("Message"),
-				purple_value_new(G_TYPE_STRING), NULL);
-	status_types = g_list_prepend(status_types, type);
-
-
-	type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
-									 OSCAR_STATUS_ID_DEPRESSION,
-									 _("Depression"), TRUE, is_icq, FALSE,
-				 "message", _("Message"),
-				purple_value_new(G_TYPE_STRING), NULL);
-	status_types = g_list_prepend(status_types, type);
-
-
-	type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
-									 OSCAR_STATUS_ID_ATHOME,
-									 _("At home"), TRUE, is_icq, FALSE,
-				"message", _("Message"),
-				purple_value_new(G_TYPE_STRING), NULL);
-	status_types = g_list_prepend(status_types, type);
-
-
-	type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
-									 OSCAR_STATUS_ID_ATWORK,
-									 _("At work"), TRUE, is_icq, FALSE,
-				"message", _("Message"),
-				purple_value_new(G_TYPE_STRING), NULL);
-
-	status_types = g_list_prepend(status_types, type);
-
-
-	type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
-									 OSCAR_STATUS_ID_LUNCH,
-									 _("Lunch"), TRUE, is_icq, FALSE,
-				"message", _("Message"),
-				purple_value_new(G_TYPE_STRING), NULL);
-
-	status_types = g_list_prepend(status_types, type);
-
-	type = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY,
-										   OSCAR_STATUS_ID_AWAY,
-										   NULL, TRUE, TRUE, FALSE,
-										   "message", _("Message"),
-										   purple_value_new(G_TYPE_STRING), NULL);
-	status_types = g_list_prepend(status_types, type);
-
-	type = purple_status_type_new_with_attrs(PURPLE_STATUS_INVISIBLE,
-									 OSCAR_STATUS_ID_INVISIBLE,
-									 NULL, TRUE, TRUE, FALSE,
-									 "message", _("Message"),
-									  purple_value_new(G_TYPE_STRING), NULL);
-
-	status_types = g_list_prepend(status_types, type);
-
-	type = purple_status_type_new_full(PURPLE_STATUS_MOBILE, OSCAR_STATUS_ID_MOBILE, NULL, FALSE, FALSE, TRUE);
-	status_types = g_list_prepend(status_types, type);
-
-	/* ICQ-specific status types */
-	type = purple_status_type_new_with_attrs(PURPLE_STATUS_UNAVAILABLE,
-				OSCAR_STATUS_ID_OCCUPIED,
-				_("Occupied"), TRUE, is_icq, FALSE,
-				"message", _("Message"),
-				purple_value_new(G_TYPE_STRING), NULL);
-	status_types = g_list_prepend(status_types, type);
-
-	type = purple_status_type_new_with_attrs(PURPLE_STATUS_UNAVAILABLE,
-				OSCAR_STATUS_ID_DND,
-				_("Do Not Disturb"), TRUE, is_icq, FALSE,
-				"message", _("Message"),
-				purple_value_new(G_TYPE_STRING), NULL);
-	status_types = g_list_prepend(status_types, type);
-
-	type = purple_status_type_new_with_attrs(PURPLE_STATUS_EXTENDED_AWAY,
-				OSCAR_STATUS_ID_NA,
-				_("Not Available"), TRUE, is_icq, FALSE,
-				"message", _("Message"),
-				purple_value_new(G_TYPE_STRING), NULL);
-	status_types = g_list_prepend(status_types, type);
-
-	type = purple_status_type_new_full(PURPLE_STATUS_OFFLINE,
-									 OSCAR_STATUS_ID_OFFLINE,
-									 NULL, TRUE, TRUE, FALSE);
-	status_types = g_list_prepend(status_types, type);
-
-	type = purple_status_type_new_with_attrs(PURPLE_STATUS_MOOD,
-			"mood", NULL, TRUE, is_icq, TRUE,
-			PURPLE_MOOD_NAME, _("Mood Name"), purple_value_new(G_TYPE_STRING),
-			PURPLE_MOOD_COMMENT, _("Mood Comment"), purple_value_new(G_TYPE_STRING),
-			NULL);
-	status_types = g_list_prepend(status_types, type);
-
-	return g_list_reverse(status_types);
-}
-
-static void oscar_ssi_editcomment(struct name_data *data, const char *text) {
-	PurpleConnection *gc;
-	PurpleAccount *account;
-	OscarData *od;
-	PurpleBuddy *b;
-	PurpleGroup *g;
-
-	gc = data->gc;
-	od = purple_connection_get_protocol_data(gc);
-	account = purple_connection_get_account(gc);
-
-	b = purple_blist_find_buddy(account, data->name);
-	if (b == NULL) {
-		oscar_free_name_data(data);
-		return;
-	}
-
-	g = purple_buddy_get_group(b);
-	if (g == NULL) {
-		oscar_free_name_data(data);
-		return;
-	}
-
-	aim_ssi_editcomment(od, purple_group_get_name(g), data->name, text);
-	oscar_free_name_data(data);
-}
-
-static void oscar_buddycb_edit_comment(PurpleBlistNode *node, gpointer ignore) {
-
-	PurpleBuddy *buddy;
-	PurpleConnection *gc;
-	OscarData *od;
-	struct name_data *data;
-	PurpleGroup *g;
-	char *comment;
-	gchar *comment_utf8;
-	gchar *title;
-	PurpleAccount *account;
-	const char *name;
-
-	g_return_if_fail(PURPLE_IS_BUDDY(node));
-
-	buddy = (PurpleBuddy *) node;
-	name = purple_buddy_get_name(buddy);
-	account = purple_buddy_get_account(buddy);
-	gc = purple_account_get_connection(account);
-	od = purple_connection_get_protocol_data(gc);
-
-	if (!(g = purple_buddy_get_group(buddy)))
-		return;
-
-	data = g_new(struct name_data, 1);
-
-	comment = aim_ssi_getcomment(&od->ssi.local, purple_group_get_name(g), name);
-	comment_utf8 = comment ? oscar_utf8_try_convert(account, od, comment) : NULL;
-
-	data->gc = gc;
-	data->name = g_strdup(name);
-	data->nick = g_strdup(purple_buddy_get_alias_only(buddy));
-
-	title = g_strdup_printf(_("Buddy Comment for %s"), data->name);
-	purple_request_input(gc, title, _("Buddy Comment:"), NULL,
-					   comment_utf8, TRUE, FALSE, NULL,
-					   _("_OK"), G_CALLBACK(oscar_ssi_editcomment),
-					   _("_Cancel"), G_CALLBACK(oscar_free_name_data),
-					   purple_request_cpar_from_connection(gc),
-					   data);
-	g_free(title);
-
-	g_free(comment);
-	g_free(comment_utf8);
-}
-
-static void
-oscar_ask_directim_yes_cb(struct oscar_ask_directim_data *data)
-{
-	peer_connection_propose(data->od, OSCAR_CAPABILITY_DIRECTIM, data->who);
-	g_free(data->who);
-	g_free(data);
-}
-
-static void
-oscar_ask_directim_no_cb(struct oscar_ask_directim_data *data)
-{
-	g_free(data->who);
-	g_free(data);
-}
-
-/* This is called from right-click menu on a buddy node. */
-static void
-oscar_ask_directim(gpointer object, gpointer ignored)
-{
-	PurpleBlistNode *node;
-	PurpleBuddy *buddy;
-	PurpleConnection *gc;
-	gchar *buf;
-	struct oscar_ask_directim_data *data;
-	PurpleAccount *account;
-
-	node = object;
-
-	g_return_if_fail(PURPLE_IS_BUDDY(node));
-
-	buddy = (PurpleBuddy *)node;
-	account = purple_buddy_get_account(buddy);
-	gc = purple_account_get_connection(account);
-
-	data = g_new0(struct oscar_ask_directim_data, 1);
-	data->who = g_strdup(purple_buddy_get_name(buddy));
-	data->od = purple_connection_get_protocol_data(gc);
-	buf = g_strdup_printf(_("You have selected to open a Direct IM connection with %s."),
-			data->who);
-
-	purple_request_action(gc, NULL, buf,
-			_("Because this reveals your IP address, it "
-			  "may be considered a security risk.  Do you "
-			  "wish to continue?"),
-			0, /* Default action is "connect" */
-			purple_request_cpar_from_account(account),
-			data, 2,
-			_("C_onnect"), G_CALLBACK(oscar_ask_directim_yes_cb),
-			_("_Cancel"), G_CALLBACK(oscar_ask_directim_no_cb));
-	g_free(buf);
-}
-
-static void
-oscar_close_directim(gpointer object, gpointer ignored)
-{
-	PurpleBlistNode *node;
-	PurpleBuddy *buddy;
-	PurpleAccount *account;
-	PurpleConnection *gc;
-	PurpleIMConversation *im;
-	OscarData *od;
-	PeerConnection *conn;
-	const char *name;
-
-	node = object;
-
-	g_return_if_fail(PURPLE_IS_BUDDY(node));
-
-	buddy = (PurpleBuddy*)node;
-	name = purple_buddy_get_name(buddy);
-	account = purple_buddy_get_account(buddy);
-	gc = purple_account_get_connection(account);
-	od = purple_connection_get_protocol_data(gc);
-	conn = peer_connection_find_by_type(od, name, OSCAR_CAPABILITY_DIRECTIM);
-
-	if (conn != NULL)
-	{
-		if (!conn->ready)
-			aim_im_sendch2_cancel(conn);
-
-		peer_connection_destroy(conn, OSCAR_DISCONNECT_LOCAL_CLOSED, NULL);
-
-		/* OSCAR_DISCONNECT_LOCAL_CLOSED doesn't write anything to the convo
-		 * window. Let the user know that we cancelled the Direct IM. */
-		im = purple_im_conversation_new(account, name);
-		purple_conversation_write_system_message(
-			PURPLE_CONVERSATION(im), _("You closed the connection."), 0);
-	}
-}
-
-static void oscar_get_icqxstatusmsg(PurpleBlistNode *node, gpointer ignore)
-{
-	PurpleBuddy *buddy;
-	PurpleConnection *gc;
-	OscarData *od;
-	PurpleAccount *account;
-	const char *bname;
-
-	g_return_if_fail(PURPLE_IS_BUDDY(node));
-
-	buddy = (PurpleBuddy *)node;
-	bname = purple_buddy_get_name(buddy);
-
-	account = purple_buddy_get_account(buddy);
-	gc = purple_account_get_connection(account);
-	od = purple_connection_get_protocol_data(gc);
-
-	purple_debug_info("oscar", "Manual X-Status Get From %s to %s:\n", bname, purple_account_get_username(account));
-
-	icq_im_xstatus_request(od, bname);
-}
-
-static void
-oscar_get_aim_info_cb(PurpleBlistNode *node, gpointer ignore)
-{
-	PurpleBuddy *buddy;
-	PurpleConnection *gc;
-
-	g_return_if_fail(PURPLE_IS_BUDDY(node));
-
-	buddy = (PurpleBuddy *)node;
-	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
-
-	aim_locate_getinfoshort(purple_connection_get_protocol_data(gc),
-			purple_buddy_get_name(buddy), 0x00000003);
-}
-
-static GList *
-oscar_buddy_menu(PurpleBuddy *buddy) {
-	PurpleConnection *gc;
-	OscarData *od;
-	GList *menu;
-	PurpleActionMenu *act;
-	aim_userinfo_t *userinfo;
-	PurpleAccount *account;
-	const char *bname = purple_buddy_get_name(buddy);
-
-	account = purple_buddy_get_account(buddy);
-	gc = purple_account_get_connection(account);
-	od = purple_connection_get_protocol_data(gc);
-	userinfo = aim_locate_finduserinfo(od, bname);
-	menu = NULL;
-
-	if (od->icq && oscar_util_valid_name_icq(bname))
-	{
-		act = purple_action_menu_new(_("Get AIM Info"),
-								   PURPLE_CALLBACK(oscar_get_aim_info_cb),
-								   NULL, NULL);
-		menu = g_list_prepend(menu, act);
-	}
-
-	if (purple_buddy_get_group(buddy) != NULL)
-	{
-		/* We only do this if the user is in our buddy list */
-		act = purple_action_menu_new(_("Edit Buddy Comment"),
-		                           PURPLE_CALLBACK(oscar_buddycb_edit_comment),
-		                           NULL, NULL);
-		menu = g_list_prepend(menu, act);
-	}
-
-	if (od->icq)
-	{
-		act = purple_action_menu_new(_("Get X-Status Msg"),
-		                           PURPLE_CALLBACK(oscar_get_icqxstatusmsg),
-		                           NULL, NULL);
-		menu = g_list_prepend(menu, act);
-		menu = g_list_prepend(menu, create_visibility_menu_item(od, bname));
-	}
-
-	if (userinfo &&
-		oscar_util_name_compare(purple_account_get_username(account), bname) &&
-		PURPLE_BUDDY_IS_ONLINE(buddy))
-	{
-		PeerConnection *conn;
-		conn = peer_connection_find_by_type(od, bname, OSCAR_CAPABILITY_DIRECTIM);
-
-		if (userinfo->capabilities & OSCAR_CAPABILITY_DIRECTIM)
-		{
-			if (conn)
-			{
-				act = purple_action_menu_new(_("End Direct IM Session"),
-				                          PURPLE_CALLBACK(oscar_close_directim),
-				                          NULL, NULL);
-			}
-			else
-			{
-				act = purple_action_menu_new(_("Direct IM"),
-				                          PURPLE_CALLBACK(oscar_ask_directim),
-				                          NULL, NULL);
-			}
-			menu = g_list_prepend(menu, act);
-		}
-	}
-
-	if (od->ssi.received_data && purple_buddy_get_group(buddy) != NULL)
-	{
-		/*
-		 * We only do this if the user is in our buddy list and we're
-		 * waiting for authorization.
-		 */
-		char *gname;
-		gname = aim_ssi_itemlist_findparentname(&od->ssi.local, bname);
-		if (gname && aim_ssi_waitingforauth(&od->ssi.local, gname, bname))
-		{
-			act = purple_action_menu_new(_("Re-request Authorization"),
-			                           PURPLE_CALLBACK(oscar_auth_sendrequest_menu),
-			                           NULL, NULL);
-			menu = g_list_prepend(menu, act);
-		}
-	}
-
-	menu = g_list_reverse(menu);
-
-	return menu;
-}
-
-
-GList *oscar_blist_node_menu(PurpleBlistNode *node) {
-	if(PURPLE_IS_BUDDY(node)) {
-		return oscar_buddy_menu((PurpleBuddy *) node);
-	} else {
-		return NULL;
-	}
-}
-
-static void
-oscar_icq_privacy_opts(PurpleConnection *gc, PurpleRequestFields *fields)
-{
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	PurpleAccount *account = purple_connection_get_account(gc);
-	PurpleRequestField *f;
-	gboolean auth, web_aware;
-
-	f = purple_request_fields_get_field(fields, "authorization");
-	auth = purple_request_field_bool_get_value(f);
-
-	f = purple_request_fields_get_field(fields, "web_aware");
-	web_aware = purple_request_field_bool_get_value(f);
-
-	purple_account_set_bool(account, "authorization", auth);
-	purple_account_set_bool(account, "web_aware", web_aware);
-
-	oscar_set_extended_status(gc);
-	aim_icq_setsecurity(od, auth, web_aware);
-}
-
-static void
-oscar_show_icq_privacy_opts(PurpleProtocolAction *action)
-{
-	PurpleConnection *gc = action->connection;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	PurpleRequestFields *fields;
-	PurpleRequestFieldGroup *g;
-	PurpleRequestField *f;
-	gboolean auth, web_aware;
-
-	auth = purple_account_get_bool(account, "authorization", OSCAR_DEFAULT_AUTHORIZATION);
-	web_aware = purple_account_get_bool(account, "web_aware", OSCAR_DEFAULT_WEB_AWARE);
-
-	fields = purple_request_fields_new();
-
-	g = purple_request_field_group_new(NULL);
-
-	f = purple_request_field_bool_new("authorization", _("Require authorization"), auth);
-	purple_request_field_group_add_field(g, f);
-
-	f = purple_request_field_bool_new("web_aware", _("Web aware (enabling this will cause you to receive SPAM!)"), web_aware);
-	purple_request_field_group_add_field(g, f);
-
-	purple_request_fields_add_group(fields, g);
-
-	purple_request_fields(gc, _("ICQ Privacy Options"), _("ICQ Privacy Options"),
-						NULL, fields,
-						_("OK"), G_CALLBACK(oscar_icq_privacy_opts),
-						_("Cancel"), NULL,
-						purple_request_cpar_from_connection(gc),
-						gc);
-}
-
-static void oscar_confirm_account(PurpleProtocolAction *action)
-{
-	PurpleConnection *gc;
-	OscarData *od;
-	FlapConnection *conn;
-
-	gc = action->connection;
-	od = purple_connection_get_protocol_data(gc);
-
-	conn = flap_connection_getbytype(od, SNAC_FAMILY_ADMIN);
-	if (conn != NULL) {
-		aim_admin_reqconfirm(od, conn);
-	} else {
-		od->conf = TRUE;
-		aim_srv_requestnew(od, SNAC_FAMILY_ADMIN);
-	}
-}
-
-static void oscar_show_email(PurpleProtocolAction *action)
-{
-	PurpleConnection *gc = action->connection;
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	FlapConnection *conn = flap_connection_getbytype(od, SNAC_FAMILY_ADMIN);
-
-	if (conn) {
-		aim_admin_getinfo(od, conn, 0x11);
-	} else {
-		od->reqemail = TRUE;
-		aim_srv_requestnew(od, SNAC_FAMILY_ADMIN);
-	}
-}
-
-static void oscar_change_email(PurpleConnection *gc, const char *email)
-{
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	FlapConnection *conn = flap_connection_getbytype(od, SNAC_FAMILY_ADMIN);
-
-	if (conn) {
-		aim_admin_setemail(od, conn, email);
-	} else {
-		od->setemail = TRUE;
-		od->email = g_strdup(email);
-		aim_srv_requestnew(od, SNAC_FAMILY_ADMIN);
-	}
-}
-
-static void oscar_show_change_email(PurpleProtocolAction *action)
-{
-	PurpleConnection *gc = action->connection;
-	purple_request_input(gc, NULL, _("Change Address To:"), NULL, NULL,
-					   FALSE, FALSE, NULL,
-					   _("_OK"), G_CALLBACK(oscar_change_email),
-					   _("_Cancel"), NULL,
-					   purple_request_cpar_from_connection(gc),
-					   gc);
-}
-
-static void oscar_show_awaitingauth(PurpleProtocolAction *action)
-{
-	PurpleConnection *gc = action->connection;
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	PurpleAccount *account = purple_connection_get_account(gc);
-	GSList *buddies, *filtered_buddies, *cur;
-	gchar *text;
-
-	buddies = purple_blist_find_buddies(account, NULL);
-	filtered_buddies = NULL;
-	for (cur = buddies; cur != NULL; cur = cur->next) {
-		PurpleBuddy *buddy;
-		const gchar *bname, *gname;
-
-		buddy = cur->data;
-		bname = purple_buddy_get_name(buddy);
-		gname = purple_group_get_name(purple_buddy_get_group(buddy));
-		if (aim_ssi_waitingforauth(&od->ssi.local, gname, bname)) {
-			filtered_buddies = g_slist_prepend(filtered_buddies, buddy);
-		}
-	}
-
-	g_slist_free(buddies);
-
-	filtered_buddies = g_slist_reverse(filtered_buddies);
-	text = oscar_format_buddies(filtered_buddies, _("you are not waiting for authorization"));
-	g_slist_free(filtered_buddies);
-
-	purple_notify_formatted(gc, NULL, _("You are awaiting authorization from "
-						  "the following buddies"),	_("You can re-request "
-						  "authorization from these buddies by "
-						  "right-clicking on them and selecting "
-						  "\"Re-request Authorization.\""), text, NULL, NULL);
-	g_free(text);
-}
-
-static void search_by_email_cb(PurpleConnection *gc, const char *email)
-{
-	OscarData *od = purple_connection_get_protocol_data(gc);
-
-	aim_search_address(od, email);
-}
-
-static void oscar_show_find_email(PurpleProtocolAction *action)
-{
-	PurpleConnection *gc = action->connection;
-	purple_request_input(gc, _("Find Buddy by Email"),
-					   _("Search for a buddy by email address"),
-					   _("Type the email address of the buddy you are "
-						 "searching for."),
-					   NULL, FALSE, FALSE, NULL,
-					   _("_Search"), G_CALLBACK(search_by_email_cb),
-					   _("_Cancel"), NULL,
-					   purple_request_cpar_from_connection(gc),
-					   gc);
-}
-
-static void oscar_show_set_info(PurpleProtocolAction *action)
-{
-	PurpleConnection *gc = action->connection;
-	purple_account_request_change_user_info(purple_connection_get_account(gc));
-}
-
-static void oscar_show_set_info_icqurl(PurpleProtocolAction *action)
-{
-	PurpleConnection *gc = action->connection;
-	purple_notify_uri(gc, "http://www.icq.com/whitepages/user_details.php");
-}
-
-static void oscar_change_pass(PurpleProtocolAction *action)
-{
-	PurpleConnection *gc = action->connection;
-	purple_account_request_change_password(purple_connection_get_account(gc));
-}
-
-/**
- * Only used when connecting with the old-style BUCP login.
- */
-static void oscar_show_chpassurl(PurpleProtocolAction *action)
-{
-	PurpleConnection *gc = action->connection;
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	gchar *substituted = purple_strreplace(od->authinfo->chpassurl, "%s", purple_account_get_username(purple_connection_get_account(gc)));
-	purple_notify_uri(gc, substituted);
-	g_free(substituted);
-}
-
-static void oscar_show_imforwardingurl(PurpleProtocolAction *action)
-{
-	PurpleConnection *gc = action->connection;
-	purple_notify_uri(gc, "http://mymobile.aol.com/dbreg/register?action=imf&clientID=1");
-}
-
-void oscar_set_icon(PurpleConnection *gc, PurpleImage *img)
-{
-	OscarData *od = purple_connection_get_protocol_data(gc);
-
-	if (img == NULL) {
-		aim_ssi_delicon(od);
-	} else {
-		GChecksum *hash;
-		guchar md5[16];
-		gsize digest_len = 16;
-		gconstpointer data = purple_image_get_data(img);
-		size_t len = purple_image_get_data_size(img);
-
-		hash = g_checksum_new(G_CHECKSUM_MD5);
-		g_checksum_update(hash, data, len);
-		g_checksum_get_digest(hash, md5, &digest_len);
-		g_checksum_free(hash);
-
-		aim_ssi_seticon(od, md5, 16);
-	}
-}
-
-/**
- * Called by the Purple core to determine whether or not we're
- * allowed to send a file to this user.
- */
-gboolean
-oscar_can_receive_file(PurpleProtocolXfer *prplxfer, PurpleConnection *gc, const char *who)
-{
-	OscarData *od;
-	PurpleAccount *account;
-
-	od = purple_connection_get_protocol_data(gc);
-	account = purple_connection_get_account(gc);
-
-	if (od != NULL)
-	{
-		aim_userinfo_t *userinfo;
-		userinfo = aim_locate_finduserinfo(od, who);
-
-		/*
-		 * Don't allowing sending a file to a user that does not support
-		 * file transfer, and don't allow sending to ourselves.
-		 */
-		if (((userinfo == NULL) ||
-			(userinfo->capabilities & OSCAR_CAPABILITY_SENDFILE)) &&
-			oscar_util_name_compare(who, purple_account_get_username(account)))
-		{
-			return TRUE;
-		}
-	}
-
-	return FALSE;
-}
-
-PurpleXfer *
-oscar_new_xfer(PurpleProtocolXfer *prplxfer, PurpleConnection *gc, const char *who)
-{
-	OscarXfer *xfer;
-	OscarData *od;
-	PurpleAccount *account;
-	PeerConnection *conn;
-
-	od = purple_connection_get_protocol_data(gc);
-	account = purple_connection_get_account(gc);
-
-	conn = peer_connection_new(od, OSCAR_CAPABILITY_SENDFILE, who);
-	conn->flags |= PEER_CONNECTION_FLAG_INITIATED_BY_ME;
-	conn->flags |= PEER_CONNECTION_FLAG_APPROVED;
-
-	xfer = g_object_new(
-		OSCAR_TYPE_XFER,
-		"account", account,
-		"type", PURPLE_XFER_TYPE_SEND,
-		"remote-user", who,
-		"conn", conn,
-		NULL
-	);
-
-	aim_icbm_makecookie(conn->cookie);
-	conn->xfer = PURPLE_XFER(xfer);
-
-	return PURPLE_XFER(xfer);
-}
-
-/*
- * Called by the Purple core when the user indicates that a
- * file is to be sent to a special someone.
- */
-void
-oscar_send_file(PurpleProtocolXfer *prplxfer, PurpleConnection *gc, const char *who, const char *file)
-{
-	PurpleXfer *xfer;
-
-	xfer = oscar_new_xfer(prplxfer, gc, who);
-
-	if (file != NULL)
-		purple_xfer_request_accepted(xfer, file);
-	else
-		purple_xfer_request(xfer);
-}
-
-GList *
-oscar_get_actions(PurpleConnection *gc)
-{
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	GList *menu = NULL;
-	PurpleProtocolAction *act;
-
-	act = purple_protocol_action_new(_("Set User Info..."),
-			oscar_show_set_info);
-	menu = g_list_prepend(menu, act);
-
-	if (od->icq)
-	{
-		act = purple_protocol_action_new(_("Set User Info (web)..."),
-				oscar_show_set_info_icqurl);
-		menu = g_list_prepend(menu, act);
-	}
-
-	act = purple_protocol_action_new(_("Change Password..."),
-			oscar_change_pass);
-	menu = g_list_prepend(menu, act);
-
-	if (od->authinfo != NULL && od->authinfo->chpassurl != NULL)
-	{
-		/* This only happens when connecting with the old-style BUCP login */
-		act = purple_protocol_action_new(_("Change Password (web)"),
-				oscar_show_chpassurl);
-		menu = g_list_prepend(menu, act);
-	}
-
-	if (!od->icq)
-	{
-		act = purple_protocol_action_new(_("Configure IM Forwarding (web)"),
-				oscar_show_imforwardingurl);
-		menu = g_list_prepend(menu, act);
-	}
-
-	menu = g_list_prepend(menu, NULL);
-
-	if (od->icq)
-	{
-		/* ICQ actions */
-		act = purple_protocol_action_new(_("Set Privacy Options..."),
-				oscar_show_icq_privacy_opts);
-		menu = g_list_prepend(menu, act);
-
-		act = purple_protocol_action_new(_("Show Visible List"), oscar_show_visible_list);
-		menu = g_list_prepend(menu, act);
-
-		act = purple_protocol_action_new(_("Show Invisible List"), oscar_show_invisible_list);
-		menu = g_list_prepend(menu, act);
-	}
-	else
-	{
-		/* AIM actions */
-		act = purple_protocol_action_new(_("Confirm Account"),
-				oscar_confirm_account);
-		menu = g_list_prepend(menu, act);
-
-		act = purple_protocol_action_new(_("Display Currently Registered Email Address"),
-				oscar_show_email);
-		menu = g_list_prepend(menu, act);
-
-		act = purple_protocol_action_new(_("Change Currently Registered Email Address..."),
-				oscar_show_change_email);
-		menu = g_list_prepend(menu, act);
-	}
-
-	menu = g_list_prepend(menu, NULL);
-
-	act = purple_protocol_action_new(_("Show Buddies Awaiting Authorization"),
-			oscar_show_awaitingauth);
-	menu = g_list_prepend(menu, act);
-
-	menu = g_list_prepend(menu, NULL);
-
-	act = purple_protocol_action_new(_("Search for Buddy by Email Address..."),
-			oscar_show_find_email);
-	menu = g_list_prepend(menu, act);
-
-	menu = g_list_reverse(menu);
-
-	return menu;
-}
-
-void oscar_change_passwd(PurpleConnection *gc, const char *old, const char *new)
-{
-	OscarData *od = purple_connection_get_protocol_data(gc);
-
-	if (od->icq) {
-		aim_icq_changepasswd(od, new);
-	} else {
-		FlapConnection *conn;
-		conn = flap_connection_getbytype(od, SNAC_FAMILY_ADMIN);
-		if (conn) {
-			aim_admin_changepasswd(od, conn, new, old);
-		} else {
-			od->chpass = TRUE;
-			od->oldp = g_strdup(old);
-			od->newp = g_strdup(new);
-			aim_srv_requestnew(od, SNAC_FAMILY_ADMIN);
-		}
-	}
-}
-
-void
-oscar_convo_closed(PurpleConnection *gc, const char *who)
-{
-	OscarData *od;
-	PeerConnection *conn;
-
-	od = purple_connection_get_protocol_data(gc);
-	conn = peer_connection_find_by_type(od, who, OSCAR_CAPABILITY_DIRECTIM);
-
-	if (conn != NULL)
-	{
-		if (!conn->ready)
-			aim_im_sendch2_cancel(conn);
-
-		peer_connection_destroy(conn, OSCAR_DISCONNECT_LOCAL_CLOSED, NULL);
-	}
-}
-
-const char *
-oscar_normalize(const PurpleAccount *account, const char *str)
-{
-	static char buf[BUF_LEN];
-	char *tmp1, *tmp2;
-	int i, j;
-
-	g_return_val_if_fail(str != NULL, NULL);
-
-	/* copy str to buf and skip all blanks */
-	i = 0;
-	for (j = 0; str[j]; j++) {
-		if (str[j] != ' ') {
-			buf[i++] = str[j];
-			if (i >= BUF_LEN - 1)
-				break;
-		}
-	}
-	buf[i] = '\0';
-
-	tmp1 = g_utf8_strdown(buf, -1);
-	tmp2 = g_utf8_normalize(tmp1, -1, G_NORMALIZE_DEFAULT);
-	if (strlen(tmp2) > sizeof(buf) - 1) {
-		purple_debug_error("oscar", "normalized string exceeds buffer length!\n");
-	}
-	g_strlcpy(buf, tmp2, sizeof(buf));
-	g_free(tmp2);
-	g_free(tmp1);
-
-	return buf;
-}
-
-gboolean
-oscar_offline_message(const PurpleBuddy *buddy)
-{
-	return TRUE;
-}
-
-gssize
-oscar_get_max_message_size(PurpleConversation *conv)
-{
-	/* XXX: got from pidgin-otr - verify and document it */
-	return 2343;
-}
-
-/* TODO: Find somewhere to put this instead of including it in a bunch of places.
- * Maybe just change purple_accounts_find() to return anything for the protocol if there is no acct_id.
- */
-static PurpleAccount *find_acct(const char *protocol, const char *acct_id)
-{
-	PurpleAccount *acct = NULL;
-
-	/* If we have a specific acct, use it */
-	if (acct_id) {
-		acct = purple_accounts_find(acct_id, protocol);
-		if (acct && !purple_account_is_connected(acct))
-			acct = NULL;
-	} else { /* Otherwise find an active account for the protocol */
-		GList *l = purple_accounts_get_all();
-		while (l) {
-			if (purple_strequal(protocol, purple_account_get_protocol_id(l->data))
-					&& purple_account_is_connected(l->data)) {
-				acct = l->data;
-				break;
-			}
-			l = l->next;
-		}
-	}
-
-	return acct;
-}
-
-gboolean oscar_uri_handler(const char *proto, const char *cmd, GHashTable *params)
-{
-	char *acct_id;
-	char prpl[11];
-	PurpleAccount *acct;
-
-	if (g_ascii_strcasecmp(proto, "aim") && g_ascii_strcasecmp(proto, "icq"))
-		return FALSE;
-
-	if (params == NULL) {
-		/* All Oscar URI actions require some parameters eventually */
-		purple_debug_warning("oscar",
-				"No required params for handling URI");
-		return FALSE;
-	}
-
-	acct_id = g_hash_table_lookup(params, "account");
-	g_snprintf(prpl, sizeof(prpl), "prpl-%s", proto);
-
-	acct = find_acct(proto, acct_id);
-
-	if (!acct)
-		return FALSE;
-
-	/* aim:GoIM?screenname=SCREENNAME&message=MESSAGE */
-	if (!g_ascii_strcasecmp(cmd, "GoIM")) {
-		char *bname = g_hash_table_lookup(params, "screenname");
-		if (bname) {
-			char *message = g_hash_table_lookup(params, "message");
-
-			PurpleIMConversation *im = purple_conversations_find_im_with_account(
-				bname, acct);
-			if (im == NULL)
-				im = purple_im_conversation_new(acct, bname);
-			purple_conversation_present(PURPLE_CONVERSATION(im));
-
-			if (message) {
-				/* Spaces are encoded as '+' */
-				g_strdelimit(message, "+", ' ');
-				purple_conversation_send_confirm(PURPLE_CONVERSATION(im), message);
-			}
-		}
-		/*else
-			**If pidgindialogs_im() was in the core, we could use it here.
-			 * It is all purple_request_* based, but I'm not sure it really belongs in the core
-			pidgindialogs_im();*/
-
-		return TRUE;
-	}
-	/* aim:GoChat?roomname=CHATROOMNAME&exchange=4 */
-	else if (!g_ascii_strcasecmp(cmd, "GoChat")) {
-		char *rname = g_hash_table_lookup(params, "roomname");
-		if (rname) {
-			/* This is somewhat hacky, but the params aren't useful after this command */
-			g_hash_table_insert(params, g_strdup("exchange"), g_strdup("4"));
-			g_hash_table_insert(params, g_strdup("room"), g_strdup(rname));
-			purple_serv_join_chat(purple_account_get_connection(acct), params);
-		}
-		/*else
-			** Same as above (except that this would have to be re-written using purple_request_*)
-			pidgin_blist_joinchat_show(); */
-
-		return TRUE;
-	}
-	/* aim:AddBuddy?screenname=SCREENNAME&groupname=GROUPNAME*/
-	else if (!g_ascii_strcasecmp(cmd, "AddBuddy")) {
-		char *bname = g_hash_table_lookup(params, "screenname");
-		char *gname = g_hash_table_lookup(params, "groupname");
-		purple_blist_request_add_buddy(acct, bname, gname, NULL);
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-void oscar_init_account_options(PurpleProtocol *protocol, gboolean is_icq)
-{
-	PurpleAccountOption *option;
-	static const gchar *encryption_keys[] = {
-		N_("Use encryption if available"),
-		N_("Require encryption"),
-		N_("Don't use encryption"),
-		NULL
-	};
-	static const gchar *encryption_values[] = {
-		OSCAR_OPPORTUNISTIC_ENCRYPTION,
-		OSCAR_REQUIRE_ENCRYPTION,
-		OSCAR_NO_ENCRYPTION,
-		NULL
-	};
-	static const gchar *aim_login_keys[] = {
-		N_("Use clientLogin authentication"),
-		N_("Use Kerberos-based authentication"),
-		N_("Use MD5 based authentication"),
-		NULL
-	};
-	static const gchar *aim_login_values[] = {
-		OSCAR_CLIENT_LOGIN,
-		OSCAR_KERBEROS_LOGIN,
-		OSCAR_MD5_LOGIN,
-		NULL
-	};
-	static const gchar *icq_login_keys[] = {
-		N_("Use clientLogin authentication"),
-		N_("Use MD5 based authentication"),
-		NULL
-	};
-	static const gchar *icq_login_values[] = {
-		OSCAR_CLIENT_LOGIN,
-		OSCAR_MD5_LOGIN,
-		NULL
-	};
-	const gchar **login_keys;
-	const gchar **login_values;
-	GList *encryption_options = NULL;
-	GList *login_options = NULL;
-	int i;
-
-	option = purple_account_option_string_new(_("Server"), "server", oscar_get_login_server(is_icq, TRUE));
-	protocol->account_options = g_list_append(protocol->account_options, option);
-
-	option = purple_account_option_int_new(_("Port"), "port", OSCAR_DEFAULT_LOGIN_PORT);
-	protocol->account_options = g_list_append(protocol->account_options, option);
-
-	for (i = 0; encryption_keys[i]; i++) {
-		PurpleKeyValuePair *kvp = g_new0(PurpleKeyValuePair, 1);
-		kvp->key = g_strdup(_(encryption_keys[i]));
-		kvp->value = g_strdup(encryption_values[i]);
-		encryption_options = g_list_append(encryption_options, kvp);
-	}
-	option = purple_account_option_list_new(_("Connection security"), "encryption", encryption_options);
-	protocol->account_options = g_list_append(protocol->account_options, option);
-
-	if (is_icq) {
-		login_keys = icq_login_keys;
-		login_values = icq_login_values;
-	} else {
-		login_keys = aim_login_keys;
-		login_values = aim_login_values;
-	}
-	for (i = 0; login_keys[i]; i++) {
-		PurpleKeyValuePair *kvp = g_new0(PurpleKeyValuePair, 1);
-		kvp->key = g_strdup(_(login_keys[i]));
-		kvp->value = g_strdup(login_values[i]);
-		login_options = g_list_append(login_options, kvp);
-	}
-	option = purple_account_option_list_new(_("Authentication method"), "login_type", login_options);
-	protocol->account_options = g_list_append(protocol->account_options, option);
-
-	option = purple_account_option_bool_new(
-		_("Always use AIM/ICQ proxy server for\nfile transfers and direct IM (slower,\nbut does not reveal your IP address)"), "always_use_rv_proxy",
-		OSCAR_DEFAULT_ALWAYS_USE_RV_PROXY);
-	protocol->account_options = g_list_append(protocol->account_options, option);
-
-	if (is_icq) {
-		option = purple_account_option_string_new(_("Encoding"), "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
-		protocol->account_options = g_list_append(protocol->account_options, option);
-	} else {
-		option = purple_account_option_bool_new(_("Allow multiple simultaneous logins"), "allow_multiple_logins",
-												OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS);
-		protocol->account_options = g_list_append(protocol->account_options, option);
-	}
-}
-
-static void
-oscar_protocol_init(OscarProtocol *self)
-{
-	PurpleProtocol *protocol = PURPLE_PROTOCOL(self);
-
-	protocol->options   = OPT_PROTO_MAIL_CHECK | OPT_PROTO_INVITE_MESSAGE |
-	                      OPT_PROTO_AUTHORIZATION_DENIED_MESSAGE;
-	protocol->icon_spec = purple_buddy_icon_spec_new("gif,jpeg,bmp,ico",
-	                                                 0, 0, 64, 64, 7168,
-	                                                 PURPLE_ICON_SCALE_SEND |
-	                                                 PURPLE_ICON_SCALE_DISPLAY);
-}
-
-static void
-oscar_protocol_class_init(OscarProtocolClass *klass)
-{
-	PurpleProtocolClass *protocol_class = PURPLE_PROTOCOL_CLASS(klass);
-
-	protocol_class->login = oscar_login;
-	protocol_class->close = oscar_close;
-	protocol_class->status_types = oscar_status_types;
-}
-
-static void
-oscar_protocol_class_finalize(G_GNUC_UNUSED OscarProtocolClass *klass)
-{
-}
-
-static void
-oscar_protocol_client_iface_init(PurpleProtocolClientInterface *client_iface)
-{
-	client_iface->get_actions     = oscar_get_actions;
-	client_iface->list_emblem     = oscar_list_emblem;
-	client_iface->status_text     = oscar_status_text;
-	client_iface->tooltip_text    = oscar_tooltip_text;
-	client_iface->blist_node_menu = oscar_blist_node_menu;
-	client_iface->convo_closed    = oscar_convo_closed;
-	client_iface->normalize       = oscar_normalize;
-	client_iface->offline_message = oscar_offline_message;
-}
-
-static void
-oscar_protocol_server_iface_init(PurpleProtocolServerInterface *server_iface)
-{
-	server_iface->set_info       = oscar_set_info;
-	server_iface->get_info       = oscar_get_info;
-	server_iface->set_status     = oscar_set_status;
-	server_iface->set_idle       = oscar_set_idle;
-	server_iface->change_passwd  = oscar_change_passwd;
-	server_iface->add_buddy      = oscar_add_buddy;
-	server_iface->remove_buddy   = oscar_remove_buddy;
-	server_iface->keepalive      = oscar_keepalive;
-	server_iface->alias_buddy    = oscar_alias_buddy;
-	server_iface->group_buddy    = oscar_move_buddy;
-	server_iface->rename_group   = oscar_rename_group;
-	server_iface->set_buddy_icon = oscar_set_icon;
-	server_iface->remove_group   = oscar_remove_group;
-}
-
-static void
-oscar_protocol_im_iface_init(PurpleProtocolIMInterface *im_iface)
-{
-	im_iface->send        = oscar_send_im;
-	im_iface->send_typing = oscar_send_typing;
-}
-
-static void
-oscar_protocol_chat_iface_init(PurpleProtocolChatInterface *chat_iface)
-{
-	chat_iface->info          = oscar_chat_info;
-	chat_iface->info_defaults = oscar_chat_info_defaults;
-	chat_iface->join          = oscar_join_chat;
-	chat_iface->get_name      = oscar_get_chat_name;
-	chat_iface->invite        = oscar_chat_invite;
-	chat_iface->leave         = oscar_chat_leave;
-	chat_iface->send          = oscar_send_chat;
-}
-
-static void
-oscar_protocol_privacy_iface_init(PurpleProtocolPrivacyInterface *privacy_iface)
-{
-	privacy_iface->add_deny = oscar_add_deny;
-	privacy_iface->rem_deny = oscar_rem_deny;
-}
-
-static void
-oscar_protocol_xfer_iface_init(PurpleProtocolXferInterface *xfer_iface)
-{
-	xfer_iface->can_receive = oscar_can_receive_file;
-	xfer_iface->send_file   = oscar_send_file;
-	xfer_iface->new_xfer    = oscar_new_xfer;
-}
-
-G_DEFINE_DYNAMIC_TYPE_EXTENDED(
-        OscarProtocol, oscar_protocol, PURPLE_TYPE_PROTOCOL,
-        G_TYPE_FLAG_ABSTRACT,
-
-        G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_CLIENT,
-                                      oscar_protocol_client_iface_init)
-
-        G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_SERVER,
-                                      oscar_protocol_server_iface_init)
-
-        G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_IM,
-                                      oscar_protocol_im_iface_init)
-
-        G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_CHAT,
-                                      oscar_protocol_chat_iface_init)
-
-        G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_PRIVACY,
-                                      oscar_protocol_privacy_iface_init)
-
-        G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_XFER,
-                                      oscar_protocol_xfer_iface_init));
-
-static PurplePluginInfo *
-plugin_query(GError **error)
-{
-	return purple_plugin_info_new(
-		"id",           "prpl-oscar",
-		"name",         "Oscar Protocols",
-		"version",      DISPLAY_VERSION,
-		"category",     N_("Protocol"),
-		"summary",      N_("Oscar (AIM/ICQ) Protocols Plugin"),
-		"description",  N_("Oscar (AIM/ICQ) Protocols Plugin"),
-		"website",      PURPLE_WEBSITE,
-		"abi-version",  PURPLE_ABI_VERSION,
-		"flags",        PURPLE_PLUGIN_INFO_FLAGS_INTERNAL |
-		                PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD,
-		NULL
-	);
-}
-
-static gboolean
-plugin_load(PurplePlugin *plugin, GError **error)
-{
-	oscar_protocol_register_type(G_TYPE_MODULE(plugin));
-
-	aim_protocol_register(plugin);
-	icq_protocol_register(plugin);
-
-	oscar_xfer_register(G_TYPE_MODULE(plugin));
-
-	aim_protocol = purple_protocols_add(AIM_TYPE_PROTOCOL, error);
-	if (!aim_protocol)
-		return FALSE;
-
-	icq_protocol = purple_protocols_add(ICQ_TYPE_PROTOCOL, error);
-	if (!icq_protocol)
-		return FALSE;
-
-	purple_signal_connect(purple_get_core(), "uri-handler", aim_protocol,
-		PURPLE_CALLBACK(oscar_uri_handler), NULL);
-	purple_signal_connect(purple_get_core(), "uri-handler", icq_protocol,
-		PURPLE_CALLBACK(oscar_uri_handler), NULL);
-
-	/* Preferences */
-	purple_prefs_add_none("/plugins/prpl/oscar");
-	purple_prefs_add_bool("/plugins/prpl/oscar/recent_buddies", FALSE);
-
-	purple_prefs_remove("/plugins/prpl/oscar/show_idle");
-	purple_prefs_remove("/plugins/prpl/oscar/always_use_rv_proxy");
-
-	return TRUE;
-}
-
-static gboolean
-plugin_unload(PurplePlugin *plugin, GError **error)
-{
-	if (!purple_protocols_remove(icq_protocol, error))
-		return FALSE;
-
-	if (!purple_protocols_remove(aim_protocol, error))
-		return FALSE;
-
-	return TRUE;
-}
-
-PURPLE_PLUGIN_INIT(oscar, plugin_query, plugin_load, plugin_unload);
--- a/libpurple/protocols/oscar/oscar.h	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1379 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Main libfaim header.  Must be included in client for prototypes/macros.
- *
- * "come on, i turned a chick lesbian; i think this is the hackish equivalent"
- *                                                -- Josh Myer
- *
- */
-
-#ifndef PURPLE_OSCAR_OSCAR_H
-#define PURPLE_OSCAR_OSCAR_H
-
-#include "internal.h"
-#include "circularbuffer.h"
-#include "debug.h"
-#include "eventloop.h"
-#include "proxy.h"
-#include "sslconn.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <time.h>
-
-#include <gmodule.h>
-#include <libsoup/soup.h>
-
-#ifndef _WIN32
-#include <sys/time.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#endif
-
-#define OSCAR_TYPE_PROTOCOL             (oscar_protocol_get_type())
-#define OSCAR_PROTOCOL(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), OSCAR_TYPE_PROTOCOL, OscarProtocol))
-#define OSCAR_PROTOCOL_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), OSCAR_TYPE_PROTOCOL, OscarProtocolClass))
-#define OSCAR_IS_PROTOCOL(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), OSCAR_TYPE_PROTOCOL))
-#define OSCAR_IS_PROTOCOL_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), OSCAR_TYPE_PROTOCOL))
-#define OSCAR_PROTOCOL_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), OSCAR_TYPE_PROTOCOL, OscarProtocolClass))
-
-typedef struct _ByteStream         ByteStream;
-typedef struct _ClientInfo         ClientInfo;
-typedef struct _FlapConnection     FlapConnection;
-typedef struct _FlapFrame          FlapFrame;
-typedef struct _IcbmArgsCh2        IcbmArgsCh2;
-typedef struct _IcbmCookie         IcbmCookie;
-typedef struct _OscarData          OscarData;
-typedef struct _QueuedSnac         QueuedSnac;
-
-typedef guint32 aim_snacid_t;
-
-#include "snactypes.h"
-
-G_BEGIN_DECLS
-
-#define FAIM_SNAC_HASH_SIZE 16
-
-/*
- * Current Maximum Length for usernames (not including NULL)
- *
- * Currently only names up to 16 characters can be registered
- * however it is apparently legal for them to be larger.
- */
-#define MAXSNLEN 97
-
-/*
- * Current Maximum Length for Instant Messages
- *
- * This was found basically by experiment, but not wholly
- * accurate experiment.  It should not be regarded
- * as completely correct.  But its a decent approximation.
- *
- * Note that although we can send this much, its impossible
- * for WinAIM clients (up through the latest (4.0.1957)) to
- * send any more than 1kb.  Amaze all your windows friends
- * with utterly oversized instant messages!
- */
-#define MAXMSGLEN 2544
-
-/*
- * Maximum size of a Buddy Icon.
- */
-#define MAXICONLEN 7168
-#define AIM_ICONIDENT "AVT1picture.id"
-
-/*
- * Found by trial and error.
- */
-#define MAXAVAILMSGLEN 251
-
-/**
- * Maximum length for the password of an ICQ account
- */
-#define MAXICQPASSLEN 16
-
-#define AIM_MD5_STRING "AOL Instant Messenger (SM)"
-
-#define OSCAR_CONNECT_STEPS 6
-
-/*
- * Client info.  Filled in by the client and passed in to
- * aim_send_login().  The information ends up getting passed to OSCAR
- * through the initial login command.
- *
- */
-struct _ClientInfo
-{
-	const char *clientstring;
-	guint16 clientid;
-	guint16 major;
-	guint16 minor;
-	guint16 point;
-	guint16 build;
-	guint32 distrib;
-	const char *country; /* two-letter abbrev */
-	const char *lang; /* two-letter abbrev */
-};
-
-/*
- * We need to use the major-minor-micro versions from the official
- * AIM and ICQ programs here or AOL won't let us use certain features.
- *
- * 0x00000611 is the distid given to us by AOL for use as the default
- * libpurple distid.
- */
-#define CLIENTINFO_PURPLE_AIM { \
-	NULL, \
-	0x0109, \
-	0x0005, 0x0001, \
-	0x0000, 0x0bdc, \
-	0x00000611, \
-	"us", "en", \
-}
-
-#define CLIENTINFO_PURPLE_ICQ { \
-	NULL, \
-	0x010a, \
-	0x0014, 0x0034, \
-	0x0000, 0x0c18, \
-	0x00000611, \
-	"us", "en", \
-}
-
-typedef enum
-{
-	OSCAR_DISCONNECT_DONE, /* not considered an error */
-	OSCAR_DISCONNECT_LOCAL_CLOSED, /* peer connections only, not considered an error */
-	OSCAR_DISCONNECT_REMOTE_CLOSED,
-	OSCAR_DISCONNECT_REMOTE_REFUSED, /* peer connections only */
-	OSCAR_DISCONNECT_LOST_CONNECTION,
-	OSCAR_DISCONNECT_INVALID_DATA,
-	OSCAR_DISCONNECT_COULD_NOT_CONNECT,
-	OSCAR_DISCONNECT_RETRYING /* peer connections only */
-} OscarDisconnectReason;
-
-#define OSCAR_CAPABILITY_BUDDYICON             0x0000000000000001LL
-#define OSCAR_CAPABILITY_TALK                  0x0000000000000002LL
-#define OSCAR_CAPABILITY_DIRECTIM              0x0000000000000004LL
-#define OSCAR_CAPABILITY_CHAT                  0x0000000000000008LL
-#define OSCAR_CAPABILITY_GETFILE               0x0000000000000010LL
-#define OSCAR_CAPABILITY_SENDFILE              0x0000000000000020LL
-#define OSCAR_CAPABILITY_GAMES                 0x0000000000000040LL
-#define OSCAR_CAPABILITY_ADDINS                0x0000000000000080LL
-#define OSCAR_CAPABILITY_SENDBUDDYLIST         0x0000000000000100LL
-#define OSCAR_CAPABILITY_GAMES2                0x0000000000000200LL
-#define OSCAR_CAPABILITY_ICQ_DIRECT            0x0000000000000400LL
-#define OSCAR_CAPABILITY_APINFO                0x0000000000000800LL
-#define OSCAR_CAPABILITY_ICQRTF                0x0000000000001000LL
-#define OSCAR_CAPABILITY_EMPTY                 0x0000000000002000LL
-#define OSCAR_CAPABILITY_ICQSERVERRELAY        0x0000000000004000LL
-#define OSCAR_CAPABILITY_UNICODEOLD            0x0000000000008000LL
-#define OSCAR_CAPABILITY_TRILLIANCRYPT         0x0000000000010000LL
-#define OSCAR_CAPABILITY_UNICODE               0x0000000000020000LL
-#define OSCAR_CAPABILITY_INTEROPERATE          0x0000000000040000LL
-#define OSCAR_CAPABILITY_SHORTCAPS             0x0000000000080000LL
-#define OSCAR_CAPABILITY_HIPTOP                0x0000000000100000LL
-#define OSCAR_CAPABILITY_SECUREIM              0x0000000000200000LL
-#define OSCAR_CAPABILITY_SMS                   0x0000000000400000LL
-#define OSCAR_CAPABILITY_VIDEO                 0x0000000000800000LL
-#define OSCAR_CAPABILITY_ICHATAV               0x0000000001000000LL
-#define OSCAR_CAPABILITY_LIVEVIDEO             0x0000000002000000LL
-#define OSCAR_CAPABILITY_CAMERA                0x0000000004000000LL
-#define OSCAR_CAPABILITY_ICHAT_SCREENSHARE     0x0000000008000000LL
-#define OSCAR_CAPABILITY_TYPING                0x0000000010000000LL
-#define OSCAR_CAPABILITY_NEWCAPS               0x0000000020000000LL
-#define OSCAR_CAPABILITY_XTRAZ                 0x0000000040000000LL
-#define OSCAR_CAPABILITY_GENERICUNKNOWN        0x0000000080000000LL
-#define OSCAR_CAPABILITY_HTML_MSGS             0x0000000100000000LL
-#define OSCAR_CAPABILITY_LAST                  0x0000000200000000LL
-
-#define OSCAR_STATUS_ID_INVISIBLE   "invisible"
-#define OSCAR_STATUS_ID_OFFLINE     "offline"
-#define OSCAR_STATUS_ID_AVAILABLE   "available"
-#define OSCAR_STATUS_ID_AWAY        "away"
-#define OSCAR_STATUS_ID_DND         "dnd"
-#define OSCAR_STATUS_ID_NA          "na"
-#define OSCAR_STATUS_ID_OCCUPIED    "occupied"
-#define OSCAR_STATUS_ID_FREE4CHAT   "free4chat"
-#define OSCAR_STATUS_ID_CUSTOM      "custom"
-#define OSCAR_STATUS_ID_MOBILE	    "mobile"
-#define OSCAR_STATUS_ID_EVIL        "evil"
-#define OSCAR_STATUS_ID_DEPRESSION	 "depression"
-#define OSCAR_STATUS_ID_ATHOME      "athome"
-#define OSCAR_STATUS_ID_ATWORK      "atwork"
-#define OSCAR_STATUS_ID_LUNCH       "lunch"
-
-typedef struct
-{
-	PurpleProtocol parent;
-} OscarProtocol;
-
-typedef struct
-{
-	PurpleProtocolClass parent_class;
-} OscarProtocolClass;
-
-/**
- * Returns the GType for the OscarProtocol object.
- */
-G_MODULE_EXPORT GType oscar_protocol_get_type(void);
-
-/*
- * Byte Stream type. Sort of.
- *
- * Use of this type serves a couple purposes:
- *   - Buffer/buflen pairs are passed all around everywhere. This turns
- *     that into one value, as well as abstracting it slightly.
- *   - Through the abstraction, it is possible to enable bounds checking
- *     for robustness at the cost of performance.  But a clean failure on
- *     weird packets is much better than a segfault.
- *   - I like having variables named "bs".
- *
- * Don't touch the insides of this struct.  Or I'll have to kill you.
- *
- */
-struct _ByteStream
-{
-	guint8 *data;
-	size_t len;
-	size_t offset;
-};
-
-struct _QueuedSnac
-{
-	guint16 family;
-	guint16 subtype;
-	FlapFrame *frame;
-};
-
-struct _FlapFrame
-{
-	guint8 channel;
-	guint16 seqnum;
-	ByteStream data;        /* payload stream */
-};
-
-struct _FlapConnection
-{
-	OscarData *od;              /**< Pointer to parent session. */
-	gboolean connected;
-	time_t lastactivity;             /**< Time of last transmit. */
-	guint destroy_timeout;
-	OscarDisconnectReason disconnect_reason;
-	gchar *error_message;
-	guint16 disconnect_code;
-
-	/* A few variables that are only used when connecting */
-	PurpleProxyConnectData *connect_data;
-	guint16 cookielen;
-	guint8 *cookie;
-	gpointer new_conn_data;
-
-	int fd;
-	PurpleSslConnection *gsc;
-	guint8 header[6];
-	gssize header_received;
-	FlapFrame buffer_incoming;
-	PurpleCircularBuffer *buffer_outgoing;
-	guint watcher_incoming;
-	guint watcher_outgoing;
-
-	guint16 type;
-	guint16 subtype;
-	guint16 seqnum_out; /**< The sequence number of most recently sent packet. */
-	guint16 seqnum_in; /**< The sequence number of most recently received packet. */
-	GSList *groups;
-	GSList *rateclasses; /* Contains nodes of struct rateclass. */
-	struct rateclass *default_rateclass;
-	GHashTable *rateclass_members; /* Key is family and subtype, value is pointer to the rateclass struct to use. */
-
-	GQueue *queued_snacs; /**< Contains QueuedSnacs. */
-	GQueue *queued_lowpriority_snacs; /**< Contains QueuedSnacs to send only once queued_snacs is empty */
-	guint queued_timeout;
-
-	void *internal; /* internal conn-specific libfaim data */
-};
-
-struct _IcbmCookie
-{
-	guchar cookie[8];
-	int type;
-	void *data;
-	time_t addtime;
-	struct _IcbmCookie *next;
-};
-
-#include "peer.h"
-
-struct aim_ssi_itemlist {
-	struct aim_ssi_item *data;
-	GHashTable *idx_gid_bid;
-	GHashTable *idx_all_named_items;
-};
-
-/**
- * The main client-data interface.
- */
-struct _OscarData
-{
-	/* Only used when connecting with clientLogin or Kerberos. */
-	SoupSession *http_conns;
-
-	gboolean iconconnecting;
-	gboolean set_icon;
-
-	GSList *create_rooms;
-
-	gboolean conf;
-	gboolean reqemail;
-	gboolean setemail;
-	char *email;
-	gboolean setnick;
-	char *newformatting;
-	gboolean chpass;
-	char *oldp;
-	char *newp;
-
-	GSList *oscar_chats;
-	GHashTable *buddyinfo;
-	GSList *requesticon;
-
-	gboolean use_ssl;
-	gboolean icq;
-	guint getblisttimer;
-
-	struct {
-		guint maxwatchers; /* max users who can watch you */
-		guint maxbuddies; /* max users you can watch */
-		guint maxgroups; /* max groups in server list */
-		guint maxpermits; /* max users on permit list */
-		guint maxdenies; /* max users on deny list */
-		guint maxsiglen; /* max size (bytes) of profile */
-		guint maxawaymsglen; /* max size (bytes) of posted away message */
-	} rights;
-
-	PurpleConnection *gc;
-
-	void *modlistv;
-
-	/*
-	 * Outstanding snac handling
-	 *
-	 * TODO: Should these be per-connection? -mid
-	 */
-	void *snac_hash[FAIM_SNAC_HASH_SIZE];
-	aim_snacid_t snacid_next;
-
-	/*
-	 * TODO: Data specific to a certain family should go into a
-	 *       hashtable and the core parts of libfaim shouldn't
-	 *       need to know about them.
-	 */
-
-	IcbmCookie *msgcookies;
-	GSList *icq_info;
-
-	/** Only used when connecting with the old-style BUCP login. */
-	struct aim_authresp_info *authinfo;
-	struct aim_emailinfo *emailinfo;
-
-	struct {
-		struct aim_userinfo_s *userinfo;
-	} locate;
-
-	struct {
-		gboolean have_rights;
-	} bos;
-
-	/* Server-stored information (ssi) */
-	struct {
-		gboolean received_data;
-		guint16 numitems;
-		struct aim_ssi_itemlist official;
-		struct aim_ssi_itemlist local;
-		struct aim_ssi_tmp *pending;
-		time_t timestamp;
-		gboolean waiting_for_ack;
-		gboolean in_transaction;
-	} ssi;
-
-	/** Contains pointers to handler functions for each family/subtype. */
-	GHashTable *handlerlist;
-
-	/** A linked list containing FlapConnections. */
-	GSList *oscar_connections;
-	guint16 default_port;
-
-	/** A linked list containing PeerConnections. */
-	GSList *peer_connections;
-};
-
-/* Valid for calling aim_icq_setstatus() and for aim_userinfo_t->icqinfo.status */
-#define AIM_ICQ_STATE_NORMAL            0x00000000
-#define AIM_ICQ_STATE_AWAY              0x00000001
-#define AIM_ICQ_STATE_DND               0x00000002
-#define AIM_ICQ_STATE_OUT               0x00000004
-#define AIM_ICQ_STATE_BUSY              0x00000010
-#define AIM_ICQ_STATE_CHAT              0x00000020
-#define AIM_ICQ_STATE_INVISIBLE         0x00000100
-#define AIM_ICQ_STATE_EVIL              0x00003000
-#define AIM_ICQ_STATE_DEPRESSION        0x00004000
-#define AIM_ICQ_STATE_ATHOME            0x00005000
-#define AIM_ICQ_STATE_ATWORK            0x00006000
-#define AIM_ICQ_STATE_LUNCH             0x00002001
-#define AIM_ICQ_STATE_EVIL              0x00003000
-#define AIM_ICQ_STATE_WEBAWARE          0x00010000
-#define AIM_ICQ_STATE_HIDEIP            0x00020000
-#define AIM_ICQ_STATE_BIRTHDAY          0x00080000
-#define AIM_ICQ_STATE_ICQHOMEPAGE       0x00200000
-#define AIM_ICQ_STATE_DIRECTREQUIREAUTH 0x10000000
-
-/**
- * Only used when connecting with the old-style BUCP login.
- */
-struct aim_clientrelease
-{
-	char *name;
-	guint32 build;
-	char *url;
-	char *info;
-};
-
-/**
- * Only used when connecting with the old-style BUCP login.
- */
-struct aim_authresp_info
-{
-	char *bn;
-	guint16 errorcode;
-	char *errorurl;
-	guint16 regstatus;
-	char *email;
-	char *bosip;
-	guint16 cookielen;
-	guint8 *cookie;
-	char *chpassurl;
-	struct aim_clientrelease latestrelease;
-	struct aim_clientrelease latestbeta;
-};
-
-/* Callback data for redirect. */
-struct aim_redirect_data
-{
-	guint16 group;
-	const char *ip;
-	guint16 cookielen;
-	const guint8 *cookie;
-	const char *ssl_cert_cn;
-	guint8 use_ssl;
-	struct { /* group == SNAC_FAMILY_CHAT */
-		guint16 exchange;
-		const char *room;
-		guint16 instance;
-	} chat;
-};
-
-int oscar_connect_to_bos(PurpleConnection *gc, OscarData *od, const char *host, guint16 port, guint8 *cookie, guint16 cookielen, const char *tls_certname);
-
-/* family_auth.c */
-
-/**
- * Only used when connecting with the old-style BUCP login.
- */
-int aim_request_login(OscarData *od, FlapConnection *conn, const char *bn);
-
-/**
- * Only used when connecting with the old-style BUCP login.
- */
-int aim_send_login(OscarData *od, FlapConnection *conn, const char *bn, const char *password, gboolean truncate_pass, ClientInfo *ci, const char *key, gboolean allow_multiple_logins);
-
-/**
- * Only used when connecting with the old-style BUCP login.
- */
-/* 0x000b */ int aim_auth_securid_send(OscarData *od, const char *securid);
-
-/**
- * Only used when connecting with clientLogin.
- */
-void send_client_login(OscarData *od, const char *username);
-
-/**
- * Only used when connecting with kerberos login.
- */
-void send_kerberos_login(OscarData *od, const char *username);
-
-
-/* flap_connection.c */
-FlapConnection *flap_connection_new(OscarData *, int type);
-void flap_connection_close(OscarData *od, FlapConnection *conn);
-void flap_connection_destroy(FlapConnection *conn, OscarDisconnectReason reason, const gchar *error_message);
-void flap_connection_schedule_destroy(FlapConnection *conn, OscarDisconnectReason reason, const gchar *error_message);
-FlapConnection *flap_connection_findbygroup(OscarData *od, guint16 group);
-FlapConnection *flap_connection_getbytype(OscarData *, int type);
-FlapConnection *flap_connection_getbytype_all(OscarData *, int type);
-void flap_connection_recv_cb(gpointer data, gint source, PurpleInputCondition cond);
-void flap_connection_recv_cb_ssl(gpointer data, PurpleSslConnection *gsc, PurpleInputCondition cond);
-
-void flap_connection_send(FlapConnection *conn, FlapFrame *frame);
-void flap_connection_send_version(OscarData *od, FlapConnection *conn);
-void flap_connection_send_version_with_cookie(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy);
-void flap_connection_send_version_with_cookie_and_clientinfo(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy, ClientInfo *ci, gboolean allow_multiple_login);
-void flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, aim_snacid_t snacid, ByteStream *data);
-void flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, aim_snacid_t snacid, ByteStream *data, gboolean high_priority);
-void flap_connection_send_keepalive(OscarData *od, FlapConnection *conn);
-FlapFrame *flap_frame_new(OscarData *od, guint16 channel, int datalen);
-
-/* oscar_data.c */
-typedef int (*aim_rxcallback_t)(OscarData *od, FlapConnection *conn, FlapFrame *frame, ...);
-
-OscarData *oscar_data_new(void);
-void oscar_data_destroy(OscarData *);
-void oscar_data_addhandler(OscarData *od, guint16 family, guint16 subtype, aim_rxcallback_t newhandler, guint16 flags);
-aim_rxcallback_t aim_callhandler(OscarData *od, guint16 family, guint16 subtype);
-
-/* 0x0001 - family_oservice.c */
-/* 0x0002 */ void aim_srv_clientready(OscarData *od, FlapConnection *conn);
-/* 0x0004 */ void aim_srv_requestnew(OscarData *od, guint16 serviceid);
-/* 0x0006 */ void aim_srv_reqrates(OscarData *od, FlapConnection *conn);
-/* 0x0008 */ void aim_srv_rates_addparam(OscarData *od, FlapConnection *conn);
-/* 0x000e */ void aim_srv_reqpersonalinfo(OscarData *od, FlapConnection *conn);
-/* 0x0011 */ void aim_srv_setidle(OscarData *od, guint32 idletime);
-/* 0x0017 */ void aim_srv_setversions(OscarData *od, FlapConnection *conn);
-/* 0x001e */ int aim_srv_setextrainfo(OscarData *od, gboolean seticqstatus, guint32 icqstatus, gboolean setstatusmsg, const char *statusmsg, const char *itmsurl);
-void aim_srv_set_dc_info(OscarData *od);
-
-
-void aim_bos_reqrights(OscarData *od, FlapConnection *conn);
-
-#define AIM_RATE_CODE_LIMIT      0x0003
-
-/* family_icbm.c */
-#define AIM_OFT_SUBTYPE_SEND_DIR	0x0002
-
-#define AIM_TRANSFER_DENY_DECLINE	0x0001
-
-#define AIM_IMPARAM_FLAG_CHANNEL_MSGS_ALLOWED   0x00000001
-#define AIM_IMPARAM_FLAG_MISSED_CALLS_ENABLED   0x00000002
-#define AIM_IMPARAM_FLAG_EVENTS_ALLOWED         0x00000008
-#define AIM_IMPARAM_FLAG_SMS_SUPPORTED          0x00000010
-#define AIM_IMPARAM_FLAG_OFFLINE_MSGS_ALLOWED   0x00000100
-
-/**
- * This flag tells the server that we always send HTML in messages
- * sent from an ICQ account to an ICQ account.  (If this flag is
- * not sent then plaintext is sent ICQ<-->ICQ (HTML is sent in all
- * other cases)).
- *
- * If we send an HTML message to an old client that doesn't support
- * HTML messages, then the oscar servers will merrily strip the HTML
- * for us.
- *
- * All incoming IMs are treated as HTML.
- */
-#define AIM_IMPARAM_FLAG_USE_HTML_FOR_ICQ       0x00000400
-
-struct aim_icbmparameters
-{
-	guint16 maxchan;
-	guint32 flags; /* AIM_IMPARAM_FLAG_ */
-	guint16 maxmsglen; /* message size that you will accept */
-	guint16 maxsenderwarn; /* this and below are *10 (999=99.9%) */
-	guint16 maxrecverwarn;
-	guint32 minmsginterval; /* in milliseconds? */
-};
-
-/*
- * TODO: Should probably combine this with struct chat_connection.
- */
-struct aim_chat_roominfo
-{
-	guint16 exchange;
-	char *name;
-	guint8 namelen;
-	guint16 instance;
-};
-
-struct chat_connection
-{
-	char *name;
-	char *show; /* AOL did something funny to us */
-	guint16 exchange;
-	guint16 instance;
-	FlapConnection *conn;
-	int id;
-	PurpleConnection *gc;
-	PurpleChatConversation *conv;
-	guint16 maxlen;
-	guint16 maxvis;
-};
-
-/*
- * All this chat struct stuff should be in family_chat.c
- */
-void oscar_chat_destroy(struct chat_connection *cc);
-
-#define AIM_IMFLAGS_AWAY				0x0001 /* mark as an autoreply */
-#define AIM_IMFLAGS_ACK					0x0002 /* request a receipt notice */
-#define AIM_IMFLAGS_BUDDYREQ			0x0010 /* buddy icon requested */
-#define AIM_IMFLAGS_HASICON				0x0020 /* already has icon */
-#define AIM_IMFLAGS_SUBENC_MACINTOSH	0x0040 /* damn that Steve Jobs! */
-#define AIM_IMFLAGS_CUSTOMFEATURES		0x0080 /* features field present */
-#define AIM_IMFLAGS_OFFLINE				0x0800 /* send to offline user */
-#define AIM_IMFLAGS_TYPINGNOT			0x1000 /* typing notification */
-
-#define AIM_CHARSET_ASCII   0x0000 /* ISO 646 */
-#define AIM_CHARSET_UNICODE 0x0002 /* ISO 10646 (UTF-16/UCS-2BE) */
-#define AIM_CHARSET_LATIN_1 0x0003 /* ISO 8859-1 */
-
-/*
- * Arguments to aim_send_im_ext().
- *
- * This is really complicated.  But immensely versatile.
- *
- */
-struct aim_sendimext_args
-{
-	/* These are _required_ */
-	const char *destbn;
-	guint32 flags; /* often 0 */
-
-	const char *msg;
-	gsize msglen;
-
-	/* Only used if AIM_IMFLAGS_HASICON is set */
-	guint32 iconlen;
-	time_t iconstamp;
-	guint32 iconsum;
-
-	guint16 featureslen;
-	guint8 *features;
-
-	guint16 charset;
-};
-
-/*
- * This information is provided in the Incoming ICBM callback for
- * Channel 1 ICBM's.
- */
-struct aim_incomingim_ch1_args
-{
-	guint32 icbmflags; /* some flags apply only to ->msg, not all mpmsg */
-	time_t timestamp; /* Only set for offline messages */
-
-	gchar *msg;
-
-	/* Only provided if AIM_IMFLAGS_HASICON is set */
-	time_t iconstamp;
-	guint32 iconlen;
-	guint16 iconsum;
-};
-
-/* Valid values for channel 2 args->status */
-#define AIM_RENDEZVOUS_PROPOSE   0x0000
-#define AIM_RENDEZVOUS_CANCEL    0x0001
-#define AIM_RENDEZVOUS_CONNECTED 0x0002
-
-struct _IcbmArgsCh2
-{
-	guint16 status;
-	guchar cookie[8];
-	guint64 type; /* One of the OSCAR_CAPABILITY_ constants */
-	const char *proxyip;
-	const char *clientip;
-	const char *verifiedip;
-	guint16 port;
-	gboolean use_proxy;
-	guint16 errorcode;
-	const char *msg; /* invite message or file description */
-	guint16 msglen;
-	const char *encoding;
-	const char *language;
-	guint16 requestnumber;
-	union {
-		struct {
-			guint32 checksum;
-			guint32 length;
-			time_t timestamp;
-			guint8 *icon;
-		} icon;
-		struct {
-			struct aim_chat_roominfo roominfo;
-		} chat;
-		struct {
-			guint8 msgtype;
-			const char *msg;
-		} rtfmsg;
-		struct {
-			guint16 subtype;
-			guint16 totfiles;
-			guint32 totsize;
-			char *filename;
-		} sendfile;
-	} info;
-	void *destructor; /* used internally only */
-};
-
-struct aim_incomingim_ch4_args
-{
-	guint32 uin; /* Of the sender of the ICBM */
-	guint8 type;
-	guint8 flags;
-	gchar *msg; /* Reason for auth request, deny, or accept */
-	int msglen;
-};
-
-/* SNAC sending functions */
-/* 0x0002 */ int aim_im_setparams(OscarData *od, struct aim_icbmparameters *params);
-/* 0x0004 */ int aim_im_reqparams(OscarData *od);
-/* 0x0006 */ int aim_im_sendch1_ext(OscarData *od, struct aim_sendimext_args *args);
-/* 0x0006 */ int aim_im_sendch1(OscarData *, const char *destbn, guint16 flags, const char *msg);
-/* 0x0006 */ int aim_im_sendch2_chatinvite(OscarData *od, const char *bn, const char *msg, guint16 exchange, const char *roomname, guint16 instance);
-/* 0x0006 */ int aim_im_sendch2_icon(OscarData *od, const char *bn, const guint8 *icon, int iconlen, time_t stamp, guint16 iconsum);
-
-/* 0x0006 */ void aim_im_sendch2_cancel(PeerConnection *peer_conn);
-/* 0x0006 */ void aim_im_sendch2_connected(PeerConnection *peer_conn);
-/* 0x0006 */ void aim_im_sendch2_odc_requestdirect(OscarData *od, guchar *cookie, const char *bn, const guint8 *ip, guint16 port, guint16 requestnumber);
-/* 0x0006 */ void aim_im_sendch2_odc_requestproxy(OscarData *od, guchar *cookie, const char *bn, const guint8 *ip, guint16 pin, guint16 requestnumber);
-/* 0x0006 */ void aim_im_sendch2_sendfile_requestdirect(OscarData *od, guchar *cookie, const char *bn, const guint8 *ip, guint16 port, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles);
-/* 0x0006 */ void aim_im_sendch2_sendfile_requestproxy(OscarData *od, guchar *cookie, const char *bn, const guint8 *ip, guint16 pin, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles);
-
-/* 0x000b */ int aim_im_denytransfer(OscarData *od, const char *bn, const guchar *cookie, guint16 code);
-/* 0x0010 */ int aim_im_reqofflinemsgs(OscarData *od);
-/* 0x0014 */ int aim_im_sendmtn(OscarData *od, guint16 type1, const char *bn, guint16 type2);
-/* 0x000b */ int icq_relay_xstatus (OscarData *od, const char *sn, const guchar* cookie);
-void aim_icbm_makecookie(guchar* cookie);
-void aim_im_send_icq_confirmation(OscarData *od, const char *bn, const guchar *cookie);
-
-/* 0x0002 - family_locate.c */
-/*
- * AIM User Info, Standard Form.
- */
-#define AIM_FLAG_ADMINISTRATOR   0x0002
-#define AIM_FLAG_AOL             0x0004
-#define AIM_FLAG_AWAY            0x0020
-#define AIM_FLAG_WIRELESS        0x0080
-#define AIM_FLAG_ICQ             0x0040
-#define AIM_FLAG_ACTIVEBUDDY     0x0400
-
-#define AIM_USERINFO_PRESENT_FLAGS        0x00000001
-#define AIM_USERINFO_PRESENT_MEMBERSINCE  0x00000002
-#define AIM_USERINFO_PRESENT_ONLINESINCE  0x00000004
-#define AIM_USERINFO_PRESENT_IDLE         0x00000008
-#define AIM_USERINFO_PRESENT_ICQEXTSTATUS 0x00000010
-#define AIM_USERINFO_PRESENT_ICQIPADDR    0x00000020
-#define AIM_USERINFO_PRESENT_ICQDATA      0x00000040
-#define AIM_USERINFO_PRESENT_CAPABILITIES 0x00000080
-#define AIM_USERINFO_PRESENT_SESSIONLEN   0x00000100
-#define AIM_USERINFO_PRESENT_CREATETIME   0x00000200
-
-struct userinfo_node
-{
-	char *bn;
-	struct userinfo_node *next;
-};
-
-typedef struct aim_userinfo_s
-{
-	char *bn;
-	guint16 warnlevel; /* evil percent * 10 (999 = 99.9%) */
-	guint16 idletime; /* in seconds */
-	guint16 flags;
-	guint32 createtime; /* time_t */
-	guint32 membersince; /* time_t */
-	guint32 onlinesince; /* time_t */
-	guint32 sessionlen;  /* in seconds */
-	guint64 capabilities;
-	struct {
-		guint32 status;
-		guint32 ipaddr;
-		guint8 crap[0x25]; /* until we figure it out... */
-	} icqinfo;
-	guint32 present;
-
-	guint8 iconcsumtype;
-	guint16 iconcsumlen;
-	guint8 *iconcsum;
-
-	char *info;
-	char *info_encoding;
-	guint16 info_len;
-
-	char *status;
-	char *status_encoding;
-	guint16 status_len;
-
-	char *itmsurl;
-	char *itmsurl_encoding;
-	guint16 itmsurl_len;
-
-	char *away;
-	char *away_encoding;
-	guint16 away_len;
-
-	struct aim_userinfo_s *next;
-} aim_userinfo_t;
-
-struct aim_invite_priv
-{
-	char *bn;
-	char *roomname;
-	guint16 exchange;
-	guint16 instance;
-};
-
-#define AIM_COOKIETYPE_CHAT     0x01
-#define AIM_COOKIETYPE_INVITE   0x02
-
-aim_userinfo_t *aim_locate_finduserinfo(OscarData *od, const char *bn);
-void aim_locate_dorequest(OscarData *od);
-
-/* 0x0002 */ int aim_locate_reqrights(OscarData *od);
-/* 0x0004 */ int aim_locate_setcaps(OscarData *od, guint64 caps);
-/* 0x0004 */ int aim_locate_setprofile(OscarData *od, const char *profile_encoding, const gchar *profile, const int profile_len, const char *awaymsg_encoding, const gchar *awaymsg, const int awaymsg_len);
-/* 0x0015 */ int aim_locate_getinfoshort(OscarData *od, const char *bn, guint32 flags);
-
-guint64 aim_locate_getcaps(OscarData *od, ByteStream *bs, int len);
-guint64 aim_locate_getcaps_short(OscarData *od, ByteStream *bs, int len);
-void aim_info_free(aim_userinfo_t *);
-int aim_info_extract(OscarData *od, ByteStream *bs, aim_userinfo_t *);
-int aim_putuserinfo(ByteStream *bs, aim_userinfo_t *info);
-PurpleMood* icq_get_purple_moods(PurpleAccount *account);
-const char* icq_get_custom_icon_description(const char *mood);
-guint8* icq_get_custom_icon_data(const char *mood);
-int icq_im_xstatus_request(OscarData *od, const char *sn);
-
-/* 0x0003 - family_buddy.c */
-/* 0x0002 */ void aim_buddylist_reqrights(OscarData *, FlapConnection *);
-
-
-/* 0x000a - family_userlookup.c */
-int aim_search_address(OscarData *, const char *);
-
-struct aim_chat_exchangeinfo
-{
-	guint16 number;
-	guint16 flags;
-	char *name;
-	char *charset1;
-	char *lang1;
-	char *charset2;
-	char *lang2;
-};
-
-#define AIM_CHATFLAGS_NOREFLECT 0x0001
-#define AIM_CHATFLAGS_AWAY      0x0002
-int aim_chat_send_im(OscarData *od, FlapConnection *conn, guint16 flags, const gchar *msg, int msglen, const char *encoding, const char *language);
-int aim_chat_join(OscarData *od, guint16 exchange, const char *roomname, guint16 instance);
-
-void aim_chatnav_reqrights(OscarData *od, FlapConnection *conn);
-
-int aim_chatnav_createroom(OscarData *od, FlapConnection *conn, const char *name, guint16 exchange);
-
-
-/* 0x0010 - family_bart.c */
-int aim_bart_upload(OscarData *od, const guint8 *icon, guint16 iconlen);
-int aim_bart_request(OscarData *od, const char *bn, guint8 iconcsumtype, const guint8 *iconstr, guint16 iconstrlen);
-
-
-
-/* 0x0013 - family_feedbag.c */
-#define AIM_SSI_TYPE_BUDDY		0x0000
-#define AIM_SSI_TYPE_GROUP		0x0001
-#define AIM_SSI_TYPE_PERMIT		0x0002
-#define AIM_SSI_TYPE_DENY		0x0003
-#define AIM_SSI_TYPE_PDINFO		0x0004
-#define AIM_SSI_TYPE_PRESENCEPREFS	0x0005
-#define AIM_SSI_TYPE_ICQDENY		0x000e
-#define AIM_SSI_TYPE_ICONINFO		0x0014
-
-/* These flags are set in the 0x00c9 TLV of SSI type 0x0005 */
-#define AIM_SSI_PRESENCE_FLAG_SHOWIDLE        0x00000400
-#define AIM_SSI_PRESENCE_FLAG_NORECENTBUDDIES 0x00020000
-
-struct aim_ssi_item
-{
-	char *name;
-	guint16 gid;
-	guint16 bid;
-	guint16 type;
-	GSList *data;
-	struct aim_ssi_item *next;
-};
-
-struct aim_ssi_tmp
-{
-	guint16 action;
-	guint16 ack;
-	char *name;
-	struct aim_ssi_item *item;
-	struct aim_ssi_tmp *next;
-};
-
-/* These build the actual SNACs and queue them to be sent */
-/* 0x0002 */ int aim_ssi_reqrights(OscarData *od);
-/* 0x0004 */ int aim_ssi_reqdata(OscarData *od);
-/* 0x0007 */ int aim_ssi_enable(OscarData *od);
-/* 0x0011 */ int aim_ssi_modbegin(OscarData *od);
-/* 0x0012 */ int aim_ssi_modend(OscarData *od);
-/* 0x0018 */ int aim_ssi_sendauthrequest(OscarData *od, const char *bn, const char *msg);
-/* 0x001a */ int aim_ssi_sendauthreply(OscarData *od, const char *bn, guint8 reply, const char *msg);
-
-/* Client functions for retrieving SSI data */
-struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_itemlist *list, guint16 gid, guint16 bid);
-struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_itemlist *list, const char *gn, const char *bn, guint16 type);
-struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_itemlist *list, const char *bn);
-char *aim_ssi_itemlist_findparentname(struct aim_ssi_itemlist *list, const char *bn);
-int aim_ssi_getpermdeny(struct aim_ssi_itemlist *list);
-guint32 aim_ssi_getpresence(struct aim_ssi_itemlist *list);
-char *aim_ssi_getalias(struct aim_ssi_itemlist *list, const char *gn, const char *bn);
-char *aim_ssi_getalias_from_item(struct aim_ssi_item *item);
-char *aim_ssi_getcomment(struct aim_ssi_itemlist *list, const char *gn, const char *bn);
-gboolean aim_ssi_waitingforauth(struct aim_ssi_itemlist *list, const char *gn, const char *bn);
-
-/* Client functions for changing SSI data */
-int aim_ssi_addbuddy(OscarData *od, const char *name, const char *group, GSList *tlvlist, const char *alias, const char *comment, const char *smsnum, gboolean needauth);
-int aim_ssi_delbuddy(OscarData *od, const char *name, const char *group);
-int aim_ssi_delgroup(OscarData *od, const char *group);
-int aim_ssi_movebuddy(OscarData *od, const char *oldgn, const char *newgn, const char *bn);
-int aim_ssi_aliasbuddy(OscarData *od, const char *gn, const char *bn, const char *alias);
-int aim_ssi_editcomment(OscarData *od, const char *gn, const char *bn, const char *alias);
-int aim_ssi_rename_group(OscarData *od, const char *oldgn, const char *newgn);
-int aim_ssi_deletelist(OscarData *od);
-int aim_ssi_setpermdeny(OscarData *od, guint8 permdeny);
-int aim_ssi_setpresence(OscarData *od, guint32 presence);
-int aim_ssi_seticon(OscarData *od, const guint8 *iconsum, guint8 iconsumlen);
-int aim_ssi_delicon(OscarData *od);
-int aim_ssi_add_to_private_list(OscarData *od, const char* name, guint16 list_type);
-int aim_ssi_del_from_private_list(OscarData* od, const char* name, guint16 list_type);
-
-guint16 aim_ssi_getdenyentrytype(OscarData* od);
-
-struct aim_icq_info
-{
-	guint16 reqid;
-
-	/* simple */
-	guint32 uin;
-
-	/* general and "home" information (0x00c8) */
-	char *nick;
-	char *first;
-	char *last;
-	char *email;
-	char *homecity;
-	char *homestate;
-	char *homephone;
-	char *homefax;
-	char *homeaddr;
-	char *mobile;
-	char *homezip;
-	guint16 homecountry;
-/*	guint8 timezone;
-	guint8 hideemail; */
-
-	/* personal (0x00dc) */
-	guint8 age;
-	guint8 unknown;
-	guint8 gender;
-	char *personalwebpage;
-	guint16 birthyear;
-	guint8 birthmonth;
-	guint8 birthday;
-	guint8 language1;
-	guint8 language2;
-	guint8 language3;
-
-	/* work (0x00d2) */
-	char *workcity;
-	char *workstate;
-	char *workphone;
-	char *workfax;
-	char *workaddr;
-	char *workzip;
-	guint16 workcountry;
-	char *workcompany;
-	char *workdivision;
-	char *workposition;
-	char *workwebpage;
-
-	/* additional personal information (0x00e6) */
-	char *info;
-
-	/* email (0x00eb) */
-	guint16 numaddresses;
-	char **email2;
-
-	/* status note info */
-	guint8 icbm_cookie[8];
-	char *status_note_title;
-
-	gboolean for_auth_request;
-	char *auth_request_reason;
-};
-
-int aim_icq_setsecurity(OscarData *od, gboolean auth_required, gboolean webaware);
-int aim_icq_changepasswd(OscarData *od, const char *passwd);
-int aim_icq_getalias(OscarData *od, const char *uin, gboolean for_auth_request, char *auth_request_reason);
-int aim_icq_getallinfo(OscarData *od, const char *uin);
-int aim_icq_sendsms(OscarData *od, const char *name, const char *msg, const char *alias);
-
-
-/* 0x0017 - family_auth.c */
-void aim_sendcookie(OscarData *, FlapConnection *, const guint16 length, const guint8 *);
-void aim_admin_changepasswd(OscarData *, FlapConnection *, const char *newpw, const char *curpw);
-void aim_admin_reqconfirm(OscarData *od, FlapConnection *conn);
-void aim_admin_getinfo(OscarData *od, FlapConnection *conn, guint16 info);
-void aim_admin_setemail(OscarData *od, FlapConnection *conn, const char *newemail);
-void aim_admin_setnick(OscarData *od, FlapConnection *conn, const char *newnick);
-
-
-
-/* 0x0018 - family_alert.c */
-struct aim_emailinfo
-{
-	guint8 *cookie16;
-	guint8 *cookie8;
-	char *url;
-	guint16 nummsgs;
-	guint8 unread;
-	char *domain;
-	guint16 flag;
-	struct aim_emailinfo *next;
-};
-
-int aim_email_sendcookies(OscarData *od);
-int aim_email_activate(OscarData *od);
-
-
-
-/* tlv.c - TLV handling */
-
-/* TLV structure */
-typedef struct aim_tlv_s
-{
-	guint16 type;
-	guint16 length;
-	guint8 *value;
-} aim_tlv_t;
-
-/* TLV handling functions */
-char *aim_tlv_getvalue_as_string(aim_tlv_t *tlv);
-
-aim_tlv_t *aim_tlv_gettlv(GSList *list, const guint16 type, const int nth);
-int aim_tlv_getlength(GSList *list, const guint16 type, const int nth);
-char *aim_tlv_getstr(GSList *list, const guint16 type, const int nth);
-guint8 aim_tlv_get8(GSList *list, const guint16 type, const int nth);
-guint16 aim_tlv_get16(GSList *list, const guint16 type, const int nth);
-guint32 aim_tlv_get32(GSList *list, const guint16 type, const int nth);
-
-/* TLV list handling functions */
-GSList *aim_tlvlist_read(ByteStream *bs);
-GSList *aim_tlvlist_readnum(ByteStream *bs, guint16 num);
-GSList *aim_tlvlist_readlen(ByteStream *bs, guint16 len);
-GSList *aim_tlvlist_copy(GSList *orig);
-
-int aim_tlvlist_count(GSList *list);
-size_t aim_tlvlist_size(GSList *list);
-int aim_tlvlist_cmp(GSList *one, GSList *two);
-int aim_tlvlist_write(ByteStream *bs, GSList **list);
-void aim_tlvlist_free(GSList *list);
-
-int aim_tlvlist_add_raw(GSList **list, const guint16 type, const guint16 length, const guint8 *value);
-int aim_tlvlist_add_noval(GSList **list, const guint16 type);
-int aim_tlvlist_add_8(GSList **list, const guint16 type, const guint8 value);
-int aim_tlvlist_add_16(GSList **list, const guint16 type, const guint16 value);
-int aim_tlvlist_add_32(GSList **list, const guint16 type, const guint32 value);
-int aim_tlvlist_add_str(GSList **list, const guint16 type, const char *value);
-int aim_tlvlist_add_caps(GSList **list, const guint16 type, const guint64 caps, const char *mood);
-int aim_tlvlist_add_userinfo(GSList **list, guint16 type, aim_userinfo_t *userinfo);
-int aim_tlvlist_add_chatroom(GSList **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance);
-int aim_tlvlist_add_frozentlvlist(GSList **list, guint16 type, GSList **tl);
-
-int aim_tlvlist_replace_raw(GSList **list, const guint16 type, const guint16 lenth, const guint8 *value);
-int aim_tlvlist_replace_str(GSList **list, const guint16 type, const char *str);
-int aim_tlvlist_replace_noval(GSList **list, const guint16 type);
-int aim_tlvlist_replace_8(GSList **list, const guint16 type, const guint8 value);
-int aim_tlvlist_replace_16(GSList **list, const guint16 type, const guint16 value);
-int aim_tlvlist_replace_32(GSList **list, const guint16 type, const guint32 value);
-
-void aim_tlvlist_remove(GSList **list, const guint16 type);
-
-
-
-/* util.c */
-/* These are really ugly.  You'd think this was LISP.  I wish it was. */
-#define aimutil_put8(buf, data) ((*(buf) = (guint8)(data)&0xff),1)
-#define aimutil_get8(buf) ((*(buf))&0xff)
-#define aimutil_put16(buf, data) ( \
-		(*(buf) = (guint8)((data)>>8)&0xff), \
-		(*((buf)+1) = (guint8)(data)&0xff),  \
-		2)
-#define aimutil_get16(buf) ((((*(buf))<<8)&0xff00) + ((*((buf)+1)) & 0xff))
-#define aimutil_put32(buf, data) ( \
-		(*((buf)) = (guint8)((data)>>24)&0xff), \
-		(*((buf)+1) = (guint8)((data)>>16)&0xff), \
-		(*((buf)+2) = (guint8)((data)>>8)&0xff), \
-		(*((buf)+3) = (guint8)(data)&0xff), \
-		4)
-#define aimutil_get32(buf) ((((*(buf))<<24)&0xff000000) + \
-		(((*((buf)+1))<<16)&0x00ff0000) + \
-		(((*((buf)+2))<< 8)&0x0000ff00) + \
-		(((*((buf)+3)    )&0x000000ff)))
-
-/* Little-endian versions (damn ICQ) */
-#define aimutil_putle8(buf, data) ( \
-		(*(buf) = (guint8)(data) & 0xff), \
-		1)
-#define aimutil_getle8(buf) ( \
-		(*(buf)) & 0xff \
-		)
-#define aimutil_putle16(buf, data) ( \
-		(*((buf)+0) = (guint8)((data) >> 0) & 0xff),  \
-		(*((buf)+1) = (guint8)((data) >> 8) & 0xff), \
-		2)
-#define aimutil_getle16(buf) ( \
-		(((*((buf)+0)) << 0) & 0x00ff) + \
-		(((*((buf)+1)) << 8) & 0xff00) \
-		)
-#define aimutil_putle32(buf, data) ( \
-		(*((buf)+0) = (guint8)((data) >>  0) & 0xff), \
-		(*((buf)+1) = (guint8)((data) >>  8) & 0xff), \
-		(*((buf)+2) = (guint8)((data) >> 16) & 0xff), \
-		(*((buf)+3) = (guint8)((data) >> 24) & 0xff), \
-		4)
-#define aimutil_getle32(buf) ( \
-		(((*((buf)+0)) <<  0) & 0x000000ff) + \
-		(((*((buf)+1)) <<  8) & 0x0000ff00) + \
-		(((*((buf)+2)) << 16) & 0x00ff0000) + \
-		(((*((buf)+3)) << 24) & 0xff000000))
-
-const char *oscar_get_msgerr_reason(size_t reason);
-int oscar_get_ui_info_int(const char *str, int default_value);
-const char *oscar_get_ui_info_string(const char *str, const char *default_value);
-gchar *oscar_get_clientstring(void);
-
-guint16 aimutil_iconsum(const guint8 *buf, int buflen);
-
-gboolean oscar_util_valid_name(const char *bn);
-gboolean oscar_util_valid_name_icq(const char *bn);
-gboolean oscar_util_valid_name_sms(const char *bn);
-int oscar_util_name_compare(const char *bn1, const char *bn2);
-gchar *oscar_util_format_string(const char *str, const char *name);
-gchar *oscar_format_buddies(GSList *buddies, const gchar *no_buddies_message);
-
-typedef struct {
-	guint16 family;
-	guint16 subtype;
-	guint16 flags;
-	guint32 id;
-} aim_modsnac_t;
-
-#define AIM_MODULENAME_MAXLEN 16
-#define AIM_MODFLAG_MULTIFAMILY 0x0001
-typedef struct aim_module_s
-{
-	guint16 family;
-	guint16 version;
-	guint16 toolid;
-	guint16 toolversion;
-	guint16 flags;
-	char name[AIM_MODULENAME_MAXLEN+1];
-	int (*snachandler)(OscarData *od, FlapConnection *conn, struct aim_module_s *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs);
-	void (*shutdown)(OscarData *od, struct aim_module_s *mod);
-	void *priv;
-	struct aim_module_s *next;
-} aim_module_t;
-
-int aim__registermodule(OscarData *od, int (*modfirst)(OscarData *, aim_module_t *));
-void aim__shutdownmodules(OscarData *od);
-aim_module_t *aim__findmodulebygroup(OscarData *od, guint16 group);
-aim_module_t *aim__findmodule(OscarData *od, const char *name);
-
-int admin_modfirst(OscarData *od, aim_module_t *mod);
-int buddylist_modfirst(OscarData *od, aim_module_t *mod);
-int bos_modfirst(OscarData *od, aim_module_t *mod);
-int search_modfirst(OscarData *od, aim_module_t *mod);
-int stats_modfirst(OscarData *od, aim_module_t *mod);
-int auth_modfirst(OscarData *od, aim_module_t *mod);
-int msg_modfirst(OscarData *od, aim_module_t *mod);
-int misc_modfirst(OscarData *od, aim_module_t *mod);
-int chatnav_modfirst(OscarData *od, aim_module_t *mod);
-int chat_modfirst(OscarData *od, aim_module_t *mod);
-int locate_modfirst(OscarData *od, aim_module_t *mod);
-int service_modfirst(OscarData *od, aim_module_t *mod);
-int popups_modfirst(OscarData *od, aim_module_t *mod);
-int bart_modfirst(OscarData *od, aim_module_t *mod);
-int ssi_modfirst(OscarData *od, aim_module_t *mod);
-int icq_modfirst(OscarData *od, aim_module_t *mod);
-int email_modfirst(OscarData *od, aim_module_t *mod);
-
-void aim_genericreq_n(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype);
-void aim_genericreq_n_snacid(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype);
-void aim_genericreq_l(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype, guint32 *);
-
-/* bstream.c */
-int byte_stream_new(ByteStream *bs, size_t len);
-int byte_stream_init(ByteStream *bs, guint8 *data, size_t len);
-void byte_stream_destroy(ByteStream *bs);
-size_t byte_stream_bytes_left(ByteStream *bs);
-int byte_stream_curpos(ByteStream *bs);
-int byte_stream_setpos(ByteStream *bs, size_t off);
-void byte_stream_rewind(ByteStream *bs);
-int byte_stream_advance(ByteStream *bs, int n);
-guint8 byte_stream_get8(ByteStream *bs);
-guint16 byte_stream_get16(ByteStream *bs);
-guint32 byte_stream_get32(ByteStream *bs);
-guint8 byte_stream_getle8(ByteStream *bs);
-guint16 byte_stream_getle16(ByteStream *bs);
-guint32 byte_stream_getle32(ByteStream *bs);
-int byte_stream_getrawbuf(ByteStream *bs, guint8 *buf, size_t len);
-guint8 *byte_stream_getraw(ByteStream *bs, size_t len);
-char *byte_stream_getstr(ByteStream *bs, size_t len);
-int byte_stream_put8(ByteStream *bs, guint8 v);
-int byte_stream_put16(ByteStream *bs, guint16 v);
-int byte_stream_put32(ByteStream *bs, guint32 v);
-int byte_stream_putle8(ByteStream *bs, guint8 v);
-int byte_stream_putle16(ByteStream *bs, guint16 v);
-int byte_stream_putle32(ByteStream *bs, guint32 v);
-int byte_stream_putraw(ByteStream *bs, const guint8 *v, size_t len);
-int byte_stream_putstr(ByteStream *bs, const char *str);
-int byte_stream_putbs(ByteStream *bs, ByteStream *srcbs, size_t len);
-int byte_stream_putuid(ByteStream *bs, OscarData *od);
-int byte_stream_putcaps(ByteStream *bs, guint64 caps);
-
-/**
- * Inserts a BART asset block into the given byte stream.  The flags
- * and length are set appropriately based on the value of data.
- */
-void byte_stream_put_bart_asset(ByteStream *bs, guint16 type, ByteStream *data);
-
-/**
- * A helper function that calls byte_stream_put_bart_asset with the
- * appropriate data ByteStream given the datastr.
- */
-void byte_stream_put_bart_asset_str(ByteStream *bs, guint16 type, const char *datastr);
-
-/*
- * Generic SNAC structure.  Rarely if ever used.
- */
-typedef struct aim_snac_s {
-	aim_snacid_t id;
-	guint16 family;
-	guint16 type;
-	guint16 flags;
-	void *data;
-	time_t issuetime;
-	struct aim_snac_s *next;
-} aim_snac_t;
-
-/* snac.c */
-void aim_initsnachash(OscarData *od);
-aim_snacid_t aim_newsnac(OscarData *, aim_snac_t *newsnac);
-aim_snacid_t aim_cachesnac(OscarData *od, const guint16 family, const guint16 type, const guint16 flags, const void *data, const int datalen);
-aim_snac_t *aim_remsnac(OscarData *, aim_snacid_t id);
-void aim_cleansnacs(OscarData *, int maxage);
-int aim_putsnac(ByteStream *, guint16 family, guint16 type, aim_snacid_t id);
-
-struct chatsnacinfo {
-	guint16 exchange;
-	char name[128];
-	guint16 instance;
-};
-
-struct rateclass {
-	guint16 classid;
-	guint32 windowsize;
-	guint32 clear;
-	guint32 alert;
-	guint32 limit;
-	guint32 disconnect;
-	guint32 current;
-	guint32 max;
-	guint8 dropping_snacs;
-
-	struct timeval last; /**< The time when we last sent a SNAC of this rate class. */
-};
-
-int aim_cachecookie(OscarData *od, IcbmCookie *cookie);
-IcbmCookie *aim_uncachecookie(OscarData *od, guint8 *cookie, int type);
-IcbmCookie *aim_mkcookie(guint8 *, int, void *);
-IcbmCookie *aim_checkcookie(OscarData *, const unsigned char *, const int);
-int aim_freecookie(OscarData *od, IcbmCookie *cookie);
-int aim_cookie_free(OscarData *od, IcbmCookie *cookie);
-
-int aim_chat_readroominfo(ByteStream *bs, struct aim_chat_roominfo *outinfo);
-
-void flap_connection_destroy_chat(OscarData *od, FlapConnection *conn);
-
-/* userinfo.c - displaying user information */
-
-void oscar_user_info_append_status(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo, gboolean use_html_status);
-void oscar_user_info_append_extra_info(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo);
-void oscar_user_info_display_error(OscarData *od, guint16 error_reason, char *buddy);
-void oscar_user_info_display_icq(OscarData *od, struct aim_icq_info *info);
-void oscar_user_info_display_aim(OscarData *od, aim_userinfo_t *userinfo);
-
-/* authorization.c - OSCAR authorization requests */
-void oscar_auth_sendrequest(PurpleConnection *gc, const char *name, const char *msg);
-void oscar_auth_sendrequest_menu(PurpleBlistNode *node, gpointer ignored);
-void oscar_auth_recvrequest(PurpleConnection *gc, gchar *name, gchar *nick, gchar *reason);
-
-void oscar_set_aim_permdeny(PurpleConnection *gc);
-
-struct buddyinfo
-{
-	gboolean typingnot;
-	guint32 ipaddr;
-
-	unsigned long ico_me_len;
-	unsigned long ico_me_csum;
-	time_t ico_me_time;
-	gboolean ico_informed;
-
-	unsigned long ico_len;
-	unsigned long ico_csum;
-	time_t ico_time;
-	gboolean ico_need;
-	gboolean ico_sent;
-};
-
-struct name_data
-{
-	PurpleConnection *gc;
-	gchar *name;
-	gchar *nick;
-};
-
-void oscar_free_name_data(struct name_data *data);
-
-void oscar_init_account_options(PurpleProtocol *protocol, gboolean is_icq);
-
-G_END_DECLS
-
-#endif /* PURPLE_OSCAR_OSCAR_H */
--- a/libpurple/protocols/oscar/oscar_data.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,167 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-#include "oscar.h"
-
-typedef struct _SnacHandler SnacHandler;
-
-struct _SnacHandler
-{
-	guint16 family;
-	guint16 subtype;
-	aim_rxcallback_t handler;
-	guint16 flags;
-};
-
-/**
- * Allocates a new OscarData and initializes it with default values.
- */
-OscarData *
-oscar_data_new(void)
-{
-	OscarData *od;
-	aim_module_t *cur;
-	GString *msg;
-
-	od = g_new0(OscarData, 1);
-
-	aim_initsnachash(od);
-	od->snacid_next = 0x00000001;
-	od->buddyinfo = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
-	od->handlerlist = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
-
-	od->ssi.local.idx_gid_bid = g_hash_table_new(g_direct_hash, g_direct_equal);
-	od->ssi.local.idx_all_named_items = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
-
-	od->ssi.official.idx_gid_bid = g_hash_table_new(g_direct_hash, g_direct_equal);
-	od->ssi.official.idx_all_named_items = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
-
-	/*
-	 * Register all the modules for this session...
-	 */
-	aim__registermodule(od, misc_modfirst); /* load the catch-all first */
-	aim__registermodule(od, service_modfirst);
-	aim__registermodule(od, locate_modfirst);
-	aim__registermodule(od, buddylist_modfirst);
-	aim__registermodule(od, msg_modfirst);
-	aim__registermodule(od, admin_modfirst);
-	aim__registermodule(od, popups_modfirst);
-	aim__registermodule(od, bos_modfirst);
-	aim__registermodule(od, search_modfirst);
-	aim__registermodule(od, stats_modfirst);
-	aim__registermodule(od, chatnav_modfirst);
-	aim__registermodule(od, chat_modfirst);
-	aim__registermodule(od, bart_modfirst);
-	/* missing 0x11 - 0x12 */
-	aim__registermodule(od, ssi_modfirst);
-	/* missing 0x14 */
-	aim__registermodule(od, icq_modfirst);
-	/* missing 0x16 */
-	/* auth_modfirst is only needed if we're connecting with the old-style BUCP login */
-	aim__registermodule(od, auth_modfirst);
-	aim__registermodule(od, email_modfirst);
-
-	msg = g_string_new("Registered modules: ");
-	for (cur = od->modlistv; cur; cur = cur->next) {
-		g_string_append_printf(
-			msg,
-			"%s (family=0x%04x, version=0x%04x, toolid=0x%04x, toolversion=0x%04x), ",
-			cur->name,
-			cur->family,
-			cur->version,
-			cur->toolid,
-			cur->toolversion);
-	}
-	purple_debug_misc("oscar", "%s\n", msg->str);
-	g_string_free(msg, TRUE);
-
-	return od;
-}
-
-/**
- * Logoff and deallocate a session.
- *
- * @param od Session to kill
- */
-void
-oscar_data_destroy(OscarData *od)
-{
-	aim_cleansnacs(od, -1);
-
-	/* Only used when connecting with clientLogin or Kerberos. */
-	if (od->http_conns) {
-		soup_session_abort(od->http_conns);
-		g_object_unref(od->http_conns);
-	}
-
-	g_slist_free_full(od->requesticon, g_free);
-	g_free(od->email);
-	g_free(od->newp);
-	g_free(od->oldp);
-	if (od->getblisttimer > 0)
-		g_source_remove(od->getblisttimer);
-	while (od->oscar_connections != NULL)
-		flap_connection_destroy(od->oscar_connections->data,
-				OSCAR_DISCONNECT_DONE, NULL);
-
-	while (od->peer_connections != NULL)
-		peer_connection_destroy(od->peer_connections->data,
-				OSCAR_DISCONNECT_LOCAL_CLOSED, NULL);
-
-	aim__shutdownmodules(od);
-
-	g_hash_table_destroy(od->buddyinfo);
-	g_hash_table_destroy(od->handlerlist);
-
-	g_hash_table_destroy(od->ssi.local.idx_gid_bid);
-	g_hash_table_destroy(od->ssi.local.idx_all_named_items);
-
-	g_hash_table_destroy(od->ssi.official.idx_gid_bid);
-	g_hash_table_destroy(od->ssi.official.idx_all_named_items);
-
-	g_free(od);
-}
-
-void
-oscar_data_addhandler(OscarData *od, guint16 family, guint16 subtype, aim_rxcallback_t newhandler, guint16 flags)
-{
-	SnacHandler *snac_handler;
-
-	snac_handler = g_new0(SnacHandler, 1);
-
-	snac_handler->family = family;
-	snac_handler->subtype = subtype;
-	snac_handler->flags = flags;
-	snac_handler->handler = newhandler;
-
-	g_hash_table_insert(od->handlerlist,
-			GUINT_TO_POINTER((family << 16) + subtype),
-			snac_handler);
-}
-
-aim_rxcallback_t
-aim_callhandler(OscarData *od, guint16 family, guint16 subtype)
-{
-	SnacHandler *snac_handler;
-
-	snac_handler = g_hash_table_lookup(od->handlerlist, GUINT_TO_POINTER((family << 16) + subtype));
-
-	return snac_handler ? snac_handler->handler : NULL;
-}
--- a/libpurple/protocols/oscar/oscarcommon.h	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-/* purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- *
- */
-
-/* oscarcommon.h contains prototypes for the protocol functions used by libaim.c
- * and libicq.c
- */
-
-#ifndef PURPLE_OSCAR_OSCARCOMMON_H
-#define PURPLE_OSCAR_OSCARCOMMON_H
-
-#include "internal.h"
-
-#include "protocol.h"
-#include "version.h"
-#include "notify.h"
-#include "purpleaccountoption.h"
-#include "status.h"
-
-#define AIM_DEFAULT_LOGIN_SERVER "login.oscar.aol.com"
-#define AIM_ALT_LOGIN_SERVER "login.messaging.aol.com"
-#define AIM_DEFAULT_SSL_LOGIN_SERVER "slogin.oscar.aol.com"
-#define ICQ_DEFAULT_LOGIN_SERVER "login.icq.com"
-#define ICQ_DEFAULT_SSL_LOGIN_SERVER "slogin.icq.com"
-
-#define AIM_DEFAULT_KDC_SERVER "kdc.uas.aol.com"
-#define AIM_DEFAULT_KDC_PORT 443
-
-/*
- * Using clientLogin requires a developer ID.  This key is for libpurple.
- * It is the default key for all libpurple-based clients.  AOL encourages
- * UIs (especially ones with lots of users) to override this with their
- * own key.
- */
-#define ICQ_DEFAULT_DIST_ID 1553
-#define ICQ_DEFAULT_CLIENT_KEY "ma15d7JTxbmVG-RP"
-#define AIM_DEFAULT_DIST_ID 1717
-#define AIM_DEFAULT_CLIENT_KEY "ma19CwYN9i9Mw5nY"
-
-#define OSCAR_DEFAULT_LOGIN_PORT 5190
-
-#define OSCAR_OPPORTUNISTIC_ENCRYPTION "opportunistic_encryption"
-#define OSCAR_REQUIRE_ENCRYPTION "require_encryption"
-#define OSCAR_NO_ENCRYPTION "no_encryption"
-
-#define OSCAR_MD5_LOGIN "md5_login"
-#define OSCAR_CLIENT_LOGIN "client_login"
-#define OSCAR_KERBEROS_LOGIN "kerberos_login"
-
-#ifndef _WIN32
-#define OSCAR_DEFAULT_CUSTOM_ENCODING "ISO-8859-1"
-#else
-#define OSCAR_DEFAULT_CUSTOM_ENCODING oscar_get_locale_charset()
-#endif
-#define OSCAR_DEFAULT_AUTHORIZATION TRUE
-#define OSCAR_DEFAULT_HIDE_IP TRUE
-#define OSCAR_DEFAULT_WEB_AWARE FALSE
-#define OSCAR_DEFAULT_ALWAYS_USE_RV_PROXY FALSE
-#define OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS TRUE
-#define OSCAR_DEFAULT_LOGIN OSCAR_CLIENT_LOGIN
-#define OSCAR_DEFAULT_ENCRYPTION OSCAR_OPPORTUNISTIC_ENCRYPTION
-
-#ifdef _WIN32
-const char *oscar_get_locale_charset(void);
-#endif
-PurpleMood* oscar_get_purple_moods(PurpleAccount *account);
-const char *oscar_list_icon_icq(PurpleAccount *a, PurpleBuddy *b);
-const char *oscar_list_icon_aim(PurpleAccount *a, PurpleBuddy *b);
-const char* oscar_list_emblem(PurpleBuddy *b);
-char *oscar_status_text(PurpleBuddy *b);
-void oscar_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full);
-GList *oscar_status_types(PurpleAccount *account);
-GList *oscar_blist_node_menu(PurpleBlistNode *node);
-GList *oscar_chat_info(PurpleConnection *gc);
-GHashTable *oscar_chat_info_defaults(PurpleConnection *gc, const char *chat_name);
-void oscar_login(PurpleAccount *account);
-void oscar_close(PurpleConnection *gc);
-int oscar_send_im(PurpleConnection *gc, PurpleMessage *msg);
-void oscar_set_info(PurpleConnection *gc, const char *rawinfo);
-unsigned int oscar_send_typing(PurpleConnection *gc, const char *name, PurpleIMTypingState state);
-void oscar_get_info(PurpleConnection *gc, const char *name);
-void oscar_set_status(PurpleAccount *account, PurpleStatus *status);
-void oscar_set_idle(PurpleConnection *gc, int time);
-void oscar_change_passwd(PurpleConnection *gc, const char *old, const char *new);
-void oscar_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group, const char *msg);
-void oscar_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group);
-void oscar_add_permit(PurpleConnection *gc, const char *who);
-void oscar_add_deny(PurpleConnection *gc, const char *who);
-void oscar_rem_permit(PurpleConnection *gc, const char *who);
-void oscar_rem_deny(PurpleConnection *gc, const char *who);
-void oscar_join_chat(PurpleConnection *gc, GHashTable *data);
-char *oscar_get_chat_name(GHashTable *data);
-void oscar_chat_invite(PurpleConnection *gc, int id, const char *message, const char *name);
-void oscar_chat_leave(PurpleConnection *gc, int id);
-int oscar_send_chat(PurpleConnection *gc, int id, PurpleMessage *msg);
-void oscar_keepalive(PurpleConnection *gc);
-void oscar_alias_buddy(PurpleConnection *gc, const char *name, const char *alias);
-void oscar_move_buddy(PurpleConnection *gc, const char *name, const char *old_group, const char *new_group);
-void oscar_rename_group(PurpleConnection *gc, const char *old_name, PurpleGroup *group, GList *moved_buddies);
-void oscar_convo_closed(PurpleConnection *gc, const char *who);
-const char *oscar_normalize(const PurpleAccount *account, const char *str);
-void oscar_set_icon(PurpleConnection *gc, PurpleImage *img);
-void oscar_remove_group(PurpleConnection *gc, PurpleGroup *group);
-gboolean oscar_can_receive_file(PurpleProtocolXfer *prplxfer, PurpleConnection *gc, const char *who);
-void oscar_send_file(PurpleProtocolXfer *prplxfer, PurpleConnection *gc, const char *who, const char *file);
-PurpleXfer *oscar_new_xfer(PurpleProtocolXfer *prplxfer, PurpleConnection *gc, const char *who);
-gboolean oscar_offline_message(const PurpleBuddy *buddy);
-gssize oscar_get_max_message_size(PurpleConversation *conv);
-GList *oscar_get_actions(PurpleConnection *gc);
-const gchar *oscar_get_login_server(gboolean is_icq, gboolean use_ssl);
-gboolean oscar_uri_handler(const char *proto, const char *cmd, GHashTable *params);
-
-#endif /* PURPLE_OSCAR_OSCARCOMMON_H */
--- a/libpurple/protocols/oscar/peer.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1212 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Functions dealing with peer connections.  This includes the code
- * used to establish a peer connection for both Oscar File transfer
- * (OFT) and Oscar Direct Connect (ODC).  (ODC is also referred to
- * as DirectIM and IM Image.)
- */
-
-#ifdef HAVE_CONFIG_H
-#include  <config.h>
-#endif
-
-/* From the oscar PRPL */
-#include "oscar.h"
-#include "peer.h"
-
-/* From Purple */
-#include "conversation.h"
-#include "xfer.h"
-#include "network.h"
-#include "notify.h"
-#include "request.h"
-#include "util.h"
-
-#ifndef _WIN32
-#include <stdio.h>
-#include <netdb.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h> /* for inet_ntoa */
-#include <limits.h> /* for UINT_MAX */
-#endif
-
-/*
- * I really want to switch all our networking code to using IPv6 only,
- * but that really isn't a good idea at all.  Evan S. of Adium says
- * OS X sets all connections as "AF_INET6/PF_INET6," even if there is
- * nothing inherently IPv6 about them.  And I feel like Linux kernel
- * 2.6.5 is doing the same thing.  So we REALLY should accept
- * connections if they're showing up as IPv6.  Old OSes (Solaris?)
- * that might not have full IPv6 support yet will fail if we try
- * to use PF_INET6 but it isn't defined.  --Mark Doliner
- */
-#ifndef PF_INET6
-#define PF_INET6 PF_INET
-#endif
-
-PeerConnection *
-peer_connection_find_by_type(OscarData *od, const char *bn, guint64 type)
-{
-	GSList *cur;
-	PeerConnection *conn;
-
-	for (cur = od->peer_connections; cur != NULL; cur = cur->next)
-	{
-		conn = cur->data;
-		if ((conn->type == type) && !oscar_util_name_compare(conn->bn, bn))
-			return conn;
-	}
-
-	return NULL;
-}
-
-/**
- * @param cookie This must be exactly 8 characters.
- */
-PeerConnection *
-peer_connection_find_by_cookie(OscarData *od, const char *bn, const guchar *cookie)
-{
-	GSList *cur;
-	PeerConnection *conn;
-
-	for (cur = od->peer_connections; cur != NULL; cur = cur->next)
-	{
-		conn = cur->data;
-		if (!memcmp(conn->cookie, cookie, 8) && !oscar_util_name_compare(conn->bn, bn))
-			return conn;
-	}
-
-	return NULL;
-}
-
-PeerConnection *
-peer_connection_new(OscarData *od, guint64 type, const char *bn)
-{
-	PeerConnection *conn;
-	PurpleAccount *account;
-
-	account = purple_connection_get_account(od->gc);
-
-	conn = g_new0(PeerConnection, 1);
-	conn->od = od;
-	conn->type = type;
-	conn->bn = g_strdup(bn);
-	conn->buffer_outgoing = purple_circular_buffer_new(0);
-	conn->listenerfd = -1;
-	conn->fd = -1;
-	conn->lastactivity = time(NULL);
-	conn->use_proxy |= purple_account_get_bool(account, "always_use_rv_proxy", FALSE);
-
-	if (type == OSCAR_CAPABILITY_DIRECTIM)
-		memcpy(conn->magic, "ODC2", 4);
-	else if (type == OSCAR_CAPABILITY_SENDFILE)
-		memcpy(conn->magic, "OFT2", 4);
-
-	od->peer_connections = g_slist_prepend(od->peer_connections, conn);
-
-	return conn;
-}
-
-static void
-peer_connection_close(PeerConnection *conn)
-{
-	if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
-		peer_odc_close(conn);
-	else if (conn->type == OSCAR_CAPABILITY_SENDFILE)
-		peer_oft_close(conn);
-
-	if (conn->verified_connect_data != NULL)
-	{
-		purple_proxy_connect_cancel(conn->verified_connect_data);
-		conn->verified_connect_data = NULL;
-	}
-
-	if (conn->client_connect_data != NULL)
-	{
-		purple_proxy_connect_cancel(conn->client_connect_data);
-		conn->client_connect_data = NULL;
-	}
-
-	if (conn->listen_data != NULL)
-	{
-		purple_network_listen_cancel(conn->listen_data);
-		conn->listen_data = NULL;
-	}
-
-	if (conn->connect_timeout_timer != 0)
-	{
-		g_source_remove(conn->connect_timeout_timer);
-		conn->connect_timeout_timer = 0;
-	}
-
-	if (conn->watcher_incoming != 0)
-	{
-		purple_input_remove(conn->watcher_incoming);
-		conn->watcher_incoming = 0;
-	}
-	if (conn->watcher_outgoing != 0)
-	{
-		purple_input_remove(conn->watcher_outgoing);
-		conn->watcher_outgoing = 0;
-	}
-	if (conn->listenerfd >= 0)
-	{
-		close(conn->listenerfd);
-		conn->listenerfd = -1;
-	}
-	if (conn->fd >= 0)
-	{
-		close(conn->fd);
-		conn->fd = -1;
-	}
-
-	g_free(conn->buffer_incoming.data);
-	conn->buffer_incoming.data = NULL;
-	conn->buffer_incoming.len = 0;
-	conn->buffer_incoming.offset = 0;
-
-	g_object_unref(G_OBJECT(conn->buffer_outgoing));
-	conn->buffer_outgoing = purple_circular_buffer_new(0);
-
-	conn->flags &= ~PEER_CONNECTION_FLAG_IS_INCOMING;
-}
-
-static gboolean
-peer_connection_destroy_cb(gpointer data)
-{
-	PeerConnection *conn;
-
-	conn = data;
-
-	purple_request_close_with_handle(conn);
-
-	peer_connection_close(conn);
-
-	if (conn->checksum_data != NULL)
-		peer_oft_checksum_destroy(conn->checksum_data);
-
-	if (conn->xfer != NULL)
-	{
-		PurpleXferStatus status;
-		status = purple_xfer_get_status(conn->xfer);
-		if ((status != PURPLE_XFER_STATUS_DONE) &&
-			(status != PURPLE_XFER_STATUS_CANCEL_LOCAL) &&
-			(status != PURPLE_XFER_STATUS_CANCEL_REMOTE))
-		{
-			if ((conn->disconnect_reason == OSCAR_DISCONNECT_REMOTE_CLOSED) ||
-				(conn->disconnect_reason == OSCAR_DISCONNECT_REMOTE_REFUSED))
-				purple_xfer_cancel_remote(conn->xfer);
-			else
-				purple_xfer_cancel_local(conn->xfer);
-		}
-		g_object_unref(conn->xfer);
-		conn->xfer = NULL;
-	}
-
-	g_free(conn->bn);
-	g_free(conn->error_message);
-	g_free(conn->proxyip);
-	g_free(conn->clientip);
-	g_free(conn->verifiedip);
-	g_free(conn->xferdata.name);
-	g_object_unref(G_OBJECT(conn->buffer_outgoing));
-
-	conn->od->peer_connections = g_slist_remove(conn->od->peer_connections, conn);
-
-	g_free(conn);
-
-	return FALSE;
-}
-
-void
-peer_connection_destroy(PeerConnection *conn, OscarDisconnectReason reason, const gchar *error_message)
-{
-	if (conn->destroy_timeout != 0)
-		g_source_remove(conn->destroy_timeout);
-	conn->disconnect_reason = reason;
-	g_free(conn->error_message);
-	conn->error_message = g_strdup(error_message);
-	peer_connection_destroy_cb(conn);
-}
-
-void
-peer_connection_schedule_destroy(PeerConnection *conn, OscarDisconnectReason reason, const gchar *error_message)
-{
-	if (conn->destroy_timeout != 0)
-		/* Already taken care of */
-		return;
-
-	purple_debug_info("oscar", "Scheduling destruction of peer connection\n");
-	conn->disconnect_reason = reason;
-	g_free(conn->error_message);
-	conn->error_message = g_strdup(error_message);
-	conn->destroy_timeout = g_timeout_add(0, peer_connection_destroy_cb, conn);
-}
-
-/*******************************************************************/
-/* Begin code for receiving data on a peer connection                */
-/*******************************************************************/
-
-/**
- * This should be used to read ODC and OFT framing info.  It should
- * NOT be used to read the payload sent across the connection (IMs,
- * file data, etc), and it should NOT be used to read proxy negotiation
- * headers.
- *
- * Unlike flap_connection_recv_cb(), this only reads one frame at a
- * time.  This is done so that the watcher can be changed during the
- * handling of the frame.  If the watcher is changed then this
- * function will not read in any more data.  This happens when
- * reading the payload of a direct IM frame, or when we're
- * receiving a file from the remote user.  Once the data has been
- * read, the watcher will be switched back to this function to
- * continue reading the next frame.
- */
-void
-peer_connection_recv_cb(gpointer data, gint source, PurpleInputCondition cond)
-{
-	PeerConnection *conn;
-	gssize read;
-
-	conn = data;
-
-	/* Start reading a new ODC/OFT frame */
-	if (conn->buffer_incoming.data == NULL)
-	{
-		/* Read the first 6 bytes (magic string and frame length) */
-		read = recv(conn->fd, conn->header + conn->header_received,
-				6 - conn->header_received, 0);
-
-		/* Check if the remote user closed the connection */
-		if (read == 0)
-		{
-			peer_connection_destroy(conn, OSCAR_DISCONNECT_REMOTE_CLOSED, NULL);
-			return;
-		}
-
-		/* If there was an error then close the connection */
-		if (read < 0)
-		{
-			if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
-				/* No worries */
-				return;
-
-			peer_connection_destroy(conn,
-					OSCAR_DISCONNECT_LOST_CONNECTION, g_strerror(errno));
-			return;
-		}
-
-		conn->lastactivity = time(NULL);
-
-		/* If we don't even have the first 6 bytes then do nothing */
-		conn->header_received += read;
-		if (conn->header_received < 6)
-			return;
-
-		/* All ODC/OFT frames must start with a magic string */
-		if (memcmp(conn->magic, conn->header, 4))
-		{
-			purple_debug_warning("oscar", "Expecting magic string to "
-				"be %c%c%c%c but received magic string %c%c%c%c.  "
-				"Closing connection.\n",
-				conn->magic[0], conn->magic[1], conn->magic[2],
-				conn->magic[3], conn->header[0], conn->header[1],
-				conn->header[2], conn->header[3]);
-			peer_connection_destroy(conn, OSCAR_DISCONNECT_INVALID_DATA, NULL);
-			return;
-		}
-
-		/* Initialize a new temporary ByteStream for incoming data */
-		conn->buffer_incoming.len = aimutil_get16(&conn->header[4]) - 6;
-		conn->buffer_incoming.data = g_new(guint8, conn->buffer_incoming.len);
-		conn->buffer_incoming.offset = 0;
-	}
-
-	/* Read data into the temporary buffer until it is complete */
-	read = recv(conn->fd,
-				&conn->buffer_incoming.data[conn->buffer_incoming.offset],
-				conn->buffer_incoming.len - conn->buffer_incoming.offset,
-				0);
-
-	/* Check if the remote user closed the connection */
-	if (read == 0)
-	{
-		peer_connection_destroy(conn, OSCAR_DISCONNECT_REMOTE_CLOSED, NULL);
-		return;
-	}
-
-	if (read < 0)
-	{
-		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
-			/* No worries */
-			return;
-
-		peer_connection_destroy(conn,
-				OSCAR_DISCONNECT_LOST_CONNECTION, g_strerror(errno));
-		return;
-	}
-
-	conn->lastactivity = time(NULL);
-	conn->buffer_incoming.offset += read;
-	if (conn->buffer_incoming.offset < conn->buffer_incoming.len)
-		/* Waiting for more data to arrive */
-		return;
-
-	/* We have a complete ODC/OFT frame!  Handle it and continue reading */
-	byte_stream_rewind(&conn->buffer_incoming);
-	if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
-	{
-		peer_odc_recv_frame(conn, &conn->buffer_incoming);
-	}
-	else if (conn->type == OSCAR_CAPABILITY_SENDFILE)
-	{
-		peer_oft_recv_frame(conn, &conn->buffer_incoming);
-	}
-
-	g_free(conn->buffer_incoming.data);
-	conn->buffer_incoming.data = NULL;
-
-	conn->header_received = 0;
-}
-
-/*******************************************************************/
-/* End code for receiving data on a peer connection                */
-/*******************************************************************/
-
-/*******************************************************************/
-/* Begin code for sending data on a peer connection                */
-/*******************************************************************/
-
-static void
-send_cb(gpointer data, gint source, PurpleInputCondition cond)
-{
-	PeerConnection *conn;
-	gsize writelen;
-	gssize wrotelen;
-	const gchar *output = NULL;
-
-	conn = data;
-	writelen = purple_circular_buffer_get_max_read(conn->buffer_outgoing);
-
-	if (writelen == 0)
-	{
-		purple_input_remove(conn->watcher_outgoing);
-		conn->watcher_outgoing = 0;
-		/*
-		 * The buffer is currently empty, so reset the current input
-		 * and output positions to the start of the buffer.  We do
-		 * this so that the next chunk of data that we put into the
-		 * buffer can be read back out of the buffer in one fell swoop.
-		 * Otherwise it gets fragmented and we have to read from the
-		 * second half of the buffer than go back and read the rest of
-		 * the chunk from the first half.
-		 *
-		 * We're using TCP, which is a stream based protocol, so this
-		 * isn't supposed to matter.  However, experience has shown
-		 * that at least the proxy file transfer code in AIM 6.1.41.2
-		 * requires that the entire OFT frame arrive all at once.  If
-		 * the frame is fragmented then AIM freaks out and aborts the
-		 * file transfer.  Somebody should teach those guys how to
-		 * write good TCP code.
-		 */
-		purple_circular_buffer_reset(conn->buffer_outgoing);
-		return;
-	}
-
-	output = purple_circular_buffer_get_output(conn->buffer_outgoing);
-
-	wrotelen = send(conn->fd, output, writelen, 0);
-	if (wrotelen <= 0)
-	{
-		if (wrotelen < 0 && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
-			/* No worries */
-			return;
-
-		if (conn->ready)
-		{
-			purple_input_remove(conn->watcher_outgoing);
-			conn->watcher_outgoing = 0;
-			close(conn->fd);
-			conn->fd = -1;
-			peer_connection_schedule_destroy(conn,
-					OSCAR_DISCONNECT_LOST_CONNECTION, NULL);
-		}
-		else
-		{
-			/*
-			 * This could happen when unable to send a negotiation
-			 * frame to a peer proxy server.
-			 */
-			peer_connection_trynext(conn);
-		}
-		return;
-	}
-
-	purple_circular_buffer_mark_read(conn->buffer_outgoing, wrotelen);
-	conn->lastactivity = time(NULL);
-}
-
-/**
- * This should be called by OFT/ODC code to send a standard OFT or ODC
- * frame across the peer connection along with some payload data.  Or
- * maybe a file.  Anything, really.
- */
-void
-peer_connection_send(PeerConnection *conn, ByteStream *bs)
-{
-	/* Add everything to our outgoing buffer */
-	purple_circular_buffer_append(conn->buffer_outgoing, bs->data, bs->len);
-
-	/* If we haven't already started writing stuff, then start the cycle */
-	if ((conn->watcher_outgoing == 0) && (conn->fd >= 0))
-	{
-		conn->watcher_outgoing = purple_input_add(conn->fd,
-				PURPLE_INPUT_WRITE, send_cb, conn);
-		send_cb(conn, conn->fd, 0);
-	}
-}
-
-/*******************************************************************/
-/* End code for sending data on a peer connection                  */
-/*******************************************************************/
-
-/*******************************************************************/
-/* Begin code for establishing a peer connection                   */
-/*******************************************************************/
-
-void
-peer_connection_finalize_connection(PeerConnection *conn)
-{
-	conn->watcher_incoming = purple_input_add(conn->fd,
-			PURPLE_INPUT_READ, peer_connection_recv_cb, conn);
-
-	if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
-	{
-		/*
-		 * If we are connecting to them then send our cookie so they
-		 * can verify who we are.  Note: This doesn't seem to be
-		 * necessary, but it also doesn't seem to hurt.
-		 */
-		if (!(conn->flags & PEER_CONNECTION_FLAG_IS_INCOMING))
-			peer_odc_send_cookie(conn);
-	}
-	else if (conn->type == OSCAR_CAPABILITY_SENDFILE)
-	{
-		if (purple_xfer_get_xfer_type(conn->xfer) == PURPLE_XFER_TYPE_SEND)
-		{
-			peer_oft_send_prompt(conn);
-		}
-	}
-
-	/*
-	 * Tell the remote user that we're connected (which may also imply
-	 * that we've accepted their request).
-	 */
-	if (!(conn->flags & PEER_CONNECTION_FLAG_IS_INCOMING))
-		aim_im_sendch2_connected(conn);
-}
-
-/**
- * We tried to make an outgoing connection to a remote user.  It
- * either connected or failed to connect.
- */
-static void
-peer_connection_common_established_cb(gpointer data, gint source, const gchar *error_message, gboolean verified)
-{
-	PeerConnection *conn;
-
-	conn = data;
-
-	if (verified)
-		conn->verified_connect_data = NULL;
-	else
-		conn->client_connect_data = NULL;
-
-	if (source < 0)
-	{
-		if ((conn->verified_connect_data == NULL) &&
-			(conn->client_connect_data == NULL))
-		{
-			/* Our parallel connection attemps have both failed. */
-			peer_connection_trynext(conn);
-		}
-		return;
-	}
-
-	g_source_remove(conn->connect_timeout_timer);
-	conn->connect_timeout_timer = 0;
-
-	if (conn->client_connect_data != NULL)
-	{
-		purple_proxy_connect_cancel(conn->client_connect_data);
-		conn->client_connect_data = NULL;
-	}
-
-	if (conn->verified_connect_data != NULL)
-	{
-		purple_proxy_connect_cancel(conn->verified_connect_data);
-		conn->verified_connect_data = NULL;
-	}
-
-	conn->fd = source;
-
-	peer_connection_finalize_connection(conn);
-}
-
-static void
-peer_connection_verified_established_cb(gpointer data, gint source, const gchar *error_message)
-{
-	peer_connection_common_established_cb(data, source, error_message, TRUE);
-}
-
-static void
-peer_connection_client_established_cb(gpointer data, gint source, const gchar *error_message)
-{
-	peer_connection_common_established_cb(data, source, error_message, FALSE);
-}
-
-/**
- * This is the watcher callback for any listening socket that is
- * waiting for a peer to connect.  When a peer connects we set the
- * input watcher to start reading data from the peer.
- *
- * To make sure that the connection is with the intended person and
- * not with a malicious middle man, we don't send anything until we've
- * received a peer frame from the remote user and have verified that
- * the cookie in the peer frame matches the cookie that was exchanged
- * in the channel 2 ICBM.
- */
-void
-peer_connection_listen_cb(gpointer data, gint source, PurpleInputCondition cond)
-{
-	PeerConnection *conn;
-	struct sockaddr addr;
-	socklen_t addrlen = sizeof(addr);
-
-	conn = data;
-
-	purple_debug_info("oscar", "Accepting connection on listener socket.\n");
-
-	conn->fd = accept(conn->listenerfd, &addr, &addrlen);
-	if (conn->fd < 0)
-	{
-		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
-			/* No connection yet--no worries */
-			/* TODO: Hmm, but they SHOULD be connected if we're here, right? */
-			return;
-
-		peer_connection_trynext(conn);
-		return;
-	}
-
-	if ((addr.sa_family != PF_INET) && (addr.sa_family != PF_INET6))
-	{
-		/* Invalid connection type?!  Continue waiting. */
-		close(conn->fd);
-		return;
-	}
-
-	_purple_network_set_common_socket_flags(conn->fd);
-
-	purple_input_remove(conn->watcher_incoming);
-
-	peer_connection_finalize_connection(conn);
-}
-
-/**
- * Converts a dot-decimal IP address to an array of unsigned
- * chars.  For example, converts 192.168.0.1 to a 4 byte
- * array containing 192, 168, 0 and 1.
- *
- * @param ip An IP address in dot-decimal notiation.
- * @return An array of 4 bytes containing an IP addresses
- *         equivalent to the given parameter, or NULL if
- *         the given IP address is invalid.  This value
- *         is statically allocated and should not be
- *         freed.
- */
-static const unsigned char *
-peer_ip_atoi(const char *ip)
-{
-	static unsigned char ret[4];
-	gchar *delimiter = ".";
-	gchar **split;
-	int i;
-
-	g_return_val_if_fail(ip != NULL, NULL);
-
-	split = g_strsplit(ip, delimiter, 4);
-	for (i = 0; split[i] != NULL; i++)
-		ret[i] = atoi(split[i]);
-	g_strfreev(split);
-
-	/* i should always be 4 */
-	if (i != 4)
-		return NULL;
-
-	return ret;
-}
-
-/**
- * We've just opened a listener socket, so we send the remote
- * user an ICBM and ask them to connect to us.
- */
-static void
-peer_connection_establish_listener_cb(int listenerfd, gpointer data)
-{
-	PeerConnection *conn;
-	OscarData *od;
-	PurpleConnection *gc;
-	PurpleAccount *account;
-	PurpleIMConversation *im;
-	char *tmp;
-	FlapConnection *bos_conn;
-	const char *listener_ip;
-	const guchar *ip_atoi;
-	unsigned short listener_port;
-
-	conn = data;
-	conn->listen_data = NULL;
-
-	if (listenerfd < 0)
-	{
-		/* Could not open listener socket */
-		peer_connection_trynext(conn);
-		return;
-	}
-
-	od = conn->od;
-	gc = od->gc;
-	account = purple_connection_get_account(gc);
-	conn->listenerfd = listenerfd;
-
-	/* Watch for new connections on our listener socket */
-	conn->watcher_incoming = purple_input_add(conn->listenerfd,
-			PURPLE_INPUT_READ, peer_connection_listen_cb, conn);
-
-	/* Send the "please connect to me!" ICBM */
-	bos_conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM);
-	if (bos_conn == NULL)
-	{
-		/* Not good */
-		peer_connection_trynext(conn);
-		return;
-	}
-
-	if (bos_conn->gsc)
-		listener_ip = purple_network_get_my_ip(bos_conn->gsc->fd);
-	else
-		listener_ip = purple_network_get_my_ip(bos_conn->fd);
-
-	ip_atoi = peer_ip_atoi(listener_ip);
-	if (ip_atoi == NULL) {
-		/* Could not convert IP to 4 byte array--weird, but this does
-		   happen for some users (#4829, Adium #15839).  Maybe they're
-		   connecting with IPv6...?  Maybe through a proxy? */
-		purple_debug_error("oscar", "Can't ask peer to connect to us "
-				"because peer_ip_atoi(%s) returned NULL. "
-				"fd=%d. is_ssl=%d\n",
-				listener_ip ? listener_ip : "(null)",
-				bos_conn->gsc ? bos_conn->gsc->fd : bos_conn->fd,
-				bos_conn->gsc ? 1 : 0);
-		peer_connection_trynext(conn);
-		return;
-	}
-
-	listener_port = purple_network_get_port_from_fd(conn->listenerfd);
-
-	if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
-	{
-		aim_im_sendch2_odc_requestdirect(od,
-				conn->cookie, conn->bn, ip_atoi,
-				listener_port, ++conn->lastrequestnumber);
-
-		/* Print a message to a local conversation window */
-		im = purple_im_conversation_new(account, conn->bn);
-		tmp = g_strdup_printf(_("Asking %s to connect to us at %s:%hu for "
-				"Direct IM."), conn->bn, listener_ip, listener_port);
-		purple_conversation_write_system_message(
-			PURPLE_CONVERSATION(im), tmp, 0);
-		g_free(tmp);
-	}
-	else if (conn->type == OSCAR_CAPABILITY_SENDFILE)
-	{
-		aim_im_sendch2_sendfile_requestdirect(od,
-				conn->cookie, conn->bn,
-				ip_atoi,
-				listener_port, ++conn->lastrequestnumber,
-				(const gchar *)conn->xferdata.name,
-				conn->xferdata.size, conn->xferdata.totfiles);
-	}
-}
-
-/**
- * This is a callback function used when we're connecting to a peer
- * using either the client IP or the verified IP and the connection
- * took longer than 5 seconds to complete.  We do this because
- * waiting for the OS to time out the connection attempt is not
- * practical--the default timeout on many OSes can be 3 minutes or
- * more, and users are impatient.
- *
- * Worst case scenario: the user is connected to the Internet using
- * a modem with severe lag.  The peer connections fail and Purple falls
- * back to using a proxied connection.  The lower bandwidth
- * limitations imposed by the proxied connection won't matter because
- * the user is using a modem.
- *
- * I suppose this line of thinking is discriminatory against people
- * with very high lag but decent throughput who are transferring
- * large files.  But we don't care about those people.
- *
- * I (Sean) changed the timeout from 15 to 5 seconds, as 60 seconds is
- * too long for a user to wait to send a file. I'm also parallelizing
- * requests when possible. The longest we should have to wait now is 10
- * seconds. We shouldn't make it shorter than this.
- */
-static gboolean
-peer_connection_tooktoolong(gpointer data)
-{
-	PeerConnection *conn;
-
-	conn = data;
-
-	purple_debug_info("oscar", "Peer connection timed out after 5 seconds.  "
-			"Trying next method...\n");
-
-	peer_connection_trynext(conn);
-
-	/* Cancel this timer.  It'll be added again, if needed. */
-	return FALSE;
-}
-
-/**
- * Try to establish the given PeerConnection using a defined
- * sequence of steps.
- */
-void
-peer_connection_trynext(PeerConnection *conn)
-{
-	PurpleAccount *account;
-
-	account = purple_connection_get_account(conn->od->gc);
-
-	/*
-	 * Close any remnants of a previous failed connection attempt.
-	 */
-	peer_connection_close(conn);
-
-	/*
-	 * 1. Attempt to connect to the remote user using their verifiedip and clientip.
-	 *    We try these at the same time and use whichever succeeds first, so we don't
-	 *    have to wait for a timeout.
-	 */
-	if (!(conn->flags & PEER_CONNECTION_FLAG_TRIED_DIRECT) &&
-		(conn->verifiedip != NULL) && (conn->port != 0) && (!conn->use_proxy))
-	{
-		conn->flags |= PEER_CONNECTION_FLAG_TRIED_DIRECT;
-
-		if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
-		{
-			gchar *tmp;
-			PurpleIMConversation *im;
-			tmp = g_strdup_printf(_("Attempting to connect to %s:%hu."),
-					conn->verifiedip, conn->port);
-			im = purple_im_conversation_new(account, conn->bn);
-			purple_conversation_write_system_message(
-				PURPLE_CONVERSATION(im), tmp, 0);
-			g_free(tmp);
-		}
-
-		conn->verified_connect_data = purple_proxy_connect(NULL, account,
-				conn->verifiedip, conn->port,
-				peer_connection_verified_established_cb, conn);
-
-		if ((conn->verifiedip == NULL) ||
-			!purple_strequal(conn->verifiedip, conn->clientip))
-		{
-			conn->client_connect_data = purple_proxy_connect(NULL, account,
-					conn->clientip, conn->port,
-					peer_connection_client_established_cb, conn);
-		}
-
-		if ((conn->verified_connect_data != NULL) ||
-			(conn->client_connect_data != NULL))
-		{
-			/* Connecting... */
-			conn->connect_timeout_timer = g_timeout_add_seconds(5,
-					peer_connection_tooktoolong, conn);
-			return;
-		}
-	}
-
-	/*
-	 * 2. Attempt to have the remote user connect to us (using both
-	 *    our verifiedip and our clientip).
-	 */
-	if (!(conn->flags & PEER_CONNECTION_FLAG_TRIED_INCOMING) &&
-		(!conn->use_proxy))
-	{
-		conn->flags |= PEER_CONNECTION_FLAG_TRIED_INCOMING;
-
-		/*
-		 * Remote user is connecting to us, so we'll need to verify
-		 * that the user who connected is our friend.
-		 */
-		conn->flags |= PEER_CONNECTION_FLAG_IS_INCOMING;
-
-		conn->listen_data = purple_network_listen_range(5190, 5290, AF_UNSPEC, SOCK_STREAM, TRUE,
-				peer_connection_establish_listener_cb, conn);
-		if (conn->listen_data != NULL)
-		{
-			/* Opening listener socket... */
-			return;
-		}
-	}
-
-	/*
-	 * 3. Attempt to have both users connect to an intermediate proxy
-	 *    server.
-	 */
-	if (!(conn->flags & PEER_CONNECTION_FLAG_TRIED_PROXY))
-	{
-		conn->flags |= PEER_CONNECTION_FLAG_TRIED_PROXY;
-
-		/*
-		 * If we initiate the proxy connection, then the remote user
-		 * could be anyone, so we need to verify that the user who
-		 * connected is our friend.
-		 */
-		if (!conn->use_proxy)
-			conn->flags |= PEER_CONNECTION_FLAG_IS_INCOMING;
-
-		if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
-		{
-			gchar *tmp;
-			PurpleIMConversation *im;
-			tmp = g_strdup(_("Attempting to connect via proxy server."));
-			im = purple_im_conversation_new(account, conn->bn);
-			purple_conversation_write_system_message(
-				PURPLE_CONVERSATION(im), tmp, 0);
-			g_free(tmp);
-		}
-
-		conn->verified_connect_data = purple_proxy_connect(NULL, account,
-				(conn->proxyip != NULL)
-					? conn->proxyip
-					: (conn->od->icq ? ICQ_PEER_PROXY_SERVER : AIM_PEER_PROXY_SERVER),
-				PEER_PROXY_PORT,
-				peer_proxy_connection_established_cb, conn);
-		if (conn->verified_connect_data != NULL)
-		{
-			/* Connecting... */
-			return;
-		}
-	}
-
-	/* Give up! */
-	peer_connection_destroy(conn, OSCAR_DISCONNECT_COULD_NOT_CONNECT, NULL);
-}
-
-/**
- * Initiate a peer connection with someone.
- */
-void
-peer_connection_propose(OscarData *od, guint64 type, const char *bn)
-{
-	PeerConnection *conn;
-
-	if (type == OSCAR_CAPABILITY_DIRECTIM)
-	{
-		conn = peer_connection_find_by_type(od, bn, type);
-		if (conn != NULL)
-		{
-			if (conn->ready)
-			{
-				PurpleAccount *account;
-				PurpleIMConversation *im;
-
-				purple_debug_info("oscar", "Already have a direct IM "
-						"session with %s.\n", bn);
-				account = purple_connection_get_account(od->gc);
-				im = purple_conversations_find_im_with_account(bn, account);
-				if (im != NULL)
-					purple_conversation_present(PURPLE_CONVERSATION(im));
-				return;
-			}
-
-			/* Cancel the old connection and try again */
-			peer_connection_destroy(conn, OSCAR_DISCONNECT_RETRYING, NULL);
-		}
-	}
-
-	conn = peer_connection_new(od, type, bn);
-	conn->flags |= PEER_CONNECTION_FLAG_INITIATED_BY_ME;
-	conn->flags |= PEER_CONNECTION_FLAG_APPROVED;
-	aim_icbm_makecookie(conn->cookie);
-
-	peer_connection_trynext(conn);
-}
-
-/**
- * Someone else wants to establish a peer connection with us,
- * and we said yes.
- */
-static void
-peer_connection_got_proposition_yes_cb(gpointer data, gint id)
-{
-	PeerConnection *conn;
-
-	conn = data;
-
-	conn->flags |= PEER_CONNECTION_FLAG_APPROVED;
-	peer_connection_trynext(conn);
-}
-
-/**
- * Someone else wants to establish a peer connection with us,
- * and we said no.
- *
- * "Well, one time my friend asked me if I wanted to play the
- *  piccolo.  But I said no."
- */
-static void
-peer_connection_got_proposition_no_cb(gpointer data, gint id)
-{
-	PeerConnection *conn;
-
-	conn = data;
-
-	aim_im_denytransfer(conn->od, conn->bn, conn->cookie,
-			AIM_TRANSFER_DENY_DECLINE);
-	peer_connection_destroy(conn, OSCAR_DISCONNECT_LOCAL_CLOSED, NULL);
-}
-
-/**
- * Someone else wants to establish a peer connection with us.
- */
-void
-peer_connection_got_proposition(OscarData *od, const gchar *bn, const gchar *message, IcbmArgsCh2 *args)
-{
-	PurpleConnection *gc;
-	PurpleAccount *account;
-	PeerConnection *conn;
-	gchar *buf;
-
-	gc = od->gc;
-	account = purple_connection_get_account(gc);
-
-	/*
-	 * If we have a connection with this same cookie then they are
-	 * probably just telling us they weren't able to connect to us
-	 * and we should try connecting to them, instead.  Or they want
-	 * to go through a proxy.
-	 */
-	conn = peer_connection_find_by_cookie(od, bn, args->cookie);
-	if ((conn != NULL) && (conn->type == args->type))
-	{
-		purple_debug_info("oscar", "Remote user wants to try a "
-				"different connection method\n");
-		g_free(conn->proxyip);
-		g_free(conn->clientip);
-		g_free(conn->verifiedip);
-		if (args->use_proxy)
-			conn->proxyip = g_strdup(args->proxyip);
-		else
-			conn->proxyip = NULL;
-		conn->verifiedip = g_strdup(args->verifiedip);
-		conn->clientip = g_strdup(args->clientip);
-		conn->port = args->port;
-		conn->use_proxy |= args->use_proxy;
-		conn->lastrequestnumber++;
-		peer_connection_trynext(conn);
-		return;
-	}
-
-	/* If this is a direct IM, then close any existing session */
-	if (args->type == OSCAR_CAPABILITY_DIRECTIM)
-	{
-		conn = peer_connection_find_by_type(od, bn, args->type);
-		if (conn != NULL)
-		{
-			/* Close the old direct IM and start a new one */
-			purple_debug_info("oscar", "Received new direct IM request "
-				"from %s.  Destroying old connection.\n", bn);
-			peer_connection_destroy(conn, OSCAR_DISCONNECT_REMOTE_CLOSED, NULL);
-		}
-	}
-
-	/* Check for proper arguments */
-	if (args->type == OSCAR_CAPABILITY_SENDFILE)
-	{
-		if ((args->info.sendfile.filename == NULL) ||
-			(args->info.sendfile.totsize == 0) ||
-			(args->info.sendfile.totfiles == 0))
-		{
-			purple_debug_warning("oscar",
-					"%s tried to send you a file with incomplete "
-					"information.\n", bn);
-			return;
-		}
-	}
-
-	conn = peer_connection_new(od, args->type, bn);
-	memcpy(conn->cookie, args->cookie, 8);
-	if (args->use_proxy)
-		conn->proxyip = g_strdup(args->proxyip);
-	conn->clientip = g_strdup(args->clientip);
-	conn->verifiedip = g_strdup(args->verifiedip);
-	conn->port = args->port;
-	conn->use_proxy |= args->use_proxy;
-	conn->lastrequestnumber++;
-
-	if (args->type == OSCAR_CAPABILITY_DIRECTIM)
-	{
-		buf = g_strdup_printf(_("%s has just asked to directly connect to %s"),
-				bn, purple_account_get_username(account));
-
-		purple_request_action(conn, NULL, buf,
-						_("This requires a direct connection between "
-						  "the two computers and is necessary for IM "
-						  "Images.  Because your IP address will be "
-						  "revealed, this may be considered a privacy "
-						  "risk."),
-						PURPLE_DEFAULT_ACTION_NONE,
-						purple_request_cpar_from_account(account),
-						conn, 2,
-						_("C_onnect"), G_CALLBACK(peer_connection_got_proposition_yes_cb),
-						_("Cancel"), G_CALLBACK(peer_connection_got_proposition_no_cb));
-	}
-	else if (args->type == OSCAR_CAPABILITY_SENDFILE)
-	{
-		gchar *filename;
-
-		conn->xfer = PURPLE_XFER(g_object_new(
-			OSCAR_TYPE_XFER,
-			"account", account,
-			"type", PURPLE_XFER_TYPE_RECEIVE,
-			"remote-user", bn,
-			"conn", conn,
-			NULL
-		));
-		purple_xfer_set_size(conn->xfer, args->info.sendfile.totsize);
-
-		/* Set the file name */
-		if (g_utf8_validate(args->info.sendfile.filename, -1, NULL))
-			filename = g_strdup(args->info.sendfile.filename);
-		else
-			filename = purple_utf8_salvage(args->info.sendfile.filename);
-
-		if (args->info.sendfile.subtype == AIM_OFT_SUBTYPE_SEND_DIR)
-		{
-			/*
-			 * If they are sending us a directory then the last character
-			 * of the file name will be an asterisk.  We don't want to
-			 * save stuff to a directory named "*" so we remove the
-			 * asterisk from the file name.
-			 */
-			char *tmp = strrchr(filename, '\\');
-			if ((tmp != NULL) && (tmp[1] == '*'))
-				tmp[0] = '\0';
-		}
-		purple_xfer_set_filename(conn->xfer, filename);
-		g_free(filename);
-
-		/*
-		 * Set the message, unless this is the dummy message from an
-		 * ICQ client or an empty message from an AIM client.
-		 * TODO: Maybe we should strip HTML and then see if strlen>0?
-		 */
-		if ((message != NULL) &&
-			(g_ascii_strncasecmp(message, "<ICQ_COOL_FT>", 13) != 0) &&
-			(g_ascii_strcasecmp(message, "<HTML>") != 0))
-		{
-			purple_xfer_set_message(conn->xfer, message);
-		}
-
-		/* Now perform the request */
-		purple_xfer_request(conn->xfer);
-	}
-}
-
-/*******************************************************************/
-/* End code for establishing a peer connection                     */
-/*******************************************************************/
-
-G_DEFINE_DYNAMIC_TYPE(OscarXfer, oscar_xfer, PURPLE_TYPE_XFER);
-
-static void
-oscar_xfer_init_xfer(PurpleXfer *xfer) {
-	PurpleXferType type = purple_xfer_get_xfer_type(xfer);
-
-	if(type == PURPLE_XFER_TYPE_SEND) {
-		peer_oft_sendcb_init(xfer);
-	} else if(type == PURPLE_XFER_TYPE_RECEIVE) {
-		peer_oft_recvcb_init(xfer);
-	}
-}
-
-static void
-oscar_xfer_ack(PurpleXfer *xfer, const guchar *buffer, size_t size) {
-	PurpleXferType type = purple_xfer_get_xfer_type(xfer);
-
-	if(type == PURPLE_XFER_TYPE_SEND) {
-		peer_oft_sendcb_ack(xfer, buffer, size);
-	} else if(type == PURPLE_XFER_TYPE_RECEIVE) {
-		peer_oft_recvcb_ack_recv(xfer, buffer, size);
-	}
-
-}
-
-static void
-oscar_xfer_init(OscarXfer *xfer) {
-
-}
-
-static void
-oscar_xfer_class_finalize(OscarXferClass *klass) {
-
-}
-
-static void
-oscar_xfer_class_init(OscarXferClass *klass) {
-	PurpleXferClass *xfer_class = PURPLE_XFER_CLASS(klass);
-
-	xfer_class->init = oscar_xfer_init_xfer;
-	xfer_class->end = peer_oft_recvcb_end;
-	xfer_class->cancel_send = peer_oft_cb_generic_cancel;
-	xfer_class->cancel_recv = peer_oft_cb_generic_cancel;
-	xfer_class->request_denied = peer_oft_cb_generic_cancel;
-	xfer_class->ack = oscar_xfer_ack;
-}
-
-void
-oscar_xfer_register(GTypeModule *module) {
-	oscar_xfer_register_type(module);
-}
-
-PeerConnection *
-oscar_xfer_get_peer_connection(OscarXfer *xfer) {
-	g_return_val_if_fail(OSCAR_IS_XFER(xfer), NULL);
-
-	return xfer->conn;
-}
--- a/libpurple/protocols/oscar/peer.h	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,295 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * OFT and ODC Services
- */
-
-#ifndef PURPLE_OSCAR_PEER_H
-#define PURPLE_OSCAR_PEER_H
-
-#include "xfer.h"
-#include "network.h"
-#include "proxy.h"
-
-typedef struct _ChecksumData          ChecksumData;
-typedef struct _OdcFrame              OdcFrame;
-typedef struct _OftFrame              OftFrame;
-typedef struct _ProxyFrame            ProxyFrame;
-typedef struct _PeerConnection        PeerConnection;
-
-#define PEER_CONNECTION_FLAG_INITIATED_BY_ME  0x0001
-#define PEER_CONNECTION_FLAG_APPROVED         0x0002
-#define PEER_CONNECTION_FLAG_TRIED_DIRECT     0x0004
-#define PEER_CONNECTION_FLAG_TRIED_INCOMING   0x0008
-#define PEER_CONNECTION_FLAG_TRIED_PROXY      0x0010
-#define PEER_CONNECTION_FLAG_IS_INCOMING      0x0020
-
-#define PEER_TYPE_PROMPT 0x0101 /* "I am going to send you this file, is that ok?" */
-#define PEER_TYPE_RESUMEACCEPT 0x0106 /* We are accepting the resume */
-#define PEER_TYPE_ACK 0x0202 /* "Yes, it is ok for you to send me that file" */
-#define PEER_TYPE_DONE 0x0204 /* "I received that file with no problems" or "I already have that file, great!" */
-#define PEER_TYPE_RESUME 0x0205 /* Resume transferring, sent by whoever receives */
-#define PEER_TYPE_RESUMEACK 0x0207 /* Our resume accept was ACKed */
-
-#define PEER_TYPE_GETFILE_REQUESTLISTING 0x1108 /* "I have a listing.txt file, do you want it?" */
-#define PEER_TYPE_GETFILE_RECEIVELISTING 0x1209 /* "Yes, please send me your listing.txt file" */
-#define PEER_TYPE_GETFILE_RECEIVEDLISTING 0x120a /* received corrupt listing.txt file? I'm just guessing about this one... */
-#define PEER_TYPE_GETFILE_ACKLISTING 0x120b /* "I received the listing.txt file successfully" */
-#define PEER_TYPE_GETFILE_REQUESTFILE 0x120c /* "Please send me this file" */
-
-/*
- * For peer proxying
- */
-#define AIM_PEER_PROXY_SERVER         "ars.oscar.aol.com"
-#define ICQ_PEER_PROXY_SERVER         "ars.icq.com"
-#define PEER_PROXY_PORT           5190   /* The port we should always connect to */
-#define PEER_PROXY_PACKET_VERSION 0x044a
-
-/* Thanks to Keith Lea and the Joust project for documenting these */
-#define PEER_PROXY_TYPE_ERROR   0x0001
-#define PEER_PROXY_TYPE_CREATE  0x0002
-#define PEER_PROXY_TYPE_CREATED 0x0003
-#define PEER_PROXY_TYPE_JOIN    0x0004
-#define PEER_PROXY_TYPE_READY   0x0005
-
-struct _OdcFrame
-{
-	/* guchar magic[4]; */        /* 0 */
-	/* guint16 length; */         /* 4 */
-	guint16 type;                 /* 6 */
-	guint16 subtype;              /* 8 */
-	/* Unknown */                 /* 10 */
-	guchar cookie[8];		      /* 12 */
-	/* Unknown */
-	/* guint32 payloadlength; */  /* 28 */
-	guint16 encoding;             /* 32 */
-	/* Unknown */
-	guint16 flags;                /* 38 */
-	/* Unknown */
-	guchar bn[32];                /* 44 */
-	/* Unknown */
-	ByteStream payload;           /* 76 */
-};
-
-struct _OftFrame
-{
-	/* guchar magic[4]; */   /* 0 */
-	/* guint16 length; */    /* 4 */
-	guint16 type;            /* 6 */
-	guchar cookie[8];        /* 8 */
-	guint16 encrypt;         /* 16 */
-	guint16 compress;        /* 18 */
-	guint16 totfiles;        /* 20 */
-	guint16 filesleft;       /* 22 */
-	guint16 totparts;        /* 24 */
-	guint16 partsleft;       /* 26 */
-	guint32 totsize;         /* 28 */
-	guint32 size;            /* 32 */
-	guint32 modtime;         /* 36 */
-	guint32 checksum;        /* 40 */
-	guint32 rfrcsum;         /* 44 */
-	guint32 rfsize;          /* 48 */
-	guint32 cretime;         /* 52 */
-	guint32 rfcsum;          /* 56 */
-	guint32 nrecvd;          /* 60 */
-	guint32 recvcsum;        /* 64 */
-	guchar idstring[32];     /* 68 */
-	guint8 flags;            /* 100 */
-	guint8 lnameoffset;      /* 101 */
-	guint8 lsizeoffset;      /* 102 */
-	guchar dummy[69];        /* 103 */
-	guchar macfileinfo[16];  /* 172 */
-	guint16 nencode;         /* 188 */
-	guint16 nlanguage;       /* 190 */
-	guchar *name;            /* 192 */
-	size_t name_length;
-	/* Payload? */           /* 256 */
-};
-
-struct _ProxyFrame
-{
-	/* guint16 length; */    /* 0 */
-	guint16 version;         /* 2 */
-	guint16 type;            /* 4 */
-	guint32 unknown;         /* 6 */
-	guint16 flags;           /* 10 */
-	ByteStream payload;      /* 12 */
-};
-
-struct _PeerConnection
-{
-	OscarData *od;
-	guint64 type;
-	char *bn;
-	guchar magic[4];
-	guchar cookie[8];
-	guint16 lastrequestnumber;
-
-	gboolean ready;
-	int flags;                       /**< Bitmask of PEER_CONNECTION_FLAG_ */
-	time_t lastactivity;             /**< Time of last transmit. */
-	guint destroy_timeout;
-	OscarDisconnectReason disconnect_reason;
-	char *error_message;
-
-	/**
-	 * A pointer to either an OdcFrame or an OftFrame.
-	 */
-	gpointer frame;
-
-	/**
-	 * This is only used when the peer connection is being established.
-	 */
-	PurpleProxyConnectData *client_connect_data;
-	PurpleProxyConnectData *verified_connect_data;
-
-	/**
-	 * This is only used when the peer connection is being established.
-	 */
-	PurpleNetworkListenData *listen_data;
-
-
-	/**
-	 * This is only used when the peer connection is being established.
-	 */
-	guint connect_timeout_timer;
-
-	/**
-	 * This is only used while the remote user is attempting to
-	 * connect to us.
-	 */
-	int listenerfd;
-
-	int fd;
-	guint8 header[6];
-	gssize header_received;
-	guint8 proxy_header[12];
-	gssize proxy_header_received;
-	ByteStream buffer_incoming;
-	PurpleCircularBuffer *buffer_outgoing;
-	guint watcher_incoming;
-	guint watcher_outgoing;
-
-	/**
-	 * IP address of the proxy server, if applicable.
-	 */
-	gchar *proxyip;
-
-	/**
-	 * IP address of the remote user from THEIR point of view.
-	 */
-	gchar *clientip;
-
-	/**
-	 * IP address of the remote user from the oscar server's
-	 * point of view.
-	 */
-	gchar *verifiedip;
-
-	guint16 port;
-	gboolean use_proxy;
-
-	/**
-	 * Checksumming
-	 */
-	ChecksumData *checksum_data;
-
-	/* TODOFT */
-	PurpleXfer *xfer;
-	OftFrame xferdata;
-	guint sending_data_timer;
-};
-
-/*
- * For all peer connections
- */
-
-/**
- * Create a new PeerConnection structure and initialize it with some
- * sane defaults.
- *
- * @param type The type of the peer connection.  One of
- *        OSCAR_CAPABILITY_DIRECTIM or OSCAR_CAPABILITY_SENDFILE.
- */
-PeerConnection *peer_connection_new(OscarData *od, guint64 type, const char *bn);
-
-void peer_connection_destroy(PeerConnection *conn, OscarDisconnectReason reason, const gchar *error_message);
-void peer_connection_schedule_destroy(PeerConnection *conn, OscarDisconnectReason reason, const gchar *error_message);
-PeerConnection *peer_connection_find_by_type(OscarData *od, const char *bn, guint64 type);
-PeerConnection *peer_connection_find_by_cookie(OscarData *od, const char *bn, const guchar *cookie);
-
-void peer_connection_listen_cb(gpointer data, gint source, PurpleInputCondition cond);
-void peer_connection_recv_cb(gpointer data, gint source, PurpleInputCondition cond);
-void peer_connection_send(PeerConnection *conn, ByteStream *bs);
-
-void peer_connection_trynext(PeerConnection *conn);
-void peer_connection_finalize_connection(PeerConnection *conn);
-void peer_connection_propose(OscarData *od, guint64 type, const char *bn);
-void peer_connection_got_proposition(OscarData *od, const gchar *bn, const gchar *message, IcbmArgsCh2 *args);
-
-/*
- * For ODC
- */
-void peer_odc_close(PeerConnection *conn);
-void peer_odc_recv_frame(PeerConnection *conn, ByteStream *bs);
-void peer_odc_send_cookie(PeerConnection *conn);
-void peer_odc_send_typing(PeerConnection *conn, PurpleIMTypingState typing);
-void peer_odc_send_im(PeerConnection *conn, const char *msg, int len, int encoding, gboolean autoreply);
-
-/*
- * For OFT
- */
-void peer_oft_close(PeerConnection *conn);
-void peer_oft_recv_frame(PeerConnection *conn, ByteStream *bs);
-void peer_oft_send_prompt(PeerConnection *conn);
-void peer_oft_checksum_destroy(ChecksumData *checksum_data);
-
-/* Xfer callbacks for receiving a file */
-void peer_oft_recvcb_init(PurpleXfer *xfer);
-void peer_oft_recvcb_end(PurpleXfer *xfer);
-void peer_oft_recvcb_ack_recv(PurpleXfer *xfer, const guchar *buffer, size_t size);
-
-/* Xfer callbacks for sending a file */
-void peer_oft_sendcb_init(PurpleXfer *xfer);
-void peer_oft_sendcb_ack(PurpleXfer *xfer, const guchar *buffer, size_t size);
-
-/* Xfer callbacks for both sending and receiving */
-void peer_oft_cb_generic_cancel(PurpleXfer *xfer);
-
-/*
- * For peer proxying
- */
-void peer_proxy_connection_established_cb(gpointer data, gint source, const gchar *error_message);
-
-/* File transfers */
-#define OSCAR_TYPE_XFER (oscar_xfer_get_type())
-G_DECLARE_FINAL_TYPE(OscarXfer, oscar_xfer, OSCAR, XFER, PurpleXfer);
-
-struct _OscarXfer {
-	PurpleXfer parent;
-
-	PeerConnection *conn;
-};
-
-void oscar_xfer_register(GTypeModule *module);
-PeerConnection *oscar_xfer_get_peer_connection(OscarXfer *xfer);
-
-#endif /* PURPLE_OSCAR_PEER_H */
--- a/libpurple/protocols/oscar/peer_proxy.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,354 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-#ifdef HAVE_CONFIG_H
-#include  <config.h>
-#endif
-
-#include "oscar.h"
-#include "peer.h"
-
-static void
-peer_proxy_send(PeerConnection *conn, ProxyFrame *frame)
-{
-	size_t length;
-	ByteStream bs;
-
-	purple_debug_info("oscar", "Outgoing peer proxy frame with "
-			"type=0x%04hx, unknown=0x%08x, flags=0x%04hx, and "
-			"payload length=%" G_GSIZE_FORMAT "\n",
-			frame->type, frame->unknown,
-			frame->flags, frame->payload.len);
-
-	length = 12 + frame->payload.len;
-	byte_stream_new(&bs, length);
-	byte_stream_put16(&bs, length - 2);
-	byte_stream_put16(&bs, PEER_PROXY_PACKET_VERSION);
-	byte_stream_put16(&bs, frame->type);
-	byte_stream_put32(&bs, frame->unknown);
-	byte_stream_put16(&bs, frame->flags);
-	byte_stream_putraw(&bs, frame->payload.data, frame->payload.len);
-
-	peer_connection_send(conn, &bs);
-
-	byte_stream_destroy(&bs);
-}
-
-/**
- * Create a rendezvous "init send" packet and send it on its merry way.
- * This is the first packet sent to the proxy server by the first client
- * to indicate that this will be a proxied connection
- *
- * @param conn The peer connection.
- */
-static void
-peer_proxy_send_create_new_conn(PeerConnection *conn)
-{
-	ProxyFrame frame;
-	PurpleAccount *account;
-	const gchar *bn;
-	guint8 bn_length;
-
-	memset(&frame, 0, sizeof(ProxyFrame));
-	frame.type = PEER_PROXY_TYPE_CREATE;
-	frame.flags = 0x0000;
-
-	account = purple_connection_get_account(conn->od->gc);
-	bn = purple_account_get_username(account);
-	bn_length = strlen(bn);
-	byte_stream_new(&frame.payload, 1 + bn_length + 8 + 20);
-	byte_stream_put8(&frame.payload, bn_length);
-	byte_stream_putraw(&frame.payload, (const guint8 *)bn, bn_length);
-	byte_stream_putraw(&frame.payload, conn->cookie, 8);
-
-	byte_stream_put16(&frame.payload, 0x0001); /* Type */
-	byte_stream_put16(&frame.payload, 16); /* Length */
-	byte_stream_putcaps(&frame.payload, conn->type); /* Value */
-
-	peer_proxy_send(conn, &frame);
-
-	byte_stream_destroy(&frame.payload);
-}
-
-/**
- * Create a rendezvous "init recv" packet and send it on its merry way.
- * This is the first packet sent to the proxy server by the second client
- * involved in this rendezvous proxy session.
- *
- * @param conn The peer connection.
- * @param pin The 2 byte PIN sent to us by the other user.  This acts
- *        as our passcode when establishing the proxy session.
- */
-static void
-peer_proxy_send_join_existing_conn(PeerConnection *conn, guint16 pin)
-{
-	ProxyFrame frame;
-	PurpleAccount *account;
-	const gchar *bn;
-	guint8 bn_length;
-
-	memset(&frame, 0, sizeof(ProxyFrame));
-	frame.type = PEER_PROXY_TYPE_JOIN;
-	frame.flags = 0x0000;
-
-	account = purple_connection_get_account(conn->od->gc);
-	bn = purple_account_get_username(account);
-	bn_length = strlen(bn);
-	byte_stream_new(&frame.payload, 1 + bn_length + 2 + 8 + 20);
-	byte_stream_put8(&frame.payload, bn_length);
-	byte_stream_putraw(&frame.payload, (const guint8 *)bn, bn_length);
-	byte_stream_put16(&frame.payload, pin);
-	byte_stream_putraw(&frame.payload, conn->cookie, 8);
-
-	byte_stream_put16(&frame.payload, 0x0001); /* Type */
-	byte_stream_put16(&frame.payload, 16); /* Length */
-	byte_stream_putcaps(&frame.payload, conn->type); /* Value */
-
-	peer_proxy_send(conn, &frame);
-
-	byte_stream_destroy(&frame.payload);
-}
-
-/**
- * Handle an incoming peer proxy negotiation frame.
- */
-static void
-peer_proxy_recv_frame(PeerConnection *conn, ProxyFrame *frame)
-{
-	purple_debug_info("oscar", "Incoming peer proxy frame with "
-			"type=0x%04hx, unknown=0x%08x, flags=0x%04hx, and "
-			"payload length=%" G_GSIZE_FORMAT "\n", frame->type,
-			frame->unknown, frame->flags, frame->payload.len);
-
-	if (frame->type == PEER_PROXY_TYPE_CREATED)
-	{
-		/*
-		 * Read in 2 byte port then 4 byte IP and tell the
-		 * remote user to connect to it by sending an ICBM.
-		 */
-		guint16 pin;
-		int i;
-		guint8 ip[4];
-
-		pin = byte_stream_get16(&frame->payload);
-		for (i = 0; i < 4; i++)
-			ip[i] = byte_stream_get8(&frame->payload);
-		if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
-			aim_im_sendch2_odc_requestproxy(conn->od,
-					conn->cookie,
-					conn->bn, ip, pin, ++conn->lastrequestnumber);
-		else if (conn->type == OSCAR_CAPABILITY_SENDFILE)
-		{
-			aim_im_sendch2_sendfile_requestproxy(conn->od,
-					conn->cookie, conn->bn,
-					ip, pin, ++conn->lastrequestnumber,
-					(const gchar *)conn->xferdata.name,
-					conn->xferdata.size, conn->xferdata.totfiles);
-		}
-	}
-	else if (frame->type == PEER_PROXY_TYPE_READY)
-	{
-		purple_input_remove(conn->watcher_incoming);
-		conn->watcher_incoming = 0;
-
-		peer_connection_finalize_connection(conn);
-	}
-	else if (frame->type == PEER_PROXY_TYPE_ERROR)
-	{
-		if (byte_stream_bytes_left(&frame->payload) >= 2)
-		{
-			guint16 error;
-			const char *msg;
-			error = byte_stream_get16(&frame->payload);
-			if (error == 0x000d)
-				msg = "bad request";
-			else if (error == 0x0010)
-				msg = "initial request timed out";
-			else if (error == 0x001a)
-				msg ="accept period timed out";
-			else
-				msg = "unknown reason";
-			purple_debug_info("oscar", "Proxy negotiation failed with "
-					"error 0x%04hx: %s\n", error, msg);
-		}
-		else
-		{
-			purple_debug_warning("oscar", "Proxy negotiation failed with "
-					"an unknown error\n");
-		}
-		peer_connection_trynext(conn);
-	}
-	else
-	{
-		purple_debug_warning("oscar", "Unknown peer proxy frame type 0x%04hx.\n",
-				frame->type);
-	}
-}
-
-static void
-peer_proxy_connection_recv_cb(gpointer data, gint source, PurpleInputCondition cond)
-{
-	PeerConnection *conn;
-	gssize read;
-	ProxyFrame *frame;
-
-	conn = data;
-	frame = conn->frame;
-
-	/* Start reading a new proxy frame */
-	if (frame == NULL)
-	{
-		/* Read the first 12 bytes (frame length and header) */
-		read = recv(conn->fd, conn->proxy_header + conn->proxy_header_received,
-				12 - conn->proxy_header_received, 0);
-
-		/* Check if the proxy server closed the connection */
-		if (read == 0)
-		{
-			purple_debug_info("oscar", "Peer proxy server closed connection\n");
-			peer_connection_trynext(conn);
-			return;
-		}
-
-		/* If there was an error then close the connection */
-		if (read < 0)
-		{
-			if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
-				/* No worries */
-				return;
-
-			purple_debug_info("oscar", "Lost connection with peer proxy server\n");
-			peer_connection_trynext(conn);
-			return;
-		}
-
-		conn->lastactivity = time(NULL);
-
-		/* If we don't even have the first 12 bytes then do nothing */
-		conn->proxy_header_received += read;
-		if (conn->proxy_header_received < 12)
-			return;
-
-		/* We only support a specific version of the proxy protocol */
-		if (aimutil_get16(&conn->proxy_header[2]) != PEER_PROXY_PACKET_VERSION)
-		{
-			purple_debug_warning("oscar", "Expected peer proxy protocol "
-				"version %u but received version %u.  Closing "
-				"connection.\n", PEER_PROXY_PACKET_VERSION,
-				aimutil_get16(&conn->proxy_header[2]));
-			peer_connection_trynext(conn);
-			return;
-		}
-
-		/* Initialize a new temporary ProxyFrame for incoming data */
-		frame = g_new0(ProxyFrame, 1);
-		frame->payload.len = aimutil_get16(&conn->proxy_header[0]) - 10;
-		frame->version = aimutil_get16(&conn->proxy_header[2]);
-		frame->type = aimutil_get16(&conn->proxy_header[4]);
-		frame->unknown = aimutil_get16(&conn->proxy_header[6]);
-		frame->flags = aimutil_get16(&conn->proxy_header[10]);
-		if (frame->payload.len > 0)
-			frame->payload.data = g_new(guint8, frame->payload.len);
-		conn->frame = frame;
-	}
-
-	/* If this frame has a payload then attempt to read it */
-	if (frame->payload.offset < frame->payload.len) {
-		/* Read data into the temporary buffer until it is complete */
-		read = recv(conn->fd,
-					&frame->payload.data[frame->payload.offset],
-					frame->payload.len - frame->payload.offset,
-					0);
-
-		/* Check if the proxy server closed the connection */
-		if (read == 0)
-		{
-			purple_debug_info("oscar", "Peer proxy server closed connection\n");
-			g_free(frame->payload.data);
-			g_free(frame);
-			conn->frame = NULL;
-			peer_connection_trynext(conn);
-			return;
-		}
-
-		/* If there was an error then close the connection */
-		if (read < 0)
-		{
-			if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
-				/* No worries */
-				return;
-
-			purple_debug_info("oscar", "Lost connection with peer proxy server\n");
-			g_free(frame->payload.data);
-			g_free(frame);
-			conn->frame = NULL;
-			peer_connection_trynext(conn);
-			return;
-		}
-
-		frame->payload.offset += read;
-	}
-
-	conn->lastactivity = time(NULL);
-	if (frame->payload.offset < frame->payload.len)
-		/* Waiting for more data to arrive */
-		return;
-
-	/* We have a complete proxy frame!  Handle it and continue reading */
-	conn->frame = NULL;
-	byte_stream_rewind(&frame->payload);
-	peer_proxy_recv_frame(conn, frame);
-
-	g_free(frame->payload.data);
-	g_free(frame);
-
-	conn->proxy_header_received = 0;
-}
-
-/**
- * We tried to make an outgoing connection to a proxy server.  It
- * either connected or failed to connect.
- */
-void
-peer_proxy_connection_established_cb(gpointer data, gint source, const gchar *error_message)
-{
-	PeerConnection *conn;
-
-	conn = data;
-
-	conn->verified_connect_data = NULL;
-
-	if (source < 0)
-	{
-		peer_connection_trynext(conn);
-		return;
-	}
-
-	conn->fd = source;
-	conn->watcher_incoming = purple_input_add(conn->fd,
-			PURPLE_INPUT_READ, peer_proxy_connection_recv_cb, conn);
-
-	if (conn->proxyip != NULL)
-		/* Connect to the session created by the remote user */
-		peer_proxy_send_join_existing_conn(conn, conn->port);
-	else
-		/* Create a new session */
-		peer_proxy_send_create_new_conn(conn);
-}
--- a/libpurple/protocols/oscar/rxhandlers.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-#include "oscar.h"
-#include "peer.h"
-
-aim_module_t *aim__findmodulebygroup(OscarData *od, guint16 group)
-{
-	aim_module_t *cur;
-
-	for (cur = (aim_module_t *)od->modlistv; cur; cur = cur->next) {
-		if (cur->family == group)
-			return cur;
-	}
-
-	return NULL;
-}
-
-aim_module_t *aim__findmodule(OscarData *od, const char *name)
-{
-	aim_module_t *cur;
-
-	for (cur = (aim_module_t *)od->modlistv; cur; cur = cur->next) {
-		if (purple_strequal(name, cur->name))
-			return cur;
-	}
-
-	return NULL;
-}
-
-int aim__registermodule(OscarData *od, int (*modfirst)(OscarData *, aim_module_t *))
-{
-	aim_module_t *mod;
-
-	if (!od || !modfirst)
-		return -1;
-
-	mod = g_new0(aim_module_t, 1);
-
-	if (modfirst(od, mod) == -1) {
-		g_free(mod);
-		return -1;
-	}
-
-	if (aim__findmodule(od, mod->name)) {
-		if (mod->shutdown)
-			mod->shutdown(od, mod);
-		g_free(mod);
-		return -1;
-	}
-
-	mod->next = (aim_module_t *)od->modlistv;
-	od->modlistv = mod;
-
-	return 0;
-}
-
-void aim__shutdownmodules(OscarData *od)
-{
-	aim_module_t *cur;
-
-	for (cur = (aim_module_t *)od->modlistv; cur; ) {
-		aim_module_t *tmp;
-
-		tmp = cur->next;
-
-		if (cur->shutdown)
-			cur->shutdown(od, cur);
-
-		g_free(cur);
-
-		cur = tmp;
-	}
-
-	od->modlistv = NULL;
-
-	return;
-}
--- a/libpurple/protocols/oscar/snac.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,163 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- *
- * Various SNAC-related dodads...
- *
- * outstanding_snacs is a list of aim_snac_t structs.  A SNAC should be added
- * whenever a new SNAC is sent and it should remain in the list until the
- * response for it has been received.
- *
- * cleansnacs() should be called periodically by the client in order
- * to facilitate the aging out of unreplied-to SNACs. This can and does
- * happen, so it should be handled.
- *
- */
-
-#include "oscar.h"
-
-/*
- * Called from oscar_session_new() to initialize the hash.
- */
-void aim_initsnachash(OscarData *od)
-{
-	int i;
-
-	for (i = 0; i < FAIM_SNAC_HASH_SIZE; i++)
-		od->snac_hash[i] = NULL;
-
-	return;
-}
-
-aim_snacid_t aim_cachesnac(OscarData *od, const guint16 family, const guint16 type, const guint16 flags, const void *data, const int datalen)
-{
-	aim_snac_t snac;
-
-	snac.id = od->snacid_next++;
-	snac.family = family;
-	snac.type = type;
-	snac.flags = flags;
-
-	if (datalen)
-		snac.data = g_memdup(data, datalen);
-	else
-		snac.data = NULL;
-
-	return aim_newsnac(od, &snac);
-}
-
-/*
- * Clones the passed snac structure and caches it in the
- * list/hash.
- */
-aim_snacid_t aim_newsnac(OscarData *od, aim_snac_t *newsnac)
-{
-	aim_snac_t *snac;
-	int index;
-
-	if (!newsnac)
-		return 0;
-
-	snac = g_memdup(newsnac, sizeof(aim_snac_t));
-	snac->issuetime = time(NULL);
-
-	index = snac->id % FAIM_SNAC_HASH_SIZE;
-
-	snac->next = (aim_snac_t *)od->snac_hash[index];
-	od->snac_hash[index] = (void *)snac;
-
-	return snac->id;
-}
-
-/*
- * Finds a snac structure with the passed SNAC ID,
- * removes it from the list/hash, and returns a pointer to it.
- *
- * The returned structure must be freed by the caller.
- *
- */
-aim_snac_t *aim_remsnac(OscarData *od, aim_snacid_t id)
-{
-	aim_snac_t *cur, **prev;
-	int index;
-
-	index = id % FAIM_SNAC_HASH_SIZE;
-
-	for (prev = (aim_snac_t **)&od->snac_hash[index]; (cur = *prev); ) {
-		if (cur->id == id) {
-			*prev = cur->next;
-			if (cur->flags & AIM_SNACFLAGS_DESTRUCTOR) {
-				g_free(cur->data);
-				cur->data = NULL;
-			}
-			return cur;
-		} else
-			prev = &cur->next;
-	}
-
-	return cur;
-}
-
-/*
- * This is for cleaning up old SNACs that either don't get replies or
- * a reply was never received for.  Garbage collection. Plain and simple.
- *
- * maxage is the _minimum_ age in seconds to keep SNACs.
- *
- */
-void aim_cleansnacs(OscarData *od, int maxage)
-{
-	int i;
-
-	for (i = 0; i < FAIM_SNAC_HASH_SIZE; i++) {
-		aim_snac_t *cur, **prev;
-		time_t curtime;
-
-		if (!od->snac_hash[i])
-			continue;
-
-		curtime = time(NULL); /* done here in case we waited for the lock */
-
-		for (prev = (aim_snac_t **)&od->snac_hash[i]; (cur = *prev); ) {
-			if ((curtime - cur->issuetime) > maxage) {
-
-				*prev = cur->next;
-
-				g_free(cur->data);
-				g_free(cur);
-			} else
-				prev = &cur->next;
-		}
-	}
-
-	return;
-}
-
-int aim_putsnac(ByteStream *bs, guint16 family, guint16 subtype, aim_snacid_t snacid)
-{
-
-	byte_stream_put16(bs, family);
-	byte_stream_put16(bs, subtype);
-	byte_stream_put16(bs, 0x0000);
-	byte_stream_put32(bs, snacid);
-
-	return 10;
-}
--- a/libpurple/protocols/oscar/snactypes.h	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,288 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * AIM Callback Types
- *
- */
-
-#ifndef PURPLE_OSCAR_SNACTYPES_H
-#define PURPLE_OSCAR_SNACTYPES_H
-
-/*
- * SNAC Families.
- */
-#define SNAC_FAMILY_OSERVICE   0x0001
-#define SNAC_FAMILY_LOCATE     0x0002
-#define SNAC_FAMILY_BUDDY      0x0003
-#define SNAC_FAMILY_ICBM       0x0004
-#define SNAC_FAMILY_ADVERT     0x0005
-#define SNAC_FAMILY_INVITE     0x0006
-#define SNAC_FAMILY_ADMIN      0x0007
-#define SNAC_FAMILY_POPUP      0x0008
-#define SNAC_FAMILY_BOS        0x0009
-#define SNAC_FAMILY_USERLOOKUP 0x000a
-#define SNAC_FAMILY_STATS      0x000b
-#define SNAC_FAMILY_TRANSLATE  0x000c
-#define SNAC_FAMILY_CHATNAV    0x000d
-#define SNAC_FAMILY_CHAT       0x000e
-#define SNAC_FAMILY_ODIR       0x000f
-#define SNAC_FAMILY_BART       0x0010
-#define SNAC_FAMILY_FEEDBAG    0x0013
-#define SNAC_FAMILY_ICQ        0x0015
-#define SNAC_FAMILY_AUTH       0x0017
-#define SNAC_FAMILY_ALERT      0x0018
-
-#define AIM_CB_FAM_SPECIAL 0xffff /* Internal libfaim use */
-
-/*
- * SNAC Family: Ack.
- *
- * Not really a family, but treating it as one really
- * helps it fit into the libfaim callback structure better.
- *
- */
-#define AIM_CB_ACK_ACK 0x0001
-
-/*
- * SNAC Family: General.
- */
-#define SNAC_SUBTYPE_OSERVICE_ERROR 0x0001
-#define SNAC_SUBTYPE_OSERVICE_CLIENTREADY 0x0002
-#define SNAC_SUBTYPE_OSERVICE_SERVERREADY 0x0003
-#define SNAC_SUBTYPE_OSERVICE_SERVICEREQ 0x0004
-#define SNAC_SUBTYPE_OSERVICE_REDIRECT 0x0005
-#define SNAC_SUBTYPE_OSERVICE_RATEINFOREQ 0x0006
-#define SNAC_SUBTYPE_OSERVICE_RATEINFO 0x0007
-#define SNAC_SUBTYPE_OSERVICE_RATEINFOACK 0x0008
-#define SNAC_SUBTYPE_OSERVICE_RATECHANGE 0x000a
-#define SNAC_SUBTYPE_OSERVICE_SERVERPAUSE 0x000b
-#define SNAC_SUBTYPE_OSERVICE_SERVERRESUME 0x000d
-#define SNAC_SUBTYPE_OSERVICE_REQSELFINFO 0x000e
-#define SNAC_SUBTYPE_OSERVICE_SELFINFO 0x000f
-#define SNAC_SUBTYPE_OSERVICE_EVIL 0x0010
-#define SNAC_SUBTYPE_OSERVICE_SETIDLE 0x0011
-#define SNAC_SUBTYPE_OSERVICE_MIGRATIONREQ 0x0012
-#define SNAC_SUBTYPE_OSERVICE_MOTD 0x0013
-#define SNAC_SUBTYPE_OSERVICE_SETPRIVFLAGS 0x0014
-#define SNAC_SUBTYPE_OSERVICE_WELLKNOWNURL 0x0015
-#define SNAC_SUBTYPE_OSERVICE_NOP 0x0016
-#define SNAC_SUBTYPE_OSERVICE_DEFAULT 0xffff
-
-/*
- * SNAC Family: Location Services.
- */
-#define SNAC_SUBTYPE_LOCATE_ERROR 0x0001
-#define SNAC_SUBTYPE_LOCATE_REQRIGHTS 0x0002
-#define SNAC_SUBTYPE_LOCATE_RIGHTSINFO 0x0003
-#define SNAC_SUBTYPE_LOCATE_SETUSERINFO 0x0004
-#define SNAC_SUBTYPE_LOCATE_REQUSERINFO 0x0005
-#define SNAC_SUBTYPE_LOCATE_USERINFO 0x0006
-#define SNAC_SUBTYPE_LOCATE_WATCHERSUBREQ 0x0007
-#define SNAC_SUBTYPE_LOCATE_WATCHERNOT 0x0008
-#define SNAC_SUBTYPE_LOCATE_DEFAULT 0xffff
-
-/*
- * SNAC Family: Buddy List Management Services.
- */
-#define SNAC_SUBTYPE_BUDDY_ERROR 0x0001
-#define SNAC_SUBTYPE_BUDDY_REQRIGHTS 0x0002
-#define SNAC_SUBTYPE_BUDDY_RIGHTSINFO 0x0003
-#define SNAC_SUBTYPE_BUDDY_ADDBUDDY 0x0004
-#define SNAC_SUBTYPE_BUDDY_REMBUDDY 0x0005
-#define SNAC_SUBTYPE_BUDDY_REJECT 0x000a
-#define SNAC_SUBTYPE_BUDDY_ONCOMING 0x000b
-#define SNAC_SUBTYPE_BUDDY_OFFGOING 0x000c
-#define SNAC_SUBTYPE_BUDDY_DEFAULT 0xffff
-
-/*
- * SNAC Family: Messaging Services.
- */
-#define SNAC_SUBTYPE_ICBM_ERROR 0x0001
-#define SNAC_SUBTYPE_ICBM_PARAMINFO 0x0005
-#define SNAC_SUBTYPE_ICBM_INCOMING 0x0007
-#define SNAC_SUBTYPE_ICBM_EVIL 0x0009
-#define SNAC_SUBTYPE_ICBM_MISSEDCALL 0x000a
-#define SNAC_SUBTYPE_ICBM_CLIENTAUTORESP 0x000b
-#define SNAC_SUBTYPE_ICBM_ACK 0x000c
-#define SNAC_SUBTYPE_ICBM_MTN 0x0014
-#define SNAC_SUBTYPE_ICBM_DEFAULT 0xffff
-
-/*
- * SNAC Family: Advertisement Services
- */
-#define SNAC_SUBTYPE_ADVERT_ERROR 0x0001
-#define SNAC_SUBTYPE_ADVERT_DEFAULT 0xffff
-
-/*
- * SNAC Family: Invitation Services.
- */
-#define SNAC_SUBTYPE_INVITE_ERROR 0x0001
-#define SNAC_SUBTYPE_INVITE_DEFAULT 0xffff
-
-/*
- * SNAC Family: Administrative Services.
- */
-#define SNAC_SUBTYPE_ADMIN_ERROR 0x0001
-#define SNAC_SUBTYPE_ADMIN_INFOCHANGE_REPLY 0x0005
-#define SNAC_SUBTYPE_ADMIN_DEFAULT 0xffff
-
-/*
- * SNAC Family: Popup Messages
- */
-#define SNAC_SUBTYPE_POPUP_ERROR 0x0001
-#define SNAC_SUBTYPE_POPUP_DEFAULT 0xffff
-
-/*
- * SNAC Family: Misc BOS Services.
- */
-#define SNAC_SUBTYPE_BOS_ERROR 0x0001
-#define SNAC_SUBTYPE_BOS_RIGHTSQUERY 0x0002
-#define SNAC_SUBTYPE_BOS_RIGHTS 0x0003
-#define SNAC_SUBTYPE_BOS_DEFAULT 0xffff
-
-/*
- * SNAC Family: User Lookup Services
- */
-#define SNAC_SUBTYPE_USERLOOKUP_ERROR 0x0001
-#define SNAC_SUBTYPE_USERLOOKUP_DEFAULT 0xffff
-
-/*
- * SNAC Family: User Status Services
- */
-#define SNAC_SUBTYPE_STATS_ERROR 0x0001
-#define SNAC_SUBTYPE_STATS_SETREPORTINTERVAL 0x0002
-#define SNAC_SUBTYPE_STATS_REPORTACK 0x0004
-#define SNAC_SUBTYPE_STATS_DEFAULT 0xffff
-
-/*
- * SNAC Family: Translation Services
- */
-#define SNAC_SUBTYPE_TRANSLATE_ERROR 0x0001
-#define SNAC_SUBTYPE_TRANSLATE_DEFAULT 0xffff
-
-/*
- * SNAC Family: Chat Navigation Services
- */
-#define SNAC_SUBTYPE_CHATNAV_ERROR 0x0001
-#define SNAC_SUBTYPE_CHATNAV_CREATE 0x0008
-#define SNAC_SUBTYPE_CHATNAV_INFO 0x0009
-#define SNAC_SUBTYPE_CHATNAV_DEFAULT 0xffff
-
-/*
- * SNAC Family: Chat Services
- */
-#define SNAC_SUBTYPE_CHAT_ERROR 0x0001
-#define SNAC_SUBTYPE_CHAT_ROOMINFOUPDATE 0x0002
-#define SNAC_SUBTYPE_CHAT_USERJOIN 0x0003
-#define SNAC_SUBTYPE_CHAT_USERLEAVE 0x0004
-#define SNAC_SUBTYPE_CHAT_OUTGOINGMSG 0x0005
-#define SNAC_SUBTYPE_CHAT_INCOMINGMSG 0x0006
-#define SNAC_SUBTYPE_CHAT_DEFAULT 0xffff
-
-/*
- * SNAC Family: "New" Search
- */
-#define SNAC_SUBTYPE_ODIR_ERROR 0x0001
-#define SNAC_SUBTYPE_ODIR_SEARCH 0x0002
-#define SNAC_SUBTYPE_ODIR_RESULTS 0x0003
-
-/*
- * SNAC Family: Buddy icons
- */
-#define SNAC_SUBTYPE_BART_ERROR 0x0001
-#define SNAC_SUBTYPE_BART_REQUEST 0x0004
-#define SNAC_SUBTYPE_BART_RESPONSE 0x0005
-
-/*
- * SNAC Family: Server-Stored Buddy Lists
- */
-#define SNAC_SUBTYPE_FEEDBAG_ERROR 0x0001
-#define SNAC_SUBTYPE_FEEDBAG_REQRIGHTS 0x0002
-#define SNAC_SUBTYPE_FEEDBAG_RIGHTSINFO 0x0003
-#define SNAC_SUBTYPE_FEEDBAG_REQDATA 0x0004
-#define SNAC_SUBTYPE_FEEDBAG_REQIFCHANGED 0x0005
-#define SNAC_SUBTYPE_FEEDBAG_LIST 0x0006
-#define SNAC_SUBTYPE_FEEDBAG_ACTIVATE 0x0007
-#define SNAC_SUBTYPE_FEEDBAG_ADD 0x0008
-#define SNAC_SUBTYPE_FEEDBAG_MOD 0x0009
-#define SNAC_SUBTYPE_FEEDBAG_DEL 0x000A
-#define SNAC_SUBTYPE_FEEDBAG_SRVACK 0x000E
-#define SNAC_SUBTYPE_FEEDBAG_NOLIST 0x000F
-#define SNAC_SUBTYPE_FEEDBAG_EDITSTART 0x0011
-#define SNAC_SUBTYPE_FEEDBAG_EDITSTOP 0x0012
-#define SNAC_SUBTYPE_FEEDBAG_SENDAUTH 0x0014
-#define SNAC_SUBTYPE_FEEDBAG_RECVAUTH 0x0015
-#define SNAC_SUBTYPE_FEEDBAG_SENDAUTHREQ 0x0018
-#define SNAC_SUBTYPE_FEEDBAG_RECVAUTHREQ 0x0019
-#define SNAC_SUBTYPE_FEEDBAG_SENDAUTHREP 0x001a
-#define SNAC_SUBTYPE_FEEDBAG_RECVAUTHREP 0x001b
-#define SNAC_SUBTYPE_FEEDBAG_ADDED 0x001c
-
-/*
- * SNAC Family: ICQ
- *
- * Most of these are actually special.
- */
-#define SNAC_SUBTYPE_ICQ_ERROR 0x0001
-#define SNAC_SUBTYPE_ICQ_OFFLINEMSG 0x00f0
-#define SNAC_SUBTYPE_ICQ_OFFLINEMSGCOMPLETE 0x00f1
-#define SNAC_SUBTYPE_ICQ_INFO 0x00f2
-#define SNAC_SUBTYPE_ICQ_ALIAS 0x00f3
-#define SNAC_SUBTYPE_ICQ_DEFAULT 0xffff
-
-/*
- * SNAC Family: Authorizer
- *
- * Used only in protocol versions three and above.
- */
-#define SNAC_SUBTYPE_AUTH_ERROR 0x0001
-#define SNAC_SUBTYPE_AUTH_LOGINREQEST 0x0002
-#define SNAC_SUBTYPE_AUTH_LOGINRESPONSE 0x0003
-#define SNAC_SUBTYPE_AUTH_AUTHREQ 0x0006
-#define SNAC_SUBTYPE_AUTH_AUTHRESPONSE 0x0007
-#define SNAC_SUBTYPE_AUTH_SECURID_REQUEST 0x000a
-#define SNAC_SUBTYPE_AUTH_SECURID_RESPONSE 0x000b
-
-/*
- * SNAC Family: Email
- *
- * Used for getting information on the email address
- * associated with your username.
- */
-#define SNAC_SUBTYPE_ALERT_ERROR 0x0001
-#define SNAC_SUBTYPE_ALERT_SENDCOOKIES 0x0006
-#define SNAC_SUBTYPE_ALERT_MAILSTATUS 0x0007
-#define SNAC_SUBTYPE_ALERT_INIT 0x0016
-
-/*
- * SNAC Family: Internal Messages
- *
- * This isn't truly a SNAC family either, but using
- * these, we can integrated non-SNAC services into
- * the SNAC-centered libfaim callback structure.
- */
-#define AIM_CB_SPECIAL_CONNERR 0x0003
-#define AIM_CB_SPECIAL_CONNINITDONE 0x0006
-
-/* SNAC flags */
-#define AIM_SNACFLAGS_DESTRUCTOR 0x0001
-
-#endif /* PURPLE_OSCAR_SNACTYPES_H */
--- a/libpurple/protocols/oscar/tests/meson.build	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-foreach prog : ['util']
-	e = executable(
-	    'test_oscar_' + prog, 'test_oscar_@0@.c'.format(prog),
-	    link_with : [oscar_prpl],
-	    dependencies : [libpurple_dep, libsoup, glib])
-
-	test('oscar_' + prog, e)
-endforeach
--- a/libpurple/protocols/oscar/tests/test_oscar_util.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-#include <glib.h>
-
-#include "../oscar.h"
-
-static void
-test_oscar_util_name_compare(void) {
-	gsize i;
-	const gchar *good[] = {
-		"test",
-		"TEST",
-		"Test",
-		"teSt",
-		" TesT",
-		"test ",
-		"  T E   s T  "
-	};
-	const gchar *bad[] = {
-		"toast",
-		"test@example.com",
-		"test@aim.com"
-	};
-
-	for(i = 0; i < G_N_ELEMENTS(good); i++) {
-		g_assert_cmpint(0, ==, oscar_util_name_compare("test", good[i]));
-		g_assert_cmpint(0, ==, oscar_util_name_compare(good[i], "test"));
-	}
-
-	for(i = 0; i < G_N_ELEMENTS(bad); i++) {
-		g_assert_cmpint(0, !=, oscar_util_name_compare("test", bad[i]));
-		g_assert_cmpint(0, !=, oscar_util_name_compare(bad[i], "test"));
-	}
-}
-
-gint
-main(gint argc, gchar **argv) {
-	g_test_init(&argc, &argv, NULL);
-
-	g_test_add_func("/oscar/util/name compare",
-	                test_oscar_util_name_compare);
-
-	return g_test_run();
-}
--- a/libpurple/protocols/oscar/tlv.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,815 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-#include "oscar.h"
-
-static aim_tlv_t *
-createtlv(guint16 type, guint16 length, guint8 *value)
-{
-	aim_tlv_t *ret;
-
-	ret = g_new(aim_tlv_t, 1);
-	ret->type = type;
-	ret->length = length;
-	ret->value = value;
-
-	return ret;
-}
-
-static void
-freetlv(aim_tlv_t *oldtlv)
-{
-	g_free(oldtlv->value);
-	g_free(oldtlv);
-}
-
-static GSList *
-aim_tlv_read(GSList *list, ByteStream *bs)
-{
-	guint16 type, length;
-	aim_tlv_t *tlv;
-
-	type = byte_stream_get16(bs);
-	length = byte_stream_get16(bs);
-
-	if (length > byte_stream_bytes_left(bs)) {
-		aim_tlvlist_free(list);
-		return NULL;
-	}
-
-	tlv = createtlv(type, length, NULL);
-	if (tlv->length > 0) {
-		tlv->value = byte_stream_getraw(bs, length);
-		if (!tlv->value) {
-			freetlv(tlv);
-			aim_tlvlist_free(list);
-			return NULL;
-		}
-	}
-
-	return g_slist_prepend(list, tlv);
-}
-
-/**
- * Read a TLV chain from a buffer.
- *
- * Reads and parses a series of TLV patterns from a data buffer; the
- * returned structure is manipulatable with the rest of the TLV
- * routines.  When done with a TLV chain, aim_tlvlist_free() should
- * be called to free the dynamic substructures.
- *
- * TODO: There should be a flag setable here to have the tlvlist contain
- * bstream references, so that at least the ->value portion of each
- * element doesn't need to be malloc/memcpy'd.  This could prove to be
- * just as efficient as the in-place TLV parsing used in a couple places
- * in libfaim.
- *
- * @param bs Input bstream
- * @return Return the TLV chain read
- */
-GSList *aim_tlvlist_read(ByteStream *bs)
-{
-	GSList *list = NULL;
-
-	while (byte_stream_bytes_left(bs) > 0) {
-		list = aim_tlv_read(list, bs);
-		if (list == NULL)
-			return NULL;
-	}
-
-	return g_slist_reverse(list);
-}
-
-/**
- * Read a TLV chain from a buffer.
- *
- * Reads and parses a series of TLV patterns from a data buffer; the
- * returned structure is manipulatable with the rest of the TLV
- * routines.  When done with a TLV chain, aim_tlvlist_free() should
- * be called to free the dynamic substructures.
- *
- * TODO: There should be a flag setable here to have the tlvlist contain
- * bstream references, so that at least the ->value portion of each
- * element doesn't need to be malloc/memcpy'd.  This could prove to be
- * just as efficient as the in-place TLV parsing used in a couple places
- * in libfaim.
- *
- * @param bs Input bstream
- * @param num The max number of TLVs that will be read, or -1 if unlimited.
- *        There are a number of places where you want to read in a tlvchain,
- *        but the chain is not at the end of the SNAC, and the chain is
- *        preceded by the number of TLVs.  So you can limit that with this.
- * @return Return the TLV chain read
- */
-GSList *aim_tlvlist_readnum(ByteStream *bs, guint16 num)
-{
-	GSList *list = NULL;
-
-	while ((byte_stream_bytes_left(bs) > 0) && (num != 0)) {
-		list = aim_tlv_read(list, bs);
-		if (list == NULL)
-			return NULL;
-		num--;
-	}
-
-	return g_slist_reverse(list);
-}
-
-/**
- * Read a TLV chain from a buffer.
- *
- * Reads and parses a series of TLV patterns from a data buffer; the
- * returned structure is manipulatable with the rest of the TLV
- * routines.  When done with a TLV chain, aim_tlvlist_free() should
- * be called to free the dynamic substructures.
- *
- * TODO: There should be a flag setable here to have the tlvlist contain
- * bstream references, so that at least the ->value portion of each
- * element doesn't need to be malloc/memcpy'd.  This could prove to be
- * just as efficient as the in-place TLV parsing used in a couple places
- * in libfaim.
- *
- * @param bs Input bstream
- * @param len The max length in bytes that will be read.
- *        There are a number of places where you want to read in a tlvchain,
- *        but the chain is not at the end of the SNAC, and the chain is
- *        preceded by the length of the TLVs.  So you can limit that with this.
- * @return Return the TLV chain read
- */
-GSList *aim_tlvlist_readlen(ByteStream *bs, guint16 len)
-{
-	GSList *list = NULL;
-
-	while ((byte_stream_bytes_left(bs) > 0) && (len > 0)) {
-		list = aim_tlv_read(list, bs);
-		if (list == NULL)
-			return NULL;
-
-		len -= 2 + 2 + ((aim_tlv_t *)list->data)->length;
-	}
-
-	return g_slist_reverse(list);
-}
-
-/**
- * Duplicate a TLV chain.
- * This is pretty self explanatory.
- *
- * @param orig The TLV chain you want to make a copy of.
- * @return A newly allocated TLV chain.
- */
-GSList *aim_tlvlist_copy(GSList *orig)
-{
-	GSList *new = NULL;
-	aim_tlv_t *tlv;
-
-	while (orig != NULL) {
-		tlv = orig->data;
-		aim_tlvlist_add_raw(&new, tlv->type, tlv->length, tlv->value);
-		orig = orig->next;
-	}
-
-	return new;
-}
-
-/*
- * Compare two TLV lists for equality.  This probably is not the most
- * efficient way to do this.
- *
- * @param one One of the TLV chains to compare.
- * @param two The other TLV chain to compare.
- * @return Return 0 if the lists are the same, return 1 if they are different.
- */
-int aim_tlvlist_cmp(GSList *one, GSList *two)
-{
-	ByteStream bs1, bs2;
-
-	if (aim_tlvlist_size(one) != aim_tlvlist_size(two))
-		return 1;
-
-	byte_stream_new(&bs1, aim_tlvlist_size(one));
-	byte_stream_new(&bs2, aim_tlvlist_size(two));
-
-	aim_tlvlist_write(&bs1, &one);
-	aim_tlvlist_write(&bs2, &two);
-
-	if (memcmp(bs1.data, bs2.data, bs1.len)) {
-		byte_stream_destroy(&bs1);
-		byte_stream_destroy(&bs2);
-		return 1;
-	}
-
-	byte_stream_destroy(&bs1);
-	byte_stream_destroy(&bs2);
-
-	return 0;
-}
-
-/**
- * Free a TLV chain structure
- *
- * Walks the list of TLVs in the passed TLV chain and
- * frees each one. Note that any references to this data
- * should be removed before calling this.
- *
- * @param list Chain to be freed
- */
-void aim_tlvlist_free(GSList *list)
-{
-	g_slist_free_full(list, (GDestroyNotify)freetlv);
-}
-
-/**
- * Count the number of TLVs in a chain.
- *
- * @param list Chain to be counted.
- * @return The number of TLVs stored in the passed chain.
- */
-int aim_tlvlist_count(GSList *list)
-{
-	return (int)g_slist_length(list);
-}
-
-/**
- * Count the number of bytes in a TLV chain.
- *
- * @param list Chain to be sized
- * @return The number of bytes that would be needed to
- *         write the passed TLV chain to a data buffer.
- */
-size_t aim_tlvlist_size(GSList *list)
-{
-	GSList *cur;
-	size_t size;
-
-	if (list == NULL)
-		return 0;
-
-	for (cur = list, size = 0; cur; cur = cur->next)
-		size += (4 + ((aim_tlv_t *)cur->data)->length);
-
-	return size;
-}
-
-/**
- * Adds the passed string as a TLV element of the passed type
- * to the TLV chain.
- *
- * @param list Desination chain (%NULL pointer if empty).
- * @param type TLV type.
- * @param length Length of string to add (not including %NULL).
- * @param value String to add.
- * @return The size of the value added.
- */
-int aim_tlvlist_add_raw(GSList **list, const guint16 type, const guint16 length, const guint8 *value)
-{
-	aim_tlv_t *tlv;
-
-	if (list == NULL)
-		return 0;
-
-	tlv = createtlv(type, length, NULL);
-	if (tlv->length > 0)
-		tlv->value = g_memdup(value, length);
-
-	*list = g_slist_append(*list, tlv);
-
-	return tlv->length;
-}
-
-/**
- * Add a one byte integer to a TLV chain.
- *
- * @param list Destination chain.
- * @param type TLV type to add.
- * @param value Value to add.
- * @return The size of the value added.
- */
-int aim_tlvlist_add_8(GSList **list, const guint16 type, const guint8 value)
-{
-	guint8 v8[1];
-
-	(void)aimutil_put8(v8, value);
-
-	return aim_tlvlist_add_raw(list, type, 1, v8);
-}
-
-/**
- * Add a two byte integer to a TLV chain.
- *
- * @param list Destination chain.
- * @param type TLV type to add.
- * @param value Value to add.
- * @return The size of the value added.
- */
-int aim_tlvlist_add_16(GSList **list, const guint16 type, const guint16 value)
-{
-	guint8 v16[2];
-
-	(void)aimutil_put16(v16, value);
-
-	return aim_tlvlist_add_raw(list, type, 2, v16);
-}
-
-/**
- * Add a four byte integer to a TLV chain.
- *
- * @param list Destination chain.
- * @param type TLV type to add.
- * @param value Value to add.
- * @return The size of the value added.
- */
-int aim_tlvlist_add_32(GSList **list, const guint16 type, const guint32 value)
-{
-	guint8 v32[4];
-
-	(void)aimutil_put32(v32, value);
-
-	return aim_tlvlist_add_raw(list, type, 4, v32);
-}
-
-/**
- * Add a string to a TLV chain.
- *
- * @param list Destination chain.
- * @param type TLV type to add.
- * @param value Value to add.
- * @return The size of the value added.
- */
-int aim_tlvlist_add_str(GSList **list, const guint16 type, const char *value)
-{
-	return aim_tlvlist_add_raw(list, type, strlen(value), (guint8 *)value);
-}
-
-static int
-count_caps(guint64 caps)
-{
-	int set_bits = 0;
-	while (caps) {
-		set_bits += caps & 1;
-		caps >>= 1;
-	}
-	return set_bits;
-}
-
-/**
- * Adds a block of capability blocks to a TLV chain. The bitfield
- * passed in should be a bitwise %OR of any of the %AIM_CAPS constants:
- *
- *     %OSCAR_CAPABILITY_BUDDYICON   Supports Buddy Icons
- *     %OSCAR_CAPABILITY_TALK        Supports Voice Chat
- *     %OSCAR_CAPABILITY_IMIMAGE     Supports DirectIM/IMImage
- *     %OSCAR_CAPABILITY_CHAT        Supports Chat
- *     %OSCAR_CAPABILITY_GETFILE     Supports Get File functions
- *     %OSCAR_CAPABILITY_SENDFILE    Supports Send File functions
- *
- * @param list Destination chain
- * @param type TLV type to add
- * @param caps Bitfield of capability flags to send
- * @return The size of the value added.
- */
-int aim_tlvlist_add_caps(GSList **list, const guint16 type, const guint64 caps, const char *mood)
-{
-	int len;
-	ByteStream bs;
-	guint32 bs_size;
-	guint8 *data;
-
-	if (caps == 0)
-		return 0; /* nothing there anyway */
-
-	data = icq_get_custom_icon_data(mood);
-	bs_size = 16*(count_caps(caps) + (data != NULL ? 1 : 0));
-
-	byte_stream_new(&bs, bs_size);
-	byte_stream_putcaps(&bs, caps);
-
-	/* adding of custom icon GUID */
-	if (data != NULL)
-		byte_stream_putraw(&bs, data, 16);
-
-	len = aim_tlvlist_add_raw(list, type, byte_stream_curpos(&bs), bs.data);
-
-	byte_stream_destroy(&bs);
-
-	return len;
-}
-
-/**
- * Adds the given chatroom info to a TLV chain.
- *
- * @param list Destination chain.
- * @param type TLV type to add.
- * @param roomname The name of the chat.
- * @param instance The instance.
- * @return The size of the value added.
- */
-int aim_tlvlist_add_chatroom(GSList **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance)
-{
-	int len;
-	ByteStream bs;
-
-	byte_stream_new(&bs, 2 + 1 + strlen(roomname) + 2);
-
-	byte_stream_put16(&bs, exchange);
-	byte_stream_put8(&bs, strlen(roomname));
-	byte_stream_putstr(&bs, roomname);
-	byte_stream_put16(&bs, instance);
-
-	len = aim_tlvlist_add_raw(list, type, byte_stream_curpos(&bs), bs.data);
-
-	byte_stream_destroy(&bs);
-
-	return len;
-}
-
-/**
- * Adds a TLV with a zero length to a TLV chain.
- *
- * @param list Destination chain.
- * @param type TLV type to add.
- * @return The size of the value added.
- */
-int aim_tlvlist_add_noval(GSList **list, const guint16 type)
-{
-	return aim_tlvlist_add_raw(list, type, 0, NULL);
-}
-
-/*
- * Note that the inner TLV chain will not be modifiable as a tlvchain once
- * it is written using this.  Or rather, it can be, but updates won't be
- * made to this.
- *
- * TODO: Should probably support sublists for real.
- *
- * This is so neat.
- *
- * @param list Destination chain.
- * @param type TLV type to add.
- * @param t1 The TLV chain you want to write.
- * @return The number of bytes written to the destination TLV chain.
- *         0 is returned if there was an error or if the destination
- *         TLV chain has length 0.
- */
-int aim_tlvlist_add_frozentlvlist(GSList **list, guint16 type, GSList **tlvlist)
-{
-	int buflen;
-	ByteStream bs;
-
-	buflen = aim_tlvlist_size(*tlvlist);
-
-	if (buflen <= 0)
-		return 0;
-
-	byte_stream_new(&bs, buflen);
-
-	aim_tlvlist_write(&bs, tlvlist);
-
-	aim_tlvlist_add_raw(list, type, byte_stream_curpos(&bs), bs.data);
-
-	byte_stream_destroy(&bs);
-
-	return buflen;
-}
-
-/**
- * Substitute a TLV of a given type with a new TLV of the same type.  If
- * you attempt to replace a TLV that does not exist, this function will
- * just add a new TLV as if you called aim_tlvlist_add_raw().
- *
- * @param list Desination chain (%NULL pointer if empty).
- * @param type TLV type.
- * @param length Length of string to add (not including %NULL).
- * @param value String to add.
- * @return The length of the TLV.
- */
-int aim_tlvlist_replace_raw(GSList **list, const guint16 type, const guint16 length, const guint8 *value)
-{
-	GSList *cur;
-	aim_tlv_t *tlv;
-
-	if (list == NULL)
-		return 0;
-
-	for (cur = *list; cur != NULL; cur = cur->next)
-	{
-		tlv = cur->data;
-		if (tlv->type == type)
-			break;
-	}
-
-	if (cur == NULL)
-		/* TLV does not exist, so add a new one */
-		return aim_tlvlist_add_raw(list, type, length, value);
-
-	g_free(tlv->value);
-	tlv->length = length;
-	if (tlv->length > 0) {
-		tlv->value = g_memdup(value, length);
-	} else
-		tlv->value = NULL;
-
-	return tlv->length;
-}
-
-/**
- * Substitute a TLV of a given type with a new TLV of the same type.  If
- * you attempt to replace a TLV that does not exist, this function will
- * just add a new TLV as if you called aim_tlvlist_add_str().
- *
- * @param list Desination chain (%NULL pointer if empty).
- * @param type TLV type.
- * @param str String to add.
- * @return The length of the TLV.
- */
-int aim_tlvlist_replace_str(GSList **list, const guint16 type, const char *str)
-{
-	return aim_tlvlist_replace_raw(list, type, strlen(str), (const guchar *)str);
-}
-
-/**
- * Substitute a TLV of a given type with a new TLV of the same type.  If
- * you attempt to replace a TLV that does not exist, this function will
- * just add a new TLV as if you called aim_tlvlist_add_raw().
- *
- * @param list Desination chain (%NULL pointer if empty).
- * @param type TLV type.
- * @return The length of the TLV.
- */
-int aim_tlvlist_replace_noval(GSList **list, const guint16 type)
-{
-	return aim_tlvlist_replace_raw(list, type, 0, NULL);
-}
-
-/**
- * Substitute a TLV of a given type with a new TLV of the same type.  If
- * you attempt to replace a TLV that does not exist, this function will
- * just add a new TLV as if you called aim_tlvlist_add_raw().
- *
- * @param list Desination chain (%NULL pointer if empty).
- * @param type TLV type.
- * @param value 8 bit value to add.
- * @return The length of the TLV.
- */
-int aim_tlvlist_replace_8(GSList **list, const guint16 type, const guint8 value)
-{
-	guint8 v8[1];
-
-	(void)aimutil_put8(v8, value);
-
-	return aim_tlvlist_replace_raw(list, type, 1, v8);
-}
-
-/**
- * Substitute a TLV of a given type with a new TLV of the same type.  If
- * you attempt to replace a TLV that does not exist, this function will
- * just add a new TLV as if you called aim_tlvlist_add_raw().
- *
- * @param list Desination chain (%NULL pointer if empty).
- * @param type TLV type.
- * @param value 32 bit value to add.
- * @return The length of the TLV.
- */
-int aim_tlvlist_replace_32(GSList **list, const guint16 type, const guint32 value)
-{
-	guint8 v32[4];
-
-	(void)aimutil_put32(v32, value);
-
-	return aim_tlvlist_replace_raw(list, type, 4, v32);
-}
-
-/**
- * Remove all TLVs of a given type.  If you attempt to remove a TLV
- * that does not exist, nothing happens.
- *
- * @param list Desination chain (%NULL pointer if empty).
- * @param type TLV type.
- */
-void aim_tlvlist_remove(GSList **list, const guint16 type)
-{
-	GSList *cur, *next;
-	aim_tlv_t *tlv;
-
-	if (list == NULL || *list == NULL)
-		return;
-
-	cur = *list;
-	while (cur != NULL)
-	{
-		tlv = cur->data;
-		next = cur->next;
-
-		if (tlv->type == type)
-		{
-			/* Delete this TLV */
-			*list = g_slist_delete_link(*list, cur);
-			g_free(tlv->value);
-			g_free(tlv);
-		}
-
-		cur = next;
-	}
-}
-
-/**
- * Write a TLV chain into a data buffer.
- *
- * Copies a TLV chain into a raw data buffer, writing only the number
- * of bytes specified. This operation does not free the chain;
- * aim_tlvlist_free() must still be called to free up the memory used
- * by the chain structures.
- *
- * TODO: Clean this up, make better use of bstreams
- *
- * @param bs Input bstream
- * @param list Source TLV chain
- * @return Return 0 if the destination bstream is too small.
- */
-int aim_tlvlist_write(ByteStream *bs, GSList **list)
-{
-	size_t goodbuflen;
-	GSList *cur;
-	aim_tlv_t *tlv;
-
-	/* do an initial run to test total length */
-	goodbuflen = aim_tlvlist_size(*list);
-
-	if (goodbuflen > byte_stream_bytes_left(bs))
-		return 0; /* not enough buffer */
-
-	/* do the real write-out */
-	for (cur = *list; cur; cur = cur->next) {
-		tlv = cur->data;
-		byte_stream_put16(bs, tlv->type);
-		byte_stream_put16(bs, tlv->length);
-		if (tlv->length > 0)
-			byte_stream_putraw(bs, tlv->value, tlv->length);
-	}
-
-	return 1; /* TODO: This is a nonsensical return */
-}
-
-
-/**
- * Grab the Nth TLV of type type in the TLV list list.
- *
- * Returns a pointer to an aim_tlv_t of the specified type;
- * %NULL on error.  The @nth parameter is specified starting at %1.
- * In most cases, there will be no more than one TLV of any type
- * in a chain.
- *
- * @param list Source chain.
- * @param type Requested TLV type.
- * @param nth Index of TLV of type to get.
- * @return The TLV you were looking for, or NULL if one could not be found.
- */
-aim_tlv_t *aim_tlv_gettlv(GSList *list, const guint16 type, const int nth)
-{
-	GSList *cur;
-	aim_tlv_t *tlv;
-	int i;
-
-	for (cur = list, i = 0; cur != NULL; cur = cur->next) {
-		tlv = cur->data;
-		if (tlv->type == type)
-			i++;
-		if (i >= nth)
-			return tlv;
-	}
-
-	return NULL;
-}
-
-/**
- * Get the length of the data of the nth TLV in the given TLV chain.
- *
- * @param list Source chain.
- * @param type Requested TLV type.
- * @param nth Index of TLV of type to get.
- * @return The length of the data in this TLV, or -1 if the TLV could not be
- *         found.  Unless -1 is returned, this value will be 2 bytes.
- */
-int aim_tlv_getlength(GSList *list, const guint16 type, const int nth)
-{
-	aim_tlv_t *tlv;
-
-	tlv = aim_tlv_gettlv(list, type, nth);
-	if (tlv == NULL)
-		return -1;
-
-	return tlv->length;
-}
-
-char *
-aim_tlv_getvalue_as_string(aim_tlv_t *tlv)
-{
-	char *ret;
-
-	ret = g_malloc(tlv->length + 1);
-	memcpy(ret, tlv->value, tlv->length);
-	ret[tlv->length] = '\0';
-
-	return ret;
-}
-
-/**
- * Retrieve the data from the nth TLV in the given TLV chain as a string.
- *
- * @param list Source TLV chain.
- * @param type TLV type to search for.
- * @param nth Index of TLV to return.
- * @return The value of the TLV you were looking for, or NULL if one could
- *         not be found.  This is a dynamic buffer and must be freed by the
- *         caller.
- */
-char *aim_tlv_getstr(GSList *list, const guint16 type, const int nth)
-{
-	aim_tlv_t *tlv;
-
-	tlv = aim_tlv_gettlv(list, type, nth);
-	if (tlv == NULL)
-		return NULL;
-
-	return aim_tlv_getvalue_as_string(tlv);
-}
-
-/**
- * Retrieve the data from the nth TLV in the given TLV chain as an 8bit
- * integer.
- *
- * @param list Source TLV chain.
- * @param type TLV type to search for.
- * @param nth Index of TLV to return.
- * @return The value the TLV you were looking for, or 0 if one could
- *         not be found.
- */
-guint8 aim_tlv_get8(GSList *list, const guint16 type, const int nth)
-{
-	aim_tlv_t *tlv;
-
-	tlv = aim_tlv_gettlv(list, type, nth);
-	if (tlv == NULL)
-		return 0; /* erm */
-
-	return aimutil_get8(tlv->value);
-}
-
-/**
- * Retrieve the data from the nth TLV in the given TLV chain as a 16bit
- * integer.
- *
- * @param list Source TLV chain.
- * @param type TLV type to search for.
- * @param nth Index of TLV to return.
- * @return The value the TLV you were looking for, or 0 if one could
- *         not be found.
- */
-guint16 aim_tlv_get16(GSList *list, const guint16 type, const int nth)
-{
-	aim_tlv_t *tlv;
-
-	tlv = aim_tlv_gettlv(list, type, nth);
-	if (tlv == NULL)
-		return 0; /* erm */
-
-	return aimutil_get16(tlv->value);
-}
-
-/**
- * Retrieve the data from the nth TLV in the given TLV chain as a 32bit
- * integer.
- *
- * @param list Source TLV chain.
- * @param type TLV type to search for.
- * @param nth Index of TLV to return.
- * @return The value the TLV you were looking for, or 0 if one could
- *         not be found.
- */
-guint32 aim_tlv_get32(GSList *list, const guint16 type, const int nth)
-{
-	aim_tlv_t *tlv;
-
-	tlv = aim_tlv_gettlv(list, type, nth);
-	if (tlv == NULL)
-		return 0; /* erm */
-
-	return aimutil_get32(tlv->value);
-}
--- a/libpurple/protocols/oscar/userinfo.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,553 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Displaying various information about buddies.
- */
-
-#include "encoding.h"
-#include "oscar.h"
-
-static gchar *
-oscar_caps_to_string(guint64 caps)
-{
-	GString *str;
-	const gchar *tmp;
-	guint64 bit = 1;
-
-	if (!caps) {
-		return NULL;
-	}
-
-	str = g_string_new("");
-	while (bit <= OSCAR_CAPABILITY_LAST) {
-		if (bit & caps) {
-			switch (bit) {
-			case OSCAR_CAPABILITY_BUDDYICON:
-				tmp = _("Buddy Icon");
-				break;
-			case OSCAR_CAPABILITY_TALK:
-				tmp = _("Voice");
-				break;
-			case OSCAR_CAPABILITY_DIRECTIM:
-				tmp = _("AIM Direct IM");
-				break;
-			case OSCAR_CAPABILITY_CHAT:
-				tmp = _("Chat");
-				break;
-			case OSCAR_CAPABILITY_GETFILE:
-				tmp = _("Get File");
-				break;
-			case OSCAR_CAPABILITY_SENDFILE:
-				tmp = _("Send File");
-				break;
-			case OSCAR_CAPABILITY_GAMES:
-			case OSCAR_CAPABILITY_GAMES2:
-				tmp = _("Games");
-				break;
-			case OSCAR_CAPABILITY_XTRAZ:
-			case OSCAR_CAPABILITY_NEWCAPS:
-				tmp = _("ICQ Xtraz");
-				break;
-			case OSCAR_CAPABILITY_ADDINS:
-				tmp = _("Add-Ins");
-				break;
-			case OSCAR_CAPABILITY_SENDBUDDYLIST:
-				tmp = _("Send Buddy List");
-				break;
-			case OSCAR_CAPABILITY_ICQ_DIRECT:
-				tmp = _("ICQ Direct Connect");
-				break;
-			case OSCAR_CAPABILITY_APINFO:
-				tmp = _("AP User");
-				break;
-			case OSCAR_CAPABILITY_ICQRTF:
-				tmp = _("ICQ RTF");
-				break;
-			case OSCAR_CAPABILITY_EMPTY:
-				tmp = _("Nihilist");
-				break;
-			case OSCAR_CAPABILITY_ICQSERVERRELAY:
-				tmp = _("ICQ Server Relay");
-				break;
-			case OSCAR_CAPABILITY_UNICODEOLD:
-				tmp = _("Old ICQ UTF8");
-				break;
-			case OSCAR_CAPABILITY_TRILLIANCRYPT:
-				tmp = _("Trillian Encryption");
-				break;
-			case OSCAR_CAPABILITY_UNICODE:
-				tmp = _("ICQ UTF8");
-				break;
-			case OSCAR_CAPABILITY_HIPTOP:
-				tmp = _("Hiptop");
-				break;
-			case OSCAR_CAPABILITY_SECUREIM:
-				tmp = _("Security Enabled");
-				break;
-			case OSCAR_CAPABILITY_VIDEO:
-				tmp = _("Video Chat");
-				break;
-			/* Not actually sure about this one... WinAIM doesn't show anything */
-			case OSCAR_CAPABILITY_ICHATAV:
-				tmp = _("iChat AV");
-				break;
-			case OSCAR_CAPABILITY_LIVEVIDEO:
-				tmp = _("Live Video");
-				break;
-			case OSCAR_CAPABILITY_CAMERA:
-				tmp = _("Camera");
-				break;
-			case OSCAR_CAPABILITY_ICHAT_SCREENSHARE:
-				tmp = _("Screen Sharing");
-				break;
-			default:
-				tmp = NULL;
-				break;
-			}
-			if (tmp)
-				g_string_append_printf(str, "%s%s", (*(str->str) == '\0' ? "" : ", "), tmp);
-		}
-		bit <<= 1;
-	}
-
-	return g_string_free(str, FALSE);
-}
-
-static void
-oscar_user_info_convert_and_add(PurpleAccount *account, OscarData *od, PurpleNotifyUserInfo *user_info,
-					const char *name, const char *value)
-{
-	gchar *utf8;
-
-	if (value && value[0] && (utf8 = oscar_utf8_try_convert(account, od, value))) {
-		/* TODO: Check whether it's correct to call add_pair_html,
-		         or if we should be using add_pair_plaintext.  Will
-		         need to check callers of this function. */
-		purple_notify_user_info_add_pair_html(user_info, name, utf8);
-		g_free(utf8);
-	}
-}
-
-static void
-oscar_user_info_convert_and_add_hyperlink(PurpleAccount *account, OscarData *od, PurpleNotifyUserInfo *user_info,
-						const char *name, const char *value, const char *url_prefix)
-{
-	gchar *utf8;
-
-	if (value && value[0] && (utf8 = oscar_utf8_try_convert(account, od, value))) {
-		gchar *tmp = g_strdup_printf("<a href=\"%s%s\">%s</a>", url_prefix, utf8, utf8);
-		/* TODO: Check whether it's correct to call add_pair_html,
-		         or if we should be using add_pair_plaintext.  Will
-		         need to check callers of this function. */
-		purple_notify_user_info_add_pair_html(user_info, name, tmp);
-		g_free(utf8);
-		g_free(tmp);
-	}
-}
-
-/**
- * @brief Append the status information to a user_info struct
- *
- * The returned information is HTML-ready, appropriately escaped, as all information in a user_info struct should be HTML.
- *
- * @param gc The PurpleConnection
- * @param user_info A PurpleNotifyUserInfo object to which status information will be added
- * @param b The PurpleBuddy whose status is desired. This or the aim_userinfo_t (or both) must be passed to oscar_user_info_append_status().
- * @param userinfo The aim_userinfo_t of the buddy whose status is desired. This or the PurpleBuddy (or both) must be passed to oscar_user_info_append_status().
- * @param use_html_status If TRUE, prefer HTML-formatted away message over plaintext available message.
- */
-void
-oscar_user_info_append_status(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo, gboolean use_html_status)
-{
-	PurpleAccount *account = purple_connection_get_account(gc);
-	OscarData *od;
-	PurplePresence *presence = NULL;
-	PurpleStatus *status = NULL;
-	gchar *message = NULL, *itmsurl = NULL, *tmp;
-	gboolean escaping_needed = TRUE;
-
-	od = purple_connection_get_protocol_data(gc);
-
-	if (b == NULL && userinfo == NULL)
-		return;
-
-	if (b == NULL)
-		b = purple_blist_find_buddy(purple_connection_get_account(gc), userinfo->bn);
-	else
-		userinfo = aim_locate_finduserinfo(od, purple_buddy_get_name(b));
-
-	if (b) {
-		presence = purple_buddy_get_presence(b);
-		status = purple_presence_get_active_status(presence);
-	}
-
-	/* If we have both b and userinfo we favor userinfo, because if we're
-	   viewing someone's profile then we want the HTML away message, and
-	   the "message" attribute of the status contains only the plaintext
-	   message. */
-	if (userinfo) {
-		if ((userinfo->flags & AIM_FLAG_AWAY) && use_html_status && userinfo->away_len > 0 && userinfo->away != NULL && userinfo->away_encoding != NULL) {
-			/* Away message */
-			message = oscar_encoding_to_utf8(userinfo->away_encoding, userinfo->away, userinfo->away_len);
-			escaping_needed = FALSE;
-		} else {
-			/*
-			 * Available message or non-HTML away message (because that's
-			 * all we have right now.
-			 */
-			if ((userinfo->status != NULL) && userinfo->status[0] != '\0') {
-				message = oscar_encoding_to_utf8(userinfo->status_encoding, userinfo->status, userinfo->status_len);
-			}
-#if defined (_WIN32) || defined (__APPLE__)
-			if (userinfo->itmsurl && (userinfo->itmsurl[0] != '\0')) {
-				itmsurl = oscar_encoding_to_utf8(userinfo->itmsurl_encoding, userinfo->itmsurl, userinfo->itmsurl_len);
-			}
-#endif
-		}
-	} else {
-		message = g_strdup(purple_status_get_attr_string(status, "message"));
-		itmsurl = g_strdup(purple_status_get_attr_string(status, "itmsurl"));
-	}
-
-	if (message) {
-		tmp = oscar_util_format_string(message, purple_account_get_username(account));
-		g_free(message);
-		message = tmp;
-		if (escaping_needed) {
-			tmp = purple_markup_escape_text(message, -1);
-			g_free(message);
-			message = tmp;
-		}
-	}
-
-	if (use_html_status && itmsurl) {
-		tmp = g_strdup_printf("<a href=\"%s\">%s</a>", itmsurl, message);
-		g_free(message);
-		message = tmp;
-	}
-
-	if (b) {
-		if (purple_presence_is_online(presence)) {
-			gboolean is_away = ((status && !purple_status_is_available(status)) || (userinfo && (userinfo->flags & AIM_FLAG_AWAY)));
-			if (oscar_util_valid_name_icq(purple_buddy_get_name(b)) || is_away || !message || !(*message)) {
-				/* Append the status name for online ICQ statuses, away AIM statuses, and for all buddies with no message.
-				 * If the status name and the message are the same, only show one. */
-				const char *status_name = purple_status_get_name(status);
-				if (status_name && message && purple_strequal(status_name, message))
-					status_name = NULL;
-
-				tmp = g_strdup_printf("%s%s%s",
-									   status_name ? status_name : "",
-									   ((status_name && message) && *message) ? ": " : "",
-									   (message && *message) ? message : "");
-				g_free(message);
-				message = tmp;
-			}
-
-		} else if (aim_ssi_waitingforauth(&od->ssi.local,
-			aim_ssi_itemlist_findparentname(&od->ssi.local, purple_buddy_get_name(b)),
-			purple_buddy_get_name(b)))
-		{
-			/* Note if an offline buddy is not authorized */
-			tmp = g_strdup_printf("%s%s%s",
-					_("Not Authorized"),
-					(message && *message) ? ": " : "",
-					(message && *message) ? message : "");
-			g_free(message);
-			message = tmp;
-		} else {
-			g_free(message);
-			message = g_strdup(_("Offline"));
-		}
-	}
-
-	if (presence) {
-		const char *mood;
-		const char *comment;
-		char *description;
-		status = purple_presence_get_status(presence, "mood");
-		mood = icq_get_custom_icon_description(purple_status_get_attr_string(status, PURPLE_MOOD_NAME));
-		if (mood) {
-			comment = purple_status_get_attr_string(status, PURPLE_MOOD_COMMENT);
-			if (comment) {
-				char *escaped_comment = purple_markup_escape_text(comment, -1);
-				description = g_strdup_printf("%s (%s)", _(mood), escaped_comment);
-				g_free(escaped_comment);
-			} else {
-				description = g_strdup(_(mood));
-			}
-			purple_notify_user_info_add_pair_html(user_info, _("Mood"), description);
-			g_free(description);
-		}
-	}
-
-	purple_notify_user_info_add_pair_html(user_info, _("Status"), message);
-	g_free(message);
-	g_free(itmsurl);
-}
-
-void
-oscar_user_info_append_extra_info(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo)
-{
-	OscarData *od;
-	PurpleAccount *account;
-	PurpleGroup *g = NULL;
-	struct buddyinfo *bi = NULL;
-	char *tmp;
-	const char *bname = NULL, *gname = NULL;
-
-	od = purple_connection_get_protocol_data(gc);
-	account = purple_connection_get_account(gc);
-
-	if ((user_info == NULL) || ((b == NULL) && (userinfo == NULL)))
-		return;
-
-	if (userinfo == NULL)
-		userinfo = aim_locate_finduserinfo(od, purple_buddy_get_name(b));
-
-	if (b == NULL)
-		b = purple_blist_find_buddy(account, userinfo->bn);
-
-	if (b != NULL) {
-		bname = purple_buddy_get_name(b);
-		g = purple_buddy_get_group(b);
-		gname = purple_group_get_name(g);
-	}
-
-	if (userinfo != NULL)
-		bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, userinfo->bn));
-
-	if ((bi != NULL) && (bi->ipaddr != 0)) {
-		char tmp2[40];
-		sprintf(tmp2, "%u.%u.%u.%u",
-			0xFF & ((bi->ipaddr & 0xff000000) >> 24),
-			0xFF & ((bi->ipaddr & 0x00ff0000) >> 16),
-			0xFF & ((bi->ipaddr & 0x0000ff00) >> 8),
-			0xFF & (bi->ipaddr & 0x000000ff));
-		purple_notify_user_info_add_pair_plaintext(user_info, _("IP Address"), tmp2);
-	}
-
-	if ((userinfo != NULL) && (userinfo->warnlevel != 0)) {
-		char tmp2[12];
-		sprintf(tmp2, "%d", (int)(userinfo->warnlevel/10.0 + .5));
-		purple_notify_user_info_add_pair_plaintext(user_info, _("Warning Level"), tmp2);
-	}
-
-	if ((b != NULL) && (bname != NULL) && (g != NULL) && (gname != NULL)) {
-		tmp = aim_ssi_getcomment(&od->ssi.local, gname, bname);
-		if (tmp != NULL) {
-			char *tmp2 = g_markup_escape_text(tmp, strlen(tmp));
-			g_free(tmp);
-
-			oscar_user_info_convert_and_add(account, od, user_info, _("Buddy Comment"), tmp2);
-			g_free(tmp2);
-		}
-	}
-}
-
-void
-oscar_user_info_display_error(OscarData *od, guint16 error_reason, gchar *buddy)
-{
-	PurpleNotifyUserInfo *user_info = purple_notify_user_info_new();
-	gchar *buf = g_strdup_printf(_("User information not available: %s"), oscar_get_msgerr_reason(error_reason));
-	purple_notify_user_info_add_pair_plaintext(user_info, NULL, buf);
-	purple_notify_userinfo(od->gc, buddy, user_info, NULL, NULL);
-	purple_notify_user_info_destroy(user_info);
-	if (!purple_conversation_present_error(buddy,
-		purple_connection_get_account(od->gc), buf))
-	{
-		purple_notify_error(od->gc, NULL, buf, NULL,
-			purple_request_cpar_from_connection(od->gc));
-	}
-	g_free(buf);
-}
-
-void
-oscar_user_info_display_icq(OscarData *od, struct aim_icq_info *info)
-{
-	PurpleConnection *gc = od->gc;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	PurpleBuddy *buddy;
-	struct buddyinfo *bi;
-	gchar who[16];
-	PurpleNotifyUserInfo *user_info;
-
-	if (!info->uin)
-		return;
-
-	user_info = purple_notify_user_info_new();
-
-	g_snprintf(who, sizeof(who), "%u", info->uin);
-	buddy = purple_blist_find_buddy(account, who);
-	if (buddy != NULL)
-		bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, purple_buddy_get_name(buddy)));
-	else
-		bi = NULL;
-
-	purple_notify_user_info_add_pair_plaintext(user_info, _("UIN"), who);
-	oscar_user_info_convert_and_add(account, od, user_info, _("Nick"), info->nick);
-	if ((bi != NULL) && (bi->ipaddr != 0)) {
-		char tstr[40];
-		sprintf(tstr, "%u.%u.%u.%u",
-			0xFF & ((bi->ipaddr & 0xff000000) >> 24),
-			0xFF & ((bi->ipaddr & 0x00ff0000) >> 16),
-			0xFF & ((bi->ipaddr & 0x0000ff00) >> 8),
-			0xFF & (bi->ipaddr & 0x000000ff));
-		purple_notify_user_info_add_pair_plaintext(user_info, _("IP Address"), tstr);
-	}
-	oscar_user_info_convert_and_add(account, od, user_info, _("First Name"), info->first);
-	oscar_user_info_convert_and_add(account, od, user_info, _("Last Name"), info->last);
-	oscar_user_info_convert_and_add_hyperlink(account, od, user_info, _("Email Address"), info->email, "mailto:");
-	if (info->numaddresses && info->email2) {
-		int i;
-		for (i = 0; i < info->numaddresses; i++) {
-			oscar_user_info_convert_and_add_hyperlink(account, od, user_info, _("Email Address"), info->email2[i], "mailto:");
-		}
-	}
-	oscar_user_info_convert_and_add(account, od, user_info, _("Mobile Phone"), info->mobile);
-
-	if (info->gender != 0)
-		purple_notify_user_info_add_pair_plaintext(user_info, _("Gender"), (info->gender == 1 ? _("Female") : _("Male")));
-
-	if ((info->birthyear > 1900) && (info->birthmonth > 0) && (info->birthday > 0)) {
-		/* Initialize the struct properly or strftime() will crash
-		 * under some conditions (e.g. Debian sarge w/ LANG=en_HK). */
-		time_t t = time(NULL);
-		struct tm *tm = localtime(&t);
-
-		tm->tm_mday = (int)info->birthday;
-		tm->tm_mon  = (int)info->birthmonth - 1;
-		tm->tm_year = (int)info->birthyear - 1900;
-
-		/* Ignore dst setting of today to avoid timezone shift between
-		 * dates in summer and winter time. */
-		tm->tm_isdst = -1;
-
-		/* To be 100% sure that the fields are re-normalized.
-		 * If you're sure strftime() ALWAYS does this EVERYWHERE,
-		 * feel free to remove it.  --rlaager */
-		mktime(tm);
-
-		oscar_user_info_convert_and_add(account, od, user_info, _("Birthday"), purple_date_format_short(tm));
-	}
-	if ((info->age > 0) && (info->age < 255)) {
-		char age[5];
-		snprintf(age, sizeof(age), "%hhd", info->age);
-		purple_notify_user_info_add_pair_plaintext(user_info, _("Age"), age);
-	}
-	/* TODO: Is it correct to pass info->email here...? */
-	oscar_user_info_convert_and_add_hyperlink(account, od, user_info, _("Personal Web Page"), info->email, "");
-	if (buddy != NULL)
-		oscar_user_info_append_status(gc, user_info, buddy, /* aim_userinfo_t */ NULL, /* use_html_status */ TRUE);
-
-	oscar_user_info_convert_and_add(account, od, user_info, _("Additional Information"), info->info);
-	purple_notify_user_info_add_section_break(user_info);
-
-	if ((info->homeaddr && (info->homeaddr[0])) || (info->homecity && info->homecity[0]) || (info->homestate && info->homestate[0]) || (info->homezip && info->homezip[0])) {
-		purple_notify_user_info_add_section_header(user_info, _("Home Address"));
-
-		oscar_user_info_convert_and_add(account, od, user_info, _("Address"), info->homeaddr);
-		oscar_user_info_convert_and_add(account, od, user_info, _("City"), info->homecity);
-		oscar_user_info_convert_and_add(account, od, user_info, _("State"), info->homestate);
-		oscar_user_info_convert_and_add(account, od, user_info, _("Zip Code"), info->homezip);
-	}
-	if ((info->workaddr && info->workaddr[0]) || (info->workcity && info->workcity[0]) || (info->workstate && info->workstate[0]) || (info->workzip && info->workzip[0])) {
-		purple_notify_user_info_add_section_header(user_info, _("Work Address"));
-
-		oscar_user_info_convert_and_add(account, od, user_info, _("Address"), info->workaddr);
-		oscar_user_info_convert_and_add(account, od, user_info, _("City"), info->workcity);
-		oscar_user_info_convert_and_add(account, od, user_info, _("State"), info->workstate);
-		oscar_user_info_convert_and_add(account, od, user_info, _("Zip Code"), info->workzip);
-	}
-	if ((info->workcompany && info->workcompany[0]) || (info->workdivision && info->workdivision[0]) || (info->workposition && info->workposition[0]) || (info->workwebpage && info->workwebpage[0])) {
-		purple_notify_user_info_add_section_header(user_info, _("Work Information"));
-
-		oscar_user_info_convert_and_add(account, od, user_info, _("Company"), info->workcompany);
-		oscar_user_info_convert_and_add(account, od, user_info, _("Division"), info->workdivision);
-		oscar_user_info_convert_and_add(account, od, user_info, _("Position"), info->workposition);
-		/* TODO: Is it correct to pass info->email here...? */
-		oscar_user_info_convert_and_add_hyperlink(account, od, user_info, _("Web Page"), info->email, "");
-	}
-
-	purple_notify_userinfo(gc, who, user_info, NULL, NULL);
-	purple_notify_user_info_destroy(user_info);
-}
-
-void
-oscar_user_info_display_aim(OscarData *od, aim_userinfo_t *userinfo)
-{
-	PurpleConnection *gc = od->gc;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	PurpleNotifyUserInfo *user_info = purple_notify_user_info_new();
-	gchar *tmp = NULL, *info_utf8 = NULL, *base_profile_url = NULL;
-
-	oscar_user_info_append_status(gc, user_info, /* PurpleBuddy */ NULL, userinfo, /* use_html_status */ TRUE);
-
-	if ((userinfo->present & AIM_USERINFO_PRESENT_IDLE) && userinfo->idletime != 0) {
-		tmp = purple_str_seconds_to_string(userinfo->idletime*60);
-		purple_notify_user_info_add_pair_plaintext(user_info, _("Idle"), tmp);
-		g_free(tmp);
-	}
-
-	oscar_user_info_append_extra_info(gc, user_info, NULL, userinfo);
-
-	if ((userinfo->present & AIM_USERINFO_PRESENT_ONLINESINCE) && !oscar_util_valid_name_sms(userinfo->bn)) {
-		/* An SMS contact is always online; its Online Since value is not useful */
-		time_t t = userinfo->onlinesince;
-		purple_notify_user_info_add_pair_plaintext(user_info, _("Online Since"), purple_date_format_full(localtime(&t)));
-	}
-
-	if (userinfo->present & AIM_USERINFO_PRESENT_MEMBERSINCE) {
-		time_t t = userinfo->membersince;
-		purple_notify_user_info_add_pair_plaintext(user_info, _("Member Since"), purple_date_format_full(localtime(&t)));
-	}
-
-	if (userinfo->capabilities != 0) {
-		tmp = oscar_caps_to_string(userinfo->capabilities);
-		if (tmp && *tmp)
-			purple_notify_user_info_add_pair_plaintext(user_info, _("Capabilities"), tmp);
-		g_free(tmp);
-	}
-
-	/* Info */
-	if ((userinfo->info_len > 0) && (userinfo->info != NULL) && (userinfo->info_encoding != NULL)) {
-		info_utf8 = oscar_encoding_to_utf8(userinfo->info_encoding, userinfo->info, userinfo->info_len);
-		tmp = oscar_util_format_string(info_utf8, purple_account_get_username(account));
-		purple_notify_user_info_add_section_break(user_info);
-		if (tmp && *tmp) {
-			/* TODO: Check whether it's correct to call add_pair_html,
-			         or if we should be using add_pair_plaintext */
-			purple_notify_user_info_add_pair_html(user_info, _("Profile"), tmp);
-		}
-		g_free(tmp);
-		g_free(info_utf8);
-	}
-
-	purple_notify_user_info_add_section_break(user_info);
-	base_profile_url = oscar_util_valid_name_icq(userinfo->bn) ? "http://www.icq.com/people" : "http://profiles.aim.com";
-	tmp = g_strdup_printf("<a href=\"%s/%s\">%s</a>",
-			base_profile_url, purple_normalize(account, userinfo->bn), _("View web profile"));
-	purple_notify_user_info_add_pair_html(user_info, NULL, tmp);
-	g_free(tmp);
-
-	purple_notify_userinfo(gc, userinfo->bn, user_info, NULL, NULL);
-	purple_notify_user_info_destroy(user_info);
-}
--- a/libpurple/protocols/oscar/util.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,322 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * A little bit of this
- * A little bit of that
- * It started with a kiss
- * Now we're up to bat
- */
-
-#include "oscar.h"
-
-#include "core.h"
-
-#include <ctype.h>
-
-static const char * const msgerrreason[] = {
-	N_("Invalid error"),
-	N_("Invalid SNAC"),
-	N_("Server rate limit exceeded"),
-	N_("Client rate limit exceeded"),
-	N_("Not logged in"),
-	N_("Service unavailable"),
-	N_("Service not defined"),
-	N_("Obsolete SNAC"),
-	N_("Not supported by host"),
-	N_("Not supported by client"),
-	N_("Refused by client"),
-	N_("Reply too big"),
-	N_("Responses lost"),
-	N_("Request denied"),
-	N_("Busted SNAC payload"),
-	N_("Insufficient rights"),
-	N_("In local permit/deny"),
-	N_("Warning level too high (sender)"),
-	N_("Warning level too high (receiver)"),
-	N_("User temporarily unavailable"),
-	N_("No match"),
-	N_("List overflow"),
-	N_("Request ambiguous"),
-	N_("Queue full"),
-	N_("Not while on AOL")
-};
-static const gsize msgerrreasonlen = G_N_ELEMENTS(msgerrreason);
-
-const char *oscar_get_msgerr_reason(size_t reason)
-{
-	return (reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason");
-}
-
-int oscar_get_ui_info_int(const char *str, int default_value)
-{
-	GHashTable *ui_info;
-
-	ui_info = purple_core_get_ui_info();
-	if (ui_info != NULL) {
-		gpointer value;
-		if (g_hash_table_lookup_extended(ui_info, str, NULL, &value))
-			return GPOINTER_TO_INT(value);
-	}
-
-	return default_value;
-}
-
-const char *oscar_get_ui_info_string(const char *str, const char *default_value)
-{
-	GHashTable *ui_info;
-	const char *value = NULL;
-
-	ui_info = purple_core_get_ui_info();
-	if (ui_info != NULL)
-		value = g_hash_table_lookup(ui_info, str);
-	if (value == NULL)
-		value = default_value;
-
-	return value;
-}
-
-gchar *oscar_get_clientstring(void)
-{
-	const char *name, *version;
-
-	name = oscar_get_ui_info_string("name", "Purple");
-	version = oscar_get_ui_info_string("version", VERSION);
-
-	return g_strdup_printf("%s/%s", name, version);;
-}
-
-/**
- * Calculate the checksum of a given icon.
- */
-guint16
-aimutil_iconsum(const guint8 *buf, int buflen)
-{
-	guint32 sum;
-	int i;
-
-	for (i=0, sum=0; i+1<buflen; i+=2)
-		sum += (buf[i+1] << 8) + buf[i];
-	if (i < buflen)
-		sum += buf[i];
-	sum = ((sum & 0xffff0000) >> 16) + (sum & 0x0000ffff);
-
-	return sum;
-}
-
-/**
- * Check if the given name is a valid AIM username.
- * Example: BobDole
- * Example: Henry_Ford@mac.com
- * Example: 1KrazyKat@example.com
- *
- * @return TRUE if the name is valid, FALSE if not.
- */
-static gboolean
-oscar_util_valid_name_aim(const char *name)
-{
-	int i;
-
-	if (purple_email_is_valid(name))
-		return TRUE;
-
-	/* Normal AIM usernames can't start with a number, period or underscore */
-	if (isalnum(name[0]) == 0)
-		return FALSE;
-
-	for (i = 0; name[i] != '\0'; i++) {
-		if (!isalnum(name[i]) && name[i] != ' ' && name[i] != '.' && name[i] != '_')
-			return FALSE;
-	}
-
-	return TRUE;
-}
-
-/**
- * Check if the given name is a valid ICQ username.
- * Example: 1234567
- *
- * @return TRUE if the name is valid, FALSE if not.
- */
-gboolean
-oscar_util_valid_name_icq(const char *name)
-{
-	int i;
-
-	for (i = 0; name[i] != '\0'; i++) {
-		if (!isdigit(name[i]))
-			return FALSE;
-	}
-
-	return TRUE;
-}
-
-/**
- * Check if the given name is a valid SMS username.
- * Example: +19195551234
- *
- * @return TRUE if the name is valid, FALSE if not.
- */
-gboolean
-oscar_util_valid_name_sms(const char *name)
-{
-	int i;
-
-	if (name[0] != '+')
-		return FALSE;
-
-	for (i = 1; name[i] != '\0'; i++) {
-		if (!isdigit(name[i]))
-			return FALSE;
-	}
-
-	return TRUE;
-}
-
-/**
- * Check if the given name is a valid oscar username.
- *
- * @return TRUE if the name is valid, FALSE if not.
- */
-gboolean
-oscar_util_valid_name(const char *name)
-{
-	if ((name == NULL) || (*name == '\0'))
-		return FALSE;
-
-	return oscar_util_valid_name_icq(name)
-			|| oscar_util_valid_name_sms(name)
-			|| oscar_util_valid_name_aim(name);
-}
-
-/**
- * This takes two names and compares them using the rules
- * on usernames for AIM/AOL.  Mainly, this means case and space
- * insensitivity (all case differences and spacing differences are
- * ignored, with the exception that usernames can not start with
- * a space).
- *
- * @return 0 if equal, non-0 if different
- */
-/* TODO: Do something different for email addresses. */
-int
-oscar_util_name_compare(const char *name1, const char *name2)
-{
-
-	if ((name1 == NULL) || (name2 == NULL))
-		return -1;
-
-	do {
-		while (*name2 == ' ')
-			name2++;
-		while (*name1 == ' ')
-			name1++;
-		if (toupper(*name1) != toupper(*name2))
-			return 1;
-	} while ((*name1 != '\0') && name1++ && name2++);
-
-	return 0;
-}
-
-/**
- * Looks for %n, %d, or %t in a string, and replaces them with the
- * specified name, date, and time, respectively.
- *
- * @param str  The string that may contain the special variables.
- * @param name The sender name.
- *
- * @return A newly allocated string where the special variables are
- *         expanded.  This should be g_free'd by the caller.
- */
-gchar *
-oscar_util_format_string(const char *str, const char *name)
-{
-	char *c;
-	GString *cpy;
-	time_t t;
-	struct tm *tme;
-
-	g_return_val_if_fail(str  != NULL, NULL);
-	g_return_val_if_fail(name != NULL, NULL);
-
-	/* Create an empty GString that is hopefully big enough for most messages */
-	cpy = g_string_sized_new(1024);
-
-	t = time(NULL);
-	tme = localtime(&t);
-
-	c = (char *)str;
-	while (*c) {
-		switch (*c) {
-		case '%':
-			if (*(c + 1)) {
-				switch (*(c + 1)) {
-				case 'n':
-					/* append name */
-					g_string_append(cpy, name);
-					c++;
-					break;
-				case 'd':
-					/* append date */
-					g_string_append(cpy, purple_date_format_short(tme));
-					c++;
-					break;
-				case 't':
-					/* append time */
-					g_string_append(cpy, purple_time_format(tme));
-					c++;
-					break;
-				default:
-					g_string_append_c(cpy, *c);
-				}
-			} else {
-				g_string_append_c(cpy, *c);
-			}
-			break;
-		default:
-			g_string_append_c(cpy, *c);
-		}
-		c++;
-	}
-
-	return g_string_free(cpy, FALSE);
-}
-
-gchar *
-oscar_format_buddies(GSList *buddies, const gchar *no_buddies_message)
-{
-	GSList *cur;
-	GString *result;
-	if (!buddies) {
-		return g_strdup_printf("<i>%s</i>", no_buddies_message);
-	}
-	result = g_string_new("");
-	for (cur = buddies; cur != NULL; cur = cur->next) {
-		PurpleBuddy *buddy = cur->data;
-		const gchar *bname = purple_buddy_get_name(buddy);
-		const gchar *alias = purple_buddy_get_alias_only(buddy);
-		g_string_append(result, bname);
-		if (alias) {
-			g_string_append_printf(result, " (%s)", alias);
-		}
-		g_string_append(result, "<br>");
-	}
-	return g_string_free(result, FALSE);
-}
--- a/libpurple/protocols/oscar/visibility.c	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,139 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-#include "visibility.h"
-
-/* Translators: This string is a menu option that, if selected, will cause
-   you to appear online to the chosen user even when your status is set to
-   Invisible. */
-#define APPEAR_ONLINE		N_("Appear Online")
-
-/* Translators: This string is a menu option that, if selected, will cause
-   you to appear offline to the chosen user when your status is set to
-   Invisible (this is the default). */
-#define DONT_APPEAR_ONLINE	N_("Don't Appear Online")
-
-/* Translators: This string is a menu option that, if selected, will cause
-   you to always appear offline to the chosen user (even when your status
-   isn't Invisible). */
-#define APPEAR_OFFLINE		N_("Appear Offline")
-
-/* Translators: This string is a menu option that, if selected, will cause
-   you to appear offline to the chosen user if you are invisible, and
-   appear online to the chosen user if you are not invisible (this is the
-   default). */
-#define DONT_APPEAR_OFFLINE	N_("Don't Appear Offline")
-
-static guint16
-get_buddy_list_type(OscarData *od)
-{
-	PurpleAccount *account = purple_connection_get_account(od->gc);
-	return purple_account_is_status_active(account, OSCAR_STATUS_ID_INVISIBLE) ? AIM_SSI_TYPE_PERMIT : AIM_SSI_TYPE_DENY;
-}
-
-static gboolean
-is_buddy_on_list(OscarData *od, const char *bname)
-{
-	return aim_ssi_itemlist_finditem(&od->ssi.local, NULL, bname, get_buddy_list_type(od)) != NULL;
-}
-
-static void
-visibility_cb(PurpleBlistNode *node, gpointer whatever)
-{
-	PurpleBuddy *buddy = PURPLE_BUDDY(node);
-	const char* bname = purple_buddy_get_name(buddy);
-	OscarData *od = purple_connection_get_protocol_data(purple_account_get_connection(purple_buddy_get_account(buddy)));
-	guint16 list_type = get_buddy_list_type(od);
-
-	if (!is_buddy_on_list(od, bname)) {
-		aim_ssi_add_to_private_list(od, bname, list_type);
-	} else {
-		aim_ssi_del_from_private_list(od, bname, list_type);
-	}
-}
-
-PurpleActionMenu *
-create_visibility_menu_item(OscarData *od, const char *bname)
-{
-	PurpleAccount *account = purple_connection_get_account(od->gc);
-	gboolean invisible = purple_account_is_status_active(account, OSCAR_STATUS_ID_INVISIBLE);
-	gboolean on_list = is_buddy_on_list(od, bname);
-	const gchar *label;
-
-	if (invisible) {
-		label = on_list ? _(DONT_APPEAR_ONLINE) : _(APPEAR_ONLINE);
-	} else {
-		label = on_list ? _(DONT_APPEAR_OFFLINE) : _(APPEAR_OFFLINE);
-	}
-	return purple_action_menu_new(label, PURPLE_CALLBACK(visibility_cb), NULL, NULL);
-}
-
-static void
-show_private_list(PurpleProtocolAction *action, guint16 list_type, const gchar *title, const gchar *list_description, const gchar *menu_action_name)
-{
-	PurpleConnection *gc = action->connection;
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	PurpleAccount *account = purple_connection_get_account(gc);
-	GSList *buddies, *filtered_buddies, *cur;
-	gchar *text, *secondary;
-
-	buddies = purple_blist_find_buddies(account, NULL);
-	filtered_buddies = NULL;
-	for (cur = buddies; cur != NULL; cur = cur->next) {
-		PurpleBuddy *buddy;
-		const gchar *bname;
-
-		buddy = cur->data;
-		bname = purple_buddy_get_name(buddy);
-		if (aim_ssi_itemlist_finditem(&od->ssi.local, NULL, bname, list_type)) {
-			filtered_buddies = g_slist_prepend(filtered_buddies, buddy);
-		}
-	}
-
-	g_slist_free(buddies);
-
-	filtered_buddies = g_slist_reverse(filtered_buddies);
-	text = oscar_format_buddies(filtered_buddies, _("you have no buddies on this list"));
-	g_slist_free(filtered_buddies);
-
-	secondary = g_strdup_printf(_("You can add a buddy to this list "
-					"by right-clicking on them and "
-					"selecting \"%s\""), menu_action_name);
-	purple_notify_formatted(gc, title, list_description, secondary, text, NULL, NULL);
-	g_free(secondary);
-	g_free(text);
-}
-
-void
-oscar_show_visible_list(PurpleProtocolAction *action)
-{
-	show_private_list(action, AIM_SSI_TYPE_PERMIT, _("Visible List"),
-			_("These buddies can see your status even when you're "
-			"invisible."),
-			_(APPEAR_ONLINE));
-}
-
-void
-oscar_show_invisible_list(PurpleProtocolAction *action)
-{
-	show_private_list(action, AIM_SSI_TYPE_DENY, _("Invisible List"),
-			_("These buddies will always see you as offline."),
-			_(APPEAR_OFFLINE));
-}
--- a/libpurple/protocols/oscar/visibility.h	Sun Oct 20 00:24:28 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-#ifndef PURPLE_OSCAR_VISIBILITY_H
-#define PURPLE_OSCAR_VISIBILITY_H
-
-#include "oscar.h"
-#include "plugins.h"
-#include "action.h"
-
-PurpleActionMenu * create_visibility_menu_item(OscarData *od, const char *bname);
-void oscar_show_visible_list(PurpleProtocolAction *action);
-void oscar_show_invisible_list(PurpleProtocolAction *action);
-
-#endif /* PURPLE_OSCAR_VISIBILITY_H */
--- a/meson.build	Sun Oct 20 00:24:28 2019 +0300
+++ b/meson.build	Fri Oct 25 07:52:44 2019 +0000
@@ -481,7 +481,7 @@
 
 
 DEFAULT_PRPLS = ['bonjour', 'facebook', 'gg', 'irc', 'jabber', 'novell',
-                 'null', 'oscar', 'sametime', 'silc', 'simple', 'zephyr']
+                 'null', 'sametime', 'silc', 'simple', 'zephyr']
 ALL_PRPLS = DEFAULT_PRPLS + ['null']
 
 dynamic_list = get_option('dynamic-prpls').split(',')
@@ -514,7 +514,6 @@
 DYNAMIC_JABBER = DYNAMIC_PRPLS.contains('jabber')
 DYNAMIC_NOVELL = DYNAMIC_PRPLS.contains('novell')
 DYNAMIC_NULL = DYNAMIC_PRPLS.contains('null')
-DYNAMIC_OSCAR = DYNAMIC_PRPLS.contains('oscar') or DYNAMIC_PRPLS.contains('aim') or DYNAMIC_PRPLS.contains('icq')
 DYNAMIC_SAMETIME = DYNAMIC_PRPLS.contains('sametime')
 DYNAMIC_SILC = DYNAMIC_PRPLS.contains('silc')
 DYNAMIC_SIMPLE = DYNAMIC_PRPLS.contains('simple')
--- a/po/POTFILES.in	Sun Oct 20 00:24:28 2019 +0300
+++ b/po/POTFILES.in	Fri Oct 25 07:52:44 2019 +0000
@@ -26,7 +26,6 @@
 finch/plugins/grouping.c
 finch/plugins/lastlog.c
 libpurple/account.c
-libpurple/accountopt.c
 libpurple/accounts.c
 libpurple/action.c
 libpurple/attention.c
@@ -49,7 +48,6 @@
 libpurple/eventloop.c
 libpurple/example/nullclient.c
 libpurple/group.c
-libpurple/http.c
 libpurple/idle.c
 libpurple/image.c
 libpurple/image-store.c
@@ -79,7 +77,7 @@
 libpurple/plugins/idle.c
 libpurple/plugins/joinpart.c
 libpurple/plugins/keyrings/internalkeyring.c
-libpurple/plugins/keyrings/kwallet.cpp
+libpurple/plugins/keyrings/kwallet/purplekwallet.cpp
 libpurple/plugins/keyrings/secretservice.c
 libpurple/plugins/keyrings/wincred.c
 libpurple/plugins/log_reader.c
@@ -208,45 +206,6 @@
 libpurple/protocols/novell/nmuserrecord.c
 libpurple/protocols/novell/novell.c
 libpurple/protocols/null/nullprpl.c
-libpurple/protocols/oscar/aim.c
-libpurple/protocols/oscar/authorization.c
-libpurple/protocols/oscar/bstream.c
-libpurple/protocols/oscar/clientlogin.c
-libpurple/protocols/oscar/encoding.c
-libpurple/protocols/oscar/family_admin.c
-libpurple/protocols/oscar/family_alert.c
-libpurple/protocols/oscar/family_auth.c
-libpurple/protocols/oscar/family_bart.c
-libpurple/protocols/oscar/family_bos.c
-libpurple/protocols/oscar/family_buddy.c
-libpurple/protocols/oscar/family_chat.c
-libpurple/protocols/oscar/family_chatnav.c
-libpurple/protocols/oscar/family_feedbag.c
-libpurple/protocols/oscar/family_icbm.c
-libpurple/protocols/oscar/family_icq.c
-libpurple/protocols/oscar/family_locate.c
-libpurple/protocols/oscar/family_oservice.c
-libpurple/protocols/oscar/family_popup.c
-libpurple/protocols/oscar/family_stats.c
-libpurple/protocols/oscar/family_userlookup.c
-libpurple/protocols/oscar/flap_connection.c
-libpurple/protocols/oscar/icq.c
-libpurple/protocols/oscar/kerberos.c
-libpurple/protocols/oscar/misc.c
-libpurple/protocols/oscar/msgcookie.c
-libpurple/protocols/oscar/odc.c
-libpurple/protocols/oscar/oft.c
-libpurple/protocols/oscar/oscar.c
-libpurple/protocols/oscar/oscar_data.c
-libpurple/protocols/oscar/peer.c
-libpurple/protocols/oscar/peer_proxy.c
-libpurple/protocols/oscar/rxhandlers.c
-libpurple/protocols/oscar/snac.c
-libpurple/protocols/oscar/tests/test_oscar_util.c
-libpurple/protocols/oscar/tlv.c
-libpurple/protocols/oscar/userinfo.c
-libpurple/protocols/oscar/util.c
-libpurple/protocols/oscar/visibility.c
 libpurple/protocols/sametime/im_mime.c
 libpurple/protocols/sametime/sametime.c
 libpurple/protocols/sametime/tests/test_sametime_im_mime.c
@@ -437,7 +396,7 @@
 pidgin/plugins/unity.c
 pidgin/plugins/win32/winprefs/gtkappbar.c
 pidgin/plugins/win32/winprefs/winprefs.c
-pidgin/plugins/xmppconsole.c
+pidgin/plugins/xmppconsole/xmppconsole.c
 pidgin/resources/About/about.ui
 pidgin/resources/Conversations/invite_dialog.ui
 pidgin/resources/Debug/debug.ui

mercurial