Index: configure
===================================================================
--- configure (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ configure (revision e5d2c5607310ef9669a051a1b93e019319495955)
@@ -34,5 +34,4 @@
# but not purple ones.
jabber="default-on"
-oscar="default-on"
twitter=1
@@ -129,5 +128,4 @@
--jabber=0/1 Disable/enable Jabber part $jabber
---oscar=0/1 Disable/enable Oscar part (ICQ, AIM) $oscar
--twitter=0/1 Disable/enable Twitter part $twitter
@@ -859,5 +857,4 @@
# only disable these if the user didn't enable them explicitly
[ "$jabber" = "default-on" ] && jabber=0
- [ "$oscar" = "default-on" ] && oscar=0
echo '#undef PACKAGE' >> config.h
@@ -886,12 +883,4 @@
protocols=$protocols'jabber '
protoobjs=$protoobjs'jabber_mod.o '
-fi
-
-if [ "$oscar" = 0 ]; then
- echo '#undef WITH_OSCAR' >> config.h
-else
- echo '#define WITH_OSCAR' >> config.h
- protocols=$protocols'oscar '
- protoobjs=$protoobjs'oscar_mod.o '
fi
Index: debian/control
===================================================================
--- debian/control (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ debian/control (revision e5d2c5607310ef9669a051a1b93e019319495955)
@@ -18,5 +18,5 @@
This program can be used as an IRC server which forwards everything you
say to people on other chat networks: Jabber (which includes Google
- Talk), ICQ, AIM, MSN and Twitter.
+ Talk), and Twitter.
Package: bitlbee-libpurple
@@ -28,5 +28,5 @@
This program can be used as an IRC server which forwards everything you
say to people on other chat networks: Jabber (which includes Google
- Talk), ICQ, AIM, MSN and Twitter.
+ Talk), and Twitter.
.
This package contains a version of BitlBee that uses the libpurple instant
@@ -44,5 +44,5 @@
This program can be used as an IRC server which forwards everything you
say to people on other chat networks: Jabber (which includes Google
- Talk), ICQ, AIM, MSN and Twitter.
+ Talk), and Twitter.
.
This package contains common files (mostly documentation) for bitlbee and
@@ -55,5 +55,5 @@
This program can be used as an IRC server which forwards everything you
say to people on other chat networks: Jabber (which includes Google
- Talk), ICQ, AIM, MSN and Twitter.
+ Talk), and Twitter.
.
This package holds development stuff for compiling plug-ins.
@@ -65,5 +65,5 @@
This program can be used as an IRC server which forwards everything you
say to people on other chat networks: Jabber (which includes Google
- Talk), ICQ, AIM, MSN and Twitter.
+ Talk), and Twitter.
.
This package contains a plugin that adds support for Off-The-Record
Index: doc/user-guide/commands.xml
===================================================================
--- doc/user-guide/commands.xml (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ doc/user-guide/commands.xml (revision e5d2c5607310ef9669a051a1b93e019319495955)
@@ -43,19 +43,4 @@
-
- account add oscar <handle> [<password>]
-
-
-
- OSCAR is the protocol used to connect to AIM and/or ICQ. The servers will automatically detect if you're using a numeric or non-numeric username so there's no need to tell which network you want to connect to.
-
-
-
-
- account add oscar 72696705 hobbelmeeuw
- Account successfully added
-
-
-
account add twitter <handle>
Index: protocols/account.c
===================================================================
--- protocols/account.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ protocols/account.c (revision e5d2c5607310ef9669a051a1b93e019319495955)
@@ -86,11 +86,5 @@
/* Hardcode some more clever tag guesses. */
strcpy(tag, prpl->name);
- if (strcmp(prpl->name, "oscar") == 0) {
- if (g_ascii_isdigit(a->user[0])) {
- strcpy(tag, "icq");
- } else {
- strcpy(tag, "aim");
- }
- } else if (strcmp(prpl->name, "jabber") == 0) {
+ if (strcmp(prpl->name, "jabber") == 0) {
if (strstr(a->user, "@gmail.com") ||
strstr(a->user, "@googlemail.com")) {
Index: protocols/nogaim.c
===================================================================
--- protocols/nogaim.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ protocols/nogaim.c (revision e5d2c5607310ef9669a051a1b93e019319495955)
@@ -240,9 +240,4 @@
#else
- if (strcmp(name, "aim") == 0 || strcmp(name, "icq") == 0) {
- return g_strdup("This account uses libpurple specific aliases for oscar. "
- "Re-add the account with `account add oscar ...'");
- }
-
extramsg = "If this is a libpurple plugin, you might need to install bitlbee-libpurple instead.";
#endif
@@ -254,12 +249,7 @@
void nogaim_init()
{
- extern void oscar_initmodule();
extern void jabber_initmodule();
extern void twitter_initmodule();
extern void purple_initmodule();
-
-#ifdef WITH_OSCAR
- oscar_initmodule();
-#endif
#ifdef WITH_JABBER
Index: otocols/oscar/AUTHORS
===================================================================
--- protocols/oscar/AUTHORS (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,31 +1,0 @@
-
-Anyone else want to be in here?
-
----
-
-N: Adam Fritzler
-H: mid
-E: mid@auk.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
-E: josh@joshisanerd.com
-D: OFT/ODC (not quite finished yet..), random little things, Munger-At-Large, compile-time warnings.
-
-N: Daniel Reed
-H: n, linuxkitty
-E: n@ml.org
-W: http://users.n.ml.org/n/
-D: Fixed aim_snac.c
-
-N: Eric Warmenhoven
-E: warmenhoven@linux.com
-D: Some OFT info, author of the faim interface for gaim
-
-N: Brock Wilcox
-H: awwaiid
-E: awwaiid@auk.cx
-D: Figured out original password roasting
-
-
Index: otocols/oscar/COPYING
===================================================================
--- protocols/oscar/COPYING (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,513 +1,0 @@
- GNU LESSER GENERAL PUBLIC LICENSE
- Version 2.1, February 1999
-
- Copyright (C) 1991, 1999 Free Software Foundation, Inc.
- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-[This is the first released version of the Lesser GPL. It also counts
- as the successor of the GNU Library Public License, version 2, hence
- the version number 2.1.]
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-Licenses are intended to guarantee your freedom to share and change
-free software--to make sure the software is free for all its users.
-
- This license, the Lesser General Public License, applies to some
-specially designated software packages--typically libraries--of the
-Free Software Foundation and other authors who decide to use it. You
-can use it too, but we suggest you first think carefully about whether
-this license or the ordinary General Public License is the better
-strategy to use in any particular case, based on the explanations below.
-
- When we speak of free software, we are referring to freedom of use,
-not price. Our General Public Licenses are designed to make sure that
-you have the freedom to distribute copies of free software (and charge
-for this service if you wish); that you receive source code or can get
-it if you want it; that you can change the software and use pieces of
-it in new free programs; and that you are informed that you can do
-these things.
-
- To protect your rights, we need to make restrictions that forbid
-distributors to deny you these rights or to ask you to surrender these
-rights. These restrictions translate to certain responsibilities for
-you if you distribute copies of the library or if you modify it.
-
- For example, if you distribute copies of the library, whether gratis
-or for a fee, you must give the recipients all the rights that we gave
-you. You must make sure that they, too, receive or can get the source
-code. If you link other code with the library, you must provide
-complete object files to the recipients, so that they can relink them
-with the library after making changes to the library and recompiling
-it. And you must show them these terms so they know their rights.
-
- We protect your rights with a two-step method: (1) we copyright the
-library, and (2) we offer you this license, which gives you legal
-permission to copy, distribute and/or modify the library.
-
- To protect each distributor, we want to make it very clear that
-there is no warranty for the free library. Also, if the library is
-modified by someone else and passed on, the recipients should know
-that what they have is not the original version, so that the original
-author's reputation will not be affected by problems that might be
-introduced by others.
-
-
- Finally, software patents pose a constant threat to the existence of
-any free program. We wish to make sure that a company cannot
-effectively restrict the users of a free program by obtaining a
-restrictive license from a patent holder. Therefore, we insist that
-any patent license obtained for a version of the library must be
-consistent with the full freedom of use specified in this license.
-
- Most GNU software, including some libraries, is covered by the
-ordinary GNU General Public License. This license, the GNU Lesser
-General Public License, applies to certain designated libraries, and
-is quite different from the ordinary General Public License. We use
-this license for certain libraries in order to permit linking those
-libraries into non-free programs.
-
- When a program is linked with a library, whether statically or using
-a shared library, the combination of the two is legally speaking a
-combined work, a derivative of the original library. The ordinary
-General Public License therefore permits such linking only if the
-entire combination fits its criteria of freedom. The Lesser General
-Public License permits more lax criteria for linking other code with
-the library.
-
- We call this license the "Lesser" General Public License because it
-does Less to protect the user's freedom than the ordinary General
-Public License. It also provides other free software developers Less
-of an advantage over competing non-free programs. These disadvantages
-are the reason we use the ordinary General Public License for many
-libraries. However, the Lesser license provides advantages in certain
-special circumstances.
-
- For example, on rare occasions, there may be a special need to
-encourage the widest possible use of a certain library, so that it becomes
-a de-facto standard. To achieve this, non-free programs must be
-allowed to use the library. A more frequent case is that a free
-library does the same job as widely used non-free libraries. In this
-case, there is little to gain by limiting the free library to free
-software only, so we use the Lesser General Public License.
-
- In other cases, permission to use a particular library in non-free
-programs enables a greater number of people to use a large body of
-free software. For example, permission to use the GNU C Library in
-non-free programs enables many more people to use the whole GNU
-operating system, as well as its variant, the GNU/Linux operating
-system.
-
- Although the Lesser General Public License is Less protective of the
-users' freedom, it does ensure that the user of a program that is
-linked with the Library has the freedom and the wherewithal to run
-that program using a modified version of the Library.
-
- The precise terms and conditions for copying, distribution and
-modification follow. Pay close attention to the difference between a
-"work based on the library" and a "work that uses the library". The
-former contains code derived from the library, whereas the latter must
-be combined with the library in order to run.
-
-
- GNU LESSER GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License Agreement applies to any software library or other
-program which contains a notice placed by the copyright holder or
-other authorized party saying it may be distributed under the terms of
-this Lesser General Public License (also called "this License").
-Each licensee is addressed as "you".
-
- A "library" means a collection of software functions and/or data
-prepared so as to be conveniently linked with application programs
-(which use some of those functions and data) to form executables.
-
- The "Library", below, refers to any such software library or work
-which has been distributed under these terms. A "work based on the
-Library" means either the Library or any derivative work under
-copyright law: that is to say, a work containing the Library or a
-portion of it, either verbatim or with modifications and/or translated
-straightforwardly into another language. (Hereinafter, translation is
-included without limitation in the term "modification".)
-
- "Source code" for a work means the preferred form of the work for
-making modifications to it. For a library, complete source code means
-all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation
-and installation of the library.
-
- Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running a program using the Library is not restricted, and output from
-such a program is covered only if its contents constitute a work based
-on the Library (independent of the use of the Library in a tool for
-writing it). Whether that is true depends on what the Library does
-and what the program that uses the Library does.
-
- 1. You may copy and distribute verbatim copies of the Library's
-complete source code as you receive it, in any medium, provided that
-you conspicuously and appropriately publish on each copy an
-appropriate copyright notice and disclaimer of warranty; keep intact
-all the notices that refer to this License and to the absence of any
-warranty; and distribute a copy of this License along with the
-Library.
-
- You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-
-
- 2. You may modify your copy or copies of the Library or any portion
-of it, thus forming a work based on the Library, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) The modified work must itself be a software library.
-
- b) You must cause the files modified to carry prominent notices
- stating that you changed the files and the date of any change.
-
- c) You must cause the whole of the work to be licensed at no
- charge to all third parties under the terms of this License.
-
- d) If a facility in the modified Library refers to a function or a
- table of data to be supplied by an application program that uses
- the facility, other than as an argument passed when the facility
- is invoked, then you must make a good faith effort to ensure that,
- in the event an application does not supply such function or
- table, the facility still operates, and performs whatever part of
- its purpose remains meaningful.
-
- (For example, a function in a library to compute square roots has
- a purpose that is entirely well-defined independent of the
- application. Therefore, Subsection 2d requires that any
- application-supplied function or table used by this function must
- be optional: if the application does not supply it, the square
- root function must still compute square roots.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Library,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Library, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Library.
-
-In addition, mere aggregation of another work not based on the Library
-with the Library (or with a work based on the Library) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may opt to apply the terms of the ordinary GNU General Public
-License instead of this License to a given copy of the Library. To do
-this, you must alter all the notices that refer to this License, so
-that they refer to the ordinary GNU General Public License, version 2,
-instead of to this License. (If a newer version than version 2 of the
-ordinary GNU General Public License has appeared, then you can specify
-that version instead if you wish.) Do not make any other change in
-these notices.
-
-
- Once this change is made in a given copy, it is irreversible for
-that copy, so the ordinary GNU General Public License applies to all
-subsequent copies and derivative works made from that copy.
-
- This option is useful when you wish to copy part of the code of
-the Library into a program that is not a library.
-
- 4. You may copy and distribute the Library (or a portion or
-derivative of it, under Section 2) in object code or executable form
-under the terms of Sections 1 and 2 above provided that you accompany
-it with the complete corresponding machine-readable source code, which
-must be distributed under the terms of Sections 1 and 2 above on a
-medium customarily used for software interchange.
-
- If distribution of object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the
-source code from the same place satisfies the requirement to
-distribute the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 5. A program that contains no derivative of any portion of the
-Library, but is designed to work with the Library by being compiled or
-linked with it, is called a "work that uses the Library". Such a
-work, in isolation, is not a derivative work of the Library, and
-therefore falls outside the scope of this License.
-
- However, linking a "work that uses the Library" with the Library
-creates an executable that is a derivative of the Library (because it
-contains portions of the Library), rather than a "work that uses the
-library". The executable is therefore covered by this License.
-Section 6 states terms for distribution of such executables.
-
- When a "work that uses the Library" uses material from a header file
-that is part of the Library, the object code for the work may be a
-derivative work of the Library even though the source code is not.
-Whether this is true is especially significant if the work can be
-linked without the Library, or if the work is itself a library. The
-threshold for this to be true is not precisely defined by law.
-
- If such an object file uses only numerical parameters, data
-structure layouts and accessors, and small macros and small inline
-functions (ten lines or less in length), then the use of the object
-file is unrestricted, regardless of whether it is legally a derivative
-work. (Executables containing this object code plus portions of the
-Library will still fall under Section 6.)
-
- Otherwise, if the work is a derivative of the Library, you may
-distribute the object code for the work under the terms of Section 6.
-Any executables containing that work also fall under Section 6,
-whether or not they are linked directly with the Library itself.
-
-
- 6. As an exception to the Sections above, you may also combine or
-link a "work that uses the Library" with the Library to produce a
-work containing portions of the Library, and distribute that work
-under terms of your choice, provided that the terms permit
-modification of the work for the customer's own use and reverse
-engineering for debugging such modifications.
-
- You must give prominent notice with each copy of the work that the
-Library is used in it and that the Library and its use are covered by
-this License. You must supply a copy of this License. If the work
-during execution displays copyright notices, you must include the
-copyright notice for the Library among them, as well as a reference
-directing the user to the copy of this License. Also, you must do one
-of these things:
-
- a) Accompany the work with the complete corresponding
- machine-readable source code for the Library including whatever
- changes were used in the work (which must be distributed under
- Sections 1 and 2 above); and, if the work is an executable linked
- with the Library, with the complete machine-readable "work that
- uses the Library", as object code and/or source code, so that the
- user can modify the Library and then relink to produce a modified
- executable containing the modified Library. (It is understood
- that the user who changes the contents of definitions files in the
- Library will not necessarily be able to recompile the application
- to use the modified definitions.)
-
- b) Use a suitable shared library mechanism for linking with the
- Library. A suitable mechanism is one that (1) uses at run time a
- copy of the library already present on the user's computer system,
- rather than copying library functions into the executable, and (2)
- will operate properly with a modified version of the library, if
- the user installs one, as long as the modified version is
- interface-compatible with the version that the work was made with.
-
- c) Accompany the work with a written offer, valid for at
- least three years, to give the same user the materials
- specified in Subsection 6a, above, for a charge no more
- than the cost of performing this distribution.
-
- d) If distribution of the work is made by offering access to copy
- from a designated place, offer equivalent access to copy the above
- specified materials from the same place.
-
- e) Verify that the user has already received a copy of these
- materials or that you have already sent this user a copy.
-
- For an executable, the required form of the "work that uses the
-Library" must include any data and utility programs needed for
-reproducing the executable from it. However, as a special exception,
-the materials to be distributed need not include anything that is
-normally distributed (in either source or binary form) with the major
-components (compiler, kernel, and so on) of the operating system on
-which the executable runs, unless that component itself accompanies
-the executable.
-
- It may happen that this requirement contradicts the license
-restrictions of other proprietary libraries that do not normally
-accompany the operating system. Such a contradiction means you cannot
-use both them and the Library together in an executable that you
-distribute.
-
-
- 7. You may place library facilities that are a work based on the
-Library side-by-side in a single library together with other library
-facilities not covered by this License, and distribute such a combined
-library, provided that the separate distribution of the work based on
-the Library and of the other library facilities is otherwise
-permitted, and provided that you do these two things:
-
- a) Accompany the combined library with a copy of the same work
- based on the Library, uncombined with any other library
- facilities. This must be distributed under the terms of the
- Sections above.
-
- b) Give prominent notice with the combined library of the fact
- that part of it is a work based on the Library, and explaining
- where to find the accompanying uncombined form of the same work.
-
- 8. You may not copy, modify, sublicense, link with, or distribute
-the Library except as expressly provided under this License. Any
-attempt otherwise to copy, modify, sublicense, link with, or
-distribute the Library is void, and will automatically terminate your
-rights under this License. However, parties who have received copies,
-or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
- 9. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Library or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Library (or any work based on the
-Library), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Library or works based on it.
-
- 10. Each time you redistribute the Library (or any work based on the
-Library), the recipient automatically receives a license from the
-original licensor to copy, distribute, link with or modify the Library
-subject to these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties with
-this License.
-
-
- 11. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Library at all. For example, if a patent
-license would not permit royalty-free redistribution of the Library by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Library.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply,
-and the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 12. If the distribution and/or use of the Library is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Library under this License may add
-an explicit geographical distribution limitation excluding those countries,
-so that distribution is permitted only in or among countries not thus
-excluded. In such case, this License incorporates the limitation as if
-written in the body of this License.
-
- 13. The Free Software Foundation may publish revised and/or new
-versions of the Lesser General Public License from time to time.
-Such new versions will be similar in spirit to the present version,
-but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Library
-specifies a version number of this License which applies to it and
-"any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation. If the Library does not specify a
-license version number, you may choose any version ever published by
-the Free Software Foundation.
-
-
- 14. If you wish to incorporate parts of the Library into other free
-programs whose distribution conditions are incompatible with these,
-write to the author to ask for permission. For software which is
-copyrighted by the Free Software Foundation, write to the Free
-Software Foundation; we sometimes make exceptions for this. Our
-decision will be guided by the two goals of preserving the free status
-of all derivatives of our free software and of promoting the sharing
-and reuse of software generally.
-
- NO WARRANTY
-
- 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
-LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
-
- How to Apply These Terms to Your New Libraries
-
- If you develop a new library, and you want it to be of the greatest
-possible use to the public, we recommend making it free software that
-everyone can redistribute and change. You can do so by permitting
-redistribution under these terms (or, alternatively, under the terms of the
-ordinary General Public License).
-
- To apply these terms, attach the following notices to the library. It is
-safest to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least the
-"copyright" line and a pointer to where the full notice is found.
-
-
- Copyright (C)
-
- 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-Also add information on how to contact you by electronic and paper mail.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the library, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the
- library `Frob' (a library for tweaking knobs) written by James Random Hacker.
-
- , 1 April 1990
- Ty Coon, President of Vice
-
-That's all there is to it!
-
-
Index: otocols/oscar/Makefile
===================================================================
--- protocols/oscar/Makefile (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,47 +1,0 @@
-###########################
-## Makefile for BitlBee ##
-## ##
-## Copyright 2002 Lintux ##
-###########################
-
-### DEFINITIONS
-
--include ../../Makefile.settings
-ifdef _SRCDIR_
-_SRCDIR_ := $(_SRCDIR_)protocols/oscar/
-CFLAGS += -I$(_SRCDIR_)
-endif
-
-# [SH] Program variables
-objects = admin.o auth.o bos.o buddylist.o chat.o chatnav.o conn.o icq.o im.o info.o misc.o msgcookie.o rxhandlers.o rxqueue.o search.o service.o snac.o ssi.o stats.o tlv.o txqueue.o oscar_util.o oscar.o
-
-LFLAGS += -r
-
-# [SH] Phony targets
-all: oscar_mod.o
-check: all
-lcov: check
-gcov:
- gcov *.c
-
-.PHONY: all clean distclean
-
-clean:
- rm -f *.o core
-
-distclean: clean
- rm -rf .depend
-
-### MAIN PROGRAM
-
-$(objects): ../../Makefile.settings Makefile
-
-$(objects): %.o: $(_SRCDIR_)%.c
- @echo '*' Compiling $<
- $(VERBOSE) $(CC) -c $(CFLAGS) $(CFLAGS_BITLBEE) $< -o $@
-
-oscar_mod.o: $(objects)
- @echo '*' Linking oscar_mod.o
- $(VERBOSE) $(LD) $(LFLAGS) $(objects) -o oscar_mod.o
-
--include .depend/*.d
Index: otocols/oscar/admin.c
===================================================================
--- protocols/oscar/admin.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,206 +1,0 @@
-#include
-#include "admin.h"
-
-/* called for both reply and change-reply */
-static int infochange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
-
- /*
- * struct {
- * guint16 perms;
- * guint16 tlvcount;
- * aim_tlv_t tlvs[tlvcount];
- * } admin_info[n];
- */
- while (aim_bstream_empty(bs)) {
- guint16 perms, tlvcount;
-
- perms = aimbs_get16(bs);
- tlvcount = aimbs_get16(bs);
-
- while (tlvcount && aim_bstream_empty(bs)) {
- aim_rxcallback_t userfunc;
- guint16 type, len;
- guint8 *val;
- int str = 0;
-
- type = aimbs_get16(bs);
- len = aimbs_get16(bs);
-
- if ((type == 0x0011) || (type == 0x0004)) {
- str = 1;
- }
-
- if (str) {
- val = (guint8 *) aimbs_getstr(bs, len);
- } else {
- val = aimbs_getraw(bs, len);
- }
-
- /* XXX fix so its only called once for the entire packet */
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- userfunc(sess, rx, (snac->subtype == 0x0005) ? 1 : 0, perms, type, len, val, str);
- }
-
- g_free(val);
-
- tlvcount--;
- }
- }
-
- return 1;
-}
-
-static int accountconfirm(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac,
- aim_bstream_t *bs)
-{
- aim_rxcallback_t userfunc;
- guint16 status;
-
- status = aimbs_get16(bs);
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- return userfunc(sess, rx, status);
- }
-
- return 0;
-}
-
-static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
-
- if ((snac->subtype == 0x0003) || (snac->subtype == 0x0005)) {
- return infochange(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x0007) {
- return accountconfirm(sess, mod, rx, snac, bs);
- }
-
- return 0;
-}
-
-int admin_modfirst(aim_session_t *sess, aim_module_t *mod)
-{
-
- mod->family = AIM_CB_FAM_ADM;
- mod->version = 0x0001;
- mod->toolid = AIM_TOOL_NEWWIN;
- mod->toolversion = 0x0629;
- mod->flags = 0;
- strncpy(mod->name, "admin", sizeof(mod->name));
- mod->snachandler = snachandler;
-
- return 0;
-}
-
-int aim_admin_changepasswd(aim_session_t *sess, aim_conn_t *conn, const char *newpw, const char *curpw)
-{
- aim_frame_t *tx;
- aim_tlvlist_t *tl = NULL;
- aim_snacid_t snacid;
-
- if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + strlen(curpw) + 4 + strlen(newpw)))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0);
- aim_putsnac(&tx->data, 0x0007, 0x0004, 0x0000, snacid);
-
- /* new password TLV t(0002) */
- aim_addtlvtochain_raw(&tl, 0x0002, strlen(newpw), (guint8 *) newpw);
-
- /* current password TLV t(0012) */
- aim_addtlvtochain_raw(&tl, 0x0012, strlen(curpw), (guint8 *) curpw);
-
- aim_writetlvchain(&tx->data, &tl);
- aim_freetlvchain(&tl);
-
- aim_tx_enqueue(sess, tx);
-
- return 0;
-}
-
-/*
- * 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.
- *
- */
-int aim_admin_reqconfirm(aim_session_t *sess, aim_conn_t *conn)
-{
- return aim_genericreq_n(sess, conn, 0x0007, 0x0006);
-}
-
-/*
- * Request a bit of account info.
- *
- * The only known valid tag is 0x0011 (email address).
- *
- */
-int aim_admin_getinfo(aim_session_t *sess, aim_conn_t *conn, guint16 info)
-{
- aim_frame_t *tx;
- aim_snacid_t snacid;
-
- if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 14))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, 0x0002, 0x0002, 0x0000, NULL, 0);
- aim_putsnac(&tx->data, 0x0007, 0x0002, 0x0000, snacid);
-
- aimbs_put16(&tx->data, info);
- aimbs_put16(&tx->data, 0x0000);
-
- aim_tx_enqueue(sess, tx);
-
- return 0;
-}
-
-int aim_admin_setemail(aim_session_t *sess, aim_conn_t *conn, const char *newemail)
-{
- aim_frame_t *tx;
- aim_snacid_t snacid;
- aim_tlvlist_t *tl = NULL;
-
- if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 2 + 2 + strlen(newemail)))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0);
- aim_putsnac(&tx->data, 0x0007, 0x0004, 0x0000, snacid);
-
- aim_addtlvtochain_raw(&tl, 0x0011, strlen(newemail), (guint8 *) newemail);
-
- aim_writetlvchain(&tx->data, &tl);
- aim_freetlvchain(&tl);
-
- aim_tx_enqueue(sess, tx);
-
- return 0;
-}
-
-int aim_admin_setnick(aim_session_t *sess, aim_conn_t *conn, const char *newnick)
-{
- aim_frame_t *tx;
- aim_snacid_t snacid;
- aim_tlvlist_t *tl = NULL;
-
- if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 2 + 2 + strlen(newnick)))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0);
- aim_putsnac(&tx->data, 0x0007, 0x0004, 0x0000, snacid);
-
- aim_addtlvtochain_raw(&tl, 0x0001, strlen(newnick), (guint8 *) newnick);
-
- aim_writetlvchain(&tx->data, &tl);
- aim_freetlvchain(&tl);
-
- aim_tx_enqueue(sess, tx);
-
-
- return 0;
-}
Index: otocols/oscar/admin.h
===================================================================
--- protocols/oscar/admin.h (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,13 +1,0 @@
-#ifndef __OSCAR_ADMIN_H__
-#define __OSCAR_ADMIN_H__
-
-#define AIM_CB_FAM_ADM 0x0007
-
-/*
- * SNAC Family: Administrative Services.
- */
-#define AIM_CB_ADM_ERROR 0x0001
-#define AIM_CB_ADM_INFOCHANGE_REPLY 0x0005
-#define AIM_CB_ADM_DEFAULT 0xffff
-
-#endif /* __OSCAR_ADMIN_H__ */
Index: otocols/oscar/aim.h
===================================================================
--- protocols/oscar/aim.h (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,892 +1,0 @@
-/*
- * 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 Meyer
- *
- */
-
-#ifndef __AIM_H__
-#define __AIM_H__
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "bitlbee.h"
-
-#ifdef WITH_PURPLE
-/* For compatibility with builds that include both purple and this oscar module */
-#include "aim_prefixes.h"
-#endif
-
-/* XXX adjust these based on autoconf-detected platform */
-typedef guint32 aim_snacid_t;
-typedef guint16 flap_seqnum_t;
-
-/* Portability stuff (DMP) */
-
-#if defined(mach) && defined(__APPLE__)
-#define gethostbyname(x) gethostbyname2(x, AF_INET)
-#endif
-
-/*
- * Current Maximum Length for Screen Names (not including NULL)
- *
- * Currently only names up to 16 characters can be registered
- * however it is aparently legal for them to be larger.
- */
-#define MAXSNLEN 32
-
-/*
- * 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!
- *
- * XXX: the real limit is the total SNAC size at 8192. Fix this.
- *
- */
-#define MAXMSGLEN 7987
-
-/*
- * Maximum size of a Buddy Icon.
- */
-#define MAXICONLEN 7168
-#define AIM_ICONIDENT "AVT1picture.id"
-
-/*
- * Current Maximum Length for Chat Room Messages
- *
- * This is actually defined by the protocol to be
- * dynamic, but I have yet to see due cause to
- * define it dynamically here. Maybe later.
- *
- */
-#define MAXCHATMSGLEN 512
-
-/*
- * Standard size of an AIM authorization cookie
- */
-#define AIM_COOKIELEN 0x100
-
-#define AIM_MD5_STRING "AOL Instant Messenger (SM)"
-
-/*
- * Default Authorizer server name and TCP port for the OSCAR farm.
- *
- * You shouldn't need to change this unless you're writing
- * your own server.
- *
- * Note that only one server is needed to start the whole
- * AIM process. The later server addresses come from
- * the authorizer service.
- *
- * This is only here for convenience. Its still up to
- * the client to connect to it.
- *
- */
-#define AIM_DEFAULT_LOGIN_SERVER_AIM "login.messaging.aol.com"
-#define AIM_DEFAULT_LOGIN_SERVER_ICQ "login.icq.com"
-#define AIM_LOGIN_PORT 5190
-
-/*
- * Size of the SNAC caching hash.
- *
- * Default: 16
- *
- */
-#define AIM_SNAC_HASH_SIZE 16
-
-/*
- * 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 client_info_s {
- const char *clientstring;
- guint16 clientid;
- int major;
- int minor;
- int point;
- int build;
- const char *country; /* two-letter abbrev */
- const char *lang; /* two-letter abbrev */
-};
-
-#define AIM_CLIENTINFO_KNOWNGOOD_3_5_1670 { \
- "AOL Instant Messenger (SM), version 3.5.1670/WIN32", \
- 0x0004, \
- 0x0003, \
- 0x0005, \
- 0x0000, \
- 0x0686, \
- "us", \
- "en", \
-}
-
-#define AIM_CLIENTINFO_KNOWNGOOD_4_1_2010 { \
- "AOL Instant Messenger (SM), version 4.1.2010/WIN32", \
- 0x0004, \
- 0x0004, \
- 0x0001, \
- 0x0000, \
- 0x07da, \
- "us", \
- "en", \
-}
-
-#define AIM_CLIENTINFO_KNOWNGOOD_5_1_3036 { \
- "AOL Instant Messenger, version 5.1.3036/WIN32", \
- 0x0109, \
- 0x0005, \
- 0x0001, \
- 0x0000, \
- 0x0bdc, \
- "us", \
- "en", \
-}
-
-/*
- * I would make 4.1.2010 the default, but they seem to have found
- * an alternate way of breaking that one.
- *
- * 3.5.1670 should work fine, however, you will be subjected to the
- * memory test, which may require you to have a WinAIM binary laying
- * around. (see login.c::memrequest())
- */
-#define AIM_CLIENTINFO_KNOWNGOOD AIM_CLIENTINFO_KNOWNGOOD_5_1_3036
-
-#ifndef TRUE
-#define TRUE 1
-#define FALSE 0
-#endif
-
-/*
- * These could be arbitrary, but its easier to use the actual AIM values
- */
-#define AIM_CONN_TYPE_AUTH 0x0007
-#define AIM_CONN_TYPE_ADS 0x0005
-#define AIM_CONN_TYPE_BOS 0x0002
-#define AIM_CONN_TYPE_CHAT 0x000e
-#define AIM_CONN_TYPE_CHATNAV 0x000d
-
-/*
- * Status values returned from aim_conn_new(). ORed together.
- */
-#define AIM_CONN_STATUS_READY 0x0001
-#define AIM_CONN_STATUS_INTERNALERR 0x0002
-#define AIM_CONN_STATUS_RESOLVERR 0x0040
-#define AIM_CONN_STATUS_CONNERR 0x0080
-#define AIM_CONN_STATUS_INPROGRESS 0x0100
-
-#define AIM_FRAMETYPE_FLAP 0x0000
-
-/*
- * message type flags
- */
-#define AIM_MTYPE_PLAIN 0x01
-#define AIM_MTYPE_CHAT 0x02
-#define AIM_MTYPE_FILEREQ 0x03
-#define AIM_MTYPE_URL 0x04
-#define AIM_MTYPE_AUTHREQ 0x06
-#define AIM_MTYPE_AUTHDENY 0x07
-#define AIM_MTYPE_AUTHOK 0x08
-#define AIM_MTYPE_SERVER 0x09
-#define AIM_MTYPE_ADDED 0x0C
-#define AIM_MTYPE_WWP 0x0D
-#define AIM_MTYPE_EEXPRESS 0x0E
-#define AIM_MTYPE_CONTACTS 0x13
-#define AIM_MTYPE_PLUGIN 0x1A
-#define AIM_MTYPE_AUTOAWAY 0xE8
-#define AIM_MTYPE_AUTOBUSY 0xE9
-#define AIM_MTYPE_AUTONA 0xEA
-#define AIM_MTYPE_AUTODND 0xEB
-#define AIM_MTYPE_AUTOFFC 0xEC
-
-typedef struct aim_conn_s {
- int fd;
- guint16 type;
- guint16 subtype;
- flap_seqnum_t seqnum;
- guint32 status;
- void *priv; /* misc data the client may want to store */
- void *internal; /* internal conn-specific libfaim data */
- time_t lastactivity; /* time of last transmit */
- int forcedlatency;
- void *handlerlist;
- void *sessv; /* pointer to parent session */
- void *inside; /* only accessible from inside libfaim */
- struct aim_conn_s *next;
-} aim_conn_t;
-
-/*
- * 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.
- *
- */
-typedef struct aim_bstream_s {
- guint8 *data;
- guint32 len;
- guint32 offset;
-} aim_bstream_t;
-
-typedef struct aim_frame_s {
- guint8 hdrtype; /* defines which piece of the union to use */
- union {
- struct {
- guint8 type;
- flap_seqnum_t seqnum;
- } flap;
- } hdr;
- aim_bstream_t data; /* payload stream */
- guint8 handled; /* 0 = new, !0 = been handled */
- guint8 nofree; /* 0 = free data on purge, 1 = only unlink */
- aim_conn_t *conn; /* the connection it came in on... */
- struct aim_frame_s *next;
-} aim_frame_t;
-
-typedef struct aim_msgcookie_s {
- unsigned char cookie[8];
- int type;
- void *data;
- time_t addtime;
- struct aim_msgcookie_s *next;
-} aim_msgcookie_t;
-
-/*
- * AIM Session: The main client-data interface.
- *
- */
-typedef struct aim_session_s {
-
- /* ---- Client Accessible ------------------------ */
-
- /* Our screen name. */
- char sn[MAXSNLEN + 1];
-
- /*
- * Pointer to anything the client wants to
- * explicitly associate with this session.
- *
- * This is for use in the callbacks mainly. In any
- * callback, you can access this with sess->aux_data.
- *
- */
- void *aux_data;
-
- /* ---- Internal Use Only ------------------------ */
-
- /* Server-stored information (ssi) */
- struct {
- int received_data;
- guint16 revision;
- struct aim_ssi_item *items;
- time_t timestamp;
- int waiting_for_ack;
- aim_frame_t *holding_queue;
- } ssi;
-
- /* Connection information */
- aim_conn_t *connlist;
-
- /*
- * Transmit/receive queues.
- *
- * These are only used when you don't use your own lowlevel
- * I/O. I don't suggest that you use libfaim's internal I/O.
- * Its really bad and the API/event model is quirky at best.
- *
- */
- aim_frame_t *queue_outgoing;
- aim_frame_t *queue_incoming;
-
- /*
- * Tx Enqueuing function.
- *
- * This is how you override the transmit direction of libfaim's
- * internal I/O. This function will be called whenever it needs
- * to send something.
- *
- */
- int (*tx_enqueue)(struct aim_session_s *, aim_frame_t *);
-
- /*
- * Outstanding snac handling
- *
- * XXX: Should these be per-connection? -mid
- */
- void *snac_hash[AIM_SNAC_HASH_SIZE];
- aim_snacid_t snacid_next;
-
- struct aim_icq_info *icq_info;
- struct aim_oft_info *oft_info;
- struct aim_authresp_info *authinfo;
- struct aim_emailinfo *emailinfo;
-
- struct {
- struct aim_userinfo_s *userinfo;
- struct userinfo_node *torequest;
- struct userinfo_node *requested;
- int waiting_for_response;
- } locate;
-
- guint32 flags; /* AIM_SESS_FLAGS_ */
-
- aim_msgcookie_t *msgcookies;
-
- void *modlistv;
-
- guint8 aim_icq_state; /* ICQ representation of away state */
-} aim_session_t;
-
-/* Values for sess->flags */
-#define AIM_SESS_FLAGS_SNACLOGIN 0x00000001
-#define AIM_SESS_FLAGS_NONBLOCKCONNECT 0x00000004
-#define AIM_SESS_FLAGS_DONTTIMEOUTONICBM 0x00000008
-
-/* 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_WEBAWARE 0x00010000
-#define AIM_ICQ_STATE_HIDEIP 0x00020000
-#define AIM_ICQ_STATE_BIRTHDAY 0x00080000
-#define AIM_ICQ_STATE_DIRECTDISABLED 0x00100000
-#define AIM_ICQ_STATE_ICQHOMEPAGE 0x00200000
-#define AIM_ICQ_STATE_DIRECTREQUIREAUTH 0x10000000
-#define AIM_ICQ_STATE_DIRECTCONTACTLIST 0x20000000
-
-/*
- * AIM User Info, Standard Form.
- */
-typedef struct {
- char sn[MAXSNLEN + 1];
- guint16 warnlevel;
- guint16 idletime;
- guint16 flags;
- guint32 membersince;
- guint32 onlinesince;
- guint32 sessionlen;
- guint32 capabilities;
- struct {
- guint32 status;
- guint32 ipaddr;
- guint8 crap[0x25]; /* until we figure it out... */
- } icqinfo;
- guint32 present;
-} aim_userinfo_t;
-
-#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_FLAG_UNCONFIRMED 0x0001 /* "damned transients" */
-#define AIM_FLAG_ADMINISTRATOR 0x0002
-#define AIM_FLAG_AOL 0x0004
-#define AIM_FLAG_OSCAR_PAY 0x0008
-#define AIM_FLAG_FREE 0x0010
-#define AIM_FLAG_AWAY 0x0020
-#define AIM_FLAG_ICQ 0x0040
-#define AIM_FLAG_WIRELESS 0x0080
-#define AIM_FLAG_UNKNOWN100 0x0100
-#define AIM_FLAG_UNKNOWN200 0x0200
-#define AIM_FLAG_ACTIVEBUDDY 0x0400
-#define AIM_FLAG_UNKNOWN800 0x0800
-#define AIM_FLAG_ABINTERNAL 0x1000
-
-#define AIM_FLAG_ALLUSERS 0x001f
-
-/*
- * TLV handling
- */
-
-/* Generic TLV structure. */
-typedef struct aim_tlv_s {
- guint16 type;
- guint16 length;
- guint8 *value;
-} aim_tlv_t;
-
-/* List of above. */
-typedef struct aim_tlvlist_s {
- aim_tlv_t *tlv;
- struct aim_tlvlist_s *next;
-} aim_tlvlist_t;
-
-/* TLV-handling functions */
-
-#if 0
-/* Very, very raw TLV handling. */
-int aim_puttlv_8(guint8 *buf, const guint16 t, const guint8 v);
-int aim_puttlv_16(guint8 *buf, const guint16 t, const guint16 v);
-int aim_puttlv_32(guint8 *buf, const guint16 t, const guint32 v);
-int aim_puttlv_raw(guint8 *buf, const guint16 t, const guint16 l, const guint8 *v);
-#endif
-
-/* TLV list handling. */
-aim_tlvlist_t *aim_readtlvchain(aim_bstream_t *bs);
-void aim_freetlvchain(aim_tlvlist_t **list);
-aim_tlv_t *aim_gettlv(aim_tlvlist_t *list, guint16 t, const int n);
-char *aim_gettlv_str(aim_tlvlist_t *list, const guint16 t, const int n);
-guint8 aim_gettlv8(aim_tlvlist_t *list, const guint16 type, const int num);
-guint16 aim_gettlv16(aim_tlvlist_t *list, const guint16 t, const int n);
-guint32 aim_gettlv32(aim_tlvlist_t *list, const guint16 t, const int n);
-int aim_writetlvchain(aim_bstream_t *bs, aim_tlvlist_t **list);
-int aim_addtlvtochain8(aim_tlvlist_t **list, const guint16 t, const guint8 v);
-int aim_addtlvtochain16(aim_tlvlist_t **list, const guint16 t, const guint16 v);
-int aim_addtlvtochain32(aim_tlvlist_t **list, const guint16 type, const guint32 v);
-int aim_addtlvtochain_raw(aim_tlvlist_t **list, const guint16 t, const guint16 l, const guint8 *v);
-int aim_addtlvtochain_caps(aim_tlvlist_t **list, const guint16 t, const guint32 caps);
-int aim_addtlvtochain_noval(aim_tlvlist_t **list, const guint16 type);
-int aim_addtlvtochain_chatroom(aim_tlvlist_t **list, guint16 type, guint16 exchange, const char *roomname,
- guint16 instance);
-int aim_addtlvtochain_userinfo(aim_tlvlist_t **list, guint16 type, aim_userinfo_t *ui);
-int aim_addtlvtochain_frozentlvlist(aim_tlvlist_t **list, guint16 type, aim_tlvlist_t **tl);
-int aim_counttlvchain(aim_tlvlist_t **list);
-int aim_sizetlvchain(aim_tlvlist_t **list);
-
-
-/*
- * Get command from connections
- *
- * aim_get_commmand() is the libfaim lowlevel I/O in the receive direction.
- * XXX Make this easily overridable.
- *
- */
-int aim_get_command(aim_session_t *, aim_conn_t *);
-
-/*
- * Dispatch commands that are in the rx queue.
- */
-void aim_rxdispatch(aim_session_t *);
-
-int aim_debugconn_sendconnect(aim_session_t *sess, aim_conn_t *conn);
-
-typedef int (*aim_rxcallback_t)(aim_session_t *, aim_frame_t *, ...);
-
-struct aim_clientrelease {
- char *name;
- guint32 build;
- char *url;
- char *info;
-};
-
-struct aim_authresp_info {
- char *sn;
- guint16 errorcode;
- char *errorurl;
- guint16 regstatus;
- char *email;
- char *bosip;
- guint8 *cookie;
- struct aim_clientrelease latestrelease;
- struct aim_clientrelease latestbeta;
-};
-
-/* Callback data for redirect. */
-struct aim_redirect_data {
- guint16 group;
- const char *ip;
- const guint8 *cookie;
- struct { /* group == AIM_CONN_TYPE_CHAT */
- guint16 exchange;
- const char *room;
- guint16 instance;
- } chat;
-};
-
-int aim_clientready(aim_session_t *sess, aim_conn_t *conn);
-int aim_sendflapver(aim_session_t *sess, aim_conn_t *conn);
-int aim_request_login(aim_session_t *sess, aim_conn_t *conn, const char *sn);
-int aim_send_login(aim_session_t *, aim_conn_t *, const char *, const char *, struct client_info_s *, const char *key);
-int aim_encode_password_md5(const char *password, const char *key, unsigned char *digest);
-void aim_purge_rxqueue(aim_session_t *);
-
-#define AIM_TX_QUEUED 0 /* default */
-#define AIM_TX_IMMEDIATE 1
-#define AIM_TX_USER 2
-int aim_tx_setenqueue(aim_session_t *sess, int what, int (*func)(aim_session_t *, aim_frame_t *));
-
-int aim_tx_flushqueue(aim_session_t *);
-void aim_tx_purgequeue(aim_session_t *);
-
-int aim_conn_setlatency(aim_conn_t *conn, int newval);
-
-void aim_conn_kill(aim_session_t *sess, aim_conn_t **deadconn);
-
-int aim_conn_addhandler(aim_session_t *, aim_conn_t *conn, u_short family, u_short type, aim_rxcallback_t newhandler,
- u_short flags);
-int aim_clearhandlers(aim_conn_t *conn);
-
-aim_conn_t *aim_conn_findbygroup(aim_session_t *sess, guint16 group);
-aim_session_t *aim_conn_getsess(aim_conn_t *conn);
-void aim_conn_close(aim_conn_t *deadconn);
-aim_conn_t *aim_newconn(aim_session_t *, int type, const char *dest);
-int aim_conngetmaxfd(aim_session_t *);
-aim_conn_t *aim_select(aim_session_t *, struct timeval *, int *);
-int aim_conn_isready(aim_conn_t *);
-int aim_conn_setstatus(aim_conn_t *, int);
-int aim_conn_completeconnect(aim_session_t *sess, aim_conn_t *conn);
-int aim_conn_isconnecting(aim_conn_t *conn);
-
-typedef void (*faim_debugging_callback_t)(aim_session_t *sess, int level, const char *format, va_list va);
-int aim_setdebuggingcb(aim_session_t * sess, faim_debugging_callback_t);
-void aim_session_init(aim_session_t *, guint32 flags, int debuglevel);
-void aim_session_kill(aim_session_t *);
-void aim_setupproxy(aim_session_t *sess, const char *server, const char *username, const char *password);
-aim_conn_t *aim_getconn_type(aim_session_t *, int type);
-aim_conn_t *aim_getconn_type_all(aim_session_t *, int type);
-aim_conn_t *aim_getconn_fd(aim_session_t *, int fd);
-
-/* aim_misc.c */
-
-
-struct aim_chat_roominfo {
- unsigned short exchange;
- char *name;
- unsigned short instance;
-};
-
-struct aim_chat_invitation {
- struct im_connection * ic;
- char * name;
- guint8 exchange;
-};
-
-#define AIM_VISIBILITYCHANGE_PERMITADD 0x05
-#define AIM_VISIBILITYCHANGE_PERMITREMOVE 0x06
-#define AIM_VISIBILITYCHANGE_DENYADD 0x07
-#define AIM_VISIBILITYCHANGE_DENYREMOVE 0x08
-
-#define AIM_PRIVFLAGS_ALLOWIDLE 0x01
-#define AIM_PRIVFLAGS_ALLOWMEMBERSINCE 0x02
-
-#define AIM_WARN_ANON 0x01
-
-int aim_flap_nop(aim_session_t *sess, aim_conn_t *conn);
-int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn, const char *profile, const char *awaymsg, guint32 caps);
-int aim_bos_setgroupperm(aim_session_t *, aim_conn_t *, guint32 mask);
-int aim_bos_setprivacyflags(aim_session_t *, aim_conn_t *, guint32);
-int aim_reqpersonalinfo(aim_session_t *, aim_conn_t *);
-int aim_reqservice(aim_session_t *, aim_conn_t *, guint16);
-int aim_bos_reqrights(aim_session_t *, aim_conn_t *);
-int aim_bos_reqbuddyrights(aim_session_t *, aim_conn_t *);
-int aim_bos_reqlocaterights(aim_session_t *, aim_conn_t *);
-int aim_setextstatus(aim_session_t *sess, aim_conn_t *conn, guint32 status);
-
-struct aim_fileheader_t *aim_getlisting(aim_session_t *sess, FILE *);
-
-#define AIM_CLIENTTYPE_UNKNOWN 0x0000
-#define AIM_CLIENTTYPE_MC 0x0001
-#define AIM_CLIENTTYPE_WINAIM 0x0002
-#define AIM_CLIENTTYPE_WINAIM41 0x0003
-#define AIM_CLIENTTYPE_AOL_TOC 0x0004
-
-#define AIM_RATE_CODE_CHANGE 0x0001
-#define AIM_RATE_CODE_WARNING 0x0002
-#define AIM_RATE_CODE_LIMIT 0x0003
-#define AIM_RATE_CODE_CLEARLIMIT 0x0004
-int aim_ads_requestads(aim_session_t *sess, aim_conn_t *conn);
-
-/* aim_im.c */
-
-aim_conn_t *aim_sendfile_initiate(aim_session_t *, const char *destsn, const char *filename, guint16 numfiles,
- guint32 totsize);
-
-aim_conn_t *aim_getfile_initiate(aim_session_t *sess, aim_conn_t *conn, const char *destsn);
-int aim_oft_getfile_request(aim_session_t *sess, aim_conn_t *conn, const char *name, int size);
-int aim_oft_getfile_ack(aim_session_t *sess, aim_conn_t *conn);
-int aim_oft_getfile_end(aim_session_t *sess, aim_conn_t *conn);
-
-#define AIM_SENDMEMBLOCK_FLAG_ISREQUEST 0
-#define AIM_SENDMEMBLOCK_FLAG_ISHASH 1
-
-#define AIM_GETINFO_GENERALINFO 0x00001
-#define AIM_GETINFO_AWAYMESSAGE 0x00003
-#define AIM_GETINFO_CAPABILITIES 0x0004
-
-struct aim_invite_priv {
- char *sn;
- char *roomname;
- guint16 exchange;
- guint16 instance;
-};
-
-#define AIM_COOKIETYPE_UNKNOWN 0x00
-#define AIM_COOKIETYPE_ICBM 0x01
-#define AIM_COOKIETYPE_ADS 0x02
-#define AIM_COOKIETYPE_BOS 0x03
-#define AIM_COOKIETYPE_IM 0x04
-#define AIM_COOKIETYPE_CHAT 0x05
-#define AIM_COOKIETYPE_CHATNAV 0x06
-#define AIM_COOKIETYPE_INVITE 0x07
-
-int aim_handlerendconnect(aim_session_t *sess, aim_conn_t *cur);
-
-#define AIM_TRANSFER_DENY_NOTSUPPORTED 0x0000
-#define AIM_TRANSFER_DENY_DECLINE 0x0001
-#define AIM_TRANSFER_DENY_NOTACCEPTING 0x0002
-aim_conn_t *aim_accepttransfer(aim_session_t *sess, aim_conn_t *conn, const char *sn, const guint8 *cookie,
- const guint8 *ip, guint16 listingfiles, guint16 listingtotsize, guint16 listingsize,
- guint32 listingchecksum, guint16 rendid);
-
-int aim_getinfo(aim_session_t *, aim_conn_t *, const char *, unsigned short);
-
-#define AIM_IMPARAM_FLAG_CHANMSGS_ALLOWED 0x00000001
-#define AIM_IMPARAM_FLAG_MISSEDCALLS_ENABLED 0x00000002
-
-/* This is what the server will give you if you don't set them yourself. */
-#define AIM_IMPARAM_DEFAULTS { \
- 0, \
- AIM_IMPARAM_FLAG_CHANMSGS_ALLOWED | AIM_IMPARAM_FLAG_MISSEDCALLS_ENABLED, \
- 512, /* !! Note how small this is. */ \
- (99.9) * 10, (99.9) * 10, \
- 1000 /* !! And how large this is. */ \
-}
-
-/* This is what most AIM versions use. */
-#define AIM_IMPARAM_REASONABLE { \
- 0, \
- AIM_IMPARAM_FLAG_CHANMSGS_ALLOWED | AIM_IMPARAM_FLAG_MISSEDCALLS_ENABLED, \
- 8000, \
- (99.9) * 10, (99.9) * 10, \
- 0 \
-}
-
-
-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? */
-};
-
-int aim_reqicbmparams(aim_session_t *sess);
-int aim_seticbmparam(aim_session_t *sess, struct aim_icbmparameters *params);
-
-/* auth.c */
-int aim_sendcookie(aim_session_t *, aim_conn_t *, const guint8 *);
-
-int aim_admin_changepasswd(aim_session_t *, aim_conn_t *, const char *newpw, const char *curpw);
-int aim_admin_reqconfirm(aim_session_t *sess, aim_conn_t *conn);
-int aim_admin_getinfo(aim_session_t *sess, aim_conn_t *conn, guint16 info);
-int aim_admin_setemail(aim_session_t *sess, aim_conn_t *conn, const char *newemail);
-int aim_admin_setnick(aim_session_t *sess, aim_conn_t *conn, const char *newnick);
-
-/* These apply to exchanges as well. */
-#define AIM_CHATROOM_FLAG_EVILABLE 0x0001
-#define AIM_CHATROOM_FLAG_NAV_ONLY 0x0002
-#define AIM_CHATROOM_FLAG_INSTANCING_ALLOWED 0x0004
-#define AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED 0x0008
-
-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
-#define AIM_CHATFLAGS_UNICODE 0x0004
-#define AIM_CHATFLAGS_ISO_8859_1 0x0008
-
-int aim_chat_send_im(aim_session_t *sess, aim_conn_t *conn, guint16 flags, const char *msg, int msglen);
-int aim_chat_join(aim_session_t *sess, aim_conn_t *conn, guint16 exchange, const char *roomname, guint16 instance);
-
-int aim_chatnav_reqrights(aim_session_t *sess, aim_conn_t *conn);
-
-int aim_chat_invite(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *msg, guint16 exchange,
- const char *roomname, guint16 instance);
-
-int aim_chatnav_createroom(aim_session_t *sess, aim_conn_t *conn, const char *name, guint16 exchange);
-
-/* aim_util.c */
-/*
- * These are really ugly. You'd think this was LISP. I wish it was.
- *
- * XXX With the advent of bstream's, these should be removed to enforce
- * their use.
- *
- */
-#define aimutil_put8(buf, data) ((*(buf) = (u_char) (data) & 0xff), 1)
-#define aimutil_get8(buf) ((*(buf)) & 0xff)
-#define aimutil_put16(buf, data) ( \
- (*(buf) = (u_char) ((data) >> 8) & 0xff), \
- (*((buf) + 1) = (u_char) (data) & 0xff), \
- 2)
-#define aimutil_get16(buf) ((((*(buf)) << 8) & 0xff00) + ((*((buf) + 1)) & 0xff))
-#define aimutil_put32(buf, data) ( \
- (*((buf)) = (u_char) ((data) >> 24) & 0xff), \
- (*((buf) + 1) = (u_char) ((data) >> 16) & 0xff), \
- (*((buf) + 2) = (u_char) ((data) >> 8) & 0xff), \
- (*((buf) + 3) = (u_char) (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) = (unsigned char) (data) & 0xff), \
- 1)
-#define aimutil_getle8(buf) ( \
- (*(buf)) & 0xff \
- )
-#define aimutil_putle16(buf, data) ( \
- (*((buf) + 0) = (unsigned char) ((data) >> 0) & 0xff), \
- (*((buf) + 1) = (unsigned char) ((data) >> 8) & 0xff), \
- 2)
-#define aimutil_getle16(buf) ( \
- (((*((buf) + 0)) << 0) & 0x00ff) + \
- (((*((buf) + 1)) << 8) & 0xff00) \
- )
-#define aimutil_putle32(buf, data) ( \
- (*((buf) + 0) = (unsigned char) ((data) >> 0) & 0xff), \
- (*((buf) + 1) = (unsigned char) ((data) >> 8) & 0xff), \
- (*((buf) + 2) = (unsigned char) ((data) >> 16) & 0xff), \
- (*((buf) + 3) = (unsigned char) ((data) >> 24) & 0xff), \
- 4)
-#define aimutil_getle32(buf) ( \
- (((*((buf) + 0)) << 0) & 0x000000ff) + \
- (((*((buf) + 1)) << 8) & 0x0000ff00) + \
- (((*((buf) + 2)) << 16) & 0x00ff0000) + \
- (((*((buf) + 3)) << 24) & 0xff000000))
-
-
-int aim_sncmp(const char *a, const char *b);
-
-#include
-
-/*
- * SNAC Families.
- */
-#define AIM_CB_FAM_ACK 0x0000
-#define AIM_CB_FAM_GEN 0x0001
-#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 AIM_CB_GEN_ERROR 0x0001
-#define AIM_CB_GEN_CLIENTREADY 0x0002
-#define AIM_CB_GEN_SERVERREADY 0x0003
-#define AIM_CB_GEN_SERVICEREQ 0x0004
-#define AIM_CB_GEN_REDIRECT 0x0005
-#define AIM_CB_GEN_RATEINFOREQ 0x0006
-#define AIM_CB_GEN_RATEINFO 0x0007
-#define AIM_CB_GEN_RATEINFOACK 0x0008
-#define AIM_CB_GEN_RATECHANGE 0x000a
-#define AIM_CB_GEN_SERVERPAUSE 0x000b
-#define AIM_CB_GEN_SERVERRESUME 0x000d
-#define AIM_CB_GEN_REQSELFINFO 0x000e
-#define AIM_CB_GEN_SELFINFO 0x000f
-#define AIM_CB_GEN_EVIL 0x0010
-#define AIM_CB_GEN_SETIDLE 0x0011
-#define AIM_CB_GEN_MIGRATIONREQ 0x0012
-#define AIM_CB_GEN_MOTD 0x0013
-#define AIM_CB_GEN_SETPRIVFLAGS 0x0014
-#define AIM_CB_GEN_WELLKNOWNURL 0x0015
-#define AIM_CB_GEN_NOP 0x0016
-#define AIM_CB_GEN_DEFAULT 0xffff
-
-/*
- * SNAC Family: Advertisement Services
- */
-#define AIM_CB_ADS_ERROR 0x0001
-#define AIM_CB_ADS_DEFAULT 0xffff
-
-/*
- * OFT Services
- *
- * See non-SNAC note below.
- */
-#define AIM_CB_OFT_DIRECTIMCONNECTREQ 0x0001 /* connect request -- actually an OSCAR CAP*/
-#define AIM_CB_OFT_DIRECTIMINCOMING 0x0002
-#define AIM_CB_OFT_DIRECTIMDISCONNECT 0x0003
-#define AIM_CB_OFT_DIRECTIMTYPING 0x0004
-#define AIM_CB_OFT_DIRECTIMINITIATE 0x0005
-
-#define AIM_CB_OFT_GETFILECONNECTREQ 0x0006 /* connect request -- actually an OSCAR CAP*/
-#define AIM_CB_OFT_GETFILELISTINGREQ 0x0007 /* OFT listing.txt request */
-#define AIM_CB_OFT_GETFILEFILEREQ 0x0008 /* received file request */
-#define AIM_CB_OFT_GETFILEFILESEND 0x0009 /* received file request confirm -- send data */
-#define AIM_CB_OFT_GETFILECOMPLETE 0x000a /* received file send complete*/
-#define AIM_CB_OFT_GETFILEINITIATE 0x000b /* request for file get acknowledge */
-#define AIM_CB_OFT_GETFILEDISCONNECT 0x000c /* OFT connection disconnected.*/
-#define AIM_CB_OFT_GETFILELISTING 0x000d /* OFT listing.txt received.*/
-#define AIM_CB_OFT_GETFILERECEIVE 0x000e /* OFT file incoming.*/
-#define AIM_CB_OFT_GETFILELISTINGRXCONFIRM 0x000f
-#define AIM_CB_OFT_GETFILESTATE4 0x0010
-
-#define AIM_CB_OFT_SENDFILEDISCONNECT 0x0020 /* OFT connection disconnected.*/
-
-
-
-/*
- * 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_AUTHSUCCESS 0x0001
-#define AIM_CB_SPECIAL_AUTHOTHER 0x0002
-#define AIM_CB_SPECIAL_CONNERR 0x0003
-#define AIM_CB_SPECIAL_CONNCOMPLETE 0x0004
-#define AIM_CB_SPECIAL_FLAPVER 0x0005
-#define AIM_CB_SPECIAL_CONNINITDONE 0x0006
-#define AIM_CB_SPECIAL_IMAGETRANSFER 0x007
-#define AIM_CB_SPECIAL_UNKNOWN 0xffff
-#define AIM_CB_SPECIAL_DEFAULT AIM_CB_SPECIAL_UNKNOWN
-
-#endif /* __AIM_H__ */
Index: otocols/oscar/aim_internal.h
===================================================================
--- protocols/oscar/aim_internal.h (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,209 +1,0 @@
-/*
- * aim_internal.h -- prototypes/structs for the guts of libfaim
- *
- */
-
-#ifndef __AIM_INTERNAL_H__
-#define __AIM_INTERNAL_H__ 1
-
-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)(aim_session_t *sess, struct aim_module_s *mod, aim_frame_t *rx, aim_modsnac_t *snac,
- aim_bstream_t *bs);
- void (*shutdown)(aim_session_t *sess, struct aim_module_s *mod);
- void *priv;
- struct aim_module_s *next;
-} aim_module_t;
-
-int aim__registermodule(aim_session_t *sess, int (*modfirst)(aim_session_t *, aim_module_t *));
-void aim__shutdownmodules(aim_session_t *sess);
-aim_module_t *aim__findmodulebygroup(aim_session_t *sess, guint16 group);
-
-int buddylist_modfirst(aim_session_t *sess, aim_module_t *mod);
-int admin_modfirst(aim_session_t *sess, aim_module_t *mod);
-int bos_modfirst(aim_session_t *sess, aim_module_t *mod);
-int search_modfirst(aim_session_t *sess, aim_module_t *mod);
-int stats_modfirst(aim_session_t *sess, aim_module_t *mod);
-int auth_modfirst(aim_session_t *sess, aim_module_t *mod);
-int msg_modfirst(aim_session_t *sess, aim_module_t *mod);
-int misc_modfirst(aim_session_t *sess, aim_module_t *mod);
-int chatnav_modfirst(aim_session_t *sess, aim_module_t *mod);
-int chat_modfirst(aim_session_t *sess, aim_module_t *mod);
-int locate_modfirst(aim_session_t *sess, aim_module_t *mod);
-int general_modfirst(aim_session_t *sess, aim_module_t *mod);
-int ssi_modfirst(aim_session_t *sess, aim_module_t *mod);
-int icq_modfirst(aim_session_t *sess, aim_module_t *mod);
-
-int aim_genericreq_n(aim_session_t *, aim_conn_t *conn, guint16 family, guint16 subtype);
-int aim_genericreq_n_snacid(aim_session_t *, aim_conn_t *conn, guint16 family, guint16 subtype);
-int aim_genericreq_l(aim_session_t *, aim_conn_t *conn, guint16 family, guint16 subtype, guint32 *);
-int aim_genericreq_s(aim_session_t *, aim_conn_t *conn, guint16 family, guint16 subtype, guint16 *);
-
-#define AIMBS_CURPOSPAIR(x) ((x)->data + (x)->offset), ((x)->len - (x)->offset)
-
-void aim_rxqueue_cleanbyconn(aim_session_t *sess, aim_conn_t *conn);
-int aim_recv(int fd, void *buf, size_t count);
-int aim_bstream_init(aim_bstream_t *bs, guint8 *data, int len);
-int aim_bstream_empty(aim_bstream_t *bs);
-int aim_bstream_curpos(aim_bstream_t *bs);
-int aim_bstream_setpos(aim_bstream_t *bs, int off);
-void aim_bstream_rewind(aim_bstream_t *bs);
-int aim_bstream_advance(aim_bstream_t *bs, int n);
-guint8 aimbs_get8(aim_bstream_t *bs);
-guint16 aimbs_get16(aim_bstream_t *bs);
-guint32 aimbs_get32(aim_bstream_t *bs);
-guint8 aimbs_getle8(aim_bstream_t *bs);
-guint16 aimbs_getle16(aim_bstream_t *bs);
-guint32 aimbs_getle32(aim_bstream_t *bs);
-int aimbs_put8(aim_bstream_t *bs, guint8 v);
-int aimbs_put16(aim_bstream_t *bs, guint16 v);
-int aimbs_put32(aim_bstream_t *bs, guint32 v);
-int aimbs_putle8(aim_bstream_t *bs, guint8 v);
-int aimbs_putle16(aim_bstream_t *bs, guint16 v);
-int aimbs_putle32(aim_bstream_t *bs, guint32 v);
-int aimbs_getrawbuf(aim_bstream_t *bs, guint8 *buf, int len);
-guint8 *aimbs_getraw(aim_bstream_t *bs, int len);
-char *aimbs_getstr(aim_bstream_t *bs, int len);
-int aimbs_putraw(aim_bstream_t *bs, const guint8 *v, int len);
-int aimbs_putbs(aim_bstream_t *bs, aim_bstream_t *srcbs, int len);
-
-int aim_get_command_rendezvous(aim_session_t *sess, aim_conn_t *conn);
-
-int aim_tx_sendframe(aim_session_t *sess, aim_frame_t *cur);
-flap_seqnum_t aim_get_next_txseqnum(aim_conn_t *);
-aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, guint8 framing, guint8 chan, int datalen);
-void aim_frame_destroy(aim_frame_t *);
-int aim_tx_enqueue(aim_session_t *, aim_frame_t *);
-int aim_tx_printqueue(aim_session_t *);
-void aim_tx_cleanqueue(aim_session_t *, aim_conn_t *);
-
-aim_rxcallback_t aim_callhandler(aim_session_t *sess, aim_conn_t *conn, u_short family, u_short type);
-
-/*
- * 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;
-
-void aim_initsnachash(aim_session_t *sess);
-aim_snacid_t aim_cachesnac(aim_session_t *sess, const guint16 family, const guint16 type, const guint16 flags,
- const void *data, const int datalen);
-aim_snac_t *aim_remsnac(aim_session_t *, aim_snacid_t id);
-void aim_cleansnacs(aim_session_t *, int maxage);
-int aim_putsnac(aim_bstream_t *, guint16 family, guint16 type, guint16 flags, aim_snacid_t id);
-
-int aim_oft_buildheader(unsigned char *, struct aim_fileheader_t *);
-
-int aim_parse_unknown(aim_session_t *, aim_frame_t *, ...);
-
-/* Stored in ->priv of the service request SNAC for chats. */
-struct chatsnacinfo {
- guint16 exchange;
- char name[128];
- guint16 instance;
-};
-
-/* these are used by aim_*_clientready */
-#define AIM_TOOL_JAVA 0x0001
-#define AIM_TOOL_MAC 0x0002
-#define AIM_TOOL_WIN16 0x0003
-#define AIM_TOOL_WIN32 0x0004
-#define AIM_TOOL_MAC68K 0x0005
-#define AIM_TOOL_MACPPC 0x0006
-#define AIM_TOOL_NEWWIN 0x0010
-struct aim_tool_version {
- guint16 group;
- guint16 version;
- guint16 tool;
- guint16 toolversion;
-};
-
-/*
- * In SNACland, the terms 'family' and 'group' are synonymous -- the former
- * is my term, the latter is AOL's.
- */
-struct snacgroup {
- guint16 group;
- struct snacgroup *next;
-};
-
-struct snacpair {
- guint16 group;
- guint16 subtype;
- struct snacpair *next;
-};
-
-struct rateclass {
- guint16 classid;
- guint32 windowsize;
- guint32 clear;
- guint32 alert;
- guint32 limit;
- guint32 disconnect;
- guint32 current;
- guint32 max;
- guint8 unknown[5]; /* only present in versions >= 3 */
- struct snacpair *members;
- struct rateclass *next;
-};
-
-/*
- * This is inside every connection. But it is a void * to anything
- * outside of libfaim. It should remain that way. It's called data
- * abstraction. Maybe you've heard of it. (Probably not if you're a
- * libfaim user.)
- *
- */
-typedef struct aim_conn_inside_s {
- struct snacgroup *groups;
- struct rateclass *rates;
-} aim_conn_inside_t;
-
-void aim_conn_addgroup(aim_conn_t *conn, guint16 group);
-
-guint32 aim_getcap(aim_session_t *sess, aim_bstream_t *bs, int len);
-int aim_putcap(aim_bstream_t *bs, guint32 caps);
-
-int aim_cachecookie(aim_session_t *sess, aim_msgcookie_t *cookie);
-aim_msgcookie_t *aim_uncachecookie(aim_session_t *sess, guint8 *cookie, int type);
-aim_msgcookie_t *aim_mkcookie(guint8 *, int, void *);
-aim_msgcookie_t *aim_checkcookie(aim_session_t *sess, const unsigned char *, const int);
-int aim_freecookie(aim_session_t *sess, aim_msgcookie_t *cookie);
-int aim_cookie_free(aim_session_t *sess, aim_msgcookie_t *cookie);
-
-int aim_extractuserinfo(aim_session_t *sess, aim_bstream_t *bs, aim_userinfo_t *);
-
-int aim_chat_readroominfo(aim_bstream_t *bs, struct aim_chat_roominfo *outinfo);
-
-void aim_conn_close_rend(aim_session_t *sess, aim_conn_t *conn);
-void aim_conn_kill_rend(aim_session_t *sess, aim_conn_t *conn);
-
-void aim_conn_kill_chat(aim_session_t *sess, aim_conn_t *conn);
-
-/* These are all handled internally now. */
-int aim_setversions(aim_session_t *sess, aim_conn_t *conn);
-int aim_reqrates(aim_session_t *, aim_conn_t *);
-int aim_rates_addparam(aim_session_t *, aim_conn_t *);
-
-#endif /* __AIM_INTERNAL_H__ */
Index: otocols/oscar/aim_prefixes.h
===================================================================
--- protocols/oscar/aim_prefixes.h (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,93 +1,0 @@
-/* Automatically generated prefixes to avoid symbol conflicts with libpurple.
- * Because sometimes people compile both oscar and purple and things break.
- * This is awful but i know no better solution other than not running libpurple in the same process.
- *
- * Made with the following commands:
- *
- * nm --defined-only oscar_mod.o | awk '{print $3}' | sort | uniq > bee_syms
- * nm --defined-only liboscar.so | awk '{print $3}' | sort | uniq > purple_syms
- * comm -12 bee_syms purple_syms | sed 's/^.*$/#define & b_&/' > aim_prefixes.h
- */
-
-#define admin_modfirst b_admin_modfirst
-#define aim_admin_changepasswd b_aim_admin_changepasswd
-#define aim_admin_getinfo b_aim_admin_getinfo
-#define aim_admin_reqconfirm b_aim_admin_reqconfirm
-#define aim_admin_setemail b_aim_admin_setemail
-#define aim_admin_setnick b_aim_admin_setnick
-#define aim_bos_reqrights b_aim_bos_reqrights
-#define aim_cachecookie b_aim_cachecookie
-#define aim_cachesnac b_aim_cachesnac
-#define aim_callhandler b_aim_callhandler
-#define aim_caps b_aim_caps
-#define aim_chat_join b_aim_chat_join
-#define aim_chatnav_createroom b_aim_chatnav_createroom
-#define aim_chatnav_reqrights b_aim_chatnav_reqrights
-#define aim_chat_readroominfo b_aim_chat_readroominfo
-#define aim_chat_send_im b_aim_chat_send_im
-#define aim_checkcookie b_aim_checkcookie
-#define aim_cleansnacs b_aim_cleansnacs
-#define aim_cookie_free b_aim_cookie_free
-#define aim__findmodule b_aim__findmodule
-#define aim__findmodulebygroup b_aim__findmodulebygroup
-#define aim_genericreq_l b_aim_genericreq_l
-#define aim_genericreq_n b_aim_genericreq_n
-#define aim_genericreq_n_snacid b_aim_genericreq_n_snacid
-#define aim_icq_freeinfo b_aim_icq_freeinfo
-#define aim_icq_getallinfo b_aim_icq_getallinfo
-#define aim_im_sendmtn b_aim_im_sendmtn
-#define aim_initsnachash b_aim_initsnachash
-#define aim_mkcookie b_aim_mkcookie
-#define aim_newsnac b_aim_newsnac
-#define aim_putsnac b_aim_putsnac
-#define aim__registermodule b_aim__registermodule
-#define aim_remsnac b_aim_remsnac
-#define aim_request_login b_aim_request_login
-#define aim_send_login b_aim_send_login
-#define aim__shutdownmodules b_aim__shutdownmodules
-#define aim_ssi_enable b_aim_ssi_enable
-#define aim_ssi_freelist b_aim_ssi_freelist
-#define aim_ssi_getpermdeny b_aim_ssi_getpermdeny
-#define aim_ssi_itemlist_add b_aim_ssi_itemlist_add
-#define aim_ssi_itemlist_find b_aim_ssi_itemlist_find
-#define aim_ssi_itemlist_finditem b_aim_ssi_itemlist_finditem
-#define aim_ssi_itemlist_rebuildgroup b_aim_ssi_itemlist_rebuildgroup
-#define aim_ssi_modbegin b_aim_ssi_modbegin
-#define aim_ssi_modend b_aim_ssi_modend
-#define aim_ssi_movebuddy b_aim_ssi_movebuddy
-#define aim_ssi_reqrights b_aim_ssi_reqrights
-#define aim_uncachecookie b_aim_uncachecookie
-#define auth_modfirst b_auth_modfirst
-#define bos_modfirst b_bos_modfirst
-#define buddylist_modfirst b_buddylist_modfirst
-#define chat_modfirst b_chat_modfirst
-#define chatnav_modfirst b_chatnav_modfirst
-#define extract_name b_extract_name
-#define icq_modfirst b_icq_modfirst
-#define incomingim b_incomingim
-#define incomingim_ch2_chat_free b_incomingim_ch2_chat_free
-#define incomingim_ch2_icqserverrelay_free b_incomingim_ch2_icqserverrelay_free
-#define locate_modfirst b_locate_modfirst
-#define misc_modfirst b_misc_modfirst
-#define msgerrreason b_msgerrreason
-#define msg_modfirst b_msg_modfirst
-#define oscar_add_buddy b_oscar_add_buddy
-#define oscar_add_deny b_oscar_add_deny
-#define oscar_add_permit b_oscar_add_permit
-#define oscar_chat_invite b_oscar_chat_invite
-#define oscar_chat_kill b_oscar_chat_kill
-#define oscar_chat_leave b_oscar_chat_leave
-#define oscar_encoding_to_utf8 b_oscar_encoding_to_utf8
-#define oscar_get_info b_oscar_get_info
-#define oscar_init b_oscar_init
-#define oscar_keepalive b_oscar_keepalive
-#define oscar_login b_oscar_login
-#define oscar_rem_deny b_oscar_rem_deny
-#define oscar_remove_buddy b_oscar_remove_buddy
-#define oscar_rem_permit b_oscar_rem_permit
-#define oscar_send_typing b_oscar_send_typing
-#define search_modfirst b_search_modfirst
-#define snachandler b_snachandler
-#define ssi_modfirst b_ssi_modfirst
-#define ssi_shutdown b_ssi_shutdown
-#define stats_modfirst b_stats_modfirst
Index: otocols/oscar/auth.c
===================================================================
--- protocols/oscar/auth.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,421 +1,0 @@
-/*
- * Deals with the authorizer (group 0x0017=23, and old-style non-SNAC login).
- *
- */
-
-#include
-
-#include "md5.h"
-
-/*
- * This just pushes the passed cookie onto the passed connection, without
- * the SNAC header or any of that.
- *
- * Very commonly used, as every connection except auth will require this to
- * be the first thing you send.
- *
- */
-int aim_sendcookie(aim_session_t *sess, aim_conn_t *conn, const guint8 *chipsahoy)
-{
- aim_frame_t *fr;
- aim_tlvlist_t *tl = NULL;
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0001, 4 + 2 + 2 + AIM_COOKIELEN))) {
- return -ENOMEM;
- }
-
- aimbs_put32(&fr->data, 0x00000001);
- aim_addtlvtochain_raw(&tl, 0x0006, AIM_COOKIELEN, chipsahoy);
- aim_writetlvchain(&fr->data, &tl);
- aim_freetlvchain(&tl);
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-/*
- * Normally the FLAP version is sent as the first few bytes of the cookie,
- * meaning you generally never call this.
- *
- * But there are times when something might want it separate. Specifically,
- * libfaim sends this internally when doing SNAC login.
- *
- */
-int aim_sendflapver(aim_session_t *sess, aim_conn_t *conn)
-{
- aim_frame_t *fr;
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x01, 4))) {
- return -ENOMEM;
- }
-
- aimbs_put32(&fr->data, 0x00000001);
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-/*
- * In AIM 3.5 protocol, the first stage of login is to request login from the
- * Authorizer, passing it the screen name 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(aim_session_t *sess, aim_conn_t *conn, const char *sn)
-{
- aim_frame_t *fr;
- aim_snacid_t snacid;
- aim_tlvlist_t *tl = NULL;
-
- if (!sess || !conn || !sn) {
- return -EINVAL;
- }
-
- sess->flags |= AIM_SESS_FLAGS_SNACLOGIN;
-
- aim_sendflapver(sess, conn);
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 2 + 2 + strlen(sn)))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, 0x0017, 0x0006, 0x0000, NULL, 0);
- aim_putsnac(&fr->data, 0x0017, 0x0006, 0x0000, snacid);
-
- aim_addtlvtochain_raw(&tl, 0x0001, strlen(sn), (guint8 *) sn);
- aim_writetlvchain(&fr->data, &tl);
- aim_freetlvchain(&tl);
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-/*
- * send_login(int socket, char *sn, char *password)
- *
- * 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.
- *
- * WinAIM 4.8.2540
- * clientstring = "AOL Instant Messenger (SM), version 4.8.2540/WIN32"
- * clientid = 0x0109
- * major = 0x0004
- * minor = 0x0008
- * point = 0x0000
- * build = 0x09ec
- * t(0x0014) = 0x000000af
- * t(0x004a) = 0x01
- *
- * WinAIM 4.3.2188:
- * clientstring = "AOL Instant Messenger (SM), version 4.3.2188/WIN32"
- * clientid = 0x0109
- * major = 0x0400
- * minor = 0x0003
- * point = 0x0000
- * build = 0x088c
- * unknown = 0x00000086
- * lang = "en"
- * country = "us"
- * unknown4a = 0x01
- *
- * Latest WinAIM that libfaim can emulate without server-side buddylists:
- * clientstring = "AOL Instant Messenger (SM), version 4.1.2010/WIN32"
- * clientid = 0x0004
- * major = 0x0004
- * minor = 0x0001
- * point = 0x0000
- * build = 0x07da
- * unknown= 0x0000004b
- *
- * WinAIM 3.5.1670:
- * clientstring = "AOL Instant Messenger (SM), version 3.5.1670/WIN32"
- * clientid = 0x0004
- * major = 0x0003
- * minor = 0x0005
- * point = 0x0000
- * build = 0x0686
- * unknown =0x0000002a
- *
- * 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
- *
- */
-int aim_send_login(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *password,
- struct client_info_s *ci, const char *key)
-{
- aim_frame_t *fr;
- aim_tlvlist_t *tl = NULL;
- guint8 digest[16];
- aim_snacid_t snacid;
-
- if (!ci || !sn || !password) {
- return -EINVAL;
- }
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, 0x0017, 0x0002, 0x0000, NULL, 0);
- aim_putsnac(&fr->data, 0x0017, 0x0002, 0x0000, snacid);
-
- aim_addtlvtochain_raw(&tl, 0x0001, strlen(sn), (guint8 *) sn);
-
- aim_encode_password_md5(password, key, digest);
- aim_addtlvtochain_raw(&tl, 0x0025, 16, digest);
-
- /*
- * Newer versions of winaim have an empty type x004c TLV here.
- */
-
- if (ci->clientstring) {
- aim_addtlvtochain_raw(&tl, 0x0003, strlen(ci->clientstring), (guint8 *) ci->clientstring);
- }
- aim_addtlvtochain16(&tl, 0x0016, (guint16) ci->clientid);
- aim_addtlvtochain16(&tl, 0x0017, (guint16) ci->major);
- aim_addtlvtochain16(&tl, 0x0018, (guint16) ci->minor);
- aim_addtlvtochain16(&tl, 0x0019, (guint16) ci->point);
- aim_addtlvtochain16(&tl, 0x001a, (guint16) ci->build);
- aim_addtlvtochain_raw(&tl, 0x000e, strlen(ci->country), (guint8 *) ci->country);
- aim_addtlvtochain_raw(&tl, 0x000f, strlen(ci->lang), (guint8 *) ci->lang);
-
- /*
- * If set, old-fashioned buddy lists will not work. You will need
- * to use SSI.
- */
- aim_addtlvtochain8(&tl, 0x004a, 0x01);
-
- aim_writetlvchain(&fr->data, &tl);
-
- aim_freetlvchain(&tl);
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-int aim_encode_password_md5(const char *password, const char *key, guint8 *digest)
-{
- md5_state_t state;
-
- md5_init(&state);
- md5_append(&state, (const md5_byte_t *) key, strlen(key));
- md5_append(&state, (const md5_byte_t *) password, strlen(password));
- md5_append(&state, (const md5_byte_t *) AIM_MD5_STRING, strlen(AIM_MD5_STRING));
- md5_finish(&state, (md5_byte_t *) digest);
-
- 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
- * precense of certain TLVs.
- *
- * The client should check the value passed as errorcode. If
- * its nonzero, there was an error.
- *
- */
-static int parse(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- aim_tlvlist_t *tlvlist;
- aim_rxcallback_t userfunc;
- struct aim_authresp_info info;
- int ret = 0;
-
- memset(&info, 0, sizeof(info));
-
- /*
- * Read block of TLVs. All further data is derived
- * from what is parsed here.
- */
- tlvlist = aim_readtlvchain(bs);
-
- /*
- * No matter what, we should have a screen name.
- */
- memset(sess->sn, 0, sizeof(sess->sn));
- if (aim_gettlv(tlvlist, 0x0001, 1)) {
- info.sn = aim_gettlv_str(tlvlist, 0x0001, 1);
- strncpy(sess->sn, info.sn, sizeof(sess->sn));
- }
-
- /*
- * Check for an error code. If so, we should also
- * have an error url.
- */
- if (aim_gettlv(tlvlist, 0x0008, 1)) {
- info.errorcode = aim_gettlv16(tlvlist, 0x0008, 1);
- }
- if (aim_gettlv(tlvlist, 0x0004, 1)) {
- info.errorurl = aim_gettlv_str(tlvlist, 0x0004, 1);
- }
-
- /*
- * BOS server address.
- */
- if (aim_gettlv(tlvlist, 0x0005, 1)) {
- info.bosip = aim_gettlv_str(tlvlist, 0x0005, 1);
- }
-
- /*
- * Authorization cookie.
- */
- if (aim_gettlv(tlvlist, 0x0006, 1)) {
- aim_tlv_t *tmptlv;
-
- tmptlv = aim_gettlv(tlvlist, 0x0006, 1);
-
- info.cookie = tmptlv->value;
- }
-
- /*
- * The email address attached to this account
- * Not available for ICQ logins.
- */
- if (aim_gettlv(tlvlist, 0x0011, 1)) {
- info.email = aim_gettlv_str(tlvlist, 0x0011, 1);
- }
-
- /*
- * The registration status. (Not real sure what it means.)
- * Not available for ICQ 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.
- *
- */
- if (aim_gettlv(tlvlist, 0x0013, 1)) {
- info.regstatus = aim_gettlv16(tlvlist, 0x0013, 1);
- }
-
- if (aim_gettlv(tlvlist, 0x0040, 1)) {
- info.latestbeta.build = aim_gettlv32(tlvlist, 0x0040, 1);
- }
- if (aim_gettlv(tlvlist, 0x0041, 1)) {
- info.latestbeta.url = aim_gettlv_str(tlvlist, 0x0041, 1);
- }
- if (aim_gettlv(tlvlist, 0x0042, 1)) {
- info.latestbeta.info = aim_gettlv_str(tlvlist, 0x0042, 1);
- }
- if (aim_gettlv(tlvlist, 0x0043, 1)) {
- info.latestbeta.name = aim_gettlv_str(tlvlist, 0x0043, 1);
- }
- if (aim_gettlv(tlvlist, 0x0048, 1)) {
- ; /* no idea what this is */
-
- }
- if (aim_gettlv(tlvlist, 0x0044, 1)) {
- info.latestrelease.build = aim_gettlv32(tlvlist, 0x0044, 1);
- }
- if (aim_gettlv(tlvlist, 0x0045, 1)) {
- info.latestrelease.url = aim_gettlv_str(tlvlist, 0x0045, 1);
- }
- if (aim_gettlv(tlvlist, 0x0046, 1)) {
- info.latestrelease.info = aim_gettlv_str(tlvlist, 0x0046, 1);
- }
- if (aim_gettlv(tlvlist, 0x0047, 1)) {
- info.latestrelease.name = aim_gettlv_str(tlvlist, 0x0047, 1);
- }
- if (aim_gettlv(tlvlist, 0x0049, 1)) {
- ; /* no idea what this is */
-
-
- }
- if ((userfunc = aim_callhandler(sess, rx->conn, snac ? snac->family : 0x0017, snac ? snac->subtype : 0x0003))) {
- ret = userfunc(sess, rx, &info);
- }
-
- g_free(info.sn);
- g_free(info.bosip);
- g_free(info.errorurl);
- g_free(info.email);
- g_free(info.latestrelease.name);
- g_free(info.latestrelease.url);
- g_free(info.latestrelease.info);
- g_free(info.latestbeta.name);
- g_free(info.latestbeta.url);
- g_free(info.latestbeta.info);
-
- aim_freetlvchain(&tlvlist);
-
- return ret;
-}
-
-/*
- * 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(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- int keylen, ret = 1;
- aim_rxcallback_t userfunc;
- char *keystr;
-
- keylen = aimbs_get16(bs);
- keystr = aimbs_getstr(bs, keylen);
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, keystr);
- }
-
- g_free(keystr);
-
- return ret;
-}
-
-static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
-
- if (snac->subtype == 0x0003) {
- return parse(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x0007) {
- return keyparse(sess, mod, rx, snac, bs);
- }
-
- return 0;
-}
-
-int auth_modfirst(aim_session_t *sess, aim_module_t *mod)
-{
-
- mod->family = 0x0017;
- mod->version = 0x0000;
- mod->flags = 0;
- strncpy(mod->name, "auth", sizeof(mod->name));
- mod->snachandler = snachandler;
-
- return 0;
-}
-
Index: otocols/oscar/bos.c
===================================================================
--- protocols/oscar/bos.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,85 +1,0 @@
-#include
-#include "bos.h"
-
-/* Request BOS rights (group 9, type 2) */
-int aim_bos_reqrights(aim_session_t *sess, aim_conn_t *conn)
-{
- return aim_genericreq_n(sess, conn, 0x0009, 0x0002);
-}
-
-/* BOS Rights (group 9, type 3) */
-static int rights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- aim_rxcallback_t userfunc;
- aim_tlvlist_t *tlvlist;
- guint16 maxpermits = 0, maxdenies = 0;
- int ret = 0;
-
- /*
- * TLVs follow
- */
- tlvlist = aim_readtlvchain(bs);
-
- /*
- * TLV type 0x0001: Maximum number of buddies on permit list.
- */
- if (aim_gettlv(tlvlist, 0x0001, 1)) {
- maxpermits = aim_gettlv16(tlvlist, 0x0001, 1);
- }
-
- /*
- * TLV type 0x0002: Maximum number of buddies on deny list.
- */
- if (aim_gettlv(tlvlist, 0x0002, 1)) {
- maxdenies = aim_gettlv16(tlvlist, 0x0002, 1);
- }
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, maxpermits, maxdenies);
- }
-
- aim_freetlvchain(&tlvlist);
-
- return ret;
-}
-
-/*
- * Set group permisson mask (group 9, type 4)
- *
- * Normally 0x1f (all classes).
- *
- * The group permission mask allows you to keep users of a certain
- * class or classes from talking to you. The mask should be
- * a bitwise OR of all the user classes you want to see you.
- *
- */
-int aim_bos_setgroupperm(aim_session_t *sess, aim_conn_t *conn, guint32 mask)
-{
- return aim_genericreq_l(sess, conn, 0x0009, 0x0004, &mask);
-}
-
-static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
-
- if (snac->subtype == 0x0003) {
- return rights(sess, mod, rx, snac, bs);
- }
-
- return 0;
-}
-
-int bos_modfirst(aim_session_t *sess, aim_module_t *mod)
-{
-
- mod->family = 0x0009;
- mod->version = 0x0001;
- mod->toolid = 0x0110;
- mod->toolversion = 0x0629;
- mod->flags = 0;
- strncpy(mod->name, "bos", sizeof(mod->name));
- mod->snachandler = snachandler;
-
- return 0;
-}
-
-
Index: otocols/oscar/bos.h
===================================================================
--- protocols/oscar/bos.h (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,14 +1,0 @@
-#ifndef __OSCAR_BOS_H__
-#define __OSCAR_BOS_H__
-
-#define AIM_CB_FAM_BOS 0x0009
-
-/*
- * SNAC Family: Misc BOS Services.
- */
-#define AIM_CB_BOS_ERROR 0x0001
-#define AIM_CB_BOS_RIGHTSQUERY 0x0002
-#define AIM_CB_BOS_RIGHTS 0x0003
-#define AIM_CB_BOS_DEFAULT 0xffff
-
-#endif /* __OSCAR_BOS_H__ */
Index: otocols/oscar/buddylist.c
===================================================================
--- protocols/oscar/buddylist.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,97 +1,0 @@
-#include
-#include "buddylist.h"
-
-/*
- * Oncoming Buddy notifications contain a subset of the
- * user information structure. Its close enough to run
- * through aim_extractuserinfo() however.
- *
- * Although the offgoing notification contains no information,
- * it is still in a format parsable by extractuserinfo.
- *
- */
-static int buddychange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- aim_userinfo_t userinfo;
- aim_rxcallback_t userfunc;
-
- aim_extractuserinfo(sess, bs, &userinfo);
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- return userfunc(sess, rx, &userinfo);
- }
-
- return 0;
-}
-
-static int rights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- aim_rxcallback_t userfunc;
- aim_tlvlist_t *tlvlist;
- guint16 maxbuddies = 0, maxwatchers = 0;
- int ret = 0;
-
- /*
- * TLVs follow
- */
- tlvlist = aim_readtlvchain(bs);
-
- /*
- * TLV type 0x0001: Maximum number of buddies.
- */
- if (aim_gettlv(tlvlist, 0x0001, 1)) {
- maxbuddies = aim_gettlv16(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_gettlv(tlvlist, 0x0002, 1)) {
- maxwatchers = aim_gettlv16(tlvlist, 0x0002, 1);
- }
-
- /*
- * TLV type 0x0003: Unknown.
- *
- * ICQ only?
- */
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, maxbuddies, maxwatchers);
- }
-
- aim_freetlvchain(&tlvlist);
-
- return ret;
-}
-
-static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
-
- if (snac->subtype == 0x0003) {
- return rights(sess, mod, rx, snac, bs);
- } else if ((snac->subtype == 0x000b) || (snac->subtype == 0x000c)) {
- return buddychange(sess, mod, rx, snac, bs);
- }
-
- return 0;
-}
-
-int buddylist_modfirst(aim_session_t *sess, aim_module_t *mod)
-{
-
- mod->family = 0x0003;
- mod->version = 0x0001;
- mod->toolid = 0x0110;
- mod->toolversion = 0x0629;
- mod->flags = 0;
- strncpy(mod->name, "buddylist", sizeof(mod->name));
- mod->snachandler = snachandler;
-
- return 0;
-}
Index: otocols/oscar/buddylist.h
===================================================================
--- protocols/oscar/buddylist.h (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,19 +1,0 @@
-#ifndef __OSCAR_BUDDYLIST_H__
-#define __OSCAR_BUDDYLIST_H__
-
-#define AIM_CB_FAM_BUD 0x0003
-
-/*
- * SNAC Family: Buddy List Management Services.
- */
-#define AIM_CB_BUD_ERROR 0x0001
-#define AIM_CB_BUD_REQRIGHTS 0x0002
-#define AIM_CB_BUD_RIGHTSINFO 0x0003
-#define AIM_CB_BUD_ADDBUDDY 0x0004
-#define AIM_CB_BUD_REMBUDDY 0x0005
-#define AIM_CB_BUD_REJECT 0x000a
-#define AIM_CB_BUD_ONCOMING 0x000b
-#define AIM_CB_BUD_OFFGOING 0x000c
-#define AIM_CB_BUD_DEFAULT 0xffff
-
-#endif /* __OSCAR_BUDDYLIST_H__ */
Index: otocols/oscar/chat.c
===================================================================
--- protocols/oscar/chat.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,671 +1,0 @@
-/*
- * aim_chat.c
- *
- * Routines for the Chat service.
- *
- */
-
-#include
-#include
-#include "info.h"
-
-/* Stored in the ->priv of chat connections */
-struct chatconnpriv {
- guint16 exchange;
- char *name;
- guint16 instance;
-};
-
-void aim_conn_kill_chat(aim_session_t *sess, aim_conn_t *conn)
-{
- struct chatconnpriv *ccp = (struct chatconnpriv *) conn->priv;
-
- if (ccp) {
- g_free(ccp->name);
- }
- g_free(ccp);
-
- return;
-}
-
-/*
- * 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(aim_session_t *sess, aim_conn_t *conn, guint16 flags, const char *msg, int msglen)
-{
- int i;
- aim_frame_t *fr;
- aim_msgcookie_t *cookie;
- aim_snacid_t snacid;
- guint8 ckstr[8];
- aim_tlvlist_t *otl = NULL, *itl = NULL;
-
- if (!sess || !conn || !msg || (msglen <= 0)) {
- return 0;
- }
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, 0x000e, 0x0005, 0x0000, NULL, 0);
- aim_putsnac(&fr->data, 0x000e, 0x0005, 0x0000, snacid);
-
-
- /*
- * Generate a random message cookie.
- *
- * XXX mkcookie should generate the cookie and cache it in one
- * operation to preserve uniqueness.
- *
- */
- for (i = 0; i < sizeof(ckstr); i++) {
- (void) aimutil_put8(ckstr + i, (guint8) rand());
- }
-
-
- cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_CHAT, NULL);
- cookie->data = NULL; /* XXX store something useful here */
-
- aim_cachecookie(sess, cookie);
-
- for (i = 0; i < sizeof(ckstr); i++) {
- aimbs_put8(&fr->data, ckstr[i]);
- }
-
-
- /*
- * Channel ID.
- */
- aimbs_put16(&fr->data, 0x0003);
-
-
- /*
- * Type 1: Flag meaning this message is destined to the room.
- */
- aim_addtlvtochain_noval(&otl, 0x0001);
-
- /*
- * Type 6: Reflect
- */
- if (!(flags & AIM_CHATFLAGS_NOREFLECT)) {
- aim_addtlvtochain_noval(&otl, 0x0006);
- }
-
- /*
- * Type 7: Autoresponse
- */
- if (flags & AIM_CHATFLAGS_AWAY) {
- aim_addtlvtochain_noval(&otl, 0x0007);
- }
-
- /* [WvG] This wasn't there originally, but we really should send
- the right charset flags, as we also do with normal
- messages. Hope this will work. :-) */
- /*
- if (flags & AIM_CHATFLAGS_UNICODE)
- aimbs_put16(&fr->data, 0x0002);
- else if (flags & AIM_CHATFLAGS_ISO_8859_1)
- aimbs_put16(&fr->data, 0x0003);
- else
- aimbs_put16(&fr->data, 0x0000);
-
- aimbs_put16(&fr->data, 0x0000);
- */
-
- /*
- * SubTLV: Type 1: Message
- */
- aim_addtlvtochain_raw(&itl, 0x0001, strlen(msg), (guint8 *) msg);
-
- /*
- * Type 5: Message block. Contains more TLVs.
- *
- * This could include other information... We just
- * put in a message TLV however.
- *
- */
- aim_addtlvtochain_frozentlvlist(&otl, 0x0005, &itl);
-
- aim_writetlvchain(&fr->data, &otl);
-
- aim_freetlvchain(&itl);
- aim_freetlvchain(&otl);
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-/*
- * 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(aim_session_t *sess, aim_conn_t *conn, guint16 exchange, const char *roomname, guint16 instance)
-{
- aim_frame_t *fr;
- aim_snacid_t snacid;
- aim_tlvlist_t *tl = NULL;
- struct chatsnacinfo csi;
-
- if (!sess || !conn || !roomname || !strlen(roomname)) {
- return -EINVAL;
- }
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 512))) {
- return -ENOMEM;
- }
-
- memset(&csi, 0, sizeof(csi));
- csi.exchange = exchange;
- strncpy(csi.name, roomname, sizeof(csi.name));
- csi.instance = instance;
-
- snacid = aim_cachesnac(sess, 0x0001, 0x0004, 0x0000, &csi, sizeof(csi));
- aim_putsnac(&fr->data, 0x0001, 0x0004, 0x0000, snacid);
-
- /*
- * Requesting service chat (0x000e)
- */
- aimbs_put16(&fr->data, 0x000e);
-
- aim_addtlvtochain_chatroom(&tl, 0x0001, exchange, roomname, instance);
- aim_writetlvchain(&fr->data, &tl);
- aim_freetlvchain(&tl);
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-int aim_chat_readroominfo(aim_bstream_t *bs, struct aim_chat_roominfo *outinfo)
-{
- int namelen;
-
- if (!bs || !outinfo) {
- return 0;
- }
-
- outinfo->exchange = aimbs_get16(bs);
- namelen = aimbs_get8(bs);
- outinfo->name = aimbs_getstr(bs, namelen);
- outinfo->instance = aimbs_get16(bs);
-
- return 0;
-}
-
-/*
- * conn must be a BOS connection!
- */
-int aim_chat_invite(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *msg, guint16 exchange,
- const char *roomname, guint16 instance)
-{
- int i;
- aim_frame_t *fr;
- aim_msgcookie_t *cookie;
- struct aim_invite_priv *priv;
- guint8 ckstr[8];
- aim_snacid_t snacid;
- aim_tlvlist_t *otl = NULL, *itl = NULL;
- guint8 *hdr;
- int hdrlen;
- aim_bstream_t hdrbs;
-
- if (!sess || !conn || !sn || !msg || !roomname) {
- return -EINVAL;
- }
-
- if (conn->type != AIM_CONN_TYPE_BOS) {
- return -EINVAL;
- }
-
- if (!(fr =
- aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152 + strlen(sn) + strlen(roomname) +
- strlen(msg)))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, sn, strlen(sn) + 1);
- aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
-
-
- /*
- * Cookie
- */
- for (i = 0; i < sizeof(ckstr); i++) {
- (void) aimutil_put8(ckstr, (guint8) rand());
- }
-
- /* XXX should be uncached by an unwritten 'invite accept' handler */
- if ((priv = g_malloc(sizeof(struct aim_invite_priv)))) {
- priv->sn = g_strdup(sn);
- priv->roomname = g_strdup(roomname);
- priv->exchange = exchange;
- priv->instance = instance;
- }
-
- if ((cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_INVITE, priv))) {
- aim_cachecookie(sess, cookie);
- } else {
- g_free(priv);
- }
-
- for (i = 0; i < sizeof(ckstr); i++) {
- aimbs_put8(&fr->data, ckstr[i]);
- }
-
-
- /*
- * Channel (2)
- */
- aimbs_put16(&fr->data, 0x0002);
-
- /*
- * Dest sn
- */
- aimbs_put8(&fr->data, strlen(sn));
- aimbs_putraw(&fr->data, (guint8 *) sn, strlen(sn));
-
- /*
- * 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.
- *
- */
- hdrlen = 2 + 8 + 16 + 6 + 4 + 4 + strlen(msg) + 4 + 2 + 1 + strlen(roomname) + 2;
- hdr = g_malloc(hdrlen);
- aim_bstream_init(&hdrbs, hdr, hdrlen);
-
- aimbs_put16(&hdrbs, 0x0000); /* Unknown! */
- aimbs_putraw(&hdrbs, ckstr, sizeof(ckstr)); /* I think... */
- aim_putcap(&hdrbs, AIM_CAPS_CHAT);
-
- aim_addtlvtochain16(&itl, 0x000a, 0x0001);
- aim_addtlvtochain_noval(&itl, 0x000f);
- aim_addtlvtochain_raw(&itl, 0x000c, strlen(msg), (guint8 *) msg);
- aim_addtlvtochain_chatroom(&itl, 0x2711, exchange, roomname, instance);
- aim_writetlvchain(&hdrbs, &itl);
-
- aim_addtlvtochain_raw(&otl, 0x0005, aim_bstream_curpos(&hdrbs), hdr);
-
- aim_writetlvchain(&fr->data, &otl);
-
- g_free(hdr);
- aim_freetlvchain(&itl);
- aim_freetlvchain(&otl);
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-/*
- * General room information. Lots of stuff.
- *
- * Values I know are in here but I havent attached
- * them to any of the 'Unknown's:
- * - Language (English)
- *
- * SNAC 000e/0002
- */
-static int infoupdate(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- aim_userinfo_t *userinfo = NULL;
- aim_rxcallback_t userfunc;
- int ret = 0;
- int usercount = 0;
- guint8 detaillevel = 0;
- char *roomname = NULL;
- struct aim_chat_roominfo roominfo;
- aim_tlvlist_t *tlvlist;
- char *roomdesc = NULL;
- guint16 flags = 0;
- guint32 creationtime = 0;
- guint16 maxmsglen = 0, maxvisiblemsglen = 0;
- guint16 unknown_d2 = 0, unknown_d5 = 0;
-
- aim_chat_readroominfo(bs, &roominfo);
-
- detaillevel = aimbs_get8(bs);
-
- if (detaillevel != 0x02) {
- imcb_error(sess->aux_data, "Only detaillevel 0x2 is support at the moment");
- return 1;
- }
-
- aimbs_get16(bs); /* tlv count */
-
- /*
- * Everything else are TLVs.
- */
- tlvlist = aim_readtlvchain(bs);
-
- /*
- * TLV type 0x006a is the room name in Human Readable Form.
- */
- if (aim_gettlv(tlvlist, 0x006a, 1)) {
- roomname = aim_gettlv_str(tlvlist, 0x006a, 1);
- }
-
- /*
- * Type 0x006f: Number of occupants.
- */
- if (aim_gettlv(tlvlist, 0x006f, 1)) {
- usercount = aim_gettlv16(tlvlist, 0x006f, 1);
- }
-
- /*
- * Type 0x0073: Occupant list.
- */
- if (aim_gettlv(tlvlist, 0x0073, 1)) {
- int curoccupant = 0;
- aim_tlv_t *tmptlv;
- aim_bstream_t occbs;
-
- tmptlv = aim_gettlv(tlvlist, 0x0073, 1);
-
- /* Allocate enough userinfo structs for all occupants */
- userinfo = g_new0(aim_userinfo_t, usercount);
-
- aim_bstream_init(&occbs, tmptlv->value, tmptlv->length);
-
- while (curoccupant < usercount) {
- aim_extractuserinfo(sess, &occbs, &userinfo[curoccupant++]);
- }
- }
-
- /*
- * Type 0x00c9: Flags. (AIM_CHATROOM_FLAG)
- */
- if (aim_gettlv(tlvlist, 0x00c9, 1)) {
- flags = aim_gettlv16(tlvlist, 0x00c9, 1);
- }
-
- /*
- * Type 0x00ca: Creation time (4 bytes)
- */
- if (aim_gettlv(tlvlist, 0x00ca, 1)) {
- creationtime = aim_gettlv32(tlvlist, 0x00ca, 1);
- }
-
- /*
- * Type 0x00d1: Maximum Message Length
- */
- if (aim_gettlv(tlvlist, 0x00d1, 1)) {
- maxmsglen = aim_gettlv16(tlvlist, 0x00d1, 1);
- }
-
- /*
- * Type 0x00d2: Unknown. (2 bytes)
- */
- if (aim_gettlv(tlvlist, 0x00d2, 1)) {
- unknown_d2 = aim_gettlv16(tlvlist, 0x00d2, 1);
- }
-
- /*
- * Type 0x00d3: Room Description
- */
- if (aim_gettlv(tlvlist, 0x00d3, 1)) {
- roomdesc = aim_gettlv_str(tlvlist, 0x00d3, 1);
- }
-
- /*
- * Type 0x000d4: Unknown (flag only)
- */
- if (aim_gettlv(tlvlist, 0x000d4, 1)) {
- ;
- }
-
- /*
- * Type 0x00d5: Unknown. (1 byte)
- */
- if (aim_gettlv(tlvlist, 0x00d5, 1)) {
- unknown_d5 = aim_gettlv8(tlvlist, 0x00d5, 1);
- }
-
-
- /*
- * Type 0x00d6: Encoding 1 ("us-ascii")
- */
- if (aim_gettlv(tlvlist, 0x000d6, 1)) {
- ;
- }
-
- /*
- * Type 0x00d7: Language 1 ("en")
- */
- if (aim_gettlv(tlvlist, 0x000d7, 1)) {
- ;
- }
-
- /*
- * Type 0x00d8: Encoding 2 ("us-ascii")
- */
- if (aim_gettlv(tlvlist, 0x000d8, 1)) {
- ;
- }
-
- /*
- * Type 0x00d9: Language 2 ("en")
- */
- if (aim_gettlv(tlvlist, 0x000d9, 1)) {
- ;
- }
-
- /*
- * Type 0x00da: Maximum visible message length
- */
- if (aim_gettlv(tlvlist, 0x000da, 1)) {
- maxvisiblemsglen = aim_gettlv16(tlvlist, 0x00da, 1);
- }
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess,
- rx,
- &roominfo,
- roomname,
- usercount,
- userinfo,
- roomdesc,
- flags,
- creationtime,
- maxmsglen,
- unknown_d2,
- unknown_d5,
- maxvisiblemsglen);
- }
-
- g_free(roominfo.name);
- g_free(userinfo);
- g_free(roomname);
- g_free(roomdesc);
- aim_freetlvchain(&tlvlist);
-
- return ret;
-}
-
-static int userlistchange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac,
- aim_bstream_t *bs)
-{
- aim_userinfo_t *userinfo = NULL;
- aim_rxcallback_t userfunc;
- int curcount = 0, ret = 0;
-
- while (aim_bstream_empty(bs)) {
- curcount++;
- userinfo = g_realloc(userinfo, curcount * sizeof(aim_userinfo_t));
- aim_extractuserinfo(sess, bs, &userinfo[curcount - 1]);
- }
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, curcount, userinfo);
- }
-
- g_free(userinfo);
-
- return ret;
-}
-
-/*
- * 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 incomingmsg(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- aim_userinfo_t userinfo;
- aim_rxcallback_t userfunc;
- int ret = 0;
- guint8 *cookie;
- guint16 channel;
- aim_tlvlist_t *otl;
- char *msg = NULL;
- aim_msgcookie_t *ck;
-
- memset(&userinfo, 0, sizeof(aim_userinfo_t));
-
- /*
- * ICBM Cookie. Uncache it.
- */
- cookie = aimbs_getraw(bs, 8);
-
- if ((ck = aim_uncachecookie(sess, cookie, AIM_COOKIETYPE_CHAT))) {
- g_free(ck->data);
- g_free(ck);
- }
-
- /*
- * Channel ID
- *
- * Channels 1 and 2 are implemented in the normal ICBM
- * parser.
- *
- * We only do channel 3 here.
- *
- */
- channel = aimbs_get16(bs);
-
- if (channel != 0x0003) {
- imcb_error(sess->aux_data, "unknown channel!");
- return 0;
- }
-
- /*
- * Start parsing TLVs right away.
- */
- otl = aim_readtlvchain(bs);
-
- /*
- * Type 0x0003: Source User Information
- */
- if (aim_gettlv(otl, 0x0003, 1)) {
- aim_tlv_t *userinfotlv;
- aim_bstream_t tbs;
-
- userinfotlv = aim_gettlv(otl, 0x0003, 1);
-
- aim_bstream_init(&tbs, userinfotlv->value, userinfotlv->length);
- aim_extractuserinfo(sess, &tbs, &userinfo);
- }
-
- /*
- * Type 0x0001: If present, it means it was a message to the
- * room (as opposed to a whisper).
- */
- if (aim_gettlv(otl, 0x0001, 1)) {
- ;
- }
-
- /*
- * Type 0x0005: Message Block. Conains more TLVs.
- */
- if (aim_gettlv(otl, 0x0005, 1)) {
- aim_tlvlist_t *itl;
- aim_tlv_t *msgblock;
- aim_bstream_t tbs;
-
- msgblock = aim_gettlv(otl, 0x0005, 1);
- aim_bstream_init(&tbs, msgblock->value, msgblock->length);
- itl = aim_readtlvchain(&tbs);
-
- /*
- * Type 0x0001: Message.
- */
- if (aim_gettlv(itl, 0x0001, 1)) {
- msg = aim_gettlv_str(itl, 0x0001, 1);
- }
-
- aim_freetlvchain(&itl);
- }
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, &userinfo, msg);
- }
-
- g_free(cookie);
- g_free(msg);
- aim_freetlvchain(&otl);
-
- return ret;
-}
-
-static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
-
- if (snac->subtype == 0x0002) {
- return infoupdate(sess, mod, rx, snac, bs);
- } else if ((snac->subtype == 0x0003) || (snac->subtype == 0x0004)) {
- return userlistchange(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x0006) {
- return incomingmsg(sess, mod, rx, snac, bs);
- }
-
- return 0;
-}
-
-int chat_modfirst(aim_session_t *sess, aim_module_t *mod)
-{
-
- mod->family = 0x000e;
- mod->version = 0x0001;
- mod->toolid = 0x0010;
- mod->toolversion = 0x0629;
- mod->flags = 0;
- strncpy(mod->name, "chat", sizeof(mod->name));
- mod->snachandler = snachandler;
-
- return 0;
-}
Index: otocols/oscar/chat.h
===================================================================
--- protocols/oscar/chat.h (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,17 +1,0 @@
-#ifndef __OSCAR_CHAT_H__
-#define __OSCAR_CHAT_H__
-
-#define AIM_CB_FAM_CHT 0x000e /* Chat */
-
-/*
- * SNAC Family: Chat Services
- */
-#define AIM_CB_CHT_ERROR 0x0001
-#define AIM_CB_CHT_ROOMINFOUPDATE 0x0002
-#define AIM_CB_CHT_USERJOIN 0x0003
-#define AIM_CB_CHT_USERLEAVE 0x0004
-#define AIM_CB_CHT_OUTGOINGMSG 0x0005
-#define AIM_CB_CHT_INCOMINGMSG 0x0006
-#define AIM_CB_CHT_DEFAULT 0xffff
-
-#endif /* __OSCAR_CHAT_H__ */
Index: otocols/oscar/chatnav.c
===================================================================
--- protocols/oscar/chatnav.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,452 +1,0 @@
-/*
- * 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
-#include "chatnav.h"
-
-/*
- * conn must be a chatnav connection!
- */
-int aim_chatnav_reqrights(aim_session_t *sess, aim_conn_t *conn)
-{
- return aim_genericreq_n_snacid(sess, conn, 0x000d, 0x0002);
-}
-
-int aim_chatnav_createroom(aim_session_t *sess, aim_conn_t *conn, const char *name, guint16 exchange)
-{
- static const char ck[] = { "create" };
- static const char lang[] = { "en" };
- static const char charset[] = { "us-ascii" };
- aim_frame_t *fr;
- aim_snacid_t snacid;
- aim_tlvlist_t *tl = NULL;
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, 0x000d, 0x0008, 0x0000, NULL, 0);
- aim_putsnac(&fr->data, 0x000d, 0x0008, 0x0000, snacid);
-
- /* exchange */
- aimbs_put16(&fr->data, 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 completly
- * 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.
- */
- aimbs_put8(&fr->data, strlen(ck));
- aimbs_putraw(&fr->data, (guint8 *) ck, strlen(ck));
-
- /*
- * instance
- *
- * Setting this to 0xffff apparently assigns the last instance.
- *
- */
- aimbs_put16(&fr->data, 0xffff);
-
- /* detail level */
- aimbs_put8(&fr->data, 0x01);
-
- aim_addtlvtochain_raw(&tl, 0x00d3, strlen(name), (guint8 *) name);
- aim_addtlvtochain_raw(&tl, 0x00d6, strlen(charset), (guint8 *) charset);
- aim_addtlvtochain_raw(&tl, 0x00d7, strlen(lang), (guint8 *) lang);
-
- /* tlvcount */
- aimbs_put16(&fr->data, aim_counttlvchain(&tl));
- aim_writetlvchain(&fr->data, &tl);
-
- aim_freetlvchain(&tl);
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-static int parseinfo_perms(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac,
- aim_bstream_t *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;
- aim_tlvlist_t *tlvlist, *innerlist;
-
- tlvlist = aim_readtlvchain(bs);
-
- /*
- * Type 0x0002: Maximum concurrent rooms.
- */
- if (aim_gettlv(tlvlist, 0x0002, 1)) {
- maxrooms = aim_gettlv8(tlvlist, 0x0002, 1);
- }
-
- /*
- * Type 0x0003: Exchange information
- *
- * There can be any number of these, each one
- * representing another exchange.
- *
- */
- for (curexchange = 0; ((exchangetlv = aim_gettlv(tlvlist, 0x0003, curexchange + 1))); ) {
- aim_bstream_t tbs;
-
- aim_bstream_init(&tbs, exchangetlv->value, exchangetlv->length);
-
- curexchange++;
-
- exchanges = g_realloc(exchanges, curexchange * sizeof(struct aim_chat_exchangeinfo));
-
- /* exchange number */
- exchanges[curexchange - 1].number = aimbs_get16(&tbs);
- innerlist = aim_readtlvchain(&tbs);
-
- /*
- * Type 0x000a: Unknown.
- *
- * Usually three bytes: 0x0114 (exchange 1) or 0x010f (others).
- *
- */
- if (aim_gettlv(innerlist, 0x000a, 1)) {
- ;
- }
-
- /*
- * Type 0x000d: Unknown.
- */
- if (aim_gettlv(innerlist, 0x000d, 1)) {
- ;
- }
-
- /*
- * Type 0x0004: Unknown
- */
- if (aim_gettlv(innerlist, 0x0004, 1)) {
- ;
- }
-
- /*
- * Type 0x0002: Unknown
- */
- if (aim_gettlv(innerlist, 0x0002, 1)) {
- ;
- }
-
- /*
- * Type 0x00c9: Flags
- *
- * 1 Evilable
- * 2 Nav Only
- * 4 Instancing Allowed
- * 8 Occupant Peek Allowed
- *
- */
- if (aim_gettlv(innerlist, 0x00c9, 1)) {
- exchanges[curexchange - 1].flags = aim_gettlv16(innerlist, 0x00c9, 1);
- }
-
- /*
- * Type 0x00ca: Creation Date
- */
- if (aim_gettlv(innerlist, 0x00ca, 1)) {
- ;
- }
-
- /*
- * Type 0x00d0: Mandatory Channels?
- */
- if (aim_gettlv(innerlist, 0x00d0, 1)) {
- ;
- }
-
- /*
- * Type 0x00d1: Maximum Message length
- */
- if (aim_gettlv(innerlist, 0x00d1, 1)) {
- ;
- }
-
- /*
- * Type 0x00d2: Maximum Occupancy?
- */
- if (aim_gettlv(innerlist, 0x00d2, 1)) {
- ;
- }
-
- /*
- * Type 0x00d3: Exchange Description
- */
- if (aim_gettlv(innerlist, 0x00d3, 1)) {
- exchanges[curexchange - 1].name = aim_gettlv_str(innerlist, 0x00d3, 1);
- } else {
- exchanges[curexchange - 1].name = NULL;
- }
-
- /*
- * Type 0x00d4: Exchange Description URL
- */
- if (aim_gettlv(innerlist, 0x00d4, 1)) {
- ;
- }
-
- /*
- * Type 0x00d5: Creation Permissions
- *
- * 0 Creation not allowed
- * 1 Room creation allowed
- * 2 Exchange creation allowed
- *
- */
- if (aim_gettlv(innerlist, 0x00d5, 1)) {
- aim_gettlv8(innerlist, 0x00d5, 1); /* createperms */
- }
-
- /*
- * Type 0x00d6: Character Set (First Time)
- */
- if (aim_gettlv(innerlist, 0x00d6, 1)) {
- exchanges[curexchange - 1].charset1 = aim_gettlv_str(innerlist, 0x00d6, 1);
- } else {
- exchanges[curexchange - 1].charset1 = NULL;
- }
-
- /*
- * Type 0x00d7: Language (First Time)
- */
- if (aim_gettlv(innerlist, 0x00d7, 1)) {
- exchanges[curexchange - 1].lang1 = aim_gettlv_str(innerlist, 0x00d7, 1);
- } else {
- exchanges[curexchange - 1].lang1 = NULL;
- }
-
- /*
- * Type 0x00d8: Character Set (Second Time)
- */
- if (aim_gettlv(innerlist, 0x00d8, 1)) {
- exchanges[curexchange - 1].charset2 = aim_gettlv_str(innerlist, 0x00d8, 1);
- } else {
- exchanges[curexchange - 1].charset2 = NULL;
- }
-
- /*
- * Type 0x00d9: Language (Second Time)
- */
- if (aim_gettlv(innerlist, 0x00d9, 1)) {
- exchanges[curexchange - 1].lang2 = aim_gettlv_str(innerlist, 0x00d9, 1);
- } else {
- exchanges[curexchange - 1].lang2 = NULL;
- }
-
- /*
- * Type 0x00da: Unknown
- */
- if (aim_gettlv(innerlist, 0x00da, 1)) {
- ;
- }
-
- aim_freetlvchain(&innerlist);
- }
-
- /*
- * Call client.
- */
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, 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_freetlvchain(&tlvlist);
-
- return ret;
-}
-
-static int parseinfo_create(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac,
- aim_bstream_t *bs, aim_snac_t *snac2)
-{
- aim_rxcallback_t userfunc;
- aim_tlvlist_t *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;
- aim_bstream_t bbbs;
-
- tlvlist = aim_readtlvchain(bs);
-
- if (!(bigblock = aim_gettlv(tlvlist, 0x0004, 1))) {
- imcb_error(sess->aux_data, "no bigblock in top tlv in create room response");
-
- aim_freetlvchain(&tlvlist);
- return 0;
- }
-
- aim_bstream_init(&bbbs, bigblock->value, bigblock->length);
-
- exchange = aimbs_get16(&bbbs);
- cklen = aimbs_get8(&bbbs);
- ck = aimbs_getstr(&bbbs, cklen);
- instance = aimbs_get16(&bbbs);
- detaillevel = aimbs_get8(&bbbs);
-
- if (detaillevel != 0x02) {
- imcb_error(sess->aux_data, "unknown detaillevel in create room response");
- aim_freetlvchain(&tlvlist);
- g_free(ck);
- return 0;
- }
-
- unknown = aimbs_get16(&bbbs);
-
- innerlist = aim_readtlvchain(&bbbs);
-
- if (aim_gettlv(innerlist, 0x006a, 1)) {
- fqcn = aim_gettlv_str(innerlist, 0x006a, 1);
- }
-
- if (aim_gettlv(innerlist, 0x00c9, 1)) {
- flags = aim_gettlv16(innerlist, 0x00c9, 1);
- }
-
- if (aim_gettlv(innerlist, 0x00ca, 1)) {
- createtime = aim_gettlv32(innerlist, 0x00ca, 1);
- }
-
- if (aim_gettlv(innerlist, 0x00d1, 1)) {
- maxmsglen = aim_gettlv16(innerlist, 0x00d1, 1);
- }
-
- if (aim_gettlv(innerlist, 0x00d2, 1)) {
- maxoccupancy = aim_gettlv16(innerlist, 0x00d2, 1);
- }
-
- if (aim_gettlv(innerlist, 0x00d3, 1)) {
- name = aim_gettlv_str(innerlist, 0x00d3, 1);
- }
-
- if (aim_gettlv(innerlist, 0x00d5, 1)) {
- createperms = aim_gettlv8(innerlist, 0x00d5, 1);
- }
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, snac2->type, fqcn, instance, exchange, flags, createtime, maxmsglen,
- maxoccupancy, createperms, unknown, name, ck);
- }
-
- g_free(ck);
- g_free(name);
- g_free(fqcn);
- aim_freetlvchain(&innerlist);
- aim_freetlvchain(&tlvlist);
-
- return ret;
-}
-
-/*
- * 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(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- aim_snac_t *snac2;
- int ret = 0;
-
- if (!(snac2 = aim_remsnac(sess, snac->id))) {
- imcb_error(sess->aux_data, "received response to unknown request!");
- return 0;
- }
-
- if (snac2->family != 0x000d) {
- imcb_error(sess->aux_data, "received response that maps to corrupt request!");
- return 0;
- }
-
- /*
- * We now know what the original SNAC subtype was.
- */
- if (snac2->type == 0x0002) { /* request chat rights */
- ret = parseinfo_perms(sess, mod, rx, snac, bs, snac2);
- } else if (snac2->type == 0x0003) {
- } /* request exchange info */
- else if (snac2->type == 0x0004) {
- } /* request room info */
- else if (snac2->type == 0x0005) {
- } /* request more room info */
- else if (snac2->type == 0x0006) {
- } /* request occupant list */
- else if (snac2->type == 0x0007) {
- } /* search for a room */
- else if (snac2->type == 0x0008) { /* create room */
- ret = parseinfo_create(sess, mod, rx, snac, bs, snac2);
- } else {
- imcb_error(sess->aux_data, "unknown request subtype");
- }
-
- if (snac2) {
- g_free(snac2->data);
- }
- g_free(snac2);
-
- return ret;
-}
-
-static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
-
- if (snac->subtype == 0x0009) {
- return parseinfo(sess, mod, rx, snac, bs);
- }
-
- return 0;
-}
-
-int chatnav_modfirst(aim_session_t *sess, aim_module_t *mod)
-{
-
- mod->family = 0x000d;
- mod->version = 0x0003;
- mod->toolid = 0x0010;
- mod->toolversion = 0x0629;
- mod->flags = 0;
- strncpy(mod->name, "chatnav", sizeof(mod->name));
- mod->snachandler = snachandler;
-
- return 0;
-}
Index: otocols/oscar/chatnav.h
===================================================================
--- protocols/oscar/chatnav.h (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,14 +1,0 @@
-#ifndef __OSCAR_CHATNAV_H__
-#define __OSCAR_CHATNAV_H__
-
-#define AIM_CB_FAM_CTN 0x000d /* ChatNav */
-
-/*
- * SNAC Family: Chat Navigation Services
- */
-#define AIM_CB_CTN_ERROR 0x0001
-#define AIM_CB_CTN_CREATE 0x0008
-#define AIM_CB_CTN_INFO 0x0009
-#define AIM_CB_CTN_DEFAULT 0xffff
-
-#endif /* __OSCAR_CHATNAV_H__ */
Index: otocols/oscar/conn.c
===================================================================
--- protocols/oscar/conn.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,633 +1,0 @@
-
-/*
- * conn.c
- *
- * Does all this gloriously nifty connection handling stuff...
- *
- */
-
-#include
-#include "sock.h"
-
-static int aim_logoff(aim_session_t *sess);
-
-/*
- * 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.
- *
- */
-void aim_conn_addgroup(aim_conn_t *conn, guint16 group)
-{
- aim_conn_inside_t *ins = (aim_conn_inside_t *) conn->inside;
- struct snacgroup *sg;
-
- if (!(sg = g_malloc(sizeof(struct snacgroup)))) {
- return;
- }
-
- sg->group = group;
-
- sg->next = ins->groups;
- ins->groups = sg;
-
- return;
-}
-
-aim_conn_t *aim_conn_findbygroup(aim_session_t *sess, guint16 group)
-{
- aim_conn_t *cur;
-
- for (cur = sess->connlist; cur; cur = cur->next) {
- aim_conn_inside_t *ins = (aim_conn_inside_t *) cur->inside;
- struct snacgroup *sg;
-
- for (sg = ins->groups; sg; sg = sg->next) {
- if (sg->group == group) {
- return cur;
- }
- }
- }
-
- return NULL;
-}
-
-static void connkill_snacgroups(struct snacgroup **head)
-{
- struct snacgroup *sg;
-
- for (sg = *head; sg; ) {
- struct snacgroup *tmp;
-
- tmp = sg->next;
- g_free(sg);
- sg = tmp;
- }
-
- *head = NULL;
-
- return;
-}
-
-static void connkill_rates(struct rateclass **head)
-{
- struct rateclass *rc;
-
- for (rc = *head; rc; ) {
- struct rateclass *tmp;
- struct snacpair *sp;
-
- tmp = rc->next;
-
- for (sp = rc->members; sp; ) {
- struct snacpair *tmpsp;
-
- tmpsp = sp->next;
- g_free(sp);
- sp = tmpsp;
- }
- g_free(rc);
-
- rc = tmp;
- }
-
- *head = NULL;
-
- return;
-}
-
-static void connkill_real(aim_session_t *sess, aim_conn_t **deadconn)
-{
-
- aim_rxqueue_cleanbyconn(sess, *deadconn);
- aim_tx_cleanqueue(sess, *deadconn);
-
- if ((*deadconn)->fd != -1) {
- aim_conn_close(*deadconn);
- }
-
- /*
- * XXX ->priv should never be touched by the library. I know
- * it used to be, but I'm getting rid of all that. Use
- * ->internal instead.
- */
- if ((*deadconn)->priv) {
- g_free((*deadconn)->priv);
- }
-
- /*
- * This will free ->internal if it necessary...
- */
- if ((*deadconn)->type == AIM_CONN_TYPE_CHAT) {
- aim_conn_kill_chat(sess, *deadconn);
- }
-
- if ((*deadconn)->inside) {
- aim_conn_inside_t *inside = (aim_conn_inside_t *) (*deadconn)->inside;
-
- connkill_snacgroups(&inside->groups);
- connkill_rates(&inside->rates);
-
- g_free(inside);
- }
-
- g_free(*deadconn);
- *deadconn = NULL;
-
- return;
-}
-
-/**
- * aim_connrst - Clears out connection list, killing remaining connections.
- * @sess: Session to be cleared
- *
- * Clears out the connection list and kills any connections left.
- *
- */
-static void aim_connrst(aim_session_t *sess)
-{
-
- if (sess->connlist) {
- aim_conn_t *cur = sess->connlist, *tmp;
-
- while (cur) {
- tmp = cur->next;
- aim_conn_close(cur);
- connkill_real(sess, &cur);
- cur = tmp;
- }
- }
-
- sess->connlist = NULL;
-
- return;
-}
-
-/**
- * aim_conn_init - Reset a connection to default values.
- * @deadconn: Connection to be reset
- *
- * Initializes and/or resets a connection structure.
- *
- */
-static void aim_conn_init(aim_conn_t *deadconn)
-{
-
- if (!deadconn) {
- return;
- }
-
- deadconn->fd = -1;
- deadconn->subtype = -1;
- deadconn->type = -1;
- deadconn->seqnum = 0;
- deadconn->lastactivity = 0;
- deadconn->forcedlatency = 0;
- deadconn->handlerlist = NULL;
- deadconn->priv = NULL;
- memset(deadconn->inside, 0, sizeof(aim_conn_inside_t));
-
- return;
-}
-
-/**
- * aim_conn_getnext - Gets a new connection structure.
- * @sess: Session
- *
- * Allocate a new empty connection structure.
- *
- */
-static aim_conn_t *aim_conn_getnext(aim_session_t *sess)
-{
- aim_conn_t *newconn;
-
- if (!(newconn = g_new0(aim_conn_t, 1))) {
- return NULL;
- }
-
- if (!(newconn->inside = g_new0(aim_conn_inside_t, 1))) {
- g_free(newconn);
- return NULL;
- }
-
- aim_conn_init(newconn);
-
- newconn->next = sess->connlist;
- sess->connlist = newconn;
-
- return newconn;
-}
-
-/**
- * aim_conn_kill - Close and free a connection.
- * @sess: Session for the connection
- * @deadconn: Connection to be freed
- *
- * Close, clear, and free a connection structure. Should never be
- * called from within libfaim.
- *
- */
-void aim_conn_kill(aim_session_t *sess, aim_conn_t **deadconn)
-{
- aim_conn_t *cur, **prev;
-
- if (!deadconn || !*deadconn) {
- return;
- }
-
- for (prev = &sess->connlist; (cur = *prev); ) {
- if (cur == *deadconn) {
- *prev = cur->next;
- break;
- }
- prev = &cur->next;
- }
-
- if (!cur) {
- return; /* oops */
-
- }
- connkill_real(sess, &cur);
-
- return;
-}
-
-/**
- * aim_conn_close - Close a connection
- * @deadconn: Connection to close
- *
- * Close (but not free) a connection.
- *
- * This leaves everything untouched except for clearing the
- * handler list and setting the fd to -1 (used to recognize
- * dead connections). It will also remove cookies if necessary.
- *
- */
-void aim_conn_close(aim_conn_t *deadconn)
-{
-
- if (deadconn->fd >= 3) {
- proxy_disconnect(deadconn->fd);
- }
- deadconn->fd = -1;
- if (deadconn->handlerlist) {
- aim_clearhandlers(deadconn);
- }
-
- return;
-}
-
-/**
- * aim_getconn_type - Find a connection of a specific type
- * @sess: Session to search
- * @type: Type of connection to look for
- *
- * Searches for a connection of the specified type in the
- * specified session. Returns the first connection of that
- * type found.
- *
- * XXX except for RENDEZVOUS, all uses of this should be removed and
- * use aim_conn_findbygroup() instead.
- */
-aim_conn_t *aim_getconn_type(aim_session_t *sess, int type)
-{
- aim_conn_t *cur;
-
- for (cur = sess->connlist; cur; cur = cur->next) {
- if ((cur->type == type) &&
- !(cur->status & AIM_CONN_STATUS_INPROGRESS)) {
- break;
- }
- }
-
- return cur;
-}
-
-aim_conn_t *aim_getconn_type_all(aim_session_t *sess, int type)
-{
- aim_conn_t *cur;
-
- for (cur = sess->connlist; cur; cur = cur->next) {
- if (cur->type == type) {
- break;
- }
- }
-
- return cur;
-}
-
-/**
- * aim_newconn - Open a new connection
- * @sess: Session to create connection in
- * @type: Type of connection to create
- * @dest: Host to connect to (in "host:port" syntax)
- *
- * Opens a new connection to the specified dest host of specified
- * type, using the proxy settings if available. If @host is %NULL,
- * the connection is allocated and returned, but no connection
- * is made.
- *
- * FIXME: Return errors in a more sane way.
- *
- */
-aim_conn_t *aim_newconn(aim_session_t *sess, int type, const char *dest)
-{
- aim_conn_t *connstruct;
-
- if (!(connstruct = aim_conn_getnext(sess))) {
- return NULL;
- }
-
- connstruct->sessv = (void *) sess;
- connstruct->type = type;
-
- if (!dest) { /* just allocate a struct */
- connstruct->fd = -1;
- connstruct->status = 0;
- return connstruct;
- }
-
- /* The code that used to be here was very broken */
- g_return_val_if_reached(connstruct);
-
- return connstruct;
-}
-
-/**
- * aim_conn_setlatency - Set a forced latency value for connection
- * @conn: Conn to set latency for
- * @newval: Number of seconds to force between transmits
- *
- * Causes @newval seconds to be spent between transmits on a connection.
- *
- * This is my lame attempt at overcoming not understanding the rate
- * limiting.
- *
- * XXX: This should really be replaced with something that scales and
- * backs off like the real rate limiting does.
- *
- */
-int aim_conn_setlatency(aim_conn_t *conn, int newval)
-{
-
- if (!conn) {
- return -1;
- }
-
- conn->forcedlatency = newval;
- conn->lastactivity = 0; /* reset this just to make sure */
-
- return 0;
-}
-
-/**
- * aim_session_init - Initializes a session structure
- * @sess: Session to initialize
- * @flags: Flags to use. Any of %AIM_SESS_FLAGS %OR'd together.
- * @debuglevel: Level of debugging output (zero is least)
- *
- * Sets up the initial values for a session.
- *
- */
-void aim_session_init(aim_session_t *sess, guint32 flags, int debuglevel)
-{
-
- if (!sess) {
- return;
- }
-
- memset(sess, 0, sizeof(aim_session_t));
- aim_connrst(sess);
- sess->queue_outgoing = NULL;
- sess->queue_incoming = NULL;
- aim_initsnachash(sess);
- sess->msgcookies = NULL;
- sess->snacid_next = 0x00000001;
-
- sess->flags = 0;
-
- sess->modlistv = NULL;
-
- sess->ssi.received_data = 0;
- sess->ssi.waiting_for_ack = 0;
- sess->ssi.holding_queue = NULL;
- sess->ssi.revision = 0;
- sess->ssi.items = NULL;
- sess->ssi.timestamp = (time_t) 0;
-
- sess->locate.userinfo = NULL;
- sess->locate.torequest = NULL;
- sess->locate.requested = NULL;
- sess->locate.waiting_for_response = FALSE;
-
- sess->icq_info = NULL;
- sess->authinfo = NULL;
- sess->emailinfo = NULL;
- sess->oft_info = NULL;
-
- sess->flags |= AIM_SESS_FLAGS_SNACLOGIN;
- sess->flags |= flags;
-
- /*
- * This must always be set. Default to the queue-based
- * version for back-compatibility.
- */
- aim_tx_setenqueue(sess, AIM_TX_QUEUED, NULL);
-
-
- /*
- * Register all the modules for this session...
- */
- aim__registermodule(sess, misc_modfirst); /* load the catch-all first */
- aim__registermodule(sess, general_modfirst);
- aim__registermodule(sess, locate_modfirst);
- aim__registermodule(sess, buddylist_modfirst);
- aim__registermodule(sess, msg_modfirst);
- aim__registermodule(sess, admin_modfirst);
- aim__registermodule(sess, bos_modfirst);
- aim__registermodule(sess, search_modfirst);
- aim__registermodule(sess, stats_modfirst);
- aim__registermodule(sess, chatnav_modfirst);
- aim__registermodule(sess, chat_modfirst);
- /* missing 0x0f - 0x12 */
- aim__registermodule(sess, ssi_modfirst);
- /* missing 0x14 */
- aim__registermodule(sess, icq_modfirst);
- /* missing 0x16 */
- aim__registermodule(sess, auth_modfirst);
-
- return;
-}
-
-/**
- * aim_session_kill - Deallocate a session
- * @sess: Session to kill
- *
- */
-void aim_session_kill(aim_session_t *sess)
-{
- aim_cleansnacs(sess, -1);
-
- aim_logoff(sess);
-
- aim__shutdownmodules(sess);
-
- return;
-}
-
-/*
- * XXX this is nearly as ugly as proxyconnect().
- */
-int aim_conn_completeconnect(aim_session_t *sess, aim_conn_t *conn)
-{
- fd_set fds, wfds;
- struct timeval tv;
- int res, error = ETIMEDOUT;
- aim_rxcallback_t userfunc;
-
- if (!conn || (conn->fd == -1)) {
- return -1;
- }
-
- if (!(conn->status & AIM_CONN_STATUS_INPROGRESS)) {
- return -1;
- }
-
- FD_ZERO(&fds);
- FD_SET(conn->fd, &fds);
- FD_ZERO(&wfds);
- FD_SET(conn->fd, &wfds);
- tv.tv_sec = 0;
- tv.tv_usec = 0;
-
- if ((res = select(conn->fd + 1, &fds, &wfds, NULL, &tv)) == -1) {
- error = errno;
- aim_conn_close(conn);
- errno = error;
- return -1;
- } else if (res == 0) {
- return 0; /* hasn't really completed yet... */
- }
-
- if (FD_ISSET(conn->fd, &fds) || FD_ISSET(conn->fd, &wfds)) {
- socklen_t len = sizeof(error);
-
- if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
- error = errno;
- }
- }
-
- if (error) {
- aim_conn_close(conn);
- errno = error;
- return -1;
- }
-
- sock_make_blocking(conn->fd);
-
- conn->status &= ~AIM_CONN_STATUS_INPROGRESS;
-
- if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE))) {
- userfunc(sess, NULL, conn);
- }
-
- /* Flush out the queues if there was something waiting for this conn */
- aim_tx_flushqueue(sess);
-
- return 0;
-}
-
-aim_session_t *aim_conn_getsess(aim_conn_t *conn)
-{
-
- if (!conn) {
- return NULL;
- }
-
- return (aim_session_t *) conn->sessv;
-}
-
-/*
- * aim_logoff()
- *
- * Closes -ALL- open connections.
- *
- */
-static int aim_logoff(aim_session_t *sess)
-{
-
- aim_connrst(sess); /* in case we want to connect again */
-
- return 0;
-
-}
-
-/*
- * aim_flap_nop()
- *
- * No-op. WinAIM 4.x sends these _every minute_ to keep
- * the connection alive.
- */
-int aim_flap_nop(aim_session_t *sess, aim_conn_t *conn)
-{
- aim_frame_t *fr;
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x05, 0))) {
- return -ENOMEM;
- }
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-
Index: otocols/oscar/icq.c
===================================================================
--- protocols/oscar/icq.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,387 +1,0 @@
-/*
- * Encapsulated ICQ.
- *
- */
-
-#include
-#include "icq.h"
-
-int aim_icq_reqofflinemsgs(aim_session_t *sess)
-{
- aim_conn_t *conn;
- aim_frame_t *fr;
- aim_snacid_t snacid;
- int bslen;
-
- if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) {
- return -EINVAL;
- }
-
- bslen = 2 + 4 + 2 + 2;
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
- aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
-
- /* For simplicity, don't bother using a tlvlist */
- aimbs_put16(&fr->data, 0x0001);
- aimbs_put16(&fr->data, bslen);
-
- aimbs_putle16(&fr->data, bslen - 2);
- aimbs_putle32(&fr->data, atoi(sess->sn));
- aimbs_putle16(&fr->data, 0x003c); /* I command thee. */
- aimbs_putle16(&fr->data, snacid); /* eh. */
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-int aim_icq_ackofflinemsgs(aim_session_t *sess)
-{
- aim_conn_t *conn;
- aim_frame_t *fr;
- aim_snacid_t snacid;
- int bslen;
-
- if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) {
- return -EINVAL;
- }
-
- bslen = 2 + 4 + 2 + 2;
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
- aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
-
- /* For simplicity, don't bother using a tlvlist */
- aimbs_put16(&fr->data, 0x0001);
- aimbs_put16(&fr->data, bslen);
-
- aimbs_putle16(&fr->data, bslen - 2);
- aimbs_putle32(&fr->data, atoi(sess->sn));
- aimbs_putle16(&fr->data, 0x003e); /* I command thee. */
- aimbs_putle16(&fr->data, snacid); /* eh. */
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-int aim_icq_getallinfo(aim_session_t *sess, const char *uin)
-{
- aim_conn_t *conn;
- aim_frame_t *fr;
- aim_snacid_t snacid;
- int bslen;
- struct aim_icq_info *info;
-
- if (!uin || uin[0] < '0' || uin[0] > '9') {
- return -EINVAL;
- }
-
- if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) {
- return -EINVAL;
- }
-
- bslen = 2 + 4 + 2 + 2 + 2 + 4;
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
- aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
-
- /* For simplicity, don't bother using a tlvlist */
- aimbs_put16(&fr->data, 0x0001);
- aimbs_put16(&fr->data, bslen);
-
- aimbs_putle16(&fr->data, bslen - 2);
- aimbs_putle32(&fr->data, atoi(sess->sn));
- aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */
- aimbs_putle16(&fr->data, snacid); /* eh. */
- aimbs_putle16(&fr->data, 0x04b2); /* shrug. */
- aimbs_putle32(&fr->data, atoi(uin));
-
- aim_tx_enqueue(sess, fr);
-
- /* 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->next = sess->icq_info;
- sess->icq_info = info;
-
- return 0;
-}
-
-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);
-}
-
-/**
- * Subtype 0x0003 - Response to 0x0015/0x002, contains an ICQesque packet.
- */
-static int icqresponse(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- int ret = 0;
- aim_tlvlist_t *tl;
- aim_tlv_t *datatlv;
- aim_bstream_t qbs;
- guint16 cmd, reqid;
-
- if (!(tl = aim_readtlvchain(bs)) || !(datatlv = aim_gettlv(tl, 0x0001, 1))) {
- aim_freetlvchain(&tl);
- imcb_error(sess->aux_data, "corrupt ICQ response\n");
- return 0;
- }
-
- aim_bstream_init(&qbs, datatlv->value, datatlv->length);
-
- aimbs_getle16(&qbs); /* cmdlen */
- aimbs_getle32(&qbs); /* ouruin */
- cmd = aimbs_getle16(&qbs);
- reqid = aimbs_getle16(&qbs);
-
- if (cmd == 0x0041) { /* offline message */
- guint16 msglen;
- struct aim_icq_offlinemsg msg;
- aim_rxcallback_t userfunc;
-
- memset(&msg, 0, sizeof(msg));
-
- msg.sender = aimbs_getle32(&qbs);
- msg.year = aimbs_getle16(&qbs);
- msg.month = aimbs_getle8(&qbs);
- msg.day = aimbs_getle8(&qbs);
- msg.hour = aimbs_getle8(&qbs);
- msg.minute = aimbs_getle8(&qbs);
- msg.type = aimbs_getle16(&qbs);
- msglen = aimbs_getle16(&qbs);
- msg.msg = aimbs_getstr(&qbs, msglen);
-
- if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG))) {
- ret = userfunc(sess, rx, &msg);
- }
-
- g_free(msg.msg);
-
- } else if (cmd == 0x0042) {
- aim_rxcallback_t userfunc;
-
- if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE))) {
- ret = userfunc(sess, rx);
- }
- } else if (cmd == 0x07da) { /* information */
- guint16 subtype;
- struct aim_icq_info *info;
- aim_rxcallback_t userfunc;
-
- subtype = aimbs_getle16(&qbs);
- aim_bstream_advance(&qbs, 1); /* 0x0a */
-
- /* find another data from the same request */
- for (info = sess->icq_info; info && (info->reqid != reqid); info = info->next) {
- ;
- }
-
- if (!info) {
- info = g_new0(struct aim_icq_info, 1);
- info->reqid = reqid;
- info->next = sess->icq_info;
- sess->icq_info = info;
- }
-
- switch (subtype) {
- case 0x00a0: { /* hide ip status */
- /* nothing */
- } break;
- case 0x00aa: { /* password change status */
- /* nothing */
- } break;
- case 0x00c8: { /* general and "home" information */
- info->nick = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->first = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->last = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->email = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->homecity = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->homestate = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->homephone = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->homefax = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->homeaddr = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->mobile = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->homezip = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->homecountry = aimbs_getle16(&qbs);
- /* 0x0a 00 02 00 */
- /* 1 byte timezone? */
- /* 1 byte hide email flag? */
- } break;
- case 0x00dc: { /* personal information */
- info->age = aimbs_getle8(&qbs);
- info->unknown = aimbs_getle8(&qbs);
- info->gender = aimbs_getle8(&qbs);
- info->personalwebpage = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->birthyear = aimbs_getle16(&qbs);
- info->birthmonth = aimbs_getle8(&qbs);
- info->birthday = aimbs_getle8(&qbs);
- info->language1 = aimbs_getle8(&qbs);
- info->language2 = aimbs_getle8(&qbs);
- info->language3 = aimbs_getle8(&qbs);
- /* 0x00 00 01 00 00 01 00 00 00 00 00 */
- } break;
- case 0x00d2: { /* work information */
- info->workcity = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->workstate = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->workphone = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->workfax = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->workaddr = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->workzip = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->workcountry = aimbs_getle16(&qbs);
- info->workcompany = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->workdivision = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->workposition = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- aim_bstream_advance(&qbs, 2); /* 0x01 00 */
- info->workwebpage = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- } break;
- case 0x00e6: { /* additional personal information */
- info->info = aimbs_getstr(&qbs, aimbs_getle16(&qbs) - 1);
- } break;
- case 0x00eb: { /* email address(es) */
- int i;
- info->numaddresses = aimbs_getle16(&qbs);
- info->email2 = g_new0(char *, info->numaddresses);
- for (i = 0; i < info->numaddresses; i++) {
- info->email2[i] = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- if (i + 1 != info->numaddresses) {
- aim_bstream_advance(&qbs, 1); /* 0x00 */
- }
- }
- } break;
- case 0x00f0: { /* personal interests */
- } break;
- case 0x00fa: { /* past background and current organizations */
- } break;
- case 0x0104: { /* alias info */
- info->nick = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->first = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->last = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- aim_bstream_advance(&qbs, aimbs_getle16(&qbs));
- /* email address? */
- /* Then 0x00 02 00 */
- } break;
- case 0x010e: { /* unknown */
- /* 0x00 00 */
- } break;
-
- case 0x019a: { /* simple info */
- aim_bstream_advance(&qbs, 2);
- info->uin = aimbs_getle32(&qbs);
- info->nick = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->first = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->last = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- info->email = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
- /* Then 0x00 02 00 00 00 00 00 */
- } break;
- } /* End switch statement */
-
-
- if (!(snac->flags & 0x0001)) {
- if (subtype != 0x0104) {
- if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_INFO))) {
- ret = userfunc(sess, rx, info);
- }
- }
-
- /* Bitlbee - not supported, yet
- if (info->uin && info->nick)
- if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_ALIAS)))
- ret = userfunc(sess, rx, info);
- */
-
- if (sess->icq_info == info) {
- sess->icq_info = info->next;
- } else {
- struct aim_icq_info *cur;
- for (cur = sess->icq_info; (cur->next && (cur->next != info)); cur = cur->next) {
- ;
- }
- if (cur->next) {
- cur->next = cur->next->next;
- }
- }
- aim_icq_freeinfo(info);
- }
- }
-
- aim_freetlvchain(&tl);
-
- return ret;
-}
-
-static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
-
- if (snac->subtype == 0x0003) {
- return icqresponse(sess, mod, rx, snac, bs);
- }
-
- return 0;
-}
-
-int icq_modfirst(aim_session_t *sess, aim_module_t *mod)
-{
-
- mod->family = 0x0015;
- mod->version = 0x0001;
- mod->toolid = 0x0110;
- mod->toolversion = 0x047c;
- mod->flags = 0;
- strncpy(mod->name, "icq", sizeof(mod->name));
- mod->snachandler = snachandler;
-
- return 0;
-}
-
-
Index: otocols/oscar/icq.h
===================================================================
--- protocols/oscar/icq.h (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,97 +1,0 @@
-#ifndef __OSCAR_ICQ_H__
-#define __OSCAR_ICQ_H__
-
-#define AIM_CB_FAM_ICQ 0x0015
-
-/*
- * SNAC Family: ICQ
- *
- * Most of these are actually special.
- */
-#define AIM_CB_ICQ_ERROR 0x0001
-#define AIM_CB_ICQ_OFFLINEMSG 0x00f0
-#define AIM_CB_ICQ_OFFLINEMSGCOMPLETE 0x00f1
-#define AIM_CB_ICQ_SIMPLEINFO 0x00f2
-#define AIM_CB_ICQ_INFO 0x00f2 /* just transitional */
-#define AIM_CB_ICQ_DEFAULT 0xffff
-
-struct aim_icq_offlinemsg {
- guint32 sender;
- guint16 year;
- guint8 month, day, hour, minute;
- guint16 type;
- char *msg;
-};
-
-struct aim_icq_simpleinfo {
- guint32 uin;
- char *nick;
- char *first;
- char *last;
- char *email;
-};
-
-struct aim_icq_info {
- gushort 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;
- gushort homecountry;
-/* guchar timezone;
- guchar hideemail; */
-
- /* personal (0x00dc) */
- guchar age;
- guchar unknown;
- guchar gender;
- char *personalwebpage;
- gushort birthyear;
- guchar birthmonth;
- guchar birthday;
- guchar language1;
- guchar language2;
- guchar language3;
-
- /* work (0x00d2) */
- char *workcity;
- char *workstate;
- char *workphone;
- char *workfax;
- char *workaddr;
- char *workzip;
- gushort workcountry;
- char *workcompany;
- char *workdivision;
- char *workposition;
- char *workwebpage;
-
- /* additional personal information (0x00e6) */
- char *info;
-
- /* email (0x00eb) */
- gushort numaddresses;
- char **email2;
-
- /* we keep track of these in a linked list because we're 1337 */
- struct aim_icq_info *next;
-};
-
-
-int aim_icq_reqofflinemsgs(aim_session_t *sess);
-int aim_icq_ackofflinemsgs(aim_session_t *sess);
-int aim_icq_getallinfo(aim_session_t *sess, const char *uin);
-
-#endif /* __OSCAR_ICQ_H__ */
Index: otocols/oscar/im.c
===================================================================
--- protocols/oscar/im.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,1561 +1,0 @@
-/*
- * aim_im.c
- *
- * The routines for sending/receiving Instant Messages.
- *
- * Note the term ICBM (Inter-Client Basic Message) which blankets
- * all types of genericly 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.
- *
- * 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.
- *
- */
-
-#include
-#include "im.h"
-#include "info.h"
-
-/*
- * Send an ICBM (instant message).
- *
- *
- * Possible flags:
- * AIM_IMFLAGS_AWAY -- Marks the message as an autoresponse
- * AIM_IMFLAGS_ACK -- Requests that the server send an ack
- * when the message is received (of type 0x0004/0x000c)
- * AIM_IMFLAGS_OFFLINE--If destination is offline, store it until they are
- * online (probably ICQ only).
- * AIM_IMFLAGS_UNICODE--Instead of ASCII7, the passed message is
- * made up of UNICODE duples. If you set
- * this, you'd better be damn sure you know
- * what you're doing.
- * AIM_IMFLAGS_ISO_8859_1 -- The message contains the ASCII8 subset
- * known as ISO-8859-1.
- *
- * Generally, you should use the lowest encoding possible to send
- * your message. If you only use basic punctuation and the generic
- * Latin alphabet, use ASCII7 (no flags). If you happen to use non-ASCII7
- * characters, but they are all clearly defined in ISO-8859-1, then
- * use that. Keep in mind that not all characters in the PC ASCII8
- * character set are defined in the ISO standard. For those cases (most
- * notably when the (r) symbol is used), you must use the full UNICODE
- * encoding for your message. In UNICODE mode, _all_ characters must
- * occupy 16bits, including ones that are not special. (Remember that
- * the first 128 UNICODE symbols are equivalent to ASCII7, however they
- * must be prefixed with a zero high order byte.)
- *
- * I strongly discourage the use of UNICODE mode, mainly because none
- * of the clients I use can parse those messages (and besides that,
- * wchars are difficult and non-portable to handle in most UNIX environments).
- * If you really need to include special characters, use the HTML UNICODE
- * entities. These are of the form ߪ where 2026 is the hex
- * representation of the UNICODE index (in this case, UNICODE
- * "Horizontal Ellipsis", or 133 in in ASCII8).
- *
- * 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 laid out. Most obviously, tlvlists should be used
- * instead of writing out the bytes manually.
- *
- * XXX more precise verification that we never send SNACs larger than 8192
- * XXX check SNAC size for multipart
- *
- */
-int aim_send_im_ext(aim_session_t *sess, struct aim_sendimext_args *args)
-{
- static const guint8 deffeatures[] = {
- 0x01, 0x01, 0x01, 0x02
- };
- aim_conn_t *conn;
- int i, msgtlvlen;
- aim_frame_t *fr;
- aim_snacid_t snacid;
-
- if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) {
- return -EINVAL;
- }
-
- if (!args) {
- return -EINVAL;
- }
-
- if (args->flags & AIM_IMFLAGS_MULTIPART) {
- if (args->mpmsg->numparts <= 0) {
- return -EINVAL;
- }
- } else {
- 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 */
-
- if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES) {
- msgtlvlen += 2 + args->featureslen;
- } else {
- msgtlvlen += 2 + sizeof(deffeatures);
- }
-
- if (args->flags & AIM_IMFLAGS_MULTIPART) {
- aim_mpmsg_section_t *sec;
-
- for (sec = args->mpmsg->parts; sec; sec = sec->next) {
- msgtlvlen += 2 /* 0101 */ + 2 /* block len */;
- msgtlvlen += 4 /* charset */ + sec->datalen;
- }
-
- } else {
- msgtlvlen += 2 /* 0101 */ + 2 /* block len */;
- msgtlvlen += 4 /* charset */ + args->msglen;
- }
-
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, msgtlvlen + 128))) {
- return -ENOMEM;
- }
-
- /* XXX should be optional */
- snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, args->destsn, strlen(args->destsn) + 1);
- aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
-
- /*
- * Generate a random message cookie
- *
- * We could cache these like we do SNAC IDs. (In fact, it
- * might be a good idea.) In the message error functions,
- * the 8byte message cookie is returned as well as the
- * SNAC ID.
- *
- */
- for (i = 0; i < 8; i++) {
- aimbs_put8(&fr->data, (guint8) rand());
- }
-
- /*
- * Channel ID
- */
- aimbs_put16(&fr->data, 0x0001);
-
- /*
- * Destination SN (prepended with byte length)
- */
- aimbs_put8(&fr->data, strlen(args->destsn));
- aimbs_putraw(&fr->data, (guint8 *) args->destsn, strlen(args->destsn));
-
- /*
- * Message TLV (type 2).
- */
- aimbs_put16(&fr->data, 0x0002);
- aimbs_put16(&fr->data, msgtlvlen);
-
- /*
- * Features
- *
- */
- aimbs_put8(&fr->data, 0x05);
- aimbs_put8(&fr->data, 0x01);
-
- if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES) {
- aimbs_put16(&fr->data, args->featureslen);
- aimbs_putraw(&fr->data, args->features, args->featureslen);
- } else {
- aimbs_put16(&fr->data, sizeof(deffeatures));
- aimbs_putraw(&fr->data, deffeatures, sizeof(deffeatures));
- }
-
- if (args->flags & AIM_IMFLAGS_MULTIPART) {
- aim_mpmsg_section_t *sec;
-
- for (sec = args->mpmsg->parts; sec; sec = sec->next) {
- aimbs_put16(&fr->data, 0x0101);
- aimbs_put16(&fr->data, sec->datalen + 4);
- aimbs_put16(&fr->data, sec->charset);
- aimbs_put16(&fr->data, sec->charsubset);
- aimbs_putraw(&fr->data, sec->data, sec->datalen);
- }
-
- } else {
-
- aimbs_put16(&fr->data, 0x0101);
-
- /*
- * Message block length.
- */
- aimbs_put16(&fr->data, args->msglen + 0x04);
-
- /*
- * Character set.
- */
- if (args->flags & AIM_IMFLAGS_CUSTOMCHARSET) {
-
- aimbs_put16(&fr->data, args->charset);
- aimbs_put16(&fr->data, args->charsubset);
-
- } else {
- if (args->flags & AIM_IMFLAGS_UNICODE) {
- aimbs_put16(&fr->data, 0x0002);
- } else if (args->flags & AIM_IMFLAGS_ISO_8859_1) {
- aimbs_put16(&fr->data, 0x0003);
- } else {
- aimbs_put16(&fr->data, 0x0000);
- }
-
- aimbs_put16(&fr->data, 0x0000);
- }
-
- /*
- * Message. Not terminated.
- */
- aimbs_putraw(&fr->data, (guint8 *) args->msg, args->msglen);
- }
-
- /*
- * Set the Request Acknowledge flag.
- */
- if (args->flags & AIM_IMFLAGS_ACK) {
- aimbs_put16(&fr->data, 0x0003);
- aimbs_put16(&fr->data, 0x0000);
- }
-
- /*
- * Set the Autoresponse flag.
- */
- if (args->flags & AIM_IMFLAGS_AWAY) {
- aimbs_put16(&fr->data, 0x0004);
- aimbs_put16(&fr->data, 0x0000);
- }
-
- if (args->flags & AIM_IMFLAGS_OFFLINE) {
- aimbs_put16(&fr->data, 0x0006);
- aimbs_put16(&fr->data, 0x0000);
- }
-
- /*
- * Set the I HAVE A REALLY PURTY ICON flag.
- */
- if (args->flags & AIM_IMFLAGS_HASICON) {
- aimbs_put16(&fr->data, 0x0008);
- aimbs_put16(&fr->data, 0x000c);
- aimbs_put32(&fr->data, args->iconlen);
- aimbs_put16(&fr->data, 0x0001);
- aimbs_put16(&fr->data, args->iconsum);
- aimbs_put32(&fr->data, args->iconstamp);
- }
-
- /*
- * Set the Buddy Icon Requested flag.
- */
- if (args->flags & AIM_IMFLAGS_BUDDYREQ) {
- aimbs_put16(&fr->data, 0x0009);
- aimbs_put16(&fr->data, 0x0000);
- }
-
- aim_tx_enqueue(sess, fr);
-
- if (!(sess->flags & AIM_SESS_FLAGS_DONTTIMEOUTONICBM)) {
- aim_cleansnacs(sess, 60); /* clean out SNACs over 60sec old */
-
- }
- return 0;
-}
-
-/*
- * Simple wrapper for aim_send_im_ext()
- *
- * You cannot use aim_send_im if you need the HASICON flag. You must
- * use aim_send_im_ext directly for that.
- *
- * aim_send_im also cannot be used if you require UNICODE messages, because
- * that requires an explicit message length. Use aim_send_im_ext().
- *
- */
-int aim_send_im(aim_session_t *sess, const char *destsn, guint16 flags, const char *msg)
-{
- struct aim_sendimext_args args;
-
- args.destsn = destsn;
- args.flags = flags;
- args.msg = msg;
- args.msglen = strlen(msg);
-
- /* Make these don't get set by accident -- they need aim_send_im_ext */
- args.flags &= ~(AIM_IMFLAGS_CUSTOMFEATURES | AIM_IMFLAGS_HASICON | AIM_IMFLAGS_MULTIPART);
-
- return aim_send_im_ext(sess, &args);
-}
-
-/**
- * answers status message requests
- * @param sess the oscar session
- * @param sender the guy whos asking
- * @param cookie message id which we are answering for
- * @param message away message
- * @param state our current away state the way icq requests it (0xE8 for away, 0xE9 occupied, ...)
- * @return 0 if no error
- */
-int aim_send_im_ch2_statusmessage(aim_session_t *sess, const char *sender, const guint8 *cookie,
- const char *message, const guint8 state, const guint16 dc)
-{
- aim_conn_t *conn;
- aim_frame_t *fr;
- aim_snacid_t snacid;
-
- if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) {
- return -EINVAL;
- }
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02,
- 10 + 8 + 2 + 1 + strlen(sender) + 2 + 0x1d + 0x10 + 9 + strlen(message) + 1))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, 0x0004, 0x000b, 0x0000, NULL, 0);
- aim_putsnac(&fr->data, 0x0004, 0x000b, 0x0000, snacid);
-
- aimbs_putraw(&fr->data, cookie, 8);
-
- aimbs_put16(&fr->data, 0x0002); /* channel */
- aimbs_put8(&fr->data, strlen(sender));
- aimbs_putraw(&fr->data, (guint8 *) sender, strlen(sender));
-
- aimbs_put16(&fr->data, 0x0003); /* reason: channel specific */
-
- aimbs_putle16(&fr->data, 0x001b); /* length of data SEQ1 */
- aimbs_putle16(&fr->data, 0x0008); /* protocol version */
-
- aimbs_putle32(&fr->data, 0x0000); /* no plugin -> 16 times 0x00 */
- aimbs_putle32(&fr->data, 0x0000);
- aimbs_putle32(&fr->data, 0x0000);
- aimbs_putle32(&fr->data, 0x0000);
-
- aimbs_putle16(&fr->data, 0x0000); /* unknown */
- aimbs_putle32(&fr->data, 0x0003); /* client features */
- aimbs_putle8(&fr->data, 0x00); /* unknown */
- aimbs_putle16(&fr->data, dc); /* Sequence number? XXX - This should decrement by 1 with each request */
- /* end of SEQ1 */
-
- aimbs_putle16(&fr->data, 0x000e); /* Length of SEQ2 */
- aimbs_putle16(&fr->data, dc); /* Sequence number? same as above
- * XXX - This should decrement by 1 with each request */
- aimbs_putle32(&fr->data, 0x00000000); /* Unknown */
- aimbs_putle32(&fr->data, 0x00000000); /* Unknown */
- aimbs_putle32(&fr->data, 0x00000000); /* Unknown */
- /* end of SEQ2 */
-
- /* now for the real fun */
- aimbs_putle8(&fr->data, state); /* away state */
- aimbs_putle8(&fr->data, 0x03); /* msg-flag: 03 for states */
- aimbs_putle16(&fr->data, 0x0000); /* status code ? */
- aimbs_putle16(&fr->data, 0x0000); /* priority code */
- aimbs_putle16(&fr->data, strlen(message) + 1); /* message length + termination */
- aimbs_putraw(&fr->data, (guint8 *) message, strlen(message) + 1); /* null terminated string */
-
- aim_tx_enqueue(sess, fr);
-
-
- return 0;
-}
-
-
-static int outgoingim(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- int i, ret = 0;
- aim_rxcallback_t userfunc;
- guint16 channel;
- aim_tlvlist_t *tlvlist;
- char *sn;
- int snlen;
- guint16 icbmflags = 0;
- guint8 flag1 = 0, flag2 = 0;
- char *msg = NULL;
- aim_tlv_t *msgblock;
-
- /* ICBM Cookie. */
- for (i = 0; i < 8; i++) {
- aimbs_get8(bs);
- }
-
- /* Channel ID */
- channel = aimbs_get16(bs);
-
- if (channel != 0x01) {
- imcb_error(sess->aux_data, "icbm: ICBM received on unsupported channel. Ignoring.");
- return 0;
- }
-
- snlen = aimbs_get8(bs);
- sn = aimbs_getstr(bs, snlen);
-
- tlvlist = aim_readtlvchain(bs);
-
- if (aim_gettlv(tlvlist, 0x0003, 1)) {
- icbmflags |= AIM_IMFLAGS_ACK;
- }
- if (aim_gettlv(tlvlist, 0x0004, 1)) {
- icbmflags |= AIM_IMFLAGS_AWAY;
- }
-
- if ((msgblock = aim_gettlv(tlvlist, 0x0002, 1))) {
- aim_bstream_t mbs;
- int featurelen, msglen;
-
- aim_bstream_init(&mbs, msgblock->value, msgblock->length);
-
- aimbs_get8(&mbs);
- aimbs_get8(&mbs);
- for (featurelen = aimbs_get16(&mbs); featurelen; featurelen--) {
- aimbs_get8(&mbs);
- }
- aimbs_get8(&mbs);
- aimbs_get8(&mbs);
-
- msglen = aimbs_get16(&mbs) - 4; /* final block length */
-
- flag1 = aimbs_get16(&mbs);
- flag2 = aimbs_get16(&mbs);
-
- msg = aimbs_getstr(&mbs, msglen);
- }
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, channel, sn, msg, icbmflags, flag1, flag2);
- }
-
- g_free(sn);
- aim_freetlvchain(&tlvlist);
-
- return ret;
-}
-
-/*
- * Ahh, the joys of nearly ridiculous over-engineering.
- *
- * Not only do AIM ICBM's support multiple channels. Not only do they
- * support multiple character sets. But they support multiple character
- * sets / encodings within the same ICBM.
- *
- * These multipart messages allow for complex space savings techniques, which
- * seem utterly unnecessary by today's standards. In fact, there is only
- * one client still in popular use that still uses this method: AOL for the
- * Macintosh, Version 5.0. Obscure, yes, I know.
- *
- * In modern (non-"legacy") clients, if the user tries to send a character
- * that is not ISO-8859-1 or ASCII, the client will send the entire message
- * as UNICODE, meaning that every character in the message will occupy the
- * full 16 bit UNICODE field, even if the high order byte would be zero.
- * Multipart messages prevent this wasted space by allowing the client to
- * only send the characters in UNICODE that need to be sent that way, and
- * the rest of the message can be sent in whatever the native character
- * set is (probably ASCII).
- *
- * An important note is that sections will be displayed in the order that
- * they appear in the ICBM. There is no facility for merging or rearranging
- * sections at run time. So if you have, say, ASCII then UNICODE then ASCII,
- * you must supply two ASCII sections with a UNICODE in the middle, and incur
- * the associated overhead.
- *
- * Normally I would have laughed and given a firm 'no' to supporting this
- * seldom-used feature, but something is attracting me to it. In the future,
- * it may be possible to abuse this to send mixed-media messages to other
- * open source clients (like encryption or something) -- see faimtest for
- * examples of how to do this.
- *
- * I would definitely recommend avoiding this feature unless you really
- * know what you are doing, and/or you have something neat to do with it.
- *
- */
-int aim_mpmsg_init(aim_session_t *sess, aim_mpmsg_t *mpm)
-{
-
- memset(mpm, 0, sizeof(aim_mpmsg_t));
-
- return 0;
-}
-
-static int mpmsg_addsection(aim_session_t *sess, aim_mpmsg_t *mpm, guint16 charset, guint16 charsubset, guint8 *data,
- guint16 datalen)
-{
- aim_mpmsg_section_t *sec;
-
- if (!(sec = g_new0(aim_mpmsg_section_t, 1))) {
- return -1;
- }
-
- sec->charset = charset;
- sec->charsubset = charsubset;
- sec->data = data;
- sec->datalen = datalen;
- sec->next = NULL;
-
- if (!mpm->parts) {
- mpm->parts = sec;
- } else {
- aim_mpmsg_section_t *cur;
-
- for (cur = mpm->parts; cur->next; cur = cur->next) {
- ;
- }
- cur->next = sec;
- }
-
- mpm->numparts++;
-
- return 0;
-}
-
-void aim_mpmsg_free(aim_session_t *sess, aim_mpmsg_t *mpm)
-{
- aim_mpmsg_section_t *cur;
-
- for (cur = mpm->parts; cur; ) {
- aim_mpmsg_section_t *tmp;
-
- tmp = cur->next;
- g_free(cur->data);
- g_free(cur);
- cur = tmp;
- }
-
- mpm->numparts = 0;
- mpm->parts = NULL;
-
- return;
-}
-
-/*
- * Start by building the multipart structures, then pick the first
- * human-readable section and stuff it into args->msg so no one gets
- * suspicious.
- *
- */
-static int incomingim_ch1_parsemsgs(aim_session_t *sess, guint8 *data, int len, struct aim_incomingim_ch1_args *args)
-{
- static const guint16 charsetpri[] = {
- 0x0000, /* ASCII first */
- 0x0003, /* then ISO-8859-1 */
- 0x0002, /* UNICODE as last resort */
- };
- static const int charsetpricount = 3;
- int i;
- aim_bstream_t mbs;
- aim_mpmsg_section_t *sec;
-
- aim_bstream_init(&mbs, data, len);
-
- while (aim_bstream_empty(&mbs)) {
- guint16 msglen, flag1, flag2;
- char *msgbuf;
-
- aimbs_get8(&mbs); /* 01 */
- aimbs_get8(&mbs); /* 01 */
-
- /* Message string length, including character set info. */
- msglen = aimbs_get16(&mbs);
-
- /* Character set info */
- flag1 = aimbs_get16(&mbs);
- flag2 = aimbs_get16(&mbs);
-
- /* Message. */
- msglen -= 4;
-
- /*
- * For now, we don't care what the encoding is. Just copy
- * it into a multipart struct and deal with it later. However,
- * always pad the ending with a NULL. This makes it easier
- * to treat ASCII sections as strings. It won't matter for
- * UNICODE or binary data, as you should never read past
- * the specified data length, which will not include the pad.
- *
- * XXX There's an API bug here. For sending, the UNICODE is
- * given in host byte order (aim_mpmsg_addunicode), but here
- * the received messages are given in network byte order.
- *
- */
- msgbuf = aimbs_getstr(&mbs, msglen);
- mpmsg_addsection(sess, &args->mpmsg, flag1, flag2, (guint8 *) msgbuf, (guint16) msglen);
-
- } /* while */
-
- args->icbmflags |= AIM_IMFLAGS_MULTIPART; /* always set */
-
- /*
- * Clients that support multiparts should never use args->msg, as it
- * will point to an arbitrary section.
- *
- * Here, we attempt to provide clients that do not support multipart
- * messages with something to look at -- hopefully a human-readable
- * string. But, failing that, a UNICODE message, or nothing at all.
- *
- * Which means that even if args->msg is NULL, it does not mean the
- * message was blank.
- *
- */
- for (i = 0; i < charsetpricount; i++) {
- for (sec = args->mpmsg.parts; sec; sec = sec->next) {
-
- if (sec->charset != charsetpri[i]) {
- continue;
- }
-
- /* Great. We found one. Fill it in. */
- args->charset = sec->charset;
- args->charsubset = sec->charsubset;
- args->icbmflags |= AIM_IMFLAGS_CUSTOMCHARSET;
-
- /* Set up the simple flags */
- if (args->charset == 0x0000) {
- ; /* ASCII */
- } else if (args->charset == 0x0002) {
- args->icbmflags |= AIM_IMFLAGS_UNICODE;
- } else if (args->charset == 0x0003) {
- args->icbmflags |= AIM_IMFLAGS_ISO_8859_1;
- } else if (args->charset == 0xffff) {
- ; /* no encoding (yeep!) */
-
- }
- if (args->charsubset == 0x0000) {
- ; /* standard subencoding? */
- } else if (args->charsubset == 0x000b) {
- args->icbmflags |= AIM_IMFLAGS_SUBENC_MACINTOSH;
- } else if (args->charsubset == 0xffff) {
- ; /* no subencoding */
- }
-#if 0
- /* XXX this isn't really necessary... */
- if (((args.flag1 != 0x0000) &&
- (args.flag1 != 0x0002) &&
- (args.flag1 != 0x0003) &&
- (args.flag1 != 0xffff)) ||
- ((args.flag2 != 0x0000) &&
- (args.flag2 != 0x000b) &&
- (args.flag2 != 0xffff))) {
- faimdprintf(sess, 0, "icbm: **warning: encoding flags are being used! {%04x, %04x}\n",
- args.flag1, args.flag2);
- }
-#endif
-
- args->msg = (char *) sec->data;
- args->msglen = sec->datalen;
-
- return 0;
- }
- }
-
- /* No human-readable sections found. Oh well. */
- args->charset = args->charsubset = 0xffff;
- args->msg = NULL;
- args->msglen = 0;
-
- return 0;
-}
-
-static int incomingim_ch1(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, guint16 channel,
- aim_userinfo_t *userinfo, aim_bstream_t *bs, guint8 *cookie)
-{
- guint16 type, length;
- aim_rxcallback_t userfunc;
- int ret = 0;
- struct aim_incomingim_ch1_args args;
- int endpos;
-
- memset(&args, 0, sizeof(args));
-
- aim_mpmsg_init(sess, &args.mpmsg);
-
- /*
- * 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 (aim_bstream_empty(bs)) {
-
- type = aimbs_get16(bs);
- length = aimbs_get16(bs);
-
- endpos = aim_bstream_curpos(bs) + length;
-
- if (type == 0x0002) { /* Message Block */
-
- /*
- * This TLV consists of the following:
- * - 0501 -- Unknown
- * - Features: Don't know how to interpret these
- * - 0101 -- Unknown
- * - Message
- *
- */
-
- aimbs_get8(bs); /* 05 */
- aimbs_get8(bs); /* 01 */
-
- args.featureslen = aimbs_get16(bs);
- /* XXX XXX this is all evil! */
- args.features = bs->data + bs->offset;
- aim_bstream_advance(bs, args.featureslen);
- args.icbmflags |= AIM_IMFLAGS_CUSTOMFEATURES;
-
- /*
- * The rest of the TLV contains one or more message
- * blocks...
- */
- incomingim_ch1_parsemsgs(sess, bs->data + bs->offset /* XXX evil!!! */,
- length - 2 - 2 - args.featureslen, &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. */
-
- /* XXX not sure if this actually gets sent. */
- args.icbmflags |= AIM_IMFLAGS_OFFLINE;
-
- } else if (type == 0x0008) { /* I-HAVE-A-REALLY-PURTY-ICON Flag */
-
- args.iconlen = aimbs_get32(bs);
- aimbs_get16(bs); /* 0x0001 */
- args.iconsum = aimbs_get16(bs);
- args.iconstamp = aimbs_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 == 0x0017) {
-
- args.extdatalen = length;
- args.extdata = aimbs_getraw(bs, args.extdatalen);
-
- } else {
- // imcb_error(sess->aux_data, "Unknown TLV encountered");
- }
-
- /*
- * This is here to protect ourselves from ourselves. That
- * is, if something above doesn't completly 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.
- *
- */
- aim_bstream_setpos(bs, endpos);
- }
-
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, channel, userinfo, &args);
- }
-
- aim_mpmsg_free(sess, &args.mpmsg);
- g_free(args.extdata);
-
- return ret;
-}
-
-
-static void incomingim_ch2_chat_free(aim_session_t *sess, struct aim_incomingim_ch2_args *args)
-{
-
- /* XXX aim_chat_roominfo_free() */
- g_free(args->info.chat.roominfo.name);
-
- return;
-}
-
-static void incomingim_ch2_chat(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac,
- aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args, aim_bstream_t *servdata)
-{
-
- /*
- * Chat room info.
- */
- if (servdata) {
- aim_chat_readroominfo(servdata, &args->info.chat.roominfo);
- }
-
- args->destructor = (void *) incomingim_ch2_chat_free;
-
- return;
-}
-
-static void incomingim_ch2_icqserverrelay_free(aim_session_t *sess, struct aim_incomingim_ch2_args *args)
-{
-
- g_free((char *) args->info.rtfmsg.rtfmsg);
-
- return;
-}
-
-/*
- * The relationship between AIM_CAPS_ICQSERVERRELAY and AIM_CAPS_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.
- *
- * This cap is used for auto status message replies, too [ft]
- *
- */
-static void incomingim_ch2_icqserverrelay(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac,
- aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args,
- aim_bstream_t *servdata)
-{
- guint16 hdrlen, msglen, dc;
- guint8 msgtype;
- guint8 *plugin;
- int i = 0, tmp = 0;
- struct im_connection *ic = sess->aux_data;
-
- /* at the moment we just can deal with requests, not with cancel or accept */
- if (args->status != 0) {
- return;
- }
-
- hdrlen = aimbs_getle16(servdata);
-
- aim_bstream_advance(servdata, 0x02); /* protocol version */
- plugin = aimbs_getraw(servdata, 0x10); /* following data is a message or
- something plugin specific */
- /* as there is no plugin handling, just skip the rest */
- aim_bstream_advance(servdata, hdrlen - 0x12);
-
- hdrlen = aimbs_getle16(servdata);
- dc = aimbs_getle16(servdata); /* save the sequence number */
- aim_bstream_advance(servdata, hdrlen - 0x02);
-
- /* TODO is it a message or something for a plugin? */
- for (i = 0; i < 0x10; i++) {
- tmp |= plugin[i];
- }
-
- if (!tmp) { /* message follows */
-
- msgtype = aimbs_getle8(servdata);
- aimbs_getle8(servdata); /* msgflags */
-
- aim_bstream_advance(servdata, 0x04); /* status code and priority code */
-
- msglen = aimbs_getle16(servdata); /* message string length */
- args->info.rtfmsg.rtfmsg = aimbs_getstr(servdata, msglen);
-
- switch (msgtype) {
- case AIM_MTYPE_PLAIN:
-
- args->info.rtfmsg.fgcolor = aimbs_getle32(servdata);
- args->info.rtfmsg.bgcolor = aimbs_getle32(servdata);
-
- hdrlen = aimbs_getle32(servdata);
- aim_bstream_advance(servdata, hdrlen);
-
- /* XXX This is such a hack. */
- args->reqclass = AIM_CAPS_ICQRTF;
- break;
-
- case AIM_MTYPE_AUTOAWAY:
- case AIM_MTYPE_AUTOBUSY:
- case AIM_MTYPE_AUTONA:
- case AIM_MTYPE_AUTODND:
- case AIM_MTYPE_AUTOFFC:
- case 0x9c: /* ICQ 5 seems to send this */
- aim_send_im_ch2_statusmessage(sess, userinfo->sn, args->cookie,
- ic->away ? ic->away : "", sess->aim_icq_state, dc);
- break;
-
- }
- } /* message or plugin specific */
-
- g_free(plugin);
- args->destructor = (void *) incomingim_ch2_icqserverrelay_free;
-
- return;
-}
-
-typedef void (*ch2_args_destructor_t)(aim_session_t *sess, struct aim_incomingim_ch2_args *args);
-
-static int incomingim_ch2(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, guint16 channel,
- aim_userinfo_t *userinfo, aim_tlvlist_t *tlvlist, guint8 *cookie)
-{
- aim_rxcallback_t userfunc;
- aim_tlv_t *block1, *servdatatlv;
- aim_tlvlist_t *list2;
- struct aim_incomingim_ch2_args args;
- aim_bstream_t bbs, sdbs, *sdbsptr = NULL;
- guint8 *cookie2;
- int ret = 0;
-
- char clientip1[30] = { "" };
- char clientip2[30] = { "" };
- char verifiedip[30] = { "" };
-
- memset(&args, 0, sizeof(args));
-
- /*
- * There's another block of TLVs embedded in the type 5 here.
- */
- block1 = aim_gettlv(tlvlist, 0x0005, 1);
- aim_bstream_init(&bbs, block1->value, block1->length);
-
- /*
- * First two bytes represent the status of the connection.
- *
- * 0 is a request, 1 is a deny (?), 2 is an accept
- */
- args.status = aimbs_get16(&bbs);
-
- /*
- * Next comes the cookie. Should match the ICBM cookie.
- */
- cookie2 = aimbs_getraw(&bbs, 8);
- if (memcmp(cookie, cookie2, 8) != 0) {
- imcb_error(sess->aux_data, "rend: warning cookies don't match!");
- }
- 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.reqclass = aim_getcap(sess, &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_readtlvchain(&bbs);
-
- /*
- * IP address from the perspective of the client.
- */
- if (aim_gettlv(list2, 0x0002, 1)) {
- aim_tlv_t *iptlv;
-
- iptlv = aim_gettlv(list2, 0x0002, 1);
-
- g_snprintf(clientip1, sizeof(clientip1), "%d.%d.%d.%d",
- aimutil_get8(iptlv->value + 0),
- aimutil_get8(iptlv->value + 1),
- aimutil_get8(iptlv->value + 2),
- aimutil_get8(iptlv->value + 3));
- }
-
- /*
- * Secondary IP address from the perspective of the client.
- */
- if (aim_gettlv(list2, 0x0003, 1)) {
- aim_tlv_t *iptlv;
-
- iptlv = aim_gettlv(list2, 0x0003, 1);
-
- g_snprintf(clientip2, sizeof(clientip2), "%d.%d.%d.%d",
- aimutil_get8(iptlv->value + 0),
- aimutil_get8(iptlv->value + 1),
- aimutil_get8(iptlv->value + 2),
- aimutil_get8(iptlv->value + 3));
- }
-
- /*
- * Verified IP address (from the perspective of Oscar).
- *
- * This is added by the server.
- */
- if (aim_gettlv(list2, 0x0004, 1)) {
- aim_tlv_t *iptlv;
-
- iptlv = aim_gettlv(list2, 0x0004, 1);
-
- g_snprintf(verifiedip, sizeof(verifiedip), "%d.%d.%d.%d",
- aimutil_get8(iptlv->value + 0),
- aimutil_get8(iptlv->value + 1),
- aimutil_get8(iptlv->value + 2),
- aimutil_get8(iptlv->value + 3));
- }
-
- /*
- * Port number for something.
- */
- if (aim_gettlv(list2, 0x0005, 1)) {
- args.port = aim_gettlv16(list2, 0x0005, 1);
- }
-
- /*
- * Error code.
- */
- if (aim_gettlv(list2, 0x000b, 1)) {
- args.errorcode = aim_gettlv16(list2, 0x000b, 1);
- }
-
- /*
- * Invitation message / chat description.
- */
- if (aim_gettlv(list2, 0x000c, 1)) {
- args.msg = aim_gettlv_str(list2, 0x000c, 1);
- }
-
- /*
- * Character set.
- */
- if (aim_gettlv(list2, 0x000d, 1)) {
- args.encoding = aim_gettlv_str(list2, 0x000d, 1);
- }
-
- /*
- * Language.
- */
- if (aim_gettlv(list2, 0x000e, 1)) {
- args.language = aim_gettlv_str(list2, 0x000e, 1);
- }
-
- /* Unknown -- two bytes = 0x0001 */
- if (aim_gettlv(list2, 0x000a, 1)) {
- ;
- }
-
- /* Unknown -- no value */
- if (aim_gettlv(list2, 0x000f, 1)) {
- ;
- }
-
- if (strlen(clientip1)) {
- args.clientip = (char *) clientip1;
- }
- if (strlen(clientip2)) {
- args.clientip2 = (char *) clientip2;
- }
- if (strlen(verifiedip)) {
- args.verifiedip = (char *) verifiedip;
- }
-
- /*
- * This is must be present in PROPOSALs, but will probably not
- * exist in CANCELs and ACCEPTs.
- *
- * Service Data blocks are module-specific in format.
- */
- if ((servdatatlv = aim_gettlv(list2, 0x2711 /* 10001 */, 1))) {
-
- aim_bstream_init(&sdbs, servdatatlv->value, servdatatlv->length);
- sdbsptr = &sdbs;
- }
-
- if (args.reqclass & AIM_CAPS_ICQSERVERRELAY) {
- incomingim_ch2_icqserverrelay(sess, mod, rx, snac, userinfo, &args, sdbsptr);
- } else if (args.reqclass & AIM_CAPS_CHAT) {
- incomingim_ch2_chat(sess, mod, rx, snac, userinfo, &args, sdbsptr);
- }
-
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, channel, userinfo, &args);
- }
-
-
- if (args.destructor) {
- ((ch2_args_destructor_t) args.destructor)(sess, &args);
- }
-
- g_free((char *) args.msg);
- g_free((char *) args.encoding);
- g_free((char *) args.language);
-
- aim_freetlvchain(&list2);
-
- return ret;
-}
-
-static int incomingim_ch4(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, guint16 channel,
- aim_userinfo_t *userinfo, aim_tlvlist_t *tlvlist, guint8 *cookie)
-{
- aim_bstream_t 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_gettlv(tlvlist, 0x0005, 1))) {
- return -1;
- }
- aim_bstream_init(&meat, block->value, block->length);
-
- args.uin = aimbs_getle32(&meat);
- args.type = aimbs_getle16(&meat);
- args.msg = (char *) aimbs_getraw(&meat, aimbs_getle16(&meat));
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, channel, userinfo, &args);
- }
-
- g_free(args.msg);
-
- return ret;
-}
-
-/*
- * 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(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- int i, ret = 0;
- guint8 cookie[8];
- guint16 channel;
- aim_userinfo_t userinfo;
-
- memset(&userinfo, 0x00, sizeof(aim_userinfo_t));
-
- /*
- * Read ICBM Cookie. And throw away.
- */
- for (i = 0; i < 8; i++) {
- cookie[i] = aimbs_get8(bs);
- }
-
- /*
- * Channel ID.
- *
- * Channel 0x0001 is the message channel. There are
- * other channels for things called "rendezvous"
- * which represent chat and some of the other new
- * features of AIM2/3/3.5.
- *
- * Channel 0x0002 is the Rendezvous channel, which
- * is where Chat Invitiations and various client-client
- * connection negotiations come from.
- *
- * Channel 0x0004 is used for ICQ authorization, or
- * possibly any system notice.
- *
- */
- channel = aimbs_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.
- * aim_extractuserinfo() returns the number of bytes used by the
- * userinfo tlvs, so you can start reading the rest of them right
- * afterward.
- *
- * 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_extractuserinfo(sess, 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(sess, mod, rx, snac, channel, &userinfo, bs, cookie);
-
- } else if (channel == 2) {
- aim_tlvlist_t *tlvlist;
-
- /*
- * Read block of TLVs (not including the userinfo data). All
- * further data is derived from what is parsed here.
- */
- tlvlist = aim_readtlvchain(bs);
-
- ret = incomingim_ch2(sess, mod, rx, snac, channel, &userinfo, tlvlist, cookie);
-
- aim_freetlvchain(&tlvlist);
-
- } else if (channel == 4) {
- aim_tlvlist_t *tlvlist;
-
- tlvlist = aim_readtlvchain(bs);
- ret = incomingim_ch4(sess, mod, rx, snac, channel, &userinfo, tlvlist, cookie);
- aim_freetlvchain(&tlvlist);
-
- } else {
-
- imcb_error(sess->aux_data, "ICBM received on an unsupported channel. Ignoring.");
-
- return 0;
- }
-
- return ret;
-}
-
-/*
- * aim_reqicbmparaminfo()
- *
- * Request ICBM parameter information.
- *
- */
-int aim_reqicbmparams(aim_session_t *sess)
-{
- aim_conn_t *conn;
-
- if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) {
- return -EINVAL;
- }
-
- return aim_genericreq_n(sess, conn, 0x0004, 0x0004);
-}
-
-/*
- *
- * I definitely recommend sending this. If you don't, you'll be stuck
- * with the rather unreasonable defaults. You don't want those. Send this.
- *
- */
-int aim_seticbmparam(aim_session_t *sess, struct aim_icbmparameters *params)
-{
- aim_conn_t *conn;
- aim_frame_t *fr;
- aim_snacid_t snacid;
-
- if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) {
- return -EINVAL;
- }
-
- if (!params) {
- return -EINVAL;
- }
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 16))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, 0x0004, 0x0002, 0x0000, NULL, 0);
- aim_putsnac(&fr->data, 0x0004, 0x0002, 0x0000, snacid);
-
- /* This is read-only (see Parameter Reply). Must be set to zero here. */
- aimbs_put16(&fr->data, 0x0000);
-
- /* These are all read-write */
- aimbs_put32(&fr->data, params->flags);
- aimbs_put16(&fr->data, params->maxmsglen);
- aimbs_put16(&fr->data, params->maxsenderwarn);
- aimbs_put16(&fr->data, params->maxrecverwarn);
- aimbs_put32(&fr->data, params->minmsginterval);
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-static int paraminfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- struct aim_icbmparameters params;
- aim_rxcallback_t userfunc;
-
- params.maxchan = aimbs_get16(bs);
- params.flags = aimbs_get32(bs);
- params.maxmsglen = aimbs_get16(bs);
- params.maxsenderwarn = aimbs_get16(bs);
- params.maxrecverwarn = aimbs_get16(bs);
- params.minmsginterval = aimbs_get32(bs);
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- return userfunc(sess, rx, ¶ms);
- }
-
- return 0;
-}
-
-static int missedcall(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- int ret = 0;
- aim_rxcallback_t userfunc;
- guint16 channel, nummissed, reason;
- aim_userinfo_t userinfo;
-
- while (aim_bstream_empty(bs)) {
-
- channel = aimbs_get16(bs);
- aim_extractuserinfo(sess, bs, &userinfo);
- nummissed = aimbs_get16(bs);
- reason = aimbs_get16(bs);
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, channel, &userinfo, nummissed, reason);
- }
- }
-
- return ret;
-}
-
-/*
- * Receive the response from an ICQ status message request. This contains the
- * ICQ status message. Go figure.
- */
-static int clientautoresp(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac,
- aim_bstream_t *bs)
-{
- int ret = 0;
- aim_rxcallback_t userfunc;
- guint16 channel, reason;
- char *sn;
- guint8 *ck, snlen;
-
- ck = aimbs_getraw(bs, 8);
- channel = aimbs_get16(bs);
- snlen = aimbs_get8(bs);
- sn = aimbs_getstr(bs, snlen);
- reason = aimbs_get16(bs);
-
- 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 = aimbs_getle16(bs); /* Should be 0x001b */
- aim_bstream_advance(bs, len); /* Unknown */
-
- len = aimbs_getle16(bs); /* Should be 0x000e */
- aim_bstream_advance(bs, len); /* Unknown */
-
- statusmsgtype = aimbs_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;
- }
-
- aimbs_getle8(bs); /* Unknown - 0x03 Maybe this means this is an auto-reply */
- aimbs_getle16(bs); /* Unknown - 0x0000 */
- aimbs_getle16(bs); /* Unknown - 0x0000 */
-
- len = aimbs_getle16(bs);
- msg = aimbs_getraw(bs, len);
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, channel, sn, reason, state, msg);
- }
-
- g_free(msg);
- } break;
-
- default: {
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, channel, sn, reason);
- }
- } break;
- } /* end switch */
-
- g_free(ck);
- g_free(sn);
-
- return ret;
-}
-
-static int msgack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- aim_rxcallback_t userfunc;
- guint16 type;
- guint8 snlen, *ck;
- char *sn;
- int ret = 0;
-
- ck = aimbs_getraw(bs, 8);
- type = aimbs_get16(bs);
- snlen = aimbs_get8(bs);
- sn = aimbs_getstr(bs, snlen);
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, type, sn);
- }
-
- g_free(sn);
- g_free(ck);
-
- return ret;
-}
-
-/*
- * 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 Gaim 0.60 and newer.
- *
- */
-int aim_im_sendmtn(aim_session_t *sess, guint16 type1, const char *sn, guint16 type2)
-{
- aim_conn_t *conn;
- aim_frame_t *fr;
- aim_snacid_t snacid;
-
- if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0002))) {
- return -EINVAL;
- }
-
- if (!sn) {
- return -EINVAL;
- }
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11 + strlen(sn) + 2))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, 0x0004, 0x0014, 0x0000, NULL, 0);
- aim_putsnac(&fr->data, 0x0004, 0x0014, 0x0000, snacid);
-
- /*
- * 8 days of light
- * Er, that is to say, 8 bytes of 0's
- */
- aimbs_put16(&fr->data, 0x0000);
- aimbs_put16(&fr->data, 0x0000);
- aimbs_put16(&fr->data, 0x0000);
- aimbs_put16(&fr->data, 0x0000);
-
- /*
- * Type 1 (should be 0x0001 for mtn)
- */
- aimbs_put16(&fr->data, type1);
-
- /*
- * Dest sn
- */
- aimbs_put8(&fr->data, strlen(sn));
- aimbs_putraw(&fr->data, (const guint8 *) sn, strlen(sn));
-
- /*
- * Type 2 (should be 0x0000, 0x0001, or 0x0002 for mtn)
- */
- aimbs_put16(&fr->data, type2);
-
- aim_tx_enqueue(sess, fr);
-
- 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 Gaim 0.60 and newer.
- *
- */
-static int mtn_receive(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- int ret = 0;
- aim_rxcallback_t userfunc;
- char *sn;
- guint8 snlen;
- guint16 type1, type2;
-
- aim_bstream_advance(bs, 8); /* Unknown - All 0's */
- type1 = aimbs_get16(bs);
- snlen = aimbs_get8(bs);
- sn = aimbs_getstr(bs, snlen);
- type2 = aimbs_get16(bs);
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, type1, sn, type2);
- }
-
- g_free(sn);
-
- return ret;
-}
-
-static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
-
- if (snac->subtype == 0x0005) {
- return paraminfo(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x0006) {
- return outgoingim(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x0007) {
- return incomingim(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x000a) {
- return missedcall(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x000b) {
- return clientautoresp(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x000c) {
- return msgack(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x0014) {
- return mtn_receive(sess, mod, rx, snac, bs);
- }
-
- return 0;
-}
-
-int msg_modfirst(aim_session_t *sess, aim_module_t *mod)
-{
-
- mod->family = 0x0004;
- mod->version = 0x0001;
- mod->toolid = 0x0110;
- mod->toolversion = 0x0629;
- mod->flags = 0;
- strncpy(mod->name, "messaging", sizeof(mod->name));
- mod->snachandler = snachandler;
-
- return 0;
-}
Index: otocols/oscar/im.h
===================================================================
--- protocols/oscar/im.h (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,184 +1,0 @@
-#ifndef __OSCAR_IM_H__
-#define __OSCAR_IM_H__
-
-#define AIM_CB_FAM_MSG 0x0004
-
-/*
- * SNAC Family: Messaging Services.
- */
-#define AIM_CB_MSG_ERROR 0x0001
-#define AIM_CB_MSG_PARAMINFO 0x0005
-#define AIM_CB_MSG_INCOMING 0x0007
-#define AIM_CB_MSG_EVIL 0x0009
-#define AIM_CB_MSG_MISSEDCALL 0x000a
-#define AIM_CB_MSG_CLIENTAUTORESP 0x000b
-#define AIM_CB_MSG_ACK 0x000c
-#define AIM_CB_MSG_MTN 0x0014
-#define AIM_CB_MSG_DEFAULT 0xffff
-
-#define AIM_IMFLAGS_AWAY 0x0001 /* mark as an autoreply */
-#define AIM_IMFLAGS_ACK 0x0002 /* request a receipt notice */
-#define AIM_IMFLAGS_UNICODE 0x0004
-#define AIM_IMFLAGS_ISO_8859_1 0x0008
-#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_EXTDATA 0x0100
-#define AIM_IMFLAGS_CUSTOMCHARSET 0x0200 /* charset fields set */
-#define AIM_IMFLAGS_MULTIPART 0x0400 /* ->mpmsg section valid */
-#define AIM_IMFLAGS_OFFLINE 0x0800 /* send to offline user */
-
-/*
- * Multipart message structures.
- */
-typedef struct aim_mpmsg_section_s {
- guint16 charset;
- guint16 charsubset;
- guint8 *data;
- guint16 datalen;
- struct aim_mpmsg_section_s *next;
-} aim_mpmsg_section_t;
-
-typedef struct aim_mpmsg_s {
- int numparts;
- aim_mpmsg_section_t *parts;
-} aim_mpmsg_t;
-
-int aim_mpmsg_init(aim_session_t *sess, aim_mpmsg_t *mpm);
-void aim_mpmsg_free(aim_session_t *sess, aim_mpmsg_t *mpm);
-
-/*
- * Arguments to aim_send_im_ext().
- *
- * This is really complicated. But immensely versatile.
- *
- */
-struct aim_sendimext_args {
-
- /* These are _required_ */
- const char *destsn;
- guint32 flags; /* often 0 */
-
- /* Only required if not using multipart messages */
- const char *msg;
- int msglen;
-
- /* Required if ->msg is not provided */
- aim_mpmsg_t *mpmsg;
-
- /* Only used if AIM_IMFLAGS_HASICON is set */
- guint32 iconlen;
- time_t iconstamp;
- guint32 iconsum;
-
- /* Only used if AIM_IMFLAGS_CUSTOMFEATURES is set */
- guint8 *features;
- guint8 featureslen;
-
- /* Only used if AIM_IMFLAGS_CUSTOMCHARSET is set and mpmsg not used */
- guint16 charset;
- guint16 charsubset;
-};
-
-/*
- * This information is provided in the Incoming ICBM callback for
- * Channel 1 ICBM's.
- *
- * Note that although CUSTOMFEATURES and CUSTOMCHARSET say they
- * are optional, both are always set by the current libfaim code.
- * That may or may not change in the future. It is mainly for
- * consistency with aim_sendimext_args.
- *
- * Multipart messages require some explanation. If you want to use them,
- * I suggest you read all the comments in im.c.
- *
- */
-struct aim_incomingim_ch1_args {
-
- /* Always provided */
- aim_mpmsg_t mpmsg;
- guint32 icbmflags; /* some flags apply only to ->msg, not all mpmsg */
-
- /* Only provided if message has a human-readable section */
- char *msg;
- int msglen;
-
- /* Only provided if AIM_IMFLAGS_HASICON is set */
- time_t iconstamp;
- guint32 iconlen;
- guint16 iconsum;
-
- /* Only provided if AIM_IMFLAGS_CUSTOMFEATURES is set */
- guint8 *features;
- guint8 featureslen;
-
- /* Only provided if AIM_IMFLAGS_EXTDATA is set */
- guint8 extdatalen;
- guint8 *extdata;
-
- /* Only used if AIM_IMFLAGS_CUSTOMCHARSET is set */
- guint16 charset;
- guint16 charsubset;
-};
-
-/* Valid values for channel 2 args->status */
-#define AIM_RENDEZVOUS_PROPOSE 0x0000
-#define AIM_RENDEZVOUS_CANCEL 0x0001
-#define AIM_RENDEZVOUS_ACCEPT 0x0002
-
-struct aim_incomingim_ch2_args {
- guint8 cookie[8];
- guint16 reqclass;
- guint16 status;
- guint16 errorcode;
- const char *clientip;
- const char *clientip2;
- const char *verifiedip;
- guint16 port;
- const char *msg; /* invite message or file description */
- const char *encoding;
- const char *language;
- union {
- struct {
- guint32 checksum;
- guint32 length;
- time_t timestamp;
- guint8 *icon;
- } icon;
- struct {
- struct aim_chat_roominfo roominfo;
- } chat;
- struct {
- guint32 fgcolor;
- guint32 bgcolor;
- const char *rtfmsg;
- } rtfmsg;
- } info;
- void *destructor; /* used internally only */
-};
-
-/* Valid values for channel 4 args->type */
-#define AIM_ICQMSG_AUTHREQUEST 0x0006
-#define AIM_ICQMSG_AUTHDENIED 0x0007
-#define AIM_ICQMSG_AUTHGRANTED 0x0008
-
-struct aim_incomingim_ch4_args {
- guint32 uin; /* Of the sender of the ICBM */
- guint16 type;
- char *msg; /* Reason for auth request, deny, or accept */
-};
-
-int aim_send_im_ext(aim_session_t *sess, struct aim_sendimext_args *args);
-int aim_send_im(aim_session_t *, const char *destsn, unsigned short flags, const char *msg);
-int aim_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing);
-int aim_send_im_direct(aim_session_t *, aim_conn_t *, const char *msg, int len);
-const char *aim_directim_getsn(aim_conn_t *conn);
-aim_conn_t *aim_directim_initiate(aim_session_t *, const char *destsn);
-aim_conn_t *aim_directim_connect(aim_session_t *, const char *sn, const char *addr, const guint8 *cookie);
-
-int aim_im_sendmtn(aim_session_t *sess, guint16 type1, const char *sn, guint16 type2);
-int aim_send_im_ch2_statusmessage(aim_session_t *sess, const char *sender, const guint8 *cookie, const char *message,
- const guint8 state, const guint16 dc);
-
-#endif /* __OSCAR_IM_H__ */
Index: otocols/oscar/info.c
===================================================================
--- protocols/oscar/info.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,557 +1,0 @@
-/*
- * aim_info.c
- *
- * The functions here are responsible for requesting and parsing information-
- * gathering SNACs. Or something like that.
- *
- */
-
-#include
-#include "info.h"
-
-struct aim_priv_inforeq {
- char sn[MAXSNLEN + 1];
- guint16 infotype;
-};
-
-int aim_getinfo(aim_session_t *sess, aim_conn_t *conn, const char *sn, guint16 infotype)
-{
- struct aim_priv_inforeq privdata;
- aim_frame_t *fr;
- aim_snacid_t snacid;
-
- if (!sess || !conn || !sn) {
- return -EINVAL;
- }
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 12 + 1 + strlen(sn)))) {
- return -ENOMEM;
- }
-
- strncpy(privdata.sn, sn, sizeof(privdata.sn));
- privdata.infotype = infotype;
- snacid = aim_cachesnac(sess, 0x0002, 0x0005, 0x0000, &privdata, sizeof(struct aim_priv_inforeq));
-
- aim_putsnac(&fr->data, 0x0002, 0x0005, 0x0000, snacid);
- aimbs_put16(&fr->data, infotype);
- aimbs_put8(&fr->data, strlen(sn));
- aimbs_putraw(&fr->data, (guint8 *) sn, strlen(sn));
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-/*
- * 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 {
- guint32 flag;
- guint8 data[16];
-} aim_caps[] = {
-
- /*
- * Chat is oddball.
- */
- { AIM_CAPS_CHAT,
- { 0x74, 0x8f, 0x24, 0x20, 0x62, 0x87, 0x11, 0xd1,
- 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } },
-
- /*
- * These are mostly in order.
- */
- { AIM_CAPS_VOICE,
- { 0x09, 0x46, 0x13, 0x41, 0x4c, 0x7f, 0x11, 0xd1,
- 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } },
-
- { AIM_CAPS_SENDFILE,
- { 0x09, 0x46, 0x13, 0x43, 0x4c, 0x7f, 0x11, 0xd1,
- 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } },
-
- /*
- * Advertised by the EveryBuddy client.
- */
- { AIM_CAPS_ICQ,
- { 0x09, 0x46, 0x13, 0x44, 0x4c, 0x7f, 0x11, 0xd1,
- 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } },
-
- { AIM_CAPS_IMIMAGE,
- { 0x09, 0x46, 0x13, 0x45, 0x4c, 0x7f, 0x11, 0xd1,
- 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } },
-
- { AIM_CAPS_BUDDYICON,
- { 0x09, 0x46, 0x13, 0x46, 0x4c, 0x7f, 0x11, 0xd1,
- 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } },
-
- { AIM_CAPS_SAVESTOCKS,
- { 0x09, 0x46, 0x13, 0x47, 0x4c, 0x7f, 0x11, 0xd1,
- 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } },
-
- { AIM_CAPS_GETFILE,
- { 0x09, 0x46, 0x13, 0x48, 0x4c, 0x7f, 0x11, 0xd1,
- 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } },
-
- /*
- * Client supports channel 2 extended, TLV(0x2711) based messages.
- * Currently used only by ICQ clients. ICQ clients and clones use this GUID
- * as message format sign. Trillian client use another GUID in channel 2
- * messages to implement its own message format (trillian doesn't use
- * TLV(x2711) in SecureIM channel 2 messages!).
- */
- { AIM_CAPS_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.
- */
- { AIM_CAPS_GAMES,
- { 0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1,
- 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } },
- { AIM_CAPS_GAMES2,
- { 0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1,
- 0x22, 0x82, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } },
-
- { AIM_CAPS_SENDBUDDYLIST,
- { 0x09, 0x46, 0x13, 0x4b, 0x4c, 0x7f, 0x11, 0xd1,
- 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } },
-
- { AIM_CAPS_UTF8,
- { 0x09, 0x46, 0x13, 0x4E, 0x4C, 0x7F, 0x11, 0xD1,
- 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } },
-
- { AIM_CAPS_ICQRTF,
- { 0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34,
- 0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x92 } },
-
- { AIM_CAPS_ICQUNKNOWN,
- { 0x2e, 0x7a, 0x64, 0x75, 0xfa, 0xdf, 0x4d, 0xc8,
- 0x88, 0x6f, 0xea, 0x35, 0x95, 0xfd, 0xb6, 0xdf } },
-
- { AIM_CAPS_EMPTY,
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
-
- { AIM_CAPS_TRILLIANCRYPT,
- { 0xf2, 0xe7, 0xc7, 0xf4, 0xfe, 0xad, 0x4d, 0xfb,
- 0xb2, 0x35, 0x36, 0x79, 0x8b, 0xdf, 0x00, 0x00 } },
-
- { AIM_CAPS_APINFO,
- { 0xAA, 0x4A, 0x32, 0xB5, 0xF8, 0x84, 0x48, 0xc6,
- 0xA3, 0xD7, 0x8C, 0x50, 0x97, 0x19, 0xFD, 0x5B } },
-
- { AIM_CAPS_INTEROP,
- { 0x09, 0x46, 0x13, 0x4d, 0x4c, 0x7f, 0x11, 0xd1,
- 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } },
-
- { AIM_CAPS_ICHAT,
- { 0x09, 0x46, 0x00, 0x00, 0x4c, 0x7f, 0x11, 0xd1,
- 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } },
-
- { AIM_CAPS_LAST }
-};
-
-/*
- * This still takes a length parameter even with a bstream because capabilities
- * are not naturally bounded.
- *
- */
-guint32 aim_getcap(aim_session_t *sess, aim_bstream_t *bs, int len)
-{
- guint32 flags = 0;
- int offset;
-
- for (offset = 0; aim_bstream_empty(bs) && (offset < len); offset += 0x10) {
- guint8 *cap;
- int i, identified;
-
- cap = aimbs_getraw(bs, 0x10);
-
- for (i = 0, identified = 0; !(aim_caps[i].flag & AIM_CAPS_LAST); i++) {
-
- if (memcmp(&aim_caps[i].data, cap, 0x10) == 0) {
- flags |= aim_caps[i].flag;
- identified++;
- break; /* should only match once... */
-
- }
- }
-
- if (!identified) {
- /*FIXME*/
- /*REMOVEME :-)
- g_strdup_printf("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;
-}
-
-int aim_putcap(aim_bstream_t *bs, guint32 caps)
-{
- int i;
-
- if (!bs) {
- return -EINVAL;
- }
-
- for (i = 0; aim_bstream_empty(bs); i++) {
-
- if (aim_caps[i].flag == AIM_CAPS_LAST) {
- break;
- }
-
- if (caps & aim_caps[i].flag) {
- aimbs_putraw(bs, aim_caps[i].data, 0x10);
- }
-
- }
-
- return 0;
-}
-
-/*
- * AIM is fairly regular about providing user info. This is a generic
- * routine to extract it in its standard form.
- */
-int aim_extractuserinfo(aim_session_t *sess, aim_bstream_t *bs, aim_userinfo_t *outinfo)
-{
- int curtlv, tlvcnt;
- guint8 snlen;
-
- if (!bs || !outinfo) {
- return -EINVAL;
- }
-
- /* Clear out old data first */
- memset(outinfo, 0x00, sizeof(aim_userinfo_t));
-
- /*
- * Screen name. Stored as an unterminated string prepended with a
- * byte containing its length.
- */
- snlen = aimbs_get8(bs);
- aimbs_getrawbuf(bs, (guint8 *) outinfo->sn, snlen);
-
- /*
- * Warning Level. Stored as an unsigned short.
- */
- outinfo->warnlevel = aimbs_get16(bs);
-
- /*
- * TLV Count. Unsigned short representing the number of
- * Type-Length-Value triples that follow.
- */
- tlvcnt = aimbs_get16(bs);
-
- /*
- * Parse out the Type-Length-Value triples as they're found.
- */
- for (curtlv = 0; curtlv < tlvcnt; curtlv++) {
- int endpos;
- guint16 type, length;
-
- type = aimbs_get16(bs);
- length = aimbs_get16(bs);
-
- endpos = aim_bstream_curpos(bs) + length;
-
- if (type == 0x0001) {
- /*
- * Type = 0x0001: User flags
- *
- * Specified as any of the following ORed together:
- * 0x0001 Trial (user less than 60days)
- * 0x0002 Unknown bit 2
- * 0x0004 AOL Main Service user
- * 0x0008 Unknown bit 4
- * 0x0010 Free (AIM) user
- * 0x0020 Away
- * 0x0400 ActiveBuddy
- *
- */
- outinfo->flags = aimbs_get16(bs);
- outinfo->present |= AIM_USERINFO_PRESENT_FLAGS;
-
- } else if (type == 0x0002) {
- /*
- * Type = 0x0002: Member-Since date.
- *
- * The time/date that the user originally registered for
- * the service, stored in time_t format.
- */
- outinfo->membersince = aimbs_get32(bs);
- outinfo->present |= AIM_USERINFO_PRESENT_MEMBERSINCE;
-
- } else if (type == 0x0003) {
- /*
- * Type = 0x0003: On-Since date.
- *
- * The time/date that the user started their current
- * session, stored in time_t format.
- */
- outinfo->onlinesince = aimbs_get32(bs);
- outinfo->present |= AIM_USERINFO_PRESENT_ONLINESINCE;
-
- } else if (type == 0x0004) {
- /*
- * Type = 0x0004: Idle time.
- *
- * Number of seconds 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 = aimbs_get16(bs);
- outinfo->present |= AIM_USERINFO_PRESENT_IDLE;
-
- } else if (type == 0x0006) {
- /*
- * Type = 0x0006: ICQ Online Status
- *
- * ICQ's Away/DND/etc "enriched" status. Some decoding
- * of values done by Scott
- */
- aimbs_get16(bs);
- outinfo->icqinfo.status = aimbs_get16(bs);
- outinfo->present |= AIM_USERINFO_PRESENT_ICQEXTSTATUS;
-
- } else if (type == 0x000a) {
- /*
- * Type = 0x000a
- *
- * ICQ User IP Address.
- * Ahh, the joy of ICQ security.
- */
- outinfo->icqinfo.ipaddr = aimbs_get32(bs);
- outinfo->present |= AIM_USERINFO_PRESENT_ICQIPADDR;
-
- } else if (type == 0x000c) {
- /*
- * Type = 0x000c
- *
- * random crap containing the IP address,
- * apparently a port number, and some Other Stuff.
- *
- */
- aimbs_getrawbuf(bs, outinfo->icqinfo.crap, 0x25);
- outinfo->present |= AIM_USERINFO_PRESENT_ICQDATA;
-
- } else if (type == 0x000d) {
- /*
- * Type = 0x000d
- *
- * Capability information.
- *
- */
- outinfo->capabilities = aim_getcap(sess, bs, length);
- outinfo->present |= AIM_USERINFO_PRESENT_CAPABILITIES;
-
- } else if (type == 0x000e) {
- /*
- * Type = 0x000e
- *
- * Unknown. Always of zero length, and always only
- * on AOL users.
- *
- * Ignore.
- *
- */
-
- } 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 = aimbs_get32(bs);
- outinfo->present |= AIM_USERINFO_PRESENT_SESSIONLEN;
-
- } 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 DEBUG
- // imcb_error(sess->aux_data, G_STRLOC);
-#endif
-
- }
-
- /* Save ourselves. */
- aim_bstream_setpos(bs, endpos);
- }
-
- return 0;
-}
-
-/*
- * 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(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- aim_tlvlist_t *tlvlist;
- aim_rxcallback_t userfunc;
- int ret = 0;
- guint16 maxsiglen = 0;
-
- tlvlist = aim_readtlvchain(bs);
-
- if (aim_gettlv(tlvlist, 0x0001, 1)) {
- maxsiglen = aim_gettlv16(tlvlist, 0x0001, 1);
- }
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, maxsiglen);
- }
-
- aim_freetlvchain(&tlvlist);
-
- return ret;
-}
-
-static int userinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- aim_userinfo_t userinfo;
- char *text_encoding = NULL, *text = NULL;
- guint16 text_length = 0;
- aim_rxcallback_t userfunc;
- aim_tlvlist_t *tlvlist;
- aim_tlv_t *tlv;
- aim_snac_t *origsnac = NULL;
- struct aim_priv_inforeq *inforeq;
- int ret = 0;
-
- origsnac = aim_remsnac(sess, snac->id);
-
- if (!origsnac || !origsnac->data) {
- imcb_error(sess->aux_data, "major problem: no snac stored!");
- return 0;
- }
-
- inforeq = (struct aim_priv_inforeq *) origsnac->data;
-
- if ((inforeq->infotype != AIM_GETINFO_GENERALINFO) &&
- (inforeq->infotype != AIM_GETINFO_AWAYMESSAGE) &&
- (inforeq->infotype != AIM_GETINFO_CAPABILITIES)) {
- imcb_error(sess->aux_data, "unknown infotype in request!");
- return 0;
- }
-
- aim_extractuserinfo(sess, bs, &userinfo);
-
- tlvlist = aim_readtlvchain(bs);
-
- /*
- * Depending on what informational text was requested, different
- * TLVs will appear here.
- *
- * Profile will be 1 and 2, away message will be 3 and 4, caps
- * will be 5.
- */
- if (inforeq->infotype == AIM_GETINFO_GENERALINFO) {
- text_encoding = aim_gettlv_str(tlvlist, 0x0001, 1);
- if ((tlv = aim_gettlv(tlvlist, 0x0002, 1))) {
- text = g_new0(char, tlv->length);
- memcpy(text, tlv->value, tlv->length);
- text_length = tlv->length;
- }
- } else if (inforeq->infotype == AIM_GETINFO_AWAYMESSAGE) {
- text_encoding = aim_gettlv_str(tlvlist, 0x0003, 1);
- if ((tlv = aim_gettlv(tlvlist, 0x0004, 1))) {
- text = g_new0(char, tlv->length);
- memcpy(text, tlv->value, tlv->length);
- text_length = tlv->length;
- }
- } else if (inforeq->infotype == AIM_GETINFO_CAPABILITIES) {
- aim_tlv_t *ct;
-
- if ((ct = aim_gettlv(tlvlist, 0x0005, 1))) {
- aim_bstream_t cbs;
-
- aim_bstream_init(&cbs, ct->value, ct->length);
-
- userinfo.capabilities = aim_getcap(sess, &cbs, ct->length);
- userinfo.present = AIM_USERINFO_PRESENT_CAPABILITIES;
- }
- }
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, &userinfo, inforeq->infotype, text_encoding, text, text_length);
- }
-
- g_free(text_encoding);
- g_free(text);
-
- aim_freetlvchain(&tlvlist);
-
- if (origsnac) {
- g_free(origsnac->data);
- }
- g_free(origsnac);
-
- return ret;
-}
-
-static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
-
- if (snac->subtype == 0x0003) {
- return rights(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x0006) {
- return userinfo(sess, mod, rx, snac, bs);
- }
-
- return 0;
-}
-
-int locate_modfirst(aim_session_t *sess, aim_module_t *mod)
-{
-
- mod->family = 0x0002;
- mod->version = 0x0001;
- mod->toolid = 0x0110;
- mod->toolversion = 0x0629;
- mod->flags = 0;
- strncpy(mod->name, "locate", sizeof(mod->name));
- mod->snachandler = snachandler;
-
- return 0;
-}
Index: otocols/oscar/info.h
===================================================================
--- protocols/oscar/info.h (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,42 +1,0 @@
-#ifndef __OSCAR_INFO_H__
-#define __OSCAR_INFO_H__
-
-#define AIM_CB_FAM_LOC 0x0002
-
-/*
- * SNAC Family: Location Services.
- */
-#define AIM_CB_LOC_ERROR 0x0001
-#define AIM_CB_LOC_REQRIGHTS 0x0002
-#define AIM_CB_LOC_RIGHTSINFO 0x0003
-#define AIM_CB_LOC_SETUSERINFO 0x0004
-#define AIM_CB_LOC_REQUSERINFO 0x0005
-#define AIM_CB_LOC_USERINFO 0x0006
-#define AIM_CB_LOC_WATCHERSUBREQ 0x0007
-#define AIM_CB_LOC_WATCHERNOT 0x0008
-#define AIM_CB_LOC_DEFAULT 0xffff
-
-#define AIM_CAPS_BUDDYICON 0x00000001
-#define AIM_CAPS_VOICE 0x00000002
-#define AIM_CAPS_IMIMAGE 0x00000004
-#define AIM_CAPS_CHAT 0x00000008
-#define AIM_CAPS_GETFILE 0x00000010
-#define AIM_CAPS_SENDFILE 0x00000020
-#define AIM_CAPS_GAMES 0x00000040
-#define AIM_CAPS_SAVESTOCKS 0x00000080
-#define AIM_CAPS_SENDBUDDYLIST 0x00000100
-#define AIM_CAPS_GAMES2 0x00000200
-#define AIM_CAPS_ICQ 0x00000400
-#define AIM_CAPS_APINFO 0x00000800
-#define AIM_CAPS_ICQRTF 0x00001000
-#define AIM_CAPS_EMPTY 0x00002000
-#define AIM_CAPS_ICQSERVERRELAY 0x00004000
-#define AIM_CAPS_ICQUNKNOWN 0x00008000
-#define AIM_CAPS_TRILLIANCRYPT 0x00010000
-#define AIM_CAPS_UTF8 0x00020000
-#define AIM_CAPS_INTEROP 0x00040000
-#define AIM_CAPS_ICHAT 0x00080000
-#define AIM_CAPS_EXTCHAN2 0x00100000
-#define AIM_CAPS_LAST 0x00200000
-
-#endif /* __OSCAR_INFO_H__ */
Index: otocols/oscar/misc.c
===================================================================
--- protocols/oscar/misc.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,239 +1,0 @@
-
-/*
- * aim_misc.c
- *
- * TODO: Separate a lot of this into an aim_bos.c.
- *
- * Other things...
- *
- * - Idle setting
- *
- *
- */
-
-#include
-
-/*
- * aim_bos_setprofile(profile)
- *
- * Gives BOS your profile.
- *
- */
-int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn, const char *profile, const char *awaymsg, guint32 caps)
-{
- static const char defencoding[] = { "text/aolrtf; charset=\"utf-8\"" };
- aim_frame_t *fr;
- aim_tlvlist_t *tl = NULL;
- aim_snacid_t snacid;
-
- /* Build to packet first to get real length */
- if (profile) {
- aim_addtlvtochain_raw(&tl, 0x0001, strlen(defencoding), (guint8 *) defencoding);
- aim_addtlvtochain_raw(&tl, 0x0002, strlen(profile), (guint8 *) profile);
- }
-
- /*
- * 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 (strlen(awaymsg)) {
- aim_addtlvtochain_raw(&tl, 0x0003, strlen(defencoding), (guint8 *) defencoding);
- aim_addtlvtochain_raw(&tl, 0x0004, strlen(awaymsg), (guint8 *) awaymsg);
- } else {
- aim_addtlvtochain_noval(&tl, 0x0004);
- }
- }
-
- aim_addtlvtochain_caps(&tl, 0x0005, caps);
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + aim_sizetlvchain(&tl)))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, 0x0002, 0x0004, 0x0000, NULL, 0);
-
- aim_putsnac(&fr->data, 0x0002, 0x004, 0x0000, snacid);
- aim_writetlvchain(&fr->data, &tl);
- aim_freetlvchain(&tl);
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-/*
- * aim_bos_reqbuddyrights()
- *
- * Request Buddy List rights.
- *
- */
-int aim_bos_reqbuddyrights(aim_session_t *sess, aim_conn_t *conn)
-{
- return aim_genericreq_n(sess, conn, 0x0003, 0x0002);
-}
-
-/*
- * 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.
- *
- */
-int aim_genericreq_n(aim_session_t *sess, aim_conn_t *conn, guint16 family, guint16 subtype)
-{
- aim_frame_t *fr;
- aim_snacid_t snacid = 0x00000000;
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10))) {
- return -ENOMEM;
- }
-
- aim_putsnac(&fr->data, family, subtype, 0x0000, snacid);
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-int aim_genericreq_n_snacid(aim_session_t *sess, aim_conn_t *conn, guint16 family, guint16 subtype)
-{
- aim_frame_t *fr;
- aim_snacid_t snacid;
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, family, subtype, 0x0000, NULL, 0);
- aim_putsnac(&fr->data, family, subtype, 0x0000, snacid);
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-int aim_genericreq_l(aim_session_t *sess, aim_conn_t *conn, guint16 family, guint16 subtype, guint32 *longdata)
-{
- aim_frame_t *fr;
- aim_snacid_t snacid;
-
- if (!longdata) {
- return aim_genericreq_n(sess, conn, family, subtype);
- }
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, family, subtype, 0x0000, NULL, 0);
-
- aim_putsnac(&fr->data, family, subtype, 0x0000, snacid);
- aimbs_put32(&fr->data, *longdata);
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-int aim_genericreq_s(aim_session_t *sess, aim_conn_t *conn, guint16 family, guint16 subtype, guint16 *shortdata)
-{
- aim_frame_t *fr;
- aim_snacid_t snacid;
-
- if (!shortdata) {
- return aim_genericreq_n(sess, conn, family, subtype);
- }
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 2))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, family, subtype, 0x0000, NULL, 0);
-
- aim_putsnac(&fr->data, family, subtype, 0x0000, snacid);
- aimbs_put16(&fr->data, *shortdata);
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-/*
- * aim_bos_reqlocaterights()
- *
- * Request Location services rights.
- *
- */
-int aim_bos_reqlocaterights(aim_session_t *sess, aim_conn_t *conn)
-{
- return aim_genericreq_n(sess, conn, 0x0002, 0x0002);
-}
-
-/*
- * Should be generic enough to handle the errors for all groups.
- *
- */
-static int generror(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- int ret = 0;
- int error = 0;
- aim_rxcallback_t userfunc;
- aim_snac_t *snac2;
-
- snac2 = aim_remsnac(sess, snac->id);
-
- if (aim_bstream_empty(bs)) {
- error = aimbs_get16(bs);
- }
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, error, snac2 ? snac2->data : NULL);
- }
-
- if (snac2) {
- g_free(snac2->data);
- }
- g_free(snac2);
-
- return ret;
-}
-
-static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
-
- if (snac->subtype == 0x0001) {
- return generror(sess, mod, rx, snac, bs);
- } else if ((snac->family == 0xffff) && (snac->subtype == 0xffff)) {
- aim_rxcallback_t userfunc;
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- return userfunc(sess, rx);
- }
- }
-
- return 0;
-}
-
-int misc_modfirst(aim_session_t *sess, 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;
-}
-
-
Index: otocols/oscar/msgcookie.c
===================================================================
--- protocols/oscar/msgcookie.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,172 +1,0 @@
-/*
- * 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
-#include "info.h"
-
-/**
- * aim_cachecookie - appends a cookie to the cookie list
- * @sess: session to add to
- * @cookie: pointer to struct to append
- *
- * if cookie->cookie for type cookie->type is found, updates the
- * ->addtime of the found structure; otherwise adds the given cookie
- * to the cache
- *
- * 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(aim_session_t *sess, aim_msgcookie_t *cookie)
-{
- aim_msgcookie_t *newcook;
-
- if (!sess || !cookie) {
- return -EINVAL;
- }
-
- newcook = aim_checkcookie(sess, cookie->cookie, cookie->type);
-
- if (newcook == cookie) {
- newcook->addtime = time(NULL);
- return 1;
- } else if (newcook) {
- aim_cookie_free(sess, newcook);
- }
-
- cookie->addtime = time(NULL);
-
- cookie->next = sess->msgcookies;
- sess->msgcookies = cookie;
-
- return 0;
-}
-
-/**
- * aim_uncachecookie - grabs a cookie from the cookie cache (removes it from the list)
- * @sess: session to grab cookie from
- * @cookie: cookie string to look for
- * @type: cookie type to look for
- *
- * 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.
- *
- * if found, returns the struct; if none found (or on error), returns NULL:
- */
-aim_msgcookie_t *aim_uncachecookie(aim_session_t *sess, guint8 *cookie, int type)
-{
- aim_msgcookie_t *cur, **prev;
-
- if (!cookie || !sess->msgcookies) {
- return NULL;
- }
-
- for (prev = &sess->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 aim_msgcookie_t *struct from a cookie string, a type, and a data pointer.
- * @c: pointer to the cookie string array
- * @type: cookie type to use
- * @data: data to be cached with the cookie
- *
- * returns NULL on error, a pointer to the newly-allocated cookie on
- * success.
- *
- */
-aim_msgcookie_t *aim_mkcookie(guint8 *c, int type, void *data)
-{
- aim_msgcookie_t *cookie;
-
- if (!c) {
- return NULL;
- }
-
- if (!(cookie = g_new0(aim_msgcookie_t, 1))) {
- return NULL;
- }
-
- cookie->data = data;
- cookie->type = type;
- memcpy(cookie->cookie, c, 8);
-
- return cookie;
-}
-
-/**
- * aim_checkcookie - check to see if a cookietuple has been cached
- * @sess: session to check for the cookie in
- * @cookie: pointer to the cookie string array
- * @type: type of the cookie to look for
- *
- * this returns a pointer to the cookie struct (still in the list) on
- * success; returns NULL on error/not found
- *
- */
-
-aim_msgcookie_t *aim_checkcookie(aim_session_t *sess, const guint8 *cookie, int type)
-{
- aim_msgcookie_t *cur;
-
- for (cur = sess->msgcookies; cur; cur = cur->next) {
- if ((cur->type == type) &&
- (memcmp(cur->cookie, cookie, 8) == 0)) {
- return cur;
- }
- }
-
- return NULL;
-}
-
-/**
- * aim_cookie_free - free an aim_msgcookie_t struct
- * @sess: session to remove the cookie from
- * @cookiep: the address of a pointer to the cookie struct to remove
- *
- * this function removes the cookie *cookie from the list of cookies
- * in sess, 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.
- *
- * returns -1 on error, 0 on success.
- *
- */
-int aim_cookie_free(aim_session_t *sess, aim_msgcookie_t *cookie)
-{
- aim_msgcookie_t *cur, **prev;
-
- if (!sess || !cookie) {
- return -EINVAL;
- }
-
- for (prev = &sess->msgcookies; (cur = *prev); ) {
- if (cur == cookie) {
- *prev = cur->next;
- } else {
- prev = &cur->next;
- }
- }
-
- g_free(cookie->data);
- g_free(cookie);
-
- return 0;
-}
Index: otocols/oscar/oscar.c
===================================================================
--- protocols/oscar/oscar.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,2720 +1,0 @@
-/*
- * gaim
- *
- * Some code copyright (C) 2002-2006, Jelmer Vernooij
- * and the BitlBee team.
- * Some code copyright (C) 1998-1999, Mark Spencer
- * libfaim code copyright 1998, 1999 Adam Fritzler
- *
- * 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 02110-1301 USA
- *
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "nogaim.h"
-#include "bitlbee.h"
-#include "proxy.h"
-#include "sock.h"
-
-#include "aim.h"
-#include "icq.h"
-#include "bos.h"
-#include "ssi.h"
-#include "im.h"
-#include "info.h"
-#include "buddylist.h"
-#include "chat.h"
-#include "chatnav.h"
-
-/* constants to identify proto_opts */
-#define USEROPT_AUTH 0
-#define USEROPT_AUTHPORT 1
-
-#define UC_AOL 0x02
-#define UC_ADMIN 0x04
-#define UC_UNCONFIRMED 0x08
-#define UC_NORMAL 0x10
-#define UC_AB 0x20
-#define UC_WIRELESS 0x40
-
-#define AIMHASHDATA "http://gaim.sourceforge.net/aim_data.php3"
-
-#define OSCAR_GROUP "Friends"
-
-#define BUF_LEN 2048
-#define BUF_LONG (BUF_LEN * 2)
-
-/* Don't know if support for UTF8 is really working. For now it's UTF16 here.
- static int gaim_caps = AIM_CAPS_UTF8; */
-
-static int gaim_caps = AIM_CAPS_INTEROP | AIM_CAPS_ICHAT | AIM_CAPS_ICQSERVERRELAY | AIM_CAPS_CHAT;
-static guint8 gaim_features[] = { 0x01, 0x01, 0x01, 0x02 };
-
-struct oscar_data {
- aim_session_t *sess;
- aim_conn_t *conn;
-
- guint cnpa;
- guint paspa;
-
- GSList *create_rooms;
-
- gboolean conf;
- gboolean reqemail;
- gboolean setemail;
- char *email;
- gboolean setnick;
- char *newsn;
- gboolean chpass;
- char *oldp;
- char *newp;
-
- GSList *oscar_chats;
-
- gboolean killme, no_reconnect;
- gboolean icq;
- GSList *evilhack;
-
- GHashTable *ips;
-
- struct {
- guint maxbuddies; /* max users you can watch */
- guint maxwatchers; /* max users who can watch you */
- 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;
-};
-
-struct create_room {
- char *name;
- int exchange;
-};
-
-struct chat_connection {
- char *name;
- char *show; /* AOL did something funny to us */
- guint16 exchange;
- guint16 instance;
- int fd; /* this is redundant since we have the conn below */
- aim_conn_t *conn;
- int inpa;
- int id;
- struct im_connection *ic; /* i hate this. */
- struct groupchat *cnv; /* bah. */
- int maxlen;
- int maxvis;
-};
-
-struct ask_direct {
- struct im_connection *ic;
- char *sn;
- char ip[64];
- guint8 cookie[8];
-};
-
-struct icq_auth {
- struct im_connection *ic;
- guint32 uin;
-};
-
-static char *extract_name(const char *name)
-{
- char *tmp;
- int i, j;
- char *x = strchr(name, '-');
-
- if (!x) {
- return g_strdup(name);
- }
- x = strchr(++x, '-');
- if (!x) {
- return g_strdup(name);
- }
- 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++] = (char) strtol(hex, NULL, 16);
- }
-
- tmp[j] = 0;
- return tmp;
-}
-
-static struct chat_connection *find_oscar_chat_by_conn(struct im_connection *ic,
- aim_conn_t *conn)
-{
- GSList *g = ((struct oscar_data *) ic->proto_data)->oscar_chats;
- struct chat_connection *c = NULL;
-
- while (g) {
- c = (struct chat_connection *) g->data;
- if (c->conn == conn) {
- break;
- }
- g = g->next;
- c = NULL;
- }
-
- return c;
-}
-
-static int gaim_parse_auth_resp(aim_session_t *, aim_frame_t *, ...);
-static int gaim_parse_login(aim_session_t *, aim_frame_t *, ...);
-static int gaim_parse_logout(aim_session_t *, aim_frame_t *, ...);
-static int gaim_handle_redirect(aim_session_t *, aim_frame_t *, ...);
-static int gaim_parse_oncoming(aim_session_t *, aim_frame_t *, ...);
-static int gaim_parse_offgoing(aim_session_t *, aim_frame_t *, ...);
-static int gaim_parse_incoming_im(aim_session_t *, aim_frame_t *, ...);
-static int gaim_parse_misses(aim_session_t *, aim_frame_t *, ...);
-static int gaim_parse_motd(aim_session_t *, aim_frame_t *, ...);
-static int gaim_chatnav_info(aim_session_t *, aim_frame_t *, ...);
-static int gaim_chat_join(aim_session_t *, aim_frame_t *, ...);
-static int gaim_chat_leave(aim_session_t *, aim_frame_t *, ...);
-static int gaim_chat_info_update(aim_session_t *, aim_frame_t *, ...);
-static int gaim_chat_incoming_msg(aim_session_t *, aim_frame_t *, ...);
-static int gaim_parse_ratechange(aim_session_t *, aim_frame_t *, ...);
-static int gaim_bosrights(aim_session_t *, aim_frame_t *, ...);
-static int conninitdone_bos(aim_session_t *, aim_frame_t *, ...);
-static int conninitdone_admin(aim_session_t *, aim_frame_t *, ...);
-static int conninitdone_chat(aim_session_t *, aim_frame_t *, ...);
-static int conninitdone_chatnav(aim_session_t *, aim_frame_t *, ...);
-static int gaim_parse_msgerr(aim_session_t *, aim_frame_t *, ...);
-static int gaim_parse_locaterights(aim_session_t *, aim_frame_t *, ...);
-static int gaim_parse_buddyrights(aim_session_t *, aim_frame_t *, ...);
-static int gaim_parse_locerr(aim_session_t *, aim_frame_t *, ...);
-static int gaim_icbm_param_info(aim_session_t *, aim_frame_t *, ...);
-static int gaim_parse_genericerr(aim_session_t *, aim_frame_t *, ...);
-static int gaim_selfinfo(aim_session_t *, aim_frame_t *, ...);
-static int gaim_offlinemsg(aim_session_t *, aim_frame_t *, ...);
-static int gaim_offlinemsgdone(aim_session_t *, aim_frame_t *, ...);
-static int gaim_ssi_parserights(aim_session_t *, aim_frame_t *, ...);
-static int gaim_ssi_parselist(aim_session_t *, aim_frame_t *, ...);
-static int gaim_ssi_parseack(aim_session_t *, aim_frame_t *, ...);
-static int gaim_parsemtn(aim_session_t *, aim_frame_t *, ...);
-static int gaim_icqinfo(aim_session_t *, aim_frame_t *, ...);
-static int gaim_parseaiminfo(aim_session_t *, aim_frame_t *, ...);
-
-static char *msgerrreason[] = {
- "Invalid error",
- "Invalid SNAC",
- "Rate to host",
- "Rate to client",
- "Not logged in",
- "Service unavailable",
- "Service not defined",
- "Obsolete SNAC",
- "Not supported by host",
- "Not supported by client",
- "Refused by client",
- "Reply too big",
- "Responses lost",
- "Request denied",
- "Busted SNAC payload",
- "Insufficient rights",
- "In local permit/deny",
- "Too evil (sender)",
- "Too evil (receiver)",
- "User temporarily unavailable",
- "No match",
- "List overflow",
- "Request ambiguous",
- "Queue full",
- "Not while on AOL"
-};
-static int msgerrreasonlen = 25;
-
-/* Hurray, this function is NOT thread-safe \o/ */
-static char *normalize(const char *s)
-{
- static char buf[BUF_LEN];
- char *t, *u;
- int x = 0;
-
- g_return_val_if_fail((s != NULL), NULL);
-
- u = t = g_ascii_strdown(s, -1);
-
- while (*t && (x < BUF_LEN - 1)) {
- if (*t != ' ' && *t != '!') {
- buf[x] = *t;
- x++;
- }
- t++;
- }
- buf[x] = '\0';
- g_free(u);
- return buf;
-}
-
-static gboolean oscar_callback(gpointer data, gint source,
- b_input_condition condition)
-{
- aim_conn_t *conn = (aim_conn_t *) data;
- aim_session_t *sess = aim_conn_getsess(conn);
- struct im_connection *ic = sess ? sess->aux_data : NULL;
- struct oscar_data *odata;
-
- if (!ic) {
- /* ic is null. we return, else we seg SIGSEG on next line. */
- return FALSE;
- }
-
- if (!g_slist_find(get_connections(), ic)) {
- /* oh boy. this is probably bad. i guess the only thing we
- * can really do is return? */
- return FALSE;
- }
-
- odata = (struct oscar_data *) ic->proto_data;
-
- if (condition & B_EV_IO_READ) {
- if (aim_get_command(odata->sess, conn) >= 0) {
- aim_rxdispatch(odata->sess);
- if (odata->killme) {
- imc_logout(ic, !odata->no_reconnect);
- }
- } else {
- if ((conn->type == AIM_CONN_TYPE_BOS) ||
- !(aim_getconn_type(odata->sess, AIM_CONN_TYPE_BOS))) {
- imcb_error(ic, _("Disconnected."));
- imc_logout(ic, TRUE);
- } else if (conn->type == AIM_CONN_TYPE_CHAT) {
- struct chat_connection *c = find_oscar_chat_by_conn(ic, conn);
- c->conn = NULL;
- if (c->inpa > 0) {
- b_event_remove(c->inpa);
- }
- c->inpa = 0;
- c->fd = -1;
- aim_conn_kill(odata->sess, &conn);
- imcb_error(sess->aux_data, _("You have been disconnected from chat room %s."), c->name);
- } else if (conn->type == AIM_CONN_TYPE_CHATNAV) {
- if (odata->cnpa > 0) {
- b_event_remove(odata->cnpa);
- }
- odata->cnpa = 0;
- while (odata->create_rooms) {
- struct create_room *cr = odata->create_rooms->data;
- g_free(cr->name);
- odata->create_rooms =
- g_slist_remove(odata->create_rooms, cr);
- g_free(cr);
- imcb_error(sess->aux_data, _("Chat is currently unavailable"));
- }
- aim_conn_kill(odata->sess, &conn);
- } else if (conn->type == AIM_CONN_TYPE_AUTH) {
- if (odata->paspa > 0) {
- b_event_remove(odata->paspa);
- }
- odata->paspa = 0;
- aim_conn_kill(odata->sess, &conn);
- } else {
- aim_conn_kill(odata->sess, &conn);
- }
- }
- } else {
- /* WTF??? */
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gboolean oscar_login_connect(gpointer data, gint source, b_input_condition cond)
-{
- struct im_connection *ic = data;
- struct oscar_data *odata;
- aim_session_t *sess;
- aim_conn_t *conn;
-
- if (!g_slist_find(get_connections(), ic)) {
- closesocket(source);
- return FALSE;
- }
-
- odata = ic->proto_data;
- sess = odata->sess;
- conn = aim_getconn_type_all(sess, AIM_CONN_TYPE_AUTH);
-
- if (source < 0) {
- imcb_error(ic, _("Couldn't connect to host"));
- imc_logout(ic, TRUE);
- return FALSE;
- }
-
- aim_conn_completeconnect(sess, conn);
- ic->inpa = b_input_add(conn->fd, B_EV_IO_READ,
- oscar_callback, conn);
-
- return FALSE;
-}
-
-static void oscar_init(account_t *acc)
-{
- set_t *s;
- gboolean icq = g_ascii_isdigit(acc->user[0]);
-
- if (icq) {
- set_add(&acc->set, "ignore_auth_requests", "false", set_eval_bool, acc);
- }
-
- s = set_add(&acc->set, "server",
- icq ? AIM_DEFAULT_LOGIN_SERVER_ICQ
- : AIM_DEFAULT_LOGIN_SERVER_AIM, set_eval_account, acc);
- s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
-
- if (icq) {
- s = set_add(&acc->set, "web_aware", "false", set_eval_bool, acc);
- s->flags |= ACC_SET_OFFLINE_ONLY;
- }
-
- acc->flags |= ACC_FLAG_AWAY_MESSAGE;
-}
-
-static void oscar_login(account_t *acc)
-{
- aim_session_t *sess;
- aim_conn_t *conn;
- struct im_connection *ic = imcb_new(acc);
- struct oscar_data *odata = ic->proto_data = g_new0(struct oscar_data, 1);
-
- if (g_ascii_isdigit(acc->user[0])) {
- odata->icq = TRUE;
- } else {
- ic->flags |= OPT_DOES_HTML;
- }
-
- sess = g_new0(aim_session_t, 1);
-
- aim_session_init(sess, AIM_SESS_FLAGS_NONBLOCKCONNECT, 0);
-
- /* we need an immediate queue because we don't use a while-loop to
- * see if things need to be sent. */
- aim_tx_setenqueue(sess, AIM_TX_IMMEDIATE, NULL);
- odata->sess = sess;
- sess->aux_data = ic;
-
- conn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, NULL);
- if (conn == NULL) {
- imcb_error(ic, _("Unable to login to AIM"));
- imc_logout(ic, TRUE);
- return;
- }
-
- imcb_log(ic, _("Signon: %s"), ic->acc->user);
-
- aim_conn_addhandler(sess, conn, 0x0017, 0x0007, gaim_parse_login, 0);
- aim_conn_addhandler(sess, conn, 0x0017, 0x0003, gaim_parse_auth_resp, 0);
-
- conn->status |= AIM_CONN_STATUS_INPROGRESS;
- conn->fd = proxy_connect(set_getstr(&acc->set, "server"),
- AIM_LOGIN_PORT, oscar_login_connect, ic);
- if (conn->fd < 0) {
- imcb_error(ic, _("Couldn't connect to host"));
- imc_logout(ic, TRUE);
- return;
- }
- aim_request_login(sess, conn, ic->acc->user);
-}
-
-static void oscar_logout(struct im_connection *ic)
-{
- struct oscar_data *odata = (struct oscar_data *) ic->proto_data;
-
- while (odata->oscar_chats) {
- struct chat_connection *n = odata->oscar_chats->data;
- if (n->inpa > 0) {
- b_event_remove(n->inpa);
- }
- n->inpa = 0;
- g_free(n->name);
- g_free(n->show);
- odata->oscar_chats = g_slist_remove(odata->oscar_chats, n);
- g_free(n);
- }
- while (odata->create_rooms) {
- struct create_room *cr = odata->create_rooms->data;
- g_free(cr->name);
- odata->create_rooms = g_slist_remove(odata->create_rooms, cr);
- g_free(cr);
- }
- if (odata->ips) {
- g_hash_table_destroy(odata->ips);
- }
- if (odata->email) {
- g_free(odata->email);
- }
- if (odata->newp) {
- g_free(odata->newp);
- }
- if (odata->oldp) {
- g_free(odata->oldp);
- }
- if (ic->inpa > 0) {
- b_event_remove(ic->inpa);
- ic->inpa = 0;
- }
- if (odata->cnpa > 0) {
- b_event_remove(odata->cnpa);
- odata->cnpa = 0;
- }
- if (odata->paspa > 0) {
- b_event_remove(odata->paspa);
- odata->paspa = 0;
- }
- aim_session_kill(odata->sess);
- g_free(odata->sess);
- odata->sess = NULL;
- g_free(ic->proto_data);
- ic->proto_data = NULL;
-}
-
-static gboolean oscar_bos_connect(gpointer data, gint source, b_input_condition cond)
-{
- struct im_connection *ic = data;
- struct oscar_data *odata;
- aim_session_t *sess;
- aim_conn_t *bosconn;
-
- if (!g_slist_find(get_connections(), ic)) {
- closesocket(source);
- return FALSE;
- }
-
- odata = ic->proto_data;
- sess = odata->sess;
- bosconn = odata->conn;
-
- if (source < 0) {
- imcb_error(ic, _("Could Not Connect"));
- imc_logout(ic, TRUE);
- return FALSE;
- }
-
- aim_conn_completeconnect(sess, bosconn);
- ic->inpa = b_input_add(bosconn->fd, B_EV_IO_READ,
- oscar_callback, bosconn);
- imcb_log(ic, _("Connection established, cookie sent"));
-
- return FALSE;
-}
-
-static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- va_list ap;
- struct aim_authresp_info *info;
- int i; char *host; int port;
- aim_conn_t *bosconn;
-
- struct im_connection *ic = sess->aux_data;
- struct oscar_data *od = ic->proto_data;
-
- port = AIM_LOGIN_PORT;
-
- va_start(ap, fr);
- info = va_arg(ap, struct aim_authresp_info *);
- va_end(ap);
-
- if (info->errorcode || !info->bosip || !info->cookie) {
- switch (info->errorcode) {
- case 0x05:
- /* Incorrect nick/password */
- imcb_error(ic, _("Incorrect nickname or password."));
- {
- int max = od->icq ? 8 : 16;
- if (strlen(ic->acc->pass) > max) {
- imcb_log(ic, "Note that the maximum password "
- "length supported by this protocol is "
- "%d characters, try logging in using "
- "a shorter password.", max);
- }
- }
-// plugin_event(event_error, (void *)980, 0, 0, 0);
- break;
- case 0x11:
- /* Suspended account */
- imcb_error(ic, _("Your account is currently suspended."));
- break;
- case 0x18:
- /* connecting too frequently */
- od->no_reconnect = TRUE;
- imcb_error(ic,
- _(
- "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."));
- break;
- case 0x1c:
- /* client too old */
- imcb_error(ic, _("The client version you are using is too old. Please upgrade at " WEBSITE));
- break;
- default:
- imcb_error(ic, _("Authentication Failed"));
- break;
- }
- od->killme = TRUE;
- return 1;
- }
-
-
- aim_conn_kill(sess, &fr->conn);
-
- bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, NULL);
- if (bosconn == NULL) {
- imcb_error(ic, _("Internal Error"));
- od->killme = TRUE;
- return 0;
- }
-
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_bos, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BOS, AIM_CB_BOS_RIGHTS, gaim_bosrights, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ACK, AIM_CB_ACK_ACK, NULL, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT, gaim_handle_redirect, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_RIGHTSINFO, gaim_parse_locaterights, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO, gaim_parse_buddyrights, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING, gaim_parse_oncoming, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING, gaim_parse_offgoing, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, gaim_parse_incoming_im, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR, gaim_parse_locerr, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL, gaim_parse_misses, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE, gaim_parse_ratechange, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR, gaim_parse_msgerr, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, gaim_parse_motd, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_PARAMINFO, gaim_icbm_param_info, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_ERROR, gaim_parse_genericerr, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ERROR, gaim_parse_genericerr, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BOS, AIM_CB_BOS_ERROR, gaim_parse_genericerr, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SELFINFO, gaim_selfinfo, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG, gaim_offlinemsg, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE, gaim_offlinemsgdone, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_INFO, gaim_icqinfo, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_RIGHTSINFO, gaim_ssi_parserights, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_LIST, gaim_ssi_parselist, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_SRVACK, gaim_ssi_parseack, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, gaim_parseaiminfo, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MTN, gaim_parsemtn, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, gaim_parse_logout, 0);
-
- ((struct oscar_data *) ic->proto_data)->conn = bosconn;
- for (i = 0; i < (int) strlen(info->bosip); i++) {
- if (info->bosip[i] == ':') {
- port = atoi(&(info->bosip[i + 1]));
- break;
- }
- }
- host = g_strndup(info->bosip, i);
- bosconn->status |= AIM_CONN_STATUS_INPROGRESS;
- bosconn->fd = proxy_connect(host, port, oscar_bos_connect, ic);
- g_free(host);
- if (bosconn->fd < 0) {
- imcb_error(ic, _("Could Not Connect"));
- od->killme = TRUE;
- return 0;
- }
- aim_sendcookie(sess, bosconn, info->cookie);
- b_event_remove(ic->inpa);
- ic->inpa = 0;
-
- return 1;
-}
-
-/* size of icbmui.ocm, the largest module in AIM 3.5 */
-#define AIM_MAX_FILE_SIZE 98304
-
-static int gaim_parse_login(aim_session_t *sess, aim_frame_t *fr, ...)
-{
-#if 0
- struct client_info_s info = { "gaim", 4, 1, 2010, "us", "en", 0x0004, 0x0000, 0x04b };
-#else
- struct client_info_s info = AIM_CLIENTINFO_KNOWNGOOD;
-#endif
- char *key;
- va_list ap;
- struct im_connection *ic = sess->aux_data;
-
- va_start(ap, fr);
- key = va_arg(ap, char *);
- va_end(ap);
-
- aim_send_login(sess, fr->conn, ic->acc->user, ic->acc->pass, &info, key);
-
- return 1;
-}
-
-static int gaim_parse_logout(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- struct im_connection *ic = sess->aux_data;
- struct oscar_data *odata = ic->proto_data;
- int code;
- va_list ap;
-
- va_start(ap, fr);
- code = va_arg(ap, int);
- va_end(ap);
-
- imcb_error(ic, "Connection aborted by server: %s", code == 1 ?
- "someone else logged in with your account" :
- "unknown reason");
-
- /* Tell BitlBee to disable auto_reconnect if code == 1, since that
- means a concurrent login somewhere else. */
- odata->no_reconnect = code == 1;
-
- /* DO NOT log out here! Just tell the callback to do it. */
- odata->killme = TRUE;
-
- return 1;
-}
-
-static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- struct im_connection *ic = sess->aux_data;
- struct chat_connection *chatcon;
- struct groupchat *c = NULL;
- static int id = 1;
-
- aim_conn_addhandler(sess, fr->conn, 0x000e, 0x0001, gaim_parse_genericerr, 0);
- aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, gaim_chat_join, 0);
- aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, gaim_chat_leave, 0);
- aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, gaim_chat_info_update, 0);
- aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, gaim_chat_incoming_msg, 0);
-
- aim_clientready(sess, fr->conn);
-
- chatcon = find_oscar_chat_by_conn(ic, fr->conn);
- chatcon->id = id;
-
- c = bee_chat_by_title(ic->bee, ic, chatcon->show);
- if (c && !c->data) {
- chatcon->cnv = c;
- } else {
- chatcon->cnv = imcb_chat_new(ic, chatcon->show);
- }
- chatcon->cnv->data = chatcon;
-
- return 1;
-}
-
-static int conninitdone_chatnav(aim_session_t *sess, aim_frame_t *fr, ...)
-{
-
- aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CTN, AIM_CB_CTN_ERROR, gaim_parse_genericerr, 0);
- aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CTN, AIM_CB_CTN_INFO, gaim_chatnav_info, 0);
-
- aim_clientready(sess, fr->conn);
-
- aim_chatnav_reqrights(sess, fr->conn);
-
- return 1;
-}
-
-static gboolean oscar_chatnav_connect(gpointer data, gint source, b_input_condition cond)
-{
- struct im_connection *ic = data;
- struct oscar_data *odata;
- aim_session_t *sess;
- aim_conn_t *tstconn;
-
- if (!g_slist_find(get_connections(), ic)) {
- closesocket(source);
- return FALSE;
- }
-
- odata = ic->proto_data;
- sess = odata->sess;
- tstconn = aim_getconn_type_all(sess, AIM_CONN_TYPE_CHATNAV);
-
- if (source < 0) {
- aim_conn_kill(sess, &tstconn);
- return FALSE;
- }
-
- aim_conn_completeconnect(sess, tstconn);
- odata->cnpa = b_input_add(tstconn->fd, B_EV_IO_READ,
- oscar_callback, tstconn);
-
- return FALSE;
-}
-
-static gboolean oscar_auth_connect(gpointer data, gint source, b_input_condition cond)
-{
- struct im_connection *ic = data;
- struct oscar_data *odata;
- aim_session_t *sess;
- aim_conn_t *tstconn;
-
- if (!g_slist_find(get_connections(), ic)) {
- closesocket(source);
- return FALSE;
- }
-
- odata = ic->proto_data;
- sess = odata->sess;
- tstconn = aim_getconn_type_all(sess, AIM_CONN_TYPE_AUTH);
-
- if (source < 0) {
- aim_conn_kill(sess, &tstconn);
- return FALSE;
- }
-
- aim_conn_completeconnect(sess, tstconn);
- odata->paspa = b_input_add(tstconn->fd, B_EV_IO_READ,
- oscar_callback, tstconn);
-
- return FALSE;
-}
-
-static gboolean oscar_chat_connect(gpointer data, gint source, b_input_condition cond)
-{
- struct chat_connection *ccon = data;
- struct im_connection *ic = ccon->ic;
- struct oscar_data *odata;
- aim_session_t *sess;
- aim_conn_t *tstconn;
-
- if (!g_slist_find(get_connections(), ic)) {
- closesocket(source);
- g_free(ccon->show);
- g_free(ccon->name);
- g_free(ccon);
- return FALSE;
- }
-
- odata = ic->proto_data;
- sess = odata->sess;
- tstconn = ccon->conn;
-
- if (source < 0) {
- aim_conn_kill(sess, &tstconn);
- g_free(ccon->show);
- g_free(ccon->name);
- g_free(ccon);
- return FALSE;
- }
-
- aim_conn_completeconnect(sess, ccon->conn);
- ccon->inpa = b_input_add(tstconn->fd,
- B_EV_IO_READ,
- oscar_callback, tstconn);
- odata->oscar_chats = g_slist_append(odata->oscar_chats, ccon);
-
- return FALSE;
-}
-
-/* Hrmph. I don't know how to make this look better. --mid */
-static int gaim_handle_redirect(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- va_list ap;
- struct aim_redirect_data *redir;
- struct im_connection *ic = sess->aux_data;
- aim_conn_t *tstconn;
- int i;
- char *host;
- int port;
-
- va_start(ap, fr);
- redir = va_arg(ap, struct aim_redirect_data *);
- va_end(ap);
-
- port = AIM_LOGIN_PORT;
- for (i = 0; i < (int) strlen(redir->ip); i++) {
- if (redir->ip[i] == ':') {
- port = atoi(&(redir->ip[i + 1]));
- break;
- }
- }
- host = g_strndup(redir->ip, i);
-
- switch (redir->group) {
- case 0x7: /* Authorizer */
- tstconn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, NULL);
- if (tstconn == NULL) {
- g_free(host);
- return 1;
- }
- aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_admin,
- 0);
-// aim_conn_addhandler(sess, tstconn, 0x0007, 0x0003, gaim_info_change, 0);
-// aim_conn_addhandler(sess, tstconn, 0x0007, 0x0005, gaim_info_change, 0);
-// aim_conn_addhandler(sess, tstconn, 0x0007, 0x0007, gaim_account_confirm, 0);
-
- tstconn->status |= AIM_CONN_STATUS_INPROGRESS;
- tstconn->fd = proxy_connect(host, port, oscar_auth_connect, ic);
- if (tstconn->fd < 0) {
- aim_conn_kill(sess, &tstconn);
- g_free(host);
- return 1;
- }
- aim_sendcookie(sess, tstconn, redir->cookie);
- break;
- case 0xd: /* ChatNav */
- tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHATNAV, NULL);
- if (tstconn == NULL) {
- g_free(host);
- return 1;
- }
- aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE,
- conninitdone_chatnav, 0);
-
- tstconn->status |= AIM_CONN_STATUS_INPROGRESS;
- tstconn->fd = proxy_connect(host, port, oscar_chatnav_connect, ic);
- if (tstconn->fd < 0) {
- aim_conn_kill(sess, &tstconn);
- g_free(host);
- return 1;
- }
- aim_sendcookie(sess, tstconn, redir->cookie);
- break;
- case 0xe: /* Chat */
- {
- struct chat_connection *ccon;
-
- tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, NULL);
- if (tstconn == NULL) {
- g_free(host);
- return 1;
- }
-
- aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat,
- 0);
-
- ccon = g_new0(struct chat_connection, 1);
- ccon->conn = tstconn;
- ccon->ic = ic;
- ccon->fd = -1;
- ccon->name = g_strdup(redir->chat.room);
- ccon->exchange = redir->chat.exchange;
- ccon->instance = redir->chat.instance;
- ccon->show = extract_name(redir->chat.room);
-
- ccon->conn->status |= AIM_CONN_STATUS_INPROGRESS;
- ccon->conn->fd = proxy_connect(host, port, oscar_chat_connect, ccon);
- if (ccon->conn->fd < 0) {
- aim_conn_kill(sess, &tstconn);
- g_free(host);
- g_free(ccon->show);
- g_free(ccon->name);
- g_free(ccon);
- return 1;
- }
- aim_sendcookie(sess, tstconn, redir->cookie);
- }
- break;
- default: /* huh? */
- break;
- }
-
- g_free(host);
- return 1;
-}
-
-static int gaim_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- struct im_connection *ic = sess->aux_data;
- struct oscar_data *od = ic->proto_data;
- aim_userinfo_t *info;
- time_t time_idle = 0, signon = 0;
- int flags = OPT_LOGGED_IN;
- char *tmp, *state_string = NULL;
-
- va_list ap;
-
- va_start(ap, fr);
- info = va_arg(ap, aim_userinfo_t *);
- va_end(ap);
-
- if ((!od->icq) && (info->present & AIM_USERINFO_PRESENT_FLAGS)) {
- if (info->flags & AIM_FLAG_AWAY) {
- flags |= OPT_AWAY;
- }
- }
-
- /* Maybe this should be done just for AIM contacts, not sure. */
- if (info->flags & AIM_FLAG_WIRELESS) {
- flags |= OPT_MOBILE;
- }
-
- if (info->present & AIM_USERINFO_PRESENT_ICQEXTSTATUS) {
- if (!(info->icqinfo.status & AIM_ICQ_STATE_CHAT) &&
- (info->icqinfo.status != AIM_ICQ_STATE_NORMAL)) {
- flags |= OPT_AWAY;
- }
-
- if (info->icqinfo.status & AIM_ICQ_STATE_DND) {
- state_string = "Do Not Disturb";
- } else if (info->icqinfo.status & AIM_ICQ_STATE_OUT) {
- state_string = "Not Available";
- } else if (info->icqinfo.status & AIM_ICQ_STATE_BUSY) {
- state_string = "Occupied";
- } else if (info->icqinfo.status & AIM_ICQ_STATE_INVISIBLE) {
- state_string = "Invisible";
- }
- }
-
- if (info->present & AIM_USERINFO_PRESENT_IDLE) {
- time(&time_idle);
- time_idle -= info->idletime * 60;
- }
-
- if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN) {
- signon = time(NULL) - info->sessionlen;
- }
-
- if (info->present & AIM_USERINFO_PRESENT_ICQIPADDR) {
- uint32_t *uin = g_new0(uint32_t, 1);
-
- if (od->ips == NULL) {
- od->ips = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, NULL);
- }
-
- if (sscanf(info->sn, "%d", uin) == 1) {
- g_hash_table_insert(od->ips, uin, (gpointer) (long) info->icqinfo.ipaddr);
- }
- }
-
- tmp = normalize(info->sn);
- imcb_buddy_status(ic, tmp, flags, state_string, NULL);
- imcb_buddy_times(ic, tmp, signon, time_idle);
-
-
- return 1;
-}
-
-static int gaim_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- aim_userinfo_t *info;
- va_list ap;
- struct im_connection *ic = sess->aux_data;
-
- va_start(ap, fr);
- info = va_arg(ap, aim_userinfo_t *);
- va_end(ap);
-
- imcb_buddy_status(ic, normalize(info->sn), 0, NULL, NULL);
-
- return 1;
-}
-
-static int incomingim_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo,
- struct aim_incomingim_ch1_args *args)
-{
- char *tmp = g_malloc(BUF_LONG + 1);
- struct im_connection *ic = sess->aux_data;
- int flags = 0;
-
- if (args->icbmflags & AIM_IMFLAGS_AWAY) {
- flags |= OPT_AWAY;
- }
-
- if ((args->icbmflags & AIM_IMFLAGS_UNICODE) || (args->icbmflags & AIM_IMFLAGS_ISO_8859_1)) {
- char *src;
-
- if (args->icbmflags & AIM_IMFLAGS_UNICODE) {
- src = "UCS-2BE";
- } else {
- src = "ISO8859-1";
- }
-
- /* Try to use iconv first to convert the message to UTF8 - which is what BitlBee expects */
- if (do_iconv(src, "UTF-8", args->msg, tmp, args->msglen, BUF_LONG) >= 0) {
- // Successfully converted!
- } else if (args->icbmflags & AIM_IMFLAGS_UNICODE) {
- int i;
-
- for (i = 0, tmp[0] = '\0'; i < args->msglen; i += 2) {
- unsigned short uni;
-
- uni = ((args->msg[i] & 0xff) << 8) | (args->msg[i + 1] & 0xff);
-
- if ((uni < 128) || ((uni >= 160) && (uni <= 255))) { /* ISO 8859-1 */
- g_snprintf(tmp + strlen(tmp), BUF_LONG - strlen(tmp), "%c", uni);
- } else { /* something else, do UNICODE entity */
- g_snprintf(tmp + strlen(tmp), BUF_LONG - strlen(tmp), "%04x;", uni);
- }
- }
- } else {
- g_snprintf(tmp, BUF_LONG, "%s", args->msg);
- }
- } else if (args->mpmsg.numparts == 0) {
- g_snprintf(tmp, BUF_LONG, "%s", args->msg);
- } else {
- aim_mpmsg_section_t *part;
-
- *tmp = 0;
- for (part = args->mpmsg.parts; part; part = part->next) {
- if (part->data) {
- g_strlcat(tmp, (char *) part->data, BUF_LONG);
- g_strlcat(tmp, "\n", BUF_LONG);
- }
- }
- }
-
- strip_linefeed(tmp);
- imcb_buddy_msg(ic, normalize(userinfo->sn), tmp, flags, 0);
- g_free(tmp);
-
- return 1;
-}
-
-void oscar_accept_chat(void *data);
-void oscar_reject_chat(void *data);
-
-static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo,
- struct aim_incomingim_ch2_args *args)
-{
- struct im_connection *ic = sess->aux_data;
-
- if (args->status != AIM_RENDEZVOUS_PROPOSE) {
- return 1;
- }
-
- if (args->reqclass & AIM_CAPS_CHAT) {
- char *name = extract_name(args->info.chat.roominfo.name);
- int *exch = g_new0(int, 1);
- GList *m = NULL;
- char txt[1024];
- struct aim_chat_invitation * inv = g_new0(struct aim_chat_invitation, 1);
-
- m = g_list_append(m, g_strdup(name ? name : args->info.chat.roominfo.name));
- *exch = args->info.chat.roominfo.exchange;
- m = g_list_append(m, exch);
-
- g_snprintf(txt, 1024, "Got an invitation to chatroom %s from %s: %s", name, userinfo->sn, args->msg);
-
- inv->ic = ic;
- inv->exchange = *exch;
- inv->name = g_strdup(name);
-
- imcb_ask(ic, txt, inv, oscar_accept_chat, oscar_reject_chat);
-
- if (name) {
- g_free(name);
- }
- } else if (args->reqclass & AIM_CAPS_ICQRTF) {
- // TODO: constify
- char text[strlen(args->info.rtfmsg.rtfmsg) + 1];
- strncpy(text, args->info.rtfmsg.rtfmsg, sizeof(text));
- imcb_buddy_msg(ic, normalize(userinfo->sn), text, 0, 0);
- }
-
- return 1;
-}
-
-static void gaim_icq_authgrant(void *data_)
-{
- struct icq_auth *data = data_;
- char *uin;
- struct oscar_data *od = (struct oscar_data *) data->ic->proto_data;
-
- uin = g_strdup_printf("%u", data->uin);
- aim_ssi_auth_reply(od->sess, od->conn, uin, 1, "");
- // char *message = 0;
- // aim_send_im_ch4(od->sess, uin, AIM_ICQMSG_AUTHGRANTED, &message);
- imcb_ask_add(data->ic, uin, NULL);
-
- g_free(uin);
- g_free(data);
-}
-
-static void gaim_icq_authdeny(void *data_)
-{
- struct icq_auth *data = data_;
- char *uin, *message;
- struct oscar_data *od = (struct oscar_data *) data->ic->proto_data;
-
- uin = g_strdup_printf("%u", data->uin);
- message = g_strdup_printf("No reason given.");
- aim_ssi_auth_reply(od->sess, od->conn, uin, 0, "");
- // aim_send_im_ch4(od->sess, uin, AIM_ICQMSG_AUTHDENIED, message);
- g_free(message);
-
- g_free(uin);
- g_free(data);
-}
-
-/*
- * For when other people ask you for authorization
- */
-static void gaim_icq_authask(struct im_connection *ic, guint32 uin, char *msg)
-{
- struct icq_auth *data;
- char *reason = NULL;
- char *dialog_msg;
-
- if (set_getbool(&ic->acc->set, "ignore_auth_requests")) {
- return;
- }
-
- data = g_new(struct icq_auth, 1);
-
- if (strlen(msg) > 6) {
- reason = msg + 6;
- }
-
- dialog_msg = g_strdup_printf("The user %u wants to add you to their buddy list for the following reason: %s",
- uin, reason ? reason : "No reason given.");
- data->ic = ic;
- data->uin = uin;
- imcb_ask(ic, dialog_msg, data, gaim_icq_authgrant, gaim_icq_authdeny);
- g_free(dialog_msg);
-}
-
-static int incomingim_chan4(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo,
- struct aim_incomingim_ch4_args *args)
-{
- struct im_connection *ic = sess->aux_data;
-
- switch (args->type) {
- case 0x0001: { /* An almost-normal instant message. Mac ICQ sends this. It's peculiar. */
- char *uin, *message;
- uin = g_strdup_printf("%u", args->uin);
- message = g_strdup(args->msg);
- strip_linefeed(message);
- imcb_buddy_msg(ic, normalize(uin), message, 0, 0);
- g_free(uin);
- g_free(message);
- } break;
-
- case 0x0004: { /* Someone sent you a URL */
- char *uin, *message;
- char **m;
-
- uin = g_strdup_printf("%u", args->uin);
- m = g_strsplit(args->msg, "\376", 2);
-
- if ((strlen(m[0]) != 0)) {
- message = g_strjoinv(" -- ", m);
- } else {
- message = m[1];
- }
-
- strip_linefeed(message);
- imcb_buddy_msg(ic, normalize(uin), message, 0, 0);
- g_free(uin);
- g_free(m);
- g_free(message);
- } break;
-
- case 0x0006: { /* Someone requested authorization */
- gaim_icq_authask(ic, args->uin, args->msg);
- } break;
-
- case 0x0007: { /* Someone has denied you authorization */
- imcb_log(sess->aux_data,
- "The user %u has denied your request to add them to your contact list for the following reason:\n%s", args->uin,
- args->msg ? args->msg : _("No reason given."));
- } break;
-
- case 0x0008: { /* Someone has granted you authorization */
- imcb_log(sess->aux_data,
- "The user %u has granted your request to add them to your contact list for the following reason:\n%s", args->uin,
- args->msg ? args->msg : _("No reason given."));
- } break;
-
- case 0x0012: {
- /* Ack for authorizing/denying someone. Or possibly an ack for sending any system notice */
- } break;
-
- default: {; } break;
- }
-
- return 1;
-}
-
-static int gaim_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- int channel, ret = 0;
- aim_userinfo_t *userinfo;
- va_list ap;
-
- va_start(ap, fr);
- channel = va_arg(ap, 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(sess, fr->conn, userinfo, args);
- } break;
-
- case 2: { /* rendezvous */
- struct aim_incomingim_ch2_args *args;
- args = va_arg(ap, struct aim_incomingim_ch2_args *);
- ret = incomingim_chan2(sess, fr->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(sess, fr->conn, userinfo, args);
- } break;
-
- default: {; } break;
- }
-
- va_end(ap);
-
- return ret;
-}
-
-static int gaim_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- va_list ap;
- guint16 nummissed, reason;
- aim_userinfo_t *userinfo;
-
- va_start(ap, fr);
- va_arg(ap, unsigned int); /* 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) */
- imcb_error(sess->aux_data,
- nummissed == 1 ?
- _("You missed %d message from %s because it was invalid.") :
- _("You missed %d messages from %s because they were invalid."),
- nummissed,
- userinfo->sn);
- break;
- case 1:
- /* Message too large */
- imcb_error(sess->aux_data,
- nummissed == 1 ?
- _("You missed %d message from %s because it was too large.") :
- _("You missed %d messages from %s because they were too large."),
- nummissed,
- userinfo->sn);
- break;
- case 2:
- /* Rate exceeded */
- imcb_error(sess->aux_data,
- nummissed == 1 ?
- _("You missed %d message from %s because the rate limit has been exceeded.") :
- _("You missed %d messages from %s because the rate limit has been exceeded."),
- nummissed,
- userinfo->sn);
- break;
- case 3:
- /* Evil Sender */
- imcb_error(sess->aux_data,
- nummissed == 1 ?
- _("You missed %d message from %s because it was too evil.") :
- _("You missed %d messages from %s because they are too evil."),
- nummissed,
- userinfo->sn);
- break;
- case 4:
- /* Evil Receiver */
- imcb_error(sess->aux_data,
- nummissed == 1 ?
- _("You missed %d message from %s because you are too evil.") :
- _("You missed %d messages from %s because you are too evil."),
- nummissed,
- userinfo->sn);
- break;
- default:
- imcb_error(sess->aux_data,
- nummissed == 1 ?
- _("You missed %d message from %s for unknown reasons.") :
- _("You missed %d messages from %s for unknown reasons."),
- nummissed,
- userinfo->sn);
- break;
- }
-
- return 1;
-}
-
-static int gaim_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- va_list ap;
- guint16 reason;
-
- va_start(ap, fr);
- reason = (guint16) va_arg(ap, unsigned int);
- va_end(ap);
-
- imcb_error(sess->aux_data, _("SNAC threw error: %s"),
- reason < msgerrreasonlen ? msgerrreason[reason] : "Unknown error");
-
- return 1;
-}
-
-static int gaim_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- va_list ap;
- char *destn;
- guint16 reason;
-
- va_start(ap, fr);
- reason = (guint16) va_arg(ap, unsigned int);
- destn = va_arg(ap, char *);
- va_end(ap);
-
- imcb_error(sess->aux_data, _("Your message to %s did not get sent: %s"), destn,
- (reason < msgerrreasonlen) ? msgerrreason[reason] : _("Reason unknown"));
-
- return 1;
-}
-
-static int gaim_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- va_list ap;
- char *destn;
- guint16 reason;
-
- va_start(ap, fr);
- reason = (guint16) va_arg(ap, unsigned int);
- destn = va_arg(ap, char *);
- va_end(ap);
-
- imcb_error(sess->aux_data, _("User information for %s unavailable: %s"), destn,
- (reason < msgerrreasonlen) ? msgerrreason[reason] : _("Reason unknown"));
-
- return 1;
-}
-
-static int gaim_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- guint16 id;
- va_list ap;
-
- va_start(ap, fr);
- id = (guint16) va_arg(ap, unsigned int);
- va_arg(ap, char *); /* msg */
- va_end(ap);
-
- if (id < 4) {
- imcb_error(sess->aux_data, _("Your connection may be lost."));
- }
-
- return 1;
-}
-
-static int gaim_chatnav_info(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- va_list ap;
- guint16 type;
- struct im_connection *ic = sess->aux_data;
- struct oscar_data *odata = (struct oscar_data *) ic->proto_data;
-
- va_start(ap, fr);
- type = (guint16) va_arg(ap, unsigned int);
-
- switch (type) {
- case 0x0002: {
- va_arg(ap, unsigned int); /* maxrooms */
- va_arg(ap, int); /* exchangecount */
- va_arg(ap, struct aim_chat_exchangeinfo *); /* exchanges */
- va_end(ap);
-
- while (odata->create_rooms) {
- struct create_room *cr = odata->create_rooms->data;
- aim_chatnav_createroom(sess, fr->conn, cr->name, cr->exchange);
- g_free(cr->name);
- odata->create_rooms = g_slist_remove(odata->create_rooms, cr);
- g_free(cr);
- }
- }
- break;
- case 0x0008: {
- char *ck;
- guint16 instance, exchange;
-
- va_arg(ap, char *); /* fqcn */
- instance = (guint16) va_arg(ap, unsigned int);
- exchange = (guint16) va_arg(ap, unsigned int);
- va_arg(ap, unsigned int); /* flags */
- va_arg(ap, guint32); /* createtime */
- va_arg(ap, unsigned int); /* maxmsglen */
- va_arg(ap, unsigned int); /* maxoccupancy */
- va_arg(ap, int); /* createperms */
- va_arg(ap, unsigned int); /* unknown */
- va_arg(ap, char *); /* name */
- ck = va_arg(ap, char *);
- va_end(ap);
-
- aim_chat_join(odata->sess, odata->conn, exchange, ck, instance);
- }
- break;
- default:
- va_end(ap);
- break;
- }
- return 1;
-}
-
-static int gaim_chat_join(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- va_list ap;
- int count, i;
- aim_userinfo_t *info;
- struct im_connection *g = sess->aux_data;
-
- 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(g, fr->conn);
- if (!c) {
- return 1;
- }
-
- for (i = 0; i < count; i++) {
- imcb_chat_add_buddy(c->cnv, normalize(info[i].sn));
- }
-
- return 1;
-}
-
-static int gaim_chat_leave(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- va_list ap;
- int count, i;
- aim_userinfo_t *info;
- struct im_connection *g = sess->aux_data;
-
- 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(g, fr->conn);
- if (!c) {
- return 1;
- }
-
- for (i = 0; i < count; i++) {
- imcb_chat_remove_buddy(c->cnv, normalize(info[i].sn), NULL);
- }
-
- return 1;
-}
-
-static int gaim_chat_info_update(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- va_list ap;
- guint16 maxmsglen, maxvisiblemsglen;
- struct im_connection *ic = sess->aux_data;
- struct chat_connection *ccon = find_oscar_chat_by_conn(ic, fr->conn);
-
- va_start(ap, fr);
- va_arg(ap, struct aim_chat_roominfo *); /* roominfo */
- va_arg(ap, char *); /* roomname */
- va_arg(ap, int); /* usercount */
- va_arg(ap, aim_userinfo_t *); /* userinfo */
- va_arg(ap, char *); /* roomdesc */
- va_arg(ap, int); /* unknown_c9 */
- va_arg(ap, unsigned long); /* creationtime */
- maxmsglen = (guint16) va_arg(ap, int);
- va_arg(ap, int); /* unknown_d2 */
- va_arg(ap, int); /* unknown_d5 */
- maxvisiblemsglen = (guint16) va_arg(ap, int);
- va_end(ap);
-
- ccon->maxlen = maxmsglen;
- ccon->maxvis = maxvisiblemsglen;
-
- return 1;
-}
-
-static int gaim_chat_incoming_msg(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- va_list ap;
- aim_userinfo_t *info;
- char *msg;
- struct im_connection *ic = sess->aux_data;
- struct chat_connection *ccon = find_oscar_chat_by_conn(ic, fr->conn);
- char *tmp;
-
- va_start(ap, fr);
- info = va_arg(ap, aim_userinfo_t *);
- msg = va_arg(ap, char *);
-
- tmp = g_malloc(BUF_LONG);
- g_snprintf(tmp, BUF_LONG, "%s", msg);
- imcb_chat_msg(ccon->cnv, normalize(info->sn), tmp, 0, 0);
- g_free(tmp);
-
- return 1;
-}
-
-static int gaim_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...)
-{
-#if 0
- static const char *codes[5] = {
- "invalid",
- "change",
- "warning",
- "limit",
- "limit cleared",
- };
-#endif
- va_list ap;
- guint16 code;
- guint32 windowsize, clear, currentavg;
-
- va_start(ap, fr);
- code = (guint16) va_arg(ap, unsigned int);
- va_arg(ap, unsigned int); /* rateclass */
- windowsize = (guint32) va_arg(ap, unsigned long);
- clear = (guint32) va_arg(ap, unsigned long);
- va_arg(ap, unsigned long); /* alert */
- va_arg(ap, unsigned long); /* limit */
- va_arg(ap, unsigned long); /* disconnect */
- currentavg = (guint32) va_arg(ap, unsigned long);
- va_arg(ap, unsigned long); /* maxavg */
- va_end(ap);
-
- /* XXX fix these values */
- if (code == AIM_RATE_CODE_CHANGE) {
- if (currentavg >= clear) {
- aim_conn_setlatency(fr->conn, 0);
- }
- } else if (code == AIM_RATE_CODE_WARNING) {
- aim_conn_setlatency(fr->conn, windowsize / 4);
- } else if (code == AIM_RATE_CODE_LIMIT) {
- imcb_error(sess->aux_data, _("The last message was not sent because you are over the rate limit. "
- "Please wait 10 seconds and try again."));
- aim_conn_setlatency(fr->conn, windowsize / 2);
- } else if (code == AIM_RATE_CODE_CLEARLIMIT) {
- aim_conn_setlatency(fr->conn, 0);
- }
-
- return 1;
-}
-
-static int gaim_selfinfo(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- return 1;
-}
-
-static int conninitdone_bos(aim_session_t *sess, aim_frame_t *fr, ...)
-{
-
- aim_reqpersonalinfo(sess, fr->conn);
- aim_bos_reqlocaterights(sess, fr->conn);
- aim_bos_reqbuddyrights(sess, fr->conn);
-
- aim_reqicbmparams(sess);
-
- aim_bos_reqrights(sess, fr->conn);
- aim_bos_setgroupperm(sess, fr->conn, AIM_FLAG_ALLUSERS);
- aim_bos_setprivacyflags(sess, fr->conn, AIM_PRIVFLAGS_ALLOWIDLE |
- AIM_PRIVFLAGS_ALLOWMEMBERSINCE);
-
- return 1;
-}
-
-static int conninitdone_admin(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- struct im_connection *ic = sess->aux_data;
- struct oscar_data *od = ic->proto_data;
-
- aim_clientready(sess, fr->conn);
-
- if (od->chpass) {
- aim_admin_changepasswd(sess, fr->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) {
- aim_admin_setnick(sess, fr->conn, od->newsn);
- g_free(od->newsn);
- od->newsn = NULL;
- od->setnick = FALSE;
- }
- if (od->conf) {
- aim_admin_reqconfirm(sess, fr->conn);
- od->conf = FALSE;
- }
- if (od->reqemail) {
- aim_admin_getinfo(sess, fr->conn, 0x0011);
- od->reqemail = FALSE;
- }
- if (od->setemail) {
- aim_admin_setemail(sess, fr->conn, od->email);
- g_free(od->email);
- od->setemail = FALSE;
- }
-
- return 1;
-}
-
-static int gaim_icbm_param_info(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- struct aim_icbmparameters *params;
- va_list ap;
-
- va_start(ap, fr);
- params = va_arg(ap, struct aim_icbmparameters *);
- va_end(ap);
-
- /* Maybe senderwarn and recverwarn should be user preferences... */
- params->flags = 0x0000000b;
- params->maxmsglen = 8000;
- params->minmsginterval = 0;
-
- aim_seticbmparam(sess, params);
-
- return 1;
-}
-
-static int gaim_parse_locaterights(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- va_list ap;
- guint16 maxsiglen;
- struct im_connection *ic = sess->aux_data;
- struct oscar_data *odata = (struct oscar_data *) ic->proto_data;
-
- va_start(ap, fr);
- maxsiglen = va_arg(ap, int);
- va_end(ap);
-
- odata->rights.maxsiglen = odata->rights.maxawaymsglen = (guint) maxsiglen;
-
- /* FIXME: It seems we're not really using this, and it broke now that
- struct aim_user is dead.
- aim_bos_setprofile(sess, fr->conn, ic->user->user_info, NULL, gaim_caps);
- */
-
- return 1;
-}
-
-static int gaim_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- va_list ap;
- guint16 maxbuddies, maxwatchers;
- struct im_connection *ic = sess->aux_data;
- struct oscar_data *odata = (struct oscar_data *) ic->proto_data;
-
- va_start(ap, fr);
- maxbuddies = (guint16) va_arg(ap, unsigned int);
- maxwatchers = (guint16) va_arg(ap, unsigned int);
- va_end(ap);
-
- odata->rights.maxbuddies = (guint) maxbuddies;
- odata->rights.maxwatchers = (guint) maxwatchers;
-
- return 1;
-}
-
-static int gaim_bosrights(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- guint16 maxpermits, maxdenies;
- va_list ap;
- struct im_connection *ic = sess->aux_data;
- struct oscar_data *odata = (struct oscar_data *) ic->proto_data;
-
- va_start(ap, fr);
- maxpermits = (guint16) va_arg(ap, unsigned int);
- maxdenies = (guint16) va_arg(ap, unsigned int);
- va_end(ap);
-
- odata->rights.maxpermits = (guint) maxpermits;
- odata->rights.maxdenies = (guint) maxdenies;
-
- aim_clientready(sess, fr->conn);
-
- aim_reqservice(sess, fr->conn, AIM_CONN_TYPE_CHATNAV);
-
- aim_ssi_reqrights(sess, fr->conn);
- aim_ssi_reqalldata(sess, fr->conn);
-
- return 1;
-}
-
-static int gaim_offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- va_list ap;
- struct aim_icq_offlinemsg *msg;
- struct im_connection *ic = sess->aux_data;
-
- va_start(ap, fr);
- msg = va_arg(ap, struct aim_icq_offlinemsg *);
- va_end(ap);
-
- switch (msg->type) {
- case 0x0001: { /* Basic offline message */
- char sender[32];
- char *dialog_msg = g_strdup(msg->msg);
- time_t t = get_time(msg->year, msg->month, msg->day, msg->hour, msg->minute, 0);
- g_snprintf(sender, sizeof(sender), "%u", msg->sender);
- strip_linefeed(dialog_msg);
- imcb_buddy_msg(ic, normalize(sender), dialog_msg, 0, t);
- g_free(dialog_msg);
- } break;
-
- case 0x0004: { /* Someone sent you a URL */
- char sender[32];
- char *dialog_msg;
- char **m;
-
- time_t t = get_time(msg->year, msg->month, msg->day, msg->hour, msg->minute, 0);
- g_snprintf(sender, sizeof(sender), "%u", msg->sender);
-
- m = g_strsplit(msg->msg, "\376", 2);
-
- if ((strlen(m[0]) != 0)) {
- dialog_msg = g_strjoinv(" -- ", m);
- } else {
- dialog_msg = m[1];
- }
-
- strip_linefeed(dialog_msg);
- imcb_buddy_msg(ic, normalize(sender), dialog_msg, 0, t);
- g_free(dialog_msg);
- g_free(m);
- } break;
-
- case 0x0006: { /* Authorization request */
- gaim_icq_authask(ic, msg->sender, msg->msg);
- } break;
-
- case 0x0007: { /* Someone has denied you authorization */
- imcb_log(sess->aux_data,
- "The user %u has denied your request to add them to your contact list for the following reason:\n%s", msg->sender,
- msg->msg ? msg->msg : _("No reason given."));
- } break;
-
- case 0x0008: { /* Someone has granted you authorization */
- imcb_log(sess->aux_data,
- "The user %u has granted your request to add them to your contact list for the following reason:\n%s", msg->sender,
- msg->msg ? msg->msg : _("No reason given."));
- } break;
-
- case 0x0012: {
- /* Ack for authorizing/denying someone. Or possibly an ack for sending any system notice */
- } break;
-
- default: {; }
- }
-
- return 1;
-}
-
-static int gaim_offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- aim_icq_ackofflinemsgs(sess);
- return 1;
-}
-
-static void oscar_keepalive(struct im_connection *ic)
-{
- struct oscar_data *odata = (struct oscar_data *) ic->proto_data;
-
- aim_flap_nop(odata->sess, odata->conn);
-}
-
-static int oscar_buddy_msg(struct im_connection *ic, char *name, char *message, int imflags)
-{
- struct oscar_data *odata = (struct oscar_data *) ic->proto_data;
- int ret = 0, len = strlen(message);
-
- if (imflags & OPT_AWAY) {
- ret = aim_send_im(odata->sess, name, AIM_IMFLAGS_AWAY, message);
- } else {
- struct aim_sendimext_args args;
- char *s;
-
- args.flags = AIM_IMFLAGS_ACK;
- if (odata->icq) {
- args.flags |= AIM_IMFLAGS_OFFLINE;
- }
- for (s = message; *s; s++) {
- if (*s & 128) {
- break;
- }
- }
-
- /* Message contains high ASCII chars, time for some translation! */
- if (*s) {
- s = g_malloc(BUF_LONG);
- /* Try if we can put it in an ISO8859-1 string first.
- If we can't, fall back to UTF16. */
- if ((ret = do_iconv("UTF-8", "ISO8859-1", message, s, len, BUF_LONG)) >= 0) {
- args.flags |= AIM_IMFLAGS_ISO_8859_1;
- len = ret;
- } else if ((ret = do_iconv("UTF-8", "UCS-2BE", message, s, len, BUF_LONG)) >= 0) {
- args.flags |= AIM_IMFLAGS_UNICODE;
- len = ret;
- } else {
- /* OOF, translation failed... Oh well.. */
- g_free(s);
- s = message;
- }
- } else {
- s = message;
- }
-
- args.features = gaim_features;
- args.featureslen = sizeof(gaim_features);
-
- args.destsn = name;
- args.msg = s;
- args.msglen = len;
-
- ret = aim_send_im_ext(odata->sess, &args);
-
- if (s != message) {
- g_free(s);
- }
- }
- if (ret >= 0) {
- return 1;
- }
- return ret;
-}
-
-static void oscar_get_info(struct im_connection *g, char *name)
-{
- struct oscar_data *odata = (struct oscar_data *) g->proto_data;
-
- if (odata->icq) {
- aim_icq_getallinfo(odata->sess, name);
- } else {
- aim_getinfo(odata->sess, odata->conn, name, AIM_GETINFO_AWAYMESSAGE);
- aim_getinfo(odata->sess, odata->conn, name, AIM_GETINFO_GENERALINFO);
- }
-}
-
-static void oscar_set_away_aim(struct im_connection *ic, struct oscar_data *od, const char *state, const char *message)
-{
- if (state == NULL) {
- state = "";
- }
-
- if (!g_strcasecmp(state, _("Visible"))) {
- aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL);
- return;
- } else if (!g_strcasecmp(state, _("Invisible"))) {
- aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_INVISIBLE);
- return;
- } else if (message == NULL) {
- message = state;
- }
-
- if (od->rights.maxawaymsglen == 0) {
- imcb_error(ic, "oscar_set_away_aim called before locate rights received");
- }
-
- aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL);
-
- g_free(ic->away);
- ic->away = NULL;
-
- if (!message) {
- aim_bos_setprofile(od->sess, od->conn, NULL, "", gaim_caps);
- return;
- }
-
- if (strlen(message) > od->rights.maxawaymsglen) {
- imcb_error(ic, "Maximum away message length of %d bytes exceeded, truncating",
- od->rights.maxawaymsglen);
- }
-
- ic->away = g_strndup(message, od->rights.maxawaymsglen);
- aim_bos_setprofile(od->sess, od->conn, NULL, ic->away, gaim_caps);
-
- return;
-}
-
-static void oscar_set_away_icq(struct im_connection *ic, struct oscar_data *od, const char *state, const char *message)
-{
- const char *msg = NULL;
- gboolean no_message = FALSE;
-
- /* clean old states */
- g_free(ic->away);
- ic->away = NULL;
- od->sess->aim_icq_state = 0;
-
- /* if no message, then use an empty message */
- if (message) {
- msg = message;
- } else {
- msg = "";
- no_message = TRUE;
- }
-
- if (state == NULL) {
- aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL);
- } else if (!g_strcasecmp(state, "Away")) {
- aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY);
- ic->away = g_strdup(msg);
- od->sess->aim_icq_state = AIM_MTYPE_AUTOAWAY;
- } else if (!g_strcasecmp(state, "Do Not Disturb")) {
- aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_DND | AIM_ICQ_STATE_BUSY);
- ic->away = g_strdup(msg);
- od->sess->aim_icq_state = AIM_MTYPE_AUTODND;
- } else if (!g_strcasecmp(state, "Not Available")) {
- aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_OUT | AIM_ICQ_STATE_AWAY);
- ic->away = g_strdup(msg);
- od->sess->aim_icq_state = AIM_MTYPE_AUTONA;
- } else if (!g_strcasecmp(state, "Occupied")) {
- aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_BUSY);
- ic->away = g_strdup(msg);
- od->sess->aim_icq_state = AIM_MTYPE_AUTOBUSY;
- } else if (!g_strcasecmp(state, "Free For Chat")) {
- aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_CHAT);
- ic->away = g_strdup(msg);
- od->sess->aim_icq_state = AIM_MTYPE_AUTOFFC;
- } else if (!g_strcasecmp(state, "Invisible")) {
- aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_INVISIBLE);
- ic->away = g_strdup(msg);
- } else {
- if (no_message) {
- aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL);
- } else {
- aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY);
- ic->away = g_strdup(msg);
- od->sess->aim_icq_state = AIM_MTYPE_AUTOAWAY;
- }
- }
-
- return;
-}
-
-static void oscar_set_away(struct im_connection *ic, char *state, char *message)
-{
- struct oscar_data *od = (struct oscar_data *) ic->proto_data;
-
- oscar_set_away_aim(ic, od, state, message);
- if (od->icq) {
- oscar_set_away_icq(ic, od, state, message);
- }
-
- return;
-}
-
-static void oscar_add_buddy(struct im_connection *g, char *name, char *group)
-{
- struct oscar_data *odata = (struct oscar_data *) g->proto_data;
- bee_user_t *bu;
-
- if (group && (bu = bee_user_by_handle(g->bee, g, name)) && bu->group) {
- aim_ssi_movebuddy(odata->sess, odata->conn, bu->group->name, group, name);
- } else {
- aim_ssi_addbuddies(odata->sess, odata->conn, group ? : OSCAR_GROUP, &name, 1, 0);
- }
-}
-
-static void oscar_remove_buddy(struct im_connection *g, char *name, char *group)
-{
- struct oscar_data *odata = (struct oscar_data *) g->proto_data;
- struct aim_ssi_item *ssigroup;
-
- while ((ssigroup =
- aim_ssi_itemlist_findparent(odata->sess->ssi.items,
- name)) &&
- !aim_ssi_delbuddies(odata->sess, odata->conn, ssigroup->name, &name, 1)) {
- ;
- }
-}
-
-static int gaim_ssi_parserights(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- return 1;
-}
-
-static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- struct im_connection *ic = sess->aux_data;
- struct aim_ssi_item *curitem, *curgroup = NULL;
- int tmp;
- char *nrm;
-
- /* Add from server list to local list */
- tmp = 0;
- for (curitem = sess->ssi.items; curitem; curitem = curitem->next) {
- nrm = curitem->name ? normalize(curitem->name) : NULL;
-
- switch (curitem->type) {
- case 0x0000: /* Buddy */
- if ((curitem->name) && (!imcb_buddy_by_handle(ic, nrm))) {
- char *realname = NULL;
-
- if (curitem->data && aim_gettlv(curitem->data, 0x0131, 1)) {
- realname = aim_gettlv_str(curitem->data, 0x0131, 1);
- }
-
- imcb_add_buddy(ic, nrm,
- curgroup ? (curgroup->gid ==
- curitem->gid ? curgroup->name : NULL) : NULL);
-
- if (realname) {
- imcb_buddy_nick_hint(ic, nrm, realname);
- imcb_rename_buddy(ic, nrm, realname);
- g_free(realname);
- }
- }
- break;
-
- case 0x0001: /* Group */
- curgroup = curitem;
- break;
-
- case 0x0002: /* Permit buddy */
- if (curitem->name) {
- GSList *list;
- for (list = ic->permit; (list && aim_sncmp(curitem->name, list->data));
- list = list->next) {
- ;
- }
- if (!list) {
- char *name;
- name = g_strdup(nrm);
- ic->permit = g_slist_append(ic->permit, name);
- tmp++;
- }
- }
- break;
-
- case 0x0003: /* Deny buddy */
- if (curitem->name) {
- GSList *list;
- for (list = ic->deny;
- (list && aim_sncmp(curitem->name, list->data)); list = list->next) {
- ;
- }
- if (!list) {
- char *name;
- name = g_strdup(nrm);
- ic->deny = g_slist_append(ic->deny, name);
- tmp++;
- }
- }
- break;
-
- case 0x0004: /* Permit/deny setting */
- if (curitem->data) {
- guint8 permdeny;
- if ((permdeny = aim_ssi_getpermdeny(sess->ssi.items)) && (permdeny != ic->permdeny)) {
- ic->permdeny = permdeny;
- tmp++;
- }
- }
- break;
-
- case 0x0005: /* Presence setting */
- /* We don't want to change Gaim's setting because it applies to all accounts */
- break;
- } /* End of switch on curitem->type */
- } /* End of for loop */
-
- aim_ssi_enable(sess, fr->conn);
-
- /* Request offline messages, now that the buddy list is complete. */
- aim_icq_reqofflinemsgs(sess);
-
- /* Now that we have a buddy list, we can tell BitlBee that we're online. */
- imcb_connected(ic);
-
- return 1;
-}
-
-static int gaim_ssi_parseack(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- aim_snac_t *origsnac;
- va_list ap;
-
- va_start(ap, fr);
- origsnac = va_arg(ap, aim_snac_t *);
- va_end(ap);
-
- if (origsnac && origsnac->family == AIM_CB_FAM_SSI && origsnac->type == AIM_CB_SSI_ADD && origsnac->data) {
- int i, st, count = aim_bstream_empty(&fr->data);
- char *list;
-
- if (count & 1) {
- /* Hmm, the length should be even... */
- imcb_error(sess->aux_data, "Received SSI ACK package with non-even length");
- return(0);
- }
- count >>= 1;
-
- list = (char *) origsnac->data;
- for (i = 0; i < count; i++) {
- struct aim_ssi_item *ssigroup = aim_ssi_itemlist_findparent(sess->ssi.items, list);
- char *group = ssigroup ? ssigroup->name : NULL;
-
- st = aimbs_get16(&fr->data);
- if (st == 0x00) {
- imcb_add_buddy(sess->aux_data, normalize(list), group);
- } else if (st == 0x0E) {
- imcb_log(sess->aux_data,
- "Buddy %s can't be added without authorization, requesting authorization",
- list);
-
- aim_ssi_auth_request(sess, fr->conn, list, "");
- aim_ssi_addbuddies(sess, fr->conn, OSCAR_GROUP, &list, 1, 1);
- } else if (st == 0x0A) {
- imcb_error(sess->aux_data, "Buddy %s is already in your list", list);
- } else {
- imcb_error(sess->aux_data, "Error while adding buddy: 0x%04x", st);
- }
- list += strlen(list) + 1;
- }
- }
-
- return(1);
-}
-
-static void oscar_add_permit(struct im_connection *ic, char *who)
-{
- struct oscar_data *od = (struct oscar_data *) ic->proto_data;
-
- if (od->icq) {
- aim_ssi_auth_reply(od->sess, od->conn, who, 1, "");
- } else {
- if (od->sess->ssi.received_data) {
- aim_ssi_addpord(od->sess, od->conn, &who, 1, AIM_SSI_TYPE_PERMIT);
- }
- }
-}
-
-static void oscar_add_deny(struct im_connection *ic, char *who)
-{
- struct oscar_data *od = (struct oscar_data *) ic->proto_data;
-
- if (od->icq) {
- aim_ssi_auth_reply(od->sess, od->conn, who, 0, "");
- } else {
- if (od->sess->ssi.received_data) {
- aim_ssi_addpord(od->sess, od->conn, &who, 1, AIM_SSI_TYPE_DENY);
- }
- }
-}
-
-static void oscar_rem_permit(struct im_connection *ic, char *who)
-{
- struct oscar_data *od = (struct oscar_data *) ic->proto_data;
-
- if (!od->icq) {
- if (od->sess->ssi.received_data) {
- aim_ssi_delpord(od->sess, od->conn, &who, 1, AIM_SSI_TYPE_PERMIT);
- }
- }
-}
-
-static void oscar_rem_deny(struct im_connection *ic, char *who)
-{
- struct oscar_data *od = (struct oscar_data *) ic->proto_data;
-
- if (!od->icq) {
- if (od->sess->ssi.received_data) {
- aim_ssi_delpord(od->sess, od->conn, &who, 1, AIM_SSI_TYPE_DENY);
- }
- }
-}
-
-static GList *oscar_away_states(struct im_connection *ic)
-{
- struct oscar_data *od = ic->proto_data;
-
- if (od->icq) {
- static GList *m = NULL;
- m = g_list_append(m, "Away");
- m = g_list_append(m, "Do Not Disturb");
- m = g_list_append(m, "Not Available");
- m = g_list_append(m, "Occupied");
- m = g_list_append(m, "Free For Chat");
- m = g_list_append(m, "Invisible");
- return m;
- } else {
- static GList *m = NULL;
- m = g_list_append(m, "Away");
- return m;
- }
-}
-
-static int gaim_icqinfo(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- struct im_connection *ic = sess->aux_data;
- struct oscar_data *od = ic->proto_data;
- gchar who[16];
- GString *str;
- va_list ap;
- struct aim_icq_info *info;
- uint32_t ip;
-
- va_start(ap, fr);
- info = va_arg(ap, struct aim_icq_info *);
- va_end(ap);
-
- if (!info->uin) {
- return 0;
- }
-
- str = g_string_sized_new(512);
- g_snprintf(who, sizeof(who), "%u", info->uin);
-
- g_string_printf(str, "%s: %s - %s: %s", _("UIN"), who, _("Nick"),
- info->nick ? info->nick : "-");
- g_string_append_printf(str, "\n%s: %s", _("First Name"), info->first);
- g_string_append_printf(str, "\n%s: %s", _("Last Name"), info->last);
- g_string_append_printf(str, "\n%s: %s", _("Email Address"), info->email);
- if (info->numaddresses && info->email2) {
- int i;
- for (i = 0; i < info->numaddresses; i++) {
- g_string_append_printf(str, "\n%s: %s", _("Email Address"), info->email2[i]);
- }
- }
- if (od->ips && (ip = (long) g_hash_table_lookup(od->ips, &info->uin)) != 0) {
- g_string_append_printf(str, "\n%s: %d.%d.%d.%d", _("Last used IP address"),
- (ip >> 24), (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
- }
- g_string_append_printf(str, "\n%s: %s", _("Mobile Phone"), info->mobile);
- if (info->gender != 0) {
- g_string_append_printf(str, "\n%s: %s", _("Gender"), info->gender == 1 ? _("Female") : _("Male"));
- }
- if (info->birthyear || info->birthmonth || info->birthday) {
- char date[30];
- struct tm tm;
- memset(&tm, 0, sizeof(struct tm));
- tm.tm_mday = (int) info->birthday;
- tm.tm_mon = (int) info->birthmonth - 1;
- tm.tm_year = (int) info->birthyear % 100;
- strftime(date, sizeof(date), "%Y-%m-%d", &tm);
- g_string_append_printf(str, "\n%s: %s", _("Birthday"), date);
- }
- if (info->age) {
- char age[5];
- g_snprintf(age, sizeof(age), "%hhd", info->age);
- g_string_append_printf(str, "\n%s: %s", _("Age"), age);
- }
- g_string_append_printf(str, "\n%s: %s", _("Personal Web Page"), info->personalwebpage);
- if (info->info && info->info[0]) {
- g_string_sprintfa(str, "\n%s:\n%s\n%s", _("Additional Information"),
- info->info, _("End of Additional Information"));
- }
- g_string_append_c(str, '\n');
- if ((info->homeaddr &&
- (info->homeaddr[0])) ||
- (info->homecity &&
- info->homecity[0]) || (info->homestate && info->homestate[0]) || (info->homezip && info->homezip[0])) {
- g_string_append_printf(str, "%s:", _("Home Address"));
- g_string_append_printf(str, "\n%s: %s", _("Address"), info->homeaddr);
- g_string_append_printf(str, "\n%s: %s", _("City"), info->homecity);
- g_string_append_printf(str, "\n%s: %s", _("State"), info->homestate);
- g_string_append_printf(str, "\n%s: %s", _("Zip Code"), info->homezip);
- g_string_append_c(str, '\n');
- }
- if ((info->workaddr &&
- info->workaddr[0]) ||
- (info->workcity &&
- info->workcity[0]) || (info->workstate && info->workstate[0]) || (info->workzip && info->workzip[0])) {
- g_string_append_printf(str, "%s:", _("Work Address"));
- g_string_append_printf(str, "\n%s: %s", _("Address"), info->workaddr);
- g_string_append_printf(str, "\n%s: %s", _("City"), info->workcity);
- g_string_append_printf(str, "\n%s: %s", _("State"), info->workstate);
- g_string_append_printf(str, "\n%s: %s", _("Zip Code"), info->workzip);
- g_string_append_c(str, '\n');
- }
- if ((info->workcompany &&
- info->workcompany[0]) ||
- (info->workdivision &&
- info->workdivision[0]) ||
- (info->workposition && info->workposition[0]) || (info->workwebpage && info->workwebpage[0])) {
- g_string_append_printf(str, "%s:", _("Work Information"));
- g_string_append_printf(str, "\n%s: %s", _("Company"), info->workcompany);
- g_string_append_printf(str, "\n%s: %s", _("Division"), info->workdivision);
- g_string_append_printf(str, "\n%s: %s", _("Position"), info->workposition);
- if (info->workwebpage && info->workwebpage[0]) {
- g_string_append_printf(str, "\n%s: %s", _("Web Page"), info->workwebpage);
- }
- g_string_append_c(str, '\n');
- }
-
- imcb_log(ic, "%s\n%s", _("User Info"), str->str);
- g_string_free(str, TRUE);
-
- return 1;
-
-}
-
-static char *oscar_encoding_extract(const char *encoding)
-{
- char *ret = NULL;
- char *begin, *end;
-
- g_return_val_if_fail(encoding != NULL, NULL);
-
- /* Make sure encoding begins with charset= */
- if (strncmp(encoding, "text/plain; charset=", 20) &&
- strncmp(encoding, "text/aolrtf; charset=", 21) &&
- strncmp(encoding, "text/x-aolrtf; charset=", 23)) {
- return NULL;
- }
-
- begin = strchr(encoding, '"');
- end = strrchr(encoding, '"');
-
- if ((begin == NULL) || (end == NULL) || (begin >= end)) {
- return NULL;
- }
-
- ret = g_strndup(begin + 1, (end - 1) - begin);
-
- return ret;
-}
-
-static char *oscar_encoding_to_utf8(char *encoding, char *text, int textlen)
-{
- char *utf8 = g_new0(char, 8192);
-
- if ((encoding == NULL) || encoding[0] == '\0') {
- /* gaim_debug_info("oscar", "Empty encoding, assuming UTF-8\n");*/
- } else if (!g_strcasecmp(encoding, "iso-8859-1")) {
- do_iconv("iso-8859-1", "UTF-8", text, utf8, textlen, 8192);
- } else if (!g_strcasecmp(encoding, "ISO-8859-1-Windows-3.1-Latin-1")) {
- do_iconv("Windows-1252", "UTF-8", text, utf8, textlen, 8192);
- } else if (!g_strcasecmp(encoding, "unicode-2-0")) {
- do_iconv("UCS-2BE", "UTF-8", text, utf8, textlen, 8192);
- } else if (g_strcasecmp(encoding, "us-ascii") && strcmp(encoding, "utf-8")) {
- /* gaim_debug_warning("oscar", "Unrecognized character encoding \"%s\", "
- "attempting to convert to UTF-8 anyway\n", encoding);*/
- do_iconv(encoding, "UTF-8", text, utf8, textlen, 8192);
- }
-
- /*
- * If utf8 is still NULL then either the encoding is us-ascii/utf-8 or
- * we have been unable to convert the text to utf-8 from the encoding
- * that was specified. So we assume it's UTF-8 and hope for the best.
- */
- if (*utf8 == 0) {
- strncpy(utf8, text, textlen);
- }
-
- return utf8;
-}
-
-static int gaim_parseaiminfo(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- struct im_connection *ic = sess->aux_data;
- va_list ap;
- aim_userinfo_t *userinfo;
- guint16 infotype;
- char *text_encoding = NULL, *text = NULL, *extracted_encoding = NULL;
- guint16 text_length;
- char *utf8 = NULL;
-
- va_start(ap, fr);
- userinfo = va_arg(ap, aim_userinfo_t *);
- infotype = va_arg(ap, int);
- text_encoding = va_arg(ap, char*);
- text = va_arg(ap, char*);
- text_length = va_arg(ap, int);
- va_end(ap);
-
- if (text_encoding) {
- extracted_encoding = oscar_encoding_extract(text_encoding);
- }
- if (infotype == AIM_GETINFO_GENERALINFO) {
- /*Display idle time*/
- char buff[256];
- struct tm idletime;
- if (userinfo->idletime) {
- memset(&idletime, 0, sizeof(struct tm));
- idletime.tm_mday = (userinfo->idletime / 60) / 24;
- idletime.tm_hour = (userinfo->idletime / 60) % 24;
- idletime.tm_min = userinfo->idletime % 60;
- idletime.tm_sec = 0;
- strftime(buff, 256, _("%d days %H hours %M minutes"), &idletime);
- imcb_log(ic, "%s: %s", _("Idle Time"), buff);
- }
-
- if (text) {
- utf8 = oscar_encoding_to_utf8(extracted_encoding, text, text_length);
- imcb_log(ic, "%s\n%s", _("User Info"), utf8);
- } else {
- imcb_log(ic, _("No user info available."));
- }
- } else if (infotype == AIM_GETINFO_AWAYMESSAGE && userinfo->flags & AIM_FLAG_AWAY) {
- utf8 = oscar_encoding_to_utf8(extracted_encoding, text, text_length);
- imcb_log(ic, "%s\n%s", _("Away Message"), utf8);
- }
-
- g_free(utf8);
-
- return 1;
-}
-
-int gaim_parsemtn(aim_session_t *sess, aim_frame_t *fr, ...)
-{
- struct im_connection * ic = sess->aux_data;
- va_list ap;
- guint16 type2;
- char * sn;
-
- va_start(ap, fr);
- va_arg(ap, int); /* type1 */
- sn = va_arg(ap, char*);
- type2 = va_arg(ap, int);
- va_end(ap);
-
- if (type2 == 0x0002) {
- /* User is typing */
- imcb_buddy_typing(ic, normalize(sn), OPT_TYPING);
- } else if (type2 == 0x0001) {
- /* User has typed something, but is not actively typing (stale) */
- imcb_buddy_typing(ic, normalize(sn), OPT_THINKING);
- } else {
- /* User has stopped typing */
- imcb_buddy_typing(ic, normalize(sn), 0);
- }
-
- return 1;
-}
-
-int oscar_send_typing(struct im_connection *ic, char * who, int typing)
-{
- struct oscar_data *od = ic->proto_data;
-
- return(aim_im_sendmtn(od->sess, 1, who, (typing & OPT_TYPING) ? 0x0002 : 0x0000));
-}
-
-void oscar_chat_msg(struct groupchat *c, char *message, int msgflags)
-{
- struct im_connection *ic = c->ic;
- struct oscar_data * od = (struct oscar_data*) ic->proto_data;
- struct chat_connection * ccon;
- int ret;
- guint8 len = strlen(message);
- guint16 flags;
- char *s;
-
- if (!(ccon = c->data)) {
- return;
- }
-
- for (s = message; *s; s++) {
- if (*s & 128) {
- break;
- }
- }
-
- flags = AIM_CHATFLAGS_NOREFLECT;
-
- /* Message contains high ASCII chars, time for some translation! */
- if (*s) {
- s = g_malloc(BUF_LONG);
- /* Try if we can put it in an ISO8859-1 string first.
- If we can't, fall back to UTF16. */
- if ((ret = do_iconv("UTF-8", "ISO8859-1", message, s, len, BUF_LONG)) >= 0) {
- flags |= AIM_CHATFLAGS_ISO_8859_1;
- len = ret;
- } else if ((ret = do_iconv("UTF-8", "UCS-2BE", message, s, len, BUF_LONG)) >= 0) {
- flags |= AIM_CHATFLAGS_UNICODE;
- len = ret;
- } else {
- /* OOF, translation failed... Oh well.. */
- g_free(s);
- s = message;
- }
- } else {
- s = message;
- }
-
- ret = aim_chat_send_im(od->sess, ccon->conn, flags, s, len);
-
- if (s != message) {
- g_free(s);
- }
-
-/* return (ret >= 0); */
-}
-
-void oscar_chat_invite(struct groupchat *c, char *who, char *message)
-{
- struct im_connection *ic = c->ic;
- struct oscar_data * od = (struct oscar_data *) ic->proto_data;
- struct chat_connection *ccon;
-
- if (!(ccon = c->data)) {
- return;
- }
-
- aim_chat_invite(od->sess, od->conn, who, message ? message : "",
- ccon->exchange, ccon->name, 0x0);
-}
-
-void oscar_chat_kill(struct im_connection *ic, struct chat_connection *cc)
-{
- struct oscar_data *od = (struct oscar_data *) ic->proto_data;
-
- /* Notify the conversation window that we've left the chat */
- imcb_chat_free(cc->cnv);
-
- /* Destroy the chat_connection */
- od->oscar_chats = g_slist_remove(od->oscar_chats, cc);
- if (cc->inpa > 0) {
- b_event_remove(cc->inpa);
- cc->inpa = 0;
- }
- aim_conn_kill(od->sess, &cc->conn);
- g_free(cc->name);
- g_free(cc->show);
- g_free(cc);
-}
-
-void oscar_chat_leave(struct groupchat *c)
-{
- if (!c->data) {
- return;
- }
- oscar_chat_kill(c->ic, c->data);
-}
-
-struct groupchat *oscar_chat_join_internal(struct im_connection *ic, const char *room,
- const char *nick, const char *password, int exchange_number)
-{
- struct oscar_data * od = (struct oscar_data *) ic->proto_data;
- struct groupchat *ret = imcb_chat_new(ic, room);
- aim_conn_t * cur;
-
- if ((cur = aim_getconn_type(od->sess, AIM_CONN_TYPE_CHATNAV))) {
- aim_chatnav_createroom(od->sess, cur, room, exchange_number);
-
- return ret;
- } else {
- struct create_room * cr = g_new0(struct create_room, 1);
-
- cr->exchange = exchange_number;
- cr->name = g_strdup(room);
- od->create_rooms = g_slist_append(od->create_rooms, cr);
- aim_reqservice(od->sess, od->conn, AIM_CONN_TYPE_CHATNAV);
-
- return ret;
- }
-}
-
-struct groupchat *oscar_chat_join(struct im_connection *ic, const char *room,
- const char *nick, const char *password, set_t **sets)
-{
- return oscar_chat_join_internal(ic, room, nick, password, set_getint(sets, "exchange_number"));
-}
-
-struct groupchat *oscar_chat_with(struct im_connection * ic, char *who)
-{
- struct oscar_data * od = (struct oscar_data *) ic->proto_data;
- struct groupchat *ret;
- static int chat_id = 0;
- char * chatname, *s;
-
- chatname = g_strdup_printf("%s%s%d", g_ascii_isdigit(*ic->acc->user) ? "icq" : "",
- ic->acc->user, chat_id++);
-
- for (s = chatname; *s; s++) {
- if (!g_ascii_isalnum(*s)) {
- *s = '0';
- }
- }
-
- ret = oscar_chat_join_internal(ic, chatname, NULL, NULL, 4);
- aim_chat_invite(od->sess, od->conn, who, "", 4, chatname, 0x0);
-
- g_free(chatname);
-
- return ret;
-}
-
-void oscar_accept_chat(void *data)
-{
- struct aim_chat_invitation * inv = data;
-
- oscar_chat_join_internal(inv->ic, inv->name, NULL, NULL, 4);
- g_free(inv->name);
- g_free(inv);
-}
-
-void oscar_reject_chat(void *data)
-{
- struct aim_chat_invitation * inv = data;
-
- g_free(inv->name);
- g_free(inv);
-}
-
-void oscar_chat_add_settings(account_t *acc, set_t **head)
-{
- set_add(head, "exchange_number", "4", set_eval_int, NULL);
-}
-
-void oscar_chat_free_settings(account_t *acc, set_t **head)
-{
- set_del(head, "exchange_number");
-}
-
-void oscar_initmodule()
-{
- struct prpl *ret = g_new0(struct prpl, 1);
-
- ret->name = "oscar";
- ret->mms = 2343; /* this guess taken from libotr UPGRADING file */
- ret->away_states = oscar_away_states;
- ret->init = oscar_init;
- ret->login = oscar_login;
- ret->keepalive = oscar_keepalive;
- ret->logout = oscar_logout;
- ret->buddy_msg = oscar_buddy_msg;
- ret->get_info = oscar_get_info;
- ret->set_away = oscar_set_away;
- ret->add_buddy = oscar_add_buddy;
- ret->remove_buddy = oscar_remove_buddy;
- ret->chat_msg = oscar_chat_msg;
- ret->chat_invite = oscar_chat_invite;
- ret->chat_leave = oscar_chat_leave;
- ret->chat_with = oscar_chat_with;
- ret->chat_join = oscar_chat_join;
- ret->chat_add_settings = oscar_chat_add_settings;
- ret->chat_free_settings = oscar_chat_free_settings;
- ret->add_permit = oscar_add_permit;
- ret->add_deny = oscar_add_deny;
- ret->rem_permit = oscar_rem_permit;
- ret->rem_deny = oscar_rem_deny;
- ret->send_typing = oscar_send_typing;
-
- ret->handle_cmp = aim_sncmp;
-
- register_protocol(ret);
-}
Index: otocols/oscar/oscar_util.c
===================================================================
--- protocols/oscar/oscar_util.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,78 +1,0 @@
-#include
-#include
-
-/*
-* int snlen(const char *)
-*
-* This takes a screen name and returns its length without
-* spaces. If there are no spaces in the SN, then the
-* return is equal to that of strlen().
-*
-*/
-static int aim_snlen(const char *sn)
-{
- int i = 0;
- const char *curPtr = NULL;
-
- if (!sn) {
- return 0;
- }
-
- curPtr = sn;
- while ((*curPtr) != (char) '\0') {
- if ((*curPtr) != ' ') {
- i++;
- }
- curPtr++;
- }
-
- return i;
-}
-
-/*
-* int sncmp(const char *, const char *)
-*
-* This takes two screen names and compares them using the rules
-* on screen names for AIM/AOL. Mainly, this means case and space
-* insensitivity (all case differences and spacing differences are
-* ignored).
-*
-* Return: 0 if equal
-* non-0 if different
-*
-*/
-
-int aim_sncmp(const char *sn1, const char *sn2)
-{
- const char *curPtr1 = NULL, *curPtr2 = NULL;
-
- if (aim_snlen(sn1) != aim_snlen(sn2)) {
- return 1;
- }
-
- curPtr1 = sn1;
- curPtr2 = sn2;
- while ((*curPtr1 != (char) '\0') && (*curPtr2 != (char) '\0')) {
- if ((*curPtr1 == ' ') || (*curPtr2 == ' ')) {
- if (*curPtr1 == ' ') {
- curPtr1++;
- }
- if (*curPtr2 == ' ') {
- curPtr2++;
- }
- } else {
- if (g_ascii_toupper(*curPtr1) != g_ascii_toupper(*curPtr2)) {
- return 1;
- }
- curPtr1++;
- curPtr2++;
- }
- }
-
- /* Should both be NULL */
- if (*curPtr1 != *curPtr2) {
- return 1;
- }
-
- return 0;
-}
Index: otocols/oscar/rxhandlers.c
===================================================================
--- protocols/oscar/rxhandlers.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,384 +1,0 @@
-/*
- * aim_rxhandlers.c
- *
- * This file contains most all of the incoming packet handlers, along
- * with aim_rxdispatch(), the Rx dispatcher. Queue/list management is
- * actually done in aim_rxqueue.c.
- *
- */
-
-#include
-
-struct aim_rxcblist_s {
- guint16 family;
- guint16 type;
- aim_rxcallback_t handler;
- u_short flags;
- struct aim_rxcblist_s *next;
-};
-
-aim_module_t *aim__findmodulebygroup(aim_session_t *sess, guint16 group)
-{
- aim_module_t *cur;
-
- for (cur = (aim_module_t *) sess->modlistv; cur; cur = cur->next) {
- if (cur->family == group) {
- return cur;
- }
- }
-
- return NULL;
-}
-
-static aim_module_t *aim__findmodule(aim_session_t *sess, const char *name)
-{
- aim_module_t *cur;
-
- for (cur = (aim_module_t *) sess->modlistv; cur; cur = cur->next) {
- if (strcmp(name, cur->name) == 0) {
- return cur;
- }
- }
-
- return NULL;
-}
-
-int aim__registermodule(aim_session_t *sess, int (*modfirst)(aim_session_t *, aim_module_t *))
-{
- aim_module_t *mod;
-
- if (!sess || !modfirst) {
- return -1;
- }
-
- if (!(mod = g_new0(aim_module_t, 1))) {
- return -1;
- }
-
- if (modfirst(sess, mod) == -1) {
- g_free(mod);
- return -1;
- }
-
- if (aim__findmodule(sess, mod->name)) {
- if (mod->shutdown) {
- mod->shutdown(sess, mod);
- }
- g_free(mod);
- return -1;
- }
-
- mod->next = (aim_module_t *) sess->modlistv;
- sess->modlistv = mod;
-
-
- return 0;
-}
-
-void aim__shutdownmodules(aim_session_t *sess)
-{
- aim_module_t *cur;
-
- for (cur = (aim_module_t *) sess->modlistv; cur; ) {
- aim_module_t *tmp;
-
- tmp = cur->next;
-
- if (cur->shutdown) {
- cur->shutdown(sess, cur);
- }
-
- g_free(cur);
-
- cur = tmp;
- }
-
- sess->modlistv = NULL;
-
- return;
-}
-
-static int consumesnac(aim_session_t *sess, aim_frame_t *rx)
-{
- aim_module_t *cur;
- aim_modsnac_t snac;
-
- if (aim_bstream_empty(&rx->data) < 10) {
- return 0;
- }
-
- snac.family = aimbs_get16(&rx->data);
- snac.subtype = aimbs_get16(&rx->data);
- snac.flags = aimbs_get16(&rx->data);
- snac.id = aimbs_get32(&rx->data);
-
- /* Contains TLV(s) in the FNAC header */
- if (snac.flags & 0x8000) {
- aim_bstream_advance(&rx->data, aimbs_get16(&rx->data));
- } else if (snac.flags & 0x0001) {
- /* Following SNAC will be related */
- }
-
- for (cur = (aim_module_t *) sess->modlistv; cur; cur = cur->next) {
-
- if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
- (cur->family != snac.family)) {
- continue;
- }
-
- if (cur->snachandler(sess, cur, rx, &snac, &rx->data)) {
- return 1;
- }
-
- }
-
- return 0;
-}
-
-static int consumenonsnac(aim_session_t *sess, aim_frame_t *rx, 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 *) sess->modlistv; cur; cur = cur->next) {
-
- if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
- (cur->family != snac.family)) {
- continue;
- }
-
- if (cur->snachandler(sess, cur, rx, &snac, &rx->data)) {
- return 1;
- }
-
- }
-
- return 0;
-}
-
-static int negchan_middle(aim_session_t *sess, aim_frame_t *fr)
-{
- aim_tlvlist_t *tlvlist;
- char *msg = NULL;
- guint16 code = 0;
- aim_rxcallback_t userfunc;
- int ret = 1;
-
- if (aim_bstream_empty(&fr->data) == 0) {
- /* XXX should do something with this */
- return 1;
- }
-
- /* Used only by the older login protocol */
- /* XXX remove this special case? */
- if (fr->conn->type == AIM_CONN_TYPE_AUTH) {
- return consumenonsnac(sess, fr, 0x0017, 0x0003);
- }
-
- tlvlist = aim_readtlvchain(&fr->data);
-
- if (aim_gettlv(tlvlist, 0x0009, 1)) {
- code = aim_gettlv16(tlvlist, 0x0009, 1);
- }
-
- if (aim_gettlv(tlvlist, 0x000b, 1)) {
- msg = aim_gettlv_str(tlvlist, 0x000b, 1);
- }
-
- if ((userfunc = aim_callhandler(sess, fr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR))) {
- ret = userfunc(sess, fr, code, msg);
- }
-
- aim_freetlvchain(&tlvlist);
-
- g_free(msg);
-
- return ret;
-}
-
-/*
- * Some SNACs we do not allow to be hooked, for good reason.
- */
-static int checkdisallowed(guint16 group, guint16 type)
-{
- static const struct {
- guint16 group;
- guint16 type;
- } dontuse[] = {
- { 0x0001, 0x0002 },
- { 0x0001, 0x0003 },
- { 0x0001, 0x0006 },
- { 0x0001, 0x0007 },
- { 0x0001, 0x0008 },
- { 0x0001, 0x0017 },
- { 0x0001, 0x0018 },
- { 0x0000, 0x0000 }
- };
- int i;
-
- for (i = 0; dontuse[i].group != 0x0000; i++) {
- if ((dontuse[i].group == group) && (dontuse[i].type == type)) {
- return 1;
- }
- }
-
- return 0;
-}
-
-int aim_conn_addhandler(aim_session_t *sess, aim_conn_t *conn, guint16 family, guint16 type,
- aim_rxcallback_t newhandler, guint16 flags)
-{
- struct aim_rxcblist_s *newcb;
-
- g_return_val_if_fail(conn, -1);
- g_return_val_if_fail(!checkdisallowed(family, type), -1);
-
- if (!(newcb = (struct aim_rxcblist_s *) g_new0(struct aim_rxcblist_s, 1))) {
- return -1;
- }
-
- newcb->family = family;
- newcb->type = type;
- newcb->flags = flags;
- newcb->handler = newhandler;
- newcb->next = NULL;
-
- if (!conn->handlerlist) {
- conn->handlerlist = (void *) newcb;
- } else {
- struct aim_rxcblist_s *cur;
-
- for (cur = (struct aim_rxcblist_s *) conn->handlerlist; cur->next; cur = cur->next) {
- ;
- }
- cur->next = newcb;
- }
-
- return 0;
-}
-
-int aim_clearhandlers(aim_conn_t *conn)
-{
- struct aim_rxcblist_s *cur;
-
- if (!conn) {
- return -1;
- }
-
- for (cur = (struct aim_rxcblist_s *) conn->handlerlist; cur; ) {
- struct aim_rxcblist_s *tmp;
-
- tmp = cur->next;
- g_free(cur);
- cur = tmp;
- }
- conn->handlerlist = NULL;
-
- return 0;
-}
-
-aim_rxcallback_t aim_callhandler(aim_session_t *sess, aim_conn_t *conn, guint16 family, guint16 type)
-{
- struct aim_rxcblist_s *cur;
-
- if (!conn) {
- return NULL;
- }
-
- for (cur = (struct aim_rxcblist_s *) conn->handlerlist; cur; cur = cur->next) {
- if ((cur->family == family) && (cur->type == type)) {
- return cur->handler;
- }
- }
-
- if (type == AIM_CB_SPECIAL_DEFAULT) {
- return NULL; /* prevent infinite recursion */
- }
-
- return aim_callhandler(sess, conn, family, AIM_CB_SPECIAL_DEFAULT);
-}
-
-static int aim_callhandler_noparam(aim_session_t *sess, aim_conn_t *conn, guint16 family, guint16 type,
- aim_frame_t *ptr)
-{
- aim_rxcallback_t userfunc;
-
- if ((userfunc = aim_callhandler(sess, conn, family, type))) {
- return userfunc(sess, ptr);
- }
-
- return 1; /* XXX */
-}
-
-/*
- * aim_rxdispatch()
- *
- * Basically, heres what this should do:
- * 1) Determine correct packet handler for this packet
- * 2) Mark the packet handled (so it can be dequeued in purge_queue())
- * 3) Send the packet to the packet handler
- * 4) Go to next packet in the queue and start over
- * 5) When done, run purge_queue() to purge handled commands
- *
- * TODO: Clean up.
- * TODO: More support for mid-level handlers.
- * TODO: Allow for NULL handlers.
- *
- */
-void aim_rxdispatch(aim_session_t *sess)
-{
- int i;
- aim_frame_t *cur;
-
- for (cur = sess->queue_incoming, i = 0; cur; cur = cur->next, i++) {
-
- /*
- * XXX: This is still fairly ugly.
- */
-
- if (cur->handled) {
- continue;
- }
-
- if (cur->hdr.flap.type == 0x01) {
-
- cur->handled = aim_callhandler_noparam(sess, cur->conn, AIM_CB_FAM_SPECIAL,
- AIM_CB_SPECIAL_FLAPVER, cur); /* XXX use consumenonsnac */
-
- continue;
-
- } else if (cur->hdr.flap.type == 0x02) {
-
- if ((cur->handled = consumesnac(sess, cur))) {
- continue;
- }
-
- } else if (cur->hdr.flap.type == 0x04) {
-
- cur->handled = negchan_middle(sess, cur);
- continue;
-
- } else if (cur->hdr.flap.type == 0x05) {
- ;
- }
-
- if (!cur->handled) {
- consumenonsnac(sess, cur, 0xffff, 0xffff); /* last chance! */
- cur->handled = 1;
- }
- }
-
- /*
- * This doesn't have to be called here. It could easily be done
- * by a separate thread or something. It's an administrative operation,
- * and can take a while. Though the less you call it the less memory
- * you'll have :)
- */
- aim_purge_rxqueue(sess);
-
- return;
-}
Index: otocols/oscar/rxqueue.c
===================================================================
--- protocols/oscar/rxqueue.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,530 +1,0 @@
-/*
- * aim_rxqueue.c
- *
- * This file contains the management routines for the receive
- * (incoming packet) queue. The actual packet handlers are in
- * aim_rxhandlers.c.
- */
-
-#include
-
-#include
-
-/*
- *
- */
-int aim_recv(int fd, void *buf, size_t count)
-{
- int left, cur;
-
- for (cur = 0, left = count; left; ) {
- int ret;
-
- ret = recv(fd, ((unsigned char *) buf) + cur, left, 0);
-
- /* Of course EOF is an error, only morons disagree with that. */
- if (ret <= 0) {
- return -1;
- }
-
- cur += ret;
- left -= ret;
- }
-
- return cur;
-}
-
-/*
- * Read into a byte stream. Will not read more than count, but may read
- * less if there is not enough room in the stream buffer.
- */
-static int aim_bstream_recv(aim_bstream_t *bs, int fd, size_t count)
-{
- int red = 0;
-
- if (!bs || (fd < 0) || (count < 0)) {
- return -1;
- }
-
- if (count > (bs->len - bs->offset)) {
- count = bs->len - bs->offset; /* truncate to remaining space */
-
- }
- if (count) {
-
- red = aim_recv(fd, bs->data + bs->offset, count);
-
- if (red <= 0) {
- return -1;
- }
- }
-
- bs->offset += red;
-
- return red;
-}
-
-int aim_bstream_init(aim_bstream_t *bs, guint8 *data, int len)
-{
-
- if (!bs) {
- return -1;
- }
-
- bs->data = data;
- bs->len = len;
- bs->offset = 0;
-
- return 0;
-}
-
-int aim_bstream_empty(aim_bstream_t *bs)
-{
- return bs->len - bs->offset;
-}
-
-int aim_bstream_curpos(aim_bstream_t *bs)
-{
- return bs->offset;
-}
-
-int aim_bstream_setpos(aim_bstream_t *bs, int off)
-{
-
- if (off > bs->len) {
- return -1;
- }
-
- bs->offset = off;
-
- return off;
-}
-
-void aim_bstream_rewind(aim_bstream_t *bs)
-{
-
- aim_bstream_setpos(bs, 0);
-
- return;
-}
-
-int aim_bstream_advance(aim_bstream_t *bs, int n)
-{
-
- if (aim_bstream_empty(bs) < n) {
- return 0; /* XXX throw an exception */
-
- }
- bs->offset += n;
-
- return n;
-}
-
-guint8 aimbs_get8(aim_bstream_t *bs)
-{
-
- if (aim_bstream_empty(bs) < 1) {
- return 0; /* XXX throw an exception */
-
- }
- bs->offset++;
-
- return aimutil_get8(bs->data + bs->offset - 1);
-}
-
-guint16 aimbs_get16(aim_bstream_t *bs)
-{
-
- if (aim_bstream_empty(bs) < 2) {
- return 0; /* XXX throw an exception */
-
- }
- bs->offset += 2;
-
- return aimutil_get16(bs->data + bs->offset - 2);
-}
-
-guint32 aimbs_get32(aim_bstream_t *bs)
-{
-
- if (aim_bstream_empty(bs) < 4) {
- return 0; /* XXX throw an exception */
-
- }
- bs->offset += 4;
-
- return aimutil_get32(bs->data + bs->offset - 4);
-}
-
-guint8 aimbs_getle8(aim_bstream_t *bs)
-{
-
- if (aim_bstream_empty(bs) < 1) {
- return 0; /* XXX throw an exception */
-
- }
- bs->offset++;
-
- return aimutil_getle8(bs->data + bs->offset - 1);
-}
-
-guint16 aimbs_getle16(aim_bstream_t *bs)
-{
-
- if (aim_bstream_empty(bs) < 2) {
- return 0; /* XXX throw an exception */
-
- }
- bs->offset += 2;
-
- return aimutil_getle16(bs->data + bs->offset - 2);
-}
-
-guint32 aimbs_getle32(aim_bstream_t *bs)
-{
-
- if (aim_bstream_empty(bs) < 4) {
- return 0; /* XXX throw an exception */
-
- }
- bs->offset += 4;
-
- return aimutil_getle32(bs->data + bs->offset - 4);
-}
-
-int aimbs_put8(aim_bstream_t *bs, guint8 v)
-{
-
- if (aim_bstream_empty(bs) < 1) {
- return 0; /* XXX throw an exception */
-
- }
- bs->offset += aimutil_put8(bs->data + bs->offset, v);
-
- return 1;
-}
-
-int aimbs_put16(aim_bstream_t *bs, guint16 v)
-{
-
- if (aim_bstream_empty(bs) < 2) {
- return 0; /* XXX throw an exception */
-
- }
- bs->offset += aimutil_put16(bs->data + bs->offset, v);
-
- return 2;
-}
-
-int aimbs_put32(aim_bstream_t *bs, guint32 v)
-{
-
- if (aim_bstream_empty(bs) < 4) {
- return 0; /* XXX throw an exception */
-
- }
- bs->offset += aimutil_put32(bs->data + bs->offset, v);
-
- return 1;
-}
-
-int aimbs_putle8(aim_bstream_t *bs, guint8 v)
-{
-
- if (aim_bstream_empty(bs) < 1) {
- return 0; /* XXX throw an exception */
-
- }
- bs->offset += aimutil_putle8(bs->data + bs->offset, v);
-
- return 1;
-}
-
-int aimbs_putle16(aim_bstream_t *bs, guint16 v)
-{
-
- if (aim_bstream_empty(bs) < 2) {
- return 0; /* XXX throw an exception */
-
- }
- bs->offset += aimutil_putle16(bs->data + bs->offset, v);
-
- return 2;
-}
-
-int aimbs_putle32(aim_bstream_t *bs, guint32 v)
-{
-
- if (aim_bstream_empty(bs) < 4) {
- return 0; /* XXX throw an exception */
-
- }
- bs->offset += aimutil_putle32(bs->data + bs->offset, v);
-
- return 1;
-}
-
-int aimbs_getrawbuf(aim_bstream_t *bs, guint8 *buf, int len)
-{
-
- if (aim_bstream_empty(bs) < len) {
- return 0;
- }
-
- memcpy(buf, bs->data + bs->offset, len);
- bs->offset += len;
-
- return len;
-}
-
-guint8 *aimbs_getraw(aim_bstream_t *bs, int len)
-{
- guint8 *ob;
-
- if (!(ob = g_malloc(len))) {
- return NULL;
- }
-
- if (aimbs_getrawbuf(bs, ob, len) < len) {
- g_free(ob);
- return NULL;
- }
-
- return ob;
-}
-
-char *aimbs_getstr(aim_bstream_t *bs, int len)
-{
- guint8 *ob;
-
- if (!(ob = g_malloc(len + 1))) {
- return NULL;
- }
-
- if (aimbs_getrawbuf(bs, ob, len) < len) {
- g_free(ob);
- return NULL;
- }
-
- ob[len] = '\0';
-
- return (char *) ob;
-}
-
-int aimbs_putraw(aim_bstream_t *bs, const guint8 *v, int len)
-{
-
- if (aim_bstream_empty(bs) < len) {
- return 0; /* XXX throw an exception */
-
- }
- memcpy(bs->data + bs->offset, v, len);
- bs->offset += len;
-
- return len;
-}
-
-int aimbs_putbs(aim_bstream_t *bs, aim_bstream_t *srcbs, int len)
-{
-
- if (aim_bstream_empty(srcbs) < len) {
- return 0; /* XXX throw exception (underrun) */
-
- }
- if (aim_bstream_empty(bs) < len) {
- return 0; /* XXX throw exception (overflow) */
-
- }
- memcpy(bs->data + bs->offset, srcbs->data + srcbs->offset, len);
- bs->offset += len;
- srcbs->offset += len;
-
- return len;
-}
-
-/**
- * aim_frame_destroy - free aim_frame_t
- * @frame: the frame to free
- *
- * returns -1 on error; 0 on success.
- *
- */
-void aim_frame_destroy(aim_frame_t *frame)
-{
-
- g_free(frame->data.data); /* XXX aim_bstream_free */
-
- g_free(frame);
-}
-
-
-/*
- * Grab a single command sequence off the socket, and enqueue
- * it in the incoming event queue in a separate struct.
- */
-int aim_get_command(aim_session_t *sess, aim_conn_t *conn)
-{
- guint8 flaphdr_raw[6];
- aim_bstream_t flaphdr;
- aim_frame_t *newrx;
- guint16 payloadlen;
-
- if (!sess || !conn) {
- return 0;
- }
-
- if (conn->fd == -1) {
- return -1; /* its a aim_conn_close()'d connection */
-
- }
- /* KIDS, THIS IS WHAT HAPPENS IF YOU USE CODE WRITTEN FOR GUIS IN A DAEMON!
-
- And wouldn't it make sense to return something that prevents this function
- from being called again IMMEDIATELY (and making the program suck up all
- CPU time)?...
-
- if (conn->fd < 3)
- return 0;
- */
-
- if (conn->status & AIM_CONN_STATUS_INPROGRESS) {
- return aim_conn_completeconnect(sess, conn);
- }
-
- aim_bstream_init(&flaphdr, flaphdr_raw, sizeof(flaphdr_raw));
-
- /*
- * Read FLAP header. Six bytes:
- *
- * 0 char -- Always 0x2a
- * 1 char -- Channel ID. Usually 2 -- 1 and 4 are used during login.
- * 2 short -- Sequence number
- * 4 short -- Number of data bytes that follow.
- */
- if (aim_bstream_recv(&flaphdr, conn->fd, 6) < 6) {
- aim_conn_close(conn);
- return -1;
- }
-
- aim_bstream_rewind(&flaphdr);
-
- /*
- * This shouldn't happen unless the socket breaks, the server breaks,
- * or we break. We must handle it just in case.
- */
- if (aimbs_get8(&flaphdr) != 0x2a) {
- aim_bstream_rewind(&flaphdr);
- aimbs_get8(&flaphdr);
- imcb_error(sess->aux_data, "FLAP framing disrupted");
- aim_conn_close(conn);
- return -1;
- }
-
- /* allocate a new struct */
- if (!(newrx = (aim_frame_t *) g_new0(aim_frame_t, 1))) {
- return -1;
- }
-
- /* we're doing FLAP if we're here */
- newrx->hdrtype = AIM_FRAMETYPE_FLAP;
-
- newrx->hdr.flap.type = aimbs_get8(&flaphdr);
- newrx->hdr.flap.seqnum = aimbs_get16(&flaphdr);
- payloadlen = aimbs_get16(&flaphdr);
-
- newrx->nofree = 0; /* free by default */
-
- if (payloadlen) {
- guint8 *payload = NULL;
-
- if (!(payload = (guint8 *) g_malloc(payloadlen))) {
- aim_frame_destroy(newrx);
- return -1;
- }
-
- aim_bstream_init(&newrx->data, payload, payloadlen);
-
- /* read the payload */
- if (aim_bstream_recv(&newrx->data, conn->fd, payloadlen) < payloadlen) {
- aim_frame_destroy(newrx); /* free's payload */
- aim_conn_close(conn);
- return -1;
- }
- } else {
- aim_bstream_init(&newrx->data, NULL, 0);
- }
-
-
- aim_bstream_rewind(&newrx->data);
-
- newrx->conn = conn;
-
- newrx->next = NULL; /* this will always be at the bottom */
-
- if (!sess->queue_incoming) {
- sess->queue_incoming = newrx;
- } else {
- aim_frame_t *cur;
-
- for (cur = sess->queue_incoming; cur->next; cur = cur->next) {
- ;
- }
- cur->next = newrx;
- }
-
- newrx->conn->lastactivity = time(NULL);
-
- return 0;
-}
-
-/*
- * Purge receive queue of all handled commands (->handled==1). Also
- * allows for selective freeing using ->nofree so that the client can
- * keep the data for various purposes.
- *
- * If ->nofree is nonzero, the frame will be delinked from the global list,
- * but will not be free'ed. The client _must_ keep a pointer to the
- * data -- libfaim will not! If the client marks ->nofree but
- * does not keep a pointer, it's lost forever.
- *
- */
-void aim_purge_rxqueue(aim_session_t *sess)
-{
- aim_frame_t *cur, **prev;
-
- for (prev = &sess->queue_incoming; (cur = *prev); ) {
- if (cur->handled) {
-
- *prev = cur->next;
-
- if (!cur->nofree) {
- aim_frame_destroy(cur);
- }
-
- } else {
- prev = &cur->next;
- }
- }
-
- return;
-}
-
-/*
- * Since aim_get_command will aim_conn_kill dead connections, we need
- * to clean up the rxqueue of unprocessed connections on that socket.
- *
- * XXX: this is something that was handled better in the old connection
- * handling method, but eh.
- */
-void aim_rxqueue_cleanbyconn(aim_session_t *sess, aim_conn_t *conn)
-{
- aim_frame_t *currx;
-
- for (currx = sess->queue_incoming; currx; currx = currx->next) {
- if ((!currx->handled) && (currx->conn == conn)) {
- currx->handled = 1;
- }
- }
- return;
-}
-
Index: otocols/oscar/search.c
===================================================================
--- protocols/oscar/search.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,106 +1,0 @@
-
-/*
- * aim_search.c
- *
- * TODO: Add aim_usersearch_name()
- *
- */
-
-#include
-
-/* XXX can this be integrated with the rest of the error handling? */
-static int error(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *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(sess, snac->id))) {
- imcb_error(sess->aux_data, "couldn't get snac");
- return 0;
- }
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, snac2->data /* address */);
- }
-
- /* XXX freesnac()? */
- if (snac2) {
- g_free(snac2->data);
- }
- g_free(snac2);
-
- return ret;
-}
-
-static int reply(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- int j = 0, m, ret = 0;
- aim_tlvlist_t *tlvlist;
- char *cur = NULL, *buf = NULL;
- aim_rxcallback_t userfunc;
- aim_snac_t *snac2;
- char *searchaddr = NULL;
-
- if ((snac2 = aim_remsnac(sess, snac->id))) {
- searchaddr = (char *) snac2->data;
- }
-
- tlvlist = aim_readtlvchain(bs);
- m = aim_counttlvchain(&tlvlist);
-
- /* XXX uhm. */
- while ((cur = aim_gettlv_str(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++;
- }
-
- aim_freetlvchain(&tlvlist);
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, searchaddr, j, buf);
- }
-
- /* XXX freesnac()? */
- if (snac2) {
- g_free(snac2->data);
- }
- g_free(snac2);
-
- g_free(buf);
-
- return ret;
-}
-
-static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
-
- if (snac->subtype == 0x0001) {
- return error(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x0003) {
- return reply(sess, mod, rx, snac, bs);
- }
-
- return 0;
-}
-
-int search_modfirst(aim_session_t *sess, aim_module_t *mod)
-{
-
- mod->family = 0x000a;
- mod->version = 0x0001;
- mod->toolid = 0x0110;
- mod->toolversion = 0x0629;
- mod->flags = 0;
- strncpy(mod->name, "search", sizeof(mod->name));
- mod->snachandler = snachandler;
-
- return 0;
-}
-
-
Index: otocols/oscar/search.h
===================================================================
--- protocols/oscar/search.h (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,4 +1,0 @@
-#ifndef __OSCAR_SEARCH_H__
-#define __OSCAR_SEARCH_H__
-
-#endif /* __OSCAR_SEARCH_H__ */
Index: otocols/oscar/service.c
===================================================================
--- protocols/oscar/service.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,806 +1,0 @@
-/*
- * Group 1. This is a very special group. All connections support
- * this group, as it does some particularly good things (like rate limiting).
- */
-
-#include
-
-#include "md5.h"
-
-/* Client Online (group 1, subtype 2) */
-int aim_clientready(aim_session_t *sess, aim_conn_t *conn)
-{
- aim_conn_inside_t *ins = (aim_conn_inside_t *) conn->inside;
- struct snacgroup *sg;
- aim_frame_t *fr;
- aim_snacid_t snacid;
-
- if (!ins) {
- return -EINVAL;
- }
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, 0x0001, 0x0002, 0x0000, NULL, 0);
- aim_putsnac(&fr->data, 0x0001, 0x0002, 0x0000, snacid);
-
- /*
- * Send only the tool versions that the server cares about (that it
- * marked as supporting in the server ready SNAC).
- */
- for (sg = ins->groups; sg; sg = sg->next) {
- aim_module_t *mod;
-
- if ((mod = aim__findmodulebygroup(sess, sg->group))) {
- aimbs_put16(&fr->data, mod->family);
- aimbs_put16(&fr->data, mod->version);
- aimbs_put16(&fr->data, mod->toolid);
- aimbs_put16(&fr->data, mod->toolversion);
- }
- }
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-/*
- * Host Online (group 1, type 3)
- *
- * 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(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- guint16 *families;
- int famcount;
-
-
- if (!(families = g_malloc(aim_bstream_empty(bs)))) {
- return 0;
- }
-
- for (famcount = 0; aim_bstream_empty(bs); famcount++) {
- families[famcount] = aimbs_get16(bs);
- aim_conn_addgroup(rx->conn, families[famcount]);
- }
-
- g_free(families);
-
-
- /*
- * 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_setversions(sess, rx->conn);
-
- return 1;
-}
-
-/* Service request (group 1, type 4) */
-int aim_reqservice(aim_session_t *sess, aim_conn_t *conn, guint16 serviceid)
-{
- return aim_genericreq_s(sess, conn, 0x0001, 0x0004, &serviceid);
-}
-
-/* Redirect (group 1, type 5) */
-static int redirect(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- struct aim_redirect_data redir;
- aim_rxcallback_t userfunc;
- aim_tlvlist_t *tlvlist;
- aim_snac_t *origsnac = NULL;
- int ret = 0;
-
- memset(&redir, 0, sizeof(redir));
-
- tlvlist = aim_readtlvchain(bs);
-
- if (!aim_gettlv(tlvlist, 0x000d, 1) ||
- !aim_gettlv(tlvlist, 0x0005, 1) ||
- !aim_gettlv(tlvlist, 0x0006, 1)) {
- aim_freetlvchain(&tlvlist);
- return 0;
- }
-
- redir.group = aim_gettlv16(tlvlist, 0x000d, 1);
- redir.ip = aim_gettlv_str(tlvlist, 0x0005, 1);
- redir.cookie = (guint8 *) aim_gettlv_str(tlvlist, 0x0006, 1);
-
- /* Fetch original SNAC so we can get csi if needed */
- origsnac = aim_remsnac(sess, snac->id);
-
- if ((redir.group == AIM_CONN_TYPE_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(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, &redir);
- }
-
- g_free((void *) redir.ip);
- g_free((void *) redir.cookie);
-
- if (origsnac) {
- g_free(origsnac->data);
- }
- g_free(origsnac);
-
- aim_freetlvchain(&tlvlist);
-
- return ret;
-}
-
-/* Request Rate Information. (group 1, type 6) */
-int aim_reqrates(aim_session_t *sess, aim_conn_t *conn)
-{
- return aim_genericreq_n(sess, conn, 0x0001, 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 are 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.
- *
- */
-
-static void rc_addclass(struct rateclass **head, struct rateclass *inrc)
-{
- struct rateclass *rc, *rc2;
-
- if (!(rc = g_malloc(sizeof(struct rateclass)))) {
- return;
- }
-
- memcpy(rc, inrc, sizeof(struct rateclass));
- rc->next = NULL;
-
- for (rc2 = *head; rc2 && rc2->next; rc2 = rc2->next) {
- ;
- }
-
- if (!rc2) {
- *head = rc;
- } else {
- rc2->next = rc;
- }
-
- return;
-}
-
-static struct rateclass *rc_findclass(struct rateclass **head, guint16 id)
-{
- struct rateclass *rc;
-
- for (rc = *head; rc; rc = rc->next) {
- if (rc->classid == id) {
- return rc;
- }
- }
-
- return NULL;
-}
-
-static void rc_addpair(struct rateclass *rc, guint16 group, guint16 type)
-{
- struct snacpair *sp, *sp2;
-
- if (!(sp = g_new0(struct snacpair, 1))) {
- return;
- }
-
- sp->group = group;
- sp->subtype = type;
- sp->next = NULL;
-
- for (sp2 = rc->members; sp2 && sp2->next; sp2 = sp2->next) {
- ;
- }
-
- if (!sp2) {
- rc->members = sp;
- } else {
- sp2->next = sp;
- }
-
- return;
-}
-
-/* Rate Parameters (group 1, type 7) */
-static int rateresp(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- aim_conn_inside_t *ins = (aim_conn_inside_t *) rx->conn->inside;
- guint16 numclasses, i;
- aim_rxcallback_t userfunc;
-
-
- /*
- * First are the parameters for each rate class.
- */
- numclasses = aimbs_get16(bs);
- for (i = 0; i < numclasses; i++) {
- struct rateclass rc;
-
- memset(&rc, 0, sizeof(struct rateclass));
-
- rc.classid = aimbs_get16(bs);
- rc.windowsize = aimbs_get32(bs);
- rc.clear = aimbs_get32(bs);
- rc.alert = aimbs_get32(bs);
- rc.limit = aimbs_get32(bs);
- rc.disconnect = aimbs_get32(bs);
- rc.current = aimbs_get32(bs);
- rc.max = aimbs_get32(bs);
-
- /*
- * The server will send an extra five bytes of parameters
- * depending on the version we advertised in 1/17. If we
- * didn't send 1/17 (evil!), then this will crash and you
- * die, as it will default to the old version but we have
- * the new version hardcoded here.
- */
- if (mod->version >= 3) {
- aimbs_getrawbuf(bs, rc.unknown, sizeof(rc.unknown));
- }
-
- rc_addclass(&ins->rates, &rc);
- }
-
- /*
- * Then the members of each class.
- */
- for (i = 0; i < numclasses; i++) {
- guint16 classid, count;
- struct rateclass *rc;
- int j;
-
- classid = aimbs_get16(bs);
- count = aimbs_get16(bs);
-
- rc = rc_findclass(&ins->rates, classid);
-
- for (j = 0; j < count; j++) {
- guint16 group, subtype;
-
- group = aimbs_get16(bs);
- subtype = aimbs_get16(bs);
-
- if (rc) {
- rc_addpair(rc, group, subtype);
- }
- }
- }
-
- /*
- * 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 more fun stuff later (not really).
- */
-
- /*
- * Last step in the conn init procedure is to acknowledge that we
- * agree to these draconian limitations.
- */
- aim_rates_addparam(sess, rx->conn);
-
- /*
- * Finally, tell the client it's ready to go...
- */
- if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE))) {
- userfunc(sess, rx);
- }
-
-
- return 1;
-}
-
-/* Add Rate Parameter (group 1, type 8) */
-int aim_rates_addparam(aim_session_t *sess, aim_conn_t *conn)
-{
- aim_conn_inside_t *ins = (aim_conn_inside_t *) conn->inside;
- aim_frame_t *fr;
- aim_snacid_t snacid;
- struct rateclass *rc;
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 512))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, 0x0001, 0x0008, 0x0000, NULL, 0);
- aim_putsnac(&fr->data, 0x0001, 0x0008, 0x0000, snacid);
-
- for (rc = ins->rates; rc; rc = rc->next) {
- aimbs_put16(&fr->data, rc->classid);
- }
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-/* Rate Change (group 1, type 0x0a) */
-static int ratechange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- aim_rxcallback_t userfunc;
- guint16 code, rateclass;
- guint32 currentavg, maxavg, windowsize, clear, alert, limit, disconnect;
-
- code = aimbs_get16(bs);
- rateclass = aimbs_get16(bs);
-
- windowsize = aimbs_get32(bs);
- clear = aimbs_get32(bs);
- alert = aimbs_get32(bs);
- limit = aimbs_get32(bs);
- disconnect = aimbs_get32(bs);
- currentavg = aimbs_get32(bs);
- maxavg = aimbs_get32(bs);
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- return userfunc(sess, rx, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg,
- maxavg);
- }
-
- return 0;
-}
-
-/*
- * 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.
- *
- */
-
-/* Service Pause (group 1, type 0x0b) */
-static int serverpause(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- aim_rxcallback_t userfunc;
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- return userfunc(sess, rx);
- }
-
- return 0;
-}
-
-/* Service Resume (group 1, type 0x0d) */
-static int serverresume(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- aim_rxcallback_t userfunc;
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- return userfunc(sess, rx);
- }
-
- return 0;
-}
-
-/* Request self-info (group 1, type 0x0e) */
-int aim_reqpersonalinfo(aim_session_t *sess, aim_conn_t *conn)
-{
- return aim_genericreq_n(sess, conn, 0x0001, 0x000e);
-}
-
-/* Self User Info (group 1, type 0x0f) */
-static int selfinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- aim_rxcallback_t userfunc;
- aim_userinfo_t userinfo;
-
- aim_extractuserinfo(sess, bs, &userinfo);
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- return userfunc(sess, rx, &userinfo);
- }
-
- return 0;
-}
-
-/* Evil Notification (group 1, type 0x10) */
-static int evilnotify(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- aim_rxcallback_t userfunc;
- guint16 newevil;
- aim_userinfo_t userinfo;
-
- memset(&userinfo, 0, sizeof(aim_userinfo_t));
-
- newevil = aimbs_get16(bs);
-
- if (aim_bstream_empty(bs)) {
- aim_extractuserinfo(sess, bs, &userinfo);
- }
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- return userfunc(sess, rx, newevil, &userinfo);
- }
-
- return 0;
-}
-
-/*
- * Service Migrate (group 1, type 0x12)
- *
- * 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(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- aim_rxcallback_t userfunc;
- int ret = 0;
- guint16 groupcount, i;
- aim_tlvlist_t *tl;
- 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 = aimbs_get16(bs);
- for (i = 0; i < groupcount; i++) {
- aimbs_get16(bs);
-
- imcb_error(sess->aux_data, "bifurcated migration unsupported");
- }
-
- tl = aim_readtlvchain(bs);
-
- if (aim_gettlv(tl, 0x0005, 1)) {
- ip = aim_gettlv_str(tl, 0x0005, 1);
- }
-
- cktlv = aim_gettlv(tl, 0x0006, 1);
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, ip, cktlv ? cktlv->value : NULL);
- }
-
- aim_freetlvchain(&tl);
- g_free(ip);
-
- return ret;
-}
-
-/* Message of the Day (group 1, type 0x13) */
-static int motd(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- aim_rxcallback_t userfunc;
- char *msg = NULL;
- int ret = 0;
- aim_tlvlist_t *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 = aimbs_get16(bs);
-
- /*
- * TLVs follow
- */
- tlvlist = aim_readtlvchain(bs);
-
- msg = aim_gettlv_str(tlvlist, 0x000b, 1);
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, id, msg);
- }
-
- g_free(msg);
-
- aim_freetlvchain(&tlvlist);
-
- return ret;
-}
-
-/*
- * Set privacy flags (group 1, type 0x14)
- *
- * Normally 0x03.
- *
- * Bit 1: Allows other AIM users to see how long you've been idle.
- * Bit 2: Allows other AIM users to see how long you've been a member.
- *
- */
-int aim_bos_setprivacyflags(aim_session_t *sess, aim_conn_t *conn, guint32 flags)
-{
- return aim_genericreq_l(sess, conn, 0x0001, 0x0014, &flags);
-}
-
-
-/*
- * Set client versions (group 1, subtype 0x17)
- *
- * 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.
- *
- */
-int aim_setversions(aim_session_t *sess, aim_conn_t *conn)
-{
- aim_conn_inside_t *ins = (aim_conn_inside_t *) conn->inside;
- struct snacgroup *sg;
- aim_frame_t *fr;
- aim_snacid_t snacid;
-
- if (!ins) {
- return -EINVAL;
- }
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, 0x0001, 0x0017, 0x0000, NULL, 0);
- aim_putsnac(&fr->data, 0x0001, 0x0017, 0x0000, snacid);
-
- /*
- * Send only the versions that the server cares about (that it
- * marked as supporting in the server ready SNAC).
- */
- for (sg = ins->groups; sg; sg = sg->next) {
- aim_module_t *mod;
-
- if ((mod = aim__findmodulebygroup(sess, sg->group))) {
- aimbs_put16(&fr->data, mod->family);
- aimbs_put16(&fr->data, mod->version);
- }
- }
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-/* Host versions (group 1, subtype 0x18) */
-static int hostversions(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- guint8 *versions;
-
- /* This is frivolous. (Thank you SmarterChild.) */
- aim_bstream_empty(bs); /* == vercount * 4 */
- versions = aimbs_getraw(bs, aim_bstream_empty(bs));
- g_free(versions);
-
- /*
- * Now request rates.
- */
- aim_reqrates(sess, rx->conn);
-
- return 1;
-}
-
-/*
- * Subtype 0x001e - Extended Status
- *
- * Sets your ICQ status (available, away, do not disturb, etc.)
- *
- * These are the same TLVs seen in user info. You can
- * also set 0x0008 and 0x000c.
- */
-int aim_setextstatus(aim_session_t *sess, aim_conn_t *conn, guint32 status)
-{
- aim_frame_t *fr;
- aim_snacid_t snacid;
- aim_tlvlist_t *tl = NULL;
- guint32 data;
- struct im_connection *ic = sess ? sess->aux_data : NULL;
-
- data = AIM_ICQ_STATE_HIDEIP | status; /* yay for error checking ;^) */
-
- if (ic && set_getbool(&ic->acc->set, "web_aware")) {
- data |= AIM_ICQ_STATE_WEBAWARE;
- }
-
- aim_addtlvtochain32(&tl, 0x0006, data); /* tlvlen */
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 8))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, 0x0001, 0x001e, 0x0000, NULL, 0);
- aim_putsnac(&fr->data, 0x0001, 0x001e, 0x0000, snacid);
-
- aim_writetlvchain(&fr->data, &tl);
- aim_freetlvchain(&tl);
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-/*
- * Starting this past week (26 Mar 2001, say), AOL has started sending
- * this nice little extra SNAC. AFAIK, it has never been used until now.
- *
- * The request contains eight bytes. The first four are an offset, the
- * second four are a length.
- *
- * The offset is an offset into aim.exe when it is mapped during execution
- * on Win32. So far, AOL has only been requesting bytes in static regions
- * of memory. (I won't put it past them to start requesting data in
- * less static regions -- regions that are initialized at run time, but still
- * before the client receives this request.)
- *
- * When the client receives the request, it adds it to the current ds
- * (0x00400000) and dereferences it, copying the data into a buffer which
- * it then runs directly through the MD5 hasher. The 16 byte output of
- * the hash is then sent back to the server.
- *
- * If the client does not send any data back, or the data does not match
- * the data that the specific client should have, the client will get the
- * following message from "AOL Instant Messenger":
- * "You have been disconnected from the AOL Instant Message Service (SM)
- * for accessing the AOL network using unauthorized software. You can
- * download a FREE, fully featured, and authorized client, here
- * http://www.aol.com/aim/download2.html"
- * The connection is then closed, receiving disconnect code 1, URL
- * http://www.aim.aol.com/errors/USER_LOGGED_OFF_NEW_LOGIN.html.
- *
- * Note, however, that numerous inconsistencies can cause the above error,
- * not just sending back a bad hash. Do not immediately suspect this code
- * if you get disconnected. AOL and the open/free software community have
- * played this game for a couple years now, generating the above message
- * on numerous occasions.
- *
- * Anyway, neener. We win again.
- *
- */
-/* Client verification (group 1, subtype 0x1f) */
-static int memrequest(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- aim_rxcallback_t userfunc;
- guint32 offset, len;
- aim_tlvlist_t *list;
- char *modname;
-
- offset = aimbs_get32(bs);
- len = aimbs_get32(bs);
- list = aim_readtlvchain(bs);
-
- modname = aim_gettlv_str(list, 0x0001, 1);
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- return userfunc(sess, rx, offset, len, modname);
- }
-
- g_free(modname);
- aim_freetlvchain(&list);
-
- return 0;
-}
-
-static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
-
- if (snac->subtype == 0x0003) {
- return hostonline(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x0005) {
- return redirect(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x0007) {
- return rateresp(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x000a) {
- return ratechange(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x000b) {
- return serverpause(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x000d) {
- return serverresume(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x000f) {
- return selfinfo(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x0010) {
- return evilnotify(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x0012) {
- return migrate(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x0013) {
- return motd(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x0018) {
- return hostversions(sess, mod, rx, snac, bs);
- } else if (snac->subtype == 0x001f) {
- return memrequest(sess, mod, rx, snac, bs);
- }
-
- return 0;
-}
-
-int general_modfirst(aim_session_t *sess, aim_module_t *mod)
-{
-
- mod->family = 0x0001;
- mod->version = 0x0003;
- mod->toolid = 0x0110;
- mod->toolversion = 0x0629;
- mod->flags = 0;
- strncpy(mod->name, "general", sizeof(mod->name));
- mod->snachandler = snachandler;
-
- return 0;
-}
-
Index: otocols/oscar/snac.c
===================================================================
--- protocols/oscar/snac.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,156 +1,0 @@
-/*
- *
- * 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 receieved.
- *
- * 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
-
-static aim_snacid_t aim_newsnac(aim_session_t *sess, aim_snac_t *newsnac);
-
-/*
- * Called from aim_session_init() to initialize the hash.
- */
-void aim_initsnachash(aim_session_t *sess)
-{
- int i;
-
- for (i = 0; i < AIM_SNAC_HASH_SIZE; i++) {
- sess->snac_hash[i] = NULL;
- }
-
- return;
-}
-
-aim_snacid_t aim_cachesnac(aim_session_t *sess, const guint16 family, const guint16 type, const guint16 flags,
- const void *data, const int datalen)
-{
- aim_snac_t snac;
-
- snac.id = sess->snacid_next++;
- snac.family = family;
- snac.type = type;
- snac.flags = flags;
-
- if (datalen) {
- if (!(snac.data = g_malloc(datalen))) {
- return 0; /* er... */
- }
- memcpy(snac.data, data, datalen);
- } else {
- snac.data = NULL;
- }
-
- return aim_newsnac(sess, &snac);
-}
-
-/*
- * Clones the passed snac structure and caches it in the
- * list/hash.
- */
-static aim_snacid_t aim_newsnac(aim_session_t *sess, aim_snac_t *newsnac)
-{
- aim_snac_t *snac;
- int index;
-
- if (!newsnac) {
- return 0;
- }
-
- if (!(snac = g_malloc(sizeof(aim_snac_t)))) {
- return 0;
- }
- memcpy(snac, newsnac, sizeof(aim_snac_t));
- snac->issuetime = time(NULL);
-
- index = snac->id % AIM_SNAC_HASH_SIZE;
-
- snac->next = (aim_snac_t *) sess->snac_hash[index];
- sess->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(aim_session_t *sess, aim_snacid_t id)
-{
- aim_snac_t *cur, **prev;
- int index;
-
- index = id % AIM_SNAC_HASH_SIZE;
-
- for (prev = (aim_snac_t **) &sess->snac_hash[index]; (cur = *prev); ) {
- if (cur->id == id) {
- *prev = cur->next;
- 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. Garabage collection. Plain and simple.
- *
- * maxage is the _minimum_ age in seconds to keep SNACs.
- *
- */
-void aim_cleansnacs(aim_session_t *sess, int maxage)
-{
- int i;
-
- for (i = 0; i < AIM_SNAC_HASH_SIZE; i++) {
- aim_snac_t *cur, **prev;
- time_t curtime;
-
- if (!sess->snac_hash[i]) {
- continue;
- }
-
- curtime = time(NULL); /* done here in case we waited for the lock */
-
- for (prev = (aim_snac_t **) &sess->snac_hash[i]; (cur = *prev); ) {
- if ((curtime - cur->issuetime) > maxage) {
-
- *prev = cur->next;
-
- /* XXX should we have destructors here? */
- g_free(cur->data);
- g_free(cur);
-
- } else {
- prev = &cur->next;
- }
- }
- }
-
- return;
-}
-
-int aim_putsnac(aim_bstream_t *bs, guint16 family, guint16 subtype, guint16 flags, aim_snacid_t snacid)
-{
-
- aimbs_put16(bs, family);
- aimbs_put16(bs, subtype);
- aimbs_put16(bs, flags);
- aimbs_put32(bs, snacid);
-
- return 10;
-}
Index: otocols/oscar/ssi.c
===================================================================
--- protocols/oscar/ssi.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,1339 +1,0 @@
-/*
- * Server-Side/Stored Information.
- *
- * Relatively new facility that allows storing of certain types of information,
- * such as a users buddy list, permit/deny list, and permit/deny preferences,
- * to be stored on the server, so that they can be accessed from any client.
- *
- * We keep a copy of the ssi data in sess->ssi, because the data needs to be
- * accessed for various reasons. So all the "aim_ssi_itemlist_bleh" functions
- * near the top just manage the local data.
- *
- * 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.
- *
- * XXX - Test for memory leaks
- * XXX - Better parsing of rights, and use the rights info to limit adds
- *
- */
-
-#include
-#include "ssi.h"
-
-/**
- * Locally add a new item to the given item list.
- *
- * @param list A pointer to a pointer to the current list of items.
- * @param parent A pointer to the parent group, or NULL if the item should have no
- * parent group (ie. the group ID# should be 0).
- * @param name A null terminated string of the name of the new item, or NULL if the
- * item should have no name.
- * @param type The type of the item, 0x0001 for a contact, 0x0002 for a group, etc.
- * @return The newly created item.
- */
-static struct aim_ssi_item *aim_ssi_itemlist_add(struct aim_ssi_item **list, struct aim_ssi_item *parent, char *name,
- guint16 type)
-{
- int i;
- struct aim_ssi_item *cur, *newitem;
-
- if (!(newitem = g_new0(struct aim_ssi_item, 1))) {
- return NULL;
- }
-
- /* Set the name */
- if (name) {
- if (!(newitem->name = (char *) g_malloc((strlen(name) + 1) * sizeof(char)))) {
- g_free(newitem);
- return NULL;
- }
- strcpy(newitem->name, name);
- } else {
- newitem->name = NULL;
- }
-
- /* Set the group ID# and the buddy ID# */
- newitem->gid = 0x0000;
- newitem->bid = 0x0000;
- if (type == AIM_SSI_TYPE_GROUP) {
- if (name) {
- do {
- newitem->gid += 0x0001;
- for (cur = *list, i = 0; ((cur) && (!i)); cur = cur->next) {
- if ((cur->bid == newitem->bid) && (cur->gid == newitem->gid)) {
- i = 1;
- }
- }
- } while (i);
- }
- } else {
- if (parent) {
- newitem->gid = parent->gid;
- }
- do {
- newitem->bid += 0x0001;
- for (cur = *list, i = 0; ((cur) && (!i)); cur = cur->next) {
- if ((cur->bid == newitem->bid) && (cur->gid == newitem->gid)) {
- i = 1;
- }
- }
- } while (i);
- }
-
- /* Set the rest */
- newitem->type = type;
- newitem->data = NULL;
- newitem->next = *list;
- *list = newitem;
-
- return newitem;
-}
-
-/**
- * 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 parentgroup A pointer to the group who's additional data you want to rebuild.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-static int aim_ssi_itemlist_rebuildgroup(struct aim_ssi_item **list, struct aim_ssi_item *parentgroup)
-{
- int newlen; //, i;
- struct aim_ssi_item *cur;
-
- /* Free the old additional data */
- if (parentgroup->data) {
- aim_freetlvchain((aim_tlvlist_t **) &parentgroup->data);
- parentgroup->data = NULL;
- }
-
- /* Find the length for the new additional data */
- newlen = 0;
- if (parentgroup->gid == 0x0000) {
- for (cur = *list; cur; cur = cur->next) {
- if ((cur->gid != 0x0000) && (cur->type == AIM_SSI_TYPE_GROUP)) {
- newlen += 2;
- }
- }
- } else {
- for (cur = *list; cur; cur = cur->next) {
- if ((cur->gid == parentgroup->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) {
- newlen += 2;
- }
- }
- }
-
- /* Rebuild the additional data */
- if (newlen > 0) {
- guint8 *newdata;
-
- if (!(newdata = (guint8 *) g_malloc((newlen) * sizeof(guint8)))) {
- return -ENOMEM;
- }
- newlen = 0;
- if (parentgroup->gid == 0x0000) {
- for (cur = *list; cur; cur = cur->next) {
- if ((cur->gid != 0x0000) && (cur->type == AIM_SSI_TYPE_GROUP)) {
- newlen += aimutil_put16(newdata + newlen, cur->gid);
- }
- }
- } else {
- for (cur = *list; cur; cur = cur->next) {
- if ((cur->gid == parentgroup->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) {
- newlen += aimutil_put16(newdata + newlen, cur->bid);
- }
- }
- }
- aim_addtlvtochain_raw((aim_tlvlist_t **) &(parentgroup->data), 0x00c8, newlen, newdata);
-
- g_free(newdata);
- }
-
- return 0;
-}
-
-/**
- * Locally free all of the stored buddy list information.
- *
- * @param sess The oscar session.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-static int aim_ssi_freelist(aim_session_t *sess)
-{
- struct aim_ssi_item *cur, *delitem;
-
- cur = sess->ssi.items;
- while (cur) {
- if (cur->name) {
- g_free(cur->name);
- }
- if (cur->data) {
- aim_freetlvchain((aim_tlvlist_t **) &cur->data);
- }
- delitem = cur;
- cur = cur->next;
- g_free(delitem);
- }
-
- sess->ssi.items = NULL;
- sess->ssi.revision = 0;
- sess->ssi.timestamp = (time_t) 0;
-
- return 0;
-}
-
-/**
- * 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_item *list, guint16 gid, guint16 bid)
-{
- struct aim_ssi_item *cur;
-
- for (cur = list; cur; cur = cur->next) {
- if ((cur->gid == gid) && (cur->bid == bid)) {
- return cur;
- }
- }
- return NULL;
-}
-
-/**
- * Locally find an item given a group name, screen name, and type. If group name
- * and screen 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_item *list, char *gn, char *sn, guint16 type)
-{
- struct aim_ssi_item *cur;
-
- if (!list) {
- return NULL;
- }
-
- if (gn && sn) { /* For finding buddies in groups */
- for (cur = list; cur; cur = cur->next) {
- if ((cur->type == type) && (cur->name) && !(aim_sncmp(cur->name, sn))) {
- struct aim_ssi_item *curg;
- for (curg = list; curg; curg = curg->next) {
- if ((curg->type == AIM_SSI_TYPE_GROUP) && (curg->gid == cur->gid) &&
- (curg->name) && !(aim_sncmp(curg->name, gn))) {
- return cur;
- }
- }
- }
- }
-
- } else if (sn) { /* For finding groups, permits, denies, and ignores */
- for (cur = list; cur; cur = cur->next) {
- if ((cur->type == type) && (cur->name) && !(aim_sncmp(cur->name, sn))) {
- return cur;
- }
- }
-
- /* For stuff without names--permit deny setting, visibility mask, etc. */
- } else { for (cur = list; cur; cur = cur->next) {
- if (cur->type == type) {
- return cur;
- }
- }
- }
-
- return NULL;
-}
-
-/**
- * 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 item if found, else return NULL;
- */
-struct aim_ssi_item *aim_ssi_itemlist_findparent(struct aim_ssi_item *list, char *sn)
-{
- struct aim_ssi_item *cur, *curg;
-
- if (!list || !sn) {
- return NULL;
- }
- if (!(cur = aim_ssi_itemlist_finditem(list, NULL, sn, AIM_SSI_TYPE_BUDDY))) {
- return NULL;
- }
- for (curg = list; curg; curg = curg->next) {
- if ((curg->type == AIM_SSI_TYPE_GROUP) && (curg->gid == cur->gid)) {
- return curg;
- }
- }
- return NULL;
-}
-
-/**
- * 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_item *list)
-{
- struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PDINFO);
-
- if (cur) {
- aim_tlvlist_t *tlvlist = cur->data;
- if (tlvlist) {
- aim_tlv_t *tlv = aim_gettlv(tlvlist, 0x00ca, 1);
- if (tlv && tlv->value) {
- return aimutil_get8(tlv->value);
- }
- }
- }
- return 0;
-}
-
-/**
- * Add the given packet to the holding queue. We totally need to send SSI SNACs one at
- * a time, so we have a local queue where packets get put before they are sent, and
- * then we send stuff one at a time, nice and orderly-like.
- *
- * @param sess The oscar session.
- * @param conn The bos connection for this session.
- * @param fr The newly created SNAC that you want to send.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-static int aim_ssi_enqueue(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *fr)
-{
- aim_frame_t *cur;
-
- if (!sess || !conn || !fr) {
- return -EINVAL;
- }
-
- fr->next = NULL;
- if (sess->ssi.holding_queue == NULL) {
- sess->ssi.holding_queue = fr;
- if (!sess->ssi.waiting_for_ack) {
- aim_ssi_modbegin(sess, conn);
- }
- } else {
- for (cur = sess->ssi.holding_queue; cur->next; cur = cur->next) {
- ;
- }
- cur->next = fr;
- }
-
- return 0;
-}
-
-/**
- * Send the next SNAC from the holding queue. This is called
- * automatically when an ack from an add, mod, or del is received.
- * If the queue is empty, it sends the modend SNAC.
- *
- * @param sess The oscar session.
- * @param conn The bos connection for this session.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-static int aim_ssi_dispatch(aim_session_t *sess, aim_conn_t *conn)
-{
- aim_frame_t *cur;
-
- if (!sess || !conn) {
- return -EINVAL;
- }
-
- if (!sess->ssi.waiting_for_ack) {
- if (sess->ssi.holding_queue) {
- sess->ssi.waiting_for_ack = 1;
- cur = sess->ssi.holding_queue->next;
- sess->ssi.holding_queue->next = NULL;
- aim_tx_enqueue(sess, sess->ssi.holding_queue);
- sess->ssi.holding_queue = cur;
- } else {
- aim_ssi_modend(sess, conn);
- }
- }
-
- return 0;
-}
-
-/**
- * Add an array of screen names to the given group.
- *
- * @param sess The oscar session.
- * @param conn The bos connection for this session.
- * @param gn The name of the group to which you want to add these names.
- * @param sn An array of null terminated strings of the names you want to add.
- * @param num The number of screen names you are adding (size of the sn array).
- * @param flags 1 - Add with TLV(0x66)
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_addbuddies(aim_session_t *sess, aim_conn_t *conn, char *gn, char **sn, unsigned int num, unsigned int flags)
-{
- struct aim_ssi_item *parentgroup, **newitems;
- guint16 i;
-
- if (!sess || !conn || !gn || !sn || !num) {
- return -EINVAL;
- }
-
- /* Look up the parent group */
- if (!(parentgroup = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn, AIM_SSI_TYPE_GROUP))) {
- aim_ssi_addgroups(sess, conn, &gn, 1);
- if (!(parentgroup = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn, AIM_SSI_TYPE_GROUP))) {
- return -ENOMEM;
- }
- }
-
- /* Allocate an array of pointers to each of the new items */
- if (!(newitems = g_new0(struct aim_ssi_item *, num))) {
- return -ENOMEM;
- }
-
- /* Add items to the local list, and index them in the array */
- for (i = 0; i < num; i++) {
- if (!(newitems[i] = aim_ssi_itemlist_add(&sess->ssi.items, parentgroup, sn[i], AIM_SSI_TYPE_BUDDY))) {
- g_free(newitems);
- return -ENOMEM;
- } else if (flags & 1) {
- aim_tlvlist_t *tl = NULL;
- aim_addtlvtochain_noval(&tl, 0x66);
- newitems[i]->data = tl;
- }
- }
-
- /* Send the add item SNAC */
- if ((i = aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD))) {
- g_free(newitems);
- return -i;
- }
-
- /* Free the array of pointers to each of the new items */
- g_free(newitems);
-
- /* Rebuild the additional data in the parent group */
- if ((i = aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup))) {
- return i;
- }
-
- /* Send the mod item SNAC */
- if ((i = aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD))) {
- return i;
- }
-
- /* Begin sending SSI SNACs */
- if (!(i = aim_ssi_dispatch(sess, conn))) {
- return i;
- }
-
- return 0;
-}
-
-/**
- * Add the master group (the group containing all groups). This is called by
- * aim_ssi_addgroups, if necessary.
- *
- * @param sess The oscar session.
- * @param conn The bos connection for this session.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_addmastergroup(aim_session_t *sess, aim_conn_t *conn)
-{
- struct aim_ssi_item *newitem;
-
- if (!sess || !conn) {
- return -EINVAL;
- }
-
- /* Add the item to the local list, and keep a pointer to it */
- if (!(newitem = aim_ssi_itemlist_add(&sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_GROUP))) {
- return -ENOMEM;
- }
-
- /* If there are any existing groups (technically there shouldn't be, but */
- /* just in case) then add their group ID#'s to the additional data */
- aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, newitem);
-
- /* Send the add item SNAC */
- aim_ssi_addmoddel(sess, conn, &newitem, 1, AIM_CB_SSI_ADD);
-
- /* Begin sending SSI SNACs */
- aim_ssi_dispatch(sess, conn);
-
- return 0;
-}
-
-/**
- * Add an array of groups to the list.
- *
- * @param sess The oscar session.
- * @param conn The bos connection for this session.
- * @param gn An array of null terminated strings of the names you want to add.
- * @param num The number of groups names you are adding (size of the sn array).
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_addgroups(aim_session_t *sess, aim_conn_t *conn, char **gn, unsigned int num)
-{
- struct aim_ssi_item *parentgroup, **newitems;
- guint16 i;
-
- if (!sess || !conn || !gn || !num) {
- return -EINVAL;
- }
-
- /* Look up the parent group */
- if (!(parentgroup = aim_ssi_itemlist_find(sess->ssi.items, 0, 0))) {
- aim_ssi_addmastergroup(sess, conn);
- if (!(parentgroup = aim_ssi_itemlist_find(sess->ssi.items, 0, 0))) {
- return -ENOMEM;
- }
- }
-
- /* Allocate an array of pointers to each of the new items */
- if (!(newitems = g_new0(struct aim_ssi_item *, num))) {
- return -ENOMEM;
- }
-
- /* Add items to the local list, and index them in the array */
- for (i = 0; i < num; i++) {
- if (!(newitems[i] = aim_ssi_itemlist_add(&sess->ssi.items, parentgroup, gn[i], AIM_SSI_TYPE_GROUP))) {
- g_free(newitems);
- return -ENOMEM;
- }
- }
-
- /* Send the add item SNAC */
- if ((i = aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD))) {
- g_free(newitems);
- return -i;
- }
-
- /* Free the array of pointers to each of the new items */
- g_free(newitems);
-
- /* Rebuild the additional data in the parent group */
- if ((i = aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup))) {
- return i;
- }
-
- /* Send the mod item SNAC */
- if ((i = aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD))) {
- return i;
- }
-
- /* Begin sending SSI SNACs */
- if (!(i = aim_ssi_dispatch(sess, conn))) {
- return i;
- }
-
- return 0;
-}
-
-/**
- * Add an array of a certain type of item to the list. This can be used for
- * permit buddies, deny buddies, ICQ's ignore buddies, and probably other
- * types, also.
- *
- * @param sess The oscar session.
- * @param conn The bos connection for this session.
- * @param sn An array of null terminated strings of the names you want to add.
- * @param num The number of groups names you are adding (size of the sn array).
- * @param type The type of item you want to add. See the AIM_SSI_TYPE_BLEH
- * #defines in aim.h.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_addpord(aim_session_t *sess, aim_conn_t *conn, char **sn, unsigned int num, guint16 type)
-{
- struct aim_ssi_item **newitems;
- guint16 i;
-
- if (!sess || !conn || !sn || !num) {
- return -EINVAL;
- }
-
- /* Allocate an array of pointers to each of the new items */
- if (!(newitems = g_new0(struct aim_ssi_item *, num))) {
- return -ENOMEM;
- }
-
- /* Add items to the local list, and index them in the array */
- for (i = 0; i < num; i++) {
- if (!(newitems[i] = aim_ssi_itemlist_add(&sess->ssi.items, NULL, sn[i], type))) {
- g_free(newitems);
- return -ENOMEM;
- }
- }
-
- /* Send the add item SNAC */
- if ((i = aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD))) {
- g_free(newitems);
- return -i;
- }
-
- /* Free the array of pointers to each of the new items */
- g_free(newitems);
-
- /* Begin sending SSI SNACs */
- if (!(i = aim_ssi_dispatch(sess, conn))) {
- return i;
- }
-
- return 0;
-}
-
-/**
- * Move a buddy from one group to another group. This basically just deletes the
- * buddy and re-adds it.
- *
- * @param sess The oscar session.
- * @param conn The bos connection for this session.
- * @param oldgn The group that the buddy is currently in.
- * @param newgn The group that the buddy should be moved in to.
- * @param sn The name of the buddy to be moved.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_movebuddy(aim_session_t *sess, aim_conn_t *conn, char *oldgn, char *newgn, char *sn)
-{
- struct aim_ssi_item **groups, *buddy, *cur;
- guint16 i;
-
- if (!sess || !conn || !oldgn || !newgn || !sn) {
- return -EINVAL;
- }
-
- /* Look up the buddy */
- if (!(buddy = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, sn, AIM_SSI_TYPE_BUDDY))) {
- return -ENOMEM;
- }
-
- /* Allocate an array of pointers to the two groups */
- if (!(groups = g_new0(struct aim_ssi_item *, 2))) {
- return -ENOMEM;
- }
-
- /* Look up the old parent group */
- if (!(groups[0] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, oldgn, AIM_SSI_TYPE_GROUP))) {
- g_free(groups);
- return -ENOMEM;
- }
-
- /* Look up the new parent group */
- if (!(groups[1] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, newgn, AIM_SSI_TYPE_GROUP))) {
- g_free(groups);
- return -ENOMEM;
- }
-
- /* Send the delete item SNAC */
- aim_ssi_addmoddel(sess, conn, &buddy, 1, AIM_CB_SSI_DEL);
-
- /* Put the buddy in the new group */
- buddy->gid = groups[1]->gid;
-
- /* Assign a new buddy ID#, because the new group might already have a buddy with this ID# */
- buddy->bid = 0;
- do {
- buddy->bid += 0x0001;
- for (cur = sess->ssi.items, i = 0; ((cur) && (!i)); cur = cur->next) {
- if ((cur->bid == buddy->bid) && (cur->gid == buddy->gid) && (cur->type == AIM_SSI_TYPE_BUDDY) &&
- (cur->name) && aim_sncmp(cur->name, buddy->name)) {
- i = 1;
- }
- }
- } while (i);
-
- /* Rebuild the additional data in the two parent groups */
- aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, groups[0]);
- aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, groups[1]);
-
- /* Send the add item SNAC */
- aim_ssi_addmoddel(sess, conn, &buddy, 1, AIM_CB_SSI_ADD);
-
- /* Send the mod item SNAC */
- aim_ssi_addmoddel(sess, conn, groups, 2, AIM_CB_SSI_MOD);
-
- /* Free the temporary array */
- g_free(groups);
-
- /* Begin sending SSI SNACs */
- aim_ssi_dispatch(sess, conn);
-
- return 0;
-}
-
-/**
- * Delete an array of screen names from the given group.
- *
- * @param sess The oscar session.
- * @param conn The bos connection for this session.
- * @param gn The name of the group from which you want to delete these names.
- * @param sn An array of null terminated strings of the names you want to delete.
- * @param num The number of screen names you are deleting (size of the sn array).
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_delbuddies(aim_session_t *sess, aim_conn_t *conn, char *gn, char **sn, unsigned int num)
-{
- struct aim_ssi_item *cur, *parentgroup, **delitems;
- int i;
-
- if (!sess || !conn || !gn || !sn || !num) {
- return -EINVAL;
- }
-
- /* Look up the parent group */
- if (!(parentgroup = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn, AIM_SSI_TYPE_GROUP))) {
- return -EINVAL;
- }
-
- /* Allocate an array of pointers to each of the items to be deleted */
- delitems = g_new0(struct aim_ssi_item *, num);
-
- /* Make the delitems array a pointer to the aim_ssi_item structs to be deleted */
- for (i = 0; i < num; i++) {
- if (!(delitems[i] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, sn[i], AIM_SSI_TYPE_BUDDY))) {
- g_free(delitems);
- return -EINVAL;
- }
-
- /* Remove the delitems from the item list */
- if (sess->ssi.items == delitems[i]) {
- sess->ssi.items = sess->ssi.items->next;
- } else {
- for (cur = sess->ssi.items; (cur->next && (cur->next != delitems[i])); cur = cur->next) {
- ;
- }
- if (cur->next) {
- cur->next = cur->next->next;
- }
- }
- }
-
- /* Send the del item SNAC */
- aim_ssi_addmoddel(sess, conn, delitems, num, AIM_CB_SSI_DEL);
-
- /* Free the items */
- for (i = 0; i < num; i++) {
- if (delitems[i]->name) {
- g_free(delitems[i]->name);
- }
- if (delitems[i]->data) {
- aim_freetlvchain((aim_tlvlist_t **) &delitems[i]->data);
- }
- g_free(delitems[i]);
- }
- g_free(delitems);
-
- /* Rebuild the additional data in the parent group */
- aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup);
-
- /* Send the mod item SNAC */
- aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD);
-
- /* Delete the group, but only if it's empty */
- if (!parentgroup->data) {
- aim_ssi_delgroups(sess, conn, &parentgroup->name, 1);
- }
-
- /* Begin sending SSI SNACs */
- aim_ssi_dispatch(sess, conn);
-
- return 0;
-}
-
-/**
- * Delete the master group from the item list. There can be only one.
- * Er, so just find the one master group and delete it.
- *
- * @param sess The oscar session.
- * @param conn The bos connection for this session.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_delmastergroup(aim_session_t *sess, aim_conn_t *conn)
-{
- struct aim_ssi_item *cur, *delitem;
-
- if (!sess || !conn) {
- return -EINVAL;
- }
-
- /* Make delitem a pointer to the aim_ssi_item to be deleted */
- if (!(delitem = aim_ssi_itemlist_find(sess->ssi.items, 0, 0))) {
- return -EINVAL;
- }
-
- /* Remove delitem from the item list */
- if (sess->ssi.items == delitem) {
- sess->ssi.items = sess->ssi.items->next;
- } else {
- for (cur = sess->ssi.items; (cur->next && (cur->next != delitem)); cur = cur->next) {
- ;
- }
- if (cur->next) {
- cur->next = cur->next->next;
- }
- }
-
- /* Send the del item SNAC */
- aim_ssi_addmoddel(sess, conn, &delitem, 1, AIM_CB_SSI_DEL);
-
- /* Free the item */
- if (delitem->name) {
- g_free(delitem->name);
- }
- if (delitem->data) {
- aim_freetlvchain((aim_tlvlist_t **) &delitem->data);
- }
- g_free(delitem);
-
- /* Begin sending SSI SNACs */
- aim_ssi_dispatch(sess, conn);
-
- return 0;
-}
-
-/**
- * Delete an array of groups.
- *
- * @param sess The oscar session.
- * @param conn The bos connection for this session.
- * @param gn An array of null terminated strings of the groups you want to delete.
- * @param num The number of groups you are deleting (size of the gn array).
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_delgroups(aim_session_t *sess, aim_conn_t *conn, char **gn, unsigned int num)
-{
- struct aim_ssi_item *cur, *parentgroup, **delitems;
- int i;
-
- if (!sess || !conn || !gn || !num) {
- return -EINVAL;
- }
-
- /* Look up the parent group */
- if (!(parentgroup = aim_ssi_itemlist_find(sess->ssi.items, 0, 0))) {
- return -EINVAL;
- }
-
- /* Allocate an array of pointers to each of the items to be deleted */
- delitems = g_new0(struct aim_ssi_item *, num);
-
- /* Make the delitems array a pointer to the aim_ssi_item structs to be deleted */
- for (i = 0; i < num; i++) {
- if (!(delitems[i] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn[i], AIM_SSI_TYPE_GROUP))) {
- g_free(delitems);
- return -EINVAL;
- }
-
- /* Remove the delitems from the item list */
- if (sess->ssi.items == delitems[i]) {
- sess->ssi.items = sess->ssi.items->next;
- } else {
- for (cur = sess->ssi.items; (cur->next && (cur->next != delitems[i])); cur = cur->next) {
- ;
- }
- if (cur->next) {
- cur->next = cur->next->next;
- }
- }
- }
-
- /* Send the del item SNAC */
- aim_ssi_addmoddel(sess, conn, delitems, num, AIM_CB_SSI_DEL);
-
- /* Free the items */
- for (i = 0; i < num; i++) {
- if (delitems[i]->name) {
- g_free(delitems[i]->name);
- }
- if (delitems[i]->data) {
- aim_freetlvchain((aim_tlvlist_t **) &delitems[i]->data);
- }
- g_free(delitems[i]);
- }
- g_free(delitems);
-
- /* Rebuild the additional data in the parent group */
- aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup);
-
- /* Send the mod item SNAC */
- aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD);
-
- /* Delete the group, but only if it's empty */
- if (!parentgroup->data) {
- aim_ssi_delmastergroup(sess, conn);
- }
-
- /* Begin sending SSI SNACs */
- aim_ssi_dispatch(sess, conn);
-
- return 0;
-}
-
-/**
- * Delete an array of a certain type of item from the list. This can be
- * used for permit buddies, deny buddies, ICQ's ignore buddies, and
- * probably other types, also.
- *
- * @param sess The oscar session.
- * @param conn The bos connection for this session.
- * @param sn An array of null terminated strings of the items you want to delete.
- * @param num The number of items you are deleting (size of the sn array).
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_delpord(aim_session_t *sess, aim_conn_t *conn, char **sn, unsigned int num, guint16 type)
-{
- struct aim_ssi_item *cur, **delitems;
- int i;
-
- if (!sess || !conn || !sn || !num || (type != AIM_SSI_TYPE_PERMIT && type != AIM_SSI_TYPE_DENY)) {
- return -EINVAL;
- }
-
- /* Allocate an array of pointers to each of the items to be deleted */
- delitems = g_new0(struct aim_ssi_item *, num);
-
- /* Make the delitems array a pointer to the aim_ssi_item structs to be deleted */
- for (i = 0; i < num; i++) {
- if (!(delitems[i] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, sn[i], type))) {
- g_free(delitems);
- return -EINVAL;
- }
-
- /* Remove the delitems from the item list */
- if (sess->ssi.items == delitems[i]) {
- sess->ssi.items = sess->ssi.items->next;
- } else {
- for (cur = sess->ssi.items; (cur->next && (cur->next != delitems[i])); cur = cur->next) {
- ;
- }
- if (cur->next) {
- cur->next = cur->next->next;
- }
- }
- }
-
- /* Send the del item SNAC */
- aim_ssi_addmoddel(sess, conn, delitems, num, AIM_CB_SSI_DEL);
-
- /* Free the items */
- for (i = 0; i < num; i++) {
- if (delitems[i]->name) {
- g_free(delitems[i]->name);
- }
- if (delitems[i]->data) {
- aim_freetlvchain((aim_tlvlist_t **) &delitems[i]->data);
- }
- g_free(delitems[i]);
- }
- g_free(delitems);
-
- /* Begin sending SSI SNACs */
- aim_ssi_dispatch(sess, conn);
-
- return 0;
-}
-
-/*
- * Request SSI Rights.
- */
-int aim_ssi_reqrights(aim_session_t *sess, aim_conn_t *conn)
-{
- return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_REQRIGHTS);
-}
-
-/*
- * SSI Rights Information.
- */
-static int parserights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- int ret = 0;
- aim_rxcallback_t userfunc;
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx);
- }
-
- return ret;
-}
-
-int aim_ssi_reqalldata(aim_session_t *sess, aim_conn_t *conn)
-{
- aim_frame_t *fr;
- aim_snacid_t snacid;
-
- if (!sess || !conn) {
- return -EINVAL;
- }
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_REQFULLLIST, 0x0000, NULL, 0);
-
- aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_REQFULLLIST, 0x0000, snacid);
-
- aim_tx_enqueue(sess, fr);
-
- return 0;
-}
-
-/*
- * SSI Data.
- */
-static int parsedata(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- int ret = 0;
- aim_rxcallback_t userfunc;
- struct aim_ssi_item *cur = NULL;
- guint8 fmtver; /* guess */
- guint16 revision;
- guint32 timestamp;
-
- /* When you set the version for the SSI family to 2-4, the beginning of this changes.
- * Instead of the version and then the revision, there is "0x0006" and then a type
- * 0x0001 TLV containing the 2 byte SSI family version that you sent earlier. Also,
- * the SNAC flags go from 0x0000 to 0x8000. I guess the 0x0006 is the length of the
- * TLV(s) that follow. The rights SNAC does the same thing, with the differing flag
- * and everything.
- */
-
- fmtver = aimbs_get8(bs); /* Version of ssi data. Should be 0x00 */
- revision = aimbs_get16(bs); /* # of times ssi data has been modified */
- if (revision != 0) {
- sess->ssi.revision = revision;
- }
-
- for (cur = sess->ssi.items; cur && cur->next; cur = cur->next) {
- ;
- }
-
- while (aim_bstream_empty(bs) > 4) { /* last four bytes are stamp */
- guint16 namelen, tbslen;
-
- if (!sess->ssi.items) {
- if (!(sess->ssi.items = g_new0(struct aim_ssi_item, 1))) {
- return -ENOMEM;
- }
- cur = sess->ssi.items;
- } else {
- if (!(cur->next = g_new0(struct aim_ssi_item, 1))) {
- return -ENOMEM;
- }
- cur = cur->next;
- }
-
- if ((namelen = aimbs_get16(bs))) {
- cur->name = aimbs_getstr(bs, namelen);
- }
- cur->gid = aimbs_get16(bs);
- cur->bid = aimbs_get16(bs);
- cur->type = aimbs_get16(bs);
-
- if ((tbslen = aimbs_get16(bs))) {
- aim_bstream_t tbs;
-
- aim_bstream_init(&tbs, bs->data + bs->offset /* XXX */, tbslen);
- cur->data = (void *) aim_readtlvchain(&tbs);
- aim_bstream_advance(bs, tbslen);
- }
- }
-
- timestamp = aimbs_get32(bs);
- if (timestamp != 0) {
- sess->ssi.timestamp = timestamp;
- }
- sess->ssi.received_data = 1;
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, fmtver, sess->ssi.revision, sess->ssi.timestamp, sess->ssi.items);
- }
-
- return ret;
-}
-
-/*
- * SSI Data Enable Presence.
- *
- * 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(aim_session_t *sess, aim_conn_t *conn)
-{
- return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, 0x0007);
-}
-
-/*
- * Stuff for SSI authorizations. The code used to work with the old im_ch4
- * messages, but those are supposed to be obsolete. This is probably
- * ICQ-specific.
- */
-
-/**
- * Request authorization to add someone to the server-side buddy list.
- *
- * @param sess The oscar session.
- * @param conn The bos connection for this session.
- * @param uin The contact's ICQ UIN.
- * @param reason The reason string to send with the request.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_auth_request(aim_session_t *sess, aim_conn_t *conn, char *uin, char *reason)
-{
- aim_frame_t *fr;
- aim_snacid_t snacid;
- int snaclen;
-
- snaclen = 10 + 1 + strlen(uin) + 2 + strlen(reason) + 2;
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, snaclen))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREQ, 0x0000, NULL, 0);
- aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREQ, 0x0000, snacid);
-
- aimbs_put8(&fr->data, strlen(uin));
- aimbs_putraw(&fr->data, (guint8 *) uin, strlen(uin));
- aimbs_put16(&fr->data, strlen(reason));
- aimbs_putraw(&fr->data, (guint8 *) reason, strlen(reason));
- aimbs_put16(&fr->data, 0);
-
- aim_tx_enqueue(sess, fr);
-
- return(0);
-}
-
-/**
- * Reply to an authorization request to add someone to the server-side buddy list.
- *
- * @param sess The oscar session.
- * @param conn The bos connection for this session.
- * @param uin The contact's ICQ UIN.
- * @param yesno 1 == Permit, 0 == Deny
- * @param reason The reason string to send with the request.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_auth_reply(aim_session_t *sess, aim_conn_t *conn, char *uin, int yesno, char *reason)
-{
- aim_frame_t *fr;
- aim_snacid_t snacid;
- int snaclen;
-
- snaclen = 10 + 1 + strlen(uin) + 3 + strlen(reason);
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, snaclen))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREP, 0x0000, NULL, 0);
- aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREP, 0x0000, snacid);
-
- aimbs_put8(&fr->data, strlen(uin));
- aimbs_putraw(&fr->data, (guint8 *) uin, strlen(uin));
- aimbs_put8(&fr->data, yesno);
- aimbs_put16(&fr->data, strlen(reason));
- aimbs_putraw(&fr->data, (guint8 *) reason, strlen(reason));
-
- aim_tx_enqueue(sess, fr);
-
- return(0);
-}
-
-
-/*
- * SSI Add/Mod/Del Item(s).
- *
- * Sends the SNAC to add, modify, or delete an item 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.
- *
- */
-int aim_ssi_addmoddel(aim_session_t *sess, aim_conn_t *conn, struct aim_ssi_item **items, unsigned int num,
- guint16 subtype)
-{
- aim_frame_t *fr;
- aim_snacid_t snacid;
- int i, snaclen, listlen;
- char *list = NULL;
-
- if (!sess || !conn || !items || !num) {
- return -EINVAL;
- }
-
- snaclen = 10; /* For family, subtype, flags, and SNAC ID */
- listlen = 0;
- for (i = 0; i < num; i++) {
- snaclen += 10; /* For length, GID, BID, type, and length */
- if (items[i]->name) {
- snaclen += strlen(items[i]->name);
-
- if (subtype == AIM_CB_SSI_ADD) {
- list = g_realloc(list, listlen + strlen(items[i]->name) + 1);
- strcpy(list + listlen, items[i]->name);
- listlen += strlen(items[i]->name) + 1;
- }
- } else {
- if (subtype == AIM_CB_SSI_ADD) {
- list = g_realloc(list, listlen + 1);
- list[listlen] = '\0';
- listlen++;
- }
- }
- if (items[i]->data) {
- snaclen += aim_sizetlvchain((aim_tlvlist_t **) &items[i]->data);
- }
- }
-
- if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, snaclen))) {
- return -ENOMEM;
- }
-
- snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, subtype, 0x0000, list, list ? listlen : 0);
- aim_putsnac(&fr->data, AIM_CB_FAM_SSI, subtype, 0x0000, snacid);
-
- g_free(list);
-
- for (i = 0; i < num; i++) {
- aimbs_put16(&fr->data, items[i]->name ? strlen(items[i]->name) : 0);
- if (items[i]->name) {
- aimbs_putraw(&fr->data, (guint8 *) items[i]->name, strlen(items[i]->name));
- }
- aimbs_put16(&fr->data, items[i]->gid);
- aimbs_put16(&fr->data, items[i]->bid);
- aimbs_put16(&fr->data, items[i]->type);
- aimbs_put16(&fr->data, items[i]->data ? aim_sizetlvchain((aim_tlvlist_t **) &items[i]->data) : 0);
- if (items[i]->data) {
- aim_writetlvchain(&fr->data, (aim_tlvlist_t **) &items[i]->data);
- }
- }
-
- aim_ssi_enqueue(sess, conn, fr);
-
- return 0;
-}
-
-/*
- * SSI Add/Mod/Del Ack.
- *
- * Response to add, modify, or delete SNAC (sent with aim_ssi_addmoddel).
- *
- */
-static int parseack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
- int ret = 0;
- aim_rxcallback_t userfunc;
- aim_snac_t *origsnac;
-
- sess->ssi.waiting_for_ack = 0;
- aim_ssi_dispatch(sess, rx->conn);
-
- origsnac = aim_remsnac(sess, snac->id);
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx, origsnac);
- }
-
- if (origsnac) {
- g_free(origsnac->data);
- g_free(origsnac);
- }
-
- return ret;
-}
-
-/*
- * SSI Begin Data Modification.
- *
- * Tells the server you're going to start modifying data.
- *
- */
-int aim_ssi_modbegin(aim_session_t *sess, aim_conn_t *conn)
-{
- return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTART);
-}
-
-/*
- * SSI End Data Modification.
- *
- * Tells the server you're done modifying data.
- *
- */
-int aim_ssi_modend(aim_session_t *sess, aim_conn_t *conn)
-{
- return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTOP);
-}
-
-/*
- * SSI Data Unchanged.
- *
- * Response to aim_ssi_reqdata() if the server-side data is not newer than
- * posted local stamp/revision.
- *
- */
-static int parsedataunchanged(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac,
- aim_bstream_t *bs)
-{
- int ret = 0;
- aim_rxcallback_t userfunc;
-
- sess->ssi.received_data = 1;
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- ret = userfunc(sess, rx);
- }
-
- return ret;
-}
-
-static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
-
- if (snac->subtype == AIM_CB_SSI_RIGHTSINFO) {
- return parserights(sess, mod, rx, snac, bs);
- } else if (snac->subtype == AIM_CB_SSI_LIST) {
- return parsedata(sess, mod, rx, snac, bs);
- } else if (snac->subtype == AIM_CB_SSI_SRVACK) {
- return parseack(sess, mod, rx, snac, bs);
- } else if (snac->subtype == AIM_CB_SSI_NOLIST) {
- return parsedataunchanged(sess, mod, rx, snac, bs);
- }
-
- return 0;
-}
-
-static void ssi_shutdown(aim_session_t *sess, aim_module_t *mod)
-{
- aim_ssi_freelist(sess);
-
- return;
-}
-
-int ssi_modfirst(aim_session_t *sess, aim_module_t *mod)
-{
-
- mod->family = AIM_CB_FAM_SSI;
- mod->version = 0x0003;
- mod->toolid = 0x0110;
- mod->toolversion = 0x0629;
- mod->flags = 0;
- strncpy(mod->name, "ssi", sizeof(mod->name));
- mod->snachandler = snachandler;
- mod->shutdown = ssi_shutdown;
-
- return 0;
-}
Index: otocols/oscar/ssi.h
===================================================================
--- protocols/oscar/ssi.h (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,74 +1,0 @@
-#ifndef __OSCAR_SSI_H__
-#define __OSCAR_SSI_H__
-
-#define AIM_CB_FAM_SSI 0x0013 /* Server stored information */
-
-/*
- * SNAC Family: Server-Stored Buddy Lists
- */
-#define AIM_CB_SSI_ERROR 0x0001
-#define AIM_CB_SSI_REQRIGHTS 0x0002
-#define AIM_CB_SSI_RIGHTSINFO 0x0003
-#define AIM_CB_SSI_REQFULLLIST 0x0004
-#define AIM_CB_SSI_REQLIST 0x0005
-#define AIM_CB_SSI_LIST 0x0006
-#define AIM_CB_SSI_ACTIVATE 0x0007
-#define AIM_CB_SSI_ADD 0x0008
-#define AIM_CB_SSI_MOD 0x0009
-#define AIM_CB_SSI_DEL 0x000A
-#define AIM_CB_SSI_SRVACK 0x000E
-#define AIM_CB_SSI_NOLIST 0x000F
-#define AIM_CB_SSI_EDITSTART 0x0011
-#define AIM_CB_SSI_EDITSTOP 0x0012
-#define AIM_CB_SSI_SENDAUTHREQ 0x0018
-#define AIM_CB_SSI_SERVAUTHREQ 0x0019
-#define AIM_CB_SSI_SENDAUTHREP 0x001A
-#define AIM_CB_SSI_SERVAUTHREP 0x001B
-
-
-#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
-
-struct aim_ssi_item {
- char *name;
- guint16 gid;
- guint16 bid;
- guint16 type;
- void *data;
- struct aim_ssi_item *next;
-};
-
-/* These build the actual SNACs and queue them to be sent */
-int aim_ssi_reqrights(aim_session_t *sess, aim_conn_t *conn);
-int aim_ssi_reqalldata(aim_session_t *sess, aim_conn_t *conn);
-int aim_ssi_enable(aim_session_t *sess, aim_conn_t *conn);
-int aim_ssi_addmoddel(aim_session_t *sess, aim_conn_t *conn, struct aim_ssi_item **items, unsigned int num,
- guint16 subtype);
-int aim_ssi_modbegin(aim_session_t *sess, aim_conn_t *conn);
-int aim_ssi_modend(aim_session_t *sess, aim_conn_t *conn);
-
-/* These handle the local variables */
-struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *list, guint16 gid, guint16 bid);
-struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, char *gn, char *sn, guint16 type);
-struct aim_ssi_item *aim_ssi_itemlist_findparent(struct aim_ssi_item *list, char *sn);
-int aim_ssi_getpermdeny(struct aim_ssi_item *list);
-
-/* Send packets */
-int aim_ssi_addbuddies(aim_session_t *sess, aim_conn_t *conn, char *gn, char **sn, unsigned int num,
- unsigned int flags);
-int aim_ssi_addmastergroup(aim_session_t *sess, aim_conn_t *conn);
-int aim_ssi_addgroups(aim_session_t *sess, aim_conn_t *conn, char **gn, unsigned int num);
-int aim_ssi_addpord(aim_session_t *sess, aim_conn_t *conn, char **sn, unsigned int num, guint16 type);
-int aim_ssi_movebuddy(aim_session_t *sess, aim_conn_t *conn, char *oldgn, char *newgn, char *sn);
-int aim_ssi_delbuddies(aim_session_t *sess, aim_conn_t *conn, char *gn, char **sn, unsigned int num);
-int aim_ssi_delmastergroup(aim_session_t *sess, aim_conn_t *conn);
-int aim_ssi_delgroups(aim_session_t *sess, aim_conn_t *conn, char **gn, unsigned int num);
-int aim_ssi_delpord(aim_session_t *sess, aim_conn_t *conn, char **sn, unsigned int num, guint16 type);
-int aim_ssi_auth_request(aim_session_t *sess, aim_conn_t *conn, char *uin, char *reason);
-int aim_ssi_auth_reply(aim_session_t *sess, aim_conn_t *conn, char *uin, int yesno, char *reason);
-
-#endif /* __OSCAR_SSI_H__ */
Index: otocols/oscar/stats.c
===================================================================
--- protocols/oscar/stats.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,41 +1,0 @@
-
-#include
-
-static int reportinterval(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac,
- aim_bstream_t *bs)
-{
- guint16 interval;
- aim_rxcallback_t userfunc;
-
- interval = aimbs_get16(bs);
-
- if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
- return userfunc(sess, rx, interval);
- }
-
- return 0;
-}
-
-static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
-{
-
- if (snac->subtype == 0x0002) {
- return reportinterval(sess, mod, rx, snac, bs);
- }
-
- return 0;
-}
-
-int stats_modfirst(aim_session_t *sess, aim_module_t *mod)
-{
-
- mod->family = 0x000b;
- mod->version = 0x0001;
- mod->toolid = 0x0104;
- mod->toolversion = 0x0001;
- mod->flags = 0;
- strncpy(mod->name, "stats", sizeof(mod->name));
- mod->snachandler = snachandler;
-
- return 0;
-}
Index: otocols/oscar/tlv.c
===================================================================
--- protocols/oscar/tlv.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,578 +1,0 @@
-#include
-
-static void freetlv(aim_tlv_t **oldtlv)
-{
- if (!oldtlv || !*oldtlv) {
- return;
- }
-
- g_free((*oldtlv)->value);
- g_free(*oldtlv);
- *oldtlv = NULL;
-}
-
-/**
- * aim_readtlvchain - Read a TLV chain from a buffer.
- * @buf: Input buffer
- * @maxlen: Length of input 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_freetlvchain() should
- * be called to free the dynamic substructures.
- *
- * XXX 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.
- *
- */
-aim_tlvlist_t *aim_readtlvchain(aim_bstream_t *bs)
-{
- aim_tlvlist_t *list = NULL, *cur;
- guint16 type, length;
-
- while (aim_bstream_empty(bs)) {
-
- type = aimbs_get16(bs);
- length = aimbs_get16(bs);
-
- cur = g_new0(aim_tlvlist_t, 1);
-
- cur->tlv = g_new0(aim_tlv_t, 1);
- cur->tlv->type = type;
- if ((cur->tlv->length = length)) {
- cur->tlv->value = aimbs_getraw(bs, length);
- }
-
- cur->next = list;
- list = cur;
- }
-
- return list;
-}
-
-/**
- * aim_freetlvchain - Free a TLV chain structure
- * @list: Chain to be freed
- *
- * 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.
- *
- */
-void aim_freetlvchain(aim_tlvlist_t **list)
-{
- aim_tlvlist_t *cur;
-
- if (!list || !*list) {
- return;
- }
-
- for (cur = *list; cur; ) {
- aim_tlvlist_t *tmp;
-
- freetlv(&cur->tlv);
-
- tmp = cur->next;
- g_free(cur);
- cur = tmp;
- }
-
- list = NULL;
-
- return;
-}
-
-/**
- * aim_counttlvchain - Count the number of TLVs in a chain
- * @list: Chain to be counted
- *
- * Returns the number of TLVs stored in the passed chain.
- *
- */
-int aim_counttlvchain(aim_tlvlist_t **list)
-{
- aim_tlvlist_t *cur;
- int count;
-
- if (!list || !*list) {
- return 0;
- }
-
- for (cur = *list, count = 0; cur; cur = cur->next) {
- count++;
- }
-
- return count;
-}
-
-/**
- * aim_sizetlvchain - Count the number of bytes in a TLV chain
- * @list: Chain to be sized
- *
- * Returns the number of bytes that would be needed to
- * write the passed TLV chain to a data buffer.
- *
- */
-int aim_sizetlvchain(aim_tlvlist_t **list)
-{
- aim_tlvlist_t *cur;
- int size;
-
- if (!list || !*list) {
- return 0;
- }
-
- for (cur = *list, size = 0; cur; cur = cur->next) {
- size += (4 + cur->tlv->length);
- }
-
- return size;
-}
-
-/**
- * aim_addtlvtochain_str - Add a string to a TLV chain
- * @list: Designation chain (%NULL pointer if empty)
- * @type: TLV type
- * @str: String to add
- * @len: Length of string to add (not including %NULL)
- *
- * Adds the passed string as a TLV element of the passed type
- * to the TLV chain.
- *
- */
-int aim_addtlvtochain_raw(aim_tlvlist_t **list, const guint16 t, const guint16 l, const guint8 *v)
-{
- aim_tlvlist_t *newtlv, *cur;
-
- if (!list) {
- return 0;
- }
-
- if (!(newtlv = g_new0(aim_tlvlist_t, 1))) {
- return 0;
- }
-
- if (!(newtlv->tlv = g_new0(aim_tlv_t, 1))) {
- g_free(newtlv);
- return 0;
- }
- newtlv->tlv->type = t;
- if ((newtlv->tlv->length = l)) {
- newtlv->tlv->value = (guint8 *) g_malloc(newtlv->tlv->length);
- memcpy(newtlv->tlv->value, v, newtlv->tlv->length);
- }
-
- if (!*list) {
- *list = newtlv;
- } else {
- for (cur = *list; cur->next; cur = cur->next) {
- ;
- }
- cur->next = newtlv;
- }
-
- return newtlv->tlv->length;
-}
-
-/**
- * aim_addtlvtochain8 - Add a 8bit integer to a TLV chain
- * @list: Destination chain
- * @type: TLV type to add
- * @val: Value to add
- *
- * Adds a one-byte unsigned integer to a TLV chain.
- *
- */
-int aim_addtlvtochain8(aim_tlvlist_t **list, const guint16 t, const guint8 v)
-{
- guint8 v8[1];
-
- (void) aimutil_put8(v8, v);
-
- return aim_addtlvtochain_raw(list, t, 1, v8);
-}
-
-/**
- * aim_addtlvtochain16 - Add a 16bit integer to a TLV chain
- * @list: Destination chain
- * @type: TLV type to add
- * @val: Value to add
- *
- * Adds a two-byte unsigned integer to a TLV chain.
- *
- */
-int aim_addtlvtochain16(aim_tlvlist_t **list, const guint16 t, const guint16 v)
-{
- guint8 v16[2];
-
- (void) aimutil_put16(v16, v);
-
- return aim_addtlvtochain_raw(list, t, 2, v16);
-}
-
-/**
- * aim_addtlvtochain32 - Add a 32bit integer to a TLV chain
- * @list: Destination chain
- * @type: TLV type to add
- * @val: Value to add
- *
- * Adds a four-byte unsigned integer to a TLV chain.
- *
- */
-int aim_addtlvtochain32(aim_tlvlist_t **list, const guint16 t, const guint32 v)
-{
- guint8 v32[4];
-
- (void) aimutil_put32(v32, v);
-
- return aim_addtlvtochain_raw(list, t, 4, v32);
-}
-
-/**
- * aim_addtlvtochain_caps - Add a capability block to a TLV chain
- * @list: Destination chain
- * @type: TLV type to add
- * @caps: Bitfield of capability flags to send
- *
- * 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:
- *
- */
-int aim_addtlvtochain_caps(aim_tlvlist_t **list, const guint16 t, const guint32 caps)
-{
- guint8 buf[16 * 16]; /* XXX icky fixed length buffer */
- aim_bstream_t bs;
-
- if (!caps) {
- return 0; /* nothing there anyway */
-
- }
- aim_bstream_init(&bs, buf, sizeof(buf));
-
- aim_putcap(&bs, caps);
-
- return aim_addtlvtochain_raw(list, t, aim_bstream_curpos(&bs), buf);
-}
-
-/**
- * aim_addtlvtochain_noval - Add a blank TLV to a TLV chain
- * @list: Destination chain
- * @type: TLV type to add
- *
- * Adds a TLV with a zero length to a TLV chain.
- *
- */
-int aim_addtlvtochain_noval(aim_tlvlist_t **list, const guint16 t)
-{
- return aim_addtlvtochain_raw(list, t, 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.
- *
- * XXX should probably support sublists for real.
- *
- * This is so neat.
- *
- */
-int aim_addtlvtochain_frozentlvlist(aim_tlvlist_t **list, guint16 type, aim_tlvlist_t **tl)
-{
- guint8 *buf;
- int buflen;
- aim_bstream_t bs;
-
- buflen = aim_sizetlvchain(tl);
-
- if (buflen <= 0) {
- return 0;
- }
-
- if (!(buf = g_malloc(buflen))) {
- return 0;
- }
-
- aim_bstream_init(&bs, buf, buflen);
-
- aim_writetlvchain(&bs, tl);
-
- aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf);
-
- g_free(buf);
-
- return buflen;
-}
-
-int aim_addtlvtochain_chatroom(aim_tlvlist_t **list, guint16 type, guint16 exchange, const char *roomname,
- guint16 instance)
-{
- guint8 *buf;
- int buflen;
- aim_bstream_t bs;
-
- buflen = 2 + 1 + strlen(roomname) + 2;
-
- if (!(buf = g_malloc(buflen))) {
- return 0;
- }
-
- aim_bstream_init(&bs, buf, buflen);
-
- aimbs_put16(&bs, exchange);
- aimbs_put8(&bs, strlen(roomname));
- aimbs_putraw(&bs, (guint8 *) roomname, strlen(roomname));
- aimbs_put16(&bs, instance);
-
- aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf);
-
- g_free(buf);
-
- return 0;
-}
-
-/**
- * aim_writetlvchain - Write a TLV chain into a data buffer.
- * @buf: Destination buffer
- * @buflen: Maximum number of bytes that will be written to buffer
- * @list: Source TLV chain
- *
- * Copies a TLV chain into a raw data buffer, writing only the number
- * of bytes specified. This operation does not free the chain;
- * aim_freetlvchain() must still be called to free up the memory used
- * by the chain structures.
- *
- * XXX clean this up, make better use of bstreams
- */
-int aim_writetlvchain(aim_bstream_t *bs, aim_tlvlist_t **list)
-{
- int goodbuflen;
- aim_tlvlist_t *cur;
-
- /* do an initial run to test total length */
- for (cur = *list, goodbuflen = 0; cur; cur = cur->next) {
- goodbuflen += 2 + 2; /* type + len */
- goodbuflen += cur->tlv->length;
- }
-
- if (goodbuflen > aim_bstream_empty(bs)) {
- return 0; /* not enough buffer */
-
- }
- /* do the real write-out */
- for (cur = *list; cur; cur = cur->next) {
- aimbs_put16(bs, cur->tlv->type);
- aimbs_put16(bs, cur->tlv->length);
- if (cur->tlv->length) {
- aimbs_putraw(bs, cur->tlv->value, cur->tlv->length);
- }
- }
-
- return 1; /* XXX this is a nonsensical return */
-}
-
-
-/**
- * aim_gettlv - Grab the Nth TLV of type type in the TLV list list.
- * @list: Source chain
- * @type: Requested TLV type
- * @nth: Index of TLV of type to get
- *
- * 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.
- *
- */
-aim_tlv_t *aim_gettlv(aim_tlvlist_t *list, const guint16 t, const int n)
-{
- aim_tlvlist_t *cur;
- int i;
-
- for (cur = list, i = 0; cur; cur = cur->next) {
- if (cur && cur->tlv) {
- if (cur->tlv->type == t) {
- i++;
- }
- if (i >= n) {
- return cur->tlv;
- }
- }
- }
-
- return NULL;
-}
-
-/**
- * aim_gettlv_str - Retrieve the Nth TLV in chain as a string.
- * @list: Source TLV chain
- * @type: TLV type to search for
- * @nth: Index of TLV to return
- *
- * Same as aim_gettlv(), except that the return value is a %NULL-
- * terminated string instead of an aim_tlv_t. This is a
- * dynamic buffer and must be freed by the caller.
- *
- */
-char *aim_gettlv_str(aim_tlvlist_t *list, const guint16 t, const int n)
-{
- aim_tlv_t *tlv;
- char *newstr;
-
- if (!(tlv = aim_gettlv(list, t, n))) {
- return NULL;
- }
-
- newstr = (char *) g_malloc(tlv->length + 1);
- memcpy(newstr, tlv->value, tlv->length);
- *(newstr + tlv->length) = '\0';
-
- return newstr;
-}
-
-/**
- * aim_gettlv8 - Retrieve the Nth TLV in chain as a 8bit integer.
- * @list: Source TLV chain
- * @type: TLV type to search for
- * @nth: Index of TLV to return
- *
- * Same as aim_gettlv(), except that the return value is a
- * 8bit integer instead of an aim_tlv_t.
- *
- */
-guint8 aim_gettlv8(aim_tlvlist_t *list, const guint16 t, const int n)
-{
- aim_tlv_t *tlv;
-
- if (!(tlv = aim_gettlv(list, t, n))) {
- return 0; /* erm */
- }
- return aimutil_get8(tlv->value);
-}
-
-/**
- * aim_gettlv16 - Retrieve the Nth TLV in chain as a 16bit integer.
- * @list: Source TLV chain
- * @type: TLV type to search for
- * @nth: Index of TLV to return
- *
- * Same as aim_gettlv(), except that the return value is a
- * 16bit integer instead of an aim_tlv_t.
- *
- */
-guint16 aim_gettlv16(aim_tlvlist_t *list, const guint16 t, const int n)
-{
- aim_tlv_t *tlv;
-
- if (!(tlv = aim_gettlv(list, t, n))) {
- return 0; /* erm */
- }
- return aimutil_get16(tlv->value);
-}
-
-/**
- * aim_gettlv32 - Retrieve the Nth TLV in chain as a 32bit integer.
- * @list: Source TLV chain
- * @type: TLV type to search for
- * @nth: Index of TLV to return
- *
- * Same as aim_gettlv(), except that the return value is a
- * 32bit integer instead of an aim_tlv_t.
- *
- */
-guint32 aim_gettlv32(aim_tlvlist_t *list, const guint16 t, const int n)
-{
- aim_tlv_t *tlv;
-
- if (!(tlv = aim_gettlv(list, t, n))) {
- return 0; /* erm */
- }
- return aimutil_get32(tlv->value);
-}
-
-#if 0
-/**
- * aim_puttlv_8 - Write a one-byte TLV.
- * @buf: Destination buffer
- * @t: TLV type
- * @v: Value
- *
- * Writes a TLV with a one-byte integer value portion.
- *
- */
-int aim_puttlv_8(guint8 *buf, const guint16 t, const guint8 v)
-{
- guint8 v8[1];
-
- aimutil_put8(v8, v);
-
- return aim_puttlv_raw(buf, t, 1, v8);
-}
-
-/**
- * aim_puttlv_16 - Write a two-byte TLV.
- * @buf: Destination buffer
- * @t: TLV type
- * @v: Value
- *
- * Writes a TLV with a two-byte integer value portion.
- *
- */
-int aim_puttlv_16(guint8 *buf, const guint16 t, const guint16 v)
-{
- guint8 v16[2];
-
- aimutil_put16(v16, v);
-
- return aim_puttlv_raw(buf, t, 2, v16);
-}
-
-
-/**
- * aim_puttlv_32 - Write a four-byte TLV.
- * @buf: Destination buffer
- * @t: TLV type
- * @v: Value
- *
- * Writes a TLV with a four-byte integer value portion.
- *
- */
-int aim_puttlv_32(guint8 *buf, const guint16 t, const guint32 v)
-{
- guint8 v32[4];
-
- aimutil_put32(v32, v);
-
- return aim_puttlv_raw(buf, t, 4, v32);
-}
-
-/**
- * aim_puttlv_raw - Write a raw TLV.
- * @buf: Destination buffer
- * @t: TLV type
- * @l: Length of string
- * @v: String to write
- *
- * Writes a TLV with a raw value portion. (Only the first @l
- * bytes of the passed buffer will be written, which should not
- * include a terminating NULL.)
- *
- */
-int aim_puttlv_raw(guint8 *buf, const guint16 t, const guint16 l, const guint8 *v)
-{
- int i;
-
- i = aimutil_put16(buf, t);
- i += aimutil_put16(buf + i, l);
- if (l) {
- memcpy(buf + i, v, l);
- }
- i += l;
-
- return i;
-}
-#endif
-
Index: otocols/oscar/txqueue.c
===================================================================
--- protocols/oscar/txqueue.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ (revision )
@@ -1,373 +1,0 @@
-/*
- * aim_txqueue.c
- *
- * Herein lies all the mangement routines for the transmit (Tx) queue.
- *
- */
-
-#include
-#include "im.h"
-
-#include
-
-/*
- * Allocate a new tx frame.
- *
- * This is more for looks than anything else.
- *
- * Right now, that is. If/when we implement a pool of transmit
- * frames, this will become the request-an-unused-frame part.
- *
- * framing = AIM_FRAMETYPE_OFT/FLAP
- * chan = channel for FLAP, hdrtype for OFT
- *
- */
-aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, guint8 framing, guint8 chan, int datalen)
-{
- aim_frame_t *fr;
-
- if (!conn) {
- imcb_error(sess->aux_data, "no connection specified");
- return NULL;
- }
-
- if (!(fr = (aim_frame_t *) g_new0(aim_frame_t, 1))) {
- return NULL;
- }
-
- fr->conn = conn;
-
- fr->hdrtype = framing;
-
- if (fr->hdrtype == AIM_FRAMETYPE_FLAP) {
-
- fr->hdr.flap.type = chan;
-
- } else {
- imcb_error(sess->aux_data, "unknown framing");
- }
-
- if (datalen > 0) {
- guint8 *data;
-
- if (!(data = (unsigned char *) g_malloc(datalen))) {
- aim_frame_destroy(fr);
- return NULL;
- }
-
- aim_bstream_init(&fr->data, data, datalen);
- }
-
- return fr;
-}
-
-/*
- * aim_tx_enqeue__queuebased()
- *
- * The overall purpose here is to enqueue the passed in command struct
- * into the outgoing (tx) queue. Basically...
- * 1) Make a scope-irrelevant copy of the struct
- * 3) Mark as not-sent-yet
- * 4) Enqueue the struct into the list
- * 6) Return
- *
- * Note that this is only used when doing queue-based transmitting;
- * that is, when sess->tx_enqueue is set to &aim_tx_enqueue__queuebased.
- *
- */
-static int aim_tx_enqueue__queuebased(aim_session_t *sess, aim_frame_t *fr)
-{
-
- if (!fr->conn) {
- imcb_error(sess->aux_data, "Warning: enqueueing packet with no connection");
- fr->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS);
- }
-
- if (fr->hdrtype == AIM_FRAMETYPE_FLAP) {
- /* assign seqnum -- XXX should really not assign until hardxmit */
- fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn);
- }
-
- fr->handled = 0; /* not sent yet */
-
- /* see overhead note in aim_rxqueue counterpart */
- if (!sess->queue_outgoing) {
- sess->queue_outgoing = fr;
- } else {
- aim_frame_t *cur;
-
- for (cur = sess->queue_outgoing; cur->next; cur = cur->next) {
- ;
- }
- cur->next = fr;
- }
-
- return 0;
-}
-
-/*
- * aim_tx_enqueue__immediate()
- *
- * Parallel to aim_tx_enqueue__queuebased, however, this bypasses
- * the whole queue mess when you want immediate writes to happen.
- *
- * Basically the same as its __queuebased couterpart, however
- * instead of doing a list append, it just calls aim_tx_sendframe()
- * right here.
- *
- */
-static int aim_tx_enqueue__immediate(aim_session_t *sess, aim_frame_t *fr)
-{
-
- if (!fr->conn) {
- imcb_error(sess->aux_data, "packet has no connection");
- aim_frame_destroy(fr);
- return 0;
- }
-
- if (fr->hdrtype == AIM_FRAMETYPE_FLAP) {
- fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn);
- }
-
- fr->handled = 0; /* not sent yet */
-
- aim_tx_sendframe(sess, fr);
-
- aim_frame_destroy(fr);
-
- return 0;
-}
-
-int aim_tx_setenqueue(aim_session_t *sess, int what, int (*func)(aim_session_t *, aim_frame_t *))
-{
-
- if (what == AIM_TX_QUEUED) {
- sess->tx_enqueue = &aim_tx_enqueue__queuebased;
- } else if (what == AIM_TX_IMMEDIATE) {
- sess->tx_enqueue = &aim_tx_enqueue__immediate;
- } else if (what == AIM_TX_USER) {
- if (!func) {
- return -EINVAL;
- }
- sess->tx_enqueue = func;
- } else {
- return -EINVAL; /* unknown action */
-
- }
- return 0;
-}
-
-int aim_tx_enqueue(aim_session_t *sess, aim_frame_t *fr)
-{
-
- /*
- * If we want to send a connection thats inprogress, we have to force
- * them to use the queue based version. Otherwise, use whatever they
- * want.
- */
- if (fr && fr->conn &&
- (fr->conn->status & AIM_CONN_STATUS_INPROGRESS)) {
- return aim_tx_enqueue__queuebased(sess, fr);
- }
-
- return (*sess->tx_enqueue)(sess, fr);
-}
-
-/*
- * aim_get_next_txseqnum()
- *
- * This increments the tx command count, and returns the seqnum
- * that should be stamped on the next FLAP packet sent. This is
- * normally called during the final step of packet preparation
- * before enqueuement (in aim_tx_enqueue()).
- *
- */
-flap_seqnum_t aim_get_next_txseqnum(aim_conn_t *conn)
-{
- flap_seqnum_t ret;
-
- ret = ++conn->seqnum;
-
- return ret;
-}
-
-static int aim_send(int fd, const void *buf, size_t count)
-{
- int left, cur;
-
- for (cur = 0, left = count; left; ) {
- int ret;
-
- ret = send(fd, ((unsigned char *) buf) + cur, left, 0);
- if (ret == -1) {
- return -1;
- } else if (ret == 0) {
- return cur;
- }
-
- cur += ret;
- left -= ret;
- }
-
- return cur;
-}
-
-static int aim_bstream_send(aim_bstream_t *bs, aim_conn_t *conn, size_t count)
-{
- int wrote = 0;
-
- if (!bs || !conn || (count < 0)) {
- return -EINVAL;
- }
-
- if (count > aim_bstream_empty(bs)) {
- count = aim_bstream_empty(bs); /* truncate to remaining space */
-
- }
- if (count) {
- if (count - wrote) {
- wrote = wrote + aim_send(conn->fd, bs->data + bs->offset + wrote, count - wrote);
- }
-
- }
-
- bs->offset += wrote;
-
- return wrote;
-}
-
-static int sendframe_flap(aim_session_t *sess, aim_frame_t *fr)
-{
- aim_bstream_t obs;
- guint8 *obs_raw;
- int payloadlen, err = 0, obslen;
-
- payloadlen = aim_bstream_curpos(&fr->data);
-
- if (!(obs_raw = g_malloc(6 + payloadlen))) {
- return -ENOMEM;
- }
-
- aim_bstream_init(&obs, obs_raw, 6 + payloadlen);
-
- /* FLAP header */
- aimbs_put8(&obs, 0x2a);
- aimbs_put8(&obs, fr->hdr.flap.type);
- aimbs_put16(&obs, fr->hdr.flap.seqnum);
- aimbs_put16(&obs, payloadlen);
-
- /* payload */
- aim_bstream_rewind(&fr->data);
- aimbs_putbs(&obs, &fr->data, payloadlen);
-
- obslen = aim_bstream_curpos(&obs);
- aim_bstream_rewind(&obs);
- if (aim_bstream_send(&obs, fr->conn, obslen) != obslen) {
- err = -errno;
- }
-
- g_free(obs_raw); /* XXX aim_bstream_free */
-
- fr->handled = 1;
- fr->conn->lastactivity = time(NULL);
-
- return err;
-}
-
-int aim_tx_sendframe(aim_session_t *sess, aim_frame_t *fr)
-{
- if (fr->hdrtype == AIM_FRAMETYPE_FLAP) {
- return sendframe_flap(sess, fr);
- }
- return -1;
-}
-
-int aim_tx_flushqueue(aim_session_t *sess)
-{
- aim_frame_t *cur;
-
- for (cur = sess->queue_outgoing; cur; cur = cur->next) {
-
- if (cur->handled) {
- continue; /* already been sent */
-
- }
- if (cur->conn && (cur->conn->status & AIM_CONN_STATUS_INPROGRESS)) {
- continue;
- }
-
- /*
- * And now for the meager attempt to force transmit
- * latency and avoid missed messages.
- */
- if ((cur->conn->lastactivity + cur->conn->forcedlatency) >= time(NULL)) {
- /*
- * XXX should be a break! we dont want to block the
- * upper layers
- *
- * XXX or better, just do this right.
- *
- */
- sleep((cur->conn->lastactivity + cur->conn->forcedlatency) - time(NULL));
- }
-
- /* XXX this should call the custom "queuing" function!! */
- aim_tx_sendframe(sess, cur);
- }
-
- /* purge sent commands from queue */
- aim_tx_purgequeue(sess);
-
- return 0;
-}
-
-/*
- * aim_tx_purgequeue()
- *
- * This is responsable for removing sent commands from the transmit
- * queue. This is not a required operation, but it of course helps
- * reduce memory footprint at run time!
- *
- */
-void aim_tx_purgequeue(aim_session_t *sess)
-{
- aim_frame_t *cur, **prev;
-
- for (prev = &sess->queue_outgoing; (cur = *prev); ) {
-
- if (cur->handled) {
- *prev = cur->next;
-
- aim_frame_destroy(cur);
-
- } else {
- prev = &cur->next;
- }
- }
-
- return;
-}
-
-/**
- * aim_tx_cleanqueue - get rid of packets waiting for tx on a dying conn
- * @sess: session
- * @conn: connection that's dying
- *
- * for now this simply marks all packets as sent and lets them
- * disappear without warning.
- *
- */
-void aim_tx_cleanqueue(aim_session_t *sess, aim_conn_t *conn)
-{
- aim_frame_t *cur;
-
- for (cur = sess->queue_outgoing; cur; cur = cur->next) {
- if (cur->conn == conn) {
- cur->handled = 1;
- }
- }
-
- return;
-}
-
-
Index: protocols/purple/purple.c
===================================================================
--- protocols/purple/purple.c (revision 9de451d72a2c5335cd8c6d48b73b4fa457f76c88)
+++ protocols/purple/purple.c (revision e5d2c5607310ef9669a051a1b93e019319495955)
@@ -107,15 +107,4 @@
}
-static char *purple_get_account_prpl_id(account_t *acc)
-{
- /* "oscar" is how non-purple bitlbee calls it,
- * and it might be icq or aim, depending on the username */
- if (g_strcmp0(acc->prpl->name, "oscar") == 0) {
- return (g_ascii_isdigit(acc->user[0])) ? "prpl-icq" : "prpl-aim";
- }
-
- return acc->prpl->data;
-}
-
static gboolean purple_account_should_set_nick(account_t *acc)
{
@@ -127,5 +116,4 @@
"prpl-hangouts",
"prpl-eionrobb-funyahoo-plusplus",
- "prpl-icq",
"prpl-line",
NULL,
@@ -144,5 +132,5 @@
static void purple_init(account_t *acc)
{
- char *prpl_id = purple_get_account_prpl_id(acc);
+ char *prpl_id = acc->prpl->data;
PurplePlugin *prpl = purple_plugins_find_with_id(prpl_id);
PurplePluginProtocolInfo *pi = prpl->info->extra_info;
@@ -399,5 +387,5 @@
ic->proto_data = pd = g_new0(struct purple_data, 1);
- pd->account = purple_account_new(acc->user, purple_get_account_prpl_id(acc));
+ pd->account = purple_account_new(acc->user, acc->prpl->data);
pd->input_requests = g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL, g_free);
@@ -1957,14 +1945,4 @@
g_string_append_printf(help, "\n* %s (%s)", ret->name, prot->info->name);
- /* libpurple doesn't define a protocol called OSCAR, but we
- need it to be compatible with normal BitlBee. */
- if (g_strcasecmp(prot->info->id, "prpl-aim") == 0) {
- ret = g_memdup(&funcs, sizeof(funcs));
- ret->name = "oscar";
- /* purple_get_account_prpl_id() determines the actual protocol ID (icq/aim) */
- ret->data = NULL;
- register_protocol(ret);
- }
-
info = g_new0(struct plugin_info, 1);
info->abiver = BITLBEE_ABI_VERSION_CODE;