From 9de3ca7e3fdcf62e088fe2a0c7fcdc219e1a5094 Mon Sep 17 00:00:00 2001 From: mid Date: Fri, 24 Dec 1999 04:59:45 +0000 Subject: [PATCH] Initial revision --- BUGS | 29 ++ CHANGES | 105 ++++++ COPYING | 504 ++++++++++++++++++++++++++++ Makefile | 47 +++ Makefile.rules | 15 + README | 82 +++++ aim.h | 457 +++++++++++++++++++++++++ aim_auth.c | 136 ++++++++ aim_buddylist.c | 95 ++++++ aim_chat.c | 67 ++++ aim_chatnav.c | 9 + aim_conn.c | 224 +++++++++++++ aim_global.c | 17 + aim_im.c | 546 ++++++++++++++++++++++++++++++ aim_info.c | 324 ++++++++++++++++++ aim_login.c | 300 +++++++++++++++++ aim_logoff.c | 28 ++ aim_misc.c | 580 ++++++++++++++++++++++++++++++++ aim_rxhandlers.c | 585 ++++++++++++++++++++++++++++++++ aim_rxqueue.c | 271 +++++++++++++++ aim_search.c | 52 +++ aim_snac.c | 108 ++++++ aim_tlv.c | 86 +++++ aim_txqueue.c | 320 ++++++++++++++++++ aim_util.c | 152 +++++++++ deprecated/aim_rxqueue.orig.c | 245 ++++++++++++++ deprecated/aim_snac.c | 114 +++++++ deprecated/discarded.c | 44 +++ deprecated/tis_telnet_proxy.c | 64 ++++ deprecated/tis_telnet_proxy.h | 8 + faimconfig.h | 42 +++ tcpdumps/chat.txt | 504 ++++++++++++++++++++++++++++ tcpdumps/newim.txt | 34 ++ tcpdumps/permitdeny.txt | 44 +++ utils/Makefile | 20 ++ utils/aimpasswd/Makefile | 12 + utils/aimpasswd/aimpasswd.c | 246 ++++++++++++++ utils/faimtest/Makefile | 12 + utils/faimtest/faimtest.c | 614 ++++++++++++++++++++++++++++++++++ 39 files changed, 7142 insertions(+) create mode 100644 BUGS create mode 100644 CHANGES create mode 100644 COPYING create mode 100644 Makefile create mode 100644 Makefile.rules create mode 100644 README create mode 100644 aim.h create mode 100644 aim_auth.c create mode 100644 aim_buddylist.c create mode 100644 aim_chat.c create mode 100644 aim_chatnav.c create mode 100644 aim_conn.c create mode 100644 aim_global.c create mode 100644 aim_im.c create mode 100644 aim_info.c create mode 100644 aim_login.c create mode 100644 aim_logoff.c create mode 100644 aim_misc.c create mode 100644 aim_rxhandlers.c create mode 100644 aim_rxqueue.c create mode 100644 aim_search.c create mode 100644 aim_snac.c create mode 100644 aim_tlv.c create mode 100644 aim_txqueue.c create mode 100644 aim_util.c create mode 100644 deprecated/aim_rxqueue.orig.c create mode 100644 deprecated/aim_snac.c create mode 100644 deprecated/discarded.c create mode 100644 deprecated/tis_telnet_proxy.c create mode 100644 deprecated/tis_telnet_proxy.h create mode 100644 faimconfig.h create mode 100644 tcpdumps/chat.txt create mode 100644 tcpdumps/newim.txt create mode 100644 tcpdumps/permitdeny.txt create mode 100644 utils/Makefile create mode 100644 utils/aimpasswd/Makefile create mode 100644 utils/aimpasswd/aimpasswd.c create mode 100644 utils/faimtest/Makefile create mode 100644 utils/faimtest/faimtest.c diff --git a/BUGS b/BUGS new file mode 100644 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 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 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. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/Makefile b/Makefile new file mode 100644 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 index 0000000..69f18a6 --- /dev/null +++ b/Makefile.rules @@ -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 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 index 0000000..09cf1a1 --- /dev/null +++ b/aim.h @@ -0,0 +1,457 @@ +#ifndef __AIM_H__ +#define __AIM_H__ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#include +#include +#else +#include +#include +#include +#include +#include +#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 index 0000000..bdb279a --- /dev/null +++ b/aim_auth.c @@ -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 index 0000000..b9ac86a --- /dev/null +++ b/aim_buddylist.c @@ -0,0 +1,95 @@ + +#include + +/* + * 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 index 0000000..1923dc7 --- /dev/null +++ b/aim_chat.c @@ -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 index 0000000..8bdc233 --- /dev/null +++ b/aim_chatnav.c @@ -0,0 +1,9 @@ +/* + * + * + * + * + */ + +#include "aim.h" + diff --git a/aim_conn.c b/aim_conn.c new file mode 100644 index 0000000..322effd --- /dev/null +++ b/aim_conn.c @@ -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;ifd >= 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; itype = 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;(istatus = (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 j) + j = aim_conns[i].fd; + return j; +} + +int aim_countconn(void) +{ + int i,cnt; + cnt = 0; + for (i=0;i -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-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 -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 index 0000000..caac61f --- /dev/null +++ b/aim_global.c @@ -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 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 index 0000000..9d085a6 --- /dev/null +++ b/aim_info.c @@ -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 (zdata+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 index 0000000..313bffe --- /dev/null +++ b/aim_login.c @@ -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 index 0000000..ebea9dc --- /dev/null +++ b/aim_logoff.c @@ -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 index 0000000..12f5c29 --- /dev/null +++ b/aim_misc.c @@ -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 index 0000000..196adde --- /dev/null +++ b/aim_rxhandlers.c @@ -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 index 0000000..f89fb2c --- /dev/null +++ b/aim_rxqueue.c @@ -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 index 0000000..62e9016 --- /dev/null +++ b/aim_search.c @@ -0,0 +1,52 @@ + +/* + * aim_search.c + * + * TODO: Add aim_usersearch_name() + * + */ + +#include + +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 index 0000000..f2701ec --- /dev/null +++ b/aim_snac.c @@ -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 +#include + +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 index 0000000..536e259 --- /dev/null +++ b/aim_tlv.c @@ -0,0 +1,86 @@ +#include + +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 index 0000000..d3f7d9e --- /dev/null +++ b/aim_txqueue.c @@ -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 index 0000000..a83a997 --- /dev/null +++ b/aim_util.c @@ -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 index 0000000..c10e3da --- /dev/null +++ b/deprecated/aim_rxqueue.orig.c @@ -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 index 0000000..15a0b66 --- /dev/null +++ b/deprecated/aim_snac.c @@ -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 + +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 index 0000000..e85a6ed --- /dev/null +++ b/deprecated/discarded.c @@ -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 index 0000000..05a6c85 --- /dev/null +++ b/deprecated/tis_telnet_proxy.c @@ -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 index 0000000..ed63951 --- /dev/null +++ b/deprecated/tis_telnet_proxy.h @@ -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 index 0000000..2584d59 --- /dev/null +++ b/faimconfig.h @@ -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 index 0000000..69c8e4a --- /dev/null +++ b/tcpdumps/chat.txt @@ -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 (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 (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 index 0000000..a02544d --- /dev/null +++ b/tcpdumps/newim.txt @@ -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 index 0000000..236aff5 --- /dev/null +++ b/tcpdumps/permitdeny.txt @@ -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 index 0000000..ae11c4e --- /dev/null +++ b/utils/Makefile @@ -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 index 0000000..3eee422 --- /dev/null +++ b/utils/aimpasswd/Makefile @@ -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 index 0000000..b42c214 --- /dev/null +++ b/utils/aimpasswd/aimpasswd.c @@ -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 index 0000000..d5187c6 --- /dev/null +++ b/utils/faimtest/Makefile @@ -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 index 0000000..5ac38c2 --- /dev/null +++ b/utils/faimtest/faimtest.c @@ -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; +} + + + + + -- 2.45.1