From: mid Date: Fri, 24 Dec 1999 04:59:45 +0000 (+0000) Subject: Initial revision X-Git-Tag: snapshot-19991224~1 X-Git-Url: http://andersk.mit.edu/gitweb/libfaim.git/commitdiff_plain/9de3ca7e3fdcf62e088fe2a0c7fcdc219e1a5094 Initial revision --- 9de3ca7e3fdcf62e088fe2a0c7fcdc219e1a5094 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; +} + + + + +