]> andersk Git - libfaim.git/commitdiff
Initial revision
authormid <mid>
Fri, 24 Dec 1999 04:59:45 +0000 (04:59 +0000)
committermid <mid>
Fri, 24 Dec 1999 04:59:45 +0000 (04:59 +0000)
39 files changed:
BUGS [new file with mode: 0644]
CHANGES [new file with mode: 0644]
COPYING [new file with mode: 0644]
Makefile [new file with mode: 0644]
Makefile.rules [new file with mode: 0644]
README [new file with mode: 0644]
aim.h [new file with mode: 0644]
aim_auth.c [new file with mode: 0644]
aim_buddylist.c [new file with mode: 0644]
aim_chat.c [new file with mode: 0644]
aim_chatnav.c [new file with mode: 0644]
aim_conn.c [new file with mode: 0644]
aim_global.c [new file with mode: 0644]
aim_im.c [new file with mode: 0644]
aim_info.c [new file with mode: 0644]
aim_login.c [new file with mode: 0644]
aim_logoff.c [new file with mode: 0644]
aim_misc.c [new file with mode: 0644]
aim_rxhandlers.c [new file with mode: 0644]
aim_rxqueue.c [new file with mode: 0644]
aim_search.c [new file with mode: 0644]
aim_snac.c [new file with mode: 0644]
aim_tlv.c [new file with mode: 0644]
aim_txqueue.c [new file with mode: 0644]
aim_util.c [new file with mode: 0644]
deprecated/aim_rxqueue.orig.c [new file with mode: 0644]
deprecated/aim_snac.c [new file with mode: 0644]
deprecated/discarded.c [new file with mode: 0644]
deprecated/tis_telnet_proxy.c [new file with mode: 0644]
deprecated/tis_telnet_proxy.h [new file with mode: 0644]
faimconfig.h [new file with mode: 0644]
tcpdumps/chat.txt [new file with mode: 0644]
tcpdumps/newim.txt [new file with mode: 0644]
tcpdumps/permitdeny.txt [new file with mode: 0644]
utils/Makefile [new file with mode: 0644]
utils/aimpasswd/Makefile [new file with mode: 0644]
utils/aimpasswd/aimpasswd.c [new file with mode: 0644]
utils/faimtest/Makefile [new file with mode: 0644]
utils/faimtest/faimtest.c [new file with mode: 0644]

diff --git a/BUGS b/BUGS
new file mode 100644 (file)
index 0000000..a2ea402
--- /dev/null
+++ b/BUGS
@@ -0,0 +1,29 @@
+
+aim.h
+-----
+  - Needs a bit of cleaning
+
+aim_auth.c
+----------
+  - Login doesn't take advantage of aim_conn constructs where it could
+  - Login should allow for multiple BOS connections
+
+aim_chat.c
+----------
+  - Needs to be implemented.
+
+aim_chatnav.c
+-------------
+  - Needs to be implemented.
+
+aim_conn.c
+----------
+  - Does not work with proxies.
+
+aim_search.c
+------------
+  - Still need aim_usersearch_name()
+
+aim_snac.c
+----------
+  - Should implement better SNAC handling
diff --git a/CHANGES b/CHANGES
new file mode 100644 (file)
index 0000000..48f7ae0
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,105 @@
+
+No release numbers
+------------------
+ - Fri Dec 24 01:23:06 UTC 1999
+   - Fixed a very minor bug in aim_newconn().
+   - Added aimutil_get{16,32}()
+   - Added aim_extractuserinfo() for extracting  user data
+       blocks and putting them into struct aim_userinfo_s's.
+         - Added a loop to print out info on extraneous TLVs.
+         - Put in lots of comments.
+   - Added parse_oncoming_middle() to parse the user data
+       block of that packet.  Now passes struct aim_userinfo_s
+       to client.
+   - Rearranged parse_userinfo_middle().  Now passes an entire
+       userinfo struct to client instead of individual variables.
+   - Convered the version of parse_im_middle() thats actually getting
+       used to pass up a userinfo struct.  
+   - Updated faimtest to accept new structs.
+
+ - Tue Dec 21 06:18:50 UTC 1999
+   - Fixed a Win32 header problem
+ - Tue Dec 21 03:44:13 UTC 1999
+   - Latency timers now update on rx as well as tx.  Gets rid of even more
+       of the rate problems that most clients are having.  
+   - Renamed lasttx and settxlatency to lastactivity and setlatency, respec.
+   - Integrated fixes needed for Win32 -- should compile cleanly now (DMP)
+   - Cleaned up some places, use aim_putsnac everywhere now.
+
+ - Sun Sep 26 20:04:20 MST 1999
+   - Reduced the IM parsing to look for 3 zeros instead of 4 -- NEEDS WORK
+       - This was needed to work with MacAIM3 and some WinAIM3s.
+   - Added aim_conn_settxlatency() for throttling outgoing frames -- NEEDS WORK
+   - Added an int to the userinfo and incoming IM user callbacks for new
+       TLV that AOL put it in -- its the number of seconds elapsed since
+       the user logged in
+   - Worked more on the callbacks (more internal rearrangements)
+   - Fixed bug in aim_select() (returning negative fds)
+   - Clear out logininfo struct before putting more data into it
+   - Other bugfixes that I can't particularly remember.
+
+ - Tue Aug 24 03:13:12 UTC 1999   --- TRANSITION RELEASE!!
+   - Added jbm's new aim_rxqueue.c, which should crash less
+   - Started the overhaul on the callback system.  No where near complete yet.
+
+ - Sun Aug  1 03:02:17 UTC 1999
+   - Added aimutil_*()s in aim_util.c for raw byte placement
+   - Cleaned up aim_im.c, aim_auth.c, and aim_login.c using aimutil_*
+   - Added AIM_IMFLAGS, flags option to aim_send_im(), removed
+       aim_send_im_away()
+   - Added client_info parameter to aim_send_login()
+   - Tweaked aim_send_im() (AOL changed a few things, there's some more
+       changes left to do)
+   - Some Chat stuff changed, still no where near functional
+   - Finally remembered to switch the license to LGPL (from GPL)
+   - Permit/Deny (blocking) list support added
+   - Released a snapshot
+
+ - Sat Jul 31 05:28:38 UTC 1999
+   - Changed aim_bos_setdeny() to aim_bos_changevisibility() and actually
+       did the implementation.  
+
+ - Fri Jul 23 17:45:22 UTC 1999
+   - Work around for the AOL change in IP syntax (thanks to Eric Peyton)
+   - Released snapshot
+
+ - Sun Apr 25 23:31:44 UTC 1999
+   - Fixed stupid off-by-one bug in aim_logoff()
+
+ - Sun Apr 25 22:43:31 UTC 1999
+   - Renamed/reclassified missed IM errors (now all callbacks -- no backend handling)
+   - Killed aim_login() -- all connections now opened in frontend
+   - aim_conn_close() will not close fd's < 3
+   - Released snapshot.
+
+ - Sat Apr 10 22:44:07 UTC 1999
+   - Changed how rx_command->handled works; now uses return value from callback
+   - Changed the if's in the dispatcher (aim_rxhandlers.c) to switch()es
+
+ - Sat Apr 10 03:51:21 UTC 1999
+   - Started CHANGES
+   - Put in n's aim_snac.c.
+   - Updated aim_{add,remove}_buddy() to use aim_conn
+   - Updated aim_usersearch_address() to use aim_conn
+   - Cleaned up aim.h a bit (removed old *phase* protos)
+   - Changed gethostbyname() to gethostbyname2() (for MacOS X)
+   - Changed aim_newconn() to pass connection errors in connstruct->status
+     - Updated faimtest.c to detect connection errors
+   - Fixed a small typo in aim_im::aim_parse_incoming_im_middle()
+   - Added free()s in that function and to userinfo counterpart (fewer leaks)
+   - Released snapshot
+
+ - Sat Apr  3 06:43:14 UTC 1999
+   - Released snapshot
+
+ - Wed Dec 30 01:20:59 MST 1998
+   - Released snapshot
+
+ - Mon Dec  7 16:57:57 MST 1998
+   - Released snapshot
+
+ - Sat Dec  5 00:01:53 MST 1998
+   - Released snapshot
+ - Thu Nov 26 17:50:02 MST 1998
+   -  Released snapshot
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..223ede7
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,504 @@
+                 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.
+\f
+  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.
+\f
+                 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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..7fb63d9
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,47 @@
+
+include Makefile.rules
+
+SONAME = libfaim.so
+SOFILENAME = libfaim.so.0.90 # used for installation
+
+LIBFAIM_OBJECTS = \
+       aim_rxhandlers.o \
+       aim_auth.o \
+       aim_info.o \
+       aim_rxqueue.o \
+       aim_txqueue.o \
+       aim_im.o \
+       aim_login.o \
+       aim_logoff.o \
+       aim_misc.o \
+       aim_global.o \
+       aim_buddylist.o \
+       aim_search.o \
+       aim_snac.o \
+       aim_tlv.o \
+       aim_conn.o \
+       aim_chat.o \
+       aim_chatnav.o \
+       aim_util.o
+
+all: libfaim allutils
+
+libfaim: $(LIBFAIM_OBJECTS)
+       $(AR) cru libfaim.a $(LIBFAIM_OBJECTS)
+       $(RANLIB) libfaim.a
+       ld -o $(SONAME) $(LIBFAIM_OBJECTS) -shared -soname $(SONAME)
+
+allutils: libfaim
+       @echo "LIBFAIM_INC = $$PWD" > utils/Makefile.dynamicrules; \
+       echo "LIBFAIM_LIB = $$PWD" >> utils/Makefile.dynamicrules; \
+       cd utils; \
+       make
+
+cleanutils:
+       @echo "LIBFAIM_INC = $$PWD" > utils/Makefile.dynamicrules; \
+       echo "LIBFAIM_LIB = $$PWD" >> utils/Makefile.dynamicrules; \
+       cd utils; \
+       make clean
+
+clean: cleanutils
+       rm -f $(LIBFAIM_OBJECTS) $(SONAME) libfaim.a
diff --git a/Makefile.rules b/Makefile.rules
new file mode 100644 (file)
index 0000000..69f18a6
--- /dev/null
@@ -0,0 +1,15 @@
+
+CFLAGS = -Wstrict-prototypes -Wall -I. 
+
+ifdef LIBFAIM_INC
+CFLAGS += -I$(LIBFAIM_INC)
+endif
+
+LDFLAGS = 
+ifdef LIBFAIM_LIB
+LDFLAGS += -lfaim -ldl -L$(LIBFAIM_LIB)
+endif
+
+AR = ar
+RANLIB = ranlib
+
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..cb9e563
--- /dev/null
+++ b/README
@@ -0,0 +1,82 @@
+
+libfaim pre-0.90 or so
+----------------------
+
+This is libfaim, the purpose of which is to implement as much as the
+AOL AIM/OSCAR protocol as possible (which should be all of it).  After
+over a year of development, its still nowhere close.  
+
+This is not a full client and never will be.  libfaim only implements
+the routines to implement a client (ie, there's no user interface).  
+
+Status
+------
+
+I would not recommend using this version of libfaim in any form yet.  It's
+beta-quality and I know it leaks memory quite badly.  It seems fairly
+stable, however.  YMMV, YAYOR, etc.  I suppose I should say regardless of
+that warning, that several clients use it and people use those clients
+on a daily basis (in particular, me).
+
+
+Building
+--------
+
+Everything in this libfaim dist should build cleanly on any UNIX(-like)
+operating system.  Originally developed on Linux+glibc.  Past versions 
+known to work on Linux+libc5, FreeBSD, HP/UX, Solaris, Mac OS X Server, 
+Win32 using VC++ 98/6 and others.
+
+libfaim builds as both libfaim.a and libfaim.so.  If your platform for
+some reason does not support dynamic libraries (eg, you get errors when
+building libfaim.so), you'll have to tweak the makefiles a bit to get
+the utils/ directory to build.  
+
+Otherwise, just do a 'make'.  I don't believe I use any specific features
+GNU make, but if something fails, make sure you have it.  And bash too.
+
+
+Accessories
+-----------
+
+In utils/, you'll find a few things extra:
+
+  faimtest:   very rudimentary front-end.  no user interface, but does
+              illustrate the basics of logging in and sending/recieving
+              messages and buddy list notifications.  Potential front-
+              end authors start here.
+
+  aimpasswd:  utility to change an AIM password without using a full
+              client.  Note that at the time of this writing, this
+              didn't work quite right yet.  See the top of the code for
+              latest status.
+
+License
+-------
+
+libfaim is covered under my copyright under the terms of the Lesser GNU
+Public License, as documented in the file COPYING in the top level directory.
+
+
+Documentation
+-------------
+
+Unfortunatly, there is not currently any documentation on the libfaim API.
+Use the source and utils/faimtest/faimtest.c as a reference when coding
+front-ends.  
+
+
+Contact Info
+------------
+
+The author (Adam Fritzler), can be reached at afritz@iname.com or mid@auk.cx.
+
+I did have mailing lists available for faim-related discussion, but they
+have dwindled and eventually broke and to my knowledge have yet to fix 
+themselves.
+
+Front-end information:
+  http://www.auk.cx/faim/
+Protocol information:
+  http://www.auk.cx/faim/protocol/
+
diff --git a/aim.h b/aim.h
new file mode 100644 (file)
index 0000000..09cf1a1
--- /dev/null
+++ b/aim.h
@@ -0,0 +1,457 @@
+#ifndef __AIM_H__
+#define __AIM_H__
+
+#include <faimconfig.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#include <time.h>
+#include <io.h>
+#else
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+/* Portability stuff (DMP) */
+
+#ifdef _WIN32
+#define sleep Sleep
+#define strlen(x) (int)strlen(x)  /* win32 has a unsigned size_t */
+#endif
+
+#if defined(_WIN32) || (defined(mach) && defined(__APPLE__)) 
+#define gethostbyname2(x,y) gethostbyname(x) /* revert to IPv4 */
+#endif 
+
+/*
+ * Login Error codes
+ */
+#define AIM_CONNECT_ERROR      -0x1
+#define AIM_SIGNON_TOO_SOON    -0x4
+#define AIM_SERVICE_FULL       -0x6f
+
+/* Current Maximum Length for Screen Names (not including NULL) */
+#define MAXSNLEN 16
+
+struct login_phase1_struct {
+  char *screen_name;
+  char *BOSIP;
+  char *cookie;
+  char *email;
+  u_short regstatus;
+};
+
+extern struct login_phase1_struct aim_logininfo;
+
+struct client_info_s {
+  char clientstring[100]; /* arbitrary number */
+  int major;
+  int minor;
+  int build;
+  char country[3];
+  char lang[3];
+};
+
+struct connection_info_struct {
+  u_int local_seq_num_origin; /* our first seq num */
+  int local_command_count;
+
+  u_int remote_seq_num_origin; /* oscar's first seqnum */
+  int remote_command_count; /* command_count + seq_num_origin = cur_seq_num */
+
+  char *sn; /* our screen name */
+
+  int fd;                   /* socket descriptor */
+};
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define AIM_CONN_MAX 5 
+/* 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 2
+#define AIM_CONN_TYPE_CHAT 0x000e
+#define AIM_CONN_TYPE_CHATNAV 0x000d
+
+#define AIM_CONN_STATUS_READY 0x0001
+#define AIM_CONN_STATUS_INTERNALERR 0x0002
+#define AIM_CONN_STATUS_RESOLVERR 0x80
+#define AIM_CONN_STATUS_CONNERR 0x40
+
+
+struct aim_conn_t {
+  int fd;
+  int type;
+  int seqnum;
+  int status;
+  time_t lastactivity; /* time of last transmit */
+  int forcedlatency; 
+  struct aim_rxcblist_t *handlerlist;
+};
+struct aim_conn_t aim_conns[AIM_CONN_MAX];
+
+
+/* struct for incoming commands */
+struct command_rx_struct {
+                            /* byte 1 assumed to always be 0x2a */
+  char type;                /* type code (byte 2) */
+  u_int seqnum;             /* sequence number (bytes 3 and 4) */
+  u_int commandlen;         /* total packet len - 6 (bytes 5 and 6) */
+  u_char *data;             /* packet data (from 7 byte on) */
+  u_int lock;               /* 0 = open, !0 = locked */
+  u_int handled;            /* 0 = new, !0 = been handled */
+  struct aim_conn_t *conn;  /* the connection it came in on... */
+  struct command_rx_struct *next; /* ptr to next struct in list */
+};
+
+/* struct for outgoing commands */
+struct command_tx_struct {
+                            /* byte 1 assumed to be 0x2a */
+  char type;                /* type/family code */
+  u_int seqnum;             /* seqnum dynamically assigned on tx */
+  u_int commandlen;         /* SNAC length */
+  u_char *data;             /* packet data */
+  u_int lock;               /* 0 = open, !0 = locked */
+  u_int sent;               /* 0 = pending, !0 = has been sent */
+  struct aim_conn_t *conn; 
+  struct command_tx_struct *next; /* ptr to next struct in list */
+};
+
+/*
+ * AIM User Info, Standard Form.
+ */
+struct aim_userinfo_s {
+  char sn[MAXSNLEN+1];
+  u_short warnlevel;
+  u_short idletime;
+  u_short class;
+  u_long membersince;
+  u_long onlinesince;
+  u_long sessionlen;  
+};
+
+/* TLV-related tidbits */
+struct aim_tlv_t {
+  u_short type;
+  u_short length;
+  u_char *value;
+};
+
+struct aim_tlv_t *aim_grabtlv(u_char *src);
+struct aim_tlv_t *aim_grabtlvstr(u_char *src);
+int aim_puttlv (u_char *dest, struct aim_tlv_t *newtlv);
+struct aim_tlv_t *aim_createtlv(void);
+int aim_freetlv(struct aim_tlv_t **oldtlv);
+int aim_puttlv_16(u_char *, u_short, u_short);
+
+/* some prototypes... */
+
+/*   implicitly or explicitly called */
+int aim_get_command(void);
+int aim_rxdispatch(void);
+int aim_logoff(void);
+
+typedef int (*rxcallback_t)(struct command_rx_struct *, ...);
+int aim_register_callbacks(rxcallback_t *);
+
+u_long aim_genericreq_n(struct aim_conn_t *conn, u_short family, u_short subtype);
+u_long aim_genericreq_l(struct aim_conn_t *conn, u_short family, u_short subtype, u_long *);
+u_long aim_genericreq_s(struct aim_conn_t *conn, u_short family, u_short subtype, u_short *);
+
+/* aim_login.c */
+int aim_send_login (struct aim_conn_t *, char *, char *, struct client_info_s *);
+int aim_encode_password(const char *, char *);
+
+
+struct command_rx_struct *aim_purge_rxqueue(struct command_rx_struct *queue);
+
+
+int aim_parse_unknown(struct command_rx_struct *command, ...);
+int aim_parse_missed_im(struct command_rx_struct *, ...);
+int aim_parse_last_bad(struct command_rx_struct *, ...);
+
+int aim_tx_enqueue(struct command_tx_struct *);
+u_int aim_get_next_txseqnum(struct aim_conn_t *);
+int aim_tx_flushqueue(void);
+int aim_tx_printqueue(void);
+int aim_tx_purgequeue(void);
+
+/* queue (linked list) pointers */
+extern struct command_tx_struct *aim_queue_outgoing; /* incoming commands */
+extern struct command_rx_struct *aim_queue_incoming; /* outgoing commands */
+
+/* The default callback handler array */
+extern rxcallback_t aim_callbacks[];
+
+struct aim_rxcblist_t {
+  u_short family;
+  u_short type;
+  rxcallback_t handler;
+  u_short flags;
+  struct aim_rxcblist_t *next;
+};
+
+int aim_conn_setlatency(struct aim_conn_t *conn, int newval);
+
+int aim_conn_addhandler(struct aim_conn_t *conn, u_short family, u_short type, rxcallback_t newhandler, u_short flags);
+rxcallback_t aim_callhandler(struct aim_conn_t *conn, u_short family, u_short type);
+int aim_clearhandlers(struct aim_conn_t *conn);
+
+extern struct aim_snac_t *aim_outstanding_snacs;
+extern u_long aim_snac_nextid;
+
+#define AIM_CB_FAM_ACK 0x0000
+#define AIM_CB_FAM_GEN 0x0001
+#define AIM_CB_FAM_LOC 0x0002
+#define AIM_CB_FAM_BUD 0x0003
+#define AIM_CB_FAM_MSG 0x0004
+#define AIM_CB_FAM_ADS 0x0005
+#define AIM_CB_FAM_INV 0x0006
+#define AIM_CB_FAM_ADM 0x0007
+#define AIM_CB_FAM_POP 0x0008
+#define AIM_CB_FAM_BOS 0x0009
+#define AIM_CB_FAM_LOK 0x000a
+#define AIM_CB_FAM_STS 0x000b
+#define AIM_CB_FAM_TRN 0x000c
+#define AIM_CB_FAM_CTN 0x000d /* ChatNav */
+#define AIM_CB_FAM_CHT 0x000e /* Chat */
+#define AIM_CB_FAM_SPECIAL 0xffff /* Internal libfaim use */
+
+#define AIM_CB_ACK_ACK 0x0001
+
+#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
+
+#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_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
+
+#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_CLIENTERROR 0x000b
+#define AIM_CB_MSG_ACK 0x000c
+#define AIM_CB_MSG_DEFAULT 0xffff
+
+#define AIM_CB_ADS_ERROR 0x0001
+#define AIM_CB_ADS_DEFAULT 0xffff
+
+#define AIM_CB_INV_ERROR 0x0001
+#define AIM_CB_INV_DEFAULT 0xffff
+
+#define AIM_CB_ADM_ERROR 0x0001
+#define AIM_CB_ADM_INFOCHANGE_REPLY 0x0005
+#define AIM_CB_ADM_DEFAULT 0xffff
+
+#define AIM_CB_POP_ERROR 0x0001
+#define AIM_CB_POP_DEFAULT 0xffff
+
+#define AIM_CB_BOS_ERROR 0x0001
+#define AIM_CB_BOS_DEFAULT 0xffff
+
+#define AIM_CB_LOK_ERROR 0x0001
+#define AIM_CB_LOK_DEFAULT 0xffff
+
+#define AIM_CB_STS_ERROR 0x0001
+#define AIM_CB_STS_SETREPORTINTERVAL 0x0002
+#define AIM_CB_STS_REPORTACK 0x0004
+#define AIM_CB_STS_DEFAULT 0xffff
+
+#define AIM_CB_TRN_ERROR 0x0001
+#define AIM_CB_TRN_DEFAULT 0xffff
+
+#define AIM_CB_CTN_ERROR 0x0001
+#define AIM_CB_CTN_DEFAULT 0xffff
+
+#define AIM_CB_CHT_ERROR 0x0001
+#define AIM_CB_CHT_DEFAULT 0xffff
+
+#define AIM_CB_SPECIAL_AUTHSUCCESS 0x0001
+#define AIM_CB_SPECIAL_AUTHOTHER 0x0002
+#define AIM_CB_SPECIAL_UNKNOWN 0xffff
+#define AIM_CB_SPECIAL_DEFAULT AIM_CB_SPECIAL_UNKNOWN
+
+#if 0
+#define AIM_CB_INCOMING_IM 0
+#define AIM_CB_ONCOMING_BUDDY 1
+#define AIM_CB_OFFGOING_BUDDY 2
+#define AIM_CB_MISSED_IM 3
+#define AIM_CB_MISSED_CALL 4
+#define AIM_CB_LOGIN_P4_C1 5
+#define AIM_CB_LOGIN_P4_C2 6
+#define AIM_CB_LOGIN_P2_1 7
+#define AIM_CB_LOGIN_P2_2 8
+#define AIM_CB_LOGIN_P3_B 9
+#define AIM_CB_LOGIN_P3D_A 10
+#define AIM_CB_LOGIN_P3D_B 11
+#define AIM_CB_LOGIN_P3D_C 12
+#define AIM_CB_LOGIN_P3D_D 13
+#define AIM_CB_LOGIN_P3D_E 14
+#define AIM_CB_LOGIN_P3D_F 15
+#define AIM_CB_RATECHANGE 16
+#define AIM_CB_USERERROR 17
+#define AIM_CB_UNKNOWN 18
+#define AIM_CB_USERINFO 19
+#define AIM_CB_SEARCH_ADDRESS 20
+#define AIM_CB_SEARCH_NAME 21
+#define AIM_CB_SEARCH_FAIL 22
+
+#define AIM_CB_AUTH_ERROR 23
+#define AIM_CB_AUTH_SUCCESS 24
+#define AIM_CB_AUTH_SVRREADY 25
+
+#define AIM_CB_AUTH_OTHER 26
+#define AIM_CB_AUTH_INFOCHNG_REPLY 27
+#define AIM_CB_CHATNAV_SVRREADY 28
+#endif
+
+int Read(int, u_char *, int);
+
+struct aim_snac_t {
+  u_long id;
+  u_short family;
+  u_short type;
+  u_short flags;
+  void *data;
+  time_t issuetime;
+  struct aim_snac_t *next;
+};
+u_long aim_newsnac(struct aim_snac_t *newsnac);
+struct aim_snac_t *aim_remsnac(u_long id);
+int aim_cleansnacs(int maxage);
+int aim_putsnac(u_char *, int, int, int, u_long);
+
+void aim_connrst(void);
+struct aim_conn_t *aim_conn_getnext(void);
+void aim_conn_close(struct aim_conn_t *deadconn);
+struct aim_conn_t *aim_getconn_type(int type);
+struct aim_conn_t *aim_newconn(int type, char *dest);
+int aim_conngetmaxfd(void);
+struct aim_conn_t *aim_select(struct timeval *);
+int aim_conn_isready(struct aim_conn_t *);
+int aim_conn_setstatus(struct aim_conn_t *, int);
+
+/* aim_misc.c */
+
+#define AIM_VISIBILITYCHANGE_PERMITADD 0x05
+#define AIM_VISIBILITYCHANGE_PERMITREMOVE 0x06
+#define AIM_VISIBILITYCHANGE_DENYADD 0x07
+#define AIM_VISIBILITYCHANGE_DENYREMOVE 0x08
+
+u_long aim_bos_setidle(struct aim_conn_t *, u_long);
+u_long aim_bos_changevisibility(struct aim_conn_t *, int, char *);
+u_long aim_bos_setbuddylist(struct aim_conn_t *, char *);
+u_long aim_bos_setprofile(struct aim_conn_t *, char *);
+u_long aim_bos_setgroupperm(struct aim_conn_t *, u_long);
+u_long aim_bos_clientready(struct aim_conn_t *);
+u_long aim_bos_reqrate(struct aim_conn_t *);
+u_long aim_bos_ackrateresp(struct aim_conn_t *);
+u_long aim_bos_setprivacyflags(struct aim_conn_t *, u_long);
+u_long aim_bos_reqpersonalinfo(struct aim_conn_t *);
+u_long aim_bos_reqservice(struct aim_conn_t *, u_short);
+u_long aim_bos_reqrights(struct aim_conn_t *);
+u_long aim_bos_reqbuddyrights(struct aim_conn_t *);
+u_long aim_bos_reqlocaterights(struct aim_conn_t *);
+u_long aim_bos_reqicbmparaminfo(struct aim_conn_t *);
+
+/* aim_rxhandlers.c */
+int aim_register_callbacks(rxcallback_t *);
+int aim_rxdispatch(void);
+int aim_authparse(struct command_rx_struct *);
+int aim_handleredirect_middle(struct command_rx_struct *, ...);
+int aim_parse_unknown(struct command_rx_struct *, ...);
+int aim_parse_missed_im(struct command_rx_struct *, ...);
+int aim_parse_last_bad(struct command_rx_struct *, ...);
+int aim_parse_generalerrs(struct command_rx_struct *command, ...);
+
+/* aim_im.c */
+#define AIM_IMFLAGS_AWAY 0x01 /* mark as an autoreply */
+#define AIM_IMFLAGS_ACK 0x02 /* request a receipt notice */
+u_long aim_send_im(struct aim_conn_t *, char *, int, char *);
+int aim_parse_incoming_im_middle(struct command_rx_struct *);
+
+/* aim_info.c */
+u_long aim_getinfo(struct aim_conn_t *, const char *);
+int aim_extractuserinfo(u_char *, struct aim_userinfo_s *);
+int aim_parse_userinfo_middle(struct command_rx_struct *);
+int aim_parse_oncoming_middle(struct command_rx_struct *);
+
+/* aim_auth.c */
+int aim_auth_sendcookie(struct aim_conn_t *, char *);
+u_long aim_auth_clientready(struct aim_conn_t *);
+u_long aim_auth_changepasswd(struct aim_conn_t *, char *, char *);
+
+/* aim_buddylist.c */
+u_long aim_add_buddy(struct aim_conn_t *, char *);
+u_long aim_remove_buddy(struct aim_conn_t *, char *);
+
+/* aim_search.c */
+u_long aim_usersearch_address(struct aim_conn_t *, char *);
+/* u_long aim_usersearch_name(struct aim_conn_t *, char *); */
+
+/* aim_util.c */
+int aimutil_put8(u_char *, u_char);
+int aimutil_put16(u_char *, u_short);
+u_short aimutil_get16(u_char *);
+int aimutil_put32(u_char *, u_long);
+u_long aimutil_get32(u_char *);
+int aimutil_putstr(u_char *, const u_char *, int);
+int aimutil_tokslen(char *toSearch, int index, char dl);
+int aimutil_itemcnt(char *toSearch, char dl);
+char *aimutil_itemidx(char *toSearch, int index, char dl);
+
+
+#endif /* __AIM_H__ */
+
diff --git a/aim_auth.c b/aim_auth.c
new file mode 100644 (file)
index 0000000..bdb279a
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+  aim_auth.c
+
+  Deals with the authorizer.
+
+ */
+
+#include "aim.h"
+
+/* this just pushes the passed cookie onto the passed connection -- NO SNAC! */
+int aim_auth_sendcookie(struct aim_conn_t *conn, char *chipsahoy)
+{
+  struct command_tx_struct newpacket;
+  int curbyte=0;
+  
+  newpacket.lock = 1;
+
+  if (conn==NULL)
+    newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_AUTH);
+  else
+    newpacket.conn = conn;
+
+  newpacket.type = 0x0001;  /* channel 1 (no SNACs, you know) */
+  
+  newpacket.commandlen = 4 + 2 + 2 + 0x100;
+  newpacket.data = (char *) calloc(1, newpacket.commandlen);
+  
+  curbyte += aimutil_put16(newpacket.data+curbyte, 0x0000);
+  curbyte += aimutil_put16(newpacket.data+curbyte, 0x0001);
+  curbyte += aimutil_put16(newpacket.data+curbyte, 0x0006);
+  curbyte += aimutil_put16(newpacket.data+curbyte, 0x0100);
+  memcpy(&(newpacket.data[curbyte]), chipsahoy, 0x100);
+
+  aim_tx_enqueue(&newpacket);
+  
+  return 0;
+}
+
+u_long aim_auth_clientready(struct aim_conn_t *conn)
+{
+  struct command_tx_struct newpacket;
+  int curbyte = 0;
+
+  newpacket.lock = 1;
+
+  if (conn==NULL)
+    newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_AUTH);
+  else
+    newpacket.conn = conn;
+
+  newpacket.type = 0x0002;
+  
+  newpacket.commandlen = 26;
+  newpacket.data = (char *) malloc(newpacket.commandlen);
+  
+  curbyte += aim_putsnac(newpacket.data+curbyte, 0x0001, 0x0002, 0x0000, aim_snac_nextid);
+  curbyte += aimutil_put16(newpacket.data+curbyte, 0x0001);
+  curbyte += aimutil_put16(newpacket.data+curbyte, 0x0002);
+  curbyte += aimutil_put16(newpacket.data+curbyte, 0x0001);
+  curbyte += aimutil_put16(newpacket.data+curbyte, 0x0013);
+  curbyte += aimutil_put16(newpacket.data+curbyte, 0x0007);
+  curbyte += aimutil_put16(newpacket.data+curbyte, 0x0001);
+  curbyte += aimutil_put16(newpacket.data+curbyte, 0x0001);
+  curbyte += aimutil_put16(newpacket.data+curbyte, 0x0001);
+
+  aim_tx_enqueue(&newpacket);
+
+  {
+    struct aim_snac_t snac;
+    
+    snac.id = aim_snac_nextid;
+    snac.family = 0x0001;
+    snac.type = 0x0004;
+    snac.flags = 0x0000;
+
+    snac.data = NULL;
+
+    aim_newsnac(&snac);
+  }
+
+  return (aim_snac_nextid++);
+}
+
+u_long aim_auth_changepasswd(struct aim_conn_t *conn, char *new, char *current)
+{
+  struct command_tx_struct newpacket;
+  int i;
+
+  newpacket.lock = 1;
+
+  if (conn==NULL)
+    newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_AUTH);
+  else
+    newpacket.conn = conn;
+
+  newpacket.type = 0x0002;
+  
+  newpacket.commandlen = 10 + 4 + strlen(current) + 4 + strlen(new);
+  newpacket.data = (char *) malloc(newpacket.commandlen);
+
+  aim_putsnac(newpacket.data, 0x0007, 0x0004, 0x0000, aim_snac_nextid);
+
+  /* current password TLV t(0002) */
+  i = 10;
+  newpacket.data[i++] = 0x00;
+  newpacket.data[i++] = 0x02;
+  newpacket.data[i++] = 0x00;
+  newpacket.data[i++] = strlen(current) & 0xff;
+  memcpy(&(newpacket.data[i]), current, strlen(current));
+  i += strlen(current);
+
+  /* new password TLV t(0012) */
+  newpacket.data[i++] = 0x00;
+  newpacket.data[i++] = 0x12;
+  newpacket.data[i++] = 0x00;
+  newpacket.data[i++] = strlen(new) & 0xff;
+  memcpy(&(newpacket.data[i]), new, strlen(new));
+  i+=strlen(new);
+
+  aim_tx_enqueue(&newpacket);
+
+  {
+    struct aim_snac_t snac;
+    
+    snac.id = aim_snac_nextid;
+    snac.family = 0x0001;
+    snac.type = 0x0004;
+    snac.flags = 0x0000;
+
+    snac.data = NULL;
+
+    aim_newsnac(&snac);
+  }
+
+  return (aim_snac_nextid++);
+}
diff --git a/aim_buddylist.c b/aim_buddylist.c
new file mode 100644 (file)
index 0000000..b9ac86a
--- /dev/null
@@ -0,0 +1,95 @@
+
+#include <aim.h>
+
+/*
+ * aim_add_buddy()
+ *
+ * Adds a single buddy to your buddy list after login.
+ *
+ */
+u_long aim_add_buddy(struct aim_conn_t *conn, char *sn )
+{
+   struct command_tx_struct newpacket;
+
+   if( !sn )
+      return -1;
+
+   if (conn)
+     newpacket.conn = conn;
+   else
+     newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS);
+
+   newpacket.lock = 1;
+   newpacket.type = 0x0002;
+   newpacket.commandlen = 11 + strlen( sn );
+   newpacket.data = (char *)malloc( newpacket.commandlen );
+
+   aim_putsnac(newpacket.data, 0x0003, 0x0004, 0x0000, aim_snac_nextid);
+
+   /* length of screenname */ 
+   newpacket.data[10] = strlen( sn );
+
+   memcpy( &(newpacket.data[11]), sn, strlen( sn ) );
+
+   aim_tx_enqueue( &newpacket );
+
+   {
+      struct aim_snac_t snac;
+    
+      snac.id = aim_snac_nextid;
+      snac.family = 0x0003;
+      snac.type = 0x0004;
+      snac.flags = 0x0000;
+
+      snac.data = malloc( strlen( sn ) + 1 );
+      memcpy( snac.data, sn, strlen( sn ) + 1 );
+
+      aim_newsnac( &snac );
+   }
+
+   return( aim_snac_nextid++ );
+}
+
+u_long aim_remove_buddy(struct aim_conn_t *conn, char *sn )
+{
+   struct command_tx_struct newpacket;
+
+   if( !sn )
+      return -1;
+
+   if (conn)
+     newpacket.conn = conn;
+   else
+     newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS);
+
+   newpacket.lock = 1;
+   newpacket.type = 0x0002;
+   newpacket.commandlen = 11 + strlen(sn);
+   newpacket.data = (char *)malloc( newpacket.commandlen );
+
+   aim_putsnac(newpacket.data, 0x0003, 0x0005, 0x0000, aim_snac_nextid);
+
+   /* length of screenname */ 
+   newpacket.data[10] = strlen( sn );
+
+   memcpy( &(newpacket.data[11]), sn, strlen( sn ) );
+
+   aim_tx_enqueue( &newpacket );
+
+   {
+      struct aim_snac_t snac;
+    
+      snac.id = aim_snac_nextid;
+      snac.family = 0x0003;
+      snac.type = 0x0005;
+      snac.flags = 0x0000;
+
+      snac.data = malloc( strlen( sn ) + 1 );
+      memcpy( snac.data, sn, strlen( sn ) + 1 );
+
+      aim_newsnac( &snac );
+   }
+
+   return( aim_snac_nextid++ );
+}
+
diff --git a/aim_chat.c b/aim_chat.c
new file mode 100644 (file)
index 0000000..1923dc7
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * aim_chat.c
+ *
+ * Routines for the Chat service.  Nothing works (yet).
+ *
+ */
+
+#include "aim.h"
+
+/*
+ * FIXME: Doesn't work.
+ *
+ */
+u_long aim_chat_join(struct aim_conn_t *conn, const char *roomname)
+{
+  struct command_tx_struct newpacket;
+  
+  newpacket.lock = 1;
+  if (conn)
+    newpacket.conn = conn;
+  else
+    newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS);
+  newpacket.type = 0x0002;
+  
+  newpacket.commandlen = 12+7+strlen(roomname)+6;
+  newpacket.data = (char *) malloc(newpacket.commandlen);
+  memset(newpacket.data, 0x00, newpacket.commandlen);
+  
+  aim_putsnac(newpacket.data, 0x0001, 0x0004, 0x0000, aim_snac_nextid);
+
+  newpacket.data[10] = 0x00;
+  newpacket.data[11] = 0x0e;
+  newpacket.data[12] = 0x00;
+  newpacket.data[13] = 0x01;
+  newpacket.data[14] = 0x00;
+  newpacket.data[15] = 0x0c;
+  newpacket.data[16] = 0x00;
+  newpacket.data[17] = 0x04;
+  newpacket.data[18] = strlen(roomname) & 0x00ff;
+  memcpy(&(newpacket.data[19]), roomname, strlen(roomname));
+  
+  {
+    u_int i = 0;
+    printf("\n\n\n");
+    for (i = 0;i < newpacket.commandlen; i++)
+      printf("0x%02x ", newpacket.data[i]);
+    printf("\n\n\n");
+  }
+
+  aim_tx_enqueue(&newpacket);
+
+  {
+    struct aim_snac_t snac;
+    
+    snac.id = aim_snac_nextid;
+    snac.family = 0x0001;
+    snac.type = 0x0004;
+    snac.flags = 0x0000;
+
+    snac.data = malloc(strlen(roomname));
+    memcpy(snac.data, roomname, strlen(roomname));
+
+    aim_newsnac(&snac);
+  }
+
+  return (aim_snac_nextid++);
+}
diff --git a/aim_chatnav.c b/aim_chatnav.c
new file mode 100644 (file)
index 0000000..8bdc233
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ *
+ *
+ *
+ *
+ */
+
+#include "aim.h"
+
diff --git a/aim_conn.c b/aim_conn.c
new file mode 100644 (file)
index 0000000..322effd
--- /dev/null
@@ -0,0 +1,224 @@
+
+/*
+ *  aim_conn.c
+ *
+ * Does all this gloriously nifty connection handling stuff...
+ *
+ */
+
+#include "aim.h"
+
+void aim_connrst(void)
+{
+  int i;
+  for (i = 0; i < AIM_CONN_MAX; i++)
+    {
+      aim_conns[i].fd = -1;
+      aim_conns[i].type = -1;
+      aim_conns[i].status = 0;
+      aim_conns[i].seqnum = 0;
+      aim_conns[i].lastactivity = 0;
+      aim_conns[i].forcedlatency = 0;
+      aim_clearhandlers(&aim_conns[i]);
+      aim_conns[i].handlerlist = NULL;
+    }
+
+}
+
+struct aim_conn_t *aim_conn_getnext(void)
+{
+  int i;
+  for (i=0;i<AIM_CONN_MAX;i++)
+    if (aim_conns[i].fd == -1)
+      return &(aim_conns[i]);
+  return NULL;
+}
+
+void aim_conn_close(struct aim_conn_t *deadconn)
+{
+  if (deadconn->fd >= 3)
+    close(deadconn->fd);
+  deadconn->fd = -1;
+  deadconn->type = -1;
+  deadconn->seqnum = 0;
+  deadconn->lastactivity = 0;
+  deadconn->forcedlatency = 0;
+  aim_clearhandlers(deadconn);
+  deadconn->handlerlist = NULL;
+}
+
+struct aim_conn_t *aim_getconn_type(int type)
+{
+  int i;
+  for (i=0; i<AIM_CONN_MAX; i++)
+    if (aim_conns[i].type == type)
+      return &(aim_conns[i]);
+  return NULL;
+}
+
+/*
+ * aim_newconn(type, dest)
+ *
+ * Opens a new connection to the specified dest host of type type.
+ *
+ * TODO: fix for proxies
+ * FIXME: Return errors in a more sane way.
+ *
+ */
+struct aim_conn_t *aim_newconn(int type, char *dest)
+{
+  struct aim_conn_t *connstruct;
+  int ret;
+  struct sockaddr_in sa;
+  struct hostent *hp;
+  u_short port = FAIM_LOGIN_PORT;
+  int i=0;
+  
+  if (!dest || ((connstruct=aim_conn_getnext())==NULL))
+    return NULL;
+
+  connstruct->type = type;
+
+  /* 
+   * As of 23 Jul 1999, AOL now sends the port number, preceded by a 
+   * colon, in the BOS redirect.  This fatally breaks all previous 
+   * libfaims.  Bad, bad AOL.
+   *
+   * We put this here to catch every case. 
+   *
+   */
+
+  for(i=0;(i<strlen(dest));i++)
+    if (dest[i] == ':') {
+      port = atoi(&(dest[i+1]));
+      dest[i]=0;
+      break;
+    }
+
+  hp = gethostbyname2(dest, AF_INET);
+  if (hp == NULL)
+    {
+      connstruct->status = (h_errno | AIM_CONN_STATUS_RESOLVERR);
+      return connstruct;
+    }
+
+  memset(&sa.sin_zero, 0, 8);
+  sa.sin_port = htons(port);
+  memcpy(&sa.sin_addr, hp->h_addr, hp->h_length);
+  sa.sin_family = hp->h_addrtype;
+  
+  connstruct->fd = socket(hp->h_addrtype, SOCK_STREAM, 0);
+  ret = connect(connstruct->fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in));
+  if( ret < 0)
+    {
+      connstruct->fd = -1;
+      connstruct->status = (errno | AIM_CONN_STATUS_CONNERR);
+      return connstruct;
+    }
+
+  return connstruct;
+}
+
+int aim_conngetmaxfd(void)
+{
+  int i,j;
+  j=0;
+  for (i=0;i<AIM_CONN_MAX;i++)
+    if(aim_conns[i].fd > j)
+      j = aim_conns[i].fd;
+  return j;
+}
+
+int aim_countconn(void)
+{
+  int i,cnt;
+  cnt = 0;
+  for (i=0;i<AIM_CONN_MAX;i++)
+    if (aim_conns[i].fd > -1)
+      cnt++;
+  return cnt;
+}
+
+/*
+ * aim_select(timeout)
+ *
+ * Waits for a socket with data or for timeout, whichever comes first.
+ * See select(2).
+ * 
+ */ 
+struct aim_conn_t *aim_select(struct timeval *timeout)
+{
+  fd_set fds;
+  fd_set errfds;
+  int i;
+
+  if (aim_countconn() <= 0)
+    return 0;
+
+  /* 
+   * If we have data waiting to be sent, return immediatly
+   */
+  if (aim_queue_outgoing)
+    return (struct aim_conn_t *)1;
+
+  FD_ZERO(&fds);
+  FD_ZERO(&errfds);
+  
+  for(i=0;i<AIM_CONN_MAX;i++)
+    if (aim_conns[i].fd>-1)
+      {
+       FD_SET(aim_conns[i].fd, &fds);
+       FD_SET(aim_conns[i].fd, &errfds);
+      }
+  
+  i = select(aim_conngetmaxfd()+1, &fds, NULL, &errfds, timeout);
+  if (i>=1)
+    {
+      int j;
+      for (j=0;j<AIM_CONN_MAX;j++)
+       {
+         if (aim_conns[j].fd > -1)
+           {
+             if ((FD_ISSET(aim_conns[j].fd, &errfds)))
+               {
+                 /* got an exception; close whats left of it up */
+                 aim_conn_close(&(aim_conns[j]));
+                 return (struct aim_conn_t *)-1;
+               }
+             else if ((FD_ISSET(aim_conns[j].fd, &fds)))
+               return &(aim_conns[j]);  /* return the first waiting struct */
+           }
+       }
+      /* should never get here */
+    }
+  else
+    return (struct aim_conn_t *)i;  /* no waiting or error, return -- FIXME: return type funnies */
+  return NULL; /* NO REACH */
+}
+
+int aim_conn_isready(struct aim_conn_t *conn)
+{
+  if (conn)
+    return (conn->status & 0x0001);
+  else
+    return -1;
+}
+
+int aim_conn_setstatus(struct aim_conn_t *conn, int status)
+{
+  if (conn)
+    return (conn->status ^= status);
+  else
+    return -1;
+}
+
+int aim_conn_setlatency(struct aim_conn_t *conn, int newval)
+{
+  if (!conn)
+    return -1;
+  
+  conn->forcedlatency = newval;
+  conn->lastactivity = 0; /* reset this just to make sure */
+
+  return 0;
+}
diff --git a/aim_global.c b/aim_global.c
new file mode 100644 (file)
index 0000000..caac61f
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+  aim_global.c
+
+  These are things that are globally required, but don't fit the
+  naming of the rest of the functions.  Namely, the queue ptrs and fds.
+
+ */
+
+#include "aim.h" 
+
+/* the dreaded global variables... */
+
+struct login_phase1_struct aim_logininfo;
+
+/* queue (linked list) pointers */
+struct command_tx_struct *aim_queue_outgoing = NULL; /* incoming commands */
+struct command_rx_struct *aim_queue_incoming = NULL; /* outgoing commands */
diff --git a/aim_im.c b/aim_im.c
new file mode 100644 (file)
index 0000000..ab07048
--- /dev/null
+++ b/aim_im.c
@@ -0,0 +1,546 @@
+/*
+ *  aim_im.c
+ *
+ *  The routines for sending/receiving Instant Messages.
+ *
+ */
+
+#include "aim.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)
+ *
+ *
+ * The first one is newer, but it seems to be broken.  Beware.  Use the 
+ * second one for normal use...for now.
+ *
+ *
+ */
+
+#if 0 /* preliminary new fangled routine */
+u_long aim_send_im(struct aim_conn_t *conn, char *destsn, int flags, char *msg)
+{   
+
+  int curbyte;
+  struct command_tx_struct newpacket;
+  
+  newpacket.lock = 1; /* lock struct */
+  newpacket.type = 0x02; /* IMs are always family 0x02 */
+  if (conn)
+    newpacket.conn = conn;
+  else
+    newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS);
+
+  newpacket.commandlen = 20+1+strlen(destsn)+1+1+2+7+2+4+strlen(msg)+2;
+
+  if (flags & AIM_IMFLAGS_ACK)
+    newpacket.commandlen += 4;
+  if (flags & AIM_IMFLAGS_AWAY)
+    newpacket.commandlen += 4;
+
+  newpacket.data = (char *) calloc(1, newpacket.commandlen);
+
+  curbyte  = 0;
+  curbyte += aim_putsnac(newpacket.data+curbyte, 0x0004, 0x0006, 0x0000, aim_snac_nextid);
+  curbyte += aimutil_put16(newpacket.data+curbyte,0x0000);
+  curbyte += aimutil_put16(newpacket.data+curbyte,0x0000);
+  curbyte += aimutil_put16(newpacket.data+curbyte,0x0000);
+  curbyte += aimutil_put16(newpacket.data+curbyte,0x0000);
+  curbyte += aimutil_put16(newpacket.data+curbyte,0x0001);
+  curbyte += aimutil_put8(newpacket.data+curbyte,strlen(destsn));
+  curbyte += aimutil_putstr(newpacket.data+curbyte, destsn, strlen(destsn));
+
+  if (flags & AIM_IMFLAGS_ACK)
+    {
+      curbyte += aimutil_put16(newpacket.data+curbyte,0x0003);
+      curbyte += aimutil_put16(newpacket.data+curbyte,0x0000);
+    }
+
+  if (flags & AIM_IMFLAGS_AWAY)
+    {
+      curbyte += aimutil_put16(newpacket.data+curbyte,0x0004);
+      curbyte += aimutil_put16(newpacket.data+curbyte,0x0000);
+    }
+
+  curbyte += aimutil_put16(newpacket.data+curbyte,0x0002);
+  curbyte += aimutil_put16(newpacket.data+curbyte,strlen(msg)+0xf);
+  curbyte += aimutil_put16(newpacket.data+curbyte,0x0501);
+  curbyte += aimutil_put16(newpacket.data+curbyte,0x0001);
+  curbyte += aimutil_put16(newpacket.data+curbyte,0x0101);
+  curbyte += aimutil_put16(newpacket.data+curbyte,0x0101);
+  curbyte += aimutil_put8(newpacket.data+curbyte,0x01);
+  curbyte += aimutil_put16(newpacket.data+curbyte,strlen(msg)+4);
+  curbyte += aimutil_put16(newpacket.data+curbyte,0x0000);
+  curbyte += aimutil_put16(newpacket.data+curbyte,0x0000);
+  curbyte += aimutil_putstr(newpacket.data+curbyte, msg, strlen(msg));
+
+  aim_tx_enqueue(&newpacket);
+
+#ifdef USE_SNAC_FOR_IMS
+ {
+    struct aim_snac_t snac;
+
+    snac.id = aim_snac_nextid;
+    snac.family = 0x0004;
+    snac.type = 0x0006;
+    snac.flags = 0x0000;
+
+    snac.data = malloc(strlen(destsn)+1);
+    memcpy(snac.data, destsn, strlen(destsn)+1);
+
+    aim_newsnac(&snac);
+  }
+
+ aim_cleansnacs(60); /* clean out all SNACs over 60sec old */
+#endif
+
+  return (aim_snac_nextid++);
+}
+#else
+u_long aim_send_im(struct aim_conn_t *conn, char *destsn, int flags, char *msg)
+{
+
+  int i;
+  struct command_tx_struct newpacket;
+
+  newpacket.lock = 1; /* lock struct */
+  newpacket.type = 0x02; /* IMs are always family 0x02 */
+  if (conn)
+    newpacket.conn = conn;
+  else
+    newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS);
+
+  i = strlen(destsn); /* used as offset later */
+  newpacket.commandlen = 20+1+strlen(destsn)+1+1+2+7+2+4+strlen(msg);
+
+  if (flags & AIM_IMFLAGS_ACK)
+    newpacket.commandlen += 4;
+  if (flags & AIM_IMFLAGS_AWAY)
+    newpacket.commandlen += 4;
+
+  newpacket.data = (char *) malloc(newpacket.commandlen);
+  memset(newpacket.data, 0x00, newpacket.commandlen);
+
+  aim_putsnac(newpacket.data, 0x0004, 0x0006, 0x0000, aim_snac_nextid);
+
+  newpacket.data[18] = 0x00;
+  newpacket.data[19] = 0x01;
+
+  newpacket.data[20] = i;
+  memcpy(&(newpacket.data[21]), destsn, i);
+
+  if (flags & AIM_IMFLAGS_ACK)
+    {
+      /* add TLV t(0004) l(0000) v(NULL) */
+      newpacket.data[21+i] = 0x00;
+      newpacket.data[22+i] = 0x03;
+      newpacket.data[23+i] = 0x00;
+      newpacket.data[24+i] = 0x00;
+      i += 4;
+    }
+  if (flags & AIM_IMFLAGS_AWAY)
+    {
+      /* add TLV t(0004) l(0000) v(NULL) */
+      newpacket.data[21+i] = 0x00;
+      newpacket.data[22+i] = 0x04;
+      newpacket.data[23+i] = 0x00;
+      newpacket.data[24+i] = 0x00;
+      i += 4;
+    }
+
+  newpacket.data[21+i] = 0x00;
+
+  newpacket.data[22+i] = 0x02;
+
+  newpacket.data[23+i] = (char) ( (strlen(msg) + 0xD) >> 8);
+  newpacket.data[24+i] = (char) ( (strlen(msg) + 0xD) & 0xFF);
+
+  newpacket.data[25+i] = 0x05;
+  newpacket.data[26+i] = 0x01;
+  newpacket.data[27+i] = 0x00;
+  newpacket.data[28+i] = 0x01;
+  newpacket.data[29+i] = 0x01;
+  newpacket.data[30+i] = 0x01;
+  newpacket.data[31+i] = 0x01;
+
+  newpacket.data[32+i] = (char) ( (strlen(msg) + 4) >> 8);
+  newpacket.data[33+i] = (char) ( (strlen(msg) + 4) & 0xFF);
+
+  memcpy(&(newpacket.data[38+i]), msg, strlen(msg));
+
+  aim_tx_enqueue(&newpacket);
+#ifdef USE_SNAC_FOR_IMS
+ {
+    struct aim_snac_t snac;
+
+    snac.id = aim_snac_nextid;
+    snac.family = 0x0004;
+    snac.type = 0x0006;
+    snac.flags = 0x0000;
+
+    snac.data = malloc(strlen(destsn)+1);
+    memcpy(snac.data, destsn, strlen(destsn)+1);
+
+    aim_newsnac(&snac);
+  }
+
+ aim_cleansnacs(60); /* clean out all SNACs over 60sec old */
+#endif
+
+  return (aim_snac_nextid++);
+}
+
+#endif
+
+#if 0 /* this is the prelim work on a new routine */
+int aim_parse_incoming_im_middle(struct command_rx_struct *command)
+{
+  int i = 0;
+  char *srcsn = NULL;
+  char *msg = NULL;
+  u_int msglen = 0;
+  int warninglevel = 0;
+  int tlvcnt = 0;
+  int class = 0;
+  u_long membersince = 0;
+  u_long onsince = 0;
+  int idletime = 0;
+  int isautoreply = 0;
+  rxcallback_t userfunc = NULL;
+
+  int unknown_f = -1;
+  int unknown_10 = -1;
+
+  i = 20; /* skip SNAC header and message cookie */
+  
+  srcsn = malloc(command->data[i] + 1);
+  memcpy(srcsn, &(command->data[i+1]), command->data[i]);
+  srcsn[(int)command->data[i]] = '\0';
+  
+  i += (int) command->data[i] + 1; /* add SN len */
+  
+  /* warning level */
+  warninglevel = (command->data[i] << 8);
+  warninglevel += (command->data[i+1]);
+  i += 2;
+  
+  /*
+   * This is suppose to be the number of TLVs that follow.  However,
+   * its not nearly as accurate as we need it to be, so we just run
+   * the TLV parser all the way to the end of the frame.  
+   */
+  tlvcnt = ((command->data[i++]) << 8) & 0xFF00;
+  tlvcnt += (command->data[i++]) & 0x00FF;
+  
+  /* a mini TLV parser */
+  {
+    int curtlv = 0;
+    int count_t4 = 0, count_t3 = 0, count_t2 = 0, count_t1 = 0;
+    
+    while (i+4 < command->commandlen)
+      {
+       if ((command->data[i] == 0x00) &&
+           (command->data[i+1] == 0x01) )
+         {
+           if (count_t1 == 0)
+             {
+               /* t(0001) = class */
+               if (command->data[i+3] != 0x02)
+                 printf("faim: userinfo: **warning: strange v(%x) for t(1)\n", command->data[i+3]);
+               class = ((command->data[i+4]) << 8) & 0xFF00;
+               class += (command->data[i+5]) & 0x00FF;
+             }
+           else
+             printf("faim: icbm: unexpected extra TLV t(0001)\n");
+           count_t1++;
+         }
+       else if ((command->data[i] == 0x00) &&
+                (command->data[i+1] == 0x02))
+         {
+           if (count_t2 == 0)
+             {
+               /* t(0002) = member since date  */
+               if (command->data[i+3] != 0x04)
+                 printf("faim: userinfo: **warning: strange v(%x) for t(2)\n", command->data[i+3]);
+               
+               membersince = ((command->data[i+4]) << 24) &  0xFF000000;
+               membersince += ((command->data[i+5]) << 16) & 0x00FF0000;
+               membersince += ((command->data[i+6]) << 8) &  0x0000FF00;
+               membersince += ((command->data[i+7]) ) &      0x000000FF;
+             }
+           else if (count_t2 == 1)
+             {
+               int biglen = 0, innerlen = 0;
+               int j;
+
+               /* message */
+
+               /* 
+                * Check for message signature (0x0501).  I still don't really
+                * like this, but it is better than the old way, and it does
+                * seem to be consistent as long as AOL doesn't do any more
+                * big changes.
+                */
+               if ( (command->data[i+4] != 0x05) ||
+                    (command->data[i+5] != 0x01) )
+                 printf("faim: icbm: warning: message signature not present, trying to recover\n");
+               
+               biglen = ((command->data[i+2] << 8) + command->data[i+3]) & 0xffff;
+
+               printf("faim: icbm: biglen = %02x\n", biglen);
+
+               j = 0;
+               while (j+3 < (biglen-6))
+                 {
+                   if ( (command->data[i+6+j+0] == 0x00) &&
+                        (command->data[i+6+j+1] == 0x00) &&
+                        (command->data[i+6+j+2] == 0x00) )
+                     {
+                       
+                       innerlen = (command->data[i+6+j]<<8) + command->data[i+6+j+1];
+                       break;
+                     }
+                   j++;
+                 }
+               if (!innerlen)
+                 {
+                   printf("faim: icbm: unable to find holy zeros; skipping message\n");
+                   msglen = 0;
+                   msg = NULL;
+                 }
+               else
+                 {
+                   printf("faim: icbm: innerlen = %d\n", innerlen);
+                   
+                   msglen = innerlen - 4;
+                   printf("faim: icbm: msglen = %u\n", msglen);
+                   
+                   msg = malloc(msglen +1);
+                   memcpy(msg, &(command->data[i+6+j+4+1]), msglen);
+                   msg[msglen] = '\0'; 
+                 }
+             }
+           else
+             printf("faim: icbm: **warning: extra TLV t(0002)\n");
+           count_t2++;
+         }
+       else if ((command->data[i] == 0x00) &&
+                (command->data[i+1] == 0x03))
+         {
+           if (count_t3 == 0)
+             {
+               /* t(0003) = on since date  */
+               if (command->data[i+3] != 0x04)
+                 printf("faim: userinfo: **warning: strange v(%x) for t(3)\n", command->data[i+3]);
+               
+               onsince = ((command->data[i+4]) << 24) &  0xFF000000;
+               onsince += ((command->data[i+5]) << 16) & 0x00FF0000;
+               onsince += ((command->data[i+6]) << 8) &  0x0000FF00;
+               onsince += ((command->data[i+7]) ) &      0x000000FF;
+             }
+           else if (count_t3 == 1)
+             printf("faim: icbm: request for acknowledgment ignored\n");
+           else
+             printf("faim: icbm: unexpected extra TLV t(0003)\n");
+           count_t3++;
+         }
+       else if ((command->data[i] == 0x00) &&
+                (command->data[i+1] == 0x04) )
+         {
+           if (count_t4 == 0)
+             {
+               /* t(0004) = idle time */
+               if (command->data[i+3] != 0x02)
+                 printf("faim: userinfo: **warning: strange v(%x) for t(4)\n", command->data[i+3]);
+               idletime = ((command->data[i+4]) << 8) & 0xFF00;
+               idletime += (command->data[i+5]) & 0x00FF;
+             }
+           else if ((count_t4 == 1) && (((command->data[i+2]<<8)+command->data[i+3])==0x0000))
+             isautoreply = 1;
+           else
+             printf("faim: icbm: unexpected extra TLV t(0004)\n");
+           count_t4++;
+         } 
+       else if ((command->data[i] == 0x00) &&
+                (command->data[i+1] == 0x0f))
+         {
+           /* t(000f) = unknown...usually from AIM3 users */
+           if (command->data[i+3] != 0x04)
+             printf("faim: userinfo: **warning: strange v(%x) for t(f)\n", command->data[i+3]);
+           unknown_f = (command->data[i+4] << 24) & 0xff000000;
+           unknown_f += (command->data[i+5] << 16) & 0x00ff0000;
+           unknown_f += (command->data[i+6] <<  8) & 0x0000ff00;
+           unknown_f += (command->data[i+7]) & 0x000000ff;
+         }
+        else if ((command->data[i] == 0x00) &&
+                 (command->data[i+1] == 0x10))
+          {
+            /* t(0010) = unknown...usually from AOL users */
+            if (command->data[i+3] != 0x04)
+              printf("faim: userinfo: **warning: strange v(%x) for t(10)\n", command->data[i+3]);
+            unknown_10 = (command->data[i+4] << 24) & 0xff000000;
+            unknown_10 += (command->data[i+5] << 16) & 0x00ff0000;
+            unknown_10 += (command->data[i+6] <<  8) & 0x0000ff00;
+            unknown_10 += (command->data[i+7]) & 0x000000ff;
+          }
+       else
+         {
+           printf("faim: userinfo: **warning: unexpected TLV t(%02x%02x) l(%02x%02x)\n", command->data[i], command->data[i+1], command->data[i+2], command->data[i+3]);
+         }
+       i += (2 + 2 + ((command->data[i+2] << 8) + command->data[i+3]));
+       curtlv++;
+      }
+  }
+
+#if 0
+  {
+    /* detect if this is an auto-response or not */
+    /*   auto-responses can be detected by the presence of a *second* TLV with
+        t(0004), but of zero length (and therefore no value portion) */
+    struct aim_tlv_t *tsttlv = NULL;
+    tsttlv = aim_grabtlv((u_char *) &(command->data[i]));
+    if (tsttlv->type == 0x04)
+      isautoreply = 1;
+    aim_freetlv(&tsttlv);
+  }
+
+  i += 2;
+  
+  i += 2; /* skip first msglen */
+  i += 7; /* skip garbage */
+  i -= 4;
+
+  /* oh boy is this terrible...  this comes from a specific of the spec */
+  while(1)
+    {
+      if ( ( (command->data[i] == 0x00) &&
+            (command->data[i+1] == 0x00) &&
+            (command->data[i+2] == 0x00) &&
+            (command->data[i+3] == 0x00) ) &&
+          (i < command->commandlen) ) /* prevent infinity */
+       break;
+      else
+       i++;
+    }
+
+  i -= 2;
+  
+  if ( (command->data[i] == 0x00) &&
+       (command->data[i+1] == 0x00) )
+    i += 2;
+
+  msglen = ( (( (u_int) command->data[i]) & 0xFF ) << 8);
+  msglen += ( (u_int) command->data[i+1]) & 0xFF; /* mask off garbage */
+  i += 2;
+
+  msglen -= 4; /* skip four 0x00s */
+  i += 4;
+  
+  msg = malloc(msglen +1);
+  
+  memcpy(msg, &(command->data[i]), msglen);
+  msg[msglen] = '\0'; 
+#endif
+  userfunc = aim_callhandler(command->conn, 0x0004, 0x0007);
+  if (userfunc)
+    i = userfunc(command, srcsn, msg, warninglevel, class, membersince, onsince, idletime, isautoreply, unknown_f, unknown_10);
+  else 
+    i = 0;
+
+  free(srcsn);
+  free(msg);
+
+  return i;
+}
+#else /* older routine, with new fixes */
+int aim_parse_incoming_im_middle(struct command_rx_struct *command)
+{
+  struct aim_userinfo_s userinfo;
+  u_int i = 0;
+  char *msg = NULL;
+  u_int msglen = 0;
+  int isautoreply = 0;
+  rxcallback_t userfunc = NULL;
+
+  i = 20;
+  i += aim_extractuserinfo(command->data+i, &userinfo);
+
+  {
+    /* 
+     *  Auto-responses can be detected by the presence of a *second* TLV with
+     *  t(0004), but of zero length (and therefore no value portion) 
+     */
+    struct aim_tlv_t *tsttlv = NULL;
+    tsttlv = aim_grabtlv((u_char *) &(command->data[i]));
+    if (tsttlv->type == 0x04)
+      isautoreply = 1;
+#if 0
+    else if (tsttlv->type == 0x03)
+      {
+       printf("faim: icbm: ack requested, ignored\n");
+       i += 2 + 2 + tsttlv->length;
+       aim_freetlv(&tsttlv);
+       tsttlv = aim_grabtlv((u_char *) &(command->data[i]));
+       if (tsttlv->type == 0x04)
+         isautoreply = 1;
+      }
+#endif
+    aim_freetlv(&tsttlv);
+  }
+  
+  i += 2;
+  
+  i += 2; /* skip first msglen */
+  i += 7; /* skip garbage */
+  i -= 4;
+
+  /* oh boy is this terrible...  this comes from a specific of the spec */
+  while(1)
+    {
+      /* 
+       * We used to look for four zeros; I've reduced this to three
+       * as it seems AOL changed it with Mac AIM 3.0 clients.
+       */
+      if ( ( (command->data[i] == 0x00) &&
+            (command->data[i+1] == 0x00) &&
+            (command->data[i+2] == 0x00) ) &&
+          (i+2 < command->commandlen) ) /* prevent infinity */
+       break;
+      else
+       i++;
+    }
+
+  i -= 2;
+  
+  if (aimutil_get16(&command->data[i]) == 0x0000)
+    i += 2;
+
+  msglen = aimutil_get16(&command->data[i]);
+  i += 2;
+
+  msglen -= 4; /* skip four 0x00s */
+  i += 4;
+  
+  msg = malloc(msglen +1);
+  
+  memcpy(msg, &(command->data[i]), msglen);
+  msg[msglen] = '\0'; 
+
+  userfunc = aim_callhandler(command->conn, 0x0004, 0x0007);
+
+  if (userfunc)
+    i = userfunc(command, &userinfo, msg, isautoreply);
+  else 
+    i = 0;
+
+  free(msg);
+
+  return i;
+}
+#endif
diff --git a/aim_info.c b/aim_info.c
new file mode 100644 (file)
index 0000000..9d085a6
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ * aim_info.c
+ *
+ * The functions here are responsible for requesting and parsing information-
+ * gathering SNACs.  
+ *
+ */
+
+
+#include "aim.h" /* for most everything */
+
+u_long aim_getinfo(struct aim_conn_t *conn, const char *sn)
+{
+  struct command_tx_struct newpacket;
+
+  if (conn)
+    newpacket.conn = conn;
+  else
+    newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS);
+
+  newpacket.lock = 1;
+  newpacket.type = 0x0002;
+
+  newpacket.commandlen = 12 + 1 + strlen(sn);
+  newpacket.data = (char *) malloc(newpacket.commandlen);
+
+  aim_putsnac(newpacket.data, 0x0002, 0x0005, 0x0000, aim_snac_nextid);
+
+  aimutil_put16(newpacket.data+10, 0x0001);
+  aimutil_put8(newpacket.data+12, strlen(sn));
+  aimutil_putstr(newpacket.data+13, sn, strlen(sn));
+
+  aim_tx_enqueue(&newpacket);
+
+  {
+    struct aim_snac_t snac;
+    
+    snac.id = aim_snac_nextid;
+    snac.family = 0x0002;
+    snac.type = 0x0005;
+    snac.flags = 0x0000;
+
+    snac.data = malloc(strlen(sn)+1);
+    memcpy(snac.data, sn, strlen(sn)+1);
+
+    aim_newsnac(&snac);
+  }
+
+  return (aim_snac_nextid++);
+}
+
+/*
+ * AIM is fairly regular about providing user info.  This
+ * is a generic routine to extract it in its standard form.
+ */
+int aim_extractuserinfo(u_char *buf, struct aim_userinfo_s *outinfo)
+{
+  int i = 0;
+  int tlvcnt = 0;
+  int curtlv = 0;
+  int tlv1 = 0;
+  u_short curtype;
+
+
+  if (!buf || !outinfo)
+    return -1;
+
+  /* Clear out old data first */
+  memset(outinfo, 0x00, sizeof(struct aim_userinfo_s));
+
+  /*
+   * Screen name.    Stored as an unterminated string prepended
+   *                 with an unsigned byte containing its length.
+   */
+  memcpy(outinfo->sn, &(buf[i+1]), buf[i]);
+  outinfo->sn[(int)buf[i]] = '\0';
+  i = 1 + (int)buf[i];
+
+  /*
+   * Warning Level.  Stored as an unsigned short.
+   */
+  outinfo->warnlevel = aimutil_get16(&buf[i]);
+  i += 2;
+
+  /*
+   * TLV Count.      Unsigned short representing the number of 
+   *                 Type-Length-Value triples that follow.
+   */
+  tlvcnt = aimutil_get16(&buf[i]);
+  i += 2;
+
+  /* 
+   * Parse out the Type-Length-Value triples as they're found.
+   */
+  while (curtlv < tlvcnt)
+    {
+      curtype = aimutil_get16(&buf[i]);
+      switch (curtype)
+       {
+         /*
+          * Type = 0x0001: Member Class.   
+          * 
+          * Specified as any of the following bitwise 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 
+          *
+          * In some odd cases, we can end up with more
+          * than one of these.  We only want the first,
+          * as the others may not be something we want.
+          *
+          */
+       case 0x0001:
+         if (tlv1) /* use only the first */
+           break;
+         outinfo->class = aimutil_get16(&buf[i+4]);
+         tlv1++;
+         break;
+         
+         /*
+          * Type = 0x0002: Member-Since date. 
+          *
+          * The time/date that the user originally
+          * registered for the service, stored in 
+          * time_t format
+          */
+       case 0x0002: 
+         outinfo->membersince = aimutil_get32(&buf[i+4]);
+         break;
+         
+         /*
+          * Type = 0x0003: On-Since date.
+          *
+          * The time/date that the user started 
+          * their current session, stored in time_t
+          * format.
+          */
+       case 0x0003:
+         outinfo->onlinesince = aimutil_get32(&buf[i+4]);
+         break;
+
+         /*
+          * Type = 0x0004: Idle time.
+          *
+          * Number of seconds since the user
+          * actively used the service.
+          */
+       case 0x0004:
+         outinfo->idletime = aimutil_get16(&buf[i+4]);
+         break;
+         
+         /*
+          * 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).
+          *
+          */
+       case 0x000f:
+       case 0x0010:
+         outinfo->sessionlen = aimutil_get32(&buf[i+4]);
+         break;
+
+         /*
+          * 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.
+          *
+          */
+       default:
+         {
+           int len,z = 0, y = 0, x = 0;
+           char tmpstr[80];
+           printf("faim: userinfo: **warning: unexpected TLV:\n");
+           printf("faim: userinfo:   sn    =%s\n", outinfo->sn);
+           printf("faim: userinfo:   curtlv=0x%04x\n", curtlv);
+           printf("faim: userinfo:   type  =0x%04x\n",aimutil_get16(&buf[i]));
+           printf("faim: userinfo:   length=0x%04x\n", len = aimutil_get16(&buf[i+2]));
+           printf("faim: userinfo:   data: \n");
+           while (z<len)
+             {
+               x = sprintf(tmpstr, "faim: userinfo:      ");
+               for (y = 0; y < 8; y++)
+                 {
+                   if (z<len)
+                     {
+                       sprintf(tmpstr+x, "%02x ", buf[i+4+z]);
+                       z++;
+                       x += 3;
+                     }
+                   else
+                     break;
+                 }
+               printf("%s\n", tmpstr);
+             }
+         }
+         break;
+       }  
+      /*
+       * No matter what, TLV triplets should always look like this:
+       *
+       *   u_short type;
+       *   u_short length;
+       *   u_char  data[length];
+       *
+       */
+      i += (2 + 2 + aimutil_get16(&buf[i+2]));
+      
+      curtlv++;
+    }
+  
+  return i;
+}
+
+/*
+ * Oncoming Buddy notifications contain a subset of the
+ * user information structure.  Its close enough to run
+ * through aim_extractuserinfo() however.
+ *
+ */
+int aim_parse_oncoming_middle(struct command_rx_struct *command)
+{
+  struct aim_userinfo_s userinfo;
+  u_int i = 0;
+  rxcallback_t userfunc=NULL;
+
+  i = 10;
+  i += aim_extractuserinfo(command->data+i, &userinfo);
+
+  userfunc = aim_callhandler(command->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING);
+  if (userfunc)
+    i = userfunc(command, &userinfo);
+
+  return 1;
+}
+
+
+/*
+ * This parses the user info stuff out all nice and pretty then calls 
+ * the higher-level callback (in the user app).
+ *
+ */
+int aim_parse_userinfo_middle(struct command_rx_struct *command)
+{
+  struct aim_userinfo_s userinfo;
+  char *prof_encoding = NULL;
+  char *prof = NULL;
+  u_int i = 0;
+  rxcallback_t userfunc=NULL;
+
+  {
+    u_long snacid = 0x000000000;
+    struct aim_snac_t *snac = NULL;
+
+    snacid = aimutil_get32(&command->data[6]);
+    snac = aim_remsnac(snacid);
+
+    free(snac->data);
+    free(snac);
+
+  }
+  
+  i = 10;
+  i += aim_extractuserinfo(command->data+i, &userinfo);
+
+  if (i < command->commandlen)
+    {
+      if (aimutil_get16(&command->data[i]) == 0x0001)
+        {
+          int len = 0;
+
+         len = aimutil_get16(&command->data[i+2]);
+
+          prof_encoding = (char *) malloc(len+1);
+          memcpy(prof_encoding, &(command->data[i+4]), len);
+          prof_encoding[len] = '\0';
+
+          i += (2+2+len);
+        }
+      else
+        {
+          printf("faim: userinfo: **warning: unexpected TLV after TLVblock t(%02x%02x) l(%02x%02x)\n", command->data[i], command->data[i+1], command->data[i+2], command->data[i+3]);
+          i += 2 + 2 + command->data[i+3];
+        }
+    }
+
+  if (i < command->commandlen)
+    {
+      if (aimutil_get16(&command->data[i]) == 0x0002)
+       {
+         int len = 0;
+         len = aimutil_get16(&command->data[i+2]);
+         
+         prof = (char *) malloc(len+1);
+         memcpy(prof, &(command->data[i+4]), len);
+         prof[len] = '\0';
+       }
+      else
+       printf("faim:userinfo: **warning: profile not found, but still have data\n");
+    }
+
+  userfunc = aim_callhandler(command->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO);
+  if (userfunc)
+    {
+      i = userfunc(command, 
+                  &userinfo, 
+                  prof_encoding, 
+                  prof); 
+    }
+
+  free(prof_encoding);
+  free(prof);
+
+  return 1;
+}
diff --git a/aim_login.c b/aim_login.c
new file mode 100644 (file)
index 0000000..313bffe
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ *  aim_login.c
+ *
+ *  This contains all the functions needed to actually login.
+ *
+ */
+
+#include "aim.h"
+
+
+/*
+ * FIXME: Reimplement the TIS stuff.
+ */
+#ifdef TIS_TELNET_PROXY
+#include "tis_telnet_proxy.h"
+#endif
+
+/*
+ *  send_login(int socket, char *sn, char *password)
+ *  
+ * This is the initial login request packet.
+ *
+ * The password is encoded before transmition, as per
+ * encode_password().  See that function for their
+ * stupid method of doing it.
+ *
+ *
+ *
+ */
+int aim_send_login (struct aim_conn_t *conn, char *sn, char *password, struct client_info_s *clientinfo)
+#if 0
+{
+  char *password_encoded = NULL;  /* to store encoded password */
+  int curbyte=0;
+
+  struct command_tx_struct newpacket;
+
+  if (conn)
+    newpacket.conn = conn;
+  else
+    newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_AUTH);
+
+  newpacket.commandlen = 6+2+strlen(sn)+1+1+2+strlen(password)+6;
+
+  if (clientinfo)
+    {
+      if (strlen(clientinfo->clientstring))
+       newpacket.commandlen += strlen(clientinfo->clientstring)+4;
+      newpacket.commandlen += 6+6+6; 
+      if (strlen(clientinfo->country))
+       newpacket.commandlen += strlen(clientinfo->country)+4;
+      if (strlen(clientinfo->lang))
+       newpacket.commandlen += strlen(clientinfo->lang)+4;
+    }
+
+  newpacket.data = (char *) calloc (1,  newpacket.commandlen );
+  newpacket.lock = 1;
+  newpacket.type = 0x01;
+
+  curbyte += aimutil_put16(newpacket.data+curbyte, 0x0000);
+  curbyte += aimutil_put16(newpacket.data+curbyte, 0x0001);
+  curbyte += aimutil_put16(newpacket.data+curbyte, 0x0001);
+  curbyte += aimutil_put16(newpacket.data+curbyte, strlen(sn));
+  curbyte += aimutil_putstr(newpacket.data+curbyte, sn, strlen(sn));
+
+  curbyte += aimutil_put16(newpacket.data+curbyte, 0x0002);
+  curbyte += aimutil_put16(newpacket.data+curbyte, strlen(password));
+  password_encoded = (char *) malloc(strlen(password));
+  aim_encode_password(password, password_encoded);
+  curbyte += aimutil_putstr(newpacket.data+curbyte, password_encoded, strlen(password));
+  free(password_encoded);
+  
+  curbyte += aim_puttlv_16(newpacket.data+curbyte, 0x0016, 0x0001);
+
+  if (clientinfo)
+    {
+      if (strlen(clientinfo->clientstring))
+       {
+         curbyte += aimutil_put16(newpacket.data+curbyte, 0x0003);
+         curbyte += aimutil_put16(newpacket.data+curbyte, strlen(clientinfo->clientstring));
+         curbyte += aimutil_putstr(newpacket.data+curbyte, clientinfo->clientstring, strlen(clientinfo->clientstring));
+       }
+      curbyte += aim_puttlv_16(newpacket.data+curbyte, 0x0017, 0x0001);
+      curbyte += aim_puttlv_16(newpacket.data+curbyte, 0x0018, 0x0001);
+      curbyte += aim_puttlv_16(newpacket.data+curbyte, 0x001a, 0x0013);
+      if (strlen(clientinfo->country))
+       {
+         curbyte += aimutil_put16(newpacket.data+curbyte, 0x000e);
+         curbyte += aimutil_put16(newpacket.data+curbyte, strlen(clientinfo->country));
+         curbyte += aimutil_putstr(newpacket.data+curbyte, clientinfo->country, strlen(clientinfo->country));
+       }
+       if (strlen(clientinfo->lang))
+       {
+         curbyte += aimutil_put16(newpacket.data+curbyte, 0x000f);
+         curbyte += aimutil_put16(newpacket.data+curbyte, strlen(clientinfo->lang));
+         curbyte += aimutil_putstr(newpacket.data+curbyte, clientinfo->lang, strlen(clientinfo->lang));
+       }
+    }
+
+  curbyte += aim_puttlv_16(newpacket.data+curbyte, 0x0009, 0x0015);
+
+  newpacket.lock = 0;
+  aim_tx_enqueue(&newpacket);
+
+  return 0;
+}
+#else
+{
+
+  /* this is for the client info field of this packet.  for now, just
+     put a few zeros in there and hope they don't notice. */
+  char info_field[] = {
+    0x00, 0x00, 0x00, 0x00
+  };
+  int info_field_len = 4;
+
+  char *password_encoded = NULL;  /* to store encoded password */
+  int n = 0; /* counter during packet construction */
+
+  struct command_tx_struct newpacket;
+
+  if (conn)
+    newpacket.conn = conn;
+  else
+    newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_AUTH);
+
+  /* breakdown of new_packet_login_len */
+  newpacket.commandlen = 6; /* SNAC: fixed bytes */
+  newpacket.commandlen += 2; /* SN len */
+  newpacket.commandlen += strlen(sn); /* SN text */
+  newpacket.commandlen += 1; /* SN null terminator */
+  newpacket.commandlen += 1; /* fixed byte */
+  newpacket.commandlen += 2; /* password len */
+  newpacket.commandlen += strlen(password); /* password text */
+  newpacket.commandlen += 1; /* password null term*/
+  newpacket.commandlen += 1; /* fixed byte */
+  newpacket.commandlen += 2; /* info field len */
+  newpacket.commandlen += info_field_len; /* info field text */
+  newpacket.commandlen += 1; /* info field null term */
+  newpacket.commandlen += 41; /* fixed bytes */
+
+  /* allocate buffer to use for constructing packet_login */
+  newpacket.data = (char *) malloc ( newpacket.commandlen );
+  memset(newpacket.data, 0x00, newpacket.commandlen);
+
+  newpacket.lock = 1;
+  newpacket.type = 0x01;
+
+  newpacket.data[0] = 0x00;
+  newpacket.data[1] = 0x00;
+  newpacket.data[2] = 0x00;
+  newpacket.data[3] = 0x01;
+  newpacket.data[4] = 0x00;
+  newpacket.data[5] = 0x01;
+
+  newpacket.data[6] = (char) ( (strlen(sn)) >> 8);
+  newpacket.data[7] = (char) ( (strlen(sn)) & 0xFF);
+
+  n = 8;
+  memcpy(&(newpacket.data[n]), sn, strlen(sn));
+  n += strlen(sn);
+  newpacket.data[n] = 0x00;
+  n++;
+
+  newpacket.data[n] = 0x02;
+  n++;
+
+  /* store password length as word */
+  newpacket.data[n] = (char) ( (strlen(password)) >> 8);
+  newpacket.data[n+1] = (char) ( (strlen(password)) & 0xFF);
+  n += 2;
+
+  /* allocate buffer for encoded password */
+  password_encoded = (char *) malloc(strlen(password));
+  /* encode password */
+  aim_encode_password(password, password_encoded);
+  /* store encoded password */
+  memcpy(&(newpacket.data[n]), password_encoded, strlen(password));
+
+  n += strlen(password);
+  /* free buffer */
+  free(password_encoded);
+  /* place null terminator after encoded password */
+  newpacket.data[n] = 0x00;
+  n++;
+
+  newpacket.data[n] = 0x03;
+  n++;
+
+  newpacket.data[n] = (char) ( (info_field_len) >> 8);
+  newpacket.data[n+1] = (char) ( (info_field_len) & 0xFF);
+  n += 2;
+  memcpy(&(newpacket.data[n]), info_field, info_field_len);
+  n += info_field_len;
+  newpacket.data[n] = 0x00;
+  n++;
+
+  newpacket.data[n] = 0x16;
+  newpacket.data[n+1] = 0x00;
+  newpacket.data[n+2] = 0x02;
+  newpacket.data[n+3] = 0x00;
+  n += 4;
+  newpacket.data[n] = 0x01;
+  newpacket.data[n+1] = 0x00;
+  newpacket.data[n+2] = 0x17;
+  newpacket.data[n+3] = 0x00;
+  n += 4;
+
+  newpacket.data[n] = 0x02;
+  newpacket.data[n+1] = 0x00;
+  newpacket.data[n+2] = 0x01;
+  newpacket.data[n+3] = 0x00;
+  n += 4;
+
+  newpacket.data[n] = 0x18;
+  newpacket.data[n+1] = 0x00;
+  newpacket.data[n+2] = 0x02;
+  newpacket.data[n+3] = 0x00;
+  n += 4;
+
+  newpacket.data[n] = 0x01;
+  newpacket.data[n+1] = 0x00;
+  newpacket.data[n+2] = 0x1a;
+  newpacket.data[n+3] = 0x00;
+  n += 4;
+
+  newpacket.data[n] = 0x02;
+  newpacket.data[n+1] = 0x00;
+  newpacket.data[n+2] = 0x13;
+  newpacket.data[n+3] = 0x00;
+  n += 4;
+
+  newpacket.data[n] = 0x0e;
+  newpacket.data[n+1] = 0x00;
+  newpacket.data[n+2] = 0x02;
+  newpacket.data[n+3] = 0x75;
+  n += 4;
+
+  newpacket.data[n] = 0x73;
+  newpacket.data[n+1] = 0x00;
+  newpacket.data[n+2] = 0x0f;
+  newpacket.data[n+3] = 0x00;
+  n += 4;
+
+  newpacket.data[n] = 0x02;
+  newpacket.data[n+1] = 0x65;
+  newpacket.data[n+2] = 0x6e;
+  newpacket.data[n+3] = 0x00;
+  n += 4;
+  newpacket.data[n] = 0x09;
+  newpacket.data[n+1] = 0x00;
+  newpacket.data[n+2] = 0x02;
+  newpacket.data[n+3] = 0x00;
+  n += 4;
+
+  newpacket.data[n] = 0x15;
+  n += 1;
+
+  aim_tx_enqueue(&newpacket);
+
+  return 0;
+}
+#endif
+
+/*
+ *  int encode_password(
+ *                      const char *password,
+ *                     char *encoded
+ *                     ); 
+ *
+ * This takes a const pointer to a (null terminated) string
+ * containing the unencoded password.  It also gets passed
+ * an already allocated buffer to store the encoded password.
+ * This buffer should be the exact length of the password without
+ * the null.  The encoded password buffer IS NOT NULL TERMINATED.
+ *
+ * The encoding_table seems to be a fixed set of values.  We'll
+ * hope it doesn't change over time!  
+ *
+ */
+int aim_encode_password(const char *password, char *encoded)
+{
+  u_char encoding_table[] = {
+    0xf3, 0xb3, 0x6c, 0x99,
+    0x95, 0x3f, 0xac, 0xb6,
+    0xc5, 0xfa, 0x6b, 0x63,
+    0x69, 0x6c, 0xc3, 0x9f
+  };
+
+  int i;
+  
+  for (i = 0; i < strlen(password); i++)
+      encoded[i] = (password[i] ^ encoding_table[i]);
+
+  return 0;
+}
+
+
+
+
diff --git a/aim_logoff.c b/aim_logoff.c
new file mode 100644 (file)
index 0000000..ebea9dc
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * aim_logoff.c
+ *
+ *
+ */
+
+#include "aim.h"
+
+/* 
+ * aim_logoff()
+ * 
+ * Closes -ALL- open connections.
+ *
+ */
+int aim_logoff(void)
+{
+  int i = AIM_CONN_MAX-1;
+  while (i > -1)
+    {
+      if (aim_conns[i].fd>-1)
+       aim_conn_close(&(aim_conns[i]));
+      i--;
+    }
+  aim_connrst();  /* in case we want to connect again */
+
+  return 0;
+
+}
diff --git a/aim_misc.c b/aim_misc.c
new file mode 100644 (file)
index 0000000..12f5c29
--- /dev/null
@@ -0,0 +1,580 @@
+
+/*
+ * aim_misc.c
+ *
+ * TODO: Seperate a lot of this into an aim_bos.c.
+ *
+ * Other things...
+ *
+ *   - Idle setting 
+ * 
+ *
+ */
+
+#include "aim.h"
+
+/*
+ * aim_bos_setidle()
+ *
+ *  Should set your current idle time in seconds.  Idealy, OSCAR should
+ *  do this for us.  But, it doesn't.  The client must call this to set idle
+ *  time.  
+ *
+ */
+u_long aim_bos_setidle(struct aim_conn_t *conn, u_long idletime)
+{
+  return aim_genericreq_l(conn, 0x0001, 0x0011, &idletime);
+}
+
+
+/*
+ * aim_bos_changevisibility(conn, changtype, namelist)
+ *
+ * Changes your visibility depending on changetype:
+ *
+ *  AIM_VISIBILITYCHANGE_PERMITADD: Lets provided list of names see you
+ *  AIM_VISIBILITYCHANGE_PERMIDREMOVE: Removes listed names from permit list
+ *  AIM_VISIBILITYCHANGE_DENYADD: Hides you from provided list of names
+ *  AIM_VISIBILITYCHANGE_DENYREMOVE: Lets list see you again
+ *
+ * list should be a list of 
+ * screen names in the form "Screen Name One&ScreenNameTwo&" etc.
+ *
+ * Equivelents to options in WinAIM:
+ *   - Allow all users to contact me: Send an AIM_VISIBILITYCHANGE_DENYADD
+ *      with only your name on it.
+ *   - Allow only users on my Buddy List: Send an 
+ *      AIM_VISIBILITYCHANGE_PERMITADD with the list the same as your
+ *      buddy list
+ *   - Allow only the uesrs below: Send an AIM_VISIBILITYCHANGE_PERMITADD 
+ *      with everyone listed that you want to see you.
+ *   - Block all users: Send an AIM_VISIBILITYCHANGE_PERMITADD with only 
+ *      yourself in the list
+ *   - Block the users below: Send an AIM_VISIBILITYCHANGE_DENYADD with
+ *      the list of users to be blocked
+ *
+ *
+ */
+u_long aim_bos_changevisibility(struct aim_conn_t *conn, int changetype, char *denylist)
+{
+  struct command_tx_struct newpacket;
+  u_short subtype;
+
+  char *localcpy = NULL;
+  char *tmpptr = NULL;
+  int i,j;
+  int listcount;
+
+  if (!denylist)
+    return 0;
+
+  newpacket.lock = 1;
+
+  if (conn)
+    newpacket.conn = conn;
+  else
+    newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS);
+
+  newpacket.type = 0x02;
+
+  localcpy = (char *) malloc(strlen(denylist)+1);
+  memcpy(localcpy, denylist, strlen(denylist)+1);
+  
+  listcount = aimutil_itemcnt(localcpy, '&');
+  newpacket.commandlen = aimutil_tokslen(localcpy, 99, '&') + listcount + 9;
+
+
+  newpacket.data = (char *) malloc(newpacket.commandlen);
+  memset(newpacket.data, 0x00, newpacket.commandlen);
+
+  switch(changetype)
+    {
+    case AIM_VISIBILITYCHANGE_PERMITADD:    subtype = 0x05; break;
+    case AIM_VISIBILITYCHANGE_PERMITREMOVE: subtype = 0x06; break;
+    case AIM_VISIBILITYCHANGE_DENYADD:      subtype = 0x07; break;
+    case AIM_VISIBILITYCHANGE_DENYREMOVE:   subtype = 0x08; break;
+    default:
+      free(newpacket.data);
+      return 0;
+    }
+
+  /* We actually DO NOT send a SNAC ID with this one! */
+  aim_putsnac(newpacket.data, 0x0009, subtype, 0x00, 0);
+  j = 10;  /* the next byte */
+  
+  for (i=0; (i < (listcount - 1)) && (i < 99); i++)
+    {
+      tmpptr = aimutil_itemidx(localcpy, i, '&');
+
+      newpacket.data[j] = strlen(tmpptr);
+      memcpy(&(newpacket.data[j+1]), tmpptr, strlen(tmpptr));
+      j += strlen(tmpptr)+1;
+      free(tmpptr);
+    }
+  free(localcpy);
+
+  newpacket.lock = 0;
+
+  aim_tx_enqueue(&newpacket);
+
+  return (aim_snac_nextid); /* dont increment */
+
+}
+
+
+
+/*
+ * aim_bos_setbuddylist(buddylist)
+ *
+ * This just builds the "set buddy list" command then queues it.
+ *
+ * buddy_list = "Screen Name One&ScreenNameTwo&";
+ *
+ * TODO: Clean this up.
+ *
+ */
+u_long aim_bos_setbuddylist(struct aim_conn_t *conn, char *buddy_list)
+{
+  int i, j;
+
+  struct command_tx_struct newpacket;
+
+  int packet_login_phase3c_hi_b_len = 0;
+
+  char *localcpy = NULL;
+  char *tmpptr = NULL;
+
+  packet_login_phase3c_hi_b_len = 16; /* 16b for FLAP and SNAC headers */
+
+  /* bail out if we can't make the packet */
+  if (buddy_list == NULL)
+    {
+      printf("\nNO BUDDIES!  ARE YOU THAT LONELY???\n");
+      return 0;
+    }
+#if debug > 0
+  printf("****buddy list: %s\n", buddy_list);
+  printf("****buddy list len: %d (%x)\n", strlen(buddy_list), strlen(buddy_list));
+#endif
+
+  localcpy = (char *) malloc(strlen(buddy_list)+1);
+  memcpy(localcpy, buddy_list, strlen(buddy_list)+1);
+
+  i = 0;
+  tmpptr = strtok(localcpy, "&");
+  while ((tmpptr != NULL) && (i < 100))
+    {
+#if debug > 0
+      printf("---adding %s (%d)\n", tmpptr, strlen(tmpptr));
+#endif
+      packet_login_phase3c_hi_b_len += strlen(tmpptr)+1;
+      i++;
+      tmpptr = strtok(NULL, "&");
+    }
+#if debug > 0
+  printf("*** send buddy list len: %d (%x)\n", packet_login_phase3c_hi_b_len, packet_login_phase3c_hi_b_len);
+#endif
+  free(localcpy);
+
+  newpacket.type = 0x02;
+  if (conn)
+    newpacket.conn = conn;
+  else
+    newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS);
+  newpacket.commandlen = packet_login_phase3c_hi_b_len - 6;
+  newpacket.lock = 1;
+  
+  newpacket.data = (char *) malloc(newpacket.commandlen);
+
+  aim_putsnac(newpacket.data, 0x0003, 0x0004, 0x0000, aim_snac_nextid);
+
+  j = 10;  /* the next byte */
+
+  i = 0;
+  tmpptr = strtok(buddy_list, "&");
+  while ((tmpptr != NULL) & (i < 100))
+    {
+#if debug > 0
+      printf("---adding %s (%d)\n", tmpptr, strlen(tmpptr));
+#endif
+      newpacket.data[j] = strlen(tmpptr);
+      memcpy(&(newpacket.data[j+1]), tmpptr, strlen(tmpptr));
+      j += strlen(tmpptr)+1;
+      i++;
+      tmpptr = strtok(NULL, "&");
+    }
+
+  newpacket.lock = 0;
+
+  aim_tx_enqueue(&newpacket);
+
+  return (aim_snac_nextid++);
+}
+
+/* 
+ * aim_bos_setprofile(profile)
+ *
+ * Gives BOS your profile.
+ *
+ */
+u_long aim_bos_setprofile(struct aim_conn_t *conn, char *profile)
+{
+  int packet_profile_len = 0;
+  struct command_tx_struct newpacket;
+  int i = 0;
+
+  /* len: SNAC */
+  packet_profile_len = 10;
+  /* len: T+L (where t(0001)) */
+  packet_profile_len += 2 + 2;
+  /* len: V (where t(0001)) */
+  packet_profile_len += strlen("text/x-aolrtf");
+  /* len: T+L (where t(0002)) */
+  packet_profile_len += 2 + 2;
+  /* len: V (where t(0002)) */
+  packet_profile_len += strlen(profile);
+
+  newpacket.type = 0x02;
+  if (conn)
+    newpacket.conn = conn;
+  else
+    newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS);
+  newpacket.commandlen = packet_profile_len;
+  newpacket.data = (char *) malloc(packet_profile_len);
+
+  i = 0;
+
+  i += aim_putsnac(newpacket.data, 0x0002, 0x004, 0x0000, aim_snac_nextid);
+
+  /* TLV t(0001) */
+  newpacket.data[i++] = 0x00;
+  newpacket.data[i++] = 0x01;
+  /* TLV l(000d) */
+  newpacket.data[i++] = 0x00;
+  newpacket.data[i++] = 0x0d;
+  /* TLV v(text/x-aolrtf) */
+  memcpy(&(newpacket.data[i]), "text/x-aolrtf", 0x000d);
+  i += 0x000d;
+  
+  /* TLV t(0002) */
+  newpacket.data[i++] = 0x00;
+  newpacket.data[i++] = 0x02;
+  /* TLV l() */
+  newpacket.data[i++] = (strlen(profile) >> 8) & 0xFF;
+  newpacket.data[i++] = (strlen(profile) & 0xFF);
+  /* TLV v(profile) */
+  memcpy(&(newpacket.data[i]), profile, strlen(profile));
+
+  aim_tx_enqueue(&newpacket);
+  
+  return (aim_snac_nextid++);
+}
+
+/* 
+ * aim_bos_setgroupperm(mask)
+ * 
+ * Set group permisson mask.  Normally 0x1f.
+ *
+ */
+u_long aim_bos_setgroupperm(struct aim_conn_t *conn, u_long mask)
+{
+  return aim_genericreq_l(conn, 0x0009, 0x0004, &mask);
+}
+
+/*
+ * aim_bos_clientready()
+ * 
+ * Send Client Ready.  
+ *
+ * TODO: Dynamisize.
+ *
+ */
+u_long aim_bos_clientready(struct aim_conn_t *conn)
+{
+  u_char command_2[] = {
+     /* placeholders for dynamic data */
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 
+     /* real data */
+                 0x00, 0x01, 0x00, 0x02, 0x00, 0x01,
+     0x00, 0x13, 0x00, 0x09, 0x00, 0x01, 0x00, 0x01,
+     0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01,
+     0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x01,
+     0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01,
+     0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x01,
+     0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x01,
+     0x00, 0x01, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x01,
+     0x00, 0x01, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x01,
+     0x00, 0x01
+  };
+  int command_2_len = 0x52;
+  struct command_tx_struct newpacket;
+  
+  newpacket.lock = 1;
+  if (conn)
+    newpacket.conn = conn;
+  else
+    newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS);
+  newpacket.type = 0x02;
+  newpacket.commandlen = command_2_len;
+  newpacket.data = (char *) malloc (newpacket.commandlen);
+  memcpy(newpacket.data, command_2, newpacket.commandlen);
+  
+  /* This write over the dynamic parts of the byte block */
+  aim_putsnac(newpacket.data, 0x0001, 0x0002, 0x0000, aim_snac_nextid);
+
+  aim_tx_enqueue(&newpacket);
+
+  return (aim_snac_nextid++);
+}
+
+/* 
+ *  send_login_phase3(int socket)   
+ *
+ *  Request Rate Information.
+ * 
+ *  TODO: Move to aim_conn.
+ *  TODO: Move to SNAC interface.
+ */
+u_long aim_bos_reqrate(struct aim_conn_t *conn)
+{
+  return aim_genericreq_n(conn, 0x0001, 0x0006);
+}
+
+/* 
+ *  send_login_phase3b(int socket)   
+ *
+ *  Rate Information Response Acknowledge.
+ *
+ */
+u_long aim_bos_ackrateresp(struct aim_conn_t *conn)
+{
+  struct command_tx_struct newpacket;
+
+  newpacket.lock = 1;
+  if (conn)
+    newpacket.conn = conn;
+  else
+    newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS);
+  newpacket.type = 0x02;
+  newpacket.commandlen = 18;
+
+  newpacket.data = (char *) malloc(newpacket.commandlen);
+  aim_putsnac(newpacket.data, 0x0001, 0x0008, 0x0000, aim_snac_nextid);
+
+  newpacket.data[10] = 0x00;
+  newpacket.data[11] = 0x01;
+  newpacket.data[12] = 0x00;
+  newpacket.data[13] = 0x02;
+  newpacket.data[14] = 0x00;
+  newpacket.data[15] = 0x03;
+  newpacket.data[16] = 0x00;
+  newpacket.data[17] = 0x04;
+
+  aim_tx_enqueue(&newpacket);
+
+  return (aim_snac_nextid++);
+}
+
+/* 
+ * aim_bos_setprivacyflags()
+ *
+ * Sets privacy flags. Normally 0x03.
+ *
+ *  Bit 1:  Allows other AIM users to see how long you've been idle.
+ *
+ *
+ */
+u_long aim_bos_setprivacyflags(struct aim_conn_t *conn, u_long flags)
+{
+  return aim_genericreq_l(conn, 0x0001, 0x0014, &flags);
+}
+
+/*
+ * aim_bos_reqpersonalinfo()
+ *
+ * Requests the current user's information. Can't go generic on this one
+ * because aparently it uses SNAC flags.
+ *
+ */
+u_long aim_bos_reqpersonalinfo(struct aim_conn_t *conn)
+{
+  struct command_tx_struct newpacket;
+  
+  newpacket.lock = 1;
+  if (conn)
+    newpacket.conn = conn;
+  else
+    newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS);
+  newpacket.type = 0x02;
+  newpacket.commandlen = 12;
+
+  newpacket.data = (char *) malloc(newpacket.commandlen);
+  aim_putsnac(newpacket.data, 0x000a, 0x0001, 0x000e /* huh? */, aim_snac_nextid);
+  
+  newpacket.data[10] = 0x0d;
+  newpacket.data[11] = 0xda;
+
+  aim_tx_enqueue(&newpacket);
+
+  return (aim_snac_nextid++);
+}
+
+/*
+ * aim_bos_reqservice(serviceid)
+ *
+ * Service request. 
+ *
+ */
+u_long aim_bos_reqservice(struct aim_conn_t *conn, u_short serviceid)
+{
+  return aim_genericreq_s(conn, 0x0001, 0x0004, &serviceid);
+}
+
+/*
+ * aim_bos_reqrights()
+ *
+ * Request BOS rights.
+ *
+ */
+u_long aim_bos_reqrights(struct aim_conn_t *conn)
+{
+  return aim_genericreq_n(conn, 0x0009, 0x0002);
+}
+
+/*
+ * aim_bos_reqbuddyrights()
+ *
+ * Request Buddy List rights.
+ *
+ */
+u_long aim_bos_reqbuddyrights(struct aim_conn_t *conn)
+{
+  return aim_genericreq_n(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.
+ *
+ */
+u_long aim_genericreq_n(struct aim_conn_t *conn, u_short family, u_short subtype)
+{
+  struct command_tx_struct newpacket;
+
+  newpacket.lock = 1;
+
+  if (conn)
+    newpacket.conn = conn;
+  else
+    newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS);
+  newpacket.type = 0x02;
+
+  newpacket.commandlen = 10;
+
+  newpacket.data = (char *) malloc(newpacket.commandlen);
+  memset(newpacket.data, 0x00, newpacket.commandlen);
+
+  aim_putsnac(newpacket.data, family, subtype, 0x0000, aim_snac_nextid);
+  aim_tx_enqueue(&newpacket);
+  return (aim_snac_nextid++);
+}
+
+/*
+ *
+ *
+ */
+u_long aim_genericreq_l(struct aim_conn_t *conn, u_short family, u_short subtype, u_long *longdata)
+{
+  struct command_tx_struct newpacket;
+  u_long newlong;
+
+  /* If we don't have data, there's no reason to use this function */
+  if (!longdata)
+    return aim_genericreq_n(conn, family, subtype);
+
+  newpacket.lock = 1;
+
+  if (conn)
+    newpacket.conn = conn;
+  else
+    newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS);
+  newpacket.type = 0x02;
+
+  newpacket.commandlen = 10+sizeof(u_long);
+
+  newpacket.data = (char *) malloc(newpacket.commandlen);
+  memset(newpacket.data, 0x00, newpacket.commandlen);
+
+  aim_putsnac(newpacket.data, family, subtype, 0x0000, aim_snac_nextid);
+
+  /* copy in data */
+  newlong = htonl(*longdata);
+  memcpy(&(newpacket.data[10]), &newlong, sizeof(u_long));
+
+  aim_tx_enqueue(&newpacket);
+  return (aim_snac_nextid++);
+}
+
+u_long aim_genericreq_s(struct aim_conn_t *conn, u_short family, u_short subtype, u_short *shortdata)
+{
+  struct command_tx_struct newpacket;
+  u_short newshort;
+
+  /* If we don't have data, there's no reason to use this function */
+  if (!shortdata)
+    return aim_genericreq_n(conn, family, subtype);
+
+  newpacket.lock = 1;
+
+  if (conn)
+    newpacket.conn = conn;
+  else
+    newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS);
+  newpacket.type = 0x02;
+
+  newpacket.commandlen = 10+sizeof(u_short);
+
+  newpacket.data = (char *) malloc(newpacket.commandlen);
+  memset(newpacket.data, 0x00, newpacket.commandlen);
+
+  aim_putsnac(newpacket.data, family, subtype, 0x0000, aim_snac_nextid);
+
+  /* copy in data */
+  newshort = htons(*shortdata);
+  memcpy(&(newpacket.data[10]), &newshort, sizeof(u_short));
+
+  aim_tx_enqueue(&newpacket);
+  return (aim_snac_nextid++);
+}
+
+/*
+ * aim_bos_reqlocaterights()
+ *
+ * Request Location services rights.
+ *
+ */
+u_long aim_bos_reqlocaterights(struct aim_conn_t *conn)
+{
+  return aim_genericreq_n(conn, 0x0002, 0x0002);
+}
+
+/*
+ * aim_bos_reqicbmparaminfo()
+ *
+ * Request ICBM parameter information.
+ *
+ */
+u_long aim_bos_reqicbmparaminfo(struct aim_conn_t *conn)
+{
+  return aim_genericreq_n(conn, 0x0004, 0x0004);
+}
diff --git a/aim_rxhandlers.c b/aim_rxhandlers.c
new file mode 100644 (file)
index 0000000..196adde
--- /dev/null
@@ -0,0 +1,585 @@
+
+/*
+  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 "aim.h" /* for most everything */
+
+
+int bleck(struct command_rx_struct *workingPtr, ...)
+{
+  u_short family;
+  u_short subtype;
+  family = (workingPtr->data[0] << 8) + workingPtr->data[1];
+  subtype = (workingPtr->data[2] << 8) + workingPtr->data[3];
+#if debug > 0
+  fprintf(stderr, "bleck: null handler for %04x/%04x\n", family, subtype);
+#endif
+  return 1;
+}
+
+int bleck2(struct command_rx_struct *workingPtr, ...)
+{
+  u_short family;
+  u_short subtype;
+  family = (workingPtr->data[0] << 8) + workingPtr->data[1];
+  subtype = (workingPtr->data[2] << 8) + workingPtr->data[3];
+  printf("OLDbleck: called for %04x/%04x -- OBSOLETE\n", family, subtype);
+  return 1;
+}
+
+int aim_conn_addhandler(struct aim_conn_t *conn,
+                       u_short family,
+                       u_short type,
+                       rxcallback_t newhandler,
+                       u_short flags)
+{
+  struct aim_rxcblist_t *new,*cur;
+
+  if (!conn)
+    return -1;
+
+#if debug > 0
+  printf("aim_conn_addhandler: adding for %04x/%04x\n", family, type);
+#endif
+
+  new = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t));
+  new->family = family;
+  new->type = type;
+  new->flags = flags;
+  if (!newhandler)
+    new->handler = &bleck;
+  else
+    new->handler = newhandler;
+  new->next = NULL;
+  
+  cur = conn->handlerlist;
+  if (!cur)
+    conn->handlerlist = new;
+  else 
+    {
+      while (cur->next)
+       cur = cur->next;
+      cur->next = new;
+    }
+
+  return 0;
+}
+
+int aim_clearhandlers(struct aim_conn_t *conn)
+{
+ struct aim_rxcblist_t *cur,*tmp;
+ if (!conn)
+   return -1;
+
+ cur = conn->handlerlist;
+ while(cur)
+   {
+     tmp = cur->next;
+     free(cur);
+     cur = tmp;
+   }
+ return 0;
+}
+
+rxcallback_t aim_callhandler(struct aim_conn_t *conn,
+                   u_short family,
+                   u_short type)
+{
+  struct aim_rxcblist_t *cur;
+
+  if (!conn)
+    return NULL;
+
+#if debug > 0
+  printf("aim_callhandler: calling for %04x/%04x\n", family, type);
+#endif
+  
+  cur = conn->handlerlist;
+  while(cur)
+    {
+      if ( (cur->family == family) && (cur->type == type) )
+       return cur->handler;
+      cur = cur->next;
+    }
+
+  if (type==0xffff)
+    return NULL;
+  return aim_callhandler(conn, family, 0xffff);
+}
+
+int aim_callhandler_noparam(struct aim_conn_t *conn,
+                           u_short family,
+                           u_short type,
+                           struct command_rx_struct *ptr)
+{
+  rxcallback_t userfunc = NULL;
+  userfunc = aim_callhandler(conn, family, type);
+  if (userfunc)
+    return userfunc(ptr);
+  return 0;
+}
+
+/*
+  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
+
+  Note that any unhandlable packets should probably be left in the
+  queue.  This is the best way to prevent data loss.  This means
+  that a single packet may get looked at by this function multiple
+  times.  This is more good than bad!  This behavior may change.
+
+  Aren't queue's fun? 
+
+  TODO: Get rid of all the ugly if's.
+  TODO: Clean up.
+  TODO: More support for mid-level handlers.
+  TODO: Allow for NULL handlers.
+  
+ */
+int aim_rxdispatch(void)
+{
+  int i = 0;
+  struct command_rx_struct *workingPtr = NULL;
+  
+  if (aim_queue_incoming == NULL)
+    /* this shouldn't really happen, unless the main loop's select is broke  */
+    printf("parse_generic: incoming packet queue empty.\n");
+  else
+    {
+      workingPtr = aim_queue_incoming;
+      for (i = 0; workingPtr != NULL; i++)
+       {
+         switch(workingPtr->conn->type)
+           {
+           case AIM_CONN_TYPE_AUTH:
+             if ( (workingPtr->data[0] == 0x00) && 
+                  (workingPtr->data[1] == 0x00) &&
+                  (workingPtr->data[2] == 0x00) &&
+                  (workingPtr->data[3] == 0x01) )
+               {
+#if debug > 0
+                 fprintf(stderr, "got connection ack on auth line\n");
+#endif
+                 workingPtr->handled = 1;
+               }
+             else
+               {
+                 /* any user callbacks will be called from here */
+                 workingPtr->handled = aim_authparse(workingPtr);
+               }
+             break;
+           case AIM_CONN_TYPE_BOS:
+             {
+               u_short family;
+               u_short subtype;
+               family = (workingPtr->data[0] << 8) + workingPtr->data[1];
+               subtype = (workingPtr->data[2] << 8) + workingPtr->data[3];
+               switch (family)
+                 {
+                 case 0x0000: /* not really a family, but it works */
+                   if (subtype == 0x0001)
+                     workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0000, 0x0001, workingPtr);
+                   else
+                     workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
+                   break;
+                 case 0x0001: /* Family: General */
+                   switch (subtype)
+                     {
+                     case 0x0001:
+                       workingPtr->handled = aim_parse_generalerrs(workingPtr);
+                       break;
+                     case 0x0003:
+                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x0003, workingPtr);
+                       break;
+                     case 0x0005:
+                       workingPtr->handled = aim_handleredirect_middle(workingPtr);
+                       break;
+                     case 0x0007:
+                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x0007, workingPtr);
+                       break;
+                     case 0x000a:
+                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x000a, workingPtr);
+                       break;
+                     case 0x000f:
+                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x000f, workingPtr);
+                       break;
+                     case 0x0013:
+                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x0013, workingPtr);
+                       break;
+                     default:
+                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
+                     }
+                   break;
+                 case 0x0002: /* Family: Location */
+                   switch (subtype)
+                     {
+                     case 0x0001:
+                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0002, 0x0001, workingPtr);
+                       break;
+                     case 0x0003:
+                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0002, 0x0003, workingPtr);
+                       break;
+                     case 0x0006:
+                       workingPtr->handled = aim_parse_userinfo_middle(workingPtr);
+                       break;
+                     default:
+                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
+                     }
+                   break;
+                 case 0x0003: /* Family: Buddy List */
+                   switch (subtype)
+                     {
+                     case 0x0001:
+                       workingPtr->handled = aim_parse_generalerrs(workingPtr);
+                       break;
+                     case 0x0003:
+                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0003, 0x0003, workingPtr);
+                       break;
+                     case 0x000b: /* oncoming buddy */
+                       workingPtr->handled = aim_parse_oncoming_middle(workingPtr);
+                       break;
+                     case 0x000c: /* offgoing buddy */
+                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0003, 0x000c, workingPtr);
+                       break;
+                     default:
+                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
+                     }
+                   break;
+                 case 0x0004: /* Family: Messeging */
+                   switch (subtype)
+                     {
+                     case 0x0001:
+                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0004, 0x0001, workingPtr);
+                       break;
+                     case 0x0005:
+                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0004, 0x0005, workingPtr);
+                       break;
+                     case 0x0007:
+                       workingPtr->handled = aim_parse_incoming_im_middle(workingPtr);
+                       break;
+                     case 0x000a:
+                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0004, 0x000a, workingPtr);
+                       break;
+                     default:
+                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
+                     }
+                   break;
+                 case 0x0009:
+                   if (subtype == 0x0001)
+                     workingPtr->handled = aim_parse_generalerrs(workingPtr);
+                   else if (subtype == 0x0003)
+                     workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0009, 0x0003, workingPtr);
+                   else
+                     workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
+                   break;
+                 case 0x000a:  /* Family: User lookup */
+                   switch (subtype)
+                     {
+                     case 0x0001:
+                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x000a, 0x0001, workingPtr);
+                       break;
+                     case 0x0003:
+                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x000a, 0x0003, workingPtr);
+                       break;
+                     default:
+                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
+                     }
+                   break;
+                 case 0x000b:
+                   if (subtype == 0x0001)
+                     workingPtr->handled = aim_parse_generalerrs(workingPtr);
+                   else if (subtype == 0x0002)
+                     workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x000b, 0x0002, workingPtr);
+                   else
+                     workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
+                   break;
+                 default:
+                   workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
+                   break;
+                 }
+             }
+             break;
+           case AIM_CONN_TYPE_CHATNAV:
+             {
+               u_short family;
+               u_short subtype;
+               family = (workingPtr->data[0] << 8) + workingPtr->data[1];
+               subtype = (workingPtr->data[2] << 8) + workingPtr->data[3];
+               if ( (workingPtr->data[0] == 0x00) &&
+                    (workingPtr->data[1] == 0x02) &&
+                    (workingPtr->data[2] == 0x00) &&
+                    (workingPtr->data[3] == 0x06) )
+                 {
+                   workingPtr->handled = 1;
+                   aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
+                 }
+               else
+                 {
+                   workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, family, subtype, workingPtr);
+                 }
+             }
+             break;
+           case AIM_CONN_TYPE_CHAT:
+             fprintf(stderr, "\nAHH! Dont know what to do with CHAT stuff yet!\n");
+             workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
+             break;
+           default:
+             fprintf(stderr, "\nAHHHHH! UNKNOWN CONNECTION TYPE! (0x%02x)\n\n", workingPtr->conn->type);
+             workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
+             break;
+           }
+             /* move to next command */
+         workingPtr = workingPtr->next;
+       }
+    }
+
+  aim_queue_incoming = aim_purge_rxqueue(aim_queue_incoming);
+  
+  return 0;
+}
+
+/*
+ * TODO: check and cure memory leakage in this function.
+ */
+int aim_authparse(struct command_rx_struct *command)
+{
+  rxcallback_t userfunc = NULL;
+  int iserror = 0;
+  struct aim_tlv_t *tlv = NULL;
+  char *errorurl = NULL;
+  short errorcode = 0x00;
+  u_int z = 0;
+
+  if ( (command->data[0] == 0x00) &&
+       (command->data[1] == 0x01) &&
+       (command->data[2] == 0x00) &&
+       (command->data[3] == 0x03) )
+    {
+      /* "server ready"  -- can be ignored */
+      userfunc = aim_callhandler(command->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY);
+    }
+  else if ( (command->data[0] == 0x00) &&
+           (command->data[1] == 0x07) &&
+           (command->data[2] == 0x00) &&
+           (command->data[3] == 0x05) )
+    {
+      /* "information change reply" */
+      userfunc = aim_callhandler(command->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY);
+    }
+  else
+    {
+      /* anything else -- usually used for login; just parse as pure TLVs */
+
+      /*
+       * Free up the loginstruct first.
+       */
+      if (aim_logininfo.screen_name)
+       {
+         free(aim_logininfo.screen_name);
+         aim_logininfo.screen_name = NULL;
+       }
+      if (aim_logininfo.BOSIP)
+       {
+         free(aim_logininfo.BOSIP);
+         aim_logininfo.BOSIP = NULL;
+       }
+      if (aim_logininfo.cookie)
+       {
+         free(aim_logininfo.cookie);
+         aim_logininfo.cookie = NULL;
+       }
+      if (aim_logininfo.email)
+       {
+         free(aim_logininfo.email);
+         aim_logininfo.email = NULL;
+       }
+      aim_logininfo.regstatus = 0;
+
+      /* all this block does is figure out if it's an
+        error or a success, nothing more */
+      while (z < command->commandlen)
+       {
+         tlv = aim_grabtlvstr(&(command->data[z]));
+         switch(tlv->type) 
+           {
+           case 0x0001: /* screen name */
+             aim_logininfo.screen_name = tlv->value;
+             z += 2 + 2 + tlv->length;
+             free(tlv);
+             tlv = NULL;
+             break;
+           case 0x0004: /* error URL */
+             errorurl = tlv->value;
+             z += 2 + 2 + tlv->length;
+             free(tlv);
+             tlv = NULL;
+             break;
+           case 0x0005: /* BOS IP */
+             aim_logininfo.BOSIP = tlv->value;
+             z += 2 + 2 + tlv->length;
+             free(tlv);
+             tlv = NULL;
+             break;
+           case 0x0006: /* auth cookie */
+             aim_logininfo.cookie = tlv->value;
+             z += 2 + 2 + tlv->length;
+             free(tlv);
+             tlv=NULL;
+             break;
+           case 0x0011: /* email addy */
+             aim_logininfo.email = tlv->value;
+             z += 2 + 2 + tlv->length;
+             free(tlv);
+             tlv = NULL;
+             break;
+           case 0x0013: /* registration status */
+             aim_logininfo.regstatus = *(tlv->value);
+             z += 2 + 2 + tlv->length;
+             aim_freetlv(&tlv);
+             break;
+           case 0x0008: /* error code */
+             errorcode = *(tlv->value);
+             z += 2 + 2 + tlv->length;
+             aim_freetlv(&tlv);
+             iserror = 1;
+             break;
+           default:
+         z += 2 + 2 + tlv->length;
+         aim_freetlv(&tlv);
+         /* dunno */
+           }
+       }
+
+      if (iserror && 
+         errorurl)
+       {
+         userfunc = aim_callhandler(command->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_ERROR);
+         if (userfunc)
+           return userfunc(command, &aim_logininfo, errorurl, errorcode);
+         return 0;
+       }
+      else if (aim_logininfo.screen_name && 
+              aim_logininfo.cookie && aim_logininfo.BOSIP)
+       {
+         userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHSUCCESS);
+         if (userfunc)
+           return userfunc(command, &aim_logininfo);
+         return 0;
+       }
+      else
+       userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHOTHER);
+    }
+
+  if (userfunc)
+    return userfunc(command);
+  printf("handler not available!\n");
+  return 0;
+}
+
+/*
+ * TODO: check for and cure any memory leaks here.
+ */
+int aim_handleredirect_middle(struct command_rx_struct *command, ...)
+{
+  struct aim_tlv_t *tlv = NULL;
+  u_int z = 10;
+  int serviceid = 0x00;
+  char *cookie = NULL;
+  char *ip = NULL;
+  rxcallback_t userfunc = NULL;
+
+  while (z < command->commandlen)
+    {
+      tlv = aim_grabtlvstr(&(command->data[z]));
+      switch(tlv->type)
+       {
+       case 0x000d:  /* service id */
+         aim_freetlv(&tlv);
+         /* regrab as an int */
+         tlv = aim_grabtlv(&(command->data[z]));
+         serviceid = (tlv->value[0] << 8) + tlv->value[1]; /* hehe */
+         z += 2 + 2 + tlv->length;
+         aim_freetlv(&tlv);
+         break;
+       case 0x0005:  /* service server IP */
+         ip = tlv->value;
+         z += 2 + 2 + tlv->length;
+         free(tlv);
+         tlv = NULL;
+         break;
+       case 0x0006: /* auth cookie */
+         cookie = tlv->value;
+         z += 2 + 2 + tlv->length;
+         free(tlv);
+         tlv = NULL;
+         break;
+       default:
+         /* dunno */
+         z += 2 + 2 + tlv->length;
+         aim_freetlv(&tlv);
+       }
+    }
+  userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
+  if (userfunc)
+    return userfunc(command, serviceid, ip, cookie);
+  return 0;
+}
+
+int aim_parse_unknown(struct command_rx_struct *command, ...)
+{
+  u_int i = 0;
+
+  printf("\nRecieved unknown packet:");
+
+  for (i = 0; i < command->commandlen; i++)
+    {
+      if ((i % 8) == 0)
+       printf("\n\t");
+
+      printf("0x%2x ", command->data[i]);
+    }
+  
+  printf("\n\n");
+
+  return 1;
+}
+
+
+/*
+ * aim_parse_generalerrs()
+ *
+ * Middle handler for 0x0001 snac of each family.
+ *
+ */
+int aim_parse_generalerrs(struct command_rx_struct *command, ...)
+{
+  u_short family;
+  u_short subtype;
+  family = (command->data[0] << 8) + command->data[1];
+  subtype = (command->data[2] << 8) + command->data[3];
+  
+  switch(family)
+    {
+    default:
+      /* Unknown family */
+      return aim_callhandler_noparam(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command);
+    }
+
+  return 1;
+}
+
+
+
diff --git a/aim_rxqueue.c b/aim_rxqueue.c
new file mode 100644 (file)
index 0000000..f89fb2c
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+  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 "aim.h"
+
+/*
+  This is a modified read() to make SURE we get the number
+  of bytes we are told to, otherwise block.
+ */
+int Read(int fd, u_char *buf, int len)
+{
+  int i = 0;
+  int j = 0;
+
+  while ((i < len) && (!(i < 0)))
+    {
+      j = read(fd, &(buf[i]), len-i);
+      if ( (j < 0) && (errno != EAGAIN))
+       return -errno; /* fail */
+      else
+       i += j; /* success, continue */
+    }
+#if 0
+  printf("\nRead Block: (%d/%04x)\n", len, len);
+  printf("\t");
+  for (j = 0; j < len; j++)
+    {
+      if (j % 8 == 0)
+       printf("\n\t");
+      if (buf[j] >= ' ' && buf[j] < 127)
+        printf("%c=%02x ",buf[j], buf[j]);
+      else
+        printf("0x%02x ", buf[j]);
+    }
+  printf("\n\n");
+#endif
+  return i;
+}
+
+/*
+  struct command_struct *
+                         get_generic(
+                                     struct connection_info struct *,
+                                    struct command_struct * 
+                                    )
+  
+  Grab as many command sequences as we can off the socket, and enqueue
+  each command in the incoming event queue in a seperate struct.
+
+*/
+int aim_get_command(void)
+{
+  int i, readgood, j, isav, err;
+  int s;
+  fd_set fds;
+  struct timeval tv;
+  char generic[6]; 
+  struct command_rx_struct *workingStruct = NULL;
+  struct command_rx_struct *workingPtr = NULL;
+  struct aim_conn_t *conn = NULL;
+#if debug > 0
+  printf("Reading generic/unknown response...");
+#endif
+  
+  
+  /* dont wait at all (ie, never call this unless something is there) */
+  tv.tv_sec = 0; 
+  tv.tv_usec = 0;
+  conn = aim_select(&tv);
+
+  if (conn==NULL)
+    return 0;  /* nothing waiting */
+
+  s = conn->fd;
+
+  if (s < 3) 
+    return 0;
+
+  FD_ZERO(&fds);
+  FD_SET(s, &fds);
+  tv.tv_sec = 0;  /* wait, but only for 10us */
+  tv.tv_usec = 10;
+  
+  generic[0] = 0x00;  
+
+  readgood = 0;
+  i = 0;
+  j = 0;
+  /* read first 6 bytes (the FLAP header only) off the socket */
+  while ( (select(s+1, &fds, NULL, NULL, &tv) == 1) && (i < 6))
+    {
+      if ((err = Read(s, &(generic[i]), 1)) < 0)
+       {
+         /* error is probably not recoverable...(must be a pessimistic day) */
+         aim_conn_close(conn);
+         return err;
+       }
+
+      if (readgood == 0)
+       {
+         if (generic[i] == 0x2a)
+         {
+           readgood = 1;
+#if debug > 1
+           printf("%x ", generic[i]);
+           fflush(stdout);
+#endif
+           i++;
+         }
+         else
+           {
+#if debug > 1
+             printf("skipping 0x%d ", generic[i]);
+             fflush(stdout);
+#endif
+             j++;
+           }
+       }
+      else
+       {
+#if debug > 1
+         printf("%x ", generic[i]);
+#endif
+         i++;
+       }
+      FD_ZERO(&fds);
+      FD_SET(s, &fds);
+      tv.tv_sec= 2;
+      tv.tv_usec= 2;
+    }
+
+  if (generic[0] != 0x2a)
+    {
+      /* this really shouldn't happen, since the main loop
+        select() should protect us from entering this function
+        without data waiting  */
+      printf("Bad incoming data!");
+      return -1;
+    }
+
+  isav = i;
+
+  /* allocate a new struct */
+  workingStruct = (struct command_rx_struct *) malloc(sizeof(struct command_rx_struct));
+  workingStruct->lock = 1;  /* lock the struct */
+
+  /* store type -- byte 2 */
+  workingStruct->type = (char) generic[1];
+
+  /* store seqnum -- bytes 3 and 4 */
+  workingStruct->seqnum = ( (( (u_int) generic[2]) & 0xFF) << 8);
+  workingStruct->seqnum += ( (u_int) generic[3]) & 0xFF;
+
+  /* store commandlen -- bytes 5 and 6 */
+  workingStruct->commandlen = ( (( (u_int) generic[4]) & 0xFF ) << 8);
+  workingStruct->commandlen += ( (u_int) generic[5]) & 0xFF;
+
+  /* malloc for data portion */
+  workingStruct->data = (char *) malloc(workingStruct->commandlen);
+
+  /* read the data portion of the packet */
+  i = Read(s, workingStruct->data, workingStruct->commandlen);
+  if (i < 0)
+    {
+      aim_conn_close(conn);
+      return i;
+    }
+
+#if debug > 0
+  printf(" done. (%db+%db read, %db skipped)\n", isav, i, j);
+#endif
+
+  workingStruct->conn = conn;
+
+  workingStruct->next = NULL;  /* this will always be at the bottom */
+  workingStruct->lock = 0; /* unlock */
+
+  /* enqueue this packet */
+  if (aim_queue_incoming == NULL)
+    {
+      aim_queue_incoming = workingStruct;
+    }
+  else
+    {
+      workingPtr = aim_queue_incoming;
+      while (workingPtr->next != NULL)
+       workingPtr = workingPtr->next;
+      workingPtr->next = workingStruct;
+    }
+  
+  
+  workingStruct->conn->lastactivity = time(NULL);
+
+  return 0;  
+}
+
+/*
+  purge_rxqueue()
+
+  This is just what it sounds.  It purges the receive (rx) queue of
+  all handled commands.  This is normally called from inside 
+  aim_rxdispatch() after it's processed all the commands in the queue.
+  
+ */
+struct command_rx_struct *aim_purge_rxqueue(struct command_rx_struct *queue)
+{
+  struct command_rx_struct *workingPtr = NULL;
+  struct command_rx_struct *workingPtr2 = NULL;
+
+  if (queue == (struct command_rx_struct *)NULL) 
+    {
+    /* do nothing */
+    }
+  else if (queue->next == (struct command_rx_struct *)NULL)
+    {
+      if (queue->handled == 1) {
+       workingPtr = queue;
+       queue = NULL;
+       free(workingPtr->data);
+       free(workingPtr);
+      }
+    }
+  else 
+    {
+      while (queue->handled == 1) 
+       {
+         workingPtr = queue;
+         queue = queue->next;
+         free(workingPtr->data);
+         free(workingPtr);
+       }
+
+      workingPtr = queue;
+
+      while (workingPtr->next != (struct command_rx_struct *)NULL)
+       {
+         if (workingPtr->next->handled == 1) 
+           {
+             workingPtr2 = workingPtr->next;
+             workingPtr->next = workingPtr->next->next;
+             free(workingPtr2->data);
+             free(workingPtr2);
+           } 
+         else /* TODO: rework this so the additional if isn't needed */
+           {
+             if (workingPtr->next == (struct command_rx_struct *)NULL) 
+               {
+                 if (workingPtr->handled == 1)
+                   {
+                     workingPtr2 = workingPtr;
+                     workingPtr = NULL;
+                     free(workingPtr2->data);
+                     free(workingPtr2);
+                     return queue;
+                   }
+               } 
+             else 
+               {
+                 workingPtr = workingPtr->next;
+               }
+           }
+       }
+    }
+  return queue;
+}
diff --git a/aim_search.c b/aim_search.c
new file mode 100644 (file)
index 0000000..62e9016
--- /dev/null
@@ -0,0 +1,52 @@
+
+/*
+ * aim_search.c
+ *
+ * TODO: Add aim_usersearch_name()
+ *
+ */
+
+#include <aim.h>
+
+u_long aim_usersearch_address(struct aim_conn_t *conn, char *address)
+{
+  struct command_tx_struct newpacket;
+  
+  if (!address)
+    return -1;
+
+  newpacket.lock = 1;
+
+  if (conn)
+    newpacket.conn = conn;
+  else
+    newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS);
+
+  newpacket.type = 0x0002;
+  
+  newpacket.commandlen = 10 + strlen(address);
+  newpacket.data = (char *) malloc(newpacket.commandlen);
+
+  aim_putsnac(newpacket.data, 0x000a, 0x0002, 0x0000, aim_snac_nextid);
+
+  memcpy(&(newpacket.data[10]), address, strlen(address));
+
+  aim_tx_enqueue(&newpacket);
+
+  {
+    struct aim_snac_t snac;
+    
+    snac.id = aim_snac_nextid;
+    snac.family = 0x000a;
+    snac.type = 0x0002;
+    snac.flags = 0x0000;
+
+    snac.data = malloc(strlen(address)+1);
+    memcpy(snac.data, address, strlen(address)+1);
+
+    aim_newsnac(&snac);
+  }
+
+  return (aim_snac_nextid++);
+}
+
diff --git a/aim_snac.c b/aim_snac.c
new file mode 100644 (file)
index 0000000..f2701ec
--- /dev/null
@@ -0,0 +1,108 @@
+
+/*
+ *
+ * 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.
+ *
+ * First edition badly written by Adam Fritzler (afritz@delphid.ml.org)
+ * Current edition nicely rewritten (it even works) by n (n@ml.org)
+ *
+ */
+
+#include <aim.h>
+#include <assert.h>
+
+struct aim_snac_t      *aim_outstanding_snacs = NULL;
+u_long aim_snac_nextid = 0x00000001;
+
+u_long aim_newsnac(struct aim_snac_t *newsnac) {
+       struct aim_snac_t       *snac = NULL, *cur = aim_outstanding_snacs;
+  
+       assert(newsnac != NULL);
+       snac = calloc(1, sizeof(struct aim_snac_t));
+       assert(snac != NULL);
+       memcpy(snac, newsnac, sizeof(struct aim_snac_t));
+       snac->issuetime = time(&snac->issuetime);
+       snac->next = NULL;
+
+       if (cur == NULL) {
+               aim_outstanding_snacs = snac;
+               return(snac->id);
+       }
+       while (cur->next != NULL)
+               cur = cur->next;
+       cur->next = snac;
+       return(snac->id);
+}
+
+struct aim_snac_t      *aim_remsnac(u_long id) {
+       struct aim_snac_t       *cur = aim_outstanding_snacs;
+
+       if (cur == NULL)
+               return(NULL);
+       if (cur->id == id) {
+               aim_outstanding_snacs = cur->next;
+               return(cur);
+       }
+       while (cur->next != NULL) {
+               if (cur->next->id == id) {
+                       struct aim_snac_t       *tmp = NULL;
+
+                       tmp = cur->next;
+                       cur->next = cur->next->next;
+                       return(tmp);
+               }
+               cur = cur->next;
+       }
+       return(NULL);
+}
+
+/*
+ * 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 (though I don't know
+ * why its called _max_age).
+ *
+ */
+int aim_cleansnacs(int maxage)
+{
+  struct aim_snac_t *cur = aim_outstanding_snacs;
+  struct aim_snac_t *remed = NULL;
+  time_t curtime;
+  
+  curtime = time(&curtime);
+
+  while (cur)
+    {
+      if ( (cur) && (((cur->issuetime) + maxage) < curtime))
+       {
+#if DEBUG > 1
+         printf("aimsnac: WARNING purged obsolete snac %ul\n", cur->id);
+#endif
+         remed = aim_remsnac(cur->id);
+         if (remed)
+           {
+             if (remed->data)
+               free(remed->data);
+             free(remed);
+           }
+       }
+      cur = cur->next;
+    }
+
+  return 0;
+}
+
+int aim_putsnac(u_char *buf, int family, int subtype, int flags, u_long snacid)
+{
+  int curbyte = 0;
+  curbyte += aimutil_put16(buf+curbyte, (u_short)(family&0xffff));
+  curbyte += aimutil_put16(buf+curbyte, (u_short)(subtype&0xffff));
+  curbyte += aimutil_put16(buf+curbyte, (u_short)(flags&0xffff));
+  curbyte += aimutil_put32(buf+curbyte, snacid);
+  return curbyte;
+}
diff --git a/aim_tlv.c b/aim_tlv.c
new file mode 100644 (file)
index 0000000..536e259
--- /dev/null
+++ b/aim_tlv.c
@@ -0,0 +1,86 @@
+#include <aim.h>
+
+struct aim_tlv_t *aim_grabtlv(u_char *src)
+{
+  struct aim_tlv_t *dest = NULL;
+
+  dest = aim_createtlv();
+
+  dest->type = src[0] << 8;
+  dest->type += src[1];
+
+  dest->length = src[2] << 8;
+  dest->length += src[3];
+
+  dest->value = (u_char *) malloc(dest->length*sizeof(u_char));
+  memset(dest->value, 0, dest->length*sizeof(u_char));
+
+  memcpy(dest->value, &(src[4]), dest->length*sizeof(u_char));
+  
+  return dest;
+}
+
+struct aim_tlv_t *aim_grabtlvstr(u_char *src)
+{
+  struct aim_tlv_t *dest = NULL;
+
+  dest = aim_createtlv();
+
+  dest->type = src[0] << 8;
+  dest->type += src[1];
+
+  dest->length = src[2] << 8;
+  dest->length += src[3];
+
+  dest->value = (u_char *) malloc((dest->length+1)*sizeof(u_char));
+  memset(dest->value, 0, (dest->length+1)*sizeof(u_char));
+
+  memcpy(dest->value, &(src[4]), dest->length*sizeof(u_char));
+  dest->value[dest->length] = '\0';
+
+  return dest;
+}
+
+int aim_puttlv (u_char *dest, struct aim_tlv_t *newtlv)
+{
+  int i=0;
+
+  dest[i++] = newtlv->type >> 8;
+  dest[i++] = newtlv->type & 0x00FF;
+  dest[i++] = newtlv->length >> 8;
+  dest[i++] = newtlv->length & 0x00FF;
+  memcpy(&(dest[i]), newtlv->value, newtlv->length);
+  i+=newtlv->length;
+  return i;
+}
+
+struct aim_tlv_t *aim_createtlv(void)
+{
+  struct aim_tlv_t *newtlv = NULL;
+  newtlv = (struct aim_tlv_t *)malloc(sizeof(struct aim_tlv_t));
+  memset(newtlv, 0, sizeof(struct aim_tlv_t));
+  return newtlv;
+}
+
+int aim_freetlv(struct aim_tlv_t **oldtlv)
+{
+  if (!oldtlv)
+    return -1;
+  if (!*oldtlv)
+    return -1;
+  if ((*oldtlv)->value)
+    free((*oldtlv)->value);
+  free(*(oldtlv));
+  (*oldtlv) = NULL;
+
+  return 0;
+}
+
+int aim_puttlv_16(u_char *buf, u_short t, u_short v)
+{
+  int curbyte=0;
+  curbyte += aimutil_put16(buf+curbyte, (u_short)(t&0xffff));
+  curbyte += aimutil_put16(buf+curbyte, (u_short)0x0002);
+  curbyte += aimutil_put16(buf+curbyte, (u_short)(v&0xffff));
+  return curbyte;
+}
diff --git a/aim_txqueue.c b/aim_txqueue.c
new file mode 100644 (file)
index 0000000..d3f7d9e
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+  aim_txqueue.c
+
+  Herein lies all the mangement routines for the transmit (Tx) queue.
+
+ */
+
+#include "aim.h"
+
+/*
+  aim_tx_enqeue()
+
+  The overall purpose here is to enqueue the passed in command struct
+  into the outgoing (tx) queue.  Basically...
+    1) Make a scope-irrelevent copy of the struct
+    2) Lock the struct
+    3) Mark as not-sent-yet
+    4) Enqueue the struct into the list
+    5) Unlock the struct once it's linked in
+    6) Return
+
+ */
+
+int aim_tx_enqueue(struct command_tx_struct *newpacket)
+{
+  struct command_tx_struct *workingPtr = NULL;
+  struct command_tx_struct *newpacket_copy = NULL;
+
+  if (newpacket->conn == NULL)
+    {
+      printf("aim_tx_enqueue: WARNING: enqueueing packet with no connecetion,  defaulting to BOS\n");
+      newpacket->conn = aim_getconn_type(AIM_CONN_TYPE_BOS);
+    }
+  newpacket_copy = (struct command_tx_struct *) malloc (sizeof(struct command_tx_struct));
+  memcpy(newpacket_copy, newpacket, sizeof(struct command_tx_struct));
+
+  /* assign seqnum */
+  newpacket_copy->seqnum = aim_get_next_txseqnum(newpacket_copy->conn);
+  /* set some more fields */
+  newpacket_copy->lock = 1; /* lock */
+  newpacket_copy->sent = 0; /* not sent yet */
+  newpacket_copy->next = NULL; /* always last */
+
+  if (aim_queue_outgoing == NULL)
+    {
+      aim_queue_outgoing = newpacket_copy;
+    }
+  else
+    {
+      workingPtr = aim_queue_outgoing;
+      while (workingPtr->next != NULL)
+       workingPtr = workingPtr->next;
+      workingPtr->next = newpacket_copy;
+    }
+
+  newpacket_copy->lock = 0; /* unlock so it can be sent */
+
+#if debug > 2
+  printf("calling aim_tx_printqueue()\n");
+  aim_tx_printqueue();
+  printf("back from aim_tx_printqueue()\n");
+#endif
+
+  /* we'll force a flush for now -- this behavior probably will change */
+#if debug > 1
+  printf("calling aim_tx_flushqueue()\n");
+#endif
+  aim_tx_flushqueue();
+#if debug > 1
+  printf("back from aim_tx_flushqueue()\n");
+#endif
+
+  return 0;
+}
+
+/* 
+   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()).
+
+ */
+u_int aim_get_next_txseqnum(struct aim_conn_t *conn)
+{
+  return ( ++conn->seqnum );
+}
+
+/*
+  aim_tx_printqueue()
+
+  This is basically for debuging purposes only.  It dumps all the
+  records in the tx queue and their current status.  Very helpful
+  if the queue isn't working quite right.
+
+ */
+#if debug > 2
+int aim_tx_printqueue(void)
+{
+  struct command_tx_struct *workingPtr = NULL;
+
+  workingPtr = aim_queue_outgoing;
+#if debug > 2
+  printf("\ncurrent aim_queue_outgoing...\n");
+  printf("\ttype seqnum  len  lock sent\n");  
+#endif
+  if (workingPtr == NULL)
+    printf("aim_tx_flushqueue(): queue empty");
+  else
+    {
+      while (workingPtr != NULL)
+       {
+         printf("\t  %2x   %4x %4x   %1d    %1d\n", workingPtr->type, workingPtr->seqnum, workingPtr->commandlen, workingPtr->lock, workingPtr->sent);
+         
+         workingPtr = workingPtr->next;
+       }
+    }
+
+  printf("\n(done printing queue)\n");
+  
+  return 0;
+}
+#endif
+
+/*
+  aim_tx_flushqueue()
+
+  This the function is responsable for putting the queued commands
+  onto the wire.  This function is critical to the operation of 
+  the queue and therefore is the most prone to brokenness.  It
+  seems to be working quite well at this point.
+
+  Procedure:
+    1) Traverse the list, only operate on commands that are unlocked
+       and haven't been sent yet.
+    2) Lock the struct
+    3) Allocate a temporary buffer to store the finished, fully
+       processed packet in.
+    4) Build the packet from the command_tx_struct data.
+    5) Write the packet to the socket.
+    6) If success, mark the packet sent, if fail report failure, do NOT
+       mark the packet sent (so it will not get purged and therefore
+       be attempted again on next call).
+    7) Unlock the struct.
+    8) Free the temp buffer
+    9) Step to next struct in list and go back to 1.
+
+ */
+int aim_tx_flushqueue(void)
+{
+  struct command_tx_struct *workingPtr = NULL;
+  u_char *curPacket = NULL;
+#if debug > 1
+  int i = 0;
+#endif
+
+  workingPtr = aim_queue_outgoing;
+#if debug > 1
+  printf("beginning txflush...\n");
+#endif
+  while (workingPtr != NULL)
+    {
+      /* only process if its unlocked and unsent */
+      if ( (workingPtr->lock == 0) &&
+          (workingPtr->sent == 0) )
+       {
+
+         /*
+          * And now for the meager attempt to force transmit
+          * latency and avoid missed messages.
+          */
+         if ((workingPtr->conn->lastactivity + workingPtr->conn->forcedlatency) 
+             >= time(NULL))
+           {
+             /* FIXME FIXME -- should be a break! we dont want to block the upper layers */
+             sleep((workingPtr->conn->lastactivity + workingPtr->conn->forcedlatency) - time(NULL));
+           }
+
+         workingPtr->lock = 1; /* lock the struct */
+         
+         /* allocate full-packet buffer */
+         curPacket = (char *) malloc(workingPtr->commandlen + 6);
+         
+         /* command byte */
+         curPacket[0] = 0x2a;
+         /* type/family byte */
+         curPacket[1] = workingPtr->type;
+         /* bytes 3+4: word: FLAP sequence number */
+         curPacket[2] = (char) ( (workingPtr->seqnum) >> 8);
+         curPacket[3] = (char) ( (workingPtr->seqnum) & 0xFF);
+         /* bytes 5+6: word: SNAC len */
+         curPacket[4] = (char) ( (workingPtr->commandlen) >> 8);
+         curPacket[5] = (char) ( (workingPtr->commandlen) & 0xFF);
+         /* bytes 7 and on: raw: SNAC data */
+         memcpy(&(curPacket[6]), workingPtr->data, workingPtr->commandlen);
+         
+         /* full image of raw packet data now in curPacket */
+
+         if ( (u_int)write(workingPtr->conn->fd, curPacket, (workingPtr->commandlen + 6)) != (workingPtr->commandlen + 6))
+           {
+             perror("write");
+             printf("\nWARNING: Error in sending packet 0x%4x -- will try again next time\n\n", workingPtr->seqnum);
+             workingPtr->sent = 0; /* mark it unsent */
+             return -1;  /* bail out */
+           }
+         else
+           {
+#if debug > 2
+             printf("\nSENT 0x%4x\n\n", workingPtr->seqnum);
+#endif
+             workingPtr->sent = 1; /* mark the struct as sent */
+             workingPtr->conn->lastactivity = time(NULL);
+           }
+#if debug > 2
+         printf("\nPacket:");
+         for (i = 0; i < (workingPtr->commandlen + 6); i++)
+           {
+             if ((i % 8) == 0)
+               printf("\n\t");
+             if (curPacket[i] >= ' ' && curPacket[i]<127)
+                printf("%c=%02x ",curPacket[i], curPacket[i]);
+             else
+                printf("0x%2x ", curPacket[i]);
+           }
+         printf("\n");
+#endif
+         workingPtr->lock = 0; /* unlock the struct */
+         free(curPacket); /* free up full-packet buffer */
+       }
+      workingPtr = workingPtr->next;
+    }
+
+  /* purge sent commands from queue */
+  /*   this may not always occur explicitly--i may put this on a timer later */
+#if debug > 1
+  printf("calling aim_tx_purgequeue()\n");
+#endif
+  aim_tx_purgequeue();
+#if debug > 1
+  printf("back from aim_tx_purgequeu() [you must be a lucky one]\n");
+#endif
+
+  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!  
+
+ */
+int aim_tx_purgequeue(void)
+{
+  struct command_tx_struct *workingPtr = NULL;
+  struct command_tx_struct *workingPtr2 = NULL;
+#if debug > 1
+  printf("purgequeue(): starting purge\n");
+#endif
+  /* Empty queue: nothing to do */
+  if (aim_queue_outgoing == NULL)
+    {
+#if debug > 1
+      printf("purgequeue(): purge done (len=0)\n");
+#endif
+      return 0;
+    }
+  /* One Node queue: free node and return */
+  else if (aim_queue_outgoing->next == NULL)
+    {
+#if debug > 1
+      printf("purgequeue(): entered case len=1\n");
+#endif
+      /* only free if sent AND unlocked -- dont assume sent structs are done */
+      if ( (aim_queue_outgoing->lock == 0) &&
+          (aim_queue_outgoing->sent == 1) )
+       {
+#if debug > 1
+         printf("purgequeue(): purging seqnum 0x%04x\n", aim_queue_outgoing->seqnum);
+#endif
+         workingPtr2 = aim_queue_outgoing;
+         aim_queue_outgoing = NULL;
+         free(workingPtr2->data);
+         free(workingPtr2);
+       }
+#if debug > 1
+      printf("purgequeue(): purge done (len=1)\n");
+#endif
+      return 0;
+    }
+  else
+    {
+#if debug > 1
+      printf("purgequeue(): entering case len>1\n");
+#endif
+      while(workingPtr->next != NULL)
+       {
+         if ( (workingPtr->next->lock == 0) &&
+              (workingPtr->next->sent == 1) )
+           {
+#if debug > 1
+             printf("purgequeue(): purging seqnum 0x%04x\n", workingPtr->next->seqnum);
+#endif
+             workingPtr2 = workingPtr->next;
+             workingPtr->next = workingPtr2->next;
+             free(workingPtr2->data);
+             free(workingPtr2);
+           }
+       }
+#if debug > 1
+      printf("purgequeue(): purge done (len>1)\n");
+#endif
+      return 0;
+    }
+
+  /* no reach */
+}
diff --git a/aim_util.c b/aim_util.c
new file mode 100644 (file)
index 0000000..a83a997
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ *
+ *
+ *
+ */
+
+#include "aim.h"
+
+int aimutil_put8(u_char *buf, u_char data)
+{
+  buf[0] = (u_char)data&0xff;
+  return 1;
+}
+
+/*
+ * Endian-ness issues here?
+ */
+int aimutil_put16(u_char *buf, u_short data)
+{
+  buf[0] = (u_char)(data>>8)&0xff;
+  buf[1] = (u_char)(data)&0xff;
+  return 2;
+}
+
+u_short aimutil_get16(u_char *buf)
+{
+  u_short val;
+  val = (buf[0] << 8) & 0xff00;
+  val+= (buf[1]) & 0xff;
+  return val;
+}
+
+int aimutil_put32(u_char *buf, u_long data)
+{
+  buf[0] = (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;
+  return 4;
+}
+
+u_long aimutil_get32(u_char *buf)
+{
+  u_long val;
+  val = (buf[0] << 24) & 0xff000000;
+  val+= (buf[1] << 16) & 0x00ff0000;
+  val+= (buf[2] <<  8) & 0x0000ff00;
+  val+= (buf[3]      ) & 0x000000ff;
+  return val;
+}
+
+int aimutil_putstr(u_char *dest, const u_char *src, int len)
+{
+  memcpy(dest, src, len);
+  return len;
+}
+
+/*
+ * Tokenizing functions.  Used to portably replace strtok/sep.
+ *   -- DMP.
+ *
+ */
+int aimutil_tokslen(char *toSearch, int index, char dl)
+{
+  int curCount = 1;
+  char *next;
+  char *last;
+  int toReturn;
+
+  last = toSearch;
+  next = strchr(toSearch, dl);
+  
+  while(curCount < index && next != NULL)
+    {
+      curCount++;
+      last = next + 1;
+      next = strchr(last, dl);
+    }
+  
+  if ((curCount < index) || (next == NULL))
+    toReturn = strlen(toSearch) - (curCount - 1);
+  else
+    toReturn = next - toSearch - (curCount - 1);
+
+  return toReturn;
+}
+
+int aimutil_itemcnt(char *toSearch, char dl)
+{
+  int curCount;
+  char *next;
+  
+  curCount = 1;
+  
+  next = strchr(toSearch, dl);
+  
+  while(next != NULL)
+    {
+      curCount++;
+      next = strchr(next + 1, dl);
+    }
+  
+  return curCount;
+}
+
+char *aimutil_itemidx(char *toSearch, int index, char dl)
+{
+  int curCount;
+  char *next;
+  char *last;
+  char *toReturn;
+  
+  curCount = 0;
+  
+  last = toSearch;
+  next = strchr(toSearch, dl);
+  
+  while(curCount < index && next != NULL)
+    {
+      curCount++;
+      last = next + 1;
+      next = strchr(last, dl);
+    }
+  
+  if (curCount < index)
+    {
+      toReturn = malloc(sizeof(char));
+      *toReturn = '\0';
+    }
+  next = strchr(last, dl);
+  
+  if (curCount < index)
+    {
+      toReturn = malloc(sizeof(char));
+      *toReturn = '\0';
+    }
+  else
+    {
+      if (next == NULL)
+       {
+         toReturn = malloc((strlen(last) + 1) * sizeof(char));
+         strcpy(toReturn, last);
+       }
+      else
+       {
+         toReturn = malloc((next - last + 1) * sizeof(char));
+         memcpy(toReturn, last, (next - last));
+         toReturn[next - last] = '\0';
+       }
+    }
+  return toReturn;
+}
diff --git a/deprecated/aim_rxqueue.orig.c b/deprecated/aim_rxqueue.orig.c
new file mode 100644 (file)
index 0000000..c10e3da
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+  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 "aim.h"
+
+/*
+  This is a modified read() to make SURE we get the number
+  of bytes we are told to, otherwise block.
+ */
+int Read(int fd, u_char *buf, int len)
+{
+  int i = 0;
+  int j = 0;
+
+  while ((i < len) && (!(i < 0)))
+    {
+      j = read(fd, &(buf[i]), len-i);
+      if ( (j < 0) && (errno != EAGAIN))
+       return -errno; /* fail */
+      else
+       i += j; /* success, continue */
+    }
+#if 0
+  printf("\nRead Block: (%d/%04x)\n", len, len);
+  printf("\t");
+  for (j = 0; j < len; j++)
+    {
+      if (j % 8 == 0)
+       printf("\n\t");
+      if (buf[j] >= ' ' && buf[j] < 127)
+        printf("%c=%02x ",buf[j], buf[j]);
+      else
+        printf("0x%02x ", buf[j]);
+    }
+  printf("\n\n");
+#endif
+  return i;
+}
+
+/*
+  struct command_struct *
+                         get_generic(
+                                     struct connection_info struct *,
+                                    struct command_struct * 
+                                    )
+  
+  Grab as many command sequences as we can off the socket, and enqueue
+  each command in the incoming event queue in a seperate struct.
+
+*/
+int aim_get_command(void)
+{
+  int i, readgood, j, isav, err;
+  int s;
+  fd_set fds;
+  struct timeval tv;
+  char generic[6]; 
+  struct command_rx_struct *workingStruct = NULL;
+  struct command_rx_struct *workingPtr = NULL;
+  struct aim_conn_t *conn = NULL;
+#if debug > 0
+  printf("Reading generic/unknown response...");
+#endif
+  
+  
+  /* dont wait at all (ie, never call this unless something is there) */
+  tv.tv_sec = 0; 
+  tv.tv_usec = 0;
+  conn = aim_select(&tv);
+
+  if (conn==NULL)
+    return 0;  /* nothing waiting */
+
+  s = conn->fd;
+
+  FD_ZERO(&fds);
+  FD_SET(s, &fds);
+  tv.tv_sec = 0;  /* wait, but only for 10us */
+  tv.tv_usec = 10;
+  
+  generic[0] = 0x00;  
+
+  readgood = 0;
+  i = 0;
+  j = 0;
+  /* read first 6 bytes (the FLAP header only) off the socket */
+  while ( (select(s+1, &fds, NULL, NULL, &tv) == 1) && (i < 6))
+    {
+      if ((err = Read(s, &(generic[i]), 1)) < 0)
+       {
+         /* error is probably not recoverable...(must be a pessimistic day) */
+         aim_conn_close(conn);
+         return err;
+       }
+
+      if (readgood == 0)
+       {
+         if (generic[i] == 0x2a)
+         {
+           readgood = 1;
+#if debug > 1
+           printf("%x ", generic[i]);
+           fflush(stdout);
+#endif
+           i++;
+         }
+         else
+           {
+#if debug > 1
+             printf("skipping 0x%d ", generic[i]);
+             fflush(stdout);
+#endif
+             j++;
+           }
+       }
+      else
+       {
+#if debug > 1
+         printf("%x ", generic[i]);
+#endif
+         i++;
+       }
+      FD_ZERO(&fds);
+      FD_SET(s, &fds);
+      tv.tv_sec= 2;
+      tv.tv_usec= 2;
+    }
+
+  if (generic[0] != 0x2a)
+    {
+      /* this really shouldn't happen, since the main loop
+        select() should protect us from entering this function
+        without data waiting  */
+      printf("Bad incoming data!");
+      return -1;
+    }
+
+  isav = i;
+
+  /* allocate a new struct */
+  workingStruct = (struct command_rx_struct *) malloc(sizeof(struct command_rx_struct));
+  workingStruct->lock = 1;  /* lock the struct */
+
+  /* store type -- byte 2 */
+  workingStruct->type = (char) generic[1];
+
+  /* store seqnum -- bytes 3 and 4 */
+  workingStruct->seqnum = ( (( (unsigned int) generic[2]) & 0xFF) << 8);
+  workingStruct->seqnum += ( (unsigned int) generic[3]) & 0xFF;
+
+  /* store commandlen -- bytes 5 and 6 */
+  workingStruct->commandlen = ( (( (unsigned int) generic[4]) & 0xFF ) << 8);
+  workingStruct->commandlen += ( (unsigned int) generic[5]) & 0xFF;
+
+  /* malloc for data portion */
+  workingStruct->data = (char *) malloc(workingStruct->commandlen);
+
+  /* read the data portion of the packet */
+  i = Read(s, workingStruct->data, workingStruct->commandlen);
+  if (i < 0)
+    {
+      aim_conn_close(conn);
+      return i;
+    }
+
+#if debug > 0
+  printf(" done. (%db+%db read, %db skipped)\n", isav, i, j);
+#endif
+
+  workingStruct->conn = conn;
+
+  workingStruct->next = NULL;  /* this will always be at the bottom */
+  workingStruct->lock = 0; /* unlock */
+
+  /* enqueue this packet */
+  if (aim_queue_incoming == NULL)
+    aim_queue_incoming = workingStruct;
+  else
+    {
+      workingPtr = aim_queue_incoming;
+      while (workingPtr->next != NULL)
+       workingPtr = workingPtr->next;
+      workingPtr->next = workingStruct;
+    }
+
+  return 0;  
+}
+
+/*
+  purge_rxqueue()
+
+  This is just what it sounds.  It purges the receive (rx) queue of
+  all handled commands.  This is normally called from inside 
+  aim_rxdispatch() after it's processed all the commands in the queue.
+  
+ */
+struct command_rx_struct *aim_purge_rxqueue(struct command_rx_struct *queue)
+{
+  int i = 0;
+  struct command_rx_struct *workingPtr = NULL;
+  struct command_rx_struct *workingPtr2 = NULL;
+
+  workingPtr = queue;
+  if (queue == NULL)
+    {
+      return queue;
+    }
+  else if (queue->next == NULL)
+    {
+      if (queue->handled == 1)
+       {
+         workingPtr2 = queue;
+         queue = NULL;
+         free(workingPtr2->data);
+         free(workingPtr2);
+       }
+      return queue;
+    }
+  else
+    {
+      for (i = 0; workingPtr != NULL; i++)
+       {
+         if (workingPtr->next->handled == 1)
+           {
+             /* save struct */
+             workingPtr2 = workingPtr->next;
+             /* dequeue */
+             workingPtr->next = workingPtr2->next;
+             /* free */
+             free(workingPtr2->data);
+             free(workingPtr2);
+           }
+
+         workingPtr = workingPtr->next;  
+       }
+    }
+
+  return queue;
+}
diff --git a/deprecated/aim_snac.c b/deprecated/aim_snac.c
new file mode 100644 (file)
index 0000000..15a0b66
--- /dev/null
@@ -0,0 +1,114 @@
+
+/*
+
+  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.
+
+ */
+
+#include <aim.h>
+
+struct aim_snac_t *aim_outstanding_snacs = NULL;
+u_long aim_snac_nextid = 0x00000001;
+
+u_long aim_newsnac(struct aim_snac_t *newsnac)
+{
+  struct aim_snac_t *local = NULL;
+  
+  local = (struct aim_snac_t *)malloc(sizeof(struct aim_snac_t));
+  memcpy(local, newsnac, sizeof(struct aim_snac_t));
+  local->next = NULL;
+  local->issuetime = time(&local->issuetime);
+
+  if (aim_outstanding_snacs!=NULL)
+    {
+      struct aim_snac_t *cur = aim_outstanding_snacs;
+      
+      if (cur->next == NULL)
+       {
+         cur->next = local;
+       }
+      else
+       {
+         for (;cur->next!=NULL; cur=cur->next)
+           ;
+         cur->next = local;
+       }
+    }
+  else
+    {
+      aim_outstanding_snacs = local;
+      aim_outstanding_snacs->next = NULL;
+    }
+
+  return local->id;
+}
+
+/* FIXME: there's a bug in here... just don't have more than two outstanding
+          SNACs and you'll be ok */
+struct aim_snac_t *aim_remsnac(u_long id)
+{
+  struct aim_snac_t *cur = aim_outstanding_snacs;
+
+  if(cur)
+    {
+      if (cur->next)
+       {
+         struct aim_snac_t *ret = NULL;
+         for(;(cur->next!=NULL) && (cur->id != id);cur=cur->next)
+           ;
+         if (cur->id == id)
+           {
+             ret = cur;
+             cur->next = NULL;
+             return ret;
+           }
+         else 
+           {
+             return NULL;
+           }
+       }
+      else
+       {
+         aim_outstanding_snacs = NULL;
+         return cur;
+       }
+    }
+  else
+    return NULL;
+}
+
+
+/*
+  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
+
+ */
+int aim_cleansnacs(int maxage)
+{
+  struct aim_snac_t *cur = aim_outstanding_snacs;
+  time_t curtime;
+  
+  curtime = time(&curtime);
+
+  while (cur)
+    {
+#if 1
+      if ( (cur) && (((cur->issuetime) + maxage) < curtime))
+       {
+         printf("aimsnac: WARNING purged obsolete snac %ul\n", (unsigned int) cur->id);
+#if 1
+         aim_remsnac(cur->id);
+#endif
+       }
+#endif
+      cur = cur->next;
+    }
+
+  return 0;
+}
diff --git a/deprecated/discarded.c b/deprecated/discarded.c
new file mode 100644 (file)
index 0000000..e85a6ed
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Hop in the Way-Back machine....  These are left over from the
+ * decoding process back in Jun/Jul 1998 and are found to no longer
+ * be necessary.  They're left here for reference _only_.  This file
+ * should _not_ be linked into libfaim!
+ */
+
+
+
+/* 
+   send_login_phase4_a(int socket)   
+
+   Set ICBM Parameter?
+
+*/
+int aim_send_login_phase4_a_1(void)
+{
+  char command_1[] = {
+    0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x7a, 0x8c,
+    0x11, 0x9c, 
+
+    0x00, 0x01, 
+    0x00, 0x00, 
+    0x00, 0x03,
+    0x1f, 0x3f, 
+    0x03, 0xe7, 
+    0x03, 0xe7, 
+    0x00, 0x00, 
+    0x00, 0x64
+  };
+  int command_1_len = 26;
+  struct command_tx_struct newpacket;
+  
+  newpacket.lock = 1;
+  newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS);
+  newpacket.type = 0x02;
+  newpacket.commandlen = command_1_len;
+  newpacket.data = (char *) malloc (newpacket.commandlen);
+  memcpy(newpacket.data, command_1, newpacket.commandlen);
+  
+  aim_tx_enqueue(&newpacket);
+
+  return 0;
+}
diff --git a/deprecated/tis_telnet_proxy.c b/deprecated/tis_telnet_proxy.c
new file mode 100644 (file)
index 0000000..05a6c85
--- /dev/null
@@ -0,0 +1,64 @@
+
+/*
+ * For working with TIS proxies.  TODO: Fix for use with aim_conn.c.
+ *
+ */
+
+
+#include "aim.h"
+#ifdef TIS_TELNET_PROXY
+#include "tis_telnet_proxy.h"
+
+void
+tis_telnet_proxy_connect( int fd, char *host, int port )
+{
+   fd_set          inset;
+   fd_set          outset;
+       struct timeval  tv;
+       char            connectstring[512];
+       char            responsestring[512];
+       char           *ptr;
+       struct hostent *hent;
+
+       hent = gethostbyname( host );
+
+       snprintf( connectstring, 512, "connect %s %d\n", hent->h_name, port );
+       snprintf( responsestring, 512, "Connected to %s.\r\n", hent->h_name);
+
+       FD_ZERO( &outset );
+       FD_SET( fd, &outset );
+       tv.tv_sec = 0;
+       tv.tv_usec = 5;
+
+       if( select( fd + 1, NULL, &outset, NULL, &tv ) == 1 )
+               if( write( fd, connectstring, strlen(connectstring) ) !=
+                        strlen(connectstring) )
+                       printf("\n****ERROR ON WRITE**** (proxy connect)\n");
+
+
+       FD_ZERO( &inset );
+       FD_SET( fd, &inset );
+
+       ptr = responsestring;
+       while( select( fd + 1, &inset, NULL, NULL, NULL ) == 1 )
+       {
+               char c;
+
+               if( read( fd, &c, sizeof(c) ) != 1 )
+                       printf("\n****ERROR ON READ**** (proxy response)\n");
+
+               if( c == *ptr )
+               {
+                       if( *(++ptr) == '\0' )
+                               break;
+               }
+               else
+                       ptr = responsestring;
+
+               FD_ZERO( &inset );
+               FD_SET( fd, &inset );
+       }
+}
+
+#endif /* TIS_TELNET_PROXY */
+
diff --git a/deprecated/tis_telnet_proxy.h b/deprecated/tis_telnet_proxy.h
new file mode 100644 (file)
index 0000000..ed63951
--- /dev/null
@@ -0,0 +1,8 @@
+
+#ifndef __TIS_TELNET_PROXY_H
+#define __TIS_TELNET_PROXY_H 1
+
+void tis_telnet_proxy_connect( int fd, char *host, int port );
+
+#endif /* !__TIS_TELNET_PROXY_H */
+
diff --git a/faimconfig.h b/faimconfig.h
new file mode 100644 (file)
index 0000000..2584d59
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef __FAIMCONFIG_H__
+#define __FAIMCONFIG_H__
+
+/*
+  faimconfig.h
+
+  Contains various compile-time options that apply _only to the faim backend_.
+  Note that setting any of these options in a frontend header does not imply
+  that they'll get set here.  Notably, the 'debug' of this file is _not_ 
+  the same as the frontend 'debug'.  They can be different values.
+
+ */
+
+/* 
+   set debug to be > 0 if you want debugging information spewing
+   on the attached tty.  set to 0 for daily use.  this value
+   is _not_ inherited by the frontend, only this backend.
+
+   Default: 0  
+*/
+#define debug 0 
+
+/*
+  define TIS_TELNET_PROXY if you have a TIS firewall (Gauntlet) and
+  you want to use FAIM through the firewall
+
+  Default: undefined
+ */
+/* #define TIS_TELNET_PROXY "proxy.mydomain.com" */
+
+
+/* #define USE_SNAC_FOR_IMS */
+
+/* ---- these shouldn't need any changes ---- */
+
+/* authentication server of OSCAR */
+#define FAIM_LOGIN_SERVER "login.oscar.aol.com"
+/* port on OSCAR authenticator to connect to */
+#define FAIM_LOGIN_PORT 5190
+
+
+#endif /* __FAIMCONFIG_H__ */
diff --git a/tcpdumps/chat.txt b/tcpdumps/chat.txt
new file mode 100644 (file)
index 0000000..69c8e4a
--- /dev/null
@@ -0,0 +1,504 @@
+diputs81       6469 7075 7473 3831
+midendian      6d69 6465 6e64 6961 6e
+
+/* Request chatnav service (BOS)*/
+01:25:35.295564 206.165.19.128.61187 > 205.188.2.18.5190: P 156459:156477(18) ack 2453659874 win 8724 (DF) (ttl 31, id 2561)
+                        2a02 7668 000c 
+                        0001 0004 0000 0000 0009 
+                        000d /* service ID */
+
+/* Chat request response (BOS) */
+01:25:35.640111 205.188.2.18.5190 > 206.165.19.128.61187: P 1:299(298) ack 18 win 16384 (DF) (ttl 44, id 0)
+                        2a02 c21f 0124 
+                        0001 0005 0000 0000 0009 
+                        000d /* TLV? Unknown */
+                         0002 
+                         000d 
+                        0005 /* TLV: IP Address */
+                         000c
+                         3230 352e 3138 382e 342e 3530
+                         /* 205.188.4.50 */ 
+                        0006 /* TLV: Cookie */
+                         0100  
+                         071a c079 7682 ad1b d8bb 173f ddc7
+                         0a8f d6de 3d4e 5014 2e45 1df7 c1c1 83f7
+                         7acd d42c d72f d2ed d75d 745f 6341 4a19
+                         f719 9687 4052 e2e5 950b 2bbe 3b2b 52a9
+                         9962 7be1 3b9c bda0 8231 5d6e f044 0018
+                         ecf6 fc74 55f9 a9fc 4959 ee52 1f41 b79c
+                         ab5f 7b01 677f 409a 5e5d 9e3d d0dd 9377
+                         2099 fd26 e62e c658 0bff d5f2 0c9f 76bd
+                         9757 2ef6 fe35 47bd 8cad 71dd e581 940b
+                         4c79 c402 12a9 9948 4901 9fa6 bdfb 0174
+                         1395 b239 971f 5820 fafa b6b2 6ed9 87b5
+                         e19d 5037 8036 2c4c 5ad7 5099 2148 c32f
+                         5fa5 a6db 8e41 be13 7fb4 127f d243 b1ec
+                         d876 33e7 f6c4 d829 febf acba 584c 1b99
+                         c5fb 3443 93ca 28f5 5abf fa04 7aee 5a0e
+                         16d6 27d7 9b13 8b1c 6c67 ef4b 3f76 24fd
+                         de80
+
+/* Open new connection (ChatNav) */
+
+01:25:35.652894 206.165.19.128.61190 > 205.188.4.50.5190: S 179050:179050(0) win 8192 <mss 1460> (DF) (ttl 31, id 2817)
+                        4500 002c 0b01 4000 1f06 9cb7 cea5 1380
+                        cdbc 0432 ef06 1446 0002 bb6a 0000 0000
+                        6002 2000 0559 0000 0204 05b4
+
+/* Unknown -- Non-SNAC (ChatNav) */
+01:25:36.130073 205.188.4.50.5190 > 206.165.19.128.61190: P 1:11(10) ack 1 win 16384 (DF) (ttl 44, id 0)
+                        2a01 5db8 0004 
+                        0000 0001
+
+/* Unknown -- Non-SNAC (ChatNav)*/
+01:25:36.143313 206.165.19.128.61190 > 205.188.4.50.5190: P 1:271(270) ack 11 win 8750 (DF) (ttl 31, id 3585)
+                        2a01 7974 0108 
+                        0000 0001 
+                        0006 /* TLV: Cookie */ 
+                         0100 
+                         071a c079 7682 ad1b d8bb
+                         173f ddc7 0a8f d6de 3d4e 5014 2e45 1df7
+                         c1c1 83f7 7acd d42c d72f d2ed d75d 745f
+                         6341 4a19 f719 9687 4052 e2e5 950b 2bbe
+                         3b2b 52a9 9962 7be1 3b9c bda0 8231 5d6e
+                         f044 0018 ecf6 fc74 55f9 a9fc 4959 ee52
+                         1f41 b79c ab5f 7b01 677f 409a 5e5d 9e3d
+                         d0dd 9377 2099 fd26 e62e c658 0bff d5f2
+                         0c9f 76bd 9757 2ef6 fe35 47bd 8cad 71dd
+                         e581 940b 4c79 c402 12a9 9948 4901 9fa6
+                         bdfb 0174 1395 b239 971f 5820 fafa b6b2
+                         6ed9 87b5 e19d 5037 8036 2c4c 5ad7 5099
+                         2148 c32f 5fa5 a6db 8e41 be13 7fb4 127f
+                         d243 b1ec d876 33e7 f6c4 d829 febf acba
+                         584c 1b99 c5fb 3443 93ca 28f5 5abf fa04
+                         7aee 5a0e 16d6 27d7 9b13 8b1c 6c67 ef4b
+                         3f76 24fd de80
+
+/* Server Ready (ChatNav) */
+01:25:36.460107 205.188.4.50.5190 > 206.165.19.128.61190: P 11:31(20) ack 271 win 16384 (DF) (ttl 44, id 0)
+                        2a02 5db9 000e 
+                        0001 0003 0000 800b e590 
+                        0001 000d
+
+/* Unknown -- SNAC (ChatNav) */
+01:25:36.472636 206.165.19.128.61190 > 205.188.4.50.5190: P 271:295(24) ack 31 win 8730 (DF) (ttl 31, id 3841)
+                        2a02 7975 0012 
+                        0001 0017 0000 0000 000a 
+                        000d 0001 0001 0003
+
+/* Unknown -- SNAC (ChatNav) */
+01:25:36.700093 205.188.4.50.5190 > 206.165.19.128.61190: P 31:55(24) ack 295 win 16384 (DF) (ttl 44, id 0)
+                        2a02 5dba 0012 
+                        0001 0018 0000 800b e591 
+                        0001 0003 000d 0001
+
+/* Request Rate Info (ChatNav) */
+01:25:36.711866 206.165.19.128.61190 > 205.188.4.50.5190: P 295:311(16) ack 55 win 8706 (DF) (ttl 31, id 4097)
+                        2a02 7976 000a 
+                        0001 0006 0000 0000 0000
+
+/* Rate Info (ChatNav) */
+01:25:37.310117 205.188.4.50.5190 > 206.165.19.128.61190: P 55:828(773) ack 311 win 16384 (DF) (ttl 44, id 0)
+                        2a02 5dbb 02ff 
+                        0001 0007 0000 0000 0000 
+
+                        0005 0001 0000 0050
+                        0000 09c4 0000 07d0 0000 05dc 0000 0320
+                        0000 16e0 0000 1770 0000 0000 0000 0200
+                        0000 5000 000b b800 0007 d000 0005 dc00
+                        0003 e800 0017 7000 0017 7000 0001 d300
+                        0003 0000 0014 0000 13ec 0000 1388 0000
+                        0fa0 0000 0bb8 0000 1770 0000 1770 0000
+                        01d3 0000 0400 0000 1400 0015 7c00 0014
+                        b400 0010 6800 000b b800 0017 7000 001f
+                        4000 0001 d300 0005 0000 000a 0000 157c
+                        0000 14b4 0000 1068 0000 0bb8 0000 1770
+                        0000 1f40 0000 01d3 0000 0100 7f00 0100
+                        0100 0100 0200 0100 0300 0100 0400 0100
+                        0500 0100 0600 0100 0700 0100 0800 0100
+                        0900 0100 0a00 0100 0b00 0100 0c00 0100
+                        0d00 0100 0e00 0100 0f00 0100 1000 0100
+                        1100 0100 1200 0100 1300 0100 1400 0100
+                        1500 0100 1600 0100 1700 0100 1800 0100
+                        1900 0100 1a00 0100 1b00 0100 1c00 0100
+                        1d00 0200 0100 0200 0200 0200 0300 0200
+                        0400 0200 0600 0200 0700 0200 0800 0200
+                        0a00 0200 0c00 0200 0d00 0200 0e00 0200
+                        0f00 0200 1000 0200 1100 0200 1200 0300
+                        0100 0300 0200 0300 0300 0300 0600 0300
+                        0700 0300 0800 0300 0900 0300 0a00 0300
+                        0b00 0300 0c00 0400 0100 0400 0200 0400
+                        0300 0400 0400 0400 0500 0400 0700 0400
+                        0800 0400 0900 0400 0a00 0400 0b00 0400
+                        0c00 0500 0100 0500 0200 0500 0300 0600
+                        0100 0600 0200 0600 0300 0700 0100 0700
+                        0200 0700 0300 0700 0400 0700 0500 0700
+                        0600 0700 0700 0700 0800 0700 0900 0800
+                        0100 0800 0200 0900 0100 0900 0200 0900
+                        0300 0900 0400 0900 0900 0a00 0100 0a00
+                        0200 0a00 0300 0b00 0100 0b00 0200 0b00
+                        0300 0b00 0400 0c00 0100 0c00 0200 0c00
+                        0300 0d00 0100 0d00 0200 0d00 0300 0d00
+                        0400 0d00 0500 0d00 0600 0d00 0700 0d00
+                        0900 0e00 0100 0e00 0200 0e00 0300 0e00
+                        0400 0e00 0600 0e00 0700 0e00 0800 0e00
+                        0900 0e00 0a00 0e00 0b00 0e00 0c00 0f00
+                        0100 0f00 0300 0f00 0400 0f00 0500 1000
+                        0100 1000 0200 1000 0300 1000 0400 1000
+                        0500 1000 0600 1000 0700 0200 0600 0300
+                        0400 0300 0500 0900 0500 0900 0600 0900
+                        0700 0900 0800 0300 0300 0200 0500 0400
+                        0600 0e00 0500 0400 0300 0200 0900 0200
+                        0b00 0f00 0200 0500 0100 0d00 08
+
+/* Rate Info Ack (ChatNav) */
+01:25:37.323531 206.165.19.128.61190 > 205.188.4.50.5190: P 311:337(26) ack 828 win 7933 (DF) (ttl 31, id 4353)
+                        2a02 7977 0014 
+                        0001 0008 0000 0000 0000 
+                        0001 0002 0003 0004 0005
+
+/* Client Ready + Request ChatNav rights (ChatNav) */
+01:25:37.751182 206.165.19.128.61190 > 205.188.4.50.5190: P 337:385(48) ack 828 win 7933 (DF) (ttl 31, id 4609)
+                        2a02 7978 001a 
+                        0001 0002 0000 0000 000b 
+                        000d 0001 0004 0001 0001 0003 0004 03e4 
+
+                        2a02 7979 000a 
+                        000d 0002 0000 0000 0000
+
+/* Response from ChatNav (ChatNav) */
+01:25:38.120120 205.188.4.50.5190 > 206.165.19.128.61190: P 828:1198(370) ack 385 win 16384 (DF) (ttl 44, id 0)
+                        2a02 5dbc 016c 
+                        000d 0009 0000 0000 0000
+                        /* Rights (0002) */
+                        0002 
+                        0001 0300 0300
+                        6d00 0400 0d00 0300 0103 0004 0002 0014
+                        00c9 0002 0011 00ca 0004 36f6 cb20 00d0
+                        0002 0003 00d1 0002 0200 00d2 0002 0017
+                        00d3 0011 6169 6d20 7072 6976 6174 6520
+                        6368 6174 7300 d500 0102 00d6 0008 7573
+                        2d61 7363 6969 00d7 0002 656e 00d8 0008
+                        7573 2d61 7363 6969 00d9 0002 656e 0003
+                        006f 0005 000d 0003 0001 0300 0400 0200
+                        1400 c900 0200 1500 ca00 0436 f6cb 2000
+                        d000 0200 0300 d100 0202 0000 d200 0200
+                        1700 d300 1361 6f6c 2063 6f6d 6d75 6e69
+                        7479 2063 6861 7473 00d5 0001 0200 d600
+                        0875 732d 6173 6369 6900 d700 0265 6e00
+                        d800 0875 732d 6173 6369 6900 d900 0265
+                        6e00 0300 7500 0600 0d00 0300 0103 0004
+                        0002 0014 00c9 0002 0015 00ca 0004 36f6
+                        cb20 00d0 0002 0003 00d1 0002 0200 00d2
+                        0002 0017 00d3 0019 6e65 7463 656e 7465
+                        7220 636f 6d6d 756e 6974 7920 6368 6174
+                        7300 d500 0102 00d6 0008 7573 2d61 7363
+                        6969 00d7 0002 656e 00d8 0008 7573 2d61
+                        7363 6969 00d9 0002 656e
+
+/* Request Exchange Info (ChatNav) */
+01:25:52.727724 206.165.19.128.61190 > 205.188.4.50.5190: P 385:403(18) ack 1198 win 7563 (DF) (ttl 31, id 5377)
+                        2a02 797a 000c
+                        000d 0003 0000 0000 9000 
+                        0004
+
+/*  (ChatNav) */
+01:25:53.000093 205.188.4.50.5190 > 206.165.19.128.61190: P 1198:1327(129) ack 403 win 16384 (DF) (ttl 44, id 0)
+                        2a02 5dbd 007b 
+                        000d 0009 0000 0000 9000 
+                        0003 /* Exchange Info */
+
+                        /*  */
+                        006d 0004 000d
+                        /*  */
+                        0003 
+                         0001 
+                         03
+                        /*  */
+                        0004 
+                         0002 
+                         0014
+                        /*  */ 
+                        00c9 
+                         0002
+                         0011 
+                        /*  */
+                        00ca
+                         0004
+                         36f6 cb20
+                        /*  */
+                        00d0
+                         0002
+                         0003
+                        /*  */
+                        00d1
+                         0002
+                         0200
+                        /* unknown */
+                        00d2
+                         0002
+                         0017
+                        /* exchange description -- "aim private chats" */
+                        00d3
+                         0011 
+                         61 696d 2070 7269 7661 7465 2063 6861 7473
+                        /* unknown -- detail level? */
+                        00d5 
+                         0001 
+                         02
+                        /* "us-ascii" */
+                        00d6
+                         0008
+                         7573 2d61 7363 6969
+                        /* "en" */
+                        00d7
+                         0002 
+                         656e
+                        /* "us-ascii" */ 
+                        00d8 
+                         0008
+                         7573 2d61 7363 6969 
+                        /* "en" */
+                        00d9
+                         0002
+                         656e
+
+/* Create Room (ChatNav) */
+01:25:53.012422 206.165.19.128.61190 > 205.188.4.50.5190: P 403:453(50) ack 1327 win 7434 (DF) (ttl 31, id 5633)
+                        2a02 797b 002c 
+                        000d 0008 0000 0000 9001 
+                        0004 
+
+                        /* "invite**" */
+                        06 69 6e76 6974 65ff ff
+
+                        01 0001 
+
+                        /* "diputs 81 Chat11" */
+                        00d3
+                         0010 
+                         6469 7075 7473 2038 3120 4368 6174 3131
+
+/*  (ChatNav) */
+01:25:53.300102 205.188.4.50.5190 > 206.165.19.128.61190: P 1327:1442(115) ack 453 win 16384 (DF) (ttl 44, id 0)
+                        2a02 5dbe 006d 
+                        000d 0009 0000 0000 9001 
+
+
+                        0004 005f 0004 
+
+                        /* "diputs_81_chat11" */
+                        10 64 6970 7574 735f 3831 5f63 6861 7431 31
+                        00
+                        0002 0007
+
+
+                        /* "diputs 81 Chat11" */
+                        006a
+                        0010
+                         6469 7075 7473 2038 3120 4368 6174 3131 
+                        00c9 
+                         0002
+                         0011
+                        00ca
+                         0004
+                         36fa de16
+                        00d1
+                         0002
+                         0200
+                        00d2
+                         0002
+                         0017
+                        00d3
+                         0010
+                         6469 7075 7473 2038 3120 4368 6174
+                           3131 00d5 0001 02
+
+
+/* Request new service, "diputs_81_chat11" (BOS) */
+01:25:53.315793 206.165.19.128.61187 > 205.188.2.18.5190: P 18:65(47) ack 299 win 8426 (DF) (ttl 31, id 5889)
+                        2a02 7669 0029
+                        0001 0004 0000 0000 000c
+                        000e 0001 0015 
+                        0004
+                        1064 6970 7574 735f 3831 5f63 6861 743131
+                        00 0000 0000 00
+
+/* New service response (BOS) */
+01:25:53.700114 205.188.2.18.5190 > 206.165.19.128.61187: P 299:600(301) ack 65 win 16384 (DF) (ttl 44, id 0)
+                        4500 0155 0000 4000 2c06 9baf cdbc 0212
+                        cea5 1380 1446 ef03 923f e20c 0002 636c
+                        5018 4000 05c8 0000 2a02 c220 0127 0001
+                        0005 0000 0000 000c 000d 0002 000e 0005
+                        000f 3135 322e 3136 332e 3234 312e 3233
+                        3700 0601 00a3 8300 b04a b690 281e bd5c
+                        5b39 99b7 d4da 394e 0db8 1f18 4dab a80c
+                        b59b 2f6f c4e9 72d9 4005 d12f ad16 18da
+                        be6e 0cf3 4e8d 1f19 bb9c 8e06 83f6 49f0
+                        b735 105c 588c d8bf 0988 fb49 416c b010
+                        6e89 9307 1580 6d55 03a5 2b3b 5861 8615
+                        c872 bf8b e567 9034 cdec 243e 6a9f 01d3
+                        8e79 6016 99a8 da57 5838 5f61 81f1 be91
+                        83f0 e4e0 6f0a 8f9b 7943 de45 8f3a f4da
+                        d86c 6ee1 2bf6 0e60 e392 012b 2760 158f
+                        8914 500c 5d6c 4e67 2c04 ef70 1d24 e4b3
+                        3a32 20ae 6381 e920 ab0c d23f 4965 2993
+                        33b9 63bd afca ef90 8f5c 8a54 7704 d42c
+                        d997 07b9 42ff 1326 d998 1526 ad14 0d68
+                        6fba d1a1 1faa 25b5 c797 c67f 01ea ce4c
+                        645b 6cd5 19fb d8fa 89b2 1b12 b9aa be57
+                        1a41 63f0 01
+
+/* Open new connection (Chat) */
+01:25:53.713788 206.165.19.128.61191 > 152.163.241.237.5190: S 197111:197111(0) win 8192 <mss 1460> (DF) (ttl 31, id 6401)
+                        4500 002c 1901 4000 1f06 d614 cea5 1380
+                        98a3 f1ed ef07 1446 0003 01f7 0000 0000
+                        6002 2000 0628 0000 0204 05b4
+
+/* Unknown -- Non-SNAC (Chat) */
+01:25:54.160060 152.163.241.237.5190 > 206.165.19.128.61191: P 1:11(10) ack 1 win 16384 (DF) (ttl 46, id 0)
+                        4500 0032 0000 4000 2e06 e00f 98a3 f1ed
+                        cea5 1380 1446 ef07 daa4 8c02 0003 01f8
+                        5018 4000 00a0 0000 2a01 6c75 0004 0000
+                        0001
+/* Unknown -- Non-SNAC (Chat) */
+01:25:54.172126 206.165.19.128.61191 > 152.163.241.237.5190: P 1:271(270) ack 11 win 8750 (DF) (ttl 31, id 7169)
+                        4500 0136 1c01 4000 1f06 d20a cea5 1380
+                        98a3 f1ed ef07 1446 0003 01f8 daa4 8c0c
+                        5018 222e 2106 0000 2a01 7375 0108 0000
+                        0001 0006 0100 a383 00b0 4ab6 9028 1ebd
+                        5c5b 3999 b7d4 da39 4e0d b81f 184d aba8
+                        0cb5 9b2f 6fc4 e972 d940 05d1 2fad 1618
+                        dabe 6e0c f34e 8d1f 19bb 9c8e 0683 f649
+                        f0b7 3510 5c58 8cd8 bf09 88fb 4941 6cb0
+                        106e 8993 0715 806d 5503 a52b 3b58 6186
+                        15c8 72bf 8be5 6790 34cd ec24 3e6a 9f01
+                        d38e 7960 1699 a8da 5758 385f 6181 f1be
+                        9183 f0e4 e06f 0a8f 9b79 43de 458f 3af4
+                        dad8 6c6e e12b f60e 60e3 9201 2b27 6015
+                        8f89 1450 0c5d 6c4e 672c 04ef 701d 24e4
+                        b33a 3220 ae63 81e9 20ab 0cd2 3f49 6529
+                        9333 b963 bdaf caef 908f 5c8a 5477 04d4
+                        2cd9 9707 b942 ff13 26d9 9815 26ad 140d
+                        686f bad1 a11f aa25 b5c7 97c6 7f01 eace
+                        4c64 5b6c d519 fbd8 fa89 b21b 12b9 aabe
+                        571a 4163 f001
+/* Server Ready (Chat) */
+01:25:54.480077 152.163.241.237.5190 > 206.165.19.128.61191: P 11:31(20) ack 271 win 16384 (DF) (ttl 46, id 0)
+                        4500 003c 0000 4000 2e06 e005 98a3 f1ed
+                        cea5 1380 1446 ef07 daa4 8c0c 0003 0306
+                        5018 4000 5bf8 0000 2a02 6c76 000e 0001
+                        0003 0000 8046 2321 0001 000e
+/* Unknown -- SNAC (Chat) */
+01:25:54.491781 206.165.19.128.61191 > 152.163.241.237.5190: P 271:295(24) ack 31 win 8730 (DF) (ttl 31, id 7425)
+                        4500 0040 1d01 4000 1f06 d200 cea5 1380
+                        98a3 f1ed ef07 1446 0003 0306 daa4 8c20
+                        5018 221a 1605 0000 2a02 7376 0012 0001
+                        0017 0000 0000 000d 000e 0001 0001 0003
+/* Unknown -- SNAC (Chat) */
+01:25:54.700096 152.163.241.237.5190 > 206.165.19.128.61191: P 31:55(24) ack 295 win 16384 (DF) (ttl 46, id 0)
+                        4500 0040 0000 4000 2e06 e001 98a3 f1ed
+                        cea5 1380 1446 ef07 daa4 8c20 0003 031e
+                        5018 4000 5ba5 0000 2a02 6c77 0012 0001
+                        0018 0000 8046 2326 0001 0003 000e 0001
+/* Request Rate Info (Chat) */
+01:25:54.711740 206.165.19.128.61191 > 152.163.241.237.5190: P 295:311(16) ack 55 win 8706 (DF) (ttl 31, id 7681)
+                        4500 0038 1e01 4000 1f06 d108 cea5 1380
+                        98a3 f1ed ef07 1446 0003 031e daa4 8c38
+                        5018 2202 162d 0000 2a02 7377 000a 0001
+                        0006 0000 0000 0000
+/* Rate Info (Chat) */
+01:25:55.290129 152.163.241.237.5190 > 206.165.19.128.61191: P 55:828(773) ack 311 win 16384 (DF) (ttl 46, id 0)
+                        4500 032d 0000 4000 2e06 dd14 98a3 f1ed
+                        cea5 1380 1446 ef07 daa4 8c38 0003 032e
+                        5018 4000 64e8 0000 2a02 6c78 02ff 0001
+                        0007 0000 0000 0000 0005 0001 0000 0050
+                        0000 09c4 0000 07d0 0000 05dc 0000 0320
+                        0000 16e0 0000 1770 0000 0000 0000 0200
+                        0000 5000 000b b800 0007 d000 0005 dc00
+                        0003 e800 0017 7000 0017 7000 0001 b600
+                        0003 0000 0014 0000 13ec 0000 1388 0000
+                        0fa0 0000 0bb8 0000 1770 0000 1770 0000
+                        01b6 0000 0400 0000 1400 0015 7c00 0014
+                        b400 0010 6800 000b b800 0017 7000 001f
+                        4000 0001 b600 0005 0000 000a 0000 157c
+                        0000 14b4 0000 1068 0000 0bb8 0000 1770
+                        0000 1f40 0000 01b6 0000 0100 7f00 0100
+                        0100 0100 0200 0100 0300 0100 0400 0100
+                        0500 0100 0600 0100 0700 0100 0800 0100
+                        0900 0100 0a00 0100 0b00 0100 0c00 0100
+                        0d00 0100 0e00 0100 0f00 0100 1000 0100
+                        1100 0100 1200 0100 1300 0100 1400 0100
+                        1500 0100 1600 0100 1700 0100 1800 0100
+                        1900 0100 1a00 0100 1b00 0100 1c00 0100
+                        1d00 0200 0100 0200 0200 0200 0300 0200
+                        0400 0200 0600 0200 0700 0200 0800 0200
+                        0a00 0200 0c00 0200 0d00 0200 0e00 0200
+                        0f00 0200 1000 0200 1100 0200 1200 0300
+                        0100 0300 0200 0300 0300 0300 0600 0300
+                        0700 0300 0800 0300 0900 0300 0a00 0300
+                        0b00 0300 0c00 0400 0100 0400 0200 0400
+                        0300 0400 0400 0400 0500 0400 0700 0400
+                        0800 0400 0900 0400 0a00 0400 0b00 0400
+                        0c00 0500 0100 0500 0200 0500 0300 0600
+                        0100 0600 0200 0600 0300 0700 0100 0700
+                        0200 0700 0300 0700 0400 0700 0500 0700
+                        0600 0700 0700 0700 0800 0700 0900 0800
+                        0100 0800 0200 0900 0100 0900 0200 0900
+                        0300 0900 0400 0900 0900 0a00 0100 0a00
+                        0200 0a00 0300 0b00 0100 0b00 0200 0b00
+                        0300 0b00 0400 0c00 0100 0c00 0200 0c00
+                        0300 0d00 0100 0d00 0200 0d00 0300 0d00
+                        0400 0d00 0500 0d00 0600 0d00 0700 0d00
+                        0900 0e00 0100 0e00 0200 0e00 0300 0e00
+                        0400 0e00 0600 0e00 0700 0e00 0800 0e00
+                        0900 0e00 0a00 0e00 0b00 0e00 0c00 0f00
+                        0100 0f00 0300 0f00 0400 0f00 0500 1000
+                        0100 1000 0200 1000 0300 1000 0400 1000
+                        0500 1000 0600 1000 0700 0200 0600 0300
+                        0400 0300 0500 0900 0500 0900 0600 0900
+                        0700 0900 0800 0300 0300 0200 0500 0400
+                        0600 0e00 0500 0400 0300 0200 0900 0200
+                        0b00 0f00 0200 0500 0100 0d00 08
+/* Rate Info Ack (Chat) */
+01:25:55.304920 206.165.19.128.61191 > 152.163.241.237.5190: P 311:337(26) ack 828 win 7933 (DF) (ttl 31, id 7937)
+                        2a02 7378 0014 0001
+                        0008 0000 0000 0000 0001 0002 0003 0004
+                        0005
+/* Invite "midendian" (BOS) */
+01:25:55.309173 206.165.19.128.61187 > 205.188.2.18.5190: P 65:197(132) ack 600 win 8125 (DF) (ttl 31, id 8193)
+                        2a02 766a 007e 0004
+                        0006 0000 0000 8000 3330 3833 3100 0000
+                        0002 096d 6964 656e 6469 616e 0005 005c
+                        0000 3330 3833 3100 0000 748f 2420 6287
+                        11d1 8222 4445 5354 0000 000a 0002 0001
+                        000f 0000 000c 001b 4a6f 696e 206d 6520
+                        696e 2074 6869 7320 4275 6464 7920 4368
+                        6174 2e27 1100 1500 0410 6469 7075 7473
+                        5f38 315f 6368 6174 3131 0000
+/* Error [Client doesn't support chat] (BOS) */
+01:25:55.600095 205.188.2.18.5190 > 206.165.19.128.61187: P 600:618(18) ack 197 win 16384 (DF) (ttl 44, id 0)
+                        2a02 c221 000c 0004
+                        0001 0000 0000 8000 0009
+/* Client Ready (Chat) */
+01:25:55.711170 206.165.19.128.61191 > 152.163.241.237.5190: P 337:369(32) ack 828 win 7933 (DF) (ttl 31, id 8449)
+                        2a02 7379 001a 0001
+                        0002 0000 0000 000e 000e 0001 0004 0001
+                        0001 0003 0004 03e4
+/* User Joined Notification (Chat) */
+01:25:56.020082 152.163.241.237.5190 > 206.165.19.128.61191: P 828:1049(221) ack 369 win 16384 (DF) (ttl 46, id 0)
+                        2a02 6c79 0034 000e
+                        0003 0000 8046 2357 0964 6970 7574 7320
+                        3831 0000 0004 0001 0002 0010 0002 0004
+                        35c7 bf17 0003 0004 36fa de17 0004 0002
+                        0000 2a02 6c7a 009d 000e 0002 0000 8046
+                        2358 0004 1064 6970 7574 735f 3831 5f63
+                        6861 7431 3100 0002 0009 006a 0010 6469
+                        7075 7473 2038 3120 4368 6174 3131 006f
+                        0002 0001 0073 002a 0964 6970 7574 7320
+                        3831 0000 0004 0001 0002 0010 0002 0004
+                        35c7 bf17 0003 0004 36fa de17 0004 0002
+                        0000 00c9 0002 0011 00ca 0004 36fa de16
+                        00d1 0002 0200 00d2 0002 0017 00d3 0010
+                        6469 7075 7473 2038 3120 4368 6174 3131
+                        00d5 0001 02
diff --git a/tcpdumps/newim.txt b/tcpdumps/newim.txt
new file mode 100644 (file)
index 0000000..a02544d
--- /dev/null
@@ -0,0 +1,34 @@
+
+2a02 1e99 0060 
+0004 0006 0000 0000 8000 
+
+3142 3738 4300 ffff
+0001 
+
+096d 6964 656e 6469 616e 
+
+0003 0000
+0002 003a 0501 0003 01 01 01 01 01
+
+002f 00
+0000 00
+
+  3c 4854 4d4c 3e3c 424f 4459 2042
+4743 4f4c 4f52 3d22 2366 6666 6666 6622
+3e6a 6173 6b66 733c 2f48 544d 4c3e
+
+
+
+
+
+
+        *=2a 0x 2 0x 0 0x b 0x 0 F=46 0x 0 0x 4
+        0x 0 0x 6 0x 0 0x 0 0x 0 0x 0 0x 0 0x 9
+        0x 0 0x 0 0x 0 0x 0 0x 0 0x 0 0x 0 0x 0
+        0x 0 0x 1 0x 6 m=6d i=69 d=64 g=67 o=6f
+        d=64 0x 0 0x 3 0x 0 0x 0 0x 0 0x 2 0x 0
+        #=23 0x 5 0x 1 0x 0 0x 1 0x 1 0x 1 0x 1
+        0x 1 0x 1 0x 0 0x18 0x 0 0x 0 0x 0 0x 0
+        G=47 o=6f o=6f d=64  =20 d=64 a=61 y=79
+         =20 t=74 o=6f  =20 y=79 o=6f u=75  =20
+        t=74 o=6f o=6f .=2e
diff --git a/tcpdumps/permitdeny.txt b/tcpdumps/permitdeny.txt
new file mode 100644 (file)
index 0000000..236aff5
--- /dev/null
@@ -0,0 +1,44 @@
+
+-----------------------------
+"Allow only the users below"
+  - midendian
+  - midguru
+
+       2a02 3b8a 001c 
+       0009 0005 0000 0000 0000 
+         09 6d69 6465 6e64 6961 6e 
+         07 6d69 6467 7572 75
+
+----------------------------
+"Allow all users to contact me" (logged on as midguru)
+
+ 2a02 3b8d 0012 
+ 0009 0007 0000 0000 0000 
+   07 6d69 6467 7572 75
+
+----------------------------
+"Allow only users on my buddy list" 
+
+
+ 2a02 3b8f 0062 0009
+                         0005 0000 0000 0000 0a4d 6f6f 6e50 5374
+                         6163 6509 6d69 6465 6e64 6961 6e08 5475
+                         6a69 6361 7431 0954 6865 4f72 6254 776f
+                         0a67 726f 6b20 6c69 6e75 7808 6569 6e6d
+                         6f72 6f6e 0864 6970 7574 7338 310a 636c
+                         6172 696e 6574 3137 074d 6964 4775 7275
+
+---------------------------
+"Block all users"
+
+Sending a 0009/0005 with only yourself on it blocks everyone (but yourself).
+
+---------------------------
+"Block the users below"
+  -midendian
+  -midguru
+
+ 2a02 3b94 001c 0009
+                         0007 0000 0000 0000 096d 6964 656e 6469
+                         616e 076d 6964 6775 7275
+
diff --git a/utils/Makefile b/utils/Makefile
new file mode 100644 (file)
index 0000000..ae11c4e
--- /dev/null
@@ -0,0 +1,20 @@
+include Makefile.dynamicrules
+
+UTIL_DIRS = faimtest #aimpasswd
+
+utils_all: 
+       @dirs='$(UTIL_DIRS)'; \
+       for i in $$dirs; do \
+         cd $$i; \
+         make; \
+         cd ..; \
+       done; 
+
+clean:
+       @dirs='$(UTIL_DIRS)'; \
+       for i in $$dirs; do \
+         cd $$i; \
+         make clean; \
+         cd ..; \
+       done;
+       @rm -f Makefile.dynamicrules
diff --git a/utils/aimpasswd/Makefile b/utils/aimpasswd/Makefile
new file mode 100644 (file)
index 0000000..3eee422
--- /dev/null
@@ -0,0 +1,12 @@
+include ../Makefile.dynamicrules
+include $(LIBFAIM_LIB)/Makefile.rules
+
+EXEC_NAME = aimpasswd
+EXEC_OBJECTS = \
+       aimpasswd.o
+
+all: $(EXEC_OBJECTS)
+       $(CC) $(CFLAGS) -o $(EXEC_NAME) $(EXEC_OBJECTS) $(LDFLAGS)
+
+clean:
+       rm -f $(EXEC_OBJECTS) $(EXEC_NAME)
diff --git a/utils/aimpasswd/aimpasswd.c b/utils/aimpasswd/aimpasswd.c
new file mode 100644 (file)
index 0000000..b42c214
--- /dev/null
@@ -0,0 +1,246 @@
+/* 
+ * aimpasswd.c -- Change AIM password without logging in.
+ * 
+ * Defintly not done yet.
+ *
+ * TODO: Make this work.
+ *
+ *  -----------------------------------------------------------
+ *
+ *  I'm releasing this code and all it's associated linkage
+ *  under the GNU General Public License.  For more information,
+ *  please refer to http://www.fsf.org.  For any questions,
+ *  please contact me at the address below.
+ *
+ *  (c) 1998/99 Adam Fritzler, PST, afritz@iname.com
+ *
+ *  -----------------------------------------------------------
+ *
+ */
+
+/*
+  Current status:
+
+
+ */
+
+#include "aim.h" /* for struct defs, global ptrs, etc */
+
+int faimtest_parse_oncoming(struct command_rx_struct *, ...);
+int faimtest_parse_offgoing(struct command_rx_struct *, ...);
+int faimtest_parse_login_phase3d_f(struct command_rx_struct *, ...);
+int faimtest_auth_error(struct command_rx_struct *, ...);
+int faimtest_auth_success(struct command_rx_struct *, ...);
+int faimtest_parse_incoming_im(struct command_rx_struct *command, ...);
+int faimtest_parse_userinfo(struct command_rx_struct *command, ...);
+int faimtest_handleredirect(struct command_rx_struct *command, ...);
+int faimtest_authsvrready(struct command_rx_struct *command, ...);
+int faimtest_pwdchngdone(struct command_rx_struct *command, ...);
+int faimtest_serverready(struct command_rx_struct *command, ...);
+
+int bleu(struct command_rx_struct *blah, ...)
+{
+  return -1;
+}
+
+int main(void)
+{
+  /*
+    specify your custom command handlers here.  I recommend
+    at least overriding the login_phase3d_f handler so that
+    you can have your own buddy list and profile.  The
+    rest are probably only useful to override for UI
+    reasons.
+   */
+  rxcallback_t faimtest_callbacks[] = {
+    bleu, /* incoming IM */
+    bleu, /* oncoming buddy */
+    bleu, /* offgoing buddy */
+    NULL, /* last IM was missed 1 */
+    NULL, /* last IM was missed 2 */
+    NULL, /* login phase 4 packet C command 1 -- depricated */
+    NULL, /* login phase 4 packet C command 2 -- depricated */
+    NULL, /* login phase 2, first resp -- depricated */
+    faimtest_serverready, /* server ready -- **HANDLING REQUIRED** */
+    NULL, /* login phase 3 packet B -- depricated */
+    NULL, /* login phase 3D packet A -- depricated */
+    NULL, /* login phase 3D packet B -- depricated */
+    NULL, /* login phase 3D packet C -- depricated */
+    NULL, /* login phase 3D packet D -- depricated */
+    NULL, /* login phase 3D packet E -- depricated */
+    faimtest_handleredirect, /* redirect -- **HANDLING REQUIRED** */
+    NULL, /* last command bad */
+    NULL, /* missed some messages */
+    NULL, /* completely unknown command */
+    bleu, /* user info response */
+    NULL, /* user search by address response */
+    NULL, /* user serach by name response */
+    NULL, /* user search fail */
+    faimtest_auth_error,
+    faimtest_auth_success,
+    faimtest_authsvrready,
+    NULL,
+    faimtest_pwdchngdone,
+    faimtest_serverready,
+    0x00 /* terminating NULL -- REQUIRED */
+  };
+
+  aim_connrst(); /* reset connection array -- there's a better place for this*/
+  /* register our callback array (optional) */
+  aim_register_callbacks(faimtest_callbacks);
+
+
+  //aim_login("a275081780", "1Fritz");  /* not real password :) */
+  aim_login("diputs 81", "1Fritz");
+  while (aim_select(NULL) > (struct aim_conn_t *)0)
+    {
+      if (aim_get_command() < 0)
+       {
+         printf("\afaimtest: connection error!\n");
+       }
+      else
+       aim_rxdispatch();
+    }
+
+  /* Close up */
+  printf("AIM just decided we didn't need to be here anymore, closing up.,,\n");
+  
+  /* close up all connections, dead or no */
+  aim_logoff(); 
+
+  /* Get out */
+  exit(0);
+}
+
+int faimtest_serverready(struct command_rx_struct *command, ...)
+{
+  switch (command->conn->type)
+    {
+    case AIM_CONN_TYPE_BOS:
+      printf("requesting AUTH service\n");
+      aim_bos_reqservice(command->conn, 0x0007);
+      break;
+    default:
+      fprintf(stderr, "faimtest: unknown connection type on Server Ready\n");
+    }
+  return 0;
+}
+
+/*
+  handleredirect()...
+
+  This, of course, handles Service Redirects from OSCAR.
+
+  Should get passed in the following:
+     struct command_rx_struct *command
+       the raw command data
+     int serviceid
+       the destination service ID
+     char *serverip
+       the IP address of the service's server
+     char *cookie
+       the raw auth cookie
+ */
+int faimtest_handleredirect(struct command_rx_struct *command, ...)
+{
+  va_list ap;
+  int serviceid;
+  char *ip;
+  char *cookie;
+
+  va_start(ap, command);
+  serviceid = va_arg(ap, int);
+  ip = va_arg(ap, char *);
+  cookie = va_arg(ap, char *);
+  va_end(ap);
+
+  switch(serviceid)
+    {
+    case 0x0007: /* Authorizer */
+      {
+       struct aim_conn_t *tstconn;
+       /* Open a connection to the Auth */
+       tstconn = aim_newconn(AIM_CONN_TYPE_AUTH, ip);
+       /* Send the cookie to the Auth */
+       aim_auth_sendcookie(tstconn, cookie);
+      }  
+      break;
+    default:
+      printf("uh oh... got redirect for unknown service 0x%04x!!\n", serviceid);
+      /* dunno */
+    }
+
+  return 0;
+}
+
+int faimtest_auth_error(struct command_rx_struct *command, ...)
+{
+  va_list ap;
+  struct login_phase1_struct *logininfo;
+  char *errorurl;
+  short errorcode;
+
+  va_start(ap, command);
+  logininfo = va_arg(ap, struct login_phase1_struct *);
+  printf("Screen name: %s\n", logininfo->screen_name);
+  errorurl = va_arg(ap, char *);
+  printf("Error URL: %s\n", errorurl);
+  errorcode = va_arg(ap, short);
+  printf("Error code: 0x%02x\n", errorcode);
+  va_end(ap);
+
+  aim_conn_close(aim_getconn_type(AIM_CONN_TYPE_AUTH));
+  exit(0);
+  
+  return 0;
+}
+
+int faimtest_auth_success(struct command_rx_struct *command, ...)
+{
+  va_list ap;
+  struct login_phase1_struct *logininfo;
+  struct aim_conn_t *bosconn = NULL;
+
+  va_start(ap, command);
+  logininfo = va_arg(ap, struct login_phase1_struct *);
+  va_end(ap);
+  
+  printf("Screen name: %s\n", logininfo->screen_name);
+  printf("Reg status: %2d\n", logininfo->regstatus);
+  printf("Email: %s\n", logininfo->email);
+  printf("Cookie len: %d\n", sizeof(logininfo->cookie));
+  printf("BOS IP: %s\n", logininfo->BOSIP);
+
+  printf("Closing auth connection...\n");
+  aim_conn_close(command->conn);
+  bosconn = aim_newconn(AIM_CONN_TYPE_BOS, logininfo->BOSIP);
+  aim_auth_sendcookie(bosconn, logininfo->cookie);
+
+  return 0;
+}
+
+int faimtest_authsvrready(struct command_rx_struct *command, ...)
+{
+  /* should just be able to tell it we're ready too... */
+  aim_auth_clientready(command->conn);
+
+  /*
+   * This is where you'd really begin changing your password.
+   *   However, this callback may get called for reasons other
+   *   than you wanting to change your password.  You should 
+   *   probably check that before actually doing it.
+   */
+  //aim_auth_changepasswd(command->conn, "Fritz", "1Fritz");
+
+  return 0;
+}
+
+int faimtest_pwdchngdone(struct command_rx_struct *command, ...)
+{
+  printf("PASSWORD CHANGE SUCCESSFUL!!!\n");
+  return 0;
+}
+
+
+
+
diff --git a/utils/faimtest/Makefile b/utils/faimtest/Makefile
new file mode 100644 (file)
index 0000000..d5187c6
--- /dev/null
@@ -0,0 +1,12 @@
+include ../Makefile.dynamicrules
+include $(LIBFAIM_LIB)/Makefile.rules
+
+EXEC_NAME = faimtest
+EXEC_OBJECTS = \
+       faimtest.o
+
+all: $(EXEC_OBJECTS)
+       $(CC) $(CFLAGS) -o $(EXEC_NAME) $(EXEC_OBJECTS) $(LDFLAGS)
+
+clean:
+       rm -f $(EXEC_OBJECTS) $(EXEC_NAME)
diff --git a/utils/faimtest/faimtest.c b/utils/faimtest/faimtest.c
new file mode 100644 (file)
index 0000000..5ac38c2
--- /dev/null
@@ -0,0 +1,614 @@
+/* 
+ *  -----------------------------------------------------------
+ *  ProtoFAIM: v1.xx.xxplxx
+ *  -----------------------------------------------------------
+ *
+ *  This is ProtoFAIM v1.xx.xxplxx!!! Its nearly completely 
+ *  different than that ugly thing called v0.  This app is
+ *  compatible with the latest version of the libfaim library.
+ *  Work is continuing. 
+ *
+ *  ProtoFAIM should only be used for two things...
+ *   1) Testing the libfaim backend.
+ *   2) For reference on the libfaim API when developing clients.
+ * 
+ *  Its very ugly.  Probably always will be.  Nothing is more
+ *  ugly than the backend itself, however.
+ *
+ *  -----------------------------------------------------------
+ *
+ *  I'm releasing this code and all it's associated linkage
+ *  under the GNU General Public License.  For more information,
+ *  please refer to http://www.fsf.org.  For any questions,
+ *  please contact me at the address below.
+ *
+ *  Most everything:
+ *  (c) 1998 Adam Fritzler, PST, afritz@iname.com
+ *
+ *  The password algorithms
+ *  (c) 1998 Brock Wilcox, awwaiid@iname.com
+ *
+ *  THERE IS NO CODE FROM AOL'S AIM IN THIS CODE, NOR
+ *  WAS THERE ANY DISASSEMBLAGE TO DEFINE PROTOCOL.  All
+ *  information was gained through painstakingly comparing
+ *  TCP dumps while the AIM Java client was running.  Nothing
+ *  more than that, except for a lot of experimenting.
+ *
+ *  -----------------------------------------------------------
+ *
+ */
+
+/*
+  Current status:
+
+
+ */
+
+#define FAIMTEST_SCREENNAME "SN"
+#define FAIMTEST_PASSWORD "PASS"
+
+#include "aim.h" /* for struct defs, global ptrs, etc */
+
+int faimtest_parse_oncoming(struct command_rx_struct *, ...);
+int faimtest_parse_offgoing(struct command_rx_struct *, ...);
+int faimtest_parse_login_phase3d_f(struct command_rx_struct *, ...);
+int faimtest_auth_error(struct command_rx_struct *, ...);
+int faimtest_auth_success(struct command_rx_struct *, ...);
+int faimtest_parse_incoming_im(struct command_rx_struct *command, ...);
+int faimtest_parse_userinfo(struct command_rx_struct *command, ...);
+int faimtest_handleredirect(struct command_rx_struct *command, ...);
+int faimtest_authsvrready(struct command_rx_struct *command, ...);
+int faimtest_pwdchngdone(struct command_rx_struct *command, ...);
+int faimtest_serverready(struct command_rx_struct *command, ...);
+int faimtest_parse_misses(struct command_rx_struct *command, ...);
+int main(void)
+{
+
+#if 0
+  /*
+    specify your custom command handlers here.  I recommend
+    at least overriding the login_phase3d_f handler so that
+    you can have your own buddy list and profile.  The
+    rest are probably only useful to override for UI
+    reasons.
+   */
+  rxcallback_t faimtest_callbacks[] = {
+    faimtest_parse_incoming_im, /* incoming IM 0 */
+    faimtest_parse_oncoming, /* oncoming buddy 1 */
+    faimtest_parse_offgoing, /* offgoing buddy 2 */
+    faimtest_parse_misses, /* AIM_CB_MISSED_IM 3 */
+    faimtest_parse_misses, /* AIM_CB_MISSED_CALL 4 */
+    NULL, /* login phase 4 packet C command 1 -- depricated 5 */
+    NULL, /* login phase 4 packet C command 2 -- depricated 6 */
+    NULL, /* login phase 2, first resp -- depricated 7 */
+    faimtest_serverready, /* server ready -- **HANDLING REQUIRED** 8 */
+    NULL, /* login phase 3 packet B -- depricated 9 */
+    NULL, /* login phase 3D packet A -- depricated 10 */
+    NULL, /* login phase 3D packet B -- depricated 11 */
+    NULL, /* login phase 3D packet C -- depricated 12 */
+    NULL, /* login phase 3D packet D -- depricated 13 */
+    NULL, /* login phase 3D packet E -- depricated 14 */
+    faimtest_handleredirect, /* redirect -- **HANDLING REQUIRED** 15 */
+    faimtest_parse_misses, /* AIM_CB_RATECHANGE 16 */
+    faimtest_parse_misses, /* AIM_CB_USERERROR 17 */
+    NULL, /* completely unknown command 18 */
+    faimtest_parse_userinfo, /* user info response 19 */
+    NULL, /* user search by address response 20 */
+    NULL, /* user serach by name response 21 */
+    NULL, /* user search fail 22 */
+    faimtest_auth_error, /* 23 */
+    faimtest_auth_success, /* 24 */
+    faimtest_authsvrready, /* 25 */
+    NULL, /* 26 */
+    faimtest_pwdchngdone, /* 27 */
+    faimtest_serverready, /* 28 */
+    0x00 /* terminating NULL -- REQUIRED 29 */
+  };
+#endif
+
+  struct client_info_s info = {"FAIMtest (Hi guys!)", 3, 90, 42, "us", "en"};
+  struct aim_conn_t *authconn = NULL;
+  int stayconnected = 1;
+  
+  aim_connrst(); /* reset connection array -- there's a better place for this*/
+  /* register our callback array (optional) */
+  //aim_register_callbacks(faimtest_callbacks);
+
+ enter:
+  authconn = aim_newconn(AIM_CONN_TYPE_AUTH, FAIM_LOGIN_SERVER);
+                      
+  if (authconn == NULL)
+    {
+      fprintf(stderr, "faimtest: internal connection error while in aim_login.  bailing out.\n");
+      return -1;
+    }
+  else if (authconn->fd == -1)
+    {
+      if (authconn->status & AIM_CONN_STATUS_RESOLVERR)
+       fprintf(stderr, "faimtest: could not resolve authorizer name\n");
+      else if (authconn->status & AIM_CONN_STATUS_CONNERR)
+       fprintf(stderr, "faimtest: could not connect to authorizer\n");
+      return -1;
+    }
+  else
+    {
+      aim_conn_addhandler(authconn, AIM_CB_FAM_GEN, AIM_CB_GEN_ERROR, faimtest_auth_error, 0);
+      aim_conn_addhandler(authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHSUCCESS, faimtest_auth_success, 0);
+      aim_conn_addhandler(authconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, faimtest_authsvrready, 0);
+      aim_send_login(authconn, FAIMTEST_SCREENNAME, FAIMTEST_PASSWORD, &info);
+    }
+
+  while (aim_select(NULL) > (struct aim_conn_t *)0)
+    {
+      if (aim_queue_outgoing)
+       aim_tx_flushqueue();
+
+      if (aim_get_command() < 0)
+       {
+         printf("\afaimtest: connection error!\n");
+       }
+      else
+       aim_rxdispatch();
+    }
+
+  /* Close up */
+  printf("AIM just decided we didn't need to be here anymore, closing up.,,\n");
+  
+  /* close up all connections, dead or no */
+  aim_logoff(); 
+
+  if (stayconnected)
+    {
+      printf("\nTrying to reconnect in 2 seconds...\n");
+      sleep(2);
+      goto enter;
+    }
+
+  /* Get out */
+  exit(0);
+}
+
+int faimtest_serverready(struct command_rx_struct *command, ...)
+{
+  switch (command->conn->type)
+    {
+    case AIM_CONN_TYPE_BOS:
+      aim_bos_reqrate(command->conn); /* request rate info */
+      aim_bos_ackrateresp(command->conn);  /* ack rate info response -- can we say timing? */
+      aim_bos_setprivacyflags(command->conn, 0x00000003);
+      
+#if 0
+      aim_bos_reqpersonalinfo(command->conn);
+#endif
+      
+      aim_bos_reqservice(command->conn, AIM_CONN_TYPE_ADS); /* 0x05 == Advertisments */
+
+#if 0
+      aim_bos_reqrights(NULL);
+      aim_bos_reqbuddyrights(NULL);
+      aim_bos_reqlocaterights(NULL);
+      aim_bos_reqicbmparaminfo(NULL);
+#endif
+      
+      /* set group permissions */
+      aim_bos_setgroupperm(NULL, 0x1f);
+      fprintf(stderr, "faimtest: done with BOS ServerReady\n");
+      break;
+    case AIM_CONN_TYPE_CHATNAV:
+      fprintf(stderr, "faimtest: chatnav: got server ready\n");
+      break;
+    default:
+      fprintf(stderr, "faimtest: unknown connection type on Server Ready\n");
+    }
+  return 1;
+}
+
+/*
+  handleredirect()...
+
+  This, of course, handles Service Redirects from OSCAR.
+
+  Should get passed in the following:
+     struct command_rx_struct *command
+       the raw command data
+     int serviceid
+       the destination service ID
+     char *serverip
+       the IP address of the service's server
+     char *cookie
+       the raw auth cookie
+ */
+int faimtest_handleredirect(struct command_rx_struct *command, ...)
+{
+  va_list ap;
+  int serviceid;
+  char *ip;
+  char *cookie;
+
+  /* this is the new buddy list */
+  char buddies[] = "Buddy1&Buddy2&";
+  /* this is the new profile */
+  char profile[] = "Hello";  
+
+  va_start(ap, command);
+  serviceid = va_arg(ap, int);
+  ip = va_arg(ap, char *);
+  cookie = va_arg(ap, char *);
+  va_end(ap);
+
+  switch(serviceid)
+    {
+    case 0x0005: /* Advertisements */
+      /*
+       * The craziest explanation yet as to why we finish logging in when
+       * we get the advertisements redirect, of which we don't use anyway....
+       *                    IT WAS EASY!
+       */
+
+      /* send the buddy list and profile (required, even if empty) */
+      aim_bos_setbuddylist(command->conn, buddies);
+      aim_bos_setprofile(command->conn, profile);
+
+      /* send final login command (required) */
+      aim_bos_clientready(command->conn); /* tell BOS we're ready to go live */
+
+      /* you should now be ready to go */
+      printf("\nYou are now officially online. (%s)\n", ip);      
+
+      break;
+    case 0x0007: /* Authorizer */
+      {
+       struct aim_conn_t *tstconn;
+       /* Open a connection to the Auth */
+       tstconn = aim_newconn(AIM_CONN_TYPE_AUTH, ip);
+       if ( (tstconn==NULL) || (tstconn->status >= AIM_CONN_STATUS_RESOLVERR) )
+         fprintf(stderr, "faimtest: unable to reconnect with authorizer\n");
+       else
+         /* Send the cookie to the Auth */
+         aim_auth_sendcookie(tstconn, cookie);
+
+      }  
+      break;
+    case 0x000d: /* ChatNav */
+      {
+       struct aim_conn_t *tstconn = NULL;
+       tstconn = aim_newconn(AIM_CONN_TYPE_CHATNAV, ip);
+       if ( (tstconn==NULL) || (tstconn->status >= AIM_CONN_STATUS_RESOLVERR))
+         {
+           fprintf(stderr, "faimtest: unable to connect to chatnav server\n");
+           return 1;
+         }
+       aim_conn_addhandler(tstconn, AIM_CB_FAM_CTN, AIM_CB_SPECIAL_DEFAULT, aim_parse_unknown, 0);
+       aim_conn_addhandler(tstconn, AIM_CB_FAM_GEN, AIM_CB_SPECIAL_DEFAULT, aim_parse_unknown, 0);
+       aim_auth_sendcookie(tstconn, cookie);
+       fprintf(stderr, "\achatnav: connected\n");
+      }
+      break;
+    case 0x000e: /* Chat */
+      {
+#if 0
+       struct aim_conn_t *tstconn = NULL;
+       tstconn = aim_newconn(AIM_CONN_TYPE_CHAT, ip);
+       if ( (tstconn==NULL) || (tstconn->status >= AIM_CONN_STATUS_RESOLVERR))
+         {
+           fprintf(stderr, "faimtest: unable to connect to chat server\n");
+           return 1;
+         }
+       aim_auth_sendcookie(aim_getconn_type(AIM_CONN_TYPE_CHAT), cookie);
+       fprintf(stderr, "\achat: connected\n");
+#endif
+      }
+      break;
+    default:
+      printf("uh oh... got redirect for unknown service 0x%04x!!\n", serviceid);
+      /* dunno */
+    }
+
+  return 1;
+}
+
+int faimtest_auth_error(struct command_rx_struct *command, ...)
+{
+  va_list ap;
+  struct login_phase1_struct *logininfo;
+  char *errorurl;
+  short errorcode;
+
+  va_start(ap, command);
+  logininfo = va_arg(ap, struct login_phase1_struct *);
+  printf("Screen name: %s\n", logininfo->screen_name);
+  errorurl = va_arg(ap, char *);
+  printf("Error URL: %s\n", errorurl);
+  errorcode = va_arg(ap, short);
+  printf("Error code: 0x%02x\n", errorcode);
+  va_end(ap);
+
+  aim_conn_close(aim_getconn_type(AIM_CONN_TYPE_AUTH));
+  exit(0);
+  
+  return 0;
+}
+
+int faimtest_auth_success(struct command_rx_struct *command, ...)
+{
+  va_list ap;
+  struct login_phase1_struct *logininfo;
+  struct aim_conn_t *bosconn = NULL;
+
+  va_start(ap, command);
+  logininfo = va_arg(ap, struct login_phase1_struct *);
+  va_end(ap);
+  
+  printf("Screen name: %s\n", logininfo->screen_name);
+  printf("Reg status: %2d\n", logininfo->regstatus);
+  printf("Email: %s\n", logininfo->email);
+  printf("Cookie len: %d\n", sizeof(logininfo->cookie));
+  printf("BOS IP: %s\n", logininfo->BOSIP);
+
+  printf("Closing auth connection...\n");
+  aim_conn_close(command->conn);
+  bosconn = aim_newconn(AIM_CONN_TYPE_BOS, logininfo->BOSIP);
+  if (bosconn == NULL)
+    {
+      fprintf(stderr, "faimtest: could not connect to BOS: internal error\n");
+    }
+  else if (bosconn->status != 0)
+    {
+      fprintf(stderr, "faimtest: could not connect to BOS\n");
+    }
+  else
+    {
+      aim_conn_addhandler(bosconn, AIM_CB_FAM_ACK, AIM_CB_ACK_ACK, NULL, 0);
+      aim_conn_addhandler(bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, faimtest_serverready, 0);
+      aim_conn_addhandler(bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATEINFO, NULL, 0);
+      aim_conn_addhandler(bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT, faimtest_handleredirect, 0);
+      aim_conn_addhandler(bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, NULL, 0);
+      aim_conn_addhandler(bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL, NULL, 0);
+      aim_conn_addhandler(bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING, faimtest_parse_oncoming, 0);
+      aim_conn_addhandler(bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING, faimtest_parse_offgoing, 0);
+      aim_conn_addhandler(bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0);
+      aim_conn_addhandler(bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR, faimtest_parse_misses, 0);
+      aim_conn_addhandler(bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL, faimtest_parse_misses, 0);
+      aim_conn_addhandler(bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE, faimtest_parse_misses, 0);
+      aim_conn_addhandler(bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR, faimtest_parse_misses, 0);
+      aim_conn_addhandler(bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, faimtest_parse_userinfo, 0);
+
+      aim_conn_addhandler(bosconn, AIM_CB_FAM_CTN, AIM_CB_CTN_DEFAULT, aim_parse_unknown, 0);
+      aim_conn_addhandler(bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEFAULT, aim_parse_unknown, 0);
+      aim_auth_sendcookie(bosconn, logininfo->cookie);
+    }
+  return 1;
+}
+
+int faimtest_parse_userinfo(struct command_rx_struct *command, ...)
+{
+  struct aim_userinfo_s *userinfo;
+  char *prof_encoding = NULL;
+  char *prof = NULL;
+
+  va_list ap;
+  va_start(ap, command);
+  userinfo = va_arg(ap, struct aim_userinfo_s *);
+  prof_encoding = va_arg(ap, char *);
+  prof = va_arg(ap, char *);
+  va_end(ap);
+  
+  printf("faimtest: userinfo: sn: %s\n", userinfo->sn);
+  printf("faimtest: userinfo: warnlevel: 0x%04x\n", userinfo->warnlevel);
+  printf("faimtest: userinfo: class: 0x%04x = ", userinfo->class);
+
+  /*
+   *  00000000  (binary)
+   *         1  Trial  
+   *        2   Unknown
+   *       3    AOL
+   *      4     Unknown
+   *     5      Free
+   * 
+   * ORed together.
+   *
+   */
+
+  if (userinfo->class & 0x0001)
+    printf("TRIAL ");
+  if (userinfo->class & 0x0002)
+    printf("UNKNOWN_BIT2 ");
+  if (userinfo->class & 0x0004)
+    printf("AOL ");
+  if (userinfo->class & 0x0008)
+    printf("UNKNOWN_BIT4 ");
+  if (userinfo->class & 0x0010)
+    printf("FREE ");
+  printf("\n");
+  
+  printf("faimtest: userinfo: membersince: %lu\n", userinfo->membersince);
+  printf("faimtest: userinfo: onlinesince: %lu\n", userinfo->onlinesince);
+  printf("faimtest: userinfo: idletime: 0x%04x\n", userinfo->idletime);
+  
+  printf("faimtest: userinfo: profile_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
+  printf("faimtest: userinfo: prof: %s\n", prof ? prof : "[none]");
+  
+  return 1;
+}
+
+/*
+ * The user-level Incoming ICBM callback.
+ *
+ * Arguments:
+ *  struct command_rx_struct *  command     if you feel like doing it yourself
+ *  char *                      srcsn       the source name
+ *  char *                      msg         message
+ *  int                         warnlevel   warning/evil level
+ *  int                         class       user class
+ *  ulong                       membersince time_t of date of signup
+ *  ulong                       onsince     time_t of date of singon
+ *  int                         idletime    min (sec?) idle
+ *  int                         isautoreply TRUE if its an auto-response
+ *
+ */
+int faimtest_parse_incoming_im(struct command_rx_struct *command, ...)
+{
+  struct aim_userinfo_s *userinfo;
+  char *msg = NULL;
+  int isautoreply = 0;
+  va_list ap;
+  char *tmpstr = NULL;
+
+  va_start(ap, command);
+  userinfo = va_arg(ap, struct aim_userinfo_s *);
+  msg = va_arg(ap, char *);
+  isautoreply = va_arg(ap, int);
+  va_end(ap);
+
+  printf("faimtest: icbm: sn = \"%s\"\n", userinfo->sn);
+  printf("faimtest: icbm: warnlevel = 0x%04x\n", userinfo->warnlevel);
+  printf("faimtest: icbm: class = 0x%04x ", userinfo->class);
+  if (userinfo->class & 0x0010)
+    printf("(FREE)\n");
+  else if (userinfo->class & 0x0001)
+    printf("(TRIAL)\n");
+  else if (userinfo->class & 0x0004)
+    printf("(AOL)\n");
+  else
+    printf("(UNKNOWN)\n");
+  printf("faimtest: icbm: membersince = %lu\n", userinfo->membersince);
+  printf("faimtest: icbm: onlinesince = %lu\n", userinfo->onlinesince);
+  printf("faimtest: icbm: idletime = 0x%04x\n", userinfo->idletime);
+  printf("faimtest: icbm: isautoreply = %s\n", isautoreply ? "TRUE" : "FALSE");  
+
+  printf("faimtest: icbm: message: %s\n", msg);
+
+  if (msg)
+    {
+      tmpstr = index(msg, '>');
+      if (tmpstr != NULL)
+       tmpstr+=1;
+      else
+       tmpstr = msg;
+      
+      if ( (strlen(tmpstr) >= 10) &&
+          (!strncmp(tmpstr, "disconnect", 10)) )
+       {
+         aim_send_im(command->conn, "midendian", 0, "ta ta...");
+         aim_logoff();
+       }
+      else if (strstr(tmpstr, "goodday"))
+       {
+         printf("faimtest: icbm: sending response\n");
+         aim_send_im(command->conn, userinfo->sn, 0, "Good day to you too.");
+       }
+#if 0
+      else if (!strncmp(tmpstr, "joinchat", 8))
+       {
+         aim_chat_join(command->conn, "GoodDay");
+       }
+#endif
+      else 
+       {
+#if 0
+         printf("faimtest: icbm:  starting chat...\n");
+         aim_bos_reqservice(command->conn, AIM_CONN_TYPE_CHATNAV);
+#else
+         aim_bos_setidle(command->conn, 0x0ffffffe);
+#endif
+       }
+
+    }
+
+  printf("faimtest: icbm: done with ICBM handling\n");
+
+  return 1;
+}
+
+int faimtest_authsvrready(struct command_rx_struct *command, ...)
+{
+  printf("faimtest_authsvrready: called (contype: %d)\n", command->conn->type);
+  sleep(10);
+  /* should just be able to tell it we're ready too... */
+  aim_auth_clientready(command->conn);
+
+#if 0
+  /*
+   * This is where you'd really begin changing your password.
+   *   However, this callback may get called for reasons other
+   *   than you wanting to change your password.  You should 
+   *   probably check that before actually doing it.
+   */
+  aim_auth_changepasswd(command->conn, "PWD1", "PWD2");
+#endif
+
+  return 1;
+}
+
+int faimtest_pwdchngdone(struct command_rx_struct *command, ...)
+{
+  printf("PASSWORD CHANGE SUCCESSFUL!!!\n");
+  return 1;
+}
+
+int faimtest_parse_oncoming(struct command_rx_struct *command, ...)
+{
+  struct aim_userinfo_s *userinfo;
+   
+  va_list ap;
+  va_start(ap, command);
+  userinfo = va_arg(ap, struct aim_userinfo_s *);
+  va_end(ap);
+
+  printf("\n%s is now online\n", userinfo->sn);
+
+  return 1;
+}
+
+int faimtest_parse_offgoing(struct command_rx_struct *command, ...)
+{
+
+  printf("\n%s has left\n", &(command->data[11]));
+
+  return 1;
+}
+
+
+/* 
+ * Handles callbacks for: AIM_CB_RATECHANGE, AIM_CB_USERERROR, 
+ *   AIM_CB_MISSED_IM, and AIM_CB_MISSED_CALL.
+ */
+int faimtest_parse_misses(struct command_rx_struct *command, ...)
+{
+  u_short family;
+  u_short subtype;
+
+  family = (command->data[0] << 8) + command->data[1];
+  subtype = (command->data[2] << 8) + command->data[3];
+  
+  switch (family)
+    {
+    case 0x0001:
+      if (subtype == 0x000a) /* or AIM_CB_RATECHANGE */
+       printf("\n****STOP SENDING/RECIEVING MESSAGES SO FAST!****\n\n");
+      break;
+    case 0x0002:
+      if (subtype == 0x0001) /* or AIM_CB_USERERROR */
+       {
+         u_long snacid = 0x00000000;
+         
+         snacid = aimutil_get32(&command->data[6]);
+         
+         printf("Received unknown error in SNAC family 0x0002 (snacid = %08lx)\n", snacid);
+       }
+      break;
+    case 0x0004:
+      if (subtype == 0x0001) /* or AIM_CB_MISSED_IM */
+       printf("\n***LAST IM DIDN\'T MAKE IT BECAUSE THE BUDDY IS NOT ONLINE***\n\n");
+      else if (subtype == 0x000a) /* or AIM_CB_MISSED_CALL */
+       printf("You missed some messages from %s because they were sent too fast\n", &(command->data[13]));
+      break;
+    }
+
+  return 0;
+}
+
+
+
+
+
This page took 5.830285 seconds and 5 git commands to generate.