diff options
Diffstat (limited to 'plugins')
77 files changed, 24172 insertions, 0 deletions
diff --git a/plugins/!Deprecated/MSN/Docs/gpl.txt b/plugins/!Deprecated/MSN/Docs/gpl.txt new file mode 100644 index 0000000000..45645b4b53 --- /dev/null +++ b/plugins/!Deprecated/MSN/Docs/gpl.txt @@ -0,0 +1,340 @@ +		    GNU GENERAL PUBLIC LICENSE
 +		       Version 2, June 1991
 +
 + Copyright (C) 1989, 1991 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.
 +
 +			    Preamble
 +
 +  The licenses for most software are designed to take away your
 +freedom to share and change it.  By contrast, the GNU General Public
 +License is intended to guarantee your freedom to share and change free
 +software--to make sure the software is free for all its users.  This
 +General Public License applies to most of the Free Software
 +Foundation's software and to any other program whose authors commit to
 +using it.  (Some other Free Software Foundation software is covered by
 +the GNU Library General Public License instead.)  You can apply it to
 +your programs, too.
 +
 +  When we speak of free software, we are referring to freedom, 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 or use pieces of it
 +in new free programs; and that you know you can do these things.
 +
 +  To protect your rights, we need to make restrictions that forbid
 +anyone to deny you these rights or to ask you to surrender the rights.
 +These restrictions translate to certain responsibilities for you if you
 +distribute copies of the software, or if you modify it.
 +
 +  For example, if you distribute copies of such a program, whether
 +gratis or for a fee, you must give the recipients all the rights that
 +you have.  You must make sure that they, too, receive or can get the
 +source code.  And you must show them these terms so they know their
 +rights.
 +
 +  We protect your rights with two steps: (1) copyright the software, and
 +(2) offer you this license which gives you legal permission to copy,
 +distribute and/or modify the software.
 +
 +  Also, for each author's protection and ours, we want to make certain
 +that everyone understands that there is no warranty for this free
 +software.  If the software is modified by someone else and passed on, we
 +want its recipients to know that what they have is not the original, so
 +that any problems introduced by others will not reflect on the original
 +authors' reputations.
 +
 +  Finally, any free program is threatened constantly by software
 +patents.  We wish to avoid the danger that redistributors of a free
 +program will individually obtain patent licenses, in effect making the
 +program proprietary.  To prevent this, we have made it clear that any
 +patent must be licensed for everyone's free use or not licensed at all.
 +
 +  The precise terms and conditions for copying, distribution and
 +modification follow.
 +
 +		    GNU GENERAL PUBLIC LICENSE
 +   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 +
 +  0. This License applies to any program or other work which contains
 +a notice placed by the copyright holder saying it may be distributed
 +under the terms of this General Public License.  The "Program", below,
 +refers to any such program or work, and a "work based on the Program"
 +means either the Program or any derivative work under copyright law:
 +that is to say, a work containing the Program or a portion of it,
 +either verbatim or with modifications and/or translated into another
 +language.  (Hereinafter, translation is included without limitation in
 +the term "modification".)  Each licensee is addressed as "you".
 +
 +Activities other than copying, distribution and modification are not
 +covered by this License; they are outside its scope.  The act of
 +running the Program is not restricted, and the output from the Program
 +is covered only if its contents constitute a work based on the
 +Program (independent of having been made by running the Program).
 +Whether that is true depends on what the Program does.
 +
 +  1. You may copy and distribute verbatim copies of the Program's
 +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 give any other recipients of the Program a copy of this License
 +along with the Program.
 +
 +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 Program or any portion
 +of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
 +    stating that you changed the files and the date of any change.
 +
 +    b) You must cause any work that you distribute or publish, that in
 +    whole or in part contains or is derived from the Program or any
 +    part thereof, to be licensed as a whole at no charge to all third
 +    parties under the terms of this License.
 +
 +    c) If the modified program normally reads commands interactively
 +    when run, you must cause it, when started running for such
 +    interactive use in the most ordinary way, to print or display an
 +    announcement including an appropriate copyright notice and a
 +    notice that there is no warranty (or else, saying that you provide
 +    a warranty) and that users may redistribute the program under
 +    these conditions, and telling the user how to view a copy of this
 +    License.  (Exception: if the Program itself is interactive but
 +    does not normally print such an announcement, your work based on
 +    the Program is not required to print an announcement.)
 +
 +These requirements apply to the modified work as a whole.  If
 +identifiable sections of that work are not derived from the Program,
 +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 Program, 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 Program.
 +
 +In addition, mere aggregation of another work not based on the Program
 +with the Program (or with a work based on the Program) on a volume of
 +a storage or distribution medium does not bring the other work under
 +the scope of this License.
 +
 +  3. You may copy and distribute the Program (or a work based on it,
 +under Section 2) in object code or executable form under the terms of
 +Sections 1 and 2 above provided that you also do one of the following:
 +
 +    a) 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; or,
 +
 +    b) Accompany it with a written offer, valid for at least three
 +    years, to give any third party, for a charge no more than your
 +    cost of physically performing source distribution, a complete
 +    machine-readable copy of the corresponding source code, to be
 +    distributed under the terms of Sections 1 and 2 above on a medium
 +    customarily used for software interchange; or,
 +
 +    c) Accompany it with the information you received as to the offer
 +    to distribute corresponding source code.  (This alternative is
 +    allowed only for noncommercial distribution and only if you
 +    received the program in object code or executable form with such
 +    an offer, in accord with Subsection b above.)
 +
 +The source code for a work means the preferred form of the work for
 +making modifications to it.  For an executable work, 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 executable.  However, as a
 +special exception, the source code 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.
 +
 +If distribution of executable or 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 counts as
 +distribution of the source code, even though third parties are not
 +compelled to copy the source along with the object code.
 +
 +  4. You may not copy, modify, sublicense, or distribute the Program
 +except as expressly provided under this License.  Any attempt
 +otherwise to copy, modify, sublicense or distribute the Program 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.
 +
 +  5. 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 Program or its derivative works.  These actions are
 +prohibited by law if you do not accept this License.  Therefore, by
 +modifying or distributing the Program (or any work based on the
 +Program), you indicate your acceptance of this License to do so, and
 +all its terms and conditions for copying, distributing or modifying
 +the Program or works based on it.
 +
 +  6. Each time you redistribute the Program (or any work based on the
 +Program), the recipient automatically receives a license from the
 +original licensor to copy, distribute or modify the Program 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 to
 +this License.
 +
 +  7. 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 Program at all.  For example, if a patent
 +license would not permit royalty-free redistribution of the Program 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 Program.
 +
 +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.
 +
 +  8. If the distribution and/or use of the Program is restricted in
 +certain countries either by patents or by copyrighted interfaces, the
 +original copyright holder who places the Program 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.
 +
 +  9. The Free Software Foundation may publish revised and/or new versions
 +of the 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 Program
 +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 Program does not specify a version number of
 +this License, you may choose any version ever published by the Free Software
 +Foundation.
 +
 +  10. If you wish to incorporate parts of the Program into other free
 +programs whose distribution conditions are different, 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
 +
 +  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
 +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
 +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
 +PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU.  SHOULD THE
 +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
 +REPAIR OR CORRECTION.
 +
 +  12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER
 +PROGRAMS), 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 Programs
 +
 +  If you develop a new program, and you want it to be of the greatest
 +possible use to the public, the best way to achieve this is to make it
 +free software which everyone can redistribute and change under these terms.
 +
 +  To do so, attach the following notices to the program.  It is safest
 +to attach them to the start of each source file to most effectively
 +convey the exclusion of warranty; and each file should have at least
 +the "copyright" line and a pointer to where the full notice is found.
 +
 +    <one line to give the program's name and a brief idea of what it does.>
 +    Copyright (C) <year>  <name of author>
 +
 +    This program is free software; you can redistribute it and/or modify
 +    it under the terms of the GNU General Public License as published by
 +    the Free Software Foundation; either version 2 of the License, or
 +    (at your option) any later version.
 +
 +    This program is distributed in the hope that it will be useful,
 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +    GNU General Public License for more details.
 +
 +    You should have received a copy of the GNU General Public License
 +    along with this program; if not, write to the Free Software
 +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 +
 +
 +Also add information on how to contact you by electronic and paper mail.
 +
 +If the program is interactive, make it output a short notice like this
 +when it starts in an interactive mode:
 +
 +    Gnomovision version 69, Copyright (C) year name of author
 +    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
 +    This is free software, and you are welcome to redistribute it
 +    under certain conditions; type `show c' for details.
 +
 +The hypothetical commands `show w' and `show c' should show the appropriate
 +parts of the General Public License.  Of course, the commands you use may
 +be called something other than `show w' and `show c'; they could even be
 +mouse-clicks or menu items--whatever suits your program.
 +
 +You should also get your employer (if you work as a programmer) or your
 +school, if any, to sign a "copyright disclaimer" for the program, if
 +necessary.  Here is a sample; alter the names:
 +
 +  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
 +  `Gnomovision' (which makes passes at compilers) written by James Hacker.
 +
 +  <signature of Ty Coon>, 1 April 1989
 +  Ty Coon, President of Vice
 +
 +This General Public License does not permit incorporating your program into
 +proprietary programs.  If your program is a subroutine library, you may
 +consider it more useful to permit linking proprietary applications with the
 +library.  If this is what you want to do, use the GNU Library General
 +Public License instead of this License.
 diff --git a/plugins/!Deprecated/MSN/Docs/history-msn.txt b/plugins/!Deprecated/MSN/Docs/history-msn.txt new file mode 100644 index 0000000000..b3f08ab339 --- /dev/null +++ b/plugins/!Deprecated/MSN/Docs/history-msn.txt @@ -0,0 +1,529 @@ +Legend:
 +[+] added
 +[*] changed
 +[-] deleted
 +[!] bug fixed
 +
 +Version 0.7.1.0
 +===============
 +[+] All bitmap processing routines were removed in honour of the loadavatars plugin
 +
 +Version 0.7.0.1
 +===============
 +[+] IcoLib Integration
 +
 +Version 0.5.0.3
 +===============
 +[+] added support for custom smileys
 +[!] bug 0001996 fixed: No Contact Idetification When an Unsupport Feature Even Occurs
 +
 +Version 0.5.0.1
 +===============
 +[!] bug 0002083 fixed: Filetransfer suddenly stops
 +[!] bug 0002067 fixed: MSN connection fails in gateway mode through http-proxy (with authentication)
 +[!] bug 0001584 fixed: Crash when sender cancels file send
 +
 +Version 0.4.3.1
 +===============
 +[!] bug 0001887 fixed: Sometimes getting Error 540 from server then disconnect.
 +[!] fix for the invalid chars in the MSN chat
 +
 +Version 0.4.3.0
 +===============
 +[+] first Unicode version of the MSN plugin
 +[!] wish 0001015: nudges (thanks Tweetie for a patch)
 +[!] bug 0001532 fixed: Hotmail does not open from miranda
 +[!] bug 0001536 fixed: Contacts displayed as online while MSN isn't connected yet
 +
 +Version 0.4.1.3
 +===============
 +[+] support for dropping idle switchboards was added
 +
 +Version 0.4.1.2
 +===============
 +[+] Unicode in the nicknames and groups. Requires clistw &  Miranda
 +0.4.3 bld. 32 or later
 +[*] avatar setting dialog was moved to View/Change User Details section
 +[!] fix for initial email notification in the MSNP11 mode
 +[!] fix for the "User is already in your contact list" error
 +[!] bug 0001427 fixed: Error 540 during login on slow connections
 +[!] bug 0001468 fixed: MSN 7.5 users cannot load Miranda users avatar.
 +[!] BYE command was handled incorrectly
 +[!] fix for the old MSN file transfers: a received file cannot be opened
 +
 +Version 0.4.1.1
 +===============
 +[!]  fixed a bug when Miranda hangs up on exit, when the
 +clist_modern plugin is installed
 +
 +Version 0.4.0.4
 +===============
 +[!] important bugfix: MSNP11 status messages may block the login
 +process.
 +[!] fix for the problems with the keep-alive thread
 +[*] numerous minor changes and bugfixes.
 +
 +Version 0.4.0.3
 +===============
 +[+] MSNP11 support added
 +[+] wish #0001239 fixed: MSN Personal Status Messages
 +[+] WebMessenger detection added
 +[!] fix for the GPF on exit
 +
 +Version 0.4.0.2
 +===============
 +[!] bug #0000913 fixed: no zero-termination after _snprintf (potential
 +security issue)
 +[!] bug #0001176 fixed: can't send messages to the MSN WebMessenger
 +[!] bug #0001202 fixed: Can't delete received file directory
 +[!] various memory leaks
 +
 +Version 0.4.0.1
 +===============
 +[+] wish #0000971 fixed: Block & Unblock actions must be separated
 +[+] wish #0000966 fixed: to show the warning when a  contact  tries
 +to establish a audio/video/webcam conference with you.
 +[-] removed support for old versions of Miranda.
 +[!] bug #0000996 fixed: File transfer fails when auto-accept is on
 +and file already exists in destination directory
 +[!] fixes for minor string allocation problems.
 +
 +WARNING!!! All versions since this one require Miranda 0.4.x core.
 +This is required by the project admins.
 +
 +Version 0.1.7.11
 +================
 +[+] full support for server-side groups and contacts
 +[+] wish #0000142 fixed: a popup for session disconnection
 +[+] wish #0000149 fixed: CHAT.DLL support was added for groupchats (thanks noname)
 +[!] bug #0000458 fixed: Messages disappear when sending to MSN.
 +[!] bug #0000684 fixed: a file with the Unicode name fails to open after
 +the successful transfer.
 +[!] bug #0000761 fixed: apply button in options->popups->msn enabled on
 +first showing of page
 +[!] minor fix for P2P file transfers over NAT
 +
 +Version 0.1.7.10
 +================
 +[!] multiple bugfixes for gateways & P2P file transfers
 +[*] login rules were changed a bit: now Miranda assigns its own
 +proxy address to SSL connection when the 'Use IE proxy settings'
 +option is turned off. If you don't use a proxy, nothing gets
 +changed.
 +[!] bug #0000580 fixed: the large messages disappear being sent.
 +[!] bug #0000601 fixed: files  with  incorrect  file  names  aren't
 +saved during P2P file transfers.
 +[!] bug #0000565 fixed: avatar file names becomes different after
 +using the dbtool, that's why the MSN folder may have the same
 +avatars several times.
 +[!] bug #0000437 fixed: expert must have an option  to  choose  the
 +needed status translation schema for Away, BRB & N/A statuses.
 +[!] bug #0000541 fixed: if Miranda asks to overwrite a file
 +during the f/t, a crash can occur when user cancels it.
 +[*] translation file modification.
 +
 +Version 0.1.7.9a
 +================
 +[!] bug #0000564 fixed: MSN Messenger doesn't confirm a file
 +transfer from Miranda when it goes via the server
 +
 +Version 0.1.7.9
 +===============
 +[+] wish #000519: the ability to create avatars from PNG images.
 +[+] contact's phone numbers support was added
 +[+] options dialog was changed to allow a user to see his own avatar.
 +[-] mSN protocol v.9 support code was removed
 +[!] option 'File Transfers -> If a file already exists  ->  Rename'
 +doesn't work for MSN P2P transfers.
 +[!] bug #0000092 fixed: 'User Is Typing' event delay is too slow.
 +[!] bug #0000423 fixed: Send Message To Offline User Return Message Time
 +Out message
 +[!] bug #0000444 fixed: the passive P2P transfer fails if MSN Messenger
 +returns bad IP address
 +[!] bug #0000554 fixed: fake Hotmail notifications are shown, even
 +when there's no new mail available
 +[*] translation file modification.
 +
 +Version 0.1.7.8
 +===============
 +[+] 'View MSN services status' menu item was added to the main menu
 +[+] Massive improvements for P2P file transfers
 +
 +Version 0.1.7.7
 +===============
 +[!] fixed some bugs with file transfer cancellation.
 +[*] minor changes in MSN object id handling.
 +[*] internal changes to the threading mechanism to make it more stable
 +
 +Version 0.1.7.6
 +===============
 +[+] the support for v10 P2P incoming passive direct connections was
 +added. DC are used when a sender reports the 'Direct-Connect'
 +connection type in the 'Conn-Type' request fiels.
 +[+] the support for newly added avatar notifications was added
 +(works only under 0.3.4+ core).
 +[+] the  MSN/GetAvatarInformation service was added to support the
 +external avatar readers like tabSRMM etc.
 +[*] incoming file transfers now use the standard settings for
 +ports: via Options -> Network, MSN plugin connections. The existing
 +settings are transferred, but you can use port ranges now to
 +establish several transfers (one transfer for each contact)
 +[-] the 'Incoming port' setting was deleted from MSN network options.
 +[*] blocked contacts from the server lists aren't temporary anymore.
 +It also avoids the contact list flickering during login.
 +[!] bugfix (error #0000331): incoming file transfers seem to fail
 +being initiated from the MSN Messenger;
 +[!] bugfix (error #0000333): contacts aren't deleted from server when
 +you press Del key in the contact list
 +
 +Version 0.1.7.5
 +===============
 +[+] full avatars support added: you can set your own avatar
 +and transfer it to another people.
 +[!] bugfix for error 0000319: MSN server list manager shall not display
 +contacts of another protocols, groups also shouldn't be displayed.
 +[!] bugfix: MSN plugin adds a contact to CL during a search by e-mail.
 +[!] bugfix: massive fixes for authorization, both for v.9 and v.10
 +
 +Version 0.1.7.4
 +===============
 +[+] server lists manager was added to Options -> Network
 +[!] bugfix for timeouts caused by User-Is-Typing notifications.
 +[!] bugfix (error #000305): MSN protocol freezes Miranda under
 +Windows 98/ME after login (many thanks to Hilary Cheng for a solution)
 +
 +Version 0.1.7.3
 +===============
 +[!] bugfix for file transfers: the incorrect address was used
 +during sending a file.
 +[+] added a 'View profile' contacts popup menu item (thanks koobs for an idea)
 +[*] numerous fixes for MSN v10.
 +
 +Version 0.1.7.2
 +===============
 +[!] bugfix (error #0000222): you can add yourself using Find/Add contacts.
 +[!] bugfix (error #0000123): Away and N/A modes are switched.
 +[!] bugfix: e-mail, password and nickname can't be saved into the
 +empty profile database.
 +[!] bugfix: Cancel button does not close the png2dib d/l dialog.
 +
 +Version 0.1.7.1
 +===============
 +[!] critical bugfix (err.#50): typing notification can result to
 +the infinite timeouts during message sending.
 +
 +Version 0.1.7.0
 +===============
 +[*] plugin lost its compatibility with Miranda 0.2.x due to stability
 +reasons, version 0.3.x is required.
 +[+] first version of MSN avatars (user-defined pictures).
 +[+] added an option to support avatars and d/l the DLL.
 +[*] PNG support was moved from IE components to libpng.
 +[+] added an option not to get the nickname from a server, to allow
 +a user to identify his/her location via a nick.
 +[!] fixed a problem with the lack of diagnostics on error 715.
 +[!] some minor bugfixes to file transfers.
 +[-] support for MSNP v.8 was removed.
 +[*] translation file was slightly modified.
 +
 +Version 0.1.6.8
 +===============
 +[!] rarely occurred GPF fixed during file transfers
 +[!] MSN gateway access without a proxy breaks connections
 +when 'user-is-typing' messages are transferred first.
 +[!] MSN server closes connection if a PNG command is send to
 +a switchboard thread
 +[!] PNG command is not send when a proxy exists.
 +
 +Version 0.1.6.7
 +===============
 +Official version for Miranda 0.3.3 release
 +[!] minor interface fixes in the options dialog.
 +
 +Version 0.1.6.6 (requires SRMM Unicode 1.0.1.3!!!)
 +===============
 +[*] keep-alive support was redesigned to avoid threading problems
 +[!] bugfix: rare GPF fixed after reconnecting to the MSN server
 +[!] bugfix for all plugins like AwaySys for sending non-Unicode
 +messages.
 +
 +Version 0.1.6.5
 +===============
 +[!] bugfix: file receiving was broken.
 +
 +Version 0.1.6.4
 +===============
 +[*] gateway support redesigned to provide the gateway access
 +without both proxies and MSN Gateway plugin.
 +[!] a few minor memory leaks were fixed.
 +[*] minor interface changes in the options dialogs, translation
 +file was synchronized with the current options dialogs.
 +
 +Version 0.1.6.3
 +===============
 +[!] bugfix: if both built-in gateway and 'Keep connection alive' checkbox
 +are enabled, disconnection occurs every 2 minutes.
 +[!] bugfix: a  blocked contact becomes unblocked after relogin, if it's
 +not deleted.
 +
 +Version 0.1.6.2
 +===============
 +[+] option "Use IE proxy settings" was added to simplify life for
 +users of the MSN Gateway plugin.
 +[*] options page was divided into two ones: general MSN options and
 +network options.
 +[!] bugfix: option 'Disable all contacts not included...' could not be changed
 +[!] bugfix: GPF sometimes occurred when starting an external mailer
 +(thanks Daniel for kind cooperation)
 +
 +Version 0.1.6.1
 +===============
 +[+] built-in gateway added (requires Miranda 0.3.3 or later)
 +[+] 'User is typing' support added (requires SRMM or SRMM MOD plugin)
 +[+] Full Unicode support for messages was added (requires SRMM MOD Unicode)
 +[+] MSN main menu item is created in the same section with all
 +another protocols
 +[*] 'block/unlock' feature is integrated with Options->Status->Visible
 +[!] bugfix: a port remains opened after the file trasnfer cancel.
 +[!] bugfix: if a contact list is very long, all contacts can be
 +shown in the Offline mode.
 +[!] a whole bunch of minor bugfixes, changes and improvements.
 +
 +Version 0.1.5.11
 +================
 +[+] Netmeeting support added
 +[-] MSNP7 support is deleted and this option is locked
 +[+] option was added to launch a specific program when the new
 +Hotmail arrives.
 +[+] option was added to display errors as popups to avoid the
 +interface locking.
 +[*] additional diagnostics was added to handle the case when
 +Internet Explorer is in the Offline mode (thanks to Jonas Svensson).
 +[*] numerous minor changes in option dialogs and debug messages.
 +
 +Version 0.1.5.10
 +================
 +[!] bug fixed: the "Use MSN protocol v.8" option is not saved
 +correctly after pressing Apply/Ok in the options dialog if this
 +option was never saved in the database before.
 +[*] the source code was changed to allow the compilation without
 +the Platform SDK.
 +
 +Version 0.1.5.9
 +===============
 +[!] bug in new URL encode mechanism prevents messages from being sent
 +if the contact's email contains underscores.
 +
 +Version 0.1.5.8
 +===============
 +[+] new MSN Menu item was added to edit user's MSN profile in a browser
 +[!] bug fixed: authorization problems when many  MSN  accounts  are
 +used in the same Miranda installation.
 +[!] bug fixed: if a password contains  non-alphabetical  characters
 +(like punctuation, ampersand, plus, etc) the MSNP8 login could return
 +error 401 Unauthorized. MSNP7 login works Ok.
 +[!] bug fixed: if a contact changes its status to  Invisible,  it's
 +not possible to send messages to him/her anymore.
 +[*] the popup displaying procedure was changed to avoid so called
 +'frozen popups'effect.
 +[*] the "Use MSN protocol v.8" option is now turned on by default.
 +
 +Version 0.1.5.7
 +===============
 +[*] the SSL autorization procedure was changed: now it uses
 +Internet Explorer's proxy settings to log in. It also resolves
 +problems with proxies that require authorization (previously you
 +could see the error 407 in the network log when trying to logon).
 +In this case MSN plugin tries automatically to apply the login and
 +the password from the Options -> Network -> MSN.
 +[*] cookies usage had been turned off, it means that you can logon
 +automatically into MSN Messenger and simultaneously logon using
 +Miranda under different account.
 +[*] error diagnostic has been slightly enhanced.
 +[*] WinInet.dll now gets unloaded from memory after login to use
 +less memory.
 +[!] bug fixed: attemp to find/add a contact that already exists  in
 +your contact list resulted to strange error message.
 +
 +Version 0.1.5.6
 +===============
 +[+] added the external IP autodetection if the protocol v.8 is
 +used. It can significantly simplify life if you have the dynamic
 +external IP address.
 +[*] minor fixes in the Options dialog
 +
 +Version 0.1.5.5
 +===============
 +[!] bug fixed: 'Cancel' button does not stop the file transfer
 +[!] bug fixed: contacts with leading digits in the e-mail are not
 +processed properly.
 +[!] bug fixed: you cannot send messages to a person if you tried to
 +send the first message in the Invisible mode.
 +
 +Version 0.1.5.4
 +===============
 +[*] the file senging does not require to talk anymore
 +[!] bug fixed: fast sending of two or more messages results to the GPF
 +
 +Version 0.1.5.3
 +===============
 +[!] bug fixed: memory corruption in multichat mode
 +
 +Version 0.1.5.2
 +===============
 +[!] bug fixed: LastSeen plugin shows the incorrect time of contact's logout.
 +[!] bug fixed: you cannot block a contact if it's offline (even if you're online).
 +[!] bug fixed: when MSNP8 is used, some contacts are skipped at all during
 +the synchronization procedure.
 +
 +Version 0.1.5.1
 +===============
 +[!] bug fixed: 'Display menu' option does not really disable the MSN menu
 +[*] translate-msn.txt updated.
 +[+] minor changes in the options dialog
 +
 +Version 0.1.5.0
 +===============
 +[+] MSN Protocol v.8 support added.
 +[+] a "Invite to chat" contact menu item is added.
 +[*] multichat support is fully redesigned and fixed.
 +[*] multiple file transfers are fully redesigned and fixed.
 +[!] bug fixed: when you set your own nickname with spaces, it appears in
 +the options dialog URL-encoded (with %20 instead of a space char).
 +[!] bug fixed: opened switchboard sessions weren't closed when you go
 +offline without closing Miranda.
 +
 +Version 0.1.4.12
 +================
 +[!] bug fixed: Hotmail inbox is not shown after a clicking on a Hotmail
 +popup under Windows 9x
 +[!] bug fixed: a user's own nickname is not properly saved after changing.
 +
 +Version 0.1.4.11
 +================
 +[*] changed blocked user visualization method: nickname is never got
 +corrupted anymore, visibility mode is used now. M will show blocked
 +contacts in italic by default, but you can tune the font/color/style of
 +the 'invisible' users at the Options/Contact List/List text tab, for item
 +called "Online contacts for whom you have a different visibility".
 +[!] bug fixed: an authorization is rerequested after deleting a contact.
 +[!] bug fixed: the very long nickname can be set, and then cut off when
 +saving to the database or the server
 +[!] bug fixed: when viewing the user options, an 'Updating...' string is
 +blinking all the time.
 +
 +Version 0.1.4.10
 +================
 +[+] option added to block all another MSN contacts. Attention: you
 +must be online to edit this option.
 +[!] search-by-email mechanism fixed.
 +[!] bug fixed: user email is shown in popups instead of nickname
 +[!] bug fixed: when migrating from previous versions of MSN plugin
 +a lot of authorization requests are shown.
 +
 +Version 0.1.4.9 (May Day Build :)
 +===============
 +[!] bug fixed: "First message delivered" displayed as a message
 +box if the Popup plugin is not installed.
 +[!] bug fixed: contact's e-mail is shown instead of a user's
 +nick name when "First message delivered" popup is shown
 +
 +Version 0.1.4.8
 +===============
 +[!] bug fixed: the first message get lost when another message
 +editor window is opened.
 +[+] "First message delivered" popup can be enabled separately.
 +
 +Version 0.1.4.7
 +===============
 +[+] separate timeout for Hotmail popups added
 +[*] options layout changed: all popup options are grouped on the
 +separate options page: Options/Popups/MSN.
 +[!] bug fixed: Hotmail popups got 'frozen' after being clicked
 +
 +Version 0.1.4.6
 +===============
 +[!] bug fixed: offline messages are get lost without notification
 +
 +Version 0.1.4.5
 +===============
 +[*] first message sending routine is changed to release message editor immediately.
 +This does not fix the delay problem completely, but user will never see the timeout
 +dialog again. If the Popup plugin is installed, user will be notified using a popup
 +message when the first message will be really delivered.
 +[!] bugfix: when you go offline from the online mode, both modes are disabled in
 +the plugin's statuses menu.
 +[!] minor interface bugfixes in the options dialog
 +
 +Version 0.1.4.4
 +===============
 +MSN plugin is added as a protocol to the Miranda's sources CVS tree.
 +[!] fixed a problem with sending raw data to the HTTP proxy.
 +[+] new option: popup timeouts. Requires Popup plugin v. 1.0.1.9 or later
 +[*] popups interface changed not to call Web browser when 'typing' popups are clicked
 +[*] FAQ is added to the readme.txt
 +
 +Version 0.1.4.3
 +===============
 +[+] new option: display 'user is typing' messages as popups if an appropriate plugin is installed
 +[+] new option: send a font color/style alongside with messages. This
 +option also fixes a problem with displaying messages in the standard
 +Windows Messenger using an ugly/incorrect font/size/style.
 +[!] fixed a memory leak when calling popups.
 +
 +Version 0.1.4.2
 +===============
 +
 +A couple of bugfixes from Pixador (thank him for a patch):
 +[!] multiple MSN plugins do not work together.
 +[!] GPF when user presses Block/Unblock several times;
 +
 +Version 0.1.4.1
 +===============
 +
 +Numerous bugfixes:
 +[!] file sending/receiving almost works now, excluding multi-file sending from Miranda to WM.
 +[!] a lot of memory leaks, double deletions, memory corruptions etc. fixed.
 +
 +Version 0.1.4.0
 +===============
 +
 +Entering next major release:
 +[+] proxy support added;
 +[+] network traffic logging added;
 +[!] fixed bug with 100% processor usage;
 +[!] fixed bug with displaying incorrect file names in the file accept dialog.
 +
 +Version 0.1.3.4
 +===============
 +
 +[*] code of Authorization/Deny changed to show an authorization request only once;
 +[!] memory corruption fixed;
 +[!] GPF with blocking/unblocking fixed.
 +
 +Version 0.1.3.3
 +===============
 +
 +[*] language of plugin is changed to C++;
 +[!] bug with offline authorization fixed;
 +
 +Version 0.1.3.0
 +===============
 +
 +[!] fixed a bug with GPF on exit;
 +[!] fixed a bug with contacts blocking/unblocking;
 +[!] fixed a bug with strange crashes time to time;
 +[!] fixed a memory leak;
 +[!] fixed the ANSI <-> UTF conversion scheme to avoid problems with old versions of Windows (like 95 OSR2).
 +
 +Version 0.1.2.1
 +===============
 +
 +Written by Rako Shizuka.
 +The second version with extended functionality: file transfers, blocking etc.
 +
 +Version 0.1.2.0
 +===============
 +
 +Written by Richard Hughes aka cyreve.
 +The first version with basic functionality
 diff --git a/plugins/!Deprecated/MSN/Docs/readme-msn.txt b/plugins/!Deprecated/MSN/Docs/readme-msn.txt new file mode 100644 index 0000000000..8c0a035958 --- /dev/null +++ b/plugins/!Deprecated/MSN/Docs/readme-msn.txt @@ -0,0 +1,125 @@ +Protocol for the Miranda IM for communicating with users of
 +the MSN Messenger protocol.
 +
 +Copyright (C) 2003-5 George Hazan (ghazan@postman.ru)
 +Copyright (C) 2001-3 Richard Hughes (original version),
 +
 +Miranda IM: the free icq client for MS Windows
 +Copyright (C) 2002-5  Martin Oberg, Robert Rainwater, Sam Kothari, Lyon Lim
 +Copyright (C) 2000-2  Richard Hughes, Roland Rabien & Tristan Van de Vreede
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program; if not, write to the Free Software
 +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 +
 +================================================================================
 +Useful plugins which can help you to work with the MSN protocol
 +================================================================================
 +
 +Popup 1.0.1.9
 +(http://miranda-im.org/download/details.php?action=viewfile&id=299)
 +Popup Plus 2.0.3.8
 +(http://miranda-im.org/download/details.php?action=viewfile&id=1170)
 +----------------------
 +All notifications in the MSN plugin are made using the Popup
 +plugin. After the Popup plugin installation there will be some
 +options available for tuning, you will find them in
 +Options/Popups/MSN tab.
 +
 +Chat 0.2.0.2
 +(http://miranda-im.org/download/details.php?action=viewfile&id=1309)
 +----------------------
 +This plugin allows you to support group chats with many MSN users. Without
 +that plugin you can't leave a chat been being invited, so if you plan to
 +use groupchats, this plugin is essential.
 +
 +SRMM (Unicode) 1.0.4.3
 +(http://miranda-im.org/download/details.php?action=viewfile&id=1136)
 +tabSRMM (Unicode) 0.9.9.95
 +(http://hell.at.eu.org/forums)
 +----------------------
 +They both are true Unicode-aware message editors. Using them you can
 +send/receive Unicode messages, so you won't be dependent on the
 +codepages, encodings etc. They work only under NT4/Win2k/XP/2003.
 +
 +Unicode History Viewer
 +(http://miranda-im.org/download/details.php?action=viewfile&id=1109)
 +----------------------
 +If you work under NT4/Win2k/XP/2003, and you can send/receive messages
 +in Unicode, the standard history viewer will show question-marks when
 +Unicode characters cannot be mapped to the current codepage. In this
 +case you can use this plugin to have no problems at all.
 +
 +================================================================================
 +Frequently asked questions.
 +================================================================================
 +
 +Q1. I want to use the OpenSSL libraries, but plugin can't find or load
 +them. Where can I find the valid DLLs for Win32?
 +
 +A1. http://www.slproweb.com/products/Win32OpenSSL.html
 +Use the latest stable version.
 +
 +----------------------------------------------------------------
 +
 +Q2. I get strange errors with connection, proxies, file sending/
 +receiving. How can I find the reason of the problem?
 +
 +A2. Some useful information is grouped in the networking-msn.txt.
 +If it does not help, try to create a network log. Go to
 +Options/Network and press a "Log Options" button (the only button
 +in the upper-right corner). Very often this log helps users to
 +find a hidden diagnostic messages, or simply understand what is
 +happening concretely. If a problem persists, you can contact me,
 +and upon request, send me (zipped!) a piece of this log.
 +
 +----------------------------------------------------------------
 +
 +Q3. My Miranda logged into the MSN network successfully, but I
 +cannot send a message, and a contact's menu item 'Message' is blocked.
 +
 +A3. The problem is in the Conversation Style Messaging plugin.
 +CSM plugin is incompatible with the MSN plugin because of the
 +error in it. Disable it and/or delete, if you want to use the MSN
 +protocol
 +
 +----------------------------------------------------------------
 +
 +Q4. I want to compile your sources, but got a lot of errors.
 +
 +A4. First, you should download new Miranda's SDK sources, and
 +place the MSN plugin's sources into Protocol\MSN subdirectory
 +(accordingly to the Miranda's directory tree). Notice that MSN is
 +not a plugin anymore, it's stored among another protocols. Look at
 +http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/miranda-icq to
 +view the complete directory structure.
 +
 +Then download the Popup plugin, and unzip header file m_popup.h
 +to the SDK\headers_c directory. Then you should be able to compile
 +MSN plugin without problems.
 +
 +Installation of Microsoft Platform SDK is not required to
 +compile MSN plugin sources
 +
 +----------------------------------------------------------------
 +
 +Q5. When I receive an authorization request, my own nickname is
 +shown in the contact list. Is it a bug?
 +
 +A5. Yes, it is, but it cannot be solved now. Miranda uses UINs
 +to identify a contact, but because MSN protocol have no UINs,
 +your own nickname (as a default one) is shown.
 +
 +----------------------------------------------------------------
 +
 +WMBR, George Hazan (ghazan@postman.ru).
 diff --git a/plugins/!Deprecated/MSN/Docs/todo-msn.txt b/plugins/!Deprecated/MSN/Docs/todo-msn.txt new file mode 100644 index 0000000000..627c0ae56b --- /dev/null +++ b/plugins/!Deprecated/MSN/Docs/todo-msn.txt @@ -0,0 +1,10 @@ +There're most important problems and known bugs:
 +
 +1. File transfers:
 +- problems with the multihomed machines.
 +- better diagnostics.
 +
 +If you know a problem that is not listed here, report it via e-mail.
 +
 +WMBR, George Hazan
 +ghazan@postman.ru
 diff --git a/plugins/!Deprecated/MSN/Docs/translate-msn.txt b/plugins/!Deprecated/MSN/Docs/translate-msn.txt new file mode 100644 index 0000000000..552e1951ec --- /dev/null +++ b/plugins/!Deprecated/MSN/Docs/translate-msn.txt @@ -0,0 +1,169 @@ +; MSN 0.1.7.9 translation strings
 +
 +[MSN Protocol]
 +[%s plugin connections]
 +[Hotmail]
 +[Hotmail Notify]
 +[Hotmail from %s]
 +[Hotmail from %s (%s)]
 +[A new mail has come from %s (title: %s).]
 +[A new mail has come from %s (%s) (title: %s).]
 +[Subject: %s]
 +[Unread mail is available: %d messages (%d junk e-mails).]
 +[Test: Arrival Hotmail]
 +[A New Hotmail has come!]
 +[Contact left channel]
 +
 +; Messages
 +
 +[%s (%s) has joined the chat with %s]
 +[First message delivered]
 +[typing...]
 +
 +; Menus
 +
 +[&Block]
 +[&Unblock]
 +[Display Hotmail &Inbox]
 +[&Invite to chat]
 +[Set &Nickname]
 +[Edit MSN &Profile]
 +[&Start Netmeeting]
 +[Set &Avatar]
 +[View MSN Services &Status]
 +[&View Profile]
 +
 +
 +; Errors
 +
 +[Attempt to make the SSL connection resulted to error %d: %s.]
 +[Cannot start the file transfer: no free sockets. Error %d: %s.]
 +[Cannot start the file transfer due to the lack of free sockets.]
 +[Cannot start the file transfer: cannot listen on a socket. Error %d: %s.]
 +[Contact tried to send its webcam data (currently not supported)]
 +[Contact tried to view our webcam data (currently not supported)]
 +[Contact tried to open an audio conference (currently not supported)]
 +[file transfer is canceled by remote host]
 +[file transfer: time out occurred]
 +[Internet Explorer is in the 'Offline' mode. Switch IE to the 'Online' mode and then try to relogin]
 +[MSN plugin cannot add a new contact because the contact list is full]
 +[MSN protocol allows only one file to be sent at a time]
 +[MSN protocol does not allow you to communicate with others when you are invisible]
 +[MSN protocol does not support offline messages]
 +[MSN Services are temporarily unavailable, please try to connect later]
 +[Message is too long: MSN messages are limited by 1202 UTF8 chars]
 +[Server has requested an unknown protocol set (%s)]
 +[Unknown or invalid host name was specified (%s). Error %d: %s]
 +[Unprocessed error: %s]
 +[Unrecognised error %d. The server has closed our connection]
 +[User is already in your contact list]
 +[You must be talking to start Netmeeting]
 +[You must specify your e-mail in Options/Network/MSN]
 +[Your username or password is incorrect]
 +[Your MSN account e-mail is unverified. Goto http://www.passport.com and verify the primary e-mail first]
 +
 +; Options dialog
 +
 +[Network]
 +[PopUps]
 +[E-mail address]
 +
 +[Full e-mail:]
 +[Password:]
 +[Nickname:]
 +[Create a new MSN messenger account using the MSN website]
 +[Expert]
 +[Use MSN protocol v.8]
 +[Disable main menu]
 +[Send message font color/size info inside messages]
 +[Disable all contacts not included into my contact list]
 +[Enable avatars support]
 +[Manage server groups]
 +[Treat Away status as 'Be Right Back']
 +[Never update your nickname from server]
 +[Run the following application when new Hotmail arrives]
 +[Server groups import may change your contact list layout after next login. Do you want to upload your groups to the server?]
 +
 +; Network options dialog
 +
 +[Connection settings]
 +[Login server:]
 +[Port:]
 +[Use HTTP gateway mode (incompatible with MSN Gateway plugin)]
 +[Use IE proxy settings]
 +[Keep connection alive (send a ping packet every minute)]
 +[Notify me when a message delivery has failed]
 +[Use MSN Messenger 7 protocol]
 +[Use OpenSSL encryption (requires LIBSSL32.DLL)]
 +
 +[Incoming file transfers]
 +[Automatically obtain host/port for incoming file transfers]
 +[Your host (or router):]
 +[Reset]
 +[The changes you have made require you to reconnect to the MSN Messenger network before they take effect]
 +[The changes you have made require you to restart Miranda IM before they take effect]
 +
 +
 +; Popup options dialog
 +
 +[Colors]
 +[Background color]
 +[Text color]
 +[&Use Windows colors]
 +[Disable receiving Hotmail notifications]
 +[Ignore new messages in 'Junk Mail' folder only (at startup)]
 +[Timeout (*)]
 +[Previe&w]
 +[Other]
 +[Display popups when user is typing]
 +[Enable 'First message delivered' popup]
 +[(*) Timeouts require Popup v. 1.0.1.9 or later]
 +[Display errors using popups]
 +
 +; pnd2dib download dialog
 +
 +[png2lib download]
 +[To enable the avatar support, you must obtain the valid copy of the
 +png2dib.dll. Choose one of the following:]
 +[[Install] - install a png2lib plugin using Miranda Installer]
 +[[Download] - manually download a zipped DLL and then unzip it to the
 +plugins folder]
 +[[Cancel] - disable the avatar support]
 +
 +
 +; Server list manager
 +
 +[Server Lists]
 +[Server List Manager]
 +[Contact is included into your server list]
 +[Somebody included you in his/her server list]
 +[Allowed (active) contact]
 +[Blocked contact]
 +
 +; chat window
 +[Me]
 +[Others]
 +
 +; chat log message
 +[This conversation has been inactive, participants will be removed.]
 +[To resume the conversation, please quit this session and start a new chat session.]
 +
 +; contact list and chat title
 +[MSN Chat #]
 +
 +; message box
 +[There is only 1 person left in the chat, do you want to switch back to standard message window?]
 +[User is already in the chat session.]
 +[No active chat session is found.]
 +
 +; menus
 +[User &details]
 +[User &history]
 +[&Leave chat session]
 +[&Invite user...]
 +
 +; options dialog
 +[Avatar]
 +[Running on a mobile device]
 +[Running on a MSN mobile device]
 +[Using MSN Webmessenger]
 diff --git a/plugins/!Deprecated/MSN/msn_10.vcxproj b/plugins/!Deprecated/MSN/msn_10.vcxproj new file mode 100644 index 0000000000..2cf0ee8aef --- /dev/null +++ b/plugins/!Deprecated/MSN/msn_10.vcxproj @@ -0,0 +1,260 @@ +<?xml version="1.0" encoding="utf-8"?>
 +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 +  <ItemGroup Label="ProjectConfigurations">
 +    <ProjectConfiguration Include="Debug|Win32">
 +      <Configuration>Debug</Configuration>
 +      <Platform>Win32</Platform>
 +    </ProjectConfiguration>
 +    <ProjectConfiguration Include="Debug|x64">
 +      <Configuration>Debug</Configuration>
 +      <Platform>x64</Platform>
 +    </ProjectConfiguration>
 +    <ProjectConfiguration Include="Release|Win32">
 +      <Configuration>Release</Configuration>
 +      <Platform>Win32</Platform>
 +    </ProjectConfiguration>
 +    <ProjectConfiguration Include="Release|x64">
 +      <Configuration>Release</Configuration>
 +      <Platform>x64</Platform>
 +    </ProjectConfiguration>
 +  </ItemGroup>
 +  <PropertyGroup Label="Globals">
 +    <ProjectName>MSN</ProjectName>
 +    <ProjectGuid>{7B0F213E-C15E-4219-8AE5-49DD3D3D553D}</ProjectGuid>
 +  </PropertyGroup>
 +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
 +    <ConfigurationType>DynamicLibrary</ConfigurationType>
 +    <CharacterSet>Unicode</CharacterSet>
 +    <WholeProgramOptimization>true</WholeProgramOptimization>
 +  </PropertyGroup>
 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
 +    <ConfigurationType>DynamicLibrary</ConfigurationType>
 +    <CharacterSet>Unicode</CharacterSet>
 +  </PropertyGroup>
 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
 +    <ConfigurationType>DynamicLibrary</ConfigurationType>
 +    <CharacterSet>Unicode</CharacterSet>
 +    <WholeProgramOptimization>true</WholeProgramOptimization>
 +  </PropertyGroup>
 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
 +    <ConfigurationType>DynamicLibrary</ConfigurationType>
 +    <CharacterSet>Unicode</CharacterSet>
 +  </PropertyGroup>
 +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
 +  <ImportGroup Label="ExtensionSettings">
 +  </ImportGroup>
 +  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
 +    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
 +  </ImportGroup>
 +  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
 +    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
 +  </ImportGroup>
 +  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
 +    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
 +  </ImportGroup>
 +  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
 +    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
 +  </ImportGroup>
 +  <PropertyGroup Label="UserMacros" />
 +  <PropertyGroup>
 +    <_ProjectFileVersion>10.0.30128.1</_ProjectFileVersion>
 +    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Plugins\</OutDir>
 +    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
 +    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Plugins\</OutDir>
 +    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
 +    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Plugins\</OutDir>
 +    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
 +    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Plugins\</OutDir>
 +    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
 +    <IgnoreImportLibrary>true</IgnoreImportLibrary>
 +  </PropertyGroup>
 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
 +    <ClCompile>
 +      <Optimization>Disabled</Optimization>
 +      <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
 +      <PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;MSN_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
 +      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
 +      <FunctionLevelLinking>true</FunctionLevelLinking>
 +      <FloatingPointModel>Fast</FloatingPointModel>
 +      <PrecompiledHeader>Use</PrecompiledHeader>
 +      <PrecompiledHeaderFile>msn_global.h</PrecompiledHeaderFile>
 +      <WarningLevel>Level3</WarningLevel>
 +      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
 +      <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
 +      <ExceptionHandling>false</ExceptionHandling>
 +    </ClCompile>
 +    <ResourceCompile>
 +      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <AdditionalIncludeDirectories>..\..\include;..\..\include\msapi</AdditionalIncludeDirectories>
 +    </ResourceCompile>
 +    <Link>
 +      <AdditionalDependencies>ws2_32.lib;comctl32.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
 +      <GenerateDebugInformation>true</GenerateDebugInformation>
 +      <RandomizedBaseAddress>false</RandomizedBaseAddress>
 +      <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
 +      <SubSystem>Windows</SubSystem>
 +      <BaseAddress>0x19000000</BaseAddress>
 +      <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin10\lib</AdditionalLibraryDirectories>
 +    </Link>
 +  </ItemDefinitionGroup>
 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
 +    <ClCompile>
 +      <Optimization>Disabled</Optimization>
 +      <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
 +      <PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;MSN_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
 +      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
 +      <FunctionLevelLinking>true</FunctionLevelLinking>
 +      <FloatingPointModel>Fast</FloatingPointModel>
 +      <PrecompiledHeader>Use</PrecompiledHeader>
 +      <PrecompiledHeaderFile>msn_global.h</PrecompiledHeaderFile>
 +      <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
 +      <WarningLevel>Level3</WarningLevel>
 +      <ExceptionHandling>false</ExceptionHandling>
 +    </ClCompile>
 +    <ResourceCompile>
 +      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <AdditionalIncludeDirectories>..\..\include;..\..\include\msapi</AdditionalIncludeDirectories>
 +    </ResourceCompile>
 +    <Link>
 +      <AdditionalDependencies>ws2_32.lib;comctl32.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
 +      <AdditionalManifestDependencies>type=%27Win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 processorArchitecture=%27*%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;%(AdditionalManifestDependencies)</AdditionalManifestDependencies>
 +      <GenerateDebugInformation>true</GenerateDebugInformation>
 +      <RandomizedBaseAddress>false</RandomizedBaseAddress>
 +      <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
 +      <SubSystem>Windows</SubSystem>
 +      <BaseAddress>0x19000000</BaseAddress>
 +      <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin10\lib</AdditionalLibraryDirectories>
 +    </Link>
 +  </ItemDefinitionGroup>
 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
 +    <ClCompile>
 +      <Optimization>Full</Optimization>
 +      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
 +      <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
 +      <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
 +      <PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;MSN_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <StringPooling>true</StringPooling>
 +      <ExceptionHandling>false</ExceptionHandling>
 +      <BufferSecurityCheck>false</BufferSecurityCheck>
 +      <FunctionLevelLinking>true</FunctionLevelLinking>
 +      <FloatingPointModel>Fast</FloatingPointModel>
 +      <PrecompiledHeader>Use</PrecompiledHeader>
 +      <PrecompiledHeaderFile>msn_global.h</PrecompiledHeaderFile>
 +      <WarningLevel>Level3</WarningLevel>
 +      <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
 +    </ClCompile>
 +    <ResourceCompile>
 +      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <AdditionalIncludeDirectories>..\..\include;..\..\include\msapi</AdditionalIncludeDirectories>
 +    </ResourceCompile>
 +    <Link>
 +      <AdditionalOptions>/PDBALTPATH:%_PDB%</AdditionalOptions>
 +      <AdditionalDependencies>ws2_32.lib;comctl32.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
 +      <AdditionalManifestDependencies>type=%27Win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 processorArchitecture=%27X86%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;%(AdditionalManifestDependencies)</AdditionalManifestDependencies>
 +      <GenerateDebugInformation>true</GenerateDebugInformation>
 +      <OptimizeReferences>true</OptimizeReferences>
 +      <EnableCOMDATFolding>true</EnableCOMDATFolding>
 +      <BaseAddress>0x19000000</BaseAddress>
 +      <RandomizedBaseAddress>false</RandomizedBaseAddress>
 +      <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
 +      <SubSystem>Windows</SubSystem>
 +      <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin10\lib</AdditionalLibraryDirectories>
 +    </Link>
 +  </ItemDefinitionGroup>
 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
 +    <ClCompile>
 +      <Optimization>Full</Optimization>
 +      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
 +      <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
 +      <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
 +      <PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;MSN_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <StringPooling>true</StringPooling>
 +      <ExceptionHandling>false</ExceptionHandling>
 +      <BufferSecurityCheck>false</BufferSecurityCheck>
 +      <FunctionLevelLinking>true</FunctionLevelLinking>
 +      <FloatingPointModel>Fast</FloatingPointModel>
 +      <PrecompiledHeader>Use</PrecompiledHeader>
 +      <PrecompiledHeaderFile>msn_global.h</PrecompiledHeaderFile>
 +      <WarningLevel>Level3</WarningLevel>
 +      <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
 +    </ClCompile>
 +    <ResourceCompile>
 +      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <AdditionalIncludeDirectories>..\..\include;..\..\include\msapi</AdditionalIncludeDirectories>
 +    </ResourceCompile>
 +    <Link>
 +      <AdditionalOptions>/PDBALTPATH:%_PDB%</AdditionalOptions>
 +      <AdditionalDependencies>ws2_32.lib;comctl32.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
 +      <AdditionalManifestDependencies>type=%27Win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 processorArchitecture=%27*%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;%(AdditionalManifestDependencies)</AdditionalManifestDependencies>
 +      <GenerateDebugInformation>true</GenerateDebugInformation>
 +      <OptimizeReferences>true</OptimizeReferences>
 +      <EnableCOMDATFolding>true</EnableCOMDATFolding>
 +      <BaseAddress>0x19000000</BaseAddress>
 +      <RandomizedBaseAddress>false</RandomizedBaseAddress>
 +      <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
 +      <SubSystem>Windows</SubSystem>
 +      <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin10\lib</AdditionalLibraryDirectories>
 +    </Link>
 +  </ItemDefinitionGroup>
 +  <ItemGroup>
 +    <ClCompile Include="src\des.c">
 +      <PrecompiledHeader>NotUsing</PrecompiledHeader>
 +    </ClCompile>
 +    <ClCompile Include="src\ezxml.c">
 +      <PrecompiledHeader>NotUsing</PrecompiledHeader>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_avatar.cpp" />
 +    <ClCompile Include="src\stdafx.cpp">
 +      <PrecompiledHeader>Create</PrecompiledHeader>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_auth.cpp" />
 +    <ClCompile Include="src\msn_chat.cpp" />
 +    <ClCompile Include="src\msn_commands.cpp" />
 +    <ClCompile Include="src\msn_contact.cpp" />
 +    <ClCompile Include="src\msn_errors.cpp" />
 +    <ClCompile Include="src\msn_ftold.cpp" />
 +    <ClCompile Include="src\msn_http.cpp" />
 +    <ClCompile Include="src\msn_libstr.cpp" />
 +    <ClCompile Include="src\msn_links.cpp" />
 +    <ClCompile Include="src\msn_lists.cpp" />
 +    <ClCompile Include="src\msn_mail.cpp" />
 +    <ClCompile Include="src\msn_menu.cpp" />
 +    <ClCompile Include="src\msn_mime.cpp" />
 +    <ClCompile Include="src\msn_misc.cpp" />
 +    <ClCompile Include="src\msn_msgqueue.cpp" />
 +    <ClCompile Include="src\msn_msgsplit.cpp" />
 +    <ClCompile Include="src\msn_natdetect.cpp" />
 +    <ClCompile Include="src\msn_opts.cpp" />
 +    <ClCompile Include="src\msn_p2p.cpp" />
 +    <ClCompile Include="src\msn_p2ps.cpp" />
 +    <ClCompile Include="src\msn_proto.cpp" />
 +    <ClCompile Include="src\msn_soapab.cpp" />
 +    <ClCompile Include="src\msn_soapstore.cpp" />
 +    <ClCompile Include="src\msn_srv.cpp" />
 +    <ClCompile Include="src\msn_ssl.cpp" />
 +    <ClCompile Include="src\msn_std.cpp" />
 +    <ClCompile Include="src\msn_svcs.cpp" />
 +    <ClCompile Include="src\msn_switchboard.cpp" />
 +    <ClCompile Include="src\msn_threads.cpp" />
 +    <ClCompile Include="src\msn_ws.cpp" />
 +    <ClCompile Include="src\msn.cpp" />
 +  </ItemGroup>
 +  <ItemGroup>
 +    <ResourceCompile Include="res\msn.rc" />
 +    <ResourceCompile Include="res\version.rc" />
 +  </ItemGroup>
 +  <ItemGroup>
 +    <ClInclude Include="src\resource.h" />
 +    <ClInclude Include="src\des.h" />
 +    <ClInclude Include="src\ezxml.h" />
 +    <ClInclude Include="src\msn_global.h" />
 +    <ClInclude Include="src\msn_proto.h" />
 +    <ClInclude Include="src\version.h" />
 +  </ItemGroup>
 +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
 +  <ImportGroup Label="ExtensionTargets">
 +  </ImportGroup>
 +</Project>
\ No newline at end of file diff --git a/plugins/!Deprecated/MSN/msn_10.vcxproj.filters b/plugins/!Deprecated/MSN/msn_10.vcxproj.filters new file mode 100644 index 0000000000..b9585f0393 --- /dev/null +++ b/plugins/!Deprecated/MSN/msn_10.vcxproj.filters @@ -0,0 +1,151 @@ +<?xml version="1.0" encoding="utf-8"?>
 +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 +  <ItemGroup>
 +    <Filter Include="Source Files">
 +      <UniqueIdentifier>{f9e2dbb2-638e-4619-a597-b259fe9cb28c}</UniqueIdentifier>
 +      <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
 +    </Filter>
 +    <Filter Include="Resource Files">
 +      <UniqueIdentifier>{851bc859-759a-4ee2-a998-896565b85abc}</UniqueIdentifier>
 +      <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>
 +    </Filter>
 +    <Filter Include="Header Files">
 +      <UniqueIdentifier>{a696658a-8e44-4b58-b62e-1afe9b41c748}</UniqueIdentifier>
 +    </Filter>
 +  </ItemGroup>
 +  <ItemGroup>
 +    <ClCompile Include="src\des.c">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\ezxml.c">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_auth.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_chat.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_commands.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_contact.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_errors.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_ftold.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_http.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_libstr.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_links.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_lists.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_mail.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_menu.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_mime.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_misc.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_msgqueue.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_msgsplit.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_natdetect.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_opts.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_p2p.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_p2ps.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_proto.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_soapab.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_soapstore.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_srv.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_ssl.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_std.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_svcs.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_switchboard.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_threads.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_ws.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\stdafx.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_avatar.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +  </ItemGroup>
 +  <ItemGroup>
 +    <ResourceCompile Include="res\msn.rc">
 +      <Filter>Resource Files</Filter>
 +    </ResourceCompile>
 +    <ResourceCompile Include="res\version.rc">
 +      <Filter>Resource Files</Filter>
 +    </ResourceCompile>
 +  </ItemGroup>
 +  <ItemGroup>
 +    <ClInclude Include="src\resource.h">
 +      <Filter>Resource Files</Filter>
 +    </ClInclude>
 +    <ClInclude Include="src\des.h">
 +      <Filter>Header Files</Filter>
 +    </ClInclude>
 +    <ClInclude Include="src\ezxml.h">
 +      <Filter>Header Files</Filter>
 +    </ClInclude>
 +    <ClInclude Include="src\msn_global.h">
 +      <Filter>Header Files</Filter>
 +    </ClInclude>
 +    <ClInclude Include="src\msn_proto.h">
 +      <Filter>Header Files</Filter>
 +    </ClInclude>
 +    <ClInclude Include="src\version.h">
 +      <Filter>Header Files</Filter>
 +    </ClInclude>
 +  </ItemGroup>
 +</Project>
\ No newline at end of file diff --git a/plugins/!Deprecated/MSN/msn_12.vcxproj b/plugins/!Deprecated/MSN/msn_12.vcxproj new file mode 100644 index 0000000000..33657ea881 --- /dev/null +++ b/plugins/!Deprecated/MSN/msn_12.vcxproj @@ -0,0 +1,263 @@ +<?xml version="1.0" encoding="utf-8"?>
 +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 +  <ItemGroup Label="ProjectConfigurations">
 +    <ProjectConfiguration Include="Debug|Win32">
 +      <Configuration>Debug</Configuration>
 +      <Platform>Win32</Platform>
 +    </ProjectConfiguration>
 +    <ProjectConfiguration Include="Debug|x64">
 +      <Configuration>Debug</Configuration>
 +      <Platform>x64</Platform>
 +    </ProjectConfiguration>
 +    <ProjectConfiguration Include="Release|Win32">
 +      <Configuration>Release</Configuration>
 +      <Platform>Win32</Platform>
 +    </ProjectConfiguration>
 +    <ProjectConfiguration Include="Release|x64">
 +      <Configuration>Release</Configuration>
 +      <Platform>x64</Platform>
 +    </ProjectConfiguration>
 +  </ItemGroup>
 +  <PropertyGroup Label="Globals">
 +    <ProjectName>MSN</ProjectName>
 +    <ProjectGuid>{7B0F213E-C15E-4219-8AE5-49DD3D3D553D}</ProjectGuid>
 +  </PropertyGroup>
 +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
 +    <ConfigurationType>DynamicLibrary</ConfigurationType>
 +    <CharacterSet>Unicode</CharacterSet>
 +    <WholeProgramOptimization>true</WholeProgramOptimization>
 +    <PlatformToolset>v120_xp</PlatformToolset>
 +  </PropertyGroup>
 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
 +    <ConfigurationType>DynamicLibrary</ConfigurationType>
 +    <CharacterSet>Unicode</CharacterSet>
 +    <PlatformToolset>v120_xp</PlatformToolset>
 +  </PropertyGroup>
 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
 +    <ConfigurationType>DynamicLibrary</ConfigurationType>
 +    <CharacterSet>Unicode</CharacterSet>
 +    <WholeProgramOptimization>true</WholeProgramOptimization>
 +    <PlatformToolset>v120_xp</PlatformToolset>
 +  </PropertyGroup>
 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
 +    <ConfigurationType>DynamicLibrary</ConfigurationType>
 +    <CharacterSet>Unicode</CharacterSet>
 +    <PlatformToolset>v120_xp</PlatformToolset>
 +  </PropertyGroup>
 +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
 +  <ImportGroup Label="ExtensionSettings">
 +  </ImportGroup>
 +  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
 +    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
 +  </ImportGroup>
 +  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
 +    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
 +  </ImportGroup>
 +  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
 +    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
 +  </ImportGroup>
 +  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
 +    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
 +  </ImportGroup>
 +  <PropertyGroup Label="UserMacros" />
 +  <PropertyGroup>
 +    <_ProjectFileVersion>10.0.30128.1</_ProjectFileVersion>
 +    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Plugins\</OutDir>
 +    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
 +    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Plugins\</OutDir>
 +    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
 +    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Plugins\</OutDir>
 +    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
 +    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Plugins\</OutDir>
 +    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
 +    <IgnoreImportLibrary>true</IgnoreImportLibrary>
 +  </PropertyGroup>
 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
 +    <ClCompile>
 +      <Optimization>Disabled</Optimization>
 +      <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
 +      <PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;MSN_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
 +      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
 +      <FunctionLevelLinking>true</FunctionLevelLinking>
 +      <FloatingPointModel>Fast</FloatingPointModel>
 +      <PrecompiledHeader>Use</PrecompiledHeader>
 +      <PrecompiledHeaderFile>msn_global.h</PrecompiledHeaderFile>
 +      <WarningLevel>Level3</WarningLevel>
 +      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
 +      <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
 +      <ExceptionHandling>false</ExceptionHandling>
 +    </ClCompile>
 +    <ResourceCompile>
 +      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <AdditionalIncludeDirectories>..\..\include;..\..\include\msapi</AdditionalIncludeDirectories>
 +    </ResourceCompile>
 +    <Link>
 +      <AdditionalDependencies>ws2_32.lib;comctl32.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
 +      <GenerateDebugInformation>true</GenerateDebugInformation>
 +      <RandomizedBaseAddress>false</RandomizedBaseAddress>
 +      <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
 +      <SubSystem>Windows</SubSystem>
 +      <BaseAddress>0x19000000</BaseAddress>
 +      <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin12\lib</AdditionalLibraryDirectories>
 +      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
 +    </Link>
 +  </ItemDefinitionGroup>
 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
 +    <ClCompile>
 +      <Optimization>Disabled</Optimization>
 +      <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
 +      <PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;MSN_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
 +      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
 +      <FunctionLevelLinking>true</FunctionLevelLinking>
 +      <FloatingPointModel>Fast</FloatingPointModel>
 +      <PrecompiledHeader>Use</PrecompiledHeader>
 +      <PrecompiledHeaderFile>msn_global.h</PrecompiledHeaderFile>
 +      <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
 +      <WarningLevel>Level3</WarningLevel>
 +      <ExceptionHandling>false</ExceptionHandling>
 +    </ClCompile>
 +    <ResourceCompile>
 +      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <AdditionalIncludeDirectories>..\..\include;..\..\include\msapi</AdditionalIncludeDirectories>
 +    </ResourceCompile>
 +    <Link>
 +      <AdditionalDependencies>ws2_32.lib;comctl32.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
 +      <AdditionalManifestDependencies>type=%27Win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 processorArchitecture=%27*%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;%(AdditionalManifestDependencies)</AdditionalManifestDependencies>
 +      <GenerateDebugInformation>true</GenerateDebugInformation>
 +      <RandomizedBaseAddress>false</RandomizedBaseAddress>
 +      <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
 +      <SubSystem>Windows</SubSystem>
 +      <BaseAddress>0x19000000</BaseAddress>
 +      <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin12\lib</AdditionalLibraryDirectories>
 +    </Link>
 +  </ItemDefinitionGroup>
 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
 +    <ClCompile>
 +      <Optimization>Full</Optimization>
 +      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
 +      <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
 +      <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
 +      <PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;MSN_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <StringPooling>true</StringPooling>
 +      <ExceptionHandling>false</ExceptionHandling>
 +      <BufferSecurityCheck>false</BufferSecurityCheck>
 +      <FunctionLevelLinking>true</FunctionLevelLinking>
 +      <FloatingPointModel>Fast</FloatingPointModel>
 +      <PrecompiledHeader>Use</PrecompiledHeader>
 +      <PrecompiledHeaderFile>msn_global.h</PrecompiledHeaderFile>
 +      <WarningLevel>Level3</WarningLevel>
 +      <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
 +    </ClCompile>
 +    <ResourceCompile>
 +      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <AdditionalIncludeDirectories>..\..\include;..\..\include\msapi</AdditionalIncludeDirectories>
 +    </ResourceCompile>
 +    <Link>
 +      <AdditionalDependencies>ws2_32.lib;comctl32.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
 +      <AdditionalManifestDependencies>type=%27Win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 processorArchitecture=%27X86%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;%(AdditionalManifestDependencies)</AdditionalManifestDependencies>
 +      <GenerateDebugInformation>true</GenerateDebugInformation>
 +      <OptimizeReferences>true</OptimizeReferences>
 +      <EnableCOMDATFolding>true</EnableCOMDATFolding>
 +      <BaseAddress>0x19000000</BaseAddress>
 +      <RandomizedBaseAddress>false</RandomizedBaseAddress>
 +      <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
 +      <SubSystem>Windows</SubSystem>
 +      <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin12\lib</AdditionalLibraryDirectories>
 +    </Link>
 +  </ItemDefinitionGroup>
 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
 +    <ClCompile>
 +      <Optimization>Full</Optimization>
 +      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
 +      <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
 +      <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
 +      <PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;MSN_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <StringPooling>true</StringPooling>
 +      <ExceptionHandling>false</ExceptionHandling>
 +      <BufferSecurityCheck>false</BufferSecurityCheck>
 +      <FunctionLevelLinking>true</FunctionLevelLinking>
 +      <FloatingPointModel>Fast</FloatingPointModel>
 +      <PrecompiledHeader>Use</PrecompiledHeader>
 +      <PrecompiledHeaderFile>msn_global.h</PrecompiledHeaderFile>
 +      <WarningLevel>Level3</WarningLevel>
 +      <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
 +    </ClCompile>
 +    <ResourceCompile>
 +      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <AdditionalIncludeDirectories>..\..\include;..\..\include\msapi</AdditionalIncludeDirectories>
 +    </ResourceCompile>
 +    <Link>
 +      <AdditionalDependencies>ws2_32.lib;comctl32.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
 +      <AdditionalManifestDependencies>type=%27Win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 processorArchitecture=%27*%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;%(AdditionalManifestDependencies)</AdditionalManifestDependencies>
 +      <GenerateDebugInformation>true</GenerateDebugInformation>
 +      <OptimizeReferences>true</OptimizeReferences>
 +      <EnableCOMDATFolding>true</EnableCOMDATFolding>
 +      <BaseAddress>0x19000000</BaseAddress>
 +      <RandomizedBaseAddress>false</RandomizedBaseAddress>
 +      <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
 +      <SubSystem>Windows</SubSystem>
 +      <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin12\lib</AdditionalLibraryDirectories>
 +    </Link>
 +  </ItemDefinitionGroup>
 +  <ItemGroup>
 +    <ClCompile Include="src\des.c">
 +      <PrecompiledHeader>NotUsing</PrecompiledHeader>
 +    </ClCompile>
 +    <ClCompile Include="src\ezxml.c">
 +      <PrecompiledHeader>NotUsing</PrecompiledHeader>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_avatar.cpp" />
 +    <ClCompile Include="src\stdafx.cpp">
 +      <PrecompiledHeader>Create</PrecompiledHeader>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_auth.cpp" />
 +    <ClCompile Include="src\msn_chat.cpp" />
 +    <ClCompile Include="src\msn_commands.cpp" />
 +    <ClCompile Include="src\msn_contact.cpp" />
 +    <ClCompile Include="src\msn_errors.cpp" />
 +    <ClCompile Include="src\msn_ftold.cpp" />
 +    <ClCompile Include="src\msn_http.cpp" />
 +    <ClCompile Include="src\msn_libstr.cpp" />
 +    <ClCompile Include="src\msn_links.cpp" />
 +    <ClCompile Include="src\msn_lists.cpp" />
 +    <ClCompile Include="src\msn_mail.cpp" />
 +    <ClCompile Include="src\msn_menu.cpp" />
 +    <ClCompile Include="src\msn_mime.cpp" />
 +    <ClCompile Include="src\msn_misc.cpp" />
 +    <ClCompile Include="src\msn_msgqueue.cpp" />
 +    <ClCompile Include="src\msn_msgsplit.cpp" />
 +    <ClCompile Include="src\msn_natdetect.cpp" />
 +    <ClCompile Include="src\msn_opts.cpp" />
 +    <ClCompile Include="src\msn_p2p.cpp" />
 +    <ClCompile Include="src\msn_p2ps.cpp" />
 +    <ClCompile Include="src\msn_proto.cpp" />
 +    <ClCompile Include="src\msn_soapab.cpp" />
 +    <ClCompile Include="src\msn_soapstore.cpp" />
 +    <ClCompile Include="src\msn_srv.cpp" />
 +    <ClCompile Include="src\msn_ssl.cpp" />
 +    <ClCompile Include="src\msn_std.cpp" />
 +    <ClCompile Include="src\msn_svcs.cpp" />
 +    <ClCompile Include="src\msn_switchboard.cpp" />
 +    <ClCompile Include="src\msn_threads.cpp" />
 +    <ClCompile Include="src\msn_ws.cpp" />
 +    <ClCompile Include="src\msn.cpp" />
 +  </ItemGroup>
 +  <ItemGroup>
 +    <ResourceCompile Include="res\msn.rc" />
 +    <ResourceCompile Include="res\version.rc" />
 +  </ItemGroup>
 +  <ItemGroup>
 +    <ClInclude Include="src\resource.h" />
 +    <ClInclude Include="src\des.h" />
 +    <ClInclude Include="src\ezxml.h" />
 +    <ClInclude Include="src\msn_global.h" />
 +    <ClInclude Include="src\msn_proto.h" />
 +    <ClInclude Include="src\version.h" />
 +  </ItemGroup>
 +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
 +  <ImportGroup Label="ExtensionTargets">
 +  </ImportGroup>
 +</Project>
\ No newline at end of file diff --git a/plugins/!Deprecated/MSN/msn_12.vcxproj.filters b/plugins/!Deprecated/MSN/msn_12.vcxproj.filters new file mode 100644 index 0000000000..b9585f0393 --- /dev/null +++ b/plugins/!Deprecated/MSN/msn_12.vcxproj.filters @@ -0,0 +1,151 @@ +<?xml version="1.0" encoding="utf-8"?>
 +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 +  <ItemGroup>
 +    <Filter Include="Source Files">
 +      <UniqueIdentifier>{f9e2dbb2-638e-4619-a597-b259fe9cb28c}</UniqueIdentifier>
 +      <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
 +    </Filter>
 +    <Filter Include="Resource Files">
 +      <UniqueIdentifier>{851bc859-759a-4ee2-a998-896565b85abc}</UniqueIdentifier>
 +      <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>
 +    </Filter>
 +    <Filter Include="Header Files">
 +      <UniqueIdentifier>{a696658a-8e44-4b58-b62e-1afe9b41c748}</UniqueIdentifier>
 +    </Filter>
 +  </ItemGroup>
 +  <ItemGroup>
 +    <ClCompile Include="src\des.c">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\ezxml.c">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_auth.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_chat.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_commands.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_contact.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_errors.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_ftold.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_http.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_libstr.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_links.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_lists.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_mail.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_menu.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_mime.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_misc.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_msgqueue.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_msgsplit.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_natdetect.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_opts.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_p2p.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_p2ps.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_proto.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_soapab.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_soapstore.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_srv.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_ssl.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_std.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_svcs.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_switchboard.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_threads.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_ws.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\stdafx.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +    <ClCompile Include="src\msn_avatar.cpp">
 +      <Filter>Source Files</Filter>
 +    </ClCompile>
 +  </ItemGroup>
 +  <ItemGroup>
 +    <ResourceCompile Include="res\msn.rc">
 +      <Filter>Resource Files</Filter>
 +    </ResourceCompile>
 +    <ResourceCompile Include="res\version.rc">
 +      <Filter>Resource Files</Filter>
 +    </ResourceCompile>
 +  </ItemGroup>
 +  <ItemGroup>
 +    <ClInclude Include="src\resource.h">
 +      <Filter>Resource Files</Filter>
 +    </ClInclude>
 +    <ClInclude Include="src\des.h">
 +      <Filter>Header Files</Filter>
 +    </ClInclude>
 +    <ClInclude Include="src\ezxml.h">
 +      <Filter>Header Files</Filter>
 +    </ClInclude>
 +    <ClInclude Include="src\msn_global.h">
 +      <Filter>Header Files</Filter>
 +    </ClInclude>
 +    <ClInclude Include="src\msn_proto.h">
 +      <Filter>Header Files</Filter>
 +    </ClInclude>
 +    <ClInclude Include="src\version.h">
 +      <Filter>Header Files</Filter>
 +    </ClInclude>
 +  </ItemGroup>
 +</Project>
\ No newline at end of file diff --git a/plugins/!Deprecated/MSN/proto_msn/Proto_MSN_10.vcxproj b/plugins/!Deprecated/MSN/proto_msn/Proto_MSN_10.vcxproj new file mode 100644 index 0000000000..b1f887ef0e --- /dev/null +++ b/plugins/!Deprecated/MSN/proto_msn/Proto_MSN_10.vcxproj @@ -0,0 +1,131 @@ +<?xml version="1.0" encoding="utf-8"?>
 +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 +  <ItemGroup Label="ProjectConfigurations">
 +    <ProjectConfiguration Include="Debug|Win32">
 +      <Configuration>Debug</Configuration>
 +      <Platform>Win32</Platform>
 +    </ProjectConfiguration>
 +    <ProjectConfiguration Include="Debug|x64">
 +      <Configuration>Debug</Configuration>
 +      <Platform>x64</Platform>
 +    </ProjectConfiguration>
 +    <ProjectConfiguration Include="Release|Win32">
 +      <Configuration>Release</Configuration>
 +      <Platform>Win32</Platform>
 +    </ProjectConfiguration>
 +    <ProjectConfiguration Include="Release|x64">
 +      <Configuration>Release</Configuration>
 +      <Platform>x64</Platform>
 +    </ProjectConfiguration>
 +  </ItemGroup>
 +  <PropertyGroup Label="Globals">
 +    <ProjectGuid>{7BC6C3E7-2B17-4718-A82E-084798710E14}</ProjectGuid>
 +    <ProjectName>Proto_MSN</ProjectName>
 +  </PropertyGroup>
 +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
 +    <ConfigurationType>DynamicLibrary</ConfigurationType>
 +    <UseDebugLibraries>true</UseDebugLibraries>
 +    <CharacterSet>Unicode</CharacterSet>
 +  </PropertyGroup>
 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
 +    <ConfigurationType>DynamicLibrary</ConfigurationType>
 +    <UseDebugLibraries>true</UseDebugLibraries>
 +    <CharacterSet>Unicode</CharacterSet>
 +  </PropertyGroup>
 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
 +    <ConfigurationType>DynamicLibrary</ConfigurationType>
 +    <UseDebugLibraries>false</UseDebugLibraries>
 +    <CharacterSet>Unicode</CharacterSet>
 +  </PropertyGroup>
 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
 +    <ConfigurationType>DynamicLibrary</ConfigurationType>
 +    <UseDebugLibraries>false</UseDebugLibraries>
 +    <CharacterSet>Unicode</CharacterSet>
 +  </PropertyGroup>
 +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
 +  <ImportGroup Label="ExtensionSettings">
 +  </ImportGroup>
 +  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
 +    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
 +  </ImportGroup>
 +  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
 +    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
 +  </ImportGroup>
 +  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
 +    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
 +  </ImportGroup>
 +  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
 +    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
 +  </ImportGroup>
 +  <PropertyGroup Label="UserMacros" />
 +  <PropertyGroup>
 +    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
 +    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Icons\</OutDir>
 +    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Icons\</OutDir>
 +    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
 +    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
 +    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Icons\</OutDir>
 +    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Icons\</OutDir>
 +    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
 +    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
 +    <IgnoreImportLibrary>true</IgnoreImportLibrary>
 +  </PropertyGroup>
 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
 +    <Link>
 +      <SubSystem>Windows</SubSystem>
 +      <NoEntryPoint>true</NoEntryPoint>
 +      <RandomizedBaseAddress>false</RandomizedBaseAddress>
 +      <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
 +    </Link>
 +    <ResourceCompile>
 +      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <AdditionalIncludeDirectories>..\..\..\include\msapi</AdditionalIncludeDirectories>
 +    </ResourceCompile>
 +  </ItemDefinitionGroup>
 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
 +    <Link>
 +      <SubSystem>Windows</SubSystem>
 +      <NoEntryPoint>true</NoEntryPoint>
 +      <RandomizedBaseAddress>false</RandomizedBaseAddress>
 +      <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
 +    </Link>
 +    <ResourceCompile>
 +      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <AdditionalIncludeDirectories>..\..\..\include\msapi</AdditionalIncludeDirectories>
 +    </ResourceCompile>
 +  </ItemDefinitionGroup>
 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
 +    <Link>
 +      <SubSystem>Windows</SubSystem>
 +      <NoEntryPoint>true</NoEntryPoint>
 +      <RandomizedBaseAddress>false</RandomizedBaseAddress>
 +      <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
 +    </Link>
 +    <ResourceCompile>
 +      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <AdditionalIncludeDirectories>..\..\..\include\msapi</AdditionalIncludeDirectories>
 +    </ResourceCompile>
 +  </ItemDefinitionGroup>
 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
 +    <Link>
 +      <SubSystem>Windows</SubSystem>
 +      <NoEntryPoint>true</NoEntryPoint>
 +      <RandomizedBaseAddress>false</RandomizedBaseAddress>
 +      <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
 +    </Link>
 +    <ResourceCompile>
 +      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <AdditionalIncludeDirectories>..\..\..\include\msapi</AdditionalIncludeDirectories>
 +    </ResourceCompile>
 +  </ItemDefinitionGroup>
 +  <ItemGroup>
 +    <ClInclude Include="src\resource.h" />
 +  </ItemGroup>
 +  <ItemGroup>
 +    <ResourceCompile Include="res\Proto_MSN.rc" />
 +  </ItemGroup>
 +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
 +  <ImportGroup Label="ExtensionTargets">
 +  </ImportGroup>
 +</Project>
\ No newline at end of file diff --git a/plugins/!Deprecated/MSN/proto_msn/Proto_MSN_10.vcxproj.filters b/plugins/!Deprecated/MSN/proto_msn/Proto_MSN_10.vcxproj.filters new file mode 100644 index 0000000000..13a42fab36 --- /dev/null +++ b/plugins/!Deprecated/MSN/proto_msn/Proto_MSN_10.vcxproj.filters @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?>
 +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 +  <ItemGroup>
 +    <Filter Include="Header Files">
 +      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
 +      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
 +    </Filter>
 +    <Filter Include="Resource Files">
 +      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
 +      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
 +    </Filter>
 +  </ItemGroup>
 +  <ItemGroup>
 +    <ClInclude Include="src\resource.h">
 +      <Filter>Header Files</Filter>
 +    </ClInclude>
 +  </ItemGroup>
 +  <ItemGroup>
 +    <ResourceCompile Include="res\Proto_MSN.rc">
 +      <Filter>Resource Files</Filter>
 +    </ResourceCompile>
 +  </ItemGroup>
 +</Project>
\ No newline at end of file diff --git a/plugins/!Deprecated/MSN/proto_msn/Proto_MSN_12.vcxproj b/plugins/!Deprecated/MSN/proto_msn/Proto_MSN_12.vcxproj new file mode 100644 index 0000000000..e85378ccbb --- /dev/null +++ b/plugins/!Deprecated/MSN/proto_msn/Proto_MSN_12.vcxproj @@ -0,0 +1,135 @@ +<?xml version="1.0" encoding="utf-8"?>
 +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 +  <ItemGroup Label="ProjectConfigurations">
 +    <ProjectConfiguration Include="Debug|Win32">
 +      <Configuration>Debug</Configuration>
 +      <Platform>Win32</Platform>
 +    </ProjectConfiguration>
 +    <ProjectConfiguration Include="Debug|x64">
 +      <Configuration>Debug</Configuration>
 +      <Platform>x64</Platform>
 +    </ProjectConfiguration>
 +    <ProjectConfiguration Include="Release|Win32">
 +      <Configuration>Release</Configuration>
 +      <Platform>Win32</Platform>
 +    </ProjectConfiguration>
 +    <ProjectConfiguration Include="Release|x64">
 +      <Configuration>Release</Configuration>
 +      <Platform>x64</Platform>
 +    </ProjectConfiguration>
 +  </ItemGroup>
 +  <PropertyGroup Label="Globals">
 +    <ProjectGuid>{7BC6C3E7-2B17-4718-A82E-084798710E14}</ProjectGuid>
 +    <ProjectName>Proto_MSN</ProjectName>
 +  </PropertyGroup>
 +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
 +    <ConfigurationType>DynamicLibrary</ConfigurationType>
 +    <UseDebugLibraries>true</UseDebugLibraries>
 +    <CharacterSet>Unicode</CharacterSet>
 +    <PlatformToolset>v120_xp</PlatformToolset>
 +  </PropertyGroup>
 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
 +    <ConfigurationType>DynamicLibrary</ConfigurationType>
 +    <UseDebugLibraries>true</UseDebugLibraries>
 +    <CharacterSet>Unicode</CharacterSet>
 +    <PlatformToolset>v120_xp</PlatformToolset>
 +  </PropertyGroup>
 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
 +    <ConfigurationType>DynamicLibrary</ConfigurationType>
 +    <UseDebugLibraries>false</UseDebugLibraries>
 +    <CharacterSet>Unicode</CharacterSet>
 +    <PlatformToolset>v120_xp</PlatformToolset>
 +  </PropertyGroup>
 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
 +    <ConfigurationType>DynamicLibrary</ConfigurationType>
 +    <UseDebugLibraries>false</UseDebugLibraries>
 +    <CharacterSet>Unicode</CharacterSet>
 +    <PlatformToolset>v120_xp</PlatformToolset>
 +  </PropertyGroup>
 +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
 +  <ImportGroup Label="ExtensionSettings">
 +  </ImportGroup>
 +  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
 +    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
 +  </ImportGroup>
 +  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
 +    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
 +  </ImportGroup>
 +  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
 +    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
 +  </ImportGroup>
 +  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
 +    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
 +  </ImportGroup>
 +  <PropertyGroup Label="UserMacros" />
 +  <PropertyGroup>
 +    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
 +    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Icons\</OutDir>
 +    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Icons\</OutDir>
 +    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
 +    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
 +    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Icons\</OutDir>
 +    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Icons\</OutDir>
 +    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
 +    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
 +    <IgnoreImportLibrary>true</IgnoreImportLibrary>
 +  </PropertyGroup>
 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
 +    <Link>
 +      <SubSystem>Windows</SubSystem>
 +      <NoEntryPoint>true</NoEntryPoint>
 +      <RandomizedBaseAddress>false</RandomizedBaseAddress>
 +      <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
 +    </Link>
 +    <ResourceCompile>
 +      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <AdditionalIncludeDirectories>..\..\..\include\msapi</AdditionalIncludeDirectories>
 +    </ResourceCompile>
 +  </ItemDefinitionGroup>
 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
 +    <Link>
 +      <SubSystem>Windows</SubSystem>
 +      <NoEntryPoint>true</NoEntryPoint>
 +      <RandomizedBaseAddress>false</RandomizedBaseAddress>
 +      <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
 +    </Link>
 +    <ResourceCompile>
 +      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <AdditionalIncludeDirectories>..\..\..\include\msapi</AdditionalIncludeDirectories>
 +    </ResourceCompile>
 +  </ItemDefinitionGroup>
 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
 +    <Link>
 +      <SubSystem>Windows</SubSystem>
 +      <NoEntryPoint>true</NoEntryPoint>
 +      <RandomizedBaseAddress>false</RandomizedBaseAddress>
 +      <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
 +    </Link>
 +    <ResourceCompile>
 +      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <AdditionalIncludeDirectories>..\..\..\include\msapi</AdditionalIncludeDirectories>
 +    </ResourceCompile>
 +  </ItemDefinitionGroup>
 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
 +    <Link>
 +      <SubSystem>Windows</SubSystem>
 +      <NoEntryPoint>true</NoEntryPoint>
 +      <RandomizedBaseAddress>false</RandomizedBaseAddress>
 +      <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
 +    </Link>
 +    <ResourceCompile>
 +      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
 +      <AdditionalIncludeDirectories>..\..\..\include\msapi</AdditionalIncludeDirectories>
 +    </ResourceCompile>
 +  </ItemDefinitionGroup>
 +  <ItemGroup>
 +    <ClInclude Include="src\resource.h" />
 +  </ItemGroup>
 +  <ItemGroup>
 +    <ResourceCompile Include="res\Proto_MSN.rc" />
 +  </ItemGroup>
 +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
 +  <ImportGroup Label="ExtensionTargets">
 +  </ImportGroup>
 +</Project>
\ No newline at end of file diff --git a/plugins/!Deprecated/MSN/proto_msn/Proto_MSN_12.vcxproj.filters b/plugins/!Deprecated/MSN/proto_msn/Proto_MSN_12.vcxproj.filters new file mode 100644 index 0000000000..13a42fab36 --- /dev/null +++ b/plugins/!Deprecated/MSN/proto_msn/Proto_MSN_12.vcxproj.filters @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?>
 +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 +  <ItemGroup>
 +    <Filter Include="Header Files">
 +      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
 +      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
 +    </Filter>
 +    <Filter Include="Resource Files">
 +      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
 +      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
 +    </Filter>
 +  </ItemGroup>
 +  <ItemGroup>
 +    <ClInclude Include="src\resource.h">
 +      <Filter>Header Files</Filter>
 +    </ClInclude>
 +  </ItemGroup>
 +  <ItemGroup>
 +    <ResourceCompile Include="res\Proto_MSN.rc">
 +      <Filter>Resource Files</Filter>
 +    </ResourceCompile>
 +  </ItemGroup>
 +</Project>
\ No newline at end of file diff --git a/plugins/!Deprecated/MSN/proto_msn/res/Away.ico b/plugins/!Deprecated/MSN/proto_msn/res/Away.ico Binary files differnew file mode 100644 index 0000000000..861c161ed1 --- /dev/null +++ b/plugins/!Deprecated/MSN/proto_msn/res/Away.ico diff --git a/plugins/!Deprecated/MSN/proto_msn/res/Invisible.ico b/plugins/!Deprecated/MSN/proto_msn/res/Invisible.ico Binary files differnew file mode 100644 index 0000000000..382e3bf50d --- /dev/null +++ b/plugins/!Deprecated/MSN/proto_msn/res/Invisible.ico diff --git a/plugins/!Deprecated/MSN/proto_msn/res/Occupied.ico b/plugins/!Deprecated/MSN/proto_msn/res/Occupied.ico Binary files differnew file mode 100644 index 0000000000..47c63a4214 --- /dev/null +++ b/plugins/!Deprecated/MSN/proto_msn/res/Occupied.ico diff --git a/plugins/!Deprecated/MSN/proto_msn/res/Offline.ico b/plugins/!Deprecated/MSN/proto_msn/res/Offline.ico Binary files differnew file mode 100644 index 0000000000..d52328aa47 --- /dev/null +++ b/plugins/!Deprecated/MSN/proto_msn/res/Offline.ico diff --git a/plugins/!Deprecated/MSN/proto_msn/res/Online.ico b/plugins/!Deprecated/MSN/proto_msn/res/Online.ico Binary files differnew file mode 100644 index 0000000000..7388d3928f --- /dev/null +++ b/plugins/!Deprecated/MSN/proto_msn/res/Online.ico diff --git a/plugins/!Deprecated/MSN/proto_msn/res/Phone.ico b/plugins/!Deprecated/MSN/proto_msn/res/Phone.ico Binary files differnew file mode 100644 index 0000000000..144bc48e59 --- /dev/null +++ b/plugins/!Deprecated/MSN/proto_msn/res/Phone.ico diff --git a/plugins/!Deprecated/MSN/proto_msn/res/Proto_MSN.rc b/plugins/!Deprecated/MSN/proto_msn/res/Proto_MSN.rc new file mode 100644 index 0000000000..6d2a82de81 --- /dev/null +++ b/plugins/!Deprecated/MSN/proto_msn/res/Proto_MSN.rc @@ -0,0 +1,74 @@ +// Microsoft Visual C++ generated resource script.
 +//
 +#include "..\src\resource.h"
 +
 +#define APSTUDIO_READONLY_SYMBOLS
 +/////////////////////////////////////////////////////////////////////////////
 +//
 +// Generated from the TEXTINCLUDE 2 resource.
 +//
 +#include "afxres.h"
 +
 +/////////////////////////////////////////////////////////////////////////////
 +#undef APSTUDIO_READONLY_SYMBOLS
 +
 +/////////////////////////////////////////////////////////////////////////////
 +// Russian (Russia) resources
 +
 +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
 +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
 +
 +#ifdef APSTUDIO_INVOKED
 +/////////////////////////////////////////////////////////////////////////////
 +//
 +// TEXTINCLUDE
 +//
 +
 +1 TEXTINCLUDE 
 +BEGIN
 +    "..\\src\\resource.h\0"
 +END
 +
 +2 TEXTINCLUDE 
 +BEGIN
 +    "#include ""afxres.h""\r\n"
 +    "\0"
 +END
 +
 +3 TEXTINCLUDE 
 +BEGIN
 +    "\r\n"
 +    "\0"
 +END
 +
 +#endif    // APSTUDIO_INVOKED
 +
 +
 +/////////////////////////////////////////////////////////////////////////////
 +//
 +// Icon
 +//
 +
 +// Icon with lowest ID value placed first to ensure application icon
 +// remains consistent on all systems.
 +IDI_ICON1               ICON                    "Offline.ico"
 +IDI_ICON2               ICON                    "Online.ico"
 +IDI_ICON3               ICON                    "Away.ico"
 +IDI_ICON4               ICON                    "Invisible.ico"
 +IDI_ICON6               ICON                    "Occupied.ico"
 +IDI_ICON8               ICON                    "Phone.ico"
 +#endif    // Russian (Russia) resources
 +/////////////////////////////////////////////////////////////////////////////
 +
 +
 +
 +#ifndef APSTUDIO_INVOKED
 +/////////////////////////////////////////////////////////////////////////////
 +//
 +// Generated from the TEXTINCLUDE 3 resource.
 +//
 +
 +
 +/////////////////////////////////////////////////////////////////////////////
 +#endif    // not APSTUDIO_INVOKED
 +
 diff --git a/plugins/!Deprecated/MSN/proto_msn/src/resource.h b/plugins/!Deprecated/MSN/proto_msn/src/resource.h new file mode 100644 index 0000000000..2842dcf4f3 --- /dev/null +++ b/plugins/!Deprecated/MSN/proto_msn/src/resource.h @@ -0,0 +1,21 @@ +//{{NO_DEPENDENCIES}}
 +// Microsoft Visual C++ generated include file.
 +// Used by Proto_MSN.rc
 +//
 +#define IDI_ICON1                       105
 +#define IDI_ICON2                       104
 +#define IDI_ICON3                       128
 +#define IDI_ICON4                       130
 +#define IDI_ICON6                       159
 +#define IDI_ICON8                       1002
 +
 +// Next default values for new objects
 +// 
 +#ifdef APSTUDIO_INVOKED
 +#ifndef APSTUDIO_READONLY_SYMBOLS
 +#define _APS_NEXT_RESOURCE_VALUE        109
 +#define _APS_NEXT_COMMAND_VALUE         40001
 +#define _APS_NEXT_CONTROL_VALUE         1001
 +#define _APS_NEXT_SYMED_VALUE           101
 +#endif
 +#endif
 diff --git a/plugins/!Deprecated/MSN/res/inbox.ico b/plugins/!Deprecated/MSN/res/inbox.ico Binary files differnew file mode 100644 index 0000000000..7a5e461f6f --- /dev/null +++ b/plugins/!Deprecated/MSN/res/inbox.ico diff --git a/plugins/!Deprecated/MSN/res/invite.ico b/plugins/!Deprecated/MSN/res/invite.ico Binary files differnew file mode 100644 index 0000000000..25bd23be86 --- /dev/null +++ b/plugins/!Deprecated/MSN/res/invite.ico diff --git a/plugins/!Deprecated/MSN/res/list_al.ico b/plugins/!Deprecated/MSN/res/list_al.ico Binary files differnew file mode 100644 index 0000000000..05bd93fac4 --- /dev/null +++ b/plugins/!Deprecated/MSN/res/list_al.ico diff --git a/plugins/!Deprecated/MSN/res/list_bl.ico b/plugins/!Deprecated/MSN/res/list_bl.ico Binary files differnew file mode 100644 index 0000000000..58d39b6fcf --- /dev/null +++ b/plugins/!Deprecated/MSN/res/list_bl.ico diff --git a/plugins/!Deprecated/MSN/res/list_fl.ico b/plugins/!Deprecated/MSN/res/list_fl.ico Binary files differnew file mode 100644 index 0000000000..fb77874fc4 --- /dev/null +++ b/plugins/!Deprecated/MSN/res/list_fl.ico diff --git a/plugins/!Deprecated/MSN/res/list_ph.ico b/plugins/!Deprecated/MSN/res/list_ph.ico Binary files differnew file mode 100644 index 0000000000..da5a991a0c --- /dev/null +++ b/plugins/!Deprecated/MSN/res/list_ph.ico diff --git a/plugins/!Deprecated/MSN/res/list_rl.ico b/plugins/!Deprecated/MSN/res/list_rl.ico Binary files differnew file mode 100644 index 0000000000..1e22656d1d --- /dev/null +++ b/plugins/!Deprecated/MSN/res/list_rl.ico diff --git a/plugins/!Deprecated/MSN/res/msn.ico b/plugins/!Deprecated/MSN/res/msn.ico Binary files differnew file mode 100644 index 0000000000..818824f3a0 --- /dev/null +++ b/plugins/!Deprecated/MSN/res/msn.ico diff --git a/plugins/!Deprecated/MSN/res/msn.rc b/plugins/!Deprecated/MSN/res/msn.rc new file mode 100644 index 0000000000..b8b9fa5d98 --- /dev/null +++ b/plugins/!Deprecated/MSN/res/msn.rc @@ -0,0 +1,367 @@ +// Microsoft Visual C++ generated resource script.
 +//
 +#include "..\src\resource.h"
 +
 +#define APSTUDIO_READONLY_SYMBOLS
 +/////////////////////////////////////////////////////////////////////////////
 +//
 +// Generated from the TEXTINCLUDE 2 resource.
 +//
 +#include <windows.h>
 +
 +/////////////////////////////////////////////////////////////////////////////
 +#undef APSTUDIO_READONLY_SYMBOLS
 +
 +/////////////////////////////////////////////////////////////////////////////
 +// Neutral resources
 +
 +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
 +#pragma code_page(1252)
 +
 +/////////////////////////////////////////////////////////////////////////////
 +//
 +// Dialog
 +//
 +
 +IDD_OPT_MSN DIALOGEX 0, 0, 304, 176
 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
 +EXSTYLE WS_EX_CONTROLPARENT
 +FONT 8, "MS Shell Dlg", 0, 0, 0x1
 +BEGIN
 +    GROUPBOX        "MSN",IDC_STMSNGROUP,5,0,298,84,WS_GROUP
 +    RTEXT           "Live ID:",IDC_STATIC,16,20,52,8
 +    EDITTEXT        IDC_HANDLE,72,18,100,12,ES_AUTOHSCROLL
 +    RTEXT           "Password:",IDC_STATIC,16,36,52,8
 +    EDITTEXT        IDC_PASSWORD,72,34,100,12,ES_PASSWORD | ES_AUTOHSCROLL
 +    RTEXT           "Nickname:",IDC_STATIC,16,52,52,8
 +    EDITTEXT        IDC_HANDLE2,72,50,100,12,ES_AUTOHSCROLL
 +    CONTROL         "Create a new Windows Live account",IDC_NEWMSNACCOUNTLINK,
 +                    "Hyperlink",WS_TABSTOP,21,68,208,8
 +    GROUPBOX        "Expert",IDC_STATIC,4,84,298,88,WS_GROUP
 +    CONTROL         "Send message font color/size info inside messages",IDC_SENDFONTINFO,
 +                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,95,280,10
 +    CONTROL         "Disable all contacts not included into my contact list",IDC_DISABLE_ANOTHER_CONTACTS,
 +                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,106,280,10
 +    CONTROL         "Manage server groups",IDC_MANAGEGROUPS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,116,280,10
 +    CONTROL         "Allow people on my contact list send messages to mobile device",IDC_MOBILESEND,
 +                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,126,280,10
 +    CONTROL         "Run the following application when new Hotmail arrives",IDC_RUN_APP_ON_HOTMAIL,
 +                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,137,280,10
 +    EDITTEXT        IDC_MAILER_APP,22,153,237,12,ES_AUTOHSCROLL
 +    PUSHBUTTON      "...",IDC_ENTER_MAILER_APP,265,153,15,12
 +END
 +
 +IDD_OPT_MSN_CONN DIALOGEX 0, 0, 304, 127
 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
 +EXSTYLE WS_EX_CONTROLPARENT
 +FONT 8, "MS Shell Dlg", 0, 0, 0x1
 +BEGIN
 +    GROUPBOX        "Connection settings",IDC_STATIC,4,3,298,64
 +    RTEXT           "Direct:",IDC_STATIC,10,18,52,8
 +    EDITTEXT        IDC_DIRECTSERVER,68,16,135,12,ES_AUTOHSCROLL
 +    LTEXT           " 1863",IDC_STATIC,209,16,28,12,SS_SUNKEN
 +    RTEXT           "Gateway:",IDC_STATIC,10,32,52,8
 +    EDITTEXT        IDC_GATEWAYSERVER,68,30,135,12,ES_AUTOHSCROLL
 +    CONTROL         " 80",IDC_STATIC,"Static",SS_SIMPLE | SS_SUNKEN | WS_GROUP,209,30,28,12
 +    PUSHBUTTON      "Reset",IDC_RESETSERVER,244,16,48,12
 +    CONTROL         "Notify me when a message delivery has failed",IDC_SLOWSEND,
 +                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,49,285,8
 +    GROUPBOX        "Incoming file transfers",IDC_STATIC,4,74,298,48
 +    COMBOBOX        IDC_HOSTOPT,10,86,285,30,CBS_DROPDOWNLIST | WS_TABSTOP
 +    RTEXT           "Your host (or router):",IDC_STATIC,10,103,90,8
 +    EDITTEXT        IDC_YOURHOST,105,102,190,12,ES_AUTOHSCROLL
 +END
 +
 +IDD_LISTSMGR DIALOGEX 0, 0, 304, 228
 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
 +EXSTYLE WS_EX_CONTROLPARENT
 +FONT 8, "MS Shell Dlg", 0, 0, 0x1
 +BEGIN
 +    GROUPBOX        "Server List Manager",IDC_STATIC,4,0,298,224
 +    CONTROL         "",IDC_LIST,"CListControl",WS_TABSTOP | 0x1f3,9,12,287,169,WS_EX_CLIENTEDGE
 +    ICON            "",IDC_ICON_LC,10,184,20,20,SS_REALSIZEIMAGE
 +    LTEXT           "Contact is on your local list",IDC_STATIC,28,184,144,8
 +    ICON            "",IDC_ICON_FL,10,197,20,20,SS_REALSIZEIMAGE
 +    LTEXT           "Contact is included into your server list",IDC_STATIC,28,197,144,8
 +    ICON            "",IDC_ICON_AL,187,184,20,20,SS_REALSIZEIMAGE
 +    LTEXT           "Allowed (active) contact",IDC_STATIC,204,184,82,8
 +    ICON            "",IDC_ICON_BL,187,196,20,20,SS_REALSIZEIMAGE
 +    LTEXT           "Blocked contact",IDC_STATIC,204,196,82,8
 +    ICON            "",IDC_ICON_RL,10,209,21,20,SS_REALSIZEIMAGE
 +    LTEXT           "Somebody included you in his/her server list",IDC_STATIC,28,209,144,8
 +    PUSHBUTTON      "Refresh",IDC_LISTREFRESH,218,209,80,13
 +END
 +
 +IDD_OPT_NOTIFY DIALOGEX 0, 0, 289, 126
 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_CHILD
 +EXSTYLE WS_EX_CONTROLPARENT
 +FONT 8, "MS Shell Dlg", 0, 0, 0x1
 +BEGIN
 +    GROUPBOX        "Hotmail",IDC_STATIC,5,7,262,60
 +    CONTROL         "Disable Popup notifications",IDC_DISABLEHOTMAILPOPUP,
 +                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,18,245,10
 +    CONTROL         "Disable Tray notifications",IDC_DISABLEHOTMAILTRAY,
 +                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,41,245,10
 +    CONTROL         "Ignore new messages not in Inbox folder",IDC_DISABLEHOTJUNK,
 +                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,52,245,10
 +    GROUPBOX        "Other",IDC_STATIC,5,68,262,49
 +    CONTROL         "Display errors using popups",IDC_ERRORS_USING_POPUPS,
 +                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,79,245,10
 +    CONTROL         "Enable 'Chat Session Established' popup",IDC_NOTIFY_FIRSTMSG,
 +                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,92,245,10
 +    CONTROL         "Enable 'Contact left channel' popup",IDC_NOTIFY_ENDSESSION,
 +                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,105,245,8
 +    CONTROL         "Disable Contact List notifications",IDC_DISABLEHOTMAILCL,
 +                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,30,245,10
 +END
 +
 +IDD_SETNICKNAME DIALOGEX 0, 0, 187, 42
 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
 +CAPTION "Set Nickname"
 +FONT 8, "MS Shell Dlg", 0, 0, 0x1
 +BEGIN
 +    EDITTEXT        IDC_NICKNAME,5,5,177,12,ES_AUTOHSCROLL
 +    DEFPUSHBUTTON   "OK",IDOK,36,23,50,14
 +    PUSHBUTTON      "Cancel",IDCANCEL,102,23,50,14
 +END
 +
 +IDD_USEROPTS DIALOGEX 0, 0, 224, 132
 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
 +FONT 8, "MS Shell Dlg", 0, 0, 0x1
 +BEGIN
 +    CONTROL         "",IDC_CCARD_TAB1,"SysTabControl32",0x0,0,0,223,117
 +END
 +
 +IDD_CARD_GEN DIALOGEX 0, 0, 278, 130
 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_SYSMENU
 +FONT 8, "MS Shell Dlg", 400, 0, 0x1
 +BEGIN
 +    LTEXT           "Mobile Device (used for SMS)",IDC_STATIC,7,8,126,8
 +    EDITTEXT        IDC_CARD_GEN_PHONE,7,17,122,12,ES_AUTOHSCROLL
 +    EDITTEXT        IDC_CARD_GEN_IM2,7,73,125,13,ES_AUTOHSCROLL
 +    LTEXT           "Spouse/Partner",IDC_STATIC,7,64,122,8
 +    EDITTEXT        IDC_EDIT5,143,18,121,12,ES_AUTOHSCROLL
 +    EDITTEXT        IDC_EDIT6,145,74,118,12,ES_AUTOHSCROLL
 +    EDITTEXT        IDC_EDIT7,144,46,119,12,ES_AUTOHSCROLL
 +    LTEXT           "Middle Name",IDC_STATIC,145,35,117,8
 +    LTEXT           "First Name",IDC_STATIC,143,8,120,8
 +    LTEXT           "Last Name",IDC_STATIC,145,63,116,8
 +    COMBOBOX        IDC_COMBO1,7,100,67,30,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP
 +    COMBOBOX        IDC_COMBO2,77,100,28,30,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP
 +    EDITTEXT        IDC_CARD_GEN_IM3,105,100,25,12,ES_AUTOHSCROLL
 +    COMBOBOX        IDC_COMBO3,144,100,67,30,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP
 +    COMBOBOX        IDC_COMBO4,212,100,28,30,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP
 +    EDITTEXT        IDC_CARD_GEN_IM4,240,100,25,12,ES_AUTOHSCROLL
 +    LTEXT           "Anniversary",IDC_STATIC,7,91,123,8
 +    LTEXT           "Birthday",IDC_STATIC,145,91,123,8
 +    EDITTEXT        IDC_CARD_GEN_IM5,7,47,125,13,ES_AUTOHSCROLL
 +    LTEXT           "Nickname",IDC_STATIC,7,38,94,8
 +END
 +
 +IDD_CARD_CONTACT DIALOGEX 0, 0, 344, 156
 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_SYSMENU
 +FONT 8, "MS Shell Dlg", 400, 0, 0x1
 +BEGIN
 +    EDITTEXT        IDC_EDIT1,7,19,107,14,ES_AUTOHSCROLL
 +    EDITTEXT        IDC_EDIT2,7,48,107,14,ES_AUTOHSCROLL
 +    EDITTEXT        IDC_EDIT3,7,77,107,14,ES_AUTOHSCROLL
 +    EDITTEXT        IDC_EDIT4,7,102,107,14,ES_AUTOHSCROLL
 +    EDITTEXT        IDC_EDIT5,7,123,107,14,ES_AUTOHSCROLL
 +    EDITTEXT        IDC_EDIT6,130,18,107,14,ES_AUTOHSCROLL
 +    EDITTEXT        IDC_EDIT7,130,46,107,14,ES_AUTOHSCROLL
 +    EDITTEXT        IDC_EDIT8,130,74,107,14,ES_AUTOHSCROLL
 +    EDITTEXT        IDC_EDIT9,130,100,107,14,ES_AUTOHSCROLL
 +    EDITTEXT        IDC_EDIT10,130,121,107,14,ES_AUTOHSCROLL
 +    LTEXT           "Middle Name",IDC_STATIC,129,7,41,8
 +    LTEXT           "First Name",IDC_STATIC,7,7,35,8
 +    LTEXT           "Last Name",IDC_STATIC,7,36,34,8
 +END
 +
 +IDD_ACCMGRUI DIALOGEX 0, 0, 186, 134
 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
 +EXSTYLE WS_EX_CONTROLPARENT
 +FONT 8, "MS Shell Dlg", 400, 0, 0x1
 +BEGIN
 +    LTEXT           "Live ID:",IDC_STATIC,0,0,53,12
 +    EDITTEXT        IDC_HANDLE,54,0,131,12,ES_AUTOHSCROLL
 +    LTEXT           "Password:",IDC_STATIC,0,16,53,12
 +    EDITTEXT        IDC_PASSWORD,54,16,131,12,ES_PASSWORD | ES_AUTOHSCROLL
 +    CONTROL         "Create a new Windows Live account",IDC_NEWMSNACCOUNTLINK,
 +                    "Hyperlink",WS_TABSTOP,0,60,183,12
 +    LTEXT           "Place:",IDC_STATIC,0,31,53,12
 +    EDITTEXT        IDC_PLACE,54,31,131,12,ES_AUTOHSCROLL
 +END
 +
 +IDD_DELETECONTACT DIALOGEX 0, 0, 213, 76
 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION
 +CAPTION "MSN Delete Contact"
 +FONT 8, "MS Shell Dlg", 400, 0, 0x1
 +BEGIN
 +    DEFPUSHBUTTON   "OK",IDOK,82,55,50,14
 +    CONTROL         "Remove from Hotmail Address book",IDC_REMOVEHOT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,32,199,10
 +    CONTROL         "Block Contact",IDC_REMOVEBLOCK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,18,199,10
 +END
 +
 +IDD_CHATROOM_INVITE DIALOGEX 0, 0, 190, 179
 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU
 +EXSTYLE WS_EX_TOPMOST
 +CAPTION "Invite Contact To Chat"
 +FONT 8, "MS Shell Dlg", 0, 0, 0x0
 +BEGIN
 +    LTEXT           "Live ID",-1,7,128,43,9
 +    PUSHBUTTON      "&Invite",IDOK,29,159,46,14
 +    PUSHBUTTON      "&Cancel",IDCANCEL,112,159,45,14
 +    CONTROL         "",IDC_CCLIST,"CListControl",WS_TABSTOP | 0x16f,7,4,174,119,WS_EX_CLIENTEDGE
 +    EDITTEXT        IDC_EDITSCR,7,138,121,12,ES_AUTOHSCROLL
 +    PUSHBUTTON      "Add",IDC_ADDSCR,133,136,49,14
 +END
 +
 +
 +/////////////////////////////////////////////////////////////////////////////
 +//
 +// DESIGNINFO
 +//
 +
 +#ifdef APSTUDIO_INVOKED
 +GUIDELINES DESIGNINFO
 +BEGIN
 +    IDD_OPT_MSN, DIALOG
 +    BEGIN
 +        VERTGUIDE, 12
 +        VERTGUIDE, 292
 +    END
 +
 +    IDD_OPT_MSN_CONN, DIALOG
 +    BEGIN
 +        VERTGUIDE, 10
 +        VERTGUIDE, 68
 +        VERTGUIDE, 203
 +        VERTGUIDE, 209
 +        VERTGUIDE, 237
 +        VERTGUIDE, 295
 +    END
 +
 +    IDD_LISTSMGR, DIALOG
 +    BEGIN
 +    END
 +
 +    IDD_OPT_NOTIFY, DIALOG
 +    BEGIN
 +        RIGHTMARGIN, 276
 +        VERTGUIDE, 5
 +        VERTGUIDE, 14
 +        VERTGUIDE, 259
 +        VERTGUIDE, 267
 +        BOTTOMMARGIN, 123
 +    END
 +
 +    IDD_SETNICKNAME, DIALOG
 +    BEGIN
 +    END
 +
 +    IDD_USEROPTS, DIALOG
 +    BEGIN
 +    END
 +
 +    IDD_CARD_GEN, DIALOG
 +    BEGIN
 +        LEFTMARGIN, 7
 +        RIGHTMARGIN, 271
 +        TOPMARGIN, 7
 +        BOTTOMMARGIN, 123
 +    END
 +
 +    IDD_CARD_CONTACT, DIALOG
 +    BEGIN
 +        LEFTMARGIN, 7
 +        RIGHTMARGIN, 337
 +        TOPMARGIN, 7
 +        BOTTOMMARGIN, 149
 +    END
 +
 +    IDD_ACCMGRUI, DIALOG
 +    BEGIN
 +        RIGHTMARGIN, 183
 +        TOPMARGIN, 7
 +        BOTTOMMARGIN, 106
 +    END
 +
 +    IDD_DELETECONTACT, DIALOG
 +    BEGIN
 +        LEFTMARGIN, 7
 +        RIGHTMARGIN, 206
 +        TOPMARGIN, 7
 +        BOTTOMMARGIN, 69
 +    END
 +
 +    IDD_CHATROOM_INVITE, DIALOG
 +    BEGIN
 +        RIGHTMARGIN, 188
 +        TOPMARGIN, 4
 +        BOTTOMMARGIN, 173
 +    END
 +END
 +#endif    // APSTUDIO_INVOKED
 +
 +
 +/////////////////////////////////////////////////////////////////////////////
 +//
 +// Icon
 +//
 +
 +// Icon with lowest ID value placed first to ensure application icon
 +// remains consistent on all systems.
 +IDI_MSN                 ICON                    "msn.ico"
 +IDI_MSNBLOCK            ICON                    "msnblock.ico"
 +IDI_SERVICES            ICON                    "services.ico"
 +IDI_INBOX               ICON                    "inbox.ico"
 +IDI_INVITE              ICON                    "invite.ico"
 +IDI_NETMEETING          ICON                    "netmeeting.ico"
 +IDI_PROFILE             ICON                    "profile.ico"
 +IDI_LIST_FL             ICON                    "list_fl.ico"
 +IDI_LIST_AL             ICON                    "list_al.ico"
 +IDI_LIST_BL             ICON                    "list_bl.ico"
 +IDI_LIST_RL             ICON                    "list_rl.ico"
 +IDI_LIST_LC             ICON                    "list_ph.ico"
 +
 +#ifdef APSTUDIO_INVOKED
 +/////////////////////////////////////////////////////////////////////////////
 +//
 +// TEXTINCLUDE
 +//
 +
 +1 TEXTINCLUDE 
 +BEGIN
 +    "..\\src\\resource.h\0"
 +END
 +
 +2 TEXTINCLUDE 
 +BEGIN
 +    "#include <windows.h>\r\n"
 +    "\0"
 +END
 +
 +3 TEXTINCLUDE 
 +BEGIN
 +    "\r\n"
 +    "\0"
 +END
 +
 +#endif    // APSTUDIO_INVOKED
 +
 +#endif    // Neutral resources
 +/////////////////////////////////////////////////////////////////////////////
 +
 +
 +
 +#ifndef APSTUDIO_INVOKED
 +/////////////////////////////////////////////////////////////////////////////
 +//
 +// Generated from the TEXTINCLUDE 3 resource.
 +//
 +
 +
 +/////////////////////////////////////////////////////////////////////////////
 +#endif    // not APSTUDIO_INVOKED
 +
 diff --git a/plugins/!Deprecated/MSN/res/msnblock.ico b/plugins/!Deprecated/MSN/res/msnblock.ico Binary files differnew file mode 100644 index 0000000000..26c0a6d040 --- /dev/null +++ b/plugins/!Deprecated/MSN/res/msnblock.ico diff --git a/plugins/!Deprecated/MSN/res/netmeeting.ico b/plugins/!Deprecated/MSN/res/netmeeting.ico Binary files differnew file mode 100644 index 0000000000..40e341ec16 --- /dev/null +++ b/plugins/!Deprecated/MSN/res/netmeeting.ico diff --git a/plugins/!Deprecated/MSN/res/profile.ico b/plugins/!Deprecated/MSN/res/profile.ico Binary files differnew file mode 100644 index 0000000000..2056f57798 --- /dev/null +++ b/plugins/!Deprecated/MSN/res/profile.ico diff --git a/plugins/!Deprecated/MSN/res/services.ico b/plugins/!Deprecated/MSN/res/services.ico Binary files differnew file mode 100644 index 0000000000..2aca9a8bb4 --- /dev/null +++ b/plugins/!Deprecated/MSN/res/services.ico diff --git a/plugins/!Deprecated/MSN/res/version.rc b/plugins/!Deprecated/MSN/res/version.rc new file mode 100644 index 0000000000..df06238f1f --- /dev/null +++ b/plugins/!Deprecated/MSN/res/version.rc @@ -0,0 +1,39 @@ +#ifdef APSTUDIO_INVOKED
 +#error this file is not editable by Microsoft Visual C++
 +#endif //APSTUDIO_INVOKED
 +
 +#include <windows.h>
 +#include "..\src\version.h"
 +
 +VS_VERSION_INFO VERSIONINFO
 + FILEVERSION __FILEVERSION_STRING
 + PRODUCTVERSION __FILEVERSION_STRING
 + FILEFLAGSMASK 0x3fL
 +#ifdef _DEBUG
 + FILEFLAGS 0x1L
 +#else
 + FILEFLAGS 0x0L
 +#endif
 + FILEOS 0x40004L
 + FILETYPE 0x1L
 + FILESUBTYPE 0x0L
 +BEGIN
 +    BLOCK "StringFileInfo"
 +    BEGIN
 +        BLOCK "000004b0"
 +        BEGIN
 +            VALUE "CompanyName", "Boris Krasnovskiy, George Hazan, Richard Hughes"
 +            VALUE "FileDescription", "Miranda NG MSN Messenger plugin"
 +            VALUE "FileVersion", __VERSION_STRING
 +            VALUE "InternalName", "msn"
 +            VALUE "LegalCopyright", "Copyright (c) 2001-2009 Boris Krasnovskiy, George Hazan, Richard Hughes"
 +			VALUE "OriginalFilename", "msn.dll"
 +            VALUE "ProductName", "Miranda"
 +            VALUE "ProductVersion", __VERSION_STRING
 +        END
 +    END
 +    BLOCK "VarFileInfo"
 +    BEGIN
 +        VALUE "Translation", 0x0, 1200
 +    END
 +END
 diff --git a/plugins/!Deprecated/MSN/src/des.c b/plugins/!Deprecated/MSN/src/des.c new file mode 100644 index 0000000000..030fb983cd --- /dev/null +++ b/plugins/!Deprecated/MSN/src/des.c @@ -0,0 +1,639 @@ +/*
 + *  FIPS-46-3 compliant Triple-DES implementation
 + *
 + *  Copyright (C) 2006-2007  Christophe Devine
 + *
 + *  This library is free software; you can redistribute it and/or
 + *  modify it under the terms of the GNU Lesser General Public
 + *  License, version 2.1 as published by the Free Software Foundation.
 + *
 + *  This library is distributed in the hope that it will be useful,
 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + *  Lesser General Public License for more details.
 + *
 + *  You should have received a copy of the GNU Lesser General Public
 + *  License along with this library; if not, write to the Free Software
 + *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 + *  MA  02110-1301  USA
 + */
 +/*
 + *  DES, on which TDES is based, was originally designed by IBM in
 + *  1974 and adopted as a standard by NIST (formerly NBS).
 + *
 + *  http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf
 + */
 +
 +
 +#ifndef __GNUC__
 +#pragma hdrstop
 +#endif
 +
 +#ifndef _CRT_SECURE_NO_DEPRECATE
 +#define _CRT_SECURE_NO_DEPRECATE 1
 +#endif
 +
 +#include <string.h>
 +
 +#include "des.h"
 +
 +/*
 + * 32-bit integer manipulation macros (big endian)
 + */
 +#ifndef GET_UINT32_BE
 +#define GET_UINT32_BE(n,b,i)                            \
 +{                                                       \
 +    (n) = ( (unsigned long) (b)[(i)    ] << 24 )        \
 +        | ( (unsigned long) (b)[(i) + 1] << 16 )        \
 +        | ( (unsigned long) (b)[(i) + 2] <<  8 )        \
 +        | ( (unsigned long) (b)[(i) + 3]       );       \
 +}
 +#endif
 +#ifndef PUT_UINT32_BE
 +#define PUT_UINT32_BE(n,b,i)                            \
 +{                                                       \
 +    (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
 +    (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
 +    (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
 +    (b)[(i) + 3] = (unsigned char) ( (n)       );       \
 +}
 +#endif
 +
 +/*
 + * Expanded DES S-boxes
 + */
 +static const unsigned long SB1[64] =
 +{
 +    0x01010400, 0x00000000, 0x00010000, 0x01010404,
 +    0x01010004, 0x00010404, 0x00000004, 0x00010000,
 +    0x00000400, 0x01010400, 0x01010404, 0x00000400,
 +    0x01000404, 0x01010004, 0x01000000, 0x00000004,
 +    0x00000404, 0x01000400, 0x01000400, 0x00010400,
 +    0x00010400, 0x01010000, 0x01010000, 0x01000404,
 +    0x00010004, 0x01000004, 0x01000004, 0x00010004,
 +    0x00000000, 0x00000404, 0x00010404, 0x01000000,
 +    0x00010000, 0x01010404, 0x00000004, 0x01010000,
 +    0x01010400, 0x01000000, 0x01000000, 0x00000400,
 +    0x01010004, 0x00010000, 0x00010400, 0x01000004,
 +    0x00000400, 0x00000004, 0x01000404, 0x00010404,
 +    0x01010404, 0x00010004, 0x01010000, 0x01000404,
 +    0x01000004, 0x00000404, 0x00010404, 0x01010400,
 +    0x00000404, 0x01000400, 0x01000400, 0x00000000,
 +    0x00010004, 0x00010400, 0x00000000, 0x01010004
 +};
 +
 +static const unsigned long SB2[64] =
 +{
 +    0x80108020, 0x80008000, 0x00008000, 0x00108020,
 +    0x00100000, 0x00000020, 0x80100020, 0x80008020,
 +    0x80000020, 0x80108020, 0x80108000, 0x80000000,
 +    0x80008000, 0x00100000, 0x00000020, 0x80100020,
 +    0x00108000, 0x00100020, 0x80008020, 0x00000000,
 +    0x80000000, 0x00008000, 0x00108020, 0x80100000,
 +    0x00100020, 0x80000020, 0x00000000, 0x00108000,
 +    0x00008020, 0x80108000, 0x80100000, 0x00008020,
 +    0x00000000, 0x00108020, 0x80100020, 0x00100000,
 +    0x80008020, 0x80100000, 0x80108000, 0x00008000,
 +    0x80100000, 0x80008000, 0x00000020, 0x80108020,
 +    0x00108020, 0x00000020, 0x00008000, 0x80000000,
 +    0x00008020, 0x80108000, 0x00100000, 0x80000020,
 +    0x00100020, 0x80008020, 0x80000020, 0x00100020,
 +    0x00108000, 0x00000000, 0x80008000, 0x00008020,
 +    0x80000000, 0x80100020, 0x80108020, 0x00108000
 +};
 +
 +static const unsigned long SB3[64] =
 +{
 +    0x00000208, 0x08020200, 0x00000000, 0x08020008,
 +    0x08000200, 0x00000000, 0x00020208, 0x08000200,
 +    0x00020008, 0x08000008, 0x08000008, 0x00020000,
 +    0x08020208, 0x00020008, 0x08020000, 0x00000208,
 +    0x08000000, 0x00000008, 0x08020200, 0x00000200,
 +    0x00020200, 0x08020000, 0x08020008, 0x00020208,
 +    0x08000208, 0x00020200, 0x00020000, 0x08000208,
 +    0x00000008, 0x08020208, 0x00000200, 0x08000000,
 +    0x08020200, 0x08000000, 0x00020008, 0x00000208,
 +    0x00020000, 0x08020200, 0x08000200, 0x00000000,
 +    0x00000200, 0x00020008, 0x08020208, 0x08000200,
 +    0x08000008, 0x00000200, 0x00000000, 0x08020008,
 +    0x08000208, 0x00020000, 0x08000000, 0x08020208,
 +    0x00000008, 0x00020208, 0x00020200, 0x08000008,
 +    0x08020000, 0x08000208, 0x00000208, 0x08020000,
 +    0x00020208, 0x00000008, 0x08020008, 0x00020200
 +};
 +
 +static const unsigned long SB4[64] =
 +{
 +    0x00802001, 0x00002081, 0x00002081, 0x00000080,
 +    0x00802080, 0x00800081, 0x00800001, 0x00002001,
 +    0x00000000, 0x00802000, 0x00802000, 0x00802081,
 +    0x00000081, 0x00000000, 0x00800080, 0x00800001,
 +    0x00000001, 0x00002000, 0x00800000, 0x00802001,
 +    0x00000080, 0x00800000, 0x00002001, 0x00002080,
 +    0x00800081, 0x00000001, 0x00002080, 0x00800080,
 +    0x00002000, 0x00802080, 0x00802081, 0x00000081,
 +    0x00800080, 0x00800001, 0x00802000, 0x00802081,
 +    0x00000081, 0x00000000, 0x00000000, 0x00802000,
 +    0x00002080, 0x00800080, 0x00800081, 0x00000001,
 +    0x00802001, 0x00002081, 0x00002081, 0x00000080,
 +    0x00802081, 0x00000081, 0x00000001, 0x00002000,
 +    0x00800001, 0x00002001, 0x00802080, 0x00800081,
 +    0x00002001, 0x00002080, 0x00800000, 0x00802001,
 +    0x00000080, 0x00800000, 0x00002000, 0x00802080
 +};
 +
 +static const unsigned long SB5[64] =
 +{
 +    0x00000100, 0x02080100, 0x02080000, 0x42000100,
 +    0x00080000, 0x00000100, 0x40000000, 0x02080000,
 +    0x40080100, 0x00080000, 0x02000100, 0x40080100,
 +    0x42000100, 0x42080000, 0x00080100, 0x40000000,
 +    0x02000000, 0x40080000, 0x40080000, 0x00000000,
 +    0x40000100, 0x42080100, 0x42080100, 0x02000100,
 +    0x42080000, 0x40000100, 0x00000000, 0x42000000,
 +    0x02080100, 0x02000000, 0x42000000, 0x00080100,
 +    0x00080000, 0x42000100, 0x00000100, 0x02000000,
 +    0x40000000, 0x02080000, 0x42000100, 0x40080100,
 +    0x02000100, 0x40000000, 0x42080000, 0x02080100,
 +    0x40080100, 0x00000100, 0x02000000, 0x42080000,
 +    0x42080100, 0x00080100, 0x42000000, 0x42080100,
 +    0x02080000, 0x00000000, 0x40080000, 0x42000000,
 +    0x00080100, 0x02000100, 0x40000100, 0x00080000,
 +    0x00000000, 0x40080000, 0x02080100, 0x40000100
 +};
 +
 +static const unsigned long SB6[64] =
 +{
 +    0x20000010, 0x20400000, 0x00004000, 0x20404010,
 +    0x20400000, 0x00000010, 0x20404010, 0x00400000,
 +    0x20004000, 0x00404010, 0x00400000, 0x20000010,
 +    0x00400010, 0x20004000, 0x20000000, 0x00004010,
 +    0x00000000, 0x00400010, 0x20004010, 0x00004000,
 +    0x00404000, 0x20004010, 0x00000010, 0x20400010,
 +    0x20400010, 0x00000000, 0x00404010, 0x20404000,
 +    0x00004010, 0x00404000, 0x20404000, 0x20000000,
 +    0x20004000, 0x00000010, 0x20400010, 0x00404000,
 +    0x20404010, 0x00400000, 0x00004010, 0x20000010,
 +    0x00400000, 0x20004000, 0x20000000, 0x00004010,
 +    0x20000010, 0x20404010, 0x00404000, 0x20400000,
 +    0x00404010, 0x20404000, 0x00000000, 0x20400010,
 +    0x00000010, 0x00004000, 0x20400000, 0x00404010,
 +    0x00004000, 0x00400010, 0x20004010, 0x00000000,
 +    0x20404000, 0x20000000, 0x00400010, 0x20004010
 +};
 +
 +static const unsigned long SB7[64] =
 +{
 +    0x00200000, 0x04200002, 0x04000802, 0x00000000,
 +    0x00000800, 0x04000802, 0x00200802, 0x04200800,
 +    0x04200802, 0x00200000, 0x00000000, 0x04000002,
 +    0x00000002, 0x04000000, 0x04200002, 0x00000802,
 +    0x04000800, 0x00200802, 0x00200002, 0x04000800,
 +    0x04000002, 0x04200000, 0x04200800, 0x00200002,
 +    0x04200000, 0x00000800, 0x00000802, 0x04200802,
 +    0x00200800, 0x00000002, 0x04000000, 0x00200800,
 +    0x04000000, 0x00200800, 0x00200000, 0x04000802,
 +    0x04000802, 0x04200002, 0x04200002, 0x00000002,
 +    0x00200002, 0x04000000, 0x04000800, 0x00200000,
 +    0x04200800, 0x00000802, 0x00200802, 0x04200800,
 +    0x00000802, 0x04000002, 0x04200802, 0x04200000,
 +    0x00200800, 0x00000000, 0x00000002, 0x04200802,
 +    0x00000000, 0x00200802, 0x04200000, 0x00000800,
 +    0x04000002, 0x04000800, 0x00000800, 0x00200002
 +};
 +
 +static const unsigned long SB8[64] =
 +{
 +    0x10001040, 0x00001000, 0x00040000, 0x10041040,
 +    0x10000000, 0x10001040, 0x00000040, 0x10000000,
 +    0x00040040, 0x10040000, 0x10041040, 0x00041000,
 +    0x10041000, 0x00041040, 0x00001000, 0x00000040,
 +    0x10040000, 0x10000040, 0x10001000, 0x00001040,
 +    0x00041000, 0x00040040, 0x10040040, 0x10041000,
 +    0x00001040, 0x00000000, 0x00000000, 0x10040040,
 +    0x10000040, 0x10001000, 0x00041040, 0x00040000,
 +    0x00041040, 0x00040000, 0x10041000, 0x00001000,
 +    0x00000040, 0x10040040, 0x00001000, 0x00041040,
 +    0x10001000, 0x00000040, 0x10000040, 0x10040000,
 +    0x10040040, 0x10000000, 0x00040000, 0x10001040,
 +    0x00000000, 0x10041040, 0x00040040, 0x10000040,
 +    0x10040000, 0x10001000, 0x10001040, 0x00000000,
 +    0x10041040, 0x00041000, 0x00041000, 0x00001040,
 +    0x00001040, 0x00040040, 0x10000000, 0x10041000
 +};
 +
 +/*
 + * PC1: left and right halves bit-swap
 + */
 +static const unsigned long LHs[16] =
 +{
 +    0x00000000, 0x00000001, 0x00000100, 0x00000101,
 +    0x00010000, 0x00010001, 0x00010100, 0x00010101,
 +    0x01000000, 0x01000001, 0x01000100, 0x01000101,
 +    0x01010000, 0x01010001, 0x01010100, 0x01010101
 +};
 +
 +static const unsigned long RHs[16] =
 +{
 +    0x00000000, 0x01000000, 0x00010000, 0x01010000,
 +    0x00000100, 0x01000100, 0x00010100, 0x01010100,
 +    0x00000001, 0x01000001, 0x00010001, 0x01010001,
 +    0x00000101, 0x01000101, 0x00010101, 0x01010101,
 +};
 +
 +/*
 + * Initial Permutation macro
 + */
 +#define DES_IP(X,Y)                                             \
 +{                                                               \
 +    T = ((X >>  4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T <<  4);   \
 +    T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16);   \
 +    T = ((Y >>  2) ^ X) & 0x33333333; X ^= T; Y ^= (T <<  2);   \
 +    T = ((Y >>  8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T <<  8);   \
 +    Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF;                    \
 +    T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T;                   \
 +    X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF;                    \
 +}
 +
 +/*
 + * Final Permutation macro
 + */
 +#define DES_FP(X,Y)                                             \
 +{                                                               \
 +    X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF;                    \
 +    T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T;                   \
 +    Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF;                    \
 +    T = ((Y >>  8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T <<  8);   \
 +    T = ((Y >>  2) ^ X) & 0x33333333; X ^= T; Y ^= (T <<  2);   \
 +    T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16);   \
 +    T = ((X >>  4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T <<  4);   \
 +}
 +
 +/*
 + * DES round macro
 + */
 +#define DES_ROUND(X,Y)                          \
 +{                                               \
 +    T = *SK++ ^ X;                              \
 +    Y ^= SB8[ (T      ) & 0x3F ] ^              \
 +         SB6[ (T >>  8) & 0x3F ] ^              \
 +         SB4[ (T >> 16) & 0x3F ] ^              \
 +         SB2[ (T >> 24) & 0x3F ];               \
 +                                                \
 +    T = *SK++ ^ ((X << 28) | (X >> 4));         \
 +    Y ^= SB7[ (T      ) & 0x3F ] ^              \
 +         SB5[ (T >>  8) & 0x3F ] ^              \
 +         SB3[ (T >> 16) & 0x3F ] ^              \
 +         SB1[ (T >> 24) & 0x3F ];               \
 +}
 +
 +static void des_main_ks( unsigned long SK[32], unsigned char key[8] )
 +{
 +    int i;
 +    unsigned long X, Y, T;
 +
 +    GET_UINT32_BE( X, key, 0 );
 +    GET_UINT32_BE( Y, key, 4 );
 +
 +    /*
 +     * Permuted Choice 1
 +     */
 +    T =  ((Y >>  4) ^ X) & 0x0F0F0F0F;  X ^= T; Y ^= (T <<  4);
 +    T =  ((Y      ) ^ X) & 0x10101010;  X ^= T; Y ^= (T      );
 +
 +    X =   (LHs[ (X      ) & 0xF] << 3) | (LHs[ (X >>  8) & 0xF ] << 2)
 +        | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ]     )
 +        | (LHs[ (X >>  5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6)
 +        | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4);
 +
 +    Y =   (RHs[ (Y >>  1) & 0xF] << 3) | (RHs[ (Y >>  9) & 0xF ] << 2)
 +        | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ]     )
 +        | (RHs[ (Y >>  4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6)
 +        | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4);
 +
 +    X &= 0x0FFFFFFF;
 +    Y &= 0x0FFFFFFF;
 +
 +    /*
 +     * calculate subkeys
 +     */
 +    for ( i = 0; i < 16; i++ )
 +    {
 +        if ( i < 2 || i == 8 || i == 15 )
 +        {
 +            X = ((X <<  1) | (X >> 27)) & 0x0FFFFFFF;
 +            Y = ((Y <<  1) | (Y >> 27)) & 0x0FFFFFFF;
 +        }
 +        else
 +        {
 +            X = ((X <<  2) | (X >> 26)) & 0x0FFFFFFF;
 +            Y = ((Y <<  2) | (Y >> 26)) & 0x0FFFFFFF;
 +        }
 +
 +        *SK++ =   ((X <<  4) & 0x24000000) | ((X << 28) & 0x10000000)
 +                | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000)
 +                | ((X <<  6) & 0x01000000) | ((X <<  9) & 0x00200000)
 +                | ((X >>  1) & 0x00100000) | ((X << 10) & 0x00040000)
 +                | ((X <<  2) & 0x00020000) | ((X >> 10) & 0x00010000)
 +                | ((Y >> 13) & 0x00002000) | ((Y >>  4) & 0x00001000)
 +                | ((Y <<  6) & 0x00000800) | ((Y >>  1) & 0x00000400)
 +                | ((Y >> 14) & 0x00000200) | ((Y      ) & 0x00000100)
 +                | ((Y >>  5) & 0x00000020) | ((Y >> 10) & 0x00000010)
 +                | ((Y >>  3) & 0x00000008) | ((Y >> 18) & 0x00000004)
 +                | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001);
 +
 +        *SK++ =   ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000)
 +                | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000)
 +                | ((X >>  2) & 0x02000000) | ((X <<  1) & 0x01000000)
 +                | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000)
 +                | ((X <<  3) & 0x00080000) | ((X >>  6) & 0x00040000)
 +                | ((X << 15) & 0x00020000) | ((X >>  4) & 0x00010000)
 +                | ((Y >>  2) & 0x00002000) | ((Y <<  8) & 0x00001000)
 +                | ((Y >> 14) & 0x00000808) | ((Y >>  9) & 0x00000400)
 +                | ((Y      ) & 0x00000200) | ((Y <<  7) & 0x00000100)
 +                | ((Y >>  7) & 0x00000020) | ((Y >>  3) & 0x00000011)
 +                | ((Y <<  2) & 0x00000004) | ((Y >> 21) & 0x00000002);
 +    }
 +}
 +
 +/*
 + * DES key schedule (56-bit)
 + */
 +void des_set_key( des_context *ctx, unsigned char key[8] )
 +{
 +    int i;
 +
 +    des_main_ks( ctx->esk, key );
 +
 +    for ( i = 0; i < 32; i += 2 )
 +    {
 +        ctx->dsk[i    ] = ctx->esk[30 - i];
 +        ctx->dsk[i + 1] = ctx->esk[31 - i];
 +    }
 +}
 +
 +static void des_crypt( unsigned long SK[32],
 +                       unsigned char input[8],
 +                       unsigned char output[8] )
 +{
 +    unsigned long X, Y, T;
 +
 +    GET_UINT32_BE( X, input, 0 );
 +    GET_UINT32_BE( Y, input, 4 );
 +
 +    DES_IP( X, Y );
 +
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +
 +    DES_FP( Y, X );
 +
 +    PUT_UINT32_BE( Y, output, 0 );
 +    PUT_UINT32_BE( X, output, 4 );
 +}
 +
 +/*
 + * DES block encryption (ECB mode)
 + */
 +void des_encrypt( des_context *ctx,
 +                  unsigned char input[8],
 +                  unsigned char output[8] )
 +{
 +    des_crypt( ctx->esk, input, output );
 +}
 +
 +/*
 + * DES block decryption (ECB mode)
 + */
 +void des_decrypt( des_context *ctx,
 +                  unsigned char input[8],
 +                  unsigned char output[8] )
 +{
 +    des_crypt( ctx->dsk, input, output );
 +}
 +
 +/*
 + * DES-CBC buffer encryption
 + */
 +void des_cbc_encrypt( des_context *ctx,
 +                      unsigned char iv[8],
 +                      unsigned char *input,
 +                      unsigned char *output,
 +                      int len )
 +{
 +    int i;
 +
 +    while( len > 0 )
 +    {
 +        for ( i = 0; i < 8; i++ )
 +            output[i] = input[i] ^ iv[i];
 +
 +        des_crypt( ctx->esk, output, output );
 +        memcpy( iv, output, 8 );
 +
 +        input  += 8;
 +        output += 8;
 +        len    -= 8;
 +    }
 +}
 +
 +/*
 + * DES-CBC buffer decryption
 + */
 +void des_cbc_decrypt( des_context *ctx,
 +                      unsigned char iv[8],
 +                      unsigned char *input,
 +                      unsigned char *output,
 +                      int len )
 +{
 +    int i;
 +    unsigned char temp[8];
 +
 +    while( len > 0 )
 +    {
 +        memcpy( temp, input, 8 );
 +        des_crypt( ctx->dsk, input, output );
 +
 +        for ( i = 0; i < 8; i++ )
 +            output[i] = output[i] ^ iv[i];
 +
 +        memcpy( iv, temp, 8 );
 +
 +        input  += 8;
 +        output += 8;
 +        len    -= 8;
 +    }
 +}
 +
 +/*
 + * Triple-DES key schedule (112-bit)
 + */
 +void des3_set_2keys( des3_context *ctx, unsigned char key[16] )
 +{
 +    int i;
 +
 +    des_main_ks( ctx->esk     , key     );
 +    des_main_ks( ctx->dsk + 32, key + 8 );
 +
 +    for ( i = 0; i < 32; i += 2 )
 +    {
 +        ctx->dsk[i     ] = ctx->esk[30 - i];
 +        ctx->dsk[i +  1] = ctx->esk[31 - i];
 +
 +        ctx->esk[i + 32] = ctx->dsk[62 - i];
 +        ctx->esk[i + 33] = ctx->dsk[63 - i];
 +
 +        ctx->esk[i + 64] = ctx->esk[     i];
 +        ctx->esk[i + 65] = ctx->esk[ 1 + i];
 +
 +        ctx->dsk[i + 64] = ctx->dsk[     i];
 +        ctx->dsk[i + 65] = ctx->dsk[ 1 + i];
 +    }
 +}
 +
 +/*
 + * Triple-DES key schedule (168-bit)
 + */
 +void des3_set_3keys( des3_context *ctx, unsigned char key[24] )
 +{
 +    int i;
 +
 +    des_main_ks( ctx->esk     , key      );
 +    des_main_ks( ctx->dsk + 32, key +  8 );
 +    des_main_ks( ctx->esk + 64, key + 16 );
 +
 +    for ( i = 0; i < 32; i += 2 )
 +    {
 +        ctx->dsk[i     ] = ctx->esk[94 - i];
 +        ctx->dsk[i +  1] = ctx->esk[95 - i];
 +
 +        ctx->esk[i + 32] = ctx->dsk[62 - i];
 +        ctx->esk[i + 33] = ctx->dsk[63 - i];
 +
 +        ctx->dsk[i + 64] = ctx->esk[30 - i];
 +        ctx->dsk[i + 65] = ctx->esk[31 - i];
 +    }
 +}
 +
 +static void des3_crypt( unsigned long SK[96],
 +                        unsigned char input[8],
 +                        unsigned char output[8] )
 +{
 +    unsigned long X, Y, T;
 +
 +    GET_UINT32_BE( X, input, 0 );
 +    GET_UINT32_BE( Y, input, 4 );
 +
 +    DES_IP( X, Y );
 +
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +
 +    DES_ROUND( X, Y );  DES_ROUND( Y, X );
 +    DES_ROUND( X, Y );  DES_ROUND( Y, X );
 +    DES_ROUND( X, Y );  DES_ROUND( Y, X );
 +    DES_ROUND( X, Y );  DES_ROUND( Y, X );
 +    DES_ROUND( X, Y );  DES_ROUND( Y, X );
 +    DES_ROUND( X, Y );  DES_ROUND( Y, X );
 +    DES_ROUND( X, Y );  DES_ROUND( Y, X );
 +    DES_ROUND( X, Y );  DES_ROUND( Y, X );
 +
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +    DES_ROUND( Y, X );  DES_ROUND( X, Y );
 +
 +    DES_FP( Y, X );
 +
 +    PUT_UINT32_BE( Y, output, 0 );
 +    PUT_UINT32_BE( X, output, 4 );
 +}
 +
 +/*
 + * Triple-DES block encryption (ECB mode)
 + */
 +void des3_encrypt( des3_context *ctx,
 +                   unsigned char input[8],
 +                   unsigned char output[8] )
 +{
 +    des3_crypt( ctx->esk, input, output );
 +}
 +
 +/*
 + * Triple-DES block decryption (ECB mode)
 + */
 +void des3_decrypt( des3_context *ctx,
 +                   unsigned char input[8],
 +                   unsigned char output[8] )
 +{
 +    des3_crypt( ctx->dsk, input, output );
 +}
 +
 +/*
 + * 3DES-CBC buffer encryption
 + */
 +void des3_cbc_encrypt( des3_context *ctx,
 +                       unsigned char iv[8],
 +                       unsigned char *input,
 +                       unsigned char *output,
 +                       int len )
 +{
 +    int i;
 +
 +    while( len > 0 )
 +    {
 +        for ( i = 0; i < 8; i++ )
 +            output[i] = input[i] ^ iv[i];
 +
 +        des3_crypt( ctx->esk, output, output );
 +        memcpy( iv, output, 8 );
 +
 +        input  += 8;
 +        output += 8;
 +        len    -= 8;
 +    }
 +}
 +
 +/*
 + * 3DES-CBC buffer decryption
 + */
 +void des3_cbc_decrypt( des3_context *ctx,
 +                       unsigned char iv[8],
 +                       unsigned char *input,
 +                       unsigned char *output,
 +                       int len )
 +{
 +    int i;
 +    unsigned char temp[8];
 +
 +    while( len > 0 )
 +    {
 +        memcpy( temp, input, 8 );
 +        des3_crypt( ctx->dsk, input, output );
 +
 +        for ( i = 0; i < 8; i++ )
 +            output[i] = output[i] ^ iv[i];
 +
 +        memcpy( iv, temp, 8 );
 +
 +        input  += 8;
 +        output += 8;
 +        len    -= 8;
 +    }
 +}
 diff --git a/plugins/!Deprecated/MSN/src/des.h b/plugins/!Deprecated/MSN/src/des.h new file mode 100644 index 0000000000..e1fc923fad --- /dev/null +++ b/plugins/!Deprecated/MSN/src/des.h @@ -0,0 +1,170 @@ +/** + * \file des.h + */ +#ifndef _DES_H +#define _DES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief          DES context structure + */ +typedef struct +{ +    unsigned long esk[32];     /*!< DES encryption subkeys */ +    unsigned long dsk[32];     /*!< DES decryption subkeys */ +} +des_context; + +/** + * \brief          Triple-DES context structure + */ +typedef struct +{ +    unsigned long esk[96];     /*!< Triple-DES encryption subkeys */ +    unsigned long dsk[96];     /*!< Triple-DES decryption subkeys */ +} +des3_context; + +/** + * \brief          DES key schedule (56-bit) + * + * \param ctx      DES context to be initialized + * \param key      8-byte secret key + */ +void des_set_key( des_context *ctx, unsigned char key[8] ); + +/** + * \brief          DES block encryption (ECB mode) + * + * \param ctx      DES context + * \param input    plaintext  block + * \param output   ciphertext block + */ +void des_encrypt( des_context *ctx, +                  unsigned char input[8], +                  unsigned char output[8] ); + +/** + * \brief          DES block decryption (ECB mode) + * + * \param ctx      DES context + * \param input    ciphertext block + * \param output   plaintext  block + */ +void des_decrypt( des_context *ctx, +                  unsigned char input[8], +                  unsigned char output[8] ); + +/** + * \brief          DES-CBC buffer encryption + * + * \param ctx      DES context + * \param iv       initialization vector (modified after use) + * \param input    buffer holding the plaintext + * \param output   buffer holding the ciphertext + * \param len      length of the data to be encrypted + */ +void des_cbc_encrypt( des_context *ctx, +                      unsigned char iv[8], +                      unsigned char *input, +                      unsigned char *output, +                      int len ); + +/** + * \brief          DES-CBC buffer decryption + * + * \param ctx      DES context + * \param iv       initialization vector (modified after use) + * \param input    buffer holding the ciphertext + * \param output   buffer holding the plaintext + * \param len      length of the data to be decrypted + */ +void des_cbc_decrypt( des_context *ctx, +                      unsigned char iv[8], +                      unsigned char *input, +                      unsigned char *output, +                      int len ); + +/** + * \brief          Triple-DES key schedule (112-bit) + * + * \param ctx      3DES context to be initialized + * \param key      16-byte secret key + */ +void des3_set_2keys( des3_context *ctx, unsigned char key[16] ); + +/** + * \brief          Triple-DES key schedule (168-bit) + * + * \param ctx      3DES context to be initialized + * \param key      24-byte secret key + */ +void des3_set_3keys( des3_context *ctx, unsigned char key[24] ); + +/** + * \brief          Triple-DES block encryption (ECB mode) + * + * \param ctx      3DES context + * \param input    plaintext  block + * \param output   ciphertext block + */ +void des3_encrypt( des3_context *ctx, +                   unsigned char input[8], +                   unsigned char output[8] ); + +/** + * \brief          Triple-DES block decryption (ECB mode) + * + * \param ctx      3DES context + * \param input    ciphertext block + * \param output   plaintext  block + */ +void des3_decrypt( des3_context *ctx, +                   unsigned char input[8], +                   unsigned char output[8] ); + +/** + * \brief          3DES-CBC buffer encryption + * + * \param ctx      3DES context + * \param iv       initialization vector (modified after use) + * \param input    buffer holding the plaintext + * \param output   buffer holding the ciphertext + * \param len      length of the data to be encrypted + */ +void des3_cbc_encrypt( des3_context *ctx, +                       unsigned char iv[8], +                       unsigned char *input, +                       unsigned char *output, +                       int len ); + +/** + * \brief          3DES-CBC buffer decryption + * + * \param ctx      3DES context + * \param iv       initialization vector (modified after use) + * \param input    buffer holding the ciphertext + * \param output   buffer holding the plaintext + * \param len      length of the data to be decrypted + */ +void des3_cbc_decrypt( des3_context *ctx, +                       unsigned char iv[8], +                       unsigned char *input, +                       unsigned char *output, +                       int len ); + +/* + * \brief          Checkup routine + * + * \return         0 if successful, or 1 if the test failed + */ +int des_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* des.h */ diff --git a/plugins/!Deprecated/MSN/src/ezxml.c b/plugins/!Deprecated/MSN/src/ezxml.c new file mode 100644 index 0000000000..41ef70598e --- /dev/null +++ b/plugins/!Deprecated/MSN/src/ezxml.c @@ -0,0 +1,967 @@ +/* ezxml.c
 + *
 + * Copyright 2004-2006 Aaron Voisine <aaron@voisine.org>
 + *
 + * Permission is hereby granted, free of charge, to any person obtaining
 + * a copy of this software and associated documentation files (the
 + * "Software"), to deal in the Software without restriction, including
 + * without limitation the rights to use, copy, modify, merge, publish,
 + * distribute, sublicense, and/or sell copies of the Software, and to
 + * permit persons to whom the Software is furnished to do so, subject to
 + * the following conditions:
 + *
 + * The above copyright notice and this permission notice shall be included
 + * in all copies or substantial portions of the Software.
 + *
 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 + */
 +
 +#if defined(_DEBUG) && !defined(__GNUC__)
 +	#define _CRTDBG_MAP_ALLOC
 +	#include <stdlib.h>
 +	#include <crtdbg.h>
 +#else
 +	#include <stdlib.h>
 +#endif
 +
 +#include <limits.h>
 +#include <stdio.h>
 +#include <stdarg.h>
 +#include <string.h>
 +#include <ctype.h>
 +
 +#include "ezxml.h"
 +
 +#ifndef SIZE_MAX
 +#define SIZE_MAX UINT_MAX
 +#endif
 +
 +#define EZXML_WS   "\t\r\n "  // whitespace
 +#define EZXML_ERRL 128        // maximum error string length
 +
 +typedef struct ezxml_root *ezxml_root_t;
 +struct ezxml_root {       // additional data for the root tag
 +    struct ezxml xml;     // is a super-struct built on top of ezxml struct
 +    ezxml_t cur;          // current xml tree insertion point
 +    char *m;              // original xml string
 +    size_t len;           // length of allocated memory for mmap, -1 for malloc
 +    char *u;              // UTF-8 conversion of string if original was UTF-16
 +    char *s;              // start of work area
 +    char *e;              // end of work area
 +    char **ent;           // general entities (ampersand sequences)
 +    char ***attr;         // default attributes
 +    char ***pi;           // processing instructions
 +    short standalone;     // non-zero if <?xml standalone="yes"?>
 +    char err[EZXML_ERRL]; // error string
 +};
 +
 +char *EZXML_NIL[] = { NULL }; // empty, null terminated array of strings
 +
 +// returns the first child tag with the given name or NULL if not found
 +ezxml_t ezxml_child(ezxml_t xml, const char *name)
 +{
 +    xml = (xml) ? xml->child : NULL;
 +    while (xml && strcmp(name, xml->name)) xml = xml->sibling;
 +    return xml;
 +}
 +
 +// returns the Nth tag with the same name in the same subsection or NULL if not
 +// found
 +ezxml_t ezxml_idx(ezxml_t xml, int idx)
 +{
 +    for (; xml && idx; idx--) xml = xml->next;
 +    return xml;
 +}
 +
 +// returns the value of the requested tag attribute or NULL if not found
 +const char *ezxml_attr(ezxml_t xml, const char *attr)
 +{
 +    int i = 0, j = 1;
 +    ezxml_root_t root = (ezxml_root_t)xml;
 +
 +    if (! xml || ! xml->attr) return NULL;
 +    while (xml->attr[i] && strcmp(attr, xml->attr[i])) i += 2;
 +    if (xml->attr[i]) return xml->attr[i + 1]; // found attribute
 +
 +    while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag
 +    for (i = 0; root->attr[i] && strcmp(xml->name, root->attr[i][0]); i++);
 +    if (! root->attr[i]) return NULL; // no matching default attributes
 +    while (root->attr[i][j] && strcmp(attr, root->attr[i][j])) j += 3;
 +    return (root->attr[i][j]) ? root->attr[i][j + 1] : NULL; // found default
 +}
 +
 +// same as ezxml_get but takes an already initialized va_list
 +ezxml_t ezxml_vget(ezxml_t xml, va_list ap)
 +{
 +    char *name = va_arg(ap, char *);
 +    int idx = -1;
 +
 +    if (name && *name) {
 +        idx = va_arg(ap, int);    
 +        xml = ezxml_child(xml, name);
 +    }
 +    return (idx < 0) ? xml : ezxml_vget(ezxml_idx(xml, idx), ap);
 +}
 +
 +// Traverses the xml tree to retrieve a specific subtag. Takes a variable
 +// length list of tag names and indexes. The argument list must be terminated
 +// by either an index of -1 or an empty string tag name. Example: 
 +// title = ezxml_get(library, "shelf", 0, "book", 2, "title", -1);
 +// This retrieves the title of the 3rd book on the 1st shelf of library.
 +// Returns NULL if not found.
 +ezxml_t ezxml_get(ezxml_t xml, ...)
 +{
 +    va_list ap;
 +    ezxml_t r;
 +
 +    va_start(ap, xml);
 +    r = ezxml_vget(xml, ap);
 +    va_end(ap);
 +    return r;
 +}
 +
 +// returns a null terminated array of processing instructions for the given
 +// target
 +const char **ezxml_pi(ezxml_t xml, const char *target)
 +{
 +    ezxml_root_t root = (ezxml_root_t)xml;
 +    int i = 0;
 +
 +    if (! root) return (const char **)EZXML_NIL;
 +    while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag
 +    while (root->pi[i] && strcmp(target, root->pi[i][0])) i++; // find target
 +    return (const char **)((root->pi[i]) ? root->pi[i] + 1 : EZXML_NIL);
 +}
 +
 +// set an error string and return root
 +ezxml_t ezxml_err(ezxml_root_t root, char *s, const char *err, ...)
 +{
 +    va_list ap;
 +    int line = 1;
 +    char *t, fmt[EZXML_ERRL];
 +    
 +    for (t = root->s; t < s; t++) if (*t == '\n') line++;
 +    _snprintf(fmt, EZXML_ERRL, "[error near line %d]: %s", line, err);
 +
 +    va_start(ap, err);
 +    _vsnprintf(root->err, EZXML_ERRL, fmt, ap);
 +    va_end(ap);
 +
 +    return &root->xml;
 +}
 +
 +// Recursively decodes entity and character references and normalizes new lines
 +// ent is a null terminated array of alternating entity names and values. set t
 +// to '&' for general entity decoding, '%' for parameter entity decoding, 'c'
 +// for cdata sections, ' ' for attribute normalization, or '*' for non-cdata
 +// attribute normalization. Returns s, or if the decoded string is longer than
 +// s, returns a malloced string that must be freed.
 +char *ezxml_decode(char *s, char **ent, char t)
 +{
 +    char *e, *r = s, *m = s;
 +    long b, c, d, l;
 +/*
 +    for (; *s; s++) { // normalize line endings
 +        while (*s == '\r') {
 +            *(s++) = '\n';
 +            if (*s == '\n') memmove(s, (s + 1), strlen(s));
 +        }
 +    }
 +*/    
 +    for (s = r; ; ) {
 +		while (*s && *s != '&' && (*s != '%' || t != '%') && (*s & 0x80 || !isspace(*s))) s++;
 +
 +        if (! *s) break;
 +        else if (t != 'c' && ! strncmp(s, "&#", 2)) { // character reference
 +            if (s[2] == 'x') c = strtol(s + 3, &e, 16); // base 16
 +            else c = strtol(s + 2, &e, 10); // base 10
 +            if (! c || *e != ';') { s++; continue; } // not a character ref
 +
 +            if (c < 0x80) *(s++) = (char)c; // US-ASCII subset
 +            else { // multi-byte UTF-8 sequence
 +                for (b = 0, d = c; d; d /= 2) b++; // number of bits in c
 +                b = (b - 2) / 5; // number of bytes in payload
 +                *(s++) = (char)((0xFF << (7 - b)) | (c >> (6 * b))); // head
 +                while (b) *(s++) = (char)(0x80 | ((c >> (6 * --b)) & 0x3F)); // payload
 +            }
 +
 +            memmove(s, strchr(s, ';') + 1, strlen(strchr(s, ';')));
 +        }
 +        else if ((*s == '&' && (t == '&' || t == ' ' || t == '*')) ||
 +                 (*s == '%' && t == '%')) { // entity reference
 +            for (b = 0; ent[b] && strncmp(s + 1, ent[b], strlen(ent[b]));
 +                 b += 2); // find entity in entity list
 +
 +            if (ent[b++]) { // found a match
 +                if ((c = (long)strlen(ent[b])) - 1 > (e = strchr(s, ';')) - s) {
 +                    l = (d = (long)(s - r)) + c + (long)strlen(e); // new length
 +                    r = (r == m) ? strcpy(malloc(l), r) : realloc(r, l);
 +                    e = strchr((s = r + d), ';'); // fix up pointers
 +                }
 +
 +                memmove(s + c, e + 1, strlen(e)); // shift rest of string
 +                strncpy(s, ent[b], c); // copy in replacement text
 +            }
 +            else s++; // not a known entity
 +        }
 +        else if ((t == ' ' || t == '*') && isspace(*s)) *(s++) = ' ';
 +        else s++; // no decoding needed
 +    }
 +
 +    if (t == '*') { // normalize spaces for non-cdata attributes
 +        for (s = r; *s; s++) {
 +            if ((l = (long)strspn(s, " "))) memmove(s, s + l, strlen(s + l) + 1);
 +            while (*s && *s != ' ') s++;
 +        }
 +        if (--s >= r && *s == ' ') *s = '\0'; // trim any trailing space
 +    }
 +    return r;
 +}
 +
 +// called when parser finds start of new tag
 +void ezxml_open_tag(ezxml_root_t root, char *name, char **attr)
 +{
 +    ezxml_t xml = root->cur;
 +    
 +    if (xml->name) xml = ezxml_add_child(xml, name, strlen(xml->txt));
 +    else xml->name = name; // first open tag
 +
 +    xml->attr = attr;
 +    root->cur = xml; // update tag insertion point
 +}
 +
 +// called when parser finds character content between open and closing tag
 +void ezxml_char_content(ezxml_root_t root, char *s, size_t len, char t)
 +{
 +    ezxml_t xml = root->cur;
 +    char *m = s;
 +    size_t l;
 +
 +    if (! xml || ! xml->name || ! len) return; // sanity check
 +
 +    s[len] = '\0'; // null terminate text (calling functions anticipate this)
 +    len = strlen(s = ezxml_decode(s, root->ent, t)) + 1;
 +
 +    if (! *(xml->txt)) xml->txt = s; // initial character content
 +    else { // allocate our own memory and make a copy
 +        xml->txt = (xml->flags & EZXML_TXTM) // allocate some space
 +                   ? realloc(xml->txt, (l = strlen(xml->txt)) + len)
 +                   : strcpy(malloc((l = strlen(xml->txt)) + len), xml->txt);
 +        strcpy(xml->txt + l, s); // add new char content
 +        if (s != m) free(s); // free s if it was malloced by ezxml_decode()
 +    }
 +
 +    if (xml->txt != m) ezxml_set_flag(xml, EZXML_TXTM);
 +}
 +
 +// called when parser finds closing tag
 +ezxml_t ezxml_close_tag(ezxml_root_t root, char *name, char *s)
 +{
 +    if (! root->cur || ! root->cur->name || strcmp(name, root->cur->name))
 +        return ezxml_err(root, s, "unexpected closing tag </%s>", name);
 +
 +    root->cur = root->cur->parent;
 +    return NULL;
 +}
 +
 +// checks for circular entity references, returns non-zero if no circular
 +// references are found, zero otherwise
 +int ezxml_ent_ok(char *name, char *s, char **ent)
 +{
 +    int i;
 +
 +    for (; ; s++) {
 +        while (*s && *s != '&') s++; // find next entity reference
 +        if (! *s) return 1;
 +        if (! strncmp(s + 1, name, strlen(name))) return 0; // circular ref.
 +        for (i = 0; ent[i] && strncmp(ent[i], s + 1, strlen(ent[i])); i += 2);
 +        if (ent[i] && ! ezxml_ent_ok(name, ent[i + 1], ent)) return 0;
 +    }
 +}
 +
 +// called when the parser finds a processing instruction
 +void ezxml_proc_inst(ezxml_root_t root, char *s, size_t len)
 +{
 +    int i = 0, j = 1;
 +    char *target = s;
 +
 +    s[len] = '\0'; // null terminate instruction
 +    if (*(s += strcspn(s, EZXML_WS))) {
 +        *s = '\0'; // null terminate target
 +        s += strspn(s + 1, EZXML_WS) + 1; // skip whitespace after target
 +    }
 +
 +    if (! strcmp(target, "xml")) { // <?xml ... ?>
 +        if ((s = strstr(s, "standalone")) && ! strncmp(s + strspn(s + 10,
 +            EZXML_WS "='\"") + 10, "yes", 3)) root->standalone = 1;
 +        return;
 +    }
 +
 +    if (! root->pi[0]) *(root->pi = malloc(sizeof(char **))) = NULL; //first pi
 +
 +    while (root->pi[i] && strcmp(target, root->pi[i][0])) i++; // find target
 +    if (! root->pi[i]) { // new target
 +        root->pi = realloc(root->pi, sizeof(char **) * (i + 2));
 +        root->pi[i] = malloc(sizeof(char *) * 3);
 +        root->pi[i][0] = target;
 +        root->pi[i][1] = (char *)(root->pi[i + 1] = NULL); // terminate pi list
 +        root->pi[i][2] = _strdup(""); // empty document position list
 +    }
 +
 +    while (root->pi[i][j]) j++; // find end of instruction list for this target
 +    root->pi[i] = realloc(root->pi[i], sizeof(char *) * (j + 3));
 +    root->pi[i][j + 2] = realloc(root->pi[i][j + 1], j + 1);
 +    strcpy(root->pi[i][j + 2] + j - 1, (root->xml.name) ? ">" : "<");
 +    root->pi[i][j + 1] = NULL; // null terminate pi list for this target
 +    root->pi[i][j] = s; // set instruction
 +}
 +
 +// called when the parser finds an internal doctype subset
 +short ezxml_internal_dtd(ezxml_root_t root, char *s, size_t len)
 +{
 +    char q, *c, *t, *n = NULL, *v, **ent, **pe;
 +    int i, j;
 +    
 +    pe = memcpy(malloc(sizeof(EZXML_NIL)), EZXML_NIL, sizeof(EZXML_NIL));
 +
 +    for (s[len] = '\0'; s; ) {
 +        while (*s && *s != '<' && *s != '%') s++; // find next declaration
 +
 +        if (! *s) break;
 +        else if (! strncmp(s, "<!ENTITY", 8)) { // parse entity definitions
 +            c = s += strspn(s + 8, EZXML_WS) + 8; // skip white space separator
 +            n = s + strspn(s, EZXML_WS "%"); // find name
 +            *(s = n + strcspn(n, EZXML_WS)) = ';'; // append ; to name
 +
 +            v = s + strspn(s + 1, EZXML_WS) + 1; // find value
 +            if ((q = *(v++)) != '"' && q != '\'') { // skip externals
 +                s = strchr(s, '>');
 +                continue;
 +            }
 +
 +            for (i = 0, ent = (*c == '%') ? pe : root->ent; ent[i]; i++);
 +            ent = realloc(ent, (i + 3) * sizeof(char *)); // space for next ent
 +            if (*c == '%') pe = ent;
 +            else root->ent = ent;
 +
 +            *(++s) = '\0'; // null terminate name
 +            if ((s = strchr(v, q))) *(s++) = '\0'; // null terminate value
 +            ent[i + 1] = ezxml_decode(v, pe, '%'); // set value
 +            ent[i + 2] = NULL; // null terminate entity list
 +            if (! ezxml_ent_ok(n, ent[i + 1], ent)) { // circular reference
 +                if (ent[i + 1] != v) free(ent[i + 1]);
 +                ezxml_err(root, v, "circular entity declaration &%s", n);
 +                break;
 +            }
 +            else ent[i] = n; // set entity name
 +        }
 +        else if (! strncmp(s, "<!ATTLIST", 9)) { // parse default attributes
 +            t = s + strspn(s + 9, EZXML_WS) + 9; // skip whitespace separator
 +            if (! *t) { ezxml_err(root, t, "unclosed <!ATTLIST"); break; }
 +            if (*(s = t + strcspn(t, EZXML_WS ">")) == '>') continue;
 +            else *s = '\0'; // null terminate tag name
 +            for (i = 0; root->attr[i] && strcmp(n, root->attr[i][0]); i++);
 +
 +            while (*(n = s + 1 + strspn(s + 1, EZXML_WS)) && *n != '>') {
 +                if (*(s = n + strcspn(n, EZXML_WS))) *s = '\0'; // attr name
 +                else { ezxml_err(root, t, "malformed <!ATTLIST"); break; }
 +
 +                s += strspn(s + 1, EZXML_WS) + 1; // find next token
 +                c = (strncmp(s, "CDATA", 5)) ? "*" : " "; // is it cdata?
 +                if (! strncmp(s, "NOTATION", 8))
 +                    s += strspn(s + 8, EZXML_WS) + 8;
 +                s = (*s == '(') ? strchr(s, ')') : s + strcspn(s, EZXML_WS);
 +                if (! s) { ezxml_err(root, t, "malformed <!ATTLIST"); break; }
 +
 +                s += strspn(s, EZXML_WS ")"); // skip white space separator
 +                if (! strncmp(s, "#FIXED", 6))
 +                    s += strspn(s + 6, EZXML_WS) + 6;
 +                if (*s == '#') { // no default value
 +                    s += strcspn(s, EZXML_WS ">") - 1;
 +                    if (*c == ' ') continue; // cdata is default, nothing to do
 +                    v = NULL;
 +                }
 +                else if ((*s == '"' || *s == '\'')  &&  // default value
 +                         (s = strchr(v = s + 1, *s))) *s = '\0';
 +                else { ezxml_err(root, t, "malformed <!ATTLIST"); break; }
 +
 +                if (! root->attr[i]) { // new tag name
 +                    root->attr = (! i) ? malloc(2 * sizeof(char **))
 +                                       : realloc(root->attr,
 +                                                 (i + 2) * sizeof(char **));
 +                    root->attr[i] = malloc(2 * sizeof(char *));
 +                    root->attr[i][0] = t; // set tag name
 +                    root->attr[i][1] = (char *)(root->attr[i + 1] = NULL);
 +                }
 +
 +                for (j = 1; root->attr[i][j]; j += 3); // find end of list
 +                root->attr[i] = realloc(root->attr[i],
 +                                        (j + 4) * sizeof(char *));
 +
 +                root->attr[i][j + 3] = NULL; // null terminate list
 +                root->attr[i][j + 2] = c; // is it cdata?
 +                root->attr[i][j + 1] = (v) ? ezxml_decode(v, root->ent, *c)
 +                                           : NULL;
 +                root->attr[i][j] = n; // attribute name 
 +            }
 +        }
 +        else if (! strncmp(s, "<!--", 4)) s = strstr(s + 4, "-->"); // comments
 +        else if (! strncmp(s, "<?", 2)) { // processing instructions
 +            if ((s = strstr(c = s + 2, "?>")))
 +                ezxml_proc_inst(root, c, s++ - c);
 +        }
 +        else if (*s == '<') s = strchr(s, '>'); // skip other declarations
 +        else if (*(s++) == '%' && ! root->standalone) break;
 +    }
 +
 +    free(pe);
 +    return ! *root->err;
 +}
 +
 +// Converts a UTF-16 string to UTF-8. Returns a new string that must be freed
 +// or NULL if no conversion was needed.
 +char *ezxml_str2utf8(char **s, size_t *len)
 +{
 +    char *u;
 +    size_t l = 0, sl, max = *len;
 +    long c, d;
 +    int b, be = (**s == '\xFE') ? 1 : (**s == '\xFF') ? 0 : -1;
 +
 +    if (be == -1) return NULL; // not UTF-16
 +
 +    u = malloc(max);
 +    for (sl = 2; sl < *len - 1; sl += 2) {
 +        c = (be) ? (((*s)[sl] & 0xFF) << 8) | ((*s)[sl + 1] & 0xFF)  //UTF-16BE
 +                 : (((*s)[sl + 1] & 0xFF) << 8) | ((*s)[sl] & 0xFF); //UTF-16LE
 +        if (c >= 0xD800 && c <= 0xDFFF && (sl += 2) < *len - 1) { // high-half
 +            d = (be) ? (((*s)[sl] & 0xFF) << 8) | ((*s)[sl + 1] & 0xFF)
 +                     : (((*s)[sl + 1] & 0xFF) << 8) | ((*s)[sl] & 0xFF);
 +            c = (((c & 0x3FF) << 10) | (d & 0x3FF)) + 0x10000;
 +        }
 +
 +        while (l + 6 > max) u = realloc(u, max += EZXML_BUFSIZE);
 +        if (c < 0x80) u[l++] = (char)c; // US-ASCII subset
 +        else { // multi-byte UTF-8 sequence
 +            for (b = 0, d = c; d; d /= 2) b++; // bits in c
 +            b = (b - 2) / 5; // bytes in payload
 +            u[l++] = (char)((0xFF << (7 - b)) | (c >> (6 * b))); // head
 +            while (b) u[l++] = (char)(0x80 | ((c >> (6 * --b)) & 0x3F)); // payload
 +        }
 +    }
 +    return *s = realloc(u, *len = l);
 +}
 +
 +// frees a tag attribute list
 +void ezxml_free_attr(char **attr) {
 +    int i = 0;
 +    char *m;
 +    
 +    if (! attr || attr == EZXML_NIL) return; // nothing to free
 +    while (attr[i]) i += 2; // find end of attribute list
 +    m = attr[i + 1]; // list of which names and values are malloced
 +    for (i = 0; m[i]; i++) {
 +        if (m[i] & EZXML_NAMEM) free(attr[i * 2]);
 +        if (m[i] & EZXML_TXTM) free(attr[(i * 2) + 1]);
 +    }
 +    free(m);
 +    free(attr);
 +}
 +
 +// parse the given xml string and return an ezxml structure
 +ezxml_t ezxml_parse_str(char *s, size_t len)
 +{
 +    ezxml_root_t root = (ezxml_root_t)ezxml_new(NULL);
 +    char q, e, *d, **attr, **a = NULL; // initialize a to avoid compile warning
 +    int l, i, j;
 +
 +    root->m = s;
 +    if (! len) return ezxml_err(root, NULL, "root tag missing");
 +    root->u = ezxml_str2utf8(&s, &len); // convert utf-16 to utf-8
 +    root->e = (root->s = s) + len; // record start and end of work area
 +    
 +    e = s[len - 1]; // save end char
 +    s[len - 1] = '\0'; // turn end char into null terminator
 +
 +    while (*s && *s != '<') s++; // find first tag
 +    if (! *s) return ezxml_err(root, s, "root tag missing");
 +
 +    for (; ; ) {
 +        attr = (char **)EZXML_NIL;
 +        d = ++s;
 +        
 +        if (isalpha(*s) || *s == '_' || *s == ':' || *s < '\0') { // new tag
 +            if (! root->cur)
 +                return ezxml_err(root, d, "markup outside of root element");
 +
 +            s += strcspn(s, EZXML_WS "/>");
 +            while (isspace(*s)) *(s++) = '\0'; // null terminate tag name
 +  
 +            if (*s && *s != '/' && *s != '>') // find tag in default attr list
 +                for (i = 0; (a = root->attr[i]) && strcmp(a[0], d); i++);
 +
 +            for (l = 0; *s && *s != '/' && *s != '>'; l += 2) { // new attrib
 +                attr = (l) ? realloc(attr, (l + 4) * sizeof(char *))
 +                           : malloc(4 * sizeof(char *)); // allocate space
 +                attr[l + 3] = (l) ? realloc(attr[l + 1], (l / 2) + 2)
 +                                  : malloc(2); // mem for list of maloced vals
 +                strcpy(attr[l + 3] + (l / 2), " "); // value is not malloced
 +                attr[l + 2] = NULL; // null terminate list
 +                attr[l + 1] = ""; // temporary attribute value
 +                attr[l] = s; // set attribute name
 +
 +                s += strcspn(s, EZXML_WS "=/>");
 +                if (*s == '=' || isspace(*s)) { 
 +                    *(s++) = '\0'; // null terminate tag attribute name
 +                    q = *(s += strspn(s, EZXML_WS "="));
 +                    if (q == '"' || q == '\'') { // attribute value
 +                        attr[l + 1] = ++s;
 +                        while (*s && *s != q) s++;
 +                        if (*s) *(s++) = '\0'; // null terminate attribute val
 +                        else {
 +                            ezxml_free_attr(attr);
 +                            return ezxml_err(root, d, "missing %c", q);
 +                        }
 +
 +                        for (j = 1; a && a[j] && strcmp(a[j], attr[l]); j +=3);
 +                        attr[l + 1] = ezxml_decode(attr[l + 1], root->ent, 
 +                                        (char)((a && a[j]) ? *a[j + 2] : ' '));
 +                        if (attr[l + 1] < d || attr[l + 1] > s)
 +                            attr[l + 3][l / 2] = EZXML_TXTM; // value malloced
 +                    }
 +                }
 +                while (isspace(*s)) s++;
 +            }
 +
 +            if (*s == '/') { // self closing tag
 +                *(s++) = '\0';
 +                if ((*s && *s != '>') || (! *s && e != '>')) {
 +                    if (l) ezxml_free_attr(attr);
 +                    return ezxml_err(root, d, "missing >");
 +                }
 +                ezxml_open_tag(root, d, attr);
 +                ezxml_close_tag(root, d, s);
 +            }
 +            else if ((q = *s) == '>' || (! *s && e == '>')) { // open tag
 +                *s = '\0'; // temporarily null terminate tag name
 +                ezxml_open_tag(root, d, attr);
 +                *s = q;
 +            }
 +            else {
 +                if (l) ezxml_free_attr(attr);
 +                return ezxml_err(root, d, "missing >"); 
 +            }
 +        }
 +        else if (*s == '/') { // close tag
 +            s += strcspn(d = s + 1, EZXML_WS ">") + 1;
 +            if (! (q = *s) && e != '>') return ezxml_err(root, d, "missing >");
 +            *s = '\0'; // temporarily null terminate tag name
 +            if (ezxml_close_tag(root, d, s)) return &root->xml;
 +            if (isspace(*s = q)) s += strspn(s, EZXML_WS);
 +        }
 +        else if (! strncmp(s, "!--", 3)) { // xml comment
 +            if (! (s = strstr(s + 3, "--")) || (*(s += 2) != '>' && *s) ||
 +                (! *s && e != '>')) return ezxml_err(root, d, "unclosed <!--");
 +        }
 +        else if (! strncmp(s, "![CDATA[", 8)) { // cdata
 +            if ((s = strstr(s, "]]>")))
 +                ezxml_char_content(root, d + 8, (s += 2) - d - 10, 'c');
 +            else return ezxml_err(root, d, "unclosed <![CDATA[");
 +        }
 +        else if (! strncmp(s, "!DOCTYPE", 8)) { // dtd
 +            for (l = 0; *s && ((! l && *s != '>') || (l && (*s != ']' || 
 +                 *(s + strspn(s + 1, EZXML_WS) + 1) != '>')));
 +                 l = (*s == '[') ? 1 : l) s += strcspn(s + 1, "[]>") + 1;
 +            if (! *s && e != '>')
 +                return ezxml_err(root, d, "unclosed <!DOCTYPE");
 +            d = (l) ? strchr(d, '[') + 1 : d;
 +            if (l && ! ezxml_internal_dtd(root, d, s++ - d)) return &root->xml;
 +        }
 +        else if (*s == '?') { // <?...?> processing instructions
 +            do { s = strchr(s, '?'); } while (s && *(++s) && *s != '>');
 +            if (! s || (! *s && e != '>')) 
 +                return ezxml_err(root, d, "unclosed <?");
 +            else ezxml_proc_inst(root, d + 1, s - d - 2);
 +        }
 +        else return ezxml_err(root, d, "unexpected <");
 +        
 +        if (! s || ! *s) break;
 +        *s = '\0';
 +        d = ++s;
 +        if (*s && *s != '<') { // tag character content
 +            while (*s && *s != '<') s++;
 +            if (*s) ezxml_char_content(root, d, s - d, '&');
 +            else break;
 +        }
 +        else if (! *s) break;
 +    }
 +
 +    if (! root->cur) return &root->xml;
 +    else if (! root->cur->name) return ezxml_err(root, d, "root tag missing");
 +    else return ezxml_err(root, d, "unclosed tag <%s>", root->cur->name);
 +}
 +
 +// Wrapper for ezxml_parse_str() that accepts a file stream. Reads the entire
 +// stream into memory and then parses it. For xml files, use ezxml_parse_file()
 +// or ezxml_parse_fd()
 +ezxml_t ezxml_parse_fp(FILE *fp)
 +{
 +    ezxml_root_t root;
 +    size_t l, len = 0;
 +    char *s;
 +
 +    if (! (s = malloc(EZXML_BUFSIZE))) return NULL;
 +    do {
 +        len += (l = fread((s + len), 1, EZXML_BUFSIZE, fp));
 +        if (l == EZXML_BUFSIZE) s = realloc(s, len + EZXML_BUFSIZE);
 +    } while (s && l == EZXML_BUFSIZE);
 +
 +    if (! s) return NULL;
 +    root = (ezxml_root_t)ezxml_parse_str(s, len);
 +    root->len = SIZE_MAX; // so we know to free s in ezxml_free()
 +    return &root->xml;
 +}
 +
 +// Encodes ampersand sequences appending the results to *dst, reallocating *dst
 +// if length excedes max. a is non-zero for attribute encoding. Returns *dst
 +char *ezxml_ampencode(const char *s, size_t len, char **dst, size_t *dlen,
 +                      size_t *max, short a)
 +{
 +    const char *e;
 +    
 +    for (e = s + len; s != e; s++) {
 +        while (*dlen + 10 > *max) *dst = realloc(*dst, *max += EZXML_BUFSIZE);
 +
 +        switch (*s) {
 +        case '\0': return *dst;
 +        case '&': *dlen += sprintf(*dst + *dlen, "&"); break; //!!!!!!!!!!!!!!
 +        case '<': *dlen += sprintf(*dst + *dlen, "<"); break; //!!!!!!!!!!!!!!
 +        case '>': *dlen += sprintf(*dst + *dlen, ">"); break; //!!!!!!!!!!!!!!
 +        case '"': *dlen += sprintf(*dst + *dlen, (a) ? """ : "\""); break; //!!!!!!!!!!!!!!
 +//        case '\n': *dlen += sprintf(*dst + *dlen, (a) ? "
" : "\n"); break; //!!!!!!!!!!!!!!
 +        case '\t': *dlen += sprintf(*dst + *dlen, (a) ? "	" : "\t"); break; //!!!!!!!!!!!!!!
 +//        case '\r': *dlen += sprintf(*dst + *dlen, "
"); break; //!!!!!!!!!!!!!!
 +        default: (*dst)[(*dlen)++] = *s;
 +        }
 +    }
 +    return *dst;
 +}
 +
 +// Recursively converts each tag to xml appending it to *s. Reallocates *s if
 +// its length excedes max. start is the location of the previous tag in the
 +// parent tag's character content. Returns *s.
 +char *ezxml_toxml_r(ezxml_t xml, char **s, size_t *len, size_t *max,
 +                    size_t start, char ***attr)
 +{
 +    int i, j;
 +    char *txt = (xml->parent) ? xml->parent->txt : "";
 +    size_t off = 0;
 +
 +    // parent character content up to this tag
 +    *s = ezxml_ampencode(txt + start, xml->off - start, s, len, max, 0);
 +
 +    while (*len + strlen(xml->name) + 4 > *max) // reallocate s
 +        *s = realloc(*s, *max += EZXML_BUFSIZE);
 +
 +    *len += sprintf(*s + *len, "<%s", xml->name); // open tag //!!!!!!!!!!!!!!
 +    for (i = 0; xml->attr[i]; i += 2) { // tag attributes
 +        if (ezxml_attr(xml, xml->attr[i]) != xml->attr[i + 1]) continue;
 +        while (*len + strlen(xml->attr[i]) + 7 > *max) // reallocate s
 +            *s = realloc(*s, *max += EZXML_BUFSIZE);
 +
 +        *len += sprintf(*s + *len, " %s=\"", xml->attr[i]); //!!!!!!!!!!!!!!
 +        ezxml_ampencode(xml->attr[i + 1], SIZE_MAX, s, len, max, 1);
 +        *len += sprintf(*s + *len, "\""); //!!!!!!!!!!!!!!
 +    }
 +
 +    for (i = 0; attr[i] && strcmp(attr[i][0], xml->name); i++);
 +    for (j = 1; attr[i] && attr[i][j]; j += 3) { // default attributes
 +        if (! attr[i][j + 1] || ezxml_attr(xml, attr[i][j]) != attr[i][j + 1])
 +            continue; // skip duplicates and non-values
 +        while (*len + strlen(attr[i][j]) + 7 > *max) // reallocate s
 +            *s = realloc(*s, *max += EZXML_BUFSIZE);
 +
 +        *len += sprintf(*s + *len, " %s=\"", attr[i][j]); //!!!!!!!!!!!!!!
 +        ezxml_ampencode(attr[i][j + 1], SIZE_MAX, s, len, max, 1);
 +        *len += sprintf(*s + *len, "\""); //!!!!!!!!!!!!!!
 +    }
 +	if (xml->attr != EZXML_NIL && xml->child == NULL && xml->txt[0] == 0)
 +		*len += sprintf(*s + *len, "/>"); //!!!!!!!!!!!!!!
 +	else
 +	{
 +		*len += sprintf(*s + *len, ">"); //!!!!!!!!!!!!!!
 +
 +		*s = (xml->child) ? ezxml_toxml_r(xml->child, s, len, max, 0, attr) //child
 +						  : ezxml_ampencode(xml->txt, SIZE_MAX, s, len, max, 0);  //data
 +	    
 +		while (*len + strlen(xml->name) + 4 > *max) // reallocate s
 +			*s = realloc(*s, *max += EZXML_BUFSIZE);
 +
 +		*len += sprintf(*s + *len, "</%s>", xml->name); // close tag //!!!!!!!!!!!!!!
 +	}
 +
 +    while (txt[off] && off < xml->off) off++; // make sure off is within bounds
 +    return (xml->ordered) ? ezxml_toxml_r(xml->ordered, s, len, max, off, attr)
 +                          : ezxml_ampencode(txt + off, SIZE_MAX, s, len, max, 0);
 +}
 +
 +// Converts an ezxml structure back to xml. Returns a string of xml data that
 +// must be freed.
 +char *ezxml_toxml(ezxml_t xml, int addhdr)
 +{
 +    ezxml_t p = (xml) ? xml->parent : NULL, o = (xml) ? xml->ordered : NULL;
 +    ezxml_root_t root = (ezxml_root_t)xml;
 +    size_t len, max = EZXML_BUFSIZE;
 +    char *s, *t, *n;
 +    int i, j, k;
 +
 +	s = strcpy(malloc(max), addhdr ? "<?xml version=\"1.0\" encoding=\"utf-8\"?>" : "");
 +	len = strlen(s);
 +
 +    if (! xml || ! xml->name) return realloc(s, len + 1);
 +    while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag
 +
 +    for (i = 0; ! p && root->pi[i]; i++) { // pre-root processing instructions
 +        for (k = 2; root->pi[i][k - 1]; k++);
 +        for (j = 1; (n = root->pi[i][j]); j++) {
 +            if (root->pi[i][k][j - 1] == '>') continue; // not pre-root
 +            while (len + strlen(t = root->pi[i][0]) + strlen(n) + 7 > max)
 +                s = realloc(s, max += EZXML_BUFSIZE);
 +            len += sprintf(s + len, "<?%s%s%s?>\n", t, *n ? " " : "", n); //!!!!!!!!!!!!!!
 +        }
 +    }
 +
 +    xml->parent = xml->ordered = NULL;
 +    s = ezxml_toxml_r(xml, &s, &len, &max, 0, root->attr);
 +    xml->parent = p;
 +    xml->ordered = o;
 +
 +    for (i = 0; ! p && root->pi[i]; i++) { // post-root processing instructions
 +        for (k = 2; root->pi[i][k - 1]; k++);
 +        for (j = 1; (n = root->pi[i][j]); j++) {
 +            if (root->pi[i][k][j - 1] == '<') continue; // not post-root
 +            while (len + strlen(t = root->pi[i][0]) + strlen(n) + 7 > max)
 +                s = realloc(s, max += EZXML_BUFSIZE);
 +            len += sprintf(s + len, "\n<?%s%s%s?>", t, *n ? " " : "", n); //!!!!!!!!!!!!!!
 +        }
 +    }
 +    return realloc(s, len + 1);
 +}
 +
 +// free the memory allocated for the ezxml structure
 +void ezxml_free(ezxml_t xml)
 +{
 +    ezxml_root_t root = (ezxml_root_t)xml;
 +    int i, j;
 +    char **a, *s;
 +
 +    if (! xml) return;
 +    ezxml_free(xml->child);
 +    ezxml_free(xml->ordered);
 +
 +    if (! xml->parent) { // free root tag allocations
 +        for (i = 10; root->ent[i]; i += 2) // 0 - 9 are default entites (<>&"')
 +            if ((s = root->ent[i + 1]) < root->s || s > root->e) free(s);
 +        free(root->ent); // free list of general entities
 +
 +        for (i = 0; (a = root->attr[i]); i++) {
 +            for (j = 1; a[j++]; j += 2) // free malloced attribute values
 +                if (a[j] && (a[j] < root->s || a[j] > root->e)) free(a[j]);
 +            free(a);
 +        }
 +        if (root->attr[0]) free(root->attr); // free default attribute list
 +
 +        for (i = 0; root->pi[i]; i++) {
 +            for (j = 1; root->pi[i][j]; j++);
 +            free(root->pi[i][j + 1]);
 +            free(root->pi[i]);
 +        }            
 +        if (root->pi[0]) free(root->pi); // free processing instructions
 +
 +        if (root->len == SIZE_MAX) free(root->m); // malloced xml data
 +        if (root->u) free(root->u); // utf8 conversion
 +    }
 +
 +    ezxml_free_attr(xml->attr); // tag attributes
 +    if ((xml->flags & EZXML_TXTM)) free(xml->txt); // character content
 +    if ((xml->flags & EZXML_NAMEM)) free(xml->name); // tag name
 +    free(xml);
 +}
 +
 +// return parser error message or empty string if none
 +const char *ezxml_error(ezxml_t xml)
 +{
 +    while (xml && xml->parent) xml = xml->parent; // find root tag
 +    return (xml) ? ((ezxml_root_t)xml)->err : "";
 +}
 +
 +// returns a new empty ezxml structure with the given root tag name
 +ezxml_t ezxml_new(const char *name)
 +{
 +    static char *ent[] = { "lt;", "<", "gt;", ">", "quot;", """,
 +                           "apos;", "'", "amp;", "&", NULL };
 +    ezxml_root_t root = (ezxml_root_t)memset(malloc(sizeof(struct ezxml_root)), 
 +                                             '\0', sizeof(struct ezxml_root));
 +    root->xml.name = (char *)name;
 +    root->cur = &root->xml;
 +    strcpy(root->err, root->xml.txt = "");
 +    root->ent = memcpy(malloc(sizeof(ent)), ent, sizeof(ent));
 +    root->attr = root->pi = (char ***)(root->xml.attr = EZXML_NIL);
 +    return &root->xml;
 +}
 +
 +// inserts an existing tag into an ezxml structure
 +ezxml_t ezxml_insert(ezxml_t xml, ezxml_t dest, size_t off)
 +{
 +    ezxml_t cur, prev, head;
 +
 +    xml->next = xml->sibling = xml->ordered = NULL;
 +    xml->off = off;
 +    xml->parent = dest;
 +
 +    if ((head = dest->child)) { // already have sub tags
 +        if (head->off <= off) { // not first subtag
 +            for (cur = head; cur->ordered && cur->ordered->off <= off;
 +                 cur = cur->ordered);
 +            xml->ordered = cur->ordered;
 +            cur->ordered = xml;
 +        }
 +        else { // first subtag
 +            xml->ordered = head;
 +            dest->child = xml;
 +        }
 +
 +        for (cur = head, prev = NULL; cur && strcmp(cur->name, xml->name);
 +             prev = cur, cur = cur->sibling); // find tag type
 +        if (cur && cur->off <= off) { // not first of type
 +            while (cur->next && cur->next->off <= off) cur = cur->next;
 +            xml->next = cur->next;
 +            cur->next = xml;
 +        }
 +        else { // first tag of this type
 +            if (prev && cur) prev->sibling = cur->sibling; // remove old first
 +            xml->next = cur; // old first tag is now next
 +            for (cur = head, prev = NULL; cur && cur->off <= off;
 +                 prev = cur, cur = cur->sibling); // new sibling insert point
 +            xml->sibling = cur;
 +            if (prev) prev->sibling = xml;
 +        }
 +    }
 +    else dest->child = xml; // only sub tag
 +
 +    return xml;
 +}
 +
 +// Adds a child tag. off is the offset of the child tag relative to the start
 +// of the parent tag's character content. Returns the child tag.
 +ezxml_t ezxml_add_child(ezxml_t xml, const char *name, size_t off)
 +{
 +    ezxml_t child;
 +
 +    if (! xml) return NULL;
 +    child = (ezxml_t)memset(malloc(sizeof(struct ezxml)), '\0',
 +                            sizeof(struct ezxml));
 +    child->name = (char *)name;
 +    child->attr = EZXML_NIL;
 +    child->txt = "";
 +
 +    return ezxml_insert(child, xml, off);
 +}
 +
 +// sets the character content for the given tag and returns the tag
 +ezxml_t ezxml_set_txt(ezxml_t xml, const char *txt)
 +{
 +    if (! xml) return NULL;
 +    if (xml->flags & EZXML_TXTM) free(xml->txt); // existing txt was malloced
 +    xml->flags &= ~EZXML_TXTM;
 +    xml->txt = (char *)txt;
 +    return xml;
 +}
 +
 +// Sets the given tag attribute or adds a new attribute if not found. A value
 +// of NULL will remove the specified attribute. Returns the tag given.
 +ezxml_t ezxml_set_attr(ezxml_t xml, const char *name, const char *value)
 +{
 +    int l = 0, c;
 +
 +    if (! xml) return NULL;
 +    while (xml->attr[l] && strcmp(xml->attr[l], name)) l += 2;
 +    if (! xml->attr[l]) { // not found, add as new attribute
 +        if (! value) return xml; // nothing to do
 +        if (xml->attr == EZXML_NIL) { // first attribute
 +            xml->attr = malloc(4 * sizeof(char *));
 +            xml->attr[1] = _strdup(""); // empty list of malloced names/vals
 +        }
 +        else xml->attr = realloc(xml->attr, (l + 4) * sizeof(char *));
 +
 +        xml->attr[l] = (char *)name; // set attribute name
 +        xml->attr[l + 2] = NULL; // null terminate attribute list
 +        xml->attr[l + 3] = realloc(xml->attr[l + 1],
 +                                   (c = (int)strlen(xml->attr[l + 1])) + 2);
 +        strcpy(xml->attr[l + 3] + c, " "); // set name/value as not malloced
 +        if (xml->flags & EZXML_DUP) xml->attr[l + 3][c] = (unsigned char)EZXML_NAMEM;
 +    }
 +    else if (xml->flags & EZXML_DUP) free((char *)name); // name was strduped
 +
 +    for (c = l; xml->attr[c]; c += 2); // find end of attribute list
 +    if (xml->attr[c + 1][l / 2] & EZXML_TXTM) free(xml->attr[l + 1]); //old val
 +    if (xml->flags & EZXML_DUP) xml->attr[c + 1][l / 2] |= EZXML_TXTM;
 +    else xml->attr[c + 1][l / 2] &= ~EZXML_TXTM;
 +
 +    if (value) xml->attr[l + 1] = (char *)value; // set attribute value
 +    else { // remove attribute
 +        if (xml->attr[c + 1][l / 2] & EZXML_NAMEM) free(xml->attr[l]);
 +        memmove(xml->attr + l, xml->attr + l + 2, (c - l + 2) * sizeof(char*));
 +        xml->attr = realloc(xml->attr, (c + 2) * sizeof(char *));
 +        memmove(xml->attr[c + 1] + (l / 2), xml->attr[c + 1] + (l / 2) + 1,
 +                (c / 2) - (l / 2)); // fix list of which name/vals are malloced
 +    }
 +    xml->flags &= ~EZXML_DUP; // clear strdup() flag
 +    return xml;
 +}
 +
 +// sets a flag for the given tag and returns the tag
 +ezxml_t ezxml_set_flag(ezxml_t xml, short flag)
 +{
 +    if (xml) xml->flags |= flag;
 +    return xml;
 +}
 +
 +// removes a tag along with its subtags without freeing its memory
 +ezxml_t ezxml_cut(ezxml_t xml)
 +{
 +    ezxml_t cur;
 +
 +    if (! xml) return NULL; // nothing to do
 +    if (xml->next) xml->next->sibling = xml->sibling; // patch sibling list
 +
 +    if (xml->parent) { // not root tag
 +        cur = xml->parent->child; // find head of subtag list
 +        if (cur == xml) xml->parent->child = xml->ordered; // first subtag
 +        else { // not first subtag
 +            while (cur->ordered != xml) cur = cur->ordered;
 +            cur->ordered = cur->ordered->ordered; // patch ordered list
 +
 +            cur = xml->parent->child; // go back to head of subtag list
 +            if (strcmp(cur->name, xml->name)) { // not in first sibling list
 +                while (strcmp(cur->sibling->name, xml->name))
 +                    cur = cur->sibling;
 +                if (cur->sibling == xml) { // first of a sibling list
 +                    cur->sibling = (xml->next) ? xml->next
 +                                               : cur->sibling->sibling;
 +                }
 +                else cur = cur->sibling; // not first of a sibling list
 +            }
 +
 +            while (cur->next && cur->next != xml) cur = cur->next;
 +            if (cur->next) cur->next = cur->next->next; // patch next list
 +        }        
 +    }
 +    xml->ordered = xml->sibling = xml->next = NULL;
 +    return xml;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/ezxml.h b/plugins/!Deprecated/MSN/src/ezxml.h new file mode 100644 index 0000000000..37a0385541 --- /dev/null +++ b/plugins/!Deprecated/MSN/src/ezxml.h @@ -0,0 +1,165 @@ +/* ezxml.h + * + * Copyright 2004-2006 Aaron Voisine <aaron@voisine.org> + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _EZXML_H +#define _EZXML_H + +#include <stdio.h> +#include <stdarg.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define EZXML_BUFSIZE 1024 // size of internal memory buffers +#define EZXML_NAMEM   0x80 // name is malloced +#define EZXML_TXTM    0x40 // txt is malloced +#define EZXML_DUP     0x20 // attribute name and value are strduped + +typedef struct ezxml *ezxml_t; +struct ezxml { +    char *name;      // tag name +    char **attr;     // tag attributes { name, value, name, value, ... NULL } +    char *txt;       // tag character content, empty string if none +    size_t off;      // tag offset from start of parent tag character content +    ezxml_t next;    // next tag with same name in this section at this depth +    ezxml_t sibling; // next tag with different name in same section and depth +    ezxml_t ordered; // next tag, same section and depth, in original order +    ezxml_t child;   // head of sub tag list, NULL if none +    ezxml_t parent;  // parent tag, NULL if current tag is root tag +    short flags;     // additional information +}; + +// Given a string of xml data and its length, parses it and creates an ezxml +// structure. For efficiency, modifies the data by adding null terminators +// and decoding ampersand sequences. If you don't want this, copy the data and +// pass in the copy. Returns NULL on failure. +ezxml_t ezxml_parse_str(char *s, size_t len); + +// A wrapper for ezxml_parse_str() that accepts a file descriptor. First +// attempts to mem map the file. Failing that, reads the file into memory. +// Returns NULL on failure. +ezxml_t ezxml_parse_fd(int fd); + +// a wrapper for ezxml_parse_fd() that accepts a file name +ezxml_t ezxml_parse_file(const char *file); +     +// Wrapper for ezxml_parse_str() that accepts a file stream. Reads the entire +// stream into memory and then parses it. For xml files, use ezxml_parse_file() +// or ezxml_parse_fd() +ezxml_t ezxml_parse_fp(FILE *fp); + +// returns the first child tag (one level deeper) with the given name or NULL +// if not found +ezxml_t ezxml_child(ezxml_t xml, const char *name); + +// returns the next tag of the same name in the same section and depth or NULL +// if not found +#define ezxml_next(xml) ((xml) ? xml->next : NULL) + +// Returns the Nth tag with the same name in the same section at the same depth +// or NULL if not found. An index of 0 returns the tag given. +ezxml_t ezxml_idx(ezxml_t xml, int idx); + +// returns the name of the given tag +#define ezxml_name(xml) ((xml) ? xml->name : NULL) + +// returns the given tag's character content or empty string if none +#define ezxml_txt(xml) ((xml) ? xml->txt : "") + +// returns the value of the requested tag attribute, or NULL if not found +const char *ezxml_attr(ezxml_t xml, const char *attr); + +// Traverses the ezxml sturcture to retrieve a specific subtag. Takes a +// variable length list of tag names and indexes. The argument list must be +// terminated by either an index of -1 or an empty string tag name. Example:  +// title = ezxml_get(library, "shelf", 0, "book", 2, "title", -1); +// This retrieves the title of the 3rd book on the 1st shelf of library. +// Returns NULL if not found. +ezxml_t ezxml_get(ezxml_t xml, ...); + +// Converts an ezxml structure back to xml. Returns a string of xml data that +// must be freed. +char *ezxml_toxml(ezxml_t xml, int addhdr); + +// returns a NULL terminated array of processing instructions for the given +// target +const char **ezxml_pi(ezxml_t xml, const char *target); + +// frees the memory allocated for an ezxml structure +void ezxml_free(ezxml_t xml); +     +// returns parser error message or empty string if none +const char *ezxml_error(ezxml_t xml); + +// returns a new empty ezxml structure with the given root tag name +ezxml_t ezxml_new(const char *name); + +// wrapper for ezxml_new() that strdup()s name +#define ezxml_new_d(name) ezxml_set_flag(ezxml_new(strdup(name)), EZXML_NAMEM) + +// Adds a child tag. off is the offset of the child tag relative to the start +// of the parent tag's character content. Returns the child tag. +ezxml_t ezxml_add_child(ezxml_t xml, const char *name, size_t off); + +// wrapper for ezxml_add_child() that strdup()s name +#define ezxml_add_child_d(xml, name, off) \ +    ezxml_set_flag(ezxml_add_child(xml, strdup(name), off), EZXML_NAMEM) + +// sets the character content for the given tag and returns the tag +ezxml_t ezxml_set_txt(ezxml_t xml, const char *txt); + +// wrapper for ezxml_set_txt() that strdup()s txt +#define ezxml_set_txt_d(xml, txt) \ +    ezxml_set_flag(ezxml_set_txt(xml, strdup(txt)), EZXML_TXTM) + +// Sets the given tag attribute or adds a new attribute if not found. A value +// of NULL will remove the specified attribute. Returns the tag given. +ezxml_t ezxml_set_attr(ezxml_t xml, const char *name, const char *value); + +// Wrapper for ezxml_set_attr() that strdup()s name/value. Value cannot be NULL +#define ezxml_set_attr_d(xml, name, value) \ +    ezxml_set_attr(ezxml_set_flag(xml, EZXML_DUP), strdup(name), strdup(value)) + +// sets a flag for the given tag and returns the tag +ezxml_t ezxml_set_flag(ezxml_t xml, short flag); + +// removes a tag along with its subtags without freeing its memory +ezxml_t ezxml_cut(ezxml_t xml); + +// inserts an existing tag into an ezxml structure +ezxml_t ezxml_insert(ezxml_t xml, ezxml_t dest, size_t off); + +// Moves an existing tag to become a subtag of dest at the given offset from +// the start of dest's character content. Returns the moved tag. +#define ezxml_move(xml, dest, off) ezxml_insert(ezxml_cut(xml), dest, off) + +// removes a tag along with all its subtags +#define ezxml_remove(xml) ezxml_free(ezxml_cut(xml)) + +#ifdef __cplusplus +} +#endif + +#endif // _EZXML_H diff --git a/plugins/!Deprecated/MSN/src/msn.cpp b/plugins/!Deprecated/MSN/src/msn.cpp new file mode 100644 index 0000000000..21e199fb77 --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn.cpp @@ -0,0 +1,151 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +#include "version.h"
 +
 +HINSTANCE hInst;
 +
 +int hLangpack;
 +TIME_API tmi;
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// Initialization routines
 +
 +void MsnLinks_Init(void);
 +void MsnLinks_Destroy(void);
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// Global variables
 +
 +int avsPresent = -1;
 +
 +static const PLUGININFOEX pluginInfo =
 +{
 +	sizeof(PLUGININFOEX),
 +	__PLUGIN_NAME,
 +	PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
 +	__DESCRIPTION,
 +	__AUTHOR,
 +	__AUTHOREMAIL,
 +	__COPYRIGHT,
 +	__AUTHORWEB,
 +	UNICODE_AWARE,
 +	// {97724AF9-F3FB-47d3-A3BF-EAA935C74E6D}
 +	{0x97724af9, 0xf3fb, 0x47d3, {0xa3, 0xbf, 0xea, 0xa9, 0x35, 0xc7, 0x4e, 0x6d}}
 +};
 +
 +int MSN_GCEventHook(WPARAM wParam, LPARAM lParam);
 +int MSN_GCMenuHook(WPARAM wParam, LPARAM lParam);
 +
 +/////////////////////////////////////////////////////////////////////////////
 +// Protocol instances
 +static int sttCompareProtocols(const CMsnProto *p1, const CMsnProto *p2)
 +{
 +	return _tcscmp(p1->m_tszUserName, p2->m_tszUserName);
 +}
 +
 +OBJLIST<CMsnProto> g_Instances(1, sttCompareProtocols);
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	Main DLL function
 +
 +extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,LPVOID lpvReserved)
 +{
 +	if (fdwReason == DLL_PROCESS_ATTACH) {
 +		hInst = hinstDLL;
 +		DisableThreadLibraryCalls(hinstDLL);
 +	}
 +	return TRUE;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	OnModulesLoaded - finalizes plugin's configuration on load
 +
 +static int OnModulesLoaded(WPARAM wParam, LPARAM lParam)
 +{
 +	avsPresent = ServiceExists(MS_AV_SETMYAVATART) != 0;
 +
 +	MsnLinks_Init();
 +
 +	return 0;
 +}
 +
 +static CMsnProto* msnProtoInit(const char* pszProtoName, const TCHAR* tszUserName)
 +{
 +	CMsnProto *ppro = new CMsnProto(pszProtoName, tszUserName);
 +	g_Instances.insert(ppro);
 +	return ppro;
 +}
 +
 +static int msnProtoUninit(CMsnProto* ppro)
 +{
 +	g_Instances.remove(ppro);
 +	return 0;
 +}
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// Performs a primary set of actions upon plugin loading
 +
 +extern "C" int __declspec(dllexport) Load(void)
 +{
 +	mir_getTMI(&tmi);
 +	mir_getLP(&pluginInfo);
 +
 +	HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded);
 +
 +	PROTOCOLDESCRIPTOR pd = { sizeof(pd) };
 +	pd.szName = "MSN";
 +	pd.fnInit = (pfnInitProto)msnProtoInit;
 +	pd.fnUninit = (pfnUninitProto)msnProtoUninit;
 +	pd.type = PROTOTYPE_PROTOCOL;
 +	CallService(MS_PROTO_REGISTERMODULE, 0, (LPARAM)&pd);
 +
 +	MsnInitIcons();
 +	MSN_InitContactMenu();
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// Unload a plugin
 +
 +extern "C" int __declspec(dllexport) Unload(void)
 +{
 +	MSN_RemoveContactMenus();
 +	MsnLinks_Destroy();
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MirandaPluginInfoEx - returns an information about a plugin
 +
 +extern "C" __declspec(dllexport) const PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion)
 +{
 +	return &pluginInfo;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MirandaInterfaces - returns the protocol interface to the core
 +
 +extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST };
 diff --git a/plugins/!Deprecated/MSN/src/msn_auth.cpp b/plugins/!Deprecated/MSN/src/msn_auth.cpp new file mode 100644 index 0000000000..9474b71dfc --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_auth.cpp @@ -0,0 +1,485 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2007-2012 Boris Krasnovskiy.
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +#include "des.h"
 +
 +static const char defaultPassportUrl[] = "https://login.live.com/RST2.srf";
 +
 +static const char authPacket[] =
 +"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
 +"<s:Envelope"
 +		" xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\""
 +		" xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\""
 +		" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\""
 +		" xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2004/09/policy\""
 +		" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\""
 +		" xmlns:wsa=\"http://www.w3.org/2005/08/addressing\""
 +		" xmlns:wssc=\"http://schemas.xmlsoap.org/ws/2005/02/sc\""
 +		" xmlns:wst=\"http://schemas.xmlsoap.org/ws/2005/02/trust\">"
 +	"<s:Header>"
 +		"<wsa:Action s:mustUnderstand=\"1\">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</wsa:Action>"
 +		"<wsa:To s:mustUnderstand=\"1\">HTTPS://login.live.com:443//RST2.srf</wsa:To>"
 +		"<wsa:MessageID>%u</wsa:MessageID>"
 +		"<ps:AuthInfo xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"PPAuthInfo\">"
 +			"<ps:HostingApp>{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}</ps:HostingApp>"
 +			"<ps:BinaryVersion>5</ps:BinaryVersion>"
 +			"<ps:UIVersion>1</ps:UIVersion>"
 +			"<ps:Cookies />"
 +			"<ps:RequestParams>AQAAAAIAAABsYwQAAAAxMDMz</ps:RequestParams>"
 +		"</ps:AuthInfo>"
 +		"<wsse:Security>"
 +			"<wsse:UsernameToken wsu:Id=\"user\">"
 +				"<wsse:Username>%s</wsse:Username>"
 +				"<wsse:Password>%s</wsse:Password>"
 +			"</wsse:UsernameToken>"
 +			"<wsu:Timestamp Id=\"Timestamp\">"
 +				"<wsu:Created>%s</wsu:Created>"
 +				"<wsu:Expires>%s</wsu:Expires>"
 +			"</wsu:Timestamp>"
 +		"</wsse:Security>"
 +	"</s:Header>"
 +	"<s:Body>"
 +		"<ps:RequestMultipleSecurityTokens xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"RSTS\">"
 +			"<wst:RequestSecurityToken Id=\"RST0\">"
 +				"<wst:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</wst:RequestType>"
 +				"<wsp:AppliesTo>"
 +					"<wsa:EndpointReference>"
 +						"<wsa:Address>http://Passport.NET/tb</wsa:Address>"
 +					"</wsa:EndpointReference>"
 +				"</wsp:AppliesTo>"
 +			"</wst:RequestSecurityToken>"
 +			"<wst:RequestSecurityToken Id=\"RST1\">"
 +				"<wst:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</wst:RequestType>"
 +				"<wsp:AppliesTo>"
 +					"<wsa:EndpointReference>"
 +						"<wsa:Address>messengerclear.live.com</wsa:Address>"
 +					"</wsa:EndpointReference>"
 +				"</wsp:AppliesTo>"
 +				"<wsp:PolicyReference URI=\"MBI_KEY_OLD\" />"
 +			"</wst:RequestSecurityToken>"
 +			"<wst:RequestSecurityToken Id=\"RST2\">"
 +				"<wst:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</wst:RequestType>"
 +				"<wsp:AppliesTo>"
 +					"<wsa:EndpointReference>"
 +						"<wsa:Address>messenger.msn.com</wsa:Address>"
 +					"</wsa:EndpointReference>"
 +				"</wsp:AppliesTo>"
 +				"<wsp:PolicyReference URI=\"?id=507\" />"
 +			"</wst:RequestSecurityToken>"
 +			"<wst:RequestSecurityToken Id=\"RST3\">"
 +				"<wst:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</wst:RequestType>"
 +				"<wsp:AppliesTo>"
 +					"<wsa:EndpointReference>"
 +						"<wsa:Address>messengersecure.live.com</wsa:Address>"
 +					"</wsa:EndpointReference>"
 +				"</wsp:AppliesTo>"
 +				"<wsp:PolicyReference URI=\"MBI_SSL\" />"
 +			"</wst:RequestSecurityToken>"
 +			"<wst:RequestSecurityToken Id=\"RST4\">"
 +				"<wst:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</wst:RequestType>"
 +				"<wsp:AppliesTo>"
 +					"<wsa:EndpointReference>"
 +						"<wsa:Address>contacts.msn.com</wsa:Address>"
 +					"</wsa:EndpointReference>"
 +				"</wsp:AppliesTo>"
 +				"<wsp:PolicyReference URI=\"MBI\" />"
 +			"</wst:RequestSecurityToken>"
 +			"<wst:RequestSecurityToken Id=\"RST5\">"
 +				"<wst:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</wst:RequestType>"
 +				"<wsp:AppliesTo>"
 +					"<wsa:EndpointReference>"
 +						"<wsa:Address>storage.msn.com</wsa:Address>"
 +					"</wsa:EndpointReference>"
 +				"</wsp:AppliesTo>"
 +				"<wsp:PolicyReference URI=\"MBI\" />"
 +			"</wst:RequestSecurityToken>"
 +			"<wst:RequestSecurityToken Id=\"RST6\">"
 +				"<wst:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</wst:RequestType>"
 +				"<wsp:AppliesTo>"
 +					"<wsa:EndpointReference>"
 +						"<wsa:Address>sup.live.com</wsa:Address>"
 +					"</wsa:EndpointReference>"
 +				"</wsp:AppliesTo>"
 +				"<wsp:PolicyReference URI=\"MBI\" />"
 +			"</wst:RequestSecurityToken>"
 +		"</ps:RequestMultipleSecurityTokens>"
 +	"</s:Body>"
 +"</s:Envelope>";
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// Performs the MSN Passport login via TLS
 +
 +int CMsnProto::MSN_GetPassportAuth(void)
 +{
 +	int retVal = -1;
 +
 +	char szPassword[100];
 +	db_get_static(NULL, m_szModuleName, "Password", szPassword, sizeof(szPassword));
 +	szPassword[16] = 0;
 +	char* szEncPassword = HtmlEncode(szPassword);
 +
 +	time_t ts = time(NULL);
 +
 +	TCHAR szTs1[64], szTs2[64];
 +
 +	tmi.printTimeStamp(UTC_TIME_HANDLE, ts, _T("I"), szTs1, SIZEOF(szTs1), 0);
 +	tmi.printTimeStamp(UTC_TIME_HANDLE, ts + 20 * 60, _T("I"), szTs2, SIZEOF(szTs2), 0);
 +
 +	char *szTs1A = mir_t2a(szTs1), *szTs2A = mir_t2a(szTs2);
 +
 +	const size_t len = sizeof(authPacket) + 2048;
 +	char* szAuthInfo = (char*)alloca(len);
 +	mir_snprintf(szAuthInfo, len, authPacket, int(ts), MyOptions.szEmail, szEncPassword, szTs1A, szTs2A);
 +
 +	mir_free(szTs2A);
 +	mir_free(szTs1A);
 +	mir_free(szEncPassword);
 +
 +	char* szPassportHost = (char*)mir_alloc(256);
 +	if (db_get_static(NULL, m_szModuleName, "MsnPassportHost", szPassportHost, 256))
 +		strcpy(szPassportHost, defaultPassportUrl);
 +
 +	bool defaultUrlAllow = strcmp(szPassportHost, defaultPassportUrl) != 0;
 +	char *tResult = NULL;
 +
 +	while (retVal == -1)
 +	{
 +		unsigned status;
 +
 +		tResult = getSslResult(&szPassportHost, szAuthInfo, NULL, status);
 +		if (tResult == NULL)
 +		{
 +			if (defaultUrlAllow)
 +			{
 +				strcpy(szPassportHost, defaultPassportUrl);
 +				defaultUrlAllow = false;
 +				continue;
 +			}
 +			else
 +			{
 +				retVal = 4;
 +				break;
 +			}
 +		}
 +
 +		switch (status)
 +		{
 +			case 200:
 +			{
 +				const char *errurl = NULL;
 +				ezxml_t xml = ezxml_parse_str(tResult, strlen(tResult));
 +
 +				ezxml_t tokr = ezxml_get(xml, "S:Body", 0,
 +					"wst:RequestSecurityTokenResponseCollection", 0,
 +					"wst:RequestSecurityTokenResponse", -1);
 +
 +				while (tokr != NULL)
 +				{
 +					ezxml_t toks = ezxml_get(tokr, "wst:RequestedSecurityToken", 0,
 +						"wsse:BinarySecurityToken", -1);
 +
 +					const char* addr = ezxml_txt(ezxml_get(tokr, "wsp:AppliesTo", 0,
 +						"wsa:EndpointReference", 0, "wsa:Address", -1));
 +
 +					if (strcmp(addr, "http://Passport.NET/tb") == 0)
 +					{
 +						ezxml_t node = ezxml_get(tokr, "wst:RequestedSecurityToken", 0, "EncryptedData", -1);
 +						free(hotAuthToken);
 +						hotAuthToken = ezxml_toxml(node, 0);
 +
 +						node = ezxml_get(tokr, "wst:RequestedProofToken", 0, "wst:BinarySecret", -1);
 +						replaceStr(hotSecretToken, ezxml_txt(node));
 +					}
 +					else if (strcmp(addr, "messengerclear.live.com") == 0)
 +					{
 +						ezxml_t node = ezxml_get(tokr, "wst:RequestedProofToken", 0,
 +							"wst:BinarySecret", -1);
 +						if (toks)
 +						{
 +							replaceStr(authStrToken, ezxml_txt(toks));
 +							replaceStr(authSecretToken, ezxml_txt(node));
 +							retVal = 0;
 +						}
 +						else
 +						{
 +							errurl = ezxml_txt(ezxml_get(tokr, "S:Fault", 0, "psf:pp", 0, "psf:flowurl", -1));
 +						}
 +					}
 +					else if (strcmp(addr, "messenger.msn.com") == 0 && toks)
 +					{
 +						const char* tok = ezxml_txt(toks);
 +						char* ch = (char*)strchr(tok, '&');
 +						*ch = 0;
 +						replaceStr(tAuthToken, tok+2);
 +						replaceStr(pAuthToken, ch+3);
 +						*ch = '&';
 +					}
 +					else if (strcmp(addr, "contacts.msn.com") == 0 && toks)
 +					{
 +						replaceStr(authContactToken, ezxml_txt(toks));
 +					}
 +					else if (strcmp(addr, "messengersecure.live.com") == 0 && toks)
 +					{
 +						replaceStr(oimSendToken, ezxml_txt(toks));
 +					}
 +					else if (strcmp(addr, "storage.msn.com") == 0 && toks)
 +					{
 +						replaceStr(authStorageToken, ezxml_txt(toks));
 +					}
 +
 +					tokr = ezxml_next(tokr);
 +				}
 +
 +				if (retVal != 0)
 +				{
 +					if (errurl)
 +					{
 +						debugLogA("Starting URL: '%s'", errurl);
 +						CallService(MS_UTILS_OPENURL, 1, (LPARAM)errurl);
 +					}
 +
 +					ezxml_t tokf = ezxml_get(xml, "S:Body", 0, "S:Fault", 0, "S:Detail", -1);
 +					ezxml_t tokrdr = ezxml_child(tokf, "psf:redirectUrl");
 +					if (tokrdr != NULL)
 +					{
 +						strcpy(szPassportHost, ezxml_txt(tokrdr));
 +						debugLogA("Redirected to '%s'", szPassportHost);
 +					}
 +					else
 +					{
 +						const char* szFault = ezxml_txt(ezxml_get(tokf, "psf:error", 0, "psf:value", -1));
 +						retVal = strcmp(szFault, "0x80048821") == 0 ? 3 : (tokf ? 5 : 7);
 +						if (retVal != 3 && defaultUrlAllow)
 +						{
 +							strcpy(szPassportHost, defaultPassportUrl);
 +							defaultUrlAllow = false;
 +							retVal = -1;
 +						}
 +						else if (retVal != 3 && retVal != 7)
 +						{
 +							char err[512];
 +							mir_snprintf(err, sizeof(err), "Unknown Authentication error: %s", szFault);
 +							MSN_ShowError(err);
 +						}
 +					}
 +				}
 +
 +				ezxml_free(xml);
 +				break;
 +			}
 +			default:
 +				if (defaultUrlAllow)
 +				{
 +					strcpy(szPassportHost, defaultPassportUrl);
 +					defaultUrlAllow = false;
 +				}
 +				else
 +					retVal = 6;
 +		}
 +		mir_free(tResult);
 +	}
 +
 +	if (retVal != 0)
 +	{
 +		if (!Miranda_Terminated())
 +		{
 +			switch (retVal)
 +			{
 +			case 3:
 +				MSN_ShowError("Your username or password is incorrect");
 +				ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD);
 +				break;
 +
 +			case 5:
 +				break;
 +
 +			default:
 +				MSN_ShowError("Unable to contact MS Passport servers check proxy/firewall settings");
 +				ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NOSERVER);
 +				break;
 +			}
 +		}
 +	}
 +	else
 +		setString("MsnPassportHost", szPassportHost);
 +
 +	mir_free(szPassportHost);
 +	debugLogA("MSN_CheckRedirector exited with errorCode = %d", retVal);
 +	return retVal;
 +}
 +
 +static void derive_key(BYTE* der, unsigned char* key, size_t keylen, unsigned char* data, size_t datalen)
 +{
 +	BYTE hash1[MIR_SHA1_HASH_SIZE];
 +	BYTE hash2[MIR_SHA1_HASH_SIZE];
 +	BYTE hash3[MIR_SHA1_HASH_SIZE];
 +	BYTE hash4[MIR_SHA1_HASH_SIZE];
 +
 +	const size_t buflen = MIR_SHA1_HASH_SIZE + datalen;
 +	BYTE* buf = (BYTE*)alloca(buflen);
 +
 +	mir_hmac_sha1(hash1, key, keylen, data, datalen);
 +	mir_hmac_sha1(hash3, key, keylen, hash1, MIR_SHA1_HASH_SIZE);
 +
 +	memcpy(buf, hash1, MIR_SHA1_HASH_SIZE);
 +	memcpy(buf + MIR_SHA1_HASH_SIZE, data, datalen);
 +	mir_hmac_sha1(hash2, key, keylen, buf, buflen);
 +
 +	memcpy(buf, hash3, MIR_SHA1_HASH_SIZE);
 +	memcpy(buf + MIR_SHA1_HASH_SIZE, data, datalen);
 +	mir_hmac_sha1(hash4, key, keylen, buf, buflen);
 +
 +	memcpy(der, hash2, MIR_SHA1_HASH_SIZE);
 +	memcpy(der + MIR_SHA1_HASH_SIZE, hash4, 4);
 +}
 +
 +typedef struct tag_MsgrUsrKeyHdr
 +{
 +	unsigned size;
 +	unsigned cryptMode;
 +	unsigned cipherType;
 +	unsigned hashType;
 +	unsigned ivLen;
 +	unsigned hashLen;
 +	unsigned long cipherLen;
 +} MsgrUsrKeyHdr;
 +
 +static const MsgrUsrKeyHdr userKeyHdr =
 +{
 +	sizeof(MsgrUsrKeyHdr),
 +	1,			// CRYPT_MODE_CBC
 +	0x6603,		// CALG_3DES
 +	0x8004,		// CALG_SHA1
 +	8,			// sizeof(ivBytes)
 +	MIR_SHA1_HASH_SIZE,
 +	72			// sizeof(cipherBytes);
 +};
 +
 +
 +static unsigned char* PKCS5_Padding(char* in, size_t &len)
 +{
 +	const size_t nlen = ((len >> 3) + 1) << 3;
 +	unsigned char* res = (unsigned char*)mir_alloc(nlen);
 +	memcpy(res, in, len);
 +
 +	const unsigned char pad =  8 - (len & 7);
 +	memset(res + len, pad, pad);
 +
 +	len = nlen;
 +	return res;
 +}
 +
 +
 +char* CMsnProto::GenerateLoginBlob(char* challenge)
 +{
 +	unsigned key1len;
 +	BYTE *key1 = (BYTE*)mir_base64_decode(authSecretToken, &key1len);
 +
 +	BYTE key2[MIR_SHA1_HASH_SIZE+4];
 +	BYTE key3[MIR_SHA1_HASH_SIZE+4];
 +
 +	static const unsigned char encdata1[] = "WS-SecureConversationSESSION KEY HASH";
 +	static const unsigned char encdata2[] = "WS-SecureConversationSESSION KEY ENCRYPTION";
 +
 +	derive_key(key2, key1, key1len, (unsigned char*)encdata1, sizeof(encdata1) - 1);
 +	derive_key(key3, key1, key1len, (unsigned char*)encdata2, sizeof(encdata2) - 1);
 +
 +	size_t chllen = strlen(challenge);
 +
 +	BYTE hash[MIR_SHA1_HASH_SIZE];
 +	mir_hmac_sha1(hash, key2, MIR_SHA1_HASH_SIZE+4, (BYTE*)challenge, chllen);
 +
 +	unsigned char* newchl = PKCS5_Padding(challenge, chllen);
 +
 +	const size_t pktsz = sizeof(MsgrUsrKeyHdr) + MIR_SHA1_HASH_SIZE + 8 + chllen;
 +	unsigned char* userKey = (unsigned char*)alloca(pktsz);
 +
 +	unsigned char* p = userKey;
 +	memcpy(p, &userKeyHdr, sizeof(MsgrUsrKeyHdr));
 +	((MsgrUsrKeyHdr*)p)->cipherLen = (int)chllen;
 +	p += sizeof(MsgrUsrKeyHdr);
 +
 +	unsigned char iv[8];
 +	CallService(MS_UTILS_GETRANDOM, sizeof(iv), (LPARAM)iv);
 +
 +	memcpy(p, iv, sizeof(iv));
 +	p += sizeof(iv);
 +
 +	memcpy(p, hash, sizeof(hash));
 +	p += MIR_SHA1_HASH_SIZE;
 +
 +	des3_context ctxd;
 +	memset(&ctxd, 0, sizeof(ctxd));
 +	des3_set_3keys(&ctxd, key3);
 +	des3_cbc_encrypt(&ctxd, iv, newchl, p, (int)chllen);
 +
 +	mir_free(newchl);
 +
 +	return mir_base64_encode(userKey, (unsigned)pktsz);
 +}
 +
 +
 +CMStringA CMsnProto::HotmailLogin(const char* url)
 +{
 +	unsigned char nonce[24];
 +	CallService(MS_UTILS_GETRANDOM, sizeof(nonce), (LPARAM)nonce);
 +
 +	const size_t hotSecretlen = strlen(hotSecretToken);
 +	unsigned key1len;
 +	BYTE *key1 = (BYTE*)mir_base64_decode(hotSecretToken, &key1len);
 +
 +	static const unsigned char encdata[] = "WS-SecureConversation";
 +	const size_t data1len = sizeof(nonce) + sizeof(encdata) - 1;
 +
 +	unsigned char* data1 = (unsigned char*)alloca(data1len);
 +	memcpy(data1, encdata, sizeof(encdata) - 1);
 +	memcpy(data1 + sizeof(encdata) - 1, nonce, sizeof(nonce));
 +
 +	unsigned char key2[MIR_SHA1_HASH_SIZE+4];
 +	derive_key(key2, key1, key1len, data1, data1len);
 +
 +	CMStringA result;
 +	result.Format("%s&da=%s&nonce=", url, ptrA(mir_urlEncode(hotAuthToken)));
 +
 +	ptrA noncenc(mir_base64_encode(nonce, sizeof(nonce)));
 +	result.Append(ptrA(mir_urlEncode(noncenc)));
 +
 +	BYTE hash[MIR_SHA1_HASH_SIZE];
 +	mir_hmac_sha1(hash, key2, sizeof(key2), (BYTE*)result.GetString(), result.GetLength());
 +	ptrA szHash(mir_base64_encode(hash, sizeof(hash)));
 +	result.AppendFormat("&hash=%s", ptrA(mir_urlEncode(szHash)));
 +	return result;
 +}
 +
 +void CMsnProto::FreeAuthTokens(void)
 +{
 +	mir_free(pAuthToken);
 +	mir_free(tAuthToken);
 +	mir_free(oimSendToken);
 +	mir_free(authStrToken);
 +	mir_free(authSecretToken);
 +	mir_free(authContactToken);
 +	mir_free(authStorageToken);
 +	mir_free(hotSecretToken);
 +	free(hotAuthToken);
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_avatar.cpp b/plugins/!Deprecated/MSN/src/msn_avatar.cpp new file mode 100644 index 0000000000..ba3b0da6ce --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_avatar.cpp @@ -0,0 +1,122 @@ +/*
 +Plugin for Miranda NG for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-14 Miranda NG Team
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +void CMsnProto::AvatarQueue_Init()
 +{
 +	hevAvatarQueue = ::CreateEvent(NULL, FALSE, FALSE, NULL);
 +
 +	ForkThread(&CMsnProto::MSN_AvatarsThread, 0);
 +}
 +
 +void CMsnProto::AvatarQueue_Uninit()
 +{
 +	::CloseHandle(hevAvatarQueue);
 +}
 +
 +void CMsnProto::pushAvatarRequest(MCONTACT hContact, LPCSTR pszUrl)
 +{
 +	ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, 0);
 +
 +	if (pszUrl != NULL && *pszUrl != 0) {
 +		mir_cslock lck(csAvatarQueue);
 +
 +		for (int i=0; i < lsAvatarQueue.getCount(); i++)
 +			if (lsAvatarQueue[i]->hContact == hContact)
 +				return;
 +
 +		lsAvatarQueue.insert(new AvatarQueueEntry(hContact, pszUrl));
 +		SetEvent(hevAvatarQueue);
 +	}
 +}
 +
 +bool CMsnProto::loadHttpAvatar(AvatarQueueEntry *p)
 +{
 +	NETLIBHTTPHEADER nlbhHeaders[1];
 +	nlbhHeaders[0].szName = "User-Agent";
 +	nlbhHeaders[0].szValue = (char*)MSN_USER_AGENT;
 +
 +	NETLIBHTTPREQUEST nlhr = { sizeof(nlhr) };
 +	nlhr.requestType = REQUEST_GET;
 +	nlhr.flags = NLHRF_HTTP11 | NLHRF_REDIRECT;
 +	nlhr.szUrl = p->pszUrl;
 +	nlhr.headers = (NETLIBHTTPHEADER*)&nlbhHeaders;
 +	nlhr.headersCount = 1;
 +
 +	NETLIBHTTPREQUEST *nlhrReply = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)m_hNetlibUser, (LPARAM)&nlhr);
 +	if (nlhrReply == NULL)
 +		return false;
 +
 +	if (nlhrReply->resultCode != 200 || nlhrReply->dataLength == 0) {
 +LBL_Error:
 +		CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)nlhrReply);
 +		return false;
 +	}
 +
 +	const TCHAR *szExt;
 +	int fmt = ProtoGetBufferFormat(nlhrReply->pData, &szExt);
 +	if (fmt == PA_FORMAT_UNKNOWN)
 +		goto LBL_Error;
 +
 +	PROTO_AVATAR_INFORMATIONT AI = { sizeof(AI) };
 +	AI.format = fmt;
 +	AI.hContact = p->hContact;
 +	MSN_GetAvatarFileName(AI.hContact, AI.filename, SIZEOF(AI.filename), szExt);
 +	_tremove(AI.filename);
 +
 +	int fileId = _topen(AI.filename, _O_CREAT | _O_TRUNC | _O_WRONLY | O_BINARY, _S_IREAD | _S_IWRITE);
 +	if (fileId == -1)
 +		goto LBL_Error;
 +
 +	_write(fileId, nlhrReply->pData, (unsigned)nlhrReply->dataLength);
 +	_close(fileId);
 +
 +	ProtoBroadcastAck(p->hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, &AI, 0);
 +	CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)nlhrReply);
 +	return true;
 +}
 +
 +void __cdecl CMsnProto::MSN_AvatarsThread(void*)
 +{
 +	while(true) {
 +		if (WaitForSingleObject(hevAvatarQueue, INFINITE) != WAIT_OBJECT_0)
 +			break;
 +
 +		if ( Miranda_Terminated())
 +			break;
 +
 +		AvatarQueueEntry *p = NULL;
 +		{
 +			mir_cslock lck(csAvatarQueue);
 +			if (lsAvatarQueue.getCount() > 0) {
 +				p = lsAvatarQueue[0];
 +				lsAvatarQueue.remove(0);
 +			}
 +		}
 +
 +		if (p == NULL)
 +			continue;
 +
 +		if ( !loadHttpAvatar(p))
 +			ProtoBroadcastAck(p->hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, 0, 0);
 +		delete p;
 +	}
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_chat.cpp b/plugins/!Deprecated/MSN/src/msn_chat.cpp new file mode 100644 index 0000000000..04b17072d5 --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_chat.cpp @@ -0,0 +1,469 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +#include <m_history.h>
 +
 +MCONTACT CMsnProto::MSN_GetChatInernalHandle(MCONTACT hContact)
 +{
 +	MCONTACT result = hContact;
 +	if ( isChatRoom(hContact)) {
 +		DBVARIANT dbv;
 +		if (getString(hContact, "ChatRoomID", &dbv) == 0) {
 +			result = (MCONTACT)(-atol(dbv.pszVal));
 +			db_free(&dbv);
 +		}
 +	}
 +	return result;
 +}
 +
 +int CMsnProto::MSN_ChatInit(ThreadData *info)
 +{
 +	InterlockedIncrement(&sttChatID);
 +	_ltot(sttChatID, info->mChatID, 10);
 +
 +	TCHAR szName[512];
 +	mir_sntprintf(szName, SIZEOF(szName), _T("%s %s%s"),
 +		m_tszUserName, TranslateT("Chat #"), info->mChatID);
 +
 +	GCSESSION gcw = { sizeof(gcw) };
 +	gcw.iType = GCW_CHATROOM;
 +	gcw.pszModule = m_szModuleName;
 +	gcw.ptszName = szName;
 +	gcw.ptszID = info->mChatID;
 +	CallServiceSync(MS_GC_NEWSESSION, 0, (LPARAM)&gcw);
 +
 +	GCDEST gcd = { m_szModuleName, info->mChatID, GC_EVENT_ADDGROUP };
 +	GCEVENT gce = { sizeof(gce), &gcd };
 +	gce.ptszStatus = TranslateT("Me");
 +	CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
 +
 +	gcd.iType = GC_EVENT_JOIN;
 +	gce.ptszUID = mir_a2t(MyOptions.szEmail);
 +	gce.ptszNick = GetContactNameT(NULL);
 +	gce.time = 0;
 +	gce.bIsMe = TRUE;
 +	CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
 +
 +	gcd.iType = GC_EVENT_ADDGROUP;
 +	gce.ptszStatus = TranslateT("Others");
 +	CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
 +
 +	gcd.iType = GC_EVENT_CONTROL;
 +	CallServiceSync(MS_GC_EVENT, SESSION_INITDONE, (LPARAM)&gce);
 +	CallServiceSync(MS_GC_EVENT, SESSION_ONLINE, (LPARAM)&gce);
 +	CallServiceSync(MS_GC_EVENT, WINDOW_VISIBLE, (LPARAM)&gce);
 +
 +	mir_free((TCHAR*)gce.ptszUID);
 +	return 0;
 +}
 +
 +void CMsnProto::MSN_ChatStart(ThreadData* info)
 +{
 +	if (info->mChatID[0] != 0)
 +		return;
 +
 +	MSN_StartStopTyping(info, false);
 +
 +	MSN_ChatInit(info);
 +
 +	// add all participants onto the list
 +	GCDEST gcd = { m_szModuleName, info->mChatID, GC_EVENT_JOIN };
 +	GCEVENT gce = { sizeof(gce), &gcd };
 +	gce.dwFlags = GCEF_ADDTOLOG;
 +	gce.ptszStatus = TranslateT("Others");
 +	gce.time = time(NULL);
 +	gce.bIsMe = FALSE;
 +
 +	for (int j=0; j < info->mJoinedContactsWLID.getCount(); j++)
 +	{
 +		MCONTACT hContact = MSN_HContactFromEmail(info->mJoinedContactsWLID[j]);
 +		TCHAR *wlid = mir_a2t(info->mJoinedContactsWLID[j]);
 +
 +		gce.ptszNick = GetContactNameT(hContact);
 +		gce.ptszUID = wlid;
 +		CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
 +
 +		mir_free(wlid);
 +	}
 +}
 +
 +void CMsnProto::MSN_KillChatSession(const TCHAR* id)
 +{
 +	GCDEST gcd = { m_szModuleName, id, GC_EVENT_CONTROL };
 +	GCEVENT gce = { sizeof(gce), &gcd };
 +	gce.dwFlags = GCEF_REMOVECONTACT;
 +	CallServiceSync(MS_GC_EVENT, SESSION_OFFLINE, (LPARAM)&gce);
 +	CallServiceSync(MS_GC_EVENT, SESSION_TERMINATE, (LPARAM)&gce);
 +}
 +
 +static void ChatInviteUser(ThreadData* info, const char* email)
 +{
 +	if (info->mJoinedContactsWLID.getCount())
 +	{
 +		for (int j=0; j < info->mJoinedContactsWLID.getCount(); j++)
 +		{
 +			if (_stricmp(info->mJoinedContactsWLID[j], email) == 0)
 +				return;
 +		}
 +
 +		info->sendPacket("CAL", email);
 +		info->proto->MSN_ChatStart(info);
 +	}
 +}
 +
 +static void ChatInviteSend(HANDLE hItem, HWND hwndList, STRLIST &str, CMsnProto *ppro)
 +{
 +	if (hItem == NULL)
 +		hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_ROOT, 0);
 +
 +	while (hItem)
 +	{
 +		if (IsHContactGroup(hItem))
 +		{
 +			HANDLE hItemT = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem);
 +			if (hItemT) ChatInviteSend(hItemT, hwndList, str, ppro);
 +		}
 +		else
 +		{
 +			int chk = SendMessage(hwndList, CLM_GETCHECKMARK, (WPARAM)hItem, 0);
 +			if (chk)
 +			{
 +				if (IsHContactInfo(hItem))
 +				{
 +					TCHAR buf[128] = _T("");
 +					SendMessage(hwndList, CLM_GETITEMTEXT, (WPARAM)hItem, (LPARAM)buf);
 +
 +					if (buf[0]) str.insert(mir_t2a(buf));
 +				}
 +				else
 +				{
 +					MsnContact *msc = ppro->Lists_Get((MCONTACT)hItem);
 +					if (msc) str.insertn(msc->email);
 +				}
 +			}
 +		}
 +		hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXT, (LPARAM)hItem);
 +	}
 +}
 +
 +
 +static void ChatValidateContact(MCONTACT hItem, HWND hwndList, CMsnProto* ppro)
 +{
 +	if (!ppro->MSN_IsMyContact(hItem) || ppro->isChatRoom(hItem) || ppro->MSN_IsMeByContact(hItem))
 +		SendMessage(hwndList, CLM_DELETEITEM, (WPARAM)hItem, 0);
 +}
 +
 +static void ChatPrepare(MCONTACT hItem, HWND hwndList, CMsnProto* ppro)
 +{
 +	if (hItem == NULL)
 +		hItem = (MCONTACT)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_ROOT, 0);
 +
 +	while (hItem)
 +	{
 +		MCONTACT hItemN = (MCONTACT)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXT, (LPARAM)hItem);
 +
 +		if (IsHContactGroup(hItem)) {
 +			MCONTACT hItemT = (MCONTACT)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem);
 +			if (hItemT)
 +				ChatPrepare(hItemT, hwndList, ppro);
 +		}
 +		else if (IsHContactContact(hItem))
 +			ChatValidateContact(hItem, hwndList, ppro);
 +
 +		hItem = hItemN;
 +   }
 +}
 +
 +INT_PTR CALLBACK DlgInviteToChat(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 +{
 +	InviteChatParam *param = (InviteChatParam*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 +
 +	switch (msg)
 +	{
 +	case WM_INITDIALOG:
 +		TranslateDialogDefault(hwndDlg);
 +
 +		SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
 +		param = (InviteChatParam*)lParam;
 +
 +//		WindowSetIcon(hwndDlg, "msn");
 +		break;
 +
 +	case WM_CLOSE:
 +		EndDialog(hwndDlg, 0);
 +		break;
 +
 +	case WM_NCDESTROY:
 +//		WindowFreeIcon(hwndDlg);
 +		delete param;
 +		break;
 +
 +	case WM_NOTIFY:
 +	{
 +		NMCLISTCONTROL* nmc = (NMCLISTCONTROL*)lParam;
 +		if (nmc->hdr.idFrom == IDC_CCLIST)
 +		{
 +			switch (nmc->hdr.code)
 +			{
 +			case CLN_NEWCONTACT:
 +				if (param && (nmc->flags & (CLNF_ISGROUP | CLNF_ISINFO)) == 0)
 +					ChatValidateContact((MCONTACT)nmc->hItem, nmc->hdr.hwndFrom, param->ppro);
 +				break;
 +
 +			case CLN_LISTREBUILT:
 +				if (param)
 +					ChatPrepare(NULL, nmc->hdr.hwndFrom, param->ppro);
 +				break;
 +			}
 +		}
 +	}
 +	break;
 +
 +	case WM_COMMAND:
 +		{
 +			switch (LOWORD(wParam))
 +			{
 +			case IDC_ADDSCR:
 +				if (param->ppro->msnLoggedIn)
 +				{
 +					TCHAR email[MSN_MAX_EMAIL_LEN];
 +					GetDlgItemText(hwndDlg, IDC_EDITSCR, email, SIZEOF(email));
 +
 +					CLCINFOITEM cii = {0};
 +					cii.cbSize = sizeof(cii);
 +					cii.flags = CLCIIF_CHECKBOX | CLCIIF_BELOWCONTACTS;
 +					cii.pszText = _tcslwr(email);
 +
 +					HANDLE hItem = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_CCLIST, CLM_ADDINFOITEM, 0, (LPARAM)&cii);
 +					SendDlgItemMessage(hwndDlg, IDC_CCLIST, CLM_SETCHECKMARK, (LPARAM)hItem, 1);
 +				}
 +				break;
 +
 +			case IDOK:
 +				{
 +					char tEmail[MSN_MAX_EMAIL_LEN] = "";
 +					ThreadData *info = NULL;
 +					if (param->id)
 +						info = param->ppro->MSN_GetThreadByChatId(param->id);
 +					else if (param->hContact)
 +					{
 +						if (!param->ppro->MSN_IsMeByContact(param->hContact, tEmail))
 +							info =  param->ppro->MSN_GetThreadByContact(tEmail);
 +					}
 +
 +					HWND hwndList = GetDlgItem(hwndDlg, IDC_CCLIST);
 +					STRLIST *cont = new STRLIST;
 +					ChatInviteSend(NULL, hwndList, *cont, param->ppro);
 +
 +					if (info)
 +					{
 +						for (int i = 0; i < cont->getCount(); ++i)
 +							ChatInviteUser(info, (*cont)[i]);
 +						delete cont;
 +					}
 +					else
 +					{
 +						if (tEmail[0]) cont->insertn(tEmail);
 +						param->ppro->MsgQueue_Add("chat", 'X', NULL, 0, NULL, 0, cont);
 +						if (param->ppro->msnLoggedIn)
 +							param->ppro->msnNsThread->sendPacket("XFR", "SB");
 +					}
 +				}
 +
 +				EndDialog(hwndDlg, IDOK);
 +				break;
 +
 +			case IDCANCEL:
 +				EndDialog(hwndDlg, IDCANCEL);
 +				break;
 +			}
 +		}
 +		break;
 +	}
 +	return FALSE;
 +}
 +
 +int CMsnProto::MSN_GCEventHook(WPARAM, LPARAM lParam)
 +{
 +	GCHOOK *gch = (GCHOOK*)lParam;
 +	if (!gch)
 +		return 1;
 +
 +	if (_stricmp(gch->pDest->pszModule, m_szModuleName)) return 0;
 +
 +	switch (gch->pDest->iType)
 +	{
 +		case GC_SESSION_TERMINATE:
 +		{
 + 			ThreadData* thread = MSN_GetThreadByChatId(gch->pDest->ptszID);
 +			if (thread != NULL)
 +				thread->sendTerminate();
 +			break;
 +		}
 +
 +		case GC_USER_MESSAGE:
 +			if (gch->ptszText && gch->ptszText[0])
 +			{
 +				ThreadData* thread = MSN_GetThreadByChatId(gch->pDest->ptszID);
 +				if (thread)
 +				{
 +					TCHAR* pszMsg = UnEscapeChatTags(NEWTSTR_ALLOCA(gch->ptszText));
 +					rtrimt(pszMsg); // remove the ending linebreak
 +					thread->sendMessage('N', NULL, NETID_MSN, UTF8(pszMsg), 0);
 +
 +					DBVARIANT dbv;
 +					int bError = getTString("Nick", &dbv);
 +
 +					GCDEST gcd = { m_szModuleName, gch->pDest->ptszID, GC_EVENT_MESSAGE };
 +					GCEVENT gce = { sizeof(gce), &gcd };
 +					gce.dwFlags = GCEF_ADDTOLOG;
 +					gce.ptszNick = bError ? _T("") : dbv.ptszVal;
 +					gce.ptszUID = mir_a2t(MyOptions.szEmail);
 +					gce.time = time(NULL);
 +					gce.ptszText = gch->ptszText;
 +					gce.bIsMe = TRUE;
 +					CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
 +
 +					mir_free((void*)gce.ptszUID);
 +					if (!bError)
 +						db_free(&dbv);
 +				}
 +			}
 +			break;
 +
 +		case GC_USER_CHANMGR:
 +			DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_CHATROOM_INVITE), NULL, DlgInviteToChat,
 +				LPARAM(new InviteChatParam(gch->pDest->ptszID, NULL, this)));
 +			break;
 +
 +		case GC_USER_PRIVMESS:
 +		{
 +			char *email = mir_t2a(gch->ptszUID);
 +			MCONTACT hContact = MSN_HContactFromEmail(email);
 +			CallService(MS_MSG_SENDMESSAGE, hContact, 0);
 +			mir_free(email);
 +			break;
 +		}
 +
 +		case GC_USER_LOGMENU:
 +			switch(gch->dwData)
 +			{
 +			case 10:
 +				DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_CHATROOM_INVITE), NULL, DlgInviteToChat,
 +					LPARAM(new InviteChatParam(gch->pDest->ptszID, NULL, this)));
 +				break;
 +
 +			case 20:
 +				MSN_KillChatSession(gch->pDest->ptszID);
 +				break;
 +			}
 +			break;
 +
 +		case GC_USER_NICKLISTMENU:
 +		{
 +			char *email = mir_t2a(gch->ptszUID);
 +			MCONTACT hContact = MSN_HContactFromEmail(email);
 +			mir_free(email);
 +
 +			switch(gch->dwData)
 +			{
 +			case 10:
 +				CallService(MS_USERINFO_SHOWDIALOG, hContact, 0);
 +				break;
 +
 +			case 20:
 +				CallService(MS_HISTORY_SHOWCONTACTHISTORY, hContact, 0);
 +				break;
 +
 +			case 110:
 +				MSN_KillChatSession(gch->pDest->ptszID);
 +				break;
 +			}
 +			break;
 +		}
 +/*	haven't implemented in chat.dll
 +		case GC_USER_TYPNOTIFY:
 +		{
 +			int chatID = atoi(p);
 +			ThreadData* thread = MSN_GetThreadByContact((HANDLE)-chatID);
 +			for (int j=0; j < thread->mJoinedCount; j++)
 +			{
 +				if ((long)thread->mJoinedContacts[j] > 0)
 +					CallService(MS_PROTO_SELFISTYPING, (WPARAM) thread->mJoinedContacts[j], (LPARAM) PROTOTYPE_SELFTYPING_ON);
 +			}
 +			break;
 +		}
 +*/
 +	}
 +
 +	return 0;
 +}
 +
 +int CMsnProto::MSN_GCMenuHook(WPARAM, LPARAM lParam)
 +{
 +	GCMENUITEMS *gcmi= (GCMENUITEMS*) lParam;
 +
 +	if (gcmi == NULL || _stricmp(gcmi->pszModule, m_szModuleName)) return 0;
 +
 +	if (gcmi->Type == MENU_ON_LOG)
 +	{
 +		static const struct gc_item Items[] =
 +		{
 +			{ LPGENT("&Invite user..."), 10, MENU_ITEM, FALSE },
 +			{ LPGENT("&Leave chat session"), 20, MENU_ITEM, FALSE }
 +		};
 +		gcmi->nItems = SIZEOF(Items);
 +		gcmi->Item = (gc_item*)Items;
 +	}
 +	else if (gcmi->Type == MENU_ON_NICKLIST)
 +	{
 +		char* email = mir_t2a(gcmi->pszUID);
 +		if (!_stricmp(MyOptions.szEmail, email))
 +		{
 +			static const struct gc_item Items[] =
 +			{
 +				{ LPGENT("User &details"), 10, MENU_ITEM, FALSE },
 +				{ LPGENT("User &history"), 20, MENU_ITEM, FALSE },
 +				{ _T(""), 100, MENU_SEPARATOR, FALSE },
 +				{ LPGENT("&Leave chat session"), 110, MENU_ITEM, FALSE }
 +			};
 +			gcmi->nItems = SIZEOF(Items);
 +			gcmi->Item = (gc_item*)Items;
 +		}
 +		else
 +		{
 +			static const struct gc_item Items[] =
 +			{
 +				{ LPGENT("User &details"), 10, MENU_ITEM, FALSE },
 +				{ LPGENT("User &history"), 20, MENU_ITEM, FALSE }
 +			};
 +			gcmi->nItems = SIZEOF(Items);
 +			gcmi->Item = (gc_item*)Items;
 +		}
 +		mir_free(email);
 +	}
 +
 +	return 0;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_commands.cpp b/plugins/!Deprecated/MSN/src/msn_commands.cpp new file mode 100644 index 0000000000..c3bfaf9ee6 --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_commands.cpp @@ -0,0 +1,1753 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// Starts a file sending thread
 +
 +void MSN_ConnectionProc(HANDLE hNewConnection, DWORD /* dwRemoteIP */, void* extra)
 +{
 +	CMsnProto *proto = (CMsnProto*)extra;
 +
 +	proto->debugLogA("File transfer connection accepted");
 +
 +	NETLIBCONNINFO connInfo = { sizeof(connInfo) };
 +	CallService(MS_NETLIB_GETCONNECTIONINFO, (WPARAM)hNewConnection, (LPARAM)&connInfo);
 +
 +	ThreadData* T = proto->MSN_GetThreadByPort(connInfo.wPort);
 +	if (T != NULL && T->s == NULL) {
 +		T->s = hNewConnection;
 +		ReleaseSemaphore(T->hWaitEvent, 1, NULL);
 +	}
 +	else {
 +		proto->debugLogA("There's no registered file transfers for incoming port #%u, connection closed", connInfo.wPort);
 +		Netlib_CloseHandle(hNewConnection);
 +	}
 +}
 +
 +void CMsnProto::MSN_SetMirVer(MCONTACT hContact, DWORD dwValue, bool always)
 +{
 +	static const char* MirVerStr[] =
 +	{
 +		"MSN 4.x-5.x",
 +		"MSN 6.0",
 +		"MSN 6.1",
 +		"MSN 6.2",
 +		"MSN 7.0",
 +		"MSN 7.5",
 +		"WLM 8.0",
 +		"WLM 8.1",
 +		"WLM 8.5",
 +		"WLM 9.0 Beta",
 +		"WLM 2009",
 +		"WLM 2011",
 +		"WLM 2012",
 +		"WLM Unknown",
 +	};
 +
 +	LPCSTR szVersion;
 +
 +	if (dwValue == 0)
 +		szVersion = "Windows Phone";
 +	else if (dwValue & 0x1)
 +		szVersion = "MSN Mobile";
 +	else if (dwValue & 0x200)
 +		szVersion = "Webmessenger";
 +	else if (dwValue == 0x800800)
 +		szVersion = "Yahoo";
 +	else if (dwValue == 0x800)
 +		szVersion = "LCS";
 +	else if (dwValue == 0x50000000)
 +		szVersion = "Miranda IM 0.5.x (MSN v.0.5.x)";
 +	else if (dwValue == 0x30000024)
 +		szVersion = "Miranda IM 0.4.x (MSN v.0.4.x)";
 +	else if (always || getByte(hContact, "StdMirVer", 0)) {
 +		unsigned wlmId = min(dwValue >> 28 & 0xff, SIZEOF(MirVerStr) - 1);
 +		szVersion = MirVerStr[wlmId];
 +	}
 +	else
 +		return;
 +
 +	setString(hContact, "MirVer", szVersion);
 +	setByte(hContact, "StdMirVer", 1);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// Processes various invitations
 +
 +void CMsnProto::MSN_InviteMessage(ThreadData* info, char* msgBody, char* email, char* nick)
 +{
 +	MimeHeaders tFileInfo;
 +	tFileInfo.readFromBuffer(msgBody);
 +
 +	const char* Appname = tFileInfo["Application-Name"];
 +	const char* AppGUID = tFileInfo["Application-GUID"];
 +	const char* Invcommand = tFileInfo["Invitation-Command"];
 +	const char* Invcookie = tFileInfo["Invitation-Cookie"];
 +	const char* Appfile = tFileInfo["Application-File"];
 +	const char* Appfilesize = tFileInfo["Application-FileSize"];
 +	const char* IPAddress = tFileInfo["IP-Address"];
 +	const char* IPAddressInt = tFileInfo["IP-Address-Internal"];
 +	const char* Port = tFileInfo["Port"];
 +	const char* PortX = tFileInfo["PortX"];
 +	const char* PortXInt = tFileInfo["PortX-Internal"];
 +	const char* AuthCookie = tFileInfo["AuthCookie"];
 +	const char* SessionID = tFileInfo["Session-ID"];
 +	const char* SessionProtocol = tFileInfo["Session-Protocol"];
 +	//	const char* Connectivity = tFileInfo["Connectivity"];
 +
 +	if (AppGUID != NULL) {
 +		if (!strcmp(AppGUID, "{02D3C01F-BF30-4825-A83A-DE7AF41648AA}")) {
 +			MSN_ShowPopup(info->getContactHandle(),
 +				TranslateT("Contact tried to open an audio conference (not currently supported)"), MSN_ALLOW_MSGBOX);
 +			return;
 +		}
 +	}
 +
 +	if (Invcommand && (strcmp(Invcommand, "CANCEL") == 0)) {
 +		delete info->mMsnFtp;
 +		info->mMsnFtp = NULL;
 +	}
 +
 +	if (Appname != NULL && Appfile != NULL && Appfilesize != NULL)  // receive first
 +	{
 +		filetransfer* ft = info->mMsnFtp = new filetransfer(this);
 +
 +		ft->std.hContact = MSN_HContactFromEmail(email, nick, true, true);
 +		mir_free(ft->std.tszCurrentFile);
 +		ft->std.tszCurrentFile = mir_utf8decodeT(Appfile);
 +		ft->std.totalBytes = ft->std.currentFileSize = _atoi64(Appfilesize);
 +		ft->std.totalFiles = 1;
 +		ft->szInvcookie = mir_strdup(Invcookie);
 +		ft->p2p_dest = mir_strdup(email);
 +
 +		TCHAR tComment[40];
 +		mir_sntprintf(tComment, SIZEOF(tComment), TranslateT("%I64u bytes"), ft->std.currentFileSize);
 +
 +		PROTORECVFILET pre = { 0 };
 +		pre.flags = PREF_TCHAR;
 +		pre.fileCount = 1;
 +		pre.timestamp = time(NULL);
 +		pre.tszDescription = tComment;
 +		pre.ptszFiles = &ft->std.tszCurrentFile;
 +		pre.lParam = (LPARAM)ft;
 +		ProtoChainRecvFile(ft->std.hContact, &pre);
 +		return;
 +	}
 +
 +	// receive Second
 +	if (IPAddress != NULL && Port != NULL && AuthCookie != NULL) {
 +		ThreadData* newThread = new ThreadData;
 +
 +		if (inet_addr(IPAddress) != MyConnection.extIP || !IPAddressInt)
 +			mir_snprintf(newThread->mServer, sizeof(newThread->mServer), "%s:%s", IPAddress, Port);
 +		else
 +			mir_snprintf(newThread->mServer, sizeof(newThread->mServer), "%s:%u", IPAddressInt, atol(PortXInt) ^ 0x3141);
 +
 +		newThread->mType = SERVER_FILETRANS;
 +
 +		if (info->mMsnFtp == NULL) {
 +			ThreadData* otherThread = MSN_GetOtherContactThread(info);
 +			if (otherThread) {
 +				info->mMsnFtp = otherThread->mMsnFtp;
 +				otherThread->mMsnFtp = NULL;
 +			}
 +		}
 +
 +		newThread->mMsnFtp = info->mMsnFtp; info->mMsnFtp = NULL;
 +		strcpy(newThread->mCookie, AuthCookie);
 +
 +		newThread->startThread(&CMsnProto::MSNServerThread, this);
 +		return;
 +	}
 +
 +	// send 1
 +	if (Invcommand != NULL && Invcookie != NULL && Port == NULL && AuthCookie == NULL && SessionID == NULL) { 
 +		msnftp_startFileSend(info, Invcommand, Invcookie);
 +		return;
 +	}
 +
 +	// netmeeting send 1
 +	if (Appname == NULL && SessionID != NULL && SessionProtocol != NULL) {
 +		if (!_stricmp(Invcommand, "ACCEPT")) {
 +			ShellExecuteA(NULL, "open", "conf.exe", NULL, NULL, SW_SHOW);
 +			Sleep(3000);
 +
 +			char command[1024];
 +			int  nBytes = mir_snprintf(command, sizeof(command),
 +				"MIME-Version: 1.0\r\n"
 +				"Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
 +				"Invitation-Command: ACCEPT\r\n"
 +				"Invitation-Cookie: %s\r\n"
 +				"Session-ID: {1A879604-D1B8-11D7-9066-0003FF431510}\r\n"
 +				"Launch-Application: TRUE\r\n"
 +				"IP-Address: %s\r\n\r\n",
 +				Invcookie, MyConnection.GetMyExtIPStr());
 +			info->sendPacket("MSG", "N %d\r\n%s", nBytes, command);
 +		}
 +		return;
 +	}
 +
 +	// netmeeting receive 1
 +	if (Appname != NULL && !_stricmp(Appname, "NetMeeting")) {
 +		char command[1024];
 +		int nBytes;
 +
 +		TCHAR text[512], *tszEmail = mir_a2t(email);
 +		mir_sntprintf(text, SIZEOF(text), TranslateT("Accept NetMeeting request from %s?"), tszEmail);
 +		mir_free(tszEmail);
 +
 +		if (MessageBox(NULL, text, TranslateT("MSN Protocol"), MB_YESNO | MB_ICONQUESTION) == IDYES) {
 +			nBytes = mir_snprintf(command, sizeof(command),
 +				"MIME-Version: 1.0\r\n"
 +				"Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
 +				"Invitation-Command: ACCEPT\r\n"
 +				"Invitation-Cookie: %s\r\n"
 +				"Session-ID: {A2ED5ACF-F784-4B47-A7D4-997CD8F643CC}\r\n"
 +				"Session-Protocol: SM1\r\n"
 +				"Launch-Application: TRUE\r\n"
 +				"Request-Data: IP-Address:\r\n"
 +				"IP-Address: %s\r\n\r\n",
 +				Invcookie, MyConnection.GetMyExtIPStr());
 +		}
 +		else {
 +			nBytes = mir_snprintf(command, sizeof(command),
 +				"MIME-Version: 1.0\r\n"
 +				"Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
 +				"Invitation-Command: CANCEL\r\n"
 +				"Invitation-Cookie: %s\r\n"
 +				"Cancel-Code: REJECT\r\n\r\n",
 +				Invcookie);
 +		}
 +		info->sendPacket("MSG", "N %d\r\n%s", nBytes, command);
 +		return;
 +	}
 +
 +	if (IPAddress != NULL && Port == NULL && SessionID != NULL && SessionProtocol == NULL) { // netmeeting receive 2
 +		char	ipaddr[256];
 +		mir_snprintf(ipaddr, sizeof(ipaddr), "callto://%s", IPAddress);
 +		ShellExecuteA(NULL, "open", ipaddr, NULL, NULL, SW_SHOW);
 +	}
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// Processes custom smiley messages
 +
 +void CMsnProto::MSN_CustomSmiley(const char* msgBody, char* email, char* nick, int iSmileyType)
 +{
 +	MCONTACT hContact = MSN_HContactFromEmail(email, nick, true, true);
 +
 +	char smileyList[500] = "";
 +
 +	const char *tok1 = msgBody, *tok2;
 +	char *smlp = smileyList;
 +	char lastsml[50];
 +
 +	unsigned iCount = 0;
 +	bool parseSmiley = true;
 +
 +	for (;;) {
 +		tok2 = strchr(tok1, '\t');
 +		if (tok2 == NULL) break;
 +
 +		size_t sz = tok2 - tok1;
 +		if (parseSmiley) {
 +			sz = min(sz, sizeof(lastsml)-1);
 +			memcpy(lastsml, tok1, sz);
 +			lastsml[sz] = 0;
 +
 +			memcpy(smlp, tok1, sz); smlp += sz;
 +			*(smlp++) = '\n'; *smlp = 0;
 +			++iCount;
 +		}
 +		else {
 +			filetransfer* ft = new filetransfer(this);
 +			ft->std.hContact = hContact;
 +
 +			ft->p2p_object = (char*)mir_alloc(sz + 1);
 +			memcpy(ft->p2p_object, tok1, sz);
 +			ft->p2p_object[sz] = 0;
 +
 +			size_t slen = strlen(lastsml);
 +			ptrA buf(mir_base64_encode((PBYTE)lastsml, (unsigned)slen));
 +			ptrA smileyName(mir_urlEncode(buf));
 +			int rlen = lstrlenA(buf);
 +
 +			TCHAR path[MAX_PATH];
 +			MSN_GetCustomSmileyFileName(hContact, path, SIZEOF(path), smileyName, iSmileyType);
 +			ft->std.tszCurrentFile = mir_tstrdup(path);
 +
 +			if (p2p_IsDlFileOk(ft))
 +				delete ft;
 +			else {
 +				debugLogA("Custom Smiley p2p invite for object : %s", ft->p2p_object);
 +				p2p_invite(iSmileyType, ft, email);
 +				Sleep(3000);
 +			}
 +		}
 +		parseSmiley = !parseSmiley;
 +		tok1 = tok2 + 1;
 +	}
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	MSN_ReceiveMessage - receives message or a file from the server
 +/////////////////////////////////////////////////////////////////////////////////////////
 +
 +
 +void CMsnProto::MSN_ReceiveMessage(ThreadData* info, char* cmdString, char* params)
 +{
 +	union {
 +		char* tWords[6];
 +		struct { char *fromEmail, *fromNick, *strMsgBytes; } data;
 +		struct { char *fromEmail, *fromNetId, *toEmail, *toNetId, *typeId, *strMsgBytes; } datau;
 +	};
 +
 +	if (sttDivideWords(params, SIZEOF(tWords), tWords) < 3) {
 +		debugLogA("Invalid %.3s command, ignoring", cmdString);
 +		return;
 +	}
 +
 +	int msgBytes;
 +	char *nick, *email;
 +	bool ubmMsg = strncmp(cmdString, "UBM", 3) == 0;
 +	bool sentMsg = false;
 +
 +	if (ubmMsg) {
 +		msgBytes = atol(datau.strMsgBytes);
 +		nick = datau.fromEmail;
 +		email = datau.fromEmail;
 +	}
 +	else {
 +		msgBytes = atol(data.strMsgBytes);
 +		nick = data.fromNick;
 +		email = data.fromEmail;
 +		UrlDecode(nick);
 +	}
 +	stripBBCode(nick);
 +	stripColorCode(nick);
 +
 +	char* msg = (char*)alloca(msgBytes+1);
 +
 +	HReadBuffer buf(info, 0);
 +	BYTE* msgb = buf.surelyRead(msgBytes);
 +	if (msgb == NULL) return;
 +
 +	memcpy(msg, msgb, msgBytes);
 +	msg[msgBytes] = 0;
 +
 +	debugLogA("Message:\n%s", msg);
 +
 +	MimeHeaders tHeader;
 +	char* msgBody = tHeader.readFromBuffer(msg);
 +
 +	const char* tMsgId = tHeader["Message-ID"];
 +
 +	// Chunked message
 +	char* newbody = NULL;
 +	if (tMsgId) {
 +		int idx;
 +		const char* tChunks = tHeader["Chunks"];
 +		if (tChunks)
 +			idx = addCachedMsg(tMsgId, msg, 0, msgBytes, atol(tChunks), true);
 +		else
 +			idx = addCachedMsg(tMsgId, msgBody, 0, strlen(msgBody), 0, true);
 +
 +		size_t newsize;
 +		if (!getCachedMsg(idx, newbody, newsize)) return;
 +		msgBody = tHeader.readFromBuffer(newbody);
 +	}
 +
 +	// message from the server (probably)
 +	if (!ubmMsg && strchr(email, '@') == NULL && _stricmp(email, "Hotmail"))
 +		return;
 +
 +	const char* tContentType = tHeader["Content-Type"];
 +	if (tContentType == NULL)
 +		return;
 +
 +	if (!_strnicmp(tContentType, "text/x-clientcaps", 17)) {
 +		MimeHeaders tFileInfo;
 +		tFileInfo.readFromBuffer(msgBody);
 +		info->firstMsgRecv = true;
 +
 +		MCONTACT hContact = MSN_HContactFromEmail(email);
 +		const char* mirver = tFileInfo["Client-Name"];
 +		if (hContact != NULL && mirver != NULL) {
 +			setString(hContact, "MirVer", mirver);
 +			delSetting(hContact, "StdMirVer");
 +		}
 +	}
 +	else if (!ubmMsg && !info->firstMsgRecv) {
 +		info->firstMsgRecv = true;
 +		MsnContact *cont = Lists_Get(email);
 +		if (cont && cont->hContact != NULL)
 +			MSN_SetMirVer(cont->hContact, cont->cap1, true);
 +	}
 +
 +	if (!_strnicmp(tContentType, "text/plain", 10)) {
 +		MCONTACT hContact = MSN_HContactFromEmail(email, nick, true, true);
 +
 +		const char* p = tHeader["X-MMS-IM-Format"];
 +		bool isRtl = p != NULL && strstr(p, "RL=1") != NULL;
 +
 +		if (info->mJoinedContactsWLID.getCount() > 1)
 +			MSN_ChatStart(info);
 +		else {
 +			char *szEmail;
 +			parseWLID(NEWSTR_ALLOCA(email), NULL, &szEmail, NULL);
 +			sentMsg = _stricmp(szEmail, MyOptions.szEmail) == 0;
 +			if (sentMsg)
 +				hContact = ubmMsg ? MSN_HContactFromEmail(datau.toEmail, nick) : info->getContactHandle();
 +		}
 +
 +		const char* tP4Context = tHeader["P4-Context"];
 +		if (tP4Context) {
 +			size_t newlen = strlen(msgBody) + strlen(tP4Context) + 4;
 +			char* newMsgBody = (char*)mir_alloc(newlen);
 +			mir_snprintf(newMsgBody, newlen, "[%s] %s", tP4Context, msgBody);
 +			mir_free(newbody);
 +			msgBody = newbody = newMsgBody;
 +		}
 +
 +		if (info->mChatID[0]) {
 +			GCDEST gcd = { m_szModuleName, info->mChatID, GC_EVENT_MESSAGE };
 +			GCEVENT gce = { sizeof(gce), &gcd };
 +			gce.dwFlags = GCEF_ADDTOLOG;
 +			gce.ptszUID = mir_a2t(email);
 +			gce.ptszNick = GetContactNameT(hContact);
 +			gce.time = time(NULL);
 +			gce.bIsMe = FALSE;
 +
 +			TCHAR* p = mir_utf8decodeT(msgBody);
 +			gce.ptszText = EscapeChatTags(p);
 +			mir_free(p);
 +
 +			CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
 +			mir_free((void*)gce.ptszText);
 +			mir_free((void*)gce.ptszUID);
 +		}
 +		else if (hContact) {
 +			if (!sentMsg) {
 +				CallService(MS_PROTO_CONTACTISTYPING, WPARAM(hContact), 0);
 +
 +				PROTORECVEVENT pre = { 0 };
 +				pre.szMessage = (char*)msgBody;
 +				pre.flags = PREF_UTF + (isRtl ? PREF_RTL : 0);
 +				pre.timestamp = (DWORD)time(NULL);
 +				pre.lParam = 0;
 +				ProtoChainRecvMsg(hContact, &pre);
 +			}
 +			else {
 +				bool haveWnd = MSN_MsgWndExist(hContact);
 +
 +				DBEVENTINFO dbei = { 0 };
 +				dbei.cbSize = sizeof(dbei);
 +				dbei.eventType = EVENTTYPE_MESSAGE;
 +				dbei.flags = DBEF_SENT | DBEF_UTF | (haveWnd ? 0 : DBEF_READ) | (isRtl ? DBEF_RTL : 0);
 +				dbei.szModule = m_szModuleName;
 +				dbei.timestamp = time(NULL);
 +				dbei.cbBlob = (unsigned)strlen(msgBody) + 1;
 +				dbei.pBlob = (PBYTE)msgBody;
 +				db_event_add(hContact, &dbei);
 +			}
 +		}
 +	}
 +	else if (!_strnicmp(tContentType, "text/x-msmsgsprofile", 20)) {
 +		replaceStr(msnExternalIP, tHeader["ClientIP"]);
 +		abchMigrated = atol(tHeader["ABCHMigrated"]);
 +		langpref = atol(tHeader["lang_preference"]);
 +		emailEnabled = atol(tHeader["EmailEnabled"]);
 +
 +		if (!MSN_RefreshContactList()) {
 +			ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NOSERVER);
 +			info->sendTerminate();
 +		}
 +		else {
 +			MSN_SetServerStatus(m_iDesiredStatus);
 +			MSN_EnableMenuItems(true);
 +		}
 +	}
 +	else if (!_strnicmp(tContentType, "text/x-msmsgscontrol", 20)) {
 +		const char* tTypingUser = tHeader["TypingUser"];
 +
 +		if (tTypingUser != NULL && info->mChatID[0] == 0 && _stricmp(email, MyOptions.szEmail)) {
 +			MCONTACT hContact = MSN_HContactFromEmail(tTypingUser, tTypingUser);
 +			CallService(MS_PROTO_CONTACTISTYPING, hContact, 7);
 +		}
 +	}
 +	else if (!_strnicmp(tContentType, "text/x-msnmsgr-datacast", 23)) {
 +		if (info->mJoinedContactsWLID.getCount()) {
 +			MCONTACT tContact;
 +
 +			if (info->mChatID[0]) {
 +				GC_INFO gci = { 0 };
 +				gci.Flags = GCF_HCONTACT;
 +				gci.pszModule = m_szModuleName;
 +				gci.pszID = info->mChatID;
 +				CallServiceSync(MS_GC_GETINFO, 0, (LPARAM)&gci);
 +				tContact = gci.hContact;
 +			}
 +			else tContact = info->getContactHandle();
 +
 +			MimeHeaders tFileInfo;
 +			tFileInfo.readFromBuffer(msgBody);
 +
 +			const char* id = tFileInfo["ID"];
 +			if (id != NULL) {
 +				switch (atol(id)) {
 +				case 1:  // Nudge
 +					NotifyEventHooks(hMSNNudge, (WPARAM)tContact, 0);
 +					break;
 +
 +				case 2: // Wink
 +					break;
 +
 +				case 4: // Action Message
 +					break;
 +				}
 +			}
 +		}
 +	}
 +	else if (!_strnicmp(tContentType, "text/x-msmsgsemailnotification", 30))
 +		sttNotificationMessage(msgBody, false);
 +	else if (!_strnicmp(tContentType, "text/x-msmsgsinitialemailnotification", 37))
 +		sttNotificationMessage(msgBody, true);
 +	else if (!_strnicmp(tContentType, "text/x-msmsgsactivemailnotification", 35))
 +		sttNotificationMessage(msgBody, false);
 +	else if (!_strnicmp(tContentType, "text/x-msmsgsinitialmdatanotification", 37))
 +		sttNotificationMessage(msgBody, true);
 +	else if (!_strnicmp(tContentType, "text/x-msmsgsoimnotification", 28))
 +		sttNotificationMessage(msgBody, false);
 +	else if (!_strnicmp(tContentType, "text/x-msmsgsinvite", 19))
 +		MSN_InviteMessage(info, msgBody, email, nick);
 +	else if (!_strnicmp(tContentType, "application/x-msnmsgrp2p", 24)) {
 +		const char* dest = tHeader["P2P-Dest"];
 +		if (dest) {
 +			char *szEmail, *szInst;
 +			parseWLID(NEWSTR_ALLOCA(dest), NULL, &szEmail, &szInst);
 +
 +			if (stricmp(szEmail, MyOptions.szEmail) == 0) {
 +				const char* src = tHeader["P2P-Src"];
 +				if (src == NULL) src = email;
 +
 +				if (szInst == NULL)
 +					p2p_processMsg(info, msgBody, src);
 +				else if (stricmp(szInst, MyOptions.szMachineGuidP2P) == 0)
 +					p2p_processMsgV2(info, msgBody, src);
 +			}
 +		}
 +	}
 +	else if (!_strnicmp(tContentType, "text/x-mms-emoticon", 19))
 +		MSN_CustomSmiley(msgBody, email, nick, MSN_APPID_CUSTOMSMILEY);
 +	else if (!_strnicmp(tContentType, "text/x-mms-animemoticon", 23))
 +		MSN_CustomSmiley(msgBody, email, nick, MSN_APPID_CUSTOMANIMATEDSMILEY);
 +
 +	mir_free(newbody);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// Process Yahoo Find
 +
 +void CMsnProto::MSN_ProcessYFind(char* buf, size_t len)
 +{
 +	if (buf == NULL) return;
 +	ezxml_t xmli = ezxml_parse_str(buf, len);
 +
 +	ezxml_t dom = ezxml_child(xmli, "d");
 +	const char* szDom = ezxml_attr(dom, "n");
 +
 +	ezxml_t cont = ezxml_child(dom, "c");
 +	const char* szCont = ezxml_attr(cont, "n");
 +
 +	char szEmail[128];
 +	mir_snprintf(szEmail, sizeof(szEmail), "%s@%s", szCont, szDom);
 +
 +	const char *szNetId = ezxml_attr(cont, "t");
 +	if (msnSearchId != NULL) {
 +		if (szNetId != NULL) {
 +			TCHAR* szEmailT = mir_utf8decodeT(szEmail);
 +			PROTOSEARCHRESULT isr = { 0 };
 +			isr.cbSize = sizeof(isr);
 +			isr.flags = PSR_TCHAR;
 +			isr.id = szEmailT;
 +			isr.nick = szEmailT;
 +			isr.email = szEmailT;
 +
 +			ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, msnSearchId, (LPARAM)&isr);
 +			mir_free(szEmailT);
 +		}
 +		ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, msnSearchId, 0);
 +
 +		msnSearchId = NULL;
 +	}
 +	else {
 +		if (szNetId != NULL) {
 +			int netId = atol(szNetId);
 +			MCONTACT hContact = MSN_HContactFromEmail(szEmail, szEmail, true, false);
 +			if (MSN_AddUser(hContact, szEmail, netId, LIST_FL)) {
 +				MSN_AddUser(hContact, szEmail, netId, LIST_PL + LIST_REMOVE);
 +				MSN_AddUser(hContact, szEmail, netId, LIST_BL + LIST_REMOVE);
 +				MSN_AddUser(hContact, szEmail, netId, LIST_AL);
 +				db_unset(hContact, "CList", "Hidden");
 +			}
 +			MSN_SetContactDb(hContact, szEmail);
 +		}
 +	}
 +
 +	ezxml_free(xmli);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// Process user addition
 +
 +void CMsnProto::MSN_ProcessAdd(char* buf, size_t len)
 +{
 +	if (buf == NULL) return;
 +
 +	ezxml_t xmli = ezxml_parse_str(buf, len);
 +	ezxml_t dom  = ezxml_child(xmli, "d");
 +	while (dom != NULL) {
 +		const char* szDom = ezxml_attr(dom, "n");
 +		ezxml_t cont = ezxml_child(dom, "c");
 +		while (cont != NULL) {
 +			const char* szCont = ezxml_attr(cont, "n");
 +			const char* szNick = ezxml_attr(cont, "f");
 +			int listId = atol(ezxml_attr(cont, "l"));
 +			int netId = atol(ezxml_attr(cont, "t"));
 +
 +			char szEmail[128];
 +			mir_snprintf(szEmail, sizeof(szEmail), "%s@%s", szCont, szDom);
 +
 +			UrlDecode((char*)szNick);
 +
 +			if (listId == LIST_FL) {
 +				MCONTACT hContact = MSN_HContactFromEmail(szEmail, szNick, true, false);
 +				MSN_SetContactDb(hContact, szEmail);
 +			}
 +
 +			if (listId == LIST_RL)
 +				MSN_SharingFindMembership(true);
 +			else
 +				MSN_AddUser(NULL, szEmail, netId, listId);
 +
 +			MsnContact* msc = Lists_Get(szEmail);
 +			if (msc == NULL) {
 +				Lists_Add(listId, netId, szEmail);
 +				msc = Lists_Get(szEmail);
 +			}
 +
 +			if (listId == LIST_RL) {
 +				if ((msc->list & (LIST_AL | LIST_BL)) == 0) {
 +					MSN_AddAuthRequest(szEmail, szNick, msc->invite);
 +					msc->netId = netId;
 +				}
 +				else MSN_AddUser(NULL, szEmail, netId, LIST_PL + LIST_REMOVE);
 +			}
 +
 +			cont = ezxml_next(cont);
 +		}
 +		dom = ezxml_next(dom);
 +	}
 +	ezxml_free(xmli);
 +}
 +
 +void CMsnProto::MSN_ProcessRemove(char* buf, size_t len)
 +{
 +	ezxml_t xmli = ezxml_parse_str(buf, len);
 +	ezxml_t dom  = ezxml_child(xmli, "d");
 +	while (dom != NULL) {
 +		const char* szDom = ezxml_attr(dom, "n");
 +		ezxml_t cont = ezxml_child(dom, "c");
 +		while (cont != NULL) {
 +			const char* szCont = ezxml_attr(cont, "n");
 +			int listId = atol(ezxml_attr(cont, "l"));
 +
 +			char szEmail[128];
 +			mir_snprintf(szEmail, sizeof(szEmail), "%s@%s", szCont, szDom);
 +			Lists_Remove(listId, szEmail);
 +
 +			MsnContact* msc = Lists_Get(szEmail);
 +			if (msc == NULL || (msc->list & (LIST_RL | LIST_FL | LIST_LL)) == 0) {
 +				if (msc->hContact && _stricmp(szEmail, MyOptions.szEmail)) {
 +					CallService(MS_DB_CONTACT_DELETE, (WPARAM)msc->hContact, 0);
 +					msc->hContact = NULL;
 +				}
 +			}
 +
 +			cont = ezxml_next(cont);
 +		}
 +		dom = ezxml_next(dom);
 +	}
 +	ezxml_free(xmli);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	MSN_HandleCommands - process commands from the server
 +/////////////////////////////////////////////////////////////////////////////////////////
 +
 +void CMsnProto::MSN_ProcessStatusMessage(char* buf, unsigned len, const char* wlid)
 +{
 +	MCONTACT hContact = MSN_HContactFromEmail(wlid);
 +	if (hContact == NULL) return;
 +
 +	ezxml_t xmli = ezxml_parse_str(buf, len);
 +
 +	char* szEmail;
 +	parseWLID(NEWSTR_ALLOCA(wlid), NULL, &szEmail, NULL);
 +
 +	// Add endpoints
 +	for (ezxml_t endp = ezxml_child(xmli, "EndpointData"); endp; endp = ezxml_next(endp)) {
 +		const char *id = ezxml_attr(endp, "id");
 +		const char *caps = ezxml_txt(ezxml_child(endp, "Capabilities"));
 +		char* end = NULL;
 +		unsigned cap1 = caps ? strtoul(caps, &end, 10) : 0;
 +		unsigned cap2 = end && *end == ':' ? strtoul(end + 1, NULL, 10) : 0;
 +
 +		Lists_AddPlace(szEmail, id, cap1, cap2);
 +	}
 +
 +	// Process status message info
 +	const char* szStatMsg = ezxml_txt(ezxml_child(xmli, "PSM"));
 +	if (*szStatMsg) {
 +		stripBBCode((char*)szStatMsg);
 +		stripColorCode((char*)szStatMsg);
 +		db_set_utf(hContact, "CList", "StatusMsg", szStatMsg);
 +	}
 +	else db_unset(hContact, "CList", "StatusMsg");
 +
 +	{
 +		ptrT tszStatus(mir_utf8decodeT(szStatMsg));
 +		ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, NULL, tszStatus);
 +	}
 +
 +	// Process current media info
 +	const char* szCrntMda = ezxml_txt(ezxml_child(xmli, "CurrentMedia"));
 +	if (!*szCrntMda) {
 +		delSetting(hContact, "ListeningTo");
 +		ezxml_free(xmli);
 +		return;
 +	}
 +
 +	// Get parts separeted by "\\0"
 +	char *parts[16];
 +	unsigned pCount;
 +
 +	char* p = (char*)szCrntMda;
 +	for (pCount = 0; pCount < SIZEOF(parts); ++pCount) {
 +		parts[pCount] = p;
 +
 +		char* p1 = strstr(p, "\\0");
 +		if (p1 == NULL) break;
 +
 +		*p1 = '\0';
 +		p = p1 + 2;
 +	}
 +
 +	// Now let's mount the final string
 +	if (pCount <= 4) {
 +		delSetting(hContact, "ListeningTo");
 +		ezxml_free(xmli);
 +		return;
 +	}
 +
 +	// Check if there is any info in the string
 +	bool foundUsefullInfo = false;
 +	for (unsigned i = 4; i < pCount; i++) {
 +		if (parts[i][0] != '\0') {
 +			foundUsefullInfo = true;
 +			break;
 +		}
 +	}
 +	if (!foundUsefullInfo) {
 +		delSetting(hContact, "ListeningTo");
 +		ezxml_free(xmli);
 +		return;
 +	}
 +
 +	if (!ServiceExists(MS_LISTENINGTO_GETPARSEDTEXT) ||
 +		!ServiceExists(MS_LISTENINGTO_OVERRIDECONTACTOPTION) ||
 +		!CallService(MS_LISTENINGTO_OVERRIDECONTACTOPTION, 0, hContact))
 +	{
 +		// User contact options
 +		char *format = mir_strdup(parts[3]);
 +		char *unknown = NULL;
 +		if (ServiceExists(MS_LISTENINGTO_GETUNKNOWNTEXT))
 +			unknown = mir_utf8encodeT((TCHAR *)CallService(MS_LISTENINGTO_GETUNKNOWNTEXT, 0, 0));
 +
 +		for (unsigned i = 4; i < pCount; i++) {
 +			char part[16];
 +			size_t lenPart = mir_snprintf(part, sizeof(part), "{%d}", i - 4);
 +			if (parts[i][0] == '\0' && unknown != NULL)
 +				parts[i] = unknown;
 +			size_t lenPartsI = strlen(parts[i]);
 +			for (p = strstr(format, part); p; p = strstr(p + lenPartsI, part)) {
 +				if (lenPart < lenPartsI) {
 +					int loc = p - format;
 +					format = (char *)mir_realloc(format, strlen(format) + (lenPartsI - lenPart) + 1);
 +					p = format + loc;
 +				}
 +				memmove(p + lenPartsI, p + lenPart, strlen(p + lenPart) + 1);
 +				memmove(p, parts[i], lenPartsI);
 +			}
 +		}
 +
 +		setStringUtf(hContact, "ListeningTo", format);
 +		mir_free(unknown);
 +		mir_free(format);
 +	}
 +	else {
 +		// Use user options
 +		LISTENINGTOINFO lti = { 0 };
 +		lti.cbSize = sizeof(LISTENINGTOINFO);
 +
 +		lti.ptszTitle = mir_utf8decodeT(parts[4]);
 +		if (pCount > 5)  lti.ptszArtist = mir_utf8decodeT(parts[5]);
 +		if (pCount > 6)  lti.ptszAlbum = mir_utf8decodeT(parts[6]);
 +		if (pCount > 7)  lti.ptszTrack = mir_utf8decodeT(parts[7]);
 +		if (pCount > 8)  lti.ptszYear = mir_utf8decodeT(parts[8]);
 +		if (pCount > 9)  lti.ptszGenre = mir_utf8decodeT(parts[9]);
 +		if (pCount > 10) lti.ptszLength = mir_utf8decodeT(parts[10]);
 +		if (pCount > 11) lti.ptszPlayer = mir_utf8decodeT(parts[11]);
 +		else lti.ptszPlayer = mir_utf8decodeT(parts[0]);
 +		if (pCount > 12) lti.ptszType = mir_utf8decodeT(parts[12]);
 +		else lti.ptszType = mir_utf8decodeT(parts[1]);
 +
 +		TCHAR *cm = (TCHAR *)CallService(MS_LISTENINGTO_GETPARSEDTEXT, (WPARAM)_T("%title% - %artist%"), (LPARAM)<i);
 +		setTString(hContact, "ListeningTo", cm);
 +
 +		mir_free(cm);
 +
 +		mir_free(lti.ptszArtist);
 +		mir_free(lti.ptszAlbum);
 +		mir_free(lti.ptszTitle);
 +		mir_free(lti.ptszTrack);
 +		mir_free(lti.ptszYear);
 +		mir_free(lti.ptszGenre);
 +		mir_free(lti.ptszLength);
 +		mir_free(lti.ptszPlayer);
 +		mir_free(lti.ptszType);
 +	}
 +	ezxml_free(xmli);
 +}
 +
 +void CMsnProto::MSN_ProcessPage(char* buf, unsigned len)
 +{
 +	if (buf == NULL) return;
 +	ezxml_t xmlnot = ezxml_parse_str(buf, len);
 +
 +	ezxml_t xmlbdy = ezxml_get(xmlnot, "MSG", 0, "BODY", -1);
 +	const char* szMsg = ezxml_txt(ezxml_child(xmlbdy, "TEXT"));
 +	const char* szTel = ezxml_attr(ezxml_child(xmlnot, "FROM"), "name");
 +
 +	if (szTel && *szMsg) {
 +		PROTORECVEVENT pre = { 0 };
 +		pre.szMessage = (char*)szMsg;
 +		pre.flags = PREF_UTF /*+ ((isRtl) ? PREF_RTL : 0)*/;
 +		pre.timestamp = time(NULL);
 +		ProtoChainRecvMsg(MSN_HContactFromEmail(szTel, szTel, true, true), &pre);
 +	}
 +	ezxml_free(xmlnot);
 +}
 +
 +void CMsnProto::MSN_ProcessNotificationMessage(char* buf, unsigned len)
 +{
 +	if (buf == NULL) return;
 +	ezxml_t xmlnot = ezxml_parse_str(buf, len);
 +
 +	if (strcmp(ezxml_attr(xmlnot, "siteid"), "0") == 0) {
 +		ezxml_free(xmlnot);
 +		return;
 +	}
 +
 +	ezxml_t xmlmsg = ezxml_child(xmlnot, "MSG");
 +	ezxml_t xmlact = ezxml_child(xmlmsg, "ACTION");
 +	ezxml_t xmlbdy = ezxml_child(xmlmsg, "BODY");
 +	ezxml_t xmltxt = ezxml_child(xmlbdy, "TEXT");
 +
 +	if (xmltxt != NULL) {
 +		char fullurl[1024];
 +		size_t sz = 0;
 +
 +		const char* acturl = ezxml_attr(xmlact, "url");
 +		if (acturl == NULL || strstr(acturl, "://") == NULL)
 +			sz += mir_snprintf(fullurl + sz, sizeof(fullurl)-sz, "%s", ezxml_attr(xmlnot, "siteurl"));
 +
 +		sz += mir_snprintf(fullurl + sz, sizeof(fullurl)-sz, "%s", acturl);
 +		if (sz != 0 && fullurl[sz - 1] != '?')
 +			sz += mir_snprintf(fullurl + sz, sizeof(fullurl)-sz, "?");
 +
 +		mir_snprintf(fullurl + sz, sizeof(fullurl)-sz, "notification_id=%s&message_id=%s",
 +			ezxml_attr(xmlnot, "id"), ezxml_attr(xmlmsg, "id"));
 +
 +		SkinPlaySound(alertsoundname);
 +
 +		TCHAR* alrt = mir_utf8decodeT(ezxml_txt(xmltxt));
 +		MSN_ShowPopup(TranslateT("MSN Alert"), alrt, MSN_ALERT_POPUP | MSN_ALLOW_MSGBOX, fullurl);
 +		mir_free(alrt);
 +	}
 +	else if (xmlbdy) {
 +		const char *txt = ezxml_txt(xmlbdy);
 +		if (strstr(txt, "ABCHInternal")) {
 +			MSN_SharingFindMembership(true);
 +			MSN_ABFind("ABFindContactsPaged", NULL, true);
 +			MSN_StoreGetProfile();
 +		}
 +	}
 +	ezxml_free(xmlnot);
 +}
 +
 +void CMsnProto::MSN_InitSB(ThreadData* info, const char* szEmail)
 +{
 +	MsnContact *cont = Lists_Get(szEmail);
 +
 +	if (cont->netId == NETID_MSN)
 +		info->sendCaps();
 +
 +	bool typing = false;
 +
 +	for (int i = 3; --i;) {
 +		MsgQueueEntry E;
 +		while (MsgQueue_GetNext(szEmail, E)) {
 +			if (E.msgType == 'X') ;
 +			else if (E.msgType == 2571)
 +				typing = E.flags != 0;
 +			else if (E.msgSize == 0) {
 +				info->sendMessage(E.msgType, NULL, 1, E.message, E.flags);
 +				ProtoBroadcastAck(cont->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)E.seq, 0);
 +			}
 +			else {
 +				if (E.msgType == 'D' && !info->mBridgeInit /*&& strchr(data.flags, ':')*/) {
 +					info->mBridgeInit = true;
 +
 +//					P2PV2_Header hdrdata(E.message);
 +//					P2PV2_Header tHdr;
 +//					tHdr.mID = hdrdata.mID;
 +//					p2p_sendMsg(info, E.wlid, 0, tHdr, NULL, 0);
 +				}
 +				info->sendRawMessage(E.msgType, E.message, E.msgSize);
 +			}
 +
 +			mir_free(E.message);
 +			mir_free(E.wlid);
 +
 +			if (E.ft != NULL)
 +				info->mMsnFtp = E.ft;
 +		}
 +		mir_free(info->mInitialContactWLID); info->mInitialContactWLID = NULL;
 +	}
 +
 +	if (typing)
 +		MSN_StartStopTyping(info, true);
 +
 +	if (getByte("EnableDeliveryPopup", 0))
 +		MSN_ShowPopup(cont->hContact, info->mCaller ?
 +			TranslateT("Chat session established by my request") :
 +			TranslateT("Chat session established by contact request"), 0);
 +
 +	PROTO_AVATAR_INFORMATIONT ai = { sizeof(ai), cont->hContact };
 +	GetAvatarInfo(GAIF_FORCE, (LPARAM)&ai);
 +}
 +
 +int CMsnProto::MSN_HandleCommands(ThreadData* info, char* cmdString)
 +{
 +	char* params = "";
 +	int trid = -1;
 +
 +	if (cmdString[3]) {
 +		if (isdigit((BYTE)cmdString[4])) {
 +			trid = strtol(cmdString + 4, ¶ms, 10);
 +			switch (*params) {
 +			case ' ':	case '\0':	case '\t':	case '\n':
 +				while (*params == ' ' || *params == '\t')
 +					params++;
 +				break;
 +
 +			default:
 +				params = cmdString + 4;
 +			}
 +		}
 +		else params = cmdString + 4;
 +	}
 +
 +	switch((*(PDWORD)cmdString & 0x00FFFFFF) | 0x20000000) {
 +	case ' KCA':    //********* ACK: section 8.7 Instant Messages
 +		ReleaseSemaphore(info->hWaitEvent, 1, NULL);
 +
 +		if (info->mJoinedContactsWLID.getCount() > 0 && MyOptions.SlowSend)
 +			ProtoBroadcastAck(info->getContactHandle(), ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)trid, 0);
 +		break;
 +
 +	case ' YQF':	//********* FQY: Find Yahoo User
 +		char* tWords[1];
 +		if (sttDivideWords(params, 1, tWords) != 1)
 +			debugLogA("Invalid %.3s command, ignoring", cmdString);
 +		else {
 +			size_t len = atol(tWords[0]);
 +			MSN_ProcessYFind((char*)HReadBuffer(info, 0).surelyRead(len), len);
 +		}
 +		break;
 +
 +	case ' LDA':	//********* ADL: Add to the list
 +		{
 +			char* tWords[1];
 +			if (sttDivideWords(params, 1, tWords) != 1) {
 +LBL_InvalidCommand:
 +				debugLogA("Invalid %.3s command, ignoring", cmdString);
 +				break;
 +			}
 +
 +			if (strcmp(tWords[0], "OK") != 0) {
 +				size_t len = atol(tWords[0]);
 +				MSN_ProcessAdd((char*)HReadBuffer(info, 0).surelyRead(len), len);
 +			}
 +		}
 +		break;
 +
 +	case ' SBS':
 +		break;
 +
 +	case ' SNA':    //********* ANS: section 8.4 Getting Invited to a Switchboard Session
 +		break;
 +
 +	case ' PRP':
 +		break;
 +
 +	case ' PLB':    //********* BLP: section 7.6 List Retrieval And Property Management
 +		break;
 +
 +	case ' EYB':   //********* BYE: section 8.5 Session Participant Changes
 +		{
 +			union {
 +				char* tWords[2];
 +				// modified for chat, orginally param2 = junk
 +				// param 2: quit due to idle = "1", normal quit = nothing
 +				struct { char *userEmail, *isIdle; } data;
 +			};
 +
 +			sttDivideWords(params, 2, tWords);
 +			UrlDecode(data.userEmail);
 +
 +			if (strchr(data.userEmail, ';')) {
 +				if (info->mJoinedContactsWLID.getCount() == 1)
 +					p2p_clearThreadSessions((MCONTACT)info->mJoinedContactsWLID[0], info->mType);
 +				info->contactLeft(data.userEmail);
 +				break;
 +			}
 +
 +			MCONTACT hContact = MSN_HContactFromEmail(data.userEmail);
 +
 +			if (getByte("EnableSessionPopup", 0))
 +				MSN_ShowPopup(hContact, TranslateT("Contact left channel"), 0);
 +
 +			// modified for chat
 +			{
 +				GCDEST gcd = { m_szModuleName, info->mChatID, GC_EVENT_QUIT };
 +				GCEVENT gce = { sizeof(gce), &gcd };
 +				gce.dwFlags = GCEF_ADDTOLOG;
 +				gce.ptszNick = GetContactNameT(hContact);
 +				gce.ptszUID = mir_a2t(data.userEmail);
 +				gce.time = time(NULL);
 +				gce.bIsMe = FALSE;
 +				CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
 +				mir_free((void*)gce.ptszUID);
 +			}
 +
 +			int personleft = info->contactLeft(data.userEmail);
 +
 +			int temp_status = getWord(hContact, "Status", ID_STATUS_OFFLINE);
 +			if (temp_status == ID_STATUS_INVISIBLE && MSN_GetThreadByContact(data.userEmail) == NULL)
 +				setWord(hContact, "Status", ID_STATUS_OFFLINE);
 +
 +			// see if the session is quit due to idleness
 +			if (info->mChatID[0] && personleft == 1) {
 +				if (!strcmp(data.isIdle, "1")) {
 +					GCDEST gcd = { m_szModuleName, info->mChatID, GC_EVENT_INFORMATION };
 +					GCEVENT gce = { sizeof(gce), &gcd };
 +					gce.dwFlags = GCEF_ADDTOLOG;
 +					gce.bIsMe = FALSE;
 +					gce.time = time(NULL);
 +					gce.ptszText = TranslateT("This conversation has been inactive, participants will be removed.");
 +					CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
 +					gce.ptszText = TranslateT("To resume the conversation, please quit this session and start a new chat session.");
 +					CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
 +				}
 +				else {
 +					if (!Miranda_Terminated() && MessageBox(NULL,
 +						TranslateT("There is only 1 person left in the chat, do you want to switch back to standard message window?"),
 +						TranslateT("MSN Chat"), MB_YESNO | MB_ICONQUESTION) == IDYES) {
 +						// kill chat dlg and open srmm dialog
 +						MSN_KillChatSession(info->mChatID);
 +
 +						// open up srmm dialog when quit while 1 person left
 +						MCONTACT hContact = info->getContactHandle();
 +						if (hContact) CallServiceSync(MS_MSG_SENDMESSAGE, hContact, 0);
 +					}
 +				}
 +			}
 +			// this is not in chat session, quit the session when everyone left
 +			else if (info->mJoinedContactsWLID.getCount() < 1)
 +				return 1;
 +
 +		}
 +		break;
 +
 +	case ' LAC':    //********* CAL: section 8.3 Inviting Users to a Switchboard Session
 +		break;
 +
 +	case ' GHC':    //********* CHG: section 7.7 Client States
 +		{
 +			int oldStatus = m_iStatus;
 +			int newStatus = MSNStatusToMiranda(params);
 +			if (oldStatus <= ID_STATUS_OFFLINE) {
 +				isConnectSuccess = true;
 +				int count = -1;
 +				for (;;) {
 +					MsnContact *msc = Lists_GetNext(count);
 +					if (msc == NULL) break;
 +
 +					if (msc->netId == NETID_MOB)
 +						setWord(msc->hContact, "Status", ID_STATUS_ONTHEPHONE);
 +				}
 +			}
 +			if (newStatus != ID_STATUS_IDLE) {
 +				m_iStatus = newStatus;
 +				ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, newStatus);
 +				debugLogA("Status change acknowledged: %s", params);
 +				MSN_RemoveEmptyGroups();
 +			}
 +			if (newStatus == ID_STATUS_OFFLINE) return 1;
 +		}
 +		break;
 +	case ' LHC':    //********* CHL: Query from Server on MSNP7
 +		{
 +			char* authChallengeInfo;
 +			if (sttDivideWords(params, 1, &authChallengeInfo) != 1)
 +				goto LBL_InvalidCommand;
 +
 +			char dgst[64];
 +			MSN_MakeDigest(authChallengeInfo, dgst);
 +			info->sendPacket("QRY", "%s 32\r\n%s", msnProductID, dgst);
 +		}
 +		break;
 +	case ' RVC':    //********* CVR: MSNP8
 +		break;
 +
 +	case ' NLF':    //********* FLN: section 7.9 Notification Messages
 +		{
 +			union {
 +				char* tWords[2];
 +				struct { char *userEmail, *netId; } data;
 +			};
 +
 +			int tArgs = sttDivideWords(params, 2, tWords);
 +			if (tArgs < 2)
 +				goto LBL_InvalidCommand;
 +
 +			MCONTACT hContact = MSN_HContactFromEmail(data.userEmail);
 +			if (hContact != NULL) {
 +				setWord(hContact, "Status", MSN_GetThreadByContact(data.userEmail) ? ID_STATUS_INVISIBLE : ID_STATUS_OFFLINE);
 +				setDword(hContact, "IdleTS", 0);
 +				ForkThread(&CMsnProto::MsgQueue_AllClearThread, mir_strdup(data.userEmail));
 +			}
 +		}
 +		break;
 +	case ' NLI':
 +	case ' NLN':    //********* ILN/NLN: section 7.9 Notification Messages
 +		{
 +			union {
 +				char* tWords[5];
 +				struct { char *userStatus, *wlid, *userNick, *objid, *cmdstring; } data;
 +			};
 +
 +			int tArgs = sttDivideWords(params, 5, tWords);
 +			if (tArgs < 3)
 +				goto LBL_InvalidCommand;
 +
 +			UrlDecode(data.userNick);
 +			stripBBCode(data.userNick);
 +			stripColorCode(data.userNick);
 +
 +			bool isMe = false;
 +			char* szEmail, *szNet;
 +			parseWLID(NEWSTR_ALLOCA(data.wlid), &szNet, &szEmail, NULL);
 +			if (!stricmp(szEmail, MyOptions.szEmail) && !strcmp(szNet, "1")) {
 +				isMe = true;
 +				int newStatus = MSNStatusToMiranda(params);
 +				if (newStatus != m_iStatus && newStatus != ID_STATUS_IDLE) {
 +					int oldMode = m_iStatus;
 +					m_iDesiredStatus = m_iStatus = newStatus;
 +					ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldMode, m_iStatus);
 +				}
 +			}
 +
 +			WORD lastStatus = ID_STATUS_OFFLINE;
 +
 +			MsnContact *cont = Lists_Get(szEmail);
 +
 +			MCONTACT hContact = NULL;
 +			if (!cont && !isMe) {
 +				hContact = MSN_HContactFromEmail(data.wlid, data.userNick, true, true);
 +				cont = Lists_Get(szEmail);
 +			}
 +			if (cont) hContact = cont->hContact;
 +
 +			if (hContact != NULL) {
 +				setStringUtf(hContact, "Nick", data.userNick);
 +				lastStatus = getWord(hContact, "Status", ID_STATUS_OFFLINE);
 +				if (lastStatus == ID_STATUS_OFFLINE || lastStatus == ID_STATUS_INVISIBLE)
 +					db_unset(hContact, "CList", "StatusMsg");
 +
 +				int newStatus = MSNStatusToMiranda(params);
 +				setWord(hContact, "Status", newStatus != ID_STATUS_IDLE ? newStatus : ID_STATUS_AWAY);
 +				setDword(hContact, "IdleTS", newStatus != ID_STATUS_IDLE ? 0 : time(NULL));
 +			}
 +
 +			if (tArgs > 3 && tArgs <= 5 && cont) {
 +				UrlDecode(data.cmdstring);
 +
 +				char* end = NULL;
 +				cont->cap1 = strtoul(data.objid, &end, 10);
 +				cont->cap2 = end && *end == ':' ? strtoul(end + 1, NULL, 10) : 0;
 +
 +				if (lastStatus == ID_STATUS_OFFLINE) {
 +					DBVARIANT dbv;
 +					bool always = getString(hContact, "MirVer", &dbv) != 0;
 +					if (!always) db_free(&dbv);
 +					MSN_SetMirVer(hContact, cont->cap1, always);
 +				}
 +
 +				if (data.cmdstring[0] && strcmp(data.cmdstring, "0")) {
 +					char *pszUrl, *pszAvatarHash = MSN_GetAvatarHash(data.cmdstring, &pszUrl);
 +					if (pszAvatarHash == NULL)
 +						goto remove;
 +
 +					setString(hContact, "PictContext", data.cmdstring);
 +					setString(hContact, "AvatarHash", pszAvatarHash);
 +					if (pszUrl)
 +						setString(hContact, "AvatarUrl", pszUrl);
 +					else
 +						delSetting(hContact, "AvatarUrl");
 +
 +					if (hContact != NULL) {
 +						char szSavedHash[64] = "";
 +						db_get_static(hContact, m_szModuleName, "AvatarSavedHash", szSavedHash, sizeof(szSavedHash));
 +						if (stricmp(szSavedHash, pszAvatarHash))
 +							pushAvatarRequest(hContact, pszUrl);
 +						else {
 +							char szSavedContext[64];
 +							int result = db_get_static(hContact, m_szModuleName, "PictSavedContext", szSavedContext, sizeof(szSavedContext));
 +							if (result || strcmp(szSavedContext, data.cmdstring))
 +								pushAvatarRequest(hContact, pszUrl);
 +						}
 +					}
 +					mir_free(pszAvatarHash);
 +					mir_free(pszUrl);
 +				}
 +				else {
 +remove:
 +					delSetting(hContact, "AvatarHash");
 +					delSetting(hContact, "AvatarSavedHash");
 +					delSetting(hContact, "AvatarUrl");
 +					delSetting(hContact, "PictContext");
 +					delSetting(hContact, "PictSavedContext");
 +
 +					ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, 0);
 +				}
 +			}
 +			else if (lastStatus == ID_STATUS_OFFLINE)
 +				delSetting(hContact, "MirVer");
 +
 +		}
 +		break;
 +	case ' ORI':    //********* IRO: section 8.4 Getting Invited to a Switchboard Session
 +		{
 +			union {
 +				char* tWords[5];
 +				struct { char *strThisContact, *totalContacts, *userEmail, *userNick, *flags; } data;
 +			};
 +
 +			int tNumTokens = sttDivideWords(params, 5, tWords);
 +			if (tNumTokens < 4)
 +				goto LBL_InvalidCommand;
 +
 +			info->contactJoined(data.userEmail);
 +
 +			if (!strchr(data.userEmail, ';')) {
 +				UrlDecode(data.userNick);
 +				MCONTACT hContact = MSN_HContactFromEmail(data.userEmail, data.userNick, true, true);
 +
 +				if (tNumTokens == 5 && strcmp(data.flags, "0:0")) {
 +					MsnContact *cont = Lists_Get(data.userEmail);
 +					if (cont) {
 +						char* end = NULL;
 +						cont->cap1 = strtoul(data.flags, &end, 10);
 +						cont->cap2 = end && *end == ':' ? strtoul(end + 1, NULL, 10) : 0;
 +					}
 +				}
 +
 +				int temp_status = getWord(hContact, "Status", ID_STATUS_OFFLINE);
 +				if (temp_status == ID_STATUS_OFFLINE && Lists_IsInList(LIST_FL, data.userEmail))
 +					setWord(hContact, "Status", ID_STATUS_INVISIBLE);
 +
 +				// only start the chat session after all the IRO messages has been recieved
 +				if (info->mJoinedContactsWLID.getCount() > 1 && !strcmp(data.strThisContact, data.totalContacts))
 +					MSN_ChatStart(info);
 +			}
 +		}
 +		break;
 +
 +	case ' IOJ':    //********* JOI: section 8.5 Session Participant Changes
 +		{
 +			union {
 +				char* tWords[3];
 +				struct { char *userEmail, *userNick, *flags; } data;
 +			};
 +
 +			int tNumTokens = sttDivideWords(params, 3, tWords);
 +			if (tNumTokens < 2)
 +				goto LBL_InvalidCommand;
 +
 +			UrlDecode(data.userEmail);
 +
 +			if (strchr(data.userEmail, ';')) {
 +				info->contactJoined(data.userEmail);
 +				break;
 +			}
 +
 +			if (_stricmp(MyOptions.szEmail, data.userEmail) == 0) {
 +				if (!info->mCaller) {
 +					if (info->mJoinedContactsWLID.getCount() == 1) {
 +						MSN_InitSB(info, info->mJoinedContactsWLID[0]);
 +					}
 +					else {
 +						info->sendCaps();
 +						if (info->mInitialContactWLID && MsgQueue_CheckContact(info->mInitialContactWLID))
 +							msnNsThread->sendPacket("XFR", "SB");
 +						mir_free(info->mInitialContactWLID); info->mInitialContactWLID = NULL;
 +					}
 +					break;
 +				}
 +
 +				const char* wlid;
 +				do {
 +					wlid = MsgQueue_GetNextRecipient();
 +				}
 +					while (wlid != NULL && MSN_GetUnconnectedThread(wlid) != NULL);
 +
 +				//can happen if both parties send first message at the same time
 +				if (wlid == NULL) {
 +					debugLogA("USR (SB) internal: thread created for no reason");
 +					return 1;
 +				}
 +
 +				if (strcmp(wlid, "chat") == 0) {
 +					MsgQueueEntry E;
 +					MsgQueue_GetNext(wlid, E);
 +
 +					for (int i = 0; i < E.cont->getCount(); ++i)
 +						info->sendPacket("CAL", (*E.cont)[i]);
 +
 +					MSN_ChatStart(info);
 +
 +					delete E.cont;
 +					mir_free(E.wlid);
 +					break;
 +				}
 +
 +				char* szEmail;
 +				parseWLID(NEWSTR_ALLOCA(wlid), NULL, &szEmail, NULL);
 +
 +				info->mInitialContactWLID = mir_strdup(szEmail);
 +				info->sendPacket("CAL", szEmail);
 +				break;
 +			}
 +
 +			UrlDecode(data.userNick);
 +			stripBBCode(data.userNick);
 +			stripColorCode(data.userNick);
 +
 +			MCONTACT hContact = MSN_HContactFromEmail(data.userEmail, data.userNick, true, true);
 +			if (tNumTokens == 3) {
 +				MsnContact *cont = Lists_Get(data.userEmail);
 +				if (cont) {
 +					char* end = NULL;
 +					cont->cap1 = strtoul(data.flags, &end, 10);
 +					cont->cap2 = end && *end == ':' ? strtoul(end + 1, NULL, 10) : 0;
 +				}
 +			}
 +
 +			mir_utf8decode(data.userNick, NULL);
 +			debugLogA("New contact in channel %s %s", data.userEmail, data.userNick);
 +
 +			if (info->contactJoined(data.userEmail) <= 1)
 +				MSN_InitSB(info, data.userEmail);
 +			else {
 +				bool chatCreated = info->mChatID[0] != 0;
 +
 +				info->sendCaps();
 +
 +				if (chatCreated) {
 +					GCDEST gcd = { m_szModuleName, info->mChatID, GC_EVENT_JOIN };
 +					GCEVENT gce = { sizeof(gce), &gcd };
 +					gce.dwFlags = GCEF_ADDTOLOG;
 +					gce.ptszNick = GetContactNameT(hContact);
 +					gce.ptszUID = mir_a2t(data.userEmail);
 +					gce.ptszStatus = TranslateT("Others");
 +					gce.time = time(NULL);
 +					gce.bIsMe = FALSE;
 +					CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
 +					mir_free((void*)gce.ptszUID);
 +				}
 +				else MSN_ChatStart(info);
 +			}
 +		}
 +		break;
 +
 +	case ' GSM':   //********* MSG: sections 8.7 Instant Messages, 8.8 Receiving an Instant Message
 +		MSN_ReceiveMessage(info, cmdString, params);
 +		break;
 +
 +	case ' MBU':
 +		MSN_ReceiveMessage(info, cmdString, params);
 +		break;
 +
 +	case ' KAN':   //********* NAK: section 8.7 Instant Messages
 +		if (info->mJoinedContactsWLID.getCount() > 0 && MyOptions.SlowSend)
 +			ProtoBroadcastAck(info->getContactHandle(),
 +				ACKTYPE_MESSAGE, ACKRESULT_FAILED,
 +				(HANDLE)trid, (LPARAM)Translate("Message delivery failed"));
 +		debugLogA("Message send failed (trid=%d)", trid);
 +		break;
 +
 +	case ' TON':   //********* NOT: notification message
 +		MSN_ProcessNotificationMessage((char*)HReadBuffer(info, 0).surelyRead(trid), trid);
 +		break;
 +
 +	case ' GPI':   //********* IPG: mobile page
 +		MSN_ProcessPage((char*)HReadBuffer(info, 0).surelyRead(trid), trid);
 +		break;
 +
 +	case ' FCG':   //********* GCF:
 +		HReadBuffer(info, 0).surelyRead(atol(params));
 +		break;
 +
 +	case ' TUO':   //********* OUT: sections 7.10 Connection Close, 8.6 Leaving a Switchboard Session
 +		if (!_stricmp(params, "OTH")) {
 +			ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_OTHERLOCATION);
 +			debugLogA("You have been disconnected from the MSN server because you logged on from another location using the same MSN passport.");
 +		}
 +
 +		if (!_stricmp(params, "MIG")) // ignore it
 +			break;
 +
 +		return 1;
 +
 +	case ' YRQ':   //********* QRY:
 +		break;
 +
 +	case ' GNQ':	//********* QNG: reply to PNG
 +		msnPingTimeout = trid;
 +		if (info->mType == SERVER_NOTIFICATION && hKeepAliveThreadEvt != NULL)
 +			SetEvent(hKeepAliveThreadEvt);
 +		break;
 +
 +	case ' LMR':	//********* RML: Remove from the list
 +		{
 +			char* tWords[1];
 +			if (sttDivideWords(params, 1, tWords) != 1)
 +				goto LBL_InvalidCommand;
 +
 +			if (strcmp(tWords[0], "OK") != 0) {
 +				size_t len = atol(tWords[0]);
 +				MSN_ProcessRemove((char*)HReadBuffer(info, 0).surelyRead(len), len);
 +			}
 +		}
 +		break;
 +
 +	case ' GNR':   //********* RNG: section 8.4 Getting Invited to a Switchboard Session
 +						//note: unusual message encoding: trid==sessionid
 +		{
 +			union {
 +				char* tWords[8];
 +				struct { char *newServer, *security, *authChallengeInfo, *callerEmail, *callerNick,
 +								*type, *srcUrl, *genGateway; } data;
 +			};
 +
 +			if (sttDivideWords(params, 8, tWords) != 8)
 +				goto LBL_InvalidCommand;
 +
 +			UrlDecode(data.newServer); UrlDecode(data.callerEmail);
 +			UrlDecode(data.callerNick);
 +			stripBBCode(data.callerNick);
 +			stripColorCode(data.callerNick);
 +
 +			if (strcmp(data.security, "CKI")) {
 +				debugLogA("Unknown security package in RNG command: %s", data.security);
 +				break;
 +			}
 +
 +			ThreadData* newThread = new ThreadData;
 +			strcpy(newThread->mServer, data.newServer);
 +			newThread->gatewayType = atol(data.genGateway) != 0;
 +			newThread->mType = SERVER_SWITCHBOARD;
 +			newThread->mInitialContactWLID = mir_strdup(data.callerEmail);
 +			MSN_HContactFromEmail(data.callerEmail, data.callerNick, true, true);
 +			mir_snprintf(newThread->mCookie, sizeof(newThread->mCookie), "%s %d", data.authChallengeInfo, trid);
 +
 +			ReleaseSemaphore(newThread->hWaitEvent, MSN_PACKETS_COMBINE, NULL);
 +
 +			debugLogA("Opening caller's switchboard server '%s'...", data.newServer);
 +			newThread->startThread(&CMsnProto::MSNServerThread, this);
 +		}
 +		break;
 +
 +	case ' XBU':   // UBX : MSNP11+ User Status Message
 +		{
 +			union {
 +				char* tWords[2];
 +				struct { char *wlid, *datalen; } data;
 +			};
 +
 +			if (sttDivideWords(params, 2, tWords) != 2)
 +				goto LBL_InvalidCommand;
 +
 +			int len = atol(data.datalen);
 +			if (len < 0 || len > 4000)
 +				goto LBL_InvalidCommand;
 +
 +			MSN_ProcessStatusMessage((char*)HReadBuffer(info, 0).surelyRead(len), len, data.wlid);
 +		}
 +		break;
 +
 +	case ' NBU':	// UBN : MSNP13+ File sharing, P2P Bootstrap, TURN setup.
 +		{
 +			union	{
 +				char* tWords[3];
 +				struct { char *email, *typeId, *datalen; } data;
 +			};
 +
 +			if (sttDivideWords(params, 3, tWords) != 3)
 +				goto LBL_InvalidCommand;
 +
 +			int len = atol(data.datalen);
 +			if (len < 0 || len > 4000)
 +				goto LBL_InvalidCommand;
 +
 +			HReadBuffer buf(info, 0);
 +			char* msgBody = (char*)buf.surelyRead(len);
 +
 +			char *szEmail = data.email;
 +			if (strstr(data.email, sttVoidUid))
 +				parseWLID(NEWSTR_ALLOCA(data.email), NULL, &szEmail, NULL);
 +
 +			switch (atol(data.typeId)) {
 +			case 1:
 +				// File sharing stuff
 +				// sttProcessFileSharing(msgBody, len, hContact);
 +				break;
 +
 +			case 3:
 +				// P2P Bootstrap
 +				p2p_processSIP(info, msgBody, NULL, szEmail);
 +				break;
 +
 +			case 4:
 +			case 8:
 +				ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_OTHERLOCATION);
 +				debugLogA("You have been disconnected from the MSN server because you logged on from another location using the same MSN passport.");
 +				break;
 +
 +			case 6:
 +				MSN_SharingFindMembership(true);
 +				MSN_ABFind("ABFindContactsPaged", NULL, true);
 +				break;
 +
 +			case 10:
 +				// TURN setup
 +				p2p_processSIP(info, msgBody, NULL, szEmail);
 +				break;
 +			}
 +		}
 +		break;
 +
 +	case ' NUU':	// UUN : MSNP13+ File sharing, P2P Bootstrap, TURN setup.
 +		break;
 +
 +	case ' RSU':	//********* USR: sections 7.3 Authentication, 8.2 Switchboard Connections and Authentication
 +		if (info->mType == SERVER_SWITCHBOARD) { //(section 8.2)
 +			union {
 +				char* tWords[3];
 +				struct { char *status, *userHandle, *friendlyName; } data;
 +			};
 +
 +			if (sttDivideWords(params, 3, tWords) != 3)
 +				goto LBL_InvalidCommand;
 +
 +			UrlDecode(data.userHandle); UrlDecode(data.friendlyName);
 +
 +			if (strcmp(data.status, "OK")) {
 +				debugLogA("Unknown status to USR command (SB): '%s'", data.status);
 +				break;
 +			}
 +
 +			info->sendPacket("CAL", MyOptions.szEmail);
 +		}
 +		else { //dispatch or notification server (section 7.3)
 +			union {
 +				char* tWords[4];
 +				struct { char *security, *sequence, *authChallengeInfo, *nonce; } data;
 +			};
 +
 +			if (sttDivideWords(params, 4, tWords) != 4)
 +				goto LBL_InvalidCommand;
 +
 +			if (!strcmp(data.security, "SSO")) {
 +				if (MSN_GetPassportAuth()) {
 +					m_iDesiredStatus = ID_STATUS_OFFLINE;
 +					return 1;
 +				}
 +
 +				char* sec = GenerateLoginBlob(data.nonce);
 +				info->sendPacket("USR", "SSO S %s %s %s", authStrToken ? authStrToken : "", sec, MyOptions.szMachineGuid);
 +				mir_free(sec);
 +
 +				ForkThread(&CMsnProto::msn_keepAliveThread, NULL);
 +				ForkThread(&CMsnProto::MSNConnDetectThread, NULL);
 +			}
 +			else if (!strcmp(data.security, "OK")) {
 +			}
 +			else {
 +				debugLogA("Unknown security package '%s'", data.security);
 +
 +				if (info->mType == SERVER_NOTIFICATION)
 +					ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPROTOCOL);
 +				return 1;
 +			}
 +		}
 +		break;
 +
 +	case ' SFR':   // RFS: Refresh Contact List
 +		if (!MSN_RefreshContactList()) {
 +			MSN_ShowError("Cannot retrieve contact list");
 +			return 1;
 +		}
 +		break;
 +
 +	case ' XUU':   // UUX: MSNP11 addition
 +		{
 +			char* tWords[1];
 +			if (sttDivideWords(params, SIZEOF(tWords), tWords) != SIZEOF(tWords))
 +				goto LBL_InvalidCommand;
 +
 +			int len = atol(tWords[0]);
 +			if (len < 0 || len > 4000)
 +				goto LBL_InvalidCommand;
 +
 +			HReadBuffer(info, 0).surelyRead(len);
 +		}
 +		break;
 +
 +	case ' REV':	//******** VER: section 7.1 Protocol Versioning
 +		{
 +			char* protocol1;
 +			if (sttDivideWords(params, 1, &protocol1) != 1)
 +				goto LBL_InvalidCommand;
 +
 +			if (MyOptions.szEmail[0] == 0) {
 +				MSN_ShowError("You must specify your e-mail in Options/Network/MSN");
 +				return 1;
 +			}
 +
 +			OSVERSIONINFOEX osvi = {0};
 +			osvi.dwOSVersionInfoSize = sizeof(osvi);
 +			GetVersionEx((LPOSVERSIONINFO)&osvi);
 +
 +			info->sendPacket("CVR","0x0409 %s %d.%d.%d i386 MSNMSGR %s msmsgs %s",
 +				osvi.dwPlatformId >= 2 ? "winnt" : "win", osvi.dwMajorVersion,
 +				osvi.dwMinorVersion, osvi.wServicePackMajor,
 +				msnProductVer, MyOptions.szEmail);
 +
 +			info->sendPacket("USR", "SSO I %s", MyOptions.szEmail);
 +		}
 +		break;
 +	case ' RFX':    //******** XFR: sections 7.4 Referral, 8.1 Referral to Switchboard
 +		{
 +			union {
 +				char* tWords[7];
 +				struct { char *type, *newServer, *security, *authChallengeInfo,
 +								*type2, *srcUrl, *genGateway; } data;
 +			};
 +
 +			int numWords = sttDivideWords(params, 7, tWords);
 +			if (numWords < 3)
 +				goto LBL_InvalidCommand;
 +
 +			if (!strcmp(data.type, "NS")) {  //notification server
 +				UrlDecode(data.newServer);
 +				ThreadData* newThread = new ThreadData;
 +				strcpy(newThread->mServer, data.newServer);
 +				newThread->mType = SERVER_NOTIFICATION;
 +				newThread->mTrid = info->mTrid;
 +				newThread->mIsMainThread = true;
 +				usingGateway |= (*data.security == 'G');
 +				info->mIsMainThread = false;
 +
 +				debugLogA("Switching to notification server '%s'...", data.newServer);
 +				newThread->startThread(&CMsnProto::MSNServerThread, this);
 +				return 1;  //kill the old thread
 +			}
 +
 +			if (!strcmp(data.type, "SB")) {  //switchboard server
 +				UrlDecode(data.newServer);
 +
 +				if (numWords < 4)
 +					goto LBL_InvalidCommand;
 +
 +				if (strcmp(data.security, "CKI")) {
 +					debugLogA("Unknown XFR SB security package '%s'", data.security);
 +					break;
 +				}
 +
 +				ThreadData* newThread = new ThreadData;
 +				strcpy(newThread->mServer, data.newServer);
 +				newThread->gatewayType = data.genGateway && atol(data.genGateway) != 0;
 +				newThread->mType = SERVER_SWITCHBOARD;
 +				newThread->mCaller = 1;
 +				strcpy(newThread->mCookie, data.authChallengeInfo);
 +
 +				debugLogA("Opening switchboard server '%s'...", data.newServer);
 +				newThread->startThread(&CMsnProto::MSNServerThread, this);
 +			}
 +			else debugLogA("Unknown referral server: %s", data.type);
 +		}
 +		break;
 +
 +	default:
 +		debugLogA("Unrecognised message: %s", cmdString);
 +		break;
 +	}
 +
 +	return 0;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_contact.cpp b/plugins/!Deprecated/MSN/src/msn_contact.cpp new file mode 100644 index 0000000000..fc3bef21a1 --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_contact.cpp @@ -0,0 +1,272 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +MCONTACT CMsnProto::MSN_HContactFromEmail(const char* wlid, const char* msnNick, bool addIfNeeded, bool temporary)
 +{
 +	MCONTACT hContact = NULL;
 +
 +	char* szEmail;
 +	parseWLID(NEWSTR_ALLOCA(wlid), NULL, &szEmail, NULL);
 +
 +	MsnContact *msc = Lists_Get(szEmail);
 +	if (msc && msc->hContact) hContact = msc->hContact;
 +
 +	if (hContact == NULL && addIfNeeded) {
 +		hContact = (MCONTACT)CallService(MS_DB_CONTACT_ADD, 0, 0);
 +		CallService(MS_PROTO_ADDTOCONTACT, hContact, (LPARAM)m_szModuleName);
 +		setString(hContact, "e-mail", szEmail);
 +		setStringUtf(hContact, "Nick", msnNick ? msnNick : wlid);
 +		if (temporary)
 +			db_set_b(hContact, "CList", "NotOnList", 1);
 +
 +		Lists_Add(0, NETID_MSN, wlid, hContact);
 +	}
 +
 +	return hContact;
 +}
 +
 +
 +void CMsnProto::MSN_SetContactDb(MCONTACT hContact, const char *szEmail)
 +{
 +	MsnContact *cont = Lists_Get(szEmail);
 +	const int listId = cont->list;
 +
 +	if (listId & LIST_FL)
 +	{
 +		if (db_get_b(hContact, "CList", "NotOnList", 0) == 1)
 +		{
 +			db_unset(hContact, "CList", "NotOnList");
 +			db_unset(hContact, "CList", "Hidden");
 +		}
 +
 +		if (listId & (LIST_BL | LIST_AL))
 +		{
 +			WORD tApparentMode = getWord(hContact, "ApparentMode", 0);
 +			if ((listId & LIST_BL) && tApparentMode == 0)
 +				setWord(hContact, "ApparentMode", ID_STATUS_OFFLINE);
 +			else if ((listId & LIST_AL) && tApparentMode != 0)
 +				delSetting(hContact, "ApparentMode");
 +		}
 +
 +		if (cont->netId == NETID_MOB)
 +		{
 +			setWord(hContact, "Status", ID_STATUS_ONTHEPHONE);
 +			setString(hContact, "MirVer", "SMS");
 +		}
 +	}
 +	if (listId & LIST_LL)
 +		setByte(hContact, "LocalList", 1);
 +	else
 +		delSetting(hContact, "LocalList");
 +
 +}
 +
 +
 +void CMsnProto::AddDelUserContList(const char* email, const int list, const int netId, const bool del)
 +{
 +	char buf[512];
 +	size_t sz;
 +
 +	if (list < LIST_RL)
 +	{
 +		const char* dom = strchr(email, '@');
 +		if (dom == NULL)
 +		{
 +			sz = mir_snprintf(buf, sizeof(buf),
 +				"<ml><t><c n=\"%s\" l=\"%d\"/></t></ml>",
 +				email, list);
 +		}
 +		else
 +		{
 +			*(char*)dom = 0;
 +			sz = mir_snprintf(buf, sizeof(buf),
 +				"<ml><d n=\"%s\"><c n=\"%s\" l=\"%d\" t=\"%d\"/></d></ml>",
 +				dom+1, email, list, netId);
 +			*(char*)dom = '@';
 +		}
 +		msnNsThread->sendPacket(del ? "RML" : "ADL", "%d\r\n%s", sz, buf);
 +	}
 +
 +	if (del)
 +		Lists_Remove(list, email);
 +	else
 +		Lists_Add(list, netId, email);
 +}
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_AddUser - adds a e-mail address to one of the MSN server lists
 +
 +bool CMsnProto::MSN_AddUser(MCONTACT hContact, const char* email, int netId, int flags, const char *msg)
 +{
 +	bool needRemove     = (flags & LIST_REMOVE) != 0;
 +	bool leaveHotmail   = (flags & LIST_REMOVENH) == LIST_REMOVENH;
 +	flags &= 0xFF;
 +
 +	if (needRemove != Lists_IsInList(flags, email))
 +		return true;
 +
 +
 +	bool res = false;
 +	if (flags == LIST_FL)
 +	{
 +		if (needRemove)
 +		{
 +			if (hContact == NULL)
 +			{
 +				hContact = MSN_HContactFromEmail(email);
 +				if (hContact == NULL) return false;
 +			}
 +
 +			char id[MSN_GUID_LEN];
 +			if (!db_get_static(hContact, m_szModuleName, "ID", id, sizeof(id)))
 +			{
 +				int netId = Lists_GetNetId(email);
 +				if (leaveHotmail)
 +					res = MSN_ABAddRemoveContact(id, netId, false);
 +				else
 +					res = MSN_ABAddDelContactGroup(id , NULL, "ABContactDelete");
 +				if (res) AddDelUserContList(email, flags, netId, true);
 +
 +				delSetting(hContact, "GroupID");
 +				delSetting(hContact, "ID");
 +				MSN_RemoveEmptyGroups();
 +			}
 +		}
 +		else
 +		{
 +			DBVARIANT dbv = {0};
 +			if (!strcmp(email, MyOptions.szEmail))
 +				getStringUtf("Nick", &dbv);
 +
 +			unsigned res1 = MSN_ABContactAdd(email, dbv.pszVal, netId, msg, false);
 +			if (netId == NETID_MSN && res1 == 2)
 +			{
 +				netId = NETID_LCS;
 +				res = MSN_ABContactAdd(email, dbv.pszVal, netId, msg, false) == 0;
 +			}
 +			else if (netId == NETID_MSN && res1 == 3)
 +			{
 +				char szContactID[100];
 +				hContact = MSN_HContactFromEmail(email);
 +				if (db_get_static(hContact, m_szModuleName, "ID", szContactID, sizeof(szContactID)) == 0)
 +				{
 +					MSN_ABAddRemoveContact(szContactID, netId, true);
 +					res = true;
 +				}
 +			}
 +
 +			else
 +				res = (res1 == 0);
 +
 +			if (res)
 +			{
 +				DBVARIANT dbv;
 +				if (!db_get_utf(hContact, "CList", "Group", &dbv))
 +				{
 +					MSN_MoveContactToGroup(hContact, dbv.pszVal);
 +					db_free(&dbv);
 +				}
 +
 +				char szContactID[100];
 +				if (db_get_static(hContact, m_szModuleName, "ID", szContactID, sizeof(szContactID)) == 0)
 +					MSN_ABFind("ABFindByContacts", szContactID);
 +
 +				MSN_SharingFindMembership(true);
 +				AddDelUserContList(email, flags, netId, false);
 +			}
 +			else
 +			{
 +				if (netId == 1 && strstr(email, "@yahoo.com") != 0)
 +					MSN_FindYahooUser(email);
 +			}
 +			db_free(&dbv);
 +		}
 +	}
 +	else if (flags == LIST_LL)
 +	{
 +		if (needRemove)
 +			Lists_Remove(LIST_LL, email);
 +		else
 +			Lists_Add(LIST_LL, NETID_MSN, email);
 +	}
 +	else
 +	{
 +		if (netId == 0) netId = Lists_GetNetId(email);
 +		res = MSN_SharingAddDelMember(email, flags, netId, needRemove ? "DeleteMember" : "AddMember");
 +//		if (res || (flags & LIST_RL))
 +			AddDelUserContList(email, flags, netId, needRemove);
 +		if ((flags & LIST_BL) && !needRemove)
 +		{
 +			ThreadData* thread =  MSN_GetThreadByContact(email, SERVER_SWITCHBOARD);
 +			if (thread) thread->sendTerminate();
 +		}
 +		if ((flags & LIST_PL) && needRemove)
 +		{
 +			MSN_AddUser(hContact, email, netId, LIST_RL);
 +		}
 +	}
 +	return res;
 +}
 +
 +
 +void CMsnProto::MSN_FindYahooUser(const char* email)
 +{
 +	const char* dom = strchr(email, '@');
 +	if (dom)
 +	{
 +		char buf[512];
 +		size_t sz;
 +
 +		*(char*)dom = '\0';
 +		sz = mir_snprintf(buf, sizeof(buf), "<ml><d n=\"%s\"><c n=\"%s\"/></d></ml>", dom+1, email);
 +		*(char*)dom = '@';
 +		msnNsThread->sendPacket("FQY", "%d\r\n%s", sz, buf);
 +	}
 +}
 +
 +bool CMsnProto::MSN_RefreshContactList(void)
 +{
 +	Lists_Wipe();
 +	Lists_Populate();
 +
 +	if (!MSN_SharingFindMembership()) return false;
 +
 +	if (m_iDesiredStatus == ID_STATUS_OFFLINE) return false;
 +
 +	if (!MSN_ABFind("ABFindContactsPaged", NULL)) return false;
 +
 +	if (m_iDesiredStatus == ID_STATUS_OFFLINE) return false;
 +
 +	MSN_CleanupLists();
 +
 +	if (m_iDesiredStatus == ID_STATUS_OFFLINE) return false;
 +
 +	msnLoggedIn = true;
 +
 +	MSN_CreateContList();
 +	MSN_StoreGetProfile();
 +	return true;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_errors.cpp b/plugins/!Deprecated/MSN/src/msn_errors.cpp new file mode 100644 index 0000000000..177122d4e0 --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_errors.cpp @@ -0,0 +1,93 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +int CMsnProto::MSN_HandleErrors(ThreadData* info, char* cmdString)
 +{
 +	int errorCode, packetID = -1;
 +	sscanf(cmdString, "%d %d", &errorCode, &packetID);
 +
 +	debugLogA("Server error:%s", cmdString);
 +
 +	switch(errorCode) {
 +	case ERR_INTERNAL_SERVER:
 +		MSN_ShowError("MSN Services are temporarily unavailable, please try to connect later");
 +		ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NOSERVER);
 +		return 1;
 +
 +	case ERR_SERVER_BUSY:
 +	case ERR_SERVER_UNAVAILABLE:
 +		MSN_ShowError("MSN Services are too busy, please try to connect later");
 +		ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NOSERVER);
 +		return 1;
 +
 +	case ERR_NOT_ALLOWED_WHEN_OFFLINE:
 +		MSN_ShowError("MSN protocol does not allow you to communicate with others when you are invisible");
 +		return 0;
 +
 +	case ERR_LIST_FULL:
 +		MSN_ShowError("MSN plugin cannot add a new contact because the contact list is full");
 +		return 0;
 +
 +	case ERR_ALREADY_THERE:
 +		MSN_ShowError("User is already in your contact list");
 +		return 0;
 +
 +	case ERR_CONTACT_LIST_FAILED:
 +	case ERR_LIST_UNAVAILABLE:
 +			char* tWords[3];
 +			if (sttDivideWords(cmdString, 3, tWords) == 3)
 +				HReadBuffer(info, 0).surelyRead(atol(tWords[2]));
 +			return 0;
 +
 +	case ERR_NOT_ONLINE:
 +		if (info->mInitialContactWLID)
 +			ProtoBroadcastAck(MSN_HContactFromEmail(info->mInitialContactWLID), ACKTYPE_MESSAGE, ACKRESULT_FAILED,
 +				(HANDLE)999999, (LPARAM)Translate("User not online"));
 +		else
 +			MSN_ShowError("User not online");
 +
 +		return 1;
 +
 +	case ERR_NOT_EXPECTED:
 +		MSN_ShowError("Your MSN account e-mail is unverified. Goto http://www.passport.com and verify the primary e-mail first");
 +		return 0;
 +
 +	case ERR_AUTHENTICATION_FAILED:
 +		if (info->mType != SERVER_SWITCHBOARD)
 +		{
 +			MSN_ShowError("Your username or password is incorrect");
 +			ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD);
 +		}
 +		return 1;
 +
 +	default:
 +		debugLogA("Unprocessed error: %s", cmdString);
 +		if (errorCode >= 500) //all these errors look fatal-ish
 +			MSN_ShowError("Unrecognised error %d. The server has closed our connection", errorCode);
 +
 +		break;
 +	}
 +	return 0;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_ftold.cpp b/plugins/!Deprecated/MSN/src/msn_ftold.cpp new file mode 100644 index 0000000000..db1ba3de66 --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_ftold.cpp @@ -0,0 +1,395 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +
 +void CMsnProto::msnftp_sendAcceptReject(filetransfer *ft, bool acc)
 +{
 +	ThreadData* thread = MSN_GetThreadByContact(ft->p2p_dest);
 +	if (thread == NULL) return;
 +
 +	if (acc)
 +	{
 +		thread->sendPacket("MSG",
 +			"U %d\r\nMIME-Version: 1.0\r\n"
 +			"Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
 +			"Invitation-Command: ACCEPT\r\n"
 +			"Invitation-Cookie: %s\r\n"
 +			"Launch-Application: FALSE\r\n"
 +			"Request-Data: IP-Address:\r\n\r\n",
 +			172+4+strlen(ft->szInvcookie), ft->szInvcookie);
 +	}
 +	else
 +	{
 +		thread->sendPacket("MSG",
 +			"U %d\r\nMIME-Version: 1.0\r\n"
 +			"Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
 +			"Invitation-Command: CANCEL\r\n"
 +			"Invitation-Cookie: %s\r\n"
 +			"Cancel-Code: REJECT\r\n\r\n",
 +			172-33+4+strlen(ft->szInvcookie), ft->szInvcookie);
 +	}
 +}
 +
 +void CMsnProto::msnftp_invite(filetransfer *ft)
 +{
 +	bool isOffline;
 +	ThreadData* thread = MSN_StartSB(ft->p2p_dest, isOffline);
 +	if (isOffline) return;
 +	if (thread != NULL) thread->mMsnFtp = ft;
 +
 +	TCHAR* pszFiles = _tcsrchr(ft->std.ptszFiles[0], '\\');
 +	if (pszFiles)
 +		pszFiles++;
 +	else
 +		pszFiles = *ft->std.ptszFiles;
 +
 +    char msg[1024];
 +    mir_snprintf(msg, SIZEOF(msg),
 +		"Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
 +		"Application-Name: File Transfer\r\n"
 +		"Application-GUID: {5D3E02AB-6190-11d3-BBBB-00C04F795683}\r\n"
 +		"Invitation-Command: INVITE\r\n"
 +		"Invitation-Cookie: %i\r\n"
 +		"Application-File: %s\r\n"
 +		"Application-FileSize: %I64u\r\n\r\n",
 +		MSN_GenRandom(), UTF8(pszFiles), ft->std.currentFileSize);
 +
 +	if (thread == NULL)
 +		MsgQueue_Add(ft->p2p_dest, 'S', msg, -1, ft);
 +	else
 +		thread->sendMessage('S', NULL, NETID_MSN, msg, MSG_DISABLE_HDR);
 +}
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	MSN File Transfer Protocol commands processing
 +
 +int CMsnProto::MSN_HandleMSNFTP(ThreadData *info, char *cmdString)
 +{
 +	char* params = "";
 +	filetransfer* ft = info->mMsnFtp;
 +
 +	if (cmdString[3])
 +		params = cmdString+4;
 +
 +	switch((*(PDWORD)cmdString&0x00FFFFFF)|0x20000000)
 +	{
 +		case ' EYB':    //********* BYE
 +		{
 +			ft->complete();
 +			return 1;
 +		}
 +		case ' LIF':    //********* FIL
 +		{
 +			char filesize[30];
 +			if (sscanf(params, "%s", filesize) < 1)
 +				goto LBL_InvalidCommand;
 +
 +			info->mCaller = 1;
 +			info->send("TFR\r\n", 5);
 +			break;
 +		}
 +		case ' RFT':    //********* TFR
 +		{
 +			char* sendpacket = (char*)alloca(2048);
 +			filetransfer* ft = info->mMsnFtp;
 +
 +			info->mCaller = 3;
 +
 +			while (ft->std.currentFileProgress < ft->std.currentFileSize)
 +			{
 +				if (ft->bCanceled)
 +                {
 +					sendpacket[0] = 0x01;
 +					sendpacket[1] = 0x00;
 +					sendpacket[2] = 0x00;
 +					info->send(sendpacket, 3);
 +					return 0;
 +				}
 +
 +				int wPlace = 0;
 +				sendpacket[wPlace++] = 0x00;
 +				unsigned __int64 packetLen = ft->std.currentFileSize - ft->std.currentFileProgress;
 +				if (packetLen > 2045) packetLen = 2045;
 +
 +				sendpacket[wPlace++] = (char)(packetLen & 0x00ff);
 +				sendpacket[wPlace++] = (char)((packetLen & 0xff00) >> 8);
 +				_read(ft->fileId, &sendpacket[wPlace], packetLen);
 +
 +				info->send(&sendpacket[0], packetLen+3);
 +
 +				ft->std.totalProgress += packetLen;
 +				ft->std.currentFileProgress += packetLen;
 +
 +				ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->std);
 +			}
 +
 +			ft->complete();
 +			break;
 +		}
 +		case ' RSU':    //********* USR
 +		{
 +			char email[130],authcookie[14];
 +			if (sscanf(params,"%129s %13s",email,authcookie) < 2)
 +			{
 +				debugLogA("Invalid USR OK command, ignoring");
 +				break;
 +			}
 +
 +			char tCommand[30];
 +			mir_snprintf(tCommand, sizeof(tCommand), "FIL %i\r\n", info->mMsnFtp->std.totalBytes);
 +			info->send(tCommand, strlen(tCommand));
 +			break;
 +		}
 +		case ' REV':    //********* VER
 +		{
 +			char protocol1[7];
 +			if (sscanf(params, "%6s", protocol1) < 1)
 +			{
 +LBL_InvalidCommand:
 +				debugLogA("Invalid %.3s command, ignoring", cmdString);
 +				break;
 +			}
 +
 +			if (strcmp(protocol1, "MSNFTP") != 0)
 +			{
 +				int tempInt;
 +				int tFieldCount = sscanf(params, "%d %6s", &tempInt, protocol1);
 +				if (tFieldCount != 2 || strcmp(protocol1, "MSNFTP") != 0)
 +				{
 +					debugLogA("Another side requested the unknown protocol (%s), closing thread", params);
 +					return 1;
 +			    }
 +            }
 +
 +			if (info->mCaller == 0)  //receive
 +			{
 +				char tCommand[MSN_MAX_EMAIL_LEN + 50];
 +				mir_snprintf(tCommand, sizeof(tCommand), "USR %s %s\r\n", MyOptions.szEmail, info->mCookie);
 +				info->send(tCommand, strlen(tCommand));
 +			}
 +			else if (info->mCaller == 2)  //send
 +			{
 +				static const char sttCommand[] = "VER MSNFTP\r\n";
 +				info->send(sttCommand, strlen(sttCommand));
 +			}
 +			break;
 +		}
 +		default:		// receiving file
 +		{
 +			HReadBuffer tBuf(info, int(cmdString - info->mData));
 +
 +			for (;;)
 +			{
 +				if (ft->bCanceled)
 +				{	info->send("CCL\r\n", 5);
 +					ft->close();
 +					return 1;
 +				}
 +
 +				BYTE* p = tBuf.surelyRead(3);
 +				if (p == NULL)
 +                {
 +LBL_Error:
 +                    ft->close();
 +					MSN_ShowError("file transfer is canceled by remote host");
 +					return 1;
 +				}
 +
 +				BYTE tIsTransitionFinished = *p++;
 +				WORD dataLen = *p++;
 +				dataLen |= (*p++ << 8);
 +
 +				if (tIsTransitionFinished)
 +                {
 +LBL_Success:
 +					static const char sttCommand[] = "BYE 16777989\r\n";
 +					info->send(sttCommand, strlen(sttCommand));
 +					return 1;
 +				}
 +
 +				p = tBuf.surelyRead(dataLen);
 +				if (p == NULL)
 +					goto LBL_Error;
 +
 +				_write(ft->fileId, p, dataLen);
 +				ft->std.totalProgress += dataLen;
 +				ft->std.currentFileProgress += dataLen;
 +
 +				ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->std);
 +
 +				if (ft->std.currentFileProgress == ft->std.totalBytes)
 +                {
 +					ft->complete();
 +					goto LBL_Success;
 +	            }
 +            }
 +        }
 +    }
 +
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	ft_startFileSend - sends a file using the old f/t protocol
 +
 +void __cdecl CMsnProto::msnftp_sendFileThread(void* arg)
 +{
 +	ThreadData* info = (ThreadData*)arg;
 +
 +	debugLogA("Waiting for an incoming connection to '%s'...", info->mServer);
 +
 +	switch(WaitForSingleObject(info->hWaitEvent, 60000))
 +	{
 +	case WAIT_TIMEOUT:
 +	case WAIT_FAILED:
 +		debugLogA("Incoming connection timed out, closing file transfer");
 +		return;
 +	}
 +
 +	info->mBytesInData = 0;
 +
 +	for (;;)
 +    {
 +		int recvResult = info->recv(info->mData+info->mBytesInData, 1000 - info->mBytesInData);
 +		if (recvResult == SOCKET_ERROR || !recvResult)
 +			break;
 +
 +		info->mBytesInData += recvResult;
 +
 +		//pull off each line for parsing
 +		if (info->mCaller == 3 && info->mType == SERVER_FILETRANS)
 +        {
 +			if (MSN_HandleMSNFTP(info, info->mData))
 +				break;
 +		}
 +		else   // info->mType!=SERVER_FILETRANS
 +        {
 +			for (;;)
 +            {
 +				char* peol = strchr(info->mData,'\r');
 +				if (peol == NULL)
 +					break;
 +
 +				if (info->mBytesInData < peol - info->mData + 2)
 +					break;  //wait for full line end
 +
 +				char msg[sizeof(info->mData)];
 +				memcpy(msg, info->mData, peol - info->mData); msg[peol - info->mData] = 0;
 +				if (*++peol != '\n')
 +					debugLogA("Dodgy line ending to command: ignoring");
 +				else
 +					peol++;
 +
 +				info->mBytesInData -= peol - info->mData;
 +				memmove(info->mData, peol, info->mBytesInData);
 +
 +				debugLogA("RECV:%s", msg);
 +
 +				if (!isalnum(msg[0]) || !isalnum(msg[1]) || !isalnum(msg[2]) || (msg[3] && msg[3]!=' '))
 +				{
 +					debugLogA("Invalid command name");
 +					continue;
 +				}
 +
 +				if (MSN_HandleMSNFTP(info, msg))
 +					break;
 +		    }
 +        }
 +
 +		if (info->mBytesInData == sizeof(info->mData))
 +        {
 +			debugLogA("sizeof(data) is too small: the longest line won't fit");
 +			break;
 +	    }
 +    }
 +
 +	debugLogA("Closing file transfer thread");
 +}
 +
 +void CMsnProto::msnftp_startFileSend(ThreadData* info, const char* Invcommand, const char* Invcookie)
 +{
 +	if (_stricmp(Invcommand, "ACCEPT"))
 +		return;
 +
 +	NETLIBBIND nlb = {0};
 +	HANDLE sb = NULL;
 +
 +	filetransfer* ft = info->mMsnFtp; info->mMsnFtp = NULL;
 +	if (ft != NULL && MyConnection.extIP)
 +    {
 +		nlb.cbSize = sizeof(nlb);
 +		nlb.pfnNewConnectionV2 = MSN_ConnectionProc;
 +		nlb.pExtra = this;
 +
 +		sb = (HANDLE)CallService(MS_NETLIB_BINDPORT, (WPARAM)m_hNetlibUser, (LPARAM)&nlb);
 +		if (sb == NULL)
 +			debugLogA("Unable to bind the port for incoming transfers");
 +	}
 +
 +	char hostname[256] = "";
 +	gethostname(hostname, sizeof(hostname));
 +	PHOSTENT he = gethostbyname(hostname);
 +
 +	const PIN_ADDR addr = (PIN_ADDR)he->h_addr_list[0];
 +	if (addr)
 +		strcpy(hostname, inet_ntoa(*addr));
 +	else
 +		hostname[0] = 0;
 +
 +	char command[1024];
 +	int  nBytes = mir_snprintf(command, sizeof(command),
 +		"MIME-Version: 1.0\r\n"
 +		"Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
 +		"Invitation-Command: %s\r\n"
 +		"Invitation-Cookie: %s\r\n"
 +		"IP-Address: %s\r\n"
 +		"IP-Address-Internal: %s\r\n"
 +		"Port: %i\r\n"
 +		"PortX: %i\r\n"
 +		"PortX-Internal: %i\r\n"
 +		"AuthCookie: %i\r\n"
 +		"Launch-Application: FALSE\r\n"
 +		"Request-Data: IP-Address:\r\n\r\n",
 +		sb && MyConnection.extIP ? "ACCEPT" : "CANCEL",
 +		Invcookie, MyConnection.GetMyExtIPStr(), hostname,
 +		nlb.wExPort, nlb.wExPort ^ 0x3141, nlb.wPort ^ 0x3141,
 +		MSN_GenRandom());
 +
 +	info->sendPacket("MSG", "N %d\r\n%s", nBytes, command);
 +
 +	if (sb)
 +    {
 +		ThreadData* newThread = new ThreadData;
 +		newThread->mType = SERVER_FILETRANS;
 +		newThread->mCaller = 2;
 +		newThread->mMsnFtp = ft;
 +		newThread->mIncomingBoundPort = sb;
 +		newThread->mIncomingPort = nlb.wPort;
 +		newThread->startThread(&CMsnProto::msnftp_sendFileThread, this);
 +	}
 +	else
 +		delete ft;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_global.h b/plugins/!Deprecated/MSN/src/msn_global.h new file mode 100644 index 0000000000..d1efa2736b --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_global.h @@ -0,0 +1,884 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2011 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include <windows.h>
 +#include <commctrl.h>
 +
 +#include <ctype.h>
 +#include <malloc.h>
 +#include <process.h>
 +#include <stdio.h>
 +#include <time.h>
 +
 +#include <direct.h>
 +#include <io.h>
 +#include <fcntl.h>
 +#include <sys/stat.h>
 +
 +#include <newpluginapi.h>
 +
 +#include <m_clist.h>
 +#include <m_clistint.h>
 +#include <m_clui.h>
 +#include <m_contacts.h>
 +#include <m_idle.h>
 +#include <m_icolib.h>
 +#include <m_message.h>
 +#include <m_options.h>
 +#include <m_protocols.h>
 +#include <m_protomod.h>
 +#include <m_protosvc.h>
 +#include <m_protoint.h>
 +#include <m_skin.h>
 +#include <m_system.h>
 +#include <m_system_cpp.h>
 +#include <m_userinfo.h>
 +#include <m_utils.h>
 +#include <win2k.h>
 +#include <m_database.h>
 +#include <m_langpack.h>
 +#include <m_netlib.h>
 +#include <m_popup.h>
 +#include <m_chat.h>
 +#include <m_avatars.h>
 +#include <m_timezones.h>
 +#include <m_extraicons.h>
 +#include <m_nudge.h>
 +#include <m_string.h>
 +
 +#include "m_proto_listeningto.h"
 +#include "m_folders.h"
 +#include "m_metacontacts.h"
 +
 +#include "ezxml.h"
 +
 +#include "resource.h"
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	MSN error codes
 +
 +#define ERR_SYNTAX_ERROR                 200
 +#define ERR_INVALID_PARAMETER            201
 +#define ERR_INVALID_USER                 205
 +#define ERR_FQDN_MISSING                 206
 +#define ERR_ALREADY_LOGIN                207
 +#define ERR_INVALID_USERNAME             208
 +#define ERR_INVALID_FRIENDLY_NAME        209
 +#define ERR_LIST_FULL                    210
 +#define ERR_ALREADY_THERE                215
 +#define ERR_NOT_ON_LIST                  216
 +#define ERR_NOT_ONLINE                   217
 +#define ERR_ALREADY_IN_THE_MODE          218
 +#define ERR_ALREADY_IN_OPPOSITE_LIST     219
 +#define ERR_CONTACT_LIST_FAILED          241
 +#define ERR_SWITCHBOARD_FAILED           280
 +#define ERR_NOTIFY_XFR_FAILED            281
 +#define ERR_REQUIRED_FIELDS_MISSING      300
 +#define ERR_NOT_LOGGED_IN                302
 +#define ERR_INTERNAL_SERVER              500
 +#define ERR_DB_SERVER                    501
 +#define ERR_LIST_UNAVAILABLE             508
 +#define ERR_FILE_OPERATION               510
 +#define ERR_MEMORY_ALLOC                 520
 +#define ERR_SERVER_BUSY                  600
 +#define ERR_SERVER_UNAVAILABLE           601
 +#define ERR_PEER_NS_DOWN                 602
 +#define ERR_DB_CONNECT                   603
 +#define ERR_SERVER_GOING_DOWN            604
 +#define ERR_CREATE_CONNECTION            707
 +#define ERR_INVALID_LOCALE               710
 +#define ERR_BLOCKING_WRITE               711
 +#define ERR_SESSION_OVERLOAD             712
 +#define ERR_USER_TOO_ACTIVE              713
 +#define ERR_TOO_MANY_SESSIONS            714
 +#define ERR_NOT_EXPECTED                 715
 +#define ERR_BAD_FRIEND_FILE              717
 +#define ERR_AUTHENTICATION_FAILED        911
 +#define ERR_NOT_ALLOWED_WHEN_OFFLINE     913
 +#define ERR_NOT_ACCEPTING_NEW_USERS      920
 +#define ERR_EMAIL_ADDRESS_NOT_VERIFIED   924
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	Global definitions
 +
 +#define MSN_MAX_EMAIL_LEN        128
 +#define MSN_GUID_LEN              40
 +
 +#define MSN_PACKETS_COMBINE         7
 +#define MSN_DEFAULT_PORT         1863
 +#define MSN_DEFAULT_GATEWAY_PORT   80
 +const char MSN_DEFAULT_LOGIN_SERVER[] = "messenger.hotmail.com";
 +const char MSN_DEFAULT_GATEWAY[] =      "gateway.messenger.hotmail.com";
 +const char MSN_USER_AGENT[] =           "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1)";
 +
 +#define MSN_BLOCK        "/BlockCommand"
 +#define MSN_INVITE       "/InviteCommand"
 +#define MSN_NETMEETING   "/NetMeeting"
 +#define MSN_VIEW_PROFILE "/ViewProfile"
 +
 +#define MS_GOTO_INBOX		"/GotoInbox"
 +#define MS_EDIT_PROFILE		"/EditProfile"
 +#define MS_EDIT_ALERTS		"/EditAlerts"
 +#define MS_SET_NICKNAME_UI  "/SetNicknameUI"
 +
 +extern const char sttVoidUid[];
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	MSN plugin functions
 +
 +struct CMsnProto;
 +
 +#define	MSN_ALLOW_MSGBOX    1
 +#define	MSN_ALLOW_ENTER	    2
 +#define	MSN_HOTMAIL_POPUP   4
 +#define MSN_SHOW_ERROR      8
 +#define	MSN_ALERT_POPUP	    16
 +
 +void        HtmlDecode(char* str);
 +char*       HtmlEncode(const char* str);
 +bool		txtParseParam (const char* szData, const char* presearch, const char* start, const char* finish, char* param, const int size);
 +void		stripBBCode(char* src);
 +void		stripColorCode(char* src);
 +void		parseWLID(char* wlid, char** net, char** email, char** inst);
 +
 +char*		GetGlobalIp(void);
 +
 +template <class chartype> void UrlDecode(chartype* str);
 +
 +void		__cdecl MSN_ConnectionProc(HANDLE hNewConnection, DWORD dwRemoteIP, void*);
 +
 +char*		MSN_GetAvatarHash(char* szContext, char** pszUrl = NULL);
 +bool		MSN_MsgWndExist(MCONTACT hContact);
 +
 +#define		MSN_SendNickname(a) MSN_SendNicknameUtf(UTF8(a))
 +
 +unsigned    MSN_GenRandom(void);
 +
 +void        MSN_InitContactMenu(void);
 +void        MSN_RemoveContactMenus(void);
 +
 +HANDLE      GetIconHandle(int iconId);
 +HICON       LoadIconEx(const char* name, bool big = false);
 +void        ReleaseIconEx(const char* name, bool big = false);
 +
 +void        MsnInitIcons(void);
 +
 +int         sttDivideWords(char* parBuffer, int parMinItems, char** parDest);
 +void		MSN_MakeDigest(const char* chl, char* dgst);
 +char*		getNewUuid(void);
 +
 +TCHAR* EscapeChatTags(const TCHAR* pszText);
 +TCHAR* UnEscapeChatTags(TCHAR* str_in);
 +
 +void   overrideStr(TCHAR*& dest, const TCHAR* src, bool unicode, const TCHAR* def = NULL);
 +
 +char* arrayToHex(BYTE* data, size_t datasz);
 +
 +inline unsigned short _htons(unsigned short s)
 +{
 +	return s>>8|s<<8;
 +}
 +
 +inline unsigned long _htonl(unsigned long s)
 +{
 +	return s<<24|(s&0xff00)<<8|((s>>8)&0xff00)|s>>24;
 +}
 +
 +inline unsigned __int64 _htonl64(unsigned __int64 s)
 +{
 +	return (unsigned __int64)_htonl(s & 0xffffffff) << 32 | _htonl(s >> 32);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// Popup interface
 +
 +typedef struct _tag_PopupData
 +{
 +	unsigned flags;
 +	char* url;
 +	TCHAR* title;
 +	TCHAR* text;
 +	CMsnProto* proto;
 +} PopupData;
 +
 +struct STRLIST : public LIST<char>
 +{
 +	static int compare(const char* p1, const char* p2)
 +	{ return _stricmp(p1, p2); }
 +
 +	STRLIST() : LIST<char>(2, compare) {}
 +	~STRLIST() { destroy(); }
 +
 +	void destroy( void )
 +	{
 +		for (int i=0; i < count; i++)
 +			mir_free(items[i]);
 +
 +		List_Destroy((SortedList*)this);
 +	}
 +
 +	int insertn(const char* p) { return insert(mir_strdup(p)); }
 +
 +	int remove(int idx)
 +	{
 +		mir_free(items[idx]);
 +		return List_Remove((SortedList*)this, idx);
 +	}
 +
 +	int remove(const char* p)
 +	{
 +		int idx;
 +		return  List_GetIndex((SortedList*)this, (char*)p, &idx) == 1 ? remove(idx) : -1;
 +	}
 +};
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	MIME headers processing
 +
 +class MimeHeaders
 +{
 +public:
 +
 +	MimeHeaders();
 +	MimeHeaders(unsigned);
 +	~MimeHeaders();
 +
 +	void        clear(void);
 +	char*       decodeMailBody(char* msgBody);
 +	const char* find(const char* fieldName);
 +	char*       flipStr(const char* src, size_t len, char* dest);
 +	size_t      getLength(void);
 +	char*       readFromBuffer(char* src);
 +	char*       writeToBuffer(char* dest);
 +
 +	void        addString(const char* name, const char* szValue, unsigned flags = 0);
 +	void        addLong(const char* name, long lValue, unsigned flags = 0);
 +	void        addULong(const char* name, unsigned lValue);
 +	void	    addBool(const char* name, bool lValue);
 +
 +	const char* operator[](const char* fieldName) { return find(fieldName); }
 +
 +	static wchar_t* decode(const char* val);
 +
 +private:
 +	typedef struct tag_MimeHeader
 +	{
 +		const char* name;
 +		const char* value;
 +		unsigned flags;
 +	} MimeHeader;
 +
 +	unsigned	mCount;
 +	unsigned	mAllocCount;
 +	MimeHeader* mVals;
 +
 +	unsigned allocSlot(void);
 +};
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	File transfer helper
 +
 +struct ThreadData;
 +
 +struct HReadBuffer
 +{
 +	HReadBuffer(ThreadData* info, int iStart = 0);
 +	~HReadBuffer();
 +
 +	BYTE* surelyRead(size_t parBytes);
 +
 +	ThreadData* owner;
 +	BYTE*			buffer;
 +	size_t			totalDataSize;
 +	size_t			startOffset;
 +};
 +
 +enum TInfoType
 +{
 +	SERVER_NOTIFICATION,
 +	SERVER_SWITCHBOARD,
 +	SERVER_FILETRANS,
 +	SERVER_P2P_DIRECT
 +};
 +
 +
 +struct filetransfer
 +{
 +	filetransfer(CMsnProto* prt);
 +	~filetransfer(void);
 +
 +	void close(void);
 +	void complete(void);
 +	int  create(void);
 +	int openNext(void);
 +
 +	CMsnProto* proto;
 +
 +	PROTOFILETRANSFERSTATUS std;
 +
 +	bool        bCanceled;		// flag to interrupt a transfer
 +	bool        bCompleted;		// was a FT ever completed?
 +	bool        bAccepted;		// was a FT ever completed?
 +
 +	int			fileId;			// handle of file being transferring (r/w)
 +
 +	HANDLE		hLockHandle;
 +
 +	ThreadData  *info;
 +	TInfoType	tType;
 +	TInfoType	tTypeReq;
 +	time_t		ts;
 +	clock_t     nNotify;
 +	unsigned	cf;
 +
 +	bool        p2p_waitack;    // wait for ack
 +	bool        p2p_isV2;       // P2P V2
 +
 +	unsigned    p2p_sessionid;	// session id
 +	unsigned    p2p_acksessid;	// acknowledged session id
 +	unsigned    p2p_sendmsgid;  // send message id
 +	unsigned    p2p_byemsgid;   // bye message id
 +	unsigned    p2p_ackID;		// number of ack's state
 +	unsigned    p2p_appID;		// application id: 1 = avatar, 2 = file transfer
 +	unsigned    p2p_type;		// application id: 1 = avatar, 2 = file transfer, 3 = custom emoticon
 +	char*       p2p_branch;		// header Branch: field
 +	char*       p2p_callID;		// header Call-ID: field
 +	char*       p2p_dest;		// destination e-mail address
 +	char*       p2p_object;     // MSN object for a transfer
 +
 +	//---- receiving a file
 +	char*       szInvcookie;	// cookie for receiving
 +
 +	unsigned __int64 lstFilePtr;
 +};
 +
 +struct directconnection
 +{
 +	directconnection(const char* CallID, const char* Wlid);
 +	~directconnection();
 +
 +	char* calcHashedNonce(UUID* nonce);
 +	char* mNonceToText(void);
 +	char* mNonceToHash(void) { return calcHashedNonce(mNonce); }
 +	void  xNonceToBin(UUID* nonce);
 +
 +	UUID* mNonce;
 +	char* xNonce;
 +
 +	char* callId;
 +	char* wlid;
 +
 +	time_t ts;
 +
 +	bool useHashedNonce;
 +	bool bAccepted;
 +
 +	CMsnProto* proto;
 +};
 +
 +
 +#pragma pack(1)
 +
 +typedef struct _tag_HFileContext
 +{
 +	unsigned len;
 +	unsigned ver;
 +	unsigned __int64 dwSize;
 +	unsigned type;
 +	wchar_t wszFileName[MAX_PATH];
 +	char unknown[30];
 +	unsigned id;
 +	char unknown2[64];
 +} HFileContext;
 +
 +struct P2PB_Header
 +{
 +	virtual char* parseMsg(char *buf) = 0;
 +	virtual char* createMsg(char *buf, const char* wlid, CMsnProto *ppro) = 0;
 +	virtual bool isV2Hdr(void) = 0;
 +	virtual void logHeader(CMsnProto *ppro) = 0;
 +};
 +
 +struct P2P_Header : P2PB_Header
 +{
 +	unsigned          mSessionID;
 +	unsigned          mID;
 +	unsigned __int64  mOffset;
 +	unsigned __int64  mTotalSize;
 +	unsigned          mPacketLen;
 +	unsigned          mFlags;
 +	unsigned          mAckSessionID;
 +	unsigned          mAckUniqueID;
 +	unsigned __int64  mAckDataSize;
 +
 +	P2P_Header() { memset(&mSessionID, 0, 48); }
 +	P2P_Header(char *buf) { parseMsg(buf); }
 +
 +	char* parseMsg(char *buf)  { memcpy(&mSessionID, buf, 48); return buf + 48; }
 +	char* createMsg(char *buf, const char* wlid, CMsnProto *ppro);
 +	bool isV2Hdr(void) { return false; }
 +	void logHeader(CMsnProto *ppro);
 +} ;
 +
 +struct P2PV2_Header : P2PB_Header
 +{
 +	unsigned          mSessionID;
 +	unsigned          mID;
 +	const char*       mCap;
 +	unsigned __int64  mRemSize;
 +	unsigned          mPacketLen;
 +	unsigned          mPacketNum;
 +	unsigned          mAckUniqueID;
 +	unsigned char     mOpCode;
 +	unsigned char     mTFCode;
 +
 +	P2PV2_Header() { memset(&mSessionID, 0, ((char*)&mTFCode - (char*)&mSessionID) + sizeof(mTFCode)); }
 +	P2PV2_Header(char *buf) { parseMsg(buf); }
 +
 +	char* parseMsg(char *buf);
 +	char* createMsg(char *buf, const char* wlid, CMsnProto *ppro);
 +	bool isV2Hdr(void) { return true; }
 +	void logHeader(CMsnProto *ppro);
 +};
 +
 +#pragma pack()
 +
 +bool p2p_IsDlFileOk(filetransfer* ft);
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	Thread handling functions and datatypes
 +
 +#define MSG_DISABLE_HDR      1
 +#define MSG_REQUIRE_ACK      2
 +#define MSG_RTL              4
 +#define MSG_OFFLINE          8
 +
 +struct CMsnProto;
 +typedef void (__cdecl CMsnProto::*MsnThreadFunc)(void*);
 +
 +struct ThreadData
 +{
 +   ThreadData();
 +   ~ThreadData();
 +
 +   STRLIST       mJoinedContactsWLID;
 +   STRLIST       mJoinedIdentContactsWLID;
 +   char*         mInitialContactWLID;
 +
 +   TInfoType     mType;            // thread type
 +   MsnThreadFunc mFunc;            // thread entry point
 +   char          mServer[80];      // server name
 +
 +   HANDLE        s;               // NetLib connection for the thread
 +   HANDLE        mIncomingBoundPort; // Netlib listen for the thread
 +   HANDLE        hWaitEvent;
 +   WORD          mIncomingPort;
 +   TCHAR         mChatID[10];
 +   bool          mIsMainThread;
 +   clock_t       mWaitPeriod;
 +
 +   CMsnProto*    proto;
 +
 +   //----| for gateways |----------------------------------------------------------------
 +   char          mSessionID[50]; // Gateway session ID
 +   char          mGatewayIP[80]; // Gateway IP address
 +   int           mGatewayTimeout;
 +   bool          sessionClosed;
 +   bool          termPending;
 +   bool          gatewayType;
 +
 +   //----| for switchboard servers only |------------------------------------------------
 +   bool          firstMsgRecv;
 +   int           mCaller;
 +   char          mCookie[130];     // for switchboard servers only
 +   LONG          mTrid;            // current message ID
 +   UINT          mTimerId;         // typing notifications timer id
 +
 +   //----| for file transfers only |-----------------------------------------------------
 +   filetransfer* mMsnFtp;          // file transfer block
 +   bool          mBridgeInit;
 +
 +   //----| internal data buffer |--------------------------------------------------------
 +   int           mBytesInData;     // bytes available in data buffer
 +   char          mData[8192];      // data buffer for connection
 +
 +   //----| methods |---------------------------------------------------------------------
 +   void          applyGatewayData(HANDLE hConn, bool isPoll);
 +   void          getGatewayUrl(char* dest, int destlen, bool isPoll);
 +   void          processSessionData(const char* xMsgr, const char* xHost);
 +   void          startThread(MsnThreadFunc , CMsnProto *prt);
 +
 +   int           send(const char data[], size_t datalen);
 +   int           recv(char* data, size_t datalen);
 +
 +   void          resetTimeout(bool term = false);
 +   bool          isTimeout(void);
 +
 +   void          sendTerminate(void);
 +   void          sendCaps(void);
 +   int           sendMessage(int msgType, const char* email, int netId, const char* msg, int parFlags);
 +   int           sendRawMessage(int msgType, const char* data, int datLen);
 +   int           sendPacket(const char* cmd, const char* fmt, ...);
 +
 +   int           contactJoined(const char* email);
 +   int           contactLeft(const char* email);
 +   MCONTACT      getContactHandle(void);
 +};
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN P2P session support
 +
 +#define MSN_APPID_AVATAR		1
 +#define MSN_APPID_AVATAR2   	12
 +#define MSN_APPID_FILE			2
 +#define MSN_APPID_WEBCAM		4
 +#define MSN_APPID_MEDIA_SHARING	35
 +#define MSN_APPID_IMAGE			33
 +
 +#define MSN_APPID_CUSTOMSMILEY  3
 +#define MSN_APPID_CUSTOMANIMATEDSMILEY  4
 +
 +#define MSN_TYPEID_FTPREVIEW		0
 +#define MSN_TYPEID_FTNOPREVIEW		1
 +#define MSN_TYPEID_CUSTOMSMILEY		2
 +#define MSN_TYPEID_DISPLAYPICT		3
 +#define MSN_TYPEID_BKGNDSHARING		4
 +#define MSN_TYPEID_BKGNDIMG			5
 +#define MSN_TYPEID_WINK				8
 +
 +
 +
 +inline bool IsChatHandle(MCONTACT hContact) { return (INT_PTR)hContact < 0; }
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	Message queue
 +
 +#define MSGQUE_RAW	1
 +
 +struct MsgQueueEntry
 +{
 +	char*          wlid;
 +	char*          message;
 +	filetransfer*  ft;
 +	STRLIST*       cont;
 +	int            msgType;
 +	int            msgSize;
 +	int            seq;
 +	int            allocatedToThread;
 +	time_t         ts;
 +	int            flags;
 +};
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	Avatars' queue
 +
 +struct AvatarQueueEntry
 +{
 +	MCONTACT hContact;
 +	char *pszUrl;
 +
 +	__forceinline AvatarQueueEntry(MCONTACT _contact, LPCSTR _url) :
 +		hContact(_contact),
 +		pszUrl( mir_strdup(_url))
 +	{}
 +
 +	__forceinline ~AvatarQueueEntry()
 +	{	mir_free(pszUrl);
 +	}
 +};
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	User lists
 +
 +template< class T >  int CompareId(const T* p1, const T* p2)
 +{
 +	return _stricmp(p1->id, p2->id);
 +}
 +
 +struct ServerGroupItem
 +{
 +	char* id;
 +	char* name; // in UTF8
 +};
 +
 +struct MsnPlace
 +{
 +	char *id;
 +	unsigned cap1;
 +	unsigned cap2;
 +	unsigned p2pMsgId;
 +	unsigned short p2pPktNum;
 +
 +	~MsnPlace() { mir_free(id); }
 +};
 +
 +struct MsnContact
 +{
 +	char *email;
 +	char *invite;
 +	char *nick;
 +	MCONTACT hContact;
 +	int list;
 +	int netId;
 +	int p2pMsgId;
 +	unsigned cap1;
 +	unsigned cap2;
 +
 +	OBJLIST<MsnPlace> places;
 +
 +	MsnContact() : places(1, CompareId) {}
 +	~MsnContact() { mir_free(email); mir_free(nick); mir_free(invite); }
 +};
 +
 +#define cap_OnlineViaMobile                 0x00000001
 +#define cap_OnlineMSN8User                  0x00000002
 +#define cap_SupportsGifInk                  0x00000004
 +#define cap_SupportsIsfInk                  0x00000008
 +#define cap_WebCamDetected                  0x00000010
 +#define cap_SupportsChunking                0x00000020
 +#define cap_MobileEnabled                   0x00000040
 +#define cap_WebWatchEnabled                 0x00000080
 +#define cap_SupportsActivities              0x00000100
 +#define cap_OnlineViaWebIM                  0x00000200
 +#define cap_MobileDevice                    0x00000400
 +#define cap_OnlineViaTGW                    0x00000800
 +#define cap_HasSpace                        0x00001000
 +#define cap_IsMceUser                       0x00002000
 +#define cap_SupportsDirectIM                0x00004000
 +#define cap_SupportsWinks                   0x00008000
 +#define cap_SupportsSharedSearch            0x00010000
 +#define cap_IsBot                           0x00020000
 +#define cap_SupportsVoiceIM                 0x00040000
 +#define cap_SupportsSChannel                0x00080000
 +#define cap_SupportsSipInvite               0x00100000
 +#define cap_SupportsMultipartyMedia         0x00200000
 +#define cap_SupportsSDrive                  0x00400000
 +#define cap_SupportsPageModeMessaging       0x00800000
 +#define cap_HasOneCare                      0x01000000
 +#define cap_SupportsTurn                    0x02000000
 +#define cap_SupportsP2PBootstrap            0x04000000
 +#define cap_UsingAlias                      0x08000000
 +
 +#define capex_IsSmsOnly                     0x00000001
 +#define capex_SupportsVoiceOverMsnp         0x00000002
 +#define capex_SupportsUucpSipStack          0x00000004
 +#define capex_SupportsApplicationMsg        0x00000008
 +#define capex_RTCVideoEnabled               0x00000010
 +#define capex_SupportsPeerToPeerV2          0x00000020
 +#define capex_IsAuthWebIMUser               0x00000040
 +#define capex_Supports1On1ViaGroup          0x00000080
 +#define capex_SupportsOfflineIM             0x00000100
 +#define capex_SupportsSharingVideo          0x00000200
 +#define capex_SupportsNudges                0x00000400
 +#define capex_CircleVoiceIMEnabled          0x00000800
 +#define capex_SharingEnabled                0x00001000
 +#define capex_MobileSuspendIMFanoutDisable  0x00002000
 +#define capex_SupportsP2PMixerRelay         0x00008000
 +#define capex_ConvWindowFileTransfer        0x00020000
 +#define capex_VideoCallSupports16x9         0x00040000
 +#define capex_SupportsP2PEnveloping         0x00080000
 +#define capex_YahooIMDisabled               0x00400000
 +#define capex_SIPTunnelVersion2             0x00800000
 +#define capex_VoiceClipSupportsWMAFormat    0x01000000
 +#define capex_VoiceClipSupportsCircleIM     0x02000000
 +#define capex_SupportsSocialNewsObjectTypes 0x04000000
 +#define capex_CustomEmoticonsCapable        0x08000000
 +#define capex_SupportsUTF8MoodMessages      0x10000000
 +#define capex_FTURNCapable                  0x20000000
 +#define capex_SupportsP4Activity            0x40000000
 +#define capex_SupportsChats                 0x80000000
 +
 +#define NETID_UNKNOWN	0x0000
 +#define NETID_MSN		0x0001
 +#define NETID_LCS		0x0002
 +#define NETID_MOB		0x0004
 +#define NETID_MOBNET	0x0008
 +#define NETID_CIRCLE	0x0009
 +#define NETID_TMPCIRCLE	0x000A
 +#define NETID_CID		0x000B
 +#define NETID_CONNECT	0x000D
 +#define NETID_REMOTE	0x000E
 +#define NETID_SMTP		0x0010
 +#define NETID_YAHOO		0x0020
 +
 +#define	LIST_FL         0x0001
 +#define	LIST_AL		    0x0002
 +#define	LIST_BL		    0x0004
 +#define	LIST_RL		    0x0008
 +#define LIST_PL		    0x0010
 +#define LIST_LL		    0x0080
 +
 +#define	LIST_REMOVE     0x0100
 +#define	LIST_REMOVENH   0x0300
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	MSN plugin options
 +
 +typedef struct _tag_MYOPTIONS
 +{
 +	bool		EnableSounds;
 +
 +	bool		ShowErrorsAsPopups;
 +	bool		SlowSend;
 +	bool		ManageServer;
 +
 +	char		szEmail[MSN_MAX_EMAIL_LEN];
 +	char		szMachineGuid[MSN_GUID_LEN];
 +	char		szMachineGuidP2P[MSN_GUID_LEN];
 +}
 +MYOPTIONS;
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	Windows error class
 +
 +struct TWinErrorCode
 +{
 +	WINAPI	TWinErrorCode();
 +	WINAPI	~TWinErrorCode();
 +
 +	char*		WINAPI getText();
 +
 +	long		mErrorCode;
 +	char*		mErrorText;
 +};
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	External variables
 +
 +#define MSN_NUM_MODES 9
 +
 +const char msnProtChallenge[] = "C1BX{V4W}Q3*10SM";
 +const char msnProductID[] = "PROD0120PW!CCV9@";
 +const char msnAppID[] = "AAD9B99B-58E6-4F23-B975-D9EC1F9EC24A";
 +const char msnStoreAppId[] = "Messenger Client 9.0";
 +const char msnProductVer[] = "14.0.8117.0416";
 +const char msnProtID[] = "MSNP18";
 +
 +extern HINSTANCE hInst;
 +
 +///////////////////////////////////////////////////////////////////////////////
 +// UTF8 encode helper
 +
 +class UTFEncoder
 +{
 +private:
 +	char* m_body;
 +
 +public:
 +	UTFEncoder(const char* pSrc) :
 +		m_body(mir_utf8encode(pSrc)) {}
 +
 +	UTFEncoder(const wchar_t* pSrc) :
 +		m_body(mir_utf8encodeW(pSrc)) {}
 +
 +	~UTFEncoder() {  mir_free(m_body);	}
 +	const char* str() const { return m_body; }
 +};
 +
 +#define UTF8(A) UTFEncoder(A).str()
 +
 +
 +typedef enum _tag_ConEnum
 +{
 +	conUnknown,
 +	conDirect,
 +	conUnknownNAT,
 +	conIPRestrictNAT,
 +	conPortRestrictNAT,
 +	conSymmetricNAT,
 +	conFirewall,
 +	conISALike
 +} ConEnum;
 +
 +#pragma pack(1)
 +typedef struct _tag_UDPProbePkt
 +{
 +	unsigned char  version;
 +	unsigned char  serviceCode;
 +	unsigned short clientPort;
 +	unsigned	   clientIP;
 +	unsigned short discardPort;
 +	unsigned short testPort;
 +	unsigned	   testIP;
 +	unsigned       trId;
 +} UDPProbePkt;
 +#pragma pack()
 +
 +extern const char* conStr[];
 +
 +typedef struct _tag_MyConnectionType
 +{
 +	unsigned intIP;
 +	unsigned extIP;
 +	ConEnum udpConType;
 +	ConEnum tcpConType;
 +	unsigned weight;
 +	bool upnpNAT;
 +	bool icf;
 +
 +	const IN_ADDR GetMyExtIP(void) { return *((PIN_ADDR)&extIP); }
 +	const char* GetMyExtIPStr(void) { return inet_ntoa(GetMyExtIP()); }
 +	const char* GetMyUdpConStr(void) { return conStr[udpConType]; }
 +	void SetUdpCon(const char* str);
 +	void CalculateWeight(void);
 +} MyConnectionType;
 +
 +struct chunkedmsg
 +{
 +	char* id;
 +	char* msg;
 +	size_t size;
 +	size_t recvsz;
 +	bool bychunk;
 +
 +	chunkedmsg(const char* tid, const size_t totsz, const bool bychunk);
 +	~chunkedmsg();
 +
 +	void add(const char* msg, size_t offset, size_t portion);
 +	bool get(char*& tmsg, size_t& tsize);
 +};
 +
 +struct DeleteParam
 +{
 +	CMsnProto *proto;
 +	MCONTACT hContact;
 +};
 +
 +INT_PTR CALLBACK DlgDeleteContactUI(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
 +
 +struct InviteChatParam
 +{
 +	TCHAR* id;
 +	MCONTACT hContact;
 +	CMsnProto* ppro;
 +
 +	InviteChatParam(const TCHAR* id, MCONTACT hContact, CMsnProto* ppro)
 +		: id(mir_tstrdup(id)), hContact(hContact), ppro(ppro) {}
 +
 +	~InviteChatParam()
 +	{ mir_free(id); }
 +};
 +
 +INT_PTR CALLBACK DlgInviteToChat(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
\ No newline at end of file diff --git a/plugins/!Deprecated/MSN/src/msn_http.cpp b/plugins/!Deprecated/MSN/src/msn_http.cpp new file mode 100644 index 0000000000..ae2f18cdf2 --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_http.cpp @@ -0,0 +1,130 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +static ThreadData* FindThreadConn(HANDLE hConn)
 +{
 +	ThreadData* res = NULL;
 +	for (int i = 0; i < g_Instances.getCount() && res == NULL; ++i)
 +		res = g_Instances[i].MSN_GetThreadByConnection(hConn);
 +
 +	return res;
 +}
 +
 +//=======================================================================================
 +// Fake function - it does nothing but confirms successful session initialization
 +//=======================================================================================
 +
 +int msn_httpGatewayInit(HANDLE hConn, NETLIBOPENCONNECTION* nloc, NETLIBHTTPREQUEST* nlhr)
 +{
 +	NETLIBHTTPPROXYINFO nlhpi = {0};
 +	nlhpi.cbSize = sizeof(nlhpi);
 +	nlhpi.szHttpGetUrl = NULL;
 +	nlhpi.szHttpPostUrl = "messenger.hotmail.com";
 +	nlhpi.flags = NLHPIF_HTTP11;
 +	nlhpi.combinePackets = MSN_PACKETS_COMBINE;
 +	return CallService(MS_NETLIB_SETHTTPPROXYINFO, (WPARAM)hConn, (LPARAM)&nlhpi);
 +}
 +
 +//=======================================================================================
 +// Prepares the szHttpPostUrl. If it's the very first send (mSessionID is void), this
 +// function generates the initial URL depending on a thread type
 +//=======================================================================================
 +
 +int msn_httpGatewayWrapSend(HANDLE hConn, PBYTE buf, int len, int flags, MIRANDASERVICE pfnNetlibSend)
 +{
 +	ThreadData* T = FindThreadConn(hConn);
 +	if (T != NULL)
 +	{
 +		if (T->sessionClosed)
 +			return SOCKET_ERROR;
 +
 +		T->applyGatewayData(hConn, len == 0);
 +	}
 +
 +	NETLIBBUFFER tBuf = { (char*)buf, len, flags };
 +	return pfnNetlibSend((LPARAM)hConn, WPARAM(&tBuf));
 +}
 +
 +//=======================================================================================
 +// Processes the results of the command execution. Parses HTTP headers to get the next
 +// SessionID & gateway IP values
 +//=======================================================================================
 +
 +PBYTE msn_httpGatewayUnwrapRecv(NETLIBHTTPREQUEST* nlhr, PBYTE buf, int len, int *outBufLen, void *(*NetlibRealloc)(void *, size_t))
 +{
 +	*outBufLen = len;
 +
 +	ThreadData* T = FindThreadConn(nlhr->nlc);
 +	if (T == NULL) return buf;
 +
 +	bool isSessionClosed = true;
 +	bool isMsnPacket = false;
 +
 +	if (nlhr->resultCode == 200)
 +	{
 +		char *xMsgr = NULL, *xHost = NULL;
 +
 +		for (int i=0; i < nlhr->headersCount; i++)
 +		{
 +			NETLIBHTTPHEADER& tHeader = nlhr->headers[i];
 +			if (_stricmp(tHeader.szName, "X-MSN-Messenger") == 0)
 +				xMsgr = tHeader.szValue;
 +			else if (_stricmp(tHeader.szName, "X-MSN-Host") == 0)
 +				xHost = tHeader.szValue;
 +
 +		}
 +
 +		if (xMsgr)
 +		{
 +			isMsnPacket = true;
 +
 +			if (strstr(xMsgr, "Session=close") == 0)
 +				isSessionClosed = false;
 +
 +			T->processSessionData(xMsgr, xHost);
 +			T->applyGatewayData(nlhr->nlc, false);
 +		}
 +	}
 +
 +	T->sessionClosed |= isSessionClosed;
 +	if (isSessionClosed && buf == NULL)
 +	{
 +		*outBufLen = 0;
 +		buf = (PBYTE)mir_alloc(1);
 +		*buf = 0;
 +	}
 +	else if (buf == NULL && len == 0)
 +	{
 +		*outBufLen = 1;
 +		buf = (PBYTE)mir_alloc(1);
 +		*buf = 0;
 +	}
 +	else if (!isMsnPacket)
 +	{
 +		*outBufLen = 0;
 +		*buf = 0;
 +	}
 +	return buf;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_libstr.cpp b/plugins/!Deprecated/MSN/src/msn_libstr.cpp new file mode 100644 index 0000000000..48296b36fb --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_libstr.cpp @@ -0,0 +1,319 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +
 +static TCHAR* a2tf(const TCHAR* str, bool unicode)
 +{
 +	if (str == NULL)
 +		return NULL;
 +
 +	return unicode ? mir_tstrdup(str) : mir_a2t((char*)str);
 +}
 +
 +void overrideStr(TCHAR*& dest, const TCHAR* src, bool unicode, const TCHAR* def)
 +{
 +	mir_free(dest);
 +	dest = NULL;
 +
 +	if (src != NULL)
 +		dest = a2tf(src, unicode);
 +	else if (def != NULL)
 +		dest = mir_tstrdup(def);
 +}
 +				
 +char* arrayToHex(BYTE* data, size_t datasz)
 +{
 +	char *res = (char*)mir_alloc(2 * datasz + 1);
 +	bin2hex(data, datasz, res);
 +	return res;
 +}
 +
 +bool txtParseParam (const char* szData, const char* presearch, const char* start, const char* finish, char* param, const int size)
 +{
 +	const char *cp, *cp1;
 +	int len;
 +
 +	if (szData == NULL) return false;
 +
 +	if (presearch != NULL) {
 +		cp1 = strstr(szData, presearch);
 +		if (cp1 == NULL) return false;
 +	}
 +	else cp1 = szData;
 +
 +	cp = strstr(cp1, start);
 +	if (cp == NULL) return false;
 +	cp += strlen(start);
 +	while (*cp == ' ') ++cp;
 +
 +	if (finish) {
 +		cp1 = strstr(cp, finish);
 +		if (cp1 == NULL) return FALSE;
 +		while (*(cp1-1) == ' ' && cp1 > cp) --cp1;
 +	}
 +	else cp1 = strchr(cp, '\0');
 +
 +	len = min(cp1 - cp, size - 1);
 +	memmove(param, cp, len);
 +	param[len] = 0;
 +
 +	return true;
 +}
 +
 +void parseWLID(char* wlid, char** net, char** email, char** inst)
 +{
 +	char *col = strchr(wlid, ':');
 +	if (col && strncmp(wlid, "tel:", 4)) {
 +		*col = 0;
 +		if (net) *net = wlid;
 +		if (email) *email = col + 1;
 +		++col;
 +	}
 +	else {
 +		if (net) *net = NULL;
 +		if (email) *email = wlid;
 +	}
 +
 +	col = strchr(wlid, ';');
 +	if (col) {
 +		*col = 0;
 +		if (inst) *inst = col + 1;
 +	}
 +	else if (inst)
 +		*inst = NULL;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// UrlDecode - converts URL chars like %20 into printable characters
 +
 +static int SingleHexToDecimal(char c)
 +{
 +	if (c >= '0' && c <= '9') return c-'0';
 +	if (c >= 'a' && c <= 'f') return c-'a'+10;
 +	if (c >= 'A' && c <= 'F') return c-'A'+10;
 +	return -1;
 +}
 +
 +template void UrlDecode(char* str);
 +template void UrlDecode(wchar_t* str);
 +
 +template <class chartype> void UrlDecode(chartype* str)
 +{
 +	chartype* s = str, *d = str;
 +
 +	while(*s) {
 +		if (*s == '%') {
 +			int digit1 = SingleHexToDecimal(s[1]);
 +			if (digit1 != -1) {
 +				int digit2 = SingleHexToDecimal(s[2]);
 +				if (digit2 != -1) {
 +					s += 3;
 +					*d++ = (char)((digit1 << 4) | digit2);
 +					continue;
 +				}
 +			}
 +		}
 +		*d++ = *s++;
 +	}
 +
 +	*d = 0;
 +}
 +
 +void HtmlDecode(char *str)
 +{
 +	if (str == NULL)
 +		return;
 +
 +	char* p, *q;
 +	for (p = q = str; *p != '\0'; p++, q++) {
 +		if (*p == '&') {
 +			if (!strncmp(p, "&", 5)) {	*q = '&'; p += 4; }
 +			else if (!strncmp(p, "'", 6)) { *q = '\''; p += 5; }
 +			else if (!strncmp(p, ">", 4)) { *q = '>'; p += 3; }
 +			else if (!strncmp(p, "<", 4)) { *q = '<'; p += 3; }
 +			else if (!strncmp(p, """, 6)) { *q = '"'; p += 5; }
 +			else { *q = *p;	}
 +		}
 +		else *q = *p;
 +	}
 +	*q = '\0';
 +}
 +
 +char* HtmlEncode(const char *str)
 +{
 +	char* s, *p, *q;
 +	int c;
 +
 +	if (str == NULL)
 +		return NULL;
 +
 +	for (c=0,p=(char*)str; *p!='\0'; p++) {
 +		switch (*p) {
 +			case '&': c += 5; break;
 +			case '\'': c += 6; break;
 +			case '>': c += 4; break;
 +			case '<': c += 4; break;
 +			case '"': c += 6; break;
 +			default: c++; break;
 +		}
 +	}
 +
 +	if ((s=(char*)mir_alloc(c+1)) != NULL) {
 +		for (p=(char*)str,q=s; *p!='\0'; p++) {
 +			switch (*p) {
 +				case '&': strcpy(q, "&"); q += 5; break;
 +				case '\'': strcpy(q, "'"); q += 6; break;
 +				case '>': strcpy(q, ">"); q += 4; break;
 +				case '<': strcpy(q, "<"); q += 4; break;
 +				case '"': strcpy(q, """); q += 6; break;
 +				default: *q = *p; q++; break;
 +			}
 +		}
 +		*q = '\0';
 +	}
 +
 +	return s;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +
 +void stripBBCode(char* src)
 +{
 +	bool tag = false;
 +	char *ps = src;
 +	char *pd = src;
 +
 +	while (*ps != 0) {
 +		if (!tag && *ps == '[') {
 +			char ch = ps[1];
 +			if (ch  == '/') ch = ps[2];
 +			tag = ch == 'b' || ch == 'u' || ch == 'i' || ch == 'c' || ch == 'a' ||  ch == 's';
 +		}
 +		if (!tag) *(pd++) = *ps;
 +		else tag = *ps != ']';
 +		++ps;
 +	}
 +	*pd = 0;
 +}
 +
 +void stripColorCode(char* src)
 +{
 +	unsigned char* ps = (unsigned char*)src;
 +	unsigned char* pd = (unsigned char*)src;
 +
 +	while (*ps != 0) {
 +		if (ps[0] == 0xc2 && ps[1] == 0xb7) {
 +			char ch = ps[2];
 +			switch (ch) {
 +			case '#':
 +			case '&':
 +			case '\'':
 +			case '@':
 +			case '0':
 +				ps += 3;
 +				continue;
 +
 +			case '$':
 +				if (isdigit(ps[3])) {
 +					ps += 3;
 +					if (isdigit(ps[1]))
 +						ps += 2;
 +					else
 +						++ps;
 +
 +					if (ps[0] == ',' && isdigit(ps[1])) {
 +						ps += 2;
 +						if (isdigit(ps[1]))
 +							ps += 2;
 +						else
 +							++ps;
 +					}
 +					continue;
 +				}
 +				else if (ps[3] == '#') {
 +					ps += 4;
 +					for (int i=0; i<6; ++i)
 +						if (isxdigit(*ps)) ++ps;
 +						else break;
 +					continue;
 +				}
 +				break;
 +			}
 +		}
 +		*(pd++) = *(ps++);
 +	}
 +	*pd = 0;
 +}
 +
 +// Process a string, and double all % characters, according to chat.dll's restrictions
 +// Returns a pointer to the new string (old one is not freed)
 +TCHAR* EscapeChatTags(const TCHAR* pszText)
 +{
 +	int nChars = 0;
 +	for (const TCHAR* p = pszText; (p = _tcschr(p, '%')) != NULL; p++)
 +		nChars++;
 +
 +	if (nChars == 0)
 +		return mir_tstrdup(pszText);
 +
 +	TCHAR *pszNewText = (TCHAR*)mir_alloc(sizeof(TCHAR)*(_tcslen(pszText) + 1 + nChars));
 +	if (pszNewText == NULL)
 +		return mir_tstrdup(pszText);
 +
 +	const TCHAR *s = pszText;
 +	TCHAR *d = pszNewText;
 +	while (*s) {
 +		if (*s == '%')
 +			*d++ = '%';
 +		*d++ = *s++;
 +	}
 +	*d = 0;
 +	return pszNewText;
 +}
 +
 +TCHAR* UnEscapeChatTags(TCHAR* str_in)
 +{
 +	TCHAR *s = str_in, *d = str_in;
 +	while (*s) {
 +		if ((*s == '%' && s[1] == '%') || (*s == '\n' && s[1] == '\n'))
 +			s++;
 +		*d++ = *s++;
 +	}
 +	*d = 0;
 +	return str_in;
 +}
 +
 +char* getNewUuid(void)
 +{
 +	UUID id;
 +	UuidCreate(&id);
 +
 +	BYTE *p;
 +	UuidToStringA(&id, &p);
 +	size_t len = strlen((char*)p) + 3;
 +	char *result = (char*)mir_alloc(len);
 +	mir_snprintf(result, len, "{%s}", p);
 +	_strupr(result);
 +	RpcStringFreeA(&p);
 +	return result;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_links.cpp b/plugins/!Deprecated/MSN/src/msn_links.cpp new file mode 100644 index 0000000000..4c3adb0a1b --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_links.cpp @@ -0,0 +1,171 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2008-2012 Boris Krasnovskiy.
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +#include <m_addcontact.h>
 +
 +#include "m_assocmgr.h"
 +
 +static HANDLE hServiceParseLink;
 +
 +static MCONTACT GetContact(TCHAR *arg, TCHAR **pemail, CMsnProto *proto)
 +{
 +	TCHAR* email = NULL;
 +	do
 +	{
 +		TCHAR *tok = _tcschr(arg, '&'); /* next token */
 +		if (tok != NULL) *tok++ = '\0';
 +
 +		if (_tcsnicmp(arg, _T("contact="), 8) == 0)
 +		{
 +			arg += 8;
 +			UrlDecode(arg);
 +			email = arg;
 +		}
 +		arg = tok;
 +	}
 +	while(arg != NULL);
 +
 +	if (email == NULL || email[0] == '\0')
 +	{
 +		if (pemail) *pemail = NULL;
 +		return NULL;
 +	}
 +	if (pemail) *pemail = email;
 +	MCONTACT hContact = proto->MSN_HContactFromEmail(UTF8(email), NULL, true, true);
 +	return hContact;
 +}
 +
 +/*
 +	add user:      msnim:add?contact=netpassport@emailaddress.com
 +	send message:  msnim:chat?contact=netpassport@emailaddress.com
 +	voice chat:    msnim:voice?contact=netpassport@emailaddress.com
 +	video chat:    msnim:video?contact=netpassport@emailaddress.com
 +*/
 +
 +static INT_PTR ServiceParseMsnimLink(WPARAM, LPARAM lParam)
 +{
 +	if (lParam == 0) return 1; /* sanity check */
 +
 +	TCHAR *arg = (TCHAR*)lParam;
 +
 +	/* skip leading prefix */
 +	arg = _tcschr(arg, ':');
 +	if (arg == NULL) return 1; /* parse failed */
 +
 +	for (++arg; *arg == '/'; ++arg) {}
 +
 +	arg = NEWTSTR_ALLOCA(arg);
 +
 +	if (g_Instances.getCount() == 0) return 0;
 +
 +	CMsnProto *proto = &g_Instances[0];
 +	for (int i = 0; i < g_Instances.getCount(); ++i)
 +	{
 +		if (g_Instances[i].m_iStatus > ID_STATUS_OFFLINE)
 +		{
 +			proto = &g_Instances[i];
 +			break;
 +		}
 +	}
 +	if (proto == NULL) return 1;
 +
 +
 +	/* add a contact to the list */
 +	if(_tcsnicmp(arg, _T("add?"), 4) == 0)
 +	{
 +		arg += 4;
 +
 +		TCHAR *email;
 +		MCONTACT hContact = GetContact(arg, &email, proto);
 +		if (email == NULL) return 1;
 +
 +		/* does not yet check if email is current user */
 +		if (hContact == NULL)
 +		{
 +			PROTOSEARCHRESULT psr = { sizeof(psr) };
 +			psr.flags = PSR_TCHAR;
 +			psr.nick = email;
 +			psr.email = email;
 +
 +			ADDCONTACTSTRUCT acs = {0};
 +			acs.handleType = HANDLE_SEARCHRESULT;
 +			acs.szProto = proto->m_szModuleName;
 +			acs.psr = &psr;
 +			CallService(MS_ADDCONTACT_SHOW, 0, (LPARAM)&acs);
 +		}
 +		return 0;
 +	}
 +	/* send a message to a contact */
 +	/* "voice" and "video" not yet implemented, perform same action as "chat" */
 +	else if(_tcsnicmp(arg, _T("chat?"), 5) == 0)
 +	{
 +		arg += 5;
 +
 +		MCONTACT hContact = GetContact(arg, NULL, proto);
 +
 +		if (hContact != NULL)
 +		{
 +			CallService(MS_MSG_SENDMESSAGE, hContact, 0);
 +			return 0;
 +		}
 +	}
 +	else if(_tcsnicmp(arg, _T("voice?"), 6) == 0)
 +	{
 +		arg += 6;
 +
 +		MCONTACT hContact = GetContact(arg, NULL, proto);
 +
 +		if (hContact != NULL)
 +		{
 +			CallService(MS_MSG_SENDMESSAGE, hContact, 0);
 +			return 0;
 +		}
 +	}
 +	else if(_tcsnicmp(arg, _T("video?"), 6) == 0)
 +	{
 +		arg += 6;
 +
 +		MCONTACT hContact = GetContact(arg, NULL, proto);
 +
 +		if (hContact != NULL)
 +		{
 +			CallService(MS_MSG_SENDMESSAGE, hContact, 0);
 +			return 0;
 +		}
 +	}
 +	return 1; /* parse failed */
 +}
 +
 +void MsnLinks_Init(void)
 +{
 +	static const char szService[] = "MSN/ParseMsnimLink";
 +
 +	hServiceParseLink = CreateServiceFunction(szService, ServiceParseMsnimLink);
 +	AssocMgr_AddNewUrlTypeT("msnim:", TranslateT("MSN Link Protocol"), hInst, IDI_MSN, szService, 0);
 +}
 +
 +void MsnLinks_Destroy(void)
 +{
 +	DestroyServiceFunction(hServiceParseLink);
 +	CallService(MS_ASSOCMGR_REMOVEURLTYPE, 0, (LPARAM)"msnim:");
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_lists.cpp b/plugins/!Deprecated/MSN/src/msn_lists.cpp new file mode 100644 index 0000000000..57a227a22f --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_lists.cpp @@ -0,0 +1,623 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +#include "m_smileyadd.h"
 +
 +void CMsnProto::Lists_Uninit(void)
 +{
 +	Lists_Wipe();
 +}
 +
 +void CMsnProto::Lists_Wipe(void)
 +{
 +	mir_cslock lck(csLists);
 +	contList.destroy();
 +}
 +
 +bool CMsnProto::Lists_IsInList(int list, const char* email)
 +{
 +	mir_cslock lck(csLists);
 +
 +	MsnContact* p = contList.find((MsnContact*)&email);
 +	bool res = p != NULL;
 +	if (res && list != -1)
 +		res &= ((p->list & list) == list);
 +	return res;
 +}
 +
 +MsnContact* CMsnProto::Lists_Get(const char* email)
 +{
 +	mir_cslock lck(csLists);
 +	return contList.find((MsnContact*)&email);
 +}
 +
 +MsnContact* CMsnProto::Lists_Get(MCONTACT hContact)
 +{
 +	mir_cslock lck(csLists);
 +
 +	for (int i = 0; i < contList.getCount(); ++i)
 +		if (contList[i].hContact == hContact)
 +			return &contList[i];
 +
 +	return NULL;
 +}
 +
 +MsnPlace* CMsnProto::Lists_GetPlace(const char* wlid)
 +{
 +	mir_cslock lck(csLists);
 +
 +	char *szEmail, *szInst;
 +	parseWLID(NEWSTR_ALLOCA(wlid), NULL, &szEmail, &szInst);
 +
 +	if (szInst == NULL)
 +		szInst = (char*)sttVoidUid;
 +
 +	MsnPlace* pl = NULL;
 +	MsnContact* p = contList.find((MsnContact*)&szEmail);
 +	if (p)
 +		pl = p->places.find((MsnPlace*)&szInst);
 +
 +	return pl;
 +}
 +
 +MsnPlace* CMsnProto::Lists_AddPlace(const char* email, const char* id, unsigned cap1, unsigned cap2)
 +{
 +	mir_cslock lck(csLists);
 +
 +	MsnPlace* pl = NULL;
 +	MsnContact* p = contList.find((MsnContact*)&email);
 +	if (p) {
 +		pl = p->places.find((MsnPlace*)&id);
 +		if (!pl) {
 +			pl = new MsnPlace;
 +
 +			pl->id = mir_strdup(id);
 +			pl->cap1 = cap1;
 +			pl->cap2 = cap2;
 +			pl->p2pMsgId = 0;
 +			pl->p2pPktNum = 0;
 +			p->places.insert(pl);
 +		}
 +	}
 +
 +	return pl;
 +}
 +
 +MsnContact* CMsnProto::Lists_GetNext(int& i)
 +{
 +	MsnContact* p = NULL;
 +
 +	mir_cslock lck(csLists);
 +
 +	while (p == NULL && ++i < contList.getCount())
 +		if (contList[i].hContact)
 +			p = &contList[i];
 +
 +	return p;
 +}
 +
 +int CMsnProto::Lists_GetMask(const char* email)
 +{
 +	mir_cslock lck(csLists);
 +
 +	MsnContact* p = contList.find((MsnContact*)&email);
 +	return p ? p->list : 0;
 +}
 +
 +int CMsnProto::Lists_GetNetId(const char* email)
 +{
 +	if (email[0] == 0) return NETID_UNKNOWN;
 +
 +	mir_cslock lck(csLists);
 +
 +	MsnContact* p = contList.find((MsnContact*)&email);
 +	return p ? p->netId : NETID_UNKNOWN;
 +}
 +
 +unsigned CMsnProto::p2p_getMsgId(const char* wlid, int inc)
 +{
 +	mir_cslock lck(csLists);
 +	MsnPlace* p = Lists_GetPlace(wlid);
 +
 +	unsigned res = p && p->p2pMsgId ? p->p2pMsgId : MSN_GenRandom();
 +	if (p)
 +		p->p2pMsgId = res + inc;
 +
 +	return res;
 +}
 +
 +unsigned CMsnProto::p2p_getPktNum(const char* wlid)
 +{
 +	mir_cslock lck(csLists);
 +
 +	MsnPlace* p = Lists_GetPlace(wlid);
 +	return p ? p->p2pPktNum++ : 0;
 +}
 +
 +int CMsnProto::Lists_Add(int list, int netId, const char* email, MCONTACT hContact, const char* nick, const char* invite)
 +{
 +	mir_cslock lck(csLists);
 +
 +	MsnContact* p = contList.find((MsnContact*)&email);
 +	if (p == NULL) {
 +		p = new MsnContact;
 +		p->list = list;
 +		p->netId = netId;
 +		p->email = _strlwr(mir_strdup(email));
 +		p->invite = mir_strdup(invite);
 +		p->nick = mir_strdup(nick);
 +		p->hContact = hContact;
 +		p->p2pMsgId = 0;
 +		contList.insert(p);
 +	}
 +	else {
 +		p->list |= list;
 +		if (invite) replaceStr(p->invite, invite);
 +		if (hContact) p->hContact = hContact;
 +		if (list & LIST_FL) p->netId = netId;
 +		if (p->netId == NETID_UNKNOWN && netId != NETID_UNKNOWN)
 +			p->netId = netId;
 +	}
 +	return p->list;
 +}
 +
 +void CMsnProto::Lists_Remove(int list, const char* email)
 +{
 +	mir_cslock lck(csLists);
 +
 +	int i = contList.getIndex((MsnContact*)&email);
 +	if (i != -1) {
 +		MsnContact &p = contList[i];
 +		p.list &= ~list;
 +		if (list & LIST_PL) { mir_free(p.invite); p.invite = NULL; }
 +		if (p.list == 0 && p.hContact == NULL)
 +			contList.remove(i);
 +	}
 +}
 +
 +
 +void CMsnProto::Lists_Populate(void)
 +{
 +	MCONTACT hContact = db_find_first(m_szModuleName);
 +	while (hContact) {
 +		MCONTACT hNext = db_find_next(hContact, m_szModuleName);
 +		char szEmail[MSN_MAX_EMAIL_LEN] = "";
 +		if (db_get_static(hContact, m_szModuleName, "wlid", szEmail, sizeof(szEmail)))
 +			db_get_static(hContact, m_szModuleName, "e-mail", szEmail, sizeof(szEmail));
 +		if (szEmail[0]) {
 +			bool localList = getByte(hContact, "LocalList", 0) != 0;
 +			if (localList)
 +				Lists_Add(LIST_LL, NETID_MSN, szEmail, hContact);
 +			else
 +				Lists_Add(0, NETID_UNKNOWN, szEmail, hContact);
 +		}
 +		else CallService(MS_DB_CONTACT_DELETE, hContact, 0);
 +		hContact = hNext;
 +	}
 +}
 +
 +void CMsnProto::MSN_CleanupLists(void)
 +{
 +	for (int i = contList.getCount(); i--;) {
 +		MsnContact& p = contList[i];
 +		if (p.list & LIST_FL)
 +			MSN_SetContactDb(p.hContact, p.email);
 +
 +		if (p.list & LIST_PL) {
 +			if (p.list & (LIST_AL | LIST_BL))
 +				MSN_AddUser(NULL, p.email, p.netId, LIST_PL + LIST_REMOVE);
 +			else
 +				MSN_AddAuthRequest(p.email, p.nick, p.invite);
 +		}
 +
 +		if (p.hContact && !(p.list & (LIST_LL | LIST_FL | LIST_PL)) && p.list != LIST_RL) {
 +			int count = db_event_count(p.hContact);
 +			if (count) {
 +				TCHAR text[256];
 +				TCHAR *sze = mir_a2t(p.email);
 +				mir_sntprintf(text, SIZEOF(text), TranslateT("Contact %s has been removed from the server.\nWould you like to keep it as \"Local Only\" contact to preserve history?"), sze);
 +				mir_free(sze);
 +
 +				TCHAR title[128];
 +				mir_sntprintf(title, SIZEOF(title), TranslateT("%s protocol"), m_tszUserName);
 +
 +				if (MessageBox(NULL, text, title, MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND) == IDYES) {
 +					MSN_AddUser(p.hContact, p.email, 0, LIST_LL);
 +					setByte(p.hContact, "LocalList", 1);
 +					continue;
 +				}
 +			}
 +
 +			if (!(p.list & (LIST_LL | LIST_FL))) {
 +				CallService(MS_DB_CONTACT_DELETE, (WPARAM)p.hContact, 0);
 +				p.hContact = NULL;
 +			}
 +		}
 +
 +		if (p.list & (LIST_LL | LIST_FL) && p.hContact) {
 +			TCHAR path[MAX_PATH];
 +			MSN_GetCustomSmileyFileName(p.hContact, path, SIZEOF(path), "", 0);
 +			if (path[0]) {
 +				SMADD_CONT cont;
 +				cont.cbSize = sizeof(SMADD_CONT);
 +				cont.hContact = p.hContact;
 +				cont.type = 0;
 +				cont.path = path;
 +
 +				CallService(MS_SMILEYADD_LOADCONTACTSMILEYS, 0, (LPARAM)&cont);
 +			}
 +		}
 +	}
 +}
 +
 +void CMsnProto::MSN_CreateContList(void)
 +{
 +	bool *used = (bool*)mir_calloc(contList.getCount()*sizeof(bool));
 +
 +	char cxml[8192];
 +
 +	size_t sz = mir_snprintf(cxml, sizeof(cxml), "<ml l=\"1\">");
 +	{
 +		mir_cslock lck(csLists);
 +
 +		for (int i = 0; i < contList.getCount(); i++) {
 +			if (used[i]) continue;
 +
 +			const char* lastds = strchr(contList[i].email, '@');
 +			bool newdom = true;
 +
 +			for (int j = 0; j < contList.getCount(); j++) {
 +				if (used[j]) continue;
 +
 +				const MsnContact& C = contList[j];
 +				if (C.list == LIST_RL || C.list == LIST_PL || C.list == LIST_LL) {
 +					used[j] = true;
 +					continue;
 +				}
 +
 +				const char *dom = strchr(C.email, '@');
 +				if (dom == NULL && lastds == NULL) {
 +					if (sz == 0) sz = mir_snprintf(cxml + sz, sizeof(cxml), "<ml l=\"1\">");
 +					if (newdom) {
 +						sz += mir_snprintf(cxml + sz, sizeof(cxml) - sz, "<t>");
 +						newdom = false;
 +					}
 +
 +					sz += mir_snprintf(cxml + sz, sizeof(cxml) - sz, "<c n=\"%s\" l=\"%d\"/>", C.email, C.list & ~(LIST_RL | LIST_LL));
 +					used[j] = true;
 +				}
 +				else if (dom != NULL && lastds != NULL && _stricmp(lastds, dom) == 0) {
 +					if (sz == 0) sz = mir_snprintf(cxml, sizeof(cxml), "<ml l=\"1\">");
 +					if (newdom) {
 +						sz += mir_snprintf(cxml + sz, sizeof(cxml) - sz, "<d n=\"%s\">", lastds + 1);
 +						newdom = false;
 +					}
 +
 +					*(char*)dom = 0;
 +					sz += mir_snprintf(cxml + sz, sizeof(cxml) - sz, "<c n=\"%s\" l=\"%d\" t=\"%d\"/>", C.email, C.list & ~(LIST_RL | LIST_LL), C.netId);
 +					*(char*)dom = '@';
 +					used[j] = true;
 +				}
 +
 +				if (used[j] && sz > 7400) {
 +					sz += mir_snprintf(cxml + sz, sizeof(cxml) - sz, "</%c></ml>", lastds ? 'd' : 't');
 +					msnNsThread->sendPacket("ADL", "%d\r\n%s", sz, cxml);
 +					sz = 0;
 +					newdom = true;
 +				}
 +			}
 +			if (!newdom)
 +				sz += mir_snprintf(cxml + sz, sizeof(cxml) - sz, lastds ? "</d>" : "</t>");
 +		}
 +	}
 +
 +	if (sz) {
 +		sz += mir_snprintf(cxml + sz, sizeof(cxml) - sz, "</ml>");
 +		msnNsThread->sendPacket("ADL", "%d\r\n%s", sz, cxml);
 +	}
 +
 +	mir_free(used);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN Server List Manager dialog procedure
 +
 +static void AddPrivacyListEntries(HWND hwndList, CMsnProto *proto)
 +{
 +	CLCINFOITEM cii = { 0 };
 +	cii.cbSize = sizeof(cii);
 +	cii.flags = CLCIIF_BELOWCONTACTS;
 +
 +	// Delete old info
 +	HANDLE hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_ROOT, 0);
 +	while (hItem) {
 +		HANDLE hItemNext = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXT, (LPARAM)hItem);
 +
 +		if (IsHContactInfo(hItem))
 +			SendMessage(hwndList, CLM_DELETEITEM, (WPARAM)hItem, 0);
 +
 +		hItem = hItemNext;
 +	}
 +
 +	// Add new info
 +	for (int i = 0; i < proto->contList.getCount(); ++i) {
 +		MsnContact &cont = proto->contList[i];
 +		if (!(cont.list & (LIST_FL | LIST_LL))) {
 +			cii.pszText = (TCHAR*)cont.email;
 +			HANDLE hItem = (HANDLE)SendMessage(hwndList, CLM_ADDINFOITEMA, 0, (LPARAM)&cii);
 +
 +			SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(0, (cont.list & LIST_LL) ? 1 : 0));
 +			SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(1, (cont.list & LIST_FL) ? 2 : 0));
 +			SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(2, (cont.list & LIST_AL) ? 3 : 0));
 +			SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(3, (cont.list & LIST_BL) ? 4 : 0));
 +			SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(4, (cont.list & LIST_RL) ? 5 : 0));
 +		}
 +	}
 +}
 +
 +static void SetContactIcons(MCONTACT hItem, HWND hwndList, CMsnProto* proto)
 +{
 +	if (!proto->MSN_IsMyContact(hItem)) {
 +		SendMessage(hwndList, CLM_DELETEITEM, (WPARAM)hItem, 0);
 +		return;
 +	}
 +
 +	char szEmail[MSN_MAX_EMAIL_LEN];
 +	if (db_get_static(hItem, proto->m_szModuleName, "e-mail", szEmail, sizeof(szEmail))) {
 +		SendMessage(hwndList, CLM_DELETEITEM, (WPARAM)hItem, 0);
 +		return;
 +	}
 +
 +	DWORD dwMask = proto->Lists_GetMask(szEmail);
 +	SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(0, (dwMask & LIST_LL) ? 1 : 0));
 +	SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(1, (dwMask & LIST_FL) ? 2 : 0));
 +	SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(2, (dwMask & LIST_AL) ? 3 : 0));
 +	SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(3, (dwMask & LIST_BL) ? 4 : 0));
 +	SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(4, (dwMask & LIST_RL) ? 5 : 0));
 +}
 +
 +static void SetAllContactIcons(MCONTACT hItem, HWND hwndList, CMsnProto* proto)
 +{
 +	if (hItem == NULL)
 +		hItem = (MCONTACT)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_ROOT, 0);
 +
 +	while (hItem) {
 +		MCONTACT hItemN = (MCONTACT)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXT, (LPARAM)hItem);
 +
 +		if (IsHContactGroup(hItem)) {
 +			MCONTACT hItemT = (MCONTACT)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem);
 +			if (hItemT)
 +				SetAllContactIcons(hItemT, hwndList, proto);
 +		}
 +		else if (IsHContactContact(hItem))
 +			SetContactIcons(hItem, hwndList, proto);
 +
 +		hItem = hItemN;
 +	}
 +}
 +
 +static void SaveListItem(MCONTACT hContact, const char* szEmail, int list, int iPrevValue, int iNewValue, CMsnProto* proto)
 +{
 +	if (iPrevValue == iNewValue)
 +		return;
 +
 +	if (iNewValue == 0) {
 +		if (list & LIST_FL) {
 +			DeleteParam param = { proto, hContact };
 +			DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_DELETECONTACT), NULL, DlgDeleteContactUI, (LPARAM)¶m);
 +			return;
 +		}
 +
 +		list |= LIST_REMOVE;
 +	}
 +
 +	proto->MSN_AddUser(hContact, szEmail, proto->Lists_GetNetId(szEmail), list);
 +}
 +
 +static void SaveSettings(MCONTACT hItem, HWND hwndList, CMsnProto* proto)
 +{
 +	if (hItem == NULL)
 +		hItem = (MCONTACT)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_ROOT, 0);
 +
 +	while (hItem) {
 +		if (IsHContactGroup(hItem)) {
 +			MCONTACT hItemT = (MCONTACT)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem);
 +			if (hItemT)
 +				SaveSettings(hItemT, hwndList, proto);
 +		}
 +		else {
 +			char szEmail[MSN_MAX_EMAIL_LEN];
 +
 +			if (IsHContactContact(hItem)) {
 +				if (db_get_static(hItem, proto->m_szModuleName, "e-mail", szEmail, sizeof(szEmail)))
 +					continue;
 +			}
 +			else if (IsHContactInfo(hItem)) {
 +				TCHAR buf[MSN_MAX_EMAIL_LEN];
 +				SendMessage(hwndList, CLM_GETITEMTEXT, (WPARAM)hItem, (LPARAM)buf);
 +				WideCharToMultiByte(CP_ACP, 0, buf, -1, szEmail, sizeof(szEmail), 0, 0);
 +
 +			}
 +
 +			int dwMask = proto->Lists_GetMask(szEmail);
 +			SaveListItem(hItem, szEmail, LIST_LL, (dwMask & LIST_LL) ? 1 : 0, SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(0, 0)), proto);
 +			SaveListItem(hItem, szEmail, LIST_FL, (dwMask & LIST_FL) ? 2 : 0, SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(1, 0)), proto);
 +			SaveListItem(hItem, szEmail, LIST_AL, (dwMask & LIST_AL) ? 3 : 0, SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(2, 0)), proto);
 +			SaveListItem(hItem, szEmail, LIST_BL, (dwMask & LIST_BL) ? 4 : 0, SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(3, 0)), proto);
 +
 +			int newMask = proto->Lists_GetMask(szEmail);
 +			int xorMask = newMask ^ dwMask;
 +
 +			if (xorMask && newMask & (LIST_FL | LIST_LL)) {
 +				MCONTACT hContact = IsHContactInfo(hItem) ? proto->MSN_HContactFromEmail(szEmail, szEmail, true, false) : hItem;
 +				proto->MSN_SetContactDb(hContact, szEmail);
 +			}
 +
 +			if (xorMask & (LIST_FL | LIST_LL) && !(newMask & (LIST_FL | LIST_LL))) {
 +				if (!IsHContactInfo(hItem)) {
 +					CallService(MS_DB_CONTACT_DELETE, (WPARAM)hItem, 0);
 +					MsnContact* msc = proto->Lists_Get(szEmail);
 +					if (msc) msc->hContact = NULL;
 +				}
 +			}
 +		}
 +		hItem = (MCONTACT)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXT, (LPARAM)hItem);
 +	}
 +}
 +
 +INT_PTR CALLBACK DlgProcMsnServLists(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 +{
 +	CMsnProto *proto = (CMsnProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 +
 +	switch (msg) {
 +	case WM_INITDIALOG:
 +		TranslateDialogDefault(hwndDlg);
 +		{
 +			SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
 +
 +			HIMAGELIST hIml = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_MASK | ILC_COLOR32, 5, 5);
 +
 +			HICON hIcon = LoadSkinnedIcon(SKINICON_OTHER_SMALLDOT);
 +			ImageList_AddIcon(hIml, hIcon);
 +			Skin_ReleaseIcon(hIcon);
 +
 +			hIcon = LoadIconEx("list_lc");
 +			ImageList_AddIcon(hIml, hIcon);
 +			SendDlgItemMessage(hwndDlg, IDC_ICON_LC, STM_SETICON, (WPARAM)hIcon, 0);
 +
 +			hIcon = LoadIconEx("list_fl");
 +			ImageList_AddIcon(hIml, hIcon);
 +			SendDlgItemMessage(hwndDlg, IDC_ICON_FL, STM_SETICON, (WPARAM)hIcon, 0);
 +
 +			hIcon = LoadIconEx("list_al");
 +			ImageList_AddIcon(hIml, hIcon);
 +			SendDlgItemMessage(hwndDlg, IDC_ICON_AL, STM_SETICON, (WPARAM)hIcon, 0);
 +
 +			hIcon = LoadIconEx("list_bl");
 +			ImageList_AddIcon(hIml, hIcon);
 +			SendDlgItemMessage(hwndDlg, IDC_ICON_BL, STM_SETICON, (WPARAM)hIcon, 0);
 +
 +			hIcon = LoadIconEx("list_rl");
 +			ImageList_AddIcon(hIml, hIcon);
 +			SendDlgItemMessage(hwndDlg, IDC_ICON_RL, STM_SETICON, (WPARAM)hIcon, 0);
 +
 +			HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST);
 +
 +			SendMessage(hwndList, CLM_SETEXTRAIMAGELIST, 0, (LPARAM)hIml);
 +			SendMessage(hwndList, CLM_SETEXTRACOLUMNS, 5, 0);
 +
 +			EnableWindow(hwndList, ((CMsnProto*)lParam)->msnLoggedIn);
 +		}
 +		return TRUE;
 +
 +//	case WM_SETFOCUS:
 +//		SetFocus(GetDlgItem(hwndDlg ,IDC_LIST));
 +//		break;
 +
 +	case WM_COMMAND:
 +		if (LOWORD(wParam) == IDC_LISTREFRESH)
 +		{
 +			HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST);
 +			SendMessage(hwndList, CLM_AUTOREBUILD, 0, 0);
 +
 +			CMsnProto* proto = (CMsnProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 +			EnableWindow(hwndList, proto->msnLoggedIn);
 +		}
 +		break;
 +
 +	case WM_NOTIFY:
 +	{
 +		CMsnProto* proto = (CMsnProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 +
 +		NMCLISTCONTROL* nmc = (NMCLISTCONTROL*)lParam;
 +		if (nmc->hdr.idFrom == 0 && nmc->hdr.code == (unsigned)PSN_APPLY)
 +		{
 +			HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST);
 +			SaveSettings(NULL, hwndList, proto);
 +			SendMessage(hwndList, CLM_AUTOREBUILD, 0, 0);
 +			EnableWindow(hwndList, proto->msnLoggedIn);
 +		}
 +		else if (nmc->hdr.idFrom == IDC_LIST)
 +		{
 +			switch (nmc->hdr.code)
 +			{
 +			case CLN_NEWCONTACT:
 +				if ((nmc->flags & (CLNF_ISGROUP | CLNF_ISINFO)) == 0)
 +					SetContactIcons((MCONTACT)nmc->hItem, nmc->hdr.hwndFrom, proto);
 +				break;
 +
 +			case CLN_LISTREBUILT:
 +				AddPrivacyListEntries(nmc->hdr.hwndFrom, proto);
 +				SetAllContactIcons(NULL, nmc->hdr.hwndFrom, proto);
 +				break;
 +
 +			case NM_CLICK:
 +				HANDLE hItem;
 +				DWORD hitFlags;
 +				int iImage;
 +
 +				// Make sure we have an extra column, also we can't change RL list
 +				if (nmc->iColumn == -1 || nmc->iColumn == 4)
 +					break;
 +
 +				// Find clicked item
 +				hItem = (HANDLE)SendMessage(nmc->hdr.hwndFrom, CLM_HITTEST, (WPARAM)&hitFlags, MAKELPARAM(nmc->pt.x,nmc->pt.y));
 +
 +				// Nothing was clicked
 +				if (hItem == NULL || !(IsHContactContact(hItem) || IsHContactInfo(hItem)))
 +					break;
 +
 +				// It was not our extended icon
 +				if (!(hitFlags & CLCHT_ONITEMEXTRA))
 +					break;
 +
 +				// Get image in clicked column (0=none, 1=LL, 2=FL, 3=AL, 4=BL, 5=RL)
 +				iImage = SendMessage(nmc->hdr.hwndFrom, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nmc->iColumn, 0));
 +				iImage = iImage ? 0 : nmc->iColumn + 1;
 +
 +				SendMessage(nmc->hdr.hwndFrom, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nmc->iColumn, iImage));
 +				if (iImage && SendMessage(nmc->hdr.hwndFrom, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nmc->iColumn ^ 1, 0)) != EMPTY_EXTRA_ICON)
 +					if (nmc->iColumn == 2 || nmc->iColumn == 3)
 +						SendMessage(nmc->hdr.hwndFrom, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nmc->iColumn ^ 1, 0));
 +
 +				// Activate Apply button
 +				SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
 +				break;
 +			}
 +		}
 +	}
 +	break;
 +
 +	case WM_DESTROY:
 +		HIMAGELIST hIml=(HIMAGELIST)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETEXTRAIMAGELIST,0,0);
 +		ImageList_Destroy(hIml);
 +		ReleaseIconEx("list_fl");
 +		ReleaseIconEx("list_al");
 +		ReleaseIconEx("list_bl");
 +		ReleaseIconEx("list_rl");
 +		break;
 +	}
 +
 +	return FALSE;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_mail.cpp b/plugins/!Deprecated/MSN/src/msn_mail.cpp new file mode 100644 index 0000000000..407375bf17 --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_mail.cpp @@ -0,0 +1,424 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2007-2012 Boris Krasnovskiy.
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +static const char oimRecvUrl[] = "https://rsi.hotmail.com/rsi/rsi.asmx";
 +static const char mailReqHdr[] =
 +	"SOAPAction: \"http://www.hotmail.msn.com/ws/2004/09/oim/rsi/%s\"\r\n";
 +
 +ezxml_t CMsnProto::oimRecvHdr(const char* service, ezxml_t& tbdy, char*& httphdr)
 +{
 +	ezxml_t xmlp = ezxml_new("soap:Envelope");
 +	ezxml_set_attr(xmlp, "xmlns:xsi",  "http://www.w3.org/2001/XMLSchema-instance");
 +	ezxml_set_attr(xmlp, "xmlns:xsd",  "http://www.w3.org/2001/XMLSchema");
 +	ezxml_set_attr(xmlp, "xmlns:soap", "http://schemas.xmlsoap.org/soap/envelope/");
 +
 +	ezxml_t hdr = ezxml_add_child(xmlp, "soap:Header", 0);
 +	ezxml_t cook = ezxml_add_child(hdr, "PassportCookie", 0);
 +	ezxml_set_attr(cook, "xmlns", "http://www.hotmail.msn.com/ws/2004/09/oim/rsi");
 +	ezxml_t tcook = ezxml_add_child(cook, "t", 0);
 +	ezxml_set_txt(tcook, tAuthToken ? tAuthToken : "");
 +	ezxml_t pcook = ezxml_add_child(cook, "p", 0);
 +	ezxml_set_txt(pcook, pAuthToken ? pAuthToken : "");
 +
 +	ezxml_t bdy = ezxml_add_child(xmlp, "soap:Body", 0);
 +
 +	tbdy = ezxml_add_child(bdy, service, 0);
 +	ezxml_set_attr(tbdy, "xmlns", "http://www.hotmail.msn.com/ws/2004/09/oim/rsi");
 +
 +	size_t hdrsz = strlen(service) + sizeof(mailReqHdr) + 20;
 +	httphdr = (char*)mir_alloc(hdrsz);
 +
 +	mir_snprintf(httphdr, hdrsz, mailReqHdr, service);
 +
 +	return xmlp;
 +}
 +
 +
 +void CMsnProto::getOIMs(ezxml_t xmli)
 +{
 +	ezxml_t toki = ezxml_child(xmli, "M");
 +	if (toki == NULL) return;
 +
 +	char* getReqHdr;
 +	ezxml_t reqmsg;
 +	ezxml_t xmlreq = oimRecvHdr("GetMessage", reqmsg, getReqHdr);
 +
 +	ezxml_t reqmid = ezxml_add_child(reqmsg, "messageId", 0);
 +	ezxml_t reqmrk = ezxml_add_child(reqmsg, "alsoMarkAsRead", 0);
 +	ezxml_set_txt(reqmrk, "false");
 +
 +	char* delReqHdr;
 +	ezxml_t delmsg;
 +	ezxml_t xmldel = oimRecvHdr("DeleteMessages", delmsg, delReqHdr);
 +	ezxml_t delmids = ezxml_add_child(delmsg, "messageIds", 0);
 +
 +	while (toki != NULL)
 +	{
 +		const char* szId    = ezxml_txt(ezxml_child(toki, "I"));
 +		const char* szEmail = ezxml_txt(ezxml_child(toki, "E"));
 +
 +		ezxml_set_txt(reqmid, szId);
 +		char* szData = ezxml_toxml(xmlreq, true);
 +
 +		unsigned status;
 +		char* url = (char*)mir_strdup(oimRecvUrl);
 +
 +		char* tResult = getSslResult(&url, szData, getReqHdr, status);
 +
 +		free(szData);
 +		mir_free(url);
 +
 +		if (tResult != NULL && status == 200)
 +		{
 +			ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +			ezxml_t body = getSoapResponse(xmlm, "GetMessage");
 +
 +			MimeHeaders mailInfo;
 +			const char* mailbody = mailInfo.readFromBuffer((char*)ezxml_txt(body));
 +
 +			time_t evtm = time(NULL);
 +			const char* arrTime = mailInfo["X-OriginalArrivalTime"];
 +			if (arrTime != NULL)
 +			{
 +				char szTime[32], *p;
 +				txtParseParam(arrTime, "FILETIME", "[", "]", szTime, sizeof(szTime));
 +
 +				unsigned filetimeLo = strtoul(szTime, &p, 16);
 +				if (*p == ':')
 +				{
 +					unsigned __int64 filetime = strtoul(p+1, &p, 16);
 +					filetime <<= 32;
 +					filetime |= filetimeLo;
 +					filetime /= 10000000;
 +#ifndef __GNUC__
 +					filetime -= 11644473600ui64;
 +#else
 +					filetime -= 11644473600ull;
 +#endif
 +					evtm = (time_t)filetime;
 +				}
 +			}
 +
 +			PROTORECVEVENT pre = {0};
 +			pre.szMessage = mailInfo.decodeMailBody((char*)mailbody);
 +			pre.flags = PREF_UTF /*+ ((isRtl) ? PREF_RTL : 0)*/;
 +			pre.timestamp = evtm;
 +			ProtoChainRecvMsg( MSN_HContactFromEmail(szEmail), &pre);
 +			mir_free(pre.szMessage);
 +
 +			ezxml_t delmid = ezxml_add_child(delmids, "messageId", 0);
 +			ezxml_set_txt(delmid, szId);
 +
 +			ezxml_free(xmlm);
 +		}
 +		mir_free(tResult);
 +		toki = ezxml_next(toki);
 +	}
 +	ezxml_free(xmlreq);
 +	mir_free(getReqHdr);
 +
 +	if (ezxml_child(delmids, "messageId") != NULL)
 +	{
 +		char* szData = ezxml_toxml(xmldel, true);
 +
 +		unsigned status;
 +		char* url = (char*)mir_strdup(oimRecvUrl);
 +
 +		char* tResult = getSslResult(&url, szData, delReqHdr, status);
 +
 +		mir_free(url);
 +		mir_free(tResult);
 +		free(szData);
 +	}
 +	ezxml_free(xmldel);
 +	mir_free(delReqHdr);
 +}
 +
 +
 +void CMsnProto::getMetaData(void)
 +{
 +	char* getReqHdr;
 +	ezxml_t reqbdy;
 +	ezxml_t xmlreq = oimRecvHdr("GetMetadata", reqbdy, getReqHdr);
 +
 +	char* szData = ezxml_toxml(xmlreq, true);
 +	ezxml_free(xmlreq);
 +
 +	unsigned status;
 +	char* url = (char*)mir_strdup(oimRecvUrl);
 +
 +	char* tResult = getSslResult(&url, szData, getReqHdr, status);
 +
 +	mir_free(url);
 +	free(szData);
 +	mir_free(getReqHdr);
 +
 +	if (tResult != NULL && status == 200)
 +	{
 +		ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +		ezxml_t xmli = ezxml_get(xmlm, "s:Body", 0, "GetMetadataResponse", 0, "MD", -1);
 +		if (!xmli)
 +			xmli = ezxml_get(xmlm, "soap:Body", 0, "GetMetadataResponse", 0, "MD", -1);
 +
 +		getOIMs(xmli);
 +		ezxml_free(xmlm);
 +	}
 +	mir_free(tResult);
 +}
 +
 +
 +void CMsnProto::processMailData(char* mailData)
 +{
 +	if (strcmp(mailData, "too-large") == 0)
 +	{
 +		getMetaData();
 +	}
 +	else
 +	{
 +		ezxml_t xmli = ezxml_parse_str(mailData, strlen(mailData));
 +
 +		ezxml_t toke = ezxml_child(xmli, "E");
 +
 +		const char* szIU = ezxml_txt(ezxml_child(toke, "IU"));
 +		if (*szIU) mUnreadMessages = atol(szIU);
 +
 +		const char* szOU = ezxml_txt(ezxml_child(toke, "OU"));
 +		if (*szOU) mUnreadJunkEmails = atol(szOU);
 +
 +		getOIMs(xmli);
 +
 +		ezxml_free(xmli);
 +	}
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// Processes e-mail notification
 +
 +void CMsnProto::sttNotificationMessage(char* msgBody, bool isInitial)
 +{
 +	TCHAR tBuffer[512];
 +	TCHAR tBuffer2[512];
 +	int  UnreadMessages = mUnreadMessages;
 +	int  UnreadJunkEmails = mUnreadJunkEmails;
 +	bool ShowPopup = isInitial;
 +
 +	MimeHeaders tFileInfo;
 +	tFileInfo.readFromBuffer(msgBody);
 +
 +	const char* From = tFileInfo["From"];
 +	const char* Subject = tFileInfo["Subject"];
 +	const char* Fromaddr = tFileInfo["From-Addr"];
 +	const char* MsgDelta = tFileInfo["Message-Delta"];
 +	const char* SrcFolder = tFileInfo["Src-Folder"];
 +	const char* DestFolder = tFileInfo["Dest-Folder"];
 +	const char* InboxUnread = tFileInfo["Inbox-Unread"];
 +	const char* FoldersUnread = tFileInfo["Folders-Unread"];
 +
 +	if (InboxUnread != NULL)
 +		mUnreadMessages = atol(InboxUnread);
 +	if (FoldersUnread != NULL)
 +		mUnreadJunkEmails = atol(FoldersUnread);
 +
 +	if (MsgDelta != NULL)
 +	{
 +		int iDelta = atol(MsgDelta);
 +		if (SrcFolder && strcmp(SrcFolder, "ACTIVE") == 0)
 +			mUnreadMessages -= iDelta;
 +		else if (DestFolder && strcmp(DestFolder, "ACTIVE") == 0)
 +			mUnreadMessages += iDelta;
 +		if (SrcFolder && strcmp(SrcFolder, "HM_BuLkMail_") == 0)
 +			mUnreadJunkEmails -= iDelta;
 +		else if (DestFolder && strcmp(DestFolder, "HM_BuLkMail_") == 0)
 +			mUnreadJunkEmails += iDelta;
 +
 +		if (mUnreadJunkEmails < 0) mUnreadJunkEmails = 0;
 +		if (mUnreadMessages < 0) mUnreadMessages = 0;
 +	}
 +
 +	if (From != NULL && Subject != NULL && Fromaddr != NULL)
 +	{
 +		if (DestFolder != NULL && SrcFolder == NULL)
 +		{
 +			mUnreadMessages += strcmp(DestFolder, "ACTIVE") == 0;
 +			mUnreadJunkEmails += strcmp(DestFolder, "HM_BuLkMail_") == 0;
 +		}
 +
 +		wchar_t* mimeFromW = tFileInfo.decode(From);
 +		wchar_t* mimeSubjectW = tFileInfo.decode(Subject);
 +
 +
 +		mir_sntprintf(tBuffer2, SIZEOF(tBuffer2), TranslateT("Subject: %s"), mimeSubjectW);
 +
 +
 +
 +		TCHAR* msgtxt = _stricmp(From, Fromaddr) ?
 +			TranslateT("Hotmail from %s (%S)") : TranslateT("Hotmail from %s");
 +
 +		mir_sntprintf(tBuffer, SIZEOF(tBuffer), msgtxt, mimeFromW, Fromaddr);
 +		mir_free(mimeFromW);
 +		mir_free(mimeSubjectW);
 +		ShowPopup = true;
 +	}
 +	else
 +	{
 +		const char* MailData = tFileInfo["Mail-Data"];
 +		if (MailData != NULL) processMailData((char*)MailData);
 +
 +		mir_sntprintf(tBuffer, SIZEOF(tBuffer), m_tszUserName);
 +		mir_sntprintf(tBuffer2, SIZEOF(tBuffer2), TranslateT("Unread mail is available: %d in Inbox and %d in other folders."), mUnreadMessages, mUnreadJunkEmails);
 +	}
 +
 +	if (UnreadMessages == mUnreadMessages && UnreadJunkEmails == mUnreadJunkEmails  && !isInitial)
 +		return;
 +
 +	ShowPopup &= mUnreadMessages != 0 || (mUnreadJunkEmails != 0 && !getByte("DisableHotmailJunk", 0));
 +
 +	MCONTACT hContact = MSN_HContactFromEmail(MyOptions.szEmail);
 +	if (hContact)
 +	{
 +		CallService(MS_CLIST_REMOVEEVENT, hContact, (LPARAM) 1);
 +		displayEmailCount(hContact);
 +
 +		if (ShowPopup && !getByte("DisableHotmailTray", 1))
 +		{
 +			CLISTEVENT cle = {0};
 +
 +			cle.cbSize = sizeof(cle);
 +			cle.hContact = hContact;
 +			cle.hDbEvent = (HANDLE) 1;
 +			cle.flags = CLEF_URGENT | CLEF_TCHAR;
 +			cle.hIcon = LoadSkinnedIcon(SKINICON_OTHER_SENDEMAIL);
 +			cle.ptszTooltip = tBuffer2;
 +			char buf[64];
 +			mir_snprintf(buf, SIZEOF(buf), "%s%s", m_szModuleName, MS_GOTO_INBOX);
 +			cle.pszService = buf;
 +
 +			CallService(MS_CLIST_ADDEVENT, hContact, (LPARAM)&cle);
 +		}
 +	}
 +
 +	ProtoBroadcastAck(NULL, ACKTYPE_EMAIL, ACKRESULT_STATUS, NULL, 0);
 +
 +	// Disable to notify receiving hotmail
 +	if (ShowPopup && !getByte("DisableHotmail", 0))
 +	{
 +		SkinPlaySound(mailsoundname);
 +
 +		const char *msgurl = tFileInfo["Message-URL"];
 +		if (msgurl)
 +		{
 +			const char *p = strchr(msgurl, '&'); if (p) *(char*)p = 0;
 +			p = strstr(msgurl, "getmsg"); if (p) msgurl = p;
 +		}
 +		else
 +			msgurl = "inbox";
 +
 +		char szUrl[256];
 +		mir_snprintf(szUrl, sizeof(szUrl), "http://mail.live.com?rru=%s", msgurl);
 +
 +		MSN_ShowPopup(tBuffer, tBuffer2,
 +			MSN_ALLOW_ENTER | MSN_ALLOW_MSGBOX | MSN_HOTMAIL_POPUP,
 +			szUrl);
 +	}
 +
 +	if (!getByte("RunMailerOnHotmail", 0) || !ShowPopup || isInitial)
 +		return;
 +
 +	char mailerpath[MAX_PATH];
 +	if (!db_get_static(NULL, m_szModuleName, "MailerPath", mailerpath, sizeof(mailerpath)))
 +	{
 +		if (mailerpath[0])
 +		{
 +			char* tParams = NULL;
 +			char* tCmd = mailerpath;
 +
 +			if (*tCmd == '\"')
 +			{
 +				++tCmd;
 +				char* tEndPtr = strchr(tCmd, '\"');
 +				if (tEndPtr != NULL)
 +				{
 +					*tEndPtr = 0;
 +					tParams = tEndPtr+1;
 +				}
 +			}
 +
 +			if (tParams == NULL)
 +			{
 +				tParams = strchr(tCmd, ' ');
 +				tParams = tParams ? tParams + 1 : strchr(tCmd, '\0');
 +			}
 +
 +			while (*tParams == ' ') ++tParams;
 +
 +			debugLogA("Running mailer \"%s\" with params \"%s\"", tCmd, tParams);
 +			ShellExecuteA(NULL, "open", tCmd, tParams, NULL, TRUE);
 +		}
 +	}
 +}
 +
 +static void TruncUtf8(char *str, size_t sz)
 +{
 +	size_t len = strlen(str);
 +	if (sz > len) sz = len;
 +
 +	size_t cntl = 0, cnt = 0;
 +	for (;;)
 +	{
 +		unsigned char p = (unsigned char)str[cnt];
 +
 +		if (p >= 0xE0) cnt += 3;
 +		else if (p >= 0xC0) cnt += 2;
 +		else if (p != 0) ++cnt;
 +		else break;
 +
 +		if (cnt <= sz) cntl = cnt;
 +		else break;
 +	}
 +	str[cntl] = 0;
 +}
 +
 +void CMsnProto::displayEmailCount(MCONTACT hContact)
 +{
 +	if (!emailEnabled || getByte("DisableHotmailCL", 0)) return;
 +
 +	TCHAR* name = GetContactNameT(hContact);
 +	if (name == NULL) return;
 +
 +	TCHAR* ch = name-1;
 +	do
 +	{
 +		ch = _tcschr(ch+1, '[');
 +	}
 +	while (ch && !_istdigit(ch[1]));
 +	if (ch) *ch = 0;
 +	rtrimt(name);
 +
 +	TCHAR szNick[128];
 +	mir_sntprintf(szNick, SIZEOF(szNick),
 +		getByte("DisableHotmailJunk", 0) ? _T("%s [%d]") : _T("%s [%d][%d]"), name, mUnreadMessages, mUnreadJunkEmails);
 +
 +	nickChg = true;
 +	db_set_ts(hContact, "CList", "MyHandle", szNick);
 +	nickChg = false;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_menu.cpp b/plugins/!Deprecated/MSN/src/msn_menu.cpp new file mode 100644 index 0000000000..84ef664f0f --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_menu.cpp @@ -0,0 +1,460 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +static HGENMENU hBlockMenuItem, hLiveSpaceMenuItem, hNetmeetingMenuItem, hChatInviteMenuItem, hOpenInboxMenuItem;
 +
 +HANDLE hNetMeeting, hBlockCom, hSendHotMail, hInviteChat, hViewProfile;
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// Block command callback function
 +
 +INT_PTR CMsnProto::MsnBlockCommand(WPARAM hContact, LPARAM)
 +{
 +	if (msnLoggedIn) {
 +		char tEmail[MSN_MAX_EMAIL_LEN];
 +		db_get_static(hContact, m_szModuleName, "e-mail", tEmail, sizeof(tEmail));
 +
 +		if (Lists_IsInList(LIST_BL, tEmail))
 +			delSetting(hContact, "ApparentMode");
 +		else
 +			setWord(hContact, "ApparentMode", ID_STATUS_OFFLINE);
 +	}
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnGotoInbox - goes to the Inbox folder at the live.com
 +
 +INT_PTR CMsnProto::MsnGotoInbox(WPARAM, LPARAM)
 +{
 +	MCONTACT hContact = MSN_HContactFromEmail(MyOptions.szEmail);
 +	if (hContact) CallService(MS_CLIST_REMOVEEVENT, hContact, (LPARAM) 1);
 +
 +	MsnInvokeMyURL(true, "http://mail.live.com?rru=inbox");
 +	return 0;
 +}
 +
 +INT_PTR CMsnProto::MsnSendHotmail(WPARAM hContact, LPARAM)
 +{
 +	char szEmail[MSN_MAX_EMAIL_LEN];
 +	if (MSN_IsMeByContact(hContact, szEmail))
 +		MsnGotoInbox(0, 0);
 +	else if (msnLoggedIn)
 +		MsnInvokeMyURL(true, CMStringA().Format("http://mail.live.com?rru=compose?to=%s", ptrA(mir_urlEncode(szEmail))));
 +
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnSetupAlerts - goes to the alerts section at the live.com
 +
 +INT_PTR CMsnProto::MsnSetupAlerts(WPARAM, LPARAM)
 +{
 +	MsnInvokeMyURL(false, "http://alerts.live.com");
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnViewProfile - view a contact's profile
 +
 +INT_PTR CMsnProto::MsnViewProfile(WPARAM hContact, LPARAM)
 +{
 +	char buf[64], *cid;
 +
 +	if (hContact == NULL)
 +		cid = mycid;
 +	else {
 +		cid = buf;
 +		if (db_get_static(hContact, m_szModuleName, "CID", buf, 30))
 +			return 0;
 +	}
 +
 +	char tUrl[256];
 +	mir_snprintf(tUrl, sizeof(tUrl), "http://cid-%I64X.profiles.live.com", _atoi64(cid));
 +	MsnInvokeMyURL(false, tUrl);
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnEditProfile - goes to the Profile section at the live.com
 +
 +INT_PTR CMsnProto::MsnEditProfile(WPARAM, LPARAM)
 +{
 +	MsnViewProfile(0, 0);
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnInviteCommand - invite command callback function
 +
 +INT_PTR CMsnProto::MsnInviteCommand(WPARAM, LPARAM)
 +{
 +	DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_CHATROOM_INVITE), NULL, DlgInviteToChat,
 +		LPARAM(new InviteChatParam(NULL, NULL, this)));
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnRebuildContactMenu - gray or ungray the block menus according to contact's status
 +
 +int CMsnProto::OnPrebuildContactMenu(WPARAM hContact, LPARAM)
 +{
 +	if ( !MSN_IsMyContact(hContact))
 +		return 0;
 +
 +	char szEmail[MSN_MAX_EMAIL_LEN];
 +	bool isMe = MSN_IsMeByContact(hContact, szEmail);
 +	if (szEmail[0]) {
 +		int listId = Lists_GetMask(szEmail);
 +		bool noChat = !(listId & LIST_FL) || isMe || isChatRoom(hContact);
 +
 +		CLISTMENUITEM mi = { sizeof(mi) };
 +		mi.flags = CMIM_NAME;
 +		mi.pszName = ((listId & LIST_BL) ? LPGEN("&Unblock") : LPGEN("&Block"));
 +		Menu_ModifyItem(hBlockMenuItem, &mi);
 +		Menu_ShowItem(hBlockMenuItem, !noChat);
 +
 +		mi.pszName = isMe ? LPGEN("Open &Hotmail Inbox") : LPGEN("Send &Hotmail E-mail");
 +		Menu_ModifyItem(hOpenInboxMenuItem, &mi);
 +		Menu_ShowItem(hOpenInboxMenuItem, emailEnabled);
 +
 +		Menu_ShowItem(hNetmeetingMenuItem, !noChat);
 +		Menu_ShowItem(hChatInviteMenuItem, !noChat);
 +	}
 +
 +	return 0;
 +}
 +
 +int CMsnProto::OnContactDoubleClicked(WPARAM hContact, LPARAM)
 +{
 +	if (emailEnabled && MSN_IsMeByContact(hContact)) {
 +		MsnSendHotmail(hContact, 0);
 +		return 1;
 +	}
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnSendNetMeeting - Netmeeting callback function
 +
 +INT_PTR CMsnProto::MsnSendNetMeeting(WPARAM wParam, LPARAM)
 +{
 +	if (!msnLoggedIn) return 0;
 +
 +	MCONTACT hContact = MCONTACT(wParam);
 +
 +	char szEmail[MSN_MAX_EMAIL_LEN];
 +	if (MSN_IsMeByContact(hContact, szEmail)) return 0;
 +
 +	ThreadData* thread = MSN_GetThreadByContact(szEmail);
 +
 +	if (thread == NULL) {
 +		MessageBox(NULL, TranslateT("You must be talking to start Netmeeting"), TranslateT("MSN Protocol"), MB_OK | MB_ICONERROR);
 +		return 0;
 +	}
 +
 +	char msg[1024];
 +
 +	mir_snprintf(msg, sizeof(msg),
 +		"Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
 +		"Application-Name: NetMeeting\r\n"
 +		"Application-GUID: {44BBA842-CC51-11CF-AAFA-00AA00B6015C}\r\n"
 +		"Session-Protocol: SM1\r\n"
 +		"Invitation-Command: INVITE\r\n"
 +		"Invitation-Cookie: %i\r\n"
 +		"Session-ID: {1A879604-D1B8-11D7-9066-0003FF431510}\r\n\r\n",
 +		MSN_GenRandom());
 +
 +	thread->sendMessage('N', NULL, 1, msg, MSG_DISABLE_HDR);
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	SetNicknameCommand - sets nick name
 +
 +static INT_PTR CALLBACK DlgProcSetNickname(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 +{
 +	switch (msg)
 +	{
 +		case WM_INITDIALOG:
 +		{
 +			TranslateDialogDefault(hwndDlg);
 +
 +			SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
 +			CMsnProto* proto = (CMsnProto*)lParam;
 +
 +			SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIconEx("main", true));
 +			SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconEx("main"));
 +			SendMessage(GetDlgItem(hwndDlg, IDC_NICKNAME), EM_LIMITTEXT, 129, 0);
 +
 +			DBVARIANT dbv;
 +			if (!proto->getTString("Nick", &dbv)) {
 +				SetDlgItemText(hwndDlg, IDC_NICKNAME, dbv.ptszVal);
 +				db_free(&dbv);
 +			}
 +			return TRUE;
 +		}
 +		case WM_COMMAND:
 +			switch(wParam)
 +			{
 +			case IDOK:
 +				{
 +					CMsnProto* proto = (CMsnProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 +					if (proto->msnLoggedIn)
 +					{
 +						TCHAR str[130];
 +						GetDlgItemText(hwndDlg, IDC_NICKNAME, str, SIZEOF(str));
 +						proto->MSN_SendNickname(str);
 +					}
 +				}
 +
 +				case IDCANCEL:
 +					DestroyWindow(hwndDlg);
 +					break;
 +			}
 +			break;
 +
 +		case WM_CLOSE:
 +			DestroyWindow(hwndDlg);
 +			break;
 +
 +		case WM_DESTROY:
 +			ReleaseIconEx("main");
 +			ReleaseIconEx("main", true);
 +			break;
 +	}
 +	return FALSE;
 +}
 +
 +INT_PTR CMsnProto::SetNicknameUI(WPARAM, LPARAM)
 +{
 +	HWND hwndSetNickname = CreateDialogParam (hInst, MAKEINTRESOURCE(IDD_SETNICKNAME),
 +		NULL, DlgProcSetNickname, (LPARAM)this);
 +
 +	SetForegroundWindow(hwndSetNickname);
 +	SetFocus(hwndSetNickname);
 +	ShowWindow(hwndSetNickname, SW_SHOW);
 +	return 0;
 +}
 +
 +//////////////////////////////////////////////////////////////////////////////////////
 +// Menus initialization
 +
 +void CMsnProto::MsnInitMainMenu(void)
 +{
 +	char servicefunction[100];
 +	strcpy(servicefunction, m_szModuleName);
 +	char* tDest = servicefunction + strlen(servicefunction);
 +
 +	CLISTMENUITEM mi = { sizeof(mi) };
 +
 +	HGENMENU hRoot = MO_GetProtoRootMenu(m_szModuleName);
 +	if (hRoot == NULL) {
 +		mi.popupPosition = 500085000;
 +		mi.hParentMenu = HGENMENU_ROOT;
 +		mi.flags = CMIF_ROOTPOPUP | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED;
 +		mi.icolibItem = GetIconHandle(IDI_MSN);
 +		mi.ptszName = m_tszUserName;
 +		hRoot = mainMenuRoot = Menu_AddProtoMenuItem(&mi);
 +	}
 +	else {
 +		MsnRemoveMainMenus();
 +		mainMenuRoot = NULL;
 +	}
 +
 +	mi.flags = CMIF_CHILDPOPUP;
 +	mi.hParentMenu = hRoot;
 +	mi.pszService = servicefunction;
 +
 +	strcpy(tDest, MS_SET_NICKNAME_UI);
 +	CreateProtoService(MS_SET_NICKNAME_UI, &CMsnProto::SetNicknameUI);
 +	mi.position = 201001;
 +	mi.icolibItem = GetIconHandle(IDI_MSN);
 +	mi.pszName = LPGEN("Set &Nickname");
 +	menuItemsMain[0] = Menu_AddProtoMenuItem(&mi);
 +
 +	strcpy(tDest, MSN_INVITE);
 +	CreateProtoService(MSN_INVITE, &CMsnProto::MsnInviteCommand);
 +	mi.position = 201002;
 +	mi.icolibItem = GetIconHandle(IDI_INVITE);
 +	mi.pszName = LPGEN("Create &Chat");
 +	menuItemsMain[0] = Menu_AddProtoMenuItem(&mi);
 +
 +	strcpy(tDest, MS_GOTO_INBOX);
 +	CreateProtoService(MS_GOTO_INBOX, &CMsnProto::MsnGotoInbox);
 +	mi.position = 201003;
 +	mi.icolibItem = GetIconHandle(IDI_INBOX);
 +	mi.pszName = LPGEN("Display &Hotmail Inbox");
 +	menuItemsMain[1] = Menu_AddProtoMenuItem(&mi);
 +
 +	strcpy(tDest, MS_EDIT_PROFILE);
 +	CreateProtoService(MS_EDIT_PROFILE, &CMsnProto::MsnEditProfile);
 +	mi.position = 201004;
 +	mi.icolibItem = GetIconHandle(IDI_PROFILE);
 +	mi.pszName = LPGEN("View &Profile");
 +	menuItemsMain[2] = Menu_AddProtoMenuItem(&mi);
 +
 +	strcpy(tDest, MS_EDIT_ALERTS);
 +	CreateProtoService(MS_EDIT_ALERTS, &CMsnProto::MsnSetupAlerts);
 +	mi.position = 201004;
 +	mi.icolibItem = GetIconHandle(IDI_PROFILE);
 +	mi.pszName = LPGEN("Setup Live &Alerts");
 +	menuItemsMain[3] = Menu_AddProtoMenuItem(&mi);
 +
 +	MSN_EnableMenuItems(m_iStatus >= ID_STATUS_ONLINE);
 +}
 +
 +void CMsnProto::MsnRemoveMainMenus(void)
 +{
 +	if (mainMenuRoot)
 +		CallService(MO_REMOVEMENUITEM, (WPARAM)mainMenuRoot, 0);
 +}
 +
 +void CMsnProto::MSN_EnableMenuItems(bool bEnable)
 +{
 +	CLISTMENUITEM mi = { sizeof(mi) };
 +	mi.flags = CMIM_FLAGS;
 +	if (!bEnable)
 +		mi.flags |= CMIF_GRAYED;
 +
 +	for (int i=0; i < SIZEOF(menuItemsMain); i++)
 +		if (menuItemsMain[i] != NULL)
 +			Menu_ModifyItem(menuItemsMain[i], &mi);
 +
 +	if (bEnable)
 +		Menu_ShowItem(menuItemsMain[1], emailEnabled);
 +}
 +
 +//////////////////////////////////////////////////////////////////////////////////////
 +
 +static CMsnProto* GetProtoInstanceByHContact(MCONTACT hContact)
 +{
 +	char* szProto = GetContactProto(hContact);
 +	if (szProto == NULL)
 +		return NULL;
 +
 +	for (int i = 0; i < g_Instances.getCount(); i++)
 +		if (!strcmp(szProto, g_Instances[i].m_szModuleName))
 +			return &g_Instances[i];
 +
 +	return NULL;
 +}
 +
 +static INT_PTR MsnMenuBlockCommand(WPARAM wParam, LPARAM lParam)
 +{
 +	CMsnProto* ppro = GetProtoInstanceByHContact(wParam);
 +	return (ppro) ? ppro->MsnBlockCommand(wParam, lParam) : 0;
 +}
 +
 +static INT_PTR MsnMenuViewProfile(WPARAM wParam, LPARAM lParam)
 +{
 +	CMsnProto* ppro = GetProtoInstanceByHContact(wParam);
 +	return (ppro) ? ppro->MsnViewProfile(wParam, lParam) : 0;
 +}
 +
 +static INT_PTR MsnMenuSendNetMeeting(WPARAM wParam, LPARAM lParam)
 +{
 +	CMsnProto* ppro = GetProtoInstanceByHContact(wParam);
 +	return (ppro) ? ppro->MsnSendNetMeeting(wParam, lParam) : 0;
 +}
 +
 +static INT_PTR MsnMenuSendHotmail(WPARAM wParam, LPARAM lParam)
 +{
 +	CMsnProto* ppro = GetProtoInstanceByHContact(wParam);
 +	return (ppro) ? ppro->MsnSendHotmail(wParam, lParam) : 0;
 +}
 +
 +static int MSN_OnPrebuildContactMenu(WPARAM wParam, LPARAM lParam)
 +{
 +	CMsnProto* ppro = GetProtoInstanceByHContact(wParam);
 +	if (ppro)
 +		ppro->OnPrebuildContactMenu(wParam, lParam);
 +	else {
 +		Menu_ShowItem(hBlockMenuItem, false);
 +		Menu_ShowItem(hLiveSpaceMenuItem, false);
 +		Menu_ShowItem(hNetmeetingMenuItem, false);
 +		Menu_ShowItem(hChatInviteMenuItem, false);
 +		Menu_ShowItem(hOpenInboxMenuItem, false);
 +	}
 +
 +	return 0;
 +}
 +
 +void MSN_InitContactMenu(void)
 +{
 +	char servicefunction[100];
 +	strcpy(servicefunction, "MSN");
 +	char* tDest = servicefunction + strlen(servicefunction);
 +
 +	CLISTMENUITEM mi = { sizeof(mi) };
 +	mi.pszService = servicefunction;
 +
 +	strcpy(tDest, MSN_BLOCK);
 +	hBlockCom = CreateServiceFunction(servicefunction, MsnMenuBlockCommand);
 +	mi.position = -500050000;
 +	mi.icolibItem = GetIconHandle(IDI_MSNBLOCK);
 +	mi.pszName = LPGEN("&Block");
 +	hBlockMenuItem = Menu_AddContactMenuItem(&mi);
 +
 +	strcpy(tDest, MSN_VIEW_PROFILE);
 +	hViewProfile = CreateServiceFunction(servicefunction, MsnMenuViewProfile);
 +	mi.position = -500050003;
 +	mi.icolibItem = GetIconHandle(IDI_PROFILE);
 +	mi.pszName = LPGEN("View &Profile");
 +	hLiveSpaceMenuItem = Menu_AddContactMenuItem(&mi);
 +
 +	strcpy(tDest, MSN_NETMEETING);
 +	hNetMeeting = CreateServiceFunction(servicefunction, MsnMenuSendNetMeeting);
 +	mi.flags = CMIF_NOTOFFLINE;
 +	mi.position = -500050002;
 +	mi.icolibItem = GetIconHandle(IDI_NETMEETING);
 +	mi.pszName = LPGEN("&Start Netmeeting");
 +	hNetmeetingMenuItem = Menu_AddContactMenuItem(&mi);
 +
 +	strcpy(tDest, "/SendHotmail");
 +	hSendHotMail = CreateServiceFunction(servicefunction, MsnMenuSendHotmail);
 +	mi.position = -2000010005;
 +	mi.flags = CMIF_HIDDEN;
 +	mi.icolibItem = LoadSkinnedIconHandle(SKINICON_OTHER_SENDEMAIL);
 +	mi.pszName = LPGEN("Open &Hotmail Inbox");
 +	hOpenInboxMenuItem = Menu_AddContactMenuItem(&mi);
 +
 +	HookEvent(ME_CLIST_PREBUILDCONTACTMENU, MSN_OnPrebuildContactMenu);
 +}
 +
 +void MSN_RemoveContactMenus(void)
 +{
 +	CallService(MO_REMOVEMENUITEM, (WPARAM)hBlockMenuItem, 0);
 +	CallService(MO_REMOVEMENUITEM, (WPARAM)hLiveSpaceMenuItem, 0);
 +	CallService(MO_REMOVEMENUITEM, (WPARAM)hNetmeetingMenuItem, 0);
 +	CallService(MO_REMOVEMENUITEM, (WPARAM)hChatInviteMenuItem, 0);
 +	CallService(MO_REMOVEMENUITEM, (WPARAM)hOpenInboxMenuItem, 0);
 +
 +	DestroyServiceFunction(hNetMeeting);
 +	DestroyServiceFunction(hBlockCom);
 +	DestroyServiceFunction(hSendHotMail);
 +	DestroyServiceFunction(hInviteChat);
 +	DestroyServiceFunction(hViewProfile);
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_mime.cpp b/plugins/!Deprecated/MSN/src/msn_mime.cpp new file mode 100644 index 0000000000..6f9d15d587 --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_mime.cpp @@ -0,0 +1,536 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// constructors and destructor
 +
 +MimeHeaders::MimeHeaders() :
 +	mCount(0),
 +	mAllocCount(0),
 +	mVals(NULL)
 +{
 +}
 +
 +MimeHeaders::MimeHeaders(unsigned iInitCount) :
 +	mCount(0)
 +{
 +	mAllocCount = iInitCount;
 +	mVals = (MimeHeader*)mir_alloc(iInitCount * sizeof(MimeHeader));
 +}
 +
 +MimeHeaders::~MimeHeaders()
 +{
 +	clear();
 +	mir_free(mVals);
 +}
 +
 +void MimeHeaders::clear(void)
 +{
 +	for (unsigned i=0; i < mCount; i++)
 +	{
 +		MimeHeader& H = mVals[i];
 +		if (H.flags & 1) mir_free((void*)H.name);
 +		if (H.flags & 2) mir_free((void*)H.value);
 +	}
 +	mCount = 0;
 +}
 +
 +unsigned MimeHeaders::allocSlot(void)
 +{
 +	if (++mCount >= mAllocCount)
 +	{
 +		mAllocCount += 10;
 +		mVals = (MimeHeader*)mir_realloc(mVals, sizeof(MimeHeader) * mAllocCount);
 +	}
 +	return mCount - 1;
 +}
 +
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// add various values
 +
 +void MimeHeaders::addString(const char* name, const char* szValue, unsigned flags)
 +{
 +	if (szValue == NULL) return;
 +
 +	MimeHeader& H = mVals[allocSlot()];
 +	H.name = name;
 +	H.value = szValue;
 +	H.flags = flags;
 +}
 +
 +void MimeHeaders::addLong(const char* name, long lValue, unsigned flags)
 +{
 +	MimeHeader& H = mVals[allocSlot()];
 +	H.name = name;
 +
 +	char szBuffer[20];
 +	_ltoa(lValue, szBuffer, 10);
 +	H.value = mir_strdup(szBuffer);
 +	H.flags = 2 | flags;
 +}
 +
 +void MimeHeaders::addULong(const char* name, unsigned lValue)
 +{
 +	MimeHeader& H = mVals[allocSlot()];
 +	H.name = name;
 +
 +	char szBuffer[20];
 +	_ultoa(lValue, szBuffer, 10);
 +	H.value = mir_strdup(szBuffer);
 +	H.flags = 2;
 +}
 +
 +void MimeHeaders::addBool(const char* name, bool lValue)
 +{
 +	MimeHeader& H = mVals[allocSlot()];
 +	H.name = name;
 +	H.value = lValue ? "true" : "false";
 +	H.flags = 0;
 +}
 +
 +char* MimeHeaders::flipStr(const char* src, size_t len, char* dest)
 +{
 +	if (len == -1) len = strlen(src);
 +
 +	if (src == dest)
 +	{
 +		const unsigned b = (unsigned)len-- / 2;
 +		for (unsigned i = 0; i < b; i++)
 +		{
 +			const char c = dest[i];
 +			dest[i] = dest[len - i];
 +			dest[len - i] = c;
 +		}
 +		++len;
 +	}
 +	else
 +	{
 +		for (unsigned i = 0; i < len; i++)
 +			dest[i] = src[len - 1 - i];
 +		dest[len] = 0;
 +	}
 +
 +	return dest + len;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// write all values to a buffer
 +
 +size_t MimeHeaders::getLength(void)
 +{
 +	size_t iResult = 0;
 +	for (unsigned i=0; i < mCount; i++)
 +	{
 +		MimeHeader& H = mVals[i];
 +		iResult += strlen(H.name) + strlen(H.value) + 4;
 +	}
 +
 +	return iResult + (iResult ? 2 : 0);
 +}
 +
 +char* MimeHeaders::writeToBuffer(char* dest)
 +{
 +	for (unsigned i=0; i < mCount; i++)
 +	{
 +		MimeHeader& H = mVals[i];
 +		if (H.flags & 4)
 +		{
 +			dest = flipStr(H.name, -1, dest);
 +
 +			*(dest++) = ':';
 +			*(dest++) = ' ';
 +
 +			dest = flipStr(H.value, -1, dest);
 +
 +			*(dest++) = '\r';
 +			*(dest++) = '\n';
 +			*dest = 0;
 +		}
 +		else
 +			dest += sprintf(dest, "%s: %s\r\n", H.name, H.value); //!!!!!!!!!!!!
 +	}
 +
 +	if (mCount)
 +	{
 +		*(dest++) = '\r';
 +		*(dest++) = '\n';
 +		*dest = 0;
 +	}
 +
 +	return dest;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// read set of values from buffer
 +
 +char* MimeHeaders::readFromBuffer(char* src)
 +{
 +	clear();
 +
 +	while (*src)
 +	{
 +		char* peol = strchr(src, '\n');
 +
 +		if (peol == NULL)
 +			return strchr(src, 0);
 +		else if (peol == src)
 +			return src + 1;
 +		else if (peol == (src + 1) &&  *src == '\r')
 +			return src + 2;
 +
 +		*peol = 0;
 +
 +		char* delim = strchr(src, ':');
 +		if (delim)
 +		{
 +			*delim = 0;
 +
 +			MimeHeader& H = mVals[allocSlot()];
 +
 +			H.name = lrtrimp(src);
 +			H.value = lrtrimp(delim + 1);
 +			H.flags = 0;
 +		}
 +
 +		src = peol + 1;
 +	}
 +
 +	return src;
 +}
 +
 +const char* MimeHeaders::find(const char* szFieldName)
 +{
 +	size_t i;
 +	for (i = 0; i < mCount; i++)
 +	{
 +		MimeHeader& MH = mVals[i];
 +		if (_stricmp(MH.name, szFieldName) == 0)
 +			return MH.value;
 +	}
 +
 +	const size_t len = strlen(szFieldName);
 +	char* szFieldNameR = (char*)alloca(len + 1);
 +	flipStr(szFieldName, len, szFieldNameR);
 +
 +	for (i = 0; i < mCount; i++)
 +	{
 +		MimeHeader& MH = mVals[i];
 +		if (_stricmp(MH.name, szFieldNameR) == 0 && (MH.flags & 3) == 0)
 +		{
 +			strcpy((char*)MH.name, szFieldNameR);
 +			flipStr(MH.value, -1, (char*)MH.value);
 +			return MH.value;
 +		}
 +	}
 +
 +	return NULL;
 +}
 +
 +static const struct _tag_cpltbl
 +{
 +	unsigned cp;
 +	const char* mimecp;
 +} cptbl[] =
 +{
 +	{    37, "IBM037" },          // IBM EBCDIC US-Canada
 +	{   437, "IBM437" },          // OEM United States
 +	{   500, "IBM500" },          // IBM EBCDIC International
 +	{   708, "ASMO-708" },        // Arabic (ASMO 708)
 +	{   720, "DOS-720" },         // Arabic (Transparent ASMO); Arabic (DOS)
 +	{   737, "ibm737" },          // OEM Greek (formerly 437G); Greek (DOS)
 +	{   775, "ibm775" },          // OEM Baltic; Baltic (DOS)
 +	{   850, "ibm850" },          // OEM Multilingual Latin 1; Western European (DOS)
 +	{   852, "ibm852" },          // OEM Latin 2; Central European (DOS)
 +	{   855, "IBM855" },          // OEM Cyrillic (primarily Russian)
 +	{   857, "ibm857" },          // OEM Turkish; Turkish (DOS)
 +	{   858, "IBM00858" },        // OEM Multilingual Latin 1 + Euro symbol
 +	{   860, "IBM860" },          // OEM Portuguese; Portuguese (DOS)
 +	{   861, "ibm861" },          // OEM Icelandic; Icelandic (DOS)
 +	{   862, "DOS-862" },         // OEM Hebrew; Hebrew (DOS)
 +	{   863, "IBM863" },          // OEM French Canadian; French Canadian (DOS)
 +	{   864, "IBM864" },          // OEM Arabic; Arabic (864)
 +	{   865, "IBM865" },          // OEM Nordic; Nordic (DOS)
 +	{   866, "cp866" },           // OEM Russian; Cyrillic (DOS)
 +	{   869, "ibm869" },          // OEM Modern Greek; Greek, Modern (DOS)
 +	{   870, "IBM870" },          // IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2
 +	{   874, "windows-874" },     // ANSI/OEM Thai (same as 28605, ISO 8859-15); Thai (Windows)
 +	{   875, "cp875" },           // IBM EBCDIC Greek Modern
 +	{   932, "shift_jis" },       // ANSI/OEM Japanese; Japanese (Shift-JIS)
 +	{   936, "gb2312" },          // ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)
 +	{   949, "ks_c_5601-1987" },  // ANSI/OEM Korean (Unified Hangul Code)
 +	{   950, "big5" },            // ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)
 +	{  1026, "IBM1026" },         // IBM EBCDIC Turkish (Latin 5)
 +	{  1047, "IBM01047" },        // IBM EBCDIC Latin 1/Open System
 +	{  1140, "IBM01140" },        // IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro)
 +	{  1141, "IBM01141" },        // IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro)
 +	{  1142, "IBM01142" },        // IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro)
 +	{  1143, "IBM01143" },        // IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro)
 +	{  1144, "IBM01144" },        // IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro)
 +	{  1145, "IBM01145" },        // IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro)
 +	{  1146, "IBM01146" },        // IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro)
 +	{  1147, "IBM01147" },        // IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro)
 +	{  1148, "IBM01148" },        // IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro)
 +	{  1149, "IBM01149" },        // IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro)
 +	{  1250, "windows-1250" },    // ANSI Central European; Central European (Windows)
 +	{  1251, "windows-1251" },    // ANSI Cyrillic; Cyrillic (Windows)
 +	{  1252, "windows-1252" },    // ANSI Latin 1; Western European (Windows)
 +	{  1253, "windows-1253" },    // ANSI Greek; Greek (Windows)
 +	{  1254, "windows-1254" },    // ANSI Turkish; Turkish (Windows)
 +	{  1255, "windows-1255" },    // ANSI Hebrew; Hebrew (Windows)
 +	{  1256, "windows-1256" },    // ANSI Arabic; Arabic (Windows)
 +	{  1257, "windows-1257" },    // ANSI Baltic; Baltic (Windows)
 +	{  1258, "windows-1258" },    // ANSI/OEM Vietnamese; Vietnamese (Windows)
 +	{ 20127, "us-ascii" },        // US-ASCII (7-bit)
 +	{ 20273, "IBM273" },          // IBM EBCDIC Germany
 +	{ 20277, "IBM277" },          // IBM EBCDIC Denmark-Norway
 +	{ 20278, "IBM278" },          // IBM EBCDIC Finland-Sweden
 +	{ 20280, "IBM280" },          // IBM EBCDIC Italy
 +	{ 20284, "IBM284" },          // IBM EBCDIC Latin America-Spain
 +	{ 20285, "IBM285" },          // IBM EBCDIC United Kingdom
 +	{ 20290, "IBM290" },          // IBM EBCDIC Japanese Katakana Extended
 +	{ 20297, "IBM297" },          // IBM EBCDIC France
 +	{ 20420, "IBM420" },          // IBM EBCDIC Arabic
 +	{ 20423, "IBM423" },          // IBM EBCDIC Greek
 +	{ 20424, "IBM424" },          // IBM EBCDIC Hebrew
 +	{ 20838, "IBM-Thai" },        // IBM EBCDIC Thai
 +	{ 20866, "koi8-r" },          // Russian (KOI8-R); Cyrillic (KOI8-R)
 +	{ 20871, "IBM871" },          // IBM EBCDIC Icelandic
 +	{ 20880, "IBM880" },          // IBM EBCDIC Cyrillic Russian
 +	{ 20905, "IBM905" },          // IBM EBCDIC Turkish
 +	{ 20924, "IBM00924" },        // IBM EBCDIC Latin 1/Open System (1047 + Euro symbol)
 +	{ 20932, "EUC-JP" },          // Japanese (JIS 0208-1990 and 0121-1990)
 +	{ 21025, "cp1025" },          // IBM EBCDIC Cyrillic Serbian-Bulgarian
 +	{ 21866, "koi8-u" },          // Ukrainian (KOI8-U); Cyrillic (KOI8-U)
 +	{ 28591, "iso-8859-1" },      // ISO 8859-1 Latin 1; Western European (ISO)
 +	{ 28592, "iso-8859-2" },      // ISO 8859-2 Central European; Central European (ISO)
 +	{ 28593, "iso-8859-3" },      // ISO 8859-3 Latin 3
 +	{ 28594, "iso-8859-4" },      // ISO 8859-4 Baltic
 +	{ 28595, "iso-8859-5" },      // ISO 8859-5 Cyrillic
 +	{ 28596, "iso-8859-6" },      // ISO 8859-6 Arabic
 +	{ 28597, "iso-8859-7" },      // ISO 8859-7 Greek
 +	{ 28598, "iso-8859-8" },      // ISO 8859-8 Hebrew; Hebrew (ISO-Visual)
 +	{ 28599, "iso-8859-9" },      // ISO 8859-9 Turkish
 +	{ 28603, "iso-8859-13" },     // ISO 8859-13 Estonian
 +	{ 28605, "iso-8859-15" },     // ISO 8859-15 Latin 9
 +	{ 38598, "iso-8859-8-i" },    // ISO 8859-8 Hebrew; Hebrew (ISO-Logical)
 +	{ 50220, "iso-2022-jp" },     // ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)
 +	{ 50221, "csISO2022JP" },     // ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana)
 +	{ 50222, "iso-2022-jp" },     // ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI)
 +	{ 50225, "iso-2022-kr" },     // ISO 2022 Korean
 +	{ 50227, "ISO-2022-CN" },     // ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022)
 +	{ 50229, "ISO-2022-CN-EXT" }, // ISO 2022 Traditional Chinese
 +	{ 51932, "euc-jp" },          // EUC Japanese
 +	{ 51936, "EUC-CN" },          // EUC Simplified Chinese; Chinese Simplified (EUC)
 +	{ 51949, "euc-kr" },          // EUC Korean
 +	{ 52936, "hz-gb-2312" },      // HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ)
 +	{ 54936, "GB18030" },         // Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030)
 +};
 +
 +
 +static unsigned FindCP(const char* mimecp)
 +{
 +	unsigned cp = CP_ACP;
 +	for (unsigned i = 0; i < SIZEOF(cptbl); ++i)
 +	{
 +		if (_stricmp(mimecp, cptbl[i].mimecp) == 0)
 +		{
 +			cp = cptbl[i].cp;
 +			break;
 +		}
 +	}
 +	return cp;
 +}
 +
 +
 +static int SingleHexToDecimal(char c)
 +{
 +	if (c >= '0' && c <= '9') return c-'0';
 +	if (c >= 'a' && c <= 'f') return c-'a'+10;
 +	if (c >= 'A' && c <= 'F') return c-'A'+10;
 +	return -1;
 +}
 +
 +static void  PQDecode(char* str)
 +{
 +	char* s = str, *d = str;
 +
 +	while(*s)
 +	{
 +		switch (*s)
 +		{
 +			case '=':
 +			{
 +				int digit1 = SingleHexToDecimal(s[1]);
 +				if (digit1 != -1)
 +				{
 +					int digit2 = SingleHexToDecimal(s[2]);
 +					if (digit2 != -1)
 +					{
 +						s += 3;
 +						*d++ = (char)((digit1 << 4) | digit2);
 +					}
 +				}
 +				break;
 +			}
 +
 +			case '_':
 +				*d++ = ' '; ++s;
 +				break;
 +
 +			default:
 +				*d++ = *s++;
 +				break;
 +		}
 +	}
 +	*d = 0;
 +}
 +
 +static size_t utf8toutf16(char* str, wchar_t* res)
 +{
 +	wchar_t *dec = mir_utf8decodeW(str);
 +	if (dec == NULL) dec = mir_a2u(str);
 +	wcscpy(res, dec);
 +	mir_free(dec);
 +	return wcslen(res);
 +}
 +
 +
 +wchar_t* MimeHeaders::decode(const char* val)
 +{
 +	size_t ssz = strlen(val) * 2 + 1;
 +	char* tbuf = (char*)alloca(ssz);
 +	memcpy(tbuf, val, ssz);
 +
 +	wchar_t* res = (wchar_t*)mir_alloc(ssz * sizeof(wchar_t));
 +	wchar_t* resp = res;
 +
 +	char *p = tbuf;
 +	while (*p)
 +	{
 +		char *cp = strstr(p, "=?");
 +		if (cp == NULL) break;
 +		*cp = 0;
 +
 +		size_t sz = utf8toutf16(p, resp);
 +		ssz -= sz; resp += sz;
 +		cp += 2;
 +
 +		char *enc = strchr(cp, '?');
 +		if (enc == NULL) break;
 +		*(enc++) = 0;
 +
 +		char *fld = strchr(enc, '?');
 +		if (fld == NULL) break;
 +		*(fld++) = 0;
 +
 +		char *pe = strstr(fld, "?=");
 +		if (pe == NULL) break;
 +		*pe = 0;
 +
 +		switch (*enc)
 +		{
 +			case 'b':
 +			case 'B':
 +			{
 +				char* dec = (char*)mir_base64_decode(fld, 0);
 +				strcpy(fld, dec);
 +				mir_free(dec);
 +				break;
 +			}
 +
 +			case 'q':
 +			case 'Q':
 +				PQDecode(fld);
 +				break;
 +		}
 +
 +		if (_stricmp(cp, "UTF-8") == 0)
 +		{
 +			sz = utf8toutf16(fld, resp);
 +			ssz -= sz; resp += sz;
 +		}
 +		else
 +		{
 +			int sz = MultiByteToWideChar(FindCP(cp), 0, fld, -1, resp, (int)ssz);
 +			if (sz == 0)
 +				sz = MultiByteToWideChar(CP_ACP, 0, fld, -1, resp, (int)ssz);
 +			ssz -= --sz; resp += sz;
 +		}
 +		p = pe + 2;
 +	}
 +
 +	utf8toutf16(p, resp);
 +
 +	return res;
 +}
 +
 +
 +char* MimeHeaders::decodeMailBody(char* msgBody)
 +{
 +	char* res;
 +	const char *val = find("Content-Transfer-Encoding");
 +	if (val && _stricmp(val, "base64") == 0)
 +	{
 +		char *src = msgBody, *dst = msgBody;
 +		while (*src != 0)
 +		{
 +			if (isspace(*src)) ++src;
 +			else *(dst++) = *(src++);
 +		}
 +		*dst = 0;
 +		res = (char*)mir_base64_decode(msgBody, 0);
 +	}
 +	else
 +	{
 +		res = mir_strdup(msgBody);
 +		if (val && _stricmp(val, "quoted-printable") == 0)
 +			PQDecode(res);
 +	}
 +	return res;
 +}
 +
 +
 +int sttDivideWords(char* parBuffer, int parMinItems, char** parDest)
 +{
 +	int i;
 +	for (i=0; i < parMinItems; i++)
 +	{
 +		parDest[i] = parBuffer;
 +
 +		size_t tWordLen = strcspn(parBuffer, " \t");
 +		if (tWordLen == 0)
 +			return i;
 +
 +		parBuffer += tWordLen;
 +		if (*parBuffer != '\0')
 +		{
 +			size_t tSpaceLen = strspn(parBuffer, " \t");
 +			memset(parBuffer, 0, tSpaceLen);
 +			parBuffer += tSpaceLen;
 +	}	}
 +
 +	return i;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_misc.cpp b/plugins/!Deprecated/MSN/src/msn_misc.cpp new file mode 100644 index 0000000000..d370429c57 --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_misc.cpp @@ -0,0 +1,1293 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +#include "version.h"
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MirandaStatusToMSN - status helper functions
 +
 +const char* CMsnProto::MirandaStatusToMSN(int status)
 +{
 +	switch(status)
 +	{
 +		case ID_STATUS_OFFLINE:		return "FLN";
 +		case ID_STATUS_ONTHEPHONE:
 +		case ID_STATUS_OUTTOLUNCH:
 +		case ID_STATUS_NA:
 +		case ID_STATUS_AWAY:		return "AWY";
 +		case ID_STATUS_DND:
 +		case ID_STATUS_OCCUPIED:	return "BSY";
 +		case ID_STATUS_INVISIBLE:	return "HDN";
 +		case ID_STATUS_IDLE:		return "IDL";
 +		default:					return "NLN";
 +}	}
 +
 +WORD CMsnProto::MSNStatusToMiranda(const char *status)
 +{
 +	switch((*(PDWORD)status&0x00FFFFFF) | 0x20000000)
 +	{
 +		case ' LDI': return ID_STATUS_IDLE;
 +		case ' NLN': return ID_STATUS_ONLINE;
 +		case ' NHP':
 +		case ' NUL':
 +		case ' BRB':
 +		case ' YWA': return ID_STATUS_AWAY;
 +		case ' YSB': return ID_STATUS_OCCUPIED;
 +		case ' NDH': return ID_STATUS_INVISIBLE;
 +		default: return ID_STATUS_OFFLINE;
 +	}
 +}
 +
 +char** CMsnProto::GetStatusMsgLoc(int status)
 +{
 +	static const int modes[MSN_NUM_MODES] =
 +	{
 +		ID_STATUS_ONLINE,
 +		ID_STATUS_AWAY,
 +		ID_STATUS_DND,
 +		ID_STATUS_NA,
 +		ID_STATUS_OCCUPIED,
 +		ID_STATUS_FREECHAT,
 +		ID_STATUS_INVISIBLE,
 +		ID_STATUS_ONTHEPHONE,
 +		ID_STATUS_OUTTOLUNCH,
 +	};
 +
 +	for (int i=0; i < MSN_NUM_MODES; i++)
 +		if (modes[i] == status) return &msnModeMsgs[i];
 +
 +	return NULL;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_AddAuthRequest - adds the authorization event to the database
 +
 +void CMsnProto::MSN_AddAuthRequest(const char *email, const char *nick, const char *reason)
 +{
 +	//blob is: UIN=0(DWORD), hContact(DWORD), nick(ASCIIZ), ""(ASCIIZ), ""(ASCIIZ), email(ASCIIZ), ""(ASCIIZ)
 +
 +	MCONTACT hContact = MSN_HContactFromEmail(email, nick, true, true);
 +
 +	int emaillen = (int)strlen(email);
 +
 +	if (nick == NULL) nick = "";
 +	int nicklen = (int)strlen(nick);
 +
 +	if (reason == NULL) reason = "";
 +	int reasonlen = (int)strlen(reason);
 +
 +	PROTORECVEVENT pre = { 0 };
 +	pre.flags = PREF_UTF;
 +	pre.timestamp = (DWORD)time(NULL);
 +	pre.lParam = sizeof(DWORD) + sizeof(HANDLE) + nicklen + emaillen + 5 + reasonlen;
 +
 +	char* pCurBlob = (char*)alloca(pre.lParam);
 +	pre.szMessage = pCurBlob;
 +
 +	*(PDWORD)pCurBlob = 0; pCurBlob += sizeof(DWORD);                // UID
 +	*(PDWORD)pCurBlob = (DWORD)hContact; pCurBlob += sizeof(DWORD);  // Contact Handle
 +	strcpy(pCurBlob, nick); pCurBlob += nicklen + 1;                 // Nickname
 +	*pCurBlob = '\0'; pCurBlob++;                                    // First Name
 +	*pCurBlob = '\0'; pCurBlob++;	                                   // Last Name
 +	strcpy(pCurBlob, email); pCurBlob += emaillen + 1;               // E-mail
 +	strcpy(pCurBlob, reason);                                        // Reason
 +
 +	ProtoChainRecv(hContact, PSR_AUTH, 0, (LPARAM)&pre);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +
 +void CMsnProto::InitCustomFolders(void)
 +{
 +	if (InitCstFldRan) return;
 +
 +	TCHAR folder[MAX_PATH];
 +	mir_sntprintf(folder, SIZEOF(folder), _T("%%miranda_avatarcache%%\\%S"), m_szModuleName);
 +	hCustomSmileyFolder = FoldersRegisterCustomPathT(LPGEN("Custom Smileys"), m_szModuleName, folder, m_tszUserName);
 +
 +	InitCstFldRan = true;
 +}
 +
 +
 +char* MSN_GetAvatarHash(char* szContext, char** pszUrl)
 +{
 +	if (pszUrl)
 +		*pszUrl = NULL;
 +
 +	if (szContext == NULL)
 +		return NULL;
 +
 +	char *res  = NULL;
 +
 +	ezxml_t xmli = ezxml_parse_str(NEWSTR_ALLOCA(szContext), strlen(szContext));
 +	const char *szAvatarHash = ezxml_attr(xmli, "SHA1D");
 +	if (szAvatarHash != NULL) {
 +		unsigned hashLen;
 +		mir_ptr<BYTE> hash((BYTE*)mir_base64_decode(szAvatarHash, &hashLen));
 +		if (hash)
 +			res = arrayToHex(hash, hashLen);
 +
 +		if (pszUrl) {
 +			const char *pszUrlAttr;
 +			for (int i=0; ; i++) {
 +				char szSetting[20];
 +				if (i == 0)
 +					strcpy(szSetting, "Url");
 +				else
 +					mir_snprintf(szSetting, sizeof(szSetting), "Url%d", i);
 +				pszUrlAttr = ezxml_attr(xmli, szSetting);
 +				if (pszUrlAttr == NULL)
 +					break;
 +
 +				if (pszUrlAttr[0] != 0) {
 +					*pszUrl = mir_strdup(pszUrlAttr);
 +					break;
 +				}
 +			}
 +		}
 +	}
 +	ezxml_free(xmli);
 +
 +	return res;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_GetAvatarFileName - gets a file name for an contact's avatar
 +
 +void CMsnProto::MSN_GetAvatarFileName(MCONTACT hContact, TCHAR* pszDest, size_t cbLen, const TCHAR *ext)
 +{
 +	size_t tPathLen = mir_sntprintf(pszDest, cbLen, _T("%s\\%S"), VARST(_T("%miranda_avatarcache%")), m_szModuleName);
 +
 +	if (_taccess(pszDest, 0))
 +		CreateDirectoryTreeT(pszDest);
 +
 +	size_t tPathLen2 = tPathLen;
 +	if (hContact != NULL) {
 +		DBVARIANT dbv;
 +		if (getString(hContact, "PictContext", &dbv) == 0) {
 +			char* szAvatarHash = MSN_GetAvatarHash(dbv.pszVal);
 +			if (szAvatarHash != NULL) {
 +				TCHAR *sztAvatarHash = mir_a2t(szAvatarHash);
 +				tPathLen += mir_sntprintf(pszDest + tPathLen, cbLen - tPathLen, _T("\\%s."), sztAvatarHash);
 +				mir_free(sztAvatarHash);
 +				mir_free(szAvatarHash);
 +			}
 +			else {
 +				delSetting(hContact, "PictContext");
 +				if (cbLen) pszDest[0] = 0;
 +			}
 +			db_free(&dbv);
 +		}
 +		else if (cbLen)
 +			pszDest[0] = 0;
 +	}
 +	else {
 +		TCHAR *sztModuleName = mir_a2t(m_szModuleName);
 +		tPathLen += mir_sntprintf(pszDest + tPathLen, cbLen - tPathLen, _T("\\%s avatar."), sztModuleName);
 +		mir_free(sztModuleName);
 +	}
 +
 +	if (ext == NULL) {
 +		mir_sntprintf(pszDest + tPathLen, cbLen - tPathLen, _T("*"));
 +
 +		bool found = false;
 +		_tfinddata_t c_file;
 +		long hFile = _tfindfirst(pszDest, &c_file);
 +		if (hFile > -1L) {
 +			do {
 +				if (_tcsrchr(c_file.name, '.')) {
 +					mir_sntprintf(pszDest + tPathLen2, cbLen - tPathLen2, _T("\\%s"), c_file.name);
 +					found = true;
 +				}
 +			}
 +				while(_tfindnext(hFile, &c_file) == 0);
 +			_findclose( hFile );
 +		}
 +
 +		if (!found) pszDest[0] = 0;
 +	}
 +	else {
 +		tPathLen--;
 +		mir_sntprintf(pszDest + tPathLen, cbLen - tPathLen, ext);
 +	}
 +}
 +
 +int CMsnProto::MSN_SetMyAvatar(const TCHAR* sztFname, void* pData, size_t cbLen)
 +{
 +	mir_sha1_ctx sha1ctx;
 +	BYTE sha1c[MIR_SHA1_HASH_SIZE], sha1d[MIR_SHA1_HASH_SIZE];
 +
 +	char *szFname = mir_utf8encodeT(sztFname);
 +
 +	mir_sha1_init(&sha1ctx);
 +	mir_sha1_append(&sha1ctx, (BYTE*)pData, (int)cbLen);
 +	mir_sha1_finish(&sha1ctx, sha1d);
 +
 +	ptrA szSha1d( mir_base64_encode((PBYTE)sha1d, sizeof(sha1d)));
 +
 +	mir_sha1_init(&sha1ctx);
 +	ezxml_t xmlp = ezxml_new("msnobj");
 +
 +	mir_sha1_append(&sha1ctx, (PBYTE)"Creator", 7);
 +	mir_sha1_append(&sha1ctx, (PBYTE)MyOptions.szEmail, (int)strlen(MyOptions.szEmail));
 +	ezxml_set_attr(xmlp, "Creator", MyOptions.szEmail);
 +
 +	char szFileSize[20];
 +	_ultoa((unsigned)cbLen, szFileSize, 10);
 +	mir_sha1_append(&sha1ctx, (PBYTE)"Size", 4);
 +	mir_sha1_append(&sha1ctx, (PBYTE)szFileSize, (int)strlen(szFileSize));
 +	ezxml_set_attr(xmlp, "Size", szFileSize);
 +
 +	mir_sha1_append(&sha1ctx, (PBYTE)"Type", 4);
 +	mir_sha1_append(&sha1ctx, (PBYTE)"3", 1);  // MSN_TYPEID_DISPLAYPICT
 +	ezxml_set_attr(xmlp, "Type", "3");
 +
 +	mir_sha1_append(&sha1ctx, (PBYTE)"Location", 8);
 +	mir_sha1_append(&sha1ctx, (PBYTE)szFname, (int)strlen(szFname));
 +	ezxml_set_attr(xmlp, "Location", szFname);
 +
 +	mir_sha1_append(&sha1ctx, (PBYTE)"Friendly", 8);
 +	mir_sha1_append(&sha1ctx, (PBYTE)"AAA=", 4);
 +	ezxml_set_attr(xmlp, "Friendly", "AAA=");
 +
 +	mir_sha1_append(&sha1ctx, (PBYTE)"SHA1D", 5);
 +	mir_sha1_append(&sha1ctx, (PBYTE)(char*)szSha1d, (int)strlen(szSha1d));
 +	ezxml_set_attr(xmlp, "SHA1D", szSha1d);
 +
 +	mir_sha1_finish(&sha1ctx, sha1c);
 +
 +	ptrA szSha1c( mir_base64_encode((PBYTE)sha1c, sizeof(sha1c)));
 +
 +	//	ezxml_set_attr(xmlp, "SHA1C", szSha1c);
 +
 +	char* szBuffer = ezxml_toxml(xmlp, false);
 +	ezxml_free(xmlp);
 +	mir_free(szFname);
 +	ptrA szEncodedBuffer(mir_urlEncode(szBuffer));
 +	free(szBuffer);
 +
 +	const TCHAR *szExt;
 +	int fmt = ProtoGetBufferFormat(pData, &szExt);
 +	if (fmt == PA_FORMAT_UNKNOWN)
 +		return fmt;
 +
 +	TCHAR szFileName[MAX_PATH];
 +	MSN_GetAvatarFileName(NULL, szFileName, SIZEOF(szFileName), NULL);
 +	_tremove(szFileName);
 +
 +	MSN_GetAvatarFileName(NULL, szFileName, SIZEOF(szFileName), szExt);
 +
 +	int fileId = _topen(szFileName, _O_CREAT | _O_TRUNC | _O_WRONLY | O_BINARY, _S_IREAD | _S_IWRITE);
 +	if (fileId >= 0) {
 +		_write(fileId, pData, (unsigned)cbLen);
 +		_close(fileId);
 +
 +		char szAvatarHashdOld[41] = "";
 +		db_get_static(NULL, m_szModuleName, "AvatarHash", szAvatarHashdOld, sizeof(szAvatarHashdOld));
 +		char *szAvatarHash = arrayToHex(sha1d, sizeof(sha1d));
 +		if (strcmp(szAvatarHashdOld, szAvatarHash)) {
 +			setString("PictObject", szEncodedBuffer);
 +			setString("AvatarHash", szAvatarHash);
 +		}
 +		mir_free(szAvatarHash);
 +	}
 +	else MSN_ShowError("Cannot set avatar. File '%s' could not be created/overwritten", szFileName);
 +
 +	return fmt;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_GetCustomSmileyFileName - gets a file name for an contact's custom smiley
 +
 +void CMsnProto::MSN_GetCustomSmileyFileName(MCONTACT hContact, TCHAR* pszDest, size_t cbLen, const char* SmileyName, int type)
 +{
 +	size_t tPathLen;
 +
 +	InitCustomFolders();
 +
 +	TCHAR* path = (TCHAR*)alloca(cbLen * sizeof(TCHAR));
 +	if (hCustomSmileyFolder == NULL || FoldersGetCustomPathT(hCustomSmileyFolder, path, (int)cbLen, _T(""))) {
 +		TCHAR *tmpPath = Utils_ReplaceVarsT(_T("%miranda_userdata%"));
 +		TCHAR *tszModuleName = mir_a2t(m_szModuleName);
 +		tPathLen = mir_sntprintf(pszDest, cbLen, _T("%s\\%s\\CustomSmiley"), tmpPath, tszModuleName);
 +		mir_free(tszModuleName);
 +		mir_free(tmpPath);
 +	}
 +	else {
 +		_tcscpy(pszDest, path);
 +		tPathLen = _tcslen(pszDest);
 +	}
 +
 +	if (hContact != NULL)
 +	{
 +		DBVARIANT dbv = {0};
 +		if (getTString(hContact, "e-mail", &dbv))
 +		{
 +			dbv.type = DBVT_ASCIIZ;
 +			dbv.ptszVal = (TCHAR*)mir_alloc(11);
 +			_ui64tot((UINT_PTR)hContact, dbv.ptszVal, 10);
 +		}
 +
 +		tPathLen += mir_sntprintf(pszDest + tPathLen, cbLen - tPathLen, _T("\\%s"), dbv.ptszVal);
 +		db_free(&dbv);
 +	}
 +	else {
 +		TCHAR *tszModuleName = mir_a2t(m_szModuleName);
 +		tPathLen += mir_sntprintf(pszDest + tPathLen, cbLen - tPathLen, _T("\\%s"), tszModuleName);
 +		mir_free(tszModuleName);
 +	}
 +
 +	bool exist = _taccess(pszDest, 0) == 0;
 +
 +	if (type == 0) {
 +		if (!exist) pszDest[0] = 0;
 +		return;
 +	}
 +
 +	if (!exist)
 +		CreateDirectoryTreeT(pszDest);
 +
 +	TCHAR *sztSmileyName = mir_a2t(SmileyName);
 +	mir_sntprintf(pszDest + tPathLen, cbLen - tPathLen, _T("\\%s.%s"), sztSmileyName,
 +		type == MSN_APPID_CUSTOMSMILEY ? _T("png") : _T("gif"));
 +	mir_free(sztSmileyName);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_GoOffline - performs several actions when a server goes offline
 +
 +void CMsnProto::MSN_GoOffline(void)
 +{
 +	if (m_iStatus == ID_STATUS_OFFLINE) return;
 +
 +	msnLoggedIn = false;
 +
 +	if (mStatusMsgTS)
 +		ForkThread(&CMsnProto::msn_storeProfileThread, NULL);
 +
 +	mir_free(msnPreviousUUX);
 +	msnPreviousUUX = NULL;
 +	msnSearchId = NULL;
 +
 +	if (!Miranda_Terminated())
 +		MSN_EnableMenuItems(false);
 +
 +	MSN_FreeGroups();
 +	MsgQueue_Clear();
 +	clearCachedMsg();
 +
 +	if (!Miranda_Terminated()) {
 +		int msnOldStatus = m_iStatus; m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
 +		ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)msnOldStatus, ID_STATUS_OFFLINE);
 +		isIdle = false;
 +
 +		int count = -1;
 +		for (;;) {
 +			MsnContact *msc = Lists_GetNext(count);
 +			if (msc == NULL) break;
 +
 +			if (ID_STATUS_OFFLINE != getWord(msc->hContact, "Status", ID_STATUS_OFFLINE)) {
 +				setWord(msc->hContact, "Status", ID_STATUS_OFFLINE);
 +				setDword(msc->hContact, "IdleTS", 0);
 +			}
 +		}
 +	}
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_SendMessage - formats and sends a MSG packet through the server
 +
 +int ThreadData::sendMessage(int msgType, const char* email, int netId, const char* parMsg, int parFlags)
 +{
 +	char buf[2048];
 +	int off;
 +
 +	off = mir_snprintf(buf, sizeof(buf), "MIME-Version: 1.0\r\n");
 +
 +	if ((parFlags & MSG_DISABLE_HDR) == 0) {
 +		char  tFontName[100], tFontStyle[3];
 +		DWORD tFontColor;
 +
 +		strcpy(tFontName, "Arial");
 +
 +		if (proto->getByte("SendFontInfo", 1)) {
 +			char* p;
 +
 +			DBVARIANT dbv;
 +			if (!db_get_s(NULL, "SRMsg", "Font0", &dbv)) {
 +				for (p = dbv.pszVal; *p; p++)
 +					if (BYTE(*p) >= 128 || *p < 32)
 +						break;
 +
 +				if (*p == 0) {
 +					strncpy_s(tFontName, sizeof(tFontName), ptrA(mir_urlEncode(dbv.pszVal)), _TRUNCATE);
 +					db_free(&dbv);
 +				}
 +			}
 +
 +			int  tStyle = db_get_b(NULL, "SRMsg", "Font0Sty", 0);
 +			p = tFontStyle;
 +			if (tStyle & 1) *p++ = 'B';
 +			if (tStyle & 2) *p++ = 'I';
 +			*p = 0;
 +
 +			tFontColor = db_get_dw(NULL, "SRMsg", "Font0Col", 0);
 +		}
 +		else {
 +			tFontColor = 0;
 +			tFontStyle[0] = 0;
 +		}
 +
 +		if (parFlags & MSG_OFFLINE)
 +			off += mir_snprintf(buf + off, sizeof(buf) - off, "Dest-Agent: client\r\n");
 +
 +		off += mir_snprintf(buf + off, sizeof(buf) - off, "Content-Type: text/plain; charset=UTF-8\r\n");
 +		off += mir_snprintf(buf + off, sizeof(buf) - off, "X-MMS-IM-Format: FN=%s; EF=%s; CO=%x; CS=0; PF=31%s\r\n\r\n",
 +			tFontName, tFontStyle, tFontColor, (parFlags & MSG_RTL) ? ";RL=1" : "");
 +	}
 +
 +	int seq;
 +	if (netId == NETID_YAHOO || netId == NETID_MOB || (parFlags & MSG_OFFLINE))
 +		seq = sendPacket("UUM", "%s %d %c %d\r\n%s%s", email, netId, msgType,
 +		strlen(parMsg)+off, buf, parMsg);
 +	else
 +		seq = sendPacket("MSG", "%c %d\r\n%s%s", msgType,
 +		strlen(parMsg)+off, buf, parMsg);
 +
 +	return seq;
 +}
 +
 +void ThreadData::sendCaps(void)
 +{
 +	char mversion[100], capMsg[1000];
 +	CallService(MS_SYSTEM_GETVERSIONTEXT, sizeof(mversion), (LPARAM)mversion);
 +
 +	mir_snprintf(capMsg, sizeof(capMsg),
 +		"Content-Type: text/x-clientcaps\r\n\r\n"
 +		"Client-Name: Miranda NG %s (MSN v.%s)\r\n",
 +		mversion, __VERSION_STRING_DOTS);
 +
 +	sendMessage('U', NULL, 1, capMsg, MSG_DISABLE_HDR);
 +}
 +
 +void ThreadData::sendTerminate(void)
 +{
 +	if (!termPending) {
 +		sendPacket("OUT", NULL);
 +		termPending = true;
 +	}
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_SendRawPacket - sends a packet accordingly to the MSN protocol
 +
 +int ThreadData::sendRawMessage(int msgType, const char* data, int datLen)
 +{
 +	if (data == NULL)
 +		data = "";
 +
 +	if (datLen == -1)
 +		datLen = (int)strlen(data);
 +
 +	char* buf = (char*)alloca(datLen + 100);
 +
 +	int thisTrid = InterlockedIncrement(&mTrid);
 +	int nBytes = mir_snprintf(buf, 100, "MSG %d %c %d\r\nMIME-Version: 1.0\r\n",
 +		thisTrid, msgType, datLen + 19);
 +	memcpy(buf + nBytes, data, datLen);
 +
 +	send(buf, nBytes + datLen);
 +
 +	return thisTrid;
 +}
 +
 +// Typing notifications support
 +
 +void CMsnProto::MSN_SendTyping(ThreadData* info, const char* email, int netId )
 +{
 +	char tCommand[1024];
 +	mir_snprintf(tCommand, sizeof(tCommand),
 +		"Content-Type: text/x-msmsgscontrol\r\n"
 +		"TypingUser: %s\r\n\r\n\r\n", MyOptions.szEmail);
 +
 +	info->sendMessage(netId == NETID_MSN ? 'U' : '2', email, netId, tCommand, MSG_DISABLE_HDR);
 +}
 +
 +
 +static ThreadData* FindThreadTimer(UINT timerId)
 +{
 +	ThreadData* res = NULL;
 +	for (int i = 0; i < g_Instances.getCount() && res == NULL; ++i)
 +		res = g_Instances[i].MSN_GetThreadByTimer(timerId);
 +
 +	return res;
 +}
 +
 +static VOID CALLBACK TypingTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
 +{
 +	ThreadData* T = FindThreadTimer(idEvent);
 +	if (T != NULL)
 +		T->proto->MSN_SendTyping(T, NULL, 1);
 +	else
 +		KillTimer(NULL, idEvent);
 +}
 +
 +
 +void CMsnProto::MSN_StartStopTyping(ThreadData* info, bool start)
 +{
 +	if (start && info->mTimerId == 0) {
 +		info->mTimerId = SetTimer(NULL, 0, 5000, TypingTimerProc);
 +		MSN_SendTyping(info, NULL, 1);
 +	}
 +	else if (!start && info->mTimerId != 0) {
 +		KillTimer(NULL, info->mTimerId);
 +		info->mTimerId = 0;
 +	}
 +}
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_SendStatusMessage - notify a server about the status message change
 +
 +// Helper to process texts
 +static char * HtmlEncodeUTF8T(const TCHAR *src)
 +{
 +	if (src == NULL)
 +		return mir_strdup("");
 +
 +	return HtmlEncode(UTF8(src));
 +}
 +
 +void CMsnProto::MSN_SendStatusMessage(const char* msg)
 +{
 +	if (!msnLoggedIn)
 +		return;
 +
 +	char* msgEnc = HtmlEncode(msg ? msg : "");
 +
 +	size_t sz;
 +	char  szMsg[2048];
 +	if (msnCurrentMedia.cbSize == 0) {
 +		sz = mir_snprintf(szMsg, sizeof(szMsg), "<Data><PSM>%s</PSM><CurrentMedia></CurrentMedia><MachineGuid>%s</MachineGuid>"
 +			"<DDP></DDP><SignatureSound></SignatureSound><Scene></Scene><ColorScheme></ColorScheme></Data>",
 +			msgEnc, MyOptions.szMachineGuid);
 +	}
 +	else {
 +		char *szFormatEnc;
 +		if (ServiceExists(MS_LISTENINGTO_GETPARSEDTEXT)) {
 +			LISTENINGTOINFO lti = {0};
 +			lti.cbSize = sizeof(lti);
 +			if (msnCurrentMedia.ptszTitle != NULL) lti.ptszTitle = _T("{0}");
 +			if (msnCurrentMedia.ptszArtist != NULL) lti.ptszArtist = _T("{1}");
 +			if (msnCurrentMedia.ptszAlbum != NULL) lti.ptszAlbum = _T("{2}");
 +			if (msnCurrentMedia.ptszTrack != NULL) lti.ptszTrack = _T("{3}");
 +			if (msnCurrentMedia.ptszYear != NULL) lti.ptszYear = _T("{4}");
 +			if (msnCurrentMedia.ptszGenre != NULL) lti.ptszGenre = _T("{5}");
 +			if (msnCurrentMedia.ptszLength != NULL) lti.ptszLength = _T("{6}");
 +			if (msnCurrentMedia.ptszPlayer != NULL) lti.ptszPlayer = _T("{7}");
 +			if (msnCurrentMedia.ptszType != NULL) lti.ptszType = _T("{8}");
 +
 +			TCHAR *tmp = (TCHAR *)CallService(MS_LISTENINGTO_GETPARSEDTEXT, (WPARAM) _T("%title% - %artist%"), (LPARAM) <i);
 +			szFormatEnc = HtmlEncodeUTF8T(tmp);
 +			mir_free(tmp);
 +		}
 +		else szFormatEnc = HtmlEncodeUTF8T(_T("{0} - {1}"));
 +
 +		char *szArtist = HtmlEncodeUTF8T(msnCurrentMedia.ptszArtist);
 +		char *szAlbum = HtmlEncodeUTF8T(msnCurrentMedia.ptszAlbum);
 +		char *szTitle = HtmlEncodeUTF8T(msnCurrentMedia.ptszTitle);
 +		char *szTrack = HtmlEncodeUTF8T(msnCurrentMedia.ptszTrack);
 +		char *szYear = HtmlEncodeUTF8T(msnCurrentMedia.ptszYear);
 +		char *szGenre = HtmlEncodeUTF8T(msnCurrentMedia.ptszGenre);
 +		char *szLength = HtmlEncodeUTF8T(msnCurrentMedia.ptszLength);
 +		char *szPlayer = HtmlEncodeUTF8T(msnCurrentMedia.ptszPlayer);
 +		char *szType = HtmlEncodeUTF8T(msnCurrentMedia.ptszType);
 +
 +		sz = mir_snprintf(szMsg, sizeof szMsg,
 +			"<Data>"
 +			"<PSM>%s</PSM>"
 +			"<CurrentMedia>%s\\0%s\\01\\0%s\\0%s\\0%s\\0%s\\0%s\\0%s\\0%s\\0%s\\0%s\\0%s\\0\\0</CurrentMedia>"
 +			"<MachineGuid>%s</MachineGuid><DDP></DDP><SignatureSound></SignatureSound><Scene></Scene><ColorScheme></ColorScheme>"
 +			"<DDP></DDP><SignatureSound></SignatureSound><Scene></Scene><ColorScheme></ColorScheme>"
 +			"</Data>",
 +			msgEnc, szPlayer, szType, szFormatEnc, szTitle, szArtist, szAlbum, szTrack, szYear, szGenre,
 +			szLength, szPlayer, szType, MyOptions.szMachineGuid);
 +
 +		mir_free(szArtist);
 +		mir_free(szAlbum);
 +		mir_free(szTitle);
 +		mir_free(szTrack);
 +		mir_free(szYear);
 +		mir_free(szGenre);
 +		mir_free(szLength);
 +		mir_free(szPlayer);
 +		mir_free(szType);
 +	}
 +	mir_free(msgEnc);
 +
 +	if (msnPreviousUUX == NULL || strcmp(msnPreviousUUX, szMsg)) {
 +		replaceStr(msnPreviousUUX, szMsg);
 +		msnNsThread->sendPacket("UUX", "%d\r\n%s", sz, szMsg);
 +		mStatusMsgTS = clock();
 +	}
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_SendPacket - sends a packet accordingly to the MSN protocol
 +
 +int ThreadData::sendPacket(const char* cmd, const char* fmt,...)
 +{
 +	if (this == NULL) return 0;
 +
 +	size_t strsize = 512;
 +	char* str = (char*)mir_alloc(strsize);
 +
 +	int thisTrid = 0;
 +
 +	if (fmt == NULL)
 +		mir_snprintf(str, strsize, "%s", cmd);
 +	else {
 +		thisTrid = InterlockedIncrement(&mTrid);
 +		if (fmt[0] == '\0')
 +			mir_snprintf(str, strsize, "%s %d", cmd, thisTrid);
 +		else {
 +			va_list vararg;
 +			va_start(vararg, fmt);
 +
 +			int paramStart = mir_snprintf(str, strsize, "%s %d ", cmd, thisTrid);
 +			while (mir_vsnprintf(str+paramStart, strsize-paramStart-3, fmt, vararg) == -1)
 +				str = (char*)mir_realloc(str, strsize += 512);
 +
 +			str[strsize-3] = 0;
 +			va_end(vararg);
 +		}
 +	}
 +
 +	if (strchr(str, '\r') == NULL)
 +		strcat(str,"\r\n");
 +
 +	int result = send(str, strlen(str));
 +	mir_free(str);
 +	return (result > 0) ? thisTrid : -1;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_SetServerStatus - changes plugins status at the server
 +
 +void CMsnProto::MSN_SetServerStatus(int newStatus)
 +{
 +	debugLogA("Setting MSN server status %d, logged in = %d", newStatus, msnLoggedIn);
 +
 +	if (!msnLoggedIn)
 +		return;
 +
 +	if (isIdle)
 +		newStatus = ID_STATUS_IDLE;
 +
 +	const char* szStatusName = MirandaStatusToMSN(newStatus);
 +
 +	if (newStatus != ID_STATUS_OFFLINE) {
 +		DBVARIANT msnObject = {0};
 +		if (ServiceExists(MS_AV_SETMYAVATAR))
 +			getString("PictObject", &msnObject);
 +
 +		// Capabilties: WLM 2009, Chunking, UUN Bootstrap
 +		myFlags = 0xA0000000 | cap_SupportsChunking | cap_SupportsP2PBootstrap | cap_SupportsSipInvite;
 +		if (getByte("MobileEnabled", 0) && getByte("MobileAllowed", 0))
 +			myFlags |= cap_MobileEnabled;
 +
 +		unsigned myFlagsEx = capex_SupportsPeerToPeerV2;
 +
 +		char szMsg[256];
 +		if (m_iStatus < ID_STATUS_ONLINE) {
 +			int sz = mir_snprintf(szMsg, sizeof(szMsg),
 +				"<EndpointData><Capabilities>%u:%u</Capabilities></EndpointData>", myFlags, myFlagsEx);
 +			msnNsThread->sendPacket( "UUX", "%d\r\n%s", sz, szMsg );
 +
 +			msnNsThread->sendPacket("BLP", msnOtherContactsBlocked ? "BL" : "AL");
 +
 +			DBVARIANT dbv;
 +			if (!getStringUtf("Nick", &dbv)) {
 +				if (dbv.pszVal[0])
 +					MSN_SetNicknameUtf(dbv.pszVal);
 +				db_free(&dbv);
 +			}
 +		}
 +
 +		char *szPlace;
 +		DBVARIANT dbv;
 +		if	(!getStringUtf("Place", &dbv))
 +			szPlace = dbv.pszVal;
 +		else {
 +			TCHAR buf[128] = _T("Miranda");
 +			DWORD buflen = SIZEOF(buf);
 +			GetComputerName(buf, &buflen);
 +			szPlace =  mir_utf8encodeT(buf);
 +		}
 +
 +		int sz = mir_snprintf(szMsg, sizeof(szMsg),
 +			"<PrivateEndpointData>"
 +			"<EpName>%s</EpName>"
 +			"<Idle>%s</Idle>"
 +			"<ClientType>1</ClientType>"
 +			"<State>%s</State>"
 +			"</PrivateEndpointData>",
 +			szPlace, newStatus == ID_STATUS_IDLE ? "true" : "false", szStatusName);
 +		msnNsThread->sendPacket("UUX", "%d\r\n%s", sz, szMsg);
 +		mir_free(szPlace);
 +
 +		if (newStatus != ID_STATUS_IDLE) {
 +			char** msgptr = GetStatusMsgLoc(newStatus);
 +			if (msgptr != NULL)
 +				MSN_SendStatusMessage(*msgptr);
 +		}
 +
 +		msnNsThread->sendPacket("CHG", "%s %u:%u %s", szStatusName, myFlags, myFlagsEx, msnObject.pszVal ? msnObject.pszVal : "0");
 +		db_free(&msnObject);
 +	}
 +	else msnNsThread->sendPacket("CHG", szStatusName);
 +}
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// Display Hotmail Inbox thread
 +
 +static const char postdataM[] = "ct=%u&bver=7&wa=wsignin1.0&ru=%s&pl=MBI";
 +static const char postdataS[] = "ct=%u&bver=7&id=73625&ru=%s&js=yes&pl=%%3Fid%%3D73625";
 +
 +void CMsnProto::MsnInvokeMyURL(bool ismail, const char* url)
 +{
 +	char* hippy = NULL;
 +	if (!url)
 +		url = ismail ? "http://mail.live.com?rru=inbox" : "http://profile.live.com";
 +
 +	const char *postdata = ismail ? postdataM : postdataS;
 +
 +	char passport[256];
 +	if (db_get_static(NULL, m_szModuleName, "MsnPassportHost", passport, 256))
 +		strcpy(passport, "https://login.live.com/");
 +
 +	char *p = strchr(passport, '/');
 +	if (p && p[1] == '/') p = strchr(p + 2, '/');
 +	if (p)
 +		*p = 0;
 +
 +	CMStringA post = HotmailLogin(CMStringA().Format(postdata, (unsigned)time(NULL), ptrA(mir_urlEncode(url))));
 +	if (!post.IsEmpty()) {
 +		CMStringA hippy(passport);
 +		hippy.AppendFormat("/ppsecure/sha1auth.srf?lc=%d&token=%s", itoa(langpref, passport, 10), ptrA(mir_urlEncode(post)));
 +
 +		debugLogA("Starting URL: '%s'", hippy);
 +		CallService(MS_UTILS_OPENURL, 1, (LPARAM)hippy.GetString());
 +	}
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_ShowError - shows an error
 +
 +void CMsnProto::MSN_ShowError(const char* msgtext, ...)
 +{
 +	TCHAR   tBuffer[4096];
 +	va_list tArgs;
 +
 +	TCHAR *buf = Langpack_PcharToTchar(msgtext);
 +
 +	va_start(tArgs, msgtext);
 +	mir_vsntprintf(tBuffer, SIZEOF(tBuffer), buf, tArgs);
 +	va_end(tArgs);
 +
 +	mir_free(buf);
 +
 +	MSN_ShowPopup(m_tszUserName, tBuffer, MSN_ALLOW_MSGBOX | MSN_SHOW_ERROR, NULL);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// Popup plugin window proc
 +
 +LRESULT CALLBACK NullWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 +{
 +	PopupData *tData = (PopupData*)PUGetPluginData(hWnd);
 +
 +	switch (msg) {
 +	case WM_COMMAND:
 +		if (tData != NULL) {
 +			if (tData->flags & MSN_HOTMAIL_POPUP) {
 +				MCONTACT hContact = tData->proto->MSN_HContactFromEmail(tData->proto->MyOptions.szEmail, NULL);
 +				if (hContact) CallService(MS_CLIST_REMOVEEVENT, hContact, (LPARAM) 1);
 +				if (tData->flags & MSN_ALLOW_ENTER)
 +					tData->proto->MsnInvokeMyURL(true, tData->url);
 +			}
 +			else if (tData->url != NULL)
 +				CallService(MS_UTILS_OPENURL, 1, (LPARAM)tData->url);
 +		}
 +		PUDeletePopup(hWnd);
 +		break;
 +
 +	case WM_CONTEXTMENU:
 +		if (tData != NULL && tData->flags & MSN_HOTMAIL_POPUP) {
 +			MCONTACT hContact = tData->proto->MSN_HContactFromEmail(tData->proto->MyOptions.szEmail, NULL);
 +			if (hContact)
 +				CallService(MS_CLIST_REMOVEEVENT, hContact, (LPARAM) 1);
 +		}
 +		PUDeletePopup(hWnd);
 +		break;
 +
 +	case UM_FREEPLUGINDATA:
 +		if (tData != NULL && tData != (PopupData*)CALLSERVICE_NOTFOUND) {
 +			mir_free(tData->title);
 +			mir_free(tData->text);
 +			mir_free(tData->url);
 +			mir_free(tData);
 +		}
 +		break;
 +	}
 +
 +	return DefWindowProc(hWnd, msg, wParam, lParam);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// InitPopups - popup plugin support
 +
 +void CMsnProto::InitPopups(void)
 +{
 +	TCHAR desc[256];
 +	char name[256];
 +
 +	POPUPCLASS ppc = { sizeof(ppc) };
 +	ppc.flags = PCF_TCHAR;
 +	ppc.PluginWindowProc = NullWindowProc;
 +	ppc.hIcon = LoadIconEx("main");
 +	ppc.ptszDescription = desc;
 +	ppc.pszName = name;
 +
 +	ppc.colorBack = RGB(173, 206, 247);
 +	ppc.colorText =  GetSysColor(COLOR_WINDOWTEXT);
 +	ppc.iSeconds = 3;
 +	mir_sntprintf(desc, SIZEOF(desc), _T("%s/%s"), m_tszUserName, TranslateT("Hotmail"));
 +	mir_snprintf(name, SIZEOF(name), "%s_%s", m_szModuleName, "Hotmail");
 +	hPopupHotmail = Popup_RegisterClass(&ppc);
 +
 +	ppc.colorBack = RGB(173, 206, 247);
 +	ppc.colorText =  GetSysColor(COLOR_WINDOWTEXT);
 +	ppc.iSeconds = 3;
 +	mir_sntprintf(desc, SIZEOF(desc), _T("%s/%s"), m_tszUserName, TranslateT("Notify"));
 +	mir_snprintf(name, SIZEOF(name), "%s_%s", m_szModuleName, "Notify");
 +	hPopupNotify = Popup_RegisterClass(&ppc);
 +
 +	ppc.hIcon = (HICON)LoadImage(NULL, IDI_WARNING, IMAGE_ICON, 0, 0, LR_SHARED);
 +	ppc.colorBack = RGB(191, 0, 0); //Red
 +	ppc.colorText = RGB(255, 245, 225); //Yellow
 +	ppc.iSeconds = 60;
 +
 +	mir_sntprintf(desc, SIZEOF(desc), _T("%s/%s"), m_tszUserName, TranslateT("Error"));
 +	mir_snprintf(name, SIZEOF(name), "%s_%s", m_szModuleName, "Error");
 +	hPopupError = Popup_RegisterClass(&ppc);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_ShowPopup - popup plugin support
 +
 +void CALLBACK sttMainThreadCallback(PVOID dwParam)
 +{
 +	PopupData* pud = (PopupData*)dwParam;
 +
 +	bool iserr = (pud->flags & MSN_SHOW_ERROR) != 0;
 +	if ((iserr && !pud->proto->MyOptions.ShowErrorsAsPopups) || !ServiceExists(MS_POPUP_ADDPOPUPCLASS)) {
 +		if (pud->flags & MSN_ALLOW_MSGBOX) {
 +			TCHAR szMsg[MAX_SECONDLINE + MAX_CONTACTNAME];
 +			mir_sntprintf(szMsg, SIZEOF(szMsg), _T("%s:\n%s"), pud->title, pud->text);
 +			MessageBox(NULL, szMsg, TranslateT("MSN Protocol"),
 +				MB_OK | (iserr ? MB_ICONERROR : MB_ICONINFORMATION));
 +		}
 +		mir_free(pud->title);
 +		mir_free(pud->text);
 +		mir_free(pud->url);
 +		mir_free(pud);
 +		return;
 +	}
 +
 +	char name[256];
 +
 +	POPUPDATACLASS ppd = { sizeof(ppd) };
 +	ppd.ptszTitle = pud->title;
 +	ppd.ptszText = pud->text;
 +	ppd.PluginData = pud;
 +	ppd.pszClassName = name;
 +
 +	if (pud->flags & MSN_SHOW_ERROR)
 +		mir_snprintf(name, SIZEOF(name), "%s_%s", pud->proto->m_szModuleName, "Error");
 +	else if (pud->flags & (MSN_HOTMAIL_POPUP | MSN_ALERT_POPUP))
 +		mir_snprintf(name, SIZEOF(name), "%s_%s", pud->proto->m_szModuleName, "Hotmail");
 +	else
 +		mir_snprintf(name, SIZEOF(name), "%s_%s", pud->proto->m_szModuleName, "Notify");
 +
 +	CallService(MS_POPUP_ADDPOPUPCLASS, 0, (LPARAM)&ppd);
 +}
 +
 +void CMsnProto::MSN_ShowPopup(const TCHAR* nickname, const TCHAR* msg, int flags, const char* url, MCONTACT hContact)
 +{
 +	if (Miranda_Terminated()) return;
 +
 +	PopupData *pud = (PopupData*)mir_calloc(sizeof(PopupData));
 +	pud->flags = flags;
 +	pud->url = mir_strdup(url);
 +	pud->title = mir_tstrdup(nickname);
 +	pud->text = mir_tstrdup(msg);
 +	pud->proto = this;
 +
 +	CallFunctionAsync(sttMainThreadCallback, pud);
 +}
 +
 +
 +void CMsnProto::MSN_ShowPopup(const MCONTACT hContact, const TCHAR* msg, int flags)
 +{
 +	const TCHAR* nickname = hContact ? GetContactNameT(hContact) : _T("Me");
 +	MSN_ShowPopup(nickname, msg, flags, NULL, hContact);
 +}
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// filetransfer class members
 +
 +filetransfer::filetransfer(CMsnProto* prt)
 +{
 +	memset(this, 0, sizeof(filetransfer));
 +	fileId = -1;
 +	std.cbSize = sizeof(std);
 +	std.flags = PFTS_TCHAR;
 +	proto = prt;
 +
 +	hLockHandle = CreateMutex(NULL, FALSE, NULL);
 +}
 +
 +filetransfer::~filetransfer(void)
 +{
 +	if (p2p_sessionid)
 +		proto->debugLogA("Destroying file transfer session %08X", p2p_sessionid);
 +
 +	WaitForSingleObject(hLockHandle, 2000);
 +	CloseHandle(hLockHandle);
 +
 +	if (fileId != -1)
 +	{
 +		_close(fileId);
 +		if (p2p_appID != MSN_APPID_FILE && !(std.flags & PFTS_SENDING))
 +			proto->p2p_pictureTransferFailed(this);
 +	}
 +
 +	if (!bCompleted && p2p_appID == MSN_APPID_FILE)
 +	{
 +		std.ptszFiles = NULL;
 +		std.totalFiles = 0;
 +		proto->ProtoBroadcastAck(std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, this, 0);
 +	}
 +
 +	mir_free(p2p_branch);
 +	mir_free(p2p_callID);
 +	mir_free(p2p_dest);
 +	mir_free(p2p_object);
 +
 +	mir_free(std.tszCurrentFile);
 +	mir_free(std.tszWorkingDir);
 +	if (std.ptszFiles != NULL)
 +	{
 +		for (int i=0; std.ptszFiles[i]; i++)
 +			mir_free(std.ptszFiles[i]);
 +		mir_free(std.ptszFiles);
 +	}
 +
 +	mir_free(szInvcookie);
 +}
 +
 +void filetransfer::close(void)
 +{
 +	if (fileId != -1) _close(fileId);
 +	fileId = -1;
 +}
 +
 +void filetransfer::complete(void)
 +{
 +	close();
 +
 +	bCompleted = true;
 +	proto->ProtoBroadcastAck(std.hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, this, 0);
 +}
 +
 +int filetransfer::create(void)
 +{
 +	fileId = _topen(std.tszCurrentFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE);
 +
 +	if (fileId == -1)
 +		proto->MSN_ShowError("Cannot create file '%s' during a file transfer", std.tszCurrentFile);
 +	//	else if (std.currentFileSize != 0)
 +	//		_chsize(fileId, std.currentFileSize);
 +
 +	return fileId;
 +}
 +
 +int filetransfer::openNext(void)
 +{
 +	if (fileId != -1)
 +	{
 +		close();
 +		++std.currentFileNumber;
 +		++cf;
 +	}
 +
 +	while (std.ptszFiles && std.ptszFiles[cf])
 +	{
 +		struct _stati64 statbuf;
 +		if (_tstati64(std.ptszFiles[cf], &statbuf) == 0 && (statbuf.st_mode & _S_IFDIR) == 0)
 +			break;
 +
 +		++cf;
 +	}
 +
 +	if (std.ptszFiles && std.ptszFiles[cf])
 +	{
 +		bCompleted = false;
 +		replaceStrT(std.tszCurrentFile, std.ptszFiles[cf]);
 +		fileId = _topen(std.tszCurrentFile, _O_BINARY | _O_RDONLY, _S_IREAD);
 +		if (fileId != -1)
 +		{
 +			std.currentFileSize = _filelengthi64(fileId);
 +			std.currentFileProgress = 0;
 +
 +			p2p_sendmsgid = 0;
 +			p2p_byemsgid = 0;
 +			tType = SERVER_NOTIFICATION;
 +			bAccepted = false;
 +
 +			mir_free(p2p_branch); p2p_branch = NULL;
 +			mir_free(p2p_callID); p2p_callID = NULL;
 +		}
 +		else
 +			proto->MSN_ShowError("Unable to open file '%s' for the file transfer, error %d", std.tszCurrentFile, errno);
 +	}
 +
 +	return fileId;
 +}
 +
 +directconnection::directconnection(const char* CallID, const char* Wlid)
 +{
 +	memset(this, 0, sizeof(directconnection));
 +
 +	wlid = mir_strdup(Wlid);
 +	callId = mir_strdup(CallID);
 +	mNonce = (UUID*)mir_alloc(sizeof(UUID));
 +	UuidCreate(mNonce);
 +	ts = time(NULL);
 +}
 +
 +directconnection::~directconnection()
 +{
 +	mir_free(wlid);
 +	mir_free(callId);
 +	mir_free(mNonce);
 +	mir_free(xNonce);
 +}
 +
 +
 +char* directconnection::calcHashedNonce(UUID* nonce)
 +{
 +	mir_sha1_ctx sha1ctx;
 +	BYTE sha[MIR_SHA1_HASH_SIZE];
 +
 +	mir_sha1_init(&sha1ctx);
 +	mir_sha1_append(&sha1ctx, (BYTE*)nonce, sizeof(UUID));
 +	mir_sha1_finish(&sha1ctx, sha);
 +
 +	char* p;
 +	UuidToStringA((UUID*)&sha, (BYTE**)&p);
 +	size_t len = strlen(p) + 3;
 +	char* result = (char*)mir_alloc(len);
 +	mir_snprintf(result, len, "{%s}", p);
 +	_strupr(result);
 +	RpcStringFreeA((BYTE**)&p);
 +
 +	return result;
 +}
 +
 +char* directconnection::mNonceToText(void)
 +{
 +	char* p;
 +	UuidToStringA(mNonce, (BYTE**)&p);
 +	size_t len = strlen(p) + 3;
 +	char* result = (char*)mir_alloc(len);
 +	mir_snprintf(result, len, "{%s}", p);
 +	_strupr(result);
 +	RpcStringFreeA((BYTE**)&p);
 +
 +	return result;
 +}
 +
 +
 +void directconnection::xNonceToBin(UUID* nonce)
 +{
 +	size_t len = strlen(xNonce);
 +	char *p = (char*)alloca(len);
 +	strcpy(p, xNonce + 1);
 +	p[len-2] = 0;
 +	UuidFromStringA((BYTE*)p, nonce);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// TWinErrorCode class
 +
 +TWinErrorCode::TWinErrorCode() : mErrorText(NULL)
 +{
 +	mErrorCode = ::GetLastError();
 +}
 +
 +TWinErrorCode::~TWinErrorCode()
 +{
 +	mir_free(mErrorText);
 +}
 +
 +char* TWinErrorCode::getText()
 +{
 +	if (mErrorText == NULL)
 +		return NULL;
 +
 +	int tBytes = 0;
 +	mErrorText = (char*)mir_alloc(256);
 +
 +	if (tBytes == 0)
 +		tBytes = FormatMessageA(
 +		FORMAT_MESSAGE_FROM_SYSTEM, NULL,
 +		mErrorCode, LANG_NEUTRAL, mErrorText, 256, NULL);
 +
 +	if (tBytes == 0)
 +		tBytes = mir_snprintf(mErrorText, 256, "unknown Windows error code %d", mErrorCode);
 +
 +	*mErrorText = (char)tolower(*mErrorText);
 +
 +	if (mErrorText[tBytes-1] == '\n')
 +		mErrorText[--tBytes] = 0;
 +	if (mErrorText[tBytes-1] == '\r')
 +		mErrorText[--tBytes] = 0;
 +	if (mErrorText[tBytes-1] == '.')
 +		mErrorText[tBytes-1] = 0;
 +
 +	return mErrorText;
 +}
 +
 +bool CMsnProto::MSN_IsMyContact(MCONTACT hContact)
 +{
 +	const char* szProto = GetContactProto(hContact);
 +	return szProto != NULL && strcmp(m_szModuleName, szProto) == 0;
 +}
 +
 +bool CMsnProto::MSN_IsMeByContact(MCONTACT hContact, char* szEmail)
 +{
 +	char tEmail[MSN_MAX_EMAIL_LEN];
 +	char *emailPtr = szEmail ? szEmail : tEmail;
 +
 +	*emailPtr = 0;
 +	if (db_get_static(hContact, m_szModuleName, "e-mail", emailPtr, sizeof(tEmail)))
 +		return false;
 +
 +	return _stricmp(emailPtr, MyOptions.szEmail) == 0;
 +}
 +
 +bool MSN_MsgWndExist(MCONTACT hContact)
 +{
 +	MessageWindowInputData msgWinInData =
 +	{ sizeof(MessageWindowInputData), hContact, MSG_WINDOW_UFLAG_MSG_BOTH };
 +	MessageWindowData msgWinData = {0};
 +	msgWinData.cbSize = sizeof(MessageWindowData);
 +
 +	bool res = CallService(MS_MSG_GETWINDOWDATA, (WPARAM)&msgWinInData, (LPARAM)&msgWinData) != 0;
 +	res = res || msgWinData.hwndWindow;
 +	if (res) {
 +		msgWinInData.hContact = db_mc_getMeta(hContact);
 +		if (msgWinInData.hContact != NULL) {
 +			res = CallService(MS_MSG_GETWINDOWDATA, (WPARAM)&msgWinInData, (LPARAM)&msgWinData) != 0;
 +			res |= (msgWinData.hwndWindow == NULL);
 +		}
 +	}
 +	return res;
 +}
 +
 +void MSN_MakeDigest(const char* chl, char* dgst)
 +{
 +	//Digest it
 +	DWORD md5hash[4], md5hashOr[4];
 +	mir_md5_state_t context;
 +	mir_md5_init(&context);
 +	mir_md5_append(&context, (BYTE*)chl, (int)strlen(chl));
 +	mir_md5_append(&context, (BYTE*)msnProtChallenge, (int)strlen(msnProtChallenge));
 +	mir_md5_finish(&context, (BYTE*)md5hash);
 +
 +	memcpy(md5hashOr, md5hash, sizeof(md5hash));
 +
 +	size_t i;
 +	for (i=0; i < 4; i++)
 +		md5hash[i] &= 0x7FFFFFFF;
 +
 +	char chlString[128];
 +	mir_snprintf(chlString, sizeof(chlString), "%s%s00000000", chl, msnProductID);
 +	chlString[(strlen(chl)+strlen(msnProductID)+7) & 0xF8] = 0;
 +
 +	LONGLONG high=0, low=0;
 +	int* chlStringArray = (int*)chlString;
 +	for (i=0; i < strlen(chlString) / 4; i += 2) {
 +		LONGLONG temp = chlStringArray[i];
 +
 +		temp = (0x0E79A9C1 * temp) % 0x7FFFFFFF;
 +		temp += high;
 +		temp = md5hash[0] * temp + md5hash[1];
 +		temp = temp % 0x7FFFFFFF;
 +
 +		high = chlStringArray[i + 1];
 +		high = (high + temp) % 0x7FFFFFFF;
 +		high = md5hash[2] * high + md5hash[3];
 +		high = high % 0x7FFFFFFF;
 +
 +		low = low + high + temp;
 +	}
 +	high = (high + md5hash[1]) % 0x7FFFFFFF;
 +	low = (low + md5hash[3]) % 0x7FFFFFFF;
 +
 +	md5hashOr[0] ^= high;
 +	md5hashOr[1] ^= low;
 +	md5hashOr[2] ^= high;
 +	md5hashOr[3] ^= low;
 +
 +	char* str = arrayToHex((PBYTE)md5hashOr, sizeof(md5hashOr));
 +	strcpy(dgst, str);
 +	mir_free(str);
 +}
 +
 +char* GetGlobalIp(void)
 +{
 +	NETLIBIPLIST* ihaddr = (NETLIBIPLIST*)CallService(MS_NETLIB_GETMYIP, 1, 0);
 +	for (unsigned i = 0; i < ihaddr->cbNum; ++i)
 +		if (strchr(ihaddr->szIp[i], ':'))
 +			return mir_strdup(ihaddr->szIp[i]);
 +
 +	mir_free(ihaddr);
 +	return NULL;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_msgqueue.cpp b/plugins/!Deprecated/MSN/src/msn_msgqueue.cpp new file mode 100644 index 0000000000..c11887c53d --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_msgqueue.cpp @@ -0,0 +1,190 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +//a few little functions to manage queuing send message requests until the
 +//connection is established
 +
 +void CMsnProto::MsgQueue_Init(void)
 +{
 +	msgQueueSeq = 1;
 +}
 +
 +void CMsnProto::MsgQueue_Uninit(void)
 +{
 +	MsgQueue_Clear();
 +}
 +
 +int CMsnProto::MsgQueue_Add(const char* wlid, int msgType, const char* msg, int msgSize, filetransfer* ft, int flags, STRLIST *cnt)
 +{
 +	mir_cslock lck(csMsgQueue);
 +
 +	MsgQueueEntry* E = new MsgQueueEntry;
 +	lsMessageQueue.insert(E);
 +
 +	int seq = msgQueueSeq++;
 +
 +	E->wlid = mir_strdup(wlid);
 +	E->msgSize = msgSize;
 +	E->msgType = msgType;
 +	if (msgSize <= 0)
 +		E->message = mir_strdup(msg);
 +	else
 +		memcpy(E->message = (char*)mir_alloc(msgSize), msg, msgSize);
 +	E->ft = ft;
 +	E->cont = cnt;
 +	E->seq = seq;
 +	E->flags = flags;
 +	E->allocatedToThread = 0;
 +	E->ts = time(NULL);
 +	return seq;
 +}
 +
 +// shall we create another session?
 +const char* CMsnProto::MsgQueue_CheckContact(const char* wlid, time_t tsc)
 +{
 +	time_t ts = time(NULL);
 +
 +	mir_cslock lck(csMsgQueue);
 +
 +	for (int i=0; i < lsMessageQueue.getCount(); i++)
 +		if (_stricmp(lsMessageQueue[i].wlid, wlid) == 0 && (tsc == 0 || (ts - lsMessageQueue[i].ts) < tsc))
 +			return wlid;
 +
 +	return NULL;
 +}
 +
 +//for threads to determine who they should connect to
 +const char* CMsnProto::MsgQueue_GetNextRecipient(void)
 +{
 +	mir_cslock lck(csMsgQueue);
 +
 +	for (int i=0; i < lsMessageQueue.getCount(); i++)
 +	{
 +		MsgQueueEntry& E = lsMessageQueue[i];
 +		if (!E.allocatedToThread)
 +		{
 +			E.allocatedToThread = 1;
 +
 +			const char *ret = E.wlid;
 +			while(++i < lsMessageQueue.getCount())
 +				if (_stricmp(lsMessageQueue[i].wlid, ret) == 0)
 +					lsMessageQueue[i].allocatedToThread = 1;
 +
 +			return ret;
 +		}
 +	}
 +
 +	return NULL;
 +}
 +
 +//deletes from list. Must mir_free() return value
 +bool CMsnProto::MsgQueue_GetNext(const char* wlid, MsgQueueEntry& retVal)
 +{
 +	int i;
 +
 +	mir_cslock lck(csMsgQueue);
 +	for (i = 0; i < lsMessageQueue.getCount(); i++)
 +		if (_stricmp(lsMessageQueue[i].wlid, wlid) == 0)
 +			break;
 +
 +	bool res = i != lsMessageQueue.getCount();
 +	if (res)
 +	{
 +		retVal = lsMessageQueue[i];
 +		lsMessageQueue.remove(i);
 +	}
 +
 +	return res;
 +}
 +
 +int CMsnProto::MsgQueue_NumMsg(const char* wlid)
 +{
 +	int res = 0;
 +	mir_cslock lck(csMsgQueue);
 +
 +	for(int i=0; i < lsMessageQueue.getCount(); i++)
 +		res += (_stricmp(lsMessageQueue[i].wlid, wlid) == 0);
 +
 +	return res;
 +}
 +
 +void CMsnProto::MsgQueue_Clear(const char* wlid, bool msg)
 +{
 +	int i;
 +
 +	mir_cslockfull lck(csMsgQueue);
 +	if (wlid == NULL)
 +	{
 +		for(i=0; i < lsMessageQueue.getCount(); i++)
 +		{
 +			const MsgQueueEntry& E = lsMessageQueue[i];
 +			if (E.msgSize == 0)
 +			{
 +				MCONTACT hContact = MSN_HContactFromEmail(E.wlid);
 +				ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED,
 +					(HANDLE)E.seq, (LPARAM)Translate("Message delivery failed"));
 +			}
 +			mir_free(E.message);
 +			mir_free(E.wlid);
 +			if (E.cont) delete E.cont;
 +		}
 +		lsMessageQueue.destroy();
 +
 +		msgQueueSeq = 1;
 +	}
 +	else
 +	{
 +		for(i=0; i < lsMessageQueue.getCount(); i++)
 +		{
 +			time_t ts = time(NULL);
 +			const MsgQueueEntry& E = lsMessageQueue[i];
 +			if (_stricmp(lsMessageQueue[i].wlid, wlid) == 0 && (!msg || E.msgSize == 0))
 +			{
 +				bool msgfnd = E.msgSize == 0 && E.ts < ts;
 +				int seq = E.seq;
 +
 +				mir_free(E.message);
 +				mir_free(E.wlid);
 +				if (E.cont) delete E.cont;
 +				lsMessageQueue.remove(i);
 +
 +				if (msgfnd) {
 +					lck.unlock();
 +					MCONTACT hContact = MSN_HContactFromEmail(wlid);
 +					ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE)seq,
 +						(LPARAM)Translate("Message delivery failed"));
 +					i = 0;
 +					lck.lock();
 +				}
 +			}
 +		}
 +	}
 +}
 +
 +void __cdecl CMsnProto::MsgQueue_AllClearThread(void* arg)
 +{
 +	MsgQueue_Clear((char*)arg);
 +	mir_free(arg);
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_msgsplit.cpp b/plugins/!Deprecated/MSN/src/msn_msgsplit.cpp new file mode 100644 index 0000000000..ab0e3bb11d --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_msgsplit.cpp @@ -0,0 +1,124 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2007-2012 Boris Krasnovskiy.
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +
 +chunkedmsg::chunkedmsg(const char* tid, const size_t totsz, const bool tbychunk)
 +	: size(totsz), recvsz(0), bychunk(tbychunk)
 +{
 +	id = mir_strdup(tid);
 +	msg = tbychunk ? NULL : (char*)mir_alloc(totsz + 1);
 +}
 +
 +chunkedmsg::~chunkedmsg()
 +{
 +	mir_free(id);
 +	mir_free(msg);
 +}
 +
 +void chunkedmsg::add(const char* tmsg, size_t offset, size_t portion)
 +{
 +	if (bychunk)
 +	{
 +		size_t oldsz = recvsz;
 +		recvsz += portion;
 +		msg  = (char*)mir_realloc(msg, recvsz + 1);
 +		memcpy( msg + oldsz, tmsg, portion );
 +		--size;
 +	}
 +	else
 +	{
 +		size_t newsz = offset + portion;
 +		if (newsz > size)
 +		{
 +			portion = size - offset;
 +			newsz = size;
 +		}
 +		memcpy(msg + offset, tmsg, portion);
 +		if (newsz > recvsz) recvsz = newsz;
 +	}
 +}
 +
 +bool chunkedmsg::get(char*& tmsg, size_t& tsize)
 +{
 +	bool alldata = bychunk ? size == 0 : recvsz == size;
 +	if (alldata)
 +	{
 +		msg[recvsz] = 0;
 +		tmsg = msg;
 +		tsize = recvsz;
 +		msg = NULL;
 +	}
 +
 +	return alldata;
 +}
 +
 +
 +int CMsnProto::addCachedMsg(const char* id, const char* msg, const size_t offset,
 +				 const size_t portion, const size_t totsz, const bool bychunk)
 +{
 +	int idx = msgCache.getIndex((chunkedmsg*)&id);
 +	if (idx == -1)
 +	{
 +		msgCache.insert(new chunkedmsg(id, totsz, bychunk));
 +		idx = msgCache.getIndex((chunkedmsg*)&id);
 +	}
 +
 +	msgCache[idx].add(msg, offset, portion);
 +
 +	return idx;
 +}
 +
 +size_t CMsnProto::getCachedMsgSize(const char* id)
 +{
 +	int idx = msgCache.getIndex((chunkedmsg*)&id);
 +	return idx != -1 ? msgCache[idx].size : 0;
 +}
 +
 +bool CMsnProto::getCachedMsg(int idx, char*& msg, size_t& size)
 +{
 +	bool res = msgCache[idx].get(msg, size);
 +	if (res)
 +		msgCache.remove(idx);
 +
 +	return res;
 +}
 +
 +bool CMsnProto::getCachedMsg(const char* id, char*& msg, size_t& size)
 +{
 +	int idx = msgCache.getIndex((chunkedmsg*)&id);
 +	return idx != -1 && getCachedMsg(idx, msg, size);
 +}
 +
 +
 +void CMsnProto::clearCachedMsg(int idx)
 +{
 +	if (idx != -1)
 +		msgCache.remove(idx);
 +	else
 +		msgCache.destroy();
 +}
 +
 +void CMsnProto::CachedMsg_Uninit(void)
 +{
 +	clearCachedMsg();
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_natdetect.cpp b/plugins/!Deprecated/MSN/src/msn_natdetect.cpp new file mode 100644 index 0000000000..c6569ff817 --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_natdetect.cpp @@ -0,0 +1,496 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2007-2012 Boris Krasnovskiy.
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +#include <netfw.h>
 +
 +#ifndef CLSID_NetFwMgr
 +#define MDEF_CLSID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
 +	const CLSID name = { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }
 +
 +	MDEF_CLSID(CLSID_NetFwMgr, 0x304ce942, 0x6e39, 0x40d8, 0x94, 0x3a, 0xb9, 0x13, 0xc4, 0x0c, 0x9c, 0xd4);
 +	MDEF_CLSID(IID_INetFwMgr, 0xf7898af5, 0xcac4, 0x4632, 0xa2, 0xec, 0xda ,0x06, 0xe5, 0x11, 0x1a, 0xf2);
 +#endif
 +
 +
 +MyConnectionType MyConnection;
 +
 +const char* conStr[] =
 +{
 +	"Unknown-Connect",
 +	"Direct-Connect",
 +	"Unknown-NAT",
 +	"IP-Restrict-NAT",
 +	"Port-Restrict-NAT",
 +	"Symmetric-NAT",
 +	"Firewall",
 +	"ISALike"
 +};
 +
 +
 +void CMsnProto::DecryptEchoPacket(UDPProbePkt& pkt)
 +{
 +	pkt.clientPort ^= 0x3141;
 +	pkt.discardPort ^= 0x3141;
 +	pkt.testPort ^= 0x3141;
 +	pkt.clientIP ^= 0x31413141;
 +	pkt.testIP ^= 0x31413141;
 +
 +
 +	IN_ADDR addr;
 +	debugLogA("Echo packet: version: 0x%x  service code: 0x%x  transaction ID: 0x%x",
 +		pkt.version, pkt.serviceCode, pkt.trId);
 +	addr.S_un.S_addr = pkt.clientIP;
 +	debugLogA("Echo packet: client port: %u  client addr: %s",
 +		pkt.clientPort, inet_ntoa(addr));
 +	addr.S_un.S_addr = pkt.testIP;
 +	debugLogA("Echo packet: discard port: %u  test port: %u test addr: %s",
 +		pkt.discardPort, pkt.testPort, inet_ntoa(addr));
 +}
 +
 +
 +static void DiscardExtraPackets(SOCKET s)
 +{
 +	Sleep(3000);
 +
 +	static const TIMEVAL tv = {0, 0};
 +	unsigned buf;
 +
 +	for (;;)
 +	{
 +		if (Miranda_Terminated()) break;
 +
 +		fd_set fd;
 +		FD_ZERO(&fd);
 +		FD_SET(s, &fd);
 +
 +		if (select(1, &fd, NULL, NULL, &tv) == 1)
 +			recv(s, (char*)&buf, sizeof(buf), 0);
 +		else
 +			break;
 +	}
 +}
 +
 +
 +void CMsnProto::MSNatDetect(void)
 +{
 +	unsigned i;
 +
 +	PHOSTENT host = gethostbyname("echo.edge.messenger.live.com");
 +	if (host == NULL)
 +	{
 +		debugLogA("P2PNAT could not find echo server \"echo.edge.messenger.live.com\"");
 +		return;
 +	}
 +
 +	SOCKADDR_IN addr;
 +	addr.sin_family = AF_INET;
 +	addr.sin_port = _htons(7001);
 +	addr.sin_addr = *( PIN_ADDR )host->h_addr_list[0];
 +
 +	debugLogA("P2PNAT Detected echo server IP %d.%d.%d.%d",
 +		addr.sin_addr.S_un.S_un_b.s_b1, addr.sin_addr.S_un.S_un_b.s_b2,
 +		addr.sin_addr.S_un.S_un_b.s_b3, addr.sin_addr.S_un.S_un_b.s_b4);
 +
 +	SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
 +
 +	connect(s, (SOCKADDR*)&addr, sizeof(addr));
 +
 +	UDPProbePkt pkt = { 0 };
 +	UDPProbePkt pkt2;
 +
 +	// Detect My IP
 +	pkt.version = 2;
 +	pkt.serviceCode = 4;
 +	send(s, (char*)&pkt, sizeof(pkt), 0);
 +
 +	SOCKADDR_IN  myaddr;
 +	int szname = sizeof(myaddr);
 +	getsockname(s, (SOCKADDR*)&myaddr, &szname);
 +
 +	MyConnection.intIP = myaddr.sin_addr.S_un.S_addr;
 +	debugLogA("P2PNAT Detected IP facing internet %d.%d.%d.%d",
 +		myaddr.sin_addr.S_un.S_un_b.s_b1, myaddr.sin_addr.S_un.S_un_b.s_b2,
 +		myaddr.sin_addr.S_un.S_un_b.s_b3, myaddr.sin_addr.S_un.S_un_b.s_b4);
 +
 +	SOCKET s1 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
 +
 +	pkt.version = 2;
 +	pkt.serviceCode = 1;
 +	pkt.clientPort = 0x3141;
 +	pkt.clientIP = 0x31413141;
 +
 +	UDPProbePkt rpkt = {0};
 +
 +	// NAT detection
 +	for (i=0; i<4; ++i)
 +	{
 +		if (Miranda_Terminated()) break;
 +
 +		// Send echo request to server 1
 +		debugLogA("P2PNAT Request 1 attempt %d sent", i);
 +		sendto(s1, (char*)&pkt, sizeof(pkt), 0, (SOCKADDR*)&addr, sizeof(addr));
 +
 +		fd_set fd;
 +		FD_ZERO(&fd);
 +		FD_SET(s1, &fd);
 +		TIMEVAL tv = {0, 200000 * (1 << i) };
 +
 +		if (select(1, &fd, NULL, NULL, &tv) == 1)
 +		{
 +			debugLogA("P2PNAT Request 1 attempt %d response", i);
 +			recv(s1, (char*)&rpkt, sizeof(rpkt), 0);
 +			pkt2 = rpkt;
 +			DecryptEchoPacket(rpkt);
 +			break;
 +		}
 +		else
 +			debugLogA("P2PNAT Request 1 attempt %d timeout", i);
 +	}
 +
 +	closesocket(s);
 +
 +	// Server did not respond
 +	if (i >= 4)
 +	{
 +		MyConnection.udpConType = conFirewall;
 +		closesocket(s1);
 +		return;
 +	}
 +
 +	MyConnection.extIP = rpkt.clientIP;
 +
 +	// Check if NAT not found
 +	if (MyConnection.extIP == MyConnection.intIP)
 +	{
 +		if (msnExternalIP != NULL && inet_addr(msnExternalIP) != MyConnection.extIP)
 +			MyConnection.udpConType = conISALike;
 +		else
 +			MyConnection.udpConType = conDirect;
 +
 +		closesocket(s1);
 +		return;
 +	}
 +
 +	// Detect UPnP NAT
 +	NETLIBBIND nlb = {0};
 +	nlb.cbSize = sizeof(nlb);
 +	nlb.pfnNewConnectionV2 = MSN_ConnectionProc;
 +	nlb.pExtra = this;
 +
 +	HANDLE sb = (HANDLE) CallService(MS_NETLIB_BINDPORT, (WPARAM)m_hNetlibUser, (LPARAM)&nlb);
 +	if ( sb != NULL )
 +	{
 +		MyConnection.upnpNAT = htonl(nlb.dwExternalIP) == MyConnection.extIP;
 +		Sleep(100);
 +		Netlib_CloseHandle(sb);
 +	}
 +
 +	DiscardExtraPackets(s1);
 +
 +	// Start IP Restricted NAT detection
 +	UDPProbePkt rpkt2 = {0};
 +	pkt2.serviceCode = 3;
 +	SOCKADDR_IN addr2 = addr;
 +	addr2.sin_addr.S_un.S_addr = rpkt.testIP;
 +	addr2.sin_port = rpkt.discardPort;
 +	for (i=0; i<4; ++i)
 +	{
 +		if (Miranda_Terminated()) break;
 +
 +		debugLogA("P2PNAT Request 2 attempt %d sent", i);
 +		// Remove IP restriction for server 2
 +		sendto(s1, NULL, 0, 0, (SOCKADDR*)&addr2, sizeof(addr2));
 +		// Send echo request to server 1 for server 2
 +		sendto(s1, (char*)&pkt2, sizeof(pkt2), 0, (SOCKADDR*)&addr, sizeof(addr));
 +
 +		fd_set fd;
 +		FD_ZERO(&fd);
 +		FD_SET(s1, &fd);
 +		TIMEVAL tv = {0, 200000 * (1 << i) };
 +
 +		if (select(1, &fd, NULL, NULL, &tv) == 1)
 +		{
 +			debugLogA("P2PNAT Request 2 attempt %d response", i);
 +			recv(s1, (char*)&rpkt2, sizeof(rpkt2), 0);
 +			DecryptEchoPacket(rpkt2);
 +			break;
 +		}
 +		else
 +			debugLogA("P2PNAT Request 2 attempt %d timeout", i);
 +	}
 +
 +	// Response recieved so it's an IP Restricted NAT (Restricted Cone NAT)
 +	// (MSN does not detect Full Cone NAT and consider it as IP Restricted NAT)
 +	if (i < 4)
 +	{
 +		MyConnection.udpConType = conIPRestrictNAT;
 +		closesocket(s1);
 +		return;
 +	}
 +
 +	DiscardExtraPackets(s1);
 +
 +	// Symmetric NAT detection
 +	addr2.sin_port = rpkt.testPort;
 +	for (i=0; i<4; ++i)
 +	{
 +		if (Miranda_Terminated()) break;
 +
 +		debugLogA("P2PNAT Request 3 attempt %d sent", i);
 +		// Send echo request to server 1
 +		sendto(s1, (char*)&pkt, sizeof(pkt), 0, (SOCKADDR*)&addr2, sizeof(addr2));
 +
 +		fd_set fd;
 +		FD_ZERO(&fd);
 +		FD_SET(s1, &fd);
 +		TIMEVAL tv = {1 << i, 0 };
 +
 +		if ( select(1, &fd, NULL, NULL, &tv) == 1 )
 +		{
 +			debugLogA("P2PNAT Request 3 attempt %d response", i);
 +			recv(s1, (char*)&rpkt2, sizeof(rpkt2), 0);
 +			DecryptEchoPacket(rpkt2);
 +			break;
 +		}
 +		else
 +			debugLogA("P2PNAT Request 3 attempt %d timeout", i);
 +	}
 +	if (i < 4)
 +	{
 +		// If ports different it's symmetric NAT
 +		MyConnection.udpConType = rpkt.clientPort == rpkt2.clientPort ?
 +			conPortRestrictNAT : conSymmetricNAT;
 +	}
 +	closesocket(s1);
 +}
 +
 +
 +static bool IsIcfEnabled(void)
 +{
 +	HRESULT hr;
 +	VARIANT_BOOL fwEnabled = VARIANT_FALSE;
 +
 +	INetFwProfile* fwProfile = NULL;
 +	INetFwMgr* fwMgr = NULL;
 +	INetFwPolicy* fwPolicy = NULL;
 +	INetFwAuthorizedApplication* fwApp = NULL;
 +	INetFwAuthorizedApplications* fwApps = NULL;
 +	BSTR fwBstrProcessImageFileName = NULL;
 +	wchar_t *wszFileName = NULL;
 +
 +	hr = CoInitialize(NULL);
 +	if (FAILED(hr)) return false;
 +
 +	// Create an instance of the firewall settings manager.
 +	hr = CoCreateInstance(CLSID_NetFwMgr, NULL, CLSCTX_INPROC_SERVER,
 +			IID_INetFwMgr, (void**)&fwMgr );
 +	if (FAILED(hr)) goto error;
 +
 +	// Retrieve the local firewall policy.
 +	hr = fwMgr->get_LocalPolicy(&fwPolicy);
 +	if (FAILED(hr)) goto error;
 +
 +	// Retrieve the firewall profile currently in effect.
 +	hr = fwPolicy->get_CurrentProfile(&fwProfile);
 +	if (FAILED(hr)) goto error;
 +
 +	// Get the current state of the firewall.
 +	hr = fwProfile->get_FirewallEnabled(&fwEnabled);
 +	if (FAILED(hr)) goto error;
 +
 +	if (fwEnabled == VARIANT_FALSE) goto error;
 +
 +	// Retrieve the authorized application collection.
 +	hr = fwProfile->get_AuthorizedApplications(&fwApps);
 +	if (FAILED(hr)) goto error;
 +
 +	TCHAR szFileName[MAX_PATH];
 +	GetModuleFileName(NULL, szFileName, SIZEOF(szFileName));
 +
 +	wszFileName = mir_t2u(szFileName);
 +
 +	// Allocate a BSTR for the process image file name.
 +	fwBstrProcessImageFileName = SysAllocString(wszFileName);
 +	if (FAILED(hr)) goto error;
 +
 +	// Attempt to retrieve the authorized application.
 +	hr = fwApps->Item(fwBstrProcessImageFileName, &fwApp);
 +	if (SUCCEEDED(hr))
 +	{
 +		// Find out if the authorized application is enabled.
 +		fwApp->get_Enabled(&fwEnabled);
 +		fwEnabled = ~fwEnabled;
 +	}
 +
 +error:
 +	// Free the BSTR.
 +	SysFreeString(fwBstrProcessImageFileName);
 +	mir_free(wszFileName);
 +
 +	// Release the authorized application instance.
 +	if (fwApp != NULL) fwApp->Release();
 +
 +	// Release the authorized application collection.
 +	if (fwApps != NULL) fwApps->Release();
 +
 +	// Release the firewall profile.
 +	if (fwProfile != NULL) fwProfile->Release();
 +
 +	// Release the local firewall policy.
 +	if (fwPolicy != NULL) fwPolicy->Release();
 +
 +	// Release the firewall settings manager.
 +	if (fwMgr != NULL) fwMgr->Release();
 +
 +	CoUninitialize();
 +
 +	return fwEnabled != VARIANT_FALSE;
 +}
 +
 +
 +void CMsnProto::MSNConnDetectThread( void* )
 +{
 +	char parBuf[512] = "";
 +
 +	memset(&MyConnection, 0, sizeof(MyConnection));
 +
 +	MyConnection.icf = IsIcfEnabled();
 +	bool portsMapped = getByte("NLSpecifyIncomingPorts", 0) != 0;
 +
 +	unsigned gethst = getByte("AutoGetHost", 1);
 +	switch (gethst)
 +	{
 +		case 0:
 +			debugLogA("P2PNAT User overwrote IP connection is guessed by user settings only");
 +
 +			// User specified host by himself so check if it matches MSN information
 +			// if it does, move to connection type autodetection,
 +			// if it does not, guess connection type from available info
 +			db_get_static(NULL, m_szModuleName, "YourHost", parBuf, sizeof(parBuf));
 +			if (msnExternalIP == NULL || strcmp(msnExternalIP, parBuf) != 0)
 +			{
 +				MyConnection.extIP = inet_addr(parBuf);
 +				if (MyConnection.extIP == INADDR_NONE)
 +				{
 +					PHOSTENT myhost = gethostbyname(parBuf);
 +					if (myhost != NULL)
 +						MyConnection.extIP = ((PIN_ADDR)myhost->h_addr)->S_un.S_addr;
 +					else
 +						setByte("AutoGetHost", 1);
 +				}
 +				if (MyConnection.extIP != INADDR_NONE)
 +				{
 +					MyConnection.intIP = MyConnection.extIP;
 +					MyConnection.udpConType = MyConnection.extIP ? (ConEnum)portsMapped : conUnknown;
 +					MyConnection.CalculateWeight();
 +					return;
 +				}
 +				else
 +					MyConnection.extIP = 0;
 +			}
 +			break;
 +
 +		case 1:
 +			if (msnExternalIP != NULL)
 +				MyConnection.extIP = inet_addr(msnExternalIP);
 +			else
 +			{
 +				gethostname(parBuf, sizeof(parBuf));
 +				PHOSTENT myhost = gethostbyname(parBuf);
 +				if (myhost != NULL)
 +					MyConnection.extIP = ((PIN_ADDR)myhost->h_addr)->S_un.S_addr;
 +			}
 +			MyConnection.intIP = MyConnection.extIP;
 +			break;
 +
 +		case 2:
 +			MyConnection.udpConType = conUnknown;
 +			MyConnection.CalculateWeight();
 +			return;
 +	}
 +
 +	if (getByte( "NLSpecifyOutgoingPorts", 0))
 +	{
 +		// User specified outgoing ports so the connection must be firewalled
 +		// do not autodetect and guess connection type from available info
 +		MyConnection.intIP = MyConnection.extIP;
 +		MyConnection.udpConType = (ConEnum)portsMapped;
 +		MyConnection.upnpNAT = false;
 +		MyConnection.CalculateWeight();
 +		return;
 +	}
 +
 +	MSNatDetect();
 +
 +	// If user mapped incoming ports consider direct connection
 +	if (portsMapped)
 +	{
 +		debugLogA("P2PNAT User manually mapped ports for incoming connection");
 +		switch(MyConnection.udpConType)
 +		{
 +		case conUnknown:
 +		case conFirewall:
 +		case conISALike:
 +			MyConnection.udpConType = conDirect;
 +			break;
 +
 +		case conUnknownNAT:
 +		case conPortRestrictNAT:
 +		case conIPRestrictNAT:
 +		case conSymmetricNAT:
 +			MyConnection.upnpNAT = true;
 +			break;
 +		}
 +	}
 +
 +	debugLogA("P2PNAT Connection %s found UPnP: %d ICF: %d", conStr[MyConnection.udpConType],
 +		MyConnection.upnpNAT, MyConnection.icf);
 +
 +	MyConnection.CalculateWeight();
 +}
 +
 +
 +void MyConnectionType::SetUdpCon(const char* str)
 +{
 +	for (unsigned i=0; i<sizeof(conStr)/sizeof(char*); ++i)
 +	{
 +		if (strcmp(conStr[i], str) == 0)
 +		{
 +			udpConType = (ConEnum)i;
 +			break;
 +		}
 +	}
 +}
 +
 +
 +void MyConnectionType::CalculateWeight(void)
 +{
 +	if (icf) weight = 0;
 +	else if (udpConType == conDirect) weight = 6;
 +	else if (udpConType >= conIPRestrictNAT && udpConType <= conSymmetricNAT)
 +		weight = upnpNAT ? 5 : 2;
 +	else if (udpConType == conUnknownNAT)
 +		weight = upnpNAT ? 4 : 1;
 +	else if (udpConType == conUnknown) weight = 1;
 +	else if (udpConType == conFirewall) weight = 2;
 +	else if (udpConType == conISALike) weight = 3;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_opts.cpp b/plugins/!Deprecated/MSN/src/msn_opts.cpp new file mode 100644 index 0000000000..ae6276b6f3 --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_opts.cpp @@ -0,0 +1,684 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +#include <commdlg.h>
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// Icons init
 +
 +static IconItem iconList[] =
 +{
 +	{	LPGEN("Protocol icon"),    "main",        IDI_MSN        },
 +	{	LPGEN("Hotmail Inbox"),    "inbox",       IDI_INBOX      },
 +	{	LPGEN("Profile"),          "profile",     IDI_PROFILE    },
 +	{	LPGEN("MSN Services"),     "services",    IDI_SERVICES   },
 +	{	LPGEN("Block user"),       "block",       IDI_MSNBLOCK   },
 +	{	LPGEN("Invite to chat"),   "invite",      IDI_INVITE     },
 +	{	LPGEN("Start Netmeeting"), "netmeeting",  IDI_NETMEETING },
 +	{	LPGEN("Contact list"),     "list_fl",     IDI_LIST_FL    },
 +	{	LPGEN("Allowed list"),     "list_al",     IDI_LIST_AL    },
 +	{	LPGEN("Blocked list"),     "list_bl",     IDI_LIST_BL    },
 +	{	LPGEN("Relative list"),    "list_rl",     IDI_LIST_RL    },
 +	{	LPGEN("Local list"),       "list_lc",     IDI_LIST_LC    },
 +};
 +
 +void MsnInitIcons(void)
 +{
 +	Icon_Register(hInst, "Protocols/MSN", iconList, SIZEOF(iconList), "MSN");
 +}
 +
 +HICON LoadIconEx(const char* name, bool big)
 +{
 +	char szSettingName[100];
 +	mir_snprintf(szSettingName, sizeof(szSettingName), "MSN_%s", name);
 +	return Skin_GetIcon(szSettingName, big);
 +}
 +
 +HANDLE GetIconHandle(int iconId)
 +{
 +	for (unsigned i=0; i < SIZEOF(iconList); i++)
 +		if (iconList[i].defIconID == iconId)
 +			return iconList[i].hIcolib;
 +
 +	return NULL;
 +}
 +
 +void  ReleaseIconEx(const char* name, bool big)
 +{
 +	char szSettingName[100];
 +	mir_snprintf(szSettingName, sizeof(szSettingName), "MSN_%s", name);
 +	Skin_ReleaseIcon(szSettingName, big);
 +}
 +
 +INT_PTR CALLBACK DlgProcMsnServLists(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN Options dialog procedure
 +
 +static INT_PTR CALLBACK DlgProcMsnOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 +{
 +	switch (msg) {
 +	case WM_INITDIALOG:
 +		TranslateDialogDefault(hwndDlg);
 +		{
 +			SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
 +			CMsnProto* proto = (CMsnProto*)lParam;
 +
 +			SetDlgItemTextA(hwndDlg, IDC_HANDLE, proto->MyOptions.szEmail);
 +
 +			char tBuffer[MAX_PATH];
 +			if (!db_get_static(NULL, proto->m_szModuleName, "Password", tBuffer, sizeof(tBuffer))) {
 +				tBuffer[16] = 0;
 +				SetDlgItemTextA(hwndDlg, IDC_PASSWORD, tBuffer);
 +			}
 +			SendDlgItemMessage(hwndDlg, IDC_PASSWORD, EM_SETLIMITTEXT, 16, 0);
 +
 +			HWND wnd = GetDlgItem(hwndDlg, IDC_HANDLE2);
 +			DBVARIANT dbv;
 +			if (!proto->getTString("Nick", &dbv)) {
 +				SetWindowText(wnd, dbv.ptszVal);
 +				db_free(&dbv);
 +			}
 +			EnableWindow(wnd, proto->msnLoggedIn);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_MOBILESEND), proto->msnLoggedIn &&
 +				proto->getByte("MobileEnabled", 0) && proto->getByte("MobileAllowed", 0));
 +
 +			CheckDlgButton(hwndDlg, IDC_MOBILESEND,        proto->getByte("MobileAllowed", 0));
 +			CheckDlgButton(hwndDlg, IDC_SENDFONTINFO,      proto->getByte("SendFontInfo", 1));
 +			CheckDlgButton(hwndDlg, IDC_MANAGEGROUPS,      proto->getByte("ManageServer", 1));
 +
 +			int tValue = proto->getByte("RunMailerOnHotmail", 0);
 +			CheckDlgButton(hwndDlg, IDC_RUN_APP_ON_HOTMAIL, tValue);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_MAILER_APP), tValue);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_ENTER_MAILER_APP), tValue);
 +
 +			if (!db_get_static(NULL, proto->m_szModuleName, "MailerPath", tBuffer, sizeof(tBuffer)))
 +				SetDlgItemTextA(hwndDlg, IDC_MAILER_APP, tBuffer);
 +
 +			if (!proto->msnLoggedIn) {
 +				EnableWindow(GetDlgItem(hwndDlg, IDC_MANAGEGROUPS), FALSE);
 +				EnableWindow(GetDlgItem(hwndDlg, IDC_DISABLE_ANOTHER_CONTACTS), FALSE);
 +			}
 +			else CheckDlgButton(hwndDlg, IDC_DISABLE_ANOTHER_CONTACTS, proto->msnOtherContactsBlocked);
 +		}
 +		return TRUE;
 +
 +	case WM_COMMAND:
 +		if (LOWORD(wParam) == IDC_NEWMSNACCOUNTLINK) {
 +			CallService(MS_UTILS_OPENURL, 1, (LPARAM)"https://signup.live.com");
 +			return TRUE;
 +		}
 +
 +		if (HIWORD(wParam) == EN_CHANGE && (HWND)lParam == GetFocus()) {
 +			switch(LOWORD(wParam)) {
 +			case IDC_HANDLE:			case IDC_PASSWORD:			case IDC_HANDLE2:
 +			case IDC_GATEWAYSERVER: 	case IDC_YOURHOST:			case IDC_DIRECTSERVER:
 +				SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
 +			}
 +		}
 +
 +		if (HIWORD(wParam) == BN_CLICKED) {
 +			switch(LOWORD(wParam)) {
 +			case IDC_SENDFONTINFO:
 +			case IDC_DISABLE_ANOTHER_CONTACTS:
 +			case IDC_MOBILESEND:
 +				SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
 +				break;
 +
 +			case IDC_MANAGEGROUPS:
 +				if (IsDlgButtonChecked(hwndDlg, IDC_MANAGEGROUPS)) {
 +					if (IDYES == MessageBox(hwndDlg,
 +						TranslateT("Server groups import may change your contact list layout after next login. Do you want to upload your groups to the server?"),
 +						TranslateT("MSN Protocol"), MB_YESNOCANCEL))
 +					{
 +						CMsnProto* proto = (CMsnProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 +						proto->MSN_UploadServerGroups(NULL);
 +					}
 +				}
 +				SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
 +				break;
 +
 +			case IDC_RUN_APP_ON_HOTMAIL:
 +				{
 +					BOOL tIsChosen = IsDlgButtonChecked(hwndDlg, IDC_RUN_APP_ON_HOTMAIL);
 +					EnableWindow(GetDlgItem(hwndDlg, IDC_MAILER_APP), tIsChosen);
 +					EnableWindow(GetDlgItem(hwndDlg, IDC_ENTER_MAILER_APP), tIsChosen);
 +					SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
 +				}
 +				break;
 +
 +			case IDC_ENTER_MAILER_APP:
 +				{
 +					HWND tEditField = GetDlgItem(hwndDlg, IDC_MAILER_APP);
 +
 +					char szFile[MAX_PATH + 2];
 +					GetWindowTextA(tEditField, szFile, sizeof(szFile));
 +
 +					size_t tSelectLen = 0;
 +
 +					if (szFile[0] == '\"') {
 +						char* p = strchr(szFile+1, '\"');
 +						if (p != NULL) {
 +							*p = '\0';
 +							memmove(szFile, szFile+1, strlen(szFile));
 +							tSelectLen += 2;
 +							goto LBL_Continue;
 +						}
 +					}
 +
 +					{
 +						char* p = strchr(szFile, ' ');
 +						if (p != NULL) *p = '\0';
 +					}
 +LBL_Continue:
 +					tSelectLen += strlen(szFile);
 +
 +					OPENFILENAMEA ofn = {0};
 +					ofn.lStructSize = sizeof(ofn);
 +					ofn.hwndOwner = hwndDlg;
 +					ofn.nMaxFile = sizeof(szFile);
 +					ofn.lpstrFile = szFile;
 +					ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
 +					if (GetOpenFileNameA(&ofn) != TRUE)
 +						break;
 +
 +					if (strchr(szFile, ' ') != NULL) {
 +						char tmpBuf[MAX_PATH + 2];
 +						mir_snprintf(tmpBuf, sizeof(tmpBuf), "\"%s\"", szFile);
 +						strcpy(szFile, tmpBuf);
 +					}
 +
 +					SendMessage(tEditField, EM_SETSEL, 0, tSelectLen);
 +					SendMessageA(tEditField, EM_REPLACESEL, TRUE, LPARAM(szFile));
 +					SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
 +				}
 +			}
 +		}
 +		break;
 +
 +	case WM_NOTIFY:
 +		if (((LPNMHDR)lParam)->code == (UINT)PSN_APPLY) {
 +			bool reconnectRequired = false;
 +			TCHAR screenStr[MAX_PATH];
 +			char  password[100], szEmail[MSN_MAX_EMAIL_LEN];
 +			DBVARIANT dbv;
 +
 +			CMsnProto* proto = (CMsnProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 +
 +			GetDlgItemTextA(hwndDlg, IDC_HANDLE, szEmail, sizeof(szEmail));
 +			if (strcmp(_strlwr(szEmail), proto->MyOptions.szEmail)) {
 +				reconnectRequired = true;
 +				strcpy(proto->MyOptions.szEmail, szEmail);
 +				proto->setString("e-mail", szEmail);
 +			}
 +
 +			GetDlgItemTextA(hwndDlg, IDC_PASSWORD, password, sizeof(password));
 +			if (!proto->getString("Password", &dbv)) {
 +				if (strcmp(password, dbv.pszVal)) {
 +					reconnectRequired = true;
 +					proto->setString("Password", password);
 +				}
 +				db_free(&dbv);
 +			}
 +			else {
 +				reconnectRequired = true;
 +				proto->setString("Password", password);
 +			}
 +
 +			GetDlgItemText(hwndDlg, IDC_HANDLE2, screenStr, SIZEOF(screenStr));
 +			if	(!proto->getTString("Nick", &dbv)) {
 +				if (_tcscmp(dbv.ptszVal, screenStr))
 +					proto->MSN_SendNickname(screenStr);
 +				db_free(&dbv);
 +			}
 +			else proto->MSN_SendNickname(screenStr);
 +
 +			BYTE mblsnd = IsDlgButtonChecked(hwndDlg, IDC_MOBILESEND) == BST_CHECKED;
 +			if (mblsnd != proto->getByte("MobileAllowed", 0)) {
 +				proto->msnNsThread->sendPacket("PRP", "MOB %c", mblsnd ? 'Y' : 'N');
 +				proto->MSN_SetServerStatus(proto->m_iStatus);
 +			}
 +
 +			unsigned tValue = IsDlgButtonChecked(hwndDlg, IDC_DISABLE_ANOTHER_CONTACTS);
 +			if (tValue != proto->msnOtherContactsBlocked && proto->msnLoggedIn) {
 +				proto->msnOtherContactsBlocked = tValue;
 +				proto->msnNsThread->sendPacket("BLP", tValue ? "BL" : "AL");
 +				proto->MSN_ABUpdateAttr(NULL, "MSN.IM.BLP", tValue ? "0" : "1");
 +				break;
 +			}
 +
 +			proto->setByte("SendFontInfo",       (BYTE)IsDlgButtonChecked(hwndDlg, IDC_SENDFONTINFO));
 +			proto->setByte("RunMailerOnHotmail", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_RUN_APP_ON_HOTMAIL));
 +			proto->setByte("ManageServer",       (BYTE)IsDlgButtonChecked(hwndDlg, IDC_MANAGEGROUPS));
 +
 +			GetDlgItemText(hwndDlg, IDC_MAILER_APP, screenStr, SIZEOF(screenStr));
 +			proto->setTString("MailerPath", screenStr);
 +
 +			if (reconnectRequired && proto->msnLoggedIn)
 +				MessageBox(hwndDlg,
 +					TranslateT("The changes you have made require you to reconnect to the MSN Messenger network before they take effect"),
 +					TranslateT("MSN Options"), MB_OK);
 +
 +			proto->LoadOptions();
 +			return TRUE;
 +		}
 +		break;
 +	}
 +
 +	return FALSE;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN Connection Options dialog procedure
 +
 +static INT_PTR CALLBACK DlgProcMsnConnOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 +{
 +	DBVARIANT dbv;
 +
 +	switch (msg) {
 +	case WM_INITDIALOG:
 +		TranslateDialogDefault(hwndDlg);
 +		{
 +			SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
 +			CMsnProto* proto = (CMsnProto*)lParam;
 +
 +			if (!proto->getString("DirectServer", &dbv)) {
 +				SetDlgItemTextA(hwndDlg, IDC_DIRECTSERVER, dbv.pszVal);
 +				db_free(&dbv);
 +			}
 +			else SetDlgItemTextA(hwndDlg, IDC_DIRECTSERVER,  MSN_DEFAULT_LOGIN_SERVER);
 +
 +			if (!proto->getString("GatewayServer", &dbv)) {
 +				SetDlgItemTextA(hwndDlg, IDC_GATEWAYSERVER, dbv.pszVal);
 +				db_free(&dbv);
 +			}
 +			else SetDlgItemTextA(hwndDlg, IDC_GATEWAYSERVER,  MSN_DEFAULT_GATEWAY);
 +
 +			CheckDlgButton(hwndDlg, IDC_SLOWSEND, proto->getByte("SlowSend",    0));
 +
 +			SendDlgItemMessage(hwndDlg, IDC_HOSTOPT, CB_ADDSTRING, 0, (LPARAM)TranslateT("Automatically obtain host/port"));
 +			SendDlgItemMessage(hwndDlg, IDC_HOSTOPT, CB_ADDSTRING, 0, (LPARAM)TranslateT("Manually specify host/port"));
 +			SendDlgItemMessage(hwndDlg, IDC_HOSTOPT, CB_ADDSTRING, 0, (LPARAM)TranslateT("Disable"));
 +
 +			unsigned gethst = proto->getByte("AutoGetHost", 1);
 +			if (gethst < 2) gethst = !gethst;
 +
 +			char ipaddr[256] = "";
 +			if (gethst == 1)
 +				if (db_get_static(NULL, proto->m_szModuleName, "YourHost", ipaddr, sizeof(ipaddr)))
 +					gethst = 0;
 +
 +			if (gethst == 0)
 +				mir_snprintf(ipaddr, sizeof(ipaddr), "%s", proto->msnLoggedIn ? proto->MyConnection.GetMyExtIPStr() : "");
 +
 +			SendDlgItemMessage(hwndDlg, IDC_HOSTOPT, CB_SETCURSEL, gethst, 0);
 +			if (ipaddr[0])
 +				SetDlgItemTextA(hwndDlg, IDC_YOURHOST, ipaddr);
 +			else
 +				SetDlgItemText(hwndDlg, IDC_YOURHOST, TranslateT("IP info available only after login"));
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_YOURHOST), gethst == 1);
 +		}
 +		return TRUE;
 +
 +	case WM_COMMAND:
 +		switch (LOWORD(wParam)) {
 +		case IDC_RESETSERVER:
 +			SetDlgItemTextA(hwndDlg, IDC_DIRECTSERVER, MSN_DEFAULT_LOGIN_SERVER);
 +			SetDlgItemTextA(hwndDlg, IDC_GATEWAYSERVER, MSN_DEFAULT_GATEWAY);
 +			SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
 +			break;
 +		}
 +
 +		if (HIWORD(wParam) == EN_CHANGE && (HWND)lParam == GetFocus())
 +			switch(LOWORD(wParam)) {
 +			case IDC_DIRECTSERVER:
 +			case IDC_GATEWAYSERVER:
 +			case IDC_YOURHOST:
 +				SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
 +		}
 +
 +		if (HIWORD(wParam) == CBN_SELCHANGE && LOWORD(wParam) == IDC_HOSTOPT) {
 +			unsigned gethst = SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_YOURHOST), gethst == 1);
 +			SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
 +		}
 +
 +		if (HIWORD(wParam) == BN_CLICKED) {
 +			switch(LOWORD(wParam)) {
 +			case IDC_SLOWSEND:
 +				SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
 +				break;
 +			}
 +		}
 +		break;
 +
 +	case WM_NOTIFY:
 +		if (((LPNMHDR)lParam)->code == (UINT)PSN_APPLY) {
 +			bool reconnectRequired = false;
 +			char str[MAX_PATH];
 +
 +			CMsnProto* proto = (CMsnProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 +
 +			GetDlgItemTextA(hwndDlg, IDC_DIRECTSERVER, str, sizeof(str));
 +			if (strcmp(str, MSN_DEFAULT_LOGIN_SERVER))
 +				proto->setString("DirectServer", str);
 +			else
 +				proto->delSetting("DirectServer");
 +
 +			GetDlgItemTextA(hwndDlg, IDC_GATEWAYSERVER, str, sizeof(str));
 +			if (strcmp(str, MSN_DEFAULT_GATEWAY))
 +				proto->setString("GatewayServer", str);
 +			else
 +				proto->delSetting("GatewayServer");
 +
 +			proto->setByte("SlowSend",   (BYTE)IsDlgButtonChecked(hwndDlg, IDC_SLOWSEND ));
 +			if (proto->getByte("SlowSend", FALSE)) {
 +				if (db_get_dw(NULL, "SRMsg", "MessageTimeout", 60000) < 60000 ||
 +					db_get_dw(NULL, "SRMM",  "MessageTimeout", 60000) < 60000)
 +				{
 +					MessageBox(NULL, TranslateT("MSN Protocol requires message timeout to be not less then 60 sec. Correct the timeout value."),
 +						TranslateT("MSN Protocol"), MB_OK|MB_ICONINFORMATION);
 +				}
 +			}
 +
 +			unsigned gethst2 = proto->getByte("AutoGetHost", 1);
 +			unsigned gethst = SendDlgItemMessage(hwndDlg, IDC_HOSTOPT, CB_GETCURSEL, 0, 0);
 +			if (gethst < 2) gethst = !gethst;
 +			proto->setByte("AutoGetHost", (BYTE)gethst);
 +
 +			if (gethst == 0) {
 +				GetDlgItemTextA(hwndDlg, IDC_YOURHOST, str, sizeof(str));
 +				proto->setString("YourHost", str);
 +			}
 +			else proto->delSetting("YourHost");
 +
 +			if (gethst != gethst2)
 +				proto->ForkThread(&CMsnProto::MSNConnDetectThread, NULL);
 +
 +			if (reconnectRequired && proto->msnLoggedIn)
 +				MessageBox(hwndDlg, TranslateT("The changes you have made require you to reconnect to the MSN Messenger network before they take effect"),
 +				TranslateT("MSN Options"), MB_OK);
 +
 +			proto->LoadOptions();
 +			return TRUE;
 +		}
 +	}
 +
 +	return FALSE;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// Popup Options Dialog: style, position, color, font...
 +
 +static INT_PTR CALLBACK DlgProcHotmailPopupOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 +{
 +	static bool bEnabled;
 +	CMsnProto* proto = (CMsnProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 +
 +	switch(msg) {
 +	case WM_INITDIALOG:
 +		TranslateDialogDefault(hwndDlg);
 +		bEnabled = false;
 +
 +		SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
 +		proto = (CMsnProto*)lParam;
 +		CheckDlgButton(hwndDlg, IDC_DISABLEHOTMAILPOPUP, proto->getByte("DisableHotmail", 0));
 +		CheckDlgButton(hwndDlg, IDC_DISABLEHOTMAILTRAY,  proto->getByte("DisableHotmailTray", 1));
 +		CheckDlgButton(hwndDlg, IDC_DISABLEHOTMAILCL,    proto->getByte("DisableHotmailCL", 0));
 +		CheckDlgButton(hwndDlg, IDC_DISABLEHOTJUNK,      proto->getByte("DisableHotmailJunk", 0));
 +		CheckDlgButton(hwndDlg, IDC_NOTIFY_ENDSESSION,   proto->getByte("EnableSessionPopup", 0));
 +		CheckDlgButton(hwndDlg, IDC_NOTIFY_FIRSTMSG,     proto->getByte("EnableDeliveryPopup", 0));
 +		CheckDlgButton(hwndDlg, IDC_ERRORS_USING_POPUPS, proto->getByte("ShowErrorsAsPopups", 0));
 +
 +		bEnabled = true;
 +		return TRUE;
 +
 +	case WM_COMMAND:
 +		switch (LOWORD(wParam)) {
 +		case IDC_DISABLEHOTMAILPOPUP:
 +		case IDC_DISABLEHOTMAILTRAY:
 +		case IDC_DISABLEHOTMAILCL:
 +		case IDC_DISABLEHOTJUNK:
 +		case IDC_NOTIFY_ENDSESSION:
 +		case IDC_NOTIFY_FIRSTMSG:
 +		case IDC_ERRORS_USING_POPUPS:
 +			if (bEnabled)
 +				SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
 +			break;
 +		}
 +		break;
 +
 +	case WM_NOTIFY: //Here we have pressed either the OK or the APPLY button.
 +		switch(((LPNMHDR)lParam)->idFrom) {
 +		case 0:
 +			switch (((LPNMHDR)lParam)->code) {
 +			case PSN_RESET:
 +				proto->LoadOptions();
 +				return TRUE;
 +	
 +			case PSN_APPLY:
 +				proto->MyOptions.ShowErrorsAsPopups = IsDlgButtonChecked(hwndDlg, IDC_ERRORS_USING_POPUPS) != 0;
 +				proto->setByte("ShowErrorsAsPopups", proto->MyOptions.ShowErrorsAsPopups);
 +
 +				proto->setByte("DisableHotmail", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_DISABLEHOTMAILPOPUP));
 +				proto->setByte("DisableHotmailCL", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_DISABLEHOTMAILCL));
 +				proto->setByte("DisableHotmailTray", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_DISABLEHOTMAILTRAY));
 +				proto->setByte("DisableHotmailJunk",(BYTE)IsDlgButtonChecked(hwndDlg, IDC_DISABLEHOTJUNK));
 +				proto->setByte("EnableDeliveryPopup", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_NOTIFY_FIRSTMSG));
 +				proto->setByte("EnableSessionPopup", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_NOTIFY_ENDSESSION));
 +
 +				MCONTACT hContact = proto->MSN_HContactFromEmail(proto->MyOptions.szEmail);
 +				if (hContact)
 +					proto->displayEmailCount(hContact);
 +				return TRUE;
 +			}
 +			break;
 +		}
 +		break;
 +	}
 +
 +	return FALSE;
 +}
 +
 +static INT_PTR CALLBACK DlgProcAccMgrUI(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 +{
 +	switch(msg) {
 +	case WM_INITDIALOG:
 +		{
 +			TranslateDialogDefault(hwndDlg);
 +
 +			SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
 +			CMsnProto* proto = (CMsnProto*)lParam;
 +
 +			SetDlgItemTextA(hwndDlg, IDC_HANDLE, proto->MyOptions.szEmail);
 +
 +			char tBuffer[MAX_PATH];
 +			if (!db_get_static(NULL, proto->m_szModuleName, "Password", tBuffer, sizeof(tBuffer))) {
 +				tBuffer[16] = 0;
 +				SetDlgItemTextA(hwndDlg, IDC_PASSWORD, tBuffer);
 +			}
 +			SendDlgItemMessage(hwndDlg, IDC_PASSWORD, EM_SETLIMITTEXT, 16, 0);
 +
 +			DBVARIANT dbv;
 +			if (!proto->getTString("Place", &dbv)) {
 +				SetDlgItemText(hwndDlg, IDC_PLACE, dbv.ptszVal);
 +				db_free(&dbv);
 +			}
 +		}
 +		return TRUE;
 +
 +	case WM_COMMAND:
 +		if (LOWORD(wParam) == IDC_NEWMSNACCOUNTLINK) {
 +			CallService(MS_UTILS_OPENURL, 1, (LPARAM)"https://signup.live.com");
 +			return TRUE;
 +		}
 +
 +		if (HIWORD(wParam) == EN_CHANGE && (HWND)lParam == GetFocus()) {
 +			switch(LOWORD(wParam)) {
 +			case IDC_HANDLE:
 +			case IDC_PASSWORD:
 +				SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
 +			}
 +		}
 +		break;
 +
 +	case WM_NOTIFY:
 +		if (((LPNMHDR)lParam)->code == (UINT)PSN_APPLY) {
 +			char  password[100], szEmail[MSN_MAX_EMAIL_LEN];
 +			DBVARIANT dbv;
 +
 +			CMsnProto* proto = (CMsnProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 +
 +			GetDlgItemTextA(hwndDlg, IDC_HANDLE, szEmail, sizeof(szEmail));
 +			if (strcmp(szEmail, proto->MyOptions.szEmail)) {
 +				strcpy(proto->MyOptions.szEmail, szEmail);
 +				proto->setString("e-mail", szEmail);
 +			}
 +
 +			GetDlgItemTextA(hwndDlg, IDC_PASSWORD, password, sizeof(password));
 +			if (!proto->getString("Password", &dbv)) {
 +				if (strcmp(password, dbv.pszVal))
 +					proto->setString("Password", password);
 +				db_free(&dbv);
 +			}
 +			else proto->setString("Password", password);
 +
 +			TCHAR szPlace[64];
 +			GetDlgItemText(hwndDlg, IDC_PLACE, szPlace, SIZEOF(szPlace));
 +			if (szPlace[0])
 +				proto->setTString("Place", szPlace);
 +			else
 +				proto->delSetting("Place");
 +
 +			return TRUE;
 +		}
 +		break;
 +	}
 +
 +	return FALSE;
 +}
 +
 +INT_PTR CALLBACK DlgDeleteContactUI(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 +{
 +	switch(msg) {
 +	case WM_INITDIALOG:
 +		TranslateDialogDefault(hwndDlg);
 +		SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
 +		return TRUE;
 +
 +	case WM_CLOSE:
 +		EndDialog(hwndDlg, 0);
 +		break;
 +
 +	case WM_COMMAND:
 +		if (LOWORD(wParam) == IDOK) {
 +			int isBlock = IsDlgButtonChecked(hwndDlg, IDC_REMOVEBLOCK);
 +			int isHot = IsDlgButtonChecked(hwndDlg, IDC_REMOVEHOT);
 +
 +			DeleteParam *param = (DeleteParam*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 +
 +			char szEmail[MSN_MAX_EMAIL_LEN];
 +			if (!db_get_static(param->hContact, param->proto->m_szModuleName, "e-mail", szEmail, sizeof(szEmail))) {
 +				param->proto->MSN_AddUser(param->hContact, szEmail, 0, LIST_FL | (isHot ? LIST_REMOVE : LIST_REMOVENH));
 +				if (isBlock) {
 +					param->proto->MSN_AddUser(param->hContact, szEmail, 0, LIST_AL | LIST_REMOVE);
 +					param->proto->MSN_AddUser(param->hContact, szEmail, 0, LIST_BL);
 +				}
 +			}
 +			EndDialog(hwndDlg, 1);
 +		}
 +		break;
 +	}
 +
 +	return FALSE;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// Initialize options pages
 +
 +int CMsnProto::OnOptionsInit(WPARAM wParam,LPARAM lParam)
 +{
 +	OPTIONSDIALOGPAGE odp = { sizeof(odp) };
 +	odp.position    = -790000000;
 +	odp.hInstance   = hInst;
 +	odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_MSN);
 +	odp.ptszTitle   = m_tszUserName;
 +	odp.ptszGroup   = LPGENT("Network");
 +	odp.ptszTab     = LPGENT("Account");
 +	odp.flags       = ODPF_BOLDGROUPS | ODPF_TCHAR | ODPF_DONTTRANSLATE;
 +	odp.pfnDlgProc  = DlgProcMsnOpts;
 +	odp.dwInitParam = (LPARAM)this;
 +	Options_AddPage(wParam, &odp);
 +
 +	odp.ptszTab     = LPGENT("Connection");
 +	odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_MSN_CONN);
 +	odp.pfnDlgProc  = DlgProcMsnConnOpts;
 +	Options_AddPage(wParam, &odp);
 +
 +	odp.ptszTab     = LPGENT("Server list");
 +	odp.pszTemplate = MAKEINTRESOURCEA(IDD_LISTSMGR);
 +	odp.pfnDlgProc  = DlgProcMsnServLists;
 +	Options_AddPage(wParam, &odp);
 +
 +	odp.ptszTab     = LPGENT("Notifications");
 +	odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_NOTIFY);
 +	odp.pfnDlgProc  = DlgProcHotmailPopupOpts;
 +	Options_AddPage(wParam, &odp);
 +
 +	return 0;
 +}
 +
 +INT_PTR CMsnProto::SvcCreateAccMgrUI(WPARAM wParam, LPARAM lParam)
 +{
 +	return (INT_PTR)CreateDialogParam (hInst, MAKEINTRESOURCE(IDD_ACCMGRUI),
 +		(HWND)lParam, DlgProcAccMgrUI, (LPARAM)this);
 +}
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// Load resident option values into memory
 +
 +void CMsnProto::LoadOptions(void)
 +{
 +	memset(&MyOptions, 0, sizeof(MyOptions));
 +
 +	//Popup Options
 +	MyOptions.ManageServer = getByte("ManageServer", TRUE) != 0;
 +	MyOptions.ShowErrorsAsPopups = getByte("ShowErrorsAsPopups", TRUE) != 0;
 +	MyOptions.SlowSend = getByte("SlowSend", FALSE) != 0;
 +	if (db_get_static(NULL, m_szModuleName, "e-mail", MyOptions.szEmail, sizeof(MyOptions.szEmail)))
 +		MyOptions.szEmail[0] = 0;
 +	_strlwr(MyOptions.szEmail);
 +
 +	if (db_get_static(NULL, m_szModuleName, "MachineGuid", MyOptions.szMachineGuid, sizeof(MyOptions.szMachineGuid))) {
 +		char* uuid = getNewUuid();
 +		strcpy(MyOptions.szMachineGuid, uuid);
 +		setString("MachineGuid", MyOptions.szMachineGuid);
 +		mir_free(uuid);
 +	}
 +	strcpy(MyOptions.szMachineGuidP2P, MyOptions.szMachineGuid);
 +	_strlwr(MyOptions.szMachineGuidP2P);
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_p2p.cpp b/plugins/!Deprecated/MSN/src/msn_p2p.cpp new file mode 100644 index 0000000000..28001e66cc --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_p2p.cpp @@ -0,0 +1,2525 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +#include "m_smileyadd.h"
 +
 +static const char sttP2Pheader[] =
 +	"Content-Type: application/x-msnmsgrp2p\r\n"
 +	"P2P-Dest: %s\r\n\r\n";
 +
 +static const char sttP2PheaderV2[] =
 +	"Content-Type: application/x-msnmsgrp2p\r\n"
 +	"P2P-Dest: %s\r\n"
 +	"P2P-Src: %s;%s\r\n\r\n";
 +
 +const char sttVoidUid[] = "{00000000-0000-0000-0000-000000000000}";
 +static const char szUbnCall[] = "{F13B5C79-0126-458F-A29D-747C79C56530}";
 +
 +static const char p2pV2Caps[] = { 0x01, 0x0C, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x0F, 0x01, 0x00, 0x00 };
 +
 +void P2P_Header::logHeader(CMsnProto *ppro)
 +{
 +	ppro->debugLogA("--- Printing message header");
 +	ppro->debugLogA("    SessionID = %08X", mSessionID);
 +	ppro->debugLogA("    MessageID = %08X", mID);
 +#ifndef __GNUC__
 +	ppro->debugLogA("    Offset of data = %I64u", mOffset);
 +	ppro->debugLogA("    Total amount of data = %I64u", mTotalSize);
 +#else
 +	ppro->debugLogA("    Offset of data = %llu", mOffset);
 +	ppro->debugLogA("    Total amount of data = %llu", hdrdata->mTotalSize);
 +#endif
 +	ppro->debugLogA("    Data in packet = %lu bytes", mPacketLen);
 +	ppro->debugLogA("    Flags = %08X", mFlags);
 +	ppro->debugLogA("    Acknowledged session ID: %08X", mAckSessionID);
 +	ppro->debugLogA("    Acknowledged message ID: %08X", mAckUniqueID);
 +#ifndef __GNUC__
 +	ppro->debugLogA("    Acknowledged data size: %I64u", mAckDataSize);
 +#else
 +	ppro->debugLogA("    Acknowledged data size: %llu", mAckDataSize);
 +#endif
 +	ppro->debugLogA("------------------------");
 +}
 +
 +void P2PV2_Header::logHeader(CMsnProto *ppro)
 +{
 +	ppro->debugLogA("--- Printing message header");
 +	ppro->debugLogA("    SessionID = %08X", mSessionID);
 +	ppro->debugLogA("    MessageID = %08X", mID);
 +#ifndef __GNUC__
 +	ppro->debugLogA("    Remaining amount of data = %I64u", mRemSize);
 +#else
 +	ppro->debugLogA("    Remaining amount of data = %llu", mTotalSize);
 +#endif
 +	ppro->debugLogA("    Data in packet = %lu bytes", mPacketLen);
 +	ppro->debugLogA("    Packet Number = %lu", mPacketNum);
 +	ppro->debugLogA("    Operation Code = %08X", mOpCode);
 +	ppro->debugLogA("    TF Code = %08X", mTFCode);
 +	ppro->debugLogA("    Acknowledged message ID: %08X", mAckUniqueID);
 +	ppro->debugLogA("------------------------");
 +}
 +
 +bool CMsnProto::p2p_createListener(filetransfer* ft, directconnection *dc, MimeHeaders& chdrs)
 +{
 +	if (MyConnection.extIP == 0) return false;
 +
 +	NETLIBBIND nlb = {0};
 +	nlb.cbSize = sizeof(nlb);
 +	nlb.pfnNewConnectionV2 = MSN_ConnectionProc;
 +	nlb.pExtra = this;
 +	HANDLE sb = (HANDLE) CallService(MS_NETLIB_BINDPORT, (WPARAM) m_hNetlibUser, (LPARAM)&nlb);
 +	if (sb == NULL)
 +	{
 +		debugLogA("Unable to bind the port for incoming transfers");
 +		return false;
 +	}
 +
 +	ThreadData* newThread = new ThreadData;
 +	newThread->mType = SERVER_P2P_DIRECT;
 +	newThread->mCaller = 3;
 +	newThread->mIncomingBoundPort = sb;
 +	newThread->mIncomingPort = nlb.wPort;
 +	strncpy(newThread->mCookie, dc->callId , sizeof(newThread->mCookie));
 +	newThread->mInitialContactWLID = mir_strdup(ft->p2p_dest);
 +
 +	newThread->startThread(&CMsnProto::p2p_filePassiveThread, this);
 +
 +	char szIpv4[256] = "";
 +	char szIpv6[256] = "";
 +	const char *szExtIp = MyConnection.GetMyExtIPStr();
 +
 +	bool ipInt = false;
 +	int i4 = 0, i6 = 0;
 +
 +	NETLIBIPLIST* ihaddr = (NETLIBIPLIST*)CallService(MS_NETLIB_GETMYIP, 1, 0);
 +	for (unsigned i = 0; i < ihaddr->cbNum; ++i)
 +	{
 +		if (strchr(ihaddr->szIp[i], ':'))
 +		{
 +			if (i6++ != 0) strcat(szIpv6, " ");
 +			strcat(szIpv6, ihaddr->szIp[i]);
 +		}
 +		else
 +		{
 +			if (i4++ != 0) strcat(szIpv4, " ");
 +			ipInt |= (strcmp(ihaddr->szIp[i], szExtIp) == 0);
 +			strcat(szIpv4, ihaddr->szIp[i]);
 +		}
 +	}
 +	mir_free(ihaddr);
 +
 +	chdrs.addString("Bridge", "TCPv1");
 +	chdrs.addBool("Listening", true);
 +
 +	if (dc->useHashedNonce)
 +		chdrs.addString("Hashed-Nonce", dc->mNonceToHash(), 2);
 +	else
 +		chdrs.addString("Nonce", dc->mNonceToText(), 2);
 +
 +	bool bUbnCall = !ft->p2p_sessionid;
 +
 +	if (!ipInt)
 +	{
 +		chdrs.addString("IPv4External-Addrs", mir_strdup(MyConnection.GetMyExtIPStr()), bUbnCall ? 6 : 2);
 +		chdrs.addLong("IPv4External-Port", nlb.wExPort, bUbnCall ? 4 : 0);
 +	}
 +	chdrs.addString("IPv4Internal-Addrs", mir_strdup(szIpv4), bUbnCall ? 6 : 2);
 +	chdrs.addLong("IPv4Internal-Port", nlb.wPort, bUbnCall ? 4 : 0);
 +	if (szIpv6[0])
 +	{
 +		chdrs.addString("IPv6-Addrs", mir_strdup(szIpv6), 2);
 +		chdrs.addLong("IPv6-Port", nlb.wPort);
 +	}
 +	chdrs.addULong("SessionID", ft->p2p_sessionid);
 +	chdrs.addString("SChannelState", "0");
 +	chdrs.addString("Capabilities-Flags", "1");
 +
 +	return true;
 +}
 +
 +bool p2p_IsDlFileOk(filetransfer* ft)
 +{
 +	mir_sha1_ctx sha1ctx;
 +	BYTE sha[MIR_SHA1_HASH_SIZE];
 +	mir_sha1_init(&sha1ctx);
 +
 +	bool res = false;
 +
 +	int fileId = _topen(ft->std.tszCurrentFile, O_RDONLY | _O_BINARY, _S_IREAD);
 +	if (fileId != -1)
 +	{
 +		BYTE buf[4096];
 +		int bytes;
 +
 +		while((bytes = _read(fileId, buf, sizeof(buf))) > 0)
 +			mir_sha1_append(&sha1ctx, buf, bytes);
 +
 +		_close(fileId);
 +		mir_sha1_finish(&sha1ctx, sha);
 +
 +		char *szSha = arrayToHex(sha, MIR_SHA1_HASH_SIZE);
 +		char *szAvatarHash = MSN_GetAvatarHash(ft->p2p_object);
 +
 +		res = szAvatarHash != NULL && _stricmp(szAvatarHash, szSha) == 0;
 +
 +		mir_free(szSha);
 +		mir_free(szAvatarHash);
 +	}
 +	return res;
 +}
 +
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// sttSavePicture2disk - final handler for avatars downloading
 +
 +void CMsnProto::p2p_pictureTransferFailed(filetransfer* ft)
 +{
 +	switch(ft->p2p_type)
 +	{
 +	case MSN_APPID_AVATAR:
 +	case MSN_APPID_AVATAR2:
 +		{
 +			PROTO_AVATAR_INFORMATIONT AI = {0};
 +			AI.cbSize = sizeof(AI);
 +			AI.hContact = ft->std.hContact;
 +			delSetting(ft->std.hContact, "AvatarHash");
 +			ProtoBroadcastAck(AI.hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, &AI, 0);
 +		}
 +		break;
 +	}
 +	_tremove(ft->std.tszCurrentFile);
 +}
 +
 +void CMsnProto::p2p_savePicture2disk(filetransfer* ft)
 +{
 +	ft->close();
 +
 +	if (p2p_IsDlFileOk(ft))
 +	{
 +		int fileId = _topen(ft->std.tszCurrentFile, O_RDONLY | _O_BINARY, _S_IREAD);
 +		if (fileId == -1) {
 +			p2p_pictureTransferFailed(ft);
 +			return;
 +		}
 +
 +		const TCHAR* ext;
 +		int format;
 +		BYTE buf[6];
 +
 +		int bytes = _read(fileId, buf, sizeof(buf));
 +		_close(fileId);
 +		if (bytes > 4)
 +			format = ProtoGetBufferFormat(buf, &ext);
 +		else {
 +			p2p_pictureTransferFailed(ft);
 +			return;
 +		}
 +
 +		switch(ft->p2p_type)
 +		{
 +		case MSN_APPID_AVATAR:
 +		case MSN_APPID_AVATAR2:
 +			{
 +				PROTO_AVATAR_INFORMATIONT AI = {0};
 +				AI.cbSize = sizeof(AI);
 +				AI.format = format;
 +				AI.hContact = ft->std.hContact;
 +				MSN_GetAvatarFileName(AI.hContact, AI.filename, SIZEOF(AI.filename), ext);
 +
 +				_trename(ft->std.tszCurrentFile, AI.filename);
 +
 +				// Store also avatar hash
 +				char *szAvatarHash = MSN_GetAvatarHash(ft->p2p_object);
 +				setString(ft->std.hContact, "AvatarSavedHash", szAvatarHash);
 +				mir_free(szAvatarHash);
 +
 +				setString(ft->std.hContact, "PictSavedContext", ft->p2p_object);
 +				ProtoBroadcastAck(AI.hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, &AI, 0);
 +
 +				char *filename = mir_utf8encodeT(AI.filename);
 +				debugLogA("Avatar for contact %08x saved to file '%s'", AI.hContact, filename);
 +				mir_free(filename);
 +			}
 +			break;
 +
 +		case MSN_APPID_CUSTOMSMILEY:
 +		case MSN_APPID_CUSTOMANIMATEDSMILEY:
 +			{
 +				SMADD_CONT cont;
 +				cont.cbSize = sizeof(SMADD_CONT);
 +				cont.hContact = ft->std.hContact;
 +				cont.type = 1;
 +
 +				TCHAR* pathcpy = mir_tstrdup(ft->std.tszCurrentFile);
 +				_tcscpy(_tcsrchr(pathcpy, '.') + 1, ext);
 +				_trename(ft->std.tszCurrentFile, pathcpy);
 +
 +				cont.path = pathcpy;
 +
 +				CallService(MS_SMILEYADD_LOADCONTACTSMILEYS, 0, (LPARAM)&cont);
 +				mir_free(pathcpy);
 +			}
 +			break;
 +		}
 +	}
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// p2p_sendAck - sends MSN P2P acknowledgement to the received message
 +
 +static const char sttVoidSession[] = "ACHTUNG!!! an attempt made to send a message via the empty session";
 +
 +void CMsnProto::p2p_sendMsg(const char *wlid, unsigned appId, P2PB_Header& hdrdata, char* msgbody, size_t msgsz)
 +{
 +	ThreadData* info = MSN_GetP2PThreadByContact(wlid);
 +	if (info == NULL)
 +	{
 +		bool isOffline;
 +		info = MSN_StartSB(wlid, isOffline);
 +	}
 +	p2p_sendMsg(info, wlid, appId, hdrdata, msgbody, msgsz);
 +}
 +
 +void CMsnProto::p2p_sendMsg(ThreadData* info, const char *wlid, unsigned appId, P2PB_Header& hdrdata, char* msgbody, size_t msgsz)
 +{
 +	unsigned msgType;
 +
 +	if (info == NULL) msgType = 0;
 +	else if (info->mType == SERVER_P2P_DIRECT) msgType = 1;
 +	else msgType = 2;
 +
 +	unsigned fportion = msgType == 1 ? 1352 : 1202;
 +	if (hdrdata.isV2Hdr()) fportion += 4;
 +
 +	char* buf = (char*) alloca(sizeof(sttP2PheaderV2)+ MSN_MAX_EMAIL_LEN +
 +		120 + fportion);
 +
 +	size_t offset = 0;
 +	do
 +	{
 +		size_t portion = msgsz - offset;
 +		if (portion > fportion) portion = fportion;
 +
 +		char* p = buf;
 +
 +		// add message header
 +		p += msgType == 1 ? sizeof(unsigned) :
 +			sprintf(p, hdrdata.isV2Hdr() ? sttP2PheaderV2 : sttP2Pheader, wlid, MyOptions.szEmail, MyOptions.szMachineGuidP2P); //!!!!!!!!!!!
 +
 +		if (hdrdata.isV2Hdr())
 +		{
 +			P2PV2_Header *ph = (P2PV2_Header*)&hdrdata;
 +			if (offset == 0)
 +			{
 +				if (!info || !info->mBridgeInit)
 +				{
 +					if (info && ph->mSessionID)
 +					{
 +						P2PV2_Header tHdr;
 +						tHdr.mID = ph->mID;
 +						p2p_sendMsg(info, wlid, 0, tHdr, NULL, 0);
 +					}
 +					else
 +					{
 +						ph->mOpCode |= ph->mAckUniqueID && msgType != 1 ? 1 : 3;
 +						ph->mCap = p2pV2Caps;
 +						if (info) info->mBridgeInit = true;
 +					}
 +				}
 +			}
 +			else
 +			{
 +				ph->mOpCode = 0;
 +				ph->mCap = NULL;
 +			}
 +		}
 +
 +		if (msgsz)
 +		{
 +			if (hdrdata.isV2Hdr())
 +			{
 +				P2PV2_Header *ph = (P2PV2_Header*)&hdrdata;
 +				ph->mPacketLen = (unsigned)portion;
 +				ph->mRemSize = msgsz - offset - portion;
 +				ph->mTFCode = offset ?  ph->mTFCode & 0xfe : ph->mTFCode | 0x01;
 +
 +				if (offset == 0)
 +					ph->mPacketNum = p2p_getPktNum(wlid);
 +			}
 +			else
 +			{
 +				P2P_Header *ph = (P2P_Header*)&hdrdata;
 +				ph->mPacketLen = (unsigned)portion;
 +				ph->mOffset = offset;
 +				ph->mTotalSize = msgsz;
 +			}
 +		}
 +
 +		// add message body
 +		p = hdrdata.createMsg(p, wlid, this);
 +		hdrdata.logHeader(this);
 +
 +		if (msgsz)
 +			memcpy(p, msgbody + offset, portion); p += portion;
 +
 +		// add message footer
 +		if (msgType != 1)
 +		{
 +			*(unsigned*)p = _htonl(appId);
 +			p += 4;
 +		}
 +
 +		char* szEmail;
 +		switch (msgType)
 +		{
 +		case 0:
 +			parseWLID(NEWSTR_ALLOCA(wlid), NULL, &szEmail, NULL);
 +			MsgQueue_Add(szEmail, 'D', buf, p - buf);
 +			break;
 +
 +		case 1:
 +			*(unsigned*)buf = (unsigned)(p - buf - sizeof(unsigned));
 +			info->send(buf, p - buf);
 +			break;
 +
 +		case 2:
 +			info->sendRawMessage('D', buf, p - buf);
 +			break;
 +		}
 +		offset += portion;
 +	}
 +	while (offset < msgsz);
 +}
 +
 +
 +void CMsnProto::p2p_sendAck(const char *wlid, P2PB_Header* hdr)
 +{
 +	if (hdr == NULL) return;
 +
 +	if (!hdr->isV2Hdr())
 +	{
 +		P2P_Header *hdrdata = (P2P_Header*)hdr;
 +		P2P_Header tHdr;
 +
 +		tHdr.mSessionID = hdrdata->mSessionID;
 +		tHdr.mAckDataSize = hdrdata->mTotalSize;
 +		tHdr.mFlags = 2;
 +		tHdr.mAckSessionID = hdrdata->mID;
 +		tHdr.mAckUniqueID = hdrdata->mAckSessionID;
 +
 +		p2p_sendMsg(wlid, 0, tHdr, NULL, 0);
 +	}
 +	else
 +	{
 +		P2PV2_Header *hdrdata = (P2PV2_Header*)hdr;
 +		P2PV2_Header tHdr;
 +
 +		tHdr.mAckUniqueID = hdrdata->mID;
 +
 +		p2p_sendMsg(wlid, 0, tHdr, NULL, 0);
 +	}
 +}
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// p2p_sendEndSession - sends MSN P2P file transfer end packet
 +
 +void CMsnProto::p2p_sendAbortSession(filetransfer* ft)
 +{
 +	if (ft == NULL)
 +	{
 +		debugLogA(sttVoidSession);
 +		return;
 +	}
 +
 +	if (ft->p2p_isV2) return;
 +
 +	P2P_Header tHdr;
 +
 +	tHdr.mSessionID = ft->p2p_sessionid;
 +	tHdr.mAckSessionID = ft->p2p_sendmsgid;
 +	tHdr.mID = p2p_getMsgId(ft->p2p_dest, 1);
 +
 +	if (ft->std.flags & PFTS_SENDING)
 +	{
 +		tHdr.mFlags = 0x40;
 +		tHdr.mAckSessionID = tHdr.mID - 2;
 +	}
 +	else
 +	{
 +		tHdr.mAckUniqueID = 0x8200000f;
 +		tHdr.mFlags = 0x80;
 +		tHdr.mAckDataSize = ft->std.currentFileSize;
 +	}
 +
 +	p2p_sendMsg(ft->p2p_dest, 0, tHdr, NULL, 0);
 +	ft->ts = time(NULL);
 +}
 +
 +void CMsnProto::p2p_sendRedirect(filetransfer* ft)
 +{
 +	if (ft == NULL)
 +	{
 +		debugLogA(sttVoidSession);
 +		return;
 +	}
 +
 +	if (ft->p2p_isV2) return;
 +
 +	P2P_Header tHdr;
 +
 +	tHdr.mSessionID = ft->p2p_sessionid;
 +	tHdr.mFlags = 0x01;
 +	tHdr.mAckSessionID = ft->p2p_sendmsgid;
 +	tHdr.mAckDataSize = ft->std.currentFileProgress;
 +
 +	p2p_sendMsg(ft->p2p_dest, 0, tHdr, NULL, 0);
 +
 +	ft->tTypeReq = MSN_GetP2PThreadByContact(ft->p2p_dest) ? SERVER_P2P_DIRECT : SERVER_SWITCHBOARD;
 +	ft->ts = time(NULL);
 +	ft->p2p_waitack = true;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// p2p_sendSlp - send MSN P2P SLP packet
 +
 +void CMsnProto::p2p_sendSlp(int iKind, filetransfer *ft, MimeHeaders &pHeaders,
 +	MimeHeaders &pContent, const char *wlid)
 +{
 +	if (ft == NULL)
 +	{
 +		debugLogA(sttVoidSession);
 +		return;
 +	}
 +
 +	if (wlid == NULL) wlid = ft->p2p_dest;
 +
 +	size_t cbContLen = pContent.getLength();
 +	pHeaders.addULong("Content-Length", (unsigned)cbContLen + 1);
 +
 +	char* buf = (char*)alloca(pHeaders.getLength() + cbContLen + 512);
 +	char* p = buf;
 +
 +	switch (iKind)
 +	{
 +		case -3:   p += sprintf(p, "ACK MSNMSGR:%s MSNSLP/1.0", wlid); break; //!!!!!!!!!!!!!!!!!!
 +		case -2:   p += sprintf(p, "INVITE MSNMSGR:%s MSNSLP/1.0", wlid); break; //!!!!!!!!!!!!!!!!!!
 +		case -1:   p += sprintf(p, "BYE MSNMSGR:%s MSNSLP/1.0", wlid); break; //!!!!!!!!!!!!!!!!!!
 +		case 200:  p += sprintf(p, "MSNSLP/1.0 200 OK");	break; //!!!!!!!!!!!!!!!!!!
 +		case 481:  p += sprintf(p, "MSNSLP/1.0 481 No Such Call"); break; //!!!!!!!!!!!!!!!!!!
 +		case 500:  p += sprintf(p, "MSNSLP/1.0 500 Internal Error"); break; //!!!!!!!!!!!!!!!!!!
 +		case 603:  p += sprintf(p, "MSNSLP/1.0 603 DECLINE"); break; //!!!!!!!!!!!!!!!!!!
 +		case 1603: p += sprintf(p, "MSNSLP/1.0 603 Decline"); break; //!!!!!!!!!!!!!!!!!!
 +		default: return;
 +	}
 +
 +	if (iKind < 0)
 +	{
 +		mir_free(ft->p2p_branch);
 +		ft->p2p_branch = getNewUuid();
 +	}
 +
 +	if (ft->p2p_isV2)
 +	{
 +		p += sprintf(p,
 +			"\r\nTo: <msnmsgr:%s>\r\n"
 +			"From: <msnmsgr:%s;%s>\r\n"
 +			"Via: MSNSLP/1.0/TLP ;branch=%s\r\n",
 +			wlid, MyOptions.szEmail, MyOptions.szMachineGuidP2P, ft->p2p_branch); //!!!!!!!!!!!!!!!!!!
 +	}
 +	else
 +	{
 +		p += sprintf(p,
 +			"\r\nTo: <msnmsgr:%s>\r\n"
 +			"From: <msnmsgr:%s>\r\n"
 +			"Via: MSNSLP/1.0/TLP ;branch=%s\r\n",
 +			wlid, MyOptions.szEmail, ft->p2p_branch); //!!!!!!!!!!!!!!!!!!
 +	}
 +
 +	p = pHeaders.writeToBuffer(p);
 +	p = pContent.writeToBuffer(p);
 +
 +	unsigned short status = getWord(ft->std.hContact, "Status", ID_STATUS_OFFLINE);
 +	if (!(myFlags & cap_SupportsP2PBootstrap) || ft->p2p_sessionid ||
 +		MSN_GetThreadByContact(wlid, SERVER_P2P_DIRECT) ||
 +		status == ID_STATUS_OFFLINE || status == ID_STATUS_INVISIBLE ||
 +		m_iStatus == ID_STATUS_INVISIBLE)
 +	{
 +		if (!ft->p2p_isV2)
 +		{
 +			P2P_Header tHdr;
 +			tHdr.mAckSessionID = ft->p2p_acksessid;
 +
 +			p2p_sendMsg(wlid, 0, tHdr, buf, p - buf + 1);
 +			ft->p2p_waitack = true;
 +
 +			switch (iKind)
 +			{
 +			case -1: case 500: case 603:
 +				ft->p2p_byemsgid  = tHdr.mID;
 +				break;
 +			}
 +
 +		}
 +		else
 +		{
 +			P2PV2_Header tHdr;
 +			tHdr.mTFCode = 0x01;
 +
 +			p2p_sendMsg(wlid, 0, tHdr, buf, p - buf + 1);
 +		}
 +	}
 +	else
 +		msnNsThread->sendPacket("UUN", "%s 3 %d\r\n%s", wlid, p - buf, buf);
 +
 +	ft->ts = time(NULL);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// p2p_sendBye - closes P2P session
 +
 +void CMsnProto::p2p_sendBye(filetransfer* ft)
 +{
 +	if (ft == NULL)
 +	{
 +		debugLogA(sttVoidSession);
 +		return;
 +	}
 +
 +	MimeHeaders tHeaders(8);
 +	tHeaders.addString("CSeq", "0 ");
 +	tHeaders.addString("Call-ID", ft->p2p_callID);
 +	tHeaders.addLong("Max-Forwards", 0);
 +	tHeaders.addString("Content-Type", "application/x-msnmsgr-sessionclosebody");
 +
 +	MimeHeaders chdrs(2);
 +	chdrs.addULong("SessionID", ft->p2p_sessionid);
 +	chdrs.addString("SChannelState", "0");
 +
 +	p2p_sendSlp(-1, ft, tHeaders, chdrs);
 +}
 +
 +void CMsnProto::p2p_sendCancel(filetransfer* ft)
 +{
 +	p2p_sendBye(ft);
 +	p2p_sendAbortSession(ft);
 +}
 +
 +void CMsnProto::p2p_sendNoCall(filetransfer* ft)
 +{
 +	if (ft == NULL)
 +	{
 +		debugLogA(sttVoidSession);
 +		return;
 +	}
 +
 +	MimeHeaders tHeaders(8);
 +	tHeaders.addString("CSeq", "0 ");
 +	tHeaders.addString("Call-ID", ft->p2p_callID);
 +	tHeaders.addLong("Max-Forwards", 0);
 +	tHeaders.addString("Content-Type", "application/x-msnmsgr-session-failure-respbody");
 +
 +	MimeHeaders chdrs(2);
 +	chdrs.addULong("SessionID", ft->p2p_sessionid);
 +	chdrs.addString("SChannelState", "0");
 +
 +	p2p_sendSlp(481, ft, tHeaders, chdrs);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// p2p_sendStatus - send MSN P2P status and its description
 +
 +void CMsnProto::p2p_sendStatus(filetransfer* ft, long lStatus)
 +{
 +	if (ft == NULL)
 +	{
 +		debugLogA(sttVoidSession);
 +		return;
 +	}
 +
 +	MimeHeaders tHeaders(8);
 +	tHeaders.addString("CSeq", "1 ");
 +	tHeaders.addString("Call-ID", ft->p2p_callID);
 +	tHeaders.addLong("Max-Forwards", 0);
 +
 +	MimeHeaders chdrs(2);
 +	chdrs.addULong("SessionID", ft->p2p_sessionid);
 +
 +	if (lStatus != 1603)
 +	{
 +		tHeaders.addString("Content-Type", "application/x-msnmsgr-sessionreqbody");
 +
 +		chdrs.addString("SChannelState", "0");
 +	}
 +	else
 +		tHeaders.addString("Content-Type", "application/x-msnmsgr-transrespbody");
 +
 +	p2p_sendSlp(lStatus, ft, tHeaders, chdrs);
 +}
 +
 +void CMsnProto::p2p_sendAvatarInit(filetransfer* ft)
 +{
 +	unsigned body = 0;
 +
 +	if (ft->p2p_isV2)
 +	{
 +		P2PV2_Header tHdr;
 +		tHdr.mSessionID = ft->p2p_sessionid;
 +		tHdr.mTFCode = 0x01;
 +		p2p_sendMsg(ft->p2p_dest, ft->p2p_appID, tHdr, (char*)&body, sizeof(body));
 +	}
 +	else
 +	{
 +		P2P_Header tHdr;
 +		tHdr.mSessionID = ft->p2p_sessionid;
 +		tHdr.mAckSessionID = ft->p2p_acksessid;
 +		p2p_sendMsg(ft->p2p_dest, ft->p2p_appID, tHdr, (char*)&body, sizeof(body));
 +
 +		ft->ts = time(NULL);
 +		ft->p2p_waitack = true;
 +	}
 +}
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// p2p_connectTo - connects to a remote P2P server
 +
 +static const char p2p_greeting[8] = { 4, 0, 0, 0, 'f', 'o', 'o', 0  };
 +
 +static void sttSendPacket(ThreadData* T, void* hdr, unsigned len)
 +{
 +	T->send((char*)&len, sizeof(unsigned));
 +	T->send((char*)hdr, len);
 +}
 +
 +bool CMsnProto::p2p_connectTo(ThreadData* info, directconnection *dc)
 +{
 +	NETLIBOPENCONNECTION tConn = {0};
 +	tConn.cbSize = sizeof(tConn);
 +	tConn.szHost = info->mServer;
 +	tConn.flags = NLOCF_V2;
 +	tConn.timeout = 5;
 +
 +	char* tPortDelim = strrchr(info->mServer, ':');
 +	if (tPortDelim != NULL)
 +	{
 +		*tPortDelim = '\0';
 +		tConn.wPort = (WORD)atol(tPortDelim + 1);
 +	}
 +
 +	debugLogA("Connecting to %s:%d", tConn.szHost, tConn.wPort);
 +
 +	info->s = (HANDLE)CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)m_hNetlibUser, (LPARAM)&tConn);
 +	if (info->s == NULL)
 +	{
 +		TWinErrorCode err;
 +		debugLogA("Connection Failed (%d): %s", err.mErrorCode, err.getText());
 +		return false;
 +	}
 +	info->send(p2p_greeting, sizeof(p2p_greeting));
 +
 +	bool isV2 = strchr(info->mInitialContactWLID, ';') != NULL;
 +
 +	P2P_Header reply;
 +	if (!isV2)
 +	{
 +		reply.mFlags = 0x100;
 +
 +		if (dc->useHashedNonce)
 +			memcpy(&reply.mAckSessionID, dc->mNonce, sizeof(UUID));
 +		else
 +			dc->xNonceToBin((UUID*)&reply.mAckSessionID);
 +
 +		char buf[48];
 +		reply.createMsg(buf, info->mInitialContactWLID, this);
 +		sttSendPacket(info, buf, sizeof(buf));
 +	}
 +	else
 +		sttSendPacket(info, dc->mNonce, sizeof(UUID));
 +
 +	long cbPacketLen;
 +	HReadBuffer buf(info, 0);
 +	BYTE* p;
 +	if ((p = buf.surelyRead(4)) == NULL)
 +	{
 +		debugLogA("Error reading data, closing filetransfer");
 +		return false;
 +	}
 +
 +	cbPacketLen = *(long*)p;
 +	if ((p = buf.surelyRead(cbPacketLen)) == NULL)
 +		return false;
 +
 +	bool cookieMatch;
 +
 +	if (!isV2)
 +	{
 +		P2P_Header cookie((char*)p);
 +
 +		if (dc->useHashedNonce)
 +		{
 +			char* hnonce = dc->calcHashedNonce((UUID*)&cookie.mAckSessionID);
 +			cookieMatch = strcmp(hnonce, dc->xNonce) == 0;
 +			mir_free(hnonce);
 +		}
 +		else
 +			cookieMatch = memcmp(&cookie.mAckSessionID, &reply.mAckSessionID, sizeof(UUID)) == 0;
 +	}
 +	else
 +	{
 +		char* hnonce = dc->calcHashedNonce((UUID*)p);
 +		cookieMatch = strcmp(hnonce, dc->xNonce) == 0;
 +		mir_free(hnonce);
 +	}
 +
 +	if (!cookieMatch)
 +	{
 +		debugLogA("Invalid cookie received, exiting");
 +		return false;
 +	}
 +
 +	return true;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// p2p_listen - acts like a local P2P server
 +
 +bool CMsnProto::p2p_listen(ThreadData* info, directconnection *dc)
 +{
 +	switch(WaitForSingleObject(info->hWaitEvent, 10000))
 +	{
 +	case WAIT_TIMEOUT:
 +	case WAIT_FAILED:
 +		debugLogA("Incoming connection timed out, closing file transfer");
 +		MSN_StartP2PTransferByContact(info->mInitialContactWLID);
 +LBL_Error:
 +		debugLogA("File listen failed");
 +		return false;
 +	}
 +
 +	HReadBuffer buf(info, 0);
 +	BYTE* p;
 +
 +	if ((p = buf.surelyRead(8)) == NULL)
 +		goto LBL_Error;
 +
 +	if (memcmp(p, p2p_greeting, 8) != 0)
 +	{
 +		debugLogA("Invalid input data, exiting");
 +		return false;
 +	}
 +
 +	if ((p = buf.surelyRead(4)) == NULL)
 +	{
 +		debugLogA("Error reading data, closing filetransfer");
 +		return false;
 +	}
 +
 +	long cbPacketLen = *(long*)p;
 +	if ((p = buf.surelyRead(cbPacketLen)) == NULL)
 +		goto LBL_Error;
 +
 +	bool cookieMatch;
 +	bool isV2 = strchr(info->mInitialContactWLID, ';') != NULL;
 +
 +	if (!isV2)
 +	{
 +		P2P_Header cookie((char*)p);
 +
 +		if (dc->useHashedNonce)
 +		{
 +			char* hnonce = dc->calcHashedNonce((UUID*)&cookie.mAckSessionID);
 +			cookieMatch = strcmp(hnonce, dc->xNonce) == 0;
 +			mir_free(hnonce);
 +			memcpy(&cookie.mAckSessionID, dc->mNonce, sizeof(UUID));
 +		}
 +		else
 +			cookieMatch = memcmp(&cookie.mAckSessionID, dc->mNonce, sizeof(UUID)) == 0;
 +
 +		if (!cookieMatch)
 +		{
 +			debugLogA("Invalid cookie received, exiting");
 +			return false;
 +		}
 +
 +		char buf[48];
 +		cookie.createMsg(buf, info->mInitialContactWLID, this);
 +		sttSendPacket(info, buf, sizeof(buf));
 +	}
 +	else
 +	{
 +		char* hnonce = dc->calcHashedNonce((UUID*)p);
 +		cookieMatch = strcmp(hnonce, dc->xNonce) == 0;
 +		mir_free(hnonce);
 +
 +		if (!cookieMatch)
 +		{
 +			debugLogA("Invalid cookie received, exiting");
 +			goto LBL_Error;
 +		}
 +
 +		sttSendPacket(info, dc->mNonce, sizeof(UUID));
 +	}
 +
 +	return true;
 +}
 +
 +LONG CMsnProto::p2p_sendPortion(filetransfer* ft, ThreadData* T, bool isV2)
 +{
 +	LONG trid;
 +	char databuf[1500], *p = databuf;
 +
 +	// Compute the amount of data to send
 +	unsigned fportion = T->mType == SERVER_P2P_DIRECT ? 1352 : 1202;
 +	if (isV2) fportion += 4;
 +
 +	const unsigned __int64 dt = ft->std.currentFileSize - ft->std.currentFileProgress;
 +	const unsigned portion = dt > fportion ? fportion : dt;
 +
 +	// Fill data size for direct transfer
 +
 +	if (T->mType != SERVER_P2P_DIRECT)
 +		p += sprintf(p, isV2 ? sttP2PheaderV2 : sttP2Pheader, ft->p2p_dest, MyOptions.szEmail, MyOptions.szMachineGuidP2P); //!!!!!!!!!!!!!!!!!!
 +	else
 +		p += sizeof(unsigned);
 +
 +	if (!isV2)
 +	{
 +		// Fill P2P header
 +		P2P_Header H;
 +
 +		H.mSessionID = ft->p2p_sessionid;
 +		H.mID = ft->p2p_sendmsgid;
 +		H.mFlags = ft->p2p_appID == MSN_APPID_FILE ? 0x01000030 : 0x20;
 +		H.mTotalSize = ft->std.currentFileSize;
 +		H.mOffset = ft->std.currentFileProgress;
 +		H.mPacketLen = portion;
 +		H.mAckSessionID = ft->p2p_acksessid;
 +
 +		p = H.createMsg(p, ft->p2p_dest, this);
 +	}
 +	else
 +	{
 +		P2PV2_Header H;
 +
 +		H.mSessionID = ft->p2p_sessionid;
 +		H.mTFCode = (ft->p2p_appID == MSN_APPID_FILE ? 6 : 4) | (ft->std.currentFileProgress ? 0 : 1);
 +		H.mRemSize = ft->std.currentFileSize - ft->std.currentFileProgress - portion;
 +		H.mPacketLen = portion;
 +		H.mPacketNum = ft->p2p_sendmsgid;
 +
 +		p = H.createMsg(p, ft->p2p_dest, this);
 +		H.logHeader(this);
 +	}
 +
 +	if (T->mType == SERVER_P2P_DIRECT)
 +		*(unsigned*)databuf = portion + (p - databuf) - (unsigned)sizeof(unsigned);
 +
 +	// Fill data (payload) for transfer
 +	if (ft->fileId == -1) return 0;
 +	_read(ft->fileId, p, portion);
 +	p += portion;
 +
 +	if (T->mType == SERVER_P2P_DIRECT)
 +		trid = T->send(databuf, p - databuf);
 +	else
 +	{
 +		// Define packet footer for server transfer
 +		*(unsigned*)p = _htonl(ft->p2p_appID);
 +		p += sizeof(unsigned);
 +
 +		trid = T->sendRawMessage('D', (char *)databuf, p - databuf);
 +	}
 +
 +	if (trid != 0)
 +	{
 +		ft->std.totalProgress += portion;
 +		ft->std.currentFileProgress += portion;
 +		if (ft->p2p_appID == MSN_APPID_FILE && clock() >= ft->nNotify)
 +		{
 +			ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->std);
 +			ft->nNotify = clock() + 500;
 +		}
 +	}
 +	else
 +		debugLogA(" Error sending");
 +	ft->ts = time(NULL);
 +	ft->p2p_waitack = true;
 +
 +	return trid;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// p2p_sendFeedThread - sends a file via server
 +
 +void __cdecl CMsnProto::p2p_sendFeedThread(void* arg)
 +{
 +	ThreadData* info = (ThreadData*)arg;
 +
 +	bool isV2 = strchr(info->mInitialContactWLID, ';') != NULL;
 +
 +	info->contactJoined(info->mInitialContactWLID);
 +	mir_free(info->mInitialContactWLID); info->mInitialContactWLID = NULL;
 +
 +	debugLogA("File send thread started");
 +
 +	switch(WaitForSingleObject(info->hWaitEvent, 6000))
 +	{
 +	case WAIT_FAILED:
 +		debugLogA("File send wait failed");
 +		return;
 +	}
 +
 +	HANDLE hLockHandle = NULL;
 +	ThreadData* T = NULL;
 +	TInfoType lastType = SERVER_NOTIFICATION;
 +
 +	filetransfer *ft = p2p_getSessionByCallID(info->mCookie,
 +		info->mJoinedIdentContactsWLID.getCount() ? info->mJoinedIdentContactsWLID[0] : info->mJoinedContactsWLID[0]);
 +
 +	if (ft != NULL && WaitForSingleObject(ft->hLockHandle, 2000) == WAIT_OBJECT_0)
 +	{
 +		hLockHandle = ft->hLockHandle;
 +
 +		if (isV2)
 +			ft->p2p_sendmsgid = p2p_getPktNum(ft->p2p_dest);
 +		else
 +		{
 +			if (ft->p2p_sendmsgid == 0)
 +				ft->p2p_sendmsgid = p2p_getMsgId(ft->p2p_dest, 1);
 +		}
 +
 +		T = MSN_GetP2PThreadByContact(ft->p2p_dest);
 +		if (T != NULL)
 +			ft->tType = lastType = T->mType;
 +
 +		ReleaseMutex(hLockHandle);
 +	}
 +	else
 +		return;
 +
 +	bool fault = false;
 +	while (WaitForSingleObject(hLockHandle, 2000) == WAIT_OBJECT_0 &&
 +		ft->std.currentFileProgress < ft->std.currentFileSize && !ft->bCanceled)
 +	{
 +		if (ft->tType != lastType)
 +			T = MSN_GetThreadByContact(ft->p2p_dest, ft->tType);
 +
 +		if (ft->bCanceled) break;
 +		bool cfault = (T == NULL || p2p_sendPortion(ft, T, isV2) == 0);
 +
 +		if (cfault)
 +		{
 +			if (fault)
 +			{
 +				debugLogA("File send failed");
 +				break;
 +			}
 +			else
 +				SleepEx(3000, TRUE);  // Allow 3 sec for redirect request
 +		}
 +		fault = cfault;
 +
 +		ReleaseMutex(hLockHandle);
 +
 +		if (T != NULL && T->mType != SERVER_P2P_DIRECT)
 +			WaitForSingleObject(T->hWaitEvent, 5000);
 +	}
 +	ReleaseMutex(hLockHandle);
 +
 +	if (ft->p2p_appID == MSN_APPID_FILE)
 +		ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->std);
 +
 +	if (isV2)
 +	{
 +		if (!ft->bCanceled)
 +		{
 +			ft->bCompleted = true;
 +			p2p_sendBye(ft);
 +		}
 +		p2p_sessionComplete(ft);
 +	}
 +
 +	debugLogA("File send thread completed");
 +}
 +
 +
 +void CMsnProto::p2p_sendFeedStart(filetransfer* ft)
 +{
 +	if (ft->std.flags & PFTS_SENDING)
 +	{
 +		ThreadData* newThread = new ThreadData;
 +		newThread->mType = SERVER_FILETRANS;
 +		strcpy(newThread->mCookie, ft->p2p_callID);
 +		newThread->mInitialContactWLID = mir_strdup(ft->p2p_dest);
 +		newThread->startThread(&CMsnProto::p2p_sendFeedThread, this);
 +	}
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// p2p_sendFileDirectly - sends a file via MSN P2P protocol
 +
 +void CMsnProto::p2p_sendRecvFileDirectly(ThreadData* info)
 +{
 +	long cbPacketLen = 0;
 +	long state = 0;
 +
 +	HReadBuffer buf(info, 0);
 +	char *wlid = info->mInitialContactWLID;
 +
 +	info->contactJoined(wlid);
 +	info->mInitialContactWLID = NULL;
 +
 +	MSN_StartP2PTransferByContact(wlid);
 +	p2p_redirectSessions(wlid);
 +	p2p_startSessions(wlid);
 +
 +	bool isV2 = strchr(wlid, ';') != NULL;
 +
 +	for (;;)
 +	{
 +		long len = state ? cbPacketLen : 4;
 +
 +		BYTE* p = buf.surelyRead(len);
 +
 +		if (p == NULL)
 +			break;
 +
 +		if (state == 0)
 +			cbPacketLen = *(long*)p;
 +		else if (!isV2)
 +			p2p_processMsg(info, (char*)p, wlid);
 +		else
 +			p2p_processMsgV2(info, (char*)p, wlid);
 +
 +		state = (state + 1) % 2;
 +	}
 +
 +	info->contactLeft(wlid);
 +	p2p_redirectSessions(wlid);
 +	mir_free(wlid);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// bunch of thread functions to cover all variants of P2P file transfers
 +
 +void __cdecl CMsnProto::p2p_fileActiveThread(void* arg)
 +{
 +	ThreadData* info = (ThreadData*)arg;
 +
 +	debugLogA("p2p_fileActiveThread() started: connecting to '%s'", info->mServer);
 +
 +	directconnection *dc = p2p_getDCByCallID(info->mCookie, info->mInitialContactWLID);
 +	if (dc)
 +	{
 +		if (p2p_connectTo(info, dc))
 +			p2p_sendRecvFileDirectly(info);
 +		else
 +		{
 +			mir_free(info->mInitialContactWLID);
 +			info->mInitialContactWLID = NULL;
 +		}
 +
 +		if (!MSN_GetThreadByContact(dc->wlid, SERVER_P2P_DIRECT) && !MSN_GetUnconnectedThread(dc->wlid, SERVER_P2P_DIRECT))
 +			p2p_unregisterDC(dc);
 +	}
 +
 +	debugLogA("p2p_fileActiveThread() completed: connecting to '%s'", info->mServer);
 +}
 +
 +void __cdecl CMsnProto::p2p_filePassiveThread(void* arg)
 +{
 +	ThreadData* info = (ThreadData*)arg;
 +
 +	debugLogA("p2p_filePassiveThread() started: listening");
 +
 +	directconnection *dc = p2p_getDCByCallID(info->mCookie, info->mInitialContactWLID);
 +	if (dc)
 +	{
 +		if (p2p_listen(info, dc))
 +			p2p_sendRecvFileDirectly(info);
 +		else
 +		{
 +			mir_free(info->mInitialContactWLID); info->mInitialContactWLID = NULL;
 +		}
 +
 +		if (!MSN_GetThreadByContact(dc->wlid, SERVER_P2P_DIRECT) && !MSN_GetUnconnectedThread(dc->wlid, SERVER_P2P_DIRECT))
 +			p2p_unregisterDC(dc);
 +	}
 +
 +	debugLogA("p2p_filePassiveThread() completed");
 +}
 +
 +
 +void CMsnProto::p2p_InitFileTransfer(
 +	ThreadData*		info,
 +	MimeHeaders&	tFileInfo,
 +	MimeHeaders&	tFileInfo2,
 +	const char* wlid)
 +{
 +	if (info->mJoinedContactsWLID.getCount() == 0 && info->mJoinedIdentContactsWLID.getCount() == 0)
 +		return;
 +
 +	const char	*szCallID = tFileInfo["Call-ID"],
 +				*szBranch = tFileInfo["Via"];
 +
 +	if (szBranch != NULL) {
 +		szBranch = strstr(szBranch, "branch=");
 +		if (szBranch != NULL)
 +			szBranch += 7;
 +	}
 +	if (szCallID == NULL || szBranch == NULL) {
 +		debugLogA("Ignoring invalid invitation: CallID='%s', szBranch='%s'", szCallID, szBranch);
 +		return;
 +	}
 +
 +	const char	*szSessionID = tFileInfo2["SessionID"],
 +				*szEufGuid   = tFileInfo2["EUF-GUID"],
 +				*szContext   = tFileInfo2["Context"],
 +				*szAppId     = tFileInfo2["AppID"];
 +
 +	if (szSessionID == NULL || szAppId == NULL || szEufGuid == NULL)
 +	{
 +		debugLogA("Ignoring invalid invitation: SessionID='%s', AppID=%s, Branch='%s',Context='%s'",
 +			szSessionID, szAppId, szEufGuid, szContext);
 +		return;
 +	}
 +
 +	unsigned dwAppID = strtoul(szAppId, NULL, 10);
 +	unsigned dwSessionId = strtoul(szSessionID, NULL, 10);
 +
 +	if (p2p_getSessionByID(dwSessionId))
 +		return;
 +
 +	szContext = (char*)mir_base64_decode(szContext, 0);
 +
 +	filetransfer* ft = new filetransfer(this);
 +	ft->p2p_acksessid = MSN_GenRandom();
 +	ft->p2p_sessionid = dwSessionId;
 +	ft->p2p_appID = dwAppID == MSN_APPID_AVATAR ? MSN_APPID_AVATAR2 : dwAppID;
 +	ft->p2p_type = dwAppID;
 +	ft->p2p_ackID = dwAppID == MSN_APPID_FILE ? 2000 : 1000;
 +	replaceStr(ft->p2p_callID, szCallID);
 +	replaceStr(ft->p2p_branch, szBranch);
 +	ft->p2p_dest = mir_strdup(wlid);
 +	ft->p2p_isV2 = strchr(wlid, ';') != NULL;
 +	ft->std.hContact = MSN_HContactFromEmail(wlid);
 +
 +	p2p_registerSession(ft);
 +
 +	switch (dwAppID)
 +	{
 +	case MSN_APPID_AVATAR:
 +	case MSN_APPID_AVATAR2:
 +		if (!_stricmp(szEufGuid, "{A4268EEC-FEC5-49E5-95C3-F126696BDBF6}")) {
 +			DBVARIANT dbv;
 +			bool pictmatch = !getString("PictObject", &dbv);
 +			if (pictmatch)
 +			{
 +				UrlDecode(dbv.pszVal);
 +
 +				ezxml_t xmlcon = ezxml_parse_str((char*)szContext, strlen(szContext));
 +				ezxml_t xmldb = ezxml_parse_str(dbv.pszVal, strlen(dbv.pszVal));
 +
 +				const char *szCtBuf = ezxml_attr(xmlcon, "SHA1C");
 +				if (szCtBuf)
 +				{
 +					const char *szPtBuf = ezxml_attr(xmldb,  "SHA1C");
 +					pictmatch = szPtBuf && strcmp(szCtBuf, szPtBuf) == 0;
 +				}
 +				else
 +				{
 +					const char *szCtBuf = ezxml_attr(xmlcon, "SHA1D");
 +					const char *szPtBuf = ezxml_attr(xmldb,  "SHA1D");
 +					pictmatch = szCtBuf && szPtBuf && strcmp(szCtBuf, szPtBuf) == 0;
 +				}
 +
 +				ezxml_free(xmlcon);
 +				ezxml_free(xmldb);
 +				db_free(&dbv);
 +			}
 +			if (pictmatch)
 +			{
 +				TCHAR szFileName[MAX_PATH];
 +				MSN_GetAvatarFileName(NULL, szFileName, SIZEOF(szFileName), NULL);
 +				ft->fileId = _topen(szFileName, O_RDONLY | _O_BINARY, _S_IREAD);
 +				if (ft->fileId == -1)
 +				{
 +					p2p_sendStatus(ft, 603);
 +					MSN_ShowError("Your avatar not set correctly. Avatar should be set in View/Change My Details | Avatar");
 +					debugLogA("Unable to open avatar file '%s', error %d", szFileName, errno);
 +					p2p_unregisterSession(ft);
 +				}
 +				else
 +				{
 +					mir_free(ft->std.tszCurrentFile);
 +					ft->std.tszCurrentFile = mir_tstrdup(szFileName);
 +//						debugLogA("My avatar file opened for %s as %08p::%d", szEmail, ft, ft->fileId);
 +					ft->std.totalBytes = ft->std.currentFileSize = _filelengthi64(ft->fileId);
 +					ft->std.flags |= PFTS_SENDING;
 +
 +					//---- send 200 OK Message
 +					p2p_sendStatus(ft, 200);
 +					p2p_sendFeedStart(ft);
 +
 +					if (ft->p2p_isV2)
 +					{
 +						p2p_sendAvatarInit(ft);
 +						MSN_StartP2PTransferByContact(ft->p2p_dest);
 +					}
 +				}
 +			}
 +			else
 +			{
 +				p2p_sendStatus(ft, 603);
 +				debugLogA("Requested avatar does not match current avatar");
 +				p2p_unregisterSession(ft);
 +			}
 +		}
 +		break;
 +
 +	case MSN_APPID_FILE:
 +		if (!_stricmp(szEufGuid, "{5D3E02AB-6190-11D3-BBBB-00C04F795683}"))
 +		{
 +			wchar_t* wszFileName = ((HFileContext*)szContext)->wszFileName;
 +			for (wchar_t* p = wszFileName; *p != 0; p++)
 +			{
 +				switch(*p)
 +				{
 +				case ':': case '?': case '/': case '\\': case '*':
 +					*p = '_';
 +				}
 +			}
 +
 +			mir_free(ft->std.tszCurrentFile);
 +			ft->std.tszCurrentFile = mir_u2t(wszFileName);
 +
 +			ft->std.totalBytes = ft->std.currentFileSize = ((HFileContext*)szContext)->dwSize;
 +			ft->std.totalFiles = 1;
 +
 +			TCHAR tComment[40];
 +			mir_sntprintf(tComment, SIZEOF(tComment), TranslateT("%I64u bytes"), ft->std.currentFileSize);
 +
 +			PROTORECVFILET pre = {0};
 +			pre.flags = PREF_TCHAR;
 +			pre.fileCount = 1;
 +			pre.timestamp = time(NULL);
 +			pre.tszDescription = tComment;
 +			pre.ptszFiles = &ft->std.tszCurrentFile;
 +			pre.lParam = (LPARAM)ft;
 +			ProtoChainRecvFile(ft->std.hContact, &pre);
 +		}
 +		break;
 +
 +	case MSN_APPID_WEBCAM:
 +		if (!_stricmp(szEufGuid, "{4BD96FC0-AB17-4425-A14A-439185962DC8}")) {
 +			MSN_ShowPopup(ft->std.hContact,
 +				TranslateT("Contact tried to send its webcam data (not currently supported)"),
 +				MSN_ALLOW_MSGBOX | MSN_SHOW_ERROR);
 +		}
 +		if (!_stricmp(szEufGuid, "{1C9AA97E-9C05-4583-A3BD-908A196F1E92}")) {
 +			MSN_ShowPopup(ft->std.hContact,
 +				TranslateT("Contact tried to view your webcam data (not currently supported)"),
 +				MSN_ALLOW_MSGBOX | MSN_SHOW_ERROR);
 +		}
 +		p2p_sendStatus(ft, 603);
 +		p2p_unregisterSession(ft);
 +		break;
 +
 +	case MSN_APPID_MEDIA_SHARING:
 +//		MSN_ShowPopup(ft->std.hContact,
 +//			TranslateT("Contact tried to share media with us (not currently supported)"),
 +//			MSN_ALLOW_MSGBOX | MSN_SHOW_ERROR);
 +		p2p_sendStatus(ft, 603);
 +		p2p_unregisterSession(ft);
 +		break;
 +
 +	default:
 +		p2p_sendStatus(ft, 603);
 +		p2p_unregisterSession(ft);
 +		debugLogA("Invalid or unknown data transfer request (AppID/EUF-GUID: %ld/%s)", dwAppID, szEufGuid);
 +		break;
 +	}
 +
 +	mir_free((void*)szContext);
 +}
 +
 +void CMsnProto::p2p_InitDirectTransfer(MimeHeaders& tFileInfo, MimeHeaders& tFileInfo2, const char* wlid)
 +{
 +	const char	*szCallID      = tFileInfo["Call-ID"],
 +				*szBranch      = tFileInfo["Via"],
 +				*szConnType    = tFileInfo2["Conn-Type"],
 +				*szUPnPNat     = tFileInfo2["UPnPNat"],
 +				*szNetID       = tFileInfo2["NetID"],
 +				*szICF         = tFileInfo2["ICF"],
 +				*szHashedNonce = tFileInfo2["Hashed-Nonce"];
 +
 +	if (szBranch != NULL)
 +	{
 +		szBranch = strstr(szBranch, "branch=");
 +		if (szBranch != NULL)
 +			szBranch += 7;
 +	}
 +	if (szCallID == NULL || szBranch == NULL)
 +	{
 +		debugLogA("Ignoring invalid invitation: CallID='%s', Branch='%s'", szCallID, szBranch);
 +		return;
 +	}
 +
 +	if (szConnType == NULL || szUPnPNat == NULL || szICF == NULL || szNetID == NULL)
 +	{
 +		debugLogA("Ignoring invalid invitation: ConnType='%s', UPnPNat='%s', ICF='%s', NetID='%s'",
 +			szConnType, szUPnPNat, szICF, szNetID);
 +		return;
 +	}
 +
 +	filetransfer ftl(this), *ft = p2p_getSessionByCallID(szCallID, wlid);
 +	if (!ft || !ft->p2p_sessionid)
 +	{
 +		ft = &ftl;
 +		replaceStr(ft->p2p_dest, wlid);
 +		replaceStr(ft->p2p_callID, szCallID);
 +		replaceStr(ft->p2p_branch, szBranch);
 +		ft->p2p_isV2 = strchr(wlid, ';') != NULL;
 +		ft->std.hContact = MSN_HContactFromEmail(wlid);
 +	}
 +	else
 +	{
 +		replaceStr(ft->p2p_callID, szCallID);
 +		replaceStr(ft->p2p_branch, szBranch);
 +		ft->p2p_acksessid = MSN_GenRandom();
 +/*
 +		if (p2p_isAvatarOnly(ft->std.hContact))
 +		{
 +			p2p_sendStatus(ft, 1603);
 +			return;
 +		}
 +		else
 +			ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, ft, 0);
 +*/
 +	}
 +
 +	directconnection *dc = p2p_getDCByCallID(szCallID, wlid);
 +	if (dc)
 +	{
 +		if (MSN_GetThreadByContact(wlid, SERVER_P2P_DIRECT))
 +		{
 +			p2p_sendStatus(ft, 1603);
 +			p2p_unregisterDC(dc);
 +			return;
 +		}
 +		p2p_unregisterDC(dc);
 +	}
 +
 +	dc = new directconnection(szCallID, wlid);
 +	dc->useHashedNonce = szHashedNonce != NULL;
 +	if (dc->useHashedNonce)
 +		dc->xNonce = mir_strdup(szHashedNonce);
 +	p2p_registerDC(dc);
 +
 +	MimeHeaders tResult(8);
 +	tResult.addString("CSeq", "1 ");
 +	tResult.addString("Call-ID", szCallID);
 +	tResult.addLong("Max-Forwards", 0);
 +
 +	MyConnectionType conType = {0};
 +
 +	conType.extIP = atol(szNetID);
 +	conType.SetUdpCon(szConnType);
 +	conType.upnpNAT = strcmp(szUPnPNat, "true") == 0;
 +	conType.icf = strcmp(szICF, "true") == 0;
 +	conType.CalculateWeight();
 +
 +	MimeHeaders chdrs(12);
 +	bool listen = false;
 +
 +	debugLogA("Connection weight, his: %d mine: %d", conType.weight, MyConnection.weight);
 +	if (conType.weight <= MyConnection.weight)
 +		listen = p2p_createListener(ft, dc, chdrs);
 +
 +	if (!listen)
 +	{
 +		chdrs.addString("Bridge", "TCPv1");
 +		chdrs.addBool("Listening", false);
 +
 +		if (dc->useHashedNonce)
 +			chdrs.addString("Hashed-Nonce", dc->mNonceToHash(), 2);
 +		else
 +			chdrs.addString("Nonce", sttVoidUid);
 +
 +		chdrs.addULong("SessionID", ft->p2p_sessionid);
 +		chdrs.addString("SChannelState", "0");
 +		chdrs.addString("Capabilities-Flags", "1");
 +	}
 +
 +	tResult.addString("Content-Type", "application/x-msnmsgr-transrespbody");
 +
 +	if (!ft->p2p_isV2) p2p_getMsgId(ft->p2p_dest, -1);
 +	p2p_sendSlp(200, ft, tResult, chdrs);
 +}
 +
 +
 +void CMsnProto::p2p_startConnect(const char* wlid, const char* szCallID, const char* addr, const char* port, bool ipv6)
 +{
 +	if (port == NULL) return;
 +
 +	char *pPortTokBeg = (char*)port;
 +	for (;;)
 +	{
 +		char *pPortTokEnd = strchr(pPortTokBeg, ' ');
 +		if (pPortTokEnd != NULL) *pPortTokEnd = 0;
 +
 +		char *pAddrTokBeg = (char*)addr;
 +		for (;;)
 +		{
 +			char *pAddrTokEnd = strchr(pAddrTokBeg, ' ');
 +			if (pAddrTokEnd != NULL) *pAddrTokEnd = 0;
 +
 +			ThreadData* newThread = new ThreadData;
 +
 +			newThread->mType = SERVER_P2P_DIRECT;
 +			newThread->mInitialContactWLID = mir_strdup(wlid);
 +			mir_snprintf(newThread->mCookie, sizeof(newThread->mCookie), "%s", szCallID);
 +			mir_snprintf(newThread->mServer, sizeof(newThread->mServer),
 +				ipv6 ? "[%s]:%s" : "%s:%s", pAddrTokBeg, pPortTokBeg);
 +
 +			newThread->startThread(&CMsnProto::p2p_fileActiveThread, this);
 +
 +			if (pAddrTokEnd == NULL) break;
 +
 +			*pAddrTokEnd = ' ';
 +			pAddrTokBeg = pAddrTokEnd + 1;
 +		}
 +
 +		if (pPortTokEnd == NULL) break;
 +
 +		*pPortTokEnd = ' ';
 +		pPortTokBeg = pPortTokEnd + 1;
 +	}
 +}
 +
 +void CMsnProto::p2p_InitDirectTransfer2(MimeHeaders& tFileInfo, MimeHeaders& tFileInfo2, const char* wlid)
 +{
 +	const char  *szCallID          = tFileInfo["Call-ID"],
 +				*szInternalAddress = tFileInfo2["IPv4Internal-Addrs"],
 +				*szInternalPort    = tFileInfo2["IPv4Internal-Port"],
 +				*szExternalAddress = tFileInfo2["IPv4External-Addrs"],
 +				*szExternalPort    = tFileInfo2["IPv4External-Port"],
 +				*szNonce           = tFileInfo2["Nonce"],
 +				*szHashedNonce     = tFileInfo2["Hashed-Nonce"],
 +				*szListening       = tFileInfo2["Listening"],
 +				*szV6Address       = tFileInfo2["IPv6-Addrs"],
 +				*szV6Port          = tFileInfo2["IPv6-Port" ];
 +
 +	if ((szNonce == NULL && szHashedNonce == NULL) || szListening == NULL)
 +	{
 +		debugLogA("Ignoring invalid invitation: Listening='%s', Nonce=%s", szListening, szNonce);
 +		return;
 +	}
 +
 +	directconnection* dc = p2p_getDCByCallID(szCallID, wlid);
 +	if (dc == NULL)
 +	{
 +		dc = new directconnection(szCallID, wlid);
 +		p2p_registerDC(dc);
 +	}
 +
 +	dc->useHashedNonce = szHashedNonce != NULL;
 +	replaceStr(dc->xNonce, szHashedNonce ? szHashedNonce : szNonce);
 +
 +	if (!strcmp(szListening, "true") && strcmp(dc->xNonce, sttVoidUid))
 +	{
 +		p2p_startConnect(wlid, szCallID, szV6Address, szV6Port, true);
 +		p2p_startConnect(wlid, szCallID, szInternalAddress, szInternalPort, false);
 +		p2p_startConnect(wlid, szCallID, szExternalAddress, szExternalPort, false);
 +	}
 +}
 +
 +void CMsnProto::p2p_AcceptTransfer(MimeHeaders& tFileInfo, MimeHeaders& tFileInfo2, const char* wlid)
 +{
 +	const char *szCallID = tFileInfo["Call-ID"];
 +	const char* szOldContentType = tFileInfo["Content-Type"];
 +	const char *szBranch = tFileInfo["Via"];
 +
 +	if (szBranch != NULL) {
 +		szBranch = strstr(szBranch, "branch=");
 +		if (szBranch != NULL)
 +			szBranch += 7;
 +	}
 +
 +	filetransfer ftl(this), *ft = p2p_getSessionByCallID(szCallID, wlid);
 +
 +	if (!ft || !ft->p2p_sessionid)
 +	{
 +		ft = &ftl;
 +		replaceStr(ft->p2p_branch, szBranch);
 +		replaceStr(ft->p2p_callID, szCallID);
 +		replaceStr(ft->p2p_dest, wlid);
 +		ft->p2p_isV2 = strchr(wlid, ';') != NULL;
 +		ft->std.hContact = MSN_HContactFromEmail(wlid);
 +	}
 +	else
 +	{
 +		if (!(ft->std.flags & PFTS_SENDING))
 +		{
 +			replaceStr(ft->p2p_branch, szBranch);
 +			replaceStr(ft->p2p_callID, szCallID);
 +		}
 +	}
 +
 +	if (szCallID == NULL || szBranch == NULL || szOldContentType == NULL)
 +	{
 +		debugLogA("Ignoring invalid invitation: CallID='%s', szBranch='%s'", szCallID, szBranch);
 +LBL_Close:
 +		p2p_sendStatus(ft, 500);
 +		return;
 +	}
 +
 +	MimeHeaders tResult(8);
 +	tResult.addString("CSeq", "0 ");
 +	tResult.addString("Call-ID", ft->p2p_callID);
 +	tResult.addLong("Max-Forwards", 0);
 +
 +	MimeHeaders chdrs(12);
 +
 +	if (!strcmp(szOldContentType, "application/x-msnmsgr-sessionreqbody"))
 +	{
 +		if (ft == &ftl)
 +		{
 +			p2p_sendCancel(ft);
 +			return;
 +		}
 +
 +		if (!ft->bAccepted)
 +		{
 +			replaceStr(ft->p2p_dest, wlid);
 +			ft->bAccepted = true;
 +		}
 +		else
 +			return;
 +
 +		if (ft->p2p_type != MSN_APPID_FILE)
 +		{
 +			if (ft->fileId == -1) ft->create();
 +			return;
 +		}
 +
 +		p2p_sendFeedStart(ft);
 +
 +		ThreadData* T = MSN_GetP2PThreadByContact(ft->p2p_dest);
 +		if (T != NULL && T->mType == SERVER_P2P_DIRECT)
 +		{
 +			MSN_StartP2PTransferByContact(ft->p2p_dest);
 +			return;
 +		}
 +
 +		if (usingGateway)
 +			MSN_StartP2PTransferByContact(ft->p2p_dest);
 +
 +		directconnection* dc = new directconnection(szCallID, wlid);
 +		p2p_registerDC(dc);
 +
 +		tResult.addString("Content-Type", "application/x-msnmsgr-transreqbody");
 +
 +		chdrs.addString("Bridges", "TCPv1");
 +		chdrs.addLong("NetID", MyConnection.extIP);
 +		chdrs.addString("Conn-Type", MyConnection.GetMyUdpConStr());
 +		chdrs.addBool("UPnPNat", MyConnection.upnpNAT);
 +		chdrs.addBool("ICF", MyConnection.icf);
 +		chdrs.addString("IPv6-global", GetGlobalIp(), 2);
 +		chdrs.addString("Hashed-Nonce", dc->mNonceToHash(), 2);
 +	}
 +	else if (!strcmp(szOldContentType, "application/x-msnmsgr-transrespbody"))
 +	{
 +		const char	*szListening       = tFileInfo2["Listening"],
 +					*szNonce           = tFileInfo2["Nonce"],
 +					*szHashedNonce     = tFileInfo2["Hashed-Nonce"],
 +					*szExternalAddress = tFileInfo2["IPv4External-Addrs"],
 +					*szExternalPort    = tFileInfo2["IPv4External-Port" ],
 +					*szInternalAddress = tFileInfo2["IPv4Internal-Addrs"],
 +					*szInternalPort    = tFileInfo2["IPv4Internal-Port" ],
 +					*szV6Address       = tFileInfo2["IPv6-Addrs"],
 +					*szV6Port          = tFileInfo2["IPv6-Port" ];
 +
 +		if ((szNonce == NULL && szHashedNonce == NULL) || szListening == NULL)
 +		{
 +			debugLogA("Invalid data packet, exiting...");
 +			goto LBL_Close;
 +		}
 +
 +		directconnection* dc = p2p_getDCByCallID(szCallID, wlid);
 +		if (dc == NULL) return;
 +
 +		if (!dc->bAccepted)
 +			dc->bAccepted = true;
 +		else
 +			return;
 +
 +		dc->useHashedNonce = szHashedNonce != NULL;
 +		replaceStr(dc->xNonce, szHashedNonce ? szHashedNonce : szNonce);
 +
 +		// another side reported that it will be a server.
 +		if (!strcmp(szListening, "true") && (szNonce == NULL || strcmp(szNonce, sttVoidUid)))
 +		{
 +			p2p_startConnect(ft->p2p_dest, szCallID, szV6Address, szV6Port, true);
 +			p2p_startConnect(ft->p2p_dest, szCallID, szInternalAddress, szInternalPort, false);
 +			p2p_startConnect(ft->p2p_dest, szCallID, szExternalAddress, szExternalPort, false);
 +			return;
 +		}
 +
 +		// no, send a file via server
 +		if (!p2p_createListener(ft, dc, chdrs))
 +		{
 +			p2p_unregisterDC(dc);
 +			if (ft != &ftl)
 +				MSN_StartP2PTransferByContact(ft->p2p_dest);
 +			else
 +				p2p_startSessions(ft->p2p_dest);
 +			return;
 +		}
 +
 +		tResult.addString("Content-Type", "application/x-msnmsgr-transrespbody");
 +	}
 +	else if (!strcmp(szOldContentType, "application/x-msnmsgr-transreqbody"))
 +	{
 +		const char *szHashedNonce = tFileInfo2["Hashed-Nonce"];
 +		const char *szNonce       = tFileInfo2["Nonce"];
 +
 +		directconnection* dc = p2p_getDCByCallID(szCallID, wlid);
 +		if (dc == NULL)
 +		{
 +			dc = new directconnection(szCallID, wlid);
 +			p2p_registerDC(dc);
 +		}
 +
 +		dc->useHashedNonce = szHashedNonce != NULL;
 +		replaceStr(dc->xNonce, szHashedNonce ? szHashedNonce : szNonce);
 +
 +		// no, send a file via server
 +		if (!p2p_createListener(ft, dc, chdrs))
 +		{
 +			p2p_unregisterDC(dc);
 +			MSN_StartP2PTransferByContact(ft->p2p_dest);
 +			return;
 +		}
 +
 +		tResult.addString("Content-Type", "application/x-msnmsgr-transrespbody");
 +	}
 +	else
 +		return;
 +
 +	if (!ft->p2p_isV2) p2p_getMsgId(ft->p2p_dest, -1);
 +	p2p_sendSlp(-2, ft, tResult, chdrs);
 +}
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// p2p_processSIP - processes all MSN SIP commands
 +
 +void CMsnProto::p2p_processSIP(ThreadData* info, char* msgbody, P2PB_Header* hdrdata, const char* wlid)
 +{
 +	int iMsgType = 0;
 +	if (!memcmp(msgbody, "INVITE MSNMSGR:", 15))
 +		iMsgType = 1;
 +	else if (!memcmp(msgbody, "MSNSLP/1.0 200 ", 15))
 +		iMsgType = 2;
 +	else if (!memcmp(msgbody, "BYE MSNMSGR:", 12))
 +		iMsgType = 3;
 +	else if (!memcmp(msgbody, "MSNSLP/1.0 603 ", 15))
 +		iMsgType = 4;
 +	else if (!memcmp(msgbody, "MSNSLP/1.0 481 ", 15))
 +		iMsgType = 4;
 +	else if (!memcmp(msgbody, "MSNSLP/1.0 500 ", 15))
 +		iMsgType = 4;
 +	else if (!memcmp(msgbody, "ACK MSNMSGR:", 12))
 +		iMsgType = 5;
 +
 +	char* peol = strstr(msgbody, "\r\n");
 +	if (peol != NULL)
 +		msgbody = peol+2;
 +
 +	MimeHeaders tFileInfo, tFileInfo2;
 +	msgbody = tFileInfo.readFromBuffer(msgbody);
 +	msgbody = tFileInfo2.readFromBuffer(msgbody);
 +
 +	const char* szContentType = tFileInfo["Content-Type"];
 +	if (szContentType == NULL)
 +	{
 +		debugLogA("Invalid or missing Content-Type field, exiting");
 +		return;
 +	}
 +
 +	if (hdrdata && !hdrdata->isV2Hdr())
 +	{
 +		if (iMsgType == 2 || (iMsgType == 1 && !strcmp(szContentType, "application/x-msnmsgr-transreqbody")))
 +			p2p_getMsgId(wlid, 1);
 +	}
 +
 +	switch(iMsgType)
 +	{
 +	case 1:
 +		if (!strcmp(szContentType, "application/x-msnmsgr-sessionreqbody"))
 +			p2p_InitFileTransfer(info, tFileInfo, tFileInfo2, wlid);
 +		else if (!strcmp(szContentType, "application/x-msnmsgr-transreqbody"))
 +			p2p_InitDirectTransfer(tFileInfo, tFileInfo2, wlid);
 +		else if (!strcmp(szContentType, "application/x-msnmsgr-transrespbody"))
 +			p2p_InitDirectTransfer2(tFileInfo, tFileInfo2, wlid);
 +		break;
 +
 +	case 2:
 +		p2p_AcceptTransfer(tFileInfo, tFileInfo2, wlid);
 +		break;
 +
 +	case 3:
 +		if (!strcmp(szContentType, "application/x-msnmsgr-sessionclosebody"))
 +		{
 +			filetransfer* ft = p2p_getSessionByCallID(tFileInfo["Call-ID"], wlid);
 +			if (ft != NULL)
 +			{
 +				if (ft->std.currentFileProgress < ft->std.currentFileSize)
 +				{
 +					ft->bCanceled = true;
 +					p2p_sendAbortSession(ft);
 +				}
 +				else
 +				{
 +					if (!(ft->std.flags & PFTS_SENDING))
 +						ft->bCompleted = true;
 +				}
 +
 +				p2p_sessionComplete(ft);
 +			}
 +		}
 +		break;
 +
 +	case 4:
 +		{
 +			const char* szCallID = tFileInfo["Call-ID"];
 +
 +//			application/x-msnmsgr-session-failure-respbody
 +
 +			directconnection *dc = p2p_getDCByCallID(szCallID, wlid);
 +			if (dc != NULL)
 +			{
 +				p2p_unregisterDC(dc);
 +				break;
 +			}
 +
 +			filetransfer* ft = p2p_getSessionByCallID(szCallID, wlid);
 +			if (ft == NULL)
 +				break;
 +
 +			ft->close();
 +			if (!(ft->std.flags & PFTS_SENDING)) _tremove(ft->std.tszCurrentFile);
 +
 +			p2p_unregisterSession(ft);
 +		}
 +		break;
 +
 +	case 5:
 +		if (!strcmp(szContentType, "application/x-msnmsgr-turnsetup"))
 +		{
 +//			tFileInfo2["ServerAddress"];
 +//			tFileInfo2["SessionUsername"];
 +//			tFileInfo2["SessionPassword"];
 +		}
 +		else if (!strcmp(szContentType, "application/x-msnmsgr-transudpswitch"))
 +		{
 +//			tFileInfo2["IPv6AddrsAndPorts"];
 +//			tFileInfo2["IPv4ExternalAddrsAndPorts"];
 +//			tFileInfo2["IPv4InternalAddrsAndPorts"];
 +		}
 +		break;
 +	}
 +}
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// p2p_processMsg - processes all MSN P2P incoming messages
 +void CMsnProto::p2p_processMsgV2(ThreadData* info,  char* msgbody, const char* wlid)
 +{
 +	P2PV2_Header hdrdata;
 +
 +	char *msg = hdrdata.parseMsg(msgbody);
 +	hdrdata.logHeader(this);
 +
 +	if (hdrdata.mSessionID == 0)
 +	{
 +		if (hdrdata.mPacketLen == 0)
 +		{
 +			if (hdrdata.mOpCode & 0x02)
 +				p2p_sendAck(wlid, &hdrdata);
 +			return;
 +		}
 +
 +		if (hdrdata.mRemSize || hdrdata.mTFCode == 0)
 +		{
 +			char msgid[128];
 +			mir_snprintf(msgid, sizeof(msgid), "%s_%08x", wlid, hdrdata.mPacketNum);
 +
 +			int idx;
 +			if (hdrdata.mTFCode == 0x01)
 +			{
 +				const size_t portion = hdrdata.mPacketLen + (msg - msgbody);
 +				const size_t len = portion + hdrdata.mRemSize;
 +				idx = addCachedMsg(msgid, msgbody, 0, portion, len, false);
 +			}
 +			else
 +			{
 +				size_t len = hdrdata.mPacketLen + hdrdata.mRemSize;
 +				size_t offset = getCachedMsgSize(msgid); if (offset >= len) offset -= len;
 +				idx = addCachedMsg(msgid, msg, offset, hdrdata.mPacketLen, len, false);
 +			}
 +
 +			if (hdrdata.mRemSize == 0)
 +			{
 +				size_t newsize;
 +				if (getCachedMsg(idx, msgbody, newsize))
 +				{
 +					unsigned id = hdrdata.mID;
 +					msg = hdrdata.parseMsg(msgbody);
 +					hdrdata.mID = id;
 +
 +					if (hdrdata.mOpCode & 0x02)
 +						p2p_sendAck(wlid, &hdrdata);
 +
 +					if (hdrdata.mTFCode)
 +						p2p_processSIP(info, msg, &hdrdata, wlid);
 +					mir_free(msgbody);
 +				}
 +				else
 +					clearCachedMsg(idx);
 +			}
 +		}
 +		else
 +		{
 +			if (hdrdata.mOpCode & 0x02)
 +				p2p_sendAck(wlid, &hdrdata);
 +
 +			p2p_processSIP(info, msg, &hdrdata, wlid);
 +		}
 +
 +		return;
 +	}
 +
 +	if (hdrdata.mOpCode & 0x02)
 +		p2p_sendAck(wlid, &hdrdata);
 +
 +	filetransfer* ft = p2p_getSessionByID(hdrdata.mSessionID);
 +	if (ft == NULL) return;
 +
 +	ft->ts = time(NULL);
 +
 +	if (hdrdata.mTFCode >= 4 && hdrdata.mTFCode <= 7)
 +	{
 +		_write(ft->fileId, msg, hdrdata.mPacketLen);
 +
 +		ft->std.totalProgress += hdrdata.mPacketLen;
 +		ft->std.currentFileProgress += hdrdata.mPacketLen;
 +
 +		if (ft->p2p_appID == MSN_APPID_FILE && clock() >= ft->nNotify)
 +		{
 +			ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->std);
 +			ft->nNotify = clock() + 500;
 +
 +			//---- send an ack: body was transferred correctly
 +			debugLogA("Transferred %I64u bytes remaining %I64u", ft->std.currentFileProgress, hdrdata.mRemSize);
 +		}
 +
 +		if (hdrdata.mRemSize == 0)
 +		{
 +			if (ft->p2p_appID == MSN_APPID_FILE)
 +			{
 +				ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->std);
 +				ft->complete();
 +			}
 +			else
 +			{
 +				p2p_savePicture2disk(ft);
 +				if (!ft->p2p_isV2) p2p_sendBye(ft);
 +			}
 +		}
 +	}
 +}
 +
 +void CMsnProto::p2p_processMsg(ThreadData* info,  char* msgbody, const char* wlid)
 +{
 +	P2P_Header hdrdata;
 +	msgbody = hdrdata.parseMsg(msgbody);
 +	hdrdata.logHeader(this);
 +
 +	//---- if we got a message
 +	if (LOWORD(hdrdata.mFlags) == 0 && hdrdata.mSessionID == 0)
 +	{
 +		//		MsnContact *cont = Lists_Get(wlid);
 +		//		if (cont && cont->places.getCount())
 +		//			return;
 +
 +		if (hdrdata.mPacketLen < hdrdata.mTotalSize)
 +		{
 +			char msgid[128];
 +			mir_snprintf(msgid, sizeof(msgid), "%s_%08x", wlid, hdrdata.mID);
 +			int idx = addCachedMsg(msgid, msgbody, (size_t)hdrdata.mOffset, hdrdata.mPacketLen,
 +				(size_t)hdrdata.mTotalSize, false);
 +
 +			char* newbody;
 +			size_t newsize;
 +			if (getCachedMsg(idx, newbody, newsize))
 +			{
 +				p2p_sendAck(wlid, &hdrdata);
 +				p2p_processSIP(info, newbody, &hdrdata, wlid);
 +				mir_free(newbody);
 +			}
 +			else
 +			{
 +				if (hdrdata.mOffset + hdrdata.mPacketLen >= hdrdata.mTotalSize)
 +					clearCachedMsg(idx);
 +			}
 +		}
 +		else
 +		{
 +			p2p_sendAck(wlid, &hdrdata);
 +			p2p_processSIP(info, msgbody, &hdrdata, wlid);
 +		}
 +
 +		return;
 +	}
 +
 +	filetransfer* ft = p2p_getSessionByID(hdrdata.mSessionID);
 +	if (ft == NULL)
 +		ft = p2p_getSessionByUniqueID(hdrdata.mAckUniqueID);
 +
 +	if (ft == NULL) return;
 +
 +	ft->ts = time(NULL);
 +
 +	//---- receiving redirect -----------
 +	if (hdrdata.mFlags == 0x01)
 +	{
 +		if (WaitForSingleObject(ft->hLockHandle, INFINITE) == WAIT_OBJECT_0)
 +		{
 +			__int64 dp = (__int64)(ft->std.currentFileProgress - hdrdata.mAckDataSize);
 +			ft->std.totalProgress -= dp ;
 +			ft->std.currentFileProgress -= dp;
 +			_lseeki64(ft->fileId, ft->std.currentFileProgress, SEEK_SET);
 +			ft->tType = info->mType;
 +			ReleaseMutex(ft->hLockHandle);
 +		}
 +	}
 +
 +	//---- receiving ack -----------
 +	if (hdrdata.mFlags == 0x02)
 +	{
 +		ft->p2p_waitack = false;
 +
 +		if (hdrdata.mAckSessionID == ft->p2p_sendmsgid)
 +		{
 +			if (ft->p2p_appID == MSN_APPID_FILE)
 +			{
 +				ft->bCompleted = true;
 +				p2p_sendBye(ft);
 +			}
 +			return;
 +		}
 +
 +		if (hdrdata.mAckSessionID == ft->p2p_byemsgid)
 +		{
 +			p2p_sessionComplete(ft);
 +			return;
 +		}
 +
 +		switch(ft->p2p_ackID)
 +		{
 +		case 1000:
 +			//---- send Data Preparation Message
 +			p2p_sendAvatarInit(ft);
 +			break;
 +
 +		case 1001:
 +			//---- send Data Messages
 +			MSN_StartP2PTransferByContact(ft->p2p_dest);
 +			break;
 +		}
 +
 +		ft->p2p_ackID++;
 +		return;
 +	}
 +
 +	if (LOWORD(hdrdata.mFlags) == 0)
 +	{
 +		//---- accept the data preparation message ------
 +		//		const unsigned* pLongs = (unsigned*)msgbody;
 +		if (hdrdata.mPacketLen == 4 && hdrdata.mTotalSize == 4)
 +		{
 +			p2p_sendAck(ft->p2p_dest, &hdrdata);
 +			return;
 +		}
 +		else
 +			hdrdata.mFlags = 0x20;
 +	}
 +
 +	//---- receiving data -----------
 +	if (LOWORD(hdrdata.mFlags) == 0x20 || LOWORD(hdrdata.mFlags) == 0x30)
 +	{
 +		if (hdrdata.mOffset + hdrdata.mPacketLen > hdrdata.mTotalSize)
 +			hdrdata.mPacketLen = DWORD(hdrdata.mTotalSize - hdrdata.mOffset);
 +
 +		if (ft->tTypeReq == 0 || ft->tTypeReq == info->mType)
 +		{
 +			ft->tType = info->mType;
 +			ft->p2p_sendmsgid = hdrdata.mID;
 +		}
 +
 +		__int64 dsz = ft->std.currentFileSize - hdrdata.mOffset;
 +		if (dsz > hdrdata.mPacketLen) dsz = hdrdata.mPacketLen;
 +
 +		if (ft->tType == info->mType)
 +		{
 +			if (dsz > 0 && ft->fileId >= 0)
 +			{
 +				if (ft->lstFilePtr != hdrdata.mOffset)
 +					_lseeki64(ft->fileId, hdrdata.mOffset, SEEK_SET);
 +				_write(ft->fileId, msgbody, (unsigned int)dsz);
 +
 +				ft->lstFilePtr = hdrdata.mOffset + dsz;
 +
 +				__int64 dp = ft->lstFilePtr - ft->std.currentFileProgress;
 +				if (dp > 0)
 +				{
 +					ft->std.totalProgress += dp;
 +					ft->std.currentFileProgress += dp;
 +
 +					if (ft->p2p_appID == MSN_APPID_FILE && clock() >= ft->nNotify)
 +					{
 +						ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->std);
 +						ft->nNotify = clock() + 500;
 +					}
 +				}
 +
 +				//---- send an ack: body was transferred correctly
 +				debugLogA("Transferred %I64u bytes out of %I64u", ft->std.currentFileProgress, hdrdata.mTotalSize);
 +			}
 +
 +			if (ft->std.currentFileProgress >= hdrdata.mTotalSize)
 +			{
 +				ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->std);
 +				p2p_sendAck(ft->p2p_dest, &hdrdata);
 +				if (ft->p2p_appID == MSN_APPID_FILE)
 +				{
 +					ft->ts = time(NULL);
 +					ft->p2p_waitack = true;
 +					ft->complete();
 +				}
 +				else
 +				{
 +					p2p_savePicture2disk(ft);
 +					p2p_sendBye(ft);
 +				}
 +			}
 +		}
 +	}
 +
 +	if (hdrdata.mFlags == 0x40 || hdrdata.mFlags == 0x80)
 +	{
 +		p2p_sendAbortSession(ft);
 +		p2p_unregisterSession(ft);
 +	}
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// p2p_invite - invite another side to transfer an avatar
 +
 +void CMsnProto::p2p_invite(unsigned iAppID, filetransfer* ft, const char *wlid)
 +{
 +	const char* szAppID;
 +	switch(iAppID)
 +	{
 +	case MSN_APPID_FILE:			        szAppID = "{5D3E02AB-6190-11D3-BBBB-00C04F795683}";	break;
 +	case MSN_APPID_AVATAR:			        szAppID = "{A4268EEC-FEC5-49E5-95C3-F126696BDBF6}";	break;
 +	case MSN_APPID_CUSTOMSMILEY:	        szAppID = "{A4268EEC-FEC5-49E5-95C3-F126696BDBF6}";	break;
 +	case MSN_APPID_CUSTOMANIMATEDSMILEY:	szAppID = "{A4268EEC-FEC5-49E5-95C3-F126696BDBF6}";	break;
 +	default: return;
 +	}
 +
 +	ft->p2p_type = iAppID;
 +	ft->p2p_acksessid = MSN_GenRandom();
 +	mir_free(ft->p2p_callID);
 +	ft->p2p_callID = getNewUuid();
 +
 +	MsnContact* cont = Lists_Get(ft->std.hContact);
 +	if (cont == NULL) return;
 +
 +	if (ft->p2p_dest == NULL)
 +	{
 +		ft->p2p_isV2 = (cont->cap2 & capex_SupportsPeerToPeerV2) != 0 || (cont->cap1 >> 28) >= 10;
 +		ft->p2p_dest = mir_strdup(wlid ? wlid : cont->email);
 +	}
 +
 +	char*  pContext = NULL;
 +	size_t cbContext = 0;
 +
 +	switch (iAppID)
 +	{
 +	case MSN_APPID_FILE:
 +		{
 +			cbContext = sizeof(HFileContext);
 +			pContext = (char*)malloc(cbContext);
 +			HFileContext* ctx = (HFileContext*)pContext;
 +			memset(pContext, 0, cbContext);
 +			if (ft->p2p_isV2)
 +			{
 +				cbContext -= 64;
 +				ctx->ver = 2;
 +			}
 +			else
 +			{
 +				ctx->ver = 3;
 +				ctx->id = 0xffffffff;
 +			}
 +			ctx->len = (unsigned)cbContext;
 +			ctx->type = MSN_TYPEID_FTNOPREVIEW;
 +			ctx->dwSize = ft->std.currentFileSize;
 +
 +			TCHAR* pszFiles = _tcsrchr(ft->std.tszCurrentFile, '\\');
 +			if (pszFiles)
 +				pszFiles++;
 +			else
 +				pszFiles = ft->std.tszCurrentFile;
 +
 +			wchar_t *fname = mir_t2u(pszFiles);
 +			wcsncpy(ctx->wszFileName, fname, MAX_PATH);
 +			mir_free(fname);
 +
 +			ft->p2p_appID = MSN_APPID_FILE;
 +		}
 +		break;
 +
 +	default:
 +		ft->p2p_appID = MSN_APPID_AVATAR2;
 +
 +		if (ft->p2p_object == NULL)
 +		{
 +			delete ft;
 +			return;
 +		}
 +
 +		ezxml_t xmlo = ezxml_parse_str(NEWSTR_ALLOCA(ft->p2p_object), strlen(ft->p2p_object));
 +		ezxml_t xmlr = ezxml_new("msnobj");
 +
 +		const char* p;
 +		p = ezxml_attr(xmlo, "Creator");
 +		if (p != NULL)
 +			ezxml_set_attr(xmlr, "Creator", p);
 +		p = ezxml_attr(xmlo, "Size");
 +		if (p != NULL) {
 +			ezxml_set_attr(xmlr, "Size", p);
 +			ft->std.totalBytes = ft->std.currentFileSize = _atoi64(p);
 +		}
 +		p = ezxml_attr(xmlo, "Type");
 +		if (p != NULL)
 +			ezxml_set_attr(xmlr, "Type", p);
 +		p = ezxml_attr(xmlo, "Location");
 +		if (p != NULL)
 +			ezxml_set_attr(xmlr, "Location", p);
 +		p = ezxml_attr(xmlo, "Friendly");
 +		if (p != NULL)
 +			ezxml_set_attr(xmlr, "Friendly", p);
 +		p = ezxml_attr(xmlo, "SHA1D");
 +		if (p != NULL)
 +			ezxml_set_attr(xmlr, "SHA1D", p);
 +		p = ezxml_attr(xmlo, "SHA1C");
 +		if (p != NULL)
 +			ezxml_set_attr(xmlr, "SHA1C", p);
 +
 +		pContext = ezxml_toxml(xmlr, false);
 +		cbContext = strlen(pContext)+1;
 +
 +		ezxml_free(xmlr);
 +		ezxml_free(xmlo);
 +
 +		break;
 +	}
 +
 +	bool sessionExist = p2p_sessionRegistered(ft);
 +	if (!sessionExist)
 +	{
 +		p2p_registerSession(ft);
 +
 +		unsigned short status = getWord(ft->std.hContact, "Status", ID_STATUS_OFFLINE);
 +		if ((myFlags & 0x4000000) && cont->places.getCount() <= 1 &&
 +			status != ID_STATUS_OFFLINE && status != ID_STATUS_INVISIBLE && m_iStatus != ID_STATUS_INVISIBLE)
 +		{
 +			if (ft->p2p_isV2)
 +			{
 +				if (cont->places.getCount() && cont->places[0].cap1 & cap_SupportsP2PBootstrap)
 +				{
 +					char wlid[128];
 +					mir_snprintf(wlid, SIZEOF(wlid),
 +						strcmp(cont->places[0].id, sttVoidUid) ? "%s;%s" : "%s",
 +						cont->email, cont->places[0].id);
 +
 +					if (!MSN_GetThreadByContact(wlid, SERVER_P2P_DIRECT))
 +						p2p_inviteDc(ft, wlid);
 +					else
 +						p2p_invite(ft->p2p_type, ft, wlid);
 +
 +					free(pContext);
 +					return;
 +				}
 +			}
 +			else
 +			{
 +				const char *wlid = cont->email;
 +				if (cont->cap1 & cap_SupportsP2PBootstrap)
 +				{
 +					if (!MSN_GetThreadByContact(wlid, SERVER_P2P_DIRECT))
 +						p2p_inviteDc(ft, wlid);
 +					else
 +						p2p_invite(ft->p2p_type, ft, wlid);
 +
 +					free(pContext);
 +					return;
 +				}
 +			}
 +		}
 +	}
 +
 +	if (!ft->bAccepted)
 +		ft->p2p_sessionid = MSN_GenRandom();
 +
 +	ptrA szContextEnc( mir_base64_encode((PBYTE)pContext, (unsigned)cbContext));
 +	int cbContextEnc = lstrlenA(szContextEnc);
 +
 +	MimeHeaders chdrs(10);
 +	chdrs.addString("EUF-GUID", szAppID);
 +	chdrs.addULong("SessionID", ft->p2p_sessionid);
 +	chdrs.addULong("AppID", ft->p2p_appID);
 +	chdrs.addString("Context", szContextEnc);
 +
 +	MimeHeaders tResult(8);
 +	tResult.addString("CSeq", "0 ");
 +	tResult.addString("Call-ID", ft->p2p_callID);
 +	tResult.addLong("Max-Forwards", 0);
 +	tResult.addString("Content-Type", "application/x-msnmsgr-sessionreqbody");
 +
 +	if (iAppID != MSN_APPID_FILE)
 +		ft->p2p_waitack = true;
 +
 +	if (ft->p2p_isV2 && ft->std.currentFileNumber == 0)
 +	{
 +		for (int i = 0; i < cont->places.getCount(); ++i)
 +		{
 +			char wlid[128];
 +			mir_snprintf(wlid, SIZEOF(wlid),
 +				strcmp(cont->places[i].id, sttVoidUid) ? "%s;%s" : "%s",
 +				cont->email, cont->places[i].id);
 +
 +			p2p_sendSlp(-2, ft, tResult, chdrs, wlid);
 +		}
 +	}
 +	else
 +		p2p_sendSlp(-2, ft, tResult, chdrs, wlid);
 +
 +	free(pContext);
 +}
 +
 +
 +void CMsnProto::p2p_inviteDc(filetransfer* ft, const char *wlid)
 +{
 +	directconnection* dc = new directconnection(szUbnCall, wlid);
 +	p2p_registerDC(dc);
 +
 +	MimeHeaders tResult(8);
 +	tResult.addString("CSeq", "0 ");
 +	tResult.addString("Call-ID", dc->callId);
 +	tResult.addLong("Max-Forwards", 0);
 +	tResult.addString("Content-Type", "application/x-msnmsgr-transreqbody");
 +
 +	MimeHeaders chdrs(12);
 +
 +	chdrs.addString("Bridges", "TCPv1 SBBridge");
 +	chdrs.addLong("NetID", MyConnection.extIP);
 +	chdrs.addString("Conn-Type", MyConnection.GetMyUdpConStr());
 +	chdrs.addBool("UPnPNat", MyConnection.upnpNAT);
 +	chdrs.addBool("ICF", MyConnection.icf);
 +	chdrs.addString("IPv6-global", GetGlobalIp(), 2);
 +	chdrs.addString("Hashed-Nonce", dc->mNonceToHash(), 2);
 +	chdrs.addString("SessionID", "0");
 +	chdrs.addString("SChannelState", "0");
 +	chdrs.addString("Capabilities-Flags", "1");
 +
 +	p2p_sendSlp(-2, ft, tResult, chdrs, wlid);
 +}
 +/*
 +void CMsnProto::p2p_sendSessionAck(filetransfer* ft)
 +{
 +	MimeHeaders tResult(8);
 +	tResult.addString("CSeq", "0 ");
 +	tResult.addString("Call-ID", sttVoidUid);
 +	tResult.addLong("Max-Forwards", 0);
 +	tResult.addString("Content-Type", "application/x-msnmsgr-transdestaddrupdate");
 +
 +	MimeHeaders chdrs(8);
 +
 +	chdrs.addString("IPv4ExternalAddrsAndPorts", mir_strdup(MyConnection.GetMyExtIPStr()), 6);
 +	chdrs.addString("IPv4InternalAddrsAndPorts", mir_strdup(MyConnection.GetMyExtIPStr()), 6);
 +	chdrs.addString("SessionID", "0");
 +	chdrs.addString("SChannelState", "0");
 +	chdrs.addString("Capabilities-Flags", "1");
 +
 +	p2p_sendSlp(-3, ft, tResult, chdrs);
 +}
 +*/
 +void CMsnProto::p2p_sessionComplete(filetransfer* ft)
 +{
 +	if (ft->p2p_appID != MSN_APPID_FILE)
 +		p2p_unregisterSession(ft);
 +	else if (ft->std.flags & PFTS_SENDING)
 +	{
 +		if (ft->openNext() == -1)
 +		{
 +			bool success = ft->std.currentFileNumber >= ft->std.totalFiles && ft->bCompleted;
 +			ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, success ? ACKRESULT_SUCCESS : ACKRESULT_FAILED, ft, 0);
 +		}
 +		else
 +		{
 +			ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0);
 +			p2p_invite(ft->p2p_appID, ft, NULL);
 +		}
 +	}
 +	else
 +	{
 +		ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ft->bCompleted ? ACKRESULT_SUCCESS : ACKRESULT_FAILED, ft, 0);
 +		p2p_unregisterSession(ft);
 +	}
 +}
 +
 +char* P2PV2_Header::parseMsg(char *buf)
 +{
 +	unsigned char hdrLen1 = *(unsigned char*)buf;
 +	mOpCode = *(unsigned char*)(buf + 1);
 +	mPacketLen = _htons(*(unsigned short*)(buf + 2));
 +	mID = _htonl(*(unsigned*)(buf + 4));
 +
 +	char* buf1 = buf + hdrLen1;
 +
 +	for (char *tlvp = buf + 8; tlvp < buf1 && *tlvp; tlvp += 2 + tlvp[1])
 +	{
 +		switch (*tlvp)
 +		{
 +		case 1:
 +			mCap = tlvp;
 +			break;
 +		case 2:
 +			mAckUniqueID = _htonl(*(unsigned*)(tlvp + 4));
 +			break;
 +		case 3:
 +			break;
 +		}
 +	}
 +
 +	if (mPacketLen == 0) return buf + hdrLen1;
 +
 +	unsigned char hdrLen2 = *(unsigned char*)buf1;
 +	mTFCode = *(unsigned char*)(buf1 + 1);
 +	mPacketNum = _htons(*(unsigned short*)(buf1 + 2));
 +	mSessionID = _htonl(*(unsigned*)(buf1 + 4));
 +
 +	char* buf2 = buf1 + hdrLen2;
 +
 +	for (char *tlvp1 = buf1 + 8; tlvp1 < buf2 && *tlvp1; tlvp1 += 2 + tlvp1[1])
 +	{
 +		switch (*tlvp1)
 +		{
 +		case 1:
 +			mRemSize = _htonl64(*(unsigned __int64*)(tlvp1 + 2));
 +			break;
 +		}
 +	}
 +
 +	mPacketLen -= hdrLen2;
 +	return buf1 + hdrLen2;
 +}
 +
 +char* P2PV2_Header::createMsg(char *buf, const char* wlid, CMsnProto *ppro)
 +{
 +	unsigned char hdrLen1 = 8 + (mAckUniqueID ? 6 : 0) + (mCap ? 2 + mCap[1] : 0);
 +	unsigned char comp = hdrLen1 & 3;
 +	hdrLen1 += comp ? 4 - comp : 0;
 +
 +	unsigned char hdrLen2 = mPacketLen ? (8 + (mRemSize ? 10 : 0)) : 0;
 +	comp = hdrLen2 & 3;
 +	hdrLen2 += comp ? 4 - comp : 0;
 +
 +	mID = ppro->p2p_getMsgId(wlid, mPacketLen + hdrLen2);
 +
 +	memset(buf, 0, hdrLen1 + hdrLen2);
 +
 +	*(unsigned char*)(buf + 0) = hdrLen1;
 +	*(unsigned char*)(buf + 1) = mOpCode;
 +	*(unsigned short*)(buf + 2) = _htons(mPacketLen + hdrLen2);
 +	*(unsigned*)(buf + 4) = _htonl(mID);
 +
 +	char *buf1 = buf + 8;
 +
 +	if (mAckUniqueID)
 +	{
 +		*(unsigned char*)buf1 = 2;
 +		*(unsigned char*)(buf1 + 1) = 4;
 +		*(unsigned*)(buf1 + 2) = _htonl(mAckUniqueID);
 +		buf1 += 6;
 +	}
 +	if (mCap)
 +	{
 +		unsigned len = 2 + mCap[1];
 +		memcpy(buf1, mCap,  len);
 +		buf1 += len;
 +	}
 +
 +	buf1 = buf + hdrLen1;
 +
 +	if (hdrLen2 == 0) return buf1;
 +
 +	*(unsigned char*)(buf1 + 0) = hdrLen2;
 +	*(unsigned char*)(buf1 + 1) = mTFCode;
 +	*(unsigned short*)(buf1 + 2) = _htons(mPacketNum);
 +	*(unsigned*)(buf1 + 4) = _htonl(mSessionID);
 +
 +	if (mRemSize)
 +	{
 +		*(unsigned char*)(buf1 + 8) = 1;
 +		*(unsigned char*)(buf1 + 9) = 8;
 +		*(unsigned __int64*)(buf1 + 10) = _htonl64(mRemSize);
 +	}
 +
 +	return buf1 + hdrLen2;
 +}
 +
 +char* P2P_Header::createMsg(char *buf, const char* wlid, CMsnProto *ppro)
 +{
 +	if (!mID) mID = ppro->p2p_getMsgId(wlid, 1);
 +	memcpy(buf, &mSessionID, 48);
 +	return buf + 48;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_p2ps.cpp b/plugins/!Deprecated/MSN/src/msn_p2ps.cpp new file mode 100644 index 0000000000..07d8f80d5a --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_p2ps.cpp @@ -0,0 +1,292 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// add file session to a list
 +
 +void CMsnProto::p2p_registerSession(filetransfer* ft)
 +{
 +	mir_cslock lck(sessionLock);
 +	sessionList.insert(ft);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// remove file session from a list
 +
 +void CMsnProto::p2p_unregisterSession(filetransfer* ft)
 +{
 +	mir_cslock lck(sessionLock);
 +	sessionList.remove(ft);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// get session by some parameter
 +
 +filetransfer* CMsnProto::p2p_getSessionByID(unsigned id)
 +{
 +	if (id == 0)
 +		return NULL;
 +
 +	mir_cslock lck(sessionLock);
 +
 +	for (int i=0; i < sessionList.getCount(); i++) {
 +		filetransfer* FT = &sessionList[i];
 +		if (FT->p2p_sessionid == id)
 +			return FT;
 +	}
 +
 +	return NULL;
 +}
 +
 +filetransfer* CMsnProto::p2p_getSessionByUniqueID(unsigned id)
 +{
 +	if (id == 0)
 +		return NULL;
 +
 +	mir_cslock lck(sessionLock);
 +
 +	for (int i=0; i < sessionList.getCount(); i++)
 +	{
 +		filetransfer* FT = &sessionList[i];
 +		if (FT->p2p_acksessid == id)
 +			return FT;
 +	}
 +
 +	return NULL;
 +}
 +
 +
 +bool CMsnProto::p2p_sessionRegistered(filetransfer* ft)
 +{
 +	if (ft != NULL && ft->p2p_appID == 0)
 +		return true;
 +
 +	mir_cslock lck(sessionLock);
 +	return sessionList.getIndex(ft) > -1;
 +}
 +
 +filetransfer* CMsnProto::p2p_getThreadSession(MCONTACT hContact, TInfoType mType)
 +{
 +	mir_cslock lck(sessionLock);
 +
 +	for (int i=0; i < sessionList.getCount(); i++)
 +	{
 +		filetransfer* FT = &sessionList[i];
 +		if (FT->std.hContact == hContact && FT->tType == mType)
 +			return FT;
 +	}
 +
 +	return NULL;
 +}
 +
 +void CMsnProto::p2p_clearThreadSessions(MCONTACT hContact, TInfoType mType)
 +{
 +	mir_cslock lck(sessionLock);
 +
 +	for (int i=0; i < sessionList.getCount(); i++)
 +	{
 +		filetransfer* ft = &sessionList[i];
 +		if (ft->std.hContact == hContact && ft->tType == mType)
 +		{
 +			ft->bCanceled = true;
 +			ft->tType = SERVER_NOTIFICATION;
 +			p2p_sendCancel(ft);
 +		}
 +	}
 +}
 +
 +filetransfer* CMsnProto::p2p_getAvatarSession(MCONTACT hContact)
 +{
 +	mir_cslock lck(sessionLock);
 +
 +	for (int i=0; i < sessionList.getCount(); i++)
 +	{
 +		filetransfer* FT = &sessionList[i];
 +		if (FT->std.hContact == hContact && !(FT->std.flags & PFTS_SENDING) && FT->p2p_type == MSN_APPID_AVATAR)
 +			return FT;
 +	}
 +
 +	return NULL;
 +}
 +
 +bool CMsnProto::p2p_isAvatarOnly(MCONTACT hContact)
 +{
 +	mir_cslock lck(sessionLock);
 +
 +	bool result = true;
 +	for (int i=0; i < sessionList.getCount(); i++)
 +	{
 +		filetransfer* FT = &sessionList[i];
 +		result &= FT->std.hContact != hContact || FT->p2p_type != MSN_APPID_FILE;
 +	}
 +
 +	return result;
 +}
 +
 +void CMsnProto::p2p_clearDormantSessions(void)
 +{
 +	mir_cslockfull lck(sessionLock);
 +
 +	time_t ts = time(NULL);
 +	for (int i=0; i < sessionList.getCount(); i++)
 +	{
 +		filetransfer* FT = &sessionList[i];
 +		if (!FT->p2p_sessionid && !MSN_GetUnconnectedThread(FT->p2p_dest, SERVER_P2P_DIRECT))
 +			p2p_invite(FT->p2p_type, FT, NULL);
 +		else if (FT->p2p_waitack && (ts - FT->ts) > 120)
 +		{
 +			FT->bCanceled = true;
 +			p2p_sendCancel(FT);
 +			lck.unlock();
 +			p2p_unregisterSession(FT);
 +			lck.lock();
 +			i = 0;
 +		}
 +	}
 +}
 +
 +void CMsnProto::p2p_redirectSessions(const char *wlid)
 +{
 +	mir_cslock lck(sessionLock);
 +
 +	ThreadData* T = MSN_GetP2PThreadByContact(wlid);
 +	for (int i=0; i < sessionList.getCount(); i++)
 +	{
 +		filetransfer* FT = &sessionList[i];
 +		if (_stricmp(FT->p2p_dest, wlid) == 0 &&
 +			FT->std.currentFileProgress < FT->std.currentFileSize &&
 +			(T == NULL || (FT->tType != T->mType && FT->tType != 0)))
 +		{
 +			if (FT->p2p_isV2)
 +			{
 +				if ((FT->std.flags & PFTS_SENDING) && T)
 +					FT->tType = T->mType;
 +			}
 +			else
 +			{
 +				if (!(FT->std.flags & PFTS_SENDING))
 +					p2p_sendRedirect(FT);
 +			}
 +		}
 +	}
 +}
 +
 +void CMsnProto::p2p_startSessions(const char* wlid)
 +{
 +	mir_cslock lck(sessionLock);
 +
 +	char* szEmail;
 +	parseWLID(NEWSTR_ALLOCA(wlid), NULL, &szEmail, NULL);
 +
 +	for (int i=0; i < sessionList.getCount(); i++)
 +	{
 +		filetransfer* FT = &sessionList[i];
 +		if (!FT->bAccepted  && !_stricmp(FT->p2p_dest, szEmail))
 +		{
 +			if (FT->p2p_appID == MSN_APPID_FILE && (FT->std.flags & PFTS_SENDING))
 +				p2p_invite(FT->p2p_type, FT, wlid);
 +			else if (FT->p2p_appID != MSN_APPID_FILE && !(FT->std.flags & PFTS_SENDING))
 +				p2p_invite(FT->p2p_type, FT, wlid);
 +		}
 +	}
 +}
 +
 +void CMsnProto::p2p_cancelAllSessions(void)
 +{
 +	mir_cslock lck(sessionLock);
 +
 +	for (int i=0; i < sessionList.getCount(); i++)
 +	{
 +		sessionList[i].bCanceled = true;
 +		p2p_sendCancel(&sessionList[i]);
 +	}
 +}
 +
 +filetransfer* CMsnProto::p2p_getSessionByCallID(const char* CallID, const char* wlid)
 +{
 +	if (CallID == NULL)
 +		return NULL;
 +
 +	mir_cslock lck(sessionLock);
 +
 +	char* szEmail = NULL;
 +	for (int i=0; i < sessionList.getCount(); i++)
 +	{
 +		filetransfer* FT = &sessionList[i];
 +		if (FT->p2p_callID && !_stricmp(FT->p2p_callID, CallID))
 +		{
 + 			if (_stricmp(FT->p2p_dest, wlid))
 +			{
 +				if (!szEmail)
 +					parseWLID(NEWSTR_ALLOCA(wlid), NULL, &szEmail, NULL);
 +				if (_stricmp(FT->p2p_dest, szEmail))
 +					continue;
 +			}
 +			return FT;
 +		}
 +	}
 +
 +	return NULL;
 +}
 +
 +
 +void CMsnProto::p2p_registerDC(directconnection* dc)
 +{
 +	mir_cslock lck(sessionLock);
 +	dcList.insert(dc);
 +}
 +
 +void CMsnProto::p2p_unregisterDC(directconnection* dc)
 +{
 +	mir_cslock lck(sessionLock);
 +	dcList.remove(dc);
 +}
 +
 +directconnection* CMsnProto::p2p_getDCByCallID(const char* CallID, const char* wlid)
 +{
 +	if (CallID == NULL)
 +		return NULL;
 +
 +	mir_cslock lck(sessionLock);
 +
 +	for (int i=0; i < dcList.getCount(); i++)
 +	{
 +		directconnection* DC = &dcList[i];
 +		if (DC->callId != NULL && !strcmp(DC->callId, CallID) && !strcmp(DC->wlid, wlid))
 +			return DC;
 +	}
 +
 +	return NULL;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// external functions
 +
 +void CMsnProto::P2pSessions_Uninit(void)
 +{
 +	mir_cslock lck(sessionLock);
 +	sessionList.destroy();
 +	dcList.destroy();
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_proto.cpp b/plugins/!Deprecated/MSN/src/msn_proto.cpp new file mode 100644 index 0000000000..f289313ee6 --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_proto.cpp @@ -0,0 +1,1107 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2008-2012 Boris Krasnovskiy.
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +static const COLORREF crCols[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
 +
 +int msn_httpGatewayInit(HANDLE hConn,NETLIBOPENCONNECTION *nloc,NETLIBHTTPREQUEST *nlhr);
 +int msn_httpGatewayBegin(HANDLE hConn,NETLIBOPENCONNECTION *nloc);
 +int msn_httpGatewayWrapSend(HANDLE hConn,PBYTE buf,int len,int flags,MIRANDASERVICE pfnNetlibSend);
 +PBYTE msn_httpGatewayUnwrapRecv(NETLIBHTTPREQUEST *nlhr,PBYTE buf,int len,int *outBufLen,void *(*NetlibRealloc)(void*,size_t));
 +
 +static int CompareLists(const MsnContact* p1, const MsnContact* p2)
 +{
 +	return _stricmp(p1->email, p2->email);
 +}
 +
 +CMsnProto::CMsnProto(const char* aProtoName, const TCHAR* aUserName) :
 +	PROTO<CMsnProto>(aProtoName, aUserName),
 +	contList(10, CompareLists),
 +	grpList(10, CompareId),
 +	sttThreads(10, PtrKeySortT),
 +	sessionList(10, PtrKeySortT),
 +	dcList(10, PtrKeySortT),
 +	lsMessageQueue(1),
 +	lsAvatarQueue(1),
 +	msgCache(5, CompareId)
 +{
 +	db_set_resident(m_szModuleName, "Status");
 +	db_set_resident(m_szModuleName, "IdleTS");
 +	db_set_resident(m_szModuleName, "p2pMsgId");
 +	db_set_resident(m_szModuleName, "MobileEnabled");
 +	db_set_resident(m_szModuleName, "MobileAllowed");
 +
 +	// Protocol services and events...
 +	hMSNNudge = CreateProtoEvent("/Nudge");
 +
 +	CreateProtoService(PS_CREATEACCMGRUI, &CMsnProto::SvcCreateAccMgrUI);
 +
 +	CreateProtoService(PS_GETAVATARINFOT, &CMsnProto::GetAvatarInfo);
 +	CreateProtoService(PS_GETMYAWAYMSG, &CMsnProto::GetMyAwayMsg);
 +
 +	CreateProtoService(PS_LEAVECHAT, &CMsnProto::OnLeaveChat);
 +
 +	CreateProtoService(PS_GETMYAVATART, &CMsnProto::GetAvatar);
 +	CreateProtoService(PS_SETMYAVATART, &CMsnProto::SetAvatar);
 +	CreateProtoService(PS_GETAVATARCAPS, &CMsnProto::GetAvatarCaps);
 +
 +	CreateProtoService(PS_GET_LISTENINGTO, &CMsnProto::GetCurrentMedia);
 +	CreateProtoService(PS_SET_LISTENINGTO, &CMsnProto::SetCurrentMedia);
 +
 +	CreateProtoService(PS_SETMYNICKNAME, &CMsnProto::SetNickName);
 +	CreateProtoService(PS_SEND_NUDGE, &CMsnProto::SendNudge);
 +
 +	CreateProtoService(PS_GETUNREADEMAILCOUNT, &CMsnProto::GetUnreadEmailCount);
 +
 +	// event hooks
 +	HookProtoEvent(ME_MSG_WINDOWPOPUP, &CMsnProto::OnWindowPopup);
 +	HookProtoEvent(ME_CLIST_GROUPCHANGE, &CMsnProto::OnGroupChange);
 +	HookProtoEvent(ME_OPT_INITIALISE, &CMsnProto::OnOptionsInit);
 +	HookProtoEvent(ME_CLIST_DOUBLECLICKED, &CMsnProto::OnContactDoubleClicked);
 +
 +	LoadOptions();
 +
 +	for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) {
 +		delSetting(hContact, "Status");
 +		delSetting(hContact, "IdleTS");
 +		delSetting(hContact, "p2pMsgId");
 +		delSetting(hContact, "AccList");
 +	}
 +	delSetting("MobileEnabled");
 +	delSetting("MobileAllowed");
 +
 +	char path[MAX_PATH];
 +	if (db_get_static(NULL, m_szModuleName, "LoginServer", path, sizeof(path)) == 0 &&
 +		(strcmp(path, MSN_DEFAULT_LOGIN_SERVER) == 0 ||
 +		strcmp(path, MSN_DEFAULT_GATEWAY) == 0))
 +		delSetting("LoginServer");
 +
 +	if (MyOptions.SlowSend) {
 +		if (db_get_dw(NULL, "SRMsg", "MessageTimeout", 10000) < 60000)
 +			db_set_dw(NULL, "SRMsg", "MessageTimeout", 60000);
 +		if (db_get_dw(NULL, "SRMM", "MessageTimeout", 10000) < 60000)
 +			db_set_dw(NULL, "SRMM", "MessageTimeout", 60000);
 +	}
 +
 +	mailsoundname = (char*)mir_alloc(64);
 +	mir_snprintf(mailsoundname, 64, "%s:Hotmail", m_szModuleName);
 +	SkinAddNewSoundExT(mailsoundname, m_tszUserName, LPGENT("Live Mail"));
 +
 +	alertsoundname = (char*)mir_alloc(64);
 +	mir_snprintf(alertsoundname, 64, "%s:Alerts", m_szModuleName);
 +	SkinAddNewSoundExT(alertsoundname, m_tszUserName, LPGENT("Live Alert"));
 +
 +	MsgQueue_Init();
 +	AvatarQueue_Init();
 +	InitCustomFolders();
 +
 +	TCHAR szBuffer[MAX_PATH];
 +	char  szDbsettings[64];
 +
 +	NETLIBUSER nlu1 = { 0 };
 +	nlu1.cbSize = sizeof(nlu1);
 +	nlu1.flags = NUF_OUTGOING | NUF_HTTPCONNS | NUF_TCHAR;
 +	nlu1.szSettingsModule = szDbsettings;
 +	nlu1.ptszDescriptiveName = szBuffer;
 +
 +	mir_snprintf(szDbsettings, sizeof(szDbsettings), "%s_HTTPS", m_szModuleName);
 +	mir_sntprintf(szBuffer, SIZEOF(szBuffer), TranslateT("%s plugin HTTPS connections"), m_tszUserName);
 +	hNetlibUserHttps = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu1);
 +
 +	NETLIBUSER nlu = { 0 };
 +	nlu.cbSize = sizeof(nlu);
 +	nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS | NUF_TCHAR;
 +	nlu.szSettingsModule = m_szModuleName;
 +	nlu.ptszDescriptiveName = szBuffer;
 +
 +	nlu.szHttpGatewayUserAgent = (char*)MSN_USER_AGENT;
 +	nlu.pfnHttpGatewayInit = msn_httpGatewayInit;
 +	nlu.pfnHttpGatewayWrapSend = msn_httpGatewayWrapSend;
 +	nlu.pfnHttpGatewayUnwrapRecv = msn_httpGatewayUnwrapRecv;
 +
 +	mir_sntprintf(szBuffer, SIZEOF(szBuffer), TranslateT("%s plugin connections"), m_tszUserName);
 +	m_hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu);
 +}
 +
 +CMsnProto::~CMsnProto()
 +{
 +	MsnRemoveMainMenus();
 +
 +	DestroyHookableEvent(hMSNNudge);
 +
 +	MSN_FreeGroups();
 +	Threads_Uninit();
 +	MsgQueue_Uninit();
 +	AvatarQueue_Uninit();
 +	Lists_Uninit();
 +	P2pSessions_Uninit();
 +	CachedMsg_Uninit();
 +
 +	Netlib_CloseHandle(m_hNetlibUser);
 +	Netlib_CloseHandle(hNetlibUserHttps);
 +
 +	mir_free(mailsoundname);
 +	mir_free(alertsoundname);
 +
 +	for (int i = 0; i < MSN_NUM_MODES; i++)
 +		mir_free(msnModeMsgs[i]);
 +
 +	mir_free(msnLastStatusMsg);
 +	mir_free(msnPreviousUUX);
 +	mir_free(msnExternalIP);
 +
 +	mir_free(abCacheKey);
 +	mir_free(sharingCacheKey);
 +	mir_free(storageCacheKey);
 +
 +	FreeAuthTokens();
 +}
 +
 +int CMsnProto::OnModulesLoaded(WPARAM, LPARAM)
 +{
 +	GCREGISTER gcr = { 0 };
 +	gcr.cbSize = sizeof(GCREGISTER);
 +	gcr.dwFlags = GC_TYPNOTIF | GC_CHANMGR;
 +	gcr.iMaxText = 0;
 +	gcr.nColors = 16;
 +	gcr.pColors = (COLORREF*)crCols;
 +	gcr.ptszDispName = m_tszUserName;
 +	gcr.pszModule = m_szModuleName;
 +	CallServiceSync(MS_GC_REGISTER, 0, (LPARAM)&gcr);
 +
 +	HookProtoEvent(ME_GC_EVENT, &CMsnProto::MSN_GCEventHook);
 +	HookProtoEvent(ME_GC_BUILDMENU, &CMsnProto::MSN_GCMenuHook);
 +
 +	HookProtoEvent(ME_IDLE_CHANGED, &CMsnProto::OnIdleChanged);
 +	InitPopups();
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// OnPreShutdown - prepare a global Miranda shutdown
 +
 +int CMsnProto::OnPreShutdown(WPARAM, LPARAM)
 +{
 +	SetEvent(hevAvatarQueue);
 +
 +	Popup_UnregisterClass(hPopupError);
 +	Popup_UnregisterClass(hPopupHotmail);
 +	Popup_UnregisterClass(hPopupNotify);
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnAddToList - adds contact to the server list
 +
 +MCONTACT CMsnProto::AddToListByEmail(const char *email, const char *nick, DWORD flags)
 +{
 +	MCONTACT hContact = MSN_HContactFromEmail(email, nick, true, flags & PALF_TEMPORARY);
 +
 +	if (flags & PALF_TEMPORARY) {
 +		if (db_get_b(hContact, "CList", "NotOnList", 0) == 1)
 +			db_set_b(hContact, "CList", "Hidden", 1);
 +	}
 +	else {
 +		db_unset(hContact, "CList", "Hidden");
 +		if (msnLoggedIn) {
 +			int netId = strncmp(email, "tel:", 4) ? NETID_MSN : NETID_MOB;
 +			if (MSN_AddUser(hContact, email, netId, LIST_FL)) {
 +				MSN_AddUser(hContact, email, netId, LIST_PL + LIST_REMOVE);
 +				MSN_AddUser(hContact, email, netId, LIST_BL + LIST_REMOVE);
 +				MSN_AddUser(hContact, email, netId, LIST_AL);
 +				db_unset(hContact, "CList", "Hidden");
 +			}
 +			MSN_SetContactDb(hContact, email);
 +
 +			if (MSN_IsMeByContact(hContact)) displayEmailCount(hContact);
 +		}
 +		else hContact = NULL;
 +	}
 +	return hContact;
 +}
 +
 +MCONTACT __cdecl CMsnProto::AddToList(int flags, PROTOSEARCHRESULT* psr)
 +{
 +	TCHAR *id = psr->id ? psr->id : psr->email;
 +	return AddToListByEmail(
 +		psr->flags & PSR_UNICODE ? UTF8((wchar_t*)id) : UTF8((char*)id),
 +		psr->flags & PSR_UNICODE ? UTF8((wchar_t*)psr->nick) : UTF8((char*)psr->nick),
 +		flags);
 +}
 +
 +MCONTACT __cdecl CMsnProto::AddToListByEvent(int flags, int iContact, HANDLE hDbEvent)
 +{
 +	DBEVENTINFO dbei = { sizeof(dbei) };
 +	if ((dbei.cbBlob = db_event_getBlobSize(hDbEvent)) == (DWORD)(-1))
 +		return NULL;
 +
 +	dbei.pBlob = (PBYTE)alloca(dbei.cbBlob);
 +	if (db_event_get(hDbEvent, &dbei)) return NULL;
 +	if (strcmp(dbei.szModule, m_szModuleName)) return NULL;
 +	if (dbei.eventType != EVENTTYPE_AUTHREQUEST) return NULL;
 +
 +	char* nick = (char *)(dbei.pBlob + sizeof(DWORD) * 2);
 +	char* firstName = nick + strlen(nick) + 1;
 +	char* lastName = firstName + strlen(firstName) + 1;
 +	char* email = lastName + strlen(lastName) + 1;
 +
 +	return AddToListByEmail(email, nick, flags);
 +}
 +
 +int CMsnProto::AuthRecv(MCONTACT hContact, PROTORECVEVENT* pre)
 +{
 +	Proto_AuthRecv(m_szModuleName, pre);
 +	return 0;
 +}
 +
 +////////////////////////////////////////////////////////////////////////////////////////
 +// PSS_AUTHREQUEST
 +
 +int __cdecl CMsnProto::AuthRequest(MCONTACT hContact, const TCHAR* szMessage)
 +{
 +	if (msnLoggedIn) {
 +		char email[MSN_MAX_EMAIL_LEN];
 +		if (db_get_static(hContact, m_szModuleName, "e-mail", email, sizeof(email)))
 +			return 1;
 +
 +		char* szMsg = mir_utf8encodeT(szMessage);
 +
 +		int netId = strncmp(email, "tel:", 4) == 0 ? NETID_MOB : NETID_MSN;
 +		if (MSN_AddUser(hContact, email, netId, LIST_FL, szMsg)) {
 +			MSN_AddUser(hContact, email, netId, LIST_PL + LIST_REMOVE);
 +			MSN_AddUser(hContact, email, netId, LIST_BL + LIST_REMOVE);
 +			MSN_AddUser(hContact, email, netId, LIST_AL);
 +		}
 +		MSN_SetContactDb(hContact, email);
 +		mir_free(szMsg);
 +
 +		if (MSN_IsMeByContact(hContact)) displayEmailCount(hContact);
 +		return 0;
 +	}
 +	return 1;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnAuthAllow - called after successful authorization
 +
 +int CMsnProto::Authorize(HANDLE hDbEvent)
 +{
 +	if (!msnLoggedIn)
 +		return 1;
 +
 +	DBEVENTINFO dbei = { sizeof(dbei) };
 +	if ((dbei.cbBlob = db_event_getBlobSize(hDbEvent)) == -1)
 +		return 1;
 +
 +	dbei.pBlob = (PBYTE)alloca(dbei.cbBlob);
 +	if (db_event_get(hDbEvent, &dbei))
 +		return 1;
 +
 +	if (dbei.eventType != EVENTTYPE_AUTHREQUEST)
 +		return 1;
 +
 +	if (strcmp(dbei.szModule, m_szModuleName))
 +		return 1;
 +
 +	char *nick = (char*)(dbei.pBlob + sizeof(DWORD) * 2);
 +	char *firstName = nick + strlen(nick) + 1;
 +	char *lastName = firstName + strlen(firstName) + 1;
 +	char *email = lastName + strlen(lastName) + 1;
 +
 +	MCONTACT hContact = MSN_HContactFromEmail(email, nick, true, 0);
 +	int netId = Lists_GetNetId(email);
 +
 +	MSN_AddUser(hContact, email, netId, LIST_AL);
 +	MSN_AddUser(hContact, email, netId, LIST_BL + LIST_REMOVE);
 +	MSN_AddUser(hContact, email, netId, LIST_PL + LIST_REMOVE);
 +
 +	MSN_SetContactDb(hContact, email);
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnAuthDeny - called after unsuccessful authorization
 +
 +int CMsnProto::AuthDeny(HANDLE hDbEvent, const TCHAR* szReason)
 +{
 +	if (!msnLoggedIn)
 +		return 1;
 +
 +	DBEVENTINFO dbei = { sizeof(dbei) };
 +	if ((dbei.cbBlob = db_event_getBlobSize(hDbEvent)) == -1)
 +		return 1;
 +
 +	dbei.pBlob = (PBYTE)alloca(dbei.cbBlob);
 +	if (db_event_get(hDbEvent, &dbei))
 +		return 1;
 +
 +	if (dbei.eventType != EVENTTYPE_AUTHREQUEST)
 +		return 1;
 +
 +	if (strcmp(dbei.szModule, m_szModuleName))
 +		return 1;
 +
 +	char* nick = (char*)(dbei.pBlob + sizeof(DWORD) * 2);
 +	char* firstName = nick + strlen(nick) + 1;
 +	char* lastName = firstName + strlen(firstName) + 1;
 +	char* email = lastName + strlen(lastName) + 1;
 +
 +	MsnContact* msc = Lists_Get(email);
 +	if (msc == NULL) return 0;
 +
 +	MSN_AddUser(NULL, email, msc->netId, LIST_PL + LIST_REMOVE);
 +	MSN_AddUser(NULL, email, msc->netId, LIST_BL);
 +	MSN_AddUser(NULL, email, msc->netId, LIST_RL);
 +
 +	if (!(msc->list & (LIST_FL | LIST_LL))) {
 +		if (msc->hContact) CallService(MS_DB_CONTACT_DELETE, (WPARAM)msc->hContact, 0);
 +		msc->hContact = NULL;
 +		MCONTACT hContact = MSN_HContactFromEmail(email);
 +		if (hContact) CallService(MS_DB_CONTACT_DELETE, hContact, 0);
 +	}
 +
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnBasicSearch - search contacts by e-mail
 +
 +void __cdecl CMsnProto::MsnSearchAckThread(void* arg)
 +{
 +	const TCHAR* emailT = (TCHAR*)arg;
 +	char *email = mir_utf8encodeT(emailT);
 +
 +	if (Lists_IsInList(LIST_FL, email)) {
 +		MSN_ShowPopup(emailT, TranslateT("Contact already in your contact list"), MSN_ALLOW_MSGBOX, NULL);
 +		ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, arg, 0);
 +		mir_free(arg);
 +		return;
 +	}
 +
 +	unsigned res = MSN_ABContactAdd(email, NULL, NETID_MSN, NULL, 1, true);
 +	switch (res) {
 +	case 0:
 +	case 2:
 +	case 3:
 +		{
 +			PROTOSEARCHRESULT isr = { 0 };
 +			isr.cbSize = sizeof(isr);
 +			isr.flags = PSR_TCHAR;
 +			isr.id = (TCHAR*)emailT;
 +			isr.nick = (TCHAR*)emailT;
 +			isr.email = (TCHAR*)emailT;
 +
 +			ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, arg, (LPARAM)&isr);
 +			ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, arg, 0);
 +		}
 +		break;
 +
 +	case 1:
 +		if (strstr(email, "@yahoo.com") == NULL)
 +			ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, arg, 0);
 +		else {
 +			msnSearchId = arg;
 +			MSN_FindYahooUser(email);
 +		}
 +		break;
 +
 +	default:
 +		ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, arg, 0);
 +		break;
 +	}
 +	mir_free(email);
 +	mir_free(arg);
 +}
 +
 +
 +HANDLE __cdecl CMsnProto::SearchBasic(const PROTOCHAR* id)
 +{
 +	if (!msnLoggedIn) return 0;
 +
 +	TCHAR* email = mir_tstrdup(id);
 +	ForkThread(&CMsnProto::MsnSearchAckThread, email);
 +
 +	return email;
 +}
 +
 +HANDLE __cdecl CMsnProto::SearchByEmail(const PROTOCHAR* email)
 +{
 +	return SearchBasic(email);
 +}
 +
 +
 +HANDLE __cdecl CMsnProto::SearchByName(const PROTOCHAR* nick, const PROTOCHAR* firstName, const PROTOCHAR* lastName)
 +{
 +	return NULL;
 +}
 +
 +HWND __cdecl CMsnProto::SearchAdvanced(HWND hwndDlg)
 +{
 +	return NULL;
 +}
 +
 +HWND __cdecl CMsnProto::CreateExtendedSearchUI(HWND parent)
 +{
 +	return NULL;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnFileAllow - starts the file transfer
 +
 +void __cdecl CMsnProto::MsnFileAckThread(void* arg)
 +{
 +	filetransfer* ft = (filetransfer*)arg;
 +
 +	TCHAR filefull[MAX_PATH];
 +	mir_sntprintf(filefull, SIZEOF(filefull), _T("%s\\%s"), ft->std.tszWorkingDir, ft->std.tszCurrentFile);
 +	replaceStrT(ft->std.tszCurrentFile, filefull);
 +
 +	if (ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, ft, (LPARAM)&ft->std))
 +		return;
 +
 +	bool fcrt = ft->create() != -1;
 +
 +	if (ft->p2p_appID != 0) {
 +		if (fcrt)
 +			p2p_sendFeedStart(ft);
 +		p2p_sendStatus(ft, fcrt ? 200 : 603);
 +	}
 +	else msnftp_sendAcceptReject(ft, fcrt);
 +
 +	ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, ft, 0);
 +}
 +
 +HANDLE __cdecl CMsnProto::FileAllow(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR* szPath)
 +{
 +	filetransfer* ft = (filetransfer*)hTransfer;
 +
 +	if (!msnLoggedIn || !p2p_sessionRegistered(ft))
 +		return 0;
 +
 +	if ((ft->std.tszWorkingDir = mir_tstrdup(szPath)) == NULL) {
 +		TCHAR szCurrDir[MAX_PATH];
 +		GetCurrentDirectory(SIZEOF(szCurrDir), szCurrDir);
 +		ft->std.tszWorkingDir = mir_tstrdup(szCurrDir);
 +	}
 +	else {
 +		size_t len = _tcslen(ft->std.tszWorkingDir) - 1;
 +		if (ft->std.tszWorkingDir[len] == '\\')
 +			ft->std.tszWorkingDir[len] = 0;
 +	}
 +
 +	ForkThread(&CMsnProto::MsnFileAckThread, ft);
 +
 +	return ft;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnFileCancel - cancels the active file transfer
 +
 +int __cdecl CMsnProto::FileCancel(MCONTACT hContact, HANDLE hTransfer)
 +{
 +	filetransfer* ft = (filetransfer*)hTransfer;
 +
 +	if (!msnLoggedIn || !p2p_sessionRegistered(ft))
 +		return 0;
 +
 +	if (!(ft->std.flags & PFTS_SENDING) && ft->fileId == -1) {
 +		if (ft->p2p_appID != 0)
 +			p2p_sendStatus(ft, 603);
 +		else
 +			msnftp_sendAcceptReject(ft, false);
 +	}
 +	else {
 +		ft->bCanceled = true;
 +		if (ft->p2p_appID != 0) {
 +			p2p_sendCancel(ft);
 +			if (!(ft->std.flags & PFTS_SENDING) && ft->p2p_isV2)
 +				p2p_sessionComplete(ft);
 +		}
 +	}
 +
 +	ft->std.ptszFiles = NULL;
 +	ft->std.totalFiles = 0;
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnFileDeny - rejects the file transfer request
 +
 +int __cdecl CMsnProto::FileDeny(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR* /*szReason*/)
 +{
 +	filetransfer* ft = (filetransfer*)hTransfer;
 +
 +	if (!msnLoggedIn || !p2p_sessionRegistered(ft))
 +		return 1;
 +
 +	if (!(ft->std.flags & PFTS_SENDING) && ft->fileId == -1) {
 +		if (ft->p2p_appID != 0)
 +			p2p_sendStatus(ft, 603);
 +		else
 +			msnftp_sendAcceptReject(ft, false);
 +	}
 +	else {
 +		ft->bCanceled = true;
 +		if (ft->p2p_appID != 0)
 +			p2p_sendCancel(ft);
 +	}
 +
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnFileResume - renames a file
 +
 +int __cdecl CMsnProto::FileResume(HANDLE hTransfer, int* action, const PROTOCHAR** szFilename)
 +{
 +	filetransfer* ft = (filetransfer*)hTransfer;
 +
 +	if (!msnLoggedIn || !p2p_sessionRegistered(ft))
 +		return 1;
 +
 +	switch (*action) {
 +	case FILERESUME_SKIP:
 +		if (ft->p2p_appID != 0)
 +			p2p_sendStatus(ft, 603);
 +		else
 +			msnftp_sendAcceptReject(ft, false);
 +		break;
 +
 +	case FILERESUME_RENAME:
 +		replaceStrT(ft->std.tszCurrentFile, *szFilename);
 +
 +	default:
 +		bool fcrt = ft->create() != -1;
 +		if (ft->p2p_appID != 0) {
 +			if (fcrt)
 +				p2p_sendFeedStart(ft);
 +
 +			p2p_sendStatus(ft, fcrt ? 200 : 603);
 +		}
 +		else
 +			msnftp_sendAcceptReject(ft, fcrt);
 +
 +		ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, ft, 0);
 +		break;
 +	}
 +
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnGetAwayMsg - reads the current status message for a user
 +
 +typedef struct AwayMsgInfo_tag
 +{
 +	INT_PTR id;
 +	MCONTACT hContact;
 +} AwayMsgInfo;
 +
 +void __cdecl CMsnProto::MsnGetAwayMsgThread(void* arg)
 +{
 +	Sleep(150);
 +
 +	AwayMsgInfo *inf = (AwayMsgInfo*)arg;
 +	DBVARIANT dbv;
 +	if (!db_get_ts(inf->hContact, "CList", "StatusMsg", &dbv)) {
 +		ProtoBroadcastAck(inf->hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)inf->id, (LPARAM)dbv.ptszVal);
 +		db_free(&dbv);
 +	}
 +	else ProtoBroadcastAck(inf->hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)inf->id, 0);
 +
 +	mir_free(inf);
 +}
 +
 +HANDLE __cdecl CMsnProto::GetAwayMsg(MCONTACT hContact)
 +{
 +	AwayMsgInfo* inf = (AwayMsgInfo*)mir_alloc(sizeof(AwayMsgInfo));
 +	inf->hContact = hContact;
 +	inf->id = MSN_GenRandom();
 +
 +	ForkThread(&CMsnProto::MsnGetAwayMsgThread, inf);
 +	return (HANDLE)inf->id;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnGetCaps - obtain the protocol capabilities
 +
 +DWORD_PTR __cdecl CMsnProto::GetCaps(int type, MCONTACT hContact)
 +{
 +	switch (type) {
 +	case PFLAGNUM_1:
 +		return PF1_IM | PF1_SERVERCLIST | PF1_AUTHREQ | PF1_BASICSEARCH |
 +			PF1_ADDSEARCHRES | PF1_CHAT |
 +			PF1_FILESEND | PF1_FILERECV | PF1_URLRECV | PF1_VISLIST | PF1_MODEMSG;
 +
 +	case PFLAGNUM_2:
 +		return PF2_ONLINE | PF2_SHORTAWAY | PF2_LIGHTDND | PF2_INVISIBLE | PF2_ONTHEPHONE | PF2_IDLE;
 +
 +	case PFLAGNUM_3:
 +		return PF2_ONLINE | PF2_SHORTAWAY | PF2_LIGHTDND;
 +
 +	case PFLAGNUM_4:
 +		return PF4_FORCEAUTH | PF4_FORCEADDED | PF4_SUPPORTTYPING | PF4_AVATARS | PF4_SUPPORTIDLE | PF4_IMSENDUTF |
 +			PF4_IMSENDOFFLINE | PF4_NOAUTHDENYREASON;
 +
 +	case PFLAGNUM_5:
 +		return PF2_ONTHEPHONE;
 +
 +	case PFLAG_UNIQUEIDTEXT:
 +		return (UINT_PTR)Translate("Live ID");
 +
 +	case PFLAG_UNIQUEIDSETTING:
 +		return (UINT_PTR)"e-mail";
 +
 +	case PFLAG_MAXLENOFMESSAGE:
 +		return 1202;
 +	}
 +
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnGetInfo - nothing to do, cause we cannot obtain information from the server
 +
 +int __cdecl CMsnProto::GetInfo(MCONTACT hContact, int infoType)
 +{
 +	return 1;
 +}
 +
 +////////////////////////////////////////////////////////////////////////////////////////
 +// RecvContacts
 +
 +int __cdecl CMsnProto::RecvContacts(MCONTACT hContact, PROTORECVEVENT*)
 +{
 +	return 1;
 +}
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnRecvFile - creates a database event from the file request been received
 +
 +int __cdecl CMsnProto::RecvFile(MCONTACT hContact, PROTOFILEEVENT* evt)
 +{
 +	return Proto_RecvFile(hContact, evt);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnRecvMessage - creates a database event from the message been received
 +
 +int __cdecl CMsnProto::RecvMsg(MCONTACT hContact, PROTORECVEVENT* pre)
 +{
 +	char tEmail[MSN_MAX_EMAIL_LEN];
 +	db_get_static(hContact, m_szModuleName, "e-mail", tEmail, sizeof(tEmail));
 +
 +	if (Lists_IsInList(LIST_FL, tEmail))
 +		db_unset(hContact, "CList", "Hidden");
 +
 +	return Proto_RecvMessage(hContact, pre);
 +}
 +
 +////////////////////////////////////////////////////////////////////////////////////////
 +// RecvUrl
 +
 +int __cdecl CMsnProto::RecvUrl(MCONTACT hContact, PROTORECVEVENT*)
 +{
 +	return 1;
 +}
 +
 +////////////////////////////////////////////////////////////////////////////////////////
 +// SendContacts
 +
 +int __cdecl CMsnProto::SendContacts(MCONTACT hContact, int flags, int nContacts, MCONTACT *hContactsList)
 +{
 +	return 1;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnSendFile - initiates a file transfer
 +
 +HANDLE __cdecl CMsnProto::SendFile(MCONTACT hContact, const PROTOCHAR* szDescription, PROTOCHAR** ppszFiles)
 +{
 +	if (!msnLoggedIn)
 +		return 0;
 +
 +	if (getWord(hContact, "Status", ID_STATUS_OFFLINE) == ID_STATUS_OFFLINE)
 +		return 0;
 +
 +	MsnContact *cont = Lists_Get(hContact);
 +
 +	if (!cont || _stricmp(cont->email, MyOptions.szEmail) == 0) return 0;
 +
 +	if ((cont->cap1 & 0xf0000000) == 0 && cont->netId != NETID_MSN) return 0;
 +
 +	filetransfer* sft = new filetransfer(this);
 +	sft->std.ptszFiles = ppszFiles;
 +	sft->std.hContact = hContact;
 +	sft->std.flags |= PFTS_SENDING;
 +
 +	int count = 0;
 +	while (ppszFiles[count] != NULL) {
 +		struct _stati64 statbuf;
 +		if (_tstati64(ppszFiles[count++], &statbuf) == 0 && (statbuf.st_mode & _S_IFDIR) == 0) {
 +			sft->std.totalBytes += statbuf.st_size;
 +			++sft->std.totalFiles;
 +		}
 +	}
 +
 +	if (sft->openNext() == -1) {
 +		delete sft;
 +		return 0;
 +	}
 +
 +	if (cont->cap1 & 0xf0000000)
 +		p2p_invite(MSN_APPID_FILE, sft, NULL);
 +	else {
 +		sft->p2p_dest = mir_strdup(cont->email);
 +		msnftp_invite(sft);
 +	}
 +
 +	ProtoBroadcastAck(hContact, ACKTYPE_FILE, ACKRESULT_SENTREQUEST, sft, 0);
 +	return sft;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnSendMessage - sends the message to a server
 +
 +struct TFakeAckParams
 +{
 +	inline TFakeAckParams(MCONTACT p2, long p3, const char* p4, CMsnProto *p5) :
 +		hContact(p2),
 +		id(p3),
 +		msg(p4),
 +		proto(p5)
 +	{}
 +
 +	MCONTACT hContact;
 +	long	id;
 +	const char*	msg;
 +	CMsnProto *proto;
 +};
 +
 +void CMsnProto::MsnFakeAck(void* arg)
 +{
 +	TFakeAckParams* tParam = (TFakeAckParams*)arg;
 +
 +	Sleep(150);
 +	tParam->proto->ProtoBroadcastAck(tParam->hContact, ACKTYPE_MESSAGE,
 +		tParam->msg ? ACKRESULT_FAILED : ACKRESULT_SUCCESS,
 +		(HANDLE)tParam->id, LPARAM(tParam->msg));
 +
 +	delete tParam;
 +}
 +
 +int __cdecl CMsnProto::SendMsg(MCONTACT hContact, int flags, const char* pszSrc)
 +{
 +	const char *errMsg = NULL;
 +
 +	if (!msnLoggedIn) {
 +		errMsg = Translate("Protocol is offline");
 +		ForkThread(&CMsnProto::MsnFakeAck, new TFakeAckParams(hContact, 999999, errMsg, this));
 +		return 999999;
 +	}
 +
 +	char tEmail[MSN_MAX_EMAIL_LEN];
 +	if (MSN_IsMeByContact(hContact, tEmail)) {
 +		errMsg = Translate("You cannot send message to yourself");
 +		ForkThread(&CMsnProto::MsnFakeAck, new TFakeAckParams(hContact, 999999, errMsg, this));
 +		return 999999;
 +	}
 +
 +	char *msg = (char*)pszSrc;
 +	if (msg == NULL) return 0;
 +
 +	if (flags & PREF_UNICODE) {
 +		char* p = strchr(msg, '\0');
 +		if (p != msg) {
 +			while (*(++p) == '\0') {}
 +			msg = mir_utf8encodeW((wchar_t*)p);
 +		}
 +		else
 +			msg = mir_strdup(msg);
 +	}
 +	else
 +		msg = (flags & PREF_UTF) ? mir_strdup(msg) : mir_utf8encode(msg);
 +
 +	int rtlFlag = (flags & PREF_RTL) ? MSG_RTL : 0;
 +
 +	int seq = 0;
 +	int netId = Lists_GetNetId(tEmail);
 +
 +	switch (netId) {
 +	case NETID_MOB:
 +		if (strlen(msg) > 133) {
 +			errMsg = Translate("Message is too long: SMS page limited to 133 UTF8 chars");
 +			seq = 999997;
 +		}
 +		else {
 +			errMsg = NULL;
 +			seq = msnNsThread->sendMessage('1', tEmail, netId, msg, rtlFlag);
 +		}
 +		ForkThread(&CMsnProto::MsnFakeAck, new TFakeAckParams(hContact, seq, errMsg, this));
 +		break;
 +
 +	case NETID_YAHOO:
 +		if (strlen(msg) > 1202) {
 +			seq = 999996;
 +			errMsg = Translate("Message is too long: MSN messages are limited by 1202 UTF8 chars");
 +			ForkThread(&CMsnProto::MsnFakeAck, new TFakeAckParams(hContact, seq, errMsg, this));
 +		}
 +		else {
 +			seq = msnNsThread->sendMessage('1', tEmail, netId, msg, rtlFlag);
 +			ForkThread(&CMsnProto::MsnFakeAck, new TFakeAckParams(hContact, seq, NULL, this));
 +		}
 +		break;
 +
 +	default:
 +		if (strlen(msg) > 1202) {
 +			seq = 999996;
 +			errMsg = Translate("Message is too long: MSN messages are limited by 1202 UTF8 chars");
 +			ForkThread(&CMsnProto::MsnFakeAck, new TFakeAckParams(hContact, seq, errMsg, this));
 +		}
 +		else {
 +			const char msgType = MyOptions.SlowSend ? 'A' : 'N';
 +			bool isOffline;
 +			ThreadData* thread = MSN_StartSB(tEmail, isOffline);
 +			if (thread == NULL) {
 +				if (isOffline) {
 +					if (netId != NETID_LCS) {
 +						seq = msnNsThread->sendMessage('1', tEmail, netId, msg, rtlFlag | MSG_OFFLINE);
 +						ForkThread(&CMsnProto::MsnFakeAck, new TFakeAckParams(hContact, seq, NULL, this));
 +					}
 +					else {
 +						seq = 999993;
 +						errMsg = Translate("Offline messaging is not allowed for LCS contacts");
 +						ForkThread(&CMsnProto::MsnFakeAck, new TFakeAckParams(hContact, seq, errMsg, this));
 +					}
 +				}
 +				else
 +					seq = MsgQueue_Add(tEmail, msgType, msg, 0, 0, rtlFlag);
 +			}
 +			else {
 +				seq = thread->sendMessage(msgType, tEmail, netId, msg, rtlFlag);
 +				if (!MyOptions.SlowSend)
 +					ForkThread(&CMsnProto::MsnFakeAck, new TFakeAckParams(hContact, seq, NULL, this));
 +			}
 +		}
 +		break;
 +	}
 +
 +	mir_free(msg);
 +	return seq;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnSetAwayMsg - sets the current status message for a user
 +
 +int __cdecl CMsnProto::SetAwayMsg(int status, const TCHAR* msg)
 +{
 +	char** msgptr = GetStatusMsgLoc(status);
 +
 +	if (msgptr == NULL)
 +		return 1;
 +
 +	mir_free(*msgptr);
 +	char* buf = *msgptr = mir_utf8encodeT(msg);
 +	if (buf && strlen(buf) > 1859) {
 +		buf[1859] = 0;
 +		const int i = 1858;
 +		if (buf[i] & 128) {
 +			if (buf[i] & 64)
 +				buf[i] = '\0';
 +			else if ((buf[i - 1] & 224) == 224)
 +				buf[i - 1] = '\0';
 +			else if ((buf[i - 2] & 240) == 240)
 +				buf[i - 2] = '\0';
 +		}
 +	}
 +
 +	if (status == m_iDesiredStatus)
 +		MSN_SendStatusMessage(*msgptr);
 +
 +	return 0;
 +}
 +
 +////////////////////////////////////////////////////////////////////////////////////////
 +// PSR_AWAYMSG
 +
 +int __cdecl CMsnProto::RecvAwayMsg(MCONTACT hContact, int statusMode, PROTORECVEVENT* evt)
 +{
 +	return 1;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnSetStatus - set the plugin's connection status
 +
 +int __cdecl CMsnProto::SetStatus(int iNewStatus)
 +{
 +	if (m_iDesiredStatus == iNewStatus) return 0;
 +
 +	m_iDesiredStatus = iNewStatus;
 +	debugLogA("PS_SETSTATUS(%d,0)", iNewStatus);
 +
 +	if (m_iDesiredStatus == ID_STATUS_OFFLINE) {
 +		if (msnNsThread)
 +			msnNsThread->sendTerminate();
 +	}
 +	else if (!msnLoggedIn && m_iStatus == ID_STATUS_OFFLINE) {
 +		char szPassword[100];
 +		int ps = db_get_static(NULL, m_szModuleName, "Password", szPassword, sizeof(szPassword));
 +		if (ps != 0 || *szPassword == 0) {
 +			ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD);
 +			m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
 +			return 0;
 +		}
 +
 +		if (*MyOptions.szEmail == 0) {
 +			ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID);
 +			m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
 +			return 0;
 +		}
 +
 +		sessionList.destroy();
 +		dcList.destroy();
 +
 +		usingGateway = false;
 +
 +		int oldMode = m_iStatus;
 +		m_iStatus = ID_STATUS_CONNECTING;
 +		ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldMode, m_iStatus);
 +
 +		ThreadData* newThread = new ThreadData;
 +
 +		newThread->mType = SERVER_NOTIFICATION;
 +		newThread->mIsMainThread = true;
 +
 +		newThread->startThread(&CMsnProto::MSNServerThread, this);
 +	}
 +	else
 +		if (m_iStatus > ID_STATUS_OFFLINE) MSN_SetServerStatus(m_iDesiredStatus);
 +
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnUserIsTyping - notify another contact that we're typing a message
 +
 +int __cdecl CMsnProto::UserIsTyping(MCONTACT hContact, int type)
 +{
 +	if (!msnLoggedIn) return 0;
 +
 +	char tEmail[MSN_MAX_EMAIL_LEN];
 +	if (MSN_IsMeByContact(hContact, tEmail)) return 0;
 +
 +	bool typing = type == PROTOTYPE_SELFTYPING_ON;
 +
 +	int netId = Lists_GetNetId(tEmail);
 +	switch (netId) {
 +	case NETID_UNKNOWN:
 +	case NETID_MSN:
 +	case NETID_LCS:
 +		{
 +			bool isOffline;
 +			ThreadData* thread = MSN_StartSB(tEmail, isOffline);
 +
 +			if (thread == NULL) {
 +				if (isOffline) return 0;
 +				MsgQueue_Add(tEmail, 2571, NULL, 0, NULL, typing);
 +			}
 +			else
 +				MSN_StartStopTyping(thread, typing);
 +		}
 +		break;
 +
 +	case NETID_YAHOO:
 +		if (typing) MSN_SendTyping(msnNsThread, tEmail, netId);
 +		break;
 +
 +	default:
 +		break;
 +	}
 +
 +	return 0;
 +}
 +
 +////////////////////////////////////////////////////////////////////////////////////////
 +// SendUrl
 +
 +int __cdecl CMsnProto::SendUrl(MCONTACT hContact, int flags, const char* url)
 +{
 +	return 1;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	MsnSetApparentMode - controls contact visibility
 +
 +int __cdecl CMsnProto::SetApparentMode(MCONTACT hContact, int mode)
 +{
 +	if (mode && mode != ID_STATUS_OFFLINE)
 +		return 1;
 +
 +	WORD oldMode = getWord(hContact, "ApparentMode", 0);
 +	if (mode != oldMode)
 +		setWord(hContact, "ApparentMode", (WORD)mode);
 +
 +	return 1;
 +}
 +
 +int __cdecl CMsnProto::OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam)
 +{
 +	switch (eventType) {
 +	case EV_PROTO_ONLOAD:
 +		return OnModulesLoaded(0, 0);
 +
 +	case EV_PROTO_ONEXIT:
 +		return OnPreShutdown(0, 0);
 +
 +	case EV_PROTO_ONOPTIONS:
 +		return OnOptionsInit(wParam, lParam);
 +
 +	case EV_PROTO_ONMENU:
 +		MsnInitMainMenu();
 +		break;
 +
 +	case EV_PROTO_ONERASE:
 +		{
 +			char szDbsettings[64];
 +			mir_snprintf(szDbsettings, sizeof(szDbsettings), "%s_HTTPS", m_szModuleName);
 +			CallService(MS_DB_MODULE_DELETE, 0, (LPARAM)szDbsettings);
 +		}
 +		break;
 +
 +	case EV_PROTO_ONRENAME:
 +		if (mainMenuRoot) {
 +			CLISTMENUITEM clmi = { sizeof(clmi) };
 +			clmi.flags = CMIM_NAME | CMIF_TCHAR;
 +			clmi.ptszName = m_tszUserName;
 +			Menu_ModifyItem(mainMenuRoot, &clmi);
 +		}
 +		break;
 +
 +	case EV_PROTO_ONCONTACTDELETED:
 +		return OnContactDeleted(wParam, lParam);
 +
 +	case EV_PROTO_DBSETTINGSCHANGED:
 +		return OnDbSettingChanged(wParam, lParam);
 +	}
 +	return 1;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_proto.h b/plugins/!Deprecated/MSN/src/msn_proto.h new file mode 100644 index 0000000000..9c0b27214b --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_proto.h @@ -0,0 +1,567 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2009-2012 Boris Krasnovskiy.
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#ifndef _MSN_PROTO_H_
 +#define _MSN_PROTO_H_
 +
 +#include <m_protoint.h>
 +
 +struct CMsnProto : public PROTO<CMsnProto>
 +{
 +	CMsnProto(const char*, const TCHAR*);
 +	~CMsnProto();
 +
 +	//====================================================================================
 +	// PROTO_INTERFACE
 +	//====================================================================================
 +
 +	virtual	MCONTACT  __cdecl AddToList(int flags, PROTOSEARCHRESULT* psr);
 +	virtual	MCONTACT  __cdecl AddToListByEvent(int flags, int iContact, HANDLE hDbEvent);
 +
 +	virtual	int       __cdecl Authorize(HANDLE hDbEvent);
 +	virtual	int       __cdecl AuthDeny(HANDLE hDbEvent, const TCHAR* szReason);
 +	virtual	int       __cdecl AuthRecv(MCONTACT hContact, PROTORECVEVENT*);
 +	virtual	int       __cdecl AuthRequest(MCONTACT hContact, const TCHAR* szMessage);
 +
 +	virtual	HANDLE    __cdecl FileAllow(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR* szPath);
 +	virtual	int       __cdecl FileCancel(MCONTACT hContact, HANDLE hTransfer);
 +	virtual	int       __cdecl FileDeny(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR* szReason);
 +	virtual	int       __cdecl FileResume(HANDLE hTransfer, int* action, const PROTOCHAR** szFilename);
 +
 +	virtual	DWORD_PTR __cdecl GetCaps(int type, MCONTACT hContact = NULL);
 +	virtual	int       __cdecl GetInfo(MCONTACT hContact, int infoType);
 +
 +	virtual	HANDLE    __cdecl SearchBasic(const PROTOCHAR* id);
 +	virtual	HANDLE    __cdecl SearchByEmail(const PROTOCHAR* email);
 +	virtual	HANDLE    __cdecl SearchByName(const PROTOCHAR* nick, const PROTOCHAR* firstName, const PROTOCHAR* lastName);
 +	virtual	HWND      __cdecl SearchAdvanced(HWND owner);
 +	virtual	HWND      __cdecl CreateExtendedSearchUI(HWND owner);
 +
 +	virtual	int       __cdecl RecvContacts(MCONTACT hContact, PROTORECVEVENT*);
 +	virtual	int       __cdecl RecvFile(MCONTACT hContact, PROTOFILEEVENT*);
 +	virtual	int       __cdecl RecvMsg(MCONTACT hContact, PROTORECVEVENT*);
 +	virtual	int       __cdecl RecvUrl(MCONTACT hContact, PROTORECVEVENT*);
 +
 +	virtual	int       __cdecl SendContacts(MCONTACT hContact, int flags, int nContacts, MCONTACT *hContactsList);
 +	virtual	HANDLE    __cdecl SendFile(MCONTACT hContact, const PROTOCHAR* szDescription, PROTOCHAR** ppszFiles);
 +	virtual	int       __cdecl SendMsg(MCONTACT hContact, int flags, const char* msg);
 +	virtual	int       __cdecl SendUrl(MCONTACT hContact, int flags, const char* url);
 +
 +	virtual	int       __cdecl SetApparentMode(MCONTACT hContact, int mode);
 +	virtual	int       __cdecl SetStatus(int iNewStatus);
 +
 +	virtual	HANDLE    __cdecl GetAwayMsg(MCONTACT hContact);
 +	virtual	int       __cdecl RecvAwayMsg(MCONTACT hContact, int mode, PROTORECVEVENT* evt);
 +	virtual	int       __cdecl SetAwayMsg(int m_iStatus, const TCHAR* msg);
 +
 +	virtual	int       __cdecl UserIsTyping(MCONTACT hContact, int type);
 +
 +	virtual	int       __cdecl OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam);
 +
 +	//====| Services |====================================================================
 +	INT_PTR  __cdecl SvcCreateAccMgrUI(WPARAM wParam, LPARAM lParam);
 +
 +	INT_PTR  __cdecl GetAvatarInfo(WPARAM wParam, LPARAM lParam);
 +	INT_PTR  __cdecl GetMyAwayMsg(WPARAM wParam,LPARAM lParam);
 +
 +	INT_PTR  __cdecl GetAvatar(WPARAM wParam, LPARAM lParam);
 +	INT_PTR  __cdecl SetAvatar(WPARAM wParam, LPARAM lParam);
 +	INT_PTR  __cdecl GetAvatarCaps(WPARAM wParam, LPARAM lParam);
 +
 +	INT_PTR  __cdecl GetCurrentMedia(WPARAM wParam, LPARAM lParam);
 +	INT_PTR  __cdecl SetCurrentMedia(WPARAM wParam, LPARAM lParam);
 +
 +	INT_PTR  __cdecl SetNickName(WPARAM wParam, LPARAM lParam);
 +	INT_PTR  __cdecl SendNudge(WPARAM wParam, LPARAM lParam);
 +
 +	INT_PTR  __cdecl GetUnreadEmailCount(WPARAM wParam, LPARAM lParam);
 +
 +	INT_PTR  __cdecl ManageAccount(WPARAM wParam, LPARAM lParam);
 +
 +	INT_PTR  __cdecl OnLeaveChat(WPARAM wParam, LPARAM lParam);
 +
 +	//====| Events |======================================================================
 +	int  __cdecl OnContactDeleted(WPARAM wParam,LPARAM lParam);
 +	int  __cdecl OnIdleChanged(WPARAM wParam, LPARAM lParam);
 +	int  __cdecl OnGroupChange(WPARAM wParam, LPARAM lParam);
 +	int  __cdecl OnModulesLoaded(WPARAM wParam, LPARAM lParam);
 +	int  __cdecl OnOptionsInit(WPARAM wParam,LPARAM lParam);
 +	int  __cdecl OnPrebuildContactMenu(WPARAM wParam,LPARAM lParam);
 +	int  __cdecl OnPreShutdown(WPARAM wParam,LPARAM lParam);
 +	int  __cdecl OnContactDoubleClicked(WPARAM wParam,LPARAM lParam);
 +	int  __cdecl OnDbSettingChanged(WPARAM wParam,LPARAM lParam);
 +	int  __cdecl OnUserInfoInit(WPARAM wParam,LPARAM lParam);
 +	int  __cdecl OnWindowEvent(WPARAM wParam, LPARAM lParam);
 +	int  __cdecl OnWindowPopup(WPARAM wParam, LPARAM lParam);
 +
 +	//====| Data |========================================================================
 +
 +	// Security Tokens
 +	char *pAuthToken, *tAuthToken;
 +	char *oimSendToken;
 +	char *authStrToken, *authSecretToken;
 +	char *authContactToken;
 +	char *authStorageToken;
 +	char *hotSecretToken, *hotAuthToken;
 +
 +	char *abCacheKey, *sharingCacheKey, *storageCacheKey;
 +
 +	mir_cs csLists;
 +	OBJLIST<MsnContact> contList;
 +
 +	LIST<ServerGroupItem> grpList;
 +
 +	mir_cs csThreads;
 +	OBJLIST<ThreadData> sttThreads;
 +
 +	mir_cs sessionLock;
 +	OBJLIST<filetransfer> sessionList;
 +	OBJLIST<directconnection> dcList;
 +
 +	mir_cs csMsgQueue;
 +	int msgQueueSeq;
 +	OBJLIST<MsgQueueEntry> lsMessageQueue;
 +
 +	mir_cs csAvatarQueue;
 +	LIST<AvatarQueueEntry> lsAvatarQueue;
 +	HANDLE hevAvatarQueue;
 +
 +	LONG sttChatID;
 +
 +	int msnPingTimeout;
 +	HANDLE hKeepAliveThreadEvt;
 +
 +	char* msnModeMsgs[MSN_NUM_MODES];
 +
 +	LISTENINGTOINFO     msnCurrentMedia;
 +	MYOPTIONS			MyOptions;
 +	MyConnectionType	MyConnection;
 +
 +	ThreadData*	msnNsThread;
 +	bool        msnLoggedIn;
 +	bool        usingGateway;
 +
 +	char*       msnExternalIP;
 +	char*       msnPreviousUUX;
 +	char*       msnLastStatusMsg;
 +
 +	char*       mailsoundname;
 +	char*       alertsoundname;
 +
 +	unsigned    langpref;
 +	unsigned    emailEnabled;
 +	unsigned    abchMigrated;
 +	unsigned    myFlags;
 +
 +	unsigned    msnOtherContactsBlocked;
 +	int			mUnreadMessages;
 +	int			mUnreadJunkEmails;
 +	clock_t		mHttpsTS;
 +	clock_t		mStatusMsgTS;
 +
 +	HANDLE		msnSearchId;
 +	HANDLE		hNetlibUserHttps;
 +	HANDLE		hHttpsConnection;
 +	HANDLE		hMSNNudge;
 +	HANDLE      hPopupError, hPopupHotmail, hPopupNotify;
 +
 +	HANDLE		hCustomSmileyFolder;
 +	bool        InitCstFldRan;
 +	bool        isConnectSuccess;
 +	bool        isIdle;
 +
 +	void        InitCustomFolders(void);
 +
 +	char*       getSslResult(char** parUrl, const char* parAuthInfo, const char* hdrs, unsigned& status);
 +	bool        getMyAvatarFile(char *url, TCHAR *fname);
 +
 +	void        MSN_GoOffline(void);
 +	void        MSN_GetCustomSmileyFileName(MCONTACT hContact, TCHAR* pszDest, size_t cbLen, const char* SmileyName, int Type);
 +
 +	const char*	MirandaStatusToMSN(int status);
 +	WORD        MSNStatusToMiranda(const char *status);
 +	char**		GetStatusMsgLoc(int status);
 +
 +	void        MSN_SendStatusMessage(const char* msg);
 +	void        MSN_SetServerStatus(int newStatus);
 +	void        MSN_StartStopTyping(ThreadData* info, bool start);
 +	void        MSN_SendTyping(ThreadData* info, const char* email, int netId );
 +
 +	void        MSN_InitSB(ThreadData* info, const char* szEmail);
 +	void        MSN_ReceiveMessage(ThreadData* info, char* cmdString, char* params);
 +	int			MSN_HandleCommands(ThreadData* info, char* cmdString);
 +	int			MSN_HandleErrors(ThreadData* info, char* cmdString);
 +	void        MSN_ProcessNotificationMessage(char* buf, unsigned len);
 +	void        MSN_ProcessStatusMessage(char* buf, unsigned len, const char* wlid);
 +	void        MSN_ProcessPage(char* buf, unsigned len);
 +	void        MSN_ProcessRemove(char* buf, size_t len);
 +	void        MSN_ProcessAdd(char* buf, size_t len);
 +	void        MSN_ProcessYFind(char* buf, size_t len);
 +	void        MSN_CustomSmiley(const char* msgBody, char* email, char* nick, int iSmileyType);
 +	void        MSN_InviteMessage(ThreadData* info, char* msgBody, char* email, char* nick);
 +	void        MSN_SetMirVer(MCONTACT hContact, DWORD dwValue, bool always);
 +
 +	void        LoadOptions(void);
 +
 +	void        InitPopups(void);
 +	void        MSN_ShowPopup(const TCHAR* nickname, const TCHAR* msg, int flags, const char* url, MCONTACT hContact = NULL);
 +	void        MSN_ShowPopup(const MCONTACT hContact, const TCHAR* msg, int flags);
 +	void        MSN_ShowError(const char* msgtext, ...);
 +
 +	void        MSN_SetNicknameUtf(const char* nickname);
 +	void        MSN_SendNicknameUtf(const char* nickname);
 +
 +	typedef struct { TCHAR *szName; const char *szMimeType; unsigned char *data; size_t dataSize; } StoreAvatarData;
 +	void __cdecl msn_storeAvatarThread(void* arg);
 +
 +	void __cdecl msn_storeProfileThread(void*);
 +
 +	/////////////////////////////////////////////////////////////////////////////////////////
 +	// MSN Connection properties detection
 +
 +	void		DecryptEchoPacket(UDPProbePkt& pkt);
 +	void		MSNatDetect(void);
 +
 +	void __cdecl MSNConnDetectThread(void*);
 +
 +	/////////////////////////////////////////////////////////////////////////////////////////
 +	// MSN menus
 +
 +	HGENMENU mainMenuRoot;
 +	HGENMENU menuItemsMain[4];
 +
 +	void MsnInitMainMenu(void);
 +	void MsnRemoveMainMenus(void);
 +	void MSN_EnableMenuItems(bool parEnable);
 +	void MsnInvokeMyURL(bool ismail, const char* url);
 +
 +	INT_PTR __cdecl MsnBlockCommand(WPARAM wParam, LPARAM lParam);
 +	INT_PTR __cdecl MsnGotoInbox(WPARAM, LPARAM);
 +	INT_PTR __cdecl MsnSendHotmail(WPARAM wParam, LPARAM);
 +	INT_PTR __cdecl MsnEditProfile(WPARAM, LPARAM);
 +	INT_PTR __cdecl MsnInviteCommand(WPARAM wParam, LPARAM lParam);
 +	INT_PTR __cdecl MsnSendNetMeeting(WPARAM wParam, LPARAM lParam);
 +	INT_PTR __cdecl SetNicknameUI(WPARAM wParam, LPARAM lParam);
 +	INT_PTR __cdecl MsnViewProfile(WPARAM wParam, LPARAM lParam);
 +	INT_PTR __cdecl MsnSetupAlerts(WPARAM wParam, LPARAM lParam);
 +
 +	/////////////////////////////////////////////////////////////////////////////////////////
 +	// MSN thread functions
 +
 +	void __cdecl msn_keepAliveThread(void* arg);
 +	void __cdecl MSNServerThread(void* arg);
 +
 +	void __cdecl MsnFileAckThread(void* arg);
 +	void __cdecl MsnSearchAckThread(void* arg);
 +	void __cdecl sttFakeAvatarAck(void* arg);
 +	void __cdecl MsnFakeAck(void* arg);
 +
 +	void __cdecl MsnGetAwayMsgThread(void* arg);
 +
 +	void __cdecl p2p_sendFeedThread(void* arg );
 +	void __cdecl p2p_fileActiveThread(void* arg );
 +	void __cdecl p2p_filePassiveThread(void* arg);
 +
 +	void __cdecl MsgQueue_AllClearThread(void* arg);
 +
 +	/////////////////////////////////////////////////////////////////////////////////////////
 +	// MSN thread support
 +
 +	void         Threads_Uninit(void);
 +	void         MSN_CloseConnections(void);
 +	int          MSN_GetChatThreads(ThreadData** parResult);
 +	int          MSN_GetActiveThreads(ThreadData**);
 +	ThreadData*  MSN_GetThreadByConnection(HANDLE hConn);
 +	ThreadData*  MSN_GetThreadByContact(const char* wlid, TInfoType type = SERVER_SWITCHBOARD);
 +	ThreadData*  MSN_GetThreadByChatId(const TCHAR* chatId);
 +	ThreadData*  MSN_GetP2PThreadByContact(const char *wlid);
 +	void         MSN_StartP2PTransferByContact(const char* wlid);
 +	ThreadData*  MSN_GetThreadByPort(WORD wPort);
 +	ThreadData*  MSN_GetUnconnectedThread(const char* wlid, TInfoType type = SERVER_SWITCHBOARD);
 +	ThreadData*  MSN_GetOtherContactThread(ThreadData* thread);
 +	ThreadData*  MSN_GetThreadByTimer(UINT timerId);
 +
 +	ThreadData*  MSN_StartSB(const char* uid, bool& isOffline);
 +	void __cdecl ThreadStub(void* arg);
 +
 +	/////////////////////////////////////////////////////////////////////////////////////////
 +	// MSN message queue support
 +
 +	int         MsgQueue_Add(const char* wlid, int msgType, const char* msg, int msglen, filetransfer* ft = NULL, int flags = 0, STRLIST *cnt = NULL);
 +	const char* MsgQueue_CheckContact(const char* wlid, time_t tsc = 0);
 +	const char* MsgQueue_GetNextRecipient(void);
 +	bool        MsgQueue_GetNext(const char* wlid, MsgQueueEntry& retVal);
 +	int         MsgQueue_NumMsg(const char* wlid);
 +	void        MsgQueue_Clear(const char* wlid = NULL, bool msg = false);
 +
 +	void MsgQueue_Init(void);
 +	void MsgQueue_Uninit(void);
 +
 +	/////////////////////////////////////////////////////////////////////////////////////////
 +	// MSN message reassembly support
 +
 +	OBJLIST<chunkedmsg> msgCache;
 +
 +	int   addCachedMsg(const char* id, const char* msg, const size_t offset,
 +						const size_t portion, const size_t totsz, const bool bychunk);
 +	size_t getCachedMsgSize(const char* id);
 +	bool  getCachedMsg(const int idx, char*& msg, size_t& size);
 +	bool  getCachedMsg(const char* id, char*& msg, size_t& size);
 +	void  clearCachedMsg(int idx = -1);
 +	void  CachedMsg_Uninit(void);
 +
 +	/////////////////////////////////////////////////////////////////////////////////////////
 +	// MSN P2P session support
 +
 +	void  p2p_clearDormantSessions(void);
 +	void  p2p_cancelAllSessions(void);
 +	void  p2p_redirectSessions(const char* wlid);
 +	void  p2p_startSessions(const char* wlid);
 +	void  p2p_clearThreadSessions(MCONTACT hContact, TInfoType mType);
 +
 +	void  p2p_invite(unsigned iAppID, filetransfer* ft, const char *wlid);
 +	void  p2p_inviteDc(filetransfer* ft, const char *wlid);
 +	void  p2p_processMsg(ThreadData* info, char* msgbody, const char* wlid);
 +	void  p2p_processMsgV2(ThreadData* info, char* msgbody, const char* wlid);
 +	void  p2p_processSIP(ThreadData* info, char* msgbody, P2PB_Header* hdr, const char* wlid);
 +
 +	void  p2p_AcceptTransfer(MimeHeaders& tFileInfo, MimeHeaders& tFileInfo2, const char* wlid);
 +	void  p2p_InitDirectTransfer(MimeHeaders& tFileInfo, MimeHeaders& tFileInfo2, const char* wlid);
 +	void  p2p_InitDirectTransfer2(MimeHeaders& tFileInfo, MimeHeaders& tFileInfo2, const char* wlid);
 +	void  p2p_InitFileTransfer(ThreadData* info, MimeHeaders& tFileInfo, MimeHeaders& tFileInfo2, const char* wlid);
 +	void  p2p_pictureTransferFailed(filetransfer* ft);
 +	void  p2p_savePicture2disk(filetransfer* ft);
 +
 +	bool  p2p_createListener(filetransfer* ft, directconnection *dc, MimeHeaders& chdrs);
 +	void  p2p_startConnect(const char* wlid, const char* szCallID, const char* addr, const char* port, bool ipv6);
 +
 +	void  p2p_sendAbortSession(filetransfer* ft);
 +	void  p2p_sendAck(const char *wlid, P2PB_Header* hdrdata);
 +	void  p2p_sendAvatarInit(filetransfer* ft);
 +	void  p2p_sendBye(filetransfer* ft);
 +	void  p2p_sendCancel(filetransfer* ft);
 +	void  p2p_sendMsg(const char *wlid, unsigned appId, P2PB_Header& hdrdata, char* msgbody, size_t msgsz);
 +	void  p2p_sendMsg(ThreadData* info, const char *wlid, unsigned appId, P2PB_Header& hdrdata, char* msgbody, size_t msgsz);
 +	void  p2p_sendNoCall(filetransfer* ft);
 +	void  p2p_sendSlp(int iKind, filetransfer *ft, MimeHeaders &pHeaders, MimeHeaders &pContent, const char *wlid = NULL);
 +	void  p2p_sendRedirect(filetransfer* ft);
 +	void  p2p_sendStatus(filetransfer* ft, long lStatus);
 +
 +	void  p2p_sendFeedStart(filetransfer* ft);
 +	LONG  p2p_sendPortion(filetransfer* ft, ThreadData* T, bool isV2);
 +	void  p2p_sendRecvFileDirectly(ThreadData* info);
 +	bool  p2p_connectTo(ThreadData* info, directconnection *dc);
 +	bool  p2p_listen(ThreadData* info, directconnection *dc);
 +
 +	void  p2p_registerSession(filetransfer* ft);
 +	void  p2p_unregisterSession(filetransfer* ft);
 +	void  p2p_sessionComplete(filetransfer* ft);
 +
 +	void P2pSessions_Uninit(void);
 +
 +	filetransfer*  p2p_getAvatarSession(MCONTACT hContact);
 +	filetransfer*  p2p_getThreadSession(MCONTACT hContact, TInfoType mType);
 +	filetransfer*  p2p_getSessionByID(unsigned id);
 +	filetransfer*  p2p_getSessionByUniqueID(unsigned id);
 +	filetransfer*  p2p_getSessionByCallID(const char* CallID, const char* wlid);
 +
 +	bool     p2p_sessionRegistered(filetransfer* ft);
 +	bool     p2p_isAvatarOnly(MCONTACT hContact);
 +	unsigned p2p_getMsgId(const char* wlid, int inc);
 +	unsigned p2p_getPktNum(const char* wlid);
 +
 +	void  p2p_registerDC(directconnection* ft);
 +	void  p2p_unregisterDC(directconnection* dc);
 +	directconnection*  p2p_getDCByCallID(const char* CallID, const char* wlid);
 +
 +	/////////////////////////////////////////////////////////////////////////////////////////
 +	// MSN MSNFTP file transfer
 +
 +	void msnftp_invite(filetransfer *ft);
 +	void msnftp_sendAcceptReject(filetransfer *ft, bool acc);
 +	void msnftp_startFileSend(ThreadData* info, const char* Invcommand, const char* Invcookie);
 +
 +	int  MSN_HandleMSNFTP(ThreadData *info, char *cmdString);
 +
 +	void __cdecl msnftp_sendFileThread(void* arg);
 +
 +	/////////////////////////////////////////////////////////////////////////////////////////
 +	//	MSN Chat support
 +
 +	int  MSN_ChatInit(ThreadData* info);
 +	void MSN_ChatStart(ThreadData* info);
 +	void MSN_KillChatSession(const TCHAR* id);
 +
 +	MCONTACT MSN_GetChatInernalHandle(MCONTACT hContact);
 +
 +	int __cdecl MSN_GCEventHook(WPARAM wParam, LPARAM lParam);
 +	int __cdecl MSN_GCMenuHook(WPARAM wParam, LPARAM lParam);
 +
 +	/////////////////////////////////////////////////////////////////////////////////////////
 +	//	MSN contact list
 +
 +	int      Lists_Add(int list, int netId, const char* email, MCONTACT hContact = NULL, const char* nick = NULL, const char* invite = NULL);
 +	bool     Lists_IsInList(int list, const char* email);
 +	int      Lists_GetMask(const char* email);
 +	int      Lists_GetNetId(const char* email);
 +	void     Lists_Remove(int list, const char* email);
 +	void     Lists_Populate(void);
 +	void     Lists_Wipe(void);
 +
 +	MsnContact* Lists_Get(const char* email);
 +	MsnContact* Lists_Get(MCONTACT hContact);
 +	MsnContact* Lists_GetNext(int& i);
 +
 +	MsnPlace* Lists_GetPlace(const char* wlid);
 +	MsnPlace* Lists_AddPlace(const char* email, const char* id, unsigned cap1, unsigned cap2);
 +
 +	void     Lists_Uninit(void);
 +
 +	void     AddDelUserContList(const char* email, const int list, const int netId, const bool del);
 +
 +	void     MSN_CreateContList(void);
 +	void     MSN_CleanupLists(void);
 +	void     MSN_FindYahooUser(const char* email);
 +	bool     MSN_RefreshContactList(void);
 +
 +	bool     MSN_IsMyContact(MCONTACT hContact);
 +	bool     MSN_IsMeByContact(MCONTACT hContact, char* szEmail  = NULL);
 +	bool     MSN_AddUser(MCONTACT hContact, const char* email, int netId, int flags, const char *msg = NULL);
 +	void     MSN_AddAuthRequest(const char *email, const char *nick, const char *reason);
 +	void     MSN_SetContactDb(MCONTACT hContact, const char *szEmail);
 +	MCONTACT MSN_HContactFromEmail(const char* msnEmail, const char* msnNick = NULL, bool addIfNeeded = false, bool temporary = false);
 +	MCONTACT AddToListByEmail(const char *email, const char *nick, DWORD flags);
 +
 +	/////////////////////////////////////////////////////////////////////////////////////////
 +	//	MSN server groups
 +
 +	void     MSN_AddGroup(const char* pName, const char* pId, bool init);
 +	void     MSN_DeleteGroup(const char* pId);
 +	void     MSN_FreeGroups(void);
 +	LPCSTR   MSN_GetGroupById(const char* pId);
 +	LPCSTR   MSN_GetGroupByName(const char* pName);
 +	void     MSN_SetGroupName(const char* pId, const char* pName);
 +
 +	void     MSN_MoveContactToGroup(MCONTACT hContact, const char* grpName);
 +	void     MSN_RenameServerGroup(LPCSTR szId, const char* newName);
 +	void     MSN_DeleteServerGroup(LPCSTR szId);
 +	void     MSN_RemoveEmptyGroups(void);
 +	void     MSN_SyncContactToServerGroup(MCONTACT hContact, const char* szContId, ezxml_t cgrp);
 +	void     MSN_UploadServerGroups(char* group);
 +
 +	/////////////////////////////////////////////////////////////////////////////////////////
 +	//	MSN Authentication
 +
 +	int       MSN_GetPassportAuth(void);
 +	char*	    GenerateLoginBlob(char* challenge);
 +	CMStringA HotmailLogin(const char* url);
 +	void	    FreeAuthTokens(void);
 +
 +	/////////////////////////////////////////////////////////////////////////////////////////
 +	//	MSN avatars support
 +
 +	void   AvatarQueue_Init(void);
 +	void   AvatarQueue_Uninit(void);
 +
 +	void   MSN_GetAvatarFileName(MCONTACT hContact, TCHAR* pszDest, size_t cbLen, const TCHAR *ext);
 +	int    MSN_SetMyAvatar(const TCHAR* szFname, void* pData, size_t cbLen);
 +
 +	void   __cdecl MSN_AvatarsThread(void*);
 +
 +	void   pushAvatarRequest(MCONTACT hContact, LPCSTR pszUrl);
 +	bool   loadHttpAvatar(AvatarQueueEntry *p);
 +
 +	/////////////////////////////////////////////////////////////////////////////////////////
 +	//	MSN Mail & Offline messaging support
 +
 +	bool nickChg;
 +
 +	void getMetaData(void);
 +	void getOIMs(ezxml_t xmli);
 +	ezxml_t oimRecvHdr(const char* service, ezxml_t& tbdy, char*& httphdr);
 +
 +	void processMailData(char* mailData);
 +	void sttNotificationMessage(char* msgBody, bool isInitial);
 +	void displayEmailCount(MCONTACT hContact);
 +
 +	/////////////////////////////////////////////////////////////////////////////////////////
 +	//	MSN SOAP Address Book
 +
 +	bool MSN_SharingFindMembership(bool deltas = false, bool allowRecurse = true);
 +	bool MSN_SharingAddDelMember(const char* szEmail, const int listId, const int netId, const char* szMethod, bool allowRecurse = true);
 +	bool MSN_SharingMyProfile(bool allowRecurse = true);
 +	bool MSN_ABAdd(bool allowRecurse = true);
 +	bool MSN_ABFind(const char* szMethod, const char* szGuid, bool deltas = false, bool allowRecurse = true);
 +	bool MSN_ABAddDelContactGroup(const char* szCntId, const char* szGrpId, const char* szMethod, bool allowRecurse = true);
 +	void MSN_ABAddGroup(const char* szGrpName, bool allowRecurse = true);
 +	void MSN_ABRenameGroup(const char* szGrpName, const char* szGrpId, bool allowRecurse = true);
 +	void MSN_ABUpdateNick(const char* szNick, const char* szCntId);
 +	void MSN_ABUpdateAttr(const char* szCntId, const char* szAttr, const char* szValue, bool allowRecurse = true);
 +	bool MSN_ABUpdateProperty(const char* szCntId, const char* propName, const char* propValue, bool allowRecurse = true);
 +	bool MSN_ABAddRemoveContact(const char* szCntId, int netId, bool add, bool allowRecurse = true);
 +	unsigned MSN_ABContactAdd(const char* szEmail, const char* szNick, int netId, const char* szInvite, bool search, bool retry = false, bool allowRecurse = true);
 +	void MSN_ABUpdateDynamicItem(bool allowRecurse = true);
 +
 +	ezxml_t abSoapHdr(const char* service, const char* scenario, ezxml_t& tbdy, char*& httphdr);
 +	char* GetABHost(const char* service, bool isSharing);
 +	void SetAbParam(MCONTACT hContact, const char *name, const char *par);
 +	void UpdateABHost(const char* service, const char* url);
 +	void UpdateABCacheKey(ezxml_t bdy,  bool isSharing);
 +
 +	ezxml_t getSoapResponse(ezxml_t bdy, const char* service);
 +	ezxml_t getSoapFault(ezxml_t bdy, bool err);
 +
 +	char mycid[32];
 +	char mypuid[32];
 +
 +	/////////////////////////////////////////////////////////////////////////////////////////
 +	//	MSN SOAP Roaming Storage
 +
 +	bool MSN_StoreGetProfile(bool allowRecurse = true);
 +	bool MSN_StoreUpdateProfile(const char* szNick, const char* szStatus, bool lock, bool allowRecurse = true);
 +	bool MSN_StoreCreateProfile(bool allowRecurse = true);
 +	bool MSN_StoreShareItem(const char* id, bool allowRecurse = true);
 +	bool MSN_StoreCreateRelationships(bool allowRecurse = true);
 +	bool MSN_StoreDeleteRelationships(bool tile, bool allowRecurse = true);
 +	bool MSN_StoreCreateDocument(const TCHAR *sztName, const char *szMimeType, const char *szPicData, bool allowRecurse = true);
 +	bool MSN_StoreUpdateDocument(const TCHAR *sztName, const char *szMimeType, const char *szPicData, bool allowRecurse = true);
 +	bool MSN_StoreFindDocuments(bool allowRecurse = true);
 +
 +	ezxml_t storeSoapHdr(const char* service, const char* scenario, ezxml_t& tbdy, char*& httphdr);
 +	char* GetStoreHost(const char* service);
 +	void UpdateStoreHost(const char* service, const char* url);
 +	void UpdateStoreCacheKey(ezxml_t bdy);
 +
 +	char proresid[64];
 +	char expresid[64];
 +	char photoid[64];
 +
 +	//////////////////////////////////////////////////////////////////////////////////////
 +
 +	TCHAR* GetContactNameT(MCONTACT hContact);
 +
 +	int    getStringUtf(MCONTACT hContact, const char* name, DBVARIANT* result);
 +	int    getStringUtf(const char* name, DBVARIANT* result);
 +	void   setStringUtf(MCONTACT hContact, const char* name, const char* value);
 +};
 +
 +extern OBJLIST<CMsnProto> g_Instances;
 +
 +#endif
 diff --git a/plugins/!Deprecated/MSN/src/msn_soapab.cpp b/plugins/!Deprecated/MSN/src/msn_soapab.cpp new file mode 100644 index 0000000000..7545a1d7d7 --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_soapab.cpp @@ -0,0 +1,1713 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2007-2012 Boris Krasnovskiy.
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +static const char abReqHdr[] =
 +	"SOAPAction: http://www.msn.com/webservices/AddressBook/%s\r\n";
 +
 +
 +ezxml_t CMsnProto::abSoapHdr(const char* service, const char* scenario, ezxml_t& tbdy, char*& httphdr)
 +{
 +	ezxml_t xmlp = ezxml_new("soap:Envelope");
 +	ezxml_set_attr(xmlp, "xmlns:soap", "http://schemas.xmlsoap.org/soap/envelope/");
 +	ezxml_set_attr(xmlp, "xmlns:xsi",  "http://www.w3.org/2001/XMLSchema-instance");
 +	ezxml_set_attr(xmlp, "xmlns:xsd",  "http://www.w3.org/2001/XMLSchema");
 +	ezxml_set_attr(xmlp, "xmlns:soapenc", "http://schemas.xmlsoap.org/soap/encoding/");
 +
 +	ezxml_t hdr = ezxml_add_child(xmlp, "soap:Header", 0);
 +	ezxml_t apphdr = ezxml_add_child(hdr, "ABApplicationHeader", 0);
 +	ezxml_set_attr(apphdr, "xmlns", "http://www.msn.com/webservices/AddressBook");
 +	ezxml_t node = ezxml_add_child(apphdr, "ApplicationId", 0);
 +	ezxml_set_txt(node, msnAppID);
 +	node = ezxml_add_child(apphdr, "IsMigration", 0);
 +	ezxml_set_txt(node, abchMigrated ? "false" : "true");
 +	node = ezxml_add_child(apphdr, "PartnerScenario", 0);
 +	ezxml_set_txt(node, scenario);
 +
 +	char *cacheKey = strstr(service, "Member") ? sharingCacheKey : abCacheKey;
 +	if (cacheKey)
 +	{
 +		node = ezxml_add_child(apphdr, "CacheKey", 0);
 +		ezxml_set_txt(node, cacheKey);
 +	}
 +
 +	ezxml_t authhdr = ezxml_add_child(hdr, "ABAuthHeader", 0);
 +	ezxml_set_attr(authhdr, "xmlns", "http://www.msn.com/webservices/AddressBook");
 +	node = ezxml_add_child(authhdr, "ManagedGroupRequest", 0);
 +	ezxml_set_txt(node, "false");
 +	node = ezxml_add_child(authhdr, "TicketToken", 0);
 +	if (authContactToken) ezxml_set_txt(node, authContactToken);
 +
 +	ezxml_t bdy = ezxml_add_child(xmlp, "soap:Body", 0);
 +
 +	tbdy = ezxml_add_child(bdy, service, 0);
 +	ezxml_set_attr(tbdy, "xmlns", "http://www.msn.com/webservices/AddressBook");
 +
 +	if (strstr(service, "Member") == NULL && strcmp(service, "ABAdd") != 0 && strcmp(service, "ABFindContactsPaged"))
 +	{
 +		ezxml_t node = ezxml_add_child(tbdy, "abId", 0);
 +		ezxml_set_txt(node, "00000000-0000-0000-0000-000000000000");
 +	}
 +
 +	size_t hdrsz = strlen(service) + sizeof(abReqHdr) + 20;
 +	httphdr = (char*)mir_alloc(hdrsz);
 +
 +	mir_snprintf(httphdr, hdrsz, abReqHdr, service);
 +
 +	return xmlp;
 +}
 +
 +
 +ezxml_t CMsnProto::getSoapResponse(ezxml_t bdy, const char* service)
 +{
 +	char resp1[40], resp2[40];
 +	mir_snprintf(resp1, sizeof(resp1), "%sResponse", service);
 +	mir_snprintf(resp2, sizeof(resp2), "%sResult", service);
 +
 +	ezxml_t res = ezxml_get(bdy, "soap:Body", 0, resp1, 0, resp2, -1);
 +	if (res == NULL)
 +		res = ezxml_get(bdy, "s:Body", 0, resp1, 0, resp2, -1);
 +
 +	return res;
 +}
 +
 +ezxml_t CMsnProto::getSoapFault(ezxml_t bdy, bool err)
 +{
 +	ezxml_t flt = ezxml_get(bdy, "soap:Body", 0, "soap:Fault", -1);
 +	return err ? ezxml_get(flt, "detail", 0, "errorcode", -1) : flt;
 +}
 +
 +void CMsnProto::UpdateABHost(const char* service, const char* url)
 +{
 +	char hostname[128];
 +	mir_snprintf(hostname, sizeof(hostname), "ABHost-%s", service);
 +
 +	if (url)
 +		setString(hostname, url);
 +	else
 +		delSetting(hostname);
 +}
 +
 +void CMsnProto::UpdateABCacheKey(ezxml_t bdy,  bool isSharing)
 +{
 +	ezxml_t hdr = ezxml_get(bdy, "soap:Header", 0, "ServiceHeader", -1);
 +	bool changed = strcmp(ezxml_txt(ezxml_child(hdr, "CacheKeyChanged")), "true") == 0;
 +	if (changed)
 +	{
 +		replaceStr(isSharing ? sharingCacheKey : abCacheKey, ezxml_txt(ezxml_child(hdr, "CacheKey")));
 +	}
 +}
 +
 +char* CMsnProto::GetABHost(const char* service, bool isSharing)
 +{
 +	char hostname[128];
 +	mir_snprintf(hostname, sizeof(hostname), "ABHost-%s", service);
 +
 +	char* host = (char*)mir_alloc(256);
 +	if (db_get_static(NULL, m_szModuleName, hostname, host, 256))
 +	{
 +		mir_snprintf(host, 256, "https://byrdr.omega.contacts.msn.com/abservice/%s.asmx",
 +			isSharing ? "SharingService" : "abservice");
 +	}
 +
 +	return host;
 +}
 +
 +/*
 +ezxml_t CMsnProto::PerformSoapReq(const char *service, bool isSharing, char *szData, const char* hdrs, unsigned& status)
 +{
 +	unsigned status = 0;
 +	char *abUrl = NULL, *tResult = NULL;
 +
 +	for (int k = 4; --k;)
 +	{
 +		mir_free(abUrl);
 +		abUrl = GetABHost(service, true);
 +		tResult = getSslResult(&abUrl, szData, hdrs, status);
 +		if (tResult == NULL) UpdateABHost(service, NULL);
 +		else break;
 +	}
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	if (tResult != NULL)
 +	{
 +		UpdateABHost(service, abUrl);
 +		ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +		if (!xmlm || !ezxml_child(xmlm, "soap:Body"))
 +		{
 +			mir_free(tResult);
 +			ezxml_free(xmlm);
 +			UpdateABHost("service", NULL);
 +			PerformSoapReq(service, isSharing, szData, hdrs, status);
 +		}
 +		else if (status == 500)
 +		{
 +			const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +			if (!szErr[0])
 +			{
 +				mir_free(tResult);
 +				ezxml_free(xmlm);
 +				UpdateABHost("service", NULL);
 +				PerformSoapReq(service, isSharing, szData, hdrs, status);
 +			}
 +		}
 +	}
 +	mir_free(abUrl);
 +}
 +*/
 +
 +
 +bool CMsnProto::MSN_ABAdd(bool allowRecurse)
 +{
 +	char* reqHdr;
 +	ezxml_t tbdy, node;
 +	ezxml_t xmlp = abSoapHdr("ABAdd", "Timer", tbdy, reqHdr);
 +
 +	ezxml_t abinf = ezxml_add_child(tbdy, "abInfo", 0);
 +	ezxml_add_child(abinf, "name", 0);
 +	node = ezxml_add_child(abinf, "ownerPuid", 0);
 +	ezxml_set_txt(node, "0");
 +	node = ezxml_add_child(abinf, "ownerEmail", 0);
 +	ezxml_set_txt(node, MyOptions.szEmail);
 +	node = ezxml_add_child(abinf, "fDefault", 0);
 +	ezxml_set_txt(node, "true");
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +	ezxml_free(xmlp);
 +
 +	unsigned status = 0;
 +	char *abUrl = NULL, *tResult = NULL;
 +
 +	for (int k = 4; --k;)
 +	{
 +		mir_free(abUrl);
 +		abUrl = GetABHost("ABAdd", false);
 +		tResult = getSslResult(&abUrl, szData, reqHdr, status);
 +		if (tResult == NULL) UpdateABHost("ABAdd", NULL);
 +		else break;
 +	}
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	if (tResult != NULL)
 +	{
 +		UpdateABHost("ABAdd", abUrl);
 +
 +		ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +		if (status == 500)
 +		{
 +			const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +			if (strcmp(szErr, "PassportAuthFail") == 0 && allowRecurse)
 +			{
 +				MSN_GetPassportAuth();
 +				status = MSN_ABAdd(false) ? 200 : 500;
 +			}
 +		}
 +		ezxml_free(xmlm);
 +	}
 +
 +	mir_free(tResult);
 +	mir_free(abUrl);
 +
 +	return status == 200;
 +}
 +
 +
 +bool CMsnProto::MSN_SharingFindMembership(bool deltas, bool allowRecurse)
 +{
 +	char* reqHdr;
 +	ezxml_t tbdy;
 +	ezxml_t xmlp = abSoapHdr("FindMembership", "Initial", tbdy, reqHdr);
 +
 +	ezxml_t svcflt = ezxml_add_child(tbdy, "serviceFilter", 0);
 +	ezxml_t tps = ezxml_add_child(svcflt, "Types", 0);
 +	ezxml_t node = ezxml_add_child(tps, "ServiceType", 0);
 +	ezxml_set_txt(node, "Messenger");
 +/*
 +	node = ezxml_add_child(tps, "ServiceType", 0);
 +	ezxml_set_txt(node, "Invitation");
 +	node = ezxml_add_child(tps, "ServiceType", 0);
 +	ezxml_set_txt(node, "SocialNetwork");
 +	node = ezxml_add_child(tps, "ServiceType", 0);
 +	ezxml_set_txt(node, "Space");
 +	node = ezxml_add_child(tps, "ServiceType", 0);
 +	ezxml_set_txt(node, "Profile");
 +	node = ezxml_add_child(tps, "ServiceType", 0);
 +	ezxml_set_txt(node, "Folder");
 +	node = ezxml_add_child(tps, "ServiceType", 0);
 +	ezxml_set_txt(node, "OfficeLiveWebNotification");
 +*/
 +	const char *szLastChange = NULL;
 +	if (deltas)
 +	{
 +		DBVARIANT dbv;
 +		if (!getString("SharingLastChange", &dbv) && dbv.pszVal[0])
 +		{
 +			szLastChange = NEWSTR_ALLOCA(dbv.pszVal);
 +			db_free(&dbv);
 +		}
 +		deltas &= (szLastChange != NULL);
 +	}
 +
 +	node = ezxml_add_child(tbdy, "View", 0);
 +	ezxml_set_txt(node, "Full");
 +	node = ezxml_add_child(tbdy, "deltasOnly", 0);
 +	ezxml_set_txt(node, deltas ? "true" : "false");
 +	node = ezxml_add_child(tbdy, "lastChange", 0);
 +	ezxml_set_txt(node, deltas ? szLastChange : "0001-01-01T00:00:00.0000000-08:00");
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +
 +	ezxml_free(xmlp);
 +
 +	unsigned status = 0;
 +	char *abUrl = NULL, *tResult = NULL;
 +
 +	for (int k = 4; --k;)
 +	{
 +		mir_free(abUrl);
 +		abUrl = GetABHost("FindMembership", true);
 +		tResult = getSslResult(&abUrl, szData, reqHdr, status);
 +		if (tResult == NULL) UpdateABHost("FindMembership", NULL);
 +		else break;
 +	}
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	if (tResult != NULL)
 +	{
 +		ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +		if (status == 200)
 +		{
 +			UpdateABCacheKey(xmlm, true);
 +			ezxml_t body = getSoapResponse(xmlm, "FindMembership");
 +			ezxml_t svcs = ezxml_get(body, "Services", 0, "Service", -1);
 +
 +			UpdateABHost("FindMembership", body ? abUrl : NULL);
 +
 +			while (svcs != NULL)
 +			{
 +				const char* szType = ezxml_txt(ezxml_get(svcs, "Info", 0, "Handle", 0, "Type", -1));
 +				if (_stricmp(szType, "Messenger") == 0) break;
 +				svcs = ezxml_next(svcs);
 +			}
 +
 +			const char* szLastChange = ezxml_txt(ezxml_child(svcs, "LastChange"));
 +			if (szLastChange[0]) setString("SharingLastChange", szLastChange);
 +
 +			ezxml_t mems = ezxml_get(svcs, "Memberships", 0, "Membership", -1);
 +
 +			while (mems != NULL)
 +			{
 +				const char* szRole = ezxml_txt(ezxml_child(mems, "MemberRole"));
 +
 +				int lstId = 0;
 +				if (strcmp(szRole, "Allow") == 0)			lstId = LIST_AL;
 +				else if (strcmp(szRole, "Block") == 0)		lstId = LIST_BL;
 +				else if (strcmp(szRole, "Reverse") == 0)	lstId = LIST_RL;
 +				else if (strcmp(szRole, "Pending") == 0)	lstId = LIST_PL;
 +
 +				ezxml_t memb = ezxml_get(mems, "Members", 0, "Member", -1);
 +				while (memb != NULL)
 +				{
 +					bool deleted = strcmp(ezxml_txt(ezxml_child(memb, "Deleted")), "true") == 0;
 +					const char* szType = ezxml_txt(ezxml_child(memb, "Type"));
 +					if (strcmp(szType, "Passport") == 0)
 +					{
 +						const char* szInvite = NULL;
 +						const char* szEmail = ezxml_txt(ezxml_child(memb, "PassportName"));
 +						const char* szNick = ezxml_txt(ezxml_child(memb, "DisplayName")); if (!szNick[0]) szNick = NULL;
 +						ezxml_t anot = ezxml_get(memb, "Annotations", 0, "Annotation", -1);
 +						while (anot != NULL)
 +						{
 +							if (strcmp(ezxml_txt(ezxml_child(anot, "Name")), "MSN.IM.InviteMessage") == 0)
 +							{
 +								szInvite = ezxml_txt(ezxml_child(anot, "Value"));
 +							}
 +							anot = ezxml_next(anot);
 +						}
 +						if (!deleted) Lists_Add(lstId, NETID_MSN, szEmail, NULL, szNick, szInvite); else Lists_Remove(lstId, szEmail);
 +					}
 +					else if (strcmp(szType, "Phone") == 0)
 +					{
 +						const char* szEmail = ezxml_txt(ezxml_child(memb, "PhoneNumber"));
 +						char email[128];
 +						mir_snprintf(email, sizeof(email), "tel:%s", szEmail);
 +						if (!deleted) Lists_Add(lstId, NETID_MOB, email); else Lists_Remove(lstId, szEmail);
 +					}
 +					else if (strcmp(szType, "Email") == 0)
 +					{
 +						const char* szInvite = NULL;
 +						const char* szEmail = ezxml_txt(ezxml_child(memb, "Email"));
 +						const char* szNick = ezxml_txt(ezxml_child(memb, "DisplayName")); if (!szNick[0]) szNick = NULL;
 +						int netId = strstr(szEmail, "@yahoo.com") ? NETID_YAHOO : NETID_LCS;
 +						ezxml_t anot = ezxml_get(memb, "Annotations", 0, "Annotation", -1);
 +						while (anot != NULL)
 +						{
 +							if (strcmp(ezxml_txt(ezxml_child(anot, "Name")), "MSN.IM.BuddyType") == 0)
 +							{
 +								netId = atol(ezxml_txt(ezxml_child(anot, "Value")));
 +							}
 +							else if (strcmp(ezxml_txt(ezxml_child(anot, "Name")), "MSN.IM.InviteMessage") == 0)
 +							{
 +								szInvite = ezxml_txt(ezxml_child(anot, "Value"));
 +							}
 +							anot = ezxml_next(anot);
 +						}
 +
 +						if (!deleted) Lists_Add(lstId, netId, szEmail, NULL, szNick, szInvite);  else Lists_Remove(lstId, szEmail);
 +					}
 +					memb = ezxml_next(memb);
 +				}
 +				mems = ezxml_next(mems);
 +			}
 +		}
 +		else if (status == 500)
 +		{
 +			const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +			if (strcmp(szErr, "ABDoesNotExist") == 0)
 +			{
 +				MSN_ABAdd();
 +				status = 200;
 +			}
 +			else if (strcmp(szErr, "PassportAuthFail") == 0 && allowRecurse)
 +			{
 +				MSN_GetPassportAuth();
 +				status = MSN_SharingFindMembership(deltas, false) ? 200 : 500;
 +			}
 +		}
 +		else
 +			UpdateABHost("FindMembership", NULL);
 +
 +		ezxml_free(xmlm);
 +	}
 +	mir_free(tResult);
 +	mir_free(abUrl);
 +
 +	return status == 200;
 +}
 +
 +// AddMember, DeleteMember
 +bool CMsnProto::MSN_SharingAddDelMember(const char* szEmail, const int listId, const int netId, const char* szMethod, bool allowRecurse)
 +{
 +	const char* szRole;
 +	if (listId & LIST_AL) szRole = "Allow";
 +	else if (listId & LIST_BL) szRole = "Block";
 +	else if (listId & LIST_PL) szRole = "Pending";
 +	else if (listId & LIST_RL) szRole = "Reverse";
 +	else return false;
 +
 +	char* reqHdr;
 +	ezxml_t tbdy;
 +	ezxml_t xmlp = abSoapHdr(szMethod, "BlockUnblock", tbdy, reqHdr);
 +
 +	ezxml_t svchnd = ezxml_add_child(tbdy, "serviceHandle", 0);
 +	ezxml_t node = ezxml_add_child(svchnd, "Id", 0);
 +	ezxml_set_txt(node, "0");
 +	node = ezxml_add_child(svchnd, "Type", 0);
 +	ezxml_set_txt(node, "Messenger");
 +	node = ezxml_add_child(svchnd, "ForeignId", 0);
 +//	ezxml_set_txt(node, "");
 +
 +	const char* szMemberName = "";
 +	const char* szTypeName = "";
 +	const char* szAccIdName = "";
 +
 +	switch (netId)
 +	{
 +		case 1:
 +			szMemberName = "PassportMember";
 +			szTypeName = "Passport";
 +			szAccIdName = "PassportName";
 +			break;
 +
 +		case 4:
 +			szMemberName = "PhoneMember";
 +			szTypeName = "Phone";
 +			szAccIdName = "PhoneNumber";
 +			szEmail = strchr(szEmail, ':') + 1;
 +			break;
 +
 +		case 2:
 +		case 32:
 +			szMemberName = "EmailMember";
 +			szTypeName = "Email";
 +			szAccIdName = "Email";
 +			break;
 +	}
 +
 +	ezxml_t memb = ezxml_add_child(tbdy, "memberships", 0);
 +	memb = ezxml_add_child(memb, "Membership", 0);
 +	node = ezxml_add_child(memb, "MemberRole", 0);
 +	ezxml_set_txt(node, szRole);
 +	memb = ezxml_add_child(memb, "Members", 0);
 +	memb = ezxml_add_child(memb, "Member", 0);
 +	ezxml_set_attr(memb, "xsi:type",  szMemberName);
 +	ezxml_set_attr(memb, "xmlns:xsi",  "http://www.w3.org/2001/XMLSchema-instance");
 +	node = ezxml_add_child(memb, "Type", 0);
 +	ezxml_set_txt(node, szTypeName);
 +	node = ezxml_add_child(memb, "State", 0);
 +	ezxml_set_txt(node, "Accepted");
 +	node = ezxml_add_child(memb, szAccIdName, 0);
 +	ezxml_set_txt(node, szEmail);
 +
 +	char buf[64];
 +	if ((netId == NETID_LCS || netId == NETID_YAHOO) && strcmp(szMethod, "DeleteMember") != 0)
 +	{
 +		node = ezxml_add_child(memb, "Annotations", 0);
 +		ezxml_t anot = ezxml_add_child(node, "Annotation", 0);
 +		node = ezxml_add_child(anot, "Name", 0);
 +		ezxml_set_txt(node, "MSN.IM.BuddyType");
 +		node = ezxml_add_child(anot, "Value", 0);
 +
 +		mir_snprintf(buf, sizeof(buf), "%02d:", netId);
 +		ezxml_set_txt(node, buf);
 +	}
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +
 +	ezxml_free(xmlp);
 +
 +	unsigned status;
 +	char *abUrl = NULL, *tResult;
 +
 +	for (int k = 4; --k;)
 +	{
 +		mir_free(abUrl);
 +		abUrl = GetABHost(szMethod, true);
 +		tResult = getSslResult(&abUrl, szData, reqHdr, status);
 +		if (tResult == NULL) UpdateABHost(szMethod, NULL);
 +		else break;
 +	}
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	if (tResult != NULL)
 +	{
 +		UpdateABHost(szMethod, abUrl);
 +		ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +		UpdateABCacheKey(xmlm, true);
 +		if (status == 500)
 +		{
 +			const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +			if (strcmp(szErr, "PassportAuthFail") == 0 && allowRecurse)
 +			{
 +				MSN_GetPassportAuth();
 +				status = MSN_SharingAddDelMember(szEmail, listId, netId, szMethod, false) ? 200 : 500;
 +			}
 +		}
 +		ezxml_free(xmlm);
 +	}
 +
 +	mir_free(tResult);
 +	mir_free(abUrl);
 +
 +	return status == 200;
 +}
 +
 +bool CMsnProto::MSN_SharingMyProfile(bool allowRecurse)
 +{
 +	char* reqHdr;
 +	ezxml_t tbdy;
 +	ezxml_t xmlp = abSoapHdr("AddMember", "RoamingSeed", tbdy, reqHdr);
 +
 +	ezxml_t svchnd = ezxml_add_child(tbdy, "serviceHandle", 0);
 +	ezxml_t node = ezxml_add_child(svchnd, "Id", 0);
 +	ezxml_set_txt(node, "0");
 +	node = ezxml_add_child(svchnd, "Type", 0);
 +	ezxml_set_txt(node, "Profile");
 +	node = ezxml_add_child(svchnd, "ForeignId", 0);
 +	ezxml_set_txt(node, "MyProfile");
 +
 +	ezxml_t memb = ezxml_add_child(tbdy, "memberships", 0);
 +	memb = ezxml_add_child(memb, "Membership", 0);
 +	node = ezxml_add_child(memb, "MemberRole", 0);
 +	ezxml_set_txt(node, "ProfileExpression");
 +	memb = ezxml_add_child(memb, "Members", 0);
 +	memb = ezxml_add_child(memb, "Member", 0);
 +	ezxml_set_attr(memb, "xsi:type", "RoleMember");
 +	ezxml_set_attr(memb, "xmlns:xsi",  "http://www.w3.org/2001/XMLSchema-instance");
 +	node = ezxml_add_child(memb, "Type", 0);
 +	ezxml_set_txt(node, "Role");
 +	node = ezxml_add_child(memb, "State", 0);
 +	ezxml_set_txt(node, "Accepted");
 +	node = ezxml_add_child(memb, "Id", 0);
 +	ezxml_set_txt(node, "Allow");
 +
 +	ezxml_t svcdef = ezxml_add_child(memb, "DefiningService", 0);
 +	node = ezxml_add_child(svcdef, "Id", 0);
 +	ezxml_set_txt(node, "0");
 +	node = ezxml_add_child(svcdef, "Type", 0);
 +	ezxml_set_txt(node, "Messenger");
 +	node = ezxml_add_child(svcdef, "ForeignId", 0);
 +
 +	node = ezxml_add_child(memb, "MaxRoleRecursionDepth", 0);
 +	ezxml_set_txt(node, "0");
 +
 +	node = ezxml_add_child(memb, "MaxDegreesSeparationDepth", 0);
 +	ezxml_set_txt(node, "0");
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +
 +	ezxml_free(xmlp);
 +
 +	unsigned status = 0;
 +	char *abUrl = NULL, *tResult = NULL;
 +
 +	for (int k = 4; --k;)
 +	{
 +		mir_free(abUrl);
 +		abUrl = GetABHost("AddMember", true);
 +		tResult = getSslResult(&abUrl, szData, reqHdr, status);
 +		if (tResult == NULL) UpdateABHost("AddMember", NULL);
 +		else break;
 +	}
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +	if (status == 500)
 +	{
 +		const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +		if (strcmp(szErr, "PassportAuthFail") == 0 && allowRecurse)
 +		{
 +			MSN_GetPassportAuth();
 +			MSN_SharingMyProfile(false);
 +		}
 +	}
 +	ezxml_free(xmlm);
 +
 +	mir_free(tResult);
 +	mir_free(abUrl);
 +
 +	return status == 200;
 +}
 +
 +
 +void CMsnProto::SetAbParam(MCONTACT hContact, const char *name, const char *par)
 +{
 +	if (*par) setStringUtf(hContact, name, (char*)par);
 +//	else delSetting(hContact, "FirstName");
 +}
 +
 +//		"ABFindAll", "ABFindByContacts", "ABFindContactsPaged"
 +bool CMsnProto::MSN_ABFind(const char* szMethod, const char* szGuid, bool deltas, bool allowRecurse)
 +{
 +	char* reqHdr;
 +	ezxml_t tbdy;
 +	ezxml_t xmlp = abSoapHdr(szMethod, "Initial", tbdy, reqHdr);
 +
 +
 +	const char *szLastChange = NULL;
 +	if (deltas)
 +	{
 +		DBVARIANT dbv;
 +		if (!getString("ABFullLastChange", &dbv) && dbv.pszVal[0])
 +		{
 +			szLastChange = NEWSTR_ALLOCA(dbv.pszVal);
 +			db_free(&dbv);
 +		}
 +		deltas &= (szLastChange != NULL);
 +	}
 +	const char *szDynLastChange = NULL;
 +	if (deltas)
 +	{
 +		DBVARIANT dbv;
 +		if (!getString("ABFullDynLastChange", &dbv) && dbv.pszVal[0])
 +		{
 +			szDynLastChange = NEWSTR_ALLOCA(dbv.pszVal);
 +			db_free(&dbv);
 +		}
 +		deltas &= (szDynLastChange != NULL);
 +	}
 +
 +	const char *szGroups, *szContacts, *szLastChangeStr;
 +	if (strcmp(szMethod, "ABFindContactsPaged"))
 +	{
 +		ezxml_t node = ezxml_add_child(tbdy, "abView", 0);
 +		ezxml_set_txt(node, "Full");
 +		node = ezxml_add_child(tbdy, "deltasOnly", 0);
 +		ezxml_set_txt(node, deltas ? "true" : "false");
 +		node = ezxml_add_child(tbdy, "dynamicItemView", 0);
 +		ezxml_set_txt(node, "Gleam");
 +		if (deltas)
 +		{
 +			node = ezxml_add_child(tbdy, "lastChange", 0);
 +			ezxml_set_txt(node, szLastChange);
 +			node = ezxml_add_child(tbdy, "dynamicItemLastChange", 0);
 +			ezxml_set_txt(node, szDynLastChange);
 +		}
 +
 +		if (szGuid)
 +		{
 +			node = ezxml_add_child(tbdy, "contactIds", 0);
 +			node = ezxml_add_child(node, "guid", 0);
 +			ezxml_set_txt(node, szGuid);
 +		}
 +		szGroups = "groups";
 +		szContacts = "contacts";
 +		szLastChangeStr = "LastChange";
 +	}
 +	else
 +	{
 +		ezxml_t node = ezxml_add_child(tbdy, "abView", 0);
 +		ezxml_set_txt(node, "MessengerClient8");
 +		node = ezxml_add_child(tbdy, "extendedContent", 0);
 +		ezxml_set_txt(node, "AB AllGroups CircleResult");
 +		ezxml_t filt = ezxml_add_child(tbdy, "filterOptions", 0);
 +
 +		node = ezxml_add_child(filt, "DeltasOnly", 0);
 +		ezxml_set_txt(node, deltas ? "true" : "false");
 +		if (deltas)
 +		{
 +			node = ezxml_add_child(filt, "LastChanged", 0);
 +			ezxml_set_txt(node, szLastChange);
 +		}
 + 		node = ezxml_add_child(filt, "ContactFilter", 0);
 +		node = ezxml_add_child(node, "IncludeHiddenContacts", 0);
 +		ezxml_set_txt(node, "true");
 +
 +		szGroups = "Groups";
 +		szContacts = "Contacts";
 +		szLastChangeStr = "lastChange";
 +	}
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +	ezxml_free(xmlp);
 +
 +	unsigned status = 0;
 +	char *abUrl = NULL, *tResult = NULL;
 +
 +	for (int k = 4; --k;)
 +	{
 +		mir_free(abUrl);
 +		abUrl = GetABHost(szMethod, false);
 +		tResult = getSslResult(&abUrl, szData, reqHdr, status);
 +		if (tResult == NULL) UpdateABHost(szMethod, NULL);
 +		else break;
 +	}
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	if (tResult != NULL)
 +	{
 +		ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +		UpdateABCacheKey(xmlm, false);
 +
 +		if (status == 200)
 +		{
 +			ezxml_t body = getSoapResponse(xmlm, szMethod);
 +			UpdateABHost(szMethod, body ? abUrl : NULL);
 +
 +			ezxml_t ab = ezxml_child(body, "Ab");
 +			if (strcmp(szMethod, "ABFindByContacts"))
 +			{
 +				const char* szLastChange = ezxml_txt(ezxml_child(ab, szLastChangeStr));
 +				if (szLastChange[0]) setString("ABFullLastChange", szLastChange);
 +				szLastChange = ezxml_txt(ezxml_child(ab, "DynamicItemLastChanged"));
 +				if (szLastChange[0]) setString("ABFullDynLastChange", szLastChange);
 +			}
 +
 +			ezxml_t abinf = ezxml_child(ab, "abInfo");
 +			mir_snprintf(mycid,  sizeof(mycid), "%s", ezxml_txt(ezxml_child(abinf, "OwnerCID")));
 +			mir_snprintf(mypuid, sizeof(mycid), "%s", ezxml_txt(ezxml_child(abinf, "ownerPuid")));
 +
 +			if (MyOptions.ManageServer)
 +			{
 +				ezxml_t grp = ezxml_get(body, szGroups, 0, "Group", -1);
 +				while (grp != NULL)
 +				{
 +					const char* szGrpId = ezxml_txt(ezxml_child(grp, "groupId"));
 +					const char* szGrpName = ezxml_txt(ezxml_get(grp, "groupInfo", 0, "name", -1));
 +					MSN_AddGroup(szGrpName, szGrpId, true);
 +
 +					grp = ezxml_next(grp);
 +				}
 +			}
 +
 +			for (ezxml_t cont = ezxml_get(body, szContacts, 0, "Contact", -1); cont != NULL; cont = ezxml_next(cont))
 +			{
 +				const char* szContId = ezxml_txt(ezxml_child(cont, "contactId"));
 +
 +				ezxml_t contInf = ezxml_child(cont, "contactInfo");
 +				const char* szType = ezxml_txt(ezxml_child(contInf, "contactType"));
 +
 +				if (strcmp(szType, "Me") != 0)
 +				{
 +					char email[128];
 +
 +					const char* szEmail = ezxml_txt(ezxml_child(contInf, "passportName"));
 +					const char* szMsgUsr = ezxml_txt(ezxml_child(contInf, "isMessengerUser"));
 +
 +					int netId = NETID_UNKNOWN;
 +					if (strcmp(szMsgUsr, "true") == 0) netId = NETID_MSN;
 +
 +					if (szEmail[0] == '\0')
 +					{
 +						ezxml_t eml = ezxml_get(contInf, "emails", 0, "ContactEmail", -1);
 +						while (eml != NULL)
 +						{
 +							szMsgUsr = ezxml_txt(ezxml_child(eml, "isMessengerEnabled"));
 +							if (strcmp(szMsgUsr, "true") == 0)
 +							{
 +								szEmail = ezxml_txt(ezxml_child(eml, "email"));
 +								const char* szCntType = ezxml_txt(ezxml_child(eml, "contactEmailType"));
 +								if (strcmp(szCntType, "Messenger2") == 0)
 +									netId = NETID_YAHOO;
 +								else if (strcmp(szCntType, "Messenger3") == 0)
 +									netId = NETID_LCS;
 +								break;
 +							}
 +							eml = ezxml_next(eml);
 +						}
 +
 +						if (netId == NETID_UNKNOWN)
 +						{
 +							ezxml_t phn = ezxml_get(contInf, "phones", 0, "ContactPhone", -1);
 +							while (phn != NULL)
 +							{
 +								szMsgUsr = ezxml_txt(ezxml_child(phn, "isMessengerEnabled"));
 +								if (strcmp(szMsgUsr, "true") == 0)
 +								{
 +									szEmail = ezxml_txt(ezxml_child(phn, "number"));
 +									mir_snprintf(email, sizeof(email), "tel:%s", szEmail);
 +									szEmail = email;
 +									netId = NETID_MOB;
 +									break;
 +								}
 +								phn = ezxml_next(phn);
 +							}
 +						}
 +					}
 +
 +					if (netId == NETID_UNKNOWN || szEmail[0] == 0) continue;
 +
 +					Lists_Add(LIST_FL, netId, szEmail);
 +					const char *szTmp;
 +
 +	//				Depricated in WLM 8.1
 +	//				const char* szNick  = ezxml_txt(ezxml_child(contInf, "displayName"));
 +	//				if (*szNick == '\0') szNick = szEmail;
 +					MCONTACT hContact = MSN_HContactFromEmail(szEmail, szEmail, true, false);
 +	//				setStringUtf(hContact, "Nick", (char*)szNick);
 +
 +					if (MyOptions.ManageServer)
 +					{
 +						ezxml_t grpid = ezxml_child(contInf, "groupIds");
 +						if (!deltas || grpid)
 +						{
 +							ezxml_t grps = ezxml_child(grpid, "guid");
 +							MSN_SyncContactToServerGroup(hContact, szContId, grps);
 +						}
 +					}
 +
 +					const char* szNick = NULL;
 +					ezxml_t anot = ezxml_get(contInf, "annotations", 0, "Annotation", -1);
 +					while (anot != NULL)
 +					{
 +						if (strcmp(ezxml_txt(ezxml_child(anot, "Name")), "AB.NickName") == 0)
 +						{
 +							szNick = ezxml_txt(ezxml_child(anot, "Value"));
 +							db_set_utf(hContact, "CList", "MyHandle", szNick);
 +						}
 +						if (strcmp(ezxml_txt(ezxml_child(anot, "Name")), "AB.JobTitle") == 0)
 +						{
 +							szTmp = ezxml_txt(ezxml_child(anot, "Value"));
 +							SetAbParam(hContact, "CompanyPosition", szTmp);
 +						}
 +						anot = ezxml_next(anot);
 +					}
 +					if (szNick == NULL)
 +						db_unset(hContact, "CList", "MyHandle");
 +
 +					setString(hContact, "ID", szContId);
 +
 +					switch (netId)
 +					{
 +					case NETID_YAHOO:
 +						setString(hContact, "Transport", "YAHOO");
 +						break;
 +
 +					case NETID_LCS:
 +						setString(hContact, "Transport", "LCS");
 +						break;
 +
 +					default:
 +						delSetting(hContact, "Transport");
 +					}
 +
 +					szTmp = ezxml_txt(ezxml_child(contInf, "CID"));
 +					SetAbParam(hContact, "CID", szTmp);
 +
 +					szTmp  = ezxml_txt(ezxml_child(contInf, "IsNotMobileVisible"));
 +					setByte(hContact, "MobileAllowed", strcmp(szTmp, "true") != 0);
 +
 +					szTmp = ezxml_txt(ezxml_child(contInf, "isMobileIMEnabled"));
 +					setByte(hContact, "MobileEnabled", strcmp(szTmp, "true") == 0);
 +
 +					szTmp = ezxml_txt(ezxml_child(contInf, "firstName"));
 +					SetAbParam(hContact, "FirstName", szTmp);
 +
 +					szTmp = ezxml_txt(ezxml_child(contInf, "lastName"));
 +					SetAbParam(hContact, "LastName", szTmp);
 +
 +					szTmp = ezxml_txt(ezxml_child(contInf, "birthdate"));
 +					char *szPtr;
 +					if (strtol(szTmp, &szPtr, 10) > 1)
 +					{
 +						setWord(hContact, "BirthYear", (WORD)strtol(szTmp, &szPtr, 10));
 +						setByte(hContact, "BirthMonth", (BYTE)strtol(szPtr+1, &szPtr, 10));
 +						setByte(hContact, "BirthDay", (BYTE)strtol(szPtr+1, &szPtr, 10));
 +					}
 +					else
 +					{
 +	//					delSetting(hContact, "BirthYear");
 +	//					delSetting(hContact, "BirthMonth");
 +	//					delSetting(hContact, "BirthDay");
 +					}
 +
 +					szTmp = ezxml_txt(ezxml_child(contInf, "comment"));
 +					if (*szTmp) db_set_s(hContact, "UserInfo", "MyNotes", szTmp);
 +	//				else db_unset(hContact, "UserInfo", "MyNotes");
 +
 +					ezxml_t loc = ezxml_get(contInf, "locations", 0, "ContactLocation", -1);
 +					while (loc != NULL)
 +					{
 +						const char* szCntType = ezxml_txt(ezxml_child(loc, "contactLocationType"));
 +
 +						int locid = -1;
 +						if (strcmp(szCntType, "ContactLocationPersonal") == 0)
 +							locid = 0;
 +						else if (strcmp(szCntType, "ContactLocationBusiness") == 0)
 +							locid = 1;
 +
 +						if (locid >= 0)
 +						{
 +							szTmp = ezxml_txt(ezxml_child(loc, "name"));
 +							SetAbParam(hContact, "Company", szTmp);
 +							szTmp = ezxml_txt(ezxml_child(loc, "street"));
 +							SetAbParam(hContact, locid ? "CompanyStreet" : "Street", szTmp);
 +							szTmp = ezxml_txt(ezxml_child(loc, "city"));
 +							SetAbParam(hContact, locid ? "CompanyCity" : "City", szTmp);
 +							szTmp = ezxml_txt(ezxml_child(loc, "state"));
 +							SetAbParam(hContact, locid ? "CompanyState" : "State", szTmp);
 +							szTmp = ezxml_txt(ezxml_child(loc, "country"));
 +							SetAbParam(hContact, locid ? "CompanyCountry" : "Country", szTmp);
 +							szTmp = ezxml_txt(ezxml_child(loc, "postalCode"));
 +							SetAbParam(hContact, locid ? "CompanyZIP" : "ZIP", szTmp);
 +						}
 +						loc = ezxml_next(loc);
 +					}
 +
 +					ezxml_t web = ezxml_get(contInf, "webSites", 0, "ContactWebSite", -1);
 +					while (web != NULL)
 +					{
 +						const char* szCntType = ezxml_txt(ezxml_child(web, "contactWebSiteType"));
 +						if (strcmp(szCntType, "ContactWebSiteBusiness") == 0)
 +						{
 +							szTmp = ezxml_txt(ezxml_child(web, "webURL"));
 +							SetAbParam(hContact, "CompanyHomepage", szTmp);
 +						}
 +						web = ezxml_next(web);
 +					}
 +				}
 +				else
 +				{
 +	//              This depricated in WLM 8.1
 +	//				if (!getByte("NeverUpdateNickname", 0))
 +	//				{
 +	//					const char* szNick  = ezxml_txt(ezxml_child(contInf, "displayName"));
 +	//					setStringUtf(NULL, "Nick", (char*)szNick);
 +	//				}
 +					const char *szTmp;
 +
 +					szTmp = ezxml_txt(ezxml_child(contInf, "isMobileIMEnabled"));
 +					setByte("MobileEnabled", strcmp(szTmp, "true") == 0);
 +
 +					szTmp = ezxml_txt(ezxml_child(contInf, "IsNotMobileVisible"));
 +					setByte("MobileAllowed", strcmp(szTmp, "true") != 0);
 +
 +					szTmp = ezxml_txt(ezxml_child(contInf, "firstName"));
 +					setStringUtf(NULL, "FirstName", szTmp);
 +
 +					szTmp = ezxml_txt(ezxml_child(contInf, "lastName"));
 +					setStringUtf(NULL, "LastName", szTmp);
 +
 +					ezxml_t anot = ezxml_get(contInf, "annotations", 0, "Annotation", -1);
 +					while (anot != NULL)
 +					{
 +						if (strcmp(ezxml_txt(ezxml_child(anot, "Name")), "MSN.IM.BLP") == 0)
 +							msnOtherContactsBlocked = !atol(ezxml_txt(ezxml_child(anot, "Value")));
 +
 +						anot = ezxml_next(anot);
 +					}
 +				}
 +			}
 +			if (!msnLoggedIn && msnNsThread)
 +			{
 +				char *szCircleTicket = ezxml_txt(ezxml_get(body, "CircleResult", 0, "CircleTicket", -1));
 +				ptrA szCircleTicketEnc( mir_base64_encode((PBYTE)szCircleTicket, (unsigned)strlen(szCircleTicket)));
 +				if (szCircleTicketEnc)
 +					msnNsThread->sendPacket("USR", "SHA A %s", szCircleTicketEnc);
 +			}
 +
 +		}
 +		else if (status == 500)
 +		{
 +			const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +			if (strcmp(szErr, "PassportAuthFail") == 0 && allowRecurse)
 +			{
 +				MSN_GetPassportAuth();
 +				status = MSN_ABFind(szMethod, szGuid, deltas, false) ? 200 : 500;
 +			}
 +			else if (strcmp(szErr, "FullSyncRequired") == 0 && deltas)
 +			{
 +				status = MSN_ABFind(szMethod, szGuid, false, false) ? 200 : 500;
 +			}
 +		}
 +		else
 +			UpdateABHost(szMethod, NULL);
 +
 +		ezxml_free(xmlm);
 +	}
 +	mir_free(tResult);
 +	mir_free(abUrl);
 +
 +	return status == 200;
 +}
 +
 +
 +//		"ABGroupContactAdd" : "ABGroupContactDelete", "ABGroupDelete", "ABContactDelete"
 +bool CMsnProto::MSN_ABAddDelContactGroup(const char* szCntId, const char* szGrpId, const char* szMethod, bool allowRecurse)
 +{
 +	char* reqHdr;
 +	ezxml_t tbdy, node;
 +	ezxml_t xmlp = abSoapHdr(szMethod, "Timer", tbdy, reqHdr);
 +
 +	if (szGrpId != NULL)
 +	{
 +		node = ezxml_add_child(tbdy, "groupFilter", 0);
 +		node = ezxml_add_child(node, "groupIds", 0);
 +		node = ezxml_add_child(node, "guid", 0);
 +		ezxml_set_txt(node, szGrpId);
 +	}
 +
 +	if (szCntId != NULL)
 +	{
 +		node = ezxml_add_child(tbdy, "contacts", 0);
 +		node = ezxml_add_child(node, "Contact", 0);
 +		node = ezxml_add_child(node, "contactId", 0);
 +		ezxml_set_txt(node, szCntId);
 +	}
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +	ezxml_free(xmlp);
 +
 +	unsigned status = 0;
 +	char *abUrl = NULL, *tResult = NULL;
 +
 +	for (int k = 4; --k;)
 +	{
 +		mir_free(abUrl);
 +		abUrl = GetABHost(szMethod, false);
 +		tResult = getSslResult(&abUrl, szData, reqHdr, status);
 +		if (tResult == NULL) UpdateABHost(szMethod, NULL);
 +		else break;
 +	}
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	if (tResult != NULL)
 +	{
 +		UpdateABHost(szMethod, abUrl);
 +		ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +		UpdateABCacheKey(xmlm, false);
 +		if (status == 500)
 +		{
 +			const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +			if (strcmp(szErr, "PassportAuthFail") == 0 && allowRecurse)
 +			{
 +				MSN_GetPassportAuth();
 +				status = MSN_ABAddDelContactGroup(szCntId, szGrpId, szMethod, false) ? 200 : 500;
 +			}
 +		}
 +		ezxml_free(xmlm);
 +	}
 +	mir_free(tResult);
 +	mir_free(abUrl);
 +
 +	return status == 200;
 +}
 +
 +void CMsnProto::MSN_ABAddGroup(const char* szGrpName, bool allowRecurse)
 +{
 +	char* reqHdr;
 +	ezxml_t tbdy;
 +	ezxml_t xmlp = abSoapHdr("ABGroupAdd", "GroupSave", tbdy, reqHdr);
 +
 +	ezxml_t node = ezxml_add_child(tbdy, "groupAddOptions", 0);
 +	node = ezxml_add_child(node, "fRenameOnMsgrConflict", 0);
 +	ezxml_set_txt(node, "false");
 +
 +	node = ezxml_add_child(tbdy, "groupInfo", 0);
 +	ezxml_t grpi = ezxml_add_child(node, "GroupInfo", 0);
 +	node = ezxml_add_child(grpi, "name", 0);
 +	ezxml_set_txt(node, szGrpName);
 +	node = ezxml_add_child(grpi, "groupType", 0);
 +	ezxml_set_txt(node, "C8529CE2-6EAD-434d-881F-341E17DB3FF8");
 +	node = ezxml_add_child(grpi, "fMessenger", 0);
 +	ezxml_set_txt(node, "false");
 +	node = ezxml_add_child(grpi, "annotations", 0);
 +	ezxml_t annt = ezxml_add_child(node, "Annotation", 0);
 +	node = ezxml_add_child(annt, "Name", 0);
 +	ezxml_set_txt(node, "MSN.IM.Display");
 +	node = ezxml_add_child(annt, "Value", 0);
 +	ezxml_set_txt(node, "1");
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +	ezxml_free(xmlp);
 +
 +	unsigned status = 0;
 +	char *abUrl = NULL, *tResult = NULL;
 +
 +	for (int k = 4; --k;)
 +	{
 +		mir_free(abUrl);
 +		abUrl = GetABHost("ABGroupAdd", false);
 +		tResult = getSslResult(&abUrl, szData, reqHdr, status);
 +		if (tResult == NULL) UpdateABHost("ABGroupAdd", NULL);
 +		else break;
 +	}
 +
 +	free(szData);
 +	mir_free(reqHdr);
 +
 +	if (tResult != NULL)
 +	{
 +		UpdateABHost("ABGroupAdd", abUrl);
 +		ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +		UpdateABCacheKey(xmlm, false);
 +		if (status == 200)
 +		{
 +			ezxml_t body = getSoapResponse(xmlm, "ABGroupAdd");
 +			const char* szGrpId = ezxml_txt(ezxml_child(body, "guid"));
 +			MSN_AddGroup(szGrpName, szGrpId, false);
 +		}
 +		else if (status == 500)
 +		{
 +			const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +			if (strcmp(szErr, "PassportAuthFail") == 0 && allowRecurse)
 +			{
 +				MSN_GetPassportAuth();
 +				MSN_ABAddGroup(szGrpName, false);
 +			}
 +		}
 +		ezxml_free(xmlm);
 +	}
 +	mir_free(tResult);
 +	mir_free(abUrl);
 +}
 +
 +
 +void CMsnProto::MSN_ABRenameGroup(const char* szGrpName, const char* szGrpId, bool allowRecurse)
 +{
 +	char* reqHdr;
 +	ezxml_t tbdy;
 +	ezxml_t xmlp = abSoapHdr("ABGroupUpdate", "Timer", tbdy, reqHdr);
 +
 +	ezxml_t node = ezxml_add_child(tbdy, "groups", 0);
 +	ezxml_t grp = ezxml_add_child(node, "Group", 0);
 +
 +	node = ezxml_add_child(grp, "groupId", 0);
 +	ezxml_set_txt(node, szGrpId);
 +	ezxml_t grpi = ezxml_add_child(grp, "groupInfo", 0);
 +	node = ezxml_add_child(grpi, "name", 0);
 +	ezxml_set_txt(node, szGrpName);
 +	node = ezxml_add_child(grp, "propertiesChanged", 0);
 +	ezxml_set_txt(node, "GroupName");
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +	ezxml_free(xmlp);
 +
 +	unsigned status = 0;
 +	char *abUrl = NULL, *tResult = NULL;
 +
 +	for (int k = 4; --k;)
 +	{
 +		mir_free(abUrl);
 +		abUrl = GetABHost("ABGroupUpdate", false);
 +		tResult = getSslResult(&abUrl, szData, reqHdr, status);
 +		if (tResult == NULL) UpdateABHost("ABGroupUpdate", NULL);
 +		else break;
 +	}
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	if (tResult != NULL)
 +	{
 +		UpdateABHost("ABGroupUpdate", abUrl);
 +		ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +		UpdateABCacheKey(xmlm, false);
 +		if (status == 500)
 +		{
 +			const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +			if (strcmp(szErr, "PassportAuthFail") == 0 && allowRecurse)
 +			{
 +				MSN_GetPassportAuth();
 +				MSN_ABRenameGroup(szGrpName, szGrpId, false);
 +			}
 +		}
 +		ezxml_free(xmlm);
 +	}
 +	mir_free(tResult);
 +	mir_free(abUrl);
 +}
 +
 +
 +bool CMsnProto::MSN_ABAddRemoveContact(const char* szCntId, int netId, bool add, bool allowRecurse)
 +{
 +	char* reqHdr;
 +	ezxml_t tbdy;
 +	ezxml_t xmlp = abSoapHdr("ABContactUpdate", "Timer", tbdy, reqHdr);
 +
 +	ezxml_t node = ezxml_add_child(tbdy, "contacts", 0);
 +	ezxml_t cont = ezxml_add_child(node, "Contact", 0);
 +	ezxml_set_attr(cont, "xmlns", "http://www.msn.com/webservices/AddressBook");
 +
 +	node = ezxml_add_child(cont, "contactId", 0);
 +	ezxml_set_txt(node, szCntId);
 +	ezxml_t conti = ezxml_add_child(cont, "contactInfo", 0);
 +
 +	switch (netId)
 +	{
 +	case NETID_MSN:
 +		node = ezxml_add_child(conti, "isMessengerUser", 0);
 +		ezxml_set_txt(node, add ? "true" : "false");
 +		node = ezxml_add_child(cont, "propertiesChanged", 0);
 +		ezxml_set_txt(node, "IsMessengerUser");
 +		break;
 +
 +	case NETID_LCS:
 +	case NETID_YAHOO:
 +		{
 +			ezxml_t contp = ezxml_add_child(conti, "emails", 0);
 +			contp = ezxml_add_child(contp, "ContactEmail", 0);
 +			node = ezxml_add_child(contp, "contactEmailType", 0);
 +			ezxml_set_txt(node, netId == NETID_YAHOO ? "Messenger2" : "Messenger3");
 +			node = ezxml_add_child(contp, "isMessengerEnabled", 0);
 +			ezxml_set_txt(node, add ? "true" : "false");
 +			node = ezxml_add_child(contp, "propertiesChanged", 0);
 +			ezxml_set_txt(node, "IsMessengerEnabled");
 +			node = ezxml_add_child(cont, "propertiesChanged", 0);
 +			ezxml_set_txt(node, "ContactEmail");
 +		}
 +		break;
 +
 +	case NETID_MOB:
 +		{
 +			ezxml_t contp = ezxml_add_child(conti, "phones", 0);
 +			contp = ezxml_add_child(contp, "ContactPhone", 0);
 +			node = ezxml_add_child(contp, "contactPhoneType", 0);
 +			ezxml_set_txt(node, "ContactPhoneMobile");
 +			node = ezxml_add_child(contp, "isMessengerEnabled", 0);
 +			ezxml_set_txt(node, add ? "true" : "false");
 +			node = ezxml_add_child(contp, "propertiesChanged", 0);
 +			ezxml_set_txt(node, "IsMessengerEnabled");
 +			node = ezxml_add_child(cont, "propertiesChanged", 0);
 +			ezxml_set_txt(node, "ContactPhone");
 +		}
 +		break;
 +	}
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +	ezxml_free(xmlp);
 +
 +	unsigned status = 0;
 +	char *abUrl = NULL, *tResult = NULL;
 +
 +	for (int k = 4; --k;)
 +	{
 +		mir_free(abUrl);
 +		abUrl = GetABHost("ABContactUpdate", false);
 +		tResult = getSslResult(&abUrl, szData, reqHdr, status);
 +		if (tResult == NULL) UpdateABHost("ABContactUpdate", NULL);
 +		else break;
 +	}
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	if (tResult != NULL)
 +	{
 +		UpdateABHost("ABContactUpdate", abUrl);
 +		ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +		UpdateABCacheKey(xmlm, false);
 +		if (status == 500)
 +		{
 +			const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +			if (strcmp(szErr, "PassportAuthFail") == 0 && allowRecurse)
 +			{
 +				MSN_GetPassportAuth();
 +				if (MSN_ABAddRemoveContact(szCntId, netId, add, false))
 +					status = 200;
 +			}
 +		}
 +		ezxml_free(xmlm);
 +	}
 +	mir_free(tResult);
 +	mir_free(abUrl);
 +
 +	return status == 200;
 +}
 +
 +
 +bool CMsnProto::MSN_ABUpdateProperty(const char* szCntId, const char* propName, const char* propValue, bool allowRecurse)
 +{
 +	char* reqHdr;
 +	ezxml_t tbdy;
 +	ezxml_t xmlp = abSoapHdr("ABContactUpdate", "Timer", tbdy, reqHdr);
 +
 +	ezxml_t node = ezxml_add_child(tbdy, "contacts", 0);
 +	ezxml_t cont = ezxml_add_child(node, "Contact", 0);
 +	ezxml_set_attr(cont, "xmlns", "http://www.msn.com/webservices/AddressBook");
 +
 +	ezxml_t conti = ezxml_add_child(cont, "contactInfo", 0);
 +	if (szCntId == NULL)
 +	{
 +		node = ezxml_add_child(conti, "contactType", 0);
 +		ezxml_set_txt(node, "Me");
 +	}
 +	else
 +	{
 +		node = ezxml_add_child(cont, "contactId", 0);
 +		ezxml_set_txt(node, szCntId);
 +	}
 +	node = ezxml_add_child(conti, propName, 0);
 +	ezxml_set_txt(node, propValue);
 +
 +	node = ezxml_add_child(cont, "propertiesChanged", 0);
 +	char* szPrpChg = mir_strdup(propName);
 +	*szPrpChg = _toupper(*szPrpChg);
 +	ezxml_set_txt(node, szPrpChg);
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +	ezxml_free(xmlp);
 +	mir_free(szPrpChg);
 +
 +	unsigned status = 0;
 +	char *abUrl = NULL, *tResult = NULL;
 +
 +	for (int k = 4; --k;)
 +	{
 +		mir_free(abUrl);
 +		abUrl = GetABHost("ABContactUpdate", false);
 +		tResult = getSslResult(&abUrl, szData, reqHdr, status);
 +		if (tResult == NULL) UpdateABHost("ABContactUpdate", NULL);
 +		else break;
 +	}
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	if (tResult != NULL)
 +	{
 +		UpdateABHost("ABContactUpdate", abUrl);
 +		ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +		UpdateABCacheKey(xmlm, false);
 +		if (status == 500)
 +		{
 +			const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +			if (strcmp(szErr, "PassportAuthFail") == 0 && allowRecurse)
 +			{
 +				MSN_GetPassportAuth();
 +				if (MSN_ABUpdateProperty(szCntId, propName, propValue, false))
 +					status = 200;
 +			}
 +		}
 +		ezxml_free(xmlm);
 +	}
 +	mir_free(tResult);
 +	mir_free(abUrl);
 +
 +	return status == 200;
 +}
 +
 +
 +void CMsnProto::MSN_ABUpdateAttr(const char* szCntId, const char* szAttr, const char* szValue, bool allowRecurse)
 +{
 +	char* reqHdr;
 +	ezxml_t tbdy;
 +	ezxml_t xmlp = abSoapHdr("ABContactUpdate", "Timer", tbdy, reqHdr);
 +
 +	ezxml_t node = ezxml_add_child(tbdy, "contacts", 0);
 +	ezxml_t cont = ezxml_add_child(node, "Contact", 0);
 +	ezxml_set_attr(cont, "xmlns", "http://www.msn.com/webservices/AddressBook");
 +	ezxml_t conti = ezxml_add_child(cont, "contactInfo", 0);
 +	if (szCntId == NULL)
 +	{
 +		node = ezxml_add_child(conti, "contactType", 0);
 +		ezxml_set_txt(node, "Me");
 +	}
 +	else
 +	{
 +		node = ezxml_add_child(cont, "contactId", 0);
 +		ezxml_set_txt(node, szCntId);
 +	}
 +	node = ezxml_add_child(conti, "annotations", 0);
 +	ezxml_t anot = ezxml_add_child(node, "Annotation", 0);
 +	node = ezxml_add_child(anot, "Name", 0);
 +	ezxml_set_txt(node, szAttr);
 +	node = ezxml_add_child(anot, "Value", 0);
 +	if (szValue != NULL) ezxml_set_txt(node, szValue);
 +
 +	node = ezxml_add_child(cont, "propertiesChanged", 0);
 +	ezxml_set_txt(node, "Annotation");
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +	ezxml_free(xmlp);
 +
 +	unsigned status = 0;
 +	char *abUrl = NULL, *tResult = NULL;
 +
 +	for (int k = 4; --k;)
 +	{
 +		mir_free(abUrl);
 +		abUrl = GetABHost("ABContactUpdate", false);
 +		tResult = getSslResult(&abUrl, szData, reqHdr, status);
 +		if (tResult == NULL) UpdateABHost("ABContactUpdate", NULL);
 +		else break;
 +	}
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	if (tResult != NULL)
 +	{
 +		UpdateABHost("ABContactUpdate", abUrl);
 +		ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +		UpdateABCacheKey(xmlm, false);
 +		if (status == 500)
 +		{
 +			const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +			if (strcmp(szErr, "PassportAuthFail") == 0 && allowRecurse)
 +			{
 +				MSN_GetPassportAuth();
 +				MSN_ABUpdateAttr(szCntId, szAttr, szValue, false);
 +			}
 +		}
 +		ezxml_free(xmlm);
 +	}
 +	mir_free(tResult);
 +	mir_free(abUrl);
 +}
 +
 +
 +void CMsnProto::MSN_ABUpdateNick(const char* szNick, const char* szCntId)
 +{
 +	if (szCntId != NULL)
 +		MSN_ABUpdateAttr(szCntId, "AB.NickName", szNick);
 +	else
 +		MSN_ABUpdateProperty(szCntId, "displayName", szNick);
 +}
 +
 +
 +unsigned CMsnProto::MSN_ABContactAdd(const char* szEmail, const char* szNick, int netId, const char* szInvite, bool search, bool retry, bool allowRecurse)
 +{
 +	char* reqHdr;
 +	ezxml_t tbdy;
 +	ezxml_t xmlp = abSoapHdr("ABContactAdd", "ContactSave", tbdy, reqHdr);
 +
 +	ezxml_t conts = ezxml_add_child(tbdy, "contacts", 0);
 +	ezxml_t node = ezxml_add_child(conts, "Contact", 0);
 +	ezxml_set_attr(node, "xmlns", "http://www.msn.com/webservices/AddressBook");
 +	ezxml_t conti = ezxml_add_child(node, "contactInfo", 0);
 +	ezxml_t contp;
 +
 +	const char* szEmailNP = strchr(szEmail, ':');
 +	if (szEmailNP != NULL) netId = NETID_MOB;
 +
 +	switch (netId)
 +	{
 +	case NETID_MSN:
 +		node = ezxml_add_child(conti, "contactType", 0);
 +		ezxml_set_txt(node, "LivePending");
 +		node = ezxml_add_child(conti, "passportName", 0);
 +		ezxml_set_txt(node, szEmail);
 +		node = ezxml_add_child(conti, "isMessengerUser", 0);
 +		ezxml_set_txt(node, "true");
 +
 +		if (szInvite)
 +		{
 +			node = ezxml_add_child(conti, "MessengerMemberInfo", 0);
 +			node = ezxml_add_child(node, "PendingAnnotations", 0);
 +			ezxml_t anot = ezxml_add_child(node, "Annotation", 0);
 +			node = ezxml_add_child(anot, "Name", 0);
 +			ezxml_set_txt(node, "MSN.IM.InviteMessage");
 +			node = ezxml_add_child(anot, "Value", 0);
 +			ezxml_set_txt(node, szInvite);
 +		}
 +		break;
 +
 +	case NETID_MOB:
 +		++szEmailNP;
 +		if (szNick == NULL) szNick = szEmailNP;
 +		node = ezxml_add_child(conti, "phones", 0);
 +		contp = ezxml_add_child(node, "ContactPhone", 0);
 +		node = ezxml_add_child(contp, "contactPhoneType", 0);
 +		ezxml_set_txt(node, "ContactPhoneMobile");
 +		node = ezxml_add_child(contp, "number", 0);
 +		ezxml_set_txt(node, szEmailNP);
 +		node = ezxml_add_child(contp, "isMessengerEnabled", 0);
 +		ezxml_set_txt(node, "true");
 +		node = ezxml_add_child(contp, "propertiesChanged", 0);
 +		ezxml_set_txt(node, "Number IsMessengerEnabled");
 +		break;
 +
 +	case NETID_LCS:
 +	case NETID_YAHOO:
 +		node = ezxml_add_child(conti, "emails", 0);
 +		contp = ezxml_add_child(node, "ContactEmail", 0);
 +		node = ezxml_add_child(contp, "contactEmailType", 0);
 +		ezxml_set_txt(node, netId == NETID_YAHOO ? "Messenger2" : "Messenger3");
 +		node = ezxml_add_child(contp, "email", 0);
 +		ezxml_set_txt(node, szEmail);
 +		node = ezxml_add_child(contp, "isMessengerEnabled", 0);
 +		ezxml_set_txt(node, "true");
 +		node = ezxml_add_child(contp, "Capability", 0);
 +		ezxml_set_txt(node,  netId == NETID_YAHOO ? "32" : "2");
 +		node = ezxml_add_child(contp, "propertiesChanged", 0);
 +		ezxml_set_txt(node, "Email IsMessengerEnabled Capability");
 +		break;
 +	}
 +
 +	if (szNick != NULL)
 +	{
 +		node = ezxml_add_child(conti, "annotations", 0);
 +		ezxml_t annt = ezxml_add_child(node, "Annotation", 0);
 +		node = ezxml_add_child(annt, "Name", 0);
 +		ezxml_set_txt(node, "MSN.IM.Display");
 +		node = ezxml_add_child(annt, "Value", 0);
 +		ezxml_set_txt(node, szNick);
 +	}
 +
 +	node = ezxml_add_child(conts, "options", 0);
 +	node = ezxml_add_child(node, "EnableAllowListManagement", 0);
 +	ezxml_set_txt(node, "true");
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +	ezxml_free(xmlp);
 +
 +	unsigned status = 0;
 +	char *abUrl = NULL, *tResult = NULL;
 +
 +	for (int k = 4; --k;)
 +	{
 +		mir_free(abUrl);
 +		abUrl = GetABHost("ABContactAdd", false);
 +		tResult = getSslResult(&abUrl, szData, reqHdr, status);
 +		if (tResult == NULL) UpdateABHost("ABContactAdd", NULL);
 +		else break;
 +	}
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	if (tResult != NULL)
 +	{
 +		ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +		UpdateABCacheKey(xmlm, false);
 +		if (status == 200)
 +		{
 +			ezxml_t body = getSoapResponse(xmlm, "ABContactAdd");
 +
 +			const char* szContId = ezxml_txt(ezxml_child(body, "guid"));
 +
 +			if (search)
 +				MSN_ABAddDelContactGroup(szContId , NULL, "ABContactDelete");
 +			else
 +			{
 +				MSN_ABAddRemoveContact(szContId, NETID_MSN, true);
 +				MCONTACT hContact = MSN_HContactFromEmail(szEmail, szNick ? szNick : szEmail, true, false);
 +				setString(hContact, "ID", szContId);
 +			}
 +			status = 0;
 +		}
 +		else if (status == 500)
 +		{
 +			const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +
 +			if (strcmp(szErr, "InvalidPassportUser") == 0)
 +				status = 1;
 +			else if (strcmp(szErr, "FederatedQueryFailure") == 0)
 +				status = 4;
 +			else if (strcmp(szErr, "EmailDomainIsFederated") == 0)
 +				status = 2;
 +			else if (strcmp(szErr, "BadEmailArgument") == 0)
 +				status = 4;
 +			else if (strcmp(szErr, "ContactAlreadyExists") == 0)
 +			{
 +				status = 3;
 +
 +				ezxml_t node = getSoapFault(xmlm, false);
 +				node = ezxml_get(node, "detail", 0, "additionalDetails", 0, "conflictObjectId", -1);
 +				const char* szContId = ezxml_txt(node);
 +
 +				if (search)
 +				{
 +					if (retry)
 +					{
 +						MSN_ABAddDelContactGroup(szContId , NULL, "ABContactDelete");
 +						status = 0;
 +					}
 +				}
 +				else
 +				{
 +					MCONTACT hContact = MSN_HContactFromEmail(szEmail, szNick ? szNick : szEmail, true, false);
 +					setString(hContact, "ID", szContId);
 +				}
 +			}
 +			else if (strcmp(szErr, "PassportAuthFail") == 0 && allowRecurse)
 +			{
 +				MSN_GetPassportAuth();
 +				status = MSN_ABContactAdd(szEmail, szNick, netId, NULL, search, retry, false);
 +			}
 +			else
 +			{
 +				status = MSN_ABContactAdd(szEmail, szNick, netId, NULL, search, false);
 +			}
 +		}
 +		ezxml_free(xmlm);
 +	}
 +	mir_free(tResult);
 +	mir_free(abUrl);
 +
 +	return status;
 +}
 +
 +
 +void CMsnProto::MSN_ABUpdateDynamicItem(bool allowRecurse)
 +{
 +	char* reqHdr;
 +	ezxml_t tbdy;
 +	ezxml_t xmlp = abSoapHdr("UpdateDynamicItem", "RoamingIdentityChanged", tbdy, reqHdr);
 +
 +	ezxml_t dynitms = ezxml_add_child(tbdy, "dynamicItems", 0);
 +	ezxml_t dynitm = ezxml_add_child(dynitms, "DynamicItem", 0);
 +
 +	ezxml_set_attr(dynitm, "xsi:type", "PassportDynamicItem");
 +	ezxml_t node = ezxml_add_child(dynitm, "Type", 0);
 +	ezxml_set_txt(node, "Passport");
 +	node = ezxml_add_child(dynitm, "PassportName", 0);
 +	ezxml_set_txt(node, MyOptions.szEmail);
 +
 +	ezxml_t nots = ezxml_add_child(dynitm, "Notifications", 0);
 +	ezxml_t notd = ezxml_add_child(nots, "NotificationData", 0);
 +	ezxml_t strsvc = ezxml_add_child(notd, "StoreService", 0);
 +	ezxml_t info = ezxml_add_child(strsvc, "Info", 0);
 +
 +	ezxml_t hnd = ezxml_add_child(info, "Handle", 0);
 +	node = ezxml_add_child(hnd, "Id", 0);
 +	ezxml_set_txt(node, "0");
 +	node = ezxml_add_child(hnd, "Type", 0);
 +	ezxml_set_txt(node, "Profile");
 +	node = ezxml_add_child(hnd, "ForeignId", 0);
 +	ezxml_set_txt(node, "MyProfile");
 +
 +	node = ezxml_add_child(info, "InverseRequired", 0);
 +	ezxml_set_txt(node, "false");
 +	node = ezxml_add_child(info, "IsBot", 0);
 +	ezxml_set_txt(node, "false");
 +
 +	node = ezxml_add_child(strsvc, "Changes", 0);
 +	node = ezxml_add_child(strsvc, "LastChange", 0);
 +	ezxml_set_txt(node, "0001-01-01T00:00:00");
 +	node = ezxml_add_child(strsvc, "Deleted", 0);
 +	ezxml_set_txt(node, "false");
 +
 +	node = ezxml_add_child(notd, "Status", 0);
 +	ezxml_set_txt(node, "Exist Access");
 +	node = ezxml_add_child(notd, "LastChanged", 0);
 +
 +	time_t timer;
 +	time(&timer);
 +	tm *tmst = gmtime(&timer);
 +
 +	char tmstr[32];
 +	mir_snprintf(tmstr, sizeof(tmstr), "%04u-%02u-%02uT%02u:%02u:%02uZ",
 +		tmst->tm_year + 1900, tmst->tm_mon+1, tmst->tm_mday,
 +		tmst->tm_hour, tmst->tm_min, tmst->tm_sec);
 +
 +	ezxml_set_txt(node, tmstr);
 +	node = ezxml_add_child(notd, "Gleam", 0);
 +	ezxml_set_txt(node, "false");
 +	node = ezxml_add_child(notd, "InstanceId", 0);
 +	ezxml_set_txt(node, "0");
 +
 +	node = ezxml_add_child(dynitm, "Changes", 0);
 +	ezxml_set_txt(node, "Notifications");
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +	ezxml_free(xmlp);
 +
 +	unsigned status;
 +	char *abUrl = NULL, *tResult;
 +
 +	for (int k = 4; --k;)
 +	{
 +		mir_free(abUrl);
 +		abUrl = GetABHost("UpdateDynamicItem", false);
 +		tResult = getSslResult(&abUrl, szData, reqHdr, status);
 +		if (tResult == NULL) UpdateABHost("UpdateDynamicItem", NULL);
 +		else break;
 +	}
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	if (tResult != NULL)
 +	{
 +		UpdateABHost("UpdateDynamicItem", abUrl);
 +		ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +		UpdateABCacheKey(xmlm, false);
 +		if (status == 500)
 +		{
 +			const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +			if (strcmp(szErr, "PassportAuthFail") == 0 && allowRecurse)
 +			{
 +				MSN_GetPassportAuth();
 +				MSN_ABUpdateDynamicItem(false);
 +			}
 +		}
 +		ezxml_free(xmlm);
 +	}
 +	mir_free(tResult);
 +	mir_free(abUrl);
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_soapstore.cpp b/plugins/!Deprecated/MSN/src/msn_soapstore.cpp new file mode 100644 index 0000000000..0edbe6b9b0 --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_soapstore.cpp @@ -0,0 +1,781 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2007-2012 Boris Krasnovskiy.
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +static const char storeReqHdr[] =
 +	"SOAPAction: http://www.msn.com/webservices/storage/2008/%s\r\n";
 +
 +ezxml_t CMsnProto::storeSoapHdr(const char* service, const char* scenario, ezxml_t& tbdy, char*& httphdr)
 +{
 +	ezxml_t xmlp = ezxml_new("soap:Envelope");
 +	ezxml_set_attr(xmlp, "xmlns:soap", "http://schemas.xmlsoap.org/soap/envelope/");
 +	ezxml_set_attr(xmlp, "xmlns:xsi",  "http://www.w3.org/2001/XMLSchema-instance");
 +	ezxml_set_attr(xmlp, "xmlns:xsd",  "http://www.w3.org/2001/XMLSchema");
 +	ezxml_set_attr(xmlp, "xmlns:soapenc", "http://schemas.xmlsoap.org/soap/encoding/");
 +
 +	ezxml_t hdr = ezxml_add_child(xmlp, "soap:Header", 0);
 +
 +	if (storageCacheKey)
 +	{
 +		ezxml_t cachehdr = ezxml_add_child(hdr, "AffinityCacheHeader", 0);
 +		ezxml_set_attr(cachehdr, "xmlns", "http://www.msn.com/webservices/storage/2008");
 +		ezxml_t node = ezxml_add_child(cachehdr, "CacheKey", 0);
 +		ezxml_set_txt(node, storageCacheKey);
 +	}
 +
 +	ezxml_t apphdr = ezxml_add_child(hdr, "StorageApplicationHeader", 0);
 +	ezxml_set_attr(apphdr, "xmlns", "http://www.msn.com/webservices/storage/2008");
 +	ezxml_t node = ezxml_add_child(apphdr, "ApplicationID", 0);
 +	ezxml_set_txt(node, "Messenger Client 9.0");
 +	node = ezxml_add_child(apphdr, "Scenario", 0);
 +	ezxml_set_txt(node, scenario);
 +
 +	ezxml_t authhdr = ezxml_add_child(hdr, "StorageUserHeader", 0);
 +	ezxml_set_attr(authhdr, "xmlns", "http://www.msn.com/webservices/storage/2008");
 +	node = ezxml_add_child(authhdr, "Puid", 0);
 +	ezxml_set_txt(node, mypuid);
 +	node = ezxml_add_child(authhdr, "TicketToken", 0);
 +	if (authStorageToken) ezxml_set_txt(node, authStorageToken);
 +
 +	ezxml_t bdy = ezxml_add_child(xmlp, "soap:Body", 0);
 +
 +	tbdy = ezxml_add_child(bdy, service, 0);
 +	ezxml_set_attr(tbdy, "xmlns", "http://www.msn.com/webservices/storage/2008");
 +
 +	size_t hdrsz = strlen(service) + sizeof(storeReqHdr) + 20;
 +	httphdr = (char*)mir_alloc(hdrsz);
 +
 +	mir_snprintf(httphdr, hdrsz, storeReqHdr, service);
 +
 +	return xmlp;
 +}
 +
 +char* CMsnProto::GetStoreHost(const char* service)
 +{
 +	char hostname[128];
 +	mir_snprintf(hostname, sizeof(hostname), "StoreHost-%s", service);
 +
 +	char* host = (char*)mir_alloc(256);
 +	if (db_get_static(NULL, m_szModuleName, hostname, host, 256))
 +		strcpy(host, "https://tkrdr.storage.msn.com/storageservice/SchematizedStore.asmx");
 +
 +	return host;
 +}
 +
 +void CMsnProto::UpdateStoreHost(const char* service, const char* url)
 +{
 +	char hostname[128];
 +	mir_snprintf(hostname, sizeof(hostname), "StoreHost-%s", service);
 +
 +	setString(hostname, url);
 +}
 +
 +void CMsnProto::UpdateStoreCacheKey(ezxml_t bdy)
 +{
 +	ezxml_t key = ezxml_get(bdy, "soap:Header", 0, "AffinityCacheHeader", 0, "CacheKey", -1);
 +	if (key) replaceStr(storageCacheKey, ezxml_txt(key));
 +}
 +
 +bool CMsnProto::MSN_StoreCreateProfile(bool allowRecurse)
 +{
 +	char* reqHdr;
 +	ezxml_t tbdy;
 +	ezxml_t xmlp = storeSoapHdr("CreateProfile", "RoamingSeed", tbdy, reqHdr);
 +
 +	ezxml_t pro = ezxml_add_child(tbdy, "profile", 0);
 +	ezxml_t node;
 +
 +	pro = ezxml_add_child(pro, "ExpressionProfile", 0);
 +	ezxml_add_child(pro, "PersonalStatus", 0);
 +	node = ezxml_add_child(pro, "RoleDefinitionName", 0);
 +	ezxml_set_txt(node, "ExpressionProfileDefault");
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +
 +	ezxml_free(xmlp);
 +
 +	unsigned status = 0;
 +	char *storeUrl, *tResult = NULL;
 +
 +	storeUrl = mir_strdup("https://storage.msn.com/storageservice/SchematizedStore.asmx");
 +	tResult = getSslResult(&storeUrl, szData, reqHdr, status);
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	if (tResult != NULL)
 +	{
 +		if (status == 200)
 +		{
 +			ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +			UpdateStoreCacheKey(xmlm);
 +			ezxml_t body = getSoapResponse(xmlm, "CreateProfile");
 +
 +			MSN_StoreShareItem(ezxml_txt(body));
 +			MSN_SharingMyProfile();
 +
 +			ezxml_free(xmlm);
 +		}
 +		else if (status == 500)
 +		{
 +			ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +			const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +			if (strcmp(szErr, "PassportAuthFail") == 0 && allowRecurse)
 +			{
 +				MSN_GetPassportAuth();
 +				status = MSN_StoreCreateProfile(false) ? 200 : 500;
 +			}
 +			ezxml_free(xmlm);
 +		}
 +	}
 +
 +	mir_free(tResult);
 +	mir_free(storeUrl);
 +
 +	return status == 200;
 +}
 +
 +bool CMsnProto::MSN_StoreShareItem(const char* id, bool allowRecurse)
 +{
 +	char* reqHdr;
 +	ezxml_t tbdy;
 +	ezxml_t xmlp = storeSoapHdr("ShareItem", "RoamingSeed", tbdy, reqHdr);
 +
 +	ezxml_t node = ezxml_add_child(tbdy, "resourceID", 0);
 +	ezxml_set_txt(node, id);
 +	node = ezxml_add_child(tbdy, "displayName", 0);
 +	ezxml_set_txt(node, "Messenger Roaming Identity");
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +
 +	ezxml_free(xmlp);
 +
 +	unsigned status = 0;
 +	char *storeUrl, *tResult = NULL;
 +
 +	storeUrl = mir_strdup("https://storage.msn.com/storageservice/SchematizedStore.asmx");
 +	tResult = getSslResult(&storeUrl, szData, reqHdr, status);
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	if (tResult != NULL && status == 500)
 +	{
 +		ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +		const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +		if (strcmp(szErr, "PassportAuthFail") == 0 && allowRecurse)
 +		{
 +			MSN_GetPassportAuth();
 +			status = MSN_StoreCreateProfile(false) ? 200 : 500;
 +		}
 +		ezxml_free(xmlm);
 +	}
 +
 +	mir_free(tResult);
 +	mir_free(storeUrl);
 +
 +	return status == 200;
 +}
 +
 +bool CMsnProto::MSN_StoreGetProfile(bool allowRecurse)
 +{
 +	char* reqHdr;
 +	ezxml_t tbdy;
 +	ezxml_t xmlp = storeSoapHdr("GetProfile", "Initial", tbdy, reqHdr);
 +
 +	ezxml_t prohndl = ezxml_add_child(tbdy, "profileHandle", 0);
 +
 +	ezxml_t alias = ezxml_add_child(prohndl, "Alias", 0);
 +	ezxml_t node = ezxml_add_child(alias, "Name", 0);
 +	ezxml_set_txt(node, mycid);
 +	node = ezxml_add_child(alias, "NameSpace", 0);
 +	ezxml_set_txt(node, "MyCidStuff");
 +
 +	node = ezxml_add_child(prohndl, "RelationshipName", 0);
 +	ezxml_set_txt(node, "MyProfile");
 +
 +	ezxml_t proattr = ezxml_add_child(tbdy, "profileAttributes", 0);
 +	node = ezxml_add_child(proattr, "ResourceID", 0);
 +	ezxml_set_txt(node, "true");
 +	node = ezxml_add_child(proattr, "DateModified", 0);
 +	ezxml_set_txt(node, "true");
 +
 +	ezxml_t exproattr = ezxml_add_child(proattr, "ExpressionProfileAttributes", 0);
 +	node = ezxml_add_child(exproattr, "ResourceID", 0);
 +	ezxml_set_txt(node, "true");
 +	node = ezxml_add_child(exproattr, "DateModified", 0);
 +	ezxml_set_txt(node, "true");
 +	node = ezxml_add_child(exproattr, "DisplayName", 0);
 +	ezxml_set_txt(node, "true");
 +	node = ezxml_add_child(exproattr, "DisplayNameLastModified", 0);
 +	ezxml_set_txt(node, "true");
 +	node = ezxml_add_child(exproattr, "PersonalStatus", 0);
 +	ezxml_set_txt(node, "true");
 +	node = ezxml_add_child(exproattr, "PersonalStatusLastModified", 0);
 +	ezxml_set_txt(node, "true");
 +	node = ezxml_add_child(exproattr, "StaticUserTilePublicURL", 0);
 +	ezxml_set_txt(node, "true");
 +	node = ezxml_add_child(exproattr, "Photo", 0);
 +	ezxml_set_txt(node, "true");
 +	node = ezxml_add_child(exproattr, "Flags", 0);
 +	ezxml_set_txt(node, "true");
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +
 +	ezxml_free(xmlp);
 +
 +	unsigned status = 0;
 +	char *storeUrl = NULL, *tResult = NULL;
 +
 +	for (int k = 4; --k;)
 +	{
 +		mir_free(storeUrl);
 +		storeUrl = GetStoreHost("GetProfile");
 +		tResult = getSslResult(&storeUrl, szData, reqHdr, status);
 +		if (tResult == NULL) UpdateStoreHost("GetProfile", NULL);
 +		else break;
 +	}
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	if (tResult != NULL)
 +	{
 +		if (status == 200)
 +		{
 +			ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +			ezxml_t body = getSoapResponse(xmlm, "GetProfile");
 +
 +			UpdateStoreHost("GetProfile", body ? storeUrl : NULL);
 +
 +			mir_snprintf(proresid, sizeof(proresid), "%s", ezxml_txt(ezxml_child(body, "ResourceID")));
 +
 +			ezxml_t expr = ezxml_child(body, "ExpressionProfile");
 +			if (expr == NULL)
 +			{
 +				MSN_StoreShareItem(proresid);
 +				MSN_SharingMyProfile();
 +				if (allowRecurse) MSN_StoreGetProfile(false);
 +			}
 +			else
 +			{
 +				const char* szNick = ezxml_txt(ezxml_child(expr, "DisplayName"));
 +				setStringUtf(NULL, "Nick", (char*)szNick);
 +
 +				const char* szStatus = ezxml_txt(ezxml_child(expr, "PersonalStatus"));
 +				replaceStr(msnLastStatusMsg, szStatus);
 +
 +				mir_snprintf(expresid, sizeof(expresid), "%s", ezxml_txt(ezxml_child(expr, "ResourceID")));
 +
 +				ezxml_t photo = ezxml_child(expr, "Photo");
 +				mir_snprintf(photoid, sizeof(photoid), "%s", ezxml_txt(ezxml_child(photo, "ResourceID")));
 +
 +				ezxml_t docstr = ezxml_get(photo, "DocumentStreams", 0, "DocumentStream", -1);
 +				while (docstr)
 +				{
 +					const char *docname = ezxml_txt(ezxml_child(docstr, "DocumentStreamName"));
 +					if (!strcmp(docname, "UserTileStatic"))
 +					{
 +						getMyAvatarFile(ezxml_txt(ezxml_child(docstr, "PreAuthURL")), _T("miranda_avatar.tmp"));
 +						break;
 +					}
 +					docstr = ezxml_next(docstr);
 +				}
 +			}
 +			ezxml_free(xmlm);
 +		}
 +		else if (status == 500 && allowRecurse)
 +		{
 +			ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +			const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +			if (strcmp(szErr, "PassportAuthFail") == 0)
 +			{
 +				MSN_GetPassportAuth();
 +				MSN_StoreGetProfile(false);
 +			}
 +			else
 +			{
 +				MSN_StoreCreateProfile();
 +				if (MSN_StoreGetProfile(false)) status = 200;
 +			}
 +			ezxml_free(xmlm);
 +		}
 +		else
 +			UpdateStoreHost("GetProfile", NULL);
 +
 +	}
 +	mir_free(tResult);
 +	mir_free(storeUrl);
 +
 +	return status == 200;
 +}
 +
 +bool CMsnProto::MSN_StoreUpdateProfile(const char* szNick, const char* szStatus, bool lock, bool allowRecurse)
 +{
 +	char* reqHdr;
 +	ezxml_t tbdy;
 +	ezxml_t xmlp = storeSoapHdr("UpdateProfile", "RoamingIdentityChanged", tbdy, reqHdr);
 +
 +	ezxml_t pro = ezxml_add_child(tbdy, "profile", 0);
 +	ezxml_t node = ezxml_add_child(pro, "ResourceID", 0);
 +	ezxml_set_txt(node, proresid);
 +
 +	ezxml_t expro = ezxml_add_child(pro, "ExpressionProfile", 0);
 +	node = ezxml_add_child(expro, "FreeText", 0);
 +	ezxml_set_txt(node, "Update");
 +	if (szNick)
 +	{
 +		node = ezxml_add_child(expro, "DisplayName", 0);
 +		ezxml_set_txt(node, szNick);
 +	}
 +	if (szStatus)
 +	{
 +		node = ezxml_add_child(expro, "PersonalStatus", 0);
 +		ezxml_set_txt(node, szStatus);
 +	}
 +	node = ezxml_add_child(expro, "Flags", 0);
 +	ezxml_set_txt(node, lock ? "1" : "0");
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +
 +	ezxml_free(xmlp);
 +
 +	unsigned status = 0;
 +	char *storeUrl = NULL, *tResult = NULL;
 +
 +	for (int k = 4; --k;)
 +	{
 +		mir_free(storeUrl);
 +		storeUrl = GetStoreHost("UpdateProfile");
 +		tResult = getSslResult(&storeUrl, szData, reqHdr, status);
 +		if (tResult == NULL) UpdateStoreHost("UpdateProfile", NULL);
 +		else break;
 +	}
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	if (tResult != NULL)
 +	{
 +		UpdateStoreHost("UpdateProfile", storeUrl);
 +		if (status == 200)
 +		{
 +			replaceStr(msnLastStatusMsg, szStatus);
 +			MSN_ABUpdateDynamicItem();
 +		}
 +		else if (status == 500 && allowRecurse)
 +		{
 +			ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +			const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +			if (strcmp(szErr, "PassportAuthFail") == 0)
 +			{
 +				MSN_GetPassportAuth();
 +				status = MSN_StoreUpdateProfile(szNick, szStatus, lock, false) ? 200 : 500;
 +			}
 +			ezxml_free(xmlm);
 +		}
 +	}
 +
 +	mir_free(tResult);
 +	mir_free(storeUrl);
 +
 +	return status == 200;
 +}
 +
 +
 +bool CMsnProto::MSN_StoreCreateRelationships(bool allowRecurse)
 +{
 +	char* reqHdr;
 +	ezxml_t tbdy;
 +	ezxml_t xmlp = storeSoapHdr("CreateRelationships", "RoamingIdentityChanged", tbdy, reqHdr);
 +
 +	ezxml_t rels = ezxml_add_child(tbdy, "relationships", 0);
 +	ezxml_t rel = ezxml_add_child(rels, "Relationship", 0);
 +	ezxml_t node = ezxml_add_child(rel, "SourceID", 0);
 +	ezxml_set_txt(node, expresid);
 +	node = ezxml_add_child(rel, "SourceType", 0);
 +	ezxml_set_txt(node, "SubProfile");
 +	node = ezxml_add_child(rel, "TargetID", 0);
 +	ezxml_set_txt(node, photoid);
 +	node = ezxml_add_child(rel, "TargetType", 0);
 +	ezxml_set_txt(node, "Photo");
 +	node = ezxml_add_child(rel, "RelationshipName", 0);
 +	ezxml_set_txt(node, "ProfilePhoto");
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +
 +	ezxml_free(xmlp);
 +
 +	unsigned status = 0;
 +	char *storeUrl = NULL, *tResult = NULL;
 +
 +	for (int k = 4; --k;)
 +	{
 +		mir_free(storeUrl);
 +		storeUrl = GetStoreHost("CreateRelationships");
 +		tResult = getSslResult(&storeUrl, szData, reqHdr, status);
 +		if (tResult == NULL) UpdateStoreHost("CreateRelationships", NULL);
 +		else break;
 +	}
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	if (tResult != NULL)
 +	{
 +		UpdateStoreHost("CreateRelationships", storeUrl);
 +
 +		if (status == 500)
 +		{
 +			ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +			const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +			if (strcmp(szErr, "PassportAuthFail") == 0 && allowRecurse)
 +			{
 +				MSN_GetPassportAuth();
 +				status = MSN_StoreCreateRelationships(false) ? 200 : 500;
 +			}
 +			ezxml_free(xmlm);
 +		}
 +	}
 +
 +	mir_free(tResult);
 +	mir_free(storeUrl);
 +
 +	return status == 200;
 +}
 +
 +
 +bool CMsnProto::MSN_StoreDeleteRelationships(bool tile, bool allowRecurse)
 +{
 +	char* reqHdr;
 +	ezxml_t tbdy;
 +	ezxml_t xmlp = storeSoapHdr("DeleteRelationships", "RoamingIdentityChanged", tbdy, reqHdr);
 +
 +	ezxml_t srch = ezxml_add_child(tbdy, "sourceHandle", 0);
 +
 +	ezxml_t node;
 +	if (tile)
 +	{
 +		node = ezxml_add_child(srch, "RelationshipName", 0);
 +		ezxml_set_txt(node, "/UserTiles");
 +
 +		ezxml_t alias = ezxml_add_child(srch, "Alias", 0);
 +		node = ezxml_add_child(alias, "Name", 0);
 +		ezxml_set_txt(node, mycid);
 +		node = ezxml_add_child(alias, "NameSpace", 0);
 +		ezxml_set_txt(node, "MyCidStuff");
 +	}
 +	else
 +	{
 +		node = ezxml_add_child(srch, "ResourceID", 0);
 +		ezxml_set_txt(node, expresid);
 +	}
 +
 +	node = ezxml_add_child(tbdy, "targetHandles", 0);
 +	node = ezxml_add_child(node, "ObjectHandle", 0);
 +	node = ezxml_add_child(node, "ResourceID", 0);
 +	ezxml_set_txt(node, photoid);
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +
 +	ezxml_free(xmlp);
 +
 +	unsigned status = 0;
 +	char *storeUrl = NULL, *tResult = NULL;
 +
 +	for (int k = 4; --k;)
 +	{
 +		mir_free(storeUrl);
 +		storeUrl = GetStoreHost("DeleteRelationships");
 +		tResult = getSslResult(&storeUrl, szData, reqHdr, status);
 +		if (tResult == NULL) UpdateStoreHost("DeleteRelationships", NULL);
 +		else break;
 +	}
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	if (tResult != NULL)
 +	{
 +		UpdateStoreHost("DeleteRelationships", storeUrl);
 +		if (status == 500)
 +		{
 +			ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +			const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +			if (strcmp(szErr, "PassportAuthFail") == 0 && allowRecurse)
 +			{
 +				MSN_GetPassportAuth();
 +				status = MSN_StoreDeleteRelationships(tile, false) ? 200 : 500;
 +			}
 +			ezxml_free(xmlm);
 +		}
 +	}
 +
 +	mir_free(tResult);
 +	mir_free(storeUrl);
 +
 +	return status == 200;
 +}
 +
 +
 +bool CMsnProto::MSN_StoreCreateDocument(const TCHAR *sztName, const char *szMimeType, const char *szPicData, bool allowRecurse)
 +{
 +	char* reqHdr;
 +	ezxml_t tbdy;
 +	char* szName = mir_utf8encodeT(sztName);
 +	ezxml_t xmlp = storeSoapHdr("CreateDocument", "RoamingIdentityChanged", tbdy, reqHdr);
 +
 +	ezxml_t hndl = ezxml_add_child(tbdy, "parentHandle", 0);
 +	ezxml_t node = ezxml_add_child(hndl, "RelationshipName", 0);
 +	ezxml_set_txt(node, "/UserTiles");
 +
 +	ezxml_t alias = ezxml_add_child(hndl, "Alias", 0);
 +	node = ezxml_add_child(alias, "Name", 0);
 +	ezxml_set_txt(node, mycid);
 +	node = ezxml_add_child(alias, "NameSpace", 0);
 +	ezxml_set_txt(node, "MyCidStuff");
 +
 +	ezxml_t doc = ezxml_add_child(tbdy, "document", 0);
 +	ezxml_set_attr(doc, "xsi:type", "Photo");
 +	node = ezxml_add_child(doc, "Name", 0);
 +	ezxml_set_txt(node, szName);
 +
 +	doc = ezxml_add_child(doc, "DocumentStreams", 0);
 +	doc = ezxml_add_child(doc, "DocumentStream", 0);
 +	ezxml_set_attr(doc, "xsi:type", "PhotoStream");
 +	node = ezxml_add_child(doc, "DocumentStreamType", 0);
 +
 +	ezxml_set_txt(node, "UserTileStatic");
 +	node = ezxml_add_child(doc, "MimeType", 0);
 +	ezxml_set_txt(node, szMimeType);
 +	node = ezxml_add_child(doc, "Data", 0);
 +	ezxml_set_txt(node, szPicData);
 +	node = ezxml_add_child(doc, "DataSize", 0);
 +	ezxml_set_txt(node, "0");
 +
 +	node = ezxml_add_child(tbdy, "relationshipName", 0);
 +	ezxml_set_txt(node, "Messenger User Tile");
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +
 +	ezxml_free(xmlp);
 +	mir_free(szName);
 +
 +	unsigned status = 0;
 +	char *storeUrl = NULL, *tResult = NULL;
 +
 +	for (int k = 4; --k;)
 +	{
 +		mir_free(storeUrl);
 +		storeUrl = GetStoreHost("CreateDocument");
 +		tResult = getSslResult(&storeUrl, szData, reqHdr, status);
 +		if (tResult == NULL) UpdateStoreHost("CreateDocument", NULL);
 +		else break;
 +	}
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	if (tResult != NULL)
 +	{
 +		UpdateStoreHost("CreateDocument", storeUrl);
 +		if (status == 200)
 +		{
 +			ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +			ezxml_t bdy = getSoapResponse(xmlm, "CreateDocument");
 +			mir_snprintf(photoid, sizeof(photoid), "%s", ezxml_txt(bdy));
 +			ezxml_free(xmlm);
 +		}
 +		else if (status == 500)
 +		{
 +			ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +			const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +			if (strcmp(szErr, "PassportAuthFail") == 0 && allowRecurse)
 +			{
 +				MSN_GetPassportAuth();
 +				status = MSN_StoreCreateDocument(sztName, szMimeType, szPicData, false) ? 200 : 500;
 +			}
 +			ezxml_free(xmlm);
 +		}
 +	}
 +
 +	mir_free(tResult);
 +	mir_free(storeUrl);
 +
 +	return status == 200;
 +}
 +
 +
 +bool CMsnProto::MSN_StoreUpdateDocument(const TCHAR *sztName, const char *szMimeType, const char *szPicData, bool allowRecurse)
 +{
 +	char* reqHdr;
 +	char* szName = mir_utf8encodeT(sztName);
 +	ezxml_t tbdy;
 +	ezxml_t xmlp = storeSoapHdr("UpdateDocument", "RoamingIdentityChanged", tbdy, reqHdr);
 +
 +	ezxml_t doc = ezxml_add_child(tbdy, "document", 0);
 +	ezxml_set_attr(doc, "xsi:type", "Photo");
 +	ezxml_t node = ezxml_add_child(doc, "ResourceID", 0);
 +	ezxml_set_txt(node, photoid);
 +	node = ezxml_add_child(doc, "Name", 0);
 +	ezxml_set_txt(node, szName);
 +
 +	doc = ezxml_add_child(doc, "DocumentStreams", 0);
 +	doc = ezxml_add_child(doc, "DocumentStream", 0);
 +	ezxml_set_attr(doc, "xsi:type", "PhotoStream");
 +
 +	node = ezxml_add_child(doc, "MimeType", 0);
 +	ezxml_set_txt(node, szMimeType);
 +	node = ezxml_add_child(doc, "Data", 0);
 +	ezxml_set_txt(node, szPicData);
 +	node = ezxml_add_child(doc, "DataSize", 0);
 +	ezxml_set_txt(node, "0");
 +	node = ezxml_add_child(doc, "DocumentStreamType", 0);
 +	ezxml_set_txt(node, "UserTileStatic");
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +
 +	ezxml_free(xmlp);
 +	mir_free(szName);
 +
 +	unsigned status = 0;
 +	char *storeUrl = NULL, *tResult = NULL;
 +
 +	for (int k = 4; --k;)
 +	{
 +		mir_free(storeUrl);
 +		storeUrl = GetStoreHost("UpdateDocument");
 +		tResult = getSslResult(&storeUrl, szData, reqHdr, status);
 +		if (tResult == NULL) UpdateStoreHost("UpdateDocument", NULL);
 +		else break;
 +	}
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	if (tResult != NULL)
 +	{
 +		UpdateStoreHost("UpdateDocument", storeUrl);
 +		if (status == 500 && allowRecurse)
 +		{
 +			ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +			const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +			if (strcmp(szErr, "PassportAuthFail") == 0)
 +			{
 +				MSN_GetPassportAuth();
 +				status = MSN_StoreUpdateDocument(sztName, szMimeType, szPicData, false) ? 200 : 500;
 +			}
 +			else if (szErr[0])
 +			{
 +				MSN_StoreDeleteRelationships(true);
 +				MSN_StoreDeleteRelationships(false);
 +
 +				MSN_StoreCreateDocument(sztName, szMimeType, szPicData);
 +				MSN_StoreCreateRelationships();
 +			}
 +			ezxml_free(xmlm);
 +		}
 +	}
 +
 +	mir_free(tResult);
 +	mir_free(storeUrl);
 +
 +	return status == 200;
 +}
 +
 +
 +bool CMsnProto::MSN_StoreFindDocuments(bool allowRecurse)
 +{
 +	char* reqHdr;
 +	ezxml_t tbdy;
 +	ezxml_t xmlp = storeSoapHdr("FindDocuments", "RoamingIdentityChanged", tbdy, reqHdr);
 +
 +	ezxml_t srch = ezxml_add_child(tbdy, "objectHandle", 0);
 +	ezxml_t node = ezxml_add_child(srch, "RelationshipName", 0);
 +	ezxml_set_txt(node, "/UserTiles");
 +
 +	ezxml_t alias = ezxml_add_child(srch, "Alias", 0);
 +	node = ezxml_add_child(alias, "Name", 0);
 +	ezxml_set_txt(node, mycid);
 +	node = ezxml_add_child(alias, "NameSpace", 0);
 +	ezxml_set_txt(node, "MyCidStuff");
 +
 +	ezxml_t doc = ezxml_add_child(tbdy, "documentAttributes", 0);
 +	node = ezxml_add_child(doc, "ResourceID", 0);
 +	ezxml_set_txt(node, "true");
 +	node = ezxml_add_child(doc, "Name", 0);
 +	ezxml_set_txt(node, "true");
 +
 +	doc = ezxml_add_child(tbdy, "documentFilter", 0);
 +	node = ezxml_add_child(doc, "FilterAttributes", 0);
 +	ezxml_set_txt(node, "None");
 +
 +	doc = ezxml_add_child(tbdy, "documentSort", 0);
 +	node = ezxml_add_child(doc, "SortBy", 0);
 +	ezxml_set_txt(node, "DateModified");
 +
 +	doc = ezxml_add_child(tbdy, "findContext", 0);
 +	node = ezxml_add_child(doc, "FindMethod", 0);
 +	ezxml_set_txt(node, "Default");
 +	node = ezxml_add_child(doc, "ChunkSize", 0);
 +	ezxml_set_txt(node, "25");
 +
 +	char* szData = ezxml_toxml(xmlp, true);
 +
 +	ezxml_free(xmlp);
 +
 +	unsigned status = 0;
 +	char *storeUrl = NULL, *tResult = NULL;
 +
 +	for (int k = 4; --k;)
 +	{
 +		mir_free(storeUrl);
 +		storeUrl = GetStoreHost("FindDocuments");
 +		tResult = getSslResult(&storeUrl, szData, reqHdr, status);
 +		if (tResult == NULL) UpdateStoreHost("FindDocuments", NULL);
 +		else break;
 +	}
 +
 +	mir_free(reqHdr);
 +	free(szData);
 +
 +	if (tResult != NULL)
 +	{
 +		UpdateStoreHost("FindDocuments", storeUrl);
 +		if (status == 500)
 +		{
 +			ezxml_t xmlm = ezxml_parse_str(tResult, strlen(tResult));
 +			const char* szErr = ezxml_txt(getSoapFault(xmlm, true));
 +			if (strcmp(szErr, "PassportAuthFail") == 0 && allowRecurse)
 +			{
 +				MSN_GetPassportAuth();
 +				status = MSN_StoreFindDocuments(false) ? 200 : 500;
 +			}
 +			ezxml_free(xmlm);
 +		}
 +	}
 +
 +	mir_free(tResult);
 +	mir_free(storeUrl);
 +
 +	return status == 200;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_srv.cpp b/plugins/!Deprecated/MSN/src/msn_srv.cpp new file mode 100644 index 0000000000..57eee9f381 --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_srv.cpp @@ -0,0 +1,378 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_AddGroup - adds new server group to the list
 +
 +void CMsnProto::MSN_AddGroup(const char* grpName, const char *grpId, bool init)
 +{
 +	ServerGroupItem* p = grpList.find((ServerGroupItem*)&grpId);
 +	if (p != NULL) return;
 +
 +	p = (ServerGroupItem*)mir_alloc(sizeof(ServerGroupItem));
 +	p->id = mir_strdup(grpId);
 +	p->name = mir_strdup(grpName);
 +
 +	grpList.insert(p);
 +
 +	if (init)
 +		Clist_CreateGroup(0, ptrT( mir_utf8decodeT(grpName)));
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_DeleteGroup - deletes a group from the list
 +
 +void CMsnProto::MSN_DeleteGroup(const char* pId)
 +{
 +	int i = grpList.getIndex((ServerGroupItem*)&pId);
 +	if (i > -1)
 +	{
 +		ServerGroupItem* p = grpList[i];
 +		mir_free(p->id);
 +		mir_free(p->name);
 +		mir_free(p);
 +		grpList.remove(i);
 +	}
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_DeleteServerGroup - deletes group from the server
 +
 +void CMsnProto::MSN_DeleteServerGroup(LPCSTR szId)
 +{
 +	if (!MyOptions.ManageServer) return;
 +
 +	MSN_ABAddDelContactGroup(NULL, szId, "ABGroupDelete");
 +
 +	int count = -1;
 +	for (;;)
 +	{
 +		MsnContact *msc = Lists_GetNext(count);
 +		if (msc == NULL) break;
 +
 +		char szGroupID[100];
 +		if (!db_get_static(msc->hContact, m_szModuleName, "GroupID", szGroupID, sizeof(szGroupID)))
 +		{
 +			if (strcmp(szGroupID, szId) == 0)
 +				delSetting(msc->hContact, "GroupID");
 +		}
 +	}
 +	MSN_DeleteGroup(szId);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_FreeGroups - clears the server groups list
 +
 +void CMsnProto::MSN_FreeGroups(void)
 +{
 +	for (int i=0; i < grpList.getCount(); i++) {
 +		ServerGroupItem* p = grpList[i];
 +		mir_free(p->id);
 +		mir_free(p->name);
 +		mir_free(p);
 +	}
 +	grpList.destroy();
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_GetGroupById - tries to return a group name associated with given UUID
 +
 +LPCSTR CMsnProto::MSN_GetGroupById(const char* pId)
 +{
 +	ServerGroupItem* p = grpList.find((ServerGroupItem*)&pId);
 +	return p ? p->name : NULL;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_GetGroupByName - tries to return a group UUID associated with the given name
 +
 +LPCSTR CMsnProto::MSN_GetGroupByName(const char* pName)
 +{
 +	for (int i=0; i < grpList.getCount(); i++)
 +	{
 +		const ServerGroupItem* p = grpList[i];
 +		if (strcmp(p->name, pName) == 0)
 +			return p->id;
 +	}
 +
 +	return NULL;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_SetGroupName - sets a new name to a server group
 +
 +void CMsnProto::MSN_SetGroupName(const char* pId, const char* pNewName)
 +{
 +	ServerGroupItem* p = grpList.find((ServerGroupItem*)&pId);
 +	if (p != NULL)
 +		replaceStr(p->name, pNewName);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_MoveContactToGroup - sends a contact to the specified group
 +
 +void CMsnProto::MSN_MoveContactToGroup(MCONTACT hContact, const char* grpName)
 +{
 +	if (!MyOptions.ManageServer) return;
 +
 +	LPCSTR szId = NULL;
 +	char szContactID[100], szGroupID[100];
 +	if (db_get_static(hContact, m_szModuleName, "ID", szContactID, sizeof(szContactID)))
 +		return;
 +
 +	if (db_get_static(hContact, m_szModuleName, "GroupID", szGroupID, sizeof(szGroupID)))
 +		szGroupID[0] = 0;
 +
 +	bool bInsert = false, bDelete = szGroupID[0] != 0;
 +
 +	if (grpName != NULL) {
 +		szId = MSN_GetGroupByName(grpName);
 +		if (szId == NULL) {
 +			MSN_ABAddGroup(grpName);
 +			szId = MSN_GetGroupByName(grpName);
 +		}
 +		if (szId == NULL) return;
 +		if (_stricmp(szGroupID, szId) == 0) bDelete = false;
 +		else                                bInsert = true;
 +	}
 +
 +	if (bDelete) {
 +		MSN_ABAddDelContactGroup(szContactID, szGroupID, "ABGroupContactDelete");
 +		delSetting(hContact, "GroupID");
 +	}
 +
 +	if (bInsert) {
 +		MSN_ABAddDelContactGroup(szContactID, szId, "ABGroupContactAdd");
 +		setString(hContact, "GroupID", szId);
 +	}
 +
 +	if (bDelete)
 +		MSN_RemoveEmptyGroups();
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_RemoveEmptyGroups - removes empty groups from the server list
 +
 +void CMsnProto::MSN_RemoveEmptyGroups(void)
 +{
 +	if (!MyOptions.ManageServer) return;
 +
 +	unsigned *cCount = (unsigned*)mir_calloc(grpList.getCount() * sizeof(unsigned));
 +
 +	int count = -1;
 +	for (;;)
 +	{
 +		MsnContact *msc = Lists_GetNext(count);
 +		if (msc == NULL) break;
 +
 +		char szGroupID[100];
 +		if (!db_get_static(msc->hContact, m_szModuleName, "GroupID", szGroupID, sizeof(szGroupID)))
 +		{
 +			const char *pId = szGroupID;
 +			int i = grpList.getIndex((ServerGroupItem*)&pId);
 +			if (i > -1) ++cCount[i];
 +		}
 +	}
 +
 +	for (int i=grpList.getCount(); i--;)
 +	{
 +		if (cCount[i] == 0) MSN_DeleteServerGroup(grpList[i]->id);
 +	}
 +	mir_free(cCount);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_RenameServerGroup - renames group on the server
 +
 +void CMsnProto::MSN_RenameServerGroup(LPCSTR szId, const char* newName)
 +{
 +	MSN_SetGroupName(szId, newName);
 +	MSN_ABRenameGroup(newName, szId);
 +}
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_UploadServerGroups - adds a group to the server list and contacts into the group
 +
 +void CMsnProto::MSN_UploadServerGroups(char* group)
 +{
 +	if (!MyOptions.ManageServer) return;
 +
 +	int count = -1;
 +	for (;;)
 +	{
 +		MsnContact *msc = Lists_GetNext(count);
 +		if (msc == NULL) break;
 +
 +		DBVARIANT dbv;
 +		if (!db_get_utf(msc->hContact, "CList", "Group", &dbv))
 +		{
 +			char szGroupID[100];
 +			if (group == NULL || (strcmp(group, dbv.pszVal) == 0 &&
 +				db_get_static(msc->hContact, m_szModuleName, "GroupID", szGroupID, sizeof(szGroupID)) != 0))
 +			{
 +				MSN_MoveContactToGroup(msc->hContact, dbv.pszVal);
 +			}
 +			db_free(&dbv);
 +		}
 +	}
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MSN_SyncContactToServerGroup - moves contact into appropriate group according to server
 +// if contact in multiple server groups it get removed from all of them other them it's
 +// in or the last one
 +
 +void CMsnProto::MSN_SyncContactToServerGroup(MCONTACT hContact, const char* szContId, ezxml_t cgrp)
 +{
 +	if (!MyOptions.ManageServer) return;
 +
 +	const char* szGrpName = "";
 +
 +	DBVARIANT dbv;
 +	if (!db_get_utf(hContact, "CList", "Group", &dbv)) {
 +		szGrpName = NEWSTR_ALLOCA(dbv.pszVal);
 +		db_free(&dbv);
 +	}
 +
 +	const char* szGrpIdF = NULL;
 +	while(cgrp != NULL)
 +	{
 +		const char* szGrpId  = ezxml_txt(cgrp);
 +		cgrp = ezxml_next(cgrp);
 +
 +		const char* szGrpNameById = MSN_GetGroupById(szGrpId);
 +
 +		if (szGrpNameById && (strcmp(szGrpNameById, szGrpName) == 0 ||
 +			(cgrp == NULL && szGrpIdF == NULL)))
 +			szGrpIdF = szGrpId;
 +		else
 +			MSN_ABAddDelContactGroup(szContId, szGrpId, "ABGroupContactDelete");
 +	}
 +
 +	if (szGrpIdF != NULL)
 +	{
 +		setString(hContact, "GroupID", szGrpIdF);
 +		const char* szGrpNameById = MSN_GetGroupById(szGrpIdF);
 +		if (strcmp(szGrpNameById, szGrpName))
 +			db_set_utf(hContact, "CList", "Group", szGrpNameById);
 +	}
 +	else
 +	{
 +		if (szGrpName[0])
 +			db_unset(hContact, "CList", "Group");
 +		delSetting(hContact, "GroupID");
 +	}
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// Msn_SendNickname - update our own nickname on the server
 +
 +void CMsnProto::MSN_SendNicknameUtf(const char* nickname)
 +{
 +	if (nickname[0])
 +		setStringUtf(NULL, "Nick", nickname);
 +	else
 +		delSetting("Nick");
 +
 +	MSN_SetNicknameUtf(nickname[0] ? nickname : MyOptions.szEmail);
 +
 +	ForkThread(&CMsnProto::msn_storeProfileThread, (void*)1);
 +}
 +
 +void CMsnProto::MSN_SetNicknameUtf(const char* nickname)
 +{
 +	msnNsThread->sendPacket("PRP", "MFN %s", ptrA(mir_urlEncode(nickname)));
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// msn_storeAvatarThread - update our own avatar on the server
 +
 +void CMsnProto::msn_storeAvatarThread(void* arg)
 +{
 +	StoreAvatarData* dat = (StoreAvatarData*)arg;
 +	ptrA szEncBuf;
 +
 +	if (dat)
 +		szEncBuf = mir_base64_encode(dat->data, (unsigned)dat->dataSize);
 +
 +	if (photoid[0] && dat)
 +		MSN_StoreUpdateDocument(dat->szName, dat->szMimeType, szEncBuf);
 +	else {
 +		MSN_StoreUpdateProfile(NULL, NULL, 1);
 +
 +		if (photoid[0]) {
 +			MSN_StoreDeleteRelationships(true);
 +			MSN_StoreDeleteRelationships(false);
 +			photoid[0] = 0;
 +		}
 +
 +		if (dat) {
 +			MSN_StoreCreateDocument(dat->szName, dat->szMimeType, szEncBuf);
 +			MSN_StoreCreateRelationships();
 +		}
 +
 +		MSN_StoreUpdateProfile(NULL, NULL, 0);
 +	}
 +
 +	MSN_ABUpdateDynamicItem();
 +
 +	if (dat)
 +	{
 +		mir_free(dat->szName);
 +		mir_free(dat->data);
 +		mir_free(dat);
 +	}
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// msn_storeProfileThread - update our own avatar on the server
 +
 +void CMsnProto::msn_storeProfileThread(void* param)
 +{
 +	DBVARIANT dbv;
 +	char *szNick = NULL;
 +	bool needFree = false;
 +	if (!getStringUtf("Nick", &dbv))
 +	{
 +		szNick = dbv.pszVal[0] ? dbv.pszVal : NULL;
 +		needFree = true;
 +	}
 +
 +	char** msgptr = GetStatusMsgLoc(m_iStatus);
 +	char *szStatus = msgptr ? *msgptr : NULL;
 +
 + 	if (param || (msnLastStatusMsg != szStatus &&
 +		(msnLastStatusMsg && szStatus && strcmp(msnLastStatusMsg, szStatus))))
 +	{
 +
 +		if (MSN_StoreUpdateProfile(szNick, szStatus, false))
 +			MSN_ABUpdateDynamicItem();
 +	//	MSN_ABUpdateNick(nickname, NULL);
 +	}
 +
 +	if (needFree) db_free(&dbv);
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_ssl.cpp b/plugins/!Deprecated/MSN/src/msn_ssl.cpp new file mode 100644 index 0000000000..42b324655c --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_ssl.cpp @@ -0,0 +1,140 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +char* CMsnProto::getSslResult(char** parUrl, const char* parAuthInfo, const char* hdrs, unsigned& status)
 +{
 +	mHttpsTS = clock();
 +
 +	char* result = NULL;
 +	NETLIBHTTPREQUEST nlhr = {0};
 +
 +	// initialize the netlib request
 +	nlhr.cbSize = sizeof(nlhr);
 +	nlhr.requestType = REQUEST_POST;
 +	nlhr.flags = NLHRF_HTTP11 | NLHRF_DUMPASTEXT | NLHRF_PERSISTENT | NLHRF_REDIRECT;
 +	nlhr.szUrl = *parUrl;
 +	nlhr.dataLength = (int)strlen(parAuthInfo);
 +	nlhr.pData = (char*)parAuthInfo;
 +	nlhr.nlc = hHttpsConnection;
 +
 +#ifndef _DEBUG
 +	if (strstr(*parUrl, "login")) nlhr.flags |= NLHRF_NODUMPSEND;
 +#endif
 +
 +	nlhr.headersCount = 4;
 +	nlhr.headers=(NETLIBHTTPHEADER*)alloca(sizeof(NETLIBHTTPHEADER) * (nlhr.headersCount + 5));
 +	nlhr.headers[0].szName   = "User-Agent";
 +	nlhr.headers[0].szValue = (char*)MSN_USER_AGENT;
 +	nlhr.headers[1].szName  = "Accept";
 +	nlhr.headers[1].szValue = "text/*";
 +	nlhr.headers[2].szName  = "Content-Type";
 +	nlhr.headers[2].szValue = "text/xml; charset=utf-8";
 +	nlhr.headers[3].szName  = "Cache-Control";
 +	nlhr.headers[3].szValue = "no-cache";
 +
 +	if (hdrs)
 +	{
 +		unsigned count = 0;
 +		char* hdrprs = NEWSTR_ALLOCA(hdrs);
 +		for (;;)
 +		{
 +			char* fnd = strchr(hdrprs, ':');
 +			if (fnd == NULL) break;
 +			*fnd = 0;
 +			fnd += 2;
 +
 +			nlhr.headers[nlhr.headersCount].szName  = hdrprs;
 +			nlhr.headers[nlhr.headersCount].szValue = fnd;
 +
 +			fnd = strchr(fnd, '\r');
 +			*fnd = 0;
 +			hdrprs = fnd + 2;
 +			++nlhr.headersCount;
 +			if (++count >= 5) break;
 +		}
 +	}
 +
 +	// download the page
 +	NETLIBHTTPREQUEST *nlhrReply = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION,
 +		(WPARAM)hNetlibUserHttps,(LPARAM)&nlhr);
 +
 +	if (nlhrReply)
 +	{
 +		hHttpsConnection = nlhrReply->nlc;
 +		status = nlhrReply->resultCode;
 +
 +		if (nlhrReply->szUrl)
 +		{
 +			mir_free(*parUrl);
 +			*parUrl = nlhrReply->szUrl;
 +			nlhrReply->szUrl = NULL;
 +		}
 +
 +		result = nlhrReply->pData;
 +
 +		nlhrReply->dataLength = 0;
 +		nlhrReply->pData = NULL;
 +
 +		CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)nlhrReply);
 +	}
 +	else
 +		hHttpsConnection = NULL;
 +
 +	mHttpsTS = clock();
 +
 +	return result;
 +}
 +
 +bool CMsnProto::getMyAvatarFile(char *url, TCHAR *fname)
 +{
 +	NETLIBHTTPREQUEST nlhr = {0};
 +	bool result = true;
 +
 +	// initialize the netlib request
 +	nlhr.cbSize = sizeof(nlhr);
 +	nlhr.requestType = REQUEST_GET;
 +	nlhr.flags = NLHRF_HTTP11 | NLHRF_REDIRECT;
 +	nlhr.szUrl = url;
 +
 +	nlhr.headersCount = 1;
 +	nlhr.headers=(NETLIBHTTPHEADER*)alloca(sizeof(NETLIBHTTPHEADER) * nlhr.headersCount);
 +	nlhr.headers[0].szName   = "User-Agent";
 +	nlhr.headers[0].szValue = (char*)MSN_USER_AGENT;
 +
 +	// download the page
 +	NETLIBHTTPREQUEST *nlhrReply = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION,
 +		(WPARAM)hNetlibUserHttps,(LPARAM)&nlhr);
 +
 +	if (nlhrReply)
 +	{
 +		if (nlhrReply->resultCode == 200 && nlhrReply->dataLength)
 +			MSN_SetMyAvatar(fname, nlhrReply->pData, nlhrReply->dataLength);
 +		else
 +			result = false;
 +
 +		CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)nlhrReply);
 +	}
 +	return result;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_std.cpp b/plugins/!Deprecated/MSN/src/msn_std.cpp new file mode 100644 index 0000000000..b6e2163e4d --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_std.cpp @@ -0,0 +1,65 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// Standard functions
 +
 +int CMsnProto::getStringUtf(MCONTACT hContact, const char* name, DBVARIANT* result)
 +{	return db_get_utf(hContact, m_szModuleName, name, result);
 +}
 +
 +int CMsnProto::getStringUtf(const char* name, DBVARIANT* result)
 +{	return db_get_utf(NULL, m_szModuleName, name, result);
 +}
 +
 +void CMsnProto::setStringUtf(MCONTACT hContact, const char* name, const char* value)
 +{	db_set_utf(hContact, m_szModuleName, name, value);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +
 +TCHAR* CMsnProto::GetContactNameT(MCONTACT hContact)
 +{
 +	if (hContact)
 +		return (TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, WPARAM(hContact), GCDNF_TCHAR);
 +	else
 +	{
 +		CONTACTINFO ci = {0};
 +		ci.cbSize = sizeof(ci);
 +		ci.dwFlag = CNF_DISPLAY | CNF_TCHAR;
 +		ci.szProto = m_szModuleName;
 +		if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM)&ci))
 +			return (TCHAR*)ci.pszVal;
 +		else
 +			return _T("Me");
 +	}
 +}
 +
 +unsigned MSN_GenRandom(void)
 +{
 +	unsigned rndnum;
 +	CallService(MS_UTILS_GETRANDOM, sizeof(rndnum), (LPARAM)&rndnum);
 +	return rndnum & 0x7FFFFFFF;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_svcs.cpp b/plugins/!Deprecated/MSN/src/msn_svcs.cpp new file mode 100644 index 0000000000..9c6c61b915 --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_svcs.cpp @@ -0,0 +1,624 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +extern int avsPresent;
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// GetMyAwayMsg - obtain the current away message
 +
 +INT_PTR CMsnProto::GetMyAwayMsg(WPARAM wParam,LPARAM lParam)
 +{
 +	char** msgptr = GetStatusMsgLoc(wParam ? wParam : m_iStatus);
 +	if (msgptr == NULL)	return 0;
 +
 +	return (lParam & SGMA_UNICODE) ? (INT_PTR)mir_utf8decodeW(*msgptr) : (INT_PTR)mir_utf8decodeA(*msgptr);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnGetAvatar - retrieves the file name of my own avatar
 +
 +INT_PTR CMsnProto::GetAvatar(WPARAM wParam, LPARAM lParam)
 +{
 +	TCHAR* buf = (TCHAR*)wParam;
 +	int  size = (int)lParam;
 +
 +	if (buf == NULL || size <= 0)
 +		return -1;
 +
 +	MSN_GetAvatarFileName(NULL, buf, size, NULL);
 +	return _taccess(buf, 0);
 +}
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnGetAvatarInfo - retrieve the avatar info
 +
 +void CMsnProto::sttFakeAvatarAck(void* arg)
 +{
 +	Sleep(100);
 +	ProtoBroadcastAck(((PROTO_AVATAR_INFORMATIONT*)arg)->hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, arg, 0);
 +}
 +
 +INT_PTR CMsnProto::GetAvatarInfo(WPARAM wParam,LPARAM lParam)
 +{
 +	PROTO_AVATAR_INFORMATIONT* AI = (PROTO_AVATAR_INFORMATIONT*)lParam;
 +	TCHAR filename[MAX_PATH];
 +	MsnContact *cont = NULL;
 +
 +	if (AI->hContact) {
 +		cont = Lists_Get(AI->hContact);
 +		if (cont == NULL) return GAIR_NOAVATAR;
 +
 +		if ((cont->cap1 & 0xf0000000) == 0)
 +			return GAIR_NOAVATAR;
 +	}
 +
 +	if (AI->hContact == NULL || _stricmp(cont->email, MyOptions.szEmail) == 0) {
 +		MSN_GetAvatarFileName(NULL, filename, SIZEOF(filename), NULL);
 +		AI->format = ProtoGetAvatarFormat(filename);
 +		if (AI->format != PA_FORMAT_UNKNOWN)
 +			_tcscpy(AI->filename, filename);
 +		return AI->format == PA_FORMAT_UNKNOWN ? GAIR_NOAVATAR : GAIR_SUCCESS;
 +	}
 +
 +	char *szContext;
 +	DBVARIANT dbv;
 +	if ( getString(AI->hContact, AI->hContact ? "PictContext" : "PictObject", &dbv) == 0) {
 +		szContext = (char*)NEWSTR_ALLOCA(dbv.pszVal);
 +		db_free(&dbv);
 +	}
 +	else return GAIR_NOAVATAR;
 +
 +	MSN_GetAvatarFileName(AI->hContact, filename, SIZEOF(filename), NULL);
 +	AI->format = ProtoGetAvatarFormat(filename);
 +
 +	if (AI->format != PA_FORMAT_UNKNOWN) {
 +		bool needupdate = true;
 +		if (getString(AI->hContact, "PictSavedContext", &dbv) == 0) {
 +			needupdate = strcmp(dbv.pszVal, szContext) != 0;
 +			db_free(&dbv);
 +		}
 +
 +		if (needupdate) {
 +			setString(AI->hContact, "PictSavedContext", szContext);
 +
 +			// Store also avatar hash
 +			char* szAvatarHash = MSN_GetAvatarHash(szContext);
 +			if (szAvatarHash != NULL) {
 +				setString(AI->hContact, "AvatarSavedHash", szAvatarHash);
 +				mir_free(szAvatarHash);
 +			}
 +		}
 +		_tcscpy(AI->filename, filename);
 +		return GAIR_SUCCESS;
 +	}
 +
 +	if ((wParam & GAIF_FORCE) != 0 && AI->hContact != NULL) {
 +		if (avsPresent < 0) avsPresent = ServiceExists(MS_AV_SETMYAVATAR) != 0;
 +		if (!avsPresent)
 +			return GAIR_NOAVATAR;
 +
 +		WORD wStatus = getWord(AI->hContact, "Status", ID_STATUS_OFFLINE);
 +		if (wStatus == ID_STATUS_OFFLINE) {
 +			delSetting(AI->hContact, "AvatarHash");
 +			PROTO_AVATAR_INFORMATIONT* fakeAI = new PROTO_AVATAR_INFORMATIONT;
 +			*fakeAI = *AI;
 +			ForkThread(&CMsnProto::sttFakeAvatarAck, fakeAI);
 +		}
 +		else if ( !getString(AI->hContact, "AvatarUrl", &dbv)) {
 +			pushAvatarRequest(AI->hContact, dbv.pszVal);
 +			db_free(&dbv);
 +		}
 +		else if (p2p_getAvatarSession(AI->hContact) == NULL) {
 +			filetransfer* ft = new filetransfer(this);
 +			ft->std.hContact = AI->hContact;
 +			ft->p2p_object = mir_strdup(szContext);
 +
 +			MSN_GetAvatarFileName(AI->hContact, filename, SIZEOF(filename), _T("unk"));
 +			ft->std.tszCurrentFile = mir_tstrdup(filename);
 +
 +			p2p_invite(MSN_APPID_AVATAR, ft, NULL);
 +		}
 +
 +		return GAIR_WAITFOR;
 +	}
 +	return GAIR_NOAVATAR;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnGetAvatarCaps - retrieves avatar capabilities
 +
 +INT_PTR CMsnProto::GetAvatarCaps(WPARAM wParam, LPARAM lParam)
 +{
 +	int res = 0;
 +
 +	switch (wParam)
 +	{
 +	case AF_MAXSIZE:
 +		((POINT*)lParam)->x = 96;
 +		((POINT*)lParam)->y = 96;
 +		break;
 +
 +	case AF_PROPORTION:
 +		res = PIP_NONE;
 +		break;
 +
 +	case AF_FORMATSUPPORTED:
 +		res = lParam == PA_FORMAT_PNG || lParam == PA_FORMAT_GIF || lParam == PA_FORMAT_JPEG;
 +		break;
 +
 +	case AF_ENABLED:
 +		res = 1;
 +		break;
 +	}
 +
 +	return res;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	MsnSetAvatar - sets an avatar without UI
 +
 +INT_PTR CMsnProto::SetAvatar(WPARAM wParam, LPARAM lParam)
 +{
 +	TCHAR* szFileName = (TCHAR*)lParam;
 +
 +	TCHAR tFileName[MAX_PATH];
 +	MSN_GetAvatarFileName(NULL, tFileName, SIZEOF(tFileName), NULL);
 +	_tremove(tFileName);
 +
 +	if (szFileName == NULL)
 +	{
 +		delSetting("PictObject");
 +		delSetting("AvatarHash");
 +		ForkThread(&CMsnProto::msn_storeAvatarThread, NULL);
 +	}
 +	else
 +	{
 +		int fileId = _topen(szFileName, _O_RDONLY | _O_BINARY, _S_IREAD);
 +		if (fileId < 0) return 1;
 +
 +		size_t dwPngSize = _filelengthi64(fileId);
 +		unsigned char* pData = (unsigned char*)mir_alloc(dwPngSize);
 +		if (pData == NULL) return 2;
 +
 +		_read(fileId, pData, (unsigned)dwPngSize);
 +		_close(fileId);
 +
 +		TCHAR drive[_MAX_DRIVE];
 +		TCHAR dir[_MAX_DIR];
 +		TCHAR fname[_MAX_FNAME];
 +		TCHAR ext[_MAX_EXT];
 +		_tsplitpath(szFileName, drive, dir, fname, ext);
 +
 +		int fmt = MSN_SetMyAvatar(fname, pData, dwPngSize);
 +
 +		StoreAvatarData* par = (StoreAvatarData*)mir_alloc(sizeof(StoreAvatarData));
 +		par->szName = mir_tstrdup(fname);
 +		par->data = pData;
 +		par->dataSize = dwPngSize;
 +		par->szMimeType = "image/png";
 +
 +		ForkThread(&CMsnProto::msn_storeAvatarThread, par);
 +	}
 +
 +	MSN_SetServerStatus(m_iStatus);
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	SetNickname - sets a nick name without UI
 +
 +INT_PTR CMsnProto::SetNickName(WPARAM wParam, LPARAM lParam)
 +{
 +	if (wParam & SMNN_UNICODE)
 +		MSN_SendNickname((wchar_t*)lParam);
 +	else
 +		MSN_SendNickname((char*)lParam);
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnSendNudge - Sending a nudge
 +
 +INT_PTR CMsnProto::SendNudge(WPARAM hContact, LPARAM lParam)
 +{
 +	if (!msnLoggedIn) return 0;
 +
 +	char tEmail[MSN_MAX_EMAIL_LEN];
 +	if (MSN_IsMeByContact(hContact, tEmail)) return 0;
 +
 +	static const char nudgemsg[] =
 +		"Content-Type: text/x-msnmsgr-datacast\r\n\r\n"
 +		"ID: 1\r\n\r\n";
 +
 +	int netId = Lists_GetNetId(tEmail);
 +
 +	switch (netId) {
 +	case NETID_UNKNOWN:
 +		hContact = MSN_GetChatInernalHandle(hContact);
 +
 +	case NETID_MSN:
 +	case NETID_LCS:
 +		{
 +			bool isOffline;
 +			ThreadData* thread = MSN_StartSB(tEmail, isOffline);
 +			if (thread == NULL)
 +			{
 +				if (isOffline) return 0;
 +				MsgQueue_Add(tEmail, 'N', nudgemsg, -1);
 +			}
 +			else
 +			{
 +				int tNnetId = netId == NETID_UNKNOWN ? NETID_MSN : netId;
 +				thread->sendMessage('N', tEmail, tNnetId, nudgemsg, MSG_DISABLE_HDR);
 +			}
 +		}
 +		break;
 +
 +	case NETID_YAHOO:
 +		msnNsThread->sendMessage('3', tEmail, netId, nudgemsg, MSG_DISABLE_HDR);
 +		break;
 +
 +	default:
 +		break;
 +	}
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	GetCurrentMedia - get current media
 +
 +INT_PTR CMsnProto::GetCurrentMedia(WPARAM wParam, LPARAM lParam)
 +{
 +	LISTENINGTOINFO *cm = (LISTENINGTOINFO *)lParam;
 +
 +	if (cm == NULL || cm->cbSize != sizeof(LISTENINGTOINFO))
 +		return -1;
 +
 +	cm->ptszArtist = mir_tstrdup(msnCurrentMedia.ptszArtist);
 +	cm->ptszAlbum = mir_tstrdup(msnCurrentMedia.ptszAlbum);
 +	cm->ptszTitle = mir_tstrdup(msnCurrentMedia.ptszTitle);
 +	cm->ptszTrack = mir_tstrdup(msnCurrentMedia.ptszTrack);
 +	cm->ptszYear = mir_tstrdup(msnCurrentMedia.ptszYear);
 +	cm->ptszGenre = mir_tstrdup(msnCurrentMedia.ptszGenre);
 +	cm->ptszLength = mir_tstrdup(msnCurrentMedia.ptszLength);
 +	cm->ptszPlayer = mir_tstrdup(msnCurrentMedia.ptszPlayer);
 +	cm->ptszType = mir_tstrdup(msnCurrentMedia.ptszType);
 +	cm->dwFlags = msnCurrentMedia.dwFlags;
 +
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	SetCurrentMedia - set current media
 +
 +INT_PTR CMsnProto::SetCurrentMedia(WPARAM wParam, LPARAM lParam)
 +{
 +	// Clear old info
 +	mir_free(msnCurrentMedia.ptszArtist);
 +	mir_free(msnCurrentMedia.ptszAlbum);
 +	mir_free(msnCurrentMedia.ptszTitle);
 +	mir_free(msnCurrentMedia.ptszTrack);
 +	mir_free(msnCurrentMedia.ptszYear);
 +	mir_free(msnCurrentMedia.ptszGenre);
 +	mir_free(msnCurrentMedia.ptszLength);
 +	mir_free(msnCurrentMedia.ptszPlayer);
 +	mir_free(msnCurrentMedia.ptszType);
 +	memset(&msnCurrentMedia, 0, sizeof(msnCurrentMedia));
 +
 +	// Copy new info
 +	LISTENINGTOINFO *cm = (LISTENINGTOINFO *)lParam;
 +	if (cm != NULL && cm->cbSize == sizeof(LISTENINGTOINFO) && (cm->ptszArtist != NULL || cm->ptszTitle != NULL))
 +	{
 +		bool unicode = (cm->dwFlags & LTI_UNICODE) != 0;
 +
 +		msnCurrentMedia.cbSize = sizeof(msnCurrentMedia);	// Marks that there is info set
 +		msnCurrentMedia.dwFlags = LTI_TCHAR;
 +
 +		overrideStr(msnCurrentMedia.ptszType, cm->ptszType, unicode, _T("Music"));
 +		overrideStr(msnCurrentMedia.ptszArtist, cm->ptszArtist, unicode);
 +		overrideStr(msnCurrentMedia.ptszAlbum, cm->ptszAlbum, unicode);
 +		overrideStr(msnCurrentMedia.ptszTitle, cm->ptszTitle, unicode, _T("No Title"));
 +		overrideStr(msnCurrentMedia.ptszTrack, cm->ptszTrack, unicode);
 +		overrideStr(msnCurrentMedia.ptszYear, cm->ptszYear, unicode);
 +		overrideStr(msnCurrentMedia.ptszGenre, cm->ptszGenre, unicode);
 +		overrideStr(msnCurrentMedia.ptszLength, cm->ptszLength, unicode);
 +		overrideStr(msnCurrentMedia.ptszPlayer, cm->ptszPlayer, unicode);
 +	}
 +
 +	// Set user text
 +	if (msnCurrentMedia.cbSize == 0)
 +		delSetting("ListeningTo");
 +	else
 +	{
 +		TCHAR *text;
 +		if (ServiceExists(MS_LISTENINGTO_GETPARSEDTEXT))
 +			text = (TCHAR *) CallService(MS_LISTENINGTO_GETPARSEDTEXT, (WPARAM) _T("%title% - %artist%"), (LPARAM) &msnCurrentMedia);
 +		else
 +		{
 +			text = (TCHAR *) mir_alloc(128 * sizeof(TCHAR));
 +			mir_sntprintf(text, 128, _T("%s - %s"), (msnCurrentMedia.ptszTitle ? msnCurrentMedia.ptszTitle : _T("")),
 +													 (msnCurrentMedia.ptszArtist ? msnCurrentMedia.ptszArtist : _T("")));
 +		}
 +		setTString("ListeningTo", text);
 +		mir_free(text);
 +	}
 +
 +	// Send it
 +	char** msgptr = GetStatusMsgLoc(m_iDesiredStatus);
 +	MSN_SendStatusMessage(msgptr ? *msgptr : NULL);
 +
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnContactDeleted - called when a contact is deleted from list
 +
 +int CMsnProto::OnContactDeleted(WPARAM hContact, LPARAM lParam)
 +{
 +	if (!msnLoggedIn)  //should never happen for MSN contacts
 +		return 0;
 +
 +	if ( isChatRoom(hContact)) {
 +		DBVARIANT dbv;
 +		if (!getTString(hContact, "ChatRoomID", &dbv)) {
 +			MSN_KillChatSession(dbv.ptszVal);
 +			db_free(&dbv);
 +		}
 +	}
 +	else {
 +		char szEmail[MSN_MAX_EMAIL_LEN];
 +		if (MSN_IsMeByContact(hContact, szEmail))
 +			CallService(MS_CLIST_REMOVEEVENT, hContact, (LPARAM) 1);
 +
 +		if (szEmail[0])
 +		{
 +			debugLogA("Deleted Handler Email");
 +
 +			if (Lists_IsInList(LIST_FL, szEmail))
 +			{
 +				DeleteParam param = { this, hContact };
 +				DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_DELETECONTACT), NULL, DlgDeleteContactUI, (LPARAM)¶m);
 +
 +				MsnContact* msc = Lists_Get(szEmail);
 +				if (msc) msc->hContact = NULL;
 +			}
 +			if (Lists_IsInList(LIST_LL, szEmail))
 +			{
 +				MSN_AddUser(hContact, szEmail, 0, LIST_LL | LIST_REMOVE);
 +			}
 +		}
 +	}
 +
 +	return 0;
 +}
 +
 +
 +int CMsnProto::OnGroupChange(WPARAM hContact, LPARAM lParam)
 +{
 +	if (!msnLoggedIn || !MyOptions.ManageServer) return 0;
 +
 +	const CLISTGROUPCHANGE* grpchg = (CLISTGROUPCHANGE*)lParam;
 +
 +	if (hContact == NULL)
 +	{
 +		if (grpchg->pszNewName == NULL && grpchg->pszOldName != NULL)
 +		{
 +			LPCSTR szId = MSN_GetGroupByName(UTF8(grpchg->pszOldName));
 +			if (szId != NULL) MSN_DeleteServerGroup(szId);
 +		}
 +		else if (grpchg->pszNewName != NULL && grpchg->pszOldName != NULL)
 +		{
 +			LPCSTR szId = MSN_GetGroupByName(UTF8(grpchg->pszOldName));
 +			if (szId != NULL) MSN_RenameServerGroup(szId, UTF8(grpchg->pszNewName));
 +		}
 +	}
 +	else
 +	{
 +		if (MSN_IsMyContact(hContact))
 +		{
 +			char* szNewName = grpchg->pszNewName ? mir_utf8encodeT(grpchg->pszNewName) : NULL;
 +			MSN_MoveContactToGroup(hContact, szNewName);
 +			mir_free(szNewName);
 +		}
 +	}
 +	return 0;
 +}
 +
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnDbSettingChanged - look for contact's settings changes
 +
 +int CMsnProto::OnDbSettingChanged(WPARAM hContact, LPARAM lParam)
 +{
 +	DBCONTACTWRITESETTING* cws = (DBCONTACTWRITESETTING*)lParam;
 +
 +	if (!msnLoggedIn)
 +		return 0;
 +
 +	if (hContact == NULL)
 +	{
 +		if (MyOptions.SlowSend && strcmp(cws->szSetting, "MessageTimeout") == 0 &&
 +		   (strcmp(cws->szModule, "SRMM") == 0 || strcmp(cws->szModule, "SRMsg") == 0))
 +		{
 +			if (cws->value.dVal < 60000)
 +				MessageBox(NULL, TranslateT("MSN requires message send timeout in your Message window plugin to be not less then 60 sec. Please correct the timeout value."),
 +					TranslateT("MSN Protocol"), MB_OK|MB_ICONINFORMATION);
 +		}
 +		return 0;
 +	}
 +
 +	if (!strcmp(cws->szSetting, "ApparentMode"))
 +	{
 +		char tEmail[MSN_MAX_EMAIL_LEN];
 +		if (!db_get_static(hContact, m_szModuleName, "e-mail", tEmail, sizeof(tEmail)))
 +		{
 +			bool isBlocked = Lists_IsInList(LIST_BL, tEmail);
 +
 +			if (isBlocked && (cws->value.type == DBVT_DELETED || cws->value.wVal == 0))
 +			{
 +				MSN_AddUser(hContact, tEmail, 0, LIST_BL + LIST_REMOVE);
 +				MSN_AddUser(hContact, tEmail, 0, LIST_AL);
 +			}
 +			else if (!isBlocked && cws->value.wVal == ID_STATUS_OFFLINE)
 +			{
 +				MSN_AddUser(hContact, tEmail, 0, LIST_AL + LIST_REMOVE);
 +				MSN_AddUser(hContact, tEmail, 0, LIST_BL);
 +			}
 +		}
 +	}
 +
 +	if (!strcmp(cws->szSetting, "MyHandle") && !strcmp(cws->szModule, "CList"))
 +	{
 +		bool isMe = MSN_IsMeByContact(hContact);
 +		if (!isMe || !nickChg)
 +		{
 +			char szContactID[100];
 +			if (!db_get_static(hContact, m_szModuleName, "ID", szContactID, sizeof(szContactID)))
 +			{
 +				if (cws->value.type != DBVT_DELETED)
 +				{
 +					if (cws->value.type == DBVT_UTF8)
 +						MSN_ABUpdateNick(cws->value.pszVal, szContactID);
 +					else
 +						MSN_ABUpdateNick(UTF8(cws->value.pszVal), szContactID);
 +				}
 +				else
 +					MSN_ABUpdateNick(NULL, szContactID);
 +			}
 +			if (isMe) displayEmailCount(hContact);
 +		}
 +	}
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// OnIdleChanged - transitions to Idle
 +
 +int CMsnProto::OnIdleChanged(WPARAM wParam, LPARAM lParam)
 +{
 +	if (m_iStatus == ID_STATUS_INVISIBLE || m_iStatus <= ID_STATUS_OFFLINE)
 +		return 0;
 +
 +	bool bIdle = (lParam & IDF_ISIDLE) != 0;
 +	bool bPrivacy = (lParam & IDF_PRIVACY) != 0;
 +
 +	if (isIdle && !bIdle)
 +	{
 +		isIdle = false;
 +		MSN_SetServerStatus(m_iDesiredStatus);
 +	}
 +	else if (!isIdle && bIdle && !bPrivacy && m_iDesiredStatus != ID_STATUS_AWAY)
 +	{
 +		isIdle = true;
 +		MSN_SetServerStatus(ID_STATUS_IDLE);
 +	}
 +
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// OnWindowEvent - creates session on window open
 +
 +int CMsnProto::OnWindowEvent(WPARAM wParam, LPARAM lParam)
 +{
 +	MessageWindowEventData* msgEvData  = (MessageWindowEventData*)lParam;
 +
 +	if (msgEvData->uType == MSG_WINDOW_EVT_OPENING)
 +	{
 +		if (m_iStatus == ID_STATUS_OFFLINE || m_iStatus == ID_STATUS_INVISIBLE)
 +			return 0;
 +
 +		if (!MSN_IsMyContact(msgEvData->hContact)) return 0;
 +
 +		char tEmail[MSN_MAX_EMAIL_LEN];
 +		if (MSN_IsMeByContact(msgEvData->hContact, tEmail)) return 0;
 +
 +		int netId = Lists_GetNetId(tEmail);
 +		if (netId != NETID_MSN && netId != NETID_LCS) return 0;
 +
 +		if (Lists_IsInList(LIST_BL, tEmail)) return 0;
 +
 +		bool isOffline;
 +		ThreadData* thread = MSN_StartSB(tEmail, isOffline);
 +
 +		if (thread == NULL && !isOffline)
 +			MsgQueue_Add(tEmail, 'X', NULL, 0);
 +	}
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// OnWindowEvent - creates session on window open
 +
 +int CMsnProto::OnWindowPopup(WPARAM wParam, LPARAM lParam)
 +{
 +	MessageWindowPopupData *mwpd = (MessageWindowPopupData *)lParam;
 +
 +	if (!MSN_IsMyContact(mwpd->hContact) || isChatRoom(mwpd->hContact))
 +		return 0;
 +
 +	switch (mwpd->uType)
 +	{
 +	case MSG_WINDOWPOPUP_SHOWING:
 +		AppendMenu(mwpd->hMenu, MF_STRING, 13465, TranslateT("Convert to Chat"));
 +		break;
 +
 +	case MSG_WINDOWPOPUP_SELECTED:
 +		if (mwpd->selection == 13465)
 +		{
 +			DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_CHATROOM_INVITE), NULL, DlgInviteToChat,
 +				LPARAM(new InviteChatParam(NULL, mwpd->hContact, this)));
 +		}
 +		break;
 +	}
 +
 +	return 0;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// MsnGetUnread - returns the actual number of unread emails in the INBOX
 +
 +INT_PTR CMsnProto::GetUnreadEmailCount(WPARAM wParam, LPARAM lParam)
 +{
 +	if (!msnLoggedIn)
 +		return 0;
 +	return mUnreadMessages;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// OnLeaveChat - closes MSN chat window
 +
 +INT_PTR CMsnProto::OnLeaveChat(WPARAM hContact, LPARAM lParam)
 +{
 +	if (isChatRoom(hContact) != 0) {
 +		DBVARIANT dbv;
 +		if (getTString(hContact, "ChatRoomID", &dbv) == 0) {
 +			MSN_KillChatSession(dbv.ptszVal);
 +			db_free(&dbv);
 +		}
 +	}
 +	return 0;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_switchboard.cpp b/plugins/!Deprecated/MSN/src/msn_switchboard.cpp new file mode 100644 index 0000000000..4ff32a7938 --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_switchboard.cpp @@ -0,0 +1,53 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +int ThreadData::contactJoined(const char* email)
 +{
 +	for (int i=0; i < mJoinedContactsWLID.getCount(); i++)
 +		if (_stricmp(mJoinedContactsWLID[i], email) == 0)
 +			return mJoinedContactsWLID.getCount();
 +
 +	if (strchr(email, ';'))
 +		mJoinedIdentContactsWLID.insertn(email);
 +	else
 +		mJoinedContactsWLID.insertn(email);
 +
 +	return mJoinedContactsWLID.getCount();
 +}
 +
 +int ThreadData::contactLeft(const char* email)
 +{
 +	if (strchr(email, ';'))
 +		mJoinedIdentContactsWLID.remove(email);
 +	else
 +		mJoinedContactsWLID.remove(email);
 +
 +	return mJoinedContactsWLID.getCount();
 +}
 +
 +MCONTACT ThreadData::getContactHandle(void)
 +{
 +	return mJoinedContactsWLID.getCount() ? proto->MSN_HContactFromEmail(mJoinedContactsWLID[0]) : NULL;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_threads.cpp b/plugins/!Deprecated/MSN/src/msn_threads.cpp new file mode 100644 index 0000000000..e643bce91b --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_threads.cpp @@ -0,0 +1,769 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	Keep-alive thread for the main connection
 +
 +void __cdecl CMsnProto::msn_keepAliveThread(void*)
 +{
 +	bool keepFlag = true;
 +
 +	hKeepAliveThreadEvt = CreateEvent(NULL, FALSE, FALSE, NULL);
 +
 +	msnPingTimeout = 45;
 +
 +	while (keepFlag)
 +	{
 +		switch (WaitForSingleObject(hKeepAliveThreadEvt, msnPingTimeout * 1000))
 +		{
 +			case WAIT_TIMEOUT:
 +				keepFlag = msnNsThread != NULL;
 +				if (usingGateway)
 +					msnPingTimeout = 45;
 +				else
 +				{
 +					msnPingTimeout = 20;
 +					keepFlag = keepFlag && msnNsThread->send("PNG\r\n", 5);
 +				}
 +				p2p_clearDormantSessions();
 +				if (hHttpsConnection && (clock() - mHttpsTS) > 60 *	CLOCKS_PER_SEC)
 +				{
 +					HANDLE hConn = hHttpsConnection;
 +					hHttpsConnection = NULL;
 +					Netlib_CloseHandle(hConn);
 +				}
 +				if (mStatusMsgTS && (clock() - mStatusMsgTS) > 60 *	CLOCKS_PER_SEC)
 +				{
 +					mStatusMsgTS = 0;
 +					ForkThread(&CMsnProto::msn_storeProfileThread, NULL);
 +				}
 +				break;
 +
 +			case WAIT_OBJECT_0:
 +				keepFlag = msnPingTimeout > 0;
 +				break;
 +
 +			default:
 +				keepFlag = false;
 +				break;
 +		}
 +	}
 +
 +	CloseHandle(hKeepAliveThreadEvt); hKeepAliveThreadEvt = NULL;
 +	debugLogA("Closing keep-alive thread");
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +//	MSN server thread - read and process commands from a server
 +
 +void __cdecl CMsnProto::MSNServerThread(void* arg)
 +{
 +	ThreadData* info = (ThreadData*)arg;
 +
 +	if (info->mIsMainThread)
 +		isConnectSuccess = false;
 +
 +	char* tPortDelim = strrchr(info->mServer, ':');
 +	if (tPortDelim != NULL)
 +		*tPortDelim = '\0';
 +
 +	if (usingGateway)
 +	{
 +		if (info->mServer[0] == 0)
 +			strcpy(info->mServer, MSN_DEFAULT_LOGIN_SERVER);
 +		else if (info->mIsMainThread)
 +			strcpy(info->mGatewayIP, info->mServer);
 +
 +		if (info->gatewayType)
 +			strcpy(info->mGatewayIP, info->mServer);
 +		else
 +		{
 +			if (info->mGatewayIP[0] == 0 && db_get_static(NULL, m_szModuleName, "GatewayServer", info->mGatewayIP, sizeof(info->mGatewayIP)))
 +				strcpy(info->mGatewayIP, MSN_DEFAULT_GATEWAY);
 +		}
 +	}
 +	else
 +	{
 +		if (info->mServer[0] == 0 && db_get_static(NULL, m_szModuleName, "DirectServer", info->mServer, sizeof(info->mServer)))
 +			strcpy(info->mServer, MSN_DEFAULT_LOGIN_SERVER);
 +	}
 +
 +	NETLIBOPENCONNECTION tConn = { 0 };
 +	tConn.cbSize  = sizeof(tConn);
 +	tConn.flags   = NLOCF_V2;
 +	tConn.timeout = 5;
 +
 +	if (usingGateway)
 +	{
 +		tConn.flags  |= NLOCF_HTTPGATEWAY;
 +		tConn.szHost  = info->mGatewayIP;
 +		tConn.wPort   = MSN_DEFAULT_GATEWAY_PORT;
 +	}
 +	else
 +	{
 +		tConn.szHost  = info->mServer;
 +		tConn.wPort   = MSN_DEFAULT_PORT;
 +		if (tPortDelim != NULL)
 +		{
 +			int tPortNumber = atoi(tPortDelim + 1);
 +			if (tPortNumber)
 +				tConn.wPort = (WORD)tPortNumber;
 +		}
 +	}
 +
 +	debugLogA("Thread started: server='%s:%d', type=%d", tConn.szHost, tConn.wPort, info->mType);
 +
 +	info->s = (HANDLE)CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)m_hNetlibUser, (LPARAM)&tConn);
 +	if (info->s == NULL)
 +	{
 +		debugLogA("Connection Failed (%d) server='%s:%d'", WSAGetLastError(), tConn.szHost, tConn.wPort);
 +
 +		switch (info->mType)
 +		{
 +			case SERVER_NOTIFICATION:
 +				goto LBL_Exit;
 +				break;
 +
 +			case SERVER_SWITCHBOARD:
 +				if (info->mCaller) msnNsThread->sendPacket("XFR", "SB");
 +				break;
 +		}
 +		return;
 +	}
 +
 +	if (usingGateway)
 +		CallService(MS_NETLIB_SETPOLLINGTIMEOUT, WPARAM(info->s), info->mGatewayTimeout);
 +
 +	debugLogA("Connected with handle=%08X", info->s);
 +
 +	if (info->mType == SERVER_NOTIFICATION)
 +	{
 +		info->sendPacket("VER", "MSNP18 MSNP17 CVR0");
 +	}
 +	else if (info->mType == SERVER_SWITCHBOARD)
 +	{
 +		info->sendPacket(info->mCaller ? "USR" : "ANS", "%s;%s %s", MyOptions.szEmail, MyOptions.szMachineGuid, info->mCookie);
 +	}
 +	else if (info->mType == SERVER_FILETRANS && info->mCaller == 0)
 +	{
 +		info->send("VER MSNFTP\r\n", 12);
 +	}
 +
 +	if (info->mIsMainThread)
 +	{
 +		msnNsThread = info;
 +	}
 +
 +	debugLogA("Entering main recv loop");
 +	info->mBytesInData = 0;
 +	for (;;)
 +	{
 +		int recvResult = info->recv(info->mData + info->mBytesInData, sizeof(info->mData) - info->mBytesInData);
 +		if (recvResult == SOCKET_ERROR)
 +		{
 +			debugLogA("Connection %08p [%08X] was abortively closed", info->s, GetCurrentThreadId());
 +			break;
 +		}
 +
 +		if (!recvResult)
 +		{
 +			debugLogA("Connection %08p [%08X] was gracefully closed", info->s, GetCurrentThreadId());
 +			break;
 +		}
 +
 +		info->mBytesInData += recvResult;
 +
 +		if (info->mCaller == 1 && info->mType == SERVER_FILETRANS)
 +		{
 +			if (MSN_HandleMSNFTP(info, info->mData))
 +				break;
 +		}
 +		else
 +		{
 +			for (;;)
 +			{
 +				char* peol = strchr(info->mData, '\r');
 +				if (peol == NULL)
 +					break;
 +
 +				if (info->mBytesInData < peol-info->mData + 2)
 +					break;  //wait for full line end
 +
 +				char msg[sizeof(info->mData)];
 +				memcpy(msg, info->mData, peol-info->mData); msg[peol-info->mData] = 0;
 +
 +				if (*++peol != '\n')
 +					debugLogA("Dodgy line ending to command: ignoring");
 +				else
 +					peol++;
 +
 +				info->mBytesInData -= peol - info->mData;
 +				memmove(info->mData, peol, info->mBytesInData);
 +				debugLogA("RECV: %s", msg);
 +
 +				if (!isalnum(msg[0]) || !isalnum(msg[1]) || !isalnum(msg[2]) || (msg[3] && msg[3] != ' '))
 +				{
 +					debugLogA("Invalid command name");
 +					continue;
 +				}
 +
 +				if (info->mType != SERVER_FILETRANS)
 +				{
 +					int handlerResult;
 +					if (isdigit(msg[0]) && isdigit(msg[1]) && isdigit(msg[2]))   //all error messages
 +						handlerResult = MSN_HandleErrors(info, msg);
 +					else
 +						handlerResult = MSN_HandleCommands(info, msg);
 +
 +					if (handlerResult)
 +					{
 +						if (info->sessionClosed) goto LBL_Exit;
 +						info->sendTerminate();
 +					}
 +				}
 +				else
 +					if (MSN_HandleMSNFTP(info, msg))
 +						goto LBL_Exit;
 +			}
 +		}
 +
 +		if (info->mBytesInData == sizeof(info->mData))
 +		{
 +			debugLogA("sizeof(data) is too small: the longest line won't fit");
 +			break;
 +		}
 +	}
 +
 +LBL_Exit:
 +	if (info->mIsMainThread)
 +	{
 +		if (!isConnectSuccess && !usingGateway && m_iDesiredStatus != ID_STATUS_OFFLINE)
 +		{
 +			msnNsThread = NULL;
 +			usingGateway = true;
 +
 +			ThreadData* newThread = new ThreadData;
 +			newThread->mType = SERVER_NOTIFICATION;
 +			newThread->mIsMainThread = true;
 +
 +			newThread->startThread(&CMsnProto::MSNServerThread, this);
 +		}
 +		else
 +		{
 +			if (hKeepAliveThreadEvt)
 +			{
 +				msnPingTimeout *= -1;
 +				SetEvent(hKeepAliveThreadEvt);
 +			}
 +
 +			if (info->s == NULL)
 +				ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK);
 +			else
 +			{
 +				p2p_cancelAllSessions();
 +				MSN_CloseConnections();
 +			}
 +
 +			if (hHttpsConnection)
 +			{
 +				Netlib_CloseHandle(hHttpsConnection);
 +				hHttpsConnection = NULL;
 +			}
 +
 +			MSN_GoOffline();
 +			msnNsThread = NULL;
 +		}
 +	}
 +
 +	debugLogA("Thread [%08X] ending now", GetCurrentThreadId());
 +}
 +
 +void CMsnProto::MSN_CloseConnections(void)
 +{
 +	mir_cslockfull lck(csThreads);
 +
 +	NETLIBSELECTEX nls = {0};
 +	nls.cbSize = sizeof(nls);
 +
 +	for (int i=0; i < sttThreads.getCount(); i++)
 +	{
 +		ThreadData* T = &sttThreads[i];
 +
 +		switch (T->mType)
 +		{
 +		case SERVER_NOTIFICATION :
 +		case SERVER_SWITCHBOARD :
 +			if (T->s != NULL && !T->sessionClosed && !T->termPending)
 +			{
 +				nls.hReadConns[0] = T->s;
 +				int res = CallService(MS_NETLIB_SELECTEX, 0, (LPARAM)&nls);
 +				if (res >= 0 || nls.hReadStatus[0] == 0)
 +					T->sendTerminate();
 +			}
 +			break;
 +
 +		case SERVER_P2P_DIRECT :
 +			CallService(MS_NETLIB_SHUTDOWN, (WPARAM)T->s, 0);
 +			break;
 +		}
 +	}
 +
 +	lck.unlock();
 +
 +	if (hHttpsConnection)
 +		CallService(MS_NETLIB_SHUTDOWN, (WPARAM)hHttpsConnection, 0);
 +}
 +
 +void CMsnProto::Threads_Uninit(void)
 +{
 +	mir_cslock lck(csThreads);
 +	sttThreads.destroy();
 +}
 +
 +ThreadData* CMsnProto::MSN_GetThreadByContact(const char* wlid, TInfoType type)
 +{
 +	mir_cslock lck(csThreads);
 +
 +	if (type == SERVER_P2P_DIRECT)
 +	{
 +		for (int i=0; i < sttThreads.getCount(); i++)
 +		{
 +			ThreadData* T = &sttThreads[i];
 +			if (T->mType != SERVER_P2P_DIRECT || !T->mJoinedIdentContactsWLID.getCount() || T->s == NULL)
 +				continue;
 +
 +			if (_stricmp(T->mJoinedIdentContactsWLID[0], wlid) == 0)
 +				return T;
 +		}
 +	}
 +
 +	char *szEmail = NULL;
 +	parseWLID(NEWSTR_ALLOCA(wlid), NULL, &szEmail, NULL);
 +
 +	for (int i=0; i < sttThreads.getCount(); i++)
 +	{
 +		ThreadData* T = &sttThreads[i];
 +		if (T->mType != type || !T->mJoinedContactsWLID.getCount() || T->mInitialContactWLID || T->s == NULL)
 +			continue;
 +
 +		if (_stricmp(T->mJoinedContactsWLID[0], szEmail) == 0 && T->mChatID[0] == 0)
 +			return T;
 +	}
 +
 +	return NULL;
 +}
 +
 +ThreadData* CMsnProto::MSN_GetThreadByChatId(const TCHAR* chatId)
 +{
 +	mir_cslock lck(csThreads);
 +
 +	for (int i=0; i < sttThreads.getCount(); i++)
 +	{
 +		ThreadData* T = &sttThreads[i];
 +
 +		if (_tcsicmp(T->mChatID, chatId) == 0)
 +			return T;
 +	}
 +
 +	return NULL;
 +}
 +
 +ThreadData* CMsnProto::MSN_GetThreadByTimer(UINT timerId)
 +{
 +	mir_cslock lck(csThreads);
 +
 +	for (int i=0; i < sttThreads.getCount(); i++)
 +	{
 +		ThreadData* T = &sttThreads[i];
 +		if (T->mType == SERVER_SWITCHBOARD && T->mTimerId == timerId)
 +			return T;
 +	}
 +
 +	return NULL;
 +}
 +
 +ThreadData* CMsnProto::MSN_GetP2PThreadByContact(const char *wlid)
 +{
 +	mir_cslock lck(csThreads);
 +
 +	for (int i=0; i < sttThreads.getCount(); i++)
 +	{
 +		ThreadData* T = &sttThreads[i];
 +		if (T->mType != SERVER_P2P_DIRECT || !T->mJoinedIdentContactsWLID.getCount())
 +			continue;
 +
 +		if (_stricmp(T->mJoinedIdentContactsWLID[0], wlid) == 0)
 +			return T;
 +	}
 +
 +	char *szEmail = NULL;
 +	parseWLID(NEWSTR_ALLOCA(wlid), NULL, &szEmail, NULL);
 +
 +	ThreadData *result = NULL;
 +	for (int i=0; i < sttThreads.getCount(); i++)
 +	{
 +		ThreadData* T = &sttThreads[i];
 +		if (T->mJoinedContactsWLID.getCount() && !T->mInitialContactWLID &&
 +			_stricmp(T->mJoinedContactsWLID[0], szEmail) == 0)
 +		{
 +			if (T->mType == SERVER_P2P_DIRECT)
 +				return T;
 +
 +			if (T->mType == SERVER_SWITCHBOARD)
 +				result = T;
 +		}
 +	}
 +
 +	return result;
 +}
 +
 +
 +void CMsnProto::MSN_StartP2PTransferByContact(const char* wlid)
 +{
 +	mir_cslock lck(csThreads);
 +
 +	for (int i=0; i < sttThreads.getCount(); i++)
 +	{
 +		ThreadData* T = &sttThreads[i];
 +		if (T->mType == SERVER_FILETRANS && T->hWaitEvent != INVALID_HANDLE_VALUE)
 +		{
 +			if ((T->mInitialContactWLID && !_stricmp(T->mInitialContactWLID, wlid)) ||
 +				 (T->mJoinedContactsWLID.getCount() && !_stricmp(T->mJoinedContactsWLID[0], wlid)) ||
 +				 (T->mJoinedIdentContactsWLID.getCount() && !_stricmp(T->mJoinedIdentContactsWLID[0], wlid)))
 +				ReleaseSemaphore(T->hWaitEvent, 1, NULL);
 +		}
 +	}
 +}
 +
 +
 +ThreadData* CMsnProto::MSN_GetOtherContactThread(ThreadData* thread)
 +{
 +	mir_cslock lck(csThreads);
 +
 +	for (int i=0; i < sttThreads.getCount(); i++)
 +	{
 +		ThreadData* T = &sttThreads[i];
 +		if (T->mJoinedContactsWLID.getCount() == 0 || T->s == NULL)
 +			continue;
 +
 +		if (T != thread && _stricmp(T->mJoinedContactsWLID[0], thread->mJoinedContactsWLID[0]) == 0)
 +			return T;
 +	}
 +
 +	return NULL;
 +}
 +
 +ThreadData* CMsnProto::MSN_GetUnconnectedThread(const char* wlid, TInfoType type)
 +{
 +	mir_cslock lck(csThreads);
 +
 +	char* szEmail = (char*)wlid;
 +
 +	if (type == SERVER_SWITCHBOARD && strchr(wlid, ';'))
 +		parseWLID(NEWSTR_ALLOCA(wlid), NULL, &szEmail, NULL);
 +
 +	for (int i=0; i < sttThreads.getCount(); i++)
 +	{
 +		ThreadData* T = &sttThreads[i];
 + 		if (T->mType == type && T->mInitialContactWLID && _stricmp(T->mInitialContactWLID, szEmail) == 0)
 +			return T;
 +	}
 +
 +	return NULL;
 +}
 +
 +
 +ThreadData* CMsnProto::MSN_StartSB(const char* wlid, bool& isOffline)
 +{
 +	isOffline = false;
 +	ThreadData* thread = MSN_GetThreadByContact(wlid);
 +	if (thread == NULL)
 +	{
 +		MCONTACT hContact = MSN_HContactFromEmail(wlid);
 +		WORD wStatus = getWord(hContact, "Status", ID_STATUS_OFFLINE);
 +		if (wStatus != ID_STATUS_OFFLINE)
 +		{
 +			if (MSN_GetUnconnectedThread(wlid) == NULL && MsgQueue_CheckContact(wlid, 5) == NULL)
 +				msnNsThread->sendPacket("XFR", "SB");
 +		}
 +		else isOffline = true;
 +	}
 +	return thread;
 +}
 +
 +
 +
 +int CMsnProto::MSN_GetActiveThreads(ThreadData** parResult)
 +{
 +	int tCount = 0;
 +	mir_cslock lck(csThreads);
 +
 +	for (int i=0; i < sttThreads.getCount(); i++)
 +	{
 +		ThreadData* T = &sttThreads[i];
 +		if (T->mType == SERVER_SWITCHBOARD && T->mJoinedContactsWLID.getCount() != 0 && T->mJoinedContactsWLID.getCount())
 +			parResult[tCount++] = T;
 +	}
 +
 +	return tCount;
 +}
 +
 +ThreadData* CMsnProto::MSN_GetThreadByConnection(HANDLE s)
 +{
 +	mir_cslock lck(csThreads);
 +
 +	for (int i = 0; i < sttThreads.getCount(); i++)
 +	{
 +		ThreadData* T = &sttThreads[i];
 +		if (T->s == s)
 +			return T;
 +	}
 +
 +	return NULL;
 +}
 +
 +ThreadData* CMsnProto::MSN_GetThreadByPort(WORD wPort)
 +{
 +	mir_cslock lck(csThreads);
 +
 +	for (int i=0; i < sttThreads.getCount(); i++)
 +	{
 +		ThreadData* T = &sttThreads[i];
 +		if (T->mIncomingPort == wPort)
 +			return T;
 +	}
 +
 +	return NULL;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// class ThreadData members
 +
 +ThreadData::ThreadData()
 +{
 +	memset(&mInitialContactWLID, 0, sizeof(ThreadData) - 2*sizeof(STRLIST));
 +	mGatewayTimeout = 2;
 +	resetTimeout();
 +	hWaitEvent = CreateSemaphore(NULL, 0, MSN_PACKETS_COMBINE, NULL);
 +}
 +
 +ThreadData::~ThreadData()
 +{
 +	int i;
 +
 +	if (s != NULL)
 +	{
 +		proto->debugLogA("Closing connection handle %08X", s);
 +		Netlib_CloseHandle(s);
 +	}
 +
 +	if (mIncomingBoundPort != NULL)
 +	{
 +		Netlib_CloseHandle(mIncomingBoundPort);
 +	}
 +
 +	if (mMsnFtp != NULL)
 +	{
 +		delete mMsnFtp;
 +		mMsnFtp = NULL;
 +	}
 +
 +	if (hWaitEvent != INVALID_HANDLE_VALUE)
 +		CloseHandle(hWaitEvent);
 +
 +	if (mTimerId != 0)
 +		KillTimer(NULL, mTimerId);
 +
 +	if (mType == SERVER_SWITCHBOARD)
 +	{
 +		for (i=0; i<mJoinedContactsWLID.getCount(); ++i)
 +		{
 +			const char* wlid = mJoinedContactsWLID[i];
 +			MCONTACT hContact = proto->MSN_HContactFromEmail(wlid);
 +			int temp_status = proto->getWord(hContact, "Status", ID_STATUS_OFFLINE);
 +			if (temp_status == ID_STATUS_INVISIBLE && proto->MSN_GetThreadByContact(wlid) == NULL)
 +				proto->setWord(hContact, "Status", ID_STATUS_OFFLINE);
 +		}
 +	}
 +
 +	mJoinedContactsWLID.destroy();
 +	mJoinedIdentContactsWLID.destroy();
 +
 +	const char* wlid = NEWSTR_ALLOCA(mInitialContactWLID);
 +	mir_free(mInitialContactWLID); mInitialContactWLID = NULL;
 +
 +	if (proto && mType == SERVER_P2P_DIRECT)
 +		proto->p2p_clearDormantSessions();
 +
 +	if (wlid != NULL && mType == SERVER_SWITCHBOARD && 
 +		 proto->MSN_GetThreadByContact(wlid) == NULL &&
 +		 proto->MSN_GetUnconnectedThread(wlid) == NULL)
 +	{
 +		proto->MsgQueue_Clear(wlid, true);
 +	}
 +}
 +
 +void ThreadData::applyGatewayData(HANDLE hConn, bool isPoll)
 +{
 +	char szHttpPostUrl[300];
 +	getGatewayUrl(szHttpPostUrl, sizeof(szHttpPostUrl), isPoll);
 +
 +	proto->debugLogA("applying '%s' to %08X [%08X]", szHttpPostUrl, this, GetCurrentThreadId());
 +
 +	NETLIBHTTPPROXYINFO nlhpi = {0};
 +	nlhpi.cbSize = sizeof(nlhpi);
 +	nlhpi.flags = NLHPIF_HTTP11;
 +	nlhpi.szHttpGetUrl = NULL;
 +	nlhpi.szHttpPostUrl = szHttpPostUrl;
 +	nlhpi.combinePackets = 5;
 +	CallService(MS_NETLIB_SETHTTPPROXYINFO, (WPARAM)hConn, (LPARAM)&nlhpi);
 +}
 +
 +void ThreadData::getGatewayUrl(char* dest, int destlen, bool isPoll)
 +{
 +	static const char openFmtStr[] = "http://%s/gateway/gateway.dll?Action=open&Server=%s&IP=%s";
 +	static const char pollFmtStr[] = "http://%s/gateway/gateway.dll?Action=poll&SessionID=%s";
 +	static const char cmdFmtStr[]  = "http://%s/gateway/gateway.dll?SessionID=%s";
 +
 +	if (mSessionID[0] == 0)
 +	{
 +		const char* svr = mType == SERVER_NOTIFICATION ? "NS" : "SB";
 +		mir_snprintf(dest, destlen, openFmtStr, mGatewayIP, svr, mServer);
 +	}
 +	else
 +		mir_snprintf(dest, destlen, isPoll ? pollFmtStr : cmdFmtStr, mGatewayIP, mSessionID);
 +}
 +
 +void ThreadData::processSessionData(const char* xMsgr, const char* xHost)
 +{
 +	char tSessionID[40], tGateIP[80];
 +
 +	char* tDelim = (char*)strchr(xMsgr, ';');
 +	if (tDelim == NULL)
 +		return;
 +
 +	*tDelim = 0; tDelim += 2;
 +
 +	if (!sscanf(xMsgr, "SessionID=%s", tSessionID))
 +		return;
 +
 +	char* tDelim2 = strchr(tDelim, ';');
 +	if (tDelim2 != NULL)
 +		*tDelim2 = '\0';
 +	if (xHost)
 +		strcpy(tGateIP, xHost);
 +	else if (!sscanf(tDelim, "GW-IP=%s", tGateIP))
 +		return;
 +
 +	strcpy(mGatewayIP, tGateIP);
 +	if (gatewayType) strcpy(mServer, tGateIP);
 +	strcpy(mSessionID, tSessionID);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// thread start code
 +/////////////////////////////////////////////////////////////////////////////////////////
 +
 +void __cdecl CMsnProto::ThreadStub(void* arg)
 +{
 +	ThreadData* info = (ThreadData*)arg;
 +
 +	debugLogA("Starting thread %08X (%08X)", GetCurrentThreadId(), info->mFunc);
 +
 +	(this->*(info->mFunc))(info);
 +
 +	debugLogA("Leaving thread %08X (%08X)", GetCurrentThreadId(), info->mFunc);
 +	{
 +		mir_cslock lck(csThreads);
 +		sttThreads.LIST<ThreadData>::remove(info);
 +	}
 +	delete info;
 +}
 +
 +void ThreadData::startThread(MsnThreadFunc parFunc, CMsnProto *prt)
 +{
 +	mFunc = parFunc;
 +	proto = prt;
 +	{
 +		mir_cslock lck(prt->csThreads);
 +		proto->sttThreads.insert(this);
 +	}
 +	proto->ForkThread(&CMsnProto::ThreadStub, this);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +// HReadBuffer members
 +
 +HReadBuffer::HReadBuffer(ThreadData* T, int iStart)
 +{
 +	owner = T;
 +	buffer = (BYTE*)T->mData;
 +	totalDataSize = T->mBytesInData;
 +	startOffset = iStart;
 +}
 +
 +HReadBuffer::~HReadBuffer()
 +{
 +	if (totalDataSize > startOffset)
 +	{
 +		memmove(buffer, buffer + startOffset, (totalDataSize -= startOffset));
 +		owner->mBytesInData = (int)totalDataSize;
 +	}
 +	else owner->mBytesInData = 0;
 +}
 +
 +BYTE* HReadBuffer::surelyRead(size_t parBytes)
 +{
 +	const size_t bufferSize = sizeof(owner->mData);
 +
 +	if ((startOffset + parBytes) > bufferSize)
 +	{
 +		if (totalDataSize > startOffset)
 +			memmove(buffer, buffer + startOffset, (totalDataSize -= startOffset));
 +		else
 +			totalDataSize = 0;
 +
 +		startOffset = 0;
 +
 +		if (parBytes > bufferSize)
 +		{
 +			owner->proto->debugLogA("HReadBuffer::surelyRead: not enough memory, %d %d %d", parBytes, bufferSize, startOffset);
 +			return NULL;
 +		}
 +	}
 +
 +	while ((startOffset + parBytes) > totalDataSize)
 +	{
 +		int recvResult = owner->recv((char*)buffer + totalDataSize, bufferSize - totalDataSize);
 +
 +		if (recvResult <= 0)
 +			return NULL;
 +
 +		totalDataSize += recvResult;
 +	}
 +
 +	BYTE* result = buffer + startOffset; startOffset += parBytes;
 +	return result;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/msn_ws.cpp b/plugins/!Deprecated/MSN/src/msn_ws.cpp new file mode 100644 index 0000000000..22a4cbc0aa --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_ws.cpp @@ -0,0 +1,180 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2006-2012 Boris Krasnovskiy.
 +Copyright (c) 2003-2005 George Hazan.
 +Copyright (c) 2002-2003 Richard Hughes (original version).
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
 +#include "msn_proto.h"
 +
 +
 +//=======================================================================================
 +
 +int ThreadData::send(const char data[], size_t datalen)
 +{
 +	NETLIBBUFFER nlb = { (char*)data, (int)datalen, 0 };
 +
 +	resetTimeout();
 +
 +	if (proto->usingGateway && !(mType == SERVER_FILETRANS || mType == SERVER_P2P_DIRECT))
 +	{
 +		mGatewayTimeout = 2;
 +		CallService(MS_NETLIB_SETPOLLINGTIMEOUT, WPARAM(s), mGatewayTimeout);
 +	}
 +
 +	int rlen = CallService(MS_NETLIB_SEND, (WPARAM)s, (LPARAM)&nlb);
 +	if (rlen == SOCKET_ERROR)
 +	{
 +		// should really also check if sendlen is the same as datalen
 +		proto->debugLogA("Send failed: %d", WSAGetLastError());
 +		return FALSE;
 +	}
 +
 +	return TRUE;
 +}
 +
 +void ThreadData::resetTimeout(bool term)
 +{
 +	int timeout = term ? 10 : mIsMainThread ? 65 : 120;
 +	mWaitPeriod = clock() + timeout * CLOCKS_PER_SEC;
 +}
 +
 +bool ThreadData::isTimeout(void)
 +{
 +	bool res = false;
 +
 +	if (mWaitPeriod >= clock()) return false;
 +
 +	if (mIsMainThread)
 +	{
 +		res = !proto->usingGateway;
 +	}
 +	else if (mJoinedContactsWLID.getCount() <= 1 || mChatID[0] == 0)
 +	{
 +		MCONTACT hContact = getContactHandle();
 +
 +		if (mJoinedContactsWLID.getCount() == 0 || termPending)
 +			res = true;
 +		else if (proto->p2p_getThreadSession(hContact, mType) != NULL)
 +			res = false;
 +		else if (mType == SERVER_SWITCHBOARD)
 +		{
 +			res = MSN_MsgWndExist(hContact);
 +			if (res)
 +			{
 +				WORD status = proto->getWord(hContact, "Status", ID_STATUS_OFFLINE);
 +				if ((status == ID_STATUS_OFFLINE || status == ID_STATUS_INVISIBLE || proto->m_iStatus == ID_STATUS_INVISIBLE))
 +					res = false;
 +			}
 +		}
 +		else
 +			res = true;
 +	}
 +
 +	if (res)
 +	{
 +		bool sbsess = mType == SERVER_SWITCHBOARD;
 +
 +		proto->debugLogA("Dropping the idle %s due to inactivity", sbsess ? "switchboard" : "p2p");
 +		if (!sbsess || termPending) return true;
 +
 +		if (proto->getByte("EnableSessionPopup", 0))
 +		{
 +			MCONTACT hContact = NULL;
 +			if (mJoinedContactsWLID.getCount())
 +				hContact = proto->MSN_HContactFromEmail(mJoinedContactsWLID[0]);
 +			else if (mInitialContactWLID)
 +				hContact = proto->MSN_HContactFromEmail(mInitialContactWLID);
 +
 +			if (hContact)
 +				proto->MSN_ShowPopup(hContact, TranslateT("Chat session dropped due to inactivity"), 0);
 +		}
 +
 +		sendTerminate();
 +		resetTimeout(true);
 +	}
 +	else
 +		resetTimeout();
 +
 +	return false;
 +}
 +
 +int ThreadData::recv(char* data, size_t datalen)
 +{
 +	NETLIBBUFFER nlb = { data, (int)datalen, 0 };
 +
 +	if (!proto->usingGateway)
 +	{
 +		resetTimeout();
 +		NETLIBSELECT nls = { 0 };
 +		nls.cbSize = sizeof(nls);
 +		nls.dwTimeout = 1000;
 +		nls.hReadConns[0] = s;
 +
 +		for (;;)
 +		{
 +			int ret = CallService(MS_NETLIB_SELECT, 0, (LPARAM)&nls);
 +			if (ret < 0)
 +			{
 +				proto->debugLogA("Connection abortively closed, error %d", WSAGetLastError());
 +				return ret;
 +			}
 +			else if (ret == 0)
 +			{
 +				if (isTimeout()) return 0;
 +			}
 +			else
 +				break;
 +		}
 +	}
 +
 +LBL_RecvAgain:
 +	int ret = CallService(MS_NETLIB_RECV, (WPARAM)s, (LPARAM)&nlb);
 +	if (ret == 0)
 +	{
 +		proto->debugLogA("Connection closed gracefully");
 +		return 0;
 +	}
 +
 +	if (ret < 0)
 +	{
 +		proto->debugLogA("Connection abortively closed, error %d", WSAGetLastError());
 +		return ret;
 +	}
 +
 +	if (proto->usingGateway)
 +	{
 +		if (ret == 1 && *data == 0)
 +		{
 +			if (sessionClosed || isTimeout()) return 0;
 +			if ((mGatewayTimeout += 2) > 20) mGatewayTimeout = 20;
 +
 +			CallService(MS_NETLIB_SETPOLLINGTIMEOUT, WPARAM(s), mGatewayTimeout);
 +			goto LBL_RecvAgain;
 +		}
 +		else
 +		{
 +			resetTimeout();
 +			mGatewayTimeout = 1;
 +			CallService(MS_NETLIB_SETPOLLINGTIMEOUT, WPARAM(s), mGatewayTimeout);
 +		}
 +	}
 +
 +	return ret;
 +}
 diff --git a/plugins/!Deprecated/MSN/src/resource.h b/plugins/!Deprecated/MSN/src/resource.h new file mode 100644 index 0000000000..938a0124b7 --- /dev/null +++ b/plugins/!Deprecated/MSN/src/resource.h @@ -0,0 +1,100 @@ +//{{NO_DEPENDENCIES}}
 +// Microsoft Visual C++ generated include file.
 +// Used by ..\res\msn.rc
 +//
 +#define IDD_CHATROOM_INVITE             40
 +#define IDI_MSN                         101
 +#define IDD_USEROPTS                    104
 +#define IDD_OPT_MSN_CONN                106
 +#define IDD_OPT_NOTIFY                  107
 +#define IDI_MSNBLOCK                    108
 +#define IDI_SERVICES                    109
 +#define IDI_INBOX                       112
 +#define IDI_INVITE                      113
 +#define IDI_NETMEETING                  114
 +#define IDI_PROFILE                     115
 +#define IDD_LISTSMGR                    119
 +#define IDI_LIST_FL                     120
 +#define IDI_LIST_AL                     121
 +#define IDI_LIST_BL                     122
 +#define IDI_LIST_RL                     123
 +#define IDD_CARD_GEN                    133
 +#define IDD_CARD_CONTACT                134
 +#define IDD_ACCMGRUI                    135
 +#define IDD_DELETECONTACT               136
 +#define IDI_LIST_LC                     138
 +#define IDC_MSG                         158
 +#define IDC_CCLIST                      173
 +#define IDC_EDITSCR                     174
 +#define IDC_ADDSCR                      175
 +#define IDD_OPT_MSN                     185
 +#define IDD_SETNICKNAME                 226
 +#define IDC_STMSNGROUP                  1002
 +#define IDC_LIST                        1015
 +#define IDC_ICON_FL                     1016
 +#define IDC_ICON_LC                     1017
 +#define IDC_ICON_AL                     1018
 +#define IDC_ICON_BL                     1019
 +#define IDC_PASSWORD                    1020
 +#define IDC_ICON_RL                     1021
 +#define IDC_PLACE                       1021
 +#define IDC_HANDLE                      1022
 +#define IDC_HANDLE2                     1023
 +#define IDC_SLOWSEND                    1033
 +#define IDC_MANAGEGROUPS                1034
 +#define IDC_NOTIFY_ENDSESSION           1035
 +#define IDC_MOBILESEND                  1035
 +#define IDC_HOSTOPT                     1038
 +#define IDC_CCARD_TAB1                  1039
 +#define IDC_CARD_GEN_PHONE              1043
 +#define IDC_EDIT1                       1043
 +#define IDC_CARD_GEN_IM2                1044
 +#define IDC_EDIT2                       1044
 +#define IDC_EDIT3                       1045
 +#define IDC_COMBO1                      1045
 +#define IDC_SENDFONTINFO                1046
 +#define IDC_EDIT4                       1046
 +#define IDC_REMOVEHOT                   1046
 +#define IDC_EDIT5                       1047
 +#define IDC_REMOVEBLOCK                 1047
 +#define IDC_LISTREFRESH                 1047
 +#define IDC_NICKNAME                    1048
 +#define IDC_EDIT6                       1048
 +#define IDC_DISABLEHOTJUNK              1049
 +#define IDC_EDIT7                       1049
 +#define IDC_EDIT8                       1050
 +#define IDC_COMBO2                      1050
 +#define IDC_EDIT9                       1051
 +#define IDC_CARD_GEN_IM3                1051
 +#define IDC_EDIT10                      1052
 +#define IDC_COMBO3                      1052
 +#define IDC_NOTIFY_FIRSTMSG             1053
 +#define IDC_COMBO4                      1053
 +#define IDC_DISABLE_ANOTHER_CONTACTS    1054
 +#define IDC_CARD_GEN_IM4                1054
 +#define IDC_ERRORS_USING_POPUPS         1056
 +#define IDC_CARD_GEN_IM5                1056
 +#define IDC_MAILER_APP                  1057
 +#define IDC_RUN_APP_ON_HOTMAIL          1058
 +#define IDC_ENTER_MAILER_APP            1059
 +#define IDC_DIRECTSERVER                1171
 +#define IDC_YOURHOST                    1172
 +#define IDC_GATEWAYSERVER               1174
 +#define IDC_DISABLEHOTMAILPOPUP         1301
 +#define IDC_DISABLEHOTMAILTRAY          1302
 +#define IDC_DISABLEHOTMAILCL            1303
 +#define IDC_NEWMSNACCOUNTLINK           1438
 +#define IDC_RESETSERVER                 1472
 +#define IDC_STATIC                      -1
 +
 +// Next default values for new objects
 +// 
 +#ifdef APSTUDIO_INVOKED
 +#ifndef APSTUDIO_READONLY_SYMBOLS
 +#define _APS_NO_MFC                     1
 +#define _APS_NEXT_RESOURCE_VALUE        139
 +#define _APS_NEXT_COMMAND_VALUE         40001
 +#define _APS_NEXT_CONTROL_VALUE         1048
 +#define _APS_NEXT_SYMED_VALUE           101
 +#endif
 +#endif
 diff --git a/plugins/!Deprecated/MSN/src/stdafx.cpp b/plugins/!Deprecated/MSN/src/stdafx.cpp new file mode 100644 index 0000000000..01a3153a4d --- /dev/null +++ b/plugins/!Deprecated/MSN/src/stdafx.cpp @@ -0,0 +1,18 @@ +/*
 +Copyright (C) 2012-14 Miranda NG team (http://miranda-ng.org)
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation version 2
 +of the License.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program. If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "msn_global.h"
\ No newline at end of file diff --git a/plugins/!Deprecated/MSN/src/version.h b/plugins/!Deprecated/MSN/src/version.h new file mode 100644 index 0000000000..f3f5952fe3 --- /dev/null +++ b/plugins/!Deprecated/MSN/src/version.h @@ -0,0 +1,33 @@ +/*
 +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
 +
 +Copyright (c) 2012-2014 Miranda NG Team
 +Copyright (c) 2008-2009 Boris Krasnovskiy.
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#define __MAJOR_VERSION          0
 +#define __MINOR_VERSION          11
 +#define __RELEASE_NUM            1
 +#define __BUILD_NUM              1
 +
 +#include <stdver.h>
 +
 +#define __PLUGIN_NAME            "MSN protocol"
 +#define __DESCRIPTION            "Microsoft Network (MSN) protocol support for Miranda NG."
 +#define __AUTHOR                 "Boris Krasnovskiy, George Hazan, Richard Hughes"
 +#define __AUTHOREMAIL            "borkra@miranda-im.org"
 +#define __COPYRIGHT              "© 2001-2012 Richard Hughes, George Hazan, Boris Krasnovskiy"
 +#define __AUTHORWEB              "http://miranda-ng.org/p/MSN/"
 diff --git a/plugins/PluginUpdater/src/DlgUpdate.cpp b/plugins/PluginUpdater/src/DlgUpdate.cpp index 610afd1d7d..ddcbc48d89 100644 --- a/plugins/PluginUpdater/src/DlgUpdate.cpp +++ b/plugins/PluginUpdater/src/DlgUpdate.cpp @@ -539,6 +539,7 @@ static renameTable[] =  	{ _T("gender.dll"),                     NULL },
  	{ _T("langman.dll"),                    NULL },
  	{ _T("metacontacts.dll"),               NULL },
 +	{ _T("msn.dll"),                        NULL },
  };
  static bool CheckFileRename(const TCHAR *ptszOldName, TCHAR *pNewName)
  | 
