diff options
Diffstat (limited to 'protocols')
333 files changed, 37414 insertions, 21831 deletions
diff --git a/protocols/AimOscar/CMakeLists.txt b/protocols/AimOscar/CMakeLists.txt deleted file mode 100644 index adb9dbb828..0000000000 --- a/protocols/AimOscar/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -file(GLOB SOURCES "src/*.h" "src/*.cpp" "res/*.rc") -set(TARGET AIM) -include(${CMAKE_SOURCE_DIR}/cmake/plugin.cmake) -add_subdirectory(proto_aim)
\ No newline at end of file diff --git a/protocols/AimOscar/docs/changelog.txt b/protocols/AimOscar/docs/changelog.txt deleted file mode 100644 index ff2bf63416..0000000000 --- a/protocols/AimOscar/docs/changelog.txt +++ /dev/null @@ -1,455 +0,0 @@ -AimOSCAR Release 6
-
- *fixed contact list snac parsing error.
- *changed sleep limit on contact adding.
- *Aim links support option now stays unticked.
- *fixed first run dialog tabbing fix.
- *fixed the firstrun dialog to show up at the right time(i.e. before miranda loads).
- *fixed a deferencing of a null pointer that caused a crash during the initiation of file transfers.
- *increased size of the profile dialog.
- *added notification of buddy list modifications.
- *bbcode url additions.
- *modification to non-bbcode converted links.
- *away message removed on status change always.
- *now respects the profile path.
- *group and buddy ids do not delete when a buddy goes offline now(caused addition and deletion failures).
- *context menu item to add buddies that aren't on your list(Yes, it knows whose been naughty and who hasn't been at all)
- *Instant Idler Dialog was added to the main menu. *Instant idle options are mostly found there.
- *Added instant idle on login option.
- *Added icons for html away message, profile, instant idle, and adding buddies
- *Addition/Deletion error code string modifications.
- *Error code 0x02 added to deletion error codes.
- *added popups to replace messageboxes.
- *additional parameters for a bunch of functions - so we can connect to multiple servers.
- *email server connection & check.
- *connection does not attempt to sleep for 5 seconds on all family 4 commands anymore.
- *a bit of cleanup.
- *Modifications to the mail checking.
- *An additional option to set mail checking on login.
- *Main menu item to check mail.
- *Main menu item to manage account- includes changing password.
- *Changed the instant idle icon to one in the round icons (colored) 1.0 by maldi.
- *Added an icon for mail taken from the Yahoo plugin(by Faithhealer I believe) & I changed it's contrast a bit.
- *Modified the aesthetics of the first run dialog.
- *fixes for instant idling- so now regular idling is ignored if instant idling is set.
- *a few migration from toc2 to aimoscar additions.
- *Fixed extra clist icons.
- *Extended status icons now delete on log off instead of the "DisableESIcons" key :-D.
- *Moved ES icons to ADV3 column.
- *fixed timer check at start.
- *lots of html & bbcode conversion fixes.
- *fixes for additions and deletions(when someone has multiple copies of the same buddy on the list).
- *More fixing for extra clist icons.
- *Auto-idle now sets AIM's status to Away if 'Do not reply to requests for this message' is ticked in Options>Status>Status Messages.
- *snac length was incorrect by 6 bytes resulting in login error detection problems.
- *stopped increasing sequence number on packet sending failure- so next packet won't get you kicked.
- *fixed a packet length bug in contact list packet.
- *Stopped removing the MirVer Key on log off.
- *stopped removing extra clist icons on logoff.
- *fixed a bug that caused module deletion to not work and potential addition/deletion bugs.
- *tons of cleanup.
- *compiles with mingwstudio now.
- *no more extra winsock dependencies- created my own htons() and htonl() functions :-).
- *fixed a packet sending race condition resulting in possible kicking.(found by ripoff).
- *replace str functions with lstr functions.
- *fix by borkra for failure to close connection handles on abrupt disconnection..
- *fix for tlv crash(thanks borkra).
- *fixed status fallback issues for offline to any status besides online, away, invis, and offline.
- *aimoscar identifies unknown client's as "?" now.
- *close file transfer socket on failure.
- *cleaned up disconnection code a bit.
- *now if you manually check your mail- you'll get a popup even if you don't have mail.
- *Fixed a bug that caused the unknown user string to overwrite the SMS string.
- *fixed a bug that causes a crash on an buddy addition failure.
- *fixed an accidental usage of utf for non-utf miranda.
- *fixed some group addition bugs.
- *fixed a bug causing unknown to be written over known clients on status change.
- *Offline all contacts on miranda startup(Oops :-D).
- *Changed how aimoscar writes the MirVer string to the db- so that client change notifications don't happen twice.
- *set a timeout for peer connection attempts so that it doesn't attempt for 45* seconds.
- *Fixed a bunch of buffer overruns involving DBVARIANTS.
- *Changed the login order to force aol to send us a list on login.
- *Changed group handling to not move manually added users to their actual group.
- *Changed group handling to not lowercase all server-side group names.
- *Added meebo client detection.
- *Added adium client detection(beta adium only).
- *Modified the gaim/adium detection to show as only gaim detection.
- *Removal of some useless strlcpy() somewhere, and #define all client names.
- *Fixed a potential bug in keepalive sending.
- *lowest keepalive value is now 15 seconds
- *fixed login problems from previous login order change.
- *fixed utf8 sending for aim clients.
-
-------------------------
-
-AimOSCAR Beta 5
-
- * fixed sending the autoaway msg- so it shouldn't result in crashes and crap.
- * Idle and automessage tlv's are now considered to be different things.
- * Instant idle- idles you if you change the setting from off to on now(instead of just when you change the time amount).
- * Options dialog changes.
- * Removed pointless structs in code.
- * Removed some functions that were not used.
- * Replaced malloc() with c++ style memory allocation.
- * Replaced free() with c++ style memory deletion.
- * now use delete[] correctly.
- * addition of a tlv class to make code more maintainable and easier to deal with.
- * major code clean up.
- * removed extra generic services not used- here and there.
- * dynamic memory allocation for all strip and conversion functions.
- * Fixed memleaks here and there.
- * Removal of most static memory buffers- they were approximately 8KB allocation for each.
- * Addition of dynamic memory buffers and small memory buffers.
- * attempted to fix buddy addition.
- * Addition of a snac and flap class.
- * gaim clients now detected as gaim/adium clients.
- * fix options dialog to show up when dialog options are not checked.
- * a buffer overrun no longer occurs if there is no profile.
- * a buffer overrun no longer occurs when viewing things with %n in them.
- * some more reorganization.
-
-------------------------
-
-AimOSCAR Beta 4
-
- * Fixed overlapping text in the options window.
- * Shows the aimoscar icon in the firstrun window now.
- * naim, gaim, aim 5.x, aim 4.x, aim triton, aim express, and aim toc detection.
- * Hiptop users now detected as GPRS clients.
- * Mobile users are now detected as SMS clients.
- * message length limit- so messages don't timeout.
- * error snac now works correctly.
- * error handling for all snac families.
- * %n now changed to a name in auto-away messages.
- * goim links(taken from AimTOC2).
- * modifications to html link handling(No longer strips the title).
- * fixed idling(forgot to flip bytes from host to network byte order).
- * Instant idling option.
- * No longer attempts to grab the away message for people who are offline.
- * Changed the confirmed, unconfirmed, aol, and bot icons.
-
-------------------------
-
-AimOSCAR Beta 3
-
- * modifications for visual studio 2005.
- * added strlcpy and wcslcpy for buffer overrun protection.
- * Modifications to handle aim links.
- * Temporary users now appear online.
- * Contacts are now added correctly when the buddy list is recieved.
- * html to bbcode conversion when a contact messages you for both wide char and ascii messages.
- * bbcode to html conversion when you message a contact for both wide char and ascii messages.
- * bold, italic, underline, and text color natively supported too and from contacts.
- * modified the strip_html functions to remove a possible buffer overrun.
- * fixed the strip_html(wide char) function.
- * if recieve flap type 4 after connection- aimoscar now offlines you and your buddies.
- * fixed a memory leak in find_contact().
- * fixed memory leaks in the packet receiving handler.
- * fixed a memory leak in add_contacts_to_groups().
- * fixed memory leak with sending messages.
- * fixed memory leaks involving the extended and account type icon functions.
- * moved freeing of globally allocated strings to the unload function(should stop some hangings on exit).
- * addition of a first run dialog for entering a username and password(contributed by RiPOFF).
- * Temporary Contacts can now added permanently to the buddy list.
- * Contacts added to the list are now added to their actual server-side group.
- * Fix for a hang in the aim keepalive thread(contributed by borkra).
- * The option title and user info dialogs now use the dll name as the title(use to be hardcoded as 'AimOSCAR').
- * Build time now included in the plugin description.
- * Now idles the user according the idle settings.
- * fixed a memory leak in the proxy file transfer handler.
- * fixed a buffer overrun in the way default away messages are handled.
- * changed the default away message to be the same in all cases.
- * An away message is no longer sent as an autoreply if 'Do not reply to request for this message' is set.
-
-------------------------
-
-AimOSCAR Beta 2
-
- * Doesn't send utf8 text to buddies who don't support it.
- * Contacts are now temporary contacts if they aren't on your buddy list.
- * Doesn't send your away message when a buddy just sent theirs.
- * doesn't add "aolsystemmsg" to your buddy list cause it's a useless piece of crap of a buddy.
- * cleaned up and functionized the code that offlines contacts.
- * cleaned up defines.h.
- * added an option to disable sending autoreplies.
- * some additional code cleaning somewhere.
-
-------------------------
-
-AimOSCAR Beta 1
-
- * Fixed a bug that caused garbage to appear instead of a recieved message.
- * Multiple threads should no longer attempt to close the direct port causing miranda to hang.
- * Added the ability to add buddies back in.
- * Ichat and trillian detection modifications.
- * Added the critical status section back in- I apparently deleted it?
- * Only adds groups to the db if there are db contacts in them.
- * No longer warns you if the username and password are not in the db if you aren't attempting to connect.
- * Now strips away message linebreaks and replaces with html linebreaks.
- * '/r' now removed correctly when stripping linebreaks.
-
-------------------------
-
- AimOSCAR Alpha 8.3
-
- * Ability to send and recieve unicode messages.
- * html characters are stripped from unicode messages.
- * Conversion of greater than and less than symbols to their escape character counterparts for unicode messages.
- * The 'disable extended status icons' now stays checked.
- * 'AimOCAR must be reconnected for this option to take effect' changed to 'AimOSCAR must be...'
- * Additional client detection: Qip, micq, im2, and sim.
- * fixed the aimoscar folders everywhere bug in the profile saving code.
- * connection now only waits a second and up to three seconds for the buddylist to be received
- * removed the on demand server-side group handling because it was a *giant* bottleneck.
- * there should be no more crappy hanging because of server-side handling slowness. Going to have to rehack the whole thing in a better way or something.
- * away message is now sent to buddies when they message.
- * modified the direct port to shutdown before the aol connection- So hopefully that solves the hangs.
- * moved most message box errors over to another thread to stop the blocking behavior.
-
-------------------------
-
-AimOSCAR Alpha 8.2
-
-+Group changes are now modularized - hopefully resulting in a smaller dll.
-+Server now set back to default if set to blank
-+New option to change the default group that contacts are added to in some cases.
-+Now one space instead of two spaces between 'Disable' and 'account' for the "Disable account type icon" option.
-+all additions and deletions of extra icons occur in different threads now
-+removed the 'sleep one second' code I accidently left in along with the old extra icon deletion code.
-+new default for keepalive packets- sent every 1 minute instead of every 7 minutes.
-+option to change the default time keepalive packets are sent.
-+added the ability to change one's profile
-+%n now codes for the user's name in both receiving profiles & away messages.
-+removed useless conversion to text for profiles(for now).
-+carrots now changed into escape character counterparts on send- so that offical clients don't get confused.
-+modified trillian detection to reduce false positives.
-+added ichat detection- no icon
-+Client information is deleted when going offline now.
-+Extended status icons are removed when a buddy goes offline now.
-+Fixed a bug that caused a user to be removed from your list if you changed a group name's case(apparently AOL considers two groups with the same name the same group even if they have case variations)
-+All group comparisions are now case insensitive. In other words, the server-side group doesn't change if you change the group name.
-
--------------------------
-
-AimOSCAR Alpha 8.1(7.2 for Goons)
-
-+icq's set extra status icon works correctly now(clist bug!)
-+changed the hiptop icon to a better one
-+file receiving shouldn't memory leak anymore
-+receiver now knows if a file transfer was cancelled
-+typing notifications(for you bitchy Goons)
-+moved the setting of extra icons to a different thread; so their creation service isn't bogged down causing some to not appear.
-
--------------------------
-
-Alpha 8.0
-
-+AimOSCAR no longer handles any type of rendervous connection as a file transfer connection
-+Added extended status icons to designate unconfirmed, confirmed, AOL, ICQ, and Admin users
-+added extended status icons to designate hiptop and bot users
-+AimOSCAR now identifies Miranda ICQ, Miranda AimOSCAR, Trillian, and Kopete users
-+Direct Connection port is now set to zero after being unaquired.
-+file transfers should now crash less or NEVER, but we'll see.
-+binding to the direct port no longer occurs until you are successfully connected.
-+Added option to disable account type icons.
-+added option to disable extended status icons.
-+added option to masquerade as a hiptop user.
-
--------------------------
-
-AimOSCAR Alpha 7.1
-
--changed main connection to a different thread so that it doesn't cause miranda to hang while AimOSCAR connects.
--moved peer and proxy connection attempts to a different thread to stop freezing.
--fixed a bug that caused hanging if miranda was exited suddenly right after starting.
--AimOSCAR no longer attempts to connect if there is no username or password specified
--AimOSCAR no longer deletes the away message of a contact when one trys to view the contact's profile if that contact doesn't have a profile.
--AimOSCAR Now adds "No Profile" when attempting to view a profile of someone who does not have one.
--fixed a bug that caused viewing html away messages not to work on buddies with spaces in their name.
--If the a user does not send the port tlv with a file transfer request- AimOSCAR no-longer attempts to save the port to the db.
--When cancelling a file AimOSCAR now correctly attempts to grab a byte from the db instead of a word.
--AimOSCAR No longer keeps the direct connection listening port open while disconnected.
--AimOSCAR Now free's all malloc'd memory.
--When connecting to aol's proxy- the connection no longer timesout after the grace period has ended.
--When a file transfer is initiated with a contact and another is attempted- AimOSCAR no longer continues to attempt the second transfer even though it says it won't.
--The File Transfer Key is now removed from the db when a proxy file transfer fails(caused attempts future file transfer attempts to fail).
-
--------------------------
-
-AimOSCAR Alpha 7.0
-
--added display name to the options dialog.
--file transfering added.
--fixed bug that causes process hanging(*ahem* file transfer bug).
--added a 'force proxy transfers' option to the options dialog.
--fixed bug that removed a user's status message from the database when their profile was requested
--added a option to specify grace period or file transfer time out(default-60 seconds, min-15 seconds, max-0xffff seconds)
--caught a bug right before the release; which, caused file transfers to fail in some cases.
--caught another bug that caused Uppercase characters to not be able to be entered in the display name box.
-
--------------------------
-
-Alpha 6.9 -Bug Fix release.
-
--Chatting with Triton users should work(probably AOL users also)
--fixed bug that causes away messages to stay when a user previously was away.
--added online time(feature)
-
--------------------------
-
-Alpha 6.8
-
--no more phantom contacts, and the contact list snac works again.... and brings your ????? groups back again! woohoo!
-
--------------------------
-
-Alpha 6.7
-
--Now sends keepalive packets every 7 minutes. See if this fixes peoples disconnection problems.:-)
-
--------------------------
-
-Alpha 6.6
-
--Changed AimOSCAR to wait five seconds before sending the ssi version to AOL if the contact list snac has not been sent by aol yet.
-
--------------------------
-
-Alpha 6.5
--fixed default group deletion if removing a user from it.
--added a check to see if a group exist before adding it
--fixed the elusive snac_contact_list bug. Apparently, aol sends an extra tlv containing the server-side list version(0x03) if the client already specified it. Because, Miranda is threaded it would sometimes specify it before the contact list was received; and because the extra data was not accounted for a buffer overrun would occur.
--Fixed some group bugs. AimOSCAR would attempt adjust groups after receiving one snac_contact_list packet before; however, AOL apparently can send multiple- so, some buddies would not have group id's specified, etc and madness would happen.
--Added some SNACs that tell the errors aol is giving via msgboxes.
--Status messages are now removed from the database if the contact isn't away anymore.
--Status messages are only retrieved if they are requested by the user now. Via, a call implemented in the core or via the HTML version I implemented. This should resolve issues were AimOSCAR was unable to request any away messages, because it already requested it's limit.
--General group handling improvements.
-
--------------------------
-
-alpha 6.4
-
--checks to see whether a group id exist before deleting a group
--fixed all contacts deletion bug
--forgot to mention in the last version dynamic creation of some module names now occurs on start up so that duplicate code could be removed
-
--------------------------
-
-AimOSCAR alpha 6.3
-
--changes to get groups working correctly again.
--changes to fix connection problems and hanging that can occur-(added some critical sections to prevent duplicate connection threads and restructured some of the code)
--created the SNAc for group deletion.(apparently i forgot to create it....no wonder groups were never deleted)
--Automatically removes empty server-side groups on log in(they will be added to your list before the server-side one is deleted-so expect them add once, but not after that)
--Removes any groups that become empty during the course of the connection to aol.
--Creates groups on the fly when users are added to them... for clarification(this isn't a new feature)
-
--------------------------
-
-Alpha 6.2 release:
-
--Utf Group support- and probably bugs.
--AimOSCAR now tells if no away message is provided by the server(Some contacts do not provide one for some reason on some occasions? I checked this on gaim, and aim 5.9 and they both did not show one either. The away message is apparently absent in the packet sent by AOL even after it is requested.)
--Fixed html appearing in away messages on the buddy list.
--fixed crash that occured when changing status to away if "do not reply to request for this message" was set in the options.
--Message Delivery Confirmation is now disabled by default
--Restructured the code for saving away messages and profiles- it is now contained in the write_away_message and write_profile functions; which, makes reading the SNACs code easier and helps reduce executable size.
-
--------------------------
-
-Alpha 6.1
-
--Now grabs the away message directly from the database if miranda hasn't aquired it yet.
--Removed some check that obviously didn't fix the random connection crashes on the buddy list SNAC.
-
--------------------------
-
-Alpha 6.0
-
--dynamic creation and deletion of cookie, away message storage, protocol name, and current working directory
--Module deletion functions added
--Fixed some bugs with group handling(module deletion fixed these bugs)
--Group deletion added. All buddies in the group that is deleted are moved to the 'Buddies' group.
--Changed group handling to not delete buddies in the 'Buddies' group when that group is deleted.
--'auto response' messages now indicate that they are auto response messages.
--added unique id return capablity to make AimOSCAR compatible with metacontacts.(hopefully)
--turned the the away message handler into a CRITICALSECTION so that it doesn't screw up and not set an away message.(Hopefully)
-
--------------------------
-
-Alpha 5.2 released.
-
--Fixed a nasty bug that caused crashes when attempting to view html away messages.
-
--------------------------
-
-Alpha 5.1
-
--Fixed a bug that caused the search dialog to display garbage names after searching.
-
--------------------------
-
-Alpha 5.0
-
--G++ Compilation
--Idle time now shows correctly
--Doesn't use 16MB of virtual memory anymore
--Added an option to remove message confirmation
--Buddy Addition/Deletion implemented
--Group Addition(Server-side)
--Implemented all backend snacks(or SNACs;-) ) for group/buddy addition/deletion
--Made a small modification to the buddylist SNAC anaylsis to catch(perhaps) a random bug that occurs when retrieving the buddy list after login.
-
--------------------------
-
-Alpha 4.3
-
--Fixed Wireless buddies to show as online(Don't be surprised when you get the two bots that AOL auto add's to your buddy list now... The change I made in the id string-e.g. emulated the offical client id string- caused aol to have THAT spectacular effect)
--And those damnedable directories should be gone for good. Hopefully.
-
--------------------------
-
-Alpha 4.2
-
--Can now see that contacts are idle.(Turn dim idle contacts on)
--Fixed SNAC(03,0B) analysis(see: http://iserverd.khstu.ru/oscar/snac_03_0b.html)- multiple tlv's can now be read.
--On the phone status no longer shows up in the aim menu.
--Now "Is Connecting" status is now shown while AimOSCAR is connecting.
--On the phone, DnD, NA, Occupied, and out to lunch are now linked to away status.
--Free for chat is now linked to Online status.
--In certain circumstances AimOSCAR would become stuck on "Is Connecting"; and would not reconnect until Miranda was restarted.- This should not happen anymore.
-
--------------------------
-
-Alpha 4.1
-
--Users appear in their actual aim groups.(No add, deletion, changing yet.)
-
--------------------------
-
-Alpha 4.0
-
--added groups
--fixed nonworking outgoing messages
-
--------------------------
-
-Alpha 3
-
--Converted to c++, so that I could clean up some of the code
--Away messages should change even if you are already away
--rogue AimOSCAR directories should no longer be created
--'to' was changed to 'too' somewhere in the code
--You should no longer appear as Unknown contact when typing(Re-apply the options)
--mobile people should have mobile status now.
-
--------------------------
-
-Alpha 2(Alpha 1.1)
--?
-
--------------------------
-
-Alpha 1
--initial release
-
diff --git a/protocols/AimOscar/docs/readme.txt b/protocols/AimOscar/docs/readme.txt deleted file mode 100644 index 7713b18ec8..0000000000 --- a/protocols/AimOscar/docs/readme.txt +++ /dev/null @@ -1,104 +0,0 @@ -AIM protocol plugin for Miranda IM
-
-About:
-
-This Miranda IM plugin allows you to connect with AIM
-instant messenger network and communicate with other AIM users.
-It also allows you to connect with other linked AOL networks
-such as, iChat and ICQ.
-
-Supported Statuses:
- -Online
- -Away
- -Invisible
- -Offline
- -idle
-
- Features:
- -Send/Receive messages
- -Addition/Deletion of buddies.
- -File Transfer
- -AOL Mail Checking
- -Instant Message Formatting(With Appropriate Plugins)
- -Away Message & Profile Viewing
- -Aim Links Handling on Websites
-
-Options Overview:
- AIM User Details:
- Screenname- Your account name.
- Display Name- The name you want to show up in your IM conversations.
- Password- Your account password.
- Login Server- The server you are going to login to.(Remove it to reset it).
- AIM Options:
- Message Delivery Confirmation- Whether to have notifications of your message reaching other buddies.
- Do Not Autoreply When Away- Whether to send an away message to a buddy if they message you.
- Convert Incoming Messages to BBCode- Enable if you want to see some formating from your buddies.
- Convert Outgoing Messages to HTML- Enable if you want some formating to be sent to your buddies.
- Disable Account Type Icons-Removes some extra clist icons that are only visible on clist_modern and clist_nicer.
- Disable Extended Status Icons-Removes some extra clist icons that are only visible on clist_modern and clist_nicer.
- Handle aim: links on websites- Enable to allow handling of goim links.
- Check Mail on Login- Enable to have your account email automatically checked on login.
- Advanced Options:
- Keep Alive Timer- The amount of time between each keepalive packet that aim sends.
- File Transfer Grace Period- The amount of time before an inactive connection is disconnected for file transfers.
- Instant Idle on Login- Idles you on login.
- Force Proxy File Transfers- Makes all file transfers go through AOL's proxy server.
- Masquerade as a Sidekick/Hiptop User- Enable to 'fake' that you are on an aim mobile sidekick device.
-
-Main Menu Options Overview:
- Manage Account- Opens the manage your account link on AOL's website.
- Check Mail- Checks your mail for new messages.
- Instant Idle- Let's you specify the amount of hours and minutes you want to set yourself to idle as.
-
-Context Menu Options Overview:
- Add To Server List- Adds a buddy to your server-side buddy list if they aren't already on it.
- File- Let's you send files to the particular buddy.
- Read Profile- Opens a browser window with the specified buddy's profile.
- Read Away Message- Opens a dialog with a text version of the specified buddy's away message.
- Read HTML Away Message- Opens a browser window the the specified buddy's away message.
-
-Contact:
-
-Current developer:
- Boris Krasnovskiy
- Email: borkra@miranda-im.org
-
-Former developer and creator:
- Aaron Myles Landwehr
- Email: aaron@miranda-im.org
- AIM: thegermanaaron
- ICQ: 197688952
- IRC: snaphat @ #miranda @ irc.freenode.net
- JABBER: snaphat@gmail.com
- MSN: whitehata_zz@hotmail.com
- YAHOO: snapdaemon
-
-Thanks (by Aaron Myles Lendwehr):
- -To the numerous bug testers who make it possible for me to code badly and get away with it.
- -To My kitten Mew for typing on the keyboard everytime I try to do something.
- -To the Project members for making the plugin possible to code.
- -To AOL for a badly designed protocol.
- -To Koobs for keeping me smiling(he made me put it).
- -To Kimberly Myers who I love a great deal more than Anything else.
- -To Elise Bader for being the greatest secret holder and friend ever.
-
-License and Copyright
-_____________________
-
-Copyright (C) 2008-2009 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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.
-
\ No newline at end of file diff --git a/protocols/AimOscar/proto_aim/CMakeLists.txt b/protocols/AimOscar/proto_aim/CMakeLists.txt deleted file mode 100644 index 883d656e17..0000000000 --- a/protocols/AimOscar/proto_aim/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -set(TARGET Proto_AIM) -include(${CMAKE_SOURCE_DIR}/cmake/icons.cmake)
\ No newline at end of file diff --git a/protocols/AimOscar/proto_aim/Proto_AIM.vcxproj b/protocols/AimOscar/proto_aim/Proto_AIM.vcxproj deleted file mode 100644 index a37a52b7e8..0000000000 --- a/protocols/AimOscar/proto_aim/Proto_AIM.vcxproj +++ /dev/null @@ -1,28 +0,0 @@ -<?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>Proto_AIM</ProjectName>
- <ProjectGuid>{975505EA-F0C7-4DAC-A95E-75249615F30C}</ProjectGuid>
- </PropertyGroup>
- <ImportGroup Label="PropertySheets">
- <Import Project="$(ProjectDir)..\..\..\build\vc.common\icons.props" />
- </ImportGroup>
-</Project>
\ No newline at end of file diff --git a/protocols/AimOscar/proto_aim/res/Away.ico b/protocols/AimOscar/proto_aim/res/Away.ico Binary files differdeleted file mode 100644 index 9f668b4fe7..0000000000 --- a/protocols/AimOscar/proto_aim/res/Away.ico +++ /dev/null diff --git a/protocols/AimOscar/proto_aim/res/Invisible.ico b/protocols/AimOscar/proto_aim/res/Invisible.ico Binary files differdeleted file mode 100644 index 5c298d2e4e..0000000000 --- a/protocols/AimOscar/proto_aim/res/Invisible.ico +++ /dev/null diff --git a/protocols/AimOscar/proto_aim/res/Offline.ico b/protocols/AimOscar/proto_aim/res/Offline.ico Binary files differdeleted file mode 100644 index 54fabffaa7..0000000000 --- a/protocols/AimOscar/proto_aim/res/Offline.ico +++ /dev/null diff --git a/protocols/AimOscar/proto_aim/res/Online.ico b/protocols/AimOscar/proto_aim/res/Online.ico Binary files differdeleted file mode 100644 index 429afcc9ff..0000000000 --- a/protocols/AimOscar/proto_aim/res/Online.ico +++ /dev/null diff --git a/protocols/AimOscar/proto_aim/res/Phone.ico b/protocols/AimOscar/proto_aim/res/Phone.ico Binary files differdeleted file mode 100644 index 5c568d67bf..0000000000 --- a/protocols/AimOscar/proto_aim/res/Phone.ico +++ /dev/null diff --git a/protocols/AimOscar/proto_aim/res/Proto_AIM.rc b/protocols/AimOscar/proto_aim/res/Proto_AIM.rc deleted file mode 100644 index 14e5082d07..0000000000 --- a/protocols/AimOscar/proto_aim/res/Proto_AIM.rc +++ /dev/null @@ -1,73 +0,0 @@ -// 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 "Online.ico"
-IDI_ICON2 ICON "Offline.ico"
-IDI_ICON3 ICON "Away.ico"
-IDI_ICON4 ICON "Invisible.ico"
-IDI_ICON5 ICON "Phone.ico"
-#endif // Russian (Russia) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif // not APSTUDIO_INVOKED
-
diff --git a/protocols/AimOscar/proto_aim/src/resource.h b/protocols/AimOscar/proto_aim/src/resource.h deleted file mode 100644 index d63bb1cdec..0000000000 --- a/protocols/AimOscar/proto_aim/src/resource.h +++ /dev/null @@ -1,20 +0,0 @@ -//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by Proto_AIM.rc
-//
-#define IDI_ICON1 104
-#define IDI_ICON2 105
-#define IDI_ICON3 128
-#define IDI_ICON4 130
-#define IDI_ICON5 1002
-
-// Next default values for new objects
-//
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 106
-#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1001
-#define _APS_NEXT_SYMED_VALUE 101
-#endif
-#endif
diff --git a/protocols/AimOscar/res/add.ico b/protocols/AimOscar/res/add.ico Binary files differdeleted file mode 100644 index fcfa03a6ad..0000000000 --- a/protocols/AimOscar/res/add.ico +++ /dev/null diff --git a/protocols/AimOscar/res/admin.ico b/protocols/AimOscar/res/admin.ico Binary files differdeleted file mode 100644 index b788d40de6..0000000000 --- a/protocols/AimOscar/res/admin.ico +++ /dev/null diff --git a/protocols/AimOscar/res/aim.rc b/protocols/AimOscar/res/aim.rc deleted file mode 100755 index dbef88d58a..0000000000 --- a/protocols/AimOscar/res/aim.rc +++ /dev/null @@ -1,403 +0,0 @@ -// 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
-
-/////////////////////////////////////////////////////////////////////////////
-// Englisch (USA) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-
-#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
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Dialog
-//
-
-IDD_AIM DIALOGEX 0, 0, 305, 212
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
-EXSTYLE WS_EX_CONTROLPARENT
-FONT 8, "MS Shell Dlg", 0, 0, 0x1
-BEGIN
- GROUPBOX "AIM user details",IDC_DETAILS,3,7,147,72,WS_GROUP
- RTEXT "Screen name:",IDC_STATIC,8,20,50,11
- EDITTEXT IDC_SN,60,17,87,15,ES_LOWERCASE | ES_AUTOHSCROLL
- RTEXT "Display name:",IDC_STATIC,8,39,50,9
- EDITTEXT IDC_NK,60,37,87,15,ES_AUTOHSCROLL
- RTEXT "Password:",IDC_STATIC,8,59,50,11
- EDITTEXT IDC_PW,60,57,87,15,ES_PASSWORD | ES_AUTOHSCROLL
- GROUPBOX "AIM options",IDC_OPTIONS,3,83,147,120,WS_GROUP
- CONTROL "Message delivery confirmation",IDC_DC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,93,139,13
- CONTROL "Do not autoreply when away",IDC_DM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,105,139,13
- CONTROL "Convert incoming messages to BBCode",IDC_FI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,117,139,13
- CONTROL "Convert outgoing messages to HTML",IDC_FO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,129,139,13
- CONTROL "Disable avatars",IDC_DA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,141,139,13
- CONTROL "Disable account type icons",IDC_AT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,153,139,13
- CONTROL "Disable extended status icons",IDC_ES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,165,139,13
- CONTROL "Notify about new mail",IDC_CM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,177,139,13
- CONTROL "Manage server groups",IDC_MG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,188,139,13
- GROUPBOX "Advanced options",IDC_EXPERT,154,7,145,72,WS_GROUP
- CONTROL "Instant idle on login",IDC_II,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,157,18,138,15
- CONTROL "Force proxy file transfers",IDC_FP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,157,33,138,11
- CONTROL "Masquerade as a Sidekick/Hiptop user",IDC_HF,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,157,46,138,13
- GROUPBOX "Connection",IDC_STATIC,154,83,145,80
- RTEXT "Login server:",IDC_STATIC,157,98,52,12
- EDITTEXT IDC_HN,212,96,83,13,ES_AUTOHSCROLL
- RTEXT "Port:",IDC_STATIC,157,115,52,12
- EDITTEXT IDC_PN,212,113,38,13,ES_AUTOHSCROLL
- PUSHBUTTON "Reset",IDC_SVRRESET,260,112,35,14
- CONTROL "Disable SSL",IDC_DSSL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,157,129,138,10
- CONTROL "Force single client",IDC_FSC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,157,149,138,10
- CONTROL "Use ""clientlogin"" (recommended)",IDC_CLIENTLOGIN,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,157,139,138,10
- CTEXT "* Some changes will take effect the next time you connect to the AIM network",IDC_MASQ,157,168,138,28,NOT WS_VISIBLE
-END
-
-IDD_INFO DIALOGEX 0, 0, 227, 165
-STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
-EXSTYLE WS_EX_CONTROLPARENT | WS_EX_APPWINDOW
-FONT 8, "MS Shell Dlg", 0, 0, 0x0
-BEGIN
- PUSHBUTTON "Save profile",IDC_SETPROFILE,157,4,60,30,WS_DISABLED
- CONTROL "",IDC_PROFILE,"RichEdit50W",WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | 0x11c4,4,36,213,112
- CONTROL "",IDC_BOLD,"Button",BS_OWNERDRAW,4,4,16,14,WS_EX_RIGHT
- CONTROL "",IDC_ITALIC,"Button",BS_OWNERDRAW,20,4,16,14,WS_EX_RIGHT
- CONTROL "",IDC_UNDERLINE,"Button",BS_OWNERDRAW,36,4,16,14,WS_EX_RIGHT
- CONTROL "",IDC_SUPERSCRIPT,"Button",BS_OWNERDRAW,52,4,16,14,WS_EX_RIGHT
- CONTROL "",IDC_SUBSCRIPT,"Button",BS_OWNERDRAW,84,4,16,14,WS_EX_RIGHT
- CONTROL "",IDC_FOREGROUNDCOLOR,"Button",BS_OWNERDRAW,100,4,16,14,WS_EX_RIGHT
- CONTROL "",IDC_FOREGROUNDCOLORPICKER,"Button",BS_OWNERDRAW,116,4,10,14,WS_EX_RIGHT
- CONTROL "",IDC_BACKGROUNDCOLOR,"Button",BS_OWNERDRAW,126,4,16,14,WS_EX_RIGHT
- CONTROL "",IDC_BACKGROUNDCOLORPICKER,"Button",BS_OWNERDRAW,142,4,10,14,WS_EX_RIGHT
- COMBOBOX IDC_TYPEFACE,4,21,112,117,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
- COMBOBOX IDC_FONTSIZE,126,21,26,117,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
- CONTROL "",IDC_NORMALSCRIPT,"Button",BS_OWNERDRAW,68,4,16,14,WS_EX_RIGHT
-END
-
-IDD_AIMACCOUNT DIALOGEX 0, 0, 186, 134
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
-EXSTYLE WS_EX_CONTROLPARENT
-FONT 8, "MS Shell Dlg", 0, 0, 0x0
-BEGIN
- LTEXT "Screen name:",IDC_STATIC,0,0,53,12
- EDITTEXT IDC_SN,54,0,131,12,ES_AUTOHSCROLL
- LTEXT "Password:",IDC_STATIC,0,16,53,12
- EDITTEXT IDC_PW,54,16,131,12,ES_PASSWORD | ES_AUTOHSCROLL
- CONTROL "Create a new AIM account",IDC_NEWAIMACCOUNTLINK,
- "Hyperlink",WS_TABSTOP,0,40,174,12
-END
-
-IDD_IDLE DIALOGEX 0, 0, 173, 74
-STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
-EXSTYLE WS_EX_TOPMOST
-CAPTION "AIM instant idler"
-FONT 8, "MS Shell Dlg", 0, 0, 0x0
-BEGIN
- EDITTEXT IDC_IIH,86,11,28,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT
- LTEXT "Number of hours:",IDC_STATIC,18,13,62,12
- LTEXT "Number of minutes:",IDC_STATIC,12,29,64,12
- EDITTEXT IDC_IIM,86,28,28,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT
- DEFPUSHBUTTON "Set idle",IDOK,78,50,46,14
- PUSHBUTTON "Unset idle",IDCANCEL,129,50,39,14
-END
-
-IDD_PRIVACY DIALOGEX 0, 0, 305, 220
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
-EXSTYLE WS_EX_CONTROLPARENT
-FONT 8, "MS Shell Dlg", 0, 0, 0x1
-BEGIN
- LTEXT "Users who can contact me:",IDC_STATIC,14,14,282,8
- CONTROL "Allow all users",IDC_ALLOWALL,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,14,29,159,10
- CONTROL "Allow only users on contact list",IDC_ALLOWCONT,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,14,40,159,10
- CONTROL "Allow only users below",IDC_ALLOWBELOW,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,14,51,159,10
- CONTROL "Block all users",IDC_BLOCKALL,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,177,40,121,10
- CONTROL "Block only users below",IDC_BLOCKBELOW,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,177,51,121,10
- EDITTEXT IDC_ALLOWEDIT,16,67,82,14,ES_AUTOHSCROLL,WS_EX_CLIENTEDGE | WS_EX_STATICEDGE
- PUSHBUTTON "Add",IDC_ALLOWADD,98,67,38,14
- LISTBOX IDC_ALLOWLIST,16,81,119,86,LBS_SORT | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP,WS_EX_STATICEDGE
- PUSHBUTTON "Remove",IDC_ALLOWREMOVE,16,167,119,12
- EDITTEXT IDC_BLOCKEDIT,177,66,82,14,ES_AUTOHSCROLL,WS_EX_STATICEDGE
- PUSHBUTTON "Add",IDC_BLOCKADD,259,66,37,14
- LISTBOX IDC_BLOCKLIST,177,80,119,86,LBS_SORT | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP,WS_EX_STATICEDGE
- PUSHBUTTON "Remove",IDC_BLOCKREMOVE,177,166,119,12
- CONTROL "Idle",IDC_SIS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,197,119,9
- LTEXT "Allow contacts to be notified of:",IDC_STATIC,14,185,284,8
-END
-
-IDD_CHAT DIALOGEX 0, 0, 162, 82
-STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
-EXSTYLE WS_EX_TOPMOST
-CAPTION "Join chat room"
-FONT 8, "MS Shell Dlg", 0, 0, 0x0
-BEGIN
- LTEXT "Chat room",IDC_STATIC,7,10,86,9
- EDITTEXT IDC_ROOM,6,26,96,12,ES_LOWERCASE | ES_AUTOHSCROLL
- DEFPUSHBUTTON "&Join",IDOK,110,6,46,14
- PUSHBUTTON "&Cancel",IDCANCEL,110,24,45,14
- LTEXT "This allows access to user defined chat rooms. To access predefined chat rooms use web links",IDC_STATIC,5,49,150,25
-END
-
-IDD_ADMIN DIALOGEX 0, 0, 224, 147
-STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | DS_CENTER | WS_CHILD
-EXSTYLE WS_EX_CONTROLPARENT
-FONT 8, "MS Shell Dlg", 0, 0, 0x0
-BEGIN
- GROUPBOX "Change password",IDC_STATIC,2,2,101,103
- LTEXT "Original",IDC_STATIC,8,14,87,8
- EDITTEXT IDC_CPW,5,23,90,14,ES_PASSWORD | ES_AUTOHSCROLL
- LTEXT "New",IDC_STATIC,7,40,87,8
- EDITTEXT IDC_NPW1,5,49,90,14,ES_PASSWORD | ES_AUTOHSCROLL
- LTEXT "Repeat",IDC_STATIC,7,65,88,8
- EDITTEXT IDC_NPW2,5,74,90,14,ES_PASSWORD | ES_AUTOHSCROLL
- LTEXT "*Passwords don't match.",IDC_PINFO,7,92,82,9,NOT WS_VISIBLE
- LTEXT "Screen name",IDC_STATIC,118,15,92,8
- EDITTEXT IDC_FNAME,117,23,93,14,ES_AUTOHSCROLL
- LTEXT "E-mail",IDC_STATIC,118,41,92,8
- EDITTEXT IDC_CEMAIL,117,49,93,14,ES_AUTOHSCROLL
- PUSHBUTTON "Confirm account",IDC_CONFIRM,5,122,86,16,BS_MULTILINE
- LTEXT "*Applied upon reconnect",IDC_STATIC,127,109,80,8
- PUSHBUTTON "Save changes",IDC_SAVECHANGES,131,122,79,16
-END
-
-IDD_CHATROOM_INVITE DIALOGEX 0, 0, 302, 125
-STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU
-EXSTYLE WS_EX_TOPMOST
-CAPTION "Invite buddy to chat room"
-FONT 8, "MS Shell Dlg", 0, 0, 0x0
-BEGIN
- LTEXT "Screen name",IDC_STATIC,154,31,43,9
- PUSHBUTTON "&Invite",IDOK,165,107,46,14
- PUSHBUTTON "&Cancel",IDCANCEL,234,107,45,14
- LTEXT "Invitation reason",IDC_STATIC,155,58,60,9
- EDITTEXT IDC_MSG,154,68,140,32,ES_MULTILINE | ES_LOWERCASE | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL
- CONTROL "",IDC_CCLIST,"CListControl",WS_TABSTOP | 0x16f,7,4,141,117,WS_EX_CLIENTEDGE
- EDITTEXT IDC_EDITSCR,154,41,93,12,ES_AUTOHSCROLL
- PUSHBUTTON "Add",IDC_ADDSCR,247,40,49,14
- CTEXT "",IDC_ROOMNAME,154,10,140,11,0,WS_EX_STATICEDGE
-END
-
-IDD_CHATROOM_INVITE_REQ DIALOGEX 0, 0, 177, 116
-STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION
-EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
-CAPTION "Chat room invitation request"
-FONT 8, "MS Shell Dlg", 0, 0, 0x0
-BEGIN
- DEFPUSHBUTTON "&Join",IDOK,77,97,46,14
- PUSHBUTTON "&Deny",IDCANCEL,125,97,45,14
- LTEXT "Message",IDC_STATIC,6,40,60,9
- CTEXT "",IDC_ROOMNAME,80,4,93,12,SS_SUNKEN
- EDITTEXT IDC_MSG,6,50,166,40,ES_MULTILINE | ES_LOWERCASE | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | WS_HSCROLL
- LTEXT "Room",IDC_STATIC,5,6,73,8
- LTEXT "Screen name",IDC_STATIC,5,24,73,8
- CTEXT "",IDC_SCREENNAME,80,22,93,12,SS_SUNKEN
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// DESIGNINFO
-//
-
-#ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO
-BEGIN
- IDD_AIM, DIALOG
- BEGIN
- RIGHTMARGIN, 299
- VERTGUIDE, 8
- VERTGUIDE, 58
- VERTGUIDE, 60
- VERTGUIDE, 147
- VERTGUIDE, 154
- VERTGUIDE, 157
- VERTGUIDE, 209
- VERTGUIDE, 212
- VERTGUIDE, 295
- BOTTOMMARGIN, 206
- END
-
- IDD_INFO, DIALOG
- BEGIN
- END
-
- IDD_AIMACCOUNT, DIALOG
- BEGIN
- RIGHTMARGIN, 183
- BOTTOMMARGIN, 72
- END
-
- IDD_IDLE, DIALOG
- BEGIN
- RIGHTMARGIN, 172
- BOTTOMMARGIN, 73
- END
-
- IDD_PRIVACY, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 298
- VERTGUIDE, 14
- VERTGUIDE, 173
- VERTGUIDE, 177
- VERTGUIDE, 296
- TOPMARGIN, 7
- BOTTOMMARGIN, 213
- END
-
- IDD_CHAT, DIALOG
- BEGIN
- RIGHTMARGIN, 155
- BOTTOMMARGIN, 80
- END
-
- IDD_ADMIN, DIALOG
- BEGIN
- RIGHTMARGIN, 223
- BOTTOMMARGIN, 146
- END
-
- IDD_CHATROOM_INVITE, DIALOG
- BEGIN
- RIGHTMARGIN, 300
- TOPMARGIN, 4
- BOTTOMMARGIN, 121
- END
-
- IDD_CHATROOM_INVITE_REQ, DIALOG
- BEGIN
- BOTTOMMARGIN, 111
- END
-END
-#endif // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Icon
-//
-
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-IDI_AIM ICON "oscar.ico"
-
-IDI_ADD ICON "add.ico"
-
-IDI_ICQ ICON "icq.ico"
-
-IDI_AOL ICON "aol.ico"
-
-IDI_HIPTOP ICON "hiptop.ico"
-
-IDI_BOT ICON "bot.ico"
-
-IDI_ADMIN ICON "admin.ico"
-
-IDI_CONFIRMED ICON "confirmed.ico"
-
-IDI_UNCONFIRMED ICON "unconfirmed.ico"
-
-IDI_AWAY ICON "away.ico"
-
-IDI_IDLE ICON "idle.ico"
-
-IDI_PROFILE ICON "profile.ico"
-
-IDI_MAIL ICON "inbox.ico"
-
-IDI_BOLD ICON "bold.ico"
-
-IDI_NBOLD ICON "nbold.ico"
-
-IDI_NITALIC ICON "nitalic.ico"
-
-IDI_ITALIC ICON "italic.ico"
-
-IDI_NUNDERLINE ICON "nunderline.ico"
-
-IDI_UNDERLINE ICON "underline.ico"
-
-IDI_NSUPERSCRIPT ICON "nsuperscript.ico"
-
-IDI_NSUBSCRIPT ICON "nsubscript.ico"
-
-IDI_FOREGROUNDCOLOR ICON "foregroundcolor.ico"
-
-IDI_BACKGROUNDCOLOR ICON "backgroundcolor.ico"
-
-IDI_NNORMALSCRIPT ICON "nnormalscript.ico"
-
-IDI_NORMALSCRIPT ICON "normalscript.ico"
-
-IDI_SUBSCRIPT ICON "subscript.ico"
-
-IDI_SUPERSCRIPT ICON "superscript.ico"
-
-IDI_BLOCK ICON "block.ico"
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// AFX_DIALOG_LAYOUT
-//
-
-IDD_AIM AFX_DIALOG_LAYOUT
-BEGIN
- 0
-END
-
-IDD_PRIVACY AFX_DIALOG_LAYOUT
-BEGIN
- 0
-END
-
-#endif // Englisch (USA) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif // not APSTUDIO_INVOKED
-
diff --git a/protocols/AimOscar/res/aol.ico b/protocols/AimOscar/res/aol.ico Binary files differdeleted file mode 100644 index 7d63eb3ad5..0000000000 --- a/protocols/AimOscar/res/aol.ico +++ /dev/null diff --git a/protocols/AimOscar/res/away.ico b/protocols/AimOscar/res/away.ico Binary files differdeleted file mode 100644 index 1b0a10ac26..0000000000 --- a/protocols/AimOscar/res/away.ico +++ /dev/null diff --git a/protocols/AimOscar/res/backgroundcolor.ico b/protocols/AimOscar/res/backgroundcolor.ico Binary files differdeleted file mode 100644 index ae4c4d25de..0000000000 --- a/protocols/AimOscar/res/backgroundcolor.ico +++ /dev/null diff --git a/protocols/AimOscar/res/block.ico b/protocols/AimOscar/res/block.ico Binary files differdeleted file mode 100644 index 6e7becdd69..0000000000 --- a/protocols/AimOscar/res/block.ico +++ /dev/null diff --git a/protocols/AimOscar/res/bold.ico b/protocols/AimOscar/res/bold.ico Binary files differdeleted file mode 100644 index 63810159f9..0000000000 --- a/protocols/AimOscar/res/bold.ico +++ /dev/null diff --git a/protocols/AimOscar/res/bot.ico b/protocols/AimOscar/res/bot.ico Binary files differdeleted file mode 100644 index e9dd0c14e1..0000000000 --- a/protocols/AimOscar/res/bot.ico +++ /dev/null diff --git a/protocols/AimOscar/res/confirmed.ico b/protocols/AimOscar/res/confirmed.ico Binary files differdeleted file mode 100644 index c33fc0317d..0000000000 --- a/protocols/AimOscar/res/confirmed.ico +++ /dev/null diff --git a/protocols/AimOscar/res/foregroundcolor.ico b/protocols/AimOscar/res/foregroundcolor.ico Binary files differdeleted file mode 100644 index b75015154a..0000000000 --- a/protocols/AimOscar/res/foregroundcolor.ico +++ /dev/null diff --git a/protocols/AimOscar/res/hiptop.ico b/protocols/AimOscar/res/hiptop.ico Binary files differdeleted file mode 100644 index 266c9d1ecc..0000000000 --- a/protocols/AimOscar/res/hiptop.ico +++ /dev/null diff --git a/protocols/AimOscar/res/icq.ico b/protocols/AimOscar/res/icq.ico Binary files differdeleted file mode 100644 index d3a9597771..0000000000 --- a/protocols/AimOscar/res/icq.ico +++ /dev/null diff --git a/protocols/AimOscar/res/idle.ico b/protocols/AimOscar/res/idle.ico Binary files differdeleted file mode 100644 index 19be9acb30..0000000000 --- a/protocols/AimOscar/res/idle.ico +++ /dev/null diff --git a/protocols/AimOscar/res/inbox.ico b/protocols/AimOscar/res/inbox.ico Binary files differdeleted file mode 100644 index 7a5e461f6f..0000000000 --- a/protocols/AimOscar/res/inbox.ico +++ /dev/null diff --git a/protocols/AimOscar/res/italic.ico b/protocols/AimOscar/res/italic.ico Binary files differdeleted file mode 100644 index 42d3fea61b..0000000000 --- a/protocols/AimOscar/res/italic.ico +++ /dev/null diff --git a/protocols/AimOscar/res/nbold.ico b/protocols/AimOscar/res/nbold.ico Binary files differdeleted file mode 100644 index dcdd5ce175..0000000000 --- a/protocols/AimOscar/res/nbold.ico +++ /dev/null diff --git a/protocols/AimOscar/res/nitalic.ico b/protocols/AimOscar/res/nitalic.ico Binary files differdeleted file mode 100644 index 6fd9fc46af..0000000000 --- a/protocols/AimOscar/res/nitalic.ico +++ /dev/null diff --git a/protocols/AimOscar/res/nnormalscript.ico b/protocols/AimOscar/res/nnormalscript.ico Binary files differdeleted file mode 100644 index b4bc629440..0000000000 --- a/protocols/AimOscar/res/nnormalscript.ico +++ /dev/null diff --git a/protocols/AimOscar/res/normalscript.ico b/protocols/AimOscar/res/normalscript.ico Binary files differdeleted file mode 100644 index a7e17f28c3..0000000000 --- a/protocols/AimOscar/res/normalscript.ico +++ /dev/null diff --git a/protocols/AimOscar/res/nsubscript.ico b/protocols/AimOscar/res/nsubscript.ico Binary files differdeleted file mode 100644 index f4921ec32d..0000000000 --- a/protocols/AimOscar/res/nsubscript.ico +++ /dev/null diff --git a/protocols/AimOscar/res/nsuperscript.ico b/protocols/AimOscar/res/nsuperscript.ico Binary files differdeleted file mode 100644 index 554ec49bac..0000000000 --- a/protocols/AimOscar/res/nsuperscript.ico +++ /dev/null diff --git a/protocols/AimOscar/res/nunderline.ico b/protocols/AimOscar/res/nunderline.ico Binary files differdeleted file mode 100644 index a67fc3219b..0000000000 --- a/protocols/AimOscar/res/nunderline.ico +++ /dev/null diff --git a/protocols/AimOscar/res/oscar.ico b/protocols/AimOscar/res/oscar.ico Binary files differdeleted file mode 100644 index 429afcc9ff..0000000000 --- a/protocols/AimOscar/res/oscar.ico +++ /dev/null diff --git a/protocols/AimOscar/res/profile.ico b/protocols/AimOscar/res/profile.ico Binary files differdeleted file mode 100644 index 2056f57798..0000000000 --- a/protocols/AimOscar/res/profile.ico +++ /dev/null diff --git a/protocols/AimOscar/res/subscript.ico b/protocols/AimOscar/res/subscript.ico Binary files differdeleted file mode 100644 index c7b2240b98..0000000000 --- a/protocols/AimOscar/res/subscript.ico +++ /dev/null diff --git a/protocols/AimOscar/res/superscript.ico b/protocols/AimOscar/res/superscript.ico Binary files differdeleted file mode 100644 index a1a282bba8..0000000000 --- a/protocols/AimOscar/res/superscript.ico +++ /dev/null diff --git a/protocols/AimOscar/res/unconfirmed.ico b/protocols/AimOscar/res/unconfirmed.ico Binary files differdeleted file mode 100644 index 102d481687..0000000000 --- a/protocols/AimOscar/res/unconfirmed.ico +++ /dev/null diff --git a/protocols/AimOscar/res/underline.ico b/protocols/AimOscar/res/underline.ico Binary files differdeleted file mode 100644 index 646d58456d..0000000000 --- a/protocols/AimOscar/res/underline.ico +++ /dev/null diff --git a/protocols/AimOscar/res/version.rc b/protocols/AimOscar/res/version.rc deleted file mode 100644 index fdeb14668c..0000000000 --- a/protocols/AimOscar/res/version.rc +++ /dev/null @@ -1,55 +0,0 @@ -// Microsoft Visual C++ generated resource script.
-//
-#ifdef APSTUDIO_INVOKED
-#error this file is not editable by Microsoft Visual C++
-#endif //APSTUDIO_INVOKED
-
-#include "..\src\version.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-#include "afxres.h"
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (U.S.) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-#endif //_WIN32
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION __FILEVERSION_STRING
- PRODUCTVERSION __FILEVERSION_STRING
- FILEFLAGSMASK 0x17L
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x2L
- FILESUBTYPE 0x0L
-BEGIN
- BLOCK "StringFileInfo"
- BEGIN
- BLOCK "000004b0"
- BEGIN
- VALUE "Author", __AUTHOR
- VALUE "FileDescription", __DESCRIPTION
- VALUE "FileVersion", __VERSION_STRING
- VALUE "InternalName", __PLUGIN_NAME
- VALUE "LegalCopyright", __COPYRIGHT
- VALUE "OriginalFilename", __FILENAME
- VALUE "ProductName", __PLUGIN_NAME
- END
- END
- BLOCK "VarFileInfo"
- BEGIN
- VALUE "Translation", 0x0, 1200
- END
-END
-
-#endif // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
diff --git a/protocols/AimOscar/src/aim.cpp b/protocols/AimOscar/src/aim.cpp deleted file mode 100644 index c169e47aa4..0000000000 --- a/protocols/AimOscar/src/aim.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2012 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 "stdafx.h"
-
-char AIM_CAP_MIRANDA[16] = "MirandaA";
-
-int hLangpack;
-
-CLIST_INTERFACE *pcli;
-HINSTANCE hInstance;
-
-/////////////////////////////////////////////////////////////////////////////
-// Protocol instances
-static int sttCompareProtocols(const CAimProto *p1, const CAimProto *p2)
-{
- return mir_wstrcmp(p1->m_tszUserName, p2->m_tszUserName);
-}
-
-OBJLIST<CAimProto> g_Instances(1, sttCompareProtocols);
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Dll entry point
-
-BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD /*fdwReason*/, LPVOID /*lpvReserved*/)
-{
- hInstance = hinstDLL;
- return TRUE;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Plugin information
-
-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,
- // {3750A5A3-BF0D-490E-B65D-41AC4D29AEB3}
- {0x3750a5a3, 0xbf0d, 0x490e, {0xb6, 0x5d, 0x41, 0xac, 0x4d, 0x29, 0xae, 0xb3}}
-};
-
-extern "C" __declspec(dllexport) const PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion)
-{
- *(unsigned long*)(&AIM_CAP_MIRANDA[8]) = _htonl(mirandaVersion);
- *(unsigned long*)(&AIM_CAP_MIRANDA[12]) = _htonl(PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM));
- return &pluginInfo;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Interface information
-
-extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST };
-
-////////////////////////////////////////////////////////////////////////////////////////
-// OnModulesLoaded - finalizes plugin's configuration on load
-
-static int OnModulesLoaded(WPARAM, LPARAM)
-{
- aim_links_init();
- return 0;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Load
-
-static PROTO_INTERFACE* protoInit(const char* pszProtoName, const wchar_t* tszUserName)
-{
- CAimProto *ppro = new CAimProto(pszProtoName, tszUserName);
- g_Instances.insert(ppro);
- return ppro;
-}
-
-static int protoUninit(PROTO_INTERFACE* ppro)
-{
- g_Instances.remove((CAimProto*)ppro);
- return 0;
-}
-
-extern "C" int __declspec(dllexport) Load(void)
-{
- mir_getLP(&pluginInfo);
- pcli = Clist_GetInterface();
-
- HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded);
-
- PROTOCOLDESCRIPTOR pd = { 0 };
- pd.cbSize = sizeof(pd);
- pd.szName = "AIM";
- pd.type = PROTOTYPE_PROTOCOL;
- pd.fnInit = protoInit;
- pd.fnUninit = protoUninit;
- Proto_RegisterModule(&pd);
-
- InitIcons();
- InitExtraIcons();
- return 0;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Unload
-
-extern "C" int __declspec(dllexport) Unload(void)
-{
- return 0;
-}
diff --git a/protocols/AimOscar/src/avatars.cpp b/protocols/AimOscar/src/avatars.cpp deleted file mode 100644 index 0c8143aa4a..0000000000 --- a/protocols/AimOscar/src/avatars.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2012 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 "stdafx.h"
-
-void __cdecl CAimProto::avatar_request_thread(void* param)
-{
- MCONTACT hContact = (UINT_PTR)param;
-
- char *sn = getStringA(hContact, AIM_KEY_SN);
- debugLogA("Starting avatar request thread for %s)", sn);
-
- if (wait_conn(m_hAvatarConn, m_hAvatarEvent, 0x10)) {
- char *hash_str = getStringA(hContact, AIM_KEY_AH);
- if (!hash_str) {
- mir_free(sn);
- return;
- }
- char type = getByte(hContact, AIM_KEY_AHT, 1);
-
- size_t len = (mir_strlen(hash_str) + 1) / 2;
- char *hash = (char*)alloca(len);
- string_to_bytes(hash_str, hash);
- debugLogA("Requesting an Avatar: %s (Hash: %s)", sn, hash_str);
- aim_request_avatar(m_hAvatarConn, m_avatar_seqno, sn, type, hash, (unsigned short)len);
-
- mir_free(hash_str);
- }
-
- mir_free(sn);
-}
-
-void __cdecl CAimProto::avatar_upload_thread(void* param)
-{
- avatar_up_req* req = (avatar_up_req*)param;
-
- if (wait_conn(m_hAvatarConn, m_hAvatarEvent, 0x10)) {
- if (req->size2) {
- aim_upload_avatar(m_hAvatarConn, m_avatar_seqno, 1, req->data2, req->size2);
- aim_upload_avatar(m_hAvatarConn, m_avatar_seqno, 12, req->data1, req->size1);
- }
- else aim_upload_avatar(m_hAvatarConn, m_avatar_seqno, 1, req->data1, req->size1);
- }
- delete req;
-}
-
-void CAimProto::avatar_request_handler(MCONTACT hContact, char* hash, unsigned char type)//checks to see if the avatar needs requested
-{
- if (hContact == NULL) {
- hash = m_hash_lg ? m_hash_lg : m_hash_sm;
- type = m_hash_lg ? 12 : 1;
- }
-
- char *saved_hash = getStringA(hContact, AIM_KEY_AH);
- if (hash && _stricmp(hash, "0201d20472") && _stricmp(hash, "2b00003341")) //gaim default icon fix- we don't want their blank icon displaying.
- {
- if (mir_strcmp(saved_hash, hash)) {
- setByte(hContact, AIM_KEY_AHT, type);
- setString(hContact, AIM_KEY_AH, hash);
-
- ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, nullptr, 0);
- }
- }
- else {
- if (saved_hash) {
- delSetting(hContact, AIM_KEY_AHT);
- delSetting(hContact, AIM_KEY_AH);
-
- ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, nullptr, 0);
- }
- }
- mir_free(saved_hash);
-}
-
-void CAimProto::avatar_retrieval_handler(const char* sn, const char* /*hash*/, const char* data, int data_len)
-{
- bool res = false;
- PROTO_AVATAR_INFORMATION ai = { 0 };
- ai.hContact = contact_from_sn(sn);
-
- if (data_len > 0) {
- const wchar_t *type;
- ai.format = ProtoGetBufferFormat(data, &type);
- get_avatar_filename(ai.hContact, ai.filename, _countof(ai.filename), type);
-
- int fileId = _wopen(ai.filename, _O_CREAT | _O_TRUNC | _O_WRONLY | O_BINARY, _S_IREAD | _S_IWRITE);
- if (fileId >= 0) {
- _write(fileId, data, data_len);
- _close(fileId);
- res = true;
-
- char *my_sn = getStringA(AIM_KEY_SN);
- if (!mir_strcmp(sn, my_sn))
- CallService(MS_AV_REPORTMYAVATARCHANGED, (WPARAM)m_szModuleName, 0);
- mir_free(my_sn);
- }
- }
- else debugLogA("AIM sent avatar of zero length for %s.(Usually caused by repeated request for the same icon)", sn);
-
- ProtoBroadcastAck(ai.hContact, ACKTYPE_AVATAR, res ? ACKRESULT_SUCCESS : ACKRESULT_FAILED, &ai, 0);
-}
-
-int CAimProto::get_avatar_filename(MCONTACT hContact, wchar_t* pszDest, size_t cbLen, const wchar_t *ext)
-{
- int tPathLen = mir_snwprintf(pszDest, cbLen, L"%s\\%S", VARSW(L"%miranda_avatarcache%"), m_szModuleName);
-
- if (ext && _waccess(pszDest, 0))
- CreateDirectoryTreeW(pszDest);
-
- size_t tPathLen2 = tPathLen;
-
- DBVARIANT dbv;
- if (getWString(hContact, AIM_KEY_AH, &dbv)) return GAIR_NOAVATAR;
- tPathLen += mir_snwprintf(pszDest + tPathLen, cbLen - tPathLen, L"\\%s", dbv.ptszVal);
- db_free(&dbv);
-
- bool found = false;
- if (ext == nullptr) {
- mir_snwprintf(pszDest + tPathLen, cbLen - tPathLen, L".*");
-
- _tfinddata_t c_file;
- long hFile = _tfindfirst(pszDest, &c_file);
- if (hFile > -1L) {
- do {
- if (wcsrchr(c_file.name, '.')) {
- mir_snwprintf(pszDest + tPathLen2, cbLen - tPathLen2, L"\\%s", c_file.name);
- found = true;
- }
- } while (_tfindnext(hFile, &c_file) == 0);
- _findclose(hFile);
- }
-
- if (!found) pszDest[0] = 0;
- }
- else {
- mir_snwprintf(pszDest + tPathLen, cbLen - tPathLen, ext);
- found = _waccess(pszDest, 0) == 0;
- }
-
- return found ? GAIR_SUCCESS : GAIR_WAITFOR;
-}
-
-bool get_avatar_hash(const wchar_t* file, char* hash, char** data, unsigned short &size)
-{
- int fileId = _wopen(file, _O_RDONLY | _O_BINARY, _S_IREAD);
- if (fileId == -1) return false;
-
- long lAvatar = _filelength(fileId);
- if (lAvatar <= 0) {
- _close(fileId);
- return false;
- }
-
- char* pResult = (char*)mir_alloc(lAvatar);
- int res = _read(fileId, pResult, lAvatar);
- _close(fileId);
-
- if (res <= 0) {
- mir_free(pResult);
- return false;
- }
-
- mir_md5_state_t state;
- mir_md5_init(&state);
- mir_md5_append(&state, (unsigned char*)pResult, lAvatar);
- mir_md5_finish(&state, (unsigned char*)hash);
-
- if (data) {
- *data = pResult;
- size = (unsigned short)lAvatar;
- }
- else
- mir_free(pResult);
-
- return true;
-}
-
-void rescale_image(char *data, unsigned short size, char *&data1, unsigned short &size1)
-{
- FI_INTERFACE *fei = nullptr;
- CallService(MS_IMG_GETINTERFACE, FI_IF_VERSION, (LPARAM)&fei);
- if (fei == nullptr) return;
-
- FIMEMORY *hmem = fei->FI_OpenMemory((BYTE *)data, size);
- FREE_IMAGE_FORMAT fif = fei->FI_GetFileTypeFromMemory(hmem, 0);
- FIBITMAP *dib = fei->FI_LoadFromMemory(fif, hmem, 0);
- fei->FI_CloseMemory(hmem);
-
- if (fei->FI_GetWidth(dib) > 64) {
- FIBITMAP *dib1 = fei->FI_Rescale(dib, 64, 64, FILTER_BSPLINE);
-
- FIMEMORY *hmem2 = fei->FI_OpenMemory(nullptr, 0);
- fei->FI_SaveToMemory(fif, dib1, hmem2, 0);
-
- BYTE *data2; DWORD size2;
- fei->FI_AcquireMemory(hmem2, &data2, &size2);
- data1 = (char*)mir_alloc(size2);
- memcpy(data1, data2, size2);
- size1 = size2;
-
- fei->FI_CloseMemory(hmem2);
- fei->FI_Unload(dib1);
- }
- fei->FI_Unload(dib);
-}
diff --git a/protocols/AimOscar/src/avatars.h b/protocols/AimOscar/src/avatars.h deleted file mode 100644 index 647e897f3f..0000000000 --- a/protocols/AimOscar/src/avatars.h +++ /dev/null @@ -1,52 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2009 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 AVATARS_H
-#define AVATARS_H
-
-struct avatar_req
-{
- char* sn;
- char* hash;
- unsigned char type;
-
- avatar_req(char* sn, char* hash, unsigned char type)
- : sn(sn), hash(mir_strdup(hash)), type(type) {}
-
- ~avatar_req()
- { mir_free(sn); mir_free(hash); }
-};
-
-struct avatar_up_req
-{
- char* data1;
- char* data2;
- unsigned short size1;
- unsigned short size2;
-
- avatar_up_req(char* data1, unsigned short size1, char* data2, unsigned short size2)
- : data1(data1), size1(size1), data2(data2), size2(size2) {}
-
- ~avatar_up_req()
- { mir_free(data1); mir_free(data2); }
-};
-
-bool get_avatar_hash(const wchar_t* file, char* hash, char** data, unsigned short &size);
-void rescale_image(char *data, unsigned short size, char *&data1, unsigned short &size1);
-
-#endif
diff --git a/protocols/AimOscar/src/away.cpp b/protocols/AimOscar/src/away.cpp deleted file mode 100644 index 96d4847d9b..0000000000 --- a/protocols/AimOscar/src/away.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2012 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 "stdafx.h"
-
-static const int 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,
-};
-
-char** CAimProto::get_status_msg_loc(int status)
-{
- for (int i = 0; i < _countof(modes); i++)
- if (modes[i] == status)
- return &m_modeMsgs[i];
-
- return nullptr;
-}
-
-int CAimProto::aim_set_away(HNETLIBCONN hServerConn, unsigned short &seqno, const char *amsg, bool set)//user info
-{
- unsigned short offset = 0;
- char *html_msg = nullptr;
- size_t msg_size = 0;
- if (set) {
- if (!amsg) return -1;
- setDword(AIM_KEY_LA, (DWORD)time(nullptr));
- html_msg = html_encode(amsg && amsg[0] ? amsg : DEFAULT_AWAY_MSG);
- msg_size = mir_strlen(html_msg);
- }
-
- aimString str(html_msg);
- const char *charset = str.isUnicode() ? AIM_MSG_TYPE_UNICODE : AIM_MSG_TYPE;
- const unsigned short charset_len = (unsigned short)mir_strlen(charset);
-
- const char *msg = str.getBuf();
- const unsigned short msg_len = str.getSize();
-
- char *buf = (char*)alloca(SNAC_SIZE + TLV_HEADER_SIZE * 3 + charset_len + msg_len + 1);
-
- aim_writesnac(0x02, 0x04, offset, buf);
- aim_writetlv(0x03, charset_len, charset, offset, buf);
- aim_writetlv(0x04, (unsigned short)msg_len, msg, offset, buf);
-
- mir_free(html_msg);
-
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_set_status(HNETLIBCONN hServerConn, unsigned short &seqno, unsigned long status_type)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE + TLV_HEADER_SIZE * 2];
- aim_writesnac(0x01, 0x1E, offset, buf);
- aim_writetlvlong(0x06, status_type, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_set_statusmsg(HNETLIBCONN hServerConn, unsigned short &seqno, const char *msg)//user info
-{
- size_t msg_size = mir_strlen(msg);
-
- unsigned short msgoffset = 0;
- char *msgbuf = (char*)alloca(10 + msg_size);
- if (msg_size) {
- char *msgb = (char*)alloca(4 + msg_size);
- msgb[0] = (unsigned char)(msg_size >> 8);
- msgb[1] = (unsigned char)(msg_size & 0xff);
- memcpy(&msgb[2], msg, msg_size);
- msgb[msg_size + 2] = 0;
- msgb[msg_size + 3] = 0;
-
- aim_writebartid(2, 4, (unsigned short)(msg_size + 4), msgb, msgoffset, msgbuf);
- }
- else aim_writebartid(2, 0, 0, nullptr, msgoffset, msgbuf);
-
- unsigned short offset = 0;
- char* buf = (char*)alloca(SNAC_SIZE + TLV_HEADER_SIZE + msgoffset + 8);
- aim_writesnac(0x01, 0x1e, offset, buf);
- aim_writetlv(0x1d, msgoffset, msgbuf, offset, buf);
-
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_query_away_message(HNETLIBCONN hServerConn, unsigned short &seqno, const char* sn)
-{
- unsigned short offset = 0;
- unsigned short sn_length = (unsigned short)mir_strlen(sn);
- char *buf = (char*)alloca(SNAC_SIZE + 5 + sn_length);
- aim_writesnac(0x02, 0x15, offset, buf);
- aim_writegeneric(4, "\0\0\0\x02", offset, buf);
- aim_writegeneric(1, (char*)&sn_length, offset, buf);
- aim_writegeneric(sn_length, sn, offset, buf);
- int res = aim_sendflap(hServerConn, 0x02, offset, buf, seqno) == 0;
- return res;
-}
diff --git a/protocols/AimOscar/src/chat.cpp b/protocols/AimOscar/src/chat.cpp deleted file mode 100644 index b084f6ca02..0000000000 --- a/protocols/AimOscar/src/chat.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-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/>.
-*/
-
-#include "stdafx.h"
-
-void CAimProto::chat_register(void)
-{
- GCREGISTER gcr = {};
- gcr.dwFlags = GC_TYPNOTIF | GC_CHANMGR;
- gcr.ptszDispName = m_tszUserName;
- gcr.pszModule = m_szModuleName;
- Chat_Register(&gcr);
-
- HookProtoEvent(ME_GC_EVENT, &CAimProto::OnGCEvent);
- HookProtoEvent(ME_GC_BUILDMENU, &CAimProto::OnGCMenuHook);
-}
-
-void CAimProto::chat_start(const char *id, unsigned short exchange)
-{
- wchar_t *idt = mir_a2u(id);
- Chat_NewSession(GCW_CHATROOM, m_szModuleName, idt, idt);
-
- Chat_AddGroup(m_szModuleName, idt, TranslateT("Me"));
- Chat_AddGroup(m_szModuleName, idt, TranslateT("Others"));
-
- Chat_Control(m_szModuleName, idt, SESSION_INITDONE);
- Chat_Control(m_szModuleName, idt, SESSION_ONLINE);
- Chat_Control(m_szModuleName, idt, WINDOW_VISIBLE);
-
- setWord(find_chat_contact(id), "Exchange", exchange);
-
- mir_free(idt);
-}
-
-void CAimProto::chat_event(const char* id, const char* sn, int evt, const wchar_t* msg)
-{
- ptrW idt(mir_a2u(id));
- ptrW snt(mir_a2u(sn));
-
- MCONTACT hContact = contact_from_sn(sn);
- wchar_t *nick = hContact ? (wchar_t*)pcli->pfnGetContactDisplayName(hContact, 0) : snt;
-
- GCEVENT gce = { m_szModuleName, idt, evt };
- gce.dwFlags = GCEF_ADDTOLOG;
- gce.ptszNick = nick;
- gce.ptszUID = snt;
- gce.bIsMe = _stricmp(sn, m_username) == 0;
- gce.ptszStatus = gce.bIsMe ? TranslateT("Me") : TranslateT("Others");
- gce.ptszText = msg;
- gce.time = time(nullptr);
- Chat_Event(&gce);
-}
-
-void CAimProto::chat_leave(const char* id)
-{
- ptrW idt(mir_a2u(id));
- Chat_Control(m_szModuleName, idt, SESSION_OFFLINE);
- Chat_Terminate(m_szModuleName, idt);
-}
-
-int CAimProto::OnGCEvent(WPARAM, LPARAM lParam)
-{
- GCHOOK *gch = (GCHOOK*)lParam;
- if (!gch) return 1;
-
- if (mir_strcmp(gch->pszModule, m_szModuleName))
- return 0;
-
- char *id = mir_u2a(gch->ptszID);
- chat_list_item* item = find_chat_by_id(id);
- if (item == nullptr)
- return 0;
-
- switch (gch->iType) {
- case GC_SESSION_TERMINATE:
- aim_sendflap(item->hconn, 0x04, 0, nullptr, item->seqno);
- Netlib_Shutdown(item->hconn);
- break;
-
- case GC_USER_MESSAGE:
- if (gch->ptszText && mir_wstrlen(gch->ptszText))
- aim_chat_send_message(item->hconn, item->seqno, T2Utf(gch->ptszText));
- break;
-
- case GC_USER_CHANMGR:
- DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_CHATROOM_INVITE), nullptr, invite_to_chat_dialog,
- LPARAM(new invite_chat_param(item->id, this)));
- break;
-
- case GC_USER_PRIVMESS:
- {
- char* sn = mir_u2a(gch->ptszUID);
- MCONTACT hContact = contact_from_sn(sn);
- mir_free(sn);
- CallService(MS_MSG_SENDMESSAGE, hContact, 0);
- }
- break;
-
- case GC_USER_LOGMENU:
- switch (gch->dwData) {
- case 10:
- DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_CHATROOM_INVITE), nullptr, invite_to_chat_dialog,
- LPARAM(new invite_chat_param(item->id, this)));
- break;
-
- case 20:
- chat_leave(id);
- break;
- }
- break;
-
- case GC_USER_NICKLISTMENU:
- {
- char *sn = mir_u2a(gch->ptszUID);
- MCONTACT hContact = contact_from_sn(sn);
- mir_free(sn);
-
- switch (gch->dwData) {
- case 10:
- CallService(MS_USERINFO_SHOWDIALOG, hContact, 0);
- break;
-
- case 20:
- CallService(MS_HISTORY_SHOWCONTACTHISTORY, hContact, 0);
- break;
-
- case 110:
- chat_leave(id);
- break;
- }
- }
- break;
-
- case GC_USER_TYPNOTIFY:
- break;
- }
- mir_free(id);
-
- return 0;
-}
-
-int CAimProto::OnGCMenuHook(WPARAM, LPARAM lParam)
-{
- GCMENUITEMS *gcmi = (GCMENUITEMS*)lParam;
- if (mir_strcmp(gcmi->pszModule, m_szModuleName))
- return 0;
-
- if (gcmi->Type == MENU_ON_LOG) {
- static const struct gc_item Items[] = {
- { LPGENW("&Invite user..."), 10, MENU_ITEM, FALSE },
- { LPGENW("&Leave chat session"), 20, MENU_ITEM, FALSE }
- };
- Chat_AddMenuItems(gcmi->hMenu, _countof(Items), Items);
- }
- else if (gcmi->Type == MENU_ON_NICKLIST) {
- char* sn = mir_u2a(gcmi->pszUID);
- if (!mir_strcmp(m_username, sn)) {
- static const struct gc_item Items[] = {
- { LPGENW("User &details"), 10, MENU_ITEM, FALSE },
- { LPGENW("User &history"), 20, MENU_ITEM, FALSE },
- { L"", 100, MENU_SEPARATOR, FALSE },
- { LPGENW("&Leave chat session"), 110, MENU_ITEM, FALSE }
- };
- Chat_AddMenuItems(gcmi->hMenu, _countof(Items), Items);
- }
- else {
- static const struct gc_item Items[] = {
- { LPGENW("User &details"), 10, MENU_ITEM, FALSE },
- { LPGENW("User &history"), 20, MENU_ITEM, FALSE }
- };
- Chat_AddMenuItems(gcmi->hMenu, _countof(Items), Items);
- }
- mir_free(sn);
- }
-
- return 0;
-}
-
-
-void __cdecl CAimProto::chatnav_request_thread(void* param)
-{
- chatnav_param *par = (chatnav_param*)param;
-
- if (wait_conn(m_hChatNavConn, m_hChatNavEvent, 0x0d)) {
- if (par->isroom)
- aim_chatnav_create(m_hChatNavConn, m_chatnav_seqno, par->id, par->exchange);
- else
- aim_chatnav_room_info(m_hChatNavConn, m_chatnav_seqno, par->id, par->exchange, par->instance);
- }
- delete par;
-}
-
-chat_list_item* CAimProto::find_chat_by_cid(unsigned short cid)
-{
- for (int i = 0; i < m_chat_rooms.getCount(); ++i)
- if (m_chat_rooms[i].cid == cid)
- return &m_chat_rooms[i];
-
- return nullptr;
-}
-
-chat_list_item* CAimProto::find_chat_by_id(char* id)
-{
- for (int i = 0; i < m_chat_rooms.getCount(); ++i)
- if (mir_strcmp(m_chat_rooms[i].id, id) == 0)
- return &m_chat_rooms[i];
-
- return nullptr;
-}
-
-chat_list_item* CAimProto::find_chat_by_conn(HANDLE conn)
-{
- for (int i = 0; i < m_chat_rooms.getCount(); ++i)
- if (m_chat_rooms[i].hconn == conn)
- return &m_chat_rooms[i];
-
- return nullptr;
-}
-
-void CAimProto::remove_chat_by_ptr(chat_list_item *item)
-{
- for (int i = 0; i < m_chat_rooms.getCount(); ++i) {
- if (&m_chat_rooms[i] == item) {
- m_chat_rooms.remove(i);
- break;
- }
- }
-}
-
-void CAimProto::shutdown_chat_conn(void)
-{
- for (int i = 0; i < m_chat_rooms.getCount(); ++i) {
- chat_list_item &item = m_chat_rooms[i];
- if (item.hconn) {
- aim_sendflap(item.hconn, 0x04, 0, nullptr, item.seqno);
- Netlib_Shutdown(item.hconn);
- }
- }
-}
-
-void CAimProto::close_chat_conn(void)
-{
- for (int i = 0; i < m_chat_rooms.getCount(); ++i) {
- chat_list_item &item = m_chat_rooms[i];
- if (item.hconn) {
- Netlib_CloseHandle(item.hconn);
- item.hconn = nullptr;
- }
- }
-}
diff --git a/protocols/AimOscar/src/chat.h b/protocols/AimOscar/src/chat.h deleted file mode 100644 index c10d0265da..0000000000 --- a/protocols/AimOscar/src/chat.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef CHAT_H
-#define CHAT_H
-
-struct chatnav_param
-{
- char* id;
- unsigned short exchange;
- unsigned short instance;
-
- char* message;
- char* sn;
- char* icbm_cookie;
-
- bool isroom;
-
- chatnav_param(char* tid, unsigned short ex, unsigned short in, char* msg, char* nm, char* icki)
- { id = tid; exchange = ex; instance = in; isroom = false;
- message = mir_strdup(msg); sn = mir_strdup(nm); icbm_cookie = (char*)mir_alloc(8); memcpy(icbm_cookie, icki, 8); }
-
- chatnav_param(char* tid, unsigned short ex)
- { id = mir_strdup(tid); exchange = ex; isroom = true;
- message = NULL; sn = NULL; icbm_cookie = NULL; }
-
- ~chatnav_param()
- {
- mir_free(id);
- mir_free(message);
- mir_free(sn);
- mir_free(icbm_cookie);
- }
-};
-
-struct chat_list_item
-{
- char* id;
- char* cookie;
- HNETLIBCONN hconn;
- unsigned short cid;
- unsigned short seqno;
- unsigned short exchange;
- unsigned short instance;
- char* CHAT_COOKIE;
- int CHAT_COOKIE_LENGTH;
-
- chat_list_item(char* tid, char* tcookie, unsigned short ex, unsigned short in)
- {
- id = mir_strdup(tid); cid = get_random(); seqno = 0; hconn = NULL;
- cookie = mir_strdup(tcookie); exchange = ex; instance = in;
- }
-
- ~chat_list_item()
- {
- mir_free(id); mir_free(cookie);
- }
-};
-
-#endif
\ No newline at end of file diff --git a/protocols/AimOscar/src/client.cpp b/protocols/AimOscar/src/client.cpp deleted file mode 100755 index 8299cc5a32..0000000000 --- a/protocols/AimOscar/src/client.cpp +++ /dev/null @@ -1,985 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2012 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 "stdafx.h"
-
-int CAimProto::aim_send_connection_packet(HNETLIBCONN hServerConn, unsigned short &seqno, char *buf)
-{
- return aim_sendflap(hServerConn, 0x01, 4, buf, seqno);
-}
-
-int CAimProto::aim_authkey_request(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- unsigned short offset = 0;
- char *buf = (char*)alloca(SNAC_SIZE + TLV_HEADER_SIZE * 3 + mir_strlen(m_username));
- aim_writesnac(0x17, 0x06, offset, buf);
- aim_writetlv(0x01, (unsigned short)mir_strlen(m_username), m_username, offset, buf);
- aim_writetlv(0x4B, 0, nullptr, offset, buf);
- aim_writetlv(0x5A, 0, nullptr, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_auth_request(HNETLIBCONN hServerConn, unsigned short &seqno, const char* key, const char* language,
- const char* country, const char* username, const char* password)
-{
- unsigned short offset = 0;
- BYTE pass_hash[16];
- BYTE auth_hash[16];
- mir_md5_state_t state;
-
- mir_md5_init(&state);
- mir_md5_append(&state, (const BYTE *)password, (int)mir_strlen(password));
- mir_md5_finish(&state, pass_hash);
- mir_md5_init(&state);
- mir_md5_append(&state, (BYTE*)key, (int)mir_strlen(key));
- mir_md5_append(&state, (BYTE*)pass_hash, MD5_HASH_LENGTH);
- mir_md5_append(&state, (BYTE*)AIM_MD5_STRING, sizeof(AIM_MD5_STRING) - 1);
- mir_md5_finish(&state, auth_hash);
-
- char client_id[64], mirver[64];
- Miranda_GetVersionText(mirver, sizeof(mirver));
- int client_id_len = mir_snprintf(client_id, "Miranda AIM, version %s", mirver);
-
- char* buf = (char*)alloca(SNAC_SIZE + TLV_HEADER_SIZE * 13 + MD5_HASH_LENGTH + mir_strlen(username) + client_id_len + 30 + mir_strlen(language) + mir_strlen(country));
-
- aim_writesnac(0x17, 0x02, offset, buf);
- aim_writetlv(0x01, (unsigned short)mir_strlen(username), username, offset, buf);
- aim_writetlv(0x25, MD5_HASH_LENGTH, (char*)auth_hash, offset, buf);
- aim_writetlv(0x4C, 0, nullptr, offset, buf);//signifies new password hash instead of old method
- aim_writetlv(0x03, (unsigned short)client_id_len, client_id, offset, buf);
-
- aim_writetlvshort(0x16, AIM_CLIENT_ID_NUMBER, offset, buf); //in pidgin it's first
- aim_writetlvshort(0x17, AIM_CLIENT_MAJOR_VERSION, offset, buf);
- aim_writetlvshort(0x18, AIM_CLIENT_MINOR_VERSION, offset, buf);
- aim_writetlvshort(0x19, AIM_CLIENT_LESSER_VERSION, offset, buf);
- aim_writetlvshort(0x1A, AIM_CLIENT_BUILD_NUMBER, offset, buf);
- aim_writetlvlong(0x14, AIM_CLIENT_DISTRIBUTION_NUMBER, offset, buf);
- aim_writetlv(0x0F, (unsigned short)mir_strlen(language), language, offset, buf);
- aim_writetlv(0x0E, (unsigned short)mir_strlen(country), country, offset, buf);
- aim_writetlvchar(0x4A, getByte(AIM_KEY_FSC, 0) ? 3 : 1, offset, buf);
- // aim_writetlvchar(0x94,0,offset,buf);
-/* if (!getByte(AIM_KEY_DSSL, 0))
- aim_writetlv(0x8c, 0, NULL, offset, buf); // Request SSL connection */
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_send_cookie(HNETLIBCONN hServerConn, unsigned short &seqno, int cookie_size, char * cookie)
-{
- unsigned short offset = 0;
- char* buf = (char*)alloca(TLV_HEADER_SIZE * 2 + cookie_size);
- aim_writelong(0x01, offset, buf);//protocol version number
- aim_writetlv(0x06, (unsigned short)cookie_size, cookie, offset, buf);
- return aim_sendflap(hServerConn, 0x01, offset, buf, seqno);
-}
-
-int CAimProto::aim_send_service_request(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE + TLV_HEADER_SIZE * 12];
- aim_writesnac(0x01, 0x17, offset, buf);
- aim_writefamily(AIM_SERVICE_GENERIC, offset, buf);
- aim_writefamily(AIM_SERVICE_SSI, offset, buf);
- aim_writefamily(AIM_SERVICE_LOCATION, offset, buf);
- aim_writefamily(AIM_SERVICE_BUDDYLIST, offset, buf);
- aim_writefamily(AIM_SERVICE_MESSAGING, offset, buf);
- aim_writefamily(AIM_SERVICE_ICQ, offset, buf);
- aim_writefamily(AIM_SERVICE_INVITATION, offset, buf);
- aim_writefamily(AIM_SERVICE_POPUP, offset, buf);
- aim_writefamily(AIM_SERVICE_BOS, offset, buf);
- aim_writefamily(AIM_SERVICE_USERLOOKUP, offset, buf);
- aim_writefamily(AIM_SERVICE_STATS, offset, buf);
- aim_writefamily(AIM_SERVICE_UNKNOWN, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_new_service_request(HNETLIBCONN hServerConn, unsigned short &seqno, unsigned short service)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE + 2 + TLV_HEADER_SIZE];
- aim_writesnac(0x01, 0x04, offset, buf);
- aim_writeshort(service, offset, buf);
-/* if (!getByte(AIM_KEY_DSSL, 0))
- aim_writetlv(0x8c, 0, NULL, offset, buf); */
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_request_rates(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE];
- aim_writesnac(0x01, 0x06, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_accept_rates(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE * 2];
- aim_writesnac(0x01, 0x08, offset, buf);
- aim_writegeneric(10, AIM_SERVICE_RATES, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_request_icbm(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE];
- aim_writesnac(0x04, 0x04, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_set_icbm(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- const unsigned icbm_flags = ICBM_CHANNEL_MSGS_ALLOWED | ICBM_MISSED_CALLS_ENABLED |
- ICBM_EVENTS_ALLOWED | ICBM_SMS_SUPPORTED | ICBM_OFFLINE_MSGS_ALLOWED;
- // const unsigned icbm_flags = 0x3db;
-
- unsigned short offset = 0;
- char buf[SNAC_SIZE + 16];
- aim_writesnac(0x04, 0x02, offset, buf);
- aim_writeshort(0, offset, buf); //channel
- aim_writelong(icbm_flags, offset, buf); //flags
- aim_writeshort(0x1f40, offset, buf); //max snac size 8000
- aim_writeshort(0x03e7, offset, buf); //max sender warning level 999 (0-1000) WinAim default
- aim_writeshort(0x03e7, offset, buf); //max receiver warning level 999 (0-1000) WinAim default
- aim_writelong(0, offset, buf); //min message interval, ms 0
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_request_offline_msgs(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE];
- aim_writesnac(0x04, 0x10, offset, buf); // Subtype for offline messages 0x10
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_request_list(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE];
- aim_writesnac(0x13, 0x04, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_activate_list(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE];
- aim_writesnac(0x13, 0x07, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-/*
-0000 00 05 00 02 00 17 00 06 00 03 00 00 00 00 07 00 ................
-0010 01 00 00 08 00 01 01 00 0a 00 14 00 02 00 08 66 ...............f
-0020 61 63 65 62 6f 6f 6b 00 06 67 6f 6f 67 6c 65 acebook..google
-
-int CAimProto::aim_request_rights(HNETLIBCONN hServerConn,unsigned short &seqno)
-{
- unsigned short offset=0;
- char buf[SNAC_SIZE+50];
- aim_writesnac(0x03,0x02,offset,buf);
- aim_writetlvshort(0x05,0x17,offset,buf);
- aim_writetlv(0x06,3,"\x0\x0",offset,buf);
- aim_writetlvchar(0x07,0x01,offset,buf);
- aim_writetlvshort(0x05,0x17,offset,buf);
- aim_writetlvshort(0x05,0x17,offset,buf);
- return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
-}
-*/
-int CAimProto::aim_set_caps(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- unsigned short offset = 0;
- int i = 1;
- char buf[SNAC_SIZE + TLV_HEADER_SIZE * 3 + AIM_CAPS_LENGTH * 50 + sizeof(AIM_MSG_TYPE)];
- char temp[AIM_CAPS_LENGTH * 20];
- memcpy(temp, AIM_CAP_SHORT_CAPS, AIM_CAPS_LENGTH);
- memcpy(&temp[AIM_CAPS_LENGTH*i++], AIM_CAP_HOST_STATUS_TEXT_AWARE, AIM_CAPS_LENGTH);
- memcpy(&temp[AIM_CAPS_LENGTH*i++], AIM_CAP_SMART_CAPS, AIM_CAPS_LENGTH);
- memcpy(&temp[AIM_CAPS_LENGTH*i++], AIM_CAP_FILE_TRANSFER, AIM_CAPS_LENGTH);
- // memcpy(&temp[AIM_CAPS_LENGTH*i++],AIM_CAP_HAS_MICROPHONE,AIM_CAPS_LENGTH);
- // memcpy(&temp[AIM_CAPS_LENGTH*i++],AIM_CAP_RTCAUDIO,AIM_CAPS_LENGTH);
- // memcpy(&temp[AIM_CAPS_LENGTH*i++],AIM_CAP_HAS_CAMERA,AIM_CAPS_LENGTH);
- // memcpy(&temp[AIM_CAPS_LENGTH*i++],AIM_CAP_RTCVIDEO,AIM_CAPS_LENGTH);
- memcpy(&temp[AIM_CAPS_LENGTH*i++], AIM_CAP_BUDDY_ICON, AIM_CAPS_LENGTH);
- memcpy(&temp[AIM_CAPS_LENGTH*i++], AIM_CAP_CHAT, AIM_CAPS_LENGTH);
- memcpy(&temp[AIM_CAPS_LENGTH*i++], AIM_CAP_SUPPORT_ICQ, AIM_CAPS_LENGTH);
- // memcpy(&temp[AIM_CAPS_LENGTH*i++],AIM_CAP_ICQ_SERVER_RELAY,AIM_CAPS_LENGTH);
- memcpy(&temp[AIM_CAPS_LENGTH*i++], AIM_CAP_UTF8, AIM_CAPS_LENGTH);
- memcpy(&temp[AIM_CAPS_LENGTH*i++], AIM_CAP_MIRANDA, AIM_CAPS_LENGTH);
- if (getByte(AIM_KEY_HF, 0))
- memcpy(&temp[AIM_CAPS_LENGTH*i++], AIM_CAP_HIPTOP, AIM_CAPS_LENGTH);
- aim_writesnac(0x02, 0x04, offset, buf);
- aim_writetlv(0x05, (unsigned short)(AIM_CAPS_LENGTH*i), temp, offset, buf);
-
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_set_profile(HNETLIBCONN hServerConn, unsigned short &seqno, char* amsg)//user info
-{
- aimString str(amsg);
- const char *charset = str.isUnicode() ? AIM_MSG_TYPE_UNICODE : AIM_MSG_TYPE;
- const unsigned short charset_len = (unsigned short)mir_strlen(charset);
-
- const char* msg = str.getBuf();
- const unsigned short msg_len = str.getSize();
-
- char* buf = (char*)alloca(SNAC_SIZE + TLV_HEADER_SIZE * 3 + 1 + charset_len + msg_len);
- unsigned short offset = 0;
-
- aim_writesnac(0x02, 0x04, offset, buf);
- aim_writetlvchar(0x0c, 1, offset, buf);
- aim_writetlv(0x01, charset_len, charset, offset, buf);
- aim_writetlv(0x02, msg_len, msg, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_client_ready(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- unsigned short offset = 0;
-
- NETLIBCONNINFO connInfo = {};
- Netlib_GetConnectionInfo(hServerConn, &connInfo);
-
- m_internal_ip = connInfo.dwIpv4;
-
- char buf[SNAC_SIZE + TLV_HEADER_SIZE * 22];
- aim_writesnac(0x01, 0x02, offset, buf);
- aim_writefamily(AIM_SERVICE_GENERIC, offset, buf);
- aim_writegeneric(4, AIM_TOOL_VERSION, offset, buf);
- aim_writefamily(AIM_SERVICE_SSI, offset, buf);
- aim_writegeneric(4, AIM_TOOL_VERSION, offset, buf);
- aim_writefamily(AIM_SERVICE_LOCATION, offset, buf);
- aim_writegeneric(4, AIM_TOOL_VERSION, offset, buf);
- aim_writefamily(AIM_SERVICE_BUDDYLIST, offset, buf);
- aim_writegeneric(4, AIM_TOOL_VERSION, offset, buf);
- aim_writefamily(AIM_SERVICE_MESSAGING, offset, buf);
- aim_writegeneric(4, AIM_TOOL_VERSION, offset, buf);
- aim_writefamily(AIM_SERVICE_ICQ, offset, buf);
- aim_writegeneric(4, AIM_TOOL_VERSION, offset, buf);
- aim_writefamily(AIM_SERVICE_INVITATION, offset, buf);
- aim_writegeneric(4, AIM_TOOL_VERSION, offset, buf);
- //removed extra generic server
- aim_writefamily(AIM_SERVICE_POPUP, offset, buf);
- aim_writegeneric(4, "\x01\x04\0\x01", offset, buf);//different version number like trillian 3.1
- aim_writefamily(AIM_SERVICE_BOS, offset, buf);
- aim_writegeneric(4, AIM_TOOL_VERSION, offset, buf);
- aim_writefamily(AIM_SERVICE_USERLOOKUP, offset, buf);
- aim_writegeneric(4, AIM_TOOL_VERSION, offset, buf);
- aim_writefamily(AIM_SERVICE_STATS, offset, buf);
- aim_writegeneric(4, AIM_TOOL_VERSION, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_mail_ready(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE + TLV_HEADER_SIZE * 4];
- aim_writesnac(0x01, 0x02, offset, buf);
- aim_writefamily(AIM_SERVICE_GENERIC, offset, buf);
- aim_writegeneric(4, AIM_TOOL_VERSION, offset, buf);
- aim_writefamily(AIM_SERVICE_MAIL, offset, buf);
- aim_writegeneric(4, AIM_TOOL_VERSION, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_avatar_ready(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE + TLV_HEADER_SIZE * 4];
- aim_writesnac(0x01, 0x02, offset, buf);
- aim_writefamily(AIM_SERVICE_GENERIC, offset, buf);
- aim_writegeneric(4, AIM_TOOL_VERSION, offset, buf);
- aim_writefamily(AIM_SERVICE_AVATAR, offset, buf);
- aim_writegeneric(4, AIM_TOOL_VERSION, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_chatnav_ready(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE + TLV_HEADER_SIZE * 4];
- aim_writesnac(0x01, 0x02, offset, buf);
- aim_writefamily(AIM_SERVICE_GENERIC, offset, buf);
- aim_writegeneric(4, AIM_TOOL_VERSION, offset, buf);
- aim_writefamily(AIM_SERVICE_CHATNAV, offset, buf);
- aim_writegeneric(4, AIM_TOOL_VERSION, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_chat_ready(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE + TLV_HEADER_SIZE * 4];
- aim_writesnac(0x01, 0x02, offset, buf);
- aim_writefamily(AIM_SERVICE_GENERIC, offset, buf);
- aim_writegeneric(4, AIM_TOOL_VERSION, offset, buf);
- aim_writefamily(AIM_SERVICE_CHAT, offset, buf);
- aim_writegeneric(4, AIM_TOOL_VERSION, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_send_message(HNETLIBCONN hServerConn, unsigned short &seqno, const char* sn, char* amsg, bool auto_response, bool blast)
-{
- aimString str(amsg);
-
- const char* msg = str.getBuf();
- const unsigned short msg_len = str.getSize();
-
- unsigned short tlv_offset = 0;
- char* tlv_buf = (char*)alloca(5 + msg_len + 8);
-
- char icbm_cookie[8];
- Utils_GetRandom(icbm_cookie, sizeof(icbm_cookie));
-
- aim_writegeneric(5, "\x05\x01\x00\x01\x01", tlv_offset, tlv_buf); // icbm im capabilities
- aim_writeshort(0x0101, tlv_offset, tlv_buf); // icbm im text tag
- aim_writeshort(msg_len + 4, tlv_offset, tlv_buf); // icbm im text tag length
- aim_writeshort(str.isUnicode() ? 2 : 0, tlv_offset, tlv_buf); // character set
- aim_writeshort(0, tlv_offset, tlv_buf); // language
-
- aim_writegeneric(msg_len, msg, tlv_offset, tlv_buf); // message text
-
- unsigned short offset = 0;
- unsigned short sn_length = (unsigned short)mir_strlen(sn);
- char* buf = (char*)alloca(SNAC_SIZE + 8 + 3 + sn_length + TLV_HEADER_SIZE * 3 + tlv_offset);
-
- aim_writesnac(0x04, 0x06, offset, buf, get_random());
- aim_writegeneric(8, icbm_cookie, offset, buf); // icbm cookie
- aim_writeshort(0x01, offset, buf); // channel
- aim_writechar((unsigned char)sn_length, offset, buf); // screen name len
- aim_writegeneric(sn_length, sn, offset, buf); // screen name
-
- aim_writetlv(0x02, tlv_offset, tlv_buf, offset, buf);
-
- if (!blast) {
- if (auto_response)
- aim_writetlv(0x04, 0, nullptr, offset, buf); // auto-response message
- else {
- aim_writetlv(0x03, 0, nullptr, offset, buf); // message ack request
- aim_writetlv(0x06, 0, nullptr, offset, buf); // offline message storage
- }
- }
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno) ? 0 : *(int*)icbm_cookie & 0x7fffffff;
-}
-
-int CAimProto::aim_query_profile(HNETLIBCONN hServerConn, unsigned short &seqno, char* sn)
-{
- unsigned short offset = 0;
- unsigned short sn_length = (unsigned short)mir_strlen(sn);
- char* buf = (char*)alloca(SNAC_SIZE + 5 + sn_length);
- aim_writesnac(0x02, 0x15, offset, buf);
- aim_writelong(0x01, offset, buf);
- aim_writechar((unsigned char)sn_length, offset, buf);
- aim_writegeneric(sn_length, sn, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno) == 0;
-}
-
-int CAimProto::aim_delete_contact(HNETLIBCONN hServerConn, unsigned short &seqno, char* sn, unsigned short item_id,
- unsigned short group_id, unsigned short list, bool nil)
-{
- unsigned short offset = 0;
- unsigned short sn_length = (unsigned short)mir_strlen(sn);
- char* buf = (char*)alloca(SNAC_SIZE + sn_length + 10);
- aim_writesnac(0x13, 0x0a, offset, buf, get_random()); // SSI Delete
- aim_writeshort(sn_length, offset, buf); // screen name length
- aim_writegeneric(sn_length, sn, offset, buf); // screen name
- aim_writeshort(group_id, offset, buf); // group id
- aim_writeshort(item_id, offset, buf); // buddy id
- aim_writeshort(list, offset, buf); // buddy type
- aim_writeshort(nil ? 4 : 0, offset, buf); // length of extra data
- if (nil) aim_writetlv(0x6a, 0, nullptr, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_add_contact(HNETLIBCONN hServerConn, unsigned short &seqno, const char* sn, unsigned short item_id,
- unsigned short group_id, unsigned short list, char* nick, char* note)
-{
- unsigned short offset = 0;
- unsigned short sn_length = (unsigned short)mir_strlen(sn);
- unsigned short nick_length = (unsigned short)mir_strlen(nick);
- unsigned short note_length = (unsigned short)mir_strlen(note);
- unsigned short tlv_len = nick || note ? TLV_HEADER_SIZE * 2 + nick_length + note_length : 0;
-
- char* buf = (char*)alloca(SNAC_SIZE + sn_length + 10 + tlv_len);
- aim_writesnac(0x13, 0x08, offset, buf, get_random()); // SSI Add
- aim_writeshort(sn_length, offset, buf); // screen name length
- aim_writegeneric(sn_length, sn, offset, buf); // screen name
- aim_writeshort(group_id, offset, buf); // group id
- aim_writeshort(item_id, offset, buf); // buddy id
- aim_writeshort(list, offset, buf); // buddy type
- aim_writeshort(tlv_len, offset, buf); // length of extra data
-
- if (nick || note) {
- aim_writetlv(0x13c, note_length, note, offset, buf);
- aim_writetlv(0x131, nick_length, nick, offset, buf);
- }
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_mod_group(HNETLIBCONN hServerConn, unsigned short &seqno, const char* name, unsigned short group_id,
- char* members, unsigned short members_length)
-{
- unsigned short offset = 0;
- unsigned short name_length = (unsigned short)mir_strlen(name);
- char* buf = (char*)alloca(SNAC_SIZE + TLV_HEADER_SIZE + name_length + members_length + 10);
- aim_writesnac(0x13, 0x09, offset, buf, get_random()); // SSI Edit
- aim_writeshort(name_length, offset, buf); // group name length
- aim_writegeneric(name_length, name, offset, buf); // group name
- aim_writeshort(group_id, offset, buf); // group id
- aim_writeshort(0, offset, buf); // buddy id
- aim_writeshort(1, offset, buf); // buddy type: Group
- aim_writeshort(TLV_HEADER_SIZE + members_length, offset, buf); // length of extra data
- aim_writetlv(0xc8, members_length, members, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_mod_buddy(HNETLIBCONN hServerConn, unsigned short &seqno, const char* sn,
- unsigned short buddy_id, unsigned short group_id,
- char* nick, char* note)
-{
- unsigned short offset = 0;
- unsigned short sn_length = (unsigned short)mir_strlen(sn);
- unsigned short nick_length = (unsigned short)mir_strlen(nick);
- unsigned short note_length = (unsigned short)mir_strlen(note);
- unsigned short tlv_len = TLV_HEADER_SIZE * 2 + nick_length + note_length;
-
- char* buf = (char*)alloca(SNAC_SIZE + sn_length + 10 + tlv_len);
- aim_writesnac(0x13, 0x09, offset, buf, get_random()); // SSI Edit
- aim_writeshort(sn_length, offset, buf); // screen name length
- aim_writegeneric(sn_length, sn, offset, buf); // screen name
- aim_writeshort(buddy_id, offset, buf); // buddy id
- aim_writeshort(group_id, offset, buf); // group id
- aim_writeshort(0, offset, buf); // buddy type: Buddy
- aim_writeshort(tlv_len, offset, buf); // length of extra data
-
- aim_writetlv(0x13c, note_length, note, offset, buf);
- aim_writetlv(0x131, nick_length, nick, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_set_pd_info(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE + TLV_HEADER_SIZE * 3 + 20];
- unsigned short req = 0x09;
- if (m_pd_info_id == 0) {
- m_pd_info_id = get_random();
- req = 0x08;
- }
- aim_writesnac(0x13, req, offset, buf, get_random()); // SSI Edit/Add
- aim_writeshort(0, offset, buf); // name length
- aim_writeshort(0, offset, buf); // group id (root)
- aim_writeshort(m_pd_info_id, offset, buf); // buddy id
- aim_writeshort(0x4, offset, buf); // pd info id
- aim_writeshort(0x15, offset, buf); // size
- aim_writetlvchar(0xca, m_pd_mode, offset, buf); // pd mode
- aim_writetlvlong(0xcb, 0xffffffff, offset, buf); // pd mask
- aim_writetlvlong(0xcc, m_pd_flags, offset, buf); // pd flags
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_ssi_update_preferences(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE + TLV_HEADER_SIZE * 4 + 100];
- unsigned short req = 0x09;
- if (m_pref1_id == 0) {
- m_pref1_id = get_random();
- req = 0x08;
- }
- aim_writesnac(0x13, req, offset, buf, get_random()); // SSI Edit/Add
- aim_writeshort(0, offset, buf); // group name length
- aim_writeshort(0, offset, buf); // group id (root)
- aim_writeshort(m_pref1_id, offset, buf); // buddy id
- aim_writeshort(5, offset, buf); // buddy type: Presence
-
- unsigned short tlv_len = TLV_HEADER_SIZE * 2 + 8;
- if (m_pref2_len) tlv_len += TLV_HEADER_SIZE + m_pref2_len;
- if (m_pref2_set_len) tlv_len += TLV_HEADER_SIZE + m_pref2_set_len;
-
- aim_writeshort(tlv_len, offset, buf); // length of extra data
- aim_writetlvlong(0xc9, m_pref1_flags, offset, buf); // Update Buddy preferences 1
- aim_writetlvlong(0xd6, m_pref1_set_flags, offset, buf); // Update Buddy preferences 1
- if (m_pref2_len)
- aim_writetlv(0xd7, m_pref2_len, m_pref2_flags, offset, buf); // Update Buddy preferences 2
- if (m_pref2_set_len)
- aim_writetlv(0xd8, m_pref2_set_len, m_pref2_set_flags, offset, buf); // Update Buddy preferences 2
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_ssi_update(HNETLIBCONN hServerConn, unsigned short &seqno, bool start)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE];
- aim_writesnac(0x13, start ? 0x11 : 0x12, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno) == 0;
-}
-
-int CAimProto::aim_keepalive(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- return aim_sendflap(hServerConn, 0x05, 4, "\x0\x0\x0\xEE", seqno);
-}
-
-// used when requesting a regular file transfer
-int CAimProto::aim_send_file(HNETLIBCONN hServerConn, unsigned short &seqno,
- unsigned long ip, unsigned short port,
- bool force_proxy, file_transfer *ft)
-{
- char msg_frag[2048];
- unsigned short frag_offset = 0;
-
- aim_writeshort(0, frag_offset, msg_frag); // request type
- aim_writegeneric(8, ft->icbm_cookie, frag_offset, msg_frag); // icbm cookie
- aim_writegeneric(AIM_CAPS_LENGTH, AIM_CAP_FILE_TRANSFER,
- frag_offset, msg_frag); // uuid
- aim_writetlvshort(0x0a, ++ft->req_num, frag_offset, msg_frag); // request number
-
- aim_writetlvlong(0x02, ip, frag_offset, msg_frag); // ip
- aim_writetlvlong(0x16, ~ip, frag_offset, msg_frag); // ip check
-
- aim_writetlvshort(0x05, port, frag_offset, msg_frag); // port
- aim_writetlvshort(0x17, ~port, frag_offset, msg_frag); // port ip check
-
- if (force_proxy)
- aim_writetlv(0x10, 0, nullptr, frag_offset, msg_frag); // request proxy transfer
- else
- aim_writetlvlong(0x03, m_internal_ip, frag_offset, msg_frag); // ip
-
- if (ft->req_num == 1) {
- if (ft->message) {
- aimString dscr(ft->message);
-
- const char* charset = dscr.isUnicode() ? "unicode-2-0" : "us-ascii";
- const unsigned short charset_len = (unsigned short)mir_strlen(charset);
-
- const char* desc_msg = dscr.getBuf();
- const unsigned short desc_len = dscr.getSize();
-
- aim_writetlv(0x0e, 2, "en", frag_offset, msg_frag); // language used by the data
- aim_writetlv(0x0d, charset_len, charset, frag_offset, msg_frag);// charset used by the data
- aim_writetlv(0x0c, desc_len, desc_msg, frag_offset, msg_frag); // invitaion text
- }
-
- aim_writetlv(0x0f, 0, nullptr, frag_offset, msg_frag); // request host check
-
- const char* fname = get_fname(ft->file);
- const unsigned short fnlen = (unsigned short)mir_strlen(fname);
-
- char* fblock = (char*)alloca(9 + fnlen);
- *(unsigned short*)&fblock[0] = _htons(ft->pfts.totalFiles > 1 ? 2 : 1); // single file transfer
- *(unsigned short*)&fblock[2] = _htons(ft->pfts.totalFiles); // number of files
- *(unsigned long*)&fblock[4] = _htonl(ft->pfts.totalBytes); // total bytes in files
- memcpy(&fblock[8], fname, fnlen + 1);
-
- const char* enc = is_utf(fname) ? "utf-8" : "us-ascii";
- aim_writetlv(0x2711, 9 + fnlen, fblock, frag_offset, msg_frag); // extra data, file names, size
- aim_writetlv(0x2712, 8, enc, frag_offset, msg_frag); // character set used by data
-// aim_writetlvlong64(0x2713,ft->pfts.totalBytes,frag_offset,msg_frag); // file length
-
- debugLogA("Attempting to Send a file to a buddy.");
- }
- else {
- aim_writetlvshort(0x14, 0x0a, frag_offset, msg_frag); // Counter proposal reason
- }
-
- unsigned short offset = 0;
- unsigned short sn_length = (unsigned short)mir_strlen(ft->sn);
- char* buf = (char*)alloca(SNAC_SIZE + TLV_HEADER_SIZE * 2 + 12 + frag_offset + sn_length);
- aim_writesnac(0x04, 0x06, offset, buf); // msg to host
- aim_writegeneric(8, ft->icbm_cookie, offset, buf); // icbm cookie
- aim_writeshort(2, offset, buf); // icbm channel
- aim_writechar((unsigned char)sn_length, offset, buf); // screen name length
- aim_writegeneric(sn_length, ft->sn, offset, buf); // screen name
- aim_writetlv(0x05, frag_offset, msg_frag, offset, buf); // icbm tags
- aim_writetlv(0x03, 0, nullptr, offset, buf); // request ack
-
- char cip[20];
- long_ip_to_char_ip(ip, cip);
- debugLogA("IP for Buddy to connect to: %s:%u", cip, port);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno) == 0;
-}
-
-
-int CAimProto::aim_file_ad(HNETLIBCONN hServerConn, unsigned short &seqno, char* sn, char* icbm_cookie, bool deny, unsigned short)
-{
- unsigned short frag_offset = 0;
- char msg_frag[10 + AIM_CAPS_LENGTH + TLV_HEADER_SIZE * 2 + 6];
- aim_writeshort(deny ? 1 : 2, frag_offset, msg_frag); // icbm accept / deny
- aim_writegeneric(8, icbm_cookie, frag_offset, msg_frag); // icbm cookie
- aim_writegeneric(AIM_CAPS_LENGTH,
- AIM_CAP_FILE_TRANSFER, frag_offset, msg_frag); // uuid
-
-// if (max_ver > 1)
-// aim_writetlvshort(0x12,2,frag_offset,msg_frag); // max protocol version
-
- unsigned short sn_length = (unsigned short)mir_strlen(sn);
- unsigned short offset = 0;
- char* buf = (char*)alloca(SNAC_SIZE + TLV_HEADER_SIZE + 21 + frag_offset + sn_length);
- aim_writesnac(0x04, 0x06, offset, buf); // msg to host
- aim_writegeneric(8, icbm_cookie, offset, buf); // icbm cookie
- aim_writeshort(2, offset, buf); // icbm channel
- aim_writechar((unsigned char)sn_length, offset, buf); // screen name length
- aim_writegeneric(sn_length, sn, offset, buf); // screen name
- aim_writetlv(0x05, frag_offset, msg_frag, offset, buf); // icbm tags
-
- debugLogA("%s a file transfer.", deny ? "Denying" : "Accepting");
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno) == 0;
-}
-
-int CAimProto::aim_typing_notification(HNETLIBCONN hServerConn, unsigned short &seqno, char* sn, unsigned short type)
-{
- unsigned short offset = 0;
- unsigned short sn_length = (unsigned short)mir_strlen(sn);
- char* buf = (char*)alloca(SNAC_SIZE + sn_length + 13);
- aim_writesnac(0x04, 0x14, offset, buf);
- aim_writegeneric(8, "\0\0\0\0\0\0\0\0", offset, buf); // icbm cookie
- aim_writeshort(1, offset, buf); // icbm channel
- aim_writechar((unsigned char)sn_length, offset, buf); // screen name length
- aim_writegeneric(sn_length, sn, offset, buf); // screen name
- aim_writeshort(type, offset, buf); // typing event
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_set_idle(HNETLIBCONN hServerConn, unsigned short &seqno, unsigned long seconds)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE + 4];
- aim_writesnac(0x01, 0x11, offset, buf);
- aim_writelong(seconds, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_request_mail(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE + 34];
- aim_writesnac(0x18, 0x06, offset, buf);
- aim_writegeneric(34,
- "\x00\x02"
- "\xb3\x80\x9a\xd8\x0d\xba\x11\xd5\x9f\x8a\x00\x60\xb0\xee\x06\x31"
- "\x5d\x5e\x17\x08\x55\xaa\x11\xd3\xb1\x43\x00\x60\xb0\xfb\x1e\xcb",
- offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_activate_mail(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE + 17];
- aim_writesnac(0x18, 0x16, offset, buf);
- aim_writegeneric(17, "\x02\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00", offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_request_avatar(HNETLIBCONN hServerConn, unsigned short &seqno, const char* sn, unsigned short bart_type, const char* hash, unsigned short hash_size)
-{
- unsigned short offset = 0;
- unsigned char sn_length = (unsigned char)mir_strlen(sn);
- char* buf = (char*)alloca(SNAC_SIZE + sn_length + hash_size + 12);
- aim_writesnac(0x10, 0x06, offset, buf);
- aim_writechar(sn_length, offset, buf); // screen name length
- aim_writegeneric(sn_length, sn, offset, buf); // screen name
- aim_writechar(1, offset, buf); // number of BART ID
- aim_writebartid(bart_type, 0, hash_size, hash, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_set_avatar_hash(HNETLIBCONN hServerConn, unsigned short &seqno, char flags, unsigned short bart_type, unsigned short &id, char size, const char* hash)
-{
- unsigned short offset = 0;
-
- char bart_type_txt[8];
- ultoa(bart_type, bart_type_txt, 10);
- unsigned short bart_type_len = (unsigned short)mir_strlen(bart_type_txt);
-
- unsigned short req = 0x09;
- if (id == 0) {
- id = get_random();
- req = 0x08;
- }
-
- char* buf = (char*)alloca(SNAC_SIZE + TLV_HEADER_SIZE * 2 + 20 + size + bart_type_len);
- aim_writesnac(0x13, req, offset, buf, get_random()); // SSI Edit/Add
- aim_writeshort(bart_type_len, offset, buf); // name length
- aim_writegeneric(bart_type_len, bart_type_txt, offset, buf); // name
- aim_writeshort(0, offset, buf); // group id
- aim_writeshort(id, offset, buf); // buddy id
- aim_writeshort(0x14, offset, buf); // buddy type: Buddy Icon
- aim_writeshort(2 + size + TLV_HEADER_SIZE, offset, buf); // length of extra data
-
- char* buf2 = (char*)alloca(2 + size);
- buf2[0] = flags;
- buf2[1] = (char)size;
- memcpy(&buf2[2], hash, size);
- aim_writetlv(0xd5, 2 + size, buf2, offset, buf); // BART
-
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_delete_avatar_hash(HNETLIBCONN hServerConn, unsigned short &seqno, char /*flags*/, unsigned short bart_type, unsigned short & id)
-{
- unsigned short offset = 0;
-
- if (id == 0) return -1;
- id = 0;
-
- char bart_type_txt[8];
- ultoa(bart_type, bart_type_txt, 10);
- unsigned short bart_type_len = (unsigned short)mir_strlen(bart_type_txt);
-
- char* buf = (char*)alloca(SNAC_SIZE + 20 + bart_type_len);
- aim_writesnac(0x13, 0x0a, offset, buf, get_random()); // SSI Delete
- aim_writeshort(bart_type_len, offset, buf); // name length
- aim_writegeneric(bart_type_len, bart_type_txt, offset, buf); // name
- aim_writeshort(0, offset, buf); // group id
- aim_writeshort(id, offset, buf); // buddy id
- aim_writeshort(0x14, offset, buf); // buddy type: Buddy Icon
- aim_writeshort(0, offset, buf); // length of extra data
-
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_upload_avatar(HNETLIBCONN hServerConn, unsigned short &seqno, unsigned short bart_type, const char* avatar, unsigned short avatar_size)
-{
- unsigned short offset = 0;
- char* buf = (char*)alloca(SNAC_SIZE + 22 + avatar_size);
- aim_writesnac(0x10, 0x02, offset, buf);
- aim_writeshort(bart_type, offset, buf); // BART id
- aim_writeshort(avatar_size, offset, buf);
- aim_writegeneric(avatar_size, avatar, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_search_by_email(HNETLIBCONN hServerConn, unsigned short &seqno, const char* email)
-{
- unsigned short offset = 0;
- char em_length = (char)mir_strlen(email);
- char* buf = (char*)alloca(SNAC_SIZE + em_length);
- aim_writesnac(0x0a, 0x02, offset, buf); // Email search
- aim_writegeneric(em_length, email, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_chatnav_request_limits(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE];
- aim_writesnac(0x0d, 0x02, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno) ? -1 : 0;
-}
-
-int CAimProto::aim_chatnav_create(HNETLIBCONN hServerConn, unsigned short &seqno, char* room, unsigned short exchage)
-{
- //* Join Pseudo Room (Get's the info we need for the real connection)
- unsigned short room_len = (unsigned short)mir_strlen(room);
-
- unsigned short offset = 0;
- char* buf = (char*)alloca(SNAC_SIZE + 10 + room_len + 26);
- aim_writesnac(0x0d, 0x08, offset, buf);
- aim_writeshort(exchage, offset, buf); // Exchange
- aim_writechar(6, offset, buf); // Command Length
- aim_writegeneric(6, "create", offset, buf); // Command
- aim_writeshort(0xffff, offset, buf); // Last Instance
- aim_writechar(1, offset, buf); // Detail
- aim_writeshort(3, offset, buf); // Number of TLVs
- aim_writetlv(0xd3, room_len, room, offset, buf); // Room Name
- aim_writetlv(0xd6, 8, "us-ascii", offset, buf); // Character Set
- aim_writetlv(0xd7, 2, "en", offset, buf); // Language Encoding
-
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_chatnav_room_info(HNETLIBCONN hServerConn, unsigned short &seqno, char* chat_cookie, unsigned short exchange, unsigned short instance)
-{
- unsigned short offset = 0;
- unsigned short chat_cookie_len = (unsigned short)mir_strlen(chat_cookie);
- char* buf = (char*)alloca(SNAC_SIZE + 7 + chat_cookie_len);
- aim_writesnac(0x0d, 0x04, offset, buf);
- aim_writeshort(exchange, offset, buf); // Exchange
- aim_writechar((unsigned char)chat_cookie_len, offset, buf); // Chat Cookie Length
- aim_writegeneric(chat_cookie_len, chat_cookie, offset, buf); // Chat Cookie
- aim_writeshort(instance, offset, buf); // Last Instance
- aim_writechar(1, offset, buf); // Detail
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_chat_join_room(HNETLIBCONN hServerConn, unsigned short &seqno, char* chat_cookie,
- unsigned short exchange, unsigned short instance, unsigned short id)
-{
- unsigned short offset = 0;
- unsigned short cookie_len = (unsigned short)mir_strlen(chat_cookie);
- char* buf = (char*)alloca(SNAC_SIZE + TLV_HEADER_SIZE * 2 + cookie_len + 8);
- aim_writesnac(0x01, 0x04, offset, buf, id);
- aim_writeshort(0x0e, offset, buf); // Service request for Chat
-
- aim_writeshort(0x01, offset, buf); // Tag
- aim_writeshort(cookie_len + 5, offset, buf); // Length
- aim_writeshort(exchange, offset, buf); // Value - Exchange
- aim_writechar((unsigned char)cookie_len, offset, buf); // Value - Cookie Length
- aim_writegeneric(cookie_len, chat_cookie, offset, buf); // Value - Cookie
- aim_writeshort(instance, offset, buf); // Value - Instance
-
-/* if (!getByte(AIM_KEY_DSSL, 0))
- aim_writetlv(0x8c, 0, NULL, offset, buf); // Request SSL connection */
-
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_chat_send_message(HNETLIBCONN hServerConn, unsigned short &seqno, char *amsg)
-{
- aimString str(amsg);
-
- const char* charset = str.isUnicode() ? "unicode-2-0" : "us-ascii";
- const unsigned short chrset_len = (unsigned short)mir_strlen(charset);
-
- const char* msg = str.getBuf();
- const unsigned short msg_len = str.getSize();
-
- unsigned short tlv_offset = 0;
- char* tlv_buf = (char*)alloca(TLV_HEADER_SIZE * 4 + chrset_len + msg_len + 20);
- aim_writetlv(0x04, 13, "text/x-aolrtf", tlv_offset, tlv_buf); // Format
- aim_writetlv(0x02, chrset_len, charset, tlv_offset, tlv_buf); // Character Set
- aim_writetlv(0x03, 2, "en", tlv_offset, tlv_buf); // Language Encoding
- aim_writetlv(0x01, msg_len, msg, tlv_offset, tlv_buf); // Message
-
- unsigned short offset = 0;
- char* buf = (char*)alloca(SNAC_SIZE + 8 + 2 + TLV_HEADER_SIZE * 3 + tlv_offset);
- aim_writesnac(0x0e, 0x05, offset, buf);
- aim_writegeneric(8, "\0\0\0\0\0\0\0\0", offset, buf); // Message Cookie (can be random)
- aim_writeshort(0x03, offset, buf); // Message Channel (Always 3 for chat)
- aim_writetlv(0x01, 0, nullptr, offset, buf); // Public/Whisper flag
- aim_writetlv(0x06, 0, nullptr, offset, buf); // Enable Reflection flag
- aim_writetlv(0x05, tlv_offset, tlv_buf, offset, buf); // Message Information TLV
-
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_chat_invite(HNETLIBCONN hServerConn, unsigned short &seqno, char* chat_cookie, unsigned short exchange, unsigned short instance, char* sn, char* msg)
-{
- unsigned short offset = 0;
- unsigned short chat_cookie_len = (unsigned short)mir_strlen(chat_cookie);
- unsigned short sn_len = (unsigned short)mir_strlen(sn);
- unsigned short msg_len = (unsigned short)mir_strlen(msg);
- char* buf = (char*)alloca(SNAC_SIZE + 64 + chat_cookie_len + sn_len + msg_len);
- aim_writesnac(0x04, 0x06, offset, buf);
- aim_writegeneric(8, "\0\0\0\0\0\0\0\0", offset, buf); // ICBM Cookie
- aim_writeshort(2, offset, buf); // ICBM Channel
- aim_writechar((unsigned char)sn_len, offset, buf); // Screen Name Length
- aim_writegeneric(sn_len, sn, offset, buf); // Screen Name
-
- aim_writeshort(0x05, offset, buf); // Rendezvous Message Data TLV
- aim_writeshort(49 + msg_len + chat_cookie_len, offset, buf); // TLV size
-
- aim_writeshort(0, offset, buf); // Message Type (0) - Request
- aim_writegeneric(8, "\0\0\0\0\0\0\0\0", offset, buf); // ICBM Cookie (same as above)
- aim_writegeneric(16, AIM_CAP_CHAT, offset, buf); // Capability
-
- aim_writetlvshort(0x0a, 1, offset, buf); // Sequence Number TLV
- aim_writetlv(0x0f, 0, nullptr, offset, buf); // Request Host Caps Check TLV
- aim_writetlv(0x0c, msg_len, msg, offset, buf); // Invitation Message TLV
-
- aim_writeshort(0x2711, offset, buf); // Capability TLV
- aim_writeshort(chat_cookie_len + 5, offset, buf); // Length
- aim_writeshort(exchange, offset, buf); // Value - Exchange
- aim_writechar((unsigned char)chat_cookie_len, offset, buf); // Value - Cookie Length
- aim_writegeneric(chat_cookie_len, chat_cookie, offset, buf); // Value - Cookie
- aim_writeshort(instance, offset, buf); // Value - Instance
-
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_chat_deny(HNETLIBCONN hServerConn, unsigned short &seqno, char* sn, char* icbm_cookie)
-{
- unsigned short offset = 0;
- unsigned short sn_length = (unsigned short)mir_strlen(sn);
- char* buf = (char*)alloca(SNAC_SIZE + 20 + sn_length);
- aim_writesnac(0x04, 0x0b, offset, buf);
- aim_writegeneric(8, icbm_cookie, offset, buf); // ICBM Cookie
- aim_writeshort(2, offset, buf); // Channel
- aim_writechar((unsigned char)sn_length, offset, buf); // Screen Name length
- aim_writegeneric(sn_length, sn, offset, buf); // Screen Name
- aim_writeshort(3, offset, buf); // Error code
- aim_writeshort(2, offset, buf); // Error code
- aim_writeshort(1, offset, buf); // Error code
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno) == 0;
-}
-
-int CAimProto::aim_admin_ready(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE + TLV_HEADER_SIZE * 4];
- aim_writesnac(0x01, 0x02, offset, buf);
- aim_writefamily(AIM_SERVICE_GENERIC, offset, buf);
- aim_writegeneric(4, AIM_TOOL_VERSION, offset, buf);
- aim_writefamily(AIM_SERVICE_ADMIN, offset, buf);
- aim_writegeneric(4, AIM_TOOL_VERSION, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_admin_format_name(HNETLIBCONN hServerConn, unsigned short &seqno, const char* sn)
-{
- unsigned short offset = 0;
- unsigned short sn_len = (unsigned short)mir_strlen(sn);
- char* buf = (char*)alloca(SNAC_SIZE + TLV_HEADER_SIZE + sn_len);
- aim_writesnac(0x07, 0x04, offset, buf);
- aim_writetlv(0x01, sn_len, sn, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_admin_change_email(HNETLIBCONN hServerConn, unsigned short &seqno, const char* email)
-{
- unsigned short offset = 0;
- unsigned short email_len = (unsigned short)mir_strlen(email);
- char* buf = (char*)alloca(SNAC_SIZE + TLV_HEADER_SIZE + email_len);
- aim_writesnac(0x07, 0x04, offset, buf);
- aim_writetlv(0x11, email_len, email, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_admin_change_password(HNETLIBCONN hServerConn, unsigned short &seqno, const char* cur_pw, const char* new_pw)
-{
- unsigned short offset = 0;
- unsigned short cur_pw_len = (unsigned short)mir_strlen(cur_pw);
- unsigned short new_pw_len = (unsigned short)mir_strlen(new_pw);
- char* buf = (char*)alloca(SNAC_SIZE + 2 * TLV_HEADER_SIZE + cur_pw_len + new_pw_len);
- aim_writesnac(0x07, 0x04, offset, buf);
- aim_writetlv(0x02, new_pw_len, new_pw, offset, buf);
- aim_writetlv(0x12, cur_pw_len, cur_pw, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_admin_request_info(HNETLIBCONN hServerConn, unsigned short &seqno, const unsigned short &type)
-{
- // types: 0x01 - nickname, 0x11 - email info, 0x13 - registration status
- unsigned short offset = 0;
- char buf[SNAC_SIZE + TLV_HEADER_SIZE];
- aim_writesnac(0x07, 0x02, offset, buf);
- aim_writetlv(type, 0, nullptr, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
-
-int CAimProto::aim_admin_account_confirm(HNETLIBCONN hServerConn, unsigned short &seqno)
-{
- unsigned short offset = 0;
- char buf[SNAC_SIZE + TLV_HEADER_SIZE];
- aim_writesnac(0x07, 0x06, offset, buf);
- return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
-}
diff --git a/protocols/AimOscar/src/connection.cpp b/protocols/AimOscar/src/connection.cpp deleted file mode 100755 index 42b69e9f3d..0000000000 --- a/protocols/AimOscar/src/connection.cpp +++ /dev/null @@ -1,784 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2009 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 "stdafx.h"
-
-HNETLIBCONN CAimProto::aim_connect(const char* server, unsigned short port, bool use_ssl, const char* host)
-{
- NETLIBOPENCONNECTION ncon = { 0 };
- ncon.cbSize = sizeof(ncon);
- ncon.szHost = server;
- ncon.wPort = port;
- ncon.timeout = 6;
- ncon.flags = NLOCF_V2;
- debugLogA("%s:%u", server, port);
- HNETLIBCONN con = Netlib_OpenConnection(m_hNetlibUser, &ncon);
- if (con && use_ssl) {
- if (!Netlib_StartSsl(con, host)) {
- Netlib_CloseHandle(con);
- con = nullptr;
- }
- }
- return con;
-}
-
-HNETLIBCONN CAimProto::aim_peer_connect(const char* ip, unsigned short port)
-{
- NETLIBOPENCONNECTION ncon = { 0 };
- ncon.cbSize = sizeof(ncon);
- ncon.flags = NLOCF_V2;
- ncon.szHost = ip;
- ncon.wPort = port;
- ncon.timeout = 3;
- return Netlib_OpenConnection(m_hNetlibPeer, &ncon);
-}
-
-HNETLIBCONN CAimProto::aim_peer_connect(unsigned long ip, unsigned short port)
-{
- char ips[20];
- long_ip_to_char_ip(ip, ips);
-
- return aim_peer_connect(ips, port);
-}
-
-void CAimProto::aim_connection_authorization(void)
-{
- if (m_iDesiredStatus != ID_STATUS_OFFLINE) {
- char *password = getStringA(AIM_KEY_PW);
- if (password != nullptr) {
- mir_free(m_username);
- m_username = getStringA(AIM_KEY_SN);
- if (m_username != nullptr) {
- HANDLE hServerPacketRecver = Netlib_CreatePacketReceiver(m_hServerConn, 2048 * 4);
-
- NETLIBPACKETRECVER packetRecv = {};
- packetRecv.dwTimeout = 5000;
- for (;;) {
- int recvResult = Netlib_GetMorePackets(hServerPacketRecver, &packetRecv);
- if (recvResult == 0) {
- debugLogA("Connection Closed: No Error? during Connection Authorization");
- break;
- }
- else if (recvResult < 0) {
- debugLogA("Connection Closed: Socket Error during Connection Authorization %d", WSAGetLastError());
- break;
- }
- else {
- unsigned short flap_length = 0;
- for (; packetRecv.bytesUsed < packetRecv.bytesAvailable; packetRecv.bytesUsed = flap_length) {
- if (!packetRecv.buffer)
- break;
-
- FLAP flap((char*)&packetRecv.buffer[packetRecv.bytesUsed], (unsigned short)(packetRecv.bytesAvailable - packetRecv.bytesUsed));
- if (!flap.len())
- break;
-
- flap_length += FLAP_SIZE + flap.len();
- if (flap.cmp(0x01)) {
- if (aim_send_connection_packet(m_hServerConn, m_seqno, flap.val()) == 0) // cookie challenge
- aim_authkey_request(m_hServerConn, m_seqno); // md5 authkey request
- }
- else if (flap.cmp(0x02)) {
- SNAC snac(flap.val(), flap.snaclen());
- if (snac.cmp(0x0017)) {
- snac_md5_authkey(snac, m_hServerConn, m_seqno, m_username, password);
- int authres = snac_authorization_reply(snac);
- switch (authres) {
- case 1:
- mir_free(password);
- Netlib_CloseHandle(hServerPacketRecver);
- debugLogA("Connection Authorization Thread Ending: Negotiation Beginning");
- return;
-
- case 2:
- ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, nullptr, LOGINERR_WRONGPASSWORD);
- goto exit;
-
- case 3:
- ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, nullptr, LOGINERR_NOSERVER);
- goto exit;
- }
- }
- }
- else if (flap.cmp(0x04)) {
- debugLogA("Connection Authorization Thread Ending: Flap 0x04");
- goto exit;
- }
- }
- }
- }
- exit:
- if (hServerPacketRecver)
- Netlib_CloseHandle(hServerPacketRecver);
- }
- }
- mir_free(password);
- }
- if (m_iStatus != ID_STATUS_OFFLINE)
- broadcast_status(ID_STATUS_OFFLINE);
- Netlib_CloseHandle(m_hServerConn);
- m_hServerConn = nullptr;
- debugLogA("Connection Authorization Thread Ending: End of Thread");
-}
-
-bool parse_clientlogin_response(NETLIBHTTPREQUEST *nlhr, NETLIBHTTPHEADER *my_headers, CMStringA &token, CMStringA &secret, time_t &hosttime)
-{
- //TODO: validate response
- //TODO: return false on errors
- //TODO: extract token, secret, hosttime from response
-
- int datalen = 0;
- for (int i = 0; i < nlhr->headersCount; i++) {
- if (!mir_strcmp(nlhr->headers[i].szName, "Set-Cookie")) {
- my_headers[0].szName = "Cookie";
- my_headers[0].szValue = mir_strdup(nlhr->headers[i].szValue);
- }
- }
-
- ptrW buf_w(mir_utf8decodeW(nlhr->pData));
- HXML root = xmlParseString(buf_w, &datalen, L"");
- if (!root)
- return false;
-
- HXML status = xmlGetChildByPath(root, L"response/statusCode", 0);
- if (!status)
- return false;
-
- LPCTSTR status_text = xmlGetText(status);
- // TODO: check other than 200 codes and print some debug info on errors
- if (wcscmp(status_text, L"200"))
- return false;
-
- HXML secret_node = xmlGetChildByPath(root, L"response/data/sessionSecret", 0);
- HXML hosttime_node = xmlGetChildByPath(root, L"response/data/hostTime", 0);
- if (!secret_node || !hosttime_node)
- return false;
-
- HXML token_node = xmlGetChildByPath(root, L"response/data/token/a", 0);
- if (!token_node)
- return false;
-
- LPCTSTR secret_w = xmlGetText(secret_node), token_w = xmlGetText(token_node), hosttime_w = xmlGetText(hosttime_node);
- if (!secret_w || !token_w || !hosttime_w)
- return false;
-
- secret = _T2A(secret_w);
- token = _T2A(token_w);
- hosttime = strtol(_T2A(hosttime_w), nullptr, 10);
- return true;
-}
-
-void generate_signature(BYTE *signature, const char *method, const char *url, const char *parameters, char *session_key)
-{
- CMStringA sig_base(FORMAT, "%s&%s&%s", method, ptrA(mir_urlEncode(url)), ptrA(mir_urlEncode(parameters)));
- mir_hmac_sha256(signature, (BYTE*)session_key, mir_strlen(session_key), (BYTE*)sig_base.GetString(), sig_base.GetLength());
-}
-
-void fill_session_url(CMStringA &buf, CMStringA &token, CMStringA &secret, time_t &hosttime, const char *password, bool encryption)
-{
- /*
- AIM_SESSION_URL?query_string?sig_sha256=signature
- */
-
- CMStringA query_string;
- query_string.Format("a=%s&distId=%s&f=xml&k=%s&ts=%llu&useTLS=%d", token.c_str(), AIM_DEFAULT_DISTID, AIM_DEFAULT_CLIENT_KEY, hosttime, (int)encryption);
-
- BYTE session_key[MIR_SHA256_HASH_SIZE], signature[MIR_SHA256_HASH_SIZE];
- mir_hmac_sha256(session_key, (BYTE*)password, mir_strlen(password), (BYTE*)secret.GetString(), secret.GetLength());
-
- ptrA szKey(mir_base64_encode(session_key, sizeof(session_key)));
-
- generate_signature(signature, "GET", AIM_SESSION_URL, query_string, szKey);
-
- ptrA szEncoded(mir_base64_encode(signature, sizeof(signature)));
- buf.Format("%s?%s&sig_sha256=%s", AIM_SESSION_URL, query_string.c_str(), (char*)szEncoded);
-}
-
-bool parse_start_socar_session_response(const char *response, CMStringA &bos_host, unsigned short &bos_port, CMStringA &cookie, CMStringA &tls_cert_name, bool encryption = true)
-{
- //TODO: extract bos_host, bos_port, cookie, tls_cert_name
-
- int datalen = 0;
- ptrW buf_w(mir_utf8decodeW(response));
- HXML root = xmlParseString(buf_w, &datalen, L"");
- if (!root)
- return false;
-
- HXML status = xmlGetChildByPath(root, L"response/statusCode", 0);
- if (!status)
- return false;
-
- LPCTSTR status_text = xmlGetText(status);
- //TODO: check other than 200 codes and print some debug info on errors
- if (wcscmp(status_text, L"200"))
- return false;
-
- HXML host_node = xmlGetChildByPath(root, L"response/data/host", 0);
- HXML port_node = xmlGetChildByPath(root, L"response/data/port", 0);
- HXML cookie_node = xmlGetChildByPath(root, L"response/data/cookie", 0);
- if (!host_node || !port_node || !cookie_node)
- return false;
-
- LPCTSTR host_w = xmlGetText(host_node), port_w = xmlGetText(port_node), cookie_w = xmlGetText(cookie_node);
- if (!host_w || !port_w || !cookie_w)
- return false;
-
- bos_host = _T2A(host_w);
- bos_port = atoi(_T2A(port_w));
- cookie = _T2A(cookie_w);
-
- if (encryption) {
- HXML tls_node = xmlGetChildByPath(root, L"response/data/tlsCertName", 0); //tls is optional, so this is not fatal error
- if (tls_node) {
- LPCTSTR certname_w = xmlGetText(tls_node);
- if (certname_w)
- tls_cert_name = _T2A(certname_w);
- }
- }
-
- return true;
-}
-
-void CAimProto::aim_connection_clientlogin(void)
-{
- pass_ptrA password(getStringA(AIM_KEY_PW));
- replaceStr(m_username, ptrA(getStringA(AIM_KEY_SN)));
-
- CMStringA buf;
- buf.Format("devId=%s&f=xml&pwd=%s&s=%s", AIM_DEFAULT_CLIENT_KEY, ptrA(mir_urlEncode(password)), ptrA(mir_urlEncode(m_username)));
-
- NETLIBHTTPHEADER headers[] = {
- { "Content-Type", "application/x-www-form-urlencoded; charset=UTF-8" }
- };
-
- NETLIBHTTPREQUEST req = { 0 };
- req.cbSize = sizeof(req);
- req.flags = NLHRF_SSL;
- req.requestType = REQUEST_POST;
- req.szUrl = AIM_LOGIN_URL;
- req.headers = headers;
- req.headersCount = _countof(headers);
- req.pData = buf.GetBuffer();
- req.dataLength = buf.GetLength();
-
- NLHR_PTR resp(Netlib_HttpTransaction(m_hNetlibUser, &req));
- if (!resp || !resp->dataLength) {
- broadcast_status(ID_STATUS_OFFLINE);
- return;
- }
-
- time_t hosttime;
- CMStringA token, secret;
- if (!parse_clientlogin_response(resp, headers, token, secret, hosttime)) {
- //TODO: handle error
- broadcast_status(ID_STATUS_OFFLINE);
- mir_free(headers[0].szValue);
- return;
- }
-
- bool encryption = !getByte(AIM_KEY_DSSL, 0);
- CMStringA url;
- fill_session_url(url, token, secret, hosttime, password, encryption);
-
- // reuse NETLIBHTTPREQUEST
- req.requestType = REQUEST_GET;
- req.pData = nullptr;
- req.flags |= NLHRF_MANUALHOST;
- req.dataLength = 0;
- req.headersCount = 1;
- req.szUrl = url.GetBuffer();
- {
- NETLIBHTTPHEADER headers2[] = {
- { "Host", "api.oscar.aol.com" },
- };
- req.headers = headers2;
-
- resp = Netlib_HttpTransaction(m_hNetlibUser, &req);
- }
-
- if (!resp || !resp->dataLength) {
- // TODO: handle error
- broadcast_status(ID_STATUS_OFFLINE);
- return;
- }
-
- CMStringA bos_host, cookie, tls_cert_name; //TODO: find efficient buf size
- unsigned short bos_port = 0;
- if (!parse_start_socar_session_response(resp->pData, bos_host, bos_port, cookie, tls_cert_name, encryption)) {
- // TODO: handle error
- broadcast_status(ID_STATUS_OFFLINE);
- return;
- }
- if(COOKIE)
- mir_free(COOKIE);
- COOKIE = (char*)mir_base64_decode(cookie, (unsigned int*)&COOKIE_LENGTH);
-
-
- m_hServerConn = aim_connect(bos_host, bos_port, (tls_cert_name[0] && encryption) ? true : false, bos_host);
- if (!m_hServerConn) {
- // TODO: handle error
- broadcast_status(ID_STATUS_OFFLINE);
- return;
- }
-
-
-
- ForkThread(&CAimProto::aim_protocol_negotiation, nullptr);
-}
-
-void __cdecl CAimProto::aim_protocol_negotiation(void*)
-{
- HANDLE hServerPacketRecver = Netlib_CreatePacketReceiver(m_hServerConn, 2048 * 8);
-
- NETLIBPACKETRECVER packetRecv = {};
- packetRecv.dwTimeout = DEFAULT_KEEPALIVE_TIMER * 1000;
- for (;;) {
- int recvResult = Netlib_GetMorePackets(hServerPacketRecver, &packetRecv);
- if (recvResult == 0) {
- debugLogA("Connection Closed: No Error during Connection Negotiation?");
- break;
- }
- else if (recvResult == SOCKET_ERROR) {
- if (WSAGetLastError() == ERROR_TIMEOUT) {
- if (aim_keepalive(m_hServerConn, m_seqno) < 0)
- break;
- }
- else {
- debugLogA("Connection Closed: Socket Error during Connection Negotiation %d", WSAGetLastError());
- break;
- }
- }
- else if (recvResult > 0) {
- unsigned short flap_length = 0;
- for (; packetRecv.bytesUsed < packetRecv.bytesAvailable; packetRecv.bytesUsed = flap_length) {
- if (!packetRecv.buffer)
- break;
- FLAP flap((char*)&packetRecv.buffer[packetRecv.bytesUsed], packetRecv.bytesAvailable - packetRecv.bytesUsed);
- if (!flap.len())
- break;
- flap_length += FLAP_SIZE + flap.len();
- if (flap.cmp(0x01)) {
- if (getByte(AIM_KEY_CLIENTLOGIN, 1) != 1)
- {
- aim_send_cookie(m_hServerConn, m_seqno, COOKIE_LENGTH, COOKIE);//cookie challenge
- mir_free(COOKIE);
- COOKIE = nullptr;
- COOKIE_LENGTH = 0;
- }
- else
- {
- unsigned short offset = 0;
- char client_id[64], mirver[64];
- Miranda_GetVersionText(mirver, sizeof(mirver));
- int client_id_len = mir_snprintf(client_id, "Miranda AIM, version %s", mirver);
-
- char* buf_ = (char*)alloca(SNAC_SIZE + TLV_HEADER_SIZE * 8 + COOKIE_LENGTH + client_id_len + 30); //TODO: correct length
-
- aim_writelong(0x01, offset, buf_);//protocol version number
-
- aim_writetlv(0x06, (unsigned short)COOKIE_LENGTH, COOKIE, offset, buf_);
-
- aim_writetlv(0x03, (unsigned short)client_id_len, client_id, offset, buf_);
-
- aim_writetlvshort(0x17, AIM_CLIENT_MAJOR_VERSION, offset, buf_);
- aim_writetlvshort(0x18, AIM_CLIENT_MINOR_VERSION, offset, buf_);
- aim_writetlvshort(0x19, AIM_CLIENT_LESSER_VERSION, offset, buf_);
- aim_writetlvshort(0x1A, AIM_CLIENT_BUILD_NUMBER, offset, buf_);
- aim_writetlvchar(0x4A, getByte(AIM_KEY_FSC, 0) ? 3 : 1, offset, buf_);
-
- aim_sendflap(m_hServerConn, 0x01, offset, buf_, m_seqno);
- mir_free(COOKIE);
- COOKIE = nullptr;
- COOKIE_LENGTH = 0;
-
- }
- }
- else if (flap.cmp(0x02)) {
- SNAC snac(flap.val(), flap.snaclen());
- if (snac.cmp(0x0001)) {
- snac_supported_families(snac, m_hServerConn, m_seqno);
- snac_supported_family_versions(snac, m_hServerConn, m_seqno);
- snac_rate_limitations(snac, m_hServerConn, m_seqno);
- snac_service_redirect(snac);
- snac_self_info(snac);
- snac_error(snac);
- }
- else if (snac.cmp(0x0002)) {
- snac_received_info(snac);
- snac_error(snac);
- }
- else if (snac.cmp(0x0003)) {
- snac_user_online(snac);
- snac_user_offline(snac);
- snac_error(snac);
- }
- else if (snac.cmp(0x0004)) {
- snac_icbm_limitations(snac, m_hServerConn, m_seqno);
- snac_message_accepted(snac);
- snac_received_message(snac, m_hServerConn, m_seqno);
- snac_typing_notification(snac);
- snac_error(snac);
- snac_file_decline(snac);
- }
- else if (snac.cmp(0x000A)) {
- snac_email_search_results(snac);
- /*
- If there's no match (error 0x14), AIM will pop up a message.
- Since it's annoying and there's no other errors that'll get
- generated, I just assume leave this commented out. It's here
- for consistency.
- */
- //snac_error(snac);
- }
- else if (snac.cmp(0x0013)) {
- snac_contact_list(snac, m_hServerConn, m_seqno);
- snac_list_modification_ack(snac);
- snac_error(snac);
- }
- }
- else if (flap.cmp(0x04)) {
- ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, nullptr, LOGINERR_OTHERLOCATION);
- debugLogA("Connection Negotiation Thread Ending: Flap 0x04");
- goto exit;
- }
- }
- }
- }
-
-exit:
- if (m_iStatus != ID_STATUS_OFFLINE) broadcast_status(ID_STATUS_OFFLINE);
- Netlib_CloseHandle(hServerPacketRecver); hServerPacketRecver = nullptr;
- Netlib_CloseHandle(m_hServerConn); m_hServerConn = nullptr;
- debugLogA("Connection Negotiation Thread Ending: End of Thread");
- offline_contacts();
-}
-
-void __cdecl CAimProto::aim_mail_negotiation(void*)
-{
- HANDLE hServerPacketRecver = Netlib_CreatePacketReceiver(m_hMailConn, 2048 * 8);
-
- NETLIBPACKETRECVER packetRecv = { 0 };
- packetRecv.dwTimeout = DEFAULT_KEEPALIVE_TIMER * 1000;
-
- while (m_iStatus != ID_STATUS_OFFLINE) {
- int recvResult = Netlib_GetMorePackets(hServerPacketRecver, &packetRecv);
- if (recvResult == 0)
- break;
-
- if (recvResult == SOCKET_ERROR) {
- if (WSAGetLastError() == ERROR_TIMEOUT) {
- if (aim_keepalive(m_hMailConn, m_mail_seqno) < 0)
- break;
- }
- else
- break;
- }
- if (recvResult > 0) {
- unsigned short flap_length = 0;
- for (; packetRecv.bytesUsed < packetRecv.bytesAvailable; packetRecv.bytesUsed = flap_length) {
- if (!packetRecv.buffer)
- break;
-
- FLAP flap((char*)&packetRecv.buffer[packetRecv.bytesUsed], packetRecv.bytesAvailable - packetRecv.bytesUsed);
- if (!flap.len())
- break;
-
- flap_length += FLAP_SIZE + flap.len();
- if (flap.cmp(0x01)) {
- aim_send_cookie(m_hMailConn, m_mail_seqno, MAIL_COOKIE_LENGTH, MAIL_COOKIE);//cookie challenge
- mir_free(MAIL_COOKIE);
- MAIL_COOKIE = nullptr;
- MAIL_COOKIE_LENGTH = 0;
- }
- else if (flap.cmp(0x02)) {
- SNAC snac(flap.val(), flap.snaclen());
- if (snac.cmp(0x0001)) {
- snac_supported_families(snac, m_hMailConn, m_mail_seqno);
- snac_supported_family_versions(snac, m_hMailConn, m_mail_seqno);
- snac_mail_rate_limitations(snac, m_hMailConn, m_mail_seqno);
- snac_error(snac);
- }
- else if (snac.cmp(0x0018)) {
- snac_mail_response(snac);
- }
- }
- else if (flap.cmp(0x04))
- goto exit;
- }
- }
- }
-
-exit:
- debugLogA("Mail Server Connection has ended");
- Netlib_CloseHandle(hServerPacketRecver);
- Netlib_CloseHandle(m_hMailConn);
- m_hMailConn = nullptr;
-}
-
-void __cdecl CAimProto::aim_avatar_negotiation(void*)
-{
- HANDLE hServerPacketRecver = Netlib_CreatePacketReceiver(m_hAvatarConn, 2048 * 8);
-
- NETLIBPACKETRECVER packetRecv = { 0 };
- packetRecv.dwTimeout = 300000;//5 minutes connected
-
- for (;;) {
- int recvResult = Netlib_GetMorePackets(hServerPacketRecver, &packetRecv);
- if (recvResult == 0)
- break;
-
- if (recvResult == SOCKET_ERROR)
- break;
-
- if (recvResult > 0) {
- unsigned short flap_length = 0;
- for (; packetRecv.bytesUsed < packetRecv.bytesAvailable; packetRecv.bytesUsed = flap_length) {
- if (!packetRecv.buffer)
- break;
-
- FLAP flap((char*)&packetRecv.buffer[packetRecv.bytesUsed], packetRecv.bytesAvailable - packetRecv.bytesUsed);
- if (!flap.len())
- break;
-
- flap_length += FLAP_SIZE + flap.len();
- if (flap.cmp(0x01)) {
- aim_send_cookie(m_hAvatarConn, m_avatar_seqno, AVATAR_COOKIE_LENGTH, AVATAR_COOKIE); // cookie challenge
- mir_free(AVATAR_COOKIE);
- AVATAR_COOKIE = nullptr;
- AVATAR_COOKIE_LENGTH = 0;
- }
- else if (flap.cmp(0x02)) {
- SNAC snac(flap.val(), flap.snaclen());
- if (snac.cmp(0x0001)) {
- snac_supported_families(snac, m_hAvatarConn, m_avatar_seqno);
- snac_supported_family_versions(snac, m_hAvatarConn, m_avatar_seqno);
- snac_avatar_rate_limitations(snac, m_hAvatarConn, m_avatar_seqno);
- snac_error(snac);
- }
- if (snac.cmp(0x0010)) {
- snac_retrieve_avatar(snac);
- snac_upload_reply_avatar(snac);
- }
- }
- else if (flap.cmp(0x04))
- goto exit;
- }
- }
- }
-
-exit:
- Netlib_CloseHandle(hServerPacketRecver);
- Netlib_CloseHandle(m_hAvatarConn);
- m_hAvatarConn = nullptr;
- ResetEvent(m_hAvatarEvent);
- debugLogA("Avatar Server Connection has ended");
-}
-
-void __cdecl CAimProto::aim_chatnav_negotiation(void*)
-{
- unsigned idle_chat = 0;
- HANDLE hServerPacketRecver = Netlib_CreatePacketReceiver(m_hChatNavConn, 2048 * 8);
-
- NETLIBPACKETRECVER packetRecv = { 0 };
- packetRecv.dwTimeout = DEFAULT_KEEPALIVE_TIMER * 1000;
-
- for (;;) {
- int recvResult = Netlib_GetMorePackets(hServerPacketRecver, &packetRecv);
- if (recvResult == 0)
- break;
-
- if (recvResult == SOCKET_ERROR) {
- if (WSAGetLastError() == ERROR_TIMEOUT) {
- if (m_chat_rooms.getCount())
- idle_chat = 0;
- else if (++idle_chat >= 6)
- break;
-
- if (aim_keepalive(m_hChatNavConn, m_chatnav_seqno) < 0)
- break;
- }
- else
- break;
- }
-
- if (recvResult > 0) {
- unsigned short flap_length = 0;
- for (; packetRecv.bytesUsed < packetRecv.bytesAvailable; packetRecv.bytesUsed = flap_length) {
- if (!packetRecv.buffer)
- break;
- FLAP flap((char*)&packetRecv.buffer[packetRecv.bytesUsed], packetRecv.bytesAvailable - packetRecv.bytesUsed);
- if (!flap.len())
- break;
- flap_length += FLAP_SIZE + flap.len();
- if (flap.cmp(0x01)) {
- aim_send_cookie(m_hChatNavConn, m_chatnav_seqno, CHATNAV_COOKIE_LENGTH, CHATNAV_COOKIE);//cookie challenge
- mir_free(CHATNAV_COOKIE);
- CHATNAV_COOKIE = nullptr;
- CHATNAV_COOKIE_LENGTH = 0;
- }
- else if (flap.cmp(0x02)) {
- SNAC snac(flap.val(), flap.snaclen());
- if (snac.cmp(0x0001)) {
- snac_supported_families(snac, m_hChatNavConn, m_chatnav_seqno);
- snac_supported_family_versions(snac, m_hChatNavConn, m_chatnav_seqno);
- snac_chatnav_rate_limitations(snac, m_hChatNavConn, m_chatnav_seqno);
- snac_error(snac);
- }
- if (snac.cmp(0x000D)) {
- snac_chatnav_info_response(snac, m_hChatNavConn, m_chatnav_seqno);
- snac_error(snac);
- }
- }
- else if (flap.cmp(0x04))
- goto exit;
- }
- }
- }
-
-exit:
- Netlib_CloseHandle(hServerPacketRecver);
- Netlib_CloseHandle(m_hChatNavConn);
- m_hChatNavConn = nullptr;
- ResetEvent(m_hChatNavEvent);
- debugLogA("Chat Navigation Server Connection has ended");
-}
-
-void __cdecl CAimProto::aim_chat_negotiation(void* param)
-{
- chat_list_item *item = (chat_list_item*)param;
- HANDLE hServerPacketRecver = Netlib_CreatePacketReceiver(item->hconn, 2048 * 8);
-
- NETLIBPACKETRECVER packetRecv = { 0 };
- packetRecv.dwTimeout = DEFAULT_KEEPALIVE_TIMER * 1000;
-
- for (;;) {
- int recvResult = Netlib_GetMorePackets(hServerPacketRecver, &packetRecv);
- if (recvResult == 0)
- break;
-
- if (recvResult == SOCKET_ERROR) {
- if (WSAGetLastError() == ERROR_TIMEOUT) {
- if (aim_keepalive(item->hconn, item->seqno) < 0)
- break;
- }
- else
- break;
- }
-
- if (recvResult > 0) {
- unsigned short flap_length = 0;
- for (; packetRecv.bytesUsed < packetRecv.bytesAvailable; packetRecv.bytesUsed = flap_length) {
- if (!packetRecv.buffer)
- break;
- FLAP flap((char*)&packetRecv.buffer[packetRecv.bytesUsed], packetRecv.bytesAvailable - packetRecv.bytesUsed);
- if (!flap.len())
- break;
- flap_length += FLAP_SIZE + flap.len();
- if (flap.cmp(0x01)) {
- aim_send_cookie(item->hconn, item->seqno, item->CHAT_COOKIE_LENGTH, item->CHAT_COOKIE);//cookie challenge
- mir_free(item->CHAT_COOKIE);
- item->CHAT_COOKIE = nullptr;
- item->CHAT_COOKIE_LENGTH = 0;
- }
- else if (flap.cmp(0x02)) {
- SNAC snac(flap.val(), flap.snaclen());
- if (snac.cmp(0x0001)) {
- snac_supported_families(snac, item->hconn, item->seqno);
- snac_supported_family_versions(snac, item->hconn, item->seqno);
- snac_chat_rate_limitations(snac, item->hconn, item->seqno);
- snac_error(snac);
-
- }
- if (snac.cmp(0x000E)) {
- snac_chat_received_message(snac, item);
- snac_chat_joined_left_users(snac, item);
- snac_error(snac);
- }
- }
- else if (flap.cmp(0x04))
- goto exit;
- }
- }
- }
-
-exit:
- Netlib_CloseHandle(hServerPacketRecver);
- Netlib_CloseHandle(item->hconn);
- chat_leave(item->id);
- remove_chat_by_ptr(item);
- debugLogA("Chat Server Connection has ended");
-}
-
-void __cdecl CAimProto::aim_admin_negotiation(void*)
-{
- HANDLE hServerPacketRecver = Netlib_CreatePacketReceiver(m_hAdminConn, 2048 * 8);
-
- NETLIBPACKETRECVER packetRecv = {};
- packetRecv.dwTimeout = 300000; // 5 minutes connected
-
- for (;;) {
- int recvResult = Netlib_GetMorePackets(hServerPacketRecver, &packetRecv);
- if (recvResult == 0)
- break;
-
- if (recvResult == SOCKET_ERROR)
- break;
-
- if (recvResult > 0) {
- unsigned short flap_length = 0;
- for (; packetRecv.bytesUsed < packetRecv.bytesAvailable; packetRecv.bytesUsed = flap_length) {
- if (!packetRecv.buffer)
- break;
- FLAP flap((char*)&packetRecv.buffer[packetRecv.bytesUsed], packetRecv.bytesAvailable - packetRecv.bytesUsed);
- if (!flap.len())
- break;
- flap_length += FLAP_SIZE + flap.len();
- if (flap.cmp(0x01)) {
- aim_send_cookie(m_hAdminConn, m_admin_seqno, ADMIN_COOKIE_LENGTH, ADMIN_COOKIE);//cookie challenge
- mir_free(ADMIN_COOKIE);
- ADMIN_COOKIE = nullptr;
- ADMIN_COOKIE_LENGTH = 0;
- }
- else if (flap.cmp(0x02)) {
- SNAC snac(flap.val(), flap.snaclen());
- if (snac.cmp(0x0001)) {
- snac_supported_families(snac, m_hAdminConn, m_admin_seqno);
- snac_supported_family_versions(snac, m_hAdminConn, m_admin_seqno);
- snac_admin_rate_limitations(snac, m_hAdminConn, m_admin_seqno);
- snac_error(snac);
- }
- if (snac.cmp(0x0007)) {
- snac_admin_account_infomod(snac);
- snac_admin_account_confirm(snac);
- snac_error(snac);
- }
- }
- else if (flap.cmp(0x04))
- goto exit;
- }
- }
- }
-
-exit:
- Netlib_CloseHandle(hServerPacketRecver);
- Netlib_CloseHandle(m_hAdminConn);
- m_hAdminConn = nullptr;
- ResetEvent(m_hAdminEvent);
- debugLogA("Admin Server Connection has ended");
-}
diff --git a/protocols/AimOscar/src/conv.cpp b/protocols/AimOscar/src/conv.cpp deleted file mode 100644 index cca0c668ac..0000000000 --- a/protocols/AimOscar/src/conv.cpp +++ /dev/null @@ -1,758 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2012 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 "stdafx.h"
-
-#pragma warning( disable: 4706 )
-
-char* process_status_msg(const char *str, const char* sn)
-{
- const char *src = str;
- size_t size = mir_strlen(src) + 1;
- char* res = (char*)mir_alloc(size);
- char* dest = res;
- size_t len = mir_strlen(sn);
-
- for (; *src; ++src) {
- if (src[0] == '\n' && (src == str || src[-1] != '\r')) {
- int off = dest - res;
- res = (char*)mir_realloc(res, ++size);
- dest = res + off;
- *(dest++) = '\r';
- *(dest++) = *src;
- }
- else if (src[0] == '%' && src[1] == 'n') {
- int off = dest - res;
- res = (char*)mir_realloc(res, size + len);
- dest = res + off;
- size += len;
- memcpy(dest, sn, len);
- dest += len;
- ++src;
- }
- else if (src[0] == '%' && src[1] == 'd') {
- int off = dest - res;
- res = (char*)mir_realloc(res, size + 20);
- dest = res + off;
- size += 20;
- dest += GetDateFormatA(LOCALE_USER_DEFAULT, 0, nullptr, nullptr, dest, 20) - 1;
- ++src;
- }
- else if (src[0] == '%' && src[1] == 't') {
- int off = dest - res;
- res = (char*)mir_realloc(res, size + 20);
- dest = res + off;
- size += 20;
- dest += GetTimeFormatA(LOCALE_USER_DEFAULT, 0, nullptr, nullptr, dest, 20) - 1;
- ++src;
- }
- else *(dest++) = *src;
- }
- *dest = '\0';
- return res;
-}
-
-
-void html_decode(char* str)
-{
- char *p, *q;
-
- if (str == nullptr) return;
-
- for (p = q = str; *p != '\0'; p++, q++) {
- if (*p == '&') {
- if (!strnicmp(p, "&", 5)) { *q = '&'; p += 4; }
- else if (!strnicmp(p, "'", 6)) { *q = '\''; p += 5; }
- else if (!strnicmp(p, ">", 4)) { *q = '>'; p += 3; }
- else if (!strnicmp(p, "<", 4)) { *q = '<'; p += 3; }
- else if (!strnicmp(p, """, 6)) { *q = '"'; p += 5; }
- else if (*(p + 1) == '#') {
- char *s = strchr(p, ';');
- if (s) {
- wchar_t t[2] = { (wchar_t)atoi(p + 2), 0 };
- char *t1 = mir_utf8encodeW(t);
- if (t1 && *t1) {
- mir_strcpy(q, t1);
- q += mir_strlen(t1) - 1;
- }
- mir_free(t1);
- p = s;
- }
- else
- *q = *p;
- }
- else { *q = *p; }
- }
- else if (*p == '<') {
- if (!strnicmp(p, "<p>", 3)) { mir_strcpy(q, "\r\n\r\n"); q += 3; p += 2; }
- else if (!strnicmp(p, "</p>", 4)) { mir_strcpy(q, "\r\n\r\n"); q += 3; p += 3; }
- else if (!strnicmp(p, "<br>", 4)) { mir_strcpy(q, "\r\n"); ++q; p += 3; }
- else if (!strnicmp(p, "<br />", 6)) { mir_strcpy(q, "\r\n"); ++q; p += 5; }
- else if (!strnicmp(p, "<hr>", 4)) { mir_strcpy(q, "\r\n"); ++q; p += 3; }
- else if (!strnicmp(p, "<hr />", 6)) { mir_strcpy(q, "\r\n"); ++q; p += 5; }
- else {
- char *l = strchr(p, '>');
- if (l) { p = l; --q; }
- else *q = *p;
- }
- }
- else *q = *p;
- }
- *q = '\0';
-}
-
-
-char* html_encode(const char* str)
-{
- char *s, *q;
- const char *p;
- int c;
-
- if (str == nullptr) return nullptr;
-
- for (c = 0, p = 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;
- case '\n': c += 4; break;
- default: c++; break;
- }
- }
-
- s = (char*)mir_alloc(c + 27);
- mir_strcpy(s, "<HTML><BODY>");
- for (p = str, q = s + 12; *p != '\0'; p++) {
- switch (*p) {
- case '&': memcpy(q, "&", 5); q += 5; break;
- case '>': memcpy(q, ">", 4); q += 4; break;
- case '<': memcpy(q, "<", 4); q += 4; break;
- case '"': memcpy(q, """, 6); q += 6; break;
- case '\r': break;
- case '\n': memcpy(q, "<BR>", 4); q += 4; break;
- default: *q = *p; ++q; break;
- }
- }
- mir_strcpy(q, "</BODY></HTML>");
-
- return s;
-}
-
-char* html_to_bbcodes(char *src)
-{
- char *ptr;
- char *ptrl;
- char *rptr;
- char* dest = mir_strdup(src);
- while ((ptr = strstr(dest, "<B>")) != nullptr || (ptr = strstr(dest, "<b>")) != nullptr) {
- *ptr = '[';
- *(ptr + 1) = 'b';
- *(ptr + 2) = ']';
- if ((ptr = strstr(dest, "</B>")) != nullptr || (ptr = strstr(dest, "</b>")) != nullptr) {
- *ptr = '[';
- *(ptr + 2) = 'b';
- *(ptr + 3) = ']';
- }
- else {
- dest = (char*)mir_realloc(dest, mir_strlen(dest) + 6);
- memcpy(&dest[mir_strlen(dest)], "[/b]", 5);
- }
- }
- while ((ptr = strstr(dest, "<I>")) != nullptr || (ptr = strstr(dest, "<i>")) != nullptr) {
- *ptr = '[';
- *(ptr + 1) = 'i';
- *(ptr + 2) = ']';
- if ((ptr = strstr(dest, "</I>")) != nullptr || (ptr = strstr(dest, "</i>")) != nullptr) {
- *ptr = '[';
- *(ptr + 2) = 'i';
- *(ptr + 3) = ']';
- }
- else {
- dest = (char*)mir_realloc(dest, mir_strlen(dest) + 6);
- memcpy(&dest[mir_strlen(dest)], "[/i]", 5);
- }
- }
- while ((ptr = strstr(dest, "<U>")) != nullptr || (ptr = strstr(dest, "<u>")) != nullptr) {
- *ptr = '[';
- *(ptr + 1) = 'u';
- *(ptr + 2) = ']';
- if ((ptr = strstr(dest, "</U>")) != nullptr || (ptr = strstr(dest, "</u>")) != nullptr) {
- *ptr = '[';
- *(ptr + 2) = 'u';
- *(ptr + 3) = ']';
- }
- else {
- dest = (char*)mir_realloc(dest, mir_strlen(dest) + 6);
- memcpy(&dest[mir_strlen(dest)], "[/u]", 5);
- }
- }
- while ((ptr = strstr(dest, "<S>")) != nullptr || (ptr = strstr(dest, "<s>")) != nullptr) {
- *ptr = '[';
- *(ptr + 1) = 's';
- *(ptr + 2) = ']';
- if ((ptr = strstr(dest, "</S>")) != nullptr || (ptr = strstr(dest, "</s>")) != nullptr) {
- *ptr = '[';
- *(ptr + 2) = 's';
- *(ptr + 3) = ']';
- }
- else {
- dest = (char*)mir_realloc(dest, mir_strlen(dest) + 6);
- memcpy(&dest[mir_strlen(dest)], "[/s]", 5);
- }
- }
- rptr = dest;
- while (ptr = strstr(rptr, "<A HREF")) {
- char* begin = ptr;
- ptrl = ptr + 4;
- memcpy(ptrl, "[url=", 5);
- memmove(ptr, ptrl, mir_strlen(ptrl) + 1);
- if ((ptr = strstr(ptrl, ">"))) {
- ptr -= 1;
- memmove(ptr, ptr + 1, mir_strlen(ptr + 1) + 1);
- *(ptr) = ']';
- ptrl -= 1;
- char* s1 = strstr(ptrl, "</A");
- char* s2 = strstr(rptr, "<A HREF");
- if (s1&&s1 < s2 || s1&&!s2) {
- ptr = s1;
- ptr = strip_tag_within(begin, ptr);
- memmove(ptr + 2, ptr, mir_strlen(ptr) + 1);
- memcpy(ptr, "[/url]", 6);
- }
- else if (s2&&s2 < s1 || s2&&!s1) {
- ptr = s2;
- ptr = strip_tag_within(begin, ptr);
- int addr = ptr - rptr;
- dest = (char*)mir_realloc(dest, mir_strlen(dest) + 8);
- rptr = dest;
- ptr = rptr + addr;
- memmove(ptr + 6, ptr, mir_strlen(ptr) + 1);
- memcpy(ptr, "[/url]", 6);
- }
- else {
- strip_tag_within(begin, &dest[mir_strlen(dest)]);
- //int addr=ptr-rptr;
- dest = (char*)mir_realloc(dest, mir_strlen(dest) + 8);
- rptr = dest;
- ptr = dest;
- memcpy(&ptr[mir_strlen(ptr)], "[/url]", 7);
- }
- }
- else rptr++;
- }
- rptr = dest;
- while (ptr = strstr(rptr, "<a href")) {
- char* begin = ptr;
- ptrl = ptr + 4;
- memcpy(ptrl, "[url=", 5);
- memmove(ptr, ptrl, mir_strlen(ptrl) + 1);
- if ((ptr = strstr(ptrl, ">"))) {
- ptr -= 1;
- memmove(ptr, ptr + 1, mir_strlen(ptr + 1) + 1);
- *(ptr) = ']';
- ptrl -= 1;
- char* s1 = strstr(ptrl, "</a");
- char* s2 = strstr(ptrl, "<a href");
- if (s1&&s1 < s2 || s1&&!s2) {
- ptr = s1;
- ptr = strip_tag_within(begin, ptr);
- memmove(ptr + 2, ptr, mir_strlen(ptr) + 1);
- memcpy(ptr, "[/url]", 6);
- }
- else if (s2&&s2 < s1 || s2&&!s1) {
- ptr = s2;
- ptr = strip_tag_within(begin, ptr);
- int addr = ptr - rptr;
- dest = (char*)mir_realloc(dest, mir_strlen(dest) + 8);
- rptr = dest;
- ptr = rptr + addr;
- memmove(ptr + 6, ptr, mir_strlen(ptr) + 1);
- memcpy(ptr, "[/url]", 6);
- }
- else {
- strip_tag_within(begin, &dest[mir_strlen(dest)]);
- //int addr=ptr-rptr;
- dest = (char*)mir_realloc(dest, mir_strlen(dest) + 8);
- rptr = dest;
- ptr = dest;
- memcpy(&ptr[mir_strlen(ptr)], "[/url]", 7);
- }
- }
- else rptr++;
- }
- rptr = dest;
- while (ptr = strstr(rptr, "<FONT COLOR=\"")) {
- int addr = ptr - rptr;
- dest = (char*)mir_realloc(dest, mir_strlen(dest) + 8);
- rptr = dest;
- ptr = rptr + addr;
- ptrl = ptr + 6;
- memcpy(ptrl, "[color=", 7);
- memmove(ptr, ptrl, mir_strlen(ptrl) + 1);
- if ((ptr = strstr(ptrl, ">"))) {
- memmove(ptrl + 7, ptr, mir_strlen(ptr) + 1);
- *(ptrl + 7) = ']';
- ptr = ptrl + 7;
- char* s1 = strstr(ptr, "</FONT");
- char* s2 = strstr(ptr, "<FONT COLOR=\"");
- if (s1&&s1 < s2 || s1&&!s2) {
- ptr = s1;
- memmove(ptr + 1, ptr, mir_strlen(ptr) + 1);
- memcpy(ptr, "[/color]", 8);
- }
- else if (s2&&s2 < s1 || s2&&!s1) {
- ptr = s2;
- memmove(ptr + 8, ptr, mir_strlen(ptr) + 1);
- memcpy(ptr, "[/color]", 8);
- }
- else {
- ptr = dest;
- memcpy(&ptr[mir_strlen(ptr)], "[/color]", 9);
- }
- }
- else rptr++;
- }
- rptr = dest;
- while (ptr = strstr(rptr, "<font color=\"")) {
- int addr = ptr - rptr;
- dest = (char*)mir_realloc(dest, mir_strlen(dest) + 8);
- rptr = dest;
- ptr = rptr + addr;
- ptrl = ptr + 6;
- memcpy(ptrl, "[color=", 7);
- memmove(ptr, ptrl, mir_strlen(ptrl) + 1);
- if ((ptr = strstr(ptrl, ">"))) {
- memmove(ptrl + 7, ptr, mir_strlen(ptr) + 1);
- *(ptrl + 7) = ']';
- ptr = ptrl + 7;
- char* s1 = strstr(ptr, "</font");
- char* s2 = strstr(ptr, "<font color=\"");
- if (s1&&s1 < s2 || s1&&!s2) {
- ptr = s1;
- memmove(ptr + 1, ptr, mir_strlen(ptr) + 1);
- memcpy(ptr, "[/color]", 8);
- }
- else if (s2&&s2 < s1 || s2&&!s1) {
- ptr = s2;
- memmove(ptr + 8, ptr, mir_strlen(ptr) + 1);
- memcpy(ptr, "[/color]", 8);
- }
- else {
- ptr = dest;
- memcpy(&ptr[mir_strlen(ptr)], "[/color]", 9);
- }
- }
- else rptr++;
- }
- rptr = dest;
- while ((ptr = strstr(rptr, "<FONT COLOR=")) || (ptr = strstr(rptr, "<font color="))) {
- int addr = ptr - rptr;
- dest = (char*)mir_realloc(dest, mir_strlen(dest) + 8);
- rptr = dest;
- ptr = rptr + addr;
- ptrl = ptr + 5;
- memcpy(ptrl, "[color=", 7);
- memmove(ptr, ptrl, mir_strlen(ptrl) + 1);
- if ((ptr = strstr(ptrl, ">"))) {
- *(ptr) = ']';
- if ((ptrl = strstr(ptr, "</FONT")) || (ptrl = strstr(ptr, "</font"))) {
- memmove(ptrl + 1, ptrl, mir_strlen(ptrl) + 1);
- memcpy(ptrl, "[/color]", 8);
- }
- else memcpy(&dest[mir_strlen(dest)], "[/color]", 9);
- }
- else rptr++;
- }
-
- return dest;
-}
-
-char* bbcodes_to_html(const char *src)
-{
- char *ptr;
- char *rptr;
- char* dest = mir_strdup(src);
- while ((ptr = strstr(dest, "[b]")) != nullptr) {
- *ptr = '<';
- *(ptr + 1) = 'b';
- *(ptr + 2) = '>';
- }
- while ((ptr = strstr(dest, "[/b]")) != nullptr) {
- *ptr = '<';
- *(ptr + 2) = 'b';
- *(ptr + 3) = '>';
- }
- while ((ptr = strstr(dest, "[i]")) != nullptr) {
- *ptr = '<';
- *(ptr + 1) = 'i';
- *(ptr + 2) = '>';
- }
- while ((ptr = strstr(dest, "[/i]")) != nullptr) {
- *ptr = '<';
- *(ptr + 2) = 'i';
- *(ptr + 3) = '>';
- }
- while ((ptr = strstr(dest, "[u]")) != nullptr) {
- *ptr = '<';
- *(ptr + 1) = 'u';
- *(ptr + 2) = '>';
- }
- while ((ptr = strstr(dest, "[/u]")) != nullptr) {
- *ptr = '<';
- *(ptr + 2) = 'u';
- *(ptr + 3) = '>';
- }
- while ((ptr = strstr(dest, "[s]")) != nullptr) {
- *ptr = '<';
- *(ptr + 1) = 's';
- *(ptr + 2) = '>';
- }
- while ((ptr = strstr(dest, "[/s]")) != nullptr) {
- *ptr = '<';
- *(ptr + 2) = 's';
- *(ptr + 3) = '>';
- }
- rptr = dest;
- while ((ptr = strstr(rptr, "[color="))) {
- int addr = ptr - rptr;
- dest = (char*)mir_realloc(dest, mir_strlen(dest) + 8);
- rptr = dest;
- ptr = rptr + addr;
- memmove(ptr + 5, ptr, mir_strlen(ptr) + 1);
- memcpy(ptr, "<font ", 6);
- if ((ptr = strstr(ptr, "]"))) {
- *(ptr) = '>';
- if ((ptr = strstr(ptr, "[/color]"))) {
- memcpy(ptr, "</font>", 7);
- memmove(ptr + 7, ptr + 8, mir_strlen(ptr + 8) + 1);
- }
- }
- else
- rptr++;
- }
- while ((ptr = strstr(rptr, "[url="))) {
- int addr = ptr - rptr;
- dest = (char*)mir_realloc(dest, mir_strlen(dest) + 8);
- rptr = dest;
- ptr = rptr + addr;
- memmove(ptr + 3, ptr, mir_strlen(ptr) + 1);
- memcpy(ptr, "<a href", 7);
- if ((ptr = strstr(ptr, "]"))) {
- *(ptr) = '>';
- if ((ptr = strstr(ptr, "[/url]"))) {
- memcpy(ptr, "</a>", 4);
- memmove(ptr + 4, ptr + 6, mir_strlen(ptr + 6) + 1);
- }
- }
- else
- rptr++;
- }
- return dest;
-}
-
-void strip_tag(char* begin, char* end)
-{
- memmove(begin, end + 1, mir_strlen(end + 1) + 1);
-}
-
-//strip a tag within a string
-char* strip_tag_within(char* begin, char* end)
-{
- while (char *sub_begin = strchr(begin, '<')) {
- if (sub_begin < end)//less than the original ending
- {
- char *sub_end = strchr(begin, '>');
- strip_tag(sub_begin, sub_end);
- end = end - (sub_end - sub_begin) - 1;
- }
- else
- break;
- }
- return end;
-}
-
-char* rtf_to_html(HWND hwndDlg, int DlgItem)
-{
- char* buf = (char*)mir_alloc(4024);
- size_t pos = 0;
- int start = 0;
- int end = 1;
- BOOL Bold = false;
- BOOL Italic = false;
- BOOL Underline = false;
- char Face[32] = "";
- COLORREF Color = 0;
- COLORREF BackColor = 0;
- int Size = 0;
- GETTEXTLENGTHEX tl;
- tl.flags = GTL_DEFAULT;
- tl.codepage = CP_ACP;
-
- int oldstart = 0, oldend = 0;
- SendDlgItemMessage(hwndDlg, DlgItem, EM_GETSEL, (WPARAM)&oldstart, (LPARAM)&oldend);
-
- int length = SendDlgItemMessage(hwndDlg, DlgItem, EM_GETTEXTLENGTHEX, (WPARAM)&tl, 0);
- while (start < length) {
- SendDlgItemMessage(hwndDlg, DlgItem, EM_SETSEL, start, end);
- CHARFORMAT2A cfOld;
- cfOld.cbSize = sizeof(cfOld);
- cfOld.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_SIZE | CFM_COLOR | CFM_BACKCOLOR | CFM_FACE;
- SendDlgItemMessageA(hwndDlg, DlgItem, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
- BOOL isBold = (cfOld.dwEffects & CFE_BOLD) && (cfOld.dwMask & CFM_BOLD);
- BOOL isItalic = (cfOld.dwEffects & CFE_ITALIC) && (cfOld.dwMask & CFM_ITALIC);
- BOOL isUnderline = (cfOld.dwEffects & CFE_UNDERLINE) && (cfOld.dwMask & CFM_UNDERLINE);
- COLORREF isColor = cfOld.crTextColor;
- COLORREF isBackColor = cfOld.crBackColor;
- int isSize;
- if (cfOld.yHeight == 38 * 20)
- isSize = 7;
- else if (cfOld.yHeight == 24 * 20)
- isSize = 6;
- else if (cfOld.yHeight == 18 * 20)
- isSize = 5;
- else if (cfOld.yHeight == 14 * 20)
- isSize = 4;
- else if (cfOld.yHeight == 12 * 20)
- isSize = 3;
- else if (cfOld.yHeight == 10 * 20)
- isSize = 2;
- else if (cfOld.yHeight == 8 * 20)
- isSize = 1;
- else
- isSize = 3;
- wchar_t text[3] = L"";
- SendDlgItemMessage(hwndDlg, DlgItem, EM_GETSELTEXT, 0, (LPARAM)&text);
- if (Bold != isBold) {
- Bold = isBold;
- if (isBold) {
- mir_strcpy(&buf[pos], "<b>");
- pos += 3;
- }
- else {
- if (start != 0) {
- mir_strcpy(&buf[pos], "</b>");
- pos += 4;
- }
- }
- }
- if (Italic != isItalic) {
- Italic = isItalic;
- if (isItalic) {
- mir_strcpy(&buf[pos], "<i>");
- pos += 3;
- }
- else {
- if (start != 0) {
- mir_strcpy(&buf[pos], "</i>");
- pos += 4;
- }
- }
- }
- if (Underline != isUnderline) {
- Underline = isUnderline;
- if (isUnderline) {
- mir_strcpy(&buf[pos], "<u>");
- pos += 3;
- }
- else {
- if (start != 0) {
- mir_strcpy(&buf[pos], "</u>");
- pos += 4;
- }
- }
- }
- if (Size != isSize || Color != isColor || BackColor != isBackColor || mir_strcmp(Face, cfOld.szFaceName)) {
- Size = isSize;
- Color = isColor;
- BackColor = isBackColor;
- mir_strcpy(Face, cfOld.szFaceName);
- if (start != 0) {
- mir_strcpy(&buf[pos], "</font>");
- pos += 7;
- }
- mir_strcpy(&buf[pos], "<font");
- pos += 5;
- mir_strcpy(&buf[pos], " face=\"");
- pos += 7;
- mir_strcpy(&buf[pos], Face);
- pos += mir_strlen(Face);
- mir_strcpy(&buf[pos], "\"");
- pos++;
- if (!(cfOld.dwEffects & CFE_AUTOBACKCOLOR)) {
- mir_strcpy(&buf[pos], " back=#");
- pos += 6;
- char chBackColor[7];
- _itoa((_htonl(BackColor) >> 8), chBackColor, 16);
- size_t len = mir_strlen(chBackColor);
- if (len < 6) {
- memmove(chBackColor + (6 - len), chBackColor, len + 1);
- for (int i = 0; i < 6; i++)
- chBackColor[i] = '0';
- }
- mir_strcpy(&buf[pos], chBackColor);
- pos += 6;
- }
- if (!(cfOld.dwEffects & CFE_AUTOCOLOR)) {
- mir_strcpy(&buf[pos], " color=#");
- pos += 8;
- char chColor[7];
- _itoa((_htonl(Color) >> 8), chColor, 16);
- size_t len = mir_strlen(chColor);
- if (len < 6) {
- memmove(chColor + (6 - len), chColor, len + 1);
- for (int i = 0; i < 6; i++)
- chColor[i] = '0';
- }
- mir_strcpy(&buf[pos], chColor);
- pos += 6;
- }
- mir_strcpy(&buf[pos], " size=");
- pos += 6;
- char chSize[2];
- _itoa(Size, chSize, 10);
- mir_strcpy(&buf[pos], chSize);
- pos++;
-
- mir_strcpy(&buf[pos], ">");
- pos++;
- }
- if (text[0] == '\r') {
- mir_strcpy(&buf[pos], "<br>");
- pos += 4;
- }
- else {
- T2Utf txt(text);
- mir_strcpy(&buf[pos], txt);
- pos += mir_strlen(txt);
- }
- start++;
- end++;
- }
- if (Bold) {
- mir_strcpy(&buf[pos], "</b>");
- pos += 4;
- }
- if (Italic) {
- mir_strcpy(&buf[pos], "</i>");
- pos += 4;
- }
- if (Underline) {
- mir_strcpy(&buf[pos], "</u>");
- pos += 4;
- }
- mir_strcpy(&buf[pos], "</font>");
- pos += 7;
-
- SendDlgItemMessage(hwndDlg, DlgItem, EM_SETSEL, oldstart, oldend);
-
- return buf;
-}
-
-void wcs_htons(wchar_t *ch)
-{
- if (ch == nullptr) return;
- for (size_t i = 0; i < mir_wstrlen(ch); i++)
- ch[i] = _htons(ch[i]);
-}
-
-char* bytes_to_string(char *bytes, int num_bytes)
-{
- if (num_bytes == 0) return nullptr;
-
- char *string = (char*)mir_alloc(num_bytes * 2 + 1);
- for (int i = 0; i < num_bytes; i++) {
- char store[2];
- unsigned char bit = (bytes[i] & 0xF0) >> 4;
- _itoa(bit, store, 16);
- memcpy(&string[i * 2], store, 1);
- bit = (bytes[i] & 0x0F);
- _itoa(bit, store, 16);
- memcpy(&string[i * 2 + 1], store, 1);
- }
- string[num_bytes * 2] = '\0';
- return string;
-}
-
-void string_to_bytes(char *string, char *bytes)
-{
- char sbyte[3];
- sbyte[2] = '\0';
- size_t length = mir_strlen(string);
- for (size_t i = 0; i < length; i += 2) {
- sbyte[0] = string[i];
- sbyte[1] = string[i + 1];
- bytes[i / 2] = (char)strtol(sbyte, nullptr, 16);
- }
-}
-
-bool is_utf(const char *msg)
-{
- bool res = false;
- if (msg) {
- for (unsigned i = 0; !res; ++i) {
- char c = msg[i];
- if (c == 0) break;
- res = (c & 0x80) != 0;
- }
- }
- return res;
-}
-
-char* get_fname(char *path)
-{
- char *pszFile = strrchr(path, '\\');
- if (pszFile) pszFile++; else pszFile = path;
-
- return pszFile;
-}
-
-wchar_t* get_dir(wchar_t *path)
-{
- wchar_t *cpath = mir_wstrdup(path);
-
- wchar_t *swd = wcsrchr(cpath, '\\');
- if (swd) swd[1] = 0; else cpath[0] = 0;
-
- return cpath;
-}
-
-aimString::aimString(char *str)
-{
- if (str == nullptr) {
- szString = nullptr;
- size = 0;
- unicode = false;
- }
- else {
- unicode = is_utf(str);
- if (unicode) {
- wszString = mir_utf8decodeW(str);
- wcs_htons(wszString);
- size = mir_wstrlen(wszString) * sizeof(wchar_t);
- }
- else {
- szString = mir_utf8decodeA(str);
- size = mir_strlen(szString);
- }
- }
-}
-
-#pragma warning( default: 4706 )
diff --git a/protocols/AimOscar/src/conv.h b/protocols/AimOscar/src/conv.h deleted file mode 100644 index d12506189b..0000000000 --- a/protocols/AimOscar/src/conv.h +++ /dev/null @@ -1,56 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2009 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 CONV_H
-#define CONV_H
-
-char* process_status_msg (const char *src, const char* sn);
-void html_decode(char* str);
-char* html_encode(const char *src);
-char* html_to_bbcodes(char *src);
-char* bbcodes_to_html(const char *src);
-void strip_tag(char* begin, char* end);
-char* strip_tag_within(char* begin, char* end);
-char* rtf_to_html(HWND hwndDlg,int DlgItem);
-void wcs_htons(wchar_t * ch);
-char* bytes_to_string(char* bytes, int num_bytes);
-void string_to_bytes(char* string, char* bytes);
-bool is_utf(const char* msg);
-char* get_fname(char* path);
-wchar_t* get_dir(wchar_t* path);
-
-struct aimString
-{
- union
- {
- char* szString;
- wchar_t* wszString;
- };
- size_t size;
- bool unicode;
-
- aimString(char* str);
- ~aimString() { mir_free(szString); }
-
- bool isUnicode(void) { return unicode; }
- unsigned short getSize(void) { return (unsigned short)size; }
- unsigned short getTermSize(void) { return (unsigned short)(size + (unicode ? sizeof(wchar_t) : sizeof(char))); }
- char* getBuf(void) { return szString; }
-};
-
-#endif
diff --git a/protocols/AimOscar/src/defines.h b/protocols/AimOscar/src/defines.h deleted file mode 100644 index 11126ac2fb..0000000000 --- a/protocols/AimOscar/src/defines.h +++ /dev/null @@ -1,353 +0,0 @@ -#ifndef DEFINES_H
-#define DEFINES_H
-#if defined __GNUC__
-#pragma GCC system_header
-#endif
-#define _CRT_SECURE_NO_DEPRECATE
-#pragma warning (disable : 4996)
-//System includes
-#include <windows.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <io.h>
-#include <malloc.h>
-#include <process.h>
-#include <prsht.h>
-#include <richedit.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <time.h>
-#include <vssym32.h>
-#include <winuser.h>
-//Miranda IM includes
-#pragma warning( disable: 4100 )
-#pragma warning( disable: 4244 )
-#pragma warning( disable: 4201 )
-#include <newpluginapi.h>
-#include <statusmodes.h>
-#include <m_button.h>
-#include <m_clist.h>
-#include <m_clui.h>
-#include "m_cluiframes.h"
-#include <m_database.h>
-#include <m_idle.h>
-#include <m_langpack.h>
-#include <m_message.h>
-#include <m_netlib.h>
-#include <m_options.h>
-#include <m_popup.h>
-#include <m_protocols.h>
-#include <m_protomod.h>
-#include <m_protosvc.h>
-#include <m_skin.h>
-#include <statusmodes.h>
-#include <m_system.h>
-#include <m_userinfo.h>
-#include <m_addcontact.h>
-#include <m_icolib.h>
-#pragma warning( default: 4100 )
-#pragma warning( default: 4244 )
-#pragma warning( default: 4201 )
-//independent includes
-#include "strl.h"
-#include "flap.h"
-#include "snac.h"
-#include "tlv.h"
-//rest o includes
-#include "avatars.h"
-#include "away.h"
-#include "utility.h"
-#include "client.h"
-#include "connection.h"
-#include "conv.h"
-#include "direct_connect.h"
-#include "error.h"
-#include "file.h"
-#include "links.h"
-#include "packets.h"
-#include "popup.h"
-#include "proxy.h"
-#include "resource.h"
-#include "services.h"
-#include "server.h"
-#include "theme.h"
-#include "thread.h"
-#include "windows.h"
-//Packet Stuff
-#define MSG_LEN 4089
-//Extended Status Icon Numbers
-#define ACCOUNT_TYPE_UNCONFIRMED 1
-#define ACCOUNT_TYPE_CONFIRMED 2
-#define ACCOUNT_TYPE_ICQ 3
-#define ACCOUNT_TYPE_AOL 4
-#define ACCOUNT_TYPE_ADMIN 5
-#define EXTENDED_STATUS_BOT 1
-#define EXTENDED_STATUS_HIPTOP 2
-//Popup flags
-#define MAIL_POPUP 4
-//Main Option Window Keys
-#define AIM_KEY_SN "SN"
-#define AIM_KEY_NK "Nick"
-#define AIM_KEY_PW "Password"
-#define AIM_KEY_HN "hostname"
-#define AIM_KEY_DC "DelConf"//delivery confirmation
-#define AIM_KEY_FP "ForceProxyTransfer"
-#define AIM_KEY_GP "FileTransferGracePeriod"//in seconds default 60
-#define AIM_KEY_KA "KeepAlive"//in seconds default 60
-#define AIM_KEY_HF "HiptopFake"
-#define AIM_KEY_AT "DisableATIcons"
-#define AIM_KEY_ES "DisableESIcons"
-#define AIM_KEY_DM "DisableModeMsg"
-#define AIM_KEY_FI "FormatIncoming"//html->bbcodes
-#define AIM_KEY_FO "FormatOutgoing"//bbcodes->html
-#define AIM_KEY_FR "FirstRun"
-#define AIM_KEY_II "InstantIdle"
-#define AIM_KEY_IIT "InstantIdleTS"
-#define AIM_KEY_CM "CheckMail"
-#define AIM_KEY_DA "DisableAvatars"
-
-//Other plugin Option Keys
-#define OTH_KEY_AI "AwayIgnore"
-#define OTH_KEY_AD "AwayDefault"
-#define OTH_KEY_AM "AwayMsg"
-#define OTH_KEY_OI "OccupiedIgnore"
-#define OTH_KEY_OD "OccupiedDefault"
-#define OTH_KEY_OM "OccupiedMsg"
-#define OTH_KEY_NI "NaIgnore"
-#define OTH_KEY_ND "NaDefault"
-#define OTH_KEY_NM "NaMsg"
-#define OTH_KEY_DI "DndIgnore"
-#define OTH_KEY_DD "DndDefault"
-#define OTH_KEY_DM "DndMsg"
-#define OTH_KEY_PI "OtpIgnore"
-#define OTH_KEY_PD "OtpDefault"
-#define OTH_KEY_PM "OtpMsg"
-#define OTH_KEY_LI "OtlIgnore"
-#define OTH_KEY_LD "OtlDefault"
-#define OTH_KEY_LM "OtlMsg"
-
-#define OTH_KEY_SM "StatusMsg"
-#define OTH_KEY_GP "Group"
-//Module Name Key
-#define MOD_KEY_SA "SRAway"
-#define MOD_KEY_CL "CList"
-//Settings Keys
-#define AIM_KEY_PR "Profile"
-#define AIM_KEY_LA "LastAwayChange"
-#define AIM_MOD_IG "ID2Group"
-#define AIM_MOD_GI "Group2ID"
-#define AIM_KEY_AL "AIMLinks"// aim: links support
-//Contact Keys
-#define AIM_KEY_BI "BuddyId"
-#define AIM_KEY_GI "GroupId"
-#define AIM_KEY_ST "Status"
-#define AIM_KEY_IT "IdleTS"
-#define AIM_KEY_OT "LogonTS"
-#define AIM_KEY_AC "AccType"//account type
-#define AIM_KEY_ET "ESType"//Extended Status type
-#define AIM_KEY_MV "MirVer"
-#define AIM_KEY_US "Utf8Support"
-#define AIM_KEY_NL "NotOnList"
-#define AIM_KEY_LM "LastMessage"
-#define AIM_KEY_NC "NewContact"
-#define AIM_KEY_AH "AvatarHash"
-//File Transfer Keys
-#define AIM_KEY_FT "FileTransfer"//1= sending 0=receiving
-#define AIM_KEY_CK "Cookie"
-#define AIM_KEY_CK2 "Cookie2"
-#define AIM_KEY_FN "FileName"
-#define AIM_KEY_FS "FileSize"
-#define AIM_KEY_FD "FileDesc"
-#define AIM_KEY_IP "IP"
-#define AIM_KEY_PS "ProxyStage"
-#define AIM_KEY_PC "PortCheck"
-#define AIM_KEY_DH "DCHandle"
-//Old Keys
-#define OLD_KEY_PW "password"
-#define OLD_KEY_DM "AutoResponse"
-
-//Some Defaults for various things
-#define DEFAULT_KEEPALIVE_TIMER 60// 1000 milliseconds * 60 = 60 secs
-#define DEFAULT_GRACE_PERIOD 60
-#define AIM_DEFAULT_GROUP "miranda merged"
-#define AIM_DEFAULT_SERVER "login.oscar.aol.com:5190"
-#define SYSTEM_BUDDY "aolsystemmsg"
-#define DEFAULT_AWAY_MSG "I am away from my computer right now."
-//Md5 Roasting stuff
-#define AIM_MD5_STRING "AOL Instant Messenger (SM)"
-#define MD5_HASH_LENGTH 16
-//Aim Version Stuff
-#define AIM_CLIENT_ID_NUMBER "\x01\x09"
-#define AIM_CLIENT_MAJOR_VERSION "\0\x05"
-#define AIM_CLIENT_MINOR_VERSION "\0\x09"
-#define AIM_CLIENT_LESSER_VERSION "\0\0"
-#define AIM_CLIENT_BUILD_NUMBER "\x0b\xdc"
-#define AIM_CLIENT_DISTRIBUTION_NUMBER "\0\0\0\xd2"
-#define AIM_LANGUAGE "en"
-#define AIM_COUNTRY "us"
-#define AIM_MSG_TYPE "text/x-aolrtf; charset=\"us-ascii\""
-#define AIM_TOOL_VERSION "\x01\x10\x08\xf1"
-extern char* AIM_CLIENT_ID_STRING; //Client id EXTERN
-//Supported Clients
-#define CLIENT_UNKNOWN "?"
-#define CLIENT_AIM5 "AIM 5.x"
-#define CLIENT_AIM4 "AIM 4.x"
-#define CLIENT_AIMEXPRESS "AIM Express"
-#define CLIENT_AIM_TRITON "AIM Triton"
-#define CLIENT_AIMTOC "AIM TOC"
-#define CLIENT_GAIM "Gaim"
-#define CLIENT_ADIUM "Adium X"
-#define CLIENT_GPRS "GPRS"
-#define CLIENT_ICHAT "iChat"
-#define CLIENT_IM2 "IM2"
-#define CLIENT_KOPETE "Kopete"
-#define CLIENT_MEEBO "Meebo"
-#define CLIENT_MICQ "mICQ"
-#define CLIENT_AIMOSCAR "Miranda IM %d.%d.%d.%d(AimOSCAR v%d.%d.%d.%d)"
-#define CLIENT_OSCARJ "Miranda IM %d.%d.%d.%d(ICQ v0.%d.%d.%d)"
-#define CLIENT_NAIM "naim"
-#define CLIENT_QIP "qip"
-#define CLIENT_SIM "SIM"
-#define CLIENT_SMS "SMS"
-#define CLIENT_TERRAIM "TerraIM"
-#define CLIENT_TRILLIAN_PRO "Trillian Pro"
-#define CLIENT_TRILLIAN "Trillian"
-//Aim Caps
-#define AIM_CAPS_LENGTH 16
-#define AIM_CAP_ICHAT "\x09\x46\x00\x00\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_UNKNOWN3 "\x09\x46\x01\x03\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_UNKNOWNA "\x09\x46\x01\x05\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_UNKNOWNB "\x09\x46\x01\xff\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_HIPTOP "\x09\x46\x13\x23\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_VOICE_CHAT "\x09\x46\x13\x41\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_DIRECT_PLAY "\x09\x46\x13\x42\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_SEND_FILES "\x09\x46\x13\x43\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_ROUTER_FIND "\x09\x46\x13\x44\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"//icq?
-#define AIM_CAP_DIRECT_IM "\x09\x46\x13\x45\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_AVATARS "\x09\x46\x13\x46\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_ADDINS "\x09\x46\x13\x47\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_RECEIVE_FILES "\x09\x46\x13\x48\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_CHANNEL_TWO "\x09\x46\x13\x49\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"//icq? channel 2 extended, TLV(0x2711) based messages
-#define AIM_CAP_GAMES "\x09\x46\x13\x4A\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_LIST_TRANSFER "\x09\x46\x13\x4B\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_ICQ_SUPPORT "\x09\x46\x13\x4D\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_UTF8 "\x09\x46\x13\x4E\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_UNKNOWN4 "\x09\x46\xf0\x03\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_UNKNOWN1 "\x09\x46\xf0\x04\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_UNKNOWNC "\x09\x46\xf0\x05\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_CHAT "\x74\x8F\x24\x20\x62\x87\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_IM2 "\x74\xed\xc3\x36\x44\xdf\x48\x5b\x8b\x1c\x67\x1a\x1f\x86\x09\x9f"
-#define AIM_CAP_TRILLIAN "\xF2\xE7\xC7\xF4\xFE\xAD\x4D\xFB\xB2\x35\x36\x79\x8B\xDF\0\0"
-extern char AIM_CAP_MIRANDA[]; //Miranda cap EXTERN
-//Aim Services
-#define AIM_SERVICE_GENERIC "\0\x01\0\x04"//version 4
-#define AIM_SERVICE_SSI "\0\x13\0\x03"//version 3
-#define AIM_SERVICE_LOCATION "\0\x02\0\x01"//version 1
-#define AIM_SERVICE_BUDDYLIST "\0\x03\0\x01"//version 1
-#define AIM_SERVICE_MESSAGING "\0\x04\0\x01"//version 1
-#define AIM_SERVICE_INVITATION "\0\x06\0\x01"//version 1
-#define AIM_SERVICE_POPUP "\0\x08\0\x01"//version 1
-#define AIM_SERVICE_BOS "\0\x09\0\x01"//version 1
-#define AIM_SERVICE_AVATAR "\0\x10\0\x01"//version 1
-#define AIM_SERVICE_USERLOOKUP "\0\x0A\0\x01"//version 1
-#define AIM_SERVICE_STATS "\0\x0B\0\x01"//version 1
-#define AIM_SERVICE_MAIL "\0\x18\0\x01"//version 1
-#define AIM_SERVICE_RATES "\0\x01\0\x02\0\x03\0\x04\0\x05"
-//Aim Statuses
-#define AIM_STATUS_WEBAWARE "\0\x01"
-#define AIM_STATUS_SHOWIP "\0\x02"
-#define AIM_STATUS_BIRTHDAY "\0\x08"
-#define AIM_STATUS_WEBFRONT "\0\x20"
-#define AIM_STATUS_DCAUTH "\x10\0"
-#define AIM_STATUS_DCCONT "\x20\0"
-#define AIM_STATUS_NULL "\0\0"
-#define AIM_STATUS_ONLINE "\0\0"
-#define AIM_STATUS_AWAY "\0\x01"
-#define AIM_STATUS_DND "\0\x02"
-#define AIM_STATUS_NA "\0\x04"
-#define AIM_STATUS_OCCUPIED "\0\x10"
-#define AIM_STATUS_FREE4CHAT "\0\x20"
-#define AIM_STATUS_INVISIBLE "\x01\0"
-
-#define HOOKEVENT_SIZE 10
-#define SERVICES_SIZE 30
-class oscar_data
-{
-public:
- char *username;
- char *password;
- unsigned short seqno;//main connection sequence number
- int state;//status of the connection; e.g. whether connected or not
- int packet_offset;//current offset of main connection client to server packet
- unsigned int status;//current status
- int initial_status;//start up status
- char* szModeMsg;//away message
- unsigned short port;
-
- //Some bools to keep track of different things
- bool request_HTML_profile;
- bool extra_icons_loaded;
- bool freeing_DirectBoundPort;
- bool shutting_down;
- bool idle;
- bool instantidle;
- bool checking_mail;
- bool list_received;
- HANDLE hKeepAliveEvent;
-
- HINSTANCE hInstance;//plugin handle instance
-
- //Some main connection stuff
- HANDLE hServerConn;//handle to the main connection
- HANDLE hServerPacketRecver;//handle to the listening device
- HANDLE hNetlib;//handle to netlib
- unsigned long InternalIP;// our ip
- unsigned short LocalPort;// our port
-
- //Peer connection stuff
- HNETLIBUSER m_hNetlibPeer;//handle to the peer netlib
- HANDLE hDirectBoundPort;//direct connection listening port
- HANDLE current_rendezvous_accept_user;//hack
-
- //Handles for the context menu items
- HANDLE hHTMLAwayContextMenuItem;
- HANDLE hAddToServerListContextMenuItem;
-
- //hook event size stuff
- HANDLE hookEvent[HOOKEVENT_SIZE];
- unsigned int hookEvent_size;//current hookevent size
-
- //services size stuff
- HANDLE services[SERVICES_SIZE];
- unsigned int services_size;//current services size
-
- //Some mail connection stuff
- HANDLE m_hMailConn;
- unsigned short mail_seqno;
- int mail_packet_offset;
-
- //avatar connection stuff
- HANDLE m_hAvatarConn;
- unsigned short avatar_seqno;
- HANDLE hAvatarEvent;
- bool AvatarLimitThread;
-
- //away message retrieval stuff
- HANDLE hAwayMsgEvent;
-
- //Some Icon handles
- HANDLE bot_icon;
- HANDLE icq_icon;
- HANDLE aol_icon;
- HANDLE hiptop_icon;
- HANDLE admin_icon;
- HANDLE confirmed_icon;
- HANDLE unconfirmed_icon;
-} extern conn;
-
-void InitIcons(void);
-HICON LoadIconEx(const char* name);
-HANDLE GetIconHandle(const char* name);
-void ReleaseIconEx(const char* name);
-
-#endif
diff --git a/protocols/AimOscar/src/direct_connect.cpp b/protocols/AimOscar/src/direct_connect.cpp deleted file mode 100644 index e79a0f1d9a..0000000000 --- a/protocols/AimOscar/src/direct_connect.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2012 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 "stdafx.h"
-
-void __cdecl CAimProto::aim_dc_helper(void* param) //only called when we are initiating a direct connection with someone else
-{
- file_transfer *ft = (file_transfer*)param;
-
- ProtoBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, ft, 0);
-
- NETLIBPACKETRECVER packetRecv = {};
- packetRecv.dwTimeout = 350000;
-
- HANDLE hServerPacketRecver = Netlib_CreatePacketReceiver(ft->hConn, 2048 * 4);
-
- int result;
- if (ft->sending)//we are sending
- result = sending_file(ft, hServerPacketRecver, packetRecv);
- else
- result = receiving_file(ft, hServerPacketRecver, packetRecv);
-
- Netlib_CloseHandle(hServerPacketRecver);
- Netlib_CloseHandle(ft->hConn);
- ft->hConn = nullptr;
-
- if (result == 0)
- ProtoBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0);
- else {
- if (!ft->requester && result == 1 && !Miranda_IsTerminated()) {
- ft->accepted = false;
- HNETLIBCONN hConn = aim_peer_connect(AIM_PROXY_SERVER, get_default_port());
- if (hConn) {
- debugLogA("Connected to proxy ip because we want to use a proxy for the file transfer.");
- ft->requester = true;
- ft->hConn = hConn;
- ForkThread(&CAimProto::aim_proxy_helper, ft);
- return;
- }
- }
- aim_file_ad(m_hServerConn, m_seqno, ft->sn, ft->icbm_cookie, true, 0);
- ProtoBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0);
- }
-
- m_ft_list.remove_by_ft(ft);
-}
-
-void aim_direct_connection_initiated(HNETLIBCONN hNewConnection, DWORD, void* extra)//for receiving stuff via dc
-{
- CAimProto *ppro = (CAimProto*)extra;
-
- NETLIBCONNINFO connInfo = {};
- Netlib_GetConnectionInfo(hNewConnection, &connInfo);
-
- ppro->debugLogA("Buddy connected: %s", connInfo.szIpPort);
-
- // okay someone connected to us or we initiated the connection- we need to figure out who they are and if they belong
- file_transfer *ft = ppro->m_ft_list.find_by_port(connInfo.wPort);
- if (ft) {
- ft->hConn = hNewConnection;
- ppro->aim_dc_helper(ft);
- }
- else Netlib_CloseHandle(hNewConnection);
-}
diff --git a/protocols/AimOscar/src/direct_connect.h b/protocols/AimOscar/src/direct_connect.h deleted file mode 100644 index 4bdcab6a4d..0000000000 --- a/protocols/AimOscar/src/direct_connect.h +++ /dev/null @@ -1,24 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2012 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 DIRECT_CONNECT_H
-#define DIRECT_CONNECT_H
-
-void aim_direct_connection_initiated(HNETLIBCONN hNewConnection, DWORD dwRemoteIP, void* extra);
-
-#endif
diff --git a/protocols/AimOscar/src/error.cpp b/protocols/AimOscar/src/error.cpp deleted file mode 100644 index e0988f5170..0000000000 --- a/protocols/AimOscar/src/error.cpp +++ /dev/null @@ -1,287 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2009 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 "stdafx.h"
-
-void CAimProto::login_error(unsigned short error)
-{
- switch (error) {
- case 0x0004:
- ShowPopup(LPGEN("Invalid screen name or password."), ERROR_POPUP);
- break;
-
- case 0x0005:
- ShowPopup(LPGEN("Mismatched screen name or password."), ERROR_POPUP);
- break;
-
- case 0x0018:
- ShowPopup(LPGEN("You are connecting too frequently. Try waiting 10 minutes to reconnect."), ERROR_POPUP);
- break;
-
- default:
- ShowPopup(LPGEN("Unknown error occurred when attempting to connect."), ERROR_POPUP);
- break;
- }
-}
-
-void CAimProto::get_error(unsigned short error)
-{
- switch (error) {
- case 0x01:
- ShowPopup(LPGEN("Invalid SNAC header."), ERROR_POPUP);
- break;
-
- case 0x02:
- ShowPopup(LPGEN("Server rate limit exceeded."), ERROR_POPUP);
- break;
-
- case 0x03:
- ShowPopup(LPGEN("Client rate limit exceeded"), ERROR_POPUP);
- break;
-
- case 0x04:
- ShowPopup(LPGEN("Recipient is not logged in."), ERROR_POPUP);
- break;
-
- case 0x05:
- ShowPopup(LPGEN("Requested service is unavailable."), ERROR_POPUP);
- break;
-
- case 0x06:
- ShowPopup(LPGEN("Requested service is not defined."), ERROR_POPUP);
- break;
-
- case 0x07:
- ShowPopup(LPGEN("You sent obsolete SNAC."), ERROR_POPUP);
- break;
-
- case 0x08:
- ShowPopup(LPGEN("Not supported by server."), ERROR_POPUP);
- break;
-
- case 0x09:
- ShowPopup(LPGEN("Not supported by the client."), ERROR_POPUP);
- break;
-
- case 0x0a:
- ShowPopup(LPGEN("Refused by client."), ERROR_POPUP);
- break;
-
- case 0x0b:
- ShowPopup(LPGEN("Reply too big."), ERROR_POPUP);
- break;
-
- case 0x0c:
- ShowPopup(LPGEN("Response lost."), ERROR_POPUP);
- break;
-
- case 0x0d:
- ShowPopup(LPGEN("Request denied."), ERROR_POPUP);
- break;
-
- case 0x0e:
- ShowPopup(LPGEN("Incorrect SNAC format."), ERROR_POPUP);
- break;
-
- case 0x0f:
- ShowPopup(LPGEN("Insufficient rights."), ERROR_POPUP);
- break;
-
- case 0x10:
- ShowPopup(LPGEN("Recipient blocked."), ERROR_POPUP);
- break;
-
- case 0x11:
- ShowPopup(LPGEN("Sender too evil."), ERROR_POPUP);
- break;
-
- case 0x12:
- ShowPopup(LPGEN("Receiver too evil."), ERROR_POPUP);
- break;
-
- case 0x13:
- ShowPopup(LPGEN("User temporarily unavailable."), ERROR_POPUP);
- break;
-
- case 0x14:
- ShowPopup(LPGEN("No match."), ERROR_POPUP);
- break;
-
- case 0x15:
- ShowPopup(LPGEN("List overflow."), ERROR_POPUP);
- break;
-
- case 0x16:
- ShowPopup(LPGEN("Request ambiguous."), ERROR_POPUP);
- break;
-
- case 0x17:
- ShowPopup(LPGEN("Server queue full."), ERROR_POPUP);
- break;
-
- case 0x18:
- ShowPopup(LPGEN("Not while on AOL."), ERROR_POPUP);
- break;
- }
-}
-
-void CAimProto::admin_error(unsigned short error)
-{
- switch (error) {
- case 0x01:
- ShowPopup(LPGEN("Check your screen name."), ERROR_POPUP);
- break;
-
- case 0x02:
- ShowPopup(LPGEN("Check your password."), ERROR_POPUP);
- break;
-
- case 0x03:
- ShowPopup(LPGEN("Check your email address."), ERROR_POPUP);
- break;
-
- case 0x04:
- ShowPopup(LPGEN("Service temporarily unavailable."), ERROR_POPUP);
- break;
-
- case 0x05:
- ShowPopup(LPGEN("Field change temporarily unavailable."), ERROR_POPUP);
- break;
-
- case 0x06:
- ShowPopup(LPGEN("Invalid screen name."), ERROR_POPUP);
- break;
-
- case 0x07:
- ShowPopup(LPGEN("Invalid password."), ERROR_POPUP);
- break;
-
- case 0x08:
- ShowPopup(LPGEN("Invalid email."), ERROR_POPUP);
- break;
-
- case 0x09:
- ShowPopup(LPGEN("Invalid registration preference."), ERROR_POPUP);
- break;
-
- case 0x0a:
- ShowPopup(LPGEN("Invalid old password."), ERROR_POPUP);
- break;
-
- case 0x0b:
- ShowPopup(LPGEN("Invalid screen name Length."), ERROR_POPUP);
- break;
-
- case 0x0c:
- ShowPopup(LPGEN("Invalid password length."), ERROR_POPUP);
- break;
-
- case 0x0d:
- ShowPopup(LPGEN("Invalid email length."), ERROR_POPUP);
- break;
-
- case 0x0e:
- ShowPopup(LPGEN("Invalid old password length."), ERROR_POPUP);
- break;
-
- case 0x0f:
- ShowPopup(LPGEN("Need old password."), ERROR_POPUP);
- break;
-
- case 0x10:
- ShowPopup(LPGEN("Read only field."), ERROR_POPUP);
- break;
-
- case 0x11:
- ShowPopup(LPGEN("Write only field."), ERROR_POPUP);
- break;
-
- case 0x12:
- ShowPopup(LPGEN("Unsupported type."), ERROR_POPUP);
- break;
-
- case 0x13:
- ShowPopup(LPGEN("An error has occurred."), ERROR_POPUP);
- break;
-
- case 0x14:
- ShowPopup(LPGEN("Incorrect SNAC format."), ERROR_POPUP);
- break;
-
- case 0x15:
- ShowPopup(LPGEN("Invalid account."), ERROR_POPUP);
- break;
-
- case 0x16:
- ShowPopup(LPGEN("Deleted account."), ERROR_POPUP);
- break;
-
- case 0x17:
- ShowPopup(LPGEN("Expired account."), ERROR_POPUP);
- break;
-
- case 0x18:
- ShowPopup(LPGEN("No database access."), ERROR_POPUP);
- break;
-
- case 0x19:
- ShowPopup(LPGEN("Invalid database fields."), ERROR_POPUP);
- break;
-
- case 0x1a:
- ShowPopup(LPGEN("Bad database status."), ERROR_POPUP);
- break;
-
- case 0x1b:
- ShowPopup(LPGEN("Migration cancel."), ERROR_POPUP);
- break;
-
- case 0x1c:
- ShowPopup(LPGEN("Internal error."), ERROR_POPUP);
- break;
-
- case 0x1d:
- ShowPopup(LPGEN("There is already a pending request for this screen name."), ERROR_POPUP);
- break;
-
- case 0x1e:
- ShowPopup(LPGEN("Not DT status."), ERROR_POPUP);
- break;
-
- case 0x1f:
- ShowPopup(LPGEN("Outstanding confirmation."), ERROR_POPUP);
- break;
-
- case 0x20:
- ShowPopup(LPGEN("No email address."), ERROR_POPUP);
- break;
-
- case 0x21:
- ShowPopup(LPGEN("Over limit."), ERROR_POPUP);
- break;
-
- case 0x22:
- ShowPopup(LPGEN("Email host fail."), ERROR_POPUP);
- break;
-
- case 0x23:
- ShowPopup(LPGEN("DNS fail."), ERROR_POPUP);
- break;
- }
-}
diff --git a/protocols/AimOscar/src/file.cpp b/protocols/AimOscar/src/file.cpp deleted file mode 100644 index 2f8e93f907..0000000000 --- a/protocols/AimOscar/src/file.cpp +++ /dev/null @@ -1,546 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2012 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 "stdafx.h"
-
-#pragma pack(push, 1)
-
-// oscar file transfer 2 class- See On_Sending_Files_via_OSCAR.pdf
-struct oft2
-{
- char protocol_version[4];//4
- unsigned short length;//6
- unsigned short type;//8
- unsigned char icbm_cookie[8];//16
- unsigned short encryption;//18
- unsigned short compression;//20
- unsigned short total_files;//22
- unsigned short num_files_left;//24
- unsigned short total_parts;//26
- unsigned short parts_left;//28
- unsigned long total_size;//32
- unsigned long size;//36
- unsigned long mod_time;//40
- unsigned long checksum;//44
- unsigned long recv_RFchecksum;//48
- unsigned long RFsize;//52
- unsigned long creation_time;//56
- unsigned long RFchecksum;//60
- unsigned long recv_bytes;//64
- unsigned long recv_checksum;//68
- unsigned char idstring[32];//100
- unsigned char flags;//101
- unsigned char list_name_offset;//102
- unsigned char list_size_offset;//103
- unsigned char dummy[69];//172
- unsigned char mac_info[16];//188
- unsigned short encoding;//190
- unsigned short sub_encoding;//192
- unsigned char filename[64];//256
- };
-
-#pragma pack(pop)
-
-bool send_init_oft2(file_transfer *ft, char* file)
-{
- aimString astr(file);
-
- unsigned short len = max(0x100, 0xc0 + astr.getTermSize());
-
- oft2 *oft = (oft2*)alloca(len);
- memset(oft, 0, len);
-
- memcpy(oft->protocol_version, "OFT2", 4);
- oft->length = _htons(len);
- oft->type = 0x0101;
- oft->total_files = _htons(ft->pfts.totalFiles);
- oft->num_files_left = _htons(ft->pfts.totalFiles - ft->pfts.currentFileNumber);
- oft->total_parts = _htons(1);
- oft->parts_left = _htons(1);
- oft->total_size = _htonl(ft->pfts.totalBytes);
- oft->size = _htonl(ft->pfts.currentFileSize);
- oft->mod_time = _htonl(ft->pfts.currentFileTime);
- oft->checksum = _htonl(aim_oft_checksum_file(ft->pfts.tszCurrentFile));
- oft->recv_RFchecksum = 0x0000FFFF;
- oft->RFchecksum = 0x0000FFFF;
- oft->recv_checksum = 0x0000FFFF;
- memcpy(oft->idstring, "Cool FileXfer", 13);
- oft->flags = 0x20;
- oft->list_name_offset = 0x1c;
- oft->list_size_offset = 0x11;
- oft->encoding = _htons(astr.isUnicode() ? 2 : 0);
- memcpy(oft->filename, astr.getBuf(), astr.getTermSize());
-
- if (!ft->requester || ft->pfts.currentFileNumber)
- memcpy(oft->icbm_cookie, ft->icbm_cookie, 8);
-
- return Netlib_Send(ft->hConn, (char*)oft, len, 0) > 0;
-}
-
-void CAimProto::report_file_error(wchar_t *fname)
-{
- wchar_t errmsg[512];
- wchar_t* error = mir_a2u(_strerror(nullptr));
- mir_snwprintf(errmsg, TranslateT("Failed to open file: %s : %s"), fname, error);
- mir_free(error);
- ShowPopup((char*)errmsg, ERROR_POPUP | TCHAR_POPUP);
-}
-
-bool setup_next_file_send(file_transfer *ft)
-{
- wchar_t *file;
- struct _stati64 statbuf;
- for (;;) {
- file = ft->pfts.ptszFiles[ft->cf];
- if (file == nullptr) return false;
-
- if (_wstat64(file, &statbuf) == 0 && (statbuf.st_mode & _S_IFDIR) == 0)
- break;
-
- ++ft->cf;
- }
-
- ft->pfts.tszCurrentFile = file;
- ft->pfts.currentFileSize = statbuf.st_size;
- ft->pfts.currentFileTime = statbuf.st_mtime;
- ft->pfts.currentFileProgress = 0;
-
- char* fnamea;
- T2Utf fname(file);
- if (ft->pfts.totalFiles > 1 && ft->file[0]) {
- size_t dlen = mir_strlen(ft->file);
- if (strncmp(fname, ft->file, dlen) == 0 && fname.get()[dlen] == '\\') {
- fnamea = &fname.get()[dlen + 1];
- for (char *p = fnamea; *p; ++p)
- if (*p == '\\')
- *p = 1;
- }
- else fnamea = get_fname(fname);
- }
- else fnamea = get_fname(fname);
-
- send_init_oft2(ft, fnamea);
- return true;
-}
-
-int CAimProto::sending_file(file_transfer *ft, HANDLE hServerPacketRecver, NETLIBPACKETRECVER &packetRecv)
-{
- debugLogA("P2P: Entered file sending thread.");
-
- bool failed = true;
- bool failed_conn = false;
-
- if (!setup_next_file_send(ft)) return 2;
-
- debugLogA("Sent file information to buddy.");
- //start listen for packets stuff
-
- for (;;) {
- int recvResult = packetRecv.bytesAvailable - packetRecv.bytesUsed;
- if (recvResult <= 0)
- recvResult = Netlib_GetMorePackets(hServerPacketRecver, &packetRecv);
- if (recvResult == 0) {
- debugLogA("P2P: File transfer connection Error: 0");
- break;
- }
- if (recvResult == SOCKET_ERROR) {
- failed_conn = true;
- debugLogA("P2P: File transfer connection Error: -1");
- break;
- }
- if (recvResult > 0) {
- if (recvResult < 0x100) continue;
-
- oft2* recv_ft = (oft2*)&packetRecv.buffer[packetRecv.bytesUsed];
-
- unsigned short pkt_len = _htons(recv_ft->length);
- if (recvResult < pkt_len) continue;
-
- packetRecv.bytesUsed += pkt_len;
- unsigned short type = _htons(recv_ft->type);
- if (type == 0x0202 || type == 0x0207) {
- debugLogA("P2P: Buddy Accepts our file transfer.");
-
- int fid = _wopen(ft->pfts.tszCurrentFile, _O_RDONLY | _O_BINARY, _S_IREAD);
- if (fid < 0) {
- report_file_error(ft->pfts.tszCurrentFile);
- return 2;
- }
-
- if (ft->pfts.currentFileProgress) _lseeki64(fid, ft->pfts.currentFileProgress, SEEK_SET);
-
- NETLIBSELECT tSelect = { 0 };
- tSelect.hReadConns[0] = ft->hConn;
-
- ProtoBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->pfts);
-
- clock_t lNotify = clock();
- for (;;) {
- char buffer[4096];
- int bytes = _read(fid, buffer, sizeof(buffer));
- if (bytes <= 0) break;
-
- if (Netlib_Send(ft->hConn, buffer, bytes, MSG_NODUMP) <= 0) break;
- ft->pfts.currentFileProgress += bytes;
- ft->pfts.totalProgress += bytes;
-
- if (clock() >= lNotify) {
- ProtoBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->pfts);
- if (Netlib_Select(&tSelect))
- break;
-
- lNotify = clock() + 500;
- }
- }
- ProtoBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->pfts);
- debugLogA("P2P: Finished sending file bytes.");
- _close(fid);
- }
- else if (type == 0x0204) {
- // Handle file skip case
- if (ft->pfts.currentFileProgress == 0) {
- ft->pfts.totalProgress += ft->pfts.currentFileSize;
- }
-
- debugLogA("P2P: Buddy says they got the file successfully");
- if ((ft->pfts.currentFileNumber + 1) < ft->pfts.totalFiles) {
- ProtoBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0);
- ++ft->pfts.currentFileNumber; ++ft->cf;
-
- if (!setup_next_file_send(ft)) {
- report_file_error(ft->pfts.tszCurrentFile);
- return 2;
- }
- }
- else {
- failed = _htonl(recv_ft->recv_bytes) != ft->pfts.currentFileSize;
- break;
- }
- }
- else if (type == 0x0205) {
- recv_ft = (oft2*)packetRecv.buffer;
- recv_ft->type = _htons(0x0106);
-
- ft->pfts.currentFileProgress = _htonl(recv_ft->recv_bytes);
- if (aim_oft_checksum_file(ft->pfts.tszCurrentFile, ft->pfts.currentFileProgress) != _htonl(recv_ft->recv_checksum)) {
- ft->pfts.currentFileProgress = 0;
- recv_ft->recv_bytes = 0;
- }
-
- debugLogA("P2P: Buddy wants us to start sending at a specified file point. (%I64u)", ft->pfts.currentFileProgress);
- if (Netlib_Send(ft->hConn, (char*)recv_ft, _htons(recv_ft->length), 0) <= 0) break;
-
- ft->pfts.totalProgress += ft->pfts.currentFileProgress;
- ProtoBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->pfts);
- }
- }
- }
-
- ft->success = !failed;
- return failed ? (failed_conn ? 1 : 2) : 0;
-}
-
-int CAimProto::receiving_file(file_transfer *ft, HANDLE hServerPacketRecver, NETLIBPACKETRECVER &packetRecv)
-{
- debugLogA("P2P: Entered file receiving thread.");
- bool failed = true;
- bool failed_conn = false;
- bool accepted_file = false;
- int fid = -1;
-
- oft2 *oft = nullptr;
-
- ft->pfts.tszWorkingDir = mir_utf8decodeW(ft->file);
-
- //start listen for packets stuff
- for (;;) {
- int recvResult = packetRecv.bytesAvailable - packetRecv.bytesUsed;
- if (recvResult <= 0)
- recvResult = Netlib_GetMorePackets(hServerPacketRecver, &packetRecv);
- if (recvResult == 0) {
- debugLogA("P2P: File transfer connection Error: 0");
- break;
- }
- if (recvResult == SOCKET_ERROR) {
- failed_conn = true;
- debugLogA("P2P: File transfer connection Error: -1");
- break;
- }
- if (recvResult > 0) {
- if (!accepted_file) {
- if (recvResult < 0x100) continue;
-
- oft2* recv_ft = (oft2*)&packetRecv.buffer[packetRecv.bytesUsed];
- unsigned short pkt_len = _htons(recv_ft->length);
-
- if (recvResult < pkt_len) continue;
- packetRecv.bytesUsed += pkt_len;
-
- unsigned short type = _htons(recv_ft->type);
- if (type == 0x0101) {
- debugLogA("P2P: Buddy Ready to begin transfer.");
- oft = (oft2*)mir_realloc(oft, pkt_len);
- memcpy(oft, recv_ft, pkt_len);
- memcpy(oft->icbm_cookie, ft->icbm_cookie, 8);
-
- int buflen = pkt_len - 0x100 + 64;
- char *buf = (char*)mir_calloc(buflen + 2);
- unsigned short enc;
-
- ft->pfts.currentFileSize = _htonl(recv_ft->size);
- ft->pfts.totalBytes = _htonl(recv_ft->total_size);
- ft->pfts.currentFileTime = _htonl(recv_ft->mod_time);
- memcpy(buf, recv_ft->filename, buflen);
- enc = _htons(recv_ft->encoding);
-
- wchar_t *name;
- if (enc == 2) {
- wchar_t* wbuf = (wchar_t*)buf;
- wcs_htons(wbuf);
- for (wchar_t *p = wbuf; *p; ++p) { if (*p == 1) *p = '\\'; }
- name = mir_wstrdup(wbuf);
- }
- else {
- for (char *p = buf; *p; ++p) { if (*p == 1) *p = '\\'; }
- name = mir_a2u(buf);
- }
-
- mir_free(buf);
-
- wchar_t fname[256];
- mir_snwprintf(fname, L"%s%s", ft->pfts.tszWorkingDir, name);
- mir_free(name);
- mir_free(ft->pfts.tszCurrentFile);
- ft->pfts.tszCurrentFile = mir_wstrdup(fname);
-
- ResetEvent(ft->hResumeEvent);
- if (ProtoBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, ft, (LPARAM)&ft->pfts))
- WaitForSingleObject(ft->hResumeEvent, INFINITE);
-
- if (ft->pfts.tszCurrentFile) {
- wchar_t* dir = get_dir(ft->pfts.tszCurrentFile);
- CreateDirectoryTreeW(dir);
- mir_free(dir);
-
- oft->type = _htons(ft->pfts.currentFileProgress ? 0x0205 : 0x0202);
-
- const int flag = ft->pfts.currentFileProgress ? 0 : _O_TRUNC;
- fid = _wopen(ft->pfts.tszCurrentFile, _O_CREAT | _O_WRONLY | _O_BINARY | flag, _S_IREAD | _S_IWRITE);
-
- if (fid < 0) {
- report_file_error(fname);
- break;
- }
-
- accepted_file = ft->pfts.currentFileProgress == 0;
-
- if (ft->pfts.currentFileProgress) {
- bool the_same;
- oft->recv_bytes = _htonl(ft->pfts.currentFileProgress);
- oft->recv_checksum = _htonl(aim_oft_checksum_file(ft->pfts.tszCurrentFile));
- the_same = oft->size == oft->recv_bytes && oft->checksum == oft->recv_checksum;
- if (the_same) {
- ft->pfts.totalProgress += ft->pfts.currentFileProgress;
- oft->type = _htons(0x0204);
- _close(fid);
-
- ProtoBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0);
- ++ft->pfts.currentFileNumber;
- ft->pfts.currentFileProgress = 0;
- }
- }
- }
- else {
- oft->type = _htons(0x0204);
-
- ProtoBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0);
- ++ft->pfts.currentFileNumber;
- ft->pfts.currentFileProgress = 0;
- }
-
- if (Netlib_Send(ft->hConn, (char*)oft, pkt_len, 0) == SOCKET_ERROR)
- break;
-
- if (ft->pfts.currentFileNumber >= ft->pfts.totalFiles && _htons(oft->type) == 0x0204) {
- failed = false;
- break;
- }
- }
- else if (type == 0x0106) {
- oft = (oft2*)mir_realloc(oft, pkt_len);
- memcpy(oft, recv_ft, pkt_len);
-
- ft->pfts.currentFileProgress = _htonl(oft->recv_bytes);
- ft->pfts.totalProgress += ft->pfts.currentFileProgress;
-
- _lseeki64(fid, ft->pfts.currentFileProgress, SEEK_SET);
- accepted_file = true;
-
- oft->type = _htons(0x0207);
- if (Netlib_Send(ft->hConn, (char*)oft, pkt_len, 0) == SOCKET_ERROR)
- break;
- }
- else break;
- }
- else {
- packetRecv.bytesUsed = packetRecv.bytesAvailable;
- _write(fid, packetRecv.buffer, packetRecv.bytesAvailable);
- ft->pfts.currentFileProgress += packetRecv.bytesAvailable;
- ft->pfts.totalProgress += packetRecv.bytesAvailable;
- ProtoBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->pfts);
- if (ft->pfts.currentFileSize == ft->pfts.currentFileProgress) {
- oft->type = _htons(0x0204);
- oft->recv_bytes = _htonl(ft->pfts.currentFileProgress);
- oft->recv_checksum = _htonl(aim_oft_checksum_file(ft->pfts.tszCurrentFile));
-
- debugLogA("P2P: We got the file successfully");
- Netlib_Send(ft->hConn, (char*)oft, _htons(oft->length), 0);
- if (_htons(oft->num_files_left) == 1) {
- failed = false;
- break;
- }
- else {
- accepted_file = false;
- _close(fid);
-
- ProtoBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0);
- ++ft->pfts.currentFileNumber;
- ft->pfts.currentFileProgress = 0;
- }
- }
- }
- }
- }
-
- if (accepted_file) _close(fid);
- mir_free(oft);
-
- ft->success = !failed;
- return failed ? (failed_conn ? 1 : 2) : 0;
-}
-
-void CAimProto::shutdown_file_transfers(void)
-{
- for (int i = 0; i < m_ft_list.getCount(); ++i) {
- file_transfer& ft = m_ft_list[i];
- if (ft.hConn)
- Netlib_Shutdown(ft.hConn);
- }
-}
-
-ft_list_type::ft_list_type() : OBJLIST <file_transfer>(10) {};
-
-file_transfer* ft_list_type::find_by_cookie(char* cookie, MCONTACT hContact)
-{
- for (int i = 0; i < getCount(); ++i) {
- file_transfer *ft = items[i];
- if (ft->hContact == hContact && memcmp(ft->icbm_cookie, cookie, 8) == 0)
- return ft;
- }
- return nullptr;
-}
-
-file_transfer* ft_list_type::find_by_port(unsigned short port)
-{
- for (int i = getCount(); i--; ) {
- file_transfer *ft = items[i];
- if (ft->requester && ft->local_port == port)
- return ft;
- }
- return nullptr;
-}
-
-
-bool ft_list_type::find_by_ft(file_transfer *ft)
-{
- for (int i = 0; i < getCount(); ++i)
- if (items[i] == ft)
- return true;
-
- return false;
-}
-
-void ft_list_type::remove_by_ft(file_transfer *ft)
-{
- for (int i = 0; i < getCount(); ++i) {
- if (items[i] == ft) {
- remove(i);
- break;
- }
- }
-}
-
-file_transfer::file_transfer(MCONTACT hCont, char* nick, char* cookie)
-{
- memset(this, 0, sizeof(*this));
-
- pfts.cbSize = sizeof(pfts);
- pfts.flags = PFTS_UNICODE;
- pfts.hContact = hCont;
-
- hContact = hCont;
- sn = mir_strdup(nick);
-
- if (cookie)
- memcpy(icbm_cookie, cookie, 8);
- else
- Utils_GetRandom(icbm_cookie, 8);
-
- hResumeEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
-}
-
-file_transfer::~file_transfer()
-{
- stop_listen();
-
- mir_free(file);
- mir_free(message);
- mir_free(sn);
-
- mir_free(pfts.tszWorkingDir);
- if (!sending) mir_free(pfts.tszCurrentFile);
-
- if (success && pfts.ptszFiles) {
- for (int i = 0; pfts.ptszFiles[i]; i++)
- mir_free(pfts.ptszFiles[i]);
-
- mir_free(pfts.ptszFiles);
- }
- CloseHandle(hResumeEvent);
-}
-
-void file_transfer::listen(CAimProto* ppro)
-{
- if (hDirectBoundPort) return;
-
- NETLIBBIND nlb = {};
- nlb.pfnNewConnectionV2 = aim_direct_connection_initiated;
- nlb.pExtra = ppro;
- hDirectBoundPort = Netlib_BindPort(ppro->m_hNetlibPeer, &nlb);
- local_port = hDirectBoundPort ? nlb.wPort : 0;
-}
-
-void file_transfer::stop_listen(void)
-{
- if (hDirectBoundPort) {
- Netlib_CloseHandle(hDirectBoundPort);
- hDirectBoundPort = nullptr;
- local_port = 0;
- }
-}
diff --git a/protocols/AimOscar/src/file.h b/protocols/AimOscar/src/file.h deleted file mode 100644 index faf6714284..0000000000 --- a/protocols/AimOscar/src/file.h +++ /dev/null @@ -1,81 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2012 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 FILE_H
-#define FILE_H
-
-struct CAimProto;
-
-struct file_transfer
-{
- MCONTACT hContact;
- char* sn;
-
- char icbm_cookie[8];
-
- HNETLIBCONN hConn;
- HANDLE hResumeEvent;
- HNETLIBBIND hDirectBoundPort;
-
- char* file;
- char* message;
-
- PROTOFILETRANSFERSTATUS pfts;
-
- unsigned long cf;
-
- //below is for when receiving only
- unsigned long local_ip;
- unsigned long verified_ip;
- unsigned long proxy_ip;
- unsigned short port;
- unsigned short max_ver;
-
- unsigned short req_num;
- unsigned short local_port;
-
- bool peer_force_proxy;
- bool me_force_proxy;
- bool sending;
- bool accepted;
- bool requester;
- bool success;
-
- file_transfer(MCONTACT hCont, char* nick, char* cookie);
- ~file_transfer();
-
- void listen(CAimProto* ppro);
- void stop_listen(void);
-
-};
-
-struct ft_list_type : OBJLIST <file_transfer>
-{
- ft_list_type();
-
- file_transfer* find_by_handle(MCONTACT hContact);
- file_transfer* find_by_cookie(char* cookie, MCONTACT hContact);
- file_transfer* find_by_port(unsigned short port);
-
- bool find_by_ft(file_transfer *ft);
-
- void remove_by_ft(file_transfer *ft);
-};
-
-
-#endif
diff --git a/protocols/AimOscar/src/flap.cpp b/protocols/AimOscar/src/flap.cpp deleted file mode 100644 index 960034d8a0..0000000000 --- a/protocols/AimOscar/src/flap.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2009 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 "stdafx.h"
-
-FLAP::FLAP(char* buf, int num_bytes)
-{
- if (FLAP_SIZE > num_bytes)
- length_ = 0;
- else {
- length_ = _htons((*(unsigned short*)&buf[4]));
- if (FLAP_SIZE + length_ > num_bytes)
- length_ = 0;
- else {
- type_ = buf[1];
- value_ = &buf[FLAP_SIZE];
- }
- }
-}
-unsigned short FLAP::len()
-{
- return length_;
-}
-
-unsigned short FLAP::snaclen()
-{
- return length_ - 10;
-}
-
-int FLAP::cmp(unsigned short type)
-{
- return (type_ == type);
-}
-
-char* FLAP::val()
-{
- return value_;
-}
diff --git a/protocols/AimOscar/src/flap.h b/protocols/AimOscar/src/flap.h deleted file mode 100644 index 190d668537..0000000000 --- a/protocols/AimOscar/src/flap.h +++ /dev/null @@ -1,37 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 FLAP_H
-#define FLAP_H
-
-#define FLAP_SIZE 6
-
-class FLAP
-{
-private:
- unsigned char type_;
- unsigned short length_;
- char* value_;
-public:
- FLAP(char* buf,int num_bytes);
- unsigned short len();
- unsigned short snaclen();
- int cmp(unsigned short type);
- char* val();
-};
-
-#endif
diff --git a/protocols/AimOscar/src/links.cpp b/protocols/AimOscar/src/links.cpp deleted file mode 100644 index b9235bde99..0000000000 --- a/protocols/AimOscar/src/links.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2010 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 "stdafx.h"
-
-extern OBJLIST<CAimProto> g_Instances;
-
-static int SingleHexToDecimal(wchar_t 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 wchar_t* url_decode(wchar_t* str)
-{
- wchar_t* 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++ = (wchar_t)((digit1 << 4) | digit2);
- continue;
- }
- }
- }
- *d++ = *s++;
- }
-
- *d = 0;
- return str;
-}
-
-static INT_PTR ServiceParseAimLink(WPARAM, LPARAM lParam)
-{
- if (lParam == 0) return 1; /* sanity check */
-
- wchar_t *arg = (wchar_t*)lParam;
-
- /* skip leading prefix */
- arg = wcschr(arg, ':');
- if (arg == nullptr) return 1; /* parse failed */
-
- for (++arg; *arg == '/'; ++arg);
-
- arg = NEWWSTR_ALLOCA(arg);
-
- if (g_Instances.getCount() == 0) return 0;
-
- CAimProto *proto = &g_Instances[0];
- for (int i = 0; i < g_Instances.getCount(); ++i) {
- if (g_Instances[i].m_iStatus != ID_STATUS_OFFLINE && !IsStatusConnecting(g_Instances[i].m_iStatus)) {
- proto = &g_Instances[i];
- break;
- }
- }
- if (proto == nullptr) return 1;
-
- /*
- add user: aim:addbuddy?screenname=NICK&groupname=GROUP
- send message: aim:goim?screenname=NICK&message=MSG
- open chatroom: aim:gochat?roomname=ROOM&exchange=NUM
- */
- /* add a contact to the list */
- if (!wcsnicmp(arg, L"addbuddy?", 9)) {
- wchar_t *tok, *tok2;
- char *sn = nullptr, *group = nullptr;
-
- for (tok = arg + 8; tok != nullptr; tok = tok2) {
- tok2 = wcschr(++tok, '&'); /* first token */
- if (tok2) *tok2 = 0;
- if (!wcsnicmp(tok, L"screenname=", 11) && *(tok + 11) != 0)
- sn = mir_u2a(url_decode(tok + 11));
- if (!wcsnicmp(tok, L"groupname=", 10) && *(tok + 10) != 0)
- group = mir_utf8encodeW(url_decode(tok + 10)); /* group is currently ignored */
- }
- if (sn == nullptr) {
- mir_free(group);
- return 1;
- }
-
- if (!proto->contact_from_sn(sn)) /* does not yet check if sn is current user */
- {
- MCONTACT hContact = proto->contact_from_sn(sn, true);
- proto->add_contact_to_group(hContact, group && group[0] ? group : AIM_DEFAULT_GROUP);
- }
- mir_free(group);
- mir_free(sn);
- return 0;
- }
- /* send a message to a contact */
- else if (!wcsnicmp(arg, L"goim?", 5)) {
- wchar_t *tok, *tok2, *msg = nullptr;
- char *sn = nullptr;
-
- for (tok = arg + 4; tok != nullptr; tok = tok2) {
- tok2 = wcschr(++tok, '&'); /* first token */
- if (tok2) *tok2 = 0;
- if (!wcsnicmp(tok, L"screenname=", 11) && *(tok + 11) != 0)
- sn = mir_u2a(url_decode(tok + 11));
- if (!wcsnicmp(tok, L"message=", 8) && *(tok + 8) != 0)
- msg = url_decode(tok + 8);
- }
- if (sn == nullptr) return 1; /* parse failed */
-
- MCONTACT hContact = proto->contact_from_sn(sn, true, true);
- if (hContact)
- CallService(MS_MSG_SENDMESSAGEW, hContact, (LPARAM)msg);
-
- mir_free(sn);
- return 0;
- }
-
- /* open a chatroom */
- else if (!wcsnicmp(arg, L"gochat?", 7)) {
- wchar_t *tok, *tok2;
- char *rm = nullptr;
- int exchange = 0;
-
- for (tok = arg + 6; tok != nullptr; tok = tok2) {
- tok2 = wcschr(++tok, '&'); /* first token */
- if (tok2) *tok2 = 0;
- if (!wcsnicmp(tok, L"roomname=", 9) && *(tok + 9) != 0) {
- rm = mir_u2a(url_decode(tok + 9));
- for (char *ch = rm; *ch; ++ch)
- if (*ch == '+') *ch = ' ';
- }
- if (!wcsnicmp(tok, L"exchange=", 9))
- exchange = _wtoi(tok + 9);
- }
- if (rm == nullptr || exchange <= 0) {
- mir_free(rm);
- return 1;
- }
-
- chatnav_param* par = new chatnav_param(rm, (unsigned short)exchange);
- proto->ForkThread(&CAimProto::chatnav_request_thread, par);
-
- mir_free(rm);
- return 0;
- }
- return 1; /* parse failed */
-}
-
-void aim_links_init(void)
-{
- static const char szService[] = "AIM/ParseAimLink";
-
- CreateServiceFunction(szService, ServiceParseAimLink);
- AssocMgr_AddNewUrlTypeT("aim:", TranslateT("AIM link protocol"), hInstance, IDI_AOL, szService, 0);
-}
diff --git a/protocols/AimOscar/src/links.h b/protocols/AimOscar/src/links.h deleted file mode 100644 index 5eb95a9eab..0000000000 --- a/protocols/AimOscar/src/links.h +++ /dev/null @@ -1,23 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-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/>.
-*/
-#ifndef LINKS_H
-#define LINKS_H
-
-void aim_links_init();
-
-#endif
diff --git a/protocols/AimOscar/src/packets.cpp b/protocols/AimOscar/src/packets.cpp deleted file mode 100644 index dc77c6a41e..0000000000 --- a/protocols/AimOscar/src/packets.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2009 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 "stdafx.h"
-
-int aim_writesnac(unsigned short service, unsigned short subgroup,unsigned short &offset, char* out, unsigned short id)
-{
- snac_header *snac = (snac_header*)&out[offset];
- snac->service=_htons(service);
- snac->subgroup=_htons(subgroup);
- snac->flags=0;
- snac->request_id[0]=_htons(id);
- snac->request_id[1]=_htons(subgroup);
- offset+=sizeof(snac_header);
- return 0;
-}
-
-int aim_writetlv(unsigned short type,unsigned short length, const char* value,unsigned short &offset,char* out)
-{
- TLV tlv(type,length,value);
- offset += tlv.whole(&out[offset]);
- return 0;
-}
-
-int aim_writetlvchar(unsigned short type, unsigned char value, unsigned short &offset, char* out)
-{
- return aim_writetlv(type, sizeof(value), (char*)&value, offset, out);
-}
-
-
-int aim_writetlvshort(unsigned short type, unsigned short value, unsigned short &offset, char* out)
-{
- value = _htons(value);
- return aim_writetlv(type, sizeof(value), (char*)&value, offset, out);
-}
-
-
-int aim_writetlvlong(unsigned short type, unsigned long value, unsigned short &offset, char* out)
-{
- value = _htonl(value);
- return aim_writetlv(type, sizeof(value), (char*)&value, offset, out);
-}
-
-int aim_writetlvlong64(unsigned short type, unsigned __int64 value, unsigned short &offset, char* out)
-{
- value = _htonl64(value);
- return aim_writetlv(type, sizeof(value), (char*)&value, offset, out);
-}
-
-
-int CAimProto::aim_sendflap(HNETLIBCONN hServerConn, char type, unsigned short length, const char *buf, unsigned short &seqno)
-{
- mir_cslock lck(SendingMutex);
- const int slen = FLAP_SIZE + length;
- char* obuf = (char*)alloca(slen);
- flap_header *flap = (flap_header*)obuf;
- flap->ast = '*';
- flap->type = type;
- flap->seqno = _htons(seqno++);
- flap->len = _htons(length);
- memcpy(&obuf[FLAP_SIZE], buf, length);
- int rlen= Netlib_Send(hServerConn, obuf, slen, 0);
- if (rlen == SOCKET_ERROR) seqno--;
- return rlen >= 0 ? 0 : -1;
-}
-
-void aim_writefamily(const char *buf,unsigned short &offset,char* out)
-{
- memcpy(&out[offset],buf,4);
- offset+=4;
-}
-
-void aim_writechar(unsigned char val, unsigned short &offset,char* out)
-{
- out[offset++] = val;
-}
-
-void aim_writeshort(unsigned short val, unsigned short &offset,char* out)
-{
- out[offset++] = (char)(val >> 8);
- out[offset++] = (char)(val & 0xFF);
-}
-
-void aim_writelong(unsigned long val, unsigned short &offset,char* out)
-{
- out[offset++] = (char)(val >> 24);
- out[offset++] = (char)((val >> 16) & 0xFF);
- out[offset++] = (char)((val >> 8) & 0xFF);
- out[offset++] = (char)(val & 0xFF);
-}
-
-void aim_writegeneric(unsigned short size,const char *buf,unsigned short &offset,char* out)
-{
- memcpy(&out[offset],buf,size);
- offset+=size;
-}
-
-void aim_writebartid(unsigned short type, unsigned char flags, unsigned short size,const char *buf,unsigned short &offset,char* out)
-{
- out[offset++]=(unsigned char)(type >> 8);
- out[offset++]=(unsigned char)(type & 0xff);
- out[offset++]=flags;
- out[offset++]=(char)size;
- memcpy(&out[offset],buf,size);
- offset+=size;
-}
diff --git a/protocols/AimOscar/src/packets.h b/protocols/AimOscar/src/packets.h deleted file mode 100644 index e7c4de6cf0..0000000000 --- a/protocols/AimOscar/src/packets.h +++ /dev/null @@ -1,66 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2010 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 PACKETS_H
-#define PACKETS_H
-
-struct flap_header
-{
- unsigned char ast;
- unsigned char type;
- unsigned short seqno;
- unsigned short len;
-};
-struct snac_header
-{
- unsigned short service;
- unsigned short subgroup;
- unsigned short flags;
- unsigned short request_id[2];
-};
-
-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);
-}
-
-
-int aim_writesnac(unsigned short service, unsigned short subgroup,unsigned short &offset,char* out, unsigned short id=0);
-int aim_writetlv(unsigned short type,unsigned short size, const char* value,unsigned short &offset,char* out);
-int aim_writetlvchar(unsigned short type, unsigned char value, unsigned short &offset, char* out);
-int aim_writetlvshort(unsigned short type, unsigned short value, unsigned short &offset, char* out);
-int aim_writetlvlong(unsigned short type, unsigned long value, unsigned short &offset, char* out);
-int aim_writetlvlong64(unsigned short type, unsigned __int64 value, unsigned short &offset, char* out);
-void aim_writefamily(const char *buf,unsigned short &offset,char* out);
-void aim_writegeneric(unsigned short size,const char *buf,unsigned short &offset,char* out);
-void aim_writebartid(unsigned short type, unsigned char flags, unsigned short size,const char *buf,unsigned short &offset,char* out);
-void aim_writechar(unsigned char val, unsigned short &offset,char* out);
-void aim_writeshort(unsigned short val, unsigned short &offset,char* out);
-void aim_writelong(unsigned long val, unsigned short &offset,char* out);
-
-#endif
diff --git a/protocols/AimOscar/src/popup.cpp b/protocols/AimOscar/src/popup.cpp deleted file mode 100644 index c6ad5624fd..0000000000 --- a/protocols/AimOscar/src/popup.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2009 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 "stdafx.h"
-
-struct CAimPopupData
-{
- CAimPopupData(CAimProto* _ppro, char* _url) :
- ppro(_ppro),
- url(mir_strdup(_url))
- {}
-
- ~CAimPopupData()
- { mir_free(url); }
-
- CAimProto* ppro;
- char* url;
-};
-
-LRESULT CALLBACK PopupWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
- switch(message)
- {
- case WM_COMMAND:
- if (HIWORD(wParam) == STN_CLICKED)
- {
- CAimPopupData* p = (CAimPopupData*)PUGetPluginData(hWnd);
- if (p->url != nullptr)
- ShellExecuteA(nullptr, "open", p->url, nullptr, nullptr, SW_SHOW);
-
- PUDeletePopup(hWnd);
- return 0;
- }
- break;
-
- case WM_CONTEXTMENU:
- PUDeletePopup(hWnd);
- break;
-
- case UM_FREEPLUGINDATA:
- CAimPopupData* p = (CAimPopupData*)PUGetPluginData(hWnd);
- ReleaseIconEx("aim");
- delete p;
- break;
- }
- return DefWindowProc(hWnd, message, wParam, lParam);
-}
-
-void CAimProto::ShowPopup(const char* msg, int flags, char* url)
-{
- POPUPDATAT ppd = {0};
-
- mir_snwprintf(ppd.lptzContactName, TranslateT("%s protocol"), m_tszUserName);
-
- if (flags & ERROR_POPUP)
- {
- if (flags & TCHAR_POPUP)
- {
- char* errmsg = mir_u2a((wchar_t*)msg);
- debugLogA(errmsg);
- mir_free(errmsg);
- }
- else
- debugLogA(msg);
- }
-
- wchar_t *msgt = (flags & TCHAR_POPUP) ? mir_wstrdup((wchar_t*)msg) : mir_a2u(msg);
- wcsncpy_s(ppd.lptzText, TranslateW(msgt), _TRUNCATE);
- mir_free(msgt);
-
- if (!ServiceExists(MS_POPUP_ADDPOPUPT))
- {
- if (flags & MAIL_POPUP)
- {
- size_t len = mir_wstrlen(ppd.lptzText);
- mir_snwprintf(&ppd.lptzText[len], _countof(ppd.lptzText) - len, L" %s", TranslateT("Open mail account?"));
- if (MessageBox(nullptr, ppd.lptzText, ppd.lptzContactName, MB_YESNO | MB_ICONINFORMATION) == IDYES)
- ShellExecuteA(nullptr, "open", url, nullptr, nullptr, SW_SHOW);
- }
- else
- {
- MessageBox(nullptr, ppd.lptzText, ppd.lptzContactName, MB_OK | MB_ICONINFORMATION);
- }
- }
- else
- {
- ppd.PluginWindowProc = PopupWindowProc;
- ppd.lchIcon = LoadIconEx("aim");
- if (flags & MAIL_POPUP)
- {
- ppd.PluginData = new CAimPopupData(this, url);
- ppd.iSeconds = -1;
- }
- else
- ppd.PluginData = new CAimPopupData(this, nullptr);
-
- CallService(MS_POPUP_ADDPOPUPT, (WPARAM)&ppd, 0);
- }
-}
diff --git a/protocols/AimOscar/src/proto.cpp b/protocols/AimOscar/src/proto.cpp deleted file mode 100644 index 5857be9f50..0000000000 --- a/protocols/AimOscar/src/proto.cpp +++ /dev/null @@ -1,685 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-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 "stdafx.h"
-
-CAimProto::CAimProto(const char* aProtoName, const wchar_t* aUserName) :
- PROTO<CAimProto>(aProtoName, aUserName),
- m_chat_rooms(5)
-{
- debugLogA("Setting protocol/module name to '%s'", m_szModuleName);
-
- //create some events
- m_hAvatarEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
- m_hChatNavEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
- m_hAdminEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
-
- CreateProtoService(PS_CREATEACCMGRUI, &CAimProto::SvcCreateAccMgrUI);
-
- CreateProtoService(PS_GETMYAWAYMSG, &CAimProto::GetMyAwayMsg);
-
- CreateProtoService(PS_GETAVATARINFO, &CAimProto::GetAvatarInfo);
- CreateProtoService(PS_GETMYAVATAR, &CAimProto::GetAvatar);
- CreateProtoService(PS_SETMYAVATAR, &CAimProto::SetAvatar);
- CreateProtoService(PS_GETAVATARCAPS, &CAimProto::GetAvatarCaps);
-
- CreateProtoService(PS_JOINCHAT, &CAimProto::OnJoinChat);
- CreateProtoService(PS_LEAVECHAT, &CAimProto::OnLeaveChat);
-
- HookProtoEvent(ME_CLIST_PREBUILDCONTACTMENU, &CAimProto::OnPreBuildContactMenu);
- HookProtoEvent(ME_CLIST_GROUPCHANGE, &CAimProto::OnGroupChange);
- HookProtoEvent(ME_OPT_INITIALISE, &CAimProto::OnOptionsInit);
-
- offline_contacts();
-
- wchar_t descr[MAX_PATH];
-
- NETLIBUSER nlu = {};
- nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS | NUF_UNICODE;
- nlu.szSettingsModule = m_szModuleName;
- mir_snwprintf(descr, TranslateT("%s server connection"), m_tszUserName);
- nlu.szDescriptiveName.w = descr;
- m_hNetlibUser = Netlib_RegisterUser(&nlu);
-
- char szP2P[128];
- mir_snprintf(szP2P, "%sP2P", m_szModuleName);
- nlu.flags = NUF_OUTGOING | NUF_INCOMING | NUF_UNICODE;
- mir_snwprintf(descr, TranslateT("%s client-to-client connections"), m_tszUserName);
- nlu.szSettingsModule = szP2P;
- nlu.minIncomingPorts = 1;
- m_hNetlibPeer = Netlib_RegisterUser(&nlu);
-}
-
-CAimProto::~CAimProto()
-{
- if (m_hServerConn)
- Netlib_CloseHandle(m_hServerConn);
- if (m_hAvatarConn && m_hAvatarConn != (HANDLE)1)
- Netlib_CloseHandle(m_hAvatarConn);
- if (m_hChatNavConn && m_hChatNavConn != (HANDLE)1)
- Netlib_CloseHandle(m_hChatNavConn);
- if (m_hAdminConn && m_hAdminConn != (HANDLE)1)
- Netlib_CloseHandle(m_hAdminConn);
-
- close_chat_conn();
-
- Netlib_CloseHandle(m_hNetlibUser);
- Netlib_CloseHandle(m_hNetlibPeer);
-
- CloseHandle(m_hAvatarEvent);
- CloseHandle(m_hChatNavEvent);
- CloseHandle(m_hAdminEvent);
-
- for (int i = 0; i < 9; ++i)
- mir_free(m_modeMsgs[i]);
-
- mir_free(m_pref2_flags);
- mir_free(m_pref2_set_flags);
-
- mir_free(COOKIE);
- mir_free(MAIL_COOKIE);
- mir_free(AVATAR_COOKIE);
- mir_free(CHATNAV_COOKIE);
- mir_free(ADMIN_COOKIE);
- mir_free(m_username);
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// OnModulesLoadedEx - performs hook registration
-
-int CAimProto::OnModulesLoaded(WPARAM, LPARAM)
-{
- HookProtoEvent(ME_IDLE_CHANGED, &CAimProto::OnIdleChanged);
- HookProtoEvent(ME_MSG_WINDOWEVENT, &CAimProto::OnWindowEvent);
- HookProtoEvent(ME_USERINFO_INITIALISE, &CAimProto::OnUserInfoInit);
-
- chat_register();
- InitContactMenus();
-
- return 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// AddToList - adds a contact to the contact list
-
-MCONTACT CAimProto::AddToList(int flags, PROTOSEARCHRESULT* psr)
-{
- if (m_state != 1)
- return 0;
-
- wchar_t *id = psr->id.w ? psr->id.w : psr->nick.w;
- char *sn = psr->flags & PSR_UNICODE ? mir_u2a((wchar_t*)id) : mir_strdup((char*)id);
- MCONTACT hContact = contact_from_sn(sn, true, (flags & PALF_TEMPORARY) != 0);
- mir_free(sn);
- return hContact; //See authrequest for serverside addition
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// PSS_AUTHREQUEST
-
-int __cdecl CAimProto::AuthRequest(MCONTACT hContact, const wchar_t*)
-{
- //Not a real authrequest- only used b/c we don't know the group until now.
- if (m_state != 1)
- return 1;
-
- DBVARIANT dbv;
- if (!db_get_utf(hContact, MOD_KEY_CL, OTH_KEY_GP, &dbv) && dbv.pszVal[0]) {
- add_contact_to_group(hContact, dbv.pszVal);
- db_free(&dbv);
- }
- else add_contact_to_group(hContact, AIM_DEFAULT_GROUP);
-
- return 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// FileAllow - starts a file transfer
-
-HANDLE __cdecl CAimProto::FileAllow(MCONTACT, HANDLE hTransfer, const wchar_t *szPath)
-{
- file_transfer *ft = (file_transfer*)hTransfer;
- if (ft && m_ft_list.find_by_ft(ft)) {
- char *path = mir_utf8encodeW(szPath);
-
- if (ft->pfts.totalFiles > 1 && ft->file[0]) {
- size_t path_len = mir_strlen(path);
- size_t len = mir_strlen(ft->file) + 2;
-
- path = (char*)mir_realloc(path, path_len + len);
- mir_snprintf(&path[path_len], len, "%s\\", ft->file);
- }
-
- mir_free(ft->file);
- ft->file = path;
-
- ForkThread(&CAimProto::accept_file_thread, ft);
- return ft;
- }
- return nullptr;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// FileCancel - cancels a file transfer
-
-int __cdecl CAimProto::FileCancel(MCONTACT, HANDLE hTransfer)
-{
- file_transfer *ft = (file_transfer*)hTransfer;
- if (!m_ft_list.find_by_ft(ft))
- return 0;
-
- debugLogA("We are cancelling a file transfer.");
-
- aim_chat_deny(m_hServerConn, m_seqno, ft->sn, ft->icbm_cookie);
-
- if (ft->hConn) {
- Netlib_Shutdown(ft->hConn);
- SetEvent(ft->hResumeEvent);
- }
- else m_ft_list.remove_by_ft(ft);
-
- return 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// FileDeny - denies a file transfer
-
-int __cdecl CAimProto::FileDeny(MCONTACT, HANDLE hTransfer, const wchar_t* /*szReason*/)
-{
- file_transfer *ft = (file_transfer*)hTransfer;
- if (!m_ft_list.find_by_ft(ft))
- return 0;
-
- debugLogA("We are denying a file transfer.");
-
- aim_chat_deny(m_hServerConn, m_seqno, ft->sn, ft->icbm_cookie);
- return 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// FileResume - processes file renaming etc
-
-int __cdecl CAimProto::FileResume(HANDLE hTransfer, int* action, const wchar_t** szFilename)
-{
- file_transfer *ft = (file_transfer*)hTransfer;
- if (!m_ft_list.find_by_ft(ft))
- return 0;
-
- switch (*action) {
- case FILERESUME_RESUME:
- {
- struct _stati64 statbuf;
- _wstat64(ft->pfts.tszCurrentFile, &statbuf);
- ft->pfts.currentFileProgress = statbuf.st_size;
- }
- break;
-
- case FILERESUME_RENAME:
- mir_free(ft->pfts.tszCurrentFile);
- ft->pfts.tszCurrentFile = mir_wstrdup(*szFilename);
- break;
-
- case FILERESUME_OVERWRITE:
- ft->pfts.currentFileProgress = 0;
- break;
-
- case FILERESUME_SKIP:
- mir_free(ft->pfts.tszCurrentFile);
- ft->pfts.tszCurrentFile = nullptr;
- break;
-
- default:
- aim_file_ad(m_hServerConn, m_seqno, ft->sn, ft->icbm_cookie, true, ft->max_ver);
- break;
- }
- SetEvent(ft->hResumeEvent);
-
- return 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// GetCaps - return protocol capabilities bits
-
-DWORD_PTR __cdecl CAimProto::GetCaps(int type, MCONTACT)
-{
- switch (type) {
- case PFLAGNUM_1:
- return PF1_IM | PF1_MODEMSG | PF1_BASICSEARCH | PF1_SEARCHBYEMAIL | PF1_FILE;
-
- case PFLAGNUM_2:
- #ifdef ALLOW_BUSY
- return PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_ONTHEPHONE | PF2_LIGHTDND;
- #else
- return PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_ONTHEPHONE;
- #endif
-
- case PFLAGNUM_3:
- #ifdef ALLOW_BUSY
- return PF2_ONLINE | PF2_SHORTAWAY | PF2_INVISIBLE | PF2_LIGHTDND;
- #else
- return PF2_ONLINE | PF2_SHORTAWAY | PF2_INVISIBLE;
- #endif
-
- case PFLAGNUM_4:
- return PF4_SUPPORTTYPING | PF4_FORCEAUTH | PF4_NOCUSTOMAUTH | PF4_FORCEADDED |
- PF4_SUPPORTIDLE | PF4_AVATARS | PF4_IMSENDOFFLINE;
-
- case PFLAGNUM_5:
- return PF2_ONTHEPHONE;
-
- case PFLAG_MAXLENOFMESSAGE:
- return MAX_MESSAGE_LENGTH;
-
- case PFLAG_UNIQUEIDTEXT:
- return (DWORD_PTR) "Screen Name";
-
- case PFLAG_UNIQUEIDSETTING:
- return (DWORD_PTR)AIM_KEY_SN;
- }
- return 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// SearchBasic - searches the contact by JID
-
-void __cdecl CAimProto::basic_search_ack_success(void *p)
-{
- char *sn = normalize_name((char*)p);
- if (sn) { // normalize it
- if (mir_strlen(sn) > 32)
- ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)1, 0);
- else {
- PROTOSEARCHRESULT psr = { 0 };
- psr.cbSize = sizeof(psr);
- psr.id.w = (wchar_t*)sn;
- ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)1, (LPARAM)& psr);
- ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)1, 0);
- }
- }
- mir_free(sn);
- mir_free(p);
-}
-
-HANDLE __cdecl CAimProto::SearchBasic(const wchar_t *szId)
-{
- if (m_state != 1)
- return nullptr;
-
- //duplicating the parameter so that it isn't deleted before it's needed- e.g. this function ends before it's used
- ForkThread(&CAimProto::basic_search_ack_success, mir_u2a(szId));
- return (HANDLE)1;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// SearchByEmail - searches the contact by its e-mail
-
-HANDLE __cdecl CAimProto::SearchByEmail(const wchar_t *email)
-{
- // Maximum email size should really be 320, but the char string is limited to 255.
- if (m_state != 1 || email == nullptr || mir_wstrlen(email) >= 254)
- return nullptr;
-
- char *szEmail = mir_u2a(email);
- aim_search_by_email(m_hServerConn, m_seqno, szEmail);
- mir_free(szEmail);
- return (HANDLE)1;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// RecvMsg
-
-int __cdecl CAimProto::RecvMsg(MCONTACT hContact, PROTORECVEVENT *pre)
-{
- char *omsg = pre->szMessage;
- char *bbuf = nullptr;
- if (getByte(AIM_KEY_FI, 1)) {
- debugLogA("Converting from html to bbcodes then stripping leftover html.");
- pre->szMessage = bbuf = html_to_bbcodes(pre->szMessage);
- }
- debugLogA("Stripping html.");
- html_decode(pre->szMessage);
-
- INT_PTR res = Proto_RecvMessage(hContact, pre);
- mir_free(bbuf);
- pre->szMessage = omsg;
- return (int)res;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// SendFile - sends a file
-
-HANDLE __cdecl CAimProto::SendFile(MCONTACT hContact, const wchar_t* szDescription, wchar_t** ppszFiles)
-{
- if (m_state != 1)
- return nullptr;
-
- if (hContact && szDescription && ppszFiles) {
- DBVARIANT dbv;
- if (!getString(hContact, AIM_KEY_SN, &dbv)) {
- file_transfer *ft = new file_transfer(hContact, dbv.pszVal, nullptr);
-
- bool isDir = false;
- int count = 0;
- while (ppszFiles[count] != nullptr) {
- struct _stati64 statbuf;
- if (_wstat64(ppszFiles[count++], &statbuf) == 0) {
- if (statbuf.st_mode & _S_IFDIR) {
- if (ft->pfts.totalFiles == 0) isDir = true;
- }
- else {
- ft->pfts.totalBytes += statbuf.st_size;
- ++ft->pfts.totalFiles;
- }
- }
- }
-
- if (ft->pfts.totalFiles == 0) {
- delete ft;
- return nullptr;
- }
-
- ft->pfts.flags |= PFTS_SENDING;
- ft->pfts.ptszFiles = ppszFiles;
-
- ft->file = ft->pfts.totalFiles == 1 || isDir ? mir_utf8encodeW(ppszFiles[0]) : (char*)mir_calloc(1);
- ft->sending = true;
- ft->message = szDescription[0] ? mir_utf8encodeW(szDescription) : nullptr;
- ft->me_force_proxy = getByte(AIM_KEY_FP, 0) != 0;
- ft->requester = true;
-
- m_ft_list.insert(ft);
-
- if (ft->me_force_proxy) {
- debugLogA("We are forcing a proxy file transfer.");
- ForkThread(&CAimProto::accept_file_thread, ft);
- }
- else {
- ft->listen(this);
- aim_send_file(m_hServerConn, m_seqno, m_detected_ip, ft->local_port, false, ft);
- }
-
- db_free(&dbv);
- return ft;
- }
- }
-
- return nullptr;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// SendMessage - sends a message
-
-void __cdecl CAimProto::msg_ack_success(void* param)
-{
- msg_ack_param *msg_ack = (msg_ack_param*)param;
-
- Sleep(150);
- ProtoBroadcastAck(msg_ack->hContact, ACKTYPE_MESSAGE,
- msg_ack->success ? ACKRESULT_SUCCESS : ACKRESULT_FAILED,
- (HANDLE)msg_ack->id, (LPARAM)msg_ack->msg);
-
- mir_free(msg_ack);
-}
-
-
-int __cdecl CAimProto::SendMsg(MCONTACT hContact, int, const char* pszSrc)
-{
- if (pszSrc == nullptr)
- return 0;
-
- if (m_state != 1) {
- msg_ack_param *msg_ack = (msg_ack_param*)mir_calloc(sizeof(msg_ack_param));
- msg_ack->hContact = hContact;
- msg_ack->msg = "Message cannot be sent, when protocol offline";
- ForkThread(&CAimProto::msg_ack_success, msg_ack);
- }
-
- char *sn = getStringA(hContact, AIM_KEY_SN);
- if (sn == nullptr) {
- msg_ack_param *msg_ack = (msg_ack_param*)mir_calloc(sizeof(msg_ack_param));
- msg_ack->hContact = hContact;
- msg_ack->msg = "Screen Name for the contact not available";
- ForkThread(&CAimProto::msg_ack_success, msg_ack);
- }
-
- char *smsg = html_encode(pszSrc), *msg;
- if (getByte(AIM_KEY_FO, 1)) {
- msg = bbcodes_to_html(smsg);
- mir_free(smsg);
- }
- else msg = smsg;
-
- bool blast = getBool(hContact, AIM_KEY_BLS, false);
- int res = aim_send_message(m_hServerConn, m_seqno, sn, msg, false, blast);
-
- mir_free(msg);
- mir_free(sn);
-
- if (!res || blast || 0 == getByte(AIM_KEY_DC, 1)) {
- msg_ack_param *msg_ack = (msg_ack_param*)mir_alloc(sizeof(msg_ack_param));
- msg_ack->hContact = hContact;
- msg_ack->msg = nullptr;
- msg_ack->id = res;
- msg_ack->success = res != 0;
- ForkThread(&CAimProto::msg_ack_success, msg_ack);
- }
-
- return res;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// SetStatus - sets the protocol m_iStatus
-
-int __cdecl CAimProto::SetStatus(int iNewStatus)
-{
- switch (iNewStatus) {
- case ID_STATUS_FREECHAT:
- iNewStatus = ID_STATUS_ONLINE;
- break;
-
- case ID_STATUS_DND:
- case ID_STATUS_OCCUPIED:
- case ID_STATUS_ONTHEPHONE:
- #ifdef ALLOW_BUSY
- iNewStatus = ID_STATUS_OCCUPIED;
- break;
- #endif
-
- case ID_STATUS_OUTTOLUNCH:
- case ID_STATUS_NA:
- iNewStatus = ID_STATUS_AWAY;
- break;
- }
-
- if (iNewStatus == m_iStatus)
- return 0;
-
- if (iNewStatus == ID_STATUS_OFFLINE) {
- broadcast_status(ID_STATUS_OFFLINE);
- return 0;
- }
-
- m_iDesiredStatus = iNewStatus;
- if (m_iStatus == ID_STATUS_OFFLINE) {
- broadcast_status(ID_STATUS_CONNECTING);
- ForkThread(&CAimProto::start_connection, (void*)iNewStatus);
- }
- else if (m_iStatus > ID_STATUS_OFFLINE) {
- switch (iNewStatus) {
- case ID_STATUS_ONLINE:
- aim_set_status(m_hServerConn, m_seqno, AIM_STATUS_ONLINE);
- broadcast_status(ID_STATUS_ONLINE);
- break;
-
- case ID_STATUS_INVISIBLE:
- aim_set_status(m_hServerConn, m_seqno, AIM_STATUS_INVISIBLE);
- broadcast_status(ID_STATUS_INVISIBLE);
- break;
-
- case ID_STATUS_OCCUPIED:
- aim_set_status(m_hServerConn, m_seqno, AIM_STATUS_BUSY | AIM_STATUS_AWAY);
- broadcast_status(ID_STATUS_OCCUPIED);
- break;
-
- case ID_STATUS_AWAY:
- aim_set_status(m_hServerConn, m_seqno, AIM_STATUS_AWAY);
- broadcast_status(ID_STATUS_AWAY);
- break;
- }
- }
-
- return 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// GetAwayMsg - returns a contact's away message
-
-void __cdecl CAimProto::get_online_msg_thread(void* arg)
-{
- Sleep(150);
-
- MCONTACT hContact = (UINT_PTR)arg;
- DBVARIANT dbv;
- if (!db_get_ws(hContact, MOD_KEY_CL, OTH_KEY_SM, &dbv)) {
- ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)dbv.ptszVal);
- db_free(&dbv);
- }
- else ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, 0);
-}
-
-HANDLE __cdecl CAimProto::GetAwayMsg(MCONTACT hContact)
-{
- if (m_state != 1)
- return nullptr;
-
- int status = getWord(hContact, AIM_KEY_ST, ID_STATUS_OFFLINE);
- switch (status) {
- case ID_STATUS_AWAY:
- case ID_STATUS_ONLINE:
- ForkThread(&CAimProto::get_online_msg_thread, (void*)hContact);
- break;
-
- default:
- return nullptr;
- }
-
- return (HANDLE)1;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// PSR_AWAYMSG
-
-int __cdecl CAimProto::RecvAwayMsg(MCONTACT hContact, int, PROTORECVEVENT* pre)
-{
- ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)pre->szMessage);
- return 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// SetAwayMsg - sets the away m_iStatus message
-
-int __cdecl CAimProto::SetAwayMsg(int status, const wchar_t* msg)
-{
- char **msgptr = get_status_msg_loc(status);
- if (msgptr == nullptr) return 1;
-
- char *nmsg = mir_utf8encodeW(msg);
- mir_free(*msgptr); *msgptr = nmsg;
-
- switch (status) {
- case ID_STATUS_FREECHAT:
- status = ID_STATUS_ONLINE;
- break;
-
- case ID_STATUS_DND:
- case ID_STATUS_OCCUPIED:
- case ID_STATUS_ONTHEPHONE:
- #ifdef ALLOW_BUSY
- status = ID_STATUS_OCCUPIED;
- break;
- #endif
-
- case ID_STATUS_OUTTOLUNCH:
- case ID_STATUS_NA:
- status = ID_STATUS_AWAY;
- break;
- }
-
- if (m_state == 1 && status == m_iStatus) {
- if (!mir_strcmp(m_last_status_msg, nmsg))
- return 0;
-
- replaceStr(m_last_status_msg, nmsg);
- aim_set_statusmsg(m_hServerConn, m_seqno, nmsg);
- aim_set_away(m_hServerConn, m_seqno, nmsg,
- status == ID_STATUS_AWAY || status == ID_STATUS_OCCUPIED);
- }
- return 0;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// UserIsTyping - sends a UTN notification
-
-int __cdecl CAimProto::UserIsTyping(MCONTACT hContact, int type)
-{
- if (m_state != 1)
- return 0;
-
- if (getWord(hContact, AIM_KEY_ST, ID_STATUS_OFFLINE) == ID_STATUS_ONTHEPHONE)
- return 0;
-
- DBVARIANT dbv;
- if (!getBool(hContact, AIM_KEY_BLS, false) && !getString(hContact, AIM_KEY_SN, &dbv)) {
- if (type == PROTOTYPE_SELFTYPING_ON)
- aim_typing_notification(m_hServerConn, m_seqno, dbv.pszVal, 0x0002);
- else if (type == PROTOTYPE_SELFTYPING_OFF)
- aim_typing_notification(m_hServerConn, m_seqno, dbv.pszVal, 0x0000);
- db_free(&dbv);
- }
- return 0;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// OnEvent - maintain protocol events
-
-int __cdecl CAimProto::OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam)
-{
- switch (eventType) {
- case EV_PROTO_ONLOAD:
- return OnModulesLoaded(0, 0);
-
- case EV_PROTO_ONMENU:
- InitMainMenus();
- break;
-
- case EV_PROTO_ONOPTIONS:
- return OnOptionsInit(wParam, lParam);
-
- case EV_PROTO_ONERASE:
- char szDbsettings[64];
- mir_snprintf(szDbsettings, "%sP2P", m_szModuleName);
- db_delete_module(0, szDbsettings);
- break;
-
- case EV_PROTO_ONCONTACTDELETED:
- return OnContactDeleted(wParam, lParam);
-
- case EV_PROTO_DBSETTINGSCHANGED:
- return OnDbSettingChanged(wParam, lParam);
- }
- return 1;
-}
diff --git a/protocols/AimOscar/src/proto.h b/protocols/AimOscar/src/proto.h deleted file mode 100755 index da05270f3d..0000000000 --- a/protocols/AimOscar/src/proto.h +++ /dev/null @@ -1,432 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-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/>.
-*/
-
-#ifndef _AIM_PROTO_H_
-#define _AIM_PROTO_H_
-
-struct CAimProto : public PROTO<CAimProto>
-{
- CAimProto(const char*, const wchar_t*);
- ~CAimProto();
-
- //====================================================================================
- // PROTO_INTERFACE
- //====================================================================================
-
- virtual MCONTACT __cdecl AddToList( int flags, PROTOSEARCHRESULT* psr );
-
- virtual int __cdecl AuthRequest(MCONTACT hContact, const wchar_t* szMessage );
-
- virtual HANDLE __cdecl FileAllow(MCONTACT hContact, HANDLE hTransfer, const wchar_t* szPath );
- virtual int __cdecl FileCancel(MCONTACT hContact, HANDLE hTransfer );
- virtual int __cdecl FileDeny(MCONTACT hContact, HANDLE hTransfer, const wchar_t* szReason );
- virtual int __cdecl FileResume( HANDLE hTransfer, int* action, const wchar_t** szFilename );
-
- virtual DWORD_PTR __cdecl GetCaps( int type, MCONTACT hContact = NULL );
-
- virtual HANDLE __cdecl SearchBasic( const wchar_t* id );
- virtual HANDLE __cdecl SearchByEmail( const wchar_t* email );
-
- virtual int __cdecl RecvMsg(MCONTACT hContact, PROTORECVEVENT* );
-
- virtual HANDLE __cdecl SendFile(MCONTACT hContact, const wchar_t* szDescription, wchar_t** ppszFiles);
- virtual int __cdecl SendMsg(MCONTACT hContact, int flags, const char* msg );
-
- 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 wchar_t* 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 ManageAccount(WPARAM wParam, LPARAM lParam);
- INT_PTR __cdecl InstantIdle(WPARAM wParam, LPARAM lParam);
- INT_PTR __cdecl JoinChatUI(WPARAM wParam, LPARAM lParam);
- INT_PTR __cdecl GetHTMLAwayMsg(WPARAM wParam, LPARAM lParam);
- INT_PTR __cdecl GetProfile(WPARAM wParam, LPARAM lParam);
- INT_PTR __cdecl EditProfile(WPARAM wParam, LPARAM lParam);
- INT_PTR __cdecl AddToServerList(WPARAM wParam, LPARAM lParam);
- INT_PTR __cdecl BlockBuddy(WPARAM wParam, LPARAM lParam);
-
- INT_PTR __cdecl OnJoinChat(WPARAM wParam, LPARAM lParam);
- INT_PTR __cdecl OnLeaveChat(WPARAM wParam, LPARAM lParam);
-
- //====| Events |======================================================================
- int __cdecl OnContactDeleted(WPARAM wParam,LPARAM lParam);
- int __cdecl OnGroupChange(WPARAM wParam,LPARAM lParam);
- int __cdecl OnIdleChanged(WPARAM wParam, LPARAM lParam);
- int __cdecl OnWindowEvent(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 OnDbSettingChanged(WPARAM wParam,LPARAM lParam);
- int __cdecl OnUserInfoInit(WPARAM wParam,LPARAM lParam);
- int __cdecl OnGCEvent(WPARAM wParam,LPARAM lParam);
- int __cdecl OnGCMenuHook(WPARAM wParam,LPARAM lParam);
-
- //====| Data |========================================================================
- mir_cs SendingMutex;
- mir_cs connMutex;
-
- char* COOKIE;
- int COOKIE_LENGTH;
- char* MAIL_COOKIE;
- int MAIL_COOKIE_LENGTH;
- char* AVATAR_COOKIE;
- int AVATAR_COOKIE_LENGTH;
- char* CHATNAV_COOKIE;
- int CHATNAV_COOKIE_LENGTH;
- char* ADMIN_COOKIE;
- int ADMIN_COOKIE_LENGTH;
-
- char *m_username;
- unsigned short m_seqno;//main connection sequence number
- int m_state;//m_iStatus of the connection; e.g. whether connected or not
- unsigned short m_port;
-
- //Some bools to keep track of different things
- bool m_request_HTML_profile;
- bool m_request_away_message;
- bool m_extra_icons_loaded;
- bool m_idle;
- bool m_instantidle;
- bool m_list_received;
-
- //Some main connection stuff
- HNETLIBCONN m_hServerConn; // handle to the main connection
-
- unsigned long m_internal_ip; // our ip
- unsigned long m_detected_ip; // our ip
- unsigned short m_local_port; // our port
-
- //Peer connection stuff
- HNETLIBUSER m_hNetlibPeer;//handle to the peer netlib
- HANDLE m_hDirectBoundPort;//direct connection listening port
-
- //Handles for the context menu items
- HGENMENU m_hHTMLAwayContextMenuItem;
- HGENMENU m_hAddToServerListContextMenuItem;
- HGENMENU m_hBlockContextMenuItem;
- HGENMENU m_hMainMenu[3];
-
- //Some mail connection stuff
- HNETLIBCONN m_hMailConn;
- unsigned short m_mail_seqno;
-
- //avatar connection stuff
- unsigned short m_avatar_seqno;
- unsigned short m_avatar_id_sm;
- unsigned short m_avatar_id_lg;
- HNETLIBCONN m_hAvatarConn;
- HANDLE m_hAvatarEvent;
-
- ft_list_type m_ft_list;
-
- //chatnav connection stuff
- unsigned short m_chatnav_seqno;
- HNETLIBCONN m_hChatNavConn;
- HANDLE m_hChatNavEvent;
- char MAX_ROOMS;
-
- OBJLIST<chat_list_item> m_chat_rooms;
-
- //admin connection stuff
- unsigned short m_admin_seqno;
- HNETLIBCONN m_hAdminConn;
- HANDLE m_hAdminEvent;
-
- // privacy settings
- unsigned long m_pd_flags;
- unsigned short m_pd_info_id;
- char m_pd_mode;
-
- // prefernces
- unsigned short m_pref1_id;
- unsigned long m_pref1_flags;
- unsigned long m_pref1_set_flags;
- unsigned long m_pref2_len;
- unsigned long m_pref2_set_len;
- char *m_pref2_flags;
- char *m_pref2_set_flags;
-
- BdList m_allow_list;
- BdList m_block_list;
- BdList m_group_list;
-
- //away message retrieval stuff
- char *m_modeMsgs[9];
- char *m_last_status_msg;
-
- //////////////////////////////////////////////////////////////////////////////////////
- // avatars.cpp
-
- char *m_hash_sm, *m_hash_lg;
-
- void __cdecl avatar_request_thread( void* param );
- void __cdecl avatar_upload_thread( void* param );
-
- void avatar_request_handler(MCONTACT hContact, char* hash, unsigned char type);
- void avatar_retrieval_handler(const char* sn, const char* hash, const char* data, int data_len);
- int get_avatar_filename(MCONTACT hContact, wchar_t* pszDest, size_t cbLen, const wchar_t *ext);
-
- //////////////////////////////////////////////////////////////////////////////////////
- // away.cpp
-
- void __cdecl get_online_msg_thread( void* arg );
-
- int aim_set_away(HNETLIBCONN hServerConn, unsigned short &seqno, const char *msg, bool set);//user info
- int aim_set_statusmsg(HNETLIBCONN hServerConn,unsigned short &seqno,const char *msg);//user info
- int aim_set_status(HNETLIBCONN hServerConn,unsigned short &seqno,unsigned long status_type);
- int aim_query_away_message(HNETLIBCONN hServerConn,unsigned short &seqno,const char* sn);
-
- char** get_status_msg_loc(int status);
-
- //////////////////////////////////////////////////////////////////////////////////////
- // chat.cpp
-
- void __cdecl chatnav_request_thread( void* param );
-
- void chat_register(void);
- void chat_start(const char* id, unsigned short exchange);
- void chat_event(const char* id, const char* sn, int evt, const wchar_t* msg = NULL);
- void chat_leave(const char* id);
-
- chat_list_item* find_chat_by_cid(unsigned short cid);
- chat_list_item* find_chat_by_id(char* id);
- chat_list_item* find_chat_by_conn(HANDLE conn);
- void remove_chat_by_ptr(chat_list_item* item);
- void shutdown_chat_conn(void);
- void close_chat_conn(void);
-
- //////////////////////////////////////////////////////////////////////////////////////
- // client.cpp
-
- int aim_send_connection_packet(HNETLIBCONN hServerConn, unsigned short &seqno, char *buf);
- int aim_authkey_request(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_auth_request(HNETLIBCONN hServerConn, unsigned short &seqno, const char* key, const char* language, const char* country, const char* username, const char* password);
- int aim_send_cookie(HNETLIBCONN hServerConn, unsigned short &seqno, int cookie_size, char * cookie);
- int aim_send_service_request(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_new_service_request(HNETLIBCONN hServerConn, unsigned short &seqno, unsigned short service);
- int aim_request_rates(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_request_icbm(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_request_offline_msgs(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_set_icbm(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_set_profile(HNETLIBCONN hServerConn, unsigned short &seqno, char* amsg);//user info
- int aim_request_list(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_activate_list(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_accept_rates(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_set_caps(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_client_ready(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_mail_ready(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_avatar_ready(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_chatnav_ready(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_chat_ready(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_send_message(HNETLIBCONN hServerConn, unsigned short &seqno, const char* sn, char* amsg, bool auto_response, bool blast);
- int aim_query_profile(HNETLIBCONN hServerConn, unsigned short &seqno, char* sn);
- int aim_delete_contact(HNETLIBCONN hServerConn, unsigned short &seqno, char* sn, unsigned short item_id, unsigned short group_id, unsigned short list, bool nil);
- int aim_add_contact(HNETLIBCONN hServerConn, unsigned short &seqno, const char* sn, unsigned short item_id, unsigned short group_id, unsigned short list, char* nick = NULL, char* note = NULL);
- int aim_mod_group(HNETLIBCONN hServerConn, unsigned short &seqno, const char* name, unsigned short group_id, char* members, unsigned short members_length);
- int aim_mod_buddy(HNETLIBCONN hServerConn, unsigned short &seqno, const char* sn, unsigned short buddy_id, unsigned short group_id, char* nick, char* note);
- int aim_ssi_update(HNETLIBCONN hServerConn, unsigned short &seqno, bool start);
- int aim_ssi_update_preferences(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_keepalive(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_send_file(HNETLIBCONN hServerConn, unsigned short &seqno, unsigned long ip, unsigned short port, bool force_proxy, file_transfer *ft);//used when requesting a regular file transfer
- int aim_file_ad(HNETLIBCONN hServerConn, unsigned short &seqno, char* sn, char* icbm_cookie, bool deny, unsigned short max_ver);
- int aim_typing_notification(HNETLIBCONN hServerConn, unsigned short &seqno, char* sn, unsigned short type);
- int aim_set_idle(HNETLIBCONN hServerConn, unsigned short &seqno, unsigned long seconds);
- int aim_request_mail(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_activate_mail(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_request_avatar(HNETLIBCONN hServerConn, unsigned short &seqno, const char* sn, unsigned short bart_type, const char* hash, unsigned short hash_size);//family 0x0010
- int aim_set_avatar_hash(HNETLIBCONN hServerConn, unsigned short &seqno, char flags, unsigned short bart_type, unsigned short &id, char size, const char* hash);
- int aim_delete_avatar_hash(HNETLIBCONN hServerConn, unsigned short &seqno, char flags, unsigned short bart_type, unsigned short &id);
- int aim_upload_avatar(HNETLIBCONN hServerConn, unsigned short &seqno, unsigned short bart_type, const char* avatar, unsigned short avatar_size);
- int aim_search_by_email(HNETLIBCONN hServerConn, unsigned short &seqno, const char* email);
- int aim_set_pd_info(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_block_buddy(HNETLIBCONN hServerConn, unsigned short &seqno, bool remove, const char* sn, unsigned short item_id);
- int aim_chatnav_request_limits(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_chatnav_create(HNETLIBCONN hServerConn, unsigned short &seqno, char* room, unsigned short exchage);
- int aim_chatnav_room_info(HNETLIBCONN hServerConn, unsigned short &seqno, char* chat_cookie, unsigned short exchange, unsigned short instance);
- int aim_chat_join_room(HNETLIBCONN hServerConn, unsigned short &seqno, char* chat_cookie, unsigned short exchange, unsigned short instance, unsigned short id);
- int aim_chat_send_message(HNETLIBCONN hServerConn, unsigned short &seqno, char *amsg);
- int aim_chat_invite(HNETLIBCONN hServerConn, unsigned short &seqno, char* chat_cookie, unsigned short exchange, unsigned short instance, char* sn, char* msg);
- int aim_chat_deny(HNETLIBCONN hServerConn, unsigned short &seqno, char* sn, char* icbm_cookie);
- int aim_admin_ready(HNETLIBCONN hServerConn, unsigned short &seqno);
- int aim_admin_format_name(HNETLIBCONN hServerConn, unsigned short &seqno, const char* sn);
- int aim_admin_change_password(HNETLIBCONN hServerConn, unsigned short &seqno, const char* cur_pw, const char* new_pw);
- int aim_admin_change_email(HNETLIBCONN hServerConn, unsigned short &seqno, const char* email);
- int aim_admin_request_info(HNETLIBCONN hServerConn, unsigned short &seqno, const unsigned short &type);
- int aim_admin_account_confirm(HNETLIBCONN hServerConn, unsigned short &seqno);
-
- //////////////////////////////////////////////////////////////////////////////////////
- // connection.cpp
-
- void aim_connection_authorization(void);
- void aim_connection_clientlogin(void);
-
- void __cdecl aim_protocol_negotiation(void*);
- void __cdecl aim_mail_negotiation(void*);
- void __cdecl aim_avatar_negotiation(void*);
- void __cdecl aim_chatnav_negotiation(void*);
- void __cdecl aim_chat_negotiation(void*);
- void __cdecl aim_admin_negotiation(void*);
-
- HNETLIBCONN aim_connect(const char* server, unsigned short port, bool use_ssl, const char* host = NULL);
- HNETLIBCONN aim_peer_connect(const char* ip, unsigned short port);
- HNETLIBCONN aim_peer_connect(unsigned long ip, unsigned short port);
-
- //////////////////////////////////////////////////////////////////////////////////////
- // direct_connect.cpp
-
- void __cdecl aim_dc_helper( void* );
-
- //////////////////////////////////////////////////////////////////////////////////////
- // error.cpp
-
- void login_error(unsigned short error);
- void get_error(unsigned short error);
- void admin_error(unsigned short error);
-
- //////////////////////////////////////////////////////////////////////////////////////
- // file.cpp
-
- int sending_file(file_transfer *ft, HANDLE hServerPacketRecver, NETLIBPACKETRECVER &packetRecv);
- int receiving_file(file_transfer *ft, HANDLE hServerPacketRecver, NETLIBPACKETRECVER &packetRecv);
- void report_file_error(wchar_t* fname);
- void shutdown_file_transfers(void);
-
- //////////////////////////////////////////////////////////////////////////////////////
- // packets.cpp
-
- int aim_sendflap(HNETLIBCONN conn, char type, unsigned short length, const char *buf, unsigned short &seqno);
-
- //////////////////////////////////////////////////////////////////////////////////////
- // proto.cpp
-
- void __cdecl basic_search_ack_success( void* p );
- void __cdecl email_search_ack_success( void* p );
-
- //////////////////////////////////////////////////////////////////////////////////////
- // proxy.cpp
-
- void __cdecl aim_proxy_helper( void* );
-
- //////////////////////////////////////////////////////////////////////////////////////
- // server.cpp
-
- void snac_md5_authkey(SNAC &snac,HNETLIBCONN hServerConn,unsigned short &seqno, const char* username, const char* password);
- int snac_authorization_reply(SNAC &snac);
- void snac_supported_families(SNAC &snac, HNETLIBCONN hServerConn,unsigned short &seqno);
- void snac_supported_family_versions(SNAC &snac,HNETLIBCONN hServerConn,unsigned short &seqno);//family 0x0001
- void snac_rate_limitations(SNAC &snac,HNETLIBCONN hServerConn,unsigned short &seqno);//family 0x0001
- void snac_mail_rate_limitations(SNAC &snac,HNETLIBCONN hServerConn,unsigned short &seqno);// family 0x0001
- void snac_avatar_rate_limitations(SNAC &snac,HNETLIBCONN hServerConn,unsigned short &seqno);// family 0x0001
- void snac_chatnav_rate_limitations(SNAC &snac,HNETLIBCONN hServerConn,unsigned short &seqno);// family 0x0001
- void snac_chat_rate_limitations(SNAC &snac,HNETLIBCONN hServerConn,unsigned short &seqno);// family 0x0001
- void snac_admin_rate_limitations(SNAC &snac,HNETLIBCONN hServerConn,unsigned short &seqno);// family 0x0001
- void snac_service_redirect(SNAC &snac);// family 0x0001
- void snac_self_info(SNAC &snac);//family 0x0001
- void snac_icbm_limitations(SNAC &snac,HNETLIBCONN hServerConn,unsigned short &seqno);//family 0x0004
- void snac_user_online(SNAC &snac);
- void snac_user_offline(SNAC &snac);
- void snac_error(SNAC &snac);//family 0x0003 or x0004
- void snac_contact_list(SNAC &snac,HNETLIBCONN hServerConn,unsigned short &seqno);
- void snac_message_accepted(SNAC &snac);//family 0x004
- void snac_received_message(SNAC &snac,HNETLIBCONN hServerConn,unsigned short &seqno);//family 0x0004
- void snac_file_decline(SNAC &snac);//family 0x0004
- void snac_received_info(SNAC &snac);//family 0x0002
- void snac_typing_notification(SNAC &snac);//family 0x004
- void snac_list_modification_ack(SNAC &snac);//family 0x0013
- void snac_mail_response(SNAC &snac);//family 0x0018
- void snac_retrieve_avatar(SNAC &snac);//family 0x0010
- void snac_upload_reply_avatar(SNAC &snac);//family 0x0010
- void snac_email_search_results(SNAC &snac);//family 0x000A
- void snac_chatnav_info_response(SNAC &snac,HNETLIBCONN hServerConn,unsigned short &seqno);//family 0x000D
- void snac_chat_joined_left_users(SNAC &snac,chat_list_item* item);//family 0x000E
- void snac_chat_received_message(SNAC &snac,chat_list_item* item);//family 0x000E
- void snac_admin_account_infomod(SNAC &snac);//family 0x0007
- void snac_admin_account_confirm(SNAC &snac);//family 0x0007
-
- void process_ssi_list(SNAC &snac, int &offset);
- void modify_ssi_list(SNAC &snac, int &offset);
- void delete_ssi_list(SNAC &snac, int &offset);
-
- //////////////////////////////////////////////////////////////////////////////////////
- // themes.cpp
-
- void InitMainMenus(void);
- void InitContactMenus(void);
-
- //////////////////////////////////////////////////////////////////////////////////////
- // thread.cpp
-
- void __cdecl accept_file_thread( void* );
-
- //////////////////////////////////////////////////////////////////////////////////////
- // utilities.cpp
-
- struct msg_ack_param { MCONTACT hContact; const char *msg; int id; bool success; };
-
- void __cdecl msg_ack_success(void*);
- void __cdecl start_connection(void*);
-
- MCONTACT find_chat_contact(const char * room);
- MCONTACT contact_from_sn(const char* sn, bool addIfNeeded = false, bool temporary = false);
-
- void broadcast_status(int status);
- bool wait_conn(HNETLIBCONN& hConn, HANDLE& hEvent, unsigned short service);
- bool is_my_contact(MCONTACT hContact);
- void add_contact_to_group(MCONTACT hContact, const char* group);
- void set_local_nick(MCONTACT hContact, char* nick, char* note);
- void upload_nicks(void);
- void update_server_group(const char* group, unsigned short group_id);
- void offline_contacts(void);
- void offline_contact(MCONTACT hContact, bool remove_settings);
- unsigned short get_default_port(void);
-
- int open_contact_file(const char* sn, const wchar_t* file, const char* mode, wchar_t* &path, bool contact_dir);
- void write_away_message(const char* sn, const char* msg, bool utf);
- void write_profile(const char* sn, const char* msg, bool utf);
-
- unsigned short getBuddyId(MCONTACT hContact, int i);
- unsigned short getGroupId(MCONTACT hContact, int i);
- void setBuddyId(MCONTACT hContact, int i, unsigned short id);
- void setGroupId(MCONTACT hContact, int i, unsigned short id);
- int deleteBuddyId(MCONTACT hContact, int i);
- int deleteGroupId(MCONTACT hContact, int i);
-
- unsigned short search_for_free_item_id(MCONTACT hbuddy);
- unsigned short* get_members_of_group(unsigned short group_id, unsigned short& size);
-
- void ShowPopup( const char* msg, int flags, char* url = 0 );
-};
-
-#endif
diff --git a/protocols/AimOscar/src/proxy.cpp b/protocols/AimOscar/src/proxy.cpp deleted file mode 100644 index 2b7fdb0f77..0000000000 --- a/protocols/AimOscar/src/proxy.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2009 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 "stdafx.h"
-
-void __cdecl CAimProto::aim_proxy_helper(void* param)
-{
- file_transfer *ft = (file_transfer*)param;
-
- if (ft->requester)
- {
- if (proxy_initialize_send(ft->hConn, m_username, ft->icbm_cookie))
- return;//error
- }
- else
- {
- if (proxy_initialize_recv(ft->hConn, m_username, ft->icbm_cookie, ft->port))
- return;//error
- }
-
- //start listen for packets stuff
- NETLIBPACKETRECVER packetRecv = {};
- packetRecv.dwTimeout = INFINITE;
-
- HANDLE hServerPacketRecver = Netlib_CreatePacketReceiver(ft->hConn, 2048 * 4);
- for (;;)
- {
- int recvResult = Netlib_GetMorePackets(hServerPacketRecver, &packetRecv);
- if (recvResult == 0)
- {
- ProtoBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0);
- break;
- }
- if (recvResult == SOCKET_ERROR)
- {
- ProtoBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0);
- break;
- }
- if (recvResult > 0)
- {
- unsigned short length = _htons(*(unsigned short*)&packetRecv.buffer[0]);
- packetRecv.bytesUsed = length + 2;
- unsigned short type = _htons(*(unsigned short*)&packetRecv.buffer[4]);
- if (type == 0x0001)
- {
- unsigned short error = _htons(*(unsigned short*)&packetRecv.buffer[12]);
- switch (error)
- {
- case 0x000D:
- ShowPopup("Proxy Server File Transfer Error: Bad Request.", ERROR_POPUP);
- break;
-
- case 0x0010:
- ShowPopup("Proxy Server File Transfer Error: Initial Request Timed Out.", ERROR_POPUP);
- break;
-
- case 0x001A:
- ShowPopup("Proxy Server File Transfer Error: Accept Period Timed Out.", ERROR_POPUP);
- break;
-
- case 0x000e:
- ShowPopup("Proxy Server File Transfer Error: Incorrect command syntax.", ERROR_POPUP);
- break;
-
- case 0x0016:
- ShowPopup("Proxy Server File Transfer Error: Unknown command issued.", ERROR_POPUP);
- break;
- }
-
- }
- else if (type == 0x0003)
- {
- unsigned short port = _htons(*(unsigned short*)&packetRecv.buffer[12]);
- unsigned long ip = _htonl(*(unsigned long*)&packetRecv.buffer[14]);
-
- aim_send_file(m_hServerConn, m_seqno, ip, port, true, ft);
- debugLogA("Stage %d Proxy ft and we are not the sender.", ft->req_num);
- }
- else if (type == 0x0005)
- {
- if (!ft->requester)
- {
- aim_file_ad(m_hServerConn, m_seqno, ft->sn, ft->icbm_cookie, false, ft->max_ver);
- ft->accepted = true;
- }
-
- ProtoBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, ft, 0);
-
- int i;
- for (i = 21; --i; )
- {
- if (Miranda_IsTerminated()) return;
- Sleep(100);
- if (ft->accepted) break;
- }
- if (i == 0)
- {
- ProtoBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0);
- break;
- }
-
- packetRecv.dwTimeout = 350000;
-
- int result;
- if (ft->sending)//we are sending
- result = sending_file(ft, hServerPacketRecver, packetRecv);
- else
- result = receiving_file(ft, hServerPacketRecver, packetRecv);
-
- ProtoBroadcastAck(ft->hContact, ACKTYPE_FILE, result ? ACKRESULT_FAILED : ACKRESULT_SUCCESS, ft, 0);
- break;
- }
- }
- }
- Netlib_CloseHandle(hServerPacketRecver);
- Netlib_CloseHandle(ft->hConn);
-
- m_ft_list.remove_by_ft(ft);
-}
-
-
-int proxy_initialize_send(HNETLIBCONN connection, char* sn, char* cookie)
-{
- const char sn_length = (char)mir_strlen(sn);
- const int len = sn_length + 21 + TLV_HEADER_SIZE + AIM_CAPS_LENGTH;
-
- char* buf= (char*)alloca(len);
- unsigned short offset=0;
-
- aim_writeshort(len-2, offset, buf);
- aim_writegeneric(10, "\x04\x4a\0\x02\0\0\0\0\0\0", offset, buf);
- aim_writechar((unsigned char)sn_length, offset, buf); // screen name len
- aim_writegeneric(sn_length, sn, offset, buf); // screen name
- aim_writegeneric(8, cookie, offset, buf); // icbm cookie
- aim_writetlv(1, AIM_CAPS_LENGTH, AIM_CAP_FILE_TRANSFER, offset, buf);
-
- return Netlib_Send(connection, buf, offset, 0) >= 0 ? 0 : -1;
-}
-
-int proxy_initialize_recv(HNETLIBCONN connection, char* sn, char* cookie, unsigned short port_check)
-{
- const char sn_length = (char)mir_strlen(sn);
- const int len = sn_length + 23 + TLV_HEADER_SIZE + AIM_CAPS_LENGTH;
-
- char* buf= (char*)alloca(len);
- unsigned short offset=0;
-
- aim_writeshort(len-2, offset, buf);
- aim_writegeneric(10, "\x04\x4a\0\x04\0\0\0\0\0\0", offset, buf);
- aim_writechar((unsigned char)sn_length, offset, buf); // screen name len
- aim_writegeneric(sn_length, sn, offset, buf); // screen name
- aim_writeshort(port_check, offset, buf);
- aim_writegeneric(8, cookie, offset, buf); // icbm cookie
- aim_writetlv(1, AIM_CAPS_LENGTH, AIM_CAP_FILE_TRANSFER, offset, buf);
-
- return Netlib_Send(connection, buf, offset, 0) >= 0 ? 0 : -1;
-}
diff --git a/protocols/AimOscar/src/proxy.h b/protocols/AimOscar/src/proxy.h deleted file mode 100644 index 83a03e2d0d..0000000000 --- a/protocols/AimOscar/src/proxy.h +++ /dev/null @@ -1,24 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 PROXY_H
-#define PROXY_H
-
-int proxy_initialize_send(HNETLIBCONN connection, char* sn, char* cookie);
-int proxy_initialize_recv(HNETLIBCONN connection, char* sn, char* cookie, unsigned short port_check);
-
-#endif
diff --git a/protocols/AimOscar/src/resource.h b/protocols/AimOscar/src/resource.h deleted file mode 100755 index c123194d8e..0000000000 --- a/protocols/AimOscar/src/resource.h +++ /dev/null @@ -1,125 +0,0 @@ -//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by X:\install\git\miranda\miranda_ng_svn\protocols\AimOscar\res\aim.rc
-//
-#define IDC_SAVECHANGES 3
-#define IDC_CONFIRM 4
-#define IDD_INFO 6
-#define IDD_AIMACCOUNT 7
-#define IDD_AIM 8
-#define IDD_IDLE 9
-#define IDI_AIM 10
-#define IDI_ICQ 11
-#define IDI_ADD 12
-#define IDI_PROFILE 13
-#define IDI_MAIL 14
-#define IDI_HIPTOP 21
-#define IDI_BOT 22
-#define IDI_ADMIN 23
-#define IDI_CONFIRMED 24
-#define IDI_UNCONFIRMED 25
-#define IDI_AWAY 26
-#define IDI_IDLE 27
-#define IDI_AOL 28
-#define IDI_FOREGROUNDCOLOR 31
-#define IDI_BACKGROUNDCOLOR 32
-#define IDD_PRIVACY 36
-#define IDD_CHAT 37
-#define IDI_BLOCK 38
-#define IDD_ADMIN 39
-#define IDD_CHATROOM_INVITE 40
-#define IDI_BOLD 41
-#define IDD_CHATROOM_INVITE_REQ 41
-#define IDI_NBOLD 42
-#define IDI_ITALIC 43
-#define IDI_NITALIC 44
-#define IDI_UNDERLINE 45
-#define IDI_NUNDERLINE 46
-#define IDI_SUBSCRIPT 53
-#define IDI_NSUBSCRIPT 54
-#define IDI_SUPERSCRIPT 55
-#define IDI_NSUPERSCRIPT 56
-#define IDI_NORMALSCRIPT 57
-#define IDI_NNORMALSCRIPT 58
-#define IDC_DETAILS 125
-#define IDC_OPTIONS 126
-#define IDC_EXPERT 127
-#define IDC_BOLD 129
-#define IDC_ITALIC 130
-#define IDC_UNDERLINE 131
-#define IDC_SUPERSCRIPT 132
-#define IDC_SUBSCRIPT 133
-#define IDC_NORMALSCRIPT 134
-#define IDC_FOREGROUNDCOLORPICKER 135
-#define IDC_FOREGROUNDCOLOR 136
-#define IDC_BACKGROUNDCOLORPICKER 137
-#define IDC_BACKGROUNDCOLOR 138
-#define IDC_TYPEFACE 139
-#define IDC_FONTSIZE 141
-#define IDC_SVRRESET 142
-#define IDC_NEWAIMACCOUNTLINK 143
-#define IDC_ALLOWALL 144
-#define IDC_ALLOWCONT 145
-#define IDC_ALLOWBELOW 146
-#define IDC_BLOCKALL 147
-#define IDC_BLOCKBELOW 148
-#define IDC_ALLOWLIST 149
-#define IDC_BLOCKLIST 150
-#define IDC_ALLOWEDIT 151
-#define IDC_ALLOWADD 152
-#define IDC_BLOCKEDIT 153
-#define IDC_BLOCKADD 154
-#define IDC_ALLOWREMOVE 155
-#define IDC_BLOCKREMOVE 156
-#define IDC_ROOM 157
-#define IDC_CEMAIL 158
-#define IDC_MSG 158
-#define IDC_FNAME 159
-#define IDC_NPW1 161
-#define IDC_NPW2 162
-#define IDC_CPW 164
-#define IDC_PINFO 165
-#define IDC_SCREENNAME 169
-#define IDC_CCLIST 173
-#define IDC_EDITSCR 174
-#define IDC_ADDSCR 175
-#define IDC_ROOMNAME 176
-#define IDC_CHECK1 178
-#define IDC_CLIENTLOGIN 178
-#define IDC_SN 1030
-#define IDC_NK 1040
-#define IDC_PW 1050
-#define IDC_HN 1060
-#define IDC_PN 1061
-#define IDC_DM 1100
-#define IDC_DC 1110
-#define IDC_FP 1120
-#define IDC_AT 1130
-#define IDC_ES 1140
-#define IDC_FI 1150
-#define IDC_FO 1160
-#define IDC_DA 1161
-#define IDC_DSSL 1162
-#define IDC_FSC 1163
-#define IDC_HF 1170
-#define IDC_SIS 1171
-#define IDC_MASQ 1180
-#define IDC_CM 1191
-#define IDC_MG 1192
-#define IDC_SETPROFILE 1200
-#define IDC_II 1210
-#define IDC_PROFILE 1220
-#define IDC_IIM 1230
-#define IDC_IIH 1240
-#define IDC_STATIC -1
-
-// Next default values for new objects
-//
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 41
-#define _APS_NEXT_COMMAND_VALUE 40002
-#define _APS_NEXT_CONTROL_VALUE 179
-#define _APS_NEXT_SYMED_VALUE 101
-#endif
-#endif
diff --git a/protocols/AimOscar/src/server.cpp b/protocols/AimOscar/src/server.cpp deleted file mode 100644 index 96038aa8d1..0000000000 --- a/protocols/AimOscar/src/server.cpp +++ /dev/null @@ -1,1994 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2012 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 "stdafx.h"
-
-void CAimProto::snac_md5_authkey(SNAC &snac, HNETLIBCONN hServerConn, unsigned short &seqno, const char* username, const char* password)//family 0x0017
-{
- if (snac.subcmp(0x0007))//md5 authkey string
- {
- unsigned short length = snac.ushort();
- char* authkey = snac.part(2, length);
- aim_auth_request(hServerConn, seqno, authkey, AIM_LANGUAGE, AIM_COUNTRY, username, password);
- mir_free(authkey);
- }
-}
-
-int CAimProto::snac_authorization_reply(SNAC &snac)//family 0x0017
-{
- int res = 0;
-
- if (snac.subcmp(0x0003)) {
- char* server = nullptr;
- int address = 0;
- unsigned short port;
- unsigned char use_ssl = 0;
-
- while (address < snac.len()) {
- TLV tlv(snac.val(address));
- if (tlv.cmp(0x0005))
- server = tlv.dup();
- else if (tlv.cmp(0x0006)) {
- Netlib_CloseHandle(m_hServerConn);
-
- if (server == nullptr) return 3;
- char* delim = strchr(server, ':');
- port = delim ? (unsigned short)atoi(delim + 1) : get_default_port();
- if (delim) *delim = 0;
-
- m_hServerConn = aim_connect(server, port, use_ssl != 0, "bos.oscar.aol.com");
- if (m_hServerConn) {
- mir_free(COOKIE);
- COOKIE_LENGTH = tlv.len();
- COOKIE = tlv.dup();
- ForkThread(&CAimProto::aim_protocol_negotiation, nullptr);
- res = 1;
- }
- else
- res = 3;
- break;
- }
- else if (tlv.cmp(0x0008)) {
- login_error(tlv.ushort());
- res = 2;
- break;
- }
- else if (tlv.cmp(0x0011)) {
- char* email = tlv.dup();
- setString(AIM_KEY_EM, email);
- mir_free(email);
- }
- else if (tlv.cmp(0x008e)) {
- use_ssl = tlv.ubyte();
- }
- address += tlv.len() + 4;
- }
- mir_free(server);
- }
- return res;
-}
-void CAimProto::snac_supported_families(SNAC &snac, HNETLIBCONN hServerConn, unsigned short &seqno)//family 0x0001
-{
- if (snac.subcmp(0x0003))//server supported service list
- {
- aim_send_service_request(hServerConn, seqno);
- }
-}
-void CAimProto::snac_supported_family_versions(SNAC &snac, HNETLIBCONN hServerConn, unsigned short &seqno)//family 0x0001
-{
- if (snac.subcmp(0x0018))//service list okayed
- {
- aim_request_rates(hServerConn, seqno);//request some rate crap
- }
-}
-void CAimProto::snac_rate_limitations(SNAC &snac, HNETLIBCONN hServerConn, unsigned short &seqno)// family 0x0001
-{
- if (snac.subcmp(0x0007)) {
- aim_accept_rates(hServerConn, seqno);
- aim_request_icbm(hServerConn, seqno);
- }
-}
-void CAimProto::snac_mail_rate_limitations(SNAC &snac, HNETLIBCONN hServerConn, unsigned short &seqno)// family 0x0001
-{
- if (snac.subcmp(0x0007)) {
- aim_accept_rates(hServerConn, seqno);
- aim_request_mail(hServerConn, seqno);
- aim_activate_mail(hServerConn, seqno);
- aim_mail_ready(hServerConn, seqno);
- }
-}
-
-void CAimProto::snac_avatar_rate_limitations(SNAC &snac, HNETLIBCONN hServerConn, unsigned short &seqno)// family 0x0001
-{
- if (snac.subcmp(0x0007)) {
- aim_accept_rates(hServerConn, seqno);
- aim_avatar_ready(hServerConn, seqno);
- SetEvent(m_hAvatarEvent);
- }
-}
-
-void CAimProto::snac_chatnav_rate_limitations(SNAC &snac, HNETLIBCONN hServerConn, unsigned short &seqno)// family 0x0001
-{
- if (snac.subcmp(0x0007)) {
- aim_accept_rates(hServerConn, seqno);
- aim_chatnav_request_limits(m_hChatNavConn, m_chatnav_seqno); // Get the max number of rooms we're allowed in.
- }
-}
-
-void CAimProto::snac_chat_rate_limitations(SNAC &snac, HNETLIBCONN hServerConn, unsigned short &seqno)// family 0x0001
-{
- if (snac.subcmp(0x0007)) {
- aim_accept_rates(hServerConn, seqno);
- aim_chat_ready(hServerConn, seqno);
- }
-}
-
-void CAimProto::snac_icbm_limitations(SNAC &snac, HNETLIBCONN hServerConn, unsigned short &seqno)//family 0x0004
-{
- if (snac.subcmp(0x0005)) {
- switch (m_iDesiredStatus) {
- case ID_STATUS_ONLINE:
- broadcast_status(ID_STATUS_ONLINE);
- aim_set_status(hServerConn, seqno, AIM_STATUS_ONLINE);
- break;
-
- case ID_STATUS_INVISIBLE:
- broadcast_status(ID_STATUS_INVISIBLE);
- aim_set_status(hServerConn, seqno, AIM_STATUS_INVISIBLE);
- break;
-
- case ID_STATUS_OCCUPIED:
- broadcast_status(ID_STATUS_OCCUPIED);
- aim_set_status(hServerConn, seqno, AIM_STATUS_BUSY | AIM_STATUS_AWAY);
- break;
-
- case ID_STATUS_AWAY:
- broadcast_status(ID_STATUS_AWAY);
- aim_set_status(hServerConn, seqno, AIM_STATUS_AWAY);
- break;
- }
-
- char** msgptr = get_status_msg_loc(m_iDesiredStatus);
- replaceStr(m_last_status_msg, msgptr ? *msgptr: nullptr);
- aim_set_statusmsg(hServerConn, seqno, m_last_status_msg);
-
- if (m_iDesiredStatus == ID_STATUS_AWAY)
- aim_set_away(hServerConn, seqno, m_last_status_msg, true);
-
- if (getByte(AIM_KEY_II, 0)) {
- unsigned long time = getDword(AIM_KEY_IIT, 0);
- aim_set_idle(hServerConn, seqno, time * 60);
- m_instantidle = 1;
- }
- aim_request_list(hServerConn, seqno);
- }
-}
-
-void CAimProto::snac_self_info(SNAC &snac)//family 0x0001
-{
- if (snac.subcmp(0x000f)) {
- int offset = snac.flags() & 0x8000 ? snac.ushort(0) + 2 : 0;
-
- unsigned char sn_len = snac.ubyte(offset++);
- char* sn = snac.part(offset, sn_len);
- offset += sn_len + 2;
-
- int tlv_count = snac.ushort(offset);
- offset += 2;
-
- for (int i = 0; i < tlv_count; i++) {
- TLV tlv(snac.val(offset));
- offset += TLV_HEADER_SIZE + tlv.len();
-
- if (tlv.cmp(0x000a)) {
- m_detected_ip = tlv.ulong();
- }
- }
- mir_free(sn);
- }
-}
-
-void CAimProto::snac_user_online(SNAC &snac)//family 0x0003
-{
- if (snac.subcmp(0x000b)) {
- char client[100] = "";
- bool hiptop_user = false;
- bool bot_user = false;
- bool wireless_user = false;
- bool away_user = false;
- bool caps_included = false;
- unsigned long status_type = 0; // 0 = online
-
- char *hash_sm = nullptr, *hash_lg = nullptr;
-
- unsigned char sn_len = snac.ubyte();
- char* sn = snac.part(1, sn_len);
- MCONTACT hContact = contact_from_sn(sn, true);
-
- int offset = sn_len + 3;
- int tlv_count = snac.ushort(offset);
- offset += 2;
-
- for (int i = 0; i < tlv_count; i++) {
- TLV tlv(snac.val(offset));
- offset += TLV_HEADER_SIZE;
- if (tlv.cmp(0x0001)) { // user m_iStatus
- unsigned short status = tlv.ushort();
- int unconfirmed = status & 0x0001;
- int admin_aol = status & 0x0002;
- int aol = status & 0x0004;
- //int nonfree = status & 0x0008;
- //int aim = status & 0x0010;
- int away = status & 0x0020;
- int icq = status & 0x0040;
- int wireless = status & 0x0080;
- int bot = status & 0x0400;
- setString(hContact, AIM_KEY_NK, sn);
-
- if (icq)
- setString(hContact, "Transport", "ICQ");
- else
- delSetting(hContact, "Transport");
-
- if (admin_aol)
- setByte(hContact, AIM_KEY_AC, ACCOUNT_TYPE_ADMIN);
- else if (aol)
- setByte(hContact, AIM_KEY_AC, ACCOUNT_TYPE_AOL);
- else if (icq)
- setByte(hContact, AIM_KEY_AC, ACCOUNT_TYPE_ICQ);
- else if (unconfirmed)
- setByte(hContact, AIM_KEY_AC, ACCOUNT_TYPE_UNCONFIRMED);
- else
- setByte(hContact, AIM_KEY_AC, ACCOUNT_TYPE_CONFIRMED);
-
- if (bot) {
- mir_strcpy(client, CLIENT_BOT);
- bot_user = 1;
- }
- if (wireless) {
- mir_strcpy(client, CLIENT_SMS);
- wireless_user = 1;
- }
- else if (away) {
- away_user = 1;
- }
- setDword(hContact, AIM_KEY_IT, 0);//erase idle time
- setDword(hContact, AIM_KEY_OT, 0);//erase online time
- }
- else if (tlv.cmp(0x0006)) // Status
- {
- status_type = tlv.ulong() & 0x00000FFF;
- }
- else if (tlv.cmp(0x000d)) {
- caps_included = true;
-
- for (int k = 0; k < tlv.len(); k += 16) {
- char *cap = tlv.part(k, 16);
- if (memcmp(cap, "MirandaM", 8) == 0) {
- char a = cap[8];
- char b = cap[9];
- char c = cap[10];
- char d = cap[11];
- char e = cap[12];
- char f = cap[13];
- char g = cap[14];
- char h = cap[15];
- mir_snprintf(client, CLIENT_OSCARJ, a & 0x7f, b, c, d, alpha_cap_str(a), e & 0x7f, f, g, h, alpha_cap_str(e));
- }
- else if (memcmp(cap, "MirandaA", 8) == 0) {
- char a = cap[8];
- char b = cap[9];
- char c = cap[10];
- char d = cap[11];
- char e = cap[12];
- char f = cap[13];
- char g = cap[14];
- char h = cap[15];
- mir_snprintf(client, CLIENT_AIMOSCAR, a, b, c, d, e, f, g, h);
- }
- if (memcmp(cap, "sinj", 4) == 0) {
- char a = cap[4];
- char b = cap[5];
- char c = cap[6];
- char d = cap[7];
- char e = cap[8];
- char f = cap[9];
- char g = cap[10];
- char h = cap[11];
- mir_snprintf(client, CLIENT_OSCARSN, a & 0x7f, b, c, d, alpha_cap_str(a), e & 0x7f, f, g, h, alpha_cap_str(e), secure_cap_str(&cap[12]));
- }
- if (memcmp(cap, "icqp", 4) == 0) {
- char a = cap[4];
- char b = cap[5];
- char c = cap[6];
- char d = cap[7];
- char e = cap[8];
- char f = cap[9];
- char g = cap[10];
- char h = cap[11];
- mir_snprintf(client, CLIENT_OSCARPL, a & 0x7f, b, c, d, alpha_cap_str(a), e & 0x7f, f, g, h, alpha_cap_str(e), secure_cap_str(&cap[12]));
- }
- else if (memcmp(cap, "Kopete ICQ", 10) == 0) {
- mir_strcpy(client, CLIENT_KOPETE);
- }
- else if (memcmp(&cap[7], "QIP", 3) == 0) {
- mir_strcpy(client, CLIENT_QIP);
- }
- else if (memcmp(cap, "mICQ", 4) == 0) {
- mir_strcpy(client, CLIENT_MICQ);
- }
- else if (cap_cmp(cap, AIM_CAP_IM2) == 0) {
- mir_strcpy(client, CLIENT_IM2);
- }
- else if (memcmp(cap, "SIM client", 10) == 0) {
- mir_strcpy(client, CLIENT_SIM);
- }
- else if (memcmp(cap + 4, "naim", 4) == 0) {
- mir_strcpy(client, CLIENT_NAIM);
- }
- else if (memcmp(cap, "digsby", 6) == 0) {
- mir_strcpy(client, CLIENT_DIGSBY);
- }
- mir_free(cap);
- }
- }
- else if (tlv.cmp(0x0019)) { // new caps
- caps_included = 1;
- bool f002 = 0, f003 = 0, f004 = 0, f005 = 0, f007 = 0, f008 = 0,
- O101 = 0, O102 = 0, O103 = 0, O104 = 0, O105 = 0, O107 = 0, O1ff = 0,
- O10a = 0, O10c = 0, O10d = 0,
- l341 = 0, l343 = 0, l345 = 0, l346 = 0, l347 = 0, l348 = 0, l349 = 0, l34b = 0, l34e = 0;
-
- for (int k = 0; k < tlv.len(); k = k + 2) {
- unsigned short cap = tlv.ushort(k);
- if (cap == 0xf002)
- f002 = 1;
- if (cap == 0xf003)
- f003 = 1;
- if (cap == 0xf004)
- f004 = 1;
- if (cap == 0xf005)
- f005 = 1;
- if (cap == 0xf007)
- f007 = 1;
- if (cap == 0xf008)
- f008 = 1;
- if (cap == 0x0101)
- O101 = 1;
- if (cap == 0x0102)
- O102 = 1;
- if (cap == 0x0103)
- O103 = 1;
- if (cap == 0x0104)
- O104 = 1;
- if (cap == 0x0105)
- O105 = 1;
- if (cap == 0x0107)
- O107 = 1;
- if (cap == 0x010a)
- O10a = 1;
- if (cap == 0x010c)
- O10c = 1;
- if (cap == 0x010d)
- O10d = 1;
- if (cap == 0x01ff)
- O1ff = 1;
- if (cap == 0x1323) {
- mir_strcpy(client, CLIENT_GPRS);
- hiptop_user = 1;
- }
- if (cap == 0x1341)
- l341 = 1;
- if (cap == 0x1343)
- l343 = 1;
- if (cap == 0x1345)
- l345 = 1;
- if (cap == 0x1346)
- l346 = 1;
- if (cap == 0x1347)
- l347 = 1;
- if (cap == 0x1348)
- l348 = 1;
- if (cap == 0x1349)
- l349 = 1;
- if (cap == 0x134b)
- l34b = 1;
- if (cap == 0x134e)
- l34e = 1;
- }
-
- if (f002 && f003 && f004 && f005)
- mir_strcpy(client, CLIENT_TRILLIAN_PRO);
- else if ((f004 && f005 && f007 && f008) || (f004 && f005 && O104 && O105))
- mir_strcpy(client, CLIENT_ICHAT);
- else if (f003&f004&f005)
- mir_strcpy(client, CLIENT_TRILLIAN);
- else if (l343 && O1ff && tlv.len() == 4)
- mir_strcpy(client, CLIENT_TRILLIAN_ASTRA);
- else if (l343 && tlv.len() == 2)
- mir_strcpy(client, CLIENT_AIMTOC);
- else if (l343 && l345 && l346 && tlv.len() == 6)
- mir_strcpy(client, CLIENT_GAIM);
- else if (l343 && l345 && l346 && l34e && tlv.len() == 8)
- mir_strcpy(client, CLIENT_PURPLE);
- else if (l343 && l345 && l346 && l349 && l34e && tlv.len() == 10)
- mir_strcpy(client, CLIENT_PURPLE);
- else if (l343 && l345 && l34e && tlv.len() == 6)
- mir_strcpy(client, CLIENT_ADIUM);
- else if (l343 && l346 && l34e && tlv.len() == 6)
- mir_strcpy(client, CLIENT_TERRAIM);
- else if (tlv.len() == 0 && getWord(hContact, AIM_KEY_ST, 0) != ID_STATUS_ONTHEPHONE)
- mir_strcpy(client, CLIENT_AIMEXPRESS5);
- else if (l34b && l343 && O1ff && l345 && l346 && tlv.len() == 10)
- mir_strcpy(client, CLIENT_AIMEXPRESS6);
- else if (l34b && l341 && l343 && O1ff && l345 && l346 && l347)
- mir_strcpy(client, CLIENT_AIM5);
- else if (l34b && l341 && l343 && l345&l346 && l347 && l348)
- mir_strcpy(client, CLIENT_AIM4);
- else if (O1ff && l343 && O107 && l341 && O104 && O105 && O101 && l346) {
- if (O10d)
- mir_strcpy(client, CLIENT_AIM6_9);
- else if (O10c)
- mir_strcpy(client, CLIENT_AIM6_8);
- else if (O10a)
- mir_strcpy(client, CLIENT_AIM6_5);
- else
- mir_strcpy(client, CLIENT_AIM_TRITON);
- }
- else if (O1ff && l343 && l341 && O104 && O105 && O101 && l346)
- mir_strcpy(client, CLIENT_AIM7_0);
- else if (l346 && l34e && tlv.len() == 4)
- mir_strcpy(client, CLIENT_MEEBO);
- else if (l34e && tlv.len() == 2)
- mir_strcpy(client, CLIENT_BEEJIVE);
- else if (l34e && l343 && tlv.len() == 4)
- mir_strcpy(client, CLIENT_BEEJIVE);
- }
- else if (tlv.cmp(0x001d)) { // bart
- if (hContact) {
- bool msg_exist = false;
- for (int k = 0; k < tlv.len(); ) {
- // Bart header
- unsigned short type = tlv.ushort(k);
- unsigned char flags = tlv.ubyte(k + 2);
- unsigned char datalen = tlv.ubyte(k + 3);
-
- switch (type) {
- case 0x0001:
- hash_sm = bytes_to_string(tlv.val() + k + 4, datalen);
- break;
-
- case 0x000c:
- hash_lg = bytes_to_string(tlv.val() + k + 4, datalen);
- break;
-
- case 0x0002:
- if ((flags & 4) && datalen > 2) {
- unsigned short len = tlv.ushort(k + 4);
- if (len) {
- msg_exist = true;
- char* msg = tlv.part(k + 6, len);
- char* msg_s = process_status_msg(msg, sn);
- db_set_utf(hContact, MOD_KEY_CL, OTH_KEY_SM, msg_s);
-
- wchar_t* tszMsg = mir_utf8decodeW(msg_s);
- ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, nullptr, (LPARAM)tszMsg);
- mir_free(tszMsg);
- mir_free(msg);
- mir_free(msg_s);
- }
- }
- break;
- }
- k += 4 + datalen;
- }
-
- if (!msg_exist)
- db_unset(hContact, MOD_KEY_CL, OTH_KEY_SM);
- }
- }
- else if (tlv.cmp(0x0004)) { //idle tlv
- if (hContact) {
- time_t current_time;
- time(¤t_time);
- setDword(hContact, AIM_KEY_IT, ((DWORD)current_time) - tlv.ushort() * 60);
- }
- }
- else if (tlv.cmp(0x0003)) { // online time tlv
- if (hContact)
- setDword(hContact, AIM_KEY_OT, tlv.ulong());
- }
- else if (tlv.cmp(0x0005)) { // member since
- if (hContact)
- setDword(hContact, AIM_KEY_MS, tlv.ulong());
- }
- offset += tlv.len();
- }
-
- if (status_type & AIM_STATUS_INVISIBLE)
- setWord(hContact, AIM_KEY_ST, ID_STATUS_INVISIBLE);
- else if (status_type & AIM_STATUS_BUSY)
- setWord(hContact, AIM_KEY_ST, ID_STATUS_OCCUPIED);
- else if (status_type & AIM_STATUS_AWAY || away_user)
- setWord(hContact, AIM_KEY_ST, ID_STATUS_AWAY);
- else if (wireless_user)
- setWord(hContact, AIM_KEY_ST, ID_STATUS_ONTHEPHONE);
- else
- setWord(hContact, AIM_KEY_ST, ID_STATUS_ONLINE);
-
- if (hash_lg)
- avatar_request_handler(hContact, hash_lg, 12);
- else
- avatar_request_handler(hContact, hash_sm, 1);
-
- if (bot_user)
- setByte(hContact, AIM_KEY_ET, EXTENDED_STATUS_BOT);
- else if (hiptop_user)
- setByte(hContact, AIM_KEY_ET, EXTENDED_STATUS_HIPTOP);
- if (caps_included)
- set_contact_icon(this, hContact);
-
- if (caps_included || client[0])
- setString(hContact, AIM_KEY_MV, client[0] ? client : "?");
- else if (atoi(sn))
- setString(hContact, AIM_KEY_MV, CLIENT_ICQ);
- else if (getBool(hContact, AIM_KEY_BLS, false))
- setString(hContact, AIM_KEY_MV, CLIENT_BLAST);
- else
- setString(hContact, AIM_KEY_MV, CLIENT_AIMEXPRESS7);
-
- mir_free(hash_lg);
- mir_free(hash_sm);
- mir_free(sn);
- }
-}
-
-void CAimProto::snac_user_offline(SNAC &snac)//family 0x0003
-{
- if (snac.subcmp(0x000c)) {
- unsigned char buddy_length = snac.ubyte();
- char* buddy = snac.part(1, buddy_length);
- MCONTACT hContact = contact_from_sn(buddy, true);
- if (hContact)
- offline_contact(hContact, 0);
- mir_free(buddy);
- }
-}
-void CAimProto::snac_error(SNAC &snac)//family 0x0003 or 0x0004
-{
- if (snac.subcmp(0x0001))
- get_error(snac.ushort());
-}
-
-void CAimProto::process_ssi_list(SNAC &snac, int &offset)
-{
- unsigned short name_length = snac.ushort(offset);
- char* name = snac.part(offset + 2, name_length);
- unsigned short group_id = snac.ushort(offset + 2 + name_length);
- unsigned short item_id = snac.ushort(offset + 4 + name_length);
- unsigned short type = snac.ushort(offset + 6 + name_length);
- unsigned short tlv_size = snac.ushort(offset + 8 + name_length);
- const int tlv_base = offset + name_length + 10;
-
- switch (type) {
- case 0x0000: //buddy record
- {
- MCONTACT hContact = contact_from_sn(name, true);
- if (hContact) {
- int i;
- for (i = 1;; i++) {
- if (!getBuddyId(hContact, i)) {
- setBuddyId(hContact, i, item_id);
- setGroupId(hContact, i, group_id);
- break;
- }
- }
- if (i == 1 && getByte(AIM_KEY_MG, 1)) {
- const char* group = m_group_list.find_name(group_id);
- if (group) {
- bool ok = false;
- DBVARIANT dbv;
- if (!db_get_utf(hContact, MOD_KEY_CL, OTH_KEY_GP, &dbv) && dbv.pszVal[0]) {
- ok = mir_strcmp(group, dbv.pszVal) == 0;
- db_free(&dbv);
- }
- else ok = mir_strcmp(group, AIM_DEFAULT_GROUP) == 0;
-
- if (!ok) {
- if (mir_strcmp(group, AIM_DEFAULT_GROUP))
- db_set_utf(hContact, MOD_KEY_CL, OTH_KEY_GP, group);
- else
- db_unset(hContact, MOD_KEY_CL, OTH_KEY_GP);
- }
- }
- }
- setWord(hContact, AIM_KEY_ST, ID_STATUS_OFFLINE);
-
- bool nickfound = false;
- for (int tlv_offset = 0; tlv_offset < tlv_size;) {
- TLV tlv(snac.val(tlv_base + tlv_offset));
-
- if (tlv.cmp(0x0131) && tlv.len()) {
- char* nick = tlv.dup();
- db_set_utf(hContact, MOD_KEY_CL, "MyHandle", nick);
- mir_free(nick);
- nickfound = true;
- }
- else if (tlv.cmp(0x7b))
- setByte(hContact, AIM_KEY_BLS, 1);
- else if (tlv.cmp(0x6a))
- setByte(hContact, AIM_KEY_NIL, 1);
-
- tlv_offset += TLV_HEADER_SIZE + tlv.len();
- }
- if (!nickfound && getDword(AIM_KEY_LV, 0) >= 0x80500)
- db_unset(hContact, MOD_KEY_CL, "MyHandle");
- }
- }
- break;
-
- case 0x0001: //group record
- if (group_id) {
- m_group_list.add(name, group_id);
- if (getByte(AIM_KEY_MG, 1))
- create_group(name);
- }
- break;
-
- case 0x0002: //permit record
- m_allow_list.add(name, item_id);
- break;
-
- case 0x0003: //deny record
- m_block_list.add(name, item_id);
- break;
-
- case 0x0004: //privacy record
- if (group_id == 0) {
- m_pd_info_id = item_id;
-
- for (int tlv_offset = 0; tlv_offset < tlv_size;) {
- TLV tlv(snac.val(tlv_base + tlv_offset));
-
- if (tlv.cmp(0x00ca))
- m_pd_mode = tlv.ubyte();
- else if (tlv.cmp(0x00cc))
- m_pd_flags = tlv.ulong();
-
- tlv_offset += TLV_HEADER_SIZE + tlv.len();
- }
- }
- break;
-
- case 0x0005: //prefernces record
- if (group_id == 0) {
- m_pref1_id = item_id;
-
- for (int tlv_offset = 0; tlv_offset < tlv_size;) {
- TLV tlv(snac.val(tlv_base + tlv_offset));
-
- if (tlv.cmp(0x00c9))
- m_pref1_flags = tlv.ulong();
- else if (tlv.cmp(0x00d6))
- m_pref1_set_flags = tlv.ulong();
- else if (tlv.cmp(0x00d7)) {
- mir_free(m_pref2_flags);
- m_pref2_flags = tlv.dup();
- m_pref2_len = tlv.len();
- }
- else if (tlv.cmp(0x00d8)) {
- mir_free(m_pref2_set_flags);
- m_pref2_set_flags = tlv.dup();
- m_pref2_set_len = tlv.len();
- }
-
- tlv_offset += TLV_HEADER_SIZE + tlv.len();
- }
- }
- break;
-
- case 0x0014: //avatar record
- if (!mir_strcmp(name, "1") || !mir_strcmp(name, "12")) {
- if (name_length == 1)
- m_avatar_id_sm = item_id;
- else
- m_avatar_id_lg = item_id;
-
- for (int tlv_offset = 0; tlv_offset < tlv_size;) {
- TLV tlv(snac.val(tlv_base + tlv_offset));
-
- if (tlv.cmp(0x00d5) && tlv.len() > 2) {
- if (name_length == 1) {
- mir_free(m_hash_sm);
- m_hash_sm = bytes_to_string(tlv.val() + 2, tlv.ubyte(1));
- }
- else {
- mir_free(m_hash_lg);
- m_hash_lg = bytes_to_string(tlv.val() + 2, tlv.ubyte(1));
- }
- }
-
- tlv_offset += TLV_HEADER_SIZE + tlv.len();
- }
- if (m_list_received)
- avatar_request_handler(NULL, nullptr, 0);
- }
- break;
-
- case 0x001D: // Vanity information
- if (group_id == 0) {
- for (int tlv_offset = 0; tlv_offset < tlv_size;) {
- TLV tlv(snac.val(tlv_base + tlv_offset));
-
- if (tlv.cmp(0x0150)) // Number of IMs sent
- setDword(AIM_KEY_TIS, tlv.ulong());
- else if (tlv.cmp(0x0151)) // Number of seconds a user is online
- setDword(AIM_KEY_TTO, tlv.ulong());
- else if (tlv.cmp(0x0152)) // Number of times a user has the away message set
- setDword(AIM_KEY_TAM, tlv.ulong());
- else if (tlv.cmp(0x0153)) // Number of IMs received
- setDword(AIM_KEY_TIR, tlv.ulong());
-
- tlv_offset += TLV_HEADER_SIZE + tlv.len();
- }
- }
- break;
- }
-
- mir_free(name);
-
- offset = tlv_base + tlv_size;
-}
-
-void CAimProto::modify_ssi_list(SNAC &snac, int &offset)
-{
- unsigned short name_length = snac.ushort(offset);
- char* name = snac.part(offset + 2, name_length);
- unsigned short group_id = snac.ushort(offset + 2 + name_length);
- unsigned short item_id = snac.ushort(offset + 4 + name_length);
- unsigned short type = snac.ushort(offset + 6 + name_length);
- unsigned short tlv_size = snac.ushort(offset + 8 + name_length);
- const int tlv_base = offset + name_length + 10;
-
- switch (type) {
- case 0x0000: //buddy record
- {
- MCONTACT hContact = contact_from_sn(name, true);
- if (hContact) {
- for (int tlv_offset = 0; tlv_offset < tlv_size; ) {
- TLV tlv(snac.val(tlv_base + tlv_offset));
-
- if (tlv.cmp(0x0131) && tlv.len()) {
- char* nick = tlv.dup();
- if (nick)
- db_set_utf(hContact, MOD_KEY_CL, "MyHandle", nick);
- else
- db_unset(hContact, MOD_KEY_CL, "MyHandle");
- mir_free(nick);
- }
-
- tlv_offset += TLV_HEADER_SIZE + tlv.len();
- }
- }
- break;
- }
-
- case 0x0004: //privacy record
- if (group_id == 0) {
- m_pd_info_id = item_id;
-
- for (int tlv_offset = 0; tlv_offset < tlv_size; ) {
- TLV tlv(snac.val(tlv_base + tlv_offset));
-
- if (tlv.cmp(0x00ca))
- m_pd_mode = tlv.ubyte();
- else if (tlv.cmp(0x00cc))
- m_pd_flags = tlv.ulong();
-
- tlv_offset += TLV_HEADER_SIZE + tlv.len();
- }
- }
- break;
-
- case 0x0005: //prefernces record
- if (group_id == 0) {
- m_pref1_id = item_id;
-
- for (int tlv_offset = 0; tlv_offset < tlv_size; ) {
- TLV tlv(snac.val(tlv_base + tlv_offset));
-
- if (tlv.cmp(0x00c9))
- m_pref1_flags = tlv.ulong();
- else if (tlv.cmp(0x00d6))
- m_pref1_set_flags = tlv.ulong();
- else if (tlv.cmp(0x00d7)) {
- mir_free(m_pref2_flags);
- m_pref2_flags = tlv.dup();
- m_pref2_len = tlv.len();
- }
- else if (tlv.cmp(0x00d8)) {
- mir_free(m_pref2_set_flags);
- m_pref2_set_flags = tlv.dup();
- m_pref2_set_len = tlv.len();
- }
-
- tlv_offset += TLV_HEADER_SIZE + tlv.len();
- }
- }
- break;
-
- case 0x0014: //avatar record
- if (!mir_strcmp(name, "1") || !mir_strcmp(name, "12")) {
- if (name_length == 1)
- m_avatar_id_sm = item_id;
- else
- m_avatar_id_lg = item_id;
-
- for (int tlv_offset = 0; tlv_offset < tlv_size; ) {
- TLV tlv(snac.val(tlv_base + tlv_offset));
-
- if (tlv.cmp(0x00d5) && tlv.len() > 2) {
- // unsigned char type = tlv.ubyte(0);
- if (name_length == 1) {
- mir_free(m_hash_sm);
- m_hash_sm = bytes_to_string(tlv.val() + 2, tlv.ubyte(1));
- }
- else {
- mir_free(m_hash_lg);
- m_hash_lg = bytes_to_string(tlv.val() + 2, tlv.ubyte(1));
- }
- }
- tlv_offset += TLV_HEADER_SIZE + tlv.len();
- }
- avatar_request_handler(NULL, nullptr, 0);
- }
- break;
- }
-
- mir_free(name);
-}
-
-void CAimProto::delete_ssi_list(SNAC &snac, int &offset)
-{
- int i;
-
- unsigned short name_length = snac.ushort(offset);
- char* name = snac.part(offset + 2, name_length);
- unsigned short group_id = snac.ushort(offset + 2 + name_length);
- unsigned short item_id = snac.ushort(offset + 4 + name_length);
- unsigned short type = snac.ushort(offset + 6 + name_length);
-
- MCONTACT hContact = contact_from_sn(name);
-
- switch (type) {
- case 0x0000: //buddy record
- for (i = 1;; ++i) {
- unsigned short item_id_st = getBuddyId(hContact, i);
- if (item_id_st == 0) break;
-
- if (item_id == item_id_st) {
- deleteBuddyId(hContact, i);
- deleteGroupId(hContact, i);
- --i;
- }
- }
- if (i == 1)
- db_delete_contact(hContact);
- break;
-
- case 0x0001: //group record
- m_group_list.remove_by_id(group_id);
- break;
-
- case 0x0014: //avatar record
- if (mir_strcmp(name, "1")) {
- m_avatar_id_sm = 0;
- mir_free(m_hash_sm);
- m_hash_sm = nullptr;
- }
- else if (!mir_strcmp(name, "12")) {
- m_avatar_id_lg = 0;
- mir_free(m_hash_lg);
- m_hash_lg = nullptr;
- }
- avatar_request_handler(NULL, nullptr, 0);
- break;
- }
- mir_free(name);
-}
-
-void CAimProto::snac_contact_list(SNAC &snac, HNETLIBCONN hServerConn, unsigned short &seqno)//family 0x0013
-{
- if (snac.subcmp(0x0006)) { //contact list
- debugLogA("Contact List Received");
- // unsigned char ver = snac.ubyte();
- int num_obj = snac.ushort(1);
-
- int offset = 3;
- for (int i = 0; i < num_obj; ++i)
- process_ssi_list(snac, offset);
-
- if (!m_list_received) { // because they can send us multiple buddy list packets
- // only want one finished connection
- m_list_received = 1;
- aim_activate_list(hServerConn, seqno);
- aim_set_caps(hServerConn, seqno);
- aim_set_icbm(hServerConn, seqno);
- aim_client_ready(hServerConn, seqno);
- aim_request_offline_msgs(hServerConn, seqno);
-
- DBVARIANT dbv;
- if (!db_get_utf(NULL, m_szModuleName, AIM_KEY_PR, &dbv)) {
- aim_set_profile(hServerConn, seqno, dbv.pszVal);
- db_free(&dbv);
- }
-
- if (getDword(AIM_KEY_LV, 0) < 0x80500) {
- upload_nicks();
- setDword(AIM_KEY_LV, Miranda_GetVersion());
- }
-
- if (getByte(AIM_KEY_CM, 0))
- aim_new_service_request(hServerConn, seqno, 0x0018);//mail
-
- avatar_request_handler(NULL, nullptr, 0);
-
- debugLogA("Connection Negotiation Finished");
- m_state = 1;
- }
- }
- else if (snac.subcmp(0x0008)) { // add buddy
- int offset = 8;
- process_ssi_list(snac, offset);
- }
- else if (snac.subcmp(0x0009)) { // modify buddy
- int offset = 8;
- modify_ssi_list(snac, offset);
- }
- else if (snac.subcmp(0x000a)) { // delete buddy
- int offset = 8;
- delete_ssi_list(snac, offset);
- }
-}
-
-void CAimProto::snac_message_accepted(SNAC &snac)//family 0x004
-{
- if (snac.subcmp(0x000c)) {
- char *icbm_cookie = snac.part(0, 8);
- unsigned char sn_length = snac.ubyte(10);
- char *sn = snac.part(11, sn_length);
-
- MCONTACT hContact = contact_from_sn(sn);
- if (hContact) {
- msg_ack_param *msg_ack = (msg_ack_param*)mir_alloc(sizeof(msg_ack_param));
- msg_ack->hContact = hContact;
- msg_ack->id = *(int*)icbm_cookie & 0x7fffffff;
- msg_ack->msg = nullptr;
- msg_ack->success = true;
- ForkThread(&CAimProto::msg_ack_success, msg_ack);
- }
-
- mir_free(sn);
- mir_free(icbm_cookie);
- }
-}
-void CAimProto::snac_received_message(SNAC &snac, HNETLIBCONN hServerConn, unsigned short &seqno)//family 0x0004
-{
- if (snac.subcmp(0x0007)) {
- unsigned short channel = snac.ushort(8);
- unsigned char sn_length = snac.ubyte(10);
- char *sn = snac.part(11, sn_length);
-
- MCONTACT hContact = contact_from_sn(sn, true, true), hMsgContact = NULL;
-
- int offset = 15 + sn_length;
-
- char *msg_buf = nullptr;
- unsigned long offline_timestamp = 0;
- bool is_offline = false;
- //file transfer stuff
- char *icbm_cookie = nullptr;
- char *filename = nullptr;
- unsigned __int64 file_size = 0;
- bool auto_response = false;
- bool force_proxy = false;
- bool descr_included = false;
- bool utf_fname = false;
- bool unicode_descr = false;
- short rdz_msg_type = -1;
- unsigned short request_num = 0;
- unsigned long local_ip = 0, verified_ip = 0, proxy_ip = 0;
- unsigned short port = 0;
- unsigned short max_ver = 0;
- unsigned short num_files = 0;
- //end file transfer stuff
-
- unsigned short tlv_head_num = snac.ushort(offset - 2);
- for (int i = 0; i < tlv_head_num; i++) { // skip server-added TLVs - prevent another problems with parsing
- TLV tlv(snac.val(offset));
- offset += TLV_HEADER_SIZE + tlv.len();
- // some extra sanity
- if (offset >= snac.len()) break;
- }
-
- while (offset < snac.len()) {
- TLV tlv(snac.val(offset));
- offset += TLV_HEADER_SIZE;
- if (tlv.cmp(0x0004) && !tlv.len())//auto response flag
- auto_response = 1;
-
- if (tlv.cmp(0x0002)) { // msg
- unsigned short caps_length = tlv.ushort(2);
- unsigned short msg_length = tlv.ushort(6 + caps_length) - 4;
- unsigned short encoding = tlv.ushort(8 + caps_length);
- char *buf = tlv.part(12 + caps_length, msg_length);
- if (hContact) {
- wchar_t* wbuf;
- hMsgContact = hContact;
- switch (encoding) {
- case 2:
- wbuf = (wchar_t*)buf;
- wcs_htons(wbuf);
-
- msg_buf = mir_utf8encodeW(wbuf);
- mir_free(wbuf);
- break;
-
- case 3:
- wbuf = mir_a2u_cp(buf, 28591);
-
- msg_buf = mir_utf8encodeW(wbuf);
- mir_free(wbuf);
- mir_free(buf);
- break;
-
- default:
- msg_buf = buf;
- break;
- }
- }
- }
-
- if (tlv.cmp(0x0004) && !tlv.len())//auto response flag
- auto_response = 1;
-
- if (channel == 2 && tlv.cmp(0x0005)) { //recv rendervous packet
- rdz_msg_type = snac.ushort(offset);
- icbm_cookie = snac.part(offset + 2, 8);
- if (cap_cmp(snac.val(offset + 10), AIM_CAP_FILE_TRANSFER) == 0) {
- for (int i = 26; i < tlv.len(); ) {
- TLV tlv2(snac.val(offset + i));
- if (tlv2.cmp(0x000A))
- request_num = tlv2.ushort();//for file transfer
- else if (tlv2.cmp(0x0002))//proxy ip
- proxy_ip = tlv2.ulong();
- else if (tlv2.cmp(0x0003))//client ip
- local_ip = tlv2.ulong();
- else if (tlv2.cmp(0x0004))//verified ip
- verified_ip = tlv2.ulong();
- else if (tlv2.cmp(0x0005))
- port = tlv2.ushort();
- else if (tlv2.cmp(0x0010))
- force_proxy = 1;
- else if (tlv2.cmp(0x0012))
- max_ver = tlv2.ushort();
- else if (tlv2.cmp(0x2711)) {
- num_files = tlv2.ushort(2);
- file_size = tlv2.ulong(4);
- filename = tlv2.part(8, tlv2.len() - 8);
- }
- else if (tlv2.cmp(0x2712)) {
- char *enc = tlv2.dup();
- utf_fname = mir_strcmp(enc, "utf-8") == 0;
- mir_free(enc);
- }
- else if (tlv2.cmp(0x2713)) {
- file_size = tlv2.u64();
- }
- else if (tlv2.cmp(0x000c)) {
- msg_buf = unicode_descr ? tlv2.dupw() : tlv2.dup();
- html_decode(msg_buf);
- descr_included = true;
- if (strstr(msg_buf, "<ICQ_COOL_FT>")) {
- char* beg = strstr(msg_buf, "<DESC>");
- char* end = strstr(msg_buf, "</DESC>");
- if (beg && end && beg < end) {
- beg += 6;
- end[0] = 0;
- memmove(msg_buf, beg, end - beg + 1);
- }
- else descr_included = false;
- }
- }
- else if (tlv2.cmp(0x000d)) {
- char* enc = tlv2.dup();
- unicode_descr = mir_strcmp(enc, "unicode-2-0") == 0;
- mir_free(enc);
- }
- i += TLV_HEADER_SIZE + tlv2.len();
- }
- }
- else if (cap_cmp(snac.val(offset + 10), AIM_CAP_RTCAUDIO) == 0 || cap_cmp(snac.val(offset + 10), AIM_CAP_RTCVIDEO) == 0) {
- for (int i = 26; i < tlv.len(); ) {
- TLV tlv2(snac.val(offset + i));
- if (tlv2.cmp(0x000A))
- request_num = tlv2.ushort();//for file transfer
- else if (tlv2.cmp(0x0002))//proxy ip
- proxy_ip = tlv2.ulong();
- else if (tlv2.cmp(0x0003))//client ip
- local_ip = tlv2.ulong();
- else if (tlv2.cmp(0x0004))//verified ip
- verified_ip = tlv2.ulong();
- else if (tlv2.cmp(0x0005))
- port = tlv2.ushort();
- }
- channel = 0;
- break;
- }
- else if (cap_cmp(snac.val(offset + 10), AIM_CAP_CHAT) == 0) { //it's a chat invite request
- for (int i = 26; i < tlv.len();) {
- TLV tlv2(snac.val(offset + i));
- if (tlv2.cmp(0x000c)) //optional message
- msg_buf = tlv2.dup();
- else if (tlv2.cmp(0x2711)) { //room information
- int cookie_len = tlv2.ubyte(2);
- chatnav_param* par =
- new chatnav_param(tlv2.part(3, cookie_len), tlv2.ushort(), tlv2.ushort(3 + cookie_len),
- msg_buf, sn, icbm_cookie);
-
- invite_chat_req_param* chat_rq = new invite_chat_req_param(par, this, msg_buf, sn, icbm_cookie);
- CallFunctionAsync(chat_request_cb, chat_rq);
- }
- i += TLV_HEADER_SIZE + tlv2.len();
- }
- }
- else {
- channel = 0;
- break;
- }
- }
-
- if (channel == 6 && tlv.cmp(0x0005))//audio/video tunnel
- msg_buf = tlv.dup();
-
- if (tlv.cmp(0x0006))//Offline message flag
- is_offline = true;
-
- if (tlv.cmp(0x0016))//Offline message timestamp
- offline_timestamp = tlv.ulong(0);
-
- offset += (tlv.len());
- }
-
- if (channel == 1) { //Message not file
- if (auto_response) { //this message must be an autoresponse
- T2Utf away(TranslateT("[Auto-response]:"));
- size_t len = mir_strlen(msg_buf) + mir_strlen(away) + 2;
- char* buf = (char*)mir_alloc(len);
- mir_snprintf(buf, len, "%s %s", away, msg_buf);
- mir_free(msg_buf);
- msg_buf = buf;
- }
-
- // Okay we are setting up the structure to give the message back to miranda's core
- CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hMsgContact, 0);
- {
- PROTORECVEVENT pre = { 0 };
- pre.timestamp = (is_offline) ? offline_timestamp : (DWORD)time(nullptr);
- pre.szMessage = msg_buf;
- ProtoChainRecvMsg(hMsgContact, &pre);
- }
-
- if (m_iStatus == ID_STATUS_AWAY && !auto_response && !getByte(AIM_KEY_DM, 0)) {
- unsigned long msg_time = getDword(hContact, AIM_KEY_LM, 0);
- unsigned long away_time = getDword(AIM_KEY_LA, 0);
- char** msgptr = get_status_msg_loc(m_iStatus);
- if (away_time > msg_time && *msgptr) {
- char* s_msg = process_status_msg(*msgptr, sn);
-
- T2Utf away(TranslateT("[Auto-response]:"));
- size_t len = mir_strlen(s_msg) + mir_strlen(away) + 2;
- char* buf = (char*)alloca(len);
- mir_snprintf(buf, len, "%s %s", away, s_msg);
-
- DBEVENTINFO dbei = {};
- dbei.szModule = m_szModuleName;
- dbei.timestamp = (DWORD)time(nullptr);
- dbei.flags = DBEF_SENT | DBEF_UTF;
- dbei.eventType = EVENTTYPE_MESSAGE;
- dbei.cbBlob = (int)len;
- dbei.pBlob = (PBYTE)buf;
- db_event_add(hContact, &dbei);
-
- aim_send_message(hServerConn, seqno, sn, s_msg, true, getBool(hContact, AIM_KEY_BLS, false));
- mir_free(s_msg);
- }
- setDword(hContact, AIM_KEY_LM, (DWORD)time(nullptr));
- }
- }
- else if (channel == 2) { // File Transfer
- if (rdz_msg_type == 0 && request_num == 1) { // buddy wants to send us a file
- debugLogA("Buddy Wants to Send us a file. Request 1");
- debugLogA(force_proxy ? "Forcing a Proxy File transfer." : "Not forcing Proxy File transfer.");
-
- file_transfer* ft = new file_transfer(hContact, sn, icbm_cookie);
-
- ft->me_force_proxy = getByte(AIM_KEY_FP, 0) != 0;
- ft->peer_force_proxy = force_proxy;
- ft->local_ip = local_ip;
- ft->verified_ip = verified_ip;
- ft->proxy_ip = proxy_ip;
- ft->port = port;
- ft->max_ver = max_ver;
- ft->req_num = request_num;
-
- ft->file = mir_strdup(filename);
-
- ft->pfts.totalBytes = file_size;
- ft->pfts.totalFiles = num_files;
-
- m_ft_list.insert(ft);
-
- if (!descr_included) msg_buf = nullptr;
-
- wchar_t* filenameT = mir_utf8decodeW(filename);
-
- PROTORECVFILET pre = { 0 };
- pre.dwFlags = PRFF_UNICODE;
- pre.fileCount = 1;
- pre.timestamp = time(nullptr);
- pre.descr.w = mir_utf8decodeW(msg_buf);
- pre.files.w = &filenameT;
- pre.lParam = (LPARAM)ft;
- ProtoChainRecvFile(hContact, &pre);
-
- mir_free(pre.descr.w);
- mir_free(filenameT);
-
- char cip[20];
- debugLogA("Local IP: %s:%u", long_ip_to_char_ip(local_ip, cip), port);
- debugLogA("Verified IP: %s:%u", long_ip_to_char_ip(verified_ip, cip), port);
- debugLogA("Proxy IP: %s:%u", long_ip_to_char_ip(proxy_ip, cip), port);
- }
- else if (rdz_msg_type == 0) {
- debugLogA("We are sending a file. Buddy wants us to connect to them. Request %d", request_num);
- debugLogA(force_proxy ? "Forcing a Proxy File transfer." : "Not forcing Proxy File transfer.");
-
- file_transfer* ft = m_ft_list.find_by_cookie(icbm_cookie, hContact);
- if (ft) {
- ft->hContact = hContact;
-
- ft->me_force_proxy |= (request_num > 2);
- ft->peer_force_proxy = force_proxy;
- ft->local_ip = local_ip;
- ft->verified_ip = verified_ip;
- ft->proxy_ip = proxy_ip;
- ft->port = port;
- ft->requester = false;
- ft->req_num = request_num;
- ft->max_ver = max_ver;
-
- char cip[20];
- debugLogA("Local IP: %s:%u", long_ip_to_char_ip(local_ip, cip), port);
- debugLogA("Verified IP: %s:%u", long_ip_to_char_ip(verified_ip, cip), port);
- debugLogA("Proxy IP: %s:%u", long_ip_to_char_ip(proxy_ip, cip), port);
-
- ForkThread(&CAimProto::accept_file_thread, ft);
- }
- else {
- debugLogA("Unknown File transfer, thus denied.");
- aim_file_ad(hServerConn, seqno, sn, icbm_cookie, true, 0);
- }
- }
- else if (rdz_msg_type == 1) { // buddy cancelled or denied file transfer
- debugLogA("File transfer cancelled or denied.");
-
- file_transfer *ft = m_ft_list.find_by_cookie(icbm_cookie, hContact);
- ProtoBroadcastAck(hContact, ACKTYPE_FILE, ACKRESULT_DENIED, ft, 0);
- m_ft_list.remove_by_ft(ft);
- }
- else if (rdz_msg_type == 2) { // buddy accepts our file transfer request
- debugLogA("File transfer accepted");
- file_transfer *ft = m_ft_list.find_by_cookie(icbm_cookie, hContact);
- if (ft) {
- ft->accepted = true;
- ft->max_ver = max_ver;
- }
- else aim_file_ad(hServerConn, seqno, sn, icbm_cookie, true, 0);
- }
- }
- else if (channel == 6) // Audio/Video call
- {
- aim_file_ad(hServerConn, seqno, sn, icbm_cookie, true, 0);
- ShowPopup(LPGEN("Contact tried to open an audio/video conference (not currently supported)"), ERROR_POPUP);
- }
-
- mir_free(sn);
- mir_free(msg_buf);
- mir_free(filename);
- mir_free(icbm_cookie);
- }
-}
-
-void CAimProto::snac_file_decline(SNAC &snac)//family 0x0004
-{
- if (snac.subcmp(0x000b)) {
- char *icbm_cookie = snac.part(0, 8);
- int channel = snac.ushort(8);
- if (channel == 0x01) {
- int sn_len = snac.ubyte(10);
- char *sn = snac.part(11, sn_len);
- MCONTACT hContact = contact_from_sn(sn);
-
- msg_ack_param *msg_ack = (msg_ack_param*)mir_alloc(sizeof(msg_ack_param));
- msg_ack->hContact = hContact;
- msg_ack->msg = nullptr;
- msg_ack->id = *(int*)icbm_cookie & 0x7fffffff;
- msg_ack->success = false;
- ForkThread(&CAimProto::msg_ack_success, msg_ack);
- }
-
- if (channel == 0x02) {
- int sn_len = snac.ubyte(10);
- char *sn = snac.part(11, sn_len);
- int reason = snac.ushort(11 + sn_len);
- if (reason == 0x03) {
- int error = snac.ushort(13 + sn_len);
- if (error == 0x02) {
- debugLogA("File Transfer declied");
- MCONTACT hContact = contact_from_sn(sn);
- file_transfer *ft = m_ft_list.find_by_cookie(icbm_cookie, hContact);
- if (ft) {
- ProtoBroadcastAck(hContact, ACKTYPE_FILE, ACKRESULT_DENIED, ft, 0);
- if (ft->hConn)
- Netlib_Shutdown(ft->hConn);
- else
- m_ft_list.remove_by_ft(ft);
- }
- }
- }
- mir_free(sn);
- }
- mir_free(icbm_cookie);
- }
-}
-void CAimProto::snac_received_info(SNAC &snac)//family 0x0002
-{
- if (snac.subcmp(0x0006)) {
- unsigned short offset = 0;
- int i = 0;
- bool away_message_received = false;
- bool away_message_unicode = false;
- bool away_message_utf = false;
- bool profile_received = false;
- bool profile_unicode = false;
- bool profile_utf = false;
- unsigned char sn_length = snac.ubyte();
- char* sn = snac.part(1, sn_length);
- unsigned short tlv_count = snac.ushort(3 + sn_length);
- offset = 5 + sn_length;
- MCONTACT hContact = contact_from_sn(sn, true, true);
-
- while (offset < snac.len()) {
- TLV tlv(snac.val(offset));
-
- if (++i > tlv_count) {
- if (tlv.cmp(0x0001)) { //profile encoding
- char *enc = tlv.dup();
- profile_unicode = strstr(enc, "unicode-2-0") != nullptr;
- profile_utf = strstr(enc, "utf-8") != nullptr;
- mir_free(enc);
- }
- else if (tlv.cmp(0x0002)) { //profile message string
- char *msg = profile_unicode ? tlv.dupw() : tlv.dup();
-
- profile_received = true;
- write_profile(sn, msg, profile_unicode | profile_utf);
- mir_free(msg);
- }
- else if (tlv.cmp(0x0003)) { //away message encoding
- char *enc = tlv.dup();
- away_message_unicode = strstr(enc, "unicode-2-0") != nullptr;
- away_message_utf = strstr(enc, "utf-8") != nullptr;
- mir_free(enc);
- }
- else if (tlv.cmp(0x0004)) { // away message string
- char *msg = away_message_unicode ? tlv.dupw() : tlv.dup();
-
- away_message_received = true;
- write_away_message(sn, msg, away_message_unicode | away_message_utf);
- mir_free(msg);
- }
- }
- offset += TLV_HEADER_SIZE + tlv.len();
- }
- if (hContact) {
- if (getWord(hContact, AIM_KEY_ST, ID_STATUS_OFFLINE) == ID_STATUS_AWAY) {
- if (!away_message_received && m_request_away_message)
- write_away_message(sn, Translate("No information has been provided by the server."), false);
- m_request_away_message = 0;
- }
- if (!profile_received && m_request_HTML_profile)
- write_profile(sn, "No Profile", false);
- m_request_HTML_profile = 0;
- }
- mir_free(sn);
- }
-}
-void CAimProto::snac_typing_notification(SNAC &snac)//family 0x004
-{
- if (snac.subcmp(0x0014)) {
- unsigned char sn_length = snac.ubyte(10);
- char *sn = snac.part(11, sn_length);
- MCONTACT hContact = contact_from_sn(sn);
- if (hContact) {
- unsigned short type = snac.ushort(11 + sn_length);
- if (type == 0x0000)//typing finished
- CallService(MS_PROTO_CONTACTISTYPING, hContact, (WPARAM)PROTOTYPE_CONTACTTYPING_OFF);
- else if (type == 0x0001)//typed
- CallService(MS_PROTO_CONTACTISTYPING, hContact, PROTOTYPE_CONTACTTYPING_INFINITE);
- else if (type == 0x0002)//typing
- CallService(MS_PROTO_CONTACTISTYPING, hContact, (LPARAM)60);
- }
- mir_free(sn);
- }
-}
-void CAimProto::snac_list_modification_ack(SNAC &snac)//family 0x0013
-{
- if (snac.subcmp(0x000e)) {
- unsigned short id = snac.id();
- TLV tlv(snac.val(2));
- unsigned short code = snac.ushort(6 + tlv.len());
-
- switch (id) {
- case 0x000a:
- switch (code) {
- case 0x0000:
- // ShowPopup(LPGEN("Successfully removed buddy from list."), ERROR_POPUP);
- break;
-
- case 0x0002:
- ShowPopup(LPGEN("Item you want to delete not found in list."), ERROR_POPUP);
- break;
-
- default:
- char msg[64];
- mir_snprintf(msg, "Error removing buddy from list. Error code %#x", code);
- ShowPopup(msg, ERROR_POPUP);
- break;
- }
- break;
-
- case 0x0008:
- switch (code) {
- case 0x0000:
- // ShowPopup("Successfully added buddy to list.", ERROR_POPUP);
- break;
-
- case 0x0003:
- ShowPopup(LPGEN("Failed to add buddy to list: Item already exist."), ERROR_POPUP);
- break;
-
- case 0x000a:
- ShowPopup(LPGEN("Error adding buddy (invalid ID or already in list?)"), ERROR_POPUP);
- break;
-
- case 0x000c:
- ShowPopup(LPGEN("Cannot add buddy. Limit for this type of item exceeded."), ERROR_POPUP);
- break;
-
- case 0x000d:
- ShowPopup(LPGEN("Error? Attempting to add ICQ contact to an AIM list."), ERROR_POPUP);
- break;
-
- case 0x000e:
- ShowPopup(LPGEN("Cannot add this buddy because it requires authorization."), ERROR_POPUP);
- break;
-
- default:
- char msg[64];
- mir_snprintf(msg, Translate("Unknown error when adding buddy to list. Error code %#x"), code);
- ShowPopup(msg, ERROR_POPUP);
- break;
- }
- break;
-
- case 0x0009:
- switch (code) {
- case 0x0000:
- case 0x000e:
- break;
-
- case 0x0002:
- ShowPopup(LPGEN("Item you want to modify not found in list."), ERROR_POPUP);
- break;
-
- default:
- char msg[64];
- mir_snprintf(msg, Translate("Unknown error when attempting to modify a group. Error code %#x"), code);
- ShowPopup(msg, ERROR_POPUP);
- break;
- }
- break;
- }
- }
-}
-
-void CAimProto::snac_service_redirect(SNAC &snac)//family 0x0001
-{
- if (snac.subcmp(0x0005)) {
- char* server = nullptr;
- char* local_cookie = nullptr;
- char* host = nullptr;
- int local_cookie_length = 0;
- unsigned short family = 0;
- unsigned char use_ssl = 0;
-
- int offset = 2; // skip number of bytes in family version tlv
- while (offset < snac.len()) {
- TLV tlv(snac.val(offset));
- if (tlv.cmp(0x000d)) {
- family = tlv.ushort();
- }
- else if (tlv.cmp(0x0005)) {
- server = tlv.dup();
- }
- else if (tlv.cmp(0x0006)) {
- local_cookie = tlv.dup();
- local_cookie_length = tlv.len();
- }
- else if (tlv.cmp(0x008d)) {
- host = tlv.dup();
- }
- else if (tlv.cmp(0x008e)) {
- use_ssl = tlv.ubyte();
- }
- offset += TLV_HEADER_SIZE + tlv.len();
- }
- if (family == 0x0018) {
- m_hMailConn = aim_connect(server, get_default_port(), false/*use_ssl != 0*/, host);
- if (m_hMailConn) {
- debugLogA("Successfully Connected to the Mail Server.");
- MAIL_COOKIE = local_cookie;
- MAIL_COOKIE_LENGTH = local_cookie_length;
- ForkThread(&CAimProto::aim_mail_negotiation, nullptr);
- }
- else debugLogA("Failed to connect to the Mail Server.");
- }
- else if (family == 0x0010) {
- m_hAvatarConn = aim_connect(server, get_default_port(), false/*use_ssl != 0*/);
- if (m_hAvatarConn) {
- debugLogA("Successfully Connected to the Avatar Server.");
- AVATAR_COOKIE = local_cookie;
- AVATAR_COOKIE_LENGTH = local_cookie_length;
- ForkThread(&CAimProto::aim_avatar_negotiation, nullptr);
- }
- else debugLogA("Failed to connect to the Avatar Server.");
- }
- else if (family == 0x000D) {
- m_hChatNavConn = aim_connect(server, get_default_port(), use_ssl != 0, host);
- if (m_hChatNavConn) {
- debugLogA("Successfully Connected to the Chat Navigation Server.");
- CHATNAV_COOKIE = local_cookie;
- CHATNAV_COOKIE_LENGTH = local_cookie_length;
- ForkThread(&CAimProto::aim_chatnav_negotiation, nullptr);
- }
- else debugLogA("Failed to connect to the Chat Navigation Server.");
- }
- else if (family == 0x000E) {
- chat_list_item* item = find_chat_by_cid(snac.idh());
- if (item) {
- item->hconn = aim_connect(server, get_default_port(), use_ssl != 0, host);
- if (item->hconn) {
- debugLogA("Successfully Connected to the Chat Server.");
- chat_start(item->id, item->exchange);
- item->CHAT_COOKIE = local_cookie;
- item->CHAT_COOKIE_LENGTH = local_cookie_length;
- ForkThread(&CAimProto::aim_chat_negotiation, item);
- }
- else debugLogA("Failed to connect to the Chat Server.");
- }
- }
- else if (family == 0x0007) {
- m_hAdminConn = aim_connect(server, get_default_port(), false /*use_ssl != 0*/);
- if (m_hAdminConn) {
- debugLogA("Successfully Connected to the Admin Server.");
- ADMIN_COOKIE = local_cookie;
- ADMIN_COOKIE_LENGTH = local_cookie_length;
- ForkThread(&CAimProto::aim_admin_negotiation, nullptr);
- }
- else debugLogA("Failed to connect to the Admin Server.");
- }
- mir_free(server);
- mir_free(host);
- }
-}
-
-void CAimProto::snac_mail_response(SNAC &snac)//family 0x0018
-{
- if (snac.subcmp(0x0007)) {
- char* sn = nullptr;
- time_t time = 0;
- unsigned short num_msgs = 0;
- unsigned short flags = 0;
- char new_mail = 0;
- char* url = nullptr;
- char* address = nullptr;
-
- int position = 26;
- int num_tlvs = snac.ushort(24);
- for (int i = 0; i < num_tlvs; i++) {
- TLV tlv(snac.val(position));
- if (tlv.cmp(0x0009)) {
- sn = tlv.dup();
- }
- else if (tlv.cmp(0x001d)) {
- time = tlv.ulong();
- }
- else if (tlv.cmp(0x0080)) {
- num_msgs = tlv.ushort();
- }
- else if (tlv.cmp(0x0081)) {
- new_mail = tlv.ubyte();
- }
- else if (tlv.cmp(0x0084)) {
- flags = tlv.ushort();
- }
- else if (tlv.cmp(0x0007)) {
- url = tlv.dup();
- }
- else if (tlv.cmp(0x0082)) {
- address = tlv.dup();
- }
- position += TLV_HEADER_SIZE + tlv.len();
- }
- if (new_mail && num_msgs) {
- wchar_t msg[1024];
-
- int len = mir_snwprintf(msg, L"%S@%S (%d)\r\n%s ", sn, address, num_msgs,
- TranslateT("You've got mail! Checked at"));
-
- SYSTEMTIME stLocal;
- GetLocalTime(&stLocal);
- GetTimeFormat(LOCALE_USER_DEFAULT, 0, &stLocal, nullptr, msg + len, _countof(msg) - len);
-
- ShowPopup((char*)msg, MAIL_POPUP | TCHAR_POPUP, url);
- }
- mir_free(sn);
- mir_free(address);
- mir_free(url);
- }
-}
-
-void CAimProto::snac_retrieve_avatar(SNAC &snac)//family 0x0010
-{
- if (snac.subcmp(0x0007)) {
- int sn_len = snac.ubyte(0);
- char* sn = snac.part(1, sn_len);
-
- int parse_off = sn_len + 4;
- parse_off += snac.ubyte(parse_off);
-
- int hash_size = snac.ubyte(5 + parse_off);
- char* hash_string = bytes_to_string(snac.val(6 + parse_off), hash_size);
- parse_off += hash_size + 6;
-
- int icon_length = snac.ushort(parse_off);
- char* icon_data = snac.val(parse_off + 2);
-
- avatar_retrieval_handler(sn, hash_string, icon_data, icon_length);
-
- mir_free(hash_string);
- mir_free(sn);
- }
-}
-void CAimProto::snac_upload_reply_avatar(SNAC &snac)//family 0x0010
-{
- if (snac.subcmp(0x0003)) {
- int code = snac.ubyte(0);
- switch (code) {
- case 0:
- break;
- case 3:
- ShowPopup(LPGEN("Error uploading avatar. (Too small)"), ERROR_POPUP);
- break;
- case 4:
- ShowPopup(LPGEN("Error uploading avatar. (Too big)"), ERROR_POPUP);
- break;
- case 5:
- ShowPopup(LPGEN("Error uploading avatar. (Wrong type)"), ERROR_POPUP);
- break;
- case 6:
- ShowPopup(LPGEN("Error uploading avatar. (Is banned)"), ERROR_POPUP);
- break;
- default:
- ShowPopup(LPGEN("Error uploading avatar. (Unknown error)"), ERROR_POPUP);
- break;
- }
- }
-}
-void CAimProto::snac_email_search_results(SNAC &snac)//family 0x000A
-{
- if (snac.subcmp(0x0003)) { // Found some buddies
- PROTOSEARCHRESULT psr = { 0 };
- psr.cbSize = sizeof(psr);
-
- unsigned short offset = 0;
- while (offset < snac.len()) { // Loop through all the TLVs and pull out the buddy name
- TLV tlv(snac.val(offset));
- offset += TLV_HEADER_SIZE;
- psr.id.w = (wchar_t*)tlv.dup();
- offset += tlv.len();
- ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)1, (LPARAM)& psr);
- mir_free(psr.nick.w);
- }
- ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)1, 0);
- }
- else // If no match, stop the search.
- CAimProto::ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)1, 0);
-}
-
-void CAimProto::snac_chatnav_info_response(SNAC &snac, HNETLIBCONN hServerConn, unsigned short &seqno)//family 0x000D
-{
- if (snac.subcmp(0x0009)) {
- debugLogA("Chat Info Received");
-
- unsigned short offset_info = 0;
- while (offset_info < snac.len()) { // Loop through all the TLVs and pull out the buddy name
- TLV info_tlv(snac.val(offset_info));
- if (info_tlv.cmp(0x0001)) // Redirect
- {
- }
- else if (info_tlv.cmp(0x0002)) { // Max Concurrent Rooms (usually 10)
- // This typecasting pointer to number and as such bogus
- MAX_ROOMS = info_tlv.ubyte();
-
- aim_chatnav_ready(hServerConn, seqno);
- SetEvent(m_hChatNavEvent);
- }
- else if (info_tlv.cmp(0x0003)) // Exchanges
- {
- }
- else if (info_tlv.cmp(0x0004)) { // Room Info
- // Main TLV info
- unsigned short exchange = 0;
- unsigned short cookie_len = 0;
- char* cookie = nullptr;
- unsigned short instance = 0;
- unsigned short num_tlv = 0;
- unsigned short tlv_offset = 0;
-
- exchange = info_tlv.ushort(0); // Exchange
- cookie_len = info_tlv.ubyte(2); // Cookie Length
- cookie = info_tlv.part(3, cookie_len); // Cookie String
- instance = info_tlv.ushort(3 + cookie_len); // Instance
- num_tlv = info_tlv.ushort(6 + cookie_len); // Number of TLVs
- tlv_offset = 8 + cookie_len; // We're looking at any remaining TLVs
-
- char* name = nullptr;
- for (int i = 0; i < num_tlv; i++) // Loop through all the TLVs
- {
- TLV tlv(info_tlv.val() + tlv_offset);
-
- // TLV List
- if (tlv.cmp(0x00d3))
- name = tlv.dup();
- tlv_offset += TLV_HEADER_SIZE + tlv.len();
- }
-
- chat_list_item *item = find_chat_by_id(name);
- if (item == nullptr) {
- item = new chat_list_item(name, cookie, exchange, instance);
- m_chat_rooms.insert(item);
-
- //Join the actual room
- aim_chat_join_room(m_hServerConn, m_seqno, cookie, exchange, instance, item->cid);
- }
-
- mir_free(name);
- mir_free(cookie);
- }
- offset_info += TLV_HEADER_SIZE + info_tlv.len();
- }
- }
-}
-void CAimProto::snac_chat_joined_left_users(SNAC &snac, chat_list_item* item)//family 0x000E
-{
- // Handles both joining and leaving users.
- if (snac.subcmp(0x0003) || snac.subcmp(0x0004)) {
- int offset = 0;
- while (offset < snac.len()) {
- int sn_len = snac.ubyte(offset);
- char* sn = snac.part(offset + 1, sn_len); // Most important part (screenname)
-
- chat_event(item->id, sn, snac.subcmp(0x0003) ? GC_EVENT_JOIN : GC_EVENT_PART);
-
- mir_free(sn);
-
- int num_tlv = snac.ushort(offset + 3 + sn_len);
- offset += 5 + sn_len; // We're looking at any remaining TLVs
-
- for (int i = 0; i < num_tlv; i++) { // Loop through all the TLVs
- TLV tlv(snac.val(offset));
- offset += TLV_HEADER_SIZE + tlv.len();
- }
- }
- }
-}
-void CAimProto::snac_chat_received_message(SNAC &snac, chat_list_item* item)//family 0x000E
-{
- if (snac.subcmp(0x0006)) {
- wchar_t* message = nullptr;
- char* sn = nullptr;
-
- // unsigned long cookie = snac.ulong(0);
- // unsigned short channel = snac.ushort(8);
-
- int tlv_offset = 10;
- while (tlv_offset < snac.len()) {
- TLV tlv(snac.val(tlv_offset));
-
- if (tlv.cmp(0x0003)) { // Sender information
- int sn_len = tlv.ubyte(0);
- sn = tlv.part(1, sn_len);
- }
- else if (tlv.cmp(0x0001)) // Public/Whisper flag
- {
- }
- else if (tlv.cmp(0x0005)) { // Message information
- bool uni = false;
- bool utf = false;
-
- int offset = 0;
- while (offset < tlv.len()) {
- TLV msg_tlv(tlv.val() + offset);
-
- // TLV List
- if (msg_tlv.cmp(0x0001)) {
- if (uni) {
- char* msg = msg_tlv.dupw();
- html_decode(msg);
- message = mir_utf8decodeW(msg);
- mir_free(msg);
- }
- else if (utf) {
- char* msg = msg_tlv.dup();
- html_decode(msg);
- message = mir_utf8decodeW(msg);
- mir_free(msg);
- }
- else {
- char* msg = msg_tlv.dup();
- html_decode(msg);
- message = mir_a2u(msg);
- mir_free(msg);
- }
- }
- else if (msg_tlv.cmp(0x0002)) {
- char* enc = msg_tlv.dup();
- uni = strstr(enc, "unicode-2-0") != nullptr;
- utf = strstr(enc, "utf-8") != nullptr;
- mir_free(enc);
- }
-
- offset += TLV_HEADER_SIZE + msg_tlv.len();
- }
- }
-
- tlv_offset += TLV_HEADER_SIZE + tlv.len();
- }
-
- chat_event(item->id, sn, GC_EVENT_MESSAGE, message);
-
- mir_free(message);
- mir_free(sn);
- }
-}
-
-void CAimProto::snac_admin_rate_limitations(SNAC &snac, HNETLIBCONN hServerConn, unsigned short &seqno)// family 0x0001
-{
- if (snac.subcmp(0x0007)) {
- aim_accept_rates(hServerConn, seqno);
- aim_admin_ready(hServerConn, seqno);
- SetEvent(m_hAdminEvent);
- }
-}
-
-void CAimProto::snac_admin_account_infomod(SNAC &snac) //family 0x0007
-{
- if (snac.subcmp(0x0003) || snac.subcmp(0x0005)) { // Handles info response and modification response
- bool err = false;
- bool req_email = false;
-
- WORD num_tlv = snac.ushort(2); // Number of TLVs
-
- char *sn = nullptr; // Screen Name
- char *email = nullptr; // Email address
-
- unsigned short offset = 0;
- for (int i = 0; i < num_tlv; i++) // Loop through all the TLVs
- {
- TLV tlv(snac.val(4 + offset));
-
- // TLV List
- if (tlv.cmp(0x0001))
- sn = tlv.dup();
-
- if (tlv.cmp(0x0011)) {
- req_email = true;
- email = tlv.dup();
- }
-
- if (tlv.cmp(0x0008)) { // Handles any problems when requesting/changing information
- err = true;
- admin_error(tlv.ushort());
- }
-
- offset += TLV_HEADER_SIZE + tlv.len();
- }
-
- if (snac.subcmp(0x0003) && !err) { // Requested info
- // Display messages
- if (email)
- setString(AIM_KEY_EM, email); // Save our email for future reference.
- if (sn)
- setString(AIM_KEY_SN, sn); // Update the database to reflect the formatted name.
- ProtoBroadcastAck(NULL, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE)1, 0);
-
- }
- else if (snac.subcmp(0x0005) && !err) { // Changed info
- // Display messages
- if (email && req_email) // We requested to change the email
- ShowPopup(LPGEN("A confirmation message has been sent to the new email address. Please follow its instructions."), 0);
- else if (sn) {
- setString(AIM_KEY_SN, sn); // Update the database to reflect the formatted name.
- //ShowPopup("Your Screen Name has been successfully formatted.", 0);
- }
- }
- mir_free(sn);
- mir_free(email);
- }
-}
-
-void CAimProto::snac_admin_account_confirm(SNAC &snac)//family 0x0007
-{
- if (snac.subcmp(0x0007)) {
- unsigned short status = 0;
-
- status = snac.ushort();
-
- switch (status) {
- case 0:
- ShowPopup(LPGEN("A confirmation message has been sent to your email address. Please follow its instructions."), 0);
- break;
-
- case 0x13:
- ShowPopup(LPGEN("Unable to confirm at this time. Please try again later."), 0);
- break;
-
- case 0x1e:
- ShowPopup(LPGEN("Your account has already been confirmed."), 0);
- break;
-
- case 0x23:
- ShowPopup(LPGEN("Can't start the confirmation procedure."), 0);
- break;
- }
- }
-}
diff --git a/protocols/AimOscar/src/services.cpp b/protocols/AimOscar/src/services.cpp deleted file mode 100644 index 1012a1c611..0000000000 --- a/protocols/AimOscar/src/services.cpp +++ /dev/null @@ -1,478 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2012 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 "stdafx.h"
-
-INT_PTR CAimProto::GetMyAwayMsg(WPARAM wParam, LPARAM lParam)
-{
- char** msgptr = get_status_msg_loc(wParam ? wParam : m_iStatus);
- if (msgptr == nullptr) return 0;
-
- return (lParam & SGMA_UNICODE) ? (INT_PTR)mir_utf8decodeW(*msgptr) : (INT_PTR)mir_utf8decodeA(*msgptr);
-}
-
-int CAimProto::OnIdleChanged(WPARAM, LPARAM lParam)
-{
- if (m_state != 1) {
- m_idle = 0;
- return 0;
- }
-
- if (m_instantidle) //ignore- we are instant idling at the moment
- return 0;
-
- bool bIdle = (lParam & IDF_ISIDLE) != 0;
- bool bPrivacy = (lParam & IDF_PRIVACY) != 0;
-
- if (bPrivacy && m_idle) {
- aim_set_idle(m_hServerConn, m_seqno, 0);
- return 0;
- }
-
- if (bPrivacy)
- return 0;
-
- if (bIdle) //don't want to change idle time if we are already idle
- {
- MIRANDA_IDLE_INFO mii = { sizeof(mii) };
- CallService(MS_IDLE_GETIDLEINFO, 0, (LPARAM)&mii);
-
- m_idle = 1;
- aim_set_idle(m_hServerConn, m_seqno, mii.idleTime * 60);
- }
- else aim_set_idle(m_hServerConn, m_seqno, 0);
-
- return 0;
-}
-
-int CAimProto::OnWindowEvent(WPARAM, LPARAM lParam)
-{
- MessageWindowEventData* msgEvData = (MessageWindowEventData*)lParam;
-
- if (msgEvData->uType == MSG_WINDOW_EVT_CLOSE) {
- if (m_state != 1 || !is_my_contact(msgEvData->hContact))
- return 0;
-
- if (getWord(msgEvData->hContact, AIM_KEY_ST, ID_STATUS_OFFLINE) == ID_STATUS_ONTHEPHONE)
- return 0;
-
- DBVARIANT dbv;
- if (!getBool(msgEvData->hContact, AIM_KEY_BLS, false) && !getString(msgEvData->hContact, AIM_KEY_SN, &dbv)) {
- if (_stricmp(dbv.pszVal, SYSTEM_BUDDY))
- aim_typing_notification(m_hServerConn, m_seqno, dbv.pszVal, 0x000f);
- db_free(&dbv);
- }
- }
- return 0;
-}
-
-INT_PTR CAimProto::GetProfile(WPARAM wParam, LPARAM)
-{
- if (m_state != 1)
- return 0;
-
- DBVARIANT dbv;
- if (!getString(wParam, AIM_KEY_SN, &dbv)) {
- m_request_HTML_profile = 1;
- aim_query_profile(m_hServerConn, m_seqno, dbv.pszVal);
- db_free(&dbv);
- }
- return 0;
-}
-
-INT_PTR CAimProto::GetHTMLAwayMsg(WPARAM wParam, LPARAM)
-{
- if (m_state != 1)
- return 0;
-
- DBVARIANT dbv;
- if (!getString(wParam, AIM_KEY_SN, &dbv)) {
- m_request_away_message = 1;
- aim_query_away_message(m_hServerConn, m_seqno, dbv.pszVal);
- }
- return 0;
-}
-
-int CAimProto::OnDbSettingChanged(WPARAM hContact, LPARAM lParam)
-{
- DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING*)lParam;
-
- if (strcmp(cws->szModule, MOD_KEY_CL) == 0 && m_state == 1 && hContact) {
- if (strcmp(cws->szSetting, AIM_KEY_NL) == 0) {
- if (cws->value.type == DBVT_DELETED) {
- DBVARIANT dbv;
- if (!db_get_utf(hContact, MOD_KEY_CL, OTH_KEY_GP, &dbv) && dbv.pszVal[0]) {
- add_contact_to_group(hContact, dbv.pszVal);
- db_free(&dbv);
- }
- else
- add_contact_to_group(hContact, AIM_DEFAULT_GROUP);
- }
- }
- else if (strcmp(cws->szSetting, "MyHandle") == 0) {
- char *name;
- switch (cws->value.type) {
- case DBVT_DELETED:
- set_local_nick(hContact, nullptr, nullptr);
- break;
-
- case DBVT_ASCIIZ:
- name = mir_utf8encode(cws->value.pszVal);
- set_local_nick(hContact, name, nullptr);
- mir_free(name);
- break;
-
- case DBVT_UTF8:
- set_local_nick(hContact, cws->value.pszVal, nullptr);
- break;
-
- case DBVT_WCHAR:
- name = mir_utf8encodeW(cws->value.pwszVal);
- set_local_nick(hContact, name, nullptr);
- mir_free(name);
- break;
- }
- }
- }
-
- return 0;
-}
-
-int CAimProto::OnContactDeleted(WPARAM hContact, LPARAM)
-{
- if (m_state != 1)
- return 0;
-
- if (db_get_b(hContact, MOD_KEY_CL, AIM_KEY_NL, 0))
- return 0;
-
- DBVARIANT dbv;
- if (!getString(hContact, AIM_KEY_SN, &dbv)) {
- for (int i = 1;; ++i) {
- unsigned short item_id = getBuddyId(hContact, i);
- if (item_id == 0) break;
-
- unsigned short group_id = getGroupId(hContact, i);
- if (group_id) {
- bool is_not_in_list = getBool(hContact, AIM_KEY_NIL, false);
- aim_ssi_update(m_hServerConn, m_seqno, true);
- aim_delete_contact(m_hServerConn, m_seqno, dbv.pszVal, item_id, group_id, 0, is_not_in_list);
- char *group = m_group_list.find_name(group_id);
- update_server_group(group, group_id);
- aim_ssi_update(m_hServerConn, m_seqno, false);
- }
- }
- db_free(&dbv);
- }
- return 0;
-}
-
-
-int CAimProto::OnGroupChange(WPARAM hContact, LPARAM lParam)
-{
- if (m_state != 1 || !getByte(AIM_KEY_MG, 1))
- return 0;
-
- CLISTGROUPCHANGE *grpchg = (CLISTGROUPCHANGE*)lParam;
-
- if (hContact == NULL) {
- if (grpchg->pszNewName == nullptr && grpchg->pszOldName != nullptr) {
- T2Utf szOldName(grpchg->pszOldName);
- unsigned short group_id = m_group_list.find_id(szOldName);
- if (group_id) {
- aim_delete_contact(m_hServerConn, m_seqno, szOldName, 0, group_id, 1, false);
- m_group_list.remove_by_id(group_id);
- update_server_group("", 0);
- }
- }
- else if (grpchg->pszNewName != nullptr && grpchg->pszOldName != nullptr) {
- unsigned short group_id = m_group_list.find_id(T2Utf(grpchg->pszOldName));
- if (group_id)
- update_server_group(T2Utf(grpchg->pszNewName), group_id);
- }
- }
- else {
- if (is_my_contact(hContact) && getBuddyId(hContact, 1) && !db_get_b(hContact, MOD_KEY_CL, AIM_KEY_NL, 0)) {
- if (grpchg->pszNewName)
- add_contact_to_group(hContact, T2Utf(grpchg->pszNewName));
- else
- add_contact_to_group(hContact, AIM_DEFAULT_GROUP);
- }
- }
- return 0;
-}
-
-INT_PTR CAimProto::AddToServerList(WPARAM hContact, LPARAM)
-{
- if (m_state != 1)
- return 0;
-
- DBVARIANT dbv;
- if (!db_get_utf(hContact, MOD_KEY_CL, OTH_KEY_GP, &dbv) && dbv.pszVal[0]) {
- add_contact_to_group(hContact, dbv.pszVal);
- db_free(&dbv);
- }
- else add_contact_to_group(hContact, AIM_DEFAULT_GROUP);
- return 0;
-}
-
-INT_PTR CAimProto::BlockBuddy(WPARAM hContact, LPARAM)
-{
- if (m_state != 1)
- return 0;
-
- unsigned short item_id;
- DBVARIANT dbv;
- if (getString(hContact, AIM_KEY_SN, &dbv))
- return 0;
-
- switch (m_pd_mode) {
- case 1:
- m_pd_mode = 4;
- aim_set_pd_info(m_hServerConn, m_seqno);
-
- case 4:
- item_id = m_block_list.find_id(dbv.pszVal);
- if (item_id != 0) {
- m_block_list.remove_by_id(item_id);
- aim_delete_contact(m_hServerConn, m_seqno, dbv.pszVal, item_id, 0, 3, false);
- }
- else {
- item_id = m_block_list.add(dbv.pszVal);
- aim_add_contact(m_hServerConn, m_seqno, dbv.pszVal, item_id, 0, 3, nullptr);
- }
- break;
-
- case 2:
- m_pd_mode = 3;
- aim_set_pd_info(m_hServerConn, m_seqno);
-
- case 3:
- item_id = m_allow_list.find_id(dbv.pszVal);
- if (item_id != 0) {
- m_allow_list.remove_by_id(item_id);
- aim_delete_contact(m_hServerConn, m_seqno, dbv.pszVal, item_id, 0, 2, false);
- }
- else {
- item_id = m_allow_list.add(dbv.pszVal);
- aim_add_contact(m_hServerConn, m_seqno, dbv.pszVal, item_id, 0, 2);
- }
- break;
- }
- db_free(&dbv);
-
- return 0;
-}
-
-INT_PTR CAimProto::JoinChatUI(WPARAM, LPARAM)
-{
- DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_CHAT), nullptr, join_chat_dialog, LPARAM(this));
- return 0;
-}
-
-INT_PTR CAimProto::OnJoinChat(WPARAM hContact, LPARAM)
-{
- if (m_state != 1)
- return 0;
-
- DBVARIANT dbv;
- if (!getString(hContact, "ChatRoomID", &dbv)) {
- chatnav_param* par = new chatnav_param(dbv.pszVal, getWord(hContact, "Exchange", 4));
- ForkThread(&CAimProto::chatnav_request_thread, par);
- db_free(&dbv);
- }
- return 0;
-}
-
-INT_PTR CAimProto::OnLeaveChat(WPARAM wParam, LPARAM)
-{
- if (m_state != 1)
- return 0;
-
- MCONTACT hContact = wParam;
-
- DBVARIANT dbv;
- if (!getString(hContact, "ChatRoomID", &dbv)) {
- chat_leave(dbv.pszVal);
- db_free(&dbv);
- }
- return 0;
-}
-
-INT_PTR CAimProto::InstantIdle(WPARAM, LPARAM)
-{
- DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_IDLE), nullptr, instant_idle_dialog, LPARAM(this));
- return 0;
-}
-
-INT_PTR CAimProto::ManageAccount(WPARAM, LPARAM)
-{
- ShellExecuteA(nullptr, "open", "https://my.screenname.aol.com", nullptr, nullptr, SW_SHOW);
- return 0;
-}
-
-INT_PTR CAimProto::GetAvatarInfo(WPARAM wParam, LPARAM lParam)
-{
- PROTO_AVATAR_INFORMATION *pai = (PROTO_AVATAR_INFORMATION*)lParam;
-
- pai->filename[0] = 0;
- pai->format = PA_FORMAT_UNKNOWN;
-
- if (getByte(AIM_KEY_DA, 0))
- return GAIR_NOAVATAR;
-
- switch (get_avatar_filename(pai->hContact, pai->filename, _countof(pai->filename), nullptr)) {
- case GAIR_SUCCESS:
- if (!(wParam & GAIF_FORCE) || m_state != 1)
- return GAIR_SUCCESS;
-
- case GAIR_WAITFOR:
- pai->format = ProtoGetAvatarFormat(pai->filename);
- break;
-
- default:
- return GAIR_NOAVATAR;
- }
-
- if (m_state == 1) {
- ForkThread(&CAimProto::avatar_request_thread, (void*)pai->hContact);
- return GAIR_WAITFOR;
- }
-
- return GAIR_NOAVATAR;
-}
-
-INT_PTR CAimProto::GetAvatarCaps(WPARAM wParam, LPARAM lParam)
-{
- int res = 0;
-
- switch (wParam) {
- case AF_MAXSIZE:
- ((POINT*)lParam)->x = 100;
- ((POINT*)lParam)->y = 100;
- break;
-
- case AF_MAXFILESIZE:
- res = 11264;
- break;
-
- case AF_PROPORTION:
- res = PIP_SQUARE;
- break;
-
- case AF_FORMATSUPPORTED:
- res = (lParam == PA_FORMAT_JPEG || lParam == PA_FORMAT_GIF || lParam == PA_FORMAT_BMP);
- break;
-
- case AF_ENABLED:
- case AF_DONTNEEDDELAYS:
- case AF_FETCHIFPROTONOTVISIBLE:
- case AF_FETCHIFCONTACTOFFLINE:
- res = 1;
- break;
- }
-
- return res;
-}
-
-INT_PTR CAimProto::GetAvatar(WPARAM wParam, LPARAM lParam)
-{
- wchar_t* buf = (wchar_t*)wParam;
- size_t size = (size_t)lParam;
- if (buf == nullptr || size <= 0)
- return -1;
-
- PROTO_AVATAR_INFORMATION ai = { 0 };
- if (GetAvatarInfo(0, (LPARAM)&ai) == GAIR_SUCCESS) {
- wcsncpy_s(buf, size, ai.filename, _TRUNCATE);
- return 0;
- }
-
- return -1;
-}
-
-INT_PTR CAimProto::SetAvatar(WPARAM, LPARAM lParam)
-{
- wchar_t *szFileName = (wchar_t*)lParam;
-
- if (m_state != 1)
- return 1;
-
- if (szFileName == nullptr) {
- aim_ssi_update(m_hServerConn, m_seqno, true);
- aim_delete_avatar_hash(m_hServerConn, m_seqno, 1, 1, m_avatar_id_sm);
- aim_delete_avatar_hash(m_hServerConn, m_seqno, 1, 12, m_avatar_id_lg);
- aim_ssi_update(m_hServerConn, m_seqno, false);
-
- avatar_request_handler(NULL, nullptr, 0);
- }
- else {
- char hash[16], hash1[16], *data, *data1 = nullptr;
- unsigned short size, size1 = 0;
-
- if (!get_avatar_hash(szFileName, hash, &data, size)) {
- mir_free(hash);
- return 1;
- }
-
- rescale_image(data, size, data1, size1);
-
- if (size1) {
- mir_md5_state_t state;
- mir_md5_init(&state);
- mir_md5_append(&state, (unsigned char*)data1, size1);
- mir_md5_finish(&state, (unsigned char*)hash1);
-
- mir_free(m_hash_lg); m_hash_lg = bytes_to_string(hash, sizeof(hash));
- mir_free(m_hash_sm); m_hash_sm = bytes_to_string(hash1, sizeof(hash1));
-
- aim_ssi_update(m_hServerConn, m_seqno, true);
- aim_set_avatar_hash(m_hServerConn, m_seqno, 1, 1, m_avatar_id_sm, 16, hash1);
- aim_set_avatar_hash(m_hServerConn, m_seqno, 1, 12, m_avatar_id_lg, 16, hash);
- aim_ssi_update(m_hServerConn, m_seqno, false);
- }
- else {
- mir_free(m_hash_lg); m_hash_lg = nullptr;
- mir_free(m_hash_sm); m_hash_sm = bytes_to_string(hash, sizeof(hash1));
-
- aim_ssi_update(m_hServerConn, m_seqno, true);
- aim_set_avatar_hash(m_hServerConn, m_seqno, 1, 1, m_avatar_id_sm, 16, hash);
- aim_delete_avatar_hash(m_hServerConn, m_seqno, 1, 12, m_avatar_id_lg);
- aim_ssi_update(m_hServerConn, m_seqno, false);
- }
-
- avatar_request_handler(NULL, nullptr, 0);
-
- avatar_up_req *req = new avatar_up_req(data, size, data1, size1);
- ForkThread(&CAimProto::avatar_upload_thread, req);
-
- wchar_t tFileName[MAX_PATH];
- wchar_t *ext = wcsrchr(szFileName, '.');
- get_avatar_filename(NULL, tFileName, _countof(tFileName), ext);
- int fileId = _wopen(tFileName, _O_CREAT | _O_TRUNC | _O_WRONLY | O_BINARY, _S_IREAD | _S_IWRITE);
- if (fileId < 0) {
- char errmsg[512];
- mir_snprintf(errmsg, "Cannot store avatar. File '%s' could not be created/overwritten", tFileName);
- ShowPopup(errmsg, ERROR_POPUP);
- return 1;
- }
- _write(fileId, data, size);
- _close(fileId);
- }
- return 0;
-}
diff --git a/protocols/AimOscar/src/snac.cpp b/protocols/AimOscar/src/snac.cpp deleted file mode 100644 index 0dd1c12d3f..0000000000 --- a/protocols/AimOscar/src/snac.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2009 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 "stdafx.h"
-
-SNAC::SNAC(char* buf,unsigned short length)
-{
- service_=_htons((*(unsigned short*)&buf[0]));
- subgroup_=_htons((*(unsigned short*)&buf[2]));
- flags_=_htons((*(unsigned short*)&buf[4]));
- idh_=_htons((*(unsigned short*)&buf[6]));
- id_=_htons((*(unsigned short*)&buf[8]));
- value_=&buf[SNAC_SIZE];
- length_=length;
-}
-int SNAC::cmp(unsigned short service)
-{
- if (service_==service)
- return 1;
- else
- return 0;
-}
-int SNAC::subcmp(unsigned short subgroup)
-{
- if (subgroup_==subgroup)
- return 1;
- else
- return 0;
-}
-unsigned short SNAC::ushort(int pos)
-{
- return _htons(*(unsigned short*)&value_[pos]);
-}
-unsigned long SNAC::ulong(int pos)
-{
- return _htonl(*(unsigned long*)&value_[pos]);
-}
-unsigned char SNAC::ubyte(int pos)
-{
- return value_[pos];
-}
-char* SNAC::part(int pos, int length)
-{
- char* value = (char*)mir_alloc(length+1);
- memcpy(value, &value_[pos], length);
- value[length] = '\0';
- return value;
-}
diff --git a/protocols/AimOscar/src/snac.h b/protocols/AimOscar/src/snac.h deleted file mode 100644 index 5c97462f22..0000000000 --- a/protocols/AimOscar/src/snac.h +++ /dev/null @@ -1,49 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2009 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 SNAC_H
-#define SNAC_H
-
-#define SNAC_SIZE 10
-
-class SNAC
-{
- unsigned short service_;
- unsigned short subgroup_;
- unsigned short length_;
- unsigned short flags_;
- unsigned short idh_;
- unsigned short id_;
- char *value_;
-
-public:
- SNAC(char *buf, unsigned short length);
- int cmp(unsigned short service);
- int subcmp(unsigned short subgroup);
- unsigned short ushort(int pos = 0);
- unsigned long ulong(int pos = 0);
- unsigned char ubyte(int pos = 0);
- char* part(int pos, int length);
- char* val(int pos = 0) { return &value_[pos]; }
- unsigned short len(void) { return length_; }
- unsigned short flags(void) { return flags_; }
- unsigned short id(void) { return id_; }
- unsigned short idh(void) { return idh_; }
-};
-
-#endif
diff --git a/protocols/AimOscar/src/stdafx.cxx b/protocols/AimOscar/src/stdafx.cxx deleted file mode 100644 index b05ed73bc5..0000000000 --- a/protocols/AimOscar/src/stdafx.cxx +++ /dev/null @@ -1,18 +0,0 @@ -/*
-Copyright (C) 2012-17 Miranda NG project (https://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 "stdafx.h"
\ No newline at end of file diff --git a/protocols/AimOscar/src/stdafx.h b/protocols/AimOscar/src/stdafx.h deleted file mode 100755 index 42beead6a0..0000000000 --- a/protocols/AimOscar/src/stdafx.h +++ /dev/null @@ -1,326 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2012 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 AIM_H
-#define AIM_H
-
-//System includes
-#include <windows.h>
-#include <fcntl.h>
-#include <io.h>
-#include <richedit.h>
-#include <sys/stat.h>
-#include <time.h>
-#include <malloc.h>
-#include <Uxtheme.h>
-
-//Miranda NG includes
-#include <msapi/vssym32.h>
-#include <newpluginapi.h>
-#include <m_avatars.h>
-#include <m_button.h>
-#include <m_chat.h>
-#include <m_clist.h>
-#include <m_database.h>
-#include <m_history.h>
-#include <m_idle.h>
-#include <m_langpack.h>
-#include <m_message.h>
-#include <m_netlib.h>
-#include <m_options.h>
-#include <m_popup.h>
-#include <m_userinfo.h>
-#include <m_icolib.h>
-#include <m_imgsrvc.h>
-#include <win2k.h>
-#include <m_extraicons.h>
-#include <m_protoint.h>
-#include <m_xml.h>
-
-#include <m_folders.h>
-#include <m_assocmgr.h>
-
-//rest of includes
-#include "avatars.h"
-#include "utility.h"
-#include "chat.h"
-#include "direct_connect.h"
-#include "conv.h"
-#include "file.h"
-#include "flap.h"
-#include "links.h"
-#include "snac.h"
-#include "tlv.h"
-#include "packets.h"
-#include "proxy.h"
-#include "resource.h"
-#include "proto.h"
-#include "theme.h"
-#include "ui.h"
-#include "version.h"
-
-// Protocol limits
-#define MAX_SCREEN_NAME_LENGTH 97
-#define MAX_GROUP_NAME_LENGTH 48
-#define MAX_NICKNAME_LENGTH 64
-#define MAX_MESSAGE_LENGTH 3978
-#define MAX_STATUS_MESSAGE_LENGTH 251
-#define MAX_AWAY_MESSAGE_LENGTH 4096
-#define MAX_ICON_SIZE 7168
-
-// ICBM parameter flags
-#define ICBM_CHANNEL_MSGS_ALLOWED 0x00000001
-#define ICBM_MISSED_CALLS_ENABLED 0x00000002
-#define ICBM_EVENTS_ALLOWED 0x00000008
-#define ICBM_SMS_SUPPORTED 0x00000010
-#define ICBM_OFFLINE_MSGS_ALLOWED 0x00000100
-
-// SSI preferences
-#define SHOW_IDLE 0x00000400
-#define SHOW_RECENT_BUDDIES 0x00020000
-#define SHOW_TYPING 0x00400000
-
-//Extended Status Icon Numbers
-#define ACCOUNT_TYPE_UNCONFIRMED 1
-#define ACCOUNT_TYPE_CONFIRMED 2
-#define ACCOUNT_TYPE_ICQ 3
-#define ACCOUNT_TYPE_AOL 4
-#define ACCOUNT_TYPE_ADMIN 5
-#define EXTENDED_STATUS_BOT 1
-#define EXTENDED_STATUS_HIPTOP 2
-
-//Popup flags
-#define MAIL_POPUP 0x04
-#define ERROR_POPUP 0x08
-#define TCHAR_POPUP 0x10
-
-//Main Option Window Keys
-#define AIM_KEY_SN "SN"
-#define AIM_KEY_NK "Nick"
-#define AIM_KEY_PW "Password"
-#define AIM_KEY_HN "loginhost"
-#define AIM_KEY_PN "loginport"
-#define AIM_KEY_DC "DelConf"//delivery confirmation
-#define AIM_KEY_FP "ForceProxyTransfer"
-#define AIM_KEY_HF "HiptopFake"
-#define AIM_KEY_AT "DisableATIcons"
-#define AIM_KEY_ES "DisableESIcons"
-#define AIM_KEY_DM "DisableModeMsg"
-#define AIM_KEY_FI "FormatIncoming"//html->bbcodes
-#define AIM_KEY_FO "FormatOutgoing"//bbcodes->html
-#define AIM_KEY_II "InstantIdle"
-#define AIM_KEY_IIT "InstantIdleTS"
-#define AIM_KEY_CM "CheckMail"
-#define AIM_KEY_MG "ManageGroups"
-#define AIM_KEY_DA "DisableAvatars"
-#define AIM_KEY_DSSL "DisableSSL"
-#define AIM_KEY_CLIENTLOGIN "UseClientLogin"
-#define AIM_KEY_FSC "ForceSingleClient"
-
-#define OTH_KEY_SM "StatusMsg"
-#define OTH_KEY_GP "Group"
-//Module Name Key
-#define MOD_KEY_CL "CList"
-//Settings Keys
-#define AIM_KEY_PR "Profile"
-#define AIM_KEY_LA "LastAwayChange"
-//Contact Keys
-#define AIM_KEY_BI "BuddyId"
-#define AIM_KEY_GI "GroupId"
-#define AIM_KEY_ST "Status"
-#define AIM_KEY_IT "IdleTS"
-#define AIM_KEY_OT "LogonTS"
-#define AIM_KEY_MS "MemberTS"
-#define AIM_KEY_AC "AccType"//account type
-#define AIM_KEY_ET "ESType"//Extended Status type
-#define AIM_KEY_MV "MirVer"
-#define AIM_KEY_US "Utf8Support"
-#define AIM_KEY_NL "NotOnList"
-#define AIM_KEY_LM "LastMessage"
-#define AIM_KEY_AH "AvatarHash"
-#define AIM_KEY_AHT "AvatarType"
-#define AIM_KEY_EM "e-mail"
-#define AIM_KEY_LV "LastVer"
-#define AIM_KEY_TIS "TotalIMsSent"
-#define AIM_KEY_TIR "TotalIMsReceived"
-#define AIM_KEY_TAM "TotalAwayMessages"
-#define AIM_KEY_TTO "TotalTimeOnline"
-#define AIM_KEY_BLS "IsBlast"
-#define AIM_KEY_NIL "IsNotInList"
-
-#define AIM_LOGIN_URL "https://api.screenname.aol.com/auth/clientLogin"
-#define AIM_SESSION_URL "https://api.oscar.aol.com/aim/startOSCARSession"
-#define AIM_DEFAULT_CLIENT_KEY "ma15d7JTxbmVG-RP" //this one from libpurple, i am not able to create one, sorry guys
-#define AIM_DEFAULT_DISTID "1553" //this one from libpurple, i am not able to create one, sorry guys
-
-
-
-#define AIM_DEFAULT_SERVER "login.oscar.aol.com"
-#define AIM_PROXY_SERVER "ars.oscar.aol.com"
-#define AIM_DEFAULT_PORT 5190
-
-//Some Defaults for various things
-#define DEFAULT_KEEPALIVE_TIMER 39 // secs
-#define DEFAULT_GRACE_PERIOD 60
-#define AIM_DEFAULT_GROUP "miranda merged"
-#define SYSTEM_BUDDY "aolsystemmsg"
-#define DEFAULT_AWAY_MSG "I am away from my computer right now."
-//Md5 Roasting stuff
-#define AIM_MD5_STRING "AOL Instant Messenger (SM)"
-#define MD5_HASH_LENGTH 16
-
-//Aim Version Stuff
-#define AIM_CLIENT_MAJOR_VERSION 0x0005
-#define AIM_CLIENT_MINOR_VERSION 0x0001
-#define AIM_CLIENT_LESSER_VERSION 0x0000
-#define AIM_CLIENT_BUILD_NUMBER 0x0bdc
-#define AIM_CLIENT_ID_NUMBER 0x0109
-#define AIM_CLIENT_DISTRIBUTION_NUMBER 0x0611
-
-#define AIM_LANGUAGE "en"
-#define AIM_COUNTRY "us"
-#define AIM_MSG_TYPE "text/x-aolrtf; charset=\"us-ascii\""
-#define AIM_MSG_TYPE_UNICODE "text/x-aolrtf; charset=\"unicode-2-0\""
-#define AIM_TOOL_VERSION "\x01\x10\x18\xf1"
-
-//Supported Clients
-#define CLIENT_UNKNOWN "?"
-#define CLIENT_AIM5 "AIM 5.x"
-#define CLIENT_AIM4 "AIM 4.x"
-#define CLIENT_AIMEXPRESS5 "AIM Express 5"
-#define CLIENT_AIMEXPRESS6 "AIM Express 6"
-#define CLIENT_AIMEXPRESS7 "AIM Express 7"
-#define CLIENT_ICQ "ICQ"
-#define CLIENT_AIM_TRITON "AIM Triton"
-#define CLIENT_AIM6_1 "AIM 6.1"
-#define CLIENT_AIM6_5 "AIM 6.5"
-#define CLIENT_AIM6_8 "AIM 6.8"
-#define CLIENT_AIM6_9 "AIM 6.9"
-#define CLIENT_AIM7_0 "AIM 7.0"
-#define CLIENT_AIMTOC "AIM TOC"
-#define CLIENT_BOT "AIM Bot"
-#define CLIENT_GAIM "Gaim"
-#define CLIENT_PURPLE "Purple"
-#define CLIENT_ADIUM "Adium X"
-#define CLIENT_GPRS "GPRS"
-#define CLIENT_ICHAT "iChat"
-#define CLIENT_IM2 "IM2"
-#define CLIENT_KOPETE "Kopete"
-#define CLIENT_MEEBO "Meebo"
-#define CLIENT_DIGSBY "Digsby"
-#define CLIENT_BEEJIVE "beejive"
-#define CLIENT_MICQ "mICQ"
-#define CLIENT_AIMOSCAR "Miranda IM %d.%d.%d.%d (AIM v%d.%d.%d.%d)"
-#define CLIENT_OSCARJ "Miranda IM %d.%d.%d.%d%s (ICQ v%d.%d.%d.%d%s)"
-#define CLIENT_OSCARSN "Miranda IM %d.%d.%d.%d%s (ICQ S!N v%d.%d.%d.%d%s)%s"
-#define CLIENT_OSCARPL "Miranda IM %d.%d.%d.%d%s (ICQ Plus v%d.%d.%d.%d%s)%s"
-#define CLIENT_NAIM "naim"
-#define CLIENT_QIP "qip"
-#define CLIENT_SIM "SIM"
-#define CLIENT_SMS "SMS"
-#define CLIENT_TERRAIM "TerraIM"
-#define CLIENT_TRILLIAN_PRO "Trillian Pro"
-#define CLIENT_TRILLIAN "Trillian"
-#define CLIENT_TRILLIAN_ASTRA "Trillian Astra"
-#define CLIENT_BLAST "Blast Group"
-
-//Aim Caps
-#define AIM_CAPS_LENGTH 16
-
-// Official
-#define AIM_CAP_SHORT_CAPS "\x09\x46\x00\x00\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_SECURE_IM "\x09\x46\x00\x01\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_XHTML_IM "\x09\x46\x00\x02\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_RTCVIDEO "\x09\x46\x01\x01\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_HAS_MICROPHONE "\x09\x46\x01\x02\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_HAS_CAMERA "\x09\x46\x01\x03\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_RTCAUDIO "\x09\x46\x01\x04\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_HOST_STATUS_TEXT_AWARE "\x09\x46\x01\x0a\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_RT_IM "\x09\x46\x01\x0b\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_SMART_CAPS "\x09\x46\x01\xff\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_FILE_TRANSFER "\x09\x46\x13\x43\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_DIRECT_IM "\x09\x46\x13\x45\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_FILE_SHARING "\x09\x46\x13\x48\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_SUPPORT_ICQ "\x09\x46\x13\x4D\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-
-#define AIM_CAP_AVAILABLE_FOR_CALL "\x09\x46\x01\x05\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_ACA "\x09\x46\x01\x06\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_MULTI_AUDIO "\x09\x46\x01\x07\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_MULTI_VIDEO "\x09\x46\x01\x08\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_VICEROY "\x09\x46\xf0\x04\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_BUDDY_ICON "\x09\x46\x13\x46\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_VOICE_CHAT "\x09\x46\x13\x41\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_DIRECT_PLAY "\x09\x46\x13\x42\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_ICQ_DIRECT_CONNECT "\x09\x46\x13\x44\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_GAMES "\x09\x46\x13\x47\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_ICQ_SERVER_RELAY "\x09\x46\x13\x49\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"//icq? channel 2 extended, TLV(0x2711) based messages
-#define AIM_CAP_CHAT_ROBOTS "\x09\x46\x13\x4A\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_SHARE_BUDDIES "\x09\x46\x13\x4B\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_CHAT "\x74\x8F\x24\x20\x62\x87\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_AMO "\x09\x46\x01\x0c\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-
-// Extensions
-#define AIM_CAP_HIPTOP "\x09\x46\x13\x23\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_UTF8 "\x09\x46\x13\x4E\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_UNKNOWN4 "\x09\x46\xf0\x03\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_UNKNOWNC "\x09\x46\xf0\x05\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
-#define AIM_CAP_IM2 "\x74\xed\xc3\x36\x44\xdf\x48\x5b\x8b\x1c\x67\x1a\x1f\x86\x09\x9f"
-#define AIM_CAP_TRILLIAN "\xF2\xE7\xC7\xF4\xFE\xAD\x4D\xFB\xB2\x35\x36\x79\x8B\xDF\0\0"
-extern char AIM_CAP_MIRANDA[]; //Miranda cap EXTERN
-
-//Aim Services
-#define AIM_SERVICE_GENERIC "\0\x01\0\x04"//version 4
-#define AIM_SERVICE_SSI "\0\x13\0\x03"//version 3
-#define AIM_SERVICE_LOCATION "\0\x02\0\x01"//version 1
-#define AIM_SERVICE_BUDDYLIST "\0\x03\0\x01"//version 1
-#define AIM_SERVICE_MESSAGING "\0\x04\0\x01"//version 1
-#define AIM_SERVICE_INVITATION "\0\x06\0\x01"//version 1
-#define AIM_SERVICE_ADMIN "\0\x07\0\x01"//version 1
-#define AIM_SERVICE_POPUP "\0\x08\0\x01"//version 1
-#define AIM_SERVICE_BOS "\0\x09\0\x01"//version 1
-#define AIM_SERVICE_AVATAR "\0\x10\0\x01"//version 1
-#define AIM_SERVICE_USERLOOKUP "\0\x0A\0\x01"//version 1
-#define AIM_SERVICE_STATS "\0\x0B\0\x01"//version 1
-#define AIM_SERVICE_CHATNAV "\0\x0D\0\x01"//version 1
-#define AIM_SERVICE_DIRSEARCH "\0\x0F\0\x01"//version 1
-#define AIM_SERVICE_CHAT "\0\x0E\0\x01"//version 1
-#define AIM_SERVICE_ICQ "\0\x15\0\x01"//version 1
-#define AIM_SERVICE_MAIL "\0\x18\0\x01"//version 1
-#define AIM_SERVICE_UNKNOWN "\0\x22\0\x01"//version 1
-#define AIM_SERVICE_RATES "\0\x01\0\x02\0\x03\0\x04\0\x05"
-
-//Aim Statuses
-#define AIM_STATUS_WEBAWARE "\0\x01"
-#define AIM_STATUS_SHOWIP "\0\x02"
-#define AIM_STATUS_BIRTHDAY "\0\x08"
-#define AIM_STATUS_WEBFRONT "\0\x20"
-#define AIM_STATUS_DCAUTH "\x10\0"
-#define AIM_STATUS_DCCONT "\x20\0"
-#define AIM_STATUS_NULL "\0\0"
-
-#define AIM_STATUS_ONLINE 0x00000000
-#define AIM_STATUS_AWAY 0x00000001
-#define AIM_STATUS_DND 0x00000002
-#define AIM_STATUS_OUT 0x00000004
-#define AIM_STATUS_BUSY 0x00000010
-#define AIM_STATUS_CHAT 0x00000020 // Broken. If set, you cannot unset.
-#define AIM_STATUS_INVISIBLE 0x00000100
-
-extern HINSTANCE hInstance; //plugin dll instance
-
-#endif
diff --git a/protocols/AimOscar/src/theme.cpp b/protocols/AimOscar/src/theme.cpp deleted file mode 100644 index 762c841a39..0000000000 --- a/protocols/AimOscar/src/theme.cpp +++ /dev/null @@ -1,270 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2009 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 "stdafx.h"
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Icons init
-
-static IconItem iconList[] =
-{
- { LPGEN("ICQ"), "icq", IDI_ICQ },
- { LPGEN("Add"), "add", IDI_ADD },
- { LPGEN("Block"), "block", IDI_BLOCK },
- { LPGEN("Profile"), "profile", IDI_PROFILE },
- { LPGEN("AOL mail"), "mail", IDI_MAIL },
- { LPGEN("AIM icon"), "aim", IDI_AIM },
- { LPGEN("Hiptop"), "hiptop", IDI_HIPTOP },
- { LPGEN("AOL bot"), "bot", IDI_BOT },
- { LPGEN("Admin"), "admin", IDI_ADMIN },
- { LPGEN("Confirmed"), "confirm", IDI_CONFIRMED },
- { LPGEN("Not confirmed"), "uconfirm", IDI_UNCONFIRMED },
- { LPGEN("Blocked list"), "away", IDI_AWAY },
- { LPGEN("Idle"), "idle", IDI_IDLE },
- { LPGEN("AOL"), "aol", IDI_AOL },
-
- { LPGEN("Foreground color"), "foreclr", IDI_FOREGROUNDCOLOR },
- { LPGEN("Background color"), "backclr", IDI_BACKGROUNDCOLOR },
- { LPGEN("Bold"), "bold", IDI_BOLD },
- { LPGEN("Not bold"), "nbold", IDI_NBOLD },
- { LPGEN("Italic"), "italic", IDI_ITALIC },
- { LPGEN("Not italic"), "nitalic", IDI_NITALIC },
- { LPGEN("Underline"), "undrln", IDI_UNDERLINE },
- { LPGEN("Not underline"), "nundrln", IDI_NUNDERLINE },
- { LPGEN("Subscript"), "sub_scrpt", IDI_SUBSCRIPT },
- { LPGEN("Not subscript"), "nsub_scrpt", IDI_NSUBSCRIPT },
- { LPGEN("Superscript"), "sup_scrpt", IDI_SUPERSCRIPT },
- { LPGEN("Not superscript"), "nsup_scrpt", IDI_NSUPERSCRIPT },
- { LPGEN("Normal script"), "norm_scrpt", IDI_NORMALSCRIPT },
- { LPGEN("Not normal script"), "nnorm_scrpt", IDI_NNORMALSCRIPT }
-};
-
-void InitIcons(void)
-{
- Icon_Register(hInstance, "Protocols/AIM", iconList, 14, "AIM");
- Icon_Register(hInstance, "Protocols/AIM/" LPGEN("Profile editor"), iconList + 14, 14, "AIM");
-}
-
-HICON LoadIconEx(const char *name, bool big)
-{
- char szSettingName[100];
- mir_snprintf(szSettingName, "AIM_%s", name);
- return IcoLib_GetIcon(szSettingName, big);
-}
-
-HANDLE GetIconHandle(const char *name)
-{
- for (int i = 0; i < _countof(iconList); i++)
- if (!mir_strcmp(iconList[i].szName, name))
- return iconList[i].hIcolib;
-
- return nullptr;
-}
-
-void ReleaseIconEx(const char *name, bool big)
-{
- char szSettingName[100];
- mir_snprintf(szSettingName, "%s_%s", "AIM", name);
- IcoLib_Release(szSettingName, big);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Extra Icons
-
-extern OBJLIST<CAimProto> g_Instances;
-
-static HANDLE bot_icon, icq_icon, aol_icon, hiptop_icon;
-static HANDLE admin_icon, confirmed_icon, unconfirmed_icon;
-
-static HANDLE hExtraAT, hExtraES;
-
-static const char* extra_AT_icon_name[5] =
-{
- "uconfirm",
- "confirm",
- "icq",
- "aol",
- "admin",
-};
-
-static const char* extra_ES_icon_name[2] =
-{
- "bot",
- "hiptop",
-};
-
-static void set_AT_icon(CAimProto* ppro, MCONTACT hContact)
-{
- if (ppro->isChatRoom(hContact)) return;
-
- unsigned i = ppro->getByte(hContact, AIM_KEY_AC, 0) - 1;
- ExtraIcon_SetIcon(hExtraAT, hContact, (i < 5) ? GetIconHandle(extra_AT_icon_name[i]) : nullptr);
-}
-
-static void set_ES_icon(CAimProto* ppro, MCONTACT hContact)
-{
- if (ppro->isChatRoom(hContact)) return;
-
- unsigned i = ppro->getByte(hContact, AIM_KEY_ET, 0) - 1;
- ExtraIcon_SetIcon(hExtraAT, hContact, (i < 2) ? GetIconHandle(extra_ES_icon_name[i]) : nullptr);
-}
-
-void set_contact_icon(CAimProto* ppro, MCONTACT hContact)
-{
- if (!ppro->getByte(AIM_KEY_AT, 0)) set_AT_icon(ppro, hContact);
- if (!ppro->getByte(AIM_KEY_ES, 0)) set_ES_icon(ppro, hContact);
-}
-
-void remove_AT_icons(CAimProto* ppro)
-{
- for (MCONTACT hContact = db_find_first(ppro->m_szModuleName); hContact; hContact = db_find_next(hContact, ppro->m_szModuleName))
- if (!ppro->isChatRoom(hContact))
- ExtraIcon_Clear(hExtraAT, hContact);
-}
-
-void remove_ES_icons(CAimProto* ppro)
-{
- for (MCONTACT hContact = db_find_first(ppro->m_szModuleName); hContact; hContact = db_find_next(hContact, ppro->m_szModuleName))
- if (!ppro->isChatRoom(hContact))
- ExtraIcon_Clear(hExtraES, hContact);
-}
-
-void add_AT_icons(CAimProto* ppro)
-{
- for (MCONTACT hContact = db_find_first(ppro->m_szModuleName); hContact; hContact = db_find_next(hContact, ppro->m_szModuleName))
- set_AT_icon(ppro, hContact);
-}
-
-void add_ES_icons(CAimProto* ppro)
-{
- for (MCONTACT hContact = db_find_first(ppro->m_szModuleName); hContact; hContact = db_find_next(hContact, ppro->m_szModuleName))
- set_ES_icon(ppro, hContact);
-}
-
-void InitExtraIcons(void)
-{
- hExtraAT = ExtraIcon_RegisterIcolib("aimaccounttype", LPGEN("AIM account type"), "AIM_aol");
- hExtraES = ExtraIcon_RegisterIcolib("aimextstatus", LPGEN("AIM extended status"), "AIM_hiptop");
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// OnPreBuildContactMenu
-
-int CAimProto::OnPreBuildContactMenu(WPARAM hContact, LPARAM)
-{
- bool bIsChatRoom = isChatRoom(hContact);
-
- //see if we should add the html away message context menu items
- Menu_ShowItem(m_hHTMLAwayContextMenuItem, getWord(hContact, AIM_KEY_ST, ID_STATUS_OFFLINE) == ID_STATUS_AWAY && !bIsChatRoom);
- Menu_ShowItem(m_hAddToServerListContextMenuItem, !getBuddyId(hContact, 1) && m_state != 0 && !bIsChatRoom);
-
- ptrA id(getStringA(hContact, AIM_KEY_SN));
- if (id == NULL)
- return 0;
-
- switch (m_pd_mode) {
- case 1:
- Menu_ModifyItem(m_hBlockContextMenuItem, LPGENW("&Block"));
- break;
-
- case 2:
- Menu_ModifyItem(m_hBlockContextMenuItem, LPGENW("&Unblock"));
- break;
-
- case 3:
- Menu_ModifyItem(m_hBlockContextMenuItem, m_allow_list.find_id(id) ? LPGENW("&Block") : LPGENW("&Unblock"));
- break;
-
- case 4:
- Menu_ModifyItem(m_hBlockContextMenuItem, m_block_list.find_id(id) ? LPGENW("&Unblock") : LPGENW("&Block"));
- break;
-
- default:
- Menu_ShowItem(m_hBlockContextMenuItem, false);
- break;
- }
- return 0;
-}
-
-void CAimProto::InitMainMenus(void)
-{
- CMenuItem mi;
- mi.root = Menu_GetProtocolRoot(this);
-
- mi.pszService = "/ManageAccount";
- CreateProtoService(mi.pszService, &CAimProto::ManageAccount);
- mi.position = 201001;
- mi.hIcolibItem = GetIconHandle("aim");
- mi.name.a = LPGEN("Manage account");
- m_hMainMenu[0] = Menu_AddProtoMenuItem(&mi, m_szModuleName);
-
- mi.pszService = "/InstantIdle";
- CreateProtoService(mi.pszService, &CAimProto::InstantIdle);
- mi.position = 201002;
- mi.hIcolibItem = GetIconHandle("idle");
- mi.name.a = LPGEN("Instant idle");
- m_hMainMenu[1] = Menu_AddProtoMenuItem(&mi, m_szModuleName);
-
- mi.pszService = "/JoinChatRoom";
- CreateProtoService(mi.pszService, &CAimProto::JoinChatUI);
- mi.position = 201003;
- mi.hIcolibItem = GetIconHandle("aol");
- mi.name.a = LPGEN("Join chat room");
- m_hMainMenu[2] = Menu_AddProtoMenuItem(&mi, m_szModuleName);
-}
-
-void CAimProto::InitContactMenus(void)
-{
- CMenuItem mi;
-
- SET_UID(mi, 0xb961e2af, 0x87a, 0x4fbf, 0xb5, 0x32, 0x6, 0xe2, 0x18, 0xad, 0x29, 0xac);
- CreateProtoService("/GetHTMLAwayMsg", &CAimProto::GetHTMLAwayMsg);
- mi.pszService = "/GetHTMLAwayMsg";
- mi.position = -2000006000;
- mi.hIcolibItem = GetIconHandle("away");
- mi.name.a = LPGEN("Read &HTML away message");
- mi.flags = CMIF_NOTOFFLINE | CMIF_HIDDEN;
- m_hHTMLAwayContextMenuItem = Menu_AddContactMenuItem(&mi, m_szModuleName);
-
- SET_UID(mi, 0x7f7e4c24, 0x821c, 0x450f, 0x93, 0x76, 0xbe, 0x65, 0xe9, 0x2f, 0xb6, 0xc2);
- CreateProtoService("/GetProfile", &CAimProto::GetProfile);
- mi.pszService = "/GetProfile";
- mi.position = -2000005090;
- mi.hIcolibItem = GetIconHandle("profile");
- mi.name.a = LPGEN("Read profile");
- mi.flags = CMIF_NOTOFFLINE;
- Menu_AddContactMenuItem(&mi, m_szModuleName);
-
- SET_UID(mi, 0x3928ba10, 0x69bc, 0x4ec9, 0x96, 0x48, 0xa4, 0x1b, 0xbe, 0x58, 0x4a, 0x7e);
- CreateProtoService("/AddToServerList", &CAimProto::AddToServerList);
- mi.pszService = "/AddToServerList";
- mi.position = -2000005080;
- mi.hIcolibItem = GetIconHandle("add");
- mi.name.a = LPGEN("Add to server list");
- mi.flags = CMIF_NOTONLINE | CMIF_HIDDEN;
- m_hAddToServerListContextMenuItem = Menu_AddContactMenuItem(&mi, m_szModuleName);
-
- SET_UID(mi, 0xc6169b8f, 0x53ab, 0x4242, 0xbe, 0x90, 0xe2, 0x4a, 0xa5, 0x73, 0x88, 0x32);
- CreateProtoService("/BlockCommand", &CAimProto::BlockBuddy);
- mi.pszService = "/BlockCommand";
- mi.position = -2000005060;
- mi.hIcolibItem = GetIconHandle("block");
- mi.name.a = LPGEN("&Block");
- mi.flags = CMIF_HIDDEN;
- m_hBlockContextMenuItem = Menu_AddContactMenuItem(&mi, m_szModuleName);
-}
diff --git a/protocols/AimOscar/src/theme.h b/protocols/AimOscar/src/theme.h deleted file mode 100644 index 73fde85851..0000000000 --- a/protocols/AimOscar/src/theme.h +++ /dev/null @@ -1,36 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2009 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 THEME_H
-#define THEME_H
-
-void InitIcons(void);
-void InitExtraIcons(void);
-
-HICON LoadIconEx(const char *name, bool big = false);
-HANDLE GetIconHandle(const char *name);
-void ReleaseIconEx(const char *name, bool big = false);
-
-void add_AT_icons(CAimProto* ppro);
-void remove_AT_icons(CAimProto* ppro);
-void add_ES_icons(CAimProto* ppro);
-void remove_ES_icons(CAimProto* ppro);
-
-void set_contact_icon(CAimProto* ppro, MCONTACT hContact);
-
-#endif
diff --git a/protocols/AimOscar/src/thread.cpp b/protocols/AimOscar/src/thread.cpp deleted file mode 100644 index 3affac892b..0000000000 --- a/protocols/AimOscar/src/thread.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2012 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 "stdafx.h"
-
-void __cdecl CAimProto::accept_file_thread(void* param)//buddy sending file
-{
- file_transfer *ft = (file_transfer*)param;
-
- HNETLIBCONN hConn = nullptr;
- if (ft->peer_force_proxy) //peer is forcing proxy
- {
- hConn = aim_peer_connect(ft->proxy_ip, get_default_port());
- if (hConn) {
- debugLogA("Connected to proxy ip that buddy specified.");
- ft->hConn = hConn;
- ForkThread(&CAimProto::aim_proxy_helper, ft);
- ft->stop_listen();
- }
- }
- else if (ft->me_force_proxy) //we are forcing proxy
- {
- hConn = aim_peer_connect(AIM_PROXY_SERVER, get_default_port());
- if (hConn) {
- debugLogA("Connected to proxy ip because we want to use a proxy for the file transfer.");
- ft->requester = true;
- ft->hConn = hConn;
- ForkThread(&CAimProto::aim_proxy_helper, ft);
- ft->stop_listen();
- }
- }
- else {
- bool verif = ft->verified_ip != m_detected_ip;
- hConn = aim_peer_connect(verif ? ft->verified_ip : ft->local_ip, ft->port);
- if (hConn) {
- debugLogA("Connected to buddy over P2P port via %s ip.", verif ? "verified" : "local");
- ft->accepted = true;
- ft->hConn = hConn;
- aim_file_ad(m_hServerConn, m_seqno, ft->sn, ft->icbm_cookie, false, ft->max_ver);
- ForkThread(&CAimProto::aim_dc_helper, ft);
- ft->stop_listen();
- }
- else if (ft->sending) {
- hConn = aim_peer_connect(AIM_PROXY_SERVER, get_default_port());
- if (hConn) {
- ft->hConn = hConn;
- ft->requester = true;
- ForkThread(&CAimProto::aim_proxy_helper, ft);
- ft->stop_listen();
- }
- }
- else {
- debugLogA("Failed to connect to buddy- asking buddy to connect to us.");
- ft->listen(this);
- ft->requester = true;
- aim_send_file(m_hServerConn, m_seqno, m_detected_ip, ft->local_port, false, ft);
- return;
- }
- }
-
- if (hConn == nullptr) {
- if (ft->req_num)
- aim_file_ad(m_hServerConn, m_seqno, ft->sn, ft->icbm_cookie, true, 0);
-
- ProtoBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0);
- m_ft_list.remove_by_ft(ft);
- }
-}
diff --git a/protocols/AimOscar/src/tlv.cpp b/protocols/AimOscar/src/tlv.cpp deleted file mode 100644 index 089a0fc17d..0000000000 --- a/protocols/AimOscar/src/tlv.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2009 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 "stdafx.h"
-
-TLV::TLV(char* buf)
-{
- type_=_htons((*(unsigned short*)&buf[0]));
- length_=_htons((*(unsigned short*)&buf[2]));
- if (length_ > 0)
- {
- value_=(char*)mir_alloc(length_+1);
- memcpy(value_,&buf[4],length_);
- }
- else
- value_= nullptr;
-}
-
-TLV::TLV(unsigned short type, unsigned short length, const char* value)
-{
- type_ = type;
- length_ = length;
- if (length_ > 0)
- {
- value_ = (char*)mir_alloc(length_+1);
- memcpy(value_, value, length_);
- }
- else
- value_= nullptr;
-}
-
-TLV::~TLV()
-{
- mir_free(value_);
-}
-
-unsigned short TLV::ushort(int pos)
-{
- return _htons(*(unsigned short*)&value_[pos]);
-}
-
-unsigned long TLV::ulong(int pos)
-{
- return _htonl(*(unsigned long*)&value_[pos]);
-}
-
-unsigned __int64 TLV::u64(int pos)
-{
- return _htonl64(*(unsigned __int64*)&value_[pos]);
-}
-
-unsigned char TLV::ubyte(int pos)
-{
- return value_[pos];
-}
-
-char* TLV::part(int pos, int length)//returns part of the tlv value
-{
- if ((pos + length) > length_) return nullptr;
-
- char* value = (char*)mir_alloc(length + 2);
- memcpy(value, &value_[pos], length);
- value[length] = '\0';
- value[length+1] = '\0';
-
- return value;
-}
-
-char* TLV::dupw(void)
-{
- wchar_t *str = (wchar_t*)part(0, length_);
- wcs_htons(str);
-
- char* stru = mir_utf8encodeW(str);
- mir_free(str);
-
- return stru;
-}
-
-
-unsigned short TLV::whole(char* buf)//returns the whole tlv
-{
- *(unsigned short*)buf = _htons(type_);
- *(unsigned short*)&buf[2] = _htons(length_);
- memcpy(&buf[4], value_, length_);
- return length_ + TLV_HEADER_SIZE;
-}
diff --git a/protocols/AimOscar/src/tlv.h b/protocols/AimOscar/src/tlv.h deleted file mode 100644 index 1522650b65..0000000000 --- a/protocols/AimOscar/src/tlv.h +++ /dev/null @@ -1,50 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2009 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 TLV_H
-#define TLV_H
-
-#define TLV_HEADER_SIZE 4
-
-class TLV
-{
-private:
- unsigned short type_;
- unsigned short length_;
- char* value_;
-public:
- TLV(char* buf);
- TLV(unsigned short type, unsigned short length, const char* value);
- ~TLV();
-
- int cmp(unsigned short type) { return type_ == type; }
- unsigned short len(void) { return length_; }
- char* val(void) { return value_; }
-
- char* part(int pos, int length);
- char* dup(void) { return part(0, length_); };
- char* dupw(void);
-
- unsigned short whole(char* buf);
- unsigned short ushort(int pos=0);
- unsigned long ulong(int pos=0);
- unsigned __int64 u64(int pos=0);
- unsigned char ubyte(int pos=0);
-};
-
-#endif
diff --git a/protocols/AimOscar/src/ui.cpp b/protocols/AimOscar/src/ui.cpp deleted file mode 100755 index 7bf8eed909..0000000000 --- a/protocols/AimOscar/src/ui.cpp +++ /dev/null @@ -1,1457 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2012 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 "stdafx.h"
-
-HANDLE hThemeButton = nullptr;
-COLORREF foreground=0;
-COLORREF background=0xffffff;
-COLORREF custColours[16]={0};
-
-static int CALLBACK EnumFontsProc(ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX* /*lpntme*/, int /*FontType*/, LPARAM lParam)
-{
- if (!IsWindow((HWND)lParam))
- return FALSE;
- if (SendMessage((HWND)lParam, CB_FINDSTRINGEXACT, 1, (LPARAM)lpelfe->elfLogFont.lfFaceName) == CB_ERR)
- SendMessage((HWND)lParam, CB_ADDSTRING, 0, (LPARAM)lpelfe->elfLogFont.lfFaceName);
- return TRUE;
-}
-
-void DrawMyControl(HDC hDC, HWND /*hwndButton*/, HANDLE hTheme, UINT iState, RECT rect)
-{
- BOOL bIsPressed = (iState & ODS_SELECTED);
- BOOL bIsFocused = (iState & ODS_FOCUS);
- if (hTheme) {
- DWORD state = (bIsPressed) ? PBS_PRESSED : PBS_NORMAL;
- if (state == PBS_NORMAL) {
- if (bIsFocused)
- state = PBS_DEFAULTED;
- }
- rect.top -= 1;
- rect.left -= 1;
- DrawThemeBackground(hTheme, hDC, BP_PUSHBUTTON, state, &rect, nullptr);
- }
- else {
- if (bIsFocused) {
- HBRUSH br = CreateSolidBrush(RGB(0, 0, 0));
- FrameRect(hDC, &rect, br);
- InflateRect(&rect, -1, -1);
- DeleteObject(br);
- } // if
- COLORREF crColor = GetSysColor(COLOR_BTNFACE);
- HBRUSH brBackground = CreateSolidBrush(crColor);
- FillRect(hDC, &rect, brBackground);
- DeleteObject(brBackground);
- // Draw pressed button
- if (bIsPressed) {
- HBRUSH brBtnShadow = CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW));
- FrameRect(hDC, &rect, brBtnShadow);
- DeleteObject(brBtnShadow);
- }
- else // ...else draw non pressed button
- {
- UINT uState = DFCS_BUTTONPUSH;
- DrawFrameControl(hDC, &rect, DFC_BUTTON, uState);
- }
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// User info dialog
-
-static INT_PTR CALLBACK userinfo_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- CAimProto* ppro = (CAimProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
-
- switch (msg) {
- case WM_INITDIALOG:
- {
- SendDlgItemMessage(hwndDlg, IDC_BOLD, BUTTONSETASPUSHBTN, TRUE, 0);
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETEVENTMASK, 0, ENM_CHANGE | ENM_SELCHANGE | ENM_REQUESTRESIZE);
- SendDlgItemMessage(hwndDlg, IDC_BACKGROUNDCOLORPICKER, CPM_SETCOLOUR, 0, 0x00ffffff);
- LOGFONT lf = { 0 };
- HDC hdc = GetDC(hwndDlg);
- lf.lfCharSet = DEFAULT_CHARSET;
- lf.lfFaceName[0] = 0;
- lf.lfPitchAndFamily = 0;
- EnumFontFamiliesEx(hdc, &lf, (FONTENUMPROC)EnumFontsProc, (LPARAM)GetDlgItem(hwndDlg, IDC_TYPEFACE), 0);
- ReleaseDC(hwndDlg, hdc);
- SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_ADDSTRING, 0, (LPARAM)TEXT("8"));
- SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_ADDSTRING, 0, (LPARAM)TEXT("10"));
- SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_ADDSTRING, 0, (LPARAM)TEXT("12"));
- SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_ADDSTRING, 0, (LPARAM)TEXT("14"));
- SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_ADDSTRING, 0, (LPARAM)TEXT("18"));
- SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_ADDSTRING, 0, (LPARAM)TEXT("24"));
- SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_ADDSTRING, 0, (LPARAM)TEXT("36"));
- SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_SETCURSEL, 2, 0);
- if (SendDlgItemMessage(hwndDlg, IDC_TYPEFACE, CB_SELECTSTRING, 1, (LPARAM)TEXT("Arial")) != CB_ERR) {
- CHARFORMAT2 cf;
- cf.cbSize = sizeof(cf);
- cf.yHeight = 12 * 20;
- cf.dwMask = CFM_SIZE | CFM_FACE;
- mir_wstrcpy(cf.szFaceName, TEXT("Arial"));
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
- }
- else {
- CHARFORMAT2 cf;
- cf.cbSize = sizeof(cf);
- cf.yHeight = 12 * 20;
- cf.dwMask = CFM_SIZE;
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
- }
- break;
- }
- case WM_CLOSE:
- EndDialog(hwndDlg, 0);
- break;
-
- case WM_SIZING:
- {
- RECT* rect = (RECT*)lParam;
-#define MIN_HEIGHT 200
-#define MIN_WIDTH 400
- if (WMSZ_RIGHT == wParam || WMSZ_TOPRIGHT == wParam || WMSZ_BOTTOMRIGHT == wParam) {
- if (rect->right - rect->left < MIN_WIDTH)
- rect->right = rect->left + MIN_WIDTH;
- }
- if (WMSZ_LEFT == wParam || WMSZ_TOPLEFT == wParam || WMSZ_BOTTOMLEFT == wParam) {
- if (rect->right - rect->left < MIN_WIDTH)
- rect->left = rect->right - MIN_WIDTH;
- }
- if (WMSZ_TOP == wParam || WMSZ_TOPRIGHT == wParam || WMSZ_TOPLEFT == wParam) {
- if (rect->bottom - rect->top < MIN_HEIGHT)
- rect->top = rect->bottom - MIN_HEIGHT;
- }
- if (WMSZ_BOTTOM == wParam || WMSZ_BOTTOMLEFT == wParam || WMSZ_BOTTOMRIGHT == wParam) {
- if (rect->bottom - rect->top < MIN_HEIGHT)
- rect->bottom = rect->top + MIN_HEIGHT;
- }
- break;
- }
-
- case WM_SIZE:
- {
- int width = LOWORD(lParam);
- int height = HIWORD(lParam);
- SetWindowPos(GetDlgItem(hwndDlg, IDC_PROFILE), HWND_TOP, 6, 60, width - 12, height - 67, 0); // this 'case' should go away
- SetWindowPos(GetDlgItem(hwndDlg, IDC_SETPROFILE), HWND_TOP, width - 97, height - 224, 0, 0, SWP_NOSIZE); // since there's no profile window resize anymore
- break;
- }
- case WM_NOTIFY:
- switch (LOWORD(wParam)) {
- case IDC_PROFILE:
- if (((LPNMHDR)lParam)->code == EN_SELCHANGE) {
- CHARFORMAT2 cfOld;
- cfOld.cbSize = sizeof(CHARFORMAT2);
- cfOld.dwMask = CFM_FACE | CFM_SIZE;
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
- if (SendDlgItemMessage(hwndDlg, IDC_TYPEFACE, CB_SELECTSTRING, 1, (LPARAM)cfOld.szFaceName) == -1) {
- SendDlgItemMessage(hwndDlg, IDC_TYPEFACE, CB_ADDSTRING, 0, (LPARAM)cfOld.szFaceName);
- SendDlgItemMessage(hwndDlg, IDC_TYPEFACE, CB_SELECTSTRING, 1, (LPARAM)cfOld.szFaceName);
- }
- char size[10];
- _itoa(cfOld.yHeight / 20, size, sizeof(size));
- //SetDlgItemText(hwndDlg, IDC_FONTSIZE, size);
- SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_SELECTSTRING, 1, (LPARAM)size);
- InvalidateRect(GetDlgItem(hwndDlg, IDC_SUPERSCRIPT), nullptr, FALSE);
- InvalidateRect(GetDlgItem(hwndDlg, IDC_NORMALSCRIPT), nullptr, FALSE);
- InvalidateRect(GetDlgItem(hwndDlg, IDC_SUBSCRIPT), nullptr, FALSE);
- InvalidateRect(GetDlgItem(hwndDlg, IDC_BOLD), nullptr, FALSE);
- InvalidateRect(GetDlgItem(hwndDlg, IDC_ITALIC), nullptr, FALSE);
- InvalidateRect(GetDlgItem(hwndDlg, IDC_UNDERLINE), nullptr, FALSE);
- }
- else if (((LPNMHDR)lParam)->code == EN_REQUESTRESIZE) {
- // REQRESIZE* rr= (REQRESIZE*)lParam;
- //SetWindowPos(GetDlgItem(hwndDlg, IDC_PROFILE),HWND_TOP,rr->rc.left,rr->rc.top,rr->rc.right,rr->rc.bottom,0);
- }
- break;
-
- default:
- if (((LPNMHDR)lParam)->code == PSN_PARAMCHANGED) {
- ppro = (CAimProto*)((PSHNOTIFY*)lParam)->lParam;
- SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)ppro);
-
- DBVARIANT dbv;
- if (!db_get_utf(NULL, ppro->m_szModuleName, AIM_KEY_PR, &dbv)) {
- html_decode(dbv.pszVal);
- wchar_t *txt = mir_utf8decodeW(dbv.pszVal);
- SetDlgItemText(hwndDlg, IDC_PROFILE, txt);
- mir_free(txt);
- db_free(&dbv);
- }
- }
- }
- break;
-
- case WM_DRAWITEM:
- {
- CloseThemeData(hThemeButton);
- hThemeButton = OpenThemeData(GetDlgItem(hwndDlg, IDC_BOLD), L"Button");
- LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)lParam;
- if (lpDIS->CtlID == IDC_SUPERSCRIPT) {
- CHARFORMAT2 cfOld;
- cfOld.cbSize = sizeof(CHARFORMAT2);
- cfOld.dwMask = CFM_SUPERSCRIPT;
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
- BOOL isSuper = (cfOld.dwEffects & CFE_SUPERSCRIPT) && (cfOld.dwMask & CFM_SUPERSCRIPT);
- if (isSuper) {
- DrawMyControl(lpDIS->hDC, GetDlgItem(hwndDlg, IDC_BOLD), hThemeButton, lpDIS->itemState | ODS_SELECTED, lpDIS->rcItem);
- DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("sup_scrpt"), 16, 16, 0, nullptr, DI_NORMAL);
- ReleaseIconEx("sup_scrpt");
- }
- else {
- DrawMyControl(lpDIS->hDC, GetDlgItem(hwndDlg, IDC_BOLD), hThemeButton, lpDIS->itemState, lpDIS->rcItem);
- DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("nsup_scrpt"), 16, 16, 0, nullptr, DI_NORMAL);
- ReleaseIconEx("nsup_scrpt");
- }
- }
- else if (lpDIS->CtlID == IDC_NORMALSCRIPT) {
- CHARFORMAT2 cfOld;
- cfOld.cbSize = sizeof(CHARFORMAT2);
- cfOld.dwMask = CFM_SUBSCRIPT | CFM_SUPERSCRIPT;
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
- BOOL isSub = (cfOld.dwEffects & CFE_SUBSCRIPT) && (cfOld.dwMask & CFM_SUBSCRIPT);
- BOOL isSuper = (cfOld.dwEffects & CFE_SUPERSCRIPT) && (cfOld.dwMask & CFM_SUPERSCRIPT);
- if (!isSub&&!isSuper) {
- DrawMyControl(lpDIS->hDC, GetDlgItem(hwndDlg, IDC_BOLD), hThemeButton, lpDIS->itemState | ODS_SELECTED, lpDIS->rcItem);
- DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("norm_scrpt"), 16, 16, 0, nullptr, DI_NORMAL);
- ReleaseIconEx("norm_scrpt");
- }
- else {
- DrawMyControl(lpDIS->hDC, GetDlgItem(hwndDlg, IDC_BOLD), hThemeButton, lpDIS->itemState, lpDIS->rcItem);
- DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("nnorm_scrpt"), 16, 16, 0, nullptr, DI_NORMAL);
- ReleaseIconEx("nnorm_scrpt");
- }
- }
- else if (lpDIS->CtlID == IDC_SUBSCRIPT) {
- CHARFORMAT2 cfOld;
- cfOld.cbSize = sizeof(CHARFORMAT2);
- cfOld.dwMask = CFM_SUBSCRIPT;
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
- BOOL isSub = (cfOld.dwEffects & CFE_SUBSCRIPT) && (cfOld.dwMask & CFM_SUBSCRIPT);
- if (isSub) {
- DrawMyControl(lpDIS->hDC, GetDlgItem(hwndDlg, IDC_BOLD), hThemeButton, lpDIS->itemState | ODS_SELECTED, lpDIS->rcItem);
- DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("sub_scrpt"), 16, 16, 0, nullptr, DI_NORMAL);
- ReleaseIconEx("sub_scrpt");
- }
- else {
- DrawMyControl(lpDIS->hDC, GetDlgItem(hwndDlg, IDC_BOLD), hThemeButton, lpDIS->itemState, lpDIS->rcItem);
- DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("nsub_scrpt"), 16, 16, 0, nullptr, DI_NORMAL);
- ReleaseIconEx("nsub_scrpt");
- }
- }
- else if (lpDIS->CtlID == IDC_BOLD) {
- CHARFORMAT2 cfOld;
- cfOld.cbSize = sizeof(CHARFORMAT2);
- cfOld.dwMask = CFM_BOLD;
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
- BOOL isBold = (cfOld.dwEffects & CFE_BOLD) && (cfOld.dwMask & CFM_BOLD);
- if (!isBold) {
- DrawMyControl(lpDIS->hDC, GetDlgItem(hwndDlg, IDC_BOLD), hThemeButton, lpDIS->itemState, lpDIS->rcItem);
- DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("nbold"), 16, 16, 0, nullptr, DI_NORMAL);
- ReleaseIconEx("nbold");
- }
- else {
- DrawMyControl(lpDIS->hDC, GetDlgItem(hwndDlg, IDC_BOLD), hThemeButton, lpDIS->itemState | ODS_SELECTED, lpDIS->rcItem);
- DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("bold"), 16, 16, 0, nullptr, DI_NORMAL);
- ReleaseIconEx("bold");
- }
- }
- else if (lpDIS->CtlID == IDC_ITALIC) {
- CHARFORMAT2 cfOld;
- cfOld.cbSize = sizeof(CHARFORMAT2);
- cfOld.dwMask = CFM_ITALIC;
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
- BOOL isItalic = (cfOld.dwEffects & CFE_ITALIC) && (cfOld.dwMask & CFM_ITALIC);
- if (!isItalic) {
- DrawMyControl(lpDIS->hDC, GetDlgItem(hwndDlg, IDC_ITALIC), hThemeButton, lpDIS->itemState, lpDIS->rcItem);
- DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("nitalic"), 16, 16, 0, nullptr, DI_NORMAL);
- ReleaseIconEx("nitalic");
- }
- else {
- DrawMyControl(lpDIS->hDC, GetDlgItem(hwndDlg, IDC_ITALIC), hThemeButton, lpDIS->itemState | ODS_SELECTED, lpDIS->rcItem);
- DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("italic"), 16, 16, 0, nullptr, DI_NORMAL);
- ReleaseIconEx("italic");
- }
- }
- else if (lpDIS->CtlID == IDC_UNDERLINE) {
- CHARFORMAT2 cfOld;
- cfOld.cbSize = sizeof(CHARFORMAT2);
- cfOld.dwMask = CFM_UNDERLINE;
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
- BOOL isUnderline = (cfOld.dwEffects & CFE_UNDERLINE) && (cfOld.dwMask & CFM_UNDERLINE);
- if (!isUnderline) {
- DrawMyControl(lpDIS->hDC, GetDlgItem(hwndDlg, IDC_UNDERLINE), hThemeButton, lpDIS->itemState, lpDIS->rcItem);
- DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("nundrln"), 16, 16, 0, nullptr, DI_NORMAL);
- ReleaseIconEx("nundrln");
- }
- else {
- DrawMyControl(lpDIS->hDC, GetDlgItem(hwndDlg, IDC_UNDERLINE), hThemeButton, lpDIS->itemState | ODS_SELECTED, lpDIS->rcItem);
- DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("undrln"), 16, 16, 0, nullptr, DI_NORMAL);
- ReleaseIconEx("undrln");
- }
- }
- else if (lpDIS->CtlID == IDC_FOREGROUNDCOLOR) {
- DrawMyControl(lpDIS->hDC, GetDlgItem(hwndDlg, IDC_FOREGROUNDCOLOR), hThemeButton, lpDIS->itemState, lpDIS->rcItem);
- DrawIconEx(lpDIS->hDC, 4, 2, LoadIconEx("foreclr"), 16, 16, 0, nullptr, DI_NORMAL);
- ReleaseIconEx("foreclr");
- HBRUSH hbr = CreateSolidBrush(foreground);
- HPEN hp = CreatePen(PS_SOLID, 1, ~foreground & 0x00ffffff);
- SelectObject(lpDIS->hDC, hp);
- RECT rect = lpDIS->rcItem;
- rect.top += 18;
- rect.bottom -= 4;
- rect.left += 5;
- rect.right -= 5;
- Rectangle(lpDIS->hDC, rect.left - 1, rect.top - 1, rect.right + 1, rect.bottom + 1);
- FillRect(lpDIS->hDC, &rect, hbr);
- DeleteObject(hbr);
- DeleteObject(hp);
- }
- else if (lpDIS->CtlID == IDC_FOREGROUNDCOLORPICKER) {
- DrawMyControl(lpDIS->hDC, GetDlgItem(hwndDlg, IDC_FOREGROUNDCOLORPICKER), hThemeButton, lpDIS->itemState, lpDIS->rcItem);
- HBRUSH hbr = CreateSolidBrush(foreground);
- HPEN hp = CreatePen(PS_SOLID, 1, ~foreground & 0x00ffffff);
- SelectObject(lpDIS->hDC, hbr);
- SelectObject(lpDIS->hDC, hp);
- POINT tri[3];
- tri[0].x = 3;
- tri[0].y = 10;
- tri[1].x = 9;
- tri[1].y = 10;
- tri[2].x = 6;
- tri[2].y = 15;
- Polygon(lpDIS->hDC, tri, 3);
- DeleteObject(hbr);
- DeleteObject(hp);
- }
- else if (lpDIS->CtlID == IDC_BACKGROUNDCOLOR) {
- DrawMyControl(lpDIS->hDC, GetDlgItem(hwndDlg, IDC_BACKGROUNDCOLOR), hThemeButton, lpDIS->itemState, lpDIS->rcItem);
- DrawIconEx(lpDIS->hDC, 4, 2, LoadIconEx("backclr"), 16, 16, 0, nullptr, DI_NORMAL);
- ReleaseIconEx("backclr");
- HBRUSH hbr = CreateSolidBrush(background);
- HPEN hp = CreatePen(PS_SOLID, 1, ~background & 0x00ffffff);
- SelectObject(lpDIS->hDC, hp);
- RECT rect = lpDIS->rcItem;
- rect.top += 18;
- rect.bottom -= 4;
- rect.left += 5;
- rect.right -= 5;
- Rectangle(lpDIS->hDC, rect.left - 1, rect.top - 1, rect.right + 1, rect.bottom + 1);
- FillRect(lpDIS->hDC, &rect, hbr);
- DeleteObject(hbr);
- DeleteObject(hp);
- }
- else if (lpDIS->CtlID == IDC_BACKGROUNDCOLORPICKER) {
- DrawMyControl(lpDIS->hDC, GetDlgItem(hwndDlg, IDC_BACKGROUNDCOLORPICKER), hThemeButton, lpDIS->itemState, lpDIS->rcItem);
- HBRUSH hbr = CreateSolidBrush(background);
- HPEN hp = CreatePen(PS_SOLID, 1, ~background & 0x00ffffff);
- SelectObject(lpDIS->hDC, hbr);
- SelectObject(lpDIS->hDC, hp);
- POINT tri[3];
- tri[0].x = 3;
- tri[0].y = 10;
- tri[1].x = 9;
- tri[1].y = 10;
- tri[2].x = 6;
- tri[2].y = 15;
- Polygon(lpDIS->hDC, tri, 3);
- DeleteObject(hbr);
- DeleteObject(hp);
- }
- break;
- }
-
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDC_PROFILE:
- if (HIWORD(wParam) == EN_CHANGE)
- EnableWindow(GetDlgItem(hwndDlg, IDC_SETPROFILE), TRUE);
- break;
-
- case IDC_SETPROFILE:
- {
- char* buf = rtf_to_html(hwndDlg, IDC_PROFILE);
- db_set_utf(NULL, ppro->m_szModuleName, AIM_KEY_PR, buf);
- if (ppro->m_state == 1)
- ppro->aim_set_profile(ppro->m_hServerConn, ppro->m_seqno, buf);//also see set caps for profile setting
-
- mir_free(buf);
- EnableWindow(GetDlgItem(hwndDlg, IDC_SETPROFILE), FALSE);
- }
- break;
-
- case IDC_SUPERSCRIPT:
- if (HIWORD(wParam) == BN_CLICKED) {
- CHARFORMAT2 cf;
- cf.cbSize = sizeof(CHARFORMAT2);
- cf.dwMask = CFM_SUPERSCRIPT;
- cf.dwEffects = CFE_SUPERSCRIPT;
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
- SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
- InvalidateRect(GetDlgItem(hwndDlg, IDC_NORMALSCRIPT), nullptr, FALSE);
- InvalidateRect(GetDlgItem(hwndDlg, IDC_SUBSCRIPT), nullptr, FALSE);
- }
- break;
-
- case IDC_NORMALSCRIPT:
- if (HIWORD(wParam) == BN_CLICKED) {
- CHARFORMAT2 cf;
- cf.cbSize = sizeof(CHARFORMAT2);
- cf.dwMask = CFM_SUPERSCRIPT;
- cf.dwEffects &= ~CFE_SUPERSCRIPT;
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
- SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
- InvalidateRect(GetDlgItem(hwndDlg, IDC_SUPERSCRIPT), nullptr, FALSE);
- InvalidateRect(GetDlgItem(hwndDlg, IDC_SUBSCRIPT), nullptr, FALSE);
- }
- break;
-
- case IDC_SUBSCRIPT:
- if (HIWORD(wParam) == BN_CLICKED) {
- CHARFORMAT2 cf;
- cf.cbSize = sizeof(CHARFORMAT2);
- cf.dwMask = CFM_SUBSCRIPT;
- cf.dwEffects = CFE_SUBSCRIPT;
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
- SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
- InvalidateRect(GetDlgItem(hwndDlg, IDC_SUPERSCRIPT), nullptr, FALSE);
- InvalidateRect(GetDlgItem(hwndDlg, IDC_NORMALSCRIPT), nullptr, FALSE);
- }
- break;
-
- case IDC_BOLD:
- if (HIWORD(wParam) == BN_CLICKED) {
- CHARFORMAT2 cfOld;
- cfOld.cbSize = sizeof(CHARFORMAT2);
- cfOld.dwMask = CFM_BOLD;
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
- BOOL isBold = (cfOld.dwEffects & CFE_BOLD) && (cfOld.dwMask & CFM_BOLD);
- CHARFORMAT2 cf;
- cf.cbSize = sizeof(CHARFORMAT2);
- cf.dwEffects = isBold ? 0 : CFE_BOLD;
- cf.dwMask = CFM_BOLD;
- CheckDlgButton(hwndDlg, IDC_BOLD, !isBold ? BST_CHECKED : BST_UNCHECKED);
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
- SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
- }
- break;
-
- case IDC_ITALIC:
- if (HIWORD(wParam) == BN_CLICKED) {
- CHARFORMAT2 cfOld;
- cfOld.cbSize = sizeof(CHARFORMAT2);
- cfOld.dwMask = CFM_ITALIC;
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
- BOOL isItalic = (cfOld.dwEffects & CFE_ITALIC) && (cfOld.dwMask & CFM_ITALIC);
- CHARFORMAT2 cf;
- cf.cbSize = sizeof(CHARFORMAT2);
- cf.dwEffects = isItalic ? 0 : CFE_ITALIC;
- cf.dwMask = CFM_ITALIC;
- CheckDlgButton(hwndDlg, IDC_ITALIC, !isItalic ? BST_CHECKED : BST_UNCHECKED);
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
- SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
- }
- break;
-
- case IDC_UNDERLINE:
- if (HIWORD(wParam) == BN_CLICKED) {
- CHARFORMAT2 cfOld;
- cfOld.cbSize = sizeof(CHARFORMAT2);
- cfOld.dwMask = CFM_UNDERLINE;
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
- BOOL isUnderline = (cfOld.dwEffects & CFE_UNDERLINE) && (cfOld.dwMask & CFM_UNDERLINE);
- CHARFORMAT2 cf;
- cf.cbSize = sizeof(CHARFORMAT2);
- cf.dwEffects = isUnderline ? 0 : CFE_UNDERLINE;
- cf.dwMask = CFM_UNDERLINE;
- CheckDlgButton(hwndDlg, IDC_UNDERLINE, !isUnderline ? BST_CHECKED : BST_UNCHECKED);
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
- SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
- }
- break;
-
- case IDC_FOREGROUNDCOLOR:
- if (HIWORD(wParam) == BN_CLICKED) {
- CHARFORMAT2 cf;
- cf.cbSize = sizeof(CHARFORMAT2);
- cf.dwMask = CFM_COLOR;
- cf.dwEffects = 0;
- cf.crTextColor = foreground;
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
- SetWindowPos(GetDlgItem(hwndDlg, IDC_FOREGROUNDCOLORPICKER), GetDlgItem(hwndDlg, IDC_FOREGROUNDCOLOR), 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
- SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
- }
- break;
-
- case IDC_FOREGROUNDCOLORPICKER:
- if (HIWORD(wParam) == BN_CLICKED) {
- CHOOSECOLOR cc = { 0 };
- custColours[0] = foreground;
- custColours[1] = background;
- cc.lStructSize = sizeof(CHOOSECOLOR);
- cc.hwndOwner = hwndDlg;
- cc.hInstance = (HWND)GetModuleHandleA("mir_app.mir");
- cc.lpCustColors = custColours;
- cc.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_RGBINIT;
- if (ChooseColor(&cc)) {
- foreground = cc.rgbResult;
- InvalidateRect(GetDlgItem(hwndDlg, IDC_FOREGROUNDCOLOR), nullptr, FALSE);
- }
- SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
- }
- break;
-
- case IDC_BACKGROUNDCOLOR:
- if (HIWORD(wParam) == BN_CLICKED) {
- CHARFORMAT2 cf;
- cf.cbSize = sizeof(CHARFORMAT2);
- cf.dwMask = CFM_BACKCOLOR;
- cf.dwEffects = 0;
- cf.crBackColor = background;
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
- SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
- }
- break;
-
- case IDC_BACKGROUNDCOLORPICKER:
- if (HIWORD(wParam) == BN_CLICKED) {
- CHOOSECOLOR cc = { 0 };
- custColours[0] = foreground;
- custColours[1] = background;
- cc.lStructSize = sizeof(CHOOSECOLOR);
- cc.hwndOwner = hwndDlg;
- cc.hInstance = (HWND)GetModuleHandle(nullptr);
- cc.lpCustColors = custColours;
- cc.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_RGBINIT;
- if (ChooseColor(&cc)) {
- background = cc.rgbResult;
- InvalidateRect(GetDlgItem(hwndDlg, IDC_BACKGROUNDCOLOR), nullptr, FALSE);
- }
- SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
- }
- break;
-
- case IDC_TYPEFACE:
- if (HIWORD(wParam) == CBN_SELENDOK) {
- CHARFORMAT2A cf;
- cf.cbSize = sizeof(cf);
- cf.dwMask = CFM_FACE;
- cf.dwEffects = 0;
- SendDlgItemMessage(hwndDlg, IDC_TYPEFACE, CB_GETLBTEXT, SendDlgItemMessage(hwndDlg, IDC_TYPEFACE, CB_GETCURSEL, 0, 0), (LPARAM)cf.szFaceName);
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
- SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
- break;
- }
- break;
-
- case IDC_FONTSIZE:
- if (HIWORD(wParam) == CBN_SELENDOK) {
- CHARFORMAT2 cf;
- cf.cbSize = sizeof(CHARFORMAT2);
- cf.dwMask = CFM_SIZE;
- cf.dwEffects = 0;
- char chsize[5] = "";
- SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_GETLBTEXT, SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_GETCURSEL, 0, 0), (LPARAM)chsize);
- //strlcpy(cf.szFaceName,size,mir_strlen(size)+1);
- cf.yHeight = atoi(chsize) * 20;
- SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
- SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
- break;
- }
- break;
- }
- break;
- }
- return FALSE;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// View admin dialog
-
-INT_PTR CALLBACK admin_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- CAimProto* ppro = (CAimProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
- DBVARIANT dbv;
-
- switch (msg) {
- case WM_INITDIALOG:
- TranslateDialogDefault(hwndDlg);
- SendDlgItemMessage(hwndDlg, IDC_FNAME, EM_LIMITTEXT, 63, 0);
- SendDlgItemMessage(hwndDlg, IDC_CEMAIL, EM_LIMITTEXT, 253, 0);
- SendDlgItemMessage(hwndDlg, IDC_CPW, EM_LIMITTEXT, 253, 0);
- SendDlgItemMessage(hwndDlg, IDC_NPW1, EM_LIMITTEXT, 253, 0);
- SendDlgItemMessage(hwndDlg, IDC_NPW2, EM_LIMITTEXT, 253, 0);
- break;
-
- case WM_NOTIFY:
- switch (((LPNMHDR)lParam)->code) {
- case PSN_PARAMCHANGED:
- ppro = (CAimProto*)((LPPSHNOTIFY)lParam)->lParam;
- SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)ppro);
-
- if (ppro->wait_conn(ppro->m_hAdminConn, ppro->m_hAdminEvent, 0x07)) { // Make a connection
- ppro->aim_admin_request_info(ppro->m_hAdminConn, ppro->m_admin_seqno, 0x01); // Get our screenname
- ppro->aim_admin_request_info(ppro->m_hAdminConn, ppro->m_admin_seqno, 0x11); // Get our email
- }
-
- case PSN_INFOCHANGED:
- if (!ppro->getString(AIM_KEY_SN, &dbv)) {
- SetDlgItemTextA(hwndDlg, IDC_FNAME, dbv.pszVal);
- db_free(&dbv);
- }
- if (!ppro->getString(AIM_KEY_EM, &dbv)) {
- SetDlgItemTextA(hwndDlg, IDC_CEMAIL, dbv.pszVal);
- db_free(&dbv);
- }
- break;
- }
- break;
-
- case WM_COMMAND:
- if (LOWORD(wParam) == IDC_SAVECHANGES) {
- if (!ppro->wait_conn(ppro->m_hAdminConn, ppro->m_hAdminEvent, 0x07)) // Make a connection
- break;
-
- char name[64];
- GetDlgItemTextA(hwndDlg, IDC_FNAME, name, _countof(name));
- if (mir_strlen(trim_str(name)) > 0 && !ppro->getString(AIM_KEY_SN, &dbv)) {
- if (mir_strcmp(name, dbv.pszVal))
- ppro->aim_admin_format_name(ppro->m_hAdminConn, ppro->m_admin_seqno, name);
- db_free(&dbv);
- }
-
- char email[254];
- GetDlgItemTextA(hwndDlg, IDC_CEMAIL, email, _countof(email));
- if (mir_strlen(trim_str(email)) > 1 && !ppro->getString(AIM_KEY_EM, &dbv)) // Must be greater than 1 or a SNAC error is thrown.
- {
- if (mir_strcmp(email, dbv.pszVal))
- ppro->aim_admin_change_email(ppro->m_hAdminConn, ppro->m_admin_seqno, email);
- db_free(&dbv);
- }
-
- ShowWindow(GetDlgItem(hwndDlg, IDC_PINFO), SW_HIDE);
-
- char cpw[256], npw1[256], npw2[256];
- GetDlgItemTextA(hwndDlg, IDC_CPW, cpw, _countof(cpw));
- GetDlgItemTextA(hwndDlg, IDC_NPW1, npw1, _countof(npw1));
- GetDlgItemTextA(hwndDlg, IDC_NPW2, npw2, _countof(npw2));
- if (cpw[0] != 0 && npw1[0] != 0 && npw2[0] != 0) {
- // AOL only requires that you send the current password and a (single) new password.
- // Let's allow the client to type (two) new passwords incase they make a mistake so we
- // can handle any input error locally.
- if (mir_strcmp(npw1, npw2) == 0) {
- ppro->aim_admin_change_password(ppro->m_hAdminConn, ppro->m_admin_seqno, cpw, npw1);
- }
- else {
- SetDlgItemTextA(hwndDlg, IDC_CPW, "");
- SetDlgItemTextA(hwndDlg, IDC_NPW1, "");
- SetDlgItemTextA(hwndDlg, IDC_NPW2, "");
- ShowWindow(GetDlgItem(hwndDlg, IDC_PINFO), SW_SHOW);
- }
- }
- }
- else if (LOWORD(wParam) == IDC_CONFIRM) // Confirmation
- {
- if (ppro->wait_conn(ppro->m_hAdminConn, ppro->m_hAdminEvent, 0x07)) // Make a connection
- ppro->aim_admin_account_confirm(ppro->m_hAdminConn, ppro->m_admin_seqno);
- }
- break;
- }
- return FALSE;
-}
-
-int CAimProto::OnUserInfoInit(WPARAM wParam, LPARAM lParam)
-{
- if (!lParam)//hContact
- {
- OPTIONSDIALOGPAGE odp = { 0 };
- odp.position = -1900000000;
- odp.flags = ODPF_USERINFOTAB | ODPF_UNICODE;
- odp.hInstance = hInstance;
- odp.szTitle.w = m_tszUserName;
- odp.dwInitParam = LPARAM(this);
-
- odp.szTab.w = LPGENW("Profile");
- odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO);
- odp.pfnDlgProc = userinfo_dialog;
- UserInfo_AddPage(wParam, &odp);
-
- odp.szTab.w = LPGENW("Admin");
- odp.pszTemplate = MAKEINTRESOURCEA(IDD_ADMIN);
- odp.pfnDlgProc = admin_dialog;
- UserInfo_AddPage(wParam, &odp);
- }
- return 0;
-}
-
-INT_PTR CAimProto::EditProfile(WPARAM, LPARAM)
-{
- DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_AIM), nullptr, userinfo_dialog, LPARAM(this));
- return 0;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Options dialog
-
-static INT_PTR CALLBACK options_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- CAimProto* ppro = (CAimProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
-
- switch (msg) {
- case WM_INITDIALOG:
- TranslateDialogDefault(hwndDlg);
-
- SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
- ppro = (CAimProto*)lParam;
- {
- DBVARIANT dbv;
- if (!ppro->getString(AIM_KEY_SN, &dbv)) {
- SetDlgItemTextA(hwndDlg, IDC_SN, dbv.pszVal);
- db_free(&dbv);
- }
- if (!ppro->getString(AIM_KEY_NK, &dbv)) {
- SetDlgItemTextA(hwndDlg, IDC_NK, dbv.pszVal);
- db_free(&dbv);
- }
- else if (!ppro->getString(AIM_KEY_SN, &dbv)) {
- SetDlgItemTextA(hwndDlg, IDC_NK, dbv.pszVal);
- db_free(&dbv);
- }
- if (!ppro->getString(AIM_KEY_PW, &dbv)) {
- SetDlgItemTextA(hwndDlg, IDC_PW, dbv.pszVal);
- db_free(&dbv);
- }
- if (!ppro->getString(AIM_KEY_HN, &dbv)) {
- SetDlgItemTextA(hwndDlg, IDC_HN, dbv.pszVal);
- db_free(&dbv);
- }
- else SetDlgItemTextA(hwndDlg, IDC_HN, AIM_DEFAULT_SERVER);
-
- SetDlgItemInt(hwndDlg, IDC_PN, ppro->get_default_port(), FALSE);
-
- CheckDlgButton(hwndDlg, IDC_DC, ppro->getByte(AIM_KEY_DC, 0) ? BST_CHECKED : BST_UNCHECKED);//Message Delivery Confirmation
- CheckDlgButton(hwndDlg, IDC_FP, ppro->getByte(AIM_KEY_FP, 0) ? BST_CHECKED : BST_UNCHECKED);//force proxy
- CheckDlgButton(hwndDlg, IDC_AT, ppro->getByte(AIM_KEY_AT, 0) ? BST_CHECKED : BST_UNCHECKED);//Account Type Icons
- CheckDlgButton(hwndDlg, IDC_ES, ppro->getByte(AIM_KEY_ES, 0) ? BST_CHECKED : BST_UNCHECKED);//Extended Status Type Icons
- CheckDlgButton(hwndDlg, IDC_HF, ppro->getByte(AIM_KEY_HF, 0) ? BST_CHECKED : BST_UNCHECKED);//Fake hiptopness
- CheckDlgButton(hwndDlg, IDC_DM, ppro->getByte(AIM_KEY_DM, 0) ? BST_CHECKED : BST_UNCHECKED);//Disable Sending Mode Message
- CheckDlgButton(hwndDlg, IDC_FI, ppro->getByte(AIM_KEY_FI, 1) ? BST_CHECKED : BST_UNCHECKED);//Format incoming messages
- CheckDlgButton(hwndDlg, IDC_FO, ppro->getByte(AIM_KEY_FO, 1) ? BST_CHECKED : BST_UNCHECKED);//Format outgoing messages
- CheckDlgButton(hwndDlg, IDC_II, ppro->getByte(AIM_KEY_II, 0) ? BST_CHECKED : BST_UNCHECKED);//Instant Idle
- CheckDlgButton(hwndDlg, IDC_CM, ppro->getByte(AIM_KEY_CM, 0) ? BST_CHECKED : BST_UNCHECKED);//Check Mail
- CheckDlgButton(hwndDlg, IDC_MG, ppro->getByte(AIM_KEY_MG, 1) ? BST_CHECKED : BST_UNCHECKED);//Manage Groups
- CheckDlgButton(hwndDlg, IDC_DA, ppro->getByte(AIM_KEY_DA, 0) ? BST_CHECKED : BST_UNCHECKED);//Disable Avatars
- CheckDlgButton(hwndDlg, IDC_DSSL, ppro->getByte(AIM_KEY_DSSL, 0) ? BST_CHECKED : BST_UNCHECKED);//Disable SSL
- CheckDlgButton(hwndDlg, IDC_CLIENTLOGIN, ppro->getByte(AIM_KEY_CLIENTLOGIN, 1) ? BST_CHECKED : BST_UNCHECKED);//use clientlogin
- {
- HWND dssl = GetDlgItem(hwndDlg, IDC_DSSL);
- bool clientlogin = ppro->getByte(AIM_KEY_CLIENTLOGIN, 1) != 0;
- EnableWindow(dssl, clientlogin);
- if(!clientlogin)
- CheckDlgButton(hwndDlg, IDC_DSSL, BST_CHECKED);
- }
- CheckDlgButton(hwndDlg, IDC_FSC, ppro->getByte(AIM_KEY_FSC, 0) ? BST_CHECKED : BST_UNCHECKED);//Force Single Client
- }
- break;
-
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
-
-
- case IDC_SVRRESET:
- SetDlgItemTextA(hwndDlg, IDC_HN, AIM_DEFAULT_SERVER);
- SetDlgItemInt(hwndDlg, IDC_PN, ppro->get_default_port(), FALSE);
- break;
-
- case IDC_SN:
- case IDC_PN:
- case IDC_NK:
- case IDC_PW:
- case IDC_HN:
- if (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())
- return 0;
- break;
- }
- if (IsDlgButtonChecked(hwndDlg, IDC_CLIENTLOGIN))
- {
- HWND dssl = GetDlgItem(hwndDlg, IDC_DSSL);
- EnableWindow(dssl, true);
- }
- else
- {
- HWND dssl = GetDlgItem(hwndDlg, IDC_DSSL);
- EnableWindow(dssl, false);
- CheckDlgButton(hwndDlg, IDC_DSSL, BST_CHECKED);
- }
- SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
- break;
-
- case WM_NOTIFY:
- switch (((LPNMHDR)lParam)->code) {
- case PSN_APPLY:
- {
- char str[128];
- //SN
- GetDlgItemTextA(hwndDlg, IDC_SN, str, _countof(str));
- if (str[0] != 0)
- ppro->setString(AIM_KEY_SN, str);
- else
- ppro->delSetting(AIM_KEY_SN);
- //END SN
-
- //NK
- if (GetDlgItemTextA(hwndDlg, IDC_NK, str, _countof(str)))
- ppro->setString(AIM_KEY_NK, str);
- else {
- GetDlgItemTextA(hwndDlg, IDC_SN, str, _countof(str));
- ppro->setString(AIM_KEY_NK, str);
- }
- //END NK
-
- //PW
- GetDlgItemTextA(hwndDlg, IDC_PW, str, _countof(str));
- if (str[0] != 0)
- ppro->setString(AIM_KEY_PW, str);
- else
- ppro->delSetting(AIM_KEY_PW);
- //END PW
-
- //HN
- GetDlgItemTextA(hwndDlg, IDC_HN, str, _countof(str));
- if (str[0] != 0 && mir_strcmp(str, AIM_DEFAULT_SERVER))
- ppro->setString(AIM_KEY_HN, str);
- else
- ppro->delSetting(AIM_KEY_HN);
- //END HN
-
- //Delivery Confirmation
- ppro->setByte(AIM_KEY_DC, IsDlgButtonChecked(hwndDlg, IDC_DC) != 0);
- //End Delivery Confirmation
-
- //Disable Avatar
- ppro->setByte(AIM_KEY_DA, IsDlgButtonChecked(hwndDlg, IDC_DA) != 0);
- //Disable Avatar
-
- //Disable SSL
- ppro->setByte(AIM_KEY_DSSL, IsDlgButtonChecked(hwndDlg, IDC_DSSL) != 0);
- //Disable SSL
-
- //use "clientlogin"
- ppro->setByte(AIM_KEY_CLIENTLOGIN, IsDlgButtonChecked(hwndDlg, IDC_CLIENTLOGIN) != 0);
- //use "clientlogin"
-
- //Force Single Login
- ppro->setByte(AIM_KEY_FSC, IsDlgButtonChecked(hwndDlg, IDC_FSC) != 0);
- //Force Single Login
-
- //Force Proxy Transfer
- ppro->setByte(AIM_KEY_FP, IsDlgButtonChecked(hwndDlg, IDC_FP) != 0);
- //End Force Proxy Transfer
-
- //PN
- int port = GetDlgItemInt(hwndDlg, IDC_PN, nullptr, FALSE);
- if (port > 0 && port != AIM_DEFAULT_PORT)
- ppro->setWord(AIM_KEY_PN, (WORD)port);
- else
- ppro->delSetting(AIM_KEY_PN);
- //END PN
-
- //Disable Account Type Icons
- if (IsDlgButtonChecked(hwndDlg, IDC_AT)) {
- int acc_disabled = ppro->getByte(AIM_KEY_AT, 0);
- if (!acc_disabled)
- remove_AT_icons(ppro);
- ppro->setByte(AIM_KEY_AT, 1);
- }
- else {
- int acc_disabled = ppro->getByte(AIM_KEY_AT, 0);
- if (acc_disabled)
- add_AT_icons(ppro);
- ppro->setByte(AIM_KEY_AT, 0);
- }
- //END
- //Disable Extra Status Icons
- if (IsDlgButtonChecked(hwndDlg, IDC_ES)) {
- int es_disabled = ppro->getByte(AIM_KEY_ES, 0);
- ppro->setByte(AIM_KEY_ES, 1);
- if (!es_disabled)
- remove_ES_icons(ppro);
- }
- else {
- int es_disabled = ppro->getByte(AIM_KEY_ES, 0);
- ppro->setByte(AIM_KEY_ES, 0);
- if (es_disabled)
- add_ES_icons(ppro);
- }
- //End
-
- //Fake Hiptop
- if (IsDlgButtonChecked(hwndDlg, IDC_HF)) {
- int hf = ppro->getByte(AIM_KEY_HF, 0);
- if (!hf)
- ShowWindow(GetDlgItem(hwndDlg, IDC_MASQ), SW_SHOW);
- ppro->setByte(AIM_KEY_HF, 1);
- }
- else {
- int hf = ppro->getByte(AIM_KEY_HF, 0);
- if (hf)
- ShowWindow(GetDlgItem(hwndDlg, IDC_MASQ), SW_SHOW);
- ppro->setByte(AIM_KEY_HF, 0);
- }
- //End
-
- //Disable Mode Message Sending
- ppro->setByte(AIM_KEY_DM, IsDlgButtonChecked(hwndDlg, IDC_DM) != 0);
- //End Disable Mode Message Sending
-
- //Format Incoming Messages
- ppro->setByte(AIM_KEY_FI, IsDlgButtonChecked(hwndDlg, IDC_FI) != 0);
- //End Format Incoming Messages
-
- //Format Outgoing Messages
- ppro->setByte(AIM_KEY_FO, IsDlgButtonChecked(hwndDlg, IDC_FO) != 0);
- //End Format Outgoing Messages
-
- //Instant Idle on Login
- ppro->setByte(AIM_KEY_II, IsDlgButtonChecked(hwndDlg, IDC_II) != 0);
- //End
- //Check Mail on Login
- ppro->setByte(AIM_KEY_CM, IsDlgButtonChecked(hwndDlg, IDC_CM) != 0);
- //End
-
- //Manage Groups
- ppro->setByte(AIM_KEY_MG, IsDlgButtonChecked(hwndDlg, IDC_MG) != 0);
- //End
- }
- }
- break;
- }
- return FALSE;
-}
-
-
-static INT_PTR CALLBACK privacy_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- static const int btns[] = { IDC_ALLOWALL, IDC_BLOCKALL, IDC_ALLOWBELOW, IDC_BLOCKBELOW, IDC_ALLOWCONT };
- CAimProto* ppro = (CAimProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
- int i;
-
- switch (msg) {
- case WM_INITDIALOG:
- TranslateDialogDefault(hwndDlg);
-
- SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
- ppro = (CAimProto*)lParam;
-
- CheckRadioButton(hwndDlg, IDC_ALLOWALL, IDC_BLOCKBELOW, btns[ppro->m_pd_mode - 1]);
-
- for (i = 0; i < ppro->m_allow_list.getCount(); ++i)
- SendDlgItemMessageA(hwndDlg, IDC_ALLOWLIST, LB_ADDSTRING, 0, (LPARAM)ppro->m_allow_list[i].name);
-
- for (i = 0; i < ppro->m_block_list.getCount(); ++i)
- SendDlgItemMessageA(hwndDlg, IDC_BLOCKLIST, LB_ADDSTRING, 0, (LPARAM)ppro->m_block_list[i].name);
-
- CheckDlgButton(hwndDlg, IDC_SIS, (ppro->m_pref1_flags & 0x400) ? BST_CHECKED : BST_CHECKED);
- break;
-
- case WM_COMMAND:
- if (LOWORD(wParam) == IDC_ALLOWADD) {
- char nick[80];
- GetDlgItemTextA(hwndDlg, IDC_ALLOWEDIT, nick, _countof(nick));
- SendDlgItemMessageA(hwndDlg, IDC_ALLOWLIST, LB_ADDSTRING, 0, (LPARAM)trim_str(nick));
- }
- else if (LOWORD(wParam) == IDC_BLOCKADD) {
- char nick[80];
- GetDlgItemTextA(hwndDlg, IDC_BLOCKEDIT, nick, _countof(nick));
- SendDlgItemMessageA(hwndDlg, IDC_BLOCKLIST, LB_ADDSTRING, 0, (LPARAM)trim_str(nick));
- }
- else if (LOWORD(wParam) == IDC_ALLOWREMOVE) {
- i = SendDlgItemMessage(hwndDlg, IDC_ALLOWLIST, LB_GETCURSEL, 0, 0);
- SendDlgItemMessage(hwndDlg, IDC_ALLOWLIST, LB_DELETESTRING, i, 0);
- }
- else if (LOWORD(wParam) == IDC_BLOCKREMOVE) {
- i = SendDlgItemMessage(hwndDlg, IDC_BLOCKLIST, LB_GETCURSEL, 0, 0);
- SendDlgItemMessage(hwndDlg, IDC_BLOCKLIST, LB_DELETESTRING, i, 0);
- }
-
- SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
- break;
-
- case WM_NOTIFY:
- if (((LPNMHDR)lParam)->code == PSN_APPLY) {
- ppro->aim_ssi_update(ppro->m_hServerConn, ppro->m_seqno, true);
- for (i = 0; i < 5; ++i) {
- if (IsDlgButtonChecked(hwndDlg, btns[i]) && ppro->m_pd_mode != i + 1) {
- ppro->m_pd_mode = (char)(i + 1);
- ppro->m_pd_flags = 1;
- ppro->aim_set_pd_info(ppro->m_hServerConn, ppro->m_seqno);
- break;
- }
- }
- for (i = 0; i < ppro->m_block_list.getCount(); ++i) {
- BdListItem& pd = ppro->m_block_list[i];
- if (SendDlgItemMessageA(hwndDlg, IDC_BLOCKLIST, LB_FINDSTRING, (WPARAM)-1, (LPARAM)pd.name) == LB_ERR) {
- ppro->aim_delete_contact(ppro->m_hServerConn, ppro->m_seqno, pd.name, pd.item_id, 0, 3, false);
- ppro->m_block_list.remove(i--);
- }
- }
- i = SendDlgItemMessage(hwndDlg, IDC_BLOCKLIST, LB_GETCOUNT, 0, 0);
- for (; i--;) {
- char nick[80];
- SendDlgItemMessageA(hwndDlg, IDC_BLOCKLIST, LB_GETTEXT, i, (LPARAM)nick);
- if (ppro->m_block_list.find_id(nick) == 0) {
- unsigned short id = ppro->m_block_list.add(nick);
- ppro->aim_add_contact(ppro->m_hServerConn, ppro->m_seqno, nick, id, 0, 3);
- }
- }
-
- for (i = 0; i < ppro->m_allow_list.getCount(); ++i) {
- BdListItem& pd = ppro->m_allow_list[i];
- if (SendDlgItemMessageA(hwndDlg, IDC_ALLOWLIST, LB_FINDSTRING, (WPARAM)-1, (LPARAM)pd.name) == LB_ERR) {
- ppro->aim_delete_contact(ppro->m_hServerConn, ppro->m_seqno, pd.name, pd.item_id, 0, 2, false);
- ppro->m_allow_list.remove(i--);
- }
- }
- i = SendDlgItemMessage(hwndDlg, IDC_ALLOWLIST, LB_GETCOUNT, 0, 0);
- for (; i--;) {
- char nick[80];
- SendDlgItemMessageA(hwndDlg, IDC_ALLOWLIST, LB_GETTEXT, i, (LPARAM)nick);
- if (ppro->m_allow_list.find_id(nick) == 0) {
- unsigned short id = ppro->m_allow_list.add(nick);
- ppro->aim_add_contact(ppro->m_hServerConn, ppro->m_seqno, nick, id, 0, 2);
- }
- }
-
- unsigned mask = (IsDlgButtonChecked(hwndDlg, IDC_SIS) == BST_CHECKED) << 10;
- if ((ppro->m_pref1_flags & 0x400) ^ mask) {
- ppro->m_pref1_flags = (ppro->m_pref1_flags & ~0x400) | mask;
- ppro->aim_ssi_update_preferences(ppro->m_hServerConn, ppro->m_seqno);
- }
-
- ppro->aim_ssi_update(ppro->m_hServerConn, ppro->m_seqno, false);
- }
- break;
- }
- return FALSE;
-}
-
-
-int CAimProto::OnOptionsInit(WPARAM wParam, LPARAM)
-{
- OPTIONSDIALOGPAGE odp = { 0 };
- odp.position = 1003000;
- odp.hInstance = hInstance;
- odp.szGroup.w = LPGENW("Network");
- odp.szTitle.w = m_tszUserName;
- odp.dwInitParam = LPARAM(this);
- odp.flags = ODPF_BOLDGROUPS | ODPF_UNICODE | ODPF_DONTTRANSLATE;
-
- odp.szTab.w = LPGENW("Basic");
- odp.pszTemplate = MAKEINTRESOURCEA(IDD_AIM);
- odp.pfnDlgProc = options_dialog;
- Options_AddPage(wParam, &odp);
-
- odp.szTab.w = LPGENW("Privacy");
- odp.pszTemplate = MAKEINTRESOURCEA(IDD_PRIVACY);
- odp.pfnDlgProc = privacy_dialog;
- Options_AddPage(wParam, &odp);
- return 0;
-}
-
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Brief account info dialog
-
-INT_PTR CALLBACK first_run_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- CAimProto* ppro = (CAimProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
-
- switch (msg) {
- case WM_INITDIALOG:
- TranslateDialogDefault(hwndDlg);
-
- ppro = (CAimProto*)lParam;
- SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
- {
- DBVARIANT dbv;
- if (!ppro->getString(AIM_KEY_SN, &dbv)) {
- SetDlgItemTextA(hwndDlg, IDC_SN, dbv.pszVal);
- db_free(&dbv);
- }
-
- if (!ppro->getString(AIM_KEY_PW, &dbv)) {
- SetDlgItemTextA(hwndDlg, IDC_PW, dbv.pszVal);
- db_free(&dbv);
- }
- }
- return TRUE;
-
- case WM_COMMAND:
- if (LOWORD(wParam) == IDC_NEWAIMACCOUNTLINK) {
- Utils_OpenUrl("http://www.aim.com/redirects/inclient/register.adp");
- return TRUE;
- }
-
- if (HIWORD(wParam) == EN_CHANGE && (HWND)lParam == GetFocus()) {
- switch (LOWORD(wParam)) {
- case IDC_SN:
- case IDC_PW:
- SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
- }
- }
- break;
-
- case WM_NOTIFY:
- if (((LPNMHDR)lParam)->code == (UINT)PSN_APPLY) {
- char str[128];
- GetDlgItemTextA(hwndDlg, IDC_SN, str, _countof(str));
- ppro->setString(AIM_KEY_SN, str);
-
- GetDlgItemTextA(hwndDlg, IDC_PW, str, _countof(str));
- ppro->setString(AIM_KEY_PW, str);
- return TRUE;
- }
- break;
- }
-
- return FALSE;
-}
-
-INT_PTR CAimProto::SvcCreateAccMgrUI(WPARAM, LPARAM lParam)
-{
- return (INT_PTR)CreateDialogParam(hInstance, MAKEINTRESOURCE(IDD_AIMACCOUNT),
- (HWND)lParam, first_run_dialog, (LPARAM)this);
-}
-
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Instant idle dialog
-
-INT_PTR CALLBACK instant_idle_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- CAimProto *ppro = (CAimProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
-
- switch (msg) {
- case WM_INITDIALOG:
- TranslateDialogDefault(hwndDlg);
-
- SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
- ppro = (CAimProto*)lParam;
- {
- Window_SetIcon_IcoLib(hwndDlg, GetIconHandle("idle"));
-
- unsigned long it = ppro->getDword(AIM_KEY_IIT, 0);
- unsigned long hours = it / 60;
- unsigned long minutes = it % 60;
- SetDlgItemInt(hwndDlg, IDC_IIH, hours, 0);
- SetDlgItemInt(hwndDlg, IDC_IIM, minutes, 0);
- }
- break;
-
- case WM_CLOSE:
- EndDialog(hwndDlg, 0);
- break;
-
- case WM_DESTROY:
- Window_FreeIcon_IcoLib(hwndDlg);
- break;
-
- case WM_COMMAND:
- {
- unsigned long hours = GetDlgItemInt(hwndDlg, IDC_IIH, nullptr, 0);
- unsigned short minutes = (unsigned short)GetDlgItemInt(hwndDlg, IDC_IIM, nullptr, 0);
- if (minutes > 59)
- minutes = 59;
-
- ppro->setDword(AIM_KEY_IIT, hours * 60 + minutes);
- switch (LOWORD(wParam)) {
- case IDOK:
- //Instant Idle
- if (ppro->m_state == 1) {
- ppro->aim_set_idle(ppro->m_hServerConn, ppro->m_seqno, hours * 60 * 60 + minutes * 60);
- ppro->m_instantidle = 1;
- }
- EndDialog(hwndDlg, IDOK);
- break;
-
- case IDCANCEL:
- ppro->aim_set_idle(ppro->m_hServerConn, ppro->m_seqno, 0);
- ppro->m_instantidle = 0;
- EndDialog(hwndDlg, IDCANCEL);
- break;
- }
- }
- break;
- }
- return FALSE;
-}
-
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Join chat dialog
-
-INT_PTR CALLBACK join_chat_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- CAimProto* ppro = (CAimProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
-
- switch (msg) {
- case WM_INITDIALOG:
- TranslateDialogDefault(hwndDlg);
-
- SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
- ppro = (CAimProto*)lParam;
- Window_SetIcon_IcoLib(hwndDlg, GetIconHandle("aol"));
- break;
-
- case WM_CLOSE:
- EndDialog(hwndDlg, 0);
- break;
-
- case WM_DESTROY:
- Window_FreeIcon_IcoLib(hwndDlg);
- break;
-
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- char room[128];
- GetDlgItemTextA(hwndDlg, IDC_ROOM, room, _countof(room));
- if (ppro->m_state == 1 && room[0] != 0) {
- chatnav_param* par = new chatnav_param(room, 4);
- ppro->ForkThread(&CAimProto::chatnav_request_thread, par);
- }
- EndDialog(hwndDlg, IDOK);
- break;
-
- case IDCANCEL:
- EndDialog(hwndDlg, IDCANCEL);
- break;
- }
- break;
- }
-
- return FALSE;
-}
-/////////////////////////////////////////////////////////////////////////////////////////
-// Invite to chat dialog
-
-static void clist_chat_invite_send(MCONTACT hItem, HWND hwndList, chat_list_item* item, CAimProto* ppro, char *msg)
-{
- 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)
- clist_chat_invite_send(hItemT, hwndList, item, ppro, msg);
- }
- else {
- int chk = SendMessage(hwndList, CLM_GETCHECKMARK, (WPARAM)hItem, 0);
- if (chk) {
- if (IsHContactInfo(hItem)) {
- wchar_t buf[128] = L"";
- SendMessage(hwndList, CLM_GETITEMTEXT, (WPARAM)hItem, (LPARAM)buf);
-
- char *sn = mir_u2a(buf);
- ppro->aim_chat_invite(ppro->m_hServerConn, ppro->m_seqno,
- item->cookie, item->exchange, item->instance, sn, msg);
- mir_free(sn);
- }
- else {
- DBVARIANT dbv;
- if (!ppro->getString(hItem, AIM_KEY_SN, &dbv)) {
- ppro->aim_chat_invite(ppro->m_hServerConn, ppro->m_seqno,
- item->cookie, item->exchange, item->instance, dbv.pszVal, msg);
- db_free(&dbv);
- }
- }
- }
- }
- hItem = (MCONTACT)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXT, (LPARAM)hItem);
- }
-}
-
-static void clist_validate_contact(MCONTACT hItem, HWND hwndList, CAimProto* ppro)
-{
- if (!ppro->is_my_contact(hItem) || ppro->isChatRoom(hItem) ||
- ppro->getWord(hItem, AIM_KEY_ST, ID_STATUS_OFFLINE) == ID_STATUS_ONTHEPHONE)
- SendMessage(hwndList, CLM_DELETEITEM, (WPARAM)hItem, 0);
-}
-
-static void clist_chat_prepare(MCONTACT hItem, HWND hwndList, CAimProto* 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)
- clist_chat_prepare(hItemT, hwndList, ppro);
- }
- else if (IsHContactContact(hItem))
- clist_validate_contact(hItem, hwndList, ppro);
-
- hItem = hItemN;
- }
-}
-
-INT_PTR CALLBACK invite_to_chat_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- invite_chat_param* param = (invite_chat_param*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
-
- switch (msg) {
- case WM_INITDIALOG:
- TranslateDialogDefault(hwndDlg);
-
- SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
- param = (invite_chat_param*)lParam;
-
- Window_SetIcon_IcoLib(hwndDlg, GetIconHandle("aol"));
- SetDlgItemTextA(hwndDlg, IDC_ROOMNAME, param->id);
- SetDlgItemTextA(hwndDlg, IDC_MSG, Translate("Join me in this buddy chat!"));
- break;
-
- case WM_CLOSE:
- EndDialog(hwndDlg, 0);
- break;
-
- case WM_NCDESTROY:
- Window_FreeIcon_IcoLib(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)
- clist_validate_contact((UINT_PTR)nmc->hItem, nmc->hdr.hwndFrom, param->ppro);
- break;
-
- case CLN_LISTREBUILT:
- if (param)
- clist_chat_prepare(NULL, nmc->hdr.hwndFrom, param->ppro);
- break;
- }
- }
- }
- break;
-
- case WM_COMMAND:
- {
- switch (LOWORD(wParam)) {
- case IDC_ADDSCR:
- if (param->ppro->m_state == 1) {
- wchar_t sn[64];
- GetDlgItemText(hwndDlg, IDC_EDITSCR, sn, _countof(sn));
-
- CLCINFOITEM cii = { 0 };
- cii.cbSize = sizeof(cii);
- cii.flags = CLCIIF_CHECKBOX | CLCIIF_BELOWCONTACTS;
- cii.pszText = sn;
-
- HANDLE hItem = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_CCLIST, CLM_ADDINFOITEM, 0, (LPARAM)&cii);
- SendDlgItemMessage(hwndDlg, IDC_CCLIST, CLM_SETCHECKMARK, (LPARAM)hItem, 1);
- }
- break;
-
- case IDOK:
- {
- chat_list_item* item = param->ppro->find_chat_by_id(param->id);
- if (item) {
- char buf[1024];
- GetDlgItemTextA(hwndDlg, IDC_MSG, buf, _countof(buf));
-
- HWND hwndList = GetDlgItem(hwndDlg, IDC_CCLIST);
- clist_chat_invite_send(NULL, hwndList, item, param->ppro, buf);
- }
- EndDialog(hwndDlg, IDOK);
- }
- break;
-
- case IDCANCEL:
- EndDialog(hwndDlg, IDCANCEL);
- break;
- }
- }
- break;
- }
- return FALSE;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Chat request dialog
-
-INT_PTR CALLBACK chat_request_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- invite_chat_req_param* param = (invite_chat_req_param*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
-
- switch (msg) {
- case WM_INITDIALOG:
- TranslateDialogDefault(hwndDlg);
-
- SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
- param = (invite_chat_req_param*)lParam;
-
- Window_SetIcon_IcoLib(hwndDlg, GetIconHandle("aol"));
-
- SetDlgItemTextA(hwndDlg, IDC_ROOMNAME, strrchr(param->cnp->id, '-') + 1);
- SetDlgItemTextA(hwndDlg, IDC_SCREENNAME, param->name);
- SetDlgItemTextA(hwndDlg, IDC_MSG, param->message);
- break;
-
- case WM_CLOSE:
- EndDialog(hwndDlg, 0);
- break;
-
- case WM_DESTROY:
- Window_FreeIcon_IcoLib(hwndDlg);
- delete param;
- break;
-
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- param->ppro->ForkThread(&CAimProto::chatnav_request_thread, param->cnp);
- EndDialog(hwndDlg, IDOK);
- break;
-
- case IDCANCEL:
- param->ppro->aim_chat_deny(param->ppro->m_hServerConn, param->ppro->m_seqno, param->name, param->icbm_cookie);
- delete param->cnp;
- EndDialog(hwndDlg, IDCANCEL);
- break;
- }
- break;
- }
- return FALSE;
-}
-
-
-void CALLBACK chat_request_cb(PVOID dwParam)
-{
- CreateDialogParam(hInstance, MAKEINTRESOURCE(IDD_CHATROOM_INVITE_REQ),
- nullptr, chat_request_dialog, (LPARAM)dwParam);
-}
diff --git a/protocols/AimOscar/src/ui.h b/protocols/AimOscar/src/ui.h deleted file mode 100644 index e6a1b984c0..0000000000 --- a/protocols/AimOscar/src/ui.h +++ /dev/null @@ -1,61 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2009 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 WINDOWS_H
-#define WINDOWS_H
-
-#ifndef CFM_BACKCOLOR
-#define CFM_BACKCOLOR 0x04000000
-#endif
-#ifndef CFE_AUTOBACKCOLOR
-#define CFE_AUTOBACKCOLOR CFM_BACKCOLOR
-#endif
-
-struct invite_chat_param
-{
- char* id;
- CAimProto* ppro;
-
- invite_chat_param(const char* idt, CAimProto* prt)
- { id = mir_strdup(idt); ppro = prt; }
-};
-
-struct invite_chat_req_param
-{
- chatnav_param* cnp;
- CAimProto* ppro;
- char* message;
- char* name;
- char* icbm_cookie;
-
- invite_chat_req_param(chatnav_param* cnpt, CAimProto* prt, char* msg, char* nm, char* icki)
- { cnp = cnpt; ppro = prt; message = mir_strdup(msg); name = mir_strdup(nm);
- icbm_cookie = (char*)mir_alloc(8); memcpy(icbm_cookie, icki, 8); }
-
- ~invite_chat_req_param()
- { mir_free(message); mir_free(name); mir_free(icbm_cookie); }
-};
-
-INT_PTR CALLBACK instant_idle_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
-INT_PTR CALLBACK join_chat_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
-INT_PTR CALLBACK invite_to_chat_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
-INT_PTR CALLBACK chat_request_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
-
-void CALLBACK chat_request_cb(PVOID dwParam);
-
-#endif
diff --git a/protocols/AimOscar/src/utility.cpp b/protocols/AimOscar/src/utility.cpp deleted file mode 100755 index eeb52b6f26..0000000000 --- a/protocols/AimOscar/src/utility.cpp +++ /dev/null @@ -1,663 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2012 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 "stdafx.h"
-
-void CAimProto::broadcast_status(int status)
-{
- debugLogA("Broadcast Status: %d", status);
- int old_status = m_iStatus;
- m_iStatus = status;
- if (m_iStatus == ID_STATUS_OFFLINE) {
- shutdown_file_transfers();
- shutdown_chat_conn();
-
- if (m_hServerConn) {
- aim_sendflap(m_hServerConn, 0x04, 0, nullptr, m_seqno);
- Netlib_Shutdown(m_hServerConn);
- }
-
- if (m_hMailConn && m_hMailConn != (HANDLE)1) {
- aim_sendflap(m_hMailConn, 0x04, 0, nullptr, m_mail_seqno);
- Netlib_Shutdown(m_hMailConn);
- }
- else if (m_hMailConn == (HANDLE)1)
- m_hMailConn = nullptr;
-
- if (m_hAvatarConn && m_hAvatarConn != (HANDLE)1) {
- aim_sendflap(m_hAvatarConn, 0x04, 0, nullptr, m_avatar_seqno);
- Netlib_Shutdown(m_hAvatarConn);
- }
- else if (m_hAvatarConn == (HANDLE)1)
- m_hAvatarConn = nullptr;
-
- if (m_hChatNavConn && m_hChatNavConn != (HANDLE)1) {
- aim_sendflap(m_hChatNavConn, 0x04, 0, nullptr, m_chatnav_seqno);
- Netlib_Shutdown(m_hChatNavConn);
- }
- else if (m_hChatNavConn == (HANDLE)1)
- m_hChatNavConn = nullptr;
-
- m_idle = false;
- m_instantidle = false;
- m_list_received = false;
- m_state = 0;
- m_iDesiredStatus = ID_STATUS_OFFLINE;
- replaceStr(m_last_status_msg, nullptr);
-
- m_avatar_id_lg = 0;
- m_avatar_id_sm = 0;
- replaceStr(m_hash_lg, nullptr);
- replaceStr(m_hash_sm, nullptr);
-
- m_pd_flags = 0;
- m_pd_info_id = 0;
- m_pd_mode = 0;
-
- m_seqno = 0;
- m_mail_seqno = 0;
- m_avatar_seqno = 0;
- m_chatnav_seqno = 0;
- m_admin_seqno = 0;
- }
- ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
-}
-
-void CAimProto::start_connection(void*)
-{
- if (m_iStatus <= ID_STATUS_OFFLINE) {
- offline_contacts();
- DBVARIANT dbv;
- if (!getString(AIM_KEY_SN, &dbv))
- db_free(&dbv);
- else {
- ShowPopup(LPGEN("Please, enter a user name in the options dialog."), 0);
- broadcast_status(ID_STATUS_OFFLINE);
- return;
- }
- if (!getString(AIM_KEY_PW, &dbv))
- db_free(&dbv);
- else {
- ShowPopup(LPGEN("Please, enter a password in the options dialog."), 0);
- broadcast_status(ID_STATUS_OFFLINE);
- return;
- }
-
-
- bool use_clientlogin = getByte(AIM_KEY_CLIENTLOGIN, 1) != 0; //clientlogin should be enabled by default
- if (!use_clientlogin)
- {
- char* login_url = getStringA(AIM_KEY_HN);
- //if (login_url == NULL) login_url = mir_strdup(use_ssl ? AIM_DEFAULT_SERVER : AIM_DEFAULT_SERVER_NS);
-
-
- if (login_url == nullptr) login_url = mir_strdup(AIM_DEFAULT_SERVER);
-
- m_hServerConn = aim_connect(login_url, get_default_port(), false, login_url); //ssl does not work anymore with old authorization algo
-
- mir_free(login_url);
-
- m_pref1_flags = 0x77ffff;
- m_pref1_set_flags = 0x77ffff;
- mir_free(m_pref2_flags); m_pref2_flags = nullptr; m_pref2_len = 0;
- mir_free(m_pref2_set_flags); m_pref2_set_flags = nullptr; m_pref2_set_len = 0;
-
- if (m_hServerConn)
- aim_connection_authorization();
- else
- broadcast_status(ID_STATUS_OFFLINE);
- }
- else
- {
- aim_connection_clientlogin();
-
- }
- }
-}
-
-bool CAimProto::wait_conn(HNETLIBCONN &hConn, HANDLE &hEvent, unsigned short service)
-{
- if (m_iStatus == ID_STATUS_OFFLINE)
- return false;
- {
- mir_cslock lck(connMutex);
- if (hConn == nullptr && m_hServerConn) {
- debugLogA("Starting Connection.");
- hConn = (HNETLIBCONN)1; //set so no additional service request attempts are made while aim is still processing the request
- aim_new_service_request(m_hServerConn, m_seqno, service);//general service connection!
- }
- }
-
- if (WaitForSingleObjectEx(hEvent, 10000, TRUE) != WAIT_OBJECT_0)
- return false;
-
- if (Miranda_IsTerminated() || m_iStatus == ID_STATUS_OFFLINE)
- return false;
-
- return true;
-}
-
-
-unsigned short CAimProto::get_default_port(void)
-{
- //return getWord(AIM_KEY_PN, getByte(AIM_KEY_DSSL, 0) ? AIM_DEFAULT_PORT : AIM_DEFAULT_SSL_PORT);
- return AIM_DEFAULT_PORT;
-}
-
-bool CAimProto::is_my_contact(MCONTACT hContact)
-{
- const char* szProto = GetContactProto(hContact);
- return szProto != nullptr && mir_strcmp(m_szModuleName, szProto) == 0;
-}
-
-MCONTACT CAimProto::find_chat_contact(const char* room)
-{
- for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) {
- DBVARIANT dbv;
- if (!getString(hContact, "ChatRoomID", &dbv)) {
- bool found = !mir_strcmp(room, dbv.pszVal);
- db_free(&dbv);
- if (found)
- return hContact;
- }
- }
- return NULL;
-}
-
-MCONTACT CAimProto::contact_from_sn(const char* sn, bool addIfNeeded, bool temporary)
-{
- ptrA norm_sn(normalize_name(sn));
-
- for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) {
- DBVARIANT dbv;
- if (!getString(hContact, AIM_KEY_SN, &dbv)) {
- bool found = !mir_strcmp(norm_sn, dbv.pszVal);
- db_free(&dbv);
- if (found)
- return hContact;
- }
- }
-
- if (addIfNeeded) {
- MCONTACT hContact = db_add_contact();
- if (hContact) {
- if (Proto_AddToContact(hContact, m_szModuleName) == 0) {
- setString(hContact, AIM_KEY_SN, norm_sn);
- setString(hContact, AIM_KEY_NK, sn);
- debugLogA("Adding contact %s to client side list.", norm_sn);
- if (temporary)
- db_set_b(hContact, "CList", "NotOnList", 1);
- return hContact;
- }
- db_delete_contact(hContact);
- }
- }
-
- return NULL;
-}
-
-void CAimProto::update_server_group(const char* group, unsigned short group_id)
-{
- unsigned short user_id_array_size;
- unsigned short* user_id_array;
-
- if (group_id)
- user_id_array = get_members_of_group(group_id, user_id_array_size);
- else {
- user_id_array_size = (unsigned short)m_group_list.getCount();
- user_id_array = (unsigned short*)mir_alloc(user_id_array_size * sizeof(unsigned short));
- for (unsigned short i = 0; i < user_id_array_size; ++i)
- user_id_array[i] = _htons(m_group_list[i].item_id);
- }
-
- debugLogA("Modifying group %s:%u on the serverside list", group, group_id);
- aim_mod_group(m_hServerConn, m_seqno, group, group_id, (char*)user_id_array,
- user_id_array_size * sizeof(unsigned short));
-
- mir_free(user_id_array);
-}
-
-void CAimProto::add_contact_to_group(MCONTACT hContact, const char* new_group)
-{
- if (new_group == nullptr)
- return;
-
- unsigned short old_group_id = getGroupId(hContact, 1);
- char *old_group = m_group_list.find_name(old_group_id);
- if (old_group && mir_strcmp(new_group, old_group) == 0)
- return;
-
- DBVARIANT dbv;
- char *nick = nullptr;
- if (!db_get_utf(hContact, MOD_KEY_CL, "MyHandle", &dbv)) {
- nick = NEWSTR_ALLOCA(dbv.pszVal);
- db_free(&dbv);
- }
-
- if (getString(hContact, AIM_KEY_SN, &dbv)) return;
-
- unsigned short item_id = getBuddyId(hContact, 1);
- unsigned short new_item_id = search_for_free_item_id(hContact);
- unsigned short new_group_id = m_group_list.find_id(new_group);
-
- if (!item_id)
- debugLogA("Contact %u not on list.", hContact);
-
- setGroupId(hContact, 1, new_group_id);
- if (new_group && mir_strcmp(new_group, AIM_DEFAULT_GROUP))
- db_set_utf(hContact, MOD_KEY_CL, OTH_KEY_GP, new_group);
- else
- db_unset(hContact, MOD_KEY_CL, OTH_KEY_GP);
-
- aim_ssi_update(m_hServerConn, m_seqno, true);
-
- if (new_group_id == 0) {
- create_group(new_group);
- debugLogA("Group %s not on list.", new_group);
- new_group_id = m_group_list.add(new_group);
- debugLogA("Adding group %s:%u to the serverside list", new_group, new_group_id);
- aim_add_contact(m_hServerConn, m_seqno, new_group, 0, new_group_id, 1);//add the group server-side even if it exist
- }
-
- debugLogA("Adding buddy %s:%u %s:%u to the serverside list", dbv.pszVal, new_item_id, new_group, new_group_id);
- aim_add_contact(m_hServerConn, m_seqno, dbv.pszVal, new_item_id, new_group_id, 0, nick);
-
- update_server_group(new_group, new_group_id);
-
- if (old_group_id && item_id) {
- bool is_not_in_list = getBool(hContact, AIM_KEY_NIL, false);
- debugLogA("Removing buddy %s:%u %s:%u from the serverside list", dbv.pszVal, item_id, old_group, old_group_id);
- aim_delete_contact(m_hServerConn, m_seqno, dbv.pszVal, item_id, old_group_id, 0, is_not_in_list);
- update_server_group(old_group, old_group_id);
- delSetting(hContact, AIM_KEY_NIL);
- }
-
- aim_ssi_update(m_hServerConn, m_seqno, false);
-
- db_free(&dbv);
-}
-
-void CAimProto::offline_contact(MCONTACT hContact, bool remove_settings)
-{
- if (remove_settings) {
- //We need some of this stuff if we are still online.
- for (int i = 1;; ++i) {
- if (deleteBuddyId(hContact, i)) break;
- deleteGroupId(hContact, i);
- }
-
- db_unset(hContact, MOD_KEY_CL, OTH_KEY_SM);
- }
- setWord(hContact, AIM_KEY_ST, ID_STATUS_OFFLINE);
-}
-
-void CAimProto::offline_contacts(void)
-{
- for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName))
- offline_contact(hContact, true);
-
- m_allow_list.destroy();
- m_block_list.destroy();
- m_group_list.destroy();
-}
-
-char *normalize_name(const char *s)
-{
- if (s == nullptr) return nullptr;
-
- char* buf = mir_strdup(s);
- _strlwr(buf);
- /*
- char *p = strchr(buf, ' ');
- if (p)
- {
- char *q = p;
- while (*p)
- {
- if (*p != ' ') *(q++) = *p;
- ++p;
- }
- *q = '\0';
- }
- */
- return buf;
-}
-
-char* trim_str(char* s)
-{
- if (s == nullptr) return nullptr;
- size_t len = mir_strlen(s);
-
- while (len) {
- if (isspace(s[len - 1])) --len;
- else break;
- }
- s[len] = 0;
-
- char* sc = s;
- while (isspace(*sc)) ++sc;
- memcpy(s, sc, mir_strlen(sc) + 1);
-
- return s;
-}
-
-void create_group(const char *group)
-{
- if (mir_strcmp(group, AIM_DEFAULT_GROUP) == 0) return;
-
- wchar_t* szGroupName = mir_utf8decodeW(group);
- Clist_GroupCreate(0, szGroupName);
- mir_free(szGroupName);
-}
-
-unsigned short CAimProto::search_for_free_item_id(MCONTACT hbuddy)//returns a free item id and links the id to the buddy
-{
- unsigned short id;
-
-retry:
- id = get_random();
-
- for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) {
- for (int i = 1; ; ++i) {
- unsigned short item_id = getBuddyId(hContact, i);
- if (item_id == 0) break;
-
- if (item_id == id) goto retry; //found one no need to look through anymore
- }
- }
-
- setBuddyId(hbuddy, 1, id);
- return id;
-}
-
-//returns the size of the list array aquired with data
-unsigned short* CAimProto::get_members_of_group(unsigned short group_id, unsigned short &size)
-{
- unsigned short* list = nullptr;
- size = 0;
-
- for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) {
- for (int i = 1; ; ++i) {
- unsigned short user_group_id = getGroupId(hContact, i);
- if (user_group_id == 0)
- break;
-
- if (group_id == user_group_id) {
- unsigned short buddy_id = getBuddyId(hContact, i);
- if (buddy_id) {
- list = (unsigned short*)mir_realloc(list, ++size*sizeof(list[0]));
- list[size - 1] = _htons(buddy_id);
- }
- }
- }
- }
- return list;
-}
-
-void CAimProto::upload_nicks(void)
-{
- for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) {
- DBVARIANT dbv;
- if (!db_get_utf(hContact, MOD_KEY_CL, "MyHandle", &dbv)) {
- set_local_nick(hContact, dbv.pszVal, nullptr);
- db_free(&dbv);
- }
- }
-}
-
-void CAimProto::set_local_nick(MCONTACT hContact, char* nick, char* note)
-{
- DBVARIANT dbv;
- if (getString(hContact, AIM_KEY_SN, &dbv)) return;
-
- for (int i = 1; ; ++i) {
- unsigned short group_id = getGroupId(hContact, i);
- if (group_id == 0) break;
-
- unsigned short buddy_id = getBuddyId(hContact, i);
- if (buddy_id == 0) break;
-
- aim_mod_buddy(m_hServerConn, m_seqno, dbv.pszVal, buddy_id, group_id, nick, note);
- }
- db_free(&dbv);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-unsigned short BdList::get_free_id(void)
-{
- unsigned short id;
-
-retry:
- id = get_random();
-
- for (int i = 0; i < count; ++i)
- if (items[i]->item_id == id) goto retry;
-
- return id;
-}
-
-unsigned short BdList::find_id(const char* name)
-{
- for (int i = 0; i < count; ++i) {
- if (_stricmp(items[i]->name, name) == 0)
- return items[i]->item_id;
- }
- return 0;
-}
-
-char* BdList::find_name(unsigned short id)
-{
- for (int i = 0; i < count; ++i) {
- if (items[i]->item_id == id)
- return items[i]->name;
- }
- return nullptr;
-}
-
-void BdList::remove_by_id(unsigned short id)
-{
- for (int i = 0; i < count; ++i) {
- if (items[i]->item_id == id) {
- remove(i);
- break;
- }
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-unsigned short CAimProto::getBuddyId(MCONTACT hContact, int i)
-{
- char item[sizeof(AIM_KEY_BI) + 10];
- mir_snprintf(item, AIM_KEY_BI"%d", i);
- return getWord(hContact, item, 0);
-}
-
-void CAimProto::setBuddyId(MCONTACT hContact, int i, unsigned short id)
-{
- char item[sizeof(AIM_KEY_BI) + 10];
- mir_snprintf(item, AIM_KEY_BI"%d", i);
- setWord(hContact, item, id);
-}
-
-int CAimProto::deleteBuddyId(MCONTACT hContact, int i)
-{
- char item[sizeof(AIM_KEY_BI) + 10];
- mir_snprintf(item, AIM_KEY_BI"%d", i);
- return delSetting(hContact, item);
-}
-
-unsigned short CAimProto::getGroupId(MCONTACT hContact, int i)
-{
- char item[sizeof(AIM_KEY_GI) + 10];
- mir_snprintf(item, AIM_KEY_GI"%d", i);
- return getWord(hContact, item, 0);
-}
-
-void CAimProto::setGroupId(MCONTACT hContact, int i, unsigned short id)
-{
- char item[sizeof(AIM_KEY_GI) + 10];
- mir_snprintf(item, AIM_KEY_GI"%d", i);
- setWord(hContact, item, id);
-}
-
-int CAimProto::deleteGroupId(MCONTACT hContact, int i)
-{
- char item[sizeof(AIM_KEY_GI) + 10];
- mir_snprintf(item, AIM_KEY_GI"%d", i);
- return delSetting(hContact, item);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-int CAimProto::open_contact_file(const char*, const wchar_t* file, const char*, wchar_t* &path, bool contact_dir)
-{
- path = (wchar_t*)mir_alloc(MAX_PATH * sizeof(wchar_t));
-
- int pos = mir_snwprintf(path, MAX_PATH, L"%s\\%S", VARSW(L"%miranda_userdata%"), m_szModuleName);
- if (contact_dir)
- pos += mir_snwprintf(path + pos, MAX_PATH - pos, L"\\%S", m_szModuleName);
-
- if (_waccess(path, 0))
- CreateDirectoryTreeW(path);
-
- mir_snwprintf(path + pos, MAX_PATH - pos, L"\\%s", file);
- int fid = _wopen(path, _O_CREAT | _O_RDWR | _O_BINARY, _S_IREAD);
- if (fid < 0) {
- wchar_t errmsg[512];
- mir_snwprintf(errmsg, TranslateT("Failed to open file: %s %s"), path, __tcserror(nullptr));
- ShowPopup((char*)errmsg, ERROR_POPUP | TCHAR_POPUP);
- }
- return fid;
-}
-
-void CAimProto::write_away_message(const char* sn, const char* msg, bool utf)
-{
- wchar_t* path;
- int fid = open_contact_file(sn, L"away.html", "wb", path, 1);
- if (fid >= 0) {
- if (utf) _write(fid, "\xEF\xBB\xBF", 3);
- char* s_msg = process_status_msg(msg, sn);
- _write(fid, "<h3>", 4);
- _write(fid, sn, (unsigned)mir_strlen(sn));
- _write(fid, "'s Away Message:</h3>", 21);
- _write(fid, s_msg, (unsigned)mir_strlen(s_msg));
- _close(fid);
- ShellExecute(nullptr, L"open", path, nullptr, nullptr, SW_SHOW);
- mir_free(path);
- mir_free(s_msg);
- }
-}
-
-void CAimProto::write_profile(const char* sn, const char* msg, bool utf)
-{
- wchar_t* path;
- int fid = open_contact_file(sn, L"profile.html", "wb", path, 1);
- if (fid >= 0) {
- if (utf) _write(fid, "\xEF\xBB\xBF", 3);
- char* s_msg = process_status_msg(msg, sn);
- _write(fid, "<h3>", 4);
- _write(fid, sn, (unsigned)mir_strlen(sn));
- _write(fid, "'s Profile:</h3>", 16);
- _write(fid, s_msg, (unsigned)mir_strlen(s_msg));
- _close(fid);
- ShellExecute(nullptr, L"open", path, nullptr, nullptr, SW_SHOW);
- mir_free(path);
- mir_free(s_msg);
- }
-}
-
-unsigned long aim_oft_checksum_chunk(unsigned long dwChecksum, const unsigned char *buffer, int len)
-{
- unsigned long checksum = (dwChecksum >> 16) & 0xffff;
-
- for (int i = 0; i < len; i++) {
- unsigned val = buffer[i];
-
- if ((i & 1) == 0)
- val <<= 8;
-
- if (checksum < val) ++val;
- checksum -= val;
- }
- checksum = ((checksum & 0x0000ffff) + (checksum >> 16));
- checksum = ((checksum & 0x0000ffff) + (checksum >> 16));
- return checksum << 16;
-}
-
-unsigned int aim_oft_checksum_file(wchar_t *filename, unsigned __int64 size)
-{
- unsigned long checksum = 0xffff0000;
- int fid = _wopen(filename, _O_RDONLY | _O_BINARY, _S_IREAD);
- if (fid >= 0) {
- unsigned __int64 sz = _filelengthi64(fid);
- if (size > sz) size = sz;
- while (size) {
- unsigned char buffer[8912];
- int bytes = (int)min(size, sizeof(buffer));
- bytes = _read(fid, buffer, bytes);
- size -= bytes;
- checksum = aim_oft_checksum_chunk(checksum, buffer, bytes);
- }
- _close(fid);
- }
- return checksum;
-}
-
-char* long_ip_to_char_ip(unsigned long host, char* ip)
-{
- host = _htonl(host);
- unsigned char* bytes = (unsigned char*)&host;
- size_t buf_loc = 0;
- for (int i = 0; i < 4; i++) {
- char store[16];
- _itoa(bytes[i], store, 10);
- size_t len = mir_strlen(store);
-
- memcpy(&ip[buf_loc], store, len);
- buf_loc += len;
- ip[buf_loc++] = '.';
- }
- ip[buf_loc - 1] = '\0';
-
- return ip;
-}
-
-unsigned long char_ip_to_long_ip(char* ip)
-{
- unsigned char chost[4] = { 0 };
- char *c = ip;
- for (int i = 0; i < 4; ++i) {
- chost[i] = (unsigned char)atoi(c);
- c = strchr(c, '.');
- if (c) ++c;
- else break;
- }
- return *(unsigned long*)&chost;
-}
-
-unsigned short get_random(void)
-{
- unsigned short id;
- Utils_GetRandom(&id, sizeof(id));
- id &= 0x7fff;
- return id;
-}
-
diff --git a/protocols/AimOscar/src/utility.h b/protocols/AimOscar/src/utility.h deleted file mode 100755 index 17d50af9e1..0000000000 --- a/protocols/AimOscar/src/utility.h +++ /dev/null @@ -1,64 +0,0 @@ -/*
-Plugin of Miranda IM for communicating with users of the AIM protocol.
-Copyright (c) 2008-2009 Boris Krasnovskiy
-Copyright (C) 2005-2006 Aaron Myles Landwehr
-
-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 UTILITY_H
-#define UTILITY_H
-
-char *normalize_name(const char *s);
-char* trim_str(char* s);
-void create_group(const char *group);
-unsigned int aim_oft_checksum_file(wchar_t *filename, unsigned __int64 size = -1);
-char* long_ip_to_char_ip(unsigned long host, char* ip);
-unsigned long char_ip_to_long_ip(char* ip);
-unsigned short get_random(void);
-
-inline int cap_cmp(const char* cap, const char* cap2) { return memcmp(cap, cap2, 16); }
-inline const char* alpha_cap_str(char ver) { return (ver & 0x80) ? " Alpha" : ""; }
-inline const char* secure_cap_str(char* ver) { return (*(int*)ver == 0xDEC0FE5A) ? " + SecureIM" : ""; }
-
-struct BdListItem
-{
- char* name;
- unsigned short item_id;
-
- BdListItem() { name = NULL; item_id = 0; }
- BdListItem(const char* snt, unsigned short id) { name = mir_strdup(snt); item_id = id; }
- ~BdListItem() { mir_free(name); }
-};
-
-struct BdList : public OBJLIST<BdListItem>
-{
- BdList() : OBJLIST<BdListItem>(5) {}
-
- void add(const char* snt, unsigned short id)
- { insert(new BdListItem(snt, id)); }
-
- unsigned short add(const char* snt)
- {
- unsigned short id = get_free_id();
- insert(new BdListItem(snt, id));
- return id;
- }
-
- unsigned short get_free_id(void);
- unsigned short find_id(const char* name);
- char* find_name(unsigned short id);
- void remove_by_id(unsigned short id);
-};
-
-#endif
diff --git a/protocols/AimOscar/src/version.h b/protocols/AimOscar/src/version.h deleted file mode 100644 index d64d0715bb..0000000000 --- a/protocols/AimOscar/src/version.h +++ /dev/null @@ -1,14 +0,0 @@ -#define __MAJOR_VERSION 0
-#define __MINOR_VERSION 11
-#define __RELEASE_NUM 0
-#define __BUILD_NUM 1
-
-#include <stdver.h>
-
-#define __PLUGIN_NAME "AIM protocol"
-#define __FILENAME "AIM.dll"
-#define __DESCRIPTION "AOL Instant Messenger (AIM) protocol support for Miranda NG."
-#define __AUTHOR "Boris Krasnovskiy, Aaron Myles Landwehr"
-#define __AUTHOREMAIL "borkra@miranda-im.org"
-#define __AUTHORWEB "https://miranda-ng.org/p/AIM/"
-#define __COPYRIGHT "© 2008-2011 Boris Krasnovskiy, 2005-2006 Aaron Myles Landwehr"
diff --git a/protocols/Discord/src/avatars.cpp b/protocols/Discord/src/avatars.cpp index d2b629e442..73c5b49da4 100644 --- a/protocols/Discord/src/avatars.cpp +++ b/protocols/Discord/src/avatars.cpp @@ -191,7 +191,7 @@ INT_PTR CDiscordProto::SetMyAvatar(WPARAM, LPARAM lParam) ptrA szFileContents((char*)mir_alloc(iFileLength)); fread(szFileContents, 1, iFileLength, in); fclose(in); - szPayload.Append(ptrA(mir_base64_encode((BYTE*)szFileContents.get(), iFileLength))); + szPayload.Append(ptrA(mir_base64_encode(szFileContents.get(), iFileLength))); JSONNode root; root << CHAR_PARAM("avatar", szPayload); Push(new AsyncHttpRequest(this, REQUEST_PATCH, "/users/@me", nullptr, &root)); diff --git a/protocols/Discord/src/gateway.cpp b/protocols/Discord/src/gateway.cpp index 0f59b9382e..228e6bad25 100644 --- a/protocols/Discord/src/gateway.cpp +++ b/protocols/Discord/src/gateway.cpp @@ -220,7 +220,7 @@ void CDiscordProto::GatewayThreadWorker() debugLogA("Got packet: buffer = %d, opcode = %d, headerSize = %d, final = %d, masked = %d", bufSize, hdr.opCode, hdr.headerSize, hdr.bIsFinal, hdr.bIsMasked); // we have some additional data, not only opcode - if (bufSize > hdr.headerSize) { + if ((size_t)bufSize > hdr.headerSize) { size_t currPacketSize = bufSize - hdr.headerSize; netbuf.append(buf, bufSize); while (currPacketSize < hdr.payloadSize) { diff --git a/protocols/Discord/src/main.cpp b/protocols/Discord/src/main.cpp index 808354befb..24c2b8e7b5 100644 --- a/protocols/Discord/src/main.cpp +++ b/protocols/Discord/src/main.cpp @@ -34,7 +34,6 @@ PLUGININFOEX pluginInfo = { PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), __DESCRIPTION, __AUTHOR, - __AUTHOREMAIL, __COPYRIGHT, __AUTHORWEB, UNICODE_AWARE, diff --git a/protocols/Discord/src/proto.h b/protocols/Discord/src/proto.h index 56c04ef157..5970ce26d3 100644 --- a/protocols/Discord/src/proto.h +++ b/protocols/Discord/src/proto.h @@ -26,64 +26,11 @@ struct AsyncHttpRequest : public NETLIBHTTPREQUEST, public MZeroedObject void *pUserInfo; }; -struct PARAM -{ - LPCSTR szName; - __forceinline PARAM(LPCSTR _name) : szName(_name) - {} -}; - -struct BOOL_PARAM : public PARAM -{ - bool bValue; - __forceinline BOOL_PARAM(LPCSTR _name, bool _value) : - PARAM(_name), bValue(_value) - {} -}; -AsyncHttpRequest* operator<<(AsyncHttpRequest*, const BOOL_PARAM&); - -struct INT_PARAM : public PARAM -{ - int iValue; - __forceinline INT_PARAM(LPCSTR _name, int _value) : - PARAM(_name), iValue(_value) - {} -}; AsyncHttpRequest* operator<<(AsyncHttpRequest*, const INT_PARAM&); - -struct INT64_PARAM : public PARAM -{ - SnowFlake iValue; - __forceinline INT64_PARAM(LPCSTR _name, SnowFlake _value) : - PARAM(_name), iValue(_value) - {} -}; AsyncHttpRequest* operator<<(AsyncHttpRequest*, const INT64_PARAM&); - -struct CHAR_PARAM : public PARAM -{ - LPCSTR szValue; - __forceinline CHAR_PARAM(LPCSTR _name, LPCSTR _value) : - PARAM(_name), szValue(_value) - {} -}; AsyncHttpRequest* operator<<(AsyncHttpRequest*, const CHAR_PARAM&); - -struct WCHAR_PARAM : public PARAM -{ - LPCWSTR wszValue; - __forceinline WCHAR_PARAM(LPCSTR _name, LPCWSTR _value) : - PARAM(_name), wszValue(_value) - {} -}; AsyncHttpRequest* operator<<(AsyncHttpRequest*, const WCHAR_PARAM&); -JSONNode& operator<<(JSONNode &json, const INT_PARAM ¶m); -JSONNode& operator<<(JSONNode &json, const INT64_PARAM ¶m); -JSONNode& operator<<(JSONNode &json, const BOOL_PARAM ¶m); -JSONNode& operator<<(JSONNode &json, const CHAR_PARAM ¶m); -JSONNode& operator<<(JSONNode &json, const WCHAR_PARAM ¶m); - ///////////////////////////////////////////////////////////////////////////////////////// struct CDiscordRole : public MZeroedObject diff --git a/protocols/Discord/src/utils.cpp b/protocols/Discord/src/utils.cpp index 2c0b254930..0b37e53167 100644 --- a/protocols/Discord/src/utils.cpp +++ b/protocols/Discord/src/utils.cpp @@ -42,40 +42,6 @@ int StrToStatus(const CMStringW &str) ///////////////////////////////////////////////////////////////////////////////////////// -JSONNode& operator<<(JSONNode &json, const INT_PARAM ¶m) -{ - json.push_back(JSONNode(param.szName, param.iValue)); - return json; -} - -JSONNode& operator<<(JSONNode &json, const INT64_PARAM ¶m) -{ - char tmp[100]; - _i64toa_s(param.iValue, tmp, _countof(tmp), 10); - json.push_back(JSONNode(param.szName, tmp)); - return json; -} - -JSONNode& operator<<(JSONNode &json, const BOOL_PARAM ¶m) -{ - json.push_back(JSONNode(param.szName, param.bValue)); - return json; -} - -JSONNode& operator<<(JSONNode &json, const CHAR_PARAM ¶m) -{ - json.push_back(JSONNode(param.szName, param.szValue)); - return json; -} - -JSONNode& operator<<(JSONNode &json, const WCHAR_PARAM ¶m) -{ - json.push_back(JSONNode(param.szName, ptrA(mir_utf8encodeW(param.wszValue)).get())); - return json; -} - -///////////////////////////////////////////////////////////////////////////////////////// - time_t StringToDate(const CMStringW &str) { struct tm T = { 0 }; diff --git a/protocols/Discord/src/version.h b/protocols/Discord/src/version.h index 2389a715d1..9114967209 100644 --- a/protocols/Discord/src/version.h +++ b/protocols/Discord/src/version.h @@ -9,6 +9,5 @@ #define __FILENAME "Discord.dll" #define __DESCRIPTION "Discord support for Miranda NG." #define __AUTHOR "George Hazan" -#define __AUTHOREMAIL "ghazan@miranda.im" #define __AUTHORWEB "https://miranda-ng.org/p/Discord/" #define __COPYRIGHT "© 2016-17 Miranda NG team" diff --git a/protocols/Dummy/src/main.cpp b/protocols/Dummy/src/main.cpp index 135358b7f8..99071455f4 100644 --- a/protocols/Dummy/src/main.cpp +++ b/protocols/Dummy/src/main.cpp @@ -29,7 +29,6 @@ PLUGININFOEX pluginInfo = PLUGIN_MAKE_VERSION(__MAJOR_VERSION,__MINOR_VERSION,__RELEASE_NUM,__BUILD_NUM),
__DESCRIPTION,
__AUTHOR,
- __AUTHOREMAIL,
__COPYRIGHT,
__AUTHORWEB,
UNICODE_AWARE,
diff --git a/protocols/Dummy/src/version.h b/protocols/Dummy/src/version.h index 99bef970b2..3a20fa8059 100644 --- a/protocols/Dummy/src/version.h +++ b/protocols/Dummy/src/version.h @@ -9,6 +9,5 @@ #define __FILENAME "Dummy.dll" #define __DESCRIPTION "Dummy protocol for Miranda NG. Could be used for holding contacts and history from deprecated protocols or for creating virtual contacts." #define __AUTHOR "Robert Pösel" -#define __AUTHOREMAIL "robyer@seznam.cz" #define __AUTHORWEB "https://miranda-ng.org/p/Dummy/" #define __COPYRIGHT "© 2014-17 Robert Pösel" diff --git a/protocols/EmLanProto/amdproto_15.vcxproj b/protocols/EmLanProto/amdproto_15.vcxproj deleted file mode 100644 index b8f71e960a..0000000000 --- a/protocols/EmLanProto/amdproto_15.vcxproj +++ /dev/null @@ -1,216 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="15.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>EmLanProto</ProjectName> - <ProjectGuid>{2115FEBC-1EC4-4F95-A058-A523ED5295A4}</ProjectGuid> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> - <ConfigurationType>DynamicLibrary</ConfigurationType> - <CharacterSet>MultiByte</CharacterSet> - <WholeProgramOptimization>true</WholeProgramOptimization> - <PlatformToolset>v141_xp</PlatformToolset> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> - <ConfigurationType>DynamicLibrary</ConfigurationType> - <CharacterSet>MultiByte</CharacterSet> - <WholeProgramOptimization>true</WholeProgramOptimization> - <PlatformToolset>v141_xp</PlatformToolset> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> - <ConfigurationType>DynamicLibrary</ConfigurationType> - <CharacterSet>MultiByte</CharacterSet> - <PlatformToolset>v141_xp</PlatformToolset> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> - <ConfigurationType>DynamicLibrary</ConfigurationType> - <CharacterSet>MultiByte</CharacterSet> - <PlatformToolset>v141_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)'=='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|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|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.40219.1</_ProjectFileVersion> - <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)\$(Configuration)\Plugins\</OutDir> - <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)\$(Configuration)64\Plugins\</OutDir> - <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)\$(Configuration)\Obj\$(ProjectName)\</IntDir> - <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)\$(Configuration)64\Obj\$(ProjectName)\</IntDir> - <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)\$(Configuration)\Plugins\</OutDir> - <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)\$(Configuration)64\Plugins\</OutDir> - <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)\$(Configuration)\Obj\$(ProjectName)\</IntDir> - <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;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <MinimalRebuild>true</MinimalRebuild> - <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> - <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> - <PrecompiledHeader>Use</PrecompiledHeader> - <WarningLevel>Level3</WarningLevel> - <DebugInformationFormat>EditAndContinue</DebugInformationFormat> - <ExceptionHandling>false</ExceptionHandling> - <AdditionalOptions>/Zc:threadSafeInit- %(AdditionalOptions)</AdditionalOptions> - </ClCompile> - <Link> - <AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> - <GenerateDebugInformation>true</GenerateDebugInformation> - <SubSystem>Windows</SubSystem> - <BaseAddress>0x22000000</BaseAddress> - <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> - <AdditionalLibraryDirectories>$(ProfileDir)..\..\libs\win$(PlatformArchitecture)</AdditionalLibraryDirectories> - <RandomizedBaseAddress>false</RandomizedBaseAddress> - <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> - </Link> - <ResourceCompile> - <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories> - <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - </ResourceCompile> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> - <ClCompile> - <Optimization>Disabled</Optimization> - <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> - <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> - <PrecompiledHeader>Use</PrecompiledHeader> - <WarningLevel>Level3</WarningLevel> - <ExceptionHandling>false</ExceptionHandling> - <AdditionalOptions>/Zc:threadSafeInit- %(AdditionalOptions)</AdditionalOptions> - </ClCompile> - <Link> - <AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> - <GenerateDebugInformation>true</GenerateDebugInformation> - <SubSystem>Windows</SubSystem> - <BaseAddress>0x22000000</BaseAddress> - <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> - <AdditionalLibraryDirectories>$(ProfileDir)..\..\libs\win$(PlatformArchitecture)</AdditionalLibraryDirectories> - <RandomizedBaseAddress>false</RandomizedBaseAddress> - </Link> - <ResourceCompile> - <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories> - <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - </ResourceCompile> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <ClCompile> - <Optimization>Full</Optimization> - <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> - <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <StringPooling>true</StringPooling> - <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet> - <PrecompiledHeader>Use</PrecompiledHeader> - <WarningLevel>Level3</WarningLevel> - <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> - <ExceptionHandling>false</ExceptionHandling> - <AdditionalOptions>/Zc:threadSafeInit- %(AdditionalOptions)</AdditionalOptions> - </ClCompile> - <Link> - <AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> - <SubSystem>Windows</SubSystem> - <OptimizeReferences>true</OptimizeReferences> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <BaseAddress>0x22000000</BaseAddress> - <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> - <AdditionalLibraryDirectories>$(ProfileDir)..\..\libs\win$(PlatformArchitecture)</AdditionalLibraryDirectories> - <GenerateDebugInformation>true</GenerateDebugInformation> - <AdditionalOptions>/PDBALTPATH:%_PDB% %(AdditionalOptions)</AdditionalOptions> - <RandomizedBaseAddress>false</RandomizedBaseAddress> - </Link> - <ResourceCompile> - <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories> - <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - </ResourceCompile> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> - <ClCompile> - <Optimization>Full</Optimization> - <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> - <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <StringPooling>true</StringPooling> - <PrecompiledHeader>Use</PrecompiledHeader> - <WarningLevel>Level3</WarningLevel> - <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> - <ExceptionHandling>false</ExceptionHandling> - <AdditionalOptions>/Zc:threadSafeInit- %(AdditionalOptions)</AdditionalOptions> - </ClCompile> - <Link> - <AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> - <GenerateDebugInformation>true</GenerateDebugInformation> - <SubSystem>Windows</SubSystem> - <OptimizeReferences>true</OptimizeReferences> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <BaseAddress>0x22000000</BaseAddress> - <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> - <AdditionalLibraryDirectories>$(ProfileDir)..\..\libs\win$(PlatformArchitecture)</AdditionalLibraryDirectories> - <AdditionalOptions>/PDBALTPATH:%_PDB% %(AdditionalOptions)</AdditionalOptions> - <RandomizedBaseAddress>false</RandomizedBaseAddress> - </Link> - <ResourceCompile> - <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories> - <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - </ResourceCompile> - </ItemDefinitionGroup> - <ItemGroup> - <ClCompile Include="src\amdproto.cpp" /> - <ClCompile Include="src\get_time.cpp" /> - <ClCompile Include="src\lan.cpp" /> - <ClCompile Include="src\mlan.cpp" /> - <ClCompile Include="src\stdafx.cpp"> - <PrecompiledHeader>Create</PrecompiledHeader> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ClInclude Include="src\get_time.h" /> - <ClInclude Include="src\lan.h" /> - <ClInclude Include="src\mlan.h" /> - <ClInclude Include="src\resource.h" /> - <ClInclude Include="src\stdafx.h" /> - <ClInclude Include="src\Version.h" /> - </ItemGroup> - <ItemGroup> - <ResourceCompile Include="res\amdproto.rc" /> - <ResourceCompile Include="res\Version.rc" /> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <ImportGroup Label="ExtensionTargets"> - </ImportGroup> -</Project>
\ No newline at end of file diff --git a/protocols/EmLanProto/amdproto_15.vcxproj.filters b/protocols/EmLanProto/amdproto_15.vcxproj.filters deleted file mode 100644 index 8d38c80fbe..0000000000 --- a/protocols/EmLanProto/amdproto_15.vcxproj.filters +++ /dev/null @@ -1,62 +0,0 @@ -<?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>{aa1fb7ce-7e83-46e8-b50b-cc87043ddfe8}</UniqueIdentifier> - <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm</Extensions> - </Filter> - <Filter Include="Header Files"> - <UniqueIdentifier>{c7da55a0-28ce-4c6f-acbe-8e2cba06f96d}</UniqueIdentifier> - <Extensions>h;hpp;hxx;hm;inl;inc</Extensions> - </Filter> - <Filter Include="Resource Files"> - <UniqueIdentifier>{ee329731-83da-4e3e-abb0-188efa6b23b2}</UniqueIdentifier> - <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions> - </Filter> - </ItemGroup> - <ItemGroup> - <ResourceCompile Include="res\amdproto.rc"> - <Filter>Resource Files</Filter> - </ResourceCompile> - <ResourceCompile Include="res\Version.rc"> - <Filter>Resource Files</Filter> - </ResourceCompile> - </ItemGroup> - <ItemGroup> - <ClCompile Include="src\amdproto.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\get_time.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\lan.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\mlan.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\stdafx.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ClInclude Include="src\get_time.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="src\lan.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="src\mlan.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="src\resource.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="src\stdafx.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/protocols/AimOscar/aim.vcxproj b/protocols/EmLanProto/emlanproto.vcxproj index e7e1191a55..27cf97a318 100644 --- a/protocols/AimOscar/aim.vcxproj +++ b/protocols/EmLanProto/emlanproto.vcxproj @@ -1,28 +1,33 @@ -<?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>AIM</ProjectName>
- <ProjectGuid>{736E59E5-CDCE-4C88-9C3A-E7913D45C9EC}</ProjectGuid>
- </PropertyGroup>
- <ImportGroup Label="PropertySheets">
- <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" />
- </ImportGroup>
+<?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>{2115FEBC-1EC4-4F95-A058-A523ED5295A4}</ProjectGuid> + <ProjectName>EmLanProto</ProjectName> + </PropertyGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" /> + </ImportGroup> + <ItemDefinitionGroup> + <ClCompile> + <ExceptionHandling>Sync</ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> </Project>
\ No newline at end of file diff --git a/protocols/AimOscar/aim.vcxproj.filters b/protocols/EmLanProto/emlanproto.vcxproj.filters index de5ad9f66c..fcae13a9d8 100644 --- a/protocols/AimOscar/aim.vcxproj.filters +++ b/protocols/EmLanProto/emlanproto.vcxproj.filters @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Project="$(ProjectDir)..\..\build\vc.common\common.filters" />
+<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(ProjectDir)..\..\build\vc.common\common.filters" /> </Project>
\ No newline at end of file diff --git a/protocols/EmLanProto/src/amdproto.cpp b/protocols/EmLanProto/src/amdproto.cpp index d25ebae2c8..1bcc43a24d 100644 --- a/protocols/EmLanProto/src/amdproto.cpp +++ b/protocols/EmLanProto/src/amdproto.cpp @@ -11,7 +11,6 @@ PLUGININFOEX pluginInfo = { PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
__DESCRIPTION,
__AUTHOR,
- __AUTHOREMAIL,
__COPYRIGHT,
__AUTHORWEB,
UNICODE_AWARE,
@@ -29,7 +28,7 @@ bool g_InitOptions = false; std::fstream emlanLog("EmLanLog.txt", std::ios::out|std::ios::app);
#endif
-extern "C" __declspec(dllexport) PLUGININFOEX* __cdecl MirandaPluginInfoEx(DWORD mirandaVersion)
+extern "C" __declspec(dllexport) PLUGININFOEX* __cdecl MirandaPluginInfoEx(DWORD)
{
return &pluginInfo;
}
@@ -96,7 +95,7 @@ static INT_PTR __cdecl EMPGetStatus(WPARAM, LPARAM) return g_lan->GetMirandaStatus();
}
-INT_PTR __cdecl EMPSetStatus(WPARAM new_status, LPARAM lParam)
+INT_PTR __cdecl EMPSetStatus(WPARAM new_status, LPARAM)
{
g_lan->SetMirandaStatus(new_status);
return 0;
@@ -125,7 +124,8 @@ static INT_PTR __cdecl EMPAddToList(WPARAM flags, LPARAM lParam) static INT_PTR __cdecl EMPBasicSearch(WPARAM, LPARAM lParam)
{
- return g_lan->Search((const char*)lParam);
+ const wchar_t *wszName = (const wchar_t*)lParam;
+ return g_lan->Search(_T2A(wszName));
}
static INT_PTR __cdecl EMPGetAwayMsg(WPARAM, LPARAM lParam)
@@ -148,27 +148,27 @@ static INT_PTR __cdecl EMPFileResume(WPARAM wParam, LPARAM lParam) return g_lan->FileResume((int)wParam, (PROTOFILERESUME*)lParam);
}
-static INT_PTR __cdecl EMPSendFileAllow(WPARAM wParam, LPARAM lParam)
+static INT_PTR __cdecl EMPSendFileAllow(WPARAM, LPARAM lParam)
{
return g_lan->FileAllow((CCSDATA*)lParam);
}
-static INT_PTR __cdecl EMPSendFileDeny(WPARAM wParam, LPARAM lParam)
+static INT_PTR __cdecl EMPSendFileDeny(WPARAM, LPARAM lParam)
{
return g_lan->FileDeny((CCSDATA*)lParam);
}
-static INT_PTR __cdecl EMPSendFileCancel(WPARAM wParam, LPARAM lParam)
+static INT_PTR __cdecl EMPSendFileCancel(WPARAM, LPARAM lParam)
{
return g_lan->FileCancel((CCSDATA*)lParam);
}
-static INT_PTR __cdecl EMPSendFile(WPARAM wParam, LPARAM lParam)
+static INT_PTR __cdecl EMPSendFile(WPARAM, LPARAM lParam)
{
return g_lan->SendFile((CCSDATA*)lParam);
}
-static INT_PTR __cdecl EMPRecvFile(WPARAM wParam, LPARAM lParam)
+static INT_PTR __cdecl EMPRecvFile(WPARAM, LPARAM lParam)
{
g_lan->RecvFile((CCSDATA*)lParam);
return 0;
@@ -188,7 +188,7 @@ INT_PTR CALLBACK EMPDlgProcMainOpts(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPAR int cind = 0;
for (int i = 0; i < count; i++) {
in_addr addr = g_lan->GetHostAddress(i);
- char* ipStr = inet_ntoa(addr);
+ wchar_t* ipStr = mir_a2u(inet_ntoa(addr));
if (addr.S_un.S_addr == caddr.S_un.S_addr)
cind = i;
SendDlgItemMessage(hwndDlg, IDC_LIST_IP, LB_ADDSTRING, 0, (LPARAM)ipStr);
@@ -276,7 +276,7 @@ int __cdecl EMPCreateOptionsDlg(WPARAM wParam, LPARAM) OPTIONSDIALOGPAGE odp = { 0 };
odp.position = 100000000;
odp.hInstance = g_hInstance;
- odp.pszTemplate = MAKEINTRESOURCE(IDD_EMP_FORM_OPT);
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_EMP_FORM_OPT);
odp.szTitle.a = LPGEN("E-mage LAN protocol");
odp.szGroup.a = LPGEN("Network");
odp.flags = ODPF_BOLDGROUPS;
@@ -287,7 +287,7 @@ int __cdecl EMPCreateOptionsDlg(WPARAM wParam, LPARAM) //////////////////////////////////////////////////////////////////////////
-INT_PTR CALLBACK EMPDlgProcMessage(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+INT_PTR CALLBACK EMPDlgProcMessage(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM)
{
HWND hwndOwner;
RECT rc, rcDlg, rcOwner;
diff --git a/protocols/EmLanProto/src/get_time.cpp b/protocols/EmLanProto/src/get_time.cpp index 76ad065fdf..6ffccc5047 100644 --- a/protocols/EmLanProto/src/get_time.cpp +++ b/protocols/EmLanProto/src/get_time.cpp @@ -19,7 +19,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "stdafx.h"
-
static int daysInMonth[]={31,28,31,30,31,30,31,31,30,31,30,31};
static int IsLeapYear(int year)
{
@@ -42,24 +41,6 @@ static DWORD YMDHMSToTime(int year,int month,int day,int hour,int minute,int sec return ret+3600*hour+60*minute+second;
}
-
-static DWORD TimestampLocalToGMT(DWORD from)
-{
- FILETIME ft1,ft2;
- LARGE_INTEGER liFiletime;
-
- //this huge number is the difference between 1970 and 1601 in seconds
- //liFiletime.QuadPart=(11644473600i64+(__int64)from)*10000000;
- __int64 t = 11644473600;
- liFiletime.QuadPart=(t+(__int64)from)*10000000;
- ft1.dwHighDateTime=liFiletime.HighPart;
- ft1.dwLowDateTime=liFiletime.LowPart;
- LocalFileTimeToFileTime(&ft1,&ft2);
- liFiletime.HighPart=ft2.dwHighDateTime;
- liFiletime.LowPart=ft2.dwLowDateTime;
- return (DWORD)(liFiletime.QuadPart/10000000-t);
-}
-
DWORD get_time()
{
SYSTEMTIME stime;
diff --git a/protocols/EmLanProto/src/lan.cpp b/protocols/EmLanProto/src/lan.cpp index 336e64bb75..301e2a8284 100644 --- a/protocols/EmLanProto/src/lan.cpp +++ b/protocols/EmLanProto/src/lan.cpp @@ -191,7 +191,7 @@ void CLan::SendPacket(in_addr addr, const u_char* mes, int len) addrTo.sin_addr = addr;
addrTo.sin_family = AF_INET;
addrTo.sin_port = PORT_NUMBER;
- int res = sendto(m_income, (const char*)mes, len, 0, (sockaddr*)&addrTo, sizeof(addrTo));
+ sendto(m_income, (const char*)mes, len, 0, (sockaddr*)&addrTo, sizeof(addrTo));
}
}
diff --git a/protocols/EmLanProto/src/lan.h b/protocols/EmLanProto/src/lan.h index 1fd2bbe80a..c6dc217c64 100644 --- a/protocols/EmLanProto/src/lan.h +++ b/protocols/EmLanProto/src/lan.h @@ -69,11 +69,11 @@ protected: void SendPacketBroadcast(const u_char* mes, int len);
//! Event - called when packet is received
- virtual void OnRecvPacket(u_char* mes, int len, in_addr from) { };
+ virtual void OnRecvPacket(u_char*, int, in_addr) { };
//! Event - called when new incoming tcp connection is created (new thread is created)
- virtual void OnInTCPConnection(u_long addr, SOCKET m_socket) { };
+ virtual void OnInTCPConnection(u_long, SOCKET) { };
//! Event - called when new outgoing tcp connection is created )new thread is created)
- virtual void OnOutTCPConnection(u_long addr, SOCKET m_socket, LPVOID lpParameter) {};
+ virtual void OnOutTCPConnection(u_long, SOCKET, LPVOID) {};
//! Creates new outgoing TCP connection
SOCKET CreateTCPConnection(u_long addr, LPVOID lpParameter);
diff --git a/protocols/EmLanProto/src/mlan.cpp b/protocols/EmLanProto/src/mlan.cpp index 14005a3294..6cd8255697 100644 --- a/protocols/EmLanProto/src/mlan.cpp +++ b/protocols/EmLanProto/src/mlan.cpp @@ -35,8 +35,6 @@ CMLan::CMLan() m_mirStatus = ID_STATUS_OFFLINE; m_pRootContact = nullptr; - - m_pRootContact = nullptr; m_hCheckThread = nullptr; m_handleId = 1; @@ -73,7 +71,7 @@ CMLan::~CMLan() void CMLan::DeleteCache() { - TContact* pCont = m_pRootContact; + TContact *pCont = m_pRootContact; m_pRootContact = nullptr; while (pCont) { delete[] pCont->m_nick; @@ -190,8 +188,9 @@ void CMLan::RequestStatus(bool answer, u_long addr) TPacket pak; memset(&pak, 0, sizeof(pak)); pak.flReqStatus = answer; - pak.strName = m_name; + pak.strName = mir_u2a(m_name); SendPacketExt(pak, addr); + mir_free(pak.strName); } void CMLan::SendPacketExt(TPacket& pak, u_long addr) @@ -283,9 +282,6 @@ void CMLan::OnRecvPacket(u_char* mes, int len, in_addr from) u_int rip = cont->m_addr.S_un.S_addr; int tip = (rip << 24) | ((rip & 0xff00) << 8) | ((rip & 0xff0000) >> 8) | (rip >> 24); db_set_dw(hContact, PROTONAME, "IP", tip); - // HOSTENT* host = gethostbyaddr((const char*)&rip, sizeof(rip), AF_INET); - // if (host) - // db_set_s(hContact, PROTONAME, "UID", host->h_name); } } } @@ -325,24 +321,22 @@ void CMLan::OnRecvPacket(u_char* mes, int len, in_addr from) } if (pak.idReqAwayMessage && cont) { - MCONTACT hContact = FindContact(cont->m_addr, cont->m_nick, true, false, false); // Removed - it causes that whoisreadingawaymessage plugin was not working - // if (hContact) - // { - // int IcqStatus = 0; - // switch (m_mirStatus) - // { - // case ID_STATUS_AWAY: IcqStatus = ICQ_MSGTYPE_GETAWAYMSG; break; - // case ID_STATUS_NA: IcqStatus = ICQ_MSGTYPE_GETNAMSG; break; - // case ID_STATUS_OCCUPIED: IcqStatus = ICQ_MSGTYPE_GETOCCUMSG; break; - // case ID_STATUS_DND: IcqStatus = ICQ_MSGTYPE_GETDNDMSG; break; - // case ID_STATUS_FREECHAT: IcqStatus = ICQ_MSGTYPE_GETFFCMSG; break; - // } - // // HACK: this is a real hack - // db_set_dw(hContact, "ICQ", "UIN", 1/*0xffffffff*/); - // NotifyEventHooks(m_hookIcqMsgReq, IcqStatus, 1/*0xffffffff*/); - // db_unset(hContact, "ICQ", "UIN"); - // } + // MCONTACT hContact = FindContact(cont->m_addr, cont->m_nick, true, false, false); + // if (hContact) { + // int IcqStatus = 0; + // switch (m_mirStatus) { + // case ID_STATUS_AWAY: IcqStatus = ICQ_MSGTYPE_GETAWAYMSG; break; + // case ID_STATUS_NA: IcqStatus = ICQ_MSGTYPE_GETNAMSG; break; + // case ID_STATUS_OCCUPIED: IcqStatus = ICQ_MSGTYPE_GETOCCUMSG; break; + // case ID_STATUS_DND: IcqStatus = ICQ_MSGTYPE_GETDNDMSG; break; + // case ID_STATUS_FREECHAT: IcqStatus = ICQ_MSGTYPE_GETFFCMSG; break; + // } + // // HACK: this is a real hack + // db_set_dw(hContact, "ICQ", "UIN", 1/*0xffffffff*/); + // NotifyEventHooks(m_hookIcqMsgReq, IcqStatus, 1/*0xffffffff*/); + // db_unset(hContact, "ICQ", "UIN"); + // } mir_cslock lck(m_csAccessAwayMes); @@ -370,7 +364,12 @@ void CMLan::OnRecvPacket(u_char* mes, int len, in_addr from) void CMLan::RecvMessageUrl(CCSDATA* ccs) { PROTORECVEVENT *pre = (PROTORECVEVENT*)ccs->lParam; - ptrA szMessage(Utf8Encode(pre->szMessage)); + ptrA szMessage; + // input string might be already utf8-encoded + if (Utf8CheckString(pre->szMessage)) + szMessage = mir_strdup(pre->szMessage); + else + szMessage = Utf8Encode(pre->szMessage); DBEVENTINFO dbei = {}; if (!mir_strcmp(ccs->szProtoService, PSR_MESSAGE)) @@ -410,31 +409,31 @@ INT_PTR CMLan::AddToContactList(u_int flags, EMPSEARCHRESULT *psr) int CMLan::SendMessageUrl(CCSDATA* ccs, bool isUrl) { int cid = GetRandomProcId(); - size_t len; + size_t len = 0; if (isUrl) { len = mir_strlen((char*)ccs->lParam); ((char*)ccs->lParam)[len] = 1; } - TDataHolder* hold = new TDataHolder(ccs, cid, isUrl ? LEXT_SENDURL : LEXT_SENDMESSAGE, this); + TDataHolder *hold = new TDataHolder(ccs, cid, isUrl ? LEXT_SENDURL : LEXT_SENDMESSAGE, this); if (isUrl) { ((char*)ccs->lParam)[len] = 0; hold->msg[len] = 0; } - CloseHandle(mir_forkthread(LaunchExt, (void*)hold)); + mir_forkthread(LaunchExt, hold); return cid; } int CMLan::Search(const char* name) { int cid = GetRandomProcId(); - CloseHandle(mir_forkthread(LaunchExt, (void*)new TDataHolder(name, cid, LEXT_SEARCH, this))); + mir_forkthread(LaunchExt, new TDataHolder(name, cid, LEXT_SEARCH, this)); return cid; } int CMLan::GetAwayMsg(CCSDATA* ccs) { int cid = GetRandomProcId(); - CloseHandle(mir_forkthread(LaunchExt, (void*)new TDataHolder(ccs, cid, LEXT_GETAWAYMSG, this))); + mir_forkthread(LaunchExt, new TDataHolder(ccs, cid, LEXT_GETAWAYMSG, this)); return cid; } @@ -484,10 +483,23 @@ void CMLan::SearchExt(TDataHolder* hold) psr.ipaddr = cont->m_addr.S_un.S_addr; psr.stat = cont->m_status; psr.ver = cont->m_ver; - ProtoBroadcastAck(PROTONAME, NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)hold->id, (LPARAM)&psr); } } + + // search string might contain some ip address + ULONG addr = inet_addr(hold->msg); + if (addr != INADDR_NONE) { + psr.nick.a = hold->msg; + psr.firstName.a = ""; + psr.lastName.a = ""; + psr.email.a = hold->msg; + psr.ipaddr = addr; + psr.stat = ID_STATUS_OFFLINE; + psr.ver = 0; + ProtoBroadcastAck(PROTONAME, NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)hold->id, (LPARAM)&psr); + } + ProtoBroadcastAck(PROTONAME, NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)hold->id, 0); delete hold; } @@ -582,7 +594,7 @@ u_char* CMLan::CreatePacket(TPacket& pak, int* pBufLen) if (pak.idStatus) len += 1 + 1 + 2; - size_t nameLen; + size_t nameLen = 0; if (pak.strName) { nameLen = mir_strlen(pak.strName); len += 1 + 1 + nameLen + 1; @@ -760,23 +772,17 @@ void CMLan::LoadSettings() m_RequiredIp = db_get_dw(NULL, PROTONAME, "ipaddr", 0); m_UseHostName = db_get_b(NULL, PROTONAME, "UseHostName", 1) != 0; if (m_UseHostName) { - gethostname(m_name, MAX_HOSTNAME_LEN); + m_nameLen = MAX_HOSTNAME_LEN; + GetComputerName(m_name, &m_nameLen); CharLower(m_name); } else { - DBVARIANT dbv; - // Deleting old 'Name' value - using 'Nick' instead of it now - if (db_get_s(NULL, PROTONAME, "Nick", &dbv)) { - if (db_get_s(NULL, PROTONAME, "Name", &dbv)) - dbv.pszVal = "EmLan_User"; - else - db_unset(NULL, PROTONAME, "Name"); - } - if (!dbv.pszVal[0]) - dbv.pszVal = "EmLan_User"; - mir_strcpy(m_name, dbv.pszVal); + ptrW nick(db_get_wsa(NULL, PROTONAME, "Nick")); + if (!nick) + nick = mir_wstrdup(L"EmLan_User"); + mir_wstrcpy(m_name, nick); } - m_nameLen = (int)mir_strlen(m_name); + m_nameLen = (int)mir_wstrlen(m_name); if (GetStatus() != LM_LISTEN) { int ipcount = GetHostAddrCount(); @@ -794,7 +800,7 @@ void CMLan::SaveSettings() { db_set_dw(NULL, PROTONAME, "ipaddr", m_RequiredIp); db_set_b(NULL, PROTONAME, "UseHostName", m_UseHostName); - db_set_s(NULL, PROTONAME, "Nick", m_name); + db_set_ws(NULL, PROTONAME, "Nick", m_name); } ////////////////////////////////////////////////////////////////////////// @@ -812,7 +818,7 @@ CMLan::TFileConnection::~TFileConnection() } delete[] m_szDescription; if (m_szFiles) { - char** cp = m_szFiles; + wchar_t** cp = m_szFiles; while (*cp) { delete[] * cp; cp++; @@ -1029,11 +1035,11 @@ void CMLan::OnInTCPConnection(u_long addr, SOCKET in_sock) char* pf_to = pre.szMessage + 4; char* pf_fr = (char*)conn->m_buf + 1 + 4 + 4; - conn->m_szFiles = new char*[rcTotalFiles + 1]; + conn->m_szFiles = new wchar_t*[rcTotalFiles + 1]; conn->m_szFiles[rcTotalFiles] = nullptr; for (int i = 0; i < rcTotalFiles; i++) { - conn->m_szFiles[i] = _strdup(pf_fr); + conn->m_szFiles[i] = mir_a2u(pf_fr); if (i) *pf_to++ = ' '; while (*pf_fr) @@ -1074,12 +1080,12 @@ void CMLan::OnInTCPConnection(u_long addr, SOCKET in_sock) } // Getting current directory - char path[MAX_PATH]; - char* pathpart; + wchar_t path[MAX_PATH]; + wchar_t* pathpart; GetFullPathName(conn->m_szDir, MAX_PATH, path, &pathpart); if (!SetCurrentDirectory(path)) { if (rcTotalFiles == 1) - conn->m_szRenamedFile = _strdup(pathpart); + conn->m_szRenamedFile = mir_wstrdup(pathpart); *pathpart = 0; if (!SetCurrentDirectory(path)) { conn->Send(nullptr, 0); @@ -1094,13 +1100,13 @@ void CMLan::OnInTCPConnection(u_long addr, SOCKET in_sock) PROTOFILETRANSFERSTATUS fts; fts.cbSize = sizeof(fts); + fts.flags = PFTS_UNICODE; + fts.hContact = conn->m_hContact; fts.totalBytes = rcTotalSize; fts.totalFiles = rcTotalFiles; fts.totalProgress = 0; - fts.szWorkingDir = conn->m_szDir; - fts.flags = false; - fts.hContact = conn->m_hContact; - fts.pszFiles = conn->m_szFiles; + fts.wszWorkingDir = conn->m_szDir; + fts.pwszFiles = conn->m_szFiles; bool err = false; @@ -1150,7 +1156,7 @@ void CMLan::OnInTCPConnection(u_long addr, SOCKET in_sock) } EMLOG("Still processing"); - char* filename = conn->m_szRenamedFile; + wchar_t* filename = conn->m_szRenamedFile; if (!filename) filename = conn->m_szFiles[fileNo]; @@ -1238,7 +1244,7 @@ void CMLan::OnInTCPConnection(u_long addr, SOCKET in_sock) delete conn; } -void CMLan::OnOutTCPConnection(u_long addr, SOCKET out_socket, LPVOID lpParameter) +void CMLan::OnOutTCPConnection(u_long, SOCKET out_socket, LPVOID lpParameter) { EMLOG("Sending OUT TCP connection"); TFileConnection* conn = (TFileConnection*)lpParameter; @@ -1258,13 +1264,13 @@ void CMLan::OnOutTCPConnection(u_long addr, SOCKET out_socket, LPVOID lpParamete FileAddToList(conn); u_char buf[FILE_SEND_BLOCK + 1]; - char name[MAX_PATH + 8]; + wchar_t name[MAX_PATH + 8]; buf[0] = FCODE_SND_FILEREQ; int len = 1 + 4 + 4; int size = 0; int filecount = 0; - char** pf = conn->m_szFiles; + wchar_t** pf = conn->m_szFiles; while (*pf) { // TODO: FIX IT ! EMLOG("Opening file"); @@ -1279,33 +1285,33 @@ void CMLan::OnOutTCPConnection(u_long addr, SOCKET out_socket, LPVOID lpParamete filecount++; CloseHandle(hFile); - char* filepart; - GetFullPathName(*pf, MAX_PATH, (char*)name, &filepart); + wchar_t* filepart; + GetFullPathName(*pf, MAX_PATH, name, &filepart); free(*pf); - *pf = _strdup(name); - mir_strcpy((char*)buf + len, filepart); - len += (int)mir_strlen(filepart) + 1; + *pf = mir_wstrdup(name); + mir_strcpy((char*)buf + len, _T2A(filepart)); + len += (int)mir_wstrlen(filepart) + 1; pf++; } - mir_strcpy((char*)buf + len, conn->m_szDescription); - len += (int)mir_strlen(conn->m_szDescription) + 1; + mir_strcpy((char*)buf + len, _T2A(conn->m_szDescription)); + len += (int)mir_wstrlen(conn->m_szDescription) + 1; *((int*)(buf + 1)) = size; *((int*)(buf + 1 + 4)) = filecount; GetCurrentDirectory(MAX_PATH, name); - conn->m_szDir = _strdup(name); + conn->m_szDir = mir_wstrdup(name); PROTOFILETRANSFERSTATUS fts; fts.cbSize = sizeof(fts); + fts.flags = PFTS_SENDING | PFTS_UNICODE; + fts.hContact = conn->m_hContact; fts.totalBytes = size; fts.totalFiles = filecount; fts.totalProgress = 0; - fts.szWorkingDir = conn->m_szDir; - fts.flags = PFTS_SENDING; - fts.hContact = conn->m_hContact; - fts.pszFiles = conn->m_szFiles; + fts.wszWorkingDir = conn->m_szDir; + fts.pwszFiles = conn->m_szFiles; EMLOG("Sending file size"); if (conn->Send(buf, len)) { @@ -1388,7 +1394,7 @@ void CMLan::OnOutTCPConnection(u_long addr, SOCKET out_socket, LPVOID lpParamete EMLOG("Ok"); buf[0] = FCODE_SND_FILEDATA; - if (readbytes != tosend) { + if ((int)readbytes != tosend) { EMLOG("Error during reading file. File was changed"); CloseHandle(hFile); conn->Send(nullptr, 0); @@ -1455,14 +1461,14 @@ int CMLan::SendFile(CCSDATA* ccs) conn->m_cid = cid; conn->m_hContact = ccs->hContact; - conn->m_szDescription = _strdup((char*)ccs->wParam); + conn->m_szDescription = mir_wstrdup((wchar_t*)ccs->wParam); int files = 0; - char** ppszFiles = (char**)ccs->lParam; + wchar_t** ppszFiles = (wchar_t**)ccs->lParam; while (ppszFiles[files]) files++; - conn->m_szFiles = new char*[files + 1]; + conn->m_szFiles = new wchar_t*[files + 1]; for (int i = 0; i < files; i++) - conn->m_szFiles[i] = _strdup(ppszFiles[i]); + conn->m_szFiles[i] = mir_wstrdup(ppszFiles[i]); conn->m_szFiles[files] = nullptr; u_long addr = db_get_dw(ccs->hContact, PROTONAME, "ipaddr", 0); @@ -1485,7 +1491,7 @@ int CMLan::FileAllow(CCSDATA* ccs) mir_cslock connLck(conn->m_csAccess); conn->m_state = TFileConnection::FCS_ALLOW; - conn->m_szDir = _strdup((char*)ccs->lParam); + conn->m_szDir = mir_wstrdup((wchar_t*)ccs->lParam); return cid; } @@ -1546,7 +1552,7 @@ int CMLan::FileResume(int cid, PROTOFILERESUME* pfr) case FILERESUME_RENAME: conn->m_state = TFileConnection::FCS_RENAME; delete[] conn->m_szRenamedFile; - conn->m_szRenamedFile = _strdup((char*)pfr->szFilename); + conn->m_szRenamedFile = mir_wstrdup(pfr->szFilename); break; case FILERESUME_SKIP: conn->m_state = TFileConnection::FCS_SKIP; diff --git a/protocols/EmLanProto/src/mlan.h b/protocols/EmLanProto/src/mlan.h index ed151e1212..a314c054cd 100644 --- a/protocols/EmLanProto/src/mlan.h +++ b/protocols/EmLanProto/src/mlan.h @@ -62,7 +62,7 @@ public: void LoadSettings();
void SaveSettings();
- char* GetName() { return m_name; }
+ wchar_t* GetName() { return m_name; }
bool GetUseHostName() { return m_UseHostName; }
void SetUseHostName(bool val) { m_UseHostName = val; }
void SetRequiredIp(u_long ip) { m_RequiredIp = ip; }
@@ -92,8 +92,8 @@ private: TContact* m_pRootContact;
HANDLE m_hCheckThread;
- char m_name[MAX_HOSTNAME_LEN];
- int m_nameLen;
+ wchar_t m_name[MAX_HOSTNAME_LEN];
+ DWORD m_nameLen;
mir_cs m_csAccessClass;
mir_cs m_csAccessAwayMes;
@@ -174,10 +174,10 @@ private: u_long m_addr;
MCONTACT m_hContact;
- char* m_szDescription;
- char** m_szFiles;
- char* m_szDir;
- char* m_szRenamedFile;
+ wchar_t* m_szDescription;
+ wchar_t** m_szFiles;
+ wchar_t* m_szDir;
+ wchar_t* m_szRenamedFile;
u_char* m_buf;
int m_recSize;
diff --git a/protocols/EmLanProto/src/stdafx.cpp b/protocols/EmLanProto/src/stdafx.cxx index fc3e963191..e8691edb87 100644 --- a/protocols/EmLanProto/src/stdafx.cpp +++ b/protocols/EmLanProto/src/stdafx.cxx @@ -1,8 +1,8 @@ -// stdafx.cpp : source file that includes just the standard includes
-// amdproto.pch will be the pre-compiled header
-// stdafx.obj will contain the pre-compiled type information
-
-#include "stdafx.h"
-
-// TODO: reference any additional headers you need in STDAFX.H
-// and not in this file
+// stdafx.cpp : source file that includes just the standard includes +// amdproto.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/protocols/EmLanProto/src/stdafx.h b/protocols/EmLanProto/src/stdafx.h index d826592439..8fefd8f2f8 100644 --- a/protocols/EmLanProto/src/stdafx.h +++ b/protocols/EmLanProto/src/stdafx.h @@ -5,7 +5,6 @@ #pragma once
-#define _CRT_SECURE_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
diff --git a/protocols/EmLanProto/src/version.h b/protocols/EmLanProto/src/version.h index e5c437a35c..4a9cf125ce 100644 --- a/protocols/EmLanProto/src/version.h +++ b/protocols/EmLanProto/src/version.h @@ -1,7 +1,7 @@ #define __MAJOR_VERSION 0 #define __MINOR_VERSION 1 #define __RELEASE_NUM 0 -#define __BUILD_NUM 1 +#define __BUILD_NUM 2 #include <stdver.h> #define __FILEVERSION_DWORD PLUGIN_MAKE_VERSION(__MAJOR_VERSION,__MINOR_VERSION,__RELEASE_NUM,__BUILD_NUM) @@ -10,6 +10,5 @@ #define __FILENAME "EmLanProto.dll" #define __DESCRIPTION "E-mage LAN protocol support for Miranda NG." #define __AUTHOR "kva" -#define __AUTHOREMAIL "kva@fromru.com" #define __AUTHORWEB "https://miranda-ng.org/p/EmLanProto/" #define __COPYRIGHT "© Viktor Kuzmin" diff --git a/protocols/FacebookRM/src/client.h b/protocols/FacebookRM/src/client.h index 8d80ea72ef..4d7fe6ef1e 100644 --- a/protocols/FacebookRM/src/client.h +++ b/protocols/FacebookRM/src/client.h @@ -161,7 +161,7 @@ public: }
__inline const char *__rev() {
- return "3496859"; // FIXME: Some version of communication protocol? This version is from 3.12.2017
+ return "2828561"; // FIXME: Some version of communication protocol? This version is from 12.2.2017
}
////////////////////////////////////////////////////////////
diff --git a/protocols/FacebookRM/src/json.cpp b/protocols/FacebookRM/src/json.cpp index aabf0823f1..2deb45172f 100644 --- a/protocols/FacebookRM/src/json.cpp +++ b/protocols/FacebookRM/src/json.cpp @@ -282,11 +282,6 @@ void parseAttachments(FacebookProto *proto, std::string *message_text, const JSO for (auto itAttachment = attachments_.begin(); itAttachment != attachments_.end(); ++itAttachment) { const JSONNode &attach_ = legacy ? (*itAttachment) : (*itAttachment)["mercury"]; - // FIXME: FB now doesn't have single "attach_type" node that we can check, but it's separated in different nodes. So we must check existence of different nodes for different types of attachments (or iterate over all existing nodes and check if some attachment node exists) - const JSONNode sticker_ = attach_["sticker_attachment"]; - const JSONNode blob_ = attach_["blob_attachment"]; - const JSONNode todo_ = attach_["todo"]; - type = attach_["attach_type"].as_string(); // "sticker", "photo", "file", "share", "animated_image", "video" if (type == "photo") { @@ -1462,43 +1457,3 @@ int facebook_json_parser::parse_messages_count(std::string *data, int *messagesC return EXIT_SUCCESS; } - -///////////////////////////////////////////////////////////////////////////////////////// - -JSONNode& operator<<(JSONNode &json, const NULL_PARAM ¶m) -{ - json.push_back(JSONNode(param.szName, nullptr)); - return json; -} - -JSONNode& operator<<(JSONNode &json, const JSON_PARAM ¶m) -{ - json.push_back(JSONNode(param.szName, param.node)); - return json; -} - -JSONNode& operator<<(JSONNode &json, const INT_PARAM ¶m) -{ - json.push_back(JSONNode(param.szName, param.iValue)); - return json; -} - -JSONNode& operator<<(JSONNode &json, const BOOL_PARAM ¶m) -{ - json.push_back(JSONNode(param.szName, param.bValue)); - return json; -} - -JSONNode& operator<<(JSONNode &json, const CHAR_PARAM ¶m) -{ - json.push_back(JSONNode(param.szName, param.szValue)); - return json; -} - -JSONNode& operator<<(JSONNode &json, const WCHAR_PARAM ¶m) -{ - json.push_back(JSONNode(param.szName, ptrA(mir_utf8encodeW(param.wszValue)).get())); - return json; -} - -/////////////////////////////////////////////////////////////////////////////////////////
\ No newline at end of file diff --git a/protocols/FacebookRM/src/json.h b/protocols/FacebookRM/src/json.h index 27dbbf1710..d62666a66d 100644 --- a/protocols/FacebookRM/src/json.h +++ b/protocols/FacebookRM/src/json.h @@ -47,63 +47,3 @@ public: this->proto = proto;
}
};
-
-struct PARAM
-{
- LPCSTR szName;
- __forceinline PARAM(LPCSTR _name) : szName(_name)
- {}
-};
-
-struct NULL_PARAM : public PARAM
-{
- __forceinline NULL_PARAM(LPCSTR _name) : PARAM(_name)
- {}
-};
-
-struct JSON_PARAM : public PARAM
-{
- JSONNode node;
- __forceinline JSON_PARAM(LPCSTR _name, JSONNode _node) :
- PARAM(_name), node(_node)
- {}
-};
-
-struct BOOL_PARAM : public PARAM
-{
- bool bValue;
- __forceinline BOOL_PARAM(LPCSTR _name, bool _value) :
- PARAM(_name), bValue(_value)
- {}
-};
-
-struct INT_PARAM : public PARAM
-{
- int iValue;
- __forceinline INT_PARAM(LPCSTR _name, int _value) :
- PARAM(_name), iValue(_value)
- {}
-};
-
-struct CHAR_PARAM : public PARAM
-{
- LPCSTR szValue;
- __forceinline CHAR_PARAM(LPCSTR _name, LPCSTR _value) :
- PARAM(_name), szValue(_value)
- {}
-};
-
-struct WCHAR_PARAM : public PARAM
-{
- LPCWSTR wszValue;
- __forceinline WCHAR_PARAM(LPCSTR _name, LPCWSTR _value) :
- PARAM(_name), wszValue(_value)
- {}
-};
-
-JSONNode& operator<<(JSONNode &json, const NULL_PARAM ¶m);
-JSONNode& operator<<(JSONNode &json, const JSON_PARAM ¶m);
-JSONNode& operator<<(JSONNode &json, const INT_PARAM ¶m);
-JSONNode& operator<<(JSONNode &json, const BOOL_PARAM ¶m);
-JSONNode& operator<<(JSONNode &json, const CHAR_PARAM ¶m);
-JSONNode& operator<<(JSONNode &json, const WCHAR_PARAM ¶m);
diff --git a/protocols/FacebookRM/src/main.cpp b/protocols/FacebookRM/src/main.cpp index 24ed75eeb1..fbf0eef6df 100644 --- a/protocols/FacebookRM/src/main.cpp +++ b/protocols/FacebookRM/src/main.cpp @@ -37,7 +37,6 @@ PLUGININFOEX pluginInfo = { PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
__DESCRIPTION,
__AUTHOR,
- __AUTHOREMAIL,
__COPYRIGHT,
__AUTHORWEB,
UNICODE_AWARE,
diff --git a/protocols/FacebookRM/src/messages.cpp b/protocols/FacebookRM/src/messages.cpp index ea3ad14b32..941f7f0327 100644 --- a/protocols/FacebookRM/src/messages.cpp +++ b/protocols/FacebookRM/src/messages.cpp @@ -204,7 +204,7 @@ void FacebookProto::StickerAsSmiley(std::string sticker, const std::string &url, if (facy.loading_history) return; - std::string b64 = ptrA(mir_base64_encode((PBYTE)sticker.c_str(), (unsigned)sticker.length())); + std::string b64 = ptrA(mir_base64_encode(sticker.c_str(), sticker.length())); b64 = utils::url::encode(b64); std::wstring filename = GetAvatarFolder() + L"\\stickers\\"; diff --git a/protocols/FacebookRM/src/proto.cpp b/protocols/FacebookRM/src/proto.cpp index c4f33dd222..17698d6e29 100644 --- a/protocols/FacebookRM/src/proto.cpp +++ b/protocols/FacebookRM/src/proto.cpp @@ -383,8 +383,8 @@ int FacebookProto::OnIdleChanged(WPARAM, LPARAM lParam) if (idle) { // User started being idle - MIRANDA_IDLE_INFO mii = { sizeof(mii) }; - CallService(MS_IDLE_GETIDLEINFO, 0, (LPARAM)&mii); + MIRANDA_IDLE_INFO mii; + Idle_GetInfo(mii); // Compute time when user really became idle m_idleTS = time(nullptr) - mii.idleTime * 60; diff --git a/protocols/FacebookRM/src/requests/contacts.h b/protocols/FacebookRM/src/requests/contacts.h index 960fb269b3..8fa60fced8 100644 --- a/protocols/FacebookRM/src/requests/contacts.h +++ b/protocols/FacebookRM/src/requests/contacts.h @@ -36,7 +36,7 @@ public: // getting info about particular friend -// revised 3.12.2017 +// revised 17.8.2016 class UserInfoRequest : public HttpRequest { public: @@ -60,11 +60,7 @@ public: << CHAR_VALUE("__rev", fc->__rev()) << "__a=1" << "__pc=PHASED:DEFAULT" - << "__be=1" - << "jazoest=" - << "__spin_r=" - << "__spin_b=" - << "__spin_t="; + << "__be=-1"; } }; diff --git a/protocols/FacebookRM/src/requests/history.h b/protocols/FacebookRM/src/requests/history.h index 88890a0f8e..9ac3d52168 100644 --- a/protocols/FacebookRM/src/requests/history.h +++ b/protocols/FacebookRM/src/requests/history.h @@ -24,20 +24,20 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #define _FACEBOOK_REQUEST_HISTORY_H_ // getting thread info and messages -// revised 3.12.2017 +// revised 17.8.2016 class ThreadInfoRequest : public HttpRequest { public: // Request only messages history ThreadInfoRequest(facebook_client *fc, bool isChat, const char *id, int offset, const char *timestamp, int limit) : - HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/api/graphqlbatch/") + HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/mercury/thread_info.php") { - setCommonBody(fc); + Url + << "dpr=1"; - // FIXME: FB removed /ajax/mercury/thread_info requests and now all messaging stuff does through /api/graphqlbatch/ - all loading of threads, (unread) messages, list of contacts in groupchat, etc. - // All these request must be rewritten to the new request. Preparation is below but unfinished. + setCommonBody(fc); - //const char *type = isChat ? "thread_fbids" : "user_ids"; + const char *type = isChat ? "thread_fbids" : "user_ids"; std::string id_ = id; // FIXME: Rewrite this without std::string... if (isChat) { // NOTE: Remove "id." prefix as here we need to give threadFbId and not threadId @@ -46,38 +46,6 @@ public: } ptrA idEncoded(mir_urlEncode(id_.c_str())); - - JSONNode root, o0, query_params; - - int before = -1; - - query_params - << CHAR_PARAM("id", id_) // TODO: Do I have to encode the id? And remove that first "id." at the begin as we do above? - << INT_PARAM("message_limit", limit) - << INT_PARAM("load_messages", 1) - << BOOL_PARAM("load_read_receipts", false); - - if (before != -1) { - query_params << INT_PARAM("before", before); - } - else { - query_params << NULL_PARAM("before"); - } - - o0 - << CHAR_PARAM("doc_id", id) - << JSON_PARAM("query_params", query_params); - - root << JSON_PARAM("o0", o0); - - Body - << "batch_name=MessengerGraphQLThreadFetcherRe" - << CHAR_VALUE("queries", root.write().c_str()); - - // example request data we need to send: { "o0":{"doc_id":"456789456123","query_params" : {"id":"123456789","message_limit" : 20,"load_messages" : 1,"load_read_receipts" : false,"before" : null}} } - - - /* //if (loadMessages) { // Grrr, offset doesn't work at all, we need to use timestamps to get back in history... // And we don't know, what's timestamp of first message, so we need to get from latest to oldest @@ -87,7 +55,7 @@ public: << CMStringA(::FORMAT, "%s[offset]=%i", begin.c_str(), offset).c_str() << CMStringA(::FORMAT, "%s[timestamp]=%s", begin.c_str(), timestamp).c_str() << CMStringA(::FORMAT, "%s[limit]=%i", begin.c_str(), limit).c_str(); - //}*/ + //} /*if (loadThreadInfo) { data += "&threads[" + type + "][0]=" + idEncoded; @@ -96,8 +64,11 @@ public: // Request only thread info // TODO: Make it array of ids ThreadInfoRequest(facebook_client *fc, bool isChat, const char *id) : - HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/api/graphqlbatch/") + HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/mercury/thread_info.php") { + Url + << "dpr=1"; + setCommonBody(fc); const char *type = isChat ? "thread_fbids" : "user_ids"; @@ -115,8 +86,11 @@ public: // Request both thread info and messages for single contact/chat ThreadInfoRequest(facebook_client *fc, bool isChat, const char *id, int limit) : - HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/api/graphqlbatch/") + HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/mercury/thread_info.php") { + Url + << "dpr=1"; + setCommonBody(fc); const char *type = isChat ? "thread_fbids" : "user_ids"; @@ -142,8 +116,11 @@ public: // Request both thread info and messages for more threads ThreadInfoRequest(facebook_client *fc, const LIST<char> &ids, int offset, int limit) : - HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/api/graphqlbatch/") + HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/mercury/thread_info.php") { + Url + << "dpr=1"; + setCommonBody(fc); for (int i = 0; i < ids.getCount(); i++) { @@ -169,6 +146,7 @@ private: void setCommonBody(facebook_client *fc) { Body + << "client=mercury" << CHAR_VALUE("__user", fc->self_.user_id.c_str()) << CHAR_VALUE("__dyn", fc->__dyn()) << CHAR_VALUE("__req", fc->__req()) @@ -177,11 +155,7 @@ private: << CHAR_VALUE("ttstamp", fc->ttstamp_.c_str()) << "__a=1" << "__pc=PHASED:DEFAULT" - << "__be=1" - << "jazoest=" - << "__spin_r=" - << "__spin_b=" - << "__spin_t="; + << "__be=-1"; } }; @@ -209,8 +183,6 @@ public: << "__a=1" << "__pc=PHASED:DEFAULT" << "__be=-1"; - - //queries={"o0":{"doc_id":"2003371749678240","query_params":{"limit":99,"before":null,"tags":["PENDING","unread"],"includeDeliveryReceipts":true,"includeSeqID":false}}} } }; diff --git a/protocols/FacebookRM/src/version.h b/protocols/FacebookRM/src/version.h index 1299f09155..08b34f8856 100644 --- a/protocols/FacebookRM/src/version.h +++ b/protocols/FacebookRM/src/version.h @@ -9,6 +9,5 @@ #define __FILENAME "Facebook.dll" #define __DESCRIPTION "Facebook protocol support for Miranda NG." #define __AUTHOR "Michal Zelinka, Robert Pösel" -#define __AUTHOREMAIL "robyer@seznam.cz" #define __AUTHORWEB "https://miranda-ng.org/p/Facebook/" #define __COPYRIGHT "© 2011-17 Robert Pösel, 2009-11 Michal Zelinka" diff --git a/protocols/Gadu-Gadu/src/avatar.cpp b/protocols/Gadu-Gadu/src/avatar.cpp index 0bdf8f04d7..096ae7bfbe 100644 --- a/protocols/Gadu-Gadu/src/avatar.cpp +++ b/protocols/Gadu-Gadu/src/avatar.cpp @@ -382,7 +382,7 @@ void __cdecl GGPROTO::setavatarthread(void *param) _read(file_fd, avatarFile, avatarFileLen);
_close(file_fd);
- ptrA avatarFileB64(mir_base64_encode((PBYTE)avatarFile, avatarFileLen));
+ ptrA avatarFileB64(mir_base64_encode(avatarFile, avatarFileLen));
mir_free(avatarFile);
ptrA avatarFileB64Enc(mir_urlEncode(avatarFileB64));
diff --git a/protocols/Gadu-Gadu/src/gg.cpp b/protocols/Gadu-Gadu/src/gg.cpp index f16fba3adb..48b578b1ec 100644 --- a/protocols/Gadu-Gadu/src/gg.cpp +++ b/protocols/Gadu-Gadu/src/gg.cpp @@ -30,7 +30,6 @@ PLUGININFOEX pluginInfo = { PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
__DESCRIPTION,
__AUTHOR,
- __AUTHOREMAIL,
__COPYRIGHT,
__AUTHORWEB,
UNICODE_AWARE,
diff --git a/protocols/Gadu-Gadu/src/version.h b/protocols/Gadu-Gadu/src/version.h index bd32b638e1..87f697f4fc 100644 --- a/protocols/Gadu-Gadu/src/version.h +++ b/protocols/Gadu-Gadu/src/version.h @@ -28,6 +28,5 @@ #define __PLUGIN_NAME "Gadu-Gadu protocol"
#define __DESCRIPTION "Gadu-Gadu protocol support for Miranda NG."
#define __AUTHOR "Bartosz Bialek, Adam Strzelecki"
-#define __AUTHOREMAIL "dezred"/*antispam*/"@"/*antispam*/"gmail"/*antispam*/"."/*antispam*/"com"
#define __COPYRIGHT "© 2009-2012 Bartosz Bialek, 2003-2009 Adam Strzelecki"
#define __AUTHORWEB "https://miranda-ng.org/p/GG/"
diff --git a/protocols/ICQCorp/src/corp.cpp b/protocols/ICQCorp/src/corp.cpp index 72d9de6ee7..27f4abaf00 100644 --- a/protocols/ICQCorp/src/corp.cpp +++ b/protocols/ICQCorp/src/corp.cpp @@ -32,7 +32,6 @@ PLUGININFOEX pluginInfo = PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
__DESCRIPTION,
__AUTHOR,
- __AUTHOREMAIL,
__COPYRIGHT,
__AUTHORWEB,
UNICODE_AWARE
diff --git a/protocols/ICQCorp/src/version.h b/protocols/ICQCorp/src/version.h index dd28b0b456..9376de1ca7 100644 --- a/protocols/ICQCorp/src/version.h +++ b/protocols/ICQCorp/src/version.h @@ -9,6 +9,5 @@ #define __FILENAME "ICQCorp.dll"
#define __DESCRIPTION "ICQ corporate protocol support for Miranda NG."
#define __AUTHOR "Miranda NG Team, Eugene Tarasenko"
-#define __AUTHOREMAIL ""
#define __AUTHORWEB "https://miranda-ng.org/p/ICQCorp/"
#define __COPYRIGHT "© 2014-17 Miranda NG Team, 2003-2005 Eugene Tarasenko"
diff --git a/protocols/IRCG/res/IRC.rc b/protocols/IRCG/res/IRC.rc index 3b7e3a71b9..9dc719003b 100644 --- a/protocols/IRCG/res/IRC.rc +++ b/protocols/IRCG/res/IRC.rc @@ -58,13 +58,13 @@ BEGIN LTEXT "Server name",IDC_STATIC,10,22,125,8,0,WS_EX_TRANSPARENT
COMBOBOX IDC_SERVERCOMBO,10,30,125,90,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
CONTROL "Internet address",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,10,45,81,8,WS_EX_TRANSPARENT
- EDITTEXT IDC_SERVER,10,53,88,12,ES_AUTOHSCROLL | ES_READONLY | WS_GROUP | WS_TABSTOP
+ EDITTEXT IDC_SERVER,10,53,88,12,ES_AUTOHSCROLL | ES_READONLY | WS_GROUP
LTEXT "SSL",IDC_STATIC,107,45,28,8,0,WS_EX_TRANSPARENT
- EDITTEXT IDC_SSL,107,53,28,12,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER | WS_TABSTOP,WS_EX_RIGHT
- LTEXT "Port range",IDC_STATIC,10,67,125,8,0,WS_EX_TRANSPARENT
- EDITTEXT IDC_PORT,10,75,50,12,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER | WS_TABSTOP,WS_EX_RIGHT
- LTEXT "->",IDC_STATIC,71,75,8,8
- EDITTEXT IDC_PORT2,85,75,50,12,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER | WS_TABSTOP,WS_EX_RIGHT
+ EDITTEXT IDC_SSL,107,53,28,12,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER,WS_EX_RIGHT
+ LTEXT "Port range",IDC_STATIC,10,67,79,8,0,WS_EX_TRANSPARENT
+ EDITTEXT IDC_PORT,10,75,33,12,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER,WS_EX_RIGHT
+ LTEXT "->",IDC_STATIC,45,76,8,8
+ EDITTEXT IDC_PORT2,54,75,33,12,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER,WS_EX_RIGHT
LTEXT "Password",IDC_STATIC,10,90,125,8,0,WS_EX_TRANSPARENT
EDITTEXT IDC_PASS,10,100,125,12,ES_PASSWORD | ES_AUTOHSCROLL
CONTROL "&Add",IDC_ADDSERVER,"MButtonClass",WS_DISABLED | WS_TABSTOP,16,116,27,14,WS_EX_NOACTIVATE | 0x10000000L
@@ -107,6 +107,7 @@ BEGIN RTEXT "Don't check if more than (users):",IDC_STATIC,142,212,124,8
EDITTEXT IDC_LIMIT,267,210,29,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT
CONTROL "Spin2",IDC_SPIN2,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,284,209,11,14
+ CONTROL "SASL",IDC_SASL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,103,77,32,10
END
IDD_INFO DIALOGEX 0, 0, 267, 214
@@ -202,8 +203,8 @@ BEGIN EDITTEXT IDC_ADD_ADDRESS,7,68,120,12,ES_AUTOHSCROLL | WS_GROUP
EDITTEXT IDC_ADD_PORT,7,92,47,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT
EDITTEXT IDC_ADD_PORT2,80,92,47,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT
- CONTROL "Auto",IDC_AUTO,"Button",BS_AUTORADIOBUTTON,139,52,32,10
- CONTROL "On",IDC_ON,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,139,69,32,10
+ CONTROL "Auto",IDC_AUTO,"Button",BS_AUTORADIOBUTTON | WS_GROUP,139,52,32,10
+ CONTROL "On",IDC_ON,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,139,69,32,10
CONTROL "Off",IDC_OFF,"Button",BS_AUTORADIOBUTTON,139,86,32,10
DEFPUSHBUTTON "&OK",IDOK,63,115,50,14
PUSHBUTTON "&Cancel",IDCANCEL,125,115,50,14
@@ -694,6 +695,18 @@ END //
IDR_SERVERS TEXT "..\\docs\\IRC_servers.ini"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// AFX_DIALOG_LAYOUT
+//
+
+IDD_PREFS_CONNECT AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
#endif // Neutral resources
/////////////////////////////////////////////////////////////////////////////
diff --git a/protocols/IRCG/src/commandmonitor.cpp b/protocols/IRCG/src/commandmonitor.cpp index 6694c24698..e07a5e6283 100644 --- a/protocols/IRCG/src/commandmonitor.cpp +++ b/protocols/IRCG/src/commandmonitor.cpp @@ -258,7 +258,7 @@ void __cdecl CIrcProto::ResolveIPThread(void *di) delete ipr;
}
-bool CIrcProto::OnIrc_PING(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_PING(const CIrcMessage *pmsg)
{
wchar_t szResponse[100];
if (pmsg->parameters.getCount() > 0)
@@ -269,7 +269,7 @@ bool CIrcProto::OnIrc_PING(const CIrcMessage* pmsg) return false;
}
-bool CIrcProto::OnIrc_WELCOME(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_WELCOME(const CIrcMessage *pmsg)
{
if (pmsg->parameters[0] != m_info.sNick)
m_info.sNick = pmsg->parameters[0];
@@ -294,7 +294,7 @@ bool CIrcProto::OnIrc_WELCOME(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_WHOTOOLONG(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_WHOTOOLONG(const CIrcMessage *pmsg)
{
CMStringW command = GetNextUserhostReason(2);
if (command[0] == 'U')
@@ -303,7 +303,7 @@ bool CIrcProto::OnIrc_WHOTOOLONG(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_BACKFROMAWAY(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_BACKFROMAWAY(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming) {
int Temp = m_iStatus;
@@ -318,7 +318,7 @@ bool CIrcProto::OnIrc_BACKFROMAWAY(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_SETAWAY(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_SETAWAY(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming) {
int Temp = m_iDesiredStatus;
@@ -357,7 +357,7 @@ bool CIrcProto::OnIrc_SETAWAY(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_JOIN(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_JOIN(const CIrcMessage *pmsg)
{
if (pmsg->parameters.getCount() > 0 && pmsg->m_bIncoming && pmsg->prefix.sNick != m_info.sNick) {
CMStringW host = pmsg->prefix.sUser + L"@" + pmsg->prefix.sHost;
@@ -369,7 +369,7 @@ bool CIrcProto::OnIrc_JOIN(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_QUIT(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_QUIT(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming) {
CMStringW host = pmsg->prefix.sUser + L"@" + pmsg->prefix.sHost;
@@ -384,7 +384,7 @@ bool CIrcProto::OnIrc_QUIT(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_PART(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_PART(const CIrcMessage *pmsg)
{
if (pmsg->parameters.getCount() > 0 && pmsg->m_bIncoming) {
CMStringW host = pmsg->prefix.sUser + L"@" + pmsg->prefix.sHost;
@@ -399,7 +399,7 @@ bool CIrcProto::OnIrc_PART(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_KICK(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_KICK(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && pmsg->parameters.getCount() > 1)
DoEvent(GC_EVENT_KICK, pmsg->parameters[0], pmsg->parameters[1], pmsg->parameters.getCount() > 2 ? pmsg->parameters[2].c_str() : nullptr, pmsg->prefix.sNick, nullptr, NULL, true, false);
@@ -422,7 +422,7 @@ bool CIrcProto::OnIrc_KICK(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_MODEQUERY(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_MODEQUERY(const CIrcMessage *pmsg)
{
if (pmsg->parameters.getCount() > 2 && pmsg->m_bIncoming && IsChannel(pmsg->parameters[1])) {
CMStringW sPassword = L"";
@@ -456,7 +456,7 @@ bool CIrcProto::OnIrc_MODEQUERY(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_MODE(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_MODE(const CIrcMessage *pmsg)
{
bool flag = false;
bool bContainsValidModes = false;
@@ -567,7 +567,7 @@ bool CIrcProto::OnIrc_MODE(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_NICK(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_NICK(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && pmsg->parameters.getCount() > 0) {
bool bIsMe = pmsg->prefix.sNick == m_info.sNick ? true : false;
@@ -596,7 +596,7 @@ bool CIrcProto::OnIrc_NICK(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_NOTICE(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_NOTICE(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && pmsg->parameters.getCount() > 1) {
if (IsCTCP(pmsg))
@@ -639,7 +639,7 @@ bool CIrcProto::OnIrc_NOTICE(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_YOURHOST(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_YOURHOST(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming) {
static const wchar_t* lpszFmt = L"Your host is %99[^ \x5b,], running version %99s";
@@ -654,7 +654,7 @@ bool CIrcProto::OnIrc_YOURHOST(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_INVITE(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_INVITE(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && (m_ignore && IsIgnored(pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'i')))
return true;
@@ -666,7 +666,7 @@ bool CIrcProto::OnIrc_INVITE(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_PINGPONG(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_PINGPONG(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && pmsg->sCommand == L"PING") {
wchar_t szResponse[100];
@@ -677,7 +677,7 @@ bool CIrcProto::OnIrc_PINGPONG(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_PRIVMSG(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_PRIVMSG(const CIrcMessage *pmsg)
{
if (pmsg->parameters.getCount() > 1) {
if (IsCTCP(pmsg))
@@ -727,7 +727,7 @@ bool CIrcProto::OnIrc_PRIVMSG(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::IsCTCP(const CIrcMessage* pmsg)
+bool CIrcProto::IsCTCP(const CIrcMessage *pmsg)
{
// is it a ctcp command, i e is the first and last characer of a PRIVMSG or NOTICE text ASCII 1
CMStringW mess = pmsg->parameters[1];
@@ -1232,7 +1232,7 @@ bool CIrcProto::IsCTCP(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_NAMES(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_NAMES(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && pmsg->parameters.getCount() > 3)
sNamesList += pmsg->parameters[3] + L" ";
@@ -1240,7 +1240,7 @@ bool CIrcProto::OnIrc_NAMES(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_ENDNAMES(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_ENDNAMES(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && pmsg->parameters.getCount() > 1) {
CMStringW name = L"a";
@@ -1411,7 +1411,7 @@ bool CIrcProto::OnIrc_ENDNAMES(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_INITIALTOPIC(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_INITIALTOPIC(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && pmsg->parameters.getCount() > 2) {
AddWindowItemData(pmsg->parameters[1], nullptr, nullptr, nullptr, pmsg->parameters[2]);
@@ -1423,7 +1423,7 @@ bool CIrcProto::OnIrc_INITIALTOPIC(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_INITIALTOPICNAME(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_INITIALTOPICNAME(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && pmsg->parameters.getCount() > 3) {
wchar_t tTimeBuf[128], *tStopStr;
@@ -1437,7 +1437,7 @@ bool CIrcProto::OnIrc_INITIALTOPICNAME(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_TOPIC(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_TOPIC(const CIrcMessage *pmsg)
{
if (pmsg->parameters.getCount() > 1 && pmsg->m_bIncoming) {
DoEvent(GC_EVENT_TOPIC, pmsg->parameters[0], pmsg->prefix.sNick, pmsg->parameters[1], nullptr, sTopicTime.IsEmpty() ? nullptr : sTopicTime.c_str(), NULL, true, false);
@@ -1457,7 +1457,7 @@ static void __stdcall sttShowDlgList(void* param) SetEvent(ppro->m_evWndCreate);
}
-bool CIrcProto::OnIrc_LISTSTART(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_LISTSTART(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming) {
CallFunctionAsync(sttShowDlgList, this);
@@ -1469,7 +1469,7 @@ bool CIrcProto::OnIrc_LISTSTART(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_LIST(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_LIST(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming == 1 && m_listDlg && pmsg->parameters.getCount() > 2) {
m_channelNumber++;
@@ -1526,7 +1526,7 @@ bool CIrcProto::OnIrc_LIST(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_LISTEND(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_LISTEND(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && m_listDlg) {
EnableWindow(GetDlgItem(m_listDlg->GetHwnd(), IDC_JOIN), true);
@@ -1551,7 +1551,7 @@ bool CIrcProto::OnIrc_LISTEND(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_BANLIST(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_BANLIST(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && pmsg->parameters.getCount() > 2) {
if (m_managerDlg->GetHwnd() && (
@@ -1580,7 +1580,7 @@ bool CIrcProto::OnIrc_BANLIST(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_BANLISTEND(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_BANLISTEND(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && pmsg->parameters.getCount() > 1) {
if (m_managerDlg->GetHwnd() &&
@@ -1617,7 +1617,7 @@ static void __stdcall sttShowWhoisWnd(void* param) delete pmsg;
}
-bool CIrcProto::OnIrc_WHOIS_NAME(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_WHOIS_NAME(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && pmsg->parameters.getCount() > 5 && m_manualWhoisCount > 0) {
CallFunctionAsync(sttShowWhoisWnd, new CIrcMessage(*pmsg));
@@ -1627,7 +1627,7 @@ bool CIrcProto::OnIrc_WHOIS_NAME(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_WHOIS_CHANNELS(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_WHOIS_CHANNELS(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0)
m_whoisDlg->m_InfoChannels.SetText(pmsg->parameters[2]);
@@ -1635,7 +1635,7 @@ bool CIrcProto::OnIrc_WHOIS_CHANNELS(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_WHOIS_AWAY(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_WHOIS_AWAY(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0)
m_whoisDlg->m_InfoAway2.SetText(pmsg->parameters[2]);
@@ -1645,7 +1645,7 @@ bool CIrcProto::OnIrc_WHOIS_AWAY(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_WHOIS_OTHER(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_WHOIS_OTHER(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0) {
wchar_t temp[1024], temp2[1024];
@@ -1658,7 +1658,7 @@ bool CIrcProto::OnIrc_WHOIS_OTHER(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_WHOIS_END(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_WHOIS_END(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 && m_manualWhoisCount < 1) {
CONTACT user = { pmsg->parameters[1], nullptr, nullptr, false, false, true };
@@ -1674,7 +1674,7 @@ bool CIrcProto::OnIrc_WHOIS_END(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_WHOIS_IDLE(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_WHOIS_IDLE(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0) {
int S = _wtoi(pmsg->parameters[2]);
@@ -1708,7 +1708,7 @@ bool CIrcProto::OnIrc_WHOIS_IDLE(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_WHOIS_SERVER(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_WHOIS_SERVER(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0)
m_whoisDlg->m_InfoServer.SetText(pmsg->parameters[2]);
@@ -1716,7 +1716,7 @@ bool CIrcProto::OnIrc_WHOIS_SERVER(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_WHOIS_AUTH(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_WHOIS_AUTH(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0) {
if (pmsg->sCommand == L"330")
@@ -1730,7 +1730,7 @@ bool CIrcProto::OnIrc_WHOIS_AUTH(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_WHOIS_NO_USER(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_WHOIS_NO_USER(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && pmsg->parameters.getCount() > 2 && !IsChannel(pmsg->parameters[1])) {
if (m_whoisDlg)
@@ -1782,7 +1782,7 @@ static void __stdcall sttShowNickWnd(void* param) delete pmsg;
}
-bool CIrcProto::OnIrc_NICK_ERR(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_NICK_ERR(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming) {
if (nickflag && ((m_alternativeNick[0] != 0)) && (pmsg->parameters.getCount() > 2 && mir_wstrcmp(pmsg->parameters[1], m_alternativeNick))) {
@@ -1801,7 +1801,7 @@ bool CIrcProto::OnIrc_NICK_ERR(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_JOINERROR(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_JOINERROR(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming) {
DBVARIANT dbv;
@@ -1831,7 +1831,7 @@ bool CIrcProto::OnIrc_JOINERROR(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_UNKNOWN(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_UNKNOWN(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && pmsg->parameters.getCount() > 0) {
if (pmsg->parameters[0] == L"WHO" && GetNextUserhostReason(2) != L"U")
@@ -1843,7 +1843,7 @@ bool CIrcProto::OnIrc_UNKNOWN(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_ENDMOTD(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_ENDMOTD(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && !bPerformDone)
DoOnConnect(pmsg);
@@ -1851,7 +1851,7 @@ bool CIrcProto::OnIrc_ENDMOTD(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_NOOFCHANNELS(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_NOOFCHANNELS(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && pmsg->parameters.getCount() > 1)
m_noOfChannels = _wtoi(pmsg->parameters[1]);
@@ -1863,7 +1863,7 @@ bool CIrcProto::OnIrc_NOOFCHANNELS(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_ERROR(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_ERROR(const CIrcMessage *pmsg)
{
if (pmsg->m_bIncoming && !m_disableErrorPopups && m_iDesiredStatus != ID_STATUS_OFFLINE) {
CMStringW S;
@@ -1877,7 +1877,7 @@ bool CIrcProto::OnIrc_ERROR(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_WHO_END(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_WHO_END(const CIrcMessage *pmsg)
{
CMStringW command = GetNextUserhostReason(2);
if (command[0] == 'S') {
@@ -1974,7 +1974,7 @@ bool CIrcProto::OnIrc_WHO_END(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_WHO_REPLY(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_WHO_REPLY(const CIrcMessage *pmsg)
{
CMStringW command = PeekAtReasons(2);
if (pmsg->m_bIncoming && pmsg->parameters.getCount() > 6 && command[0] == 'S') {
@@ -1991,7 +1991,7 @@ bool CIrcProto::OnIrc_WHO_REPLY(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_TRYAGAIN(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_TRYAGAIN(const CIrcMessage *pmsg)
{
CMStringW command = L"";
if (pmsg->m_bIncoming && pmsg->parameters.getCount() > 1) {
@@ -2006,7 +2006,7 @@ bool CIrcProto::OnIrc_TRYAGAIN(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_USERHOST_REPLY(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_USERHOST_REPLY(const CIrcMessage *pmsg)
{
CMStringW command;
if (pmsg->m_bIncoming) {
@@ -2145,7 +2145,46 @@ bool CIrcProto::OnIrc_USERHOST_REPLY(const CIrcMessage* pmsg) return true;
}
-bool CIrcProto::OnIrc_SUPPORT(const CIrcMessage* pmsg)
+bool CIrcProto::OnIrc_AUTH_OK(const CIrcMessage *pmsg)
+{
+ if (pmsg->m_bIncoming && !bPerformDone)
+ DoOnConnect(pmsg);
+
+ return true;
+}
+
+bool CIrcProto::OnIrc_AUTH_FAIL(const CIrcMessage*)
+{
+ int Temp = m_iDesiredStatus;
+ m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
+ ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, nullptr, LOGINERR_WRONGPASSWORD);
+ ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)Temp, ID_STATUS_OFFLINE);
+ return false;
+}
+
+bool CIrcProto::OnIrc_AUTHENTICATE(const CIrcMessage *pmsg)
+{
+ if (m_bUseSASL && pmsg->parameters[0] == "+") {
+ CMStringA payload(FORMAT, "%S%c%S%c%s%c", m_userID, 0, m_userID, 0, m_password, 0);
+ NLSend("AUTHENTICATE %s\r\n", ptrA(mir_base64_encode(payload, payload.GetLength())).get());
+ NLSend("CAP END\r\n");
+ }
+
+ return true;
+}
+
+bool CIrcProto::OnIrc_CAP(const CIrcMessage *pmsg)
+{
+ if (pmsg->parameters.getCount() < 3)
+ return true;
+
+ if (m_bUseSASL && pmsg->parameters[1] == "ACK" && pmsg->parameters[2].Trim() == "sasl") {
+ NLSend("AUTHENTICATE PLAIN\r\n");
+ }
+ return true;
+}
+
+bool CIrcProto::OnIrc_SUPPORT(const CIrcMessage *pmsg)
{
static const wchar_t *lpszFmt = L"Try server %99[^ ,], port %19s";
wchar_t szAltServer[100];
@@ -2224,7 +2263,7 @@ bool CIrcProto::OnIrc_SUPPORT(const CIrcMessage* pmsg) return true;
}
-void CIrcProto::OnIrcDefault(const CIrcMessage* pmsg)
+void CIrcProto::OnIrcDefault(const CIrcMessage *pmsg)
{
ShowMessage(pmsg);
}
diff --git a/protocols/IRCG/src/irc_dlg.h b/protocols/IRCG/src/irc_dlg.h index a9610a97f3..0a23223930 100644 --- a/protocols/IRCG/src/irc_dlg.h +++ b/protocols/IRCG/src/irc_dlg.h @@ -203,8 +203,9 @@ struct CConnectPrefsDlg : public CProtoDlgBase < CIrcProto > CCtrlCheck m_forceVisible, m_rejoinOnKick, m_rejoinChannels, m_disableError,
m_address, m_useServer, m_showServer, m_keepAlive, m_autoJoin,
- m_oldStyle, m_onlineNotif, m_channelAway, m_enableServer;
- CCtrlEdit m_onlineTimer, m_limit, m_spin1, m_spin2, m_ssl;
+ m_oldStyle, m_onlineNotif, m_channelAway, m_enableServer, m_useSasl;
+ CCtrlEdit m_onlineTimer, m_limit, m_ssl;
+ CCtrlSpin m_spin1, m_spin2;
CConnectPrefsDlg(CIrcProto* _pro);
diff --git a/protocols/IRCG/src/irclib.cpp b/protocols/IRCG/src/irclib.cpp index 94f736affa..0033ec2d6c 100644 --- a/protocols/IRCG/src/irclib.cpp +++ b/protocols/IRCG/src/irclib.cpp @@ -224,11 +224,12 @@ bool CIrcProto::Connect(const CIrcSessionInfo& info) m_info = info; + if (m_bUseSASL) + NLSend("CAP REQ :sasl\r\n"); + // start receiving messages from host ForkThread(&CIrcProto::ThreadProc, nullptr); Sleep(100); - if (info.sPassword.GetLength()) - NLSend("PASS %s\r\n", info.sPassword.c_str()); NLSend(L"NICK %s\r\n", info.sNick.c_str()); CMStringW userID = GetWord(info.sUserID.c_str(), 0); @@ -242,6 +243,9 @@ bool CIrcProto::Connect(const CIrcSessionInfo& info) HostName = L"host"; NLSend(L"USER %s %s %s :%s\r\n", userID.c_str(), HostName.c_str(), L"server", info.sFullName.c_str()); + if (!m_bUseSASL && info.sPassword.GetLength()) + NLSend("PASS %s\r\n", info.sPassword.c_str()); + return con != nullptr; } diff --git a/protocols/IRCG/src/ircproto.cpp b/protocols/IRCG/src/ircproto.cpp index 869732806a..69b19da59b 100644 --- a/protocols/IRCG/src/ircproto.cpp +++ b/protocols/IRCG/src/ircproto.cpp @@ -82,6 +82,8 @@ CIrcProto::CIrcProto(const char* szModuleName, const wchar_t* tszUserName) : IRC_MAP_ENTRY("NOTICE", NOTICE)
IRC_MAP_ENTRY("PING", PINGPONG)
IRC_MAP_ENTRY("PONG", PINGPONG)
+ IRC_MAP_ENTRY("CAP", CAP)
+ IRC_MAP_ENTRY("AUTHENTICATE", AUTHENTICATE)
IRC_MAP_ENTRY("INVITE", INVITE)
IRC_MAP_ENTRY("ERROR", ERROR)
IRC_MAP_ENTRY("001", WELCOME)
@@ -134,6 +136,10 @@ CIrcProto::CIrcProto(const char* szModuleName, const wchar_t* tszUserName) : IRC_MAP_ENTRY("474", JOINERROR)
IRC_MAP_ENTRY("475", JOINERROR)
IRC_MAP_ENTRY("671", WHOIS_OTHER) //Encryption info (SSL connect)
+ IRC_MAP_ENTRY("903", AUTH_OK)
+ IRC_MAP_ENTRY("904", AUTH_FAIL)
+ IRC_MAP_ENTRY("905", AUTH_FAIL)
+ IRC_MAP_ENTRY("906", AUTH_FAIL)
}
CIrcProto::~CIrcProto()
diff --git a/protocols/IRCG/src/main.cpp b/protocols/IRCG/src/main.cpp index 8ca2aa485d..c821c183c2 100644 --- a/protocols/IRCG/src/main.cpp +++ b/protocols/IRCG/src/main.cpp @@ -52,7 +52,6 @@ PLUGININFOEX pluginInfo = PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
__DESC,
__AUTHOR,
- __AUTHOREMAIL,
__COPYRIGHT,
__AUTHORWEB,
UNICODE_AWARE,
diff --git a/protocols/IRCG/src/options.cpp b/protocols/IRCG/src/options.cpp index 374500cb5f..0fedca772e 100644 --- a/protocols/IRCG/src/options.cpp +++ b/protocols/IRCG/src/options.cpp @@ -423,6 +423,7 @@ static TDbSetting ConnectSettings[] = { FIELD_OFFSET(CIrcProto, m_showAddresses), "ShowAddresses", DBVT_BYTE },
{ FIELD_OFFSET(CIrcProto, m_oldStyleModes), "OldStyleModes", DBVT_BYTE },
{ FIELD_OFFSET(CIrcProto, m_useServer), "UseServer", DBVT_BYTE, 0, 1 },
+ { FIELD_OFFSET(CIrcProto, m_bUseSASL), "UseSASL", DBVT_BYTE },
{ FIELD_OFFSET(CIrcProto, m_hideServerWindow), "HideServerWindow", DBVT_BYTE, 0, 1 },
{ FIELD_OFFSET(CIrcProto, m_serverComboSelection), "ServerComboSelection", DBVT_DWORD, 0 },
{ FIELD_OFFSET(CIrcProto, m_sendKeepAlive), "SendKeepAlive", DBVT_BYTE, 0, 1 },
@@ -457,6 +458,7 @@ CConnectPrefsDlg::CConnectPrefsDlg(CIrcProto* _pro) m_keepAlive(this, IDC_KEEPALIVE),
m_autoJoin(this, IDC_AUTOJOIN),
m_oldStyle(this, IDC_OLDSTYLE),
+ m_useSasl(this, IDC_SASL),
m_onlineNotif(this, IDC_ONLINENOTIF),
m_channelAway(this, IDC_CHANNELAWAY),
m_enableServer(this, IDC_STARTUP),
@@ -509,10 +511,12 @@ void CConnectPrefsDlg::OnInitDialog() }
}
- m_spin1.SendMsg(UDM_SETRANGE, 0, MAKELONG(999, 20));
- m_spin1.SendMsg(UDM_SETPOS, 0, MAKELONG(m_proto->m_onlineNotificationTime, 0));
- m_spin2.SendMsg(UDM_SETRANGE, 0, MAKELONG(200, 0));
- m_spin2.SendMsg(UDM_SETPOS, 0, MAKELONG(m_proto->m_onlineNotificationLimit, 0));
+ m_spin1.SetRange(999, 20);
+ m_spin1.SetPosition(m_proto->m_onlineNotificationTime);
+
+ m_spin2.SetRange(200);
+ m_spin2.SetPosition(m_proto->m_onlineNotificationLimit);
+
m_nick.SetText(m_proto->m_nick);
m_nick2.SetText(m_proto->m_alternativeNick);
m_userID.SetText(m_proto->m_userID);
@@ -522,6 +526,7 @@ void CConnectPrefsDlg::OnInitDialog() m_identPort.SetText(m_proto->m_identPort);
m_address.SetState(m_proto->m_showAddresses);
m_oldStyle.SetState(m_proto->m_oldStyleModes);
+ m_useSasl.SetState(m_proto->m_bUseSASL);
m_channelAway.SetState(m_proto->m_channelAwayNotification);
m_onlineNotif.SetState(m_proto->m_autoOnlineNotification);
m_onlineTimer.Enable(m_proto->m_autoOnlineNotification);
@@ -708,6 +713,7 @@ void CConnectPrefsDlg::OnApply() m_proto->m_showAddresses = m_address.GetState();
m_proto->m_oldStyleModes = m_oldStyle.GetState();
m_proto->m_useServer = m_useServer.GetState();
+ m_proto->m_bUseSASL = m_useSasl.GetState();
Menu_EnableItem(m_proto->hMenuServer, m_proto->m_useServer != 0);
diff --git a/protocols/IRCG/src/resource.h b/protocols/IRCG/src/resource.h index b2462f00ca..6f21099b10 100644 --- a/protocols/IRCG/src/resource.h +++ b/protocols/IRCG/src/resource.h @@ -1,6 +1,6 @@ //{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
-// Used by ..\res\IRC.rc
+// Used by w:\miranda-ng\protocols\IRCG\res\IRC.rc
//
#define ID_INFO_QUERY 3
#define IDD_PREFS_MAIN 101
@@ -184,6 +184,7 @@ #define IDC_FILTER_STRING 1235
#define IDC_BUTTON1 1236
#define IDC_FILTER_BTN 1237
+#define IDC_SASL 1238
#define ID_MENU1_OP 40013
#define ID_MENU1_DEOP 40014
#define ID_MENU1_VOICE 40015
@@ -242,9 +243,9 @@ //
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 203
+#define _APS_NEXT_RESOURCE_VALUE 204
#define _APS_NEXT_COMMAND_VALUE 40067
-#define _APS_NEXT_CONTROL_VALUE 1238
+#define _APS_NEXT_CONTROL_VALUE 1239
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
diff --git a/protocols/IRCG/src/services.cpp b/protocols/IRCG/src/services.cpp index c6ed1fb46c..07097155ce 100644 --- a/protocols/IRCG/src/services.cpp +++ b/protocols/IRCG/src/services.cpp @@ -704,17 +704,12 @@ int __cdecl CIrcProto::GCEventHook(WPARAM, LPARAM lParam) break;
case 30:
{
- PROTOSEARCHRESULT psr = { 0 };
+ PROTOSEARCHRESULT psr = {};
psr.cbSize = sizeof(psr);
psr.flags = PSR_UNICODE;
psr.id.w = gch->ptszUID;
psr.nick.w = gch->ptszUID;
-
- ADDCONTACTSTRUCT acs = { 0 };
- acs.handleType = HANDLE_SEARCHRESULT;
- acs.szProto = m_szModuleName;
- acs.psr = &psr;
- CallService(MS_ADDCONTACT_SHOW, 0, (LPARAM)&acs);
+ Contact_AddBySearch(m_szModuleName, &psr);
}
break;
case 31: //slap
diff --git a/protocols/IRCG/src/stdafx.h b/protocols/IRCG/src/stdafx.h index 4a5c6eea79..14da73d80a 100644 --- a/protocols/IRCG/src/stdafx.h +++ b/protocols/IRCG/src/stdafx.h @@ -56,7 +56,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "m_chat_int.h"
#include "m_message.h"
#include "m_userinfo.h"
-#include "m_addcontact.h"
+#include "m_contacts.h"
#include "m_button.h"
#include "m_genmenu.h"
#include "m_file.h"
@@ -324,6 +324,7 @@ struct CIrcProto : public PROTO<CIrcProto> BYTE m_channelAwayNotification;
BYTE m_sendNotice;
BYTE m_utfAutodetect;
+ BYTE m_bUseSASL;
int m_codepage;
COLORREF colors[16];
HICON hIcon[13];
@@ -567,6 +568,10 @@ private: bool OnIrc_WHO_END(const CIrcMessage *pmsg);
bool OnIrc_WHO_REPLY(const CIrcMessage *pmsg);
bool OnIrc_WHOTOOLONG(const CIrcMessage *pmsg);
+ bool OnIrc_AUTHENTICATE(const CIrcMessage *pmsg);
+ bool OnIrc_AUTH_OK(const CIrcMessage *pmsg);
+ bool OnIrc_AUTH_FAIL(const CIrcMessage *pmsg);
+ bool OnIrc_CAP(const CIrcMessage *pmsg);
bool IsCTCP(const CIrcMessage *pmsg);
diff --git a/protocols/IRCG/src/version.h b/protocols/IRCG/src/version.h index a708c116a6..4ef31cab0e 100644 --- a/protocols/IRCG/src/version.h +++ b/protocols/IRCG/src/version.h @@ -1,13 +1,12 @@ #define __MAJOR_VERSION 0
#define __MINOR_VERSION 95
#define __RELEASE_NUM 7
-#define __BUILD_NUM 1
+#define __BUILD_NUM 2
#include <stdver.h>
#define __DESC "Internet Relay Chat (IRC) protocol support for Miranda NG."
#define __AUTHOR "Miranda team"
-#define __AUTHOREMAIL "ghazan@miranda.im"
#define __COPYRIGHT "© 2003-17 Jurgen Persson, George Hazan"
#define __AUTHORWEB "https://miranda-ng.org/p/IRC/"
diff --git a/protocols/IcqOscarJ/src/init.cpp b/protocols/IcqOscarJ/src/init.cpp index ca3806e78a..da3403e901 100644 --- a/protocols/IcqOscarJ/src/init.cpp +++ b/protocols/IcqOscarJ/src/init.cpp @@ -43,7 +43,6 @@ PLUGININFOEX pluginInfo = { PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
__DESCRIPTION,
__AUTHOR,
- __AUTHOREMAIL,
__COPYRIGHT,
__AUTHORWEB,
UNICODE_AWARE, //doesn't replace anything built-in
diff --git a/protocols/IcqOscarJ/src/version.h b/protocols/IcqOscarJ/src/version.h index ade9e14996..2f441cda7d 100644 --- a/protocols/IcqOscarJ/src/version.h +++ b/protocols/IcqOscarJ/src/version.h @@ -9,6 +9,5 @@ #define __FILENAME "ICQ.dll"
#define __DESCRIPTION "ICQ protocol support for Miranda NG."
#define __AUTHOR "Joe Kucera, Bio, Martin Öberg, Richard Hughes, Jon Keating, etc."
-#define __AUTHOREMAIL "jokusoftware@miranda-im.org"
#define __AUTHORWEB "https://miranda-ng.org/p/ICQ/"
#define __COPYRIGHT "© 2000-17 M.Öberg, R.Hughes, J.Keating, Bio, Angeli-Ka, G.Hazan, J.Kucera"
diff --git a/protocols/JabberG/src/jabber.cpp b/protocols/JabberG/src/jabber.cpp index 4b4b4eb268..ff2a4290af 100755 --- a/protocols/JabberG/src/jabber.cpp +++ b/protocols/JabberG/src/jabber.cpp @@ -53,7 +53,6 @@ PLUGININFOEX pluginInfo = { PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
__DESCRIPTION,
__AUTHOR,
- __AUTHOREMAIL,
__COPYRIGHT,
__AUTHORWEB,
UNICODE_AWARE,
diff --git a/protocols/JabberG/src/jabber_caps.cpp b/protocols/JabberG/src/jabber_caps.cpp index 94d2432ff6..89d3bf9c13 100755 --- a/protocols/JabberG/src/jabber_caps.cpp +++ b/protocols/JabberG/src/jabber_caps.cpp @@ -498,7 +498,7 @@ void CJabberClientCapsManager::UpdateFeatHash() BYTE hash[MIR_SHA1_HASH_SIZE];
mir_sha1_hash((BYTE*)feat_buf.c_str(), feat_buf.GetLength(), hash);
- ptrA szHash(mir_base64_encode((BYTE*)&hash, sizeof(hash)));
+ ptrA szHash(mir_base64_encode(&hash, sizeof(hash)));
m_szFeaturesCrc = szHash;
}
diff --git a/protocols/JabberG/src/jabber_captcha.cpp b/protocols/JabberG/src/jabber_captcha.cpp index 31112306bb..6fcc3418a5 100644 --- a/protocols/JabberG/src/jabber_captcha.cpp +++ b/protocols/JabberG/src/jabber_captcha.cpp @@ -141,7 +141,7 @@ bool CJabberProto::ProcessCaptcha(HXML node, HXML parentNode, ThreadData *info) if (o == nullptr || XmlGetText(o) == nullptr)
return false;
- unsigned bufferLen;
+ size_t bufferLen;
ptrA buffer((char*)mir_base64_decode( _T2A(XmlGetText(o)), &bufferLen));
if (buffer == nullptr)
return false;
diff --git a/protocols/JabberG/src/jabber_chat.cpp b/protocols/JabberG/src/jabber_chat.cpp index b609d1a111..f0ed8f315e 100644 --- a/protocols/JabberG/src/jabber_chat.cpp +++ b/protocols/JabberG/src/jabber_chat.cpp @@ -1204,12 +1204,7 @@ static void sttNickListHook(CJabberProto *ppro, JABBER_LIST_ITEM *item, GCHOOK* if (wchar_t *tmp = wcschr(psr.id.w, '/'))
*tmp = 0;
psr.nick.w = psr.id.w;
-
- ADDCONTACTSTRUCT acs = { 0 };
- acs.handleType = HANDLE_SEARCHRESULT;
- acs.szProto = ppro->m_szModuleName;
- acs.psr = &psr;
- CallService(MS_ADDCONTACT_SHOW, (WPARAM)pcli->hwndContactList, (LPARAM)&acs);
+ Contact_AddBySearch(ppro->m_szModuleName, &psr, pcli->hwndContactList);
}
break;
}
diff --git a/protocols/JabberG/src/jabber_events.cpp b/protocols/JabberG/src/jabber_events.cpp index 46cfe9a356..ce10d6b7aa 100644 --- a/protocols/JabberG/src/jabber_events.cpp +++ b/protocols/JabberG/src/jabber_events.cpp @@ -187,8 +187,8 @@ int CJabberProto::OnIdleChanged(WPARAM, LPARAM lParam) }
if (lParam & IDF_ISIDLE) {
- MIRANDA_IDLE_INFO mii = { sizeof(mii) };
- CallService(MS_IDLE_GETIDLEINFO, 0, (LPARAM)&mii);
+ MIRANDA_IDLE_INFO mii;
+ Idle_GetInfo(mii);
m_tmJabberIdleStartTime = time(nullptr) - mii.idleTime * 60;
}
else m_tmJabberIdleStartTime = 0;
diff --git a/protocols/JabberG/src/jabber_ft.cpp b/protocols/JabberG/src/jabber_ft.cpp index 94a7fae28b..1da840f38e 100644 --- a/protocols/JabberG/src/jabber_ft.cpp +++ b/protocols/JabberG/src/jabber_ft.cpp @@ -244,7 +244,7 @@ BOOL CJabberProto::FtIbbSend(int blocksize, filetransfer *ft) // let others send data too
Sleep(2);
- char *encoded = mir_base64_encode((PBYTE)(char*)buffer, numRead);
+ char *encoded = mir_base64_encode(buffer, numRead);
msg << XCHILD(L"data", _A2T(encoded)) << XATTR(L"xmlns", JABBER_FEAT_IBB)
<< XATTR(L"sid", ft->jibb->sid) << XATTRI(L"seq", ft->jibb->wPacketId);
diff --git a/protocols/JabberG/src/jabber_ibb.cpp b/protocols/JabberG/src/jabber_ibb.cpp index 68d2e942eb..aa6d60f45c 100644 --- a/protocols/JabberG/src/jabber_ibb.cpp +++ b/protocols/JabberG/src/jabber_ibb.cpp @@ -178,7 +178,7 @@ BOOL CJabberProto::OnIbbRecvdData(const wchar_t *data, const wchar_t *sid, const item->jibb->wPacketId++;
- unsigned length;
+ size_t length;
ptrA decodedData((char*)mir_base64_decode( _T2A(data), &length));
if (decodedData == nullptr)
return FALSE;
diff --git a/protocols/JabberG/src/jabber_iq_handlers.cpp b/protocols/JabberG/src/jabber_iq_handlers.cpp index b5ef1970c6..f48da30b6e 100644 --- a/protocols/JabberG/src/jabber_iq_handlers.cpp +++ b/protocols/JabberG/src/jabber_iq_handlers.cpp @@ -172,7 +172,7 @@ BOOL CJabberProto::OnIqRequestAvatar(HXML, CJabberIqInfo *pInfo) fread(buffer, bytes, 1, in);
fclose(in);
- ptrA str(mir_base64_encode((PBYTE)(char*)buffer, bytes));
+ ptrA str(mir_base64_encode(buffer, bytes));
m_ThreadInfo->send(XmlNodeIq(L"result", pInfo) << XQUERY(JABBER_FEAT_AVATAR) << XCHILD(L"query", _A2T(str)) << XATTR(L"mimetype", szMimeType));
return TRUE;
}
diff --git a/protocols/JabberG/src/jabber_iqid.cpp b/protocols/JabberG/src/jabber_iqid.cpp index 0b3fc98448..a021a4bf40 100755 --- a/protocols/JabberG/src/jabber_iqid.cpp +++ b/protocols/JabberG/src/jabber_iqid.cpp @@ -588,7 +588,7 @@ void CJabberProto::OnIqResultGetVcardPhoto(HXML n, MCONTACT hContact, bool &hasP if (o == nullptr || ptszBinval == nullptr)
return;
- unsigned bufferLen;
+ size_t bufferLen;
ptrA buffer((char*)mir_base64_decode(_T2A(ptszBinval), &bufferLen));
if (buffer == nullptr)
return;
@@ -1406,7 +1406,7 @@ void CJabberProto::OnIqResultGetServerAvatar(HXML iqNode, CJabberIqInfo*) void CJabberProto::OnIqResultGotAvatar(MCONTACT hContact, HXML n, const wchar_t *mimeType)
{
- unsigned resultLen;
+ size_t resultLen;
ptrA body((char*)mir_base64_decode(_T2A(XmlGetText(n)), &resultLen));
if (body == nullptr)
return;
diff --git a/protocols/JabberG/src/jabber_misc.cpp b/protocols/JabberG/src/jabber_misc.cpp index c0c14eb400..f255edfd28 100755 --- a/protocols/JabberG/src/jabber_misc.cpp +++ b/protocols/JabberG/src/jabber_misc.cpp @@ -476,7 +476,7 @@ CMStringW CJabberProto::ExtractImage(HXML node) if (h != INVALID_HANDLE_VALUE) {
DWORD n;
- unsigned int bufferLen;
+ size_t bufferLen;
ptrA buffer((char*)mir_base64_decode(_T2A(image), &bufferLen));
WriteFile(h, buffer, bufferLen, &n, nullptr);
CloseHandle(h);
diff --git a/protocols/JabberG/src/jabber_omemo.cpp b/protocols/JabberG/src/jabber_omemo.cpp index 5d09ec7042..0ac611151a 100755 --- a/protocols/JabberG/src/jabber_omemo.cpp +++ b/protocols/JabberG/src/jabber_omemo.cpp @@ -570,7 +570,7 @@ namespace omemo { signal_buffer *key_buf;
ec_public_key_serialize(&key_buf, public_key);
// SIGNAL_UNREF(public_key);
- char *key = mir_base64_encode(signal_buffer_data(key_buf), (unsigned int)signal_buffer_len(key_buf));
+ char *key = mir_base64_encode(signal_buffer_data(key_buf), signal_buffer_len(key_buf));
char *fingerprint = (char*)mir_alloc((signal_buffer_len(key_buf) * 2) + 1);
bin2hex(signal_buffer_data(key_buf), signal_buffer_len(key_buf), fingerprint);
proto->setString("OmemoFingerprintOwn", fingerprint);
@@ -581,7 +581,7 @@ namespace omemo { ec_private_key *private_key = ratchet_identity_key_pair_get_private(new_dev->device_key);
ec_private_key_serialize(&key_buf, private_key);
// SIGNAL_UNREF(private_key);
- key = mir_base64_encode(signal_buffer_data(key_buf), (unsigned int)signal_buffer_len(key_buf));
+ key = mir_base64_encode(signal_buffer_data(key_buf), signal_buffer_len(key_buf));
proto->setString("OmemoDevicePrivateKey", key);
mir_free(key);
signal_buffer_free(key_buf);
@@ -608,11 +608,11 @@ namespace omemo { public_key = ec_key_pair_get_public(signed_pre_key_pair);
ec_public_key_serialize(&key_buf, public_key);
// SIGNAL_UNREF(public_key);
- key = mir_base64_encode(signal_buffer_data(key_buf), (unsigned int)signal_buffer_len(key_buf));
+ key = mir_base64_encode(signal_buffer_data(key_buf), signal_buffer_len(key_buf));
proto->setString("OmemoSignedPreKeyPublic", key);
mir_free(key);
signal_buffer_free(key_buf);
- char *signature = mir_base64_encode(session_signed_pre_key_get_signature(signed_pre_key), (unsigned int)session_signed_pre_key_get_signature_len(signed_pre_key));
+ char *signature = mir_base64_encode(session_signed_pre_key_get_signature(signed_pre_key), session_signed_pre_key_get_signature_len(signed_pre_key));
proto->setString("OmemoSignedPreKeySignature", signature);
mir_free(signature);
@@ -638,7 +638,7 @@ namespace omemo { public_key = ec_key_pair_get_public(pre_key_pair);
ec_public_key_serialize(&key_buf, public_key);
SIGNAL_UNREF(public_key);
- key = mir_base64_encode(signal_buffer_data(key_buf), (unsigned int)signal_buffer_len(key_buf));
+ key = mir_base64_encode(signal_buffer_data(key_buf), signal_buffer_len(key_buf));
mir_snprintf(setting_name, "OmemoPreKey%uPublic", pre_key_id);
proto->setString(setting_name, key);
mir_free(key);
@@ -689,7 +689,7 @@ namespace omemo { char *id_buf_ptr = id_buf;
id_buf_ptr += address->name_len;
memcpy(id_buf_ptr, &address->device_id, sizeof(int32_t));
- char *id_str = mir_base64_encode((BYTE*)id_buf, (unsigned int)(address->name_len + sizeof(int32_t)));
+ char *id_str = mir_base64_encode(id_buf, address->name_len + sizeof(int32_t));
mir_free(id_buf);
char *setting_name = (char*)mir_alloc(strlen(id_str) + 65);
mir_snprintf(setting_name, strlen(id_str) + 64, "%s%s", "OmemoSignalSession_", id_str);
@@ -729,12 +729,12 @@ namespace omemo { {
char *ptr = (char*)szSetting;
ptr += mir_strlen("OmemoSignalSession_");
- char *current_name = mir_base64_encode((BYTE*)data->name, (unsigned int)data->name_len);
+ char *current_name = mir_base64_encode(data->name, data->name_len);
if (strstr(ptr, current_name))
{
char *dev_encoded = ptr;
dev_encoded += strlen(current_name);
- unsigned int len;
+ size_t len;
void *dev_tmp = mir_base64_decode(dev_encoded, &len);
signal_int_list_push_back(data->sessions, *((int *)dev_tmp));
data->arr_size++;
@@ -790,7 +790,7 @@ namespace omemo { char *id_buf_ptr = id_buf;
id_buf_ptr += address->name_len;
memcpy(id_buf_ptr, &address->device_id, sizeof(int32_t));
- char *id_str = mir_base64_encode((BYTE*)id_buf, (unsigned int)(address->name_len + sizeof(int32_t)));
+ char *id_str = mir_base64_encode(id_buf, address->name_len + sizeof(int32_t));
mir_free(id_buf);
char *setting_name = (char*)mir_alloc(strlen(id_str) + 65);
mir_snprintf(setting_name, strlen(id_str) + 64, "%s%s", "OmemoSignalSession_", id_str);
@@ -817,7 +817,7 @@ namespace omemo { char *id_buf_ptr = id_buf;
id_buf_ptr += address->name_len;
memcpy(id_buf_ptr, &address->device_id, sizeof(int32_t));
- char *id_str = mir_base64_encode((BYTE*)id_buf, (unsigned int)(address->name_len + sizeof(int32_t)));
+ char *id_str = mir_base64_encode(id_buf, address->name_len + sizeof(int32_t));
mir_free(id_buf);
char *setting_name = (char*)mir_alloc(strlen(id_str) + 65);
mir_snprintf(setting_name, strlen(id_str) + 64, "%s%s", "OmemoSignalSession_", id_str);
@@ -852,7 +852,7 @@ namespace omemo { char *id_buf_ptr = id_buf;
id_buf_ptr += address->name_len;
memcpy(id_buf_ptr, &address->device_id, sizeof(int32_t));
- char *id_str = mir_base64_encode((BYTE*)id_buf, (unsigned int)(address->name_len + sizeof(int32_t)));
+ char *id_str = mir_base64_encode(id_buf, address->name_len + sizeof(int32_t));
mir_free(id_buf);
char *setting_name = (char*)mir_alloc(strlen(id_str) + 65);
mir_snprintf(setting_name, strlen(id_str) + 64, "%s%s", "OmemoSignalSession_", id_str);
@@ -877,7 +877,7 @@ namespace omemo { {
char *ptr = (char*)szSetting;
ptr += mir_strlen("OmemoSignalSession_");
- char *current_name = mir_base64_encode((BYTE*)data->name, (unsigned int)data->name_len);
+ char *current_name = mir_base64_encode(data->name, data->name_len);
if (strstr(ptr, current_name))
data->settings.push_back(mir_strdup(szSetting));
mir_free(current_name);
@@ -984,7 +984,7 @@ namespace omemo { public_key = ec_key_pair_get_public(pre_key_pair);
ec_public_key_serialize(&key_buf, public_key);
SIGNAL_UNREF(public_key);
- key = mir_base64_encode(signal_buffer_data(key_buf), (unsigned int)signal_buffer_len(key_buf));
+ key = mir_base64_encode(signal_buffer_data(key_buf), signal_buffer_len(key_buf));
mir_snprintf(setting_name, strlen("OmemoSignalPreKey_") + 31, "OmemoPreKey%uPublic", pre_key_id);
data->proto->setString(setting_name, key);
mir_free(key);
@@ -992,7 +992,7 @@ namespace omemo { /* private_key = ec_key_pair_get_private(pre_key_pair);
ec_private_key_serialize(&key_buf, private_key);
SIGNAL_UNREF(private_key);
- key = mir_base64_encode(signal_buffer_data(key_buf), (unsigned int)signal_buffer_len(key_buf));
+ key = mir_base64_encode(signal_buffer_data(key_buf), signal_buffer_len(key_buf));
mir_snprintf(setting_name, strlen("OmemoSignalPreKey_") + 31, "OmemoPreKey%uPrivate", pre_key_id);
data->proto->setString(setting_name, key);
mir_free(key);
@@ -1187,7 +1187,7 @@ namespace omemo { signal_store_backend_user_data* data = (signal_store_backend_user_data*)user_data;
char *pub_key = data->proto->getStringA("OmemoDevicePublicKey");
char *priv_key = data->proto->getStringA("OmemoDevicePrivateKey");
- unsigned int pub_key_len = 0, priv_key_len = 0;
+ size_t pub_key_len = 0, priv_key_len = 0;
char *pub_key_buf = (char*)mir_base64_decode(pub_key, &pub_key_len);
mir_free(pub_key);
char *priv_key_buf = (char*)mir_base64_decode(priv_key, &priv_key_len);
@@ -1242,7 +1242,7 @@ namespace omemo { char *id_buf_ptr = id_buf;
id_buf_ptr += address->name_len;
memcpy(id_buf_ptr, &address->device_id, sizeof(int32_t));
- char *id_str = mir_base64_encode((BYTE*)id_buf, (unsigned int)(address->name_len + sizeof(int32_t)));
+ char *id_str = mir_base64_encode(id_buf, address->name_len + sizeof(int32_t));
mir_free(id_buf);
char *setting_name = (char*)mir_alloc(strlen(id_str) + 65);
mir_snprintf(setting_name, strlen(id_str) + 64, "%s%s", "OmemoSignalIdentity_", id_str);
@@ -1284,7 +1284,7 @@ namespace omemo { char *id_buf_ptr = id_buf;
id_buf_ptr += address->name_len;
memcpy(id_buf_ptr, &address->device_id, sizeof(int32_t));
- char *id_str = mir_base64_encode((BYTE*)id_buf, (unsigned int)(address->name_len + sizeof(int32_t)));
+ char *id_str = mir_base64_encode(id_buf, address->name_len + sizeof(int32_t));
mir_free(id_buf);
char *setting_name = (char*)mir_alloc(strlen(id_str) + 65);
mir_snprintf(setting_name, strlen(id_str) + 64, "%s%s", "OmemoSignalIdentity_", id_str);
@@ -1400,7 +1400,7 @@ namespace omemo { unsigned int key_id_int = _wtoi(key_id);
char *pre_key_a = mir_u2a(pre_key_public);
- unsigned int key_buf_len;
+ size_t key_buf_len;
uint8_t *key_buf = (uint8_t*)mir_base64_decode(pre_key_a, &key_buf_len);
ec_public_key *prekey;
if (curve_decode_point(&prekey, key_buf, key_buf_len, global_context))
@@ -1542,7 +1542,7 @@ namespace omemo { public_key = ec_key_pair_get_public(pre_key_pair);
ec_public_key_serialize(&key_buf, public_key);
SIGNAL_UNREF(public_key);
- key = mir_base64_encode(signal_buffer_data(key_buf), (unsigned int)signal_buffer_len(key_buf));
+ key = mir_base64_encode(signal_buffer_data(key_buf), signal_buffer_len(key_buf));
mir_snprintf(setting_name, "OmemoPreKey%uPublic", pre_key_id);
proto->setString(setting_name, key);
mir_free(key);
@@ -1670,14 +1670,14 @@ void CJabberProto::OmemoHandleMessage(HXML node, wchar_t *jid, time_t msgTime) debugLogA("Jabber OMEMO: message does not have decryption key for our device");
return; //node does not contain key for our device
}
- unsigned int encrypted_key_len;
+ size_t encrypted_key_len;
unsigned char *encrypted_key;
{
char *key_buf = mir_u2a(encrypted_key_base64);
encrypted_key = (unsigned char*)mir_base64_decode(key_buf, &encrypted_key_len);
mir_free(key_buf);
}
- unsigned int iv_len;
+ size_t iv_len;
unsigned char *iv;
{
char *iv_buf = mir_u2a(iv_base64);
@@ -1799,7 +1799,7 @@ void CJabberProto::OmemoHandleMessage(HXML node, wchar_t *jid, time_t msgTime) char *out = nullptr;
{
int dec_success = 0;
- unsigned int payload_len = 0;
+ size_t payload_len = 0;
int outl = 0, round_len = 0;
char *payload_base64 = mir_u2a(payload_base64w);
unsigned char *payload = (unsigned char*)mir_base64_decode(payload_base64, &payload_len);
@@ -2317,7 +2317,7 @@ unsigned int CJabberProto::OmemoEncryptMessage(XmlNode &msg, const wchar_t *msg_ mir_free(in);
HXML encrypted = msg << XCHILDNS(L"encrypted", JABBER_FEAT_OMEMO);
HXML payload = encrypted << XCHILD(L"payload");
- char *payload_base64 = mir_base64_encode((BYTE*)out, tmp_len);
+ char *payload_base64 = mir_base64_encode(out, tmp_len);
wchar_t *payload_base64w = mir_a2u(payload_base64);
mir_free(payload_base64);
xmlSetText(payload, payload_base64w);
@@ -2357,7 +2357,7 @@ unsigned int CJabberProto::OmemoEncryptMessage(XmlNode &msg, const wchar_t *msg_ key_node << XATTR(L"prekey", L"true");
}
signal_buffer *serialized_encrypted_key = ciphertext_message_get_serialized(encrypted_key);
- char *key_base64 = mir_base64_encode(signal_buffer_data(serialized_encrypted_key), (unsigned int)signal_buffer_len(serialized_encrypted_key));
+ char *key_base64 = mir_base64_encode(signal_buffer_data(serialized_encrypted_key), signal_buffer_len(serialized_encrypted_key));
wchar_t *key_base64w = mir_a2u(key_base64);
mir_free(key_base64);
xmlSetText(key_node, key_base64w);
@@ -2367,7 +2367,7 @@ unsigned int CJabberProto::OmemoEncryptMessage(XmlNode &msg, const wchar_t *msg_ }
}
HXML iv_node = header << XCHILD(L"iv");
- char *iv_base64 = mir_base64_encode((BYTE*)iv, _countof_portable(iv));
+ char *iv_base64 = mir_base64_encode(iv, _countof_portable(iv));
wchar_t *iv_base64w = mir_a2u(iv_base64);
mir_free(iv_base64);
xmlSetText(iv_node, iv_base64w);
diff --git a/protocols/JabberG/src/jabber_secur.cpp b/protocols/JabberG/src/jabber_secur.cpp index edf0324766..25a0f2bad4 100644 --- a/protocols/JabberG/src/jabber_secur.cpp +++ b/protocols/JabberG/src/jabber_secur.cpp @@ -144,7 +144,7 @@ char* TMD5Auth::getChallenge(const wchar_t *challenge) iCallCount++;
- unsigned resultLen;
+ size_t resultLen;
ptrA text((char*)mir_base64_decode( _T2A(challenge), &resultLen));
TStringPairs pairs(text);
@@ -201,7 +201,7 @@ char* TMD5Auth::getChallenge(const wchar_t *challenge) uname, realm, nonce, cnonce, iCallCount, serv,
htonl(digest[0]), htonl(digest[1]), htonl(digest[2]), htonl(digest[3]));
- return mir_base64_encode((PBYTE)buf, cbLen);
+ return mir_base64_encode(buf, cbLen);
}
/////////////////////////////////////////////////////////////////////////////////////////
@@ -240,7 +240,7 @@ void TScramAuth::Hi(BYTE* res, char* passw, size_t passwLen, char* salt, size_t char* TScramAuth::getChallenge(const wchar_t *challenge)
{
- unsigned chlLen, saltLen = 0;
+ size_t chlLen, saltLen = 0;
ptrA snonce, salt;
int ind = -1;
@@ -293,12 +293,12 @@ char* TScramAuth::getChallenge(const wchar_t *challenge) BYTE srvSig[MIR_SHA1_HASH_SIZE];
mir_hmac_sha1(srvSig, serverKey, sizeof(serverKey), (BYTE*)authmsg, authmsgLen);
- serverSignature = mir_base64_encode((PBYTE)srvSig, sizeof(srvSig));
+ serverSignature = mir_base64_encode(srvSig, sizeof(srvSig));
char buf[4096];
- ptrA encproof(mir_base64_encode((PBYTE)clientProof, sizeof(clientProof)));
+ ptrA encproof(mir_base64_encode(clientProof, sizeof(clientProof)));
int cbLen = mir_snprintf(buf, "c=biws,r=%s,p=%s", snonce, encproof);
- return mir_base64_encode((PBYTE)buf, cbLen);
+ return mir_base64_encode(buf, cbLen);
}
char* TScramAuth::getInitialRequest()
@@ -307,17 +307,17 @@ char* TScramAuth::getInitialRequest() unsigned char nonce[24];
Utils_GetRandom(nonce, sizeof(nonce));
- cnonce = mir_base64_encode((PBYTE)nonce, sizeof(nonce));
+ cnonce = mir_base64_encode(nonce, sizeof(nonce));
char buf[4096];
int cbLen = mir_snprintf(buf, "n,,n=%s,r=%s", uname, cnonce);
msg1 = mir_strdup(buf + 3);
- return mir_base64_encode((PBYTE)buf, cbLen);
+ return mir_base64_encode(buf, cbLen);
}
bool TScramAuth::validateLogin(const wchar_t *challenge)
{
- unsigned chlLen;
+ size_t chlLen;
ptrA chl((char*)mir_base64_decode(_T2A(challenge), &chlLen));
return chl && strncmp((char*)chl + 2, serverSignature, chlLen - 2) == 0;
}
@@ -347,7 +347,7 @@ char* TPlainAuth::getInitialRequest() else
size = mir_snprintf(toEncode, size, "%c%s%c%s", 0, uname, 0, passw);
- return mir_base64_encode((PBYTE)toEncode, (int)size);
+ return mir_base64_encode(toEncode, size);
}
/////////////////////////////////////////////////////////////////////////////////////////
diff --git a/protocols/JabberG/src/jabber_svc.cpp b/protocols/JabberG/src/jabber_svc.cpp index b4895f1cc3..8241b8a2ee 100644 --- a/protocols/JabberG/src/jabber_svc.cpp +++ b/protocols/JabberG/src/jabber_svc.cpp @@ -30,7 +30,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include <sys/types.h>
#include <sys/stat.h>
-#include "m_addcontact.h"
#include "jabber_disco.h"
/////////////////////////////////////////////////////////////////////////////////////////
@@ -456,12 +455,7 @@ INT_PTR __cdecl CJabberProto::JabberServiceParseXmppURI(WPARAM, LPARAM lParam) psr.flags = PSR_UNICODE;
psr.nick.w = szJid;
psr.id.w = szJid;
-
- ADDCONTACTSTRUCT acs;
- acs.handleType = HANDLE_SEARCHRESULT;
- acs.szProto = m_szModuleName;
- acs.psr = &psr;
- CallService(MS_ADDCONTACT_SHOW, 0, (LPARAM)&acs);
+ Contact_AddBySearch(m_szModuleName, &psr);
}
return 0;
}
diff --git a/protocols/JabberG/src/jabber_vcard.cpp b/protocols/JabberG/src/jabber_vcard.cpp index 9c3214a985..550d9f5612 100644 --- a/protocols/JabberG/src/jabber_vcard.cpp +++ b/protocols/JabberG/src/jabber_vcard.cpp @@ -1130,7 +1130,7 @@ void CJabberProto::SetServerVcard(BOOL bPhotoChanged, wchar_t* szPhotoFileName) if (buffer != nullptr) {
DWORD nRead;
if (ReadFile(hFile, buffer, st.st_size, &nRead, nullptr)) {
- ptrA str(mir_base64_encode((PBYTE)(LPSTR)buffer, nRead));
+ ptrA str(mir_base64_encode(buffer, nRead));
const wchar_t *szFileType = ProtoGetAvatarMimeType(ProtoGetBufferFormat(buffer));
if (str != nullptr && szFileType != nullptr) {
n = v << XCHILD(L"PHOTO");
diff --git a/protocols/JabberG/src/stdafx.h b/protocols/JabberG/src/stdafx.h index 6610c2288c..830bb3685f 100644 --- a/protocols/JabberG/src/stdafx.h +++ b/protocols/JabberG/src/stdafx.h @@ -88,7 +88,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include <m_imgsrvc.h>
#include <m_clc.h>
-#include <m_addcontact.h>
#include <m_folders.h>
#include <m_fingerprint.h>
#include <m_jabber.h>
diff --git a/protocols/JabberG/src/version.h b/protocols/JabberG/src/version.h index 088b87f37c..b64aefa1b7 100644 --- a/protocols/JabberG/src/version.h +++ b/protocols/JabberG/src/version.h @@ -8,6 +8,5 @@ #define __PLUGIN_NAME "Jabber protocol"
#define __DESCRIPTION "Jabber (XMPP) protocol support for Miranda NG."
#define __AUTHOR "George Hazan, Maxim Mluhov, Victor Pavlychko, Artem Shpynov, Michael Stepura"
-#define __AUTHOREMAIL "ghazan@miranda.im"
#define __COPYRIGHT "© 2005-17 George Hazan, Maxim Mluhov, Victor Pavlychko, Artem Shpynov, Michael Stepura"
#define __AUTHORWEB "https://miranda-ng.org/p/Jabber/"
diff --git a/protocols/MRA/src/Mra.cpp b/protocols/MRA/src/Mra.cpp index d162edeb5e..2e10d02fae 100644 --- a/protocols/MRA/src/Mra.cpp +++ b/protocols/MRA/src/Mra.cpp @@ -11,7 +11,6 @@ PLUGININFOEX pluginInfoEx = { PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
__DESCRIPTION,
__AUTHOR,
- __AUTHOREMAIL,
__COPYRIGHT,
__AUTHORWEB,
UNICODE_AWARE,
diff --git a/protocols/MRA/src/MraOfflineMsg.cpp b/protocols/MRA/src/MraOfflineMsg.cpp index a5e786a6ba..1495f6d2a2 100644 --- a/protocols/MRA/src/MraOfflineMsg.cpp +++ b/protocols/MRA/src/MraOfflineMsg.cpp @@ -138,7 +138,7 @@ static DWORD PlainText2message(const CMStringA &szContentType, const CMStringA & // Content-Type: text/plain; charset = CP-1251
if ( strstr(szContentType, "utf-16le")) {
// charset = UTF-16LE// предполагаем что оно в base64
- unsigned dwTextSize;
+ size_t dwTextSize;
ptrA lpszText((LPSTR)mir_base64_decode(szBody, &dwTextSize));
if (lpszText) {
plpsText = CMStringA(lpszText, dwTextSize);
diff --git a/protocols/MRA/src/MraSendCommand.cpp b/protocols/MRA/src/MraSendCommand.cpp index 32dd012880..54352926ac 100644 --- a/protocols/MRA/src/MraSendCommand.cpp +++ b/protocols/MRA/src/MraSendCommand.cpp @@ -89,7 +89,7 @@ DWORD CMraProto::MraMessage(BOOL bAddToQueue, MCONTACT hContact, DWORD dwAckType buf.SetUL(2);
buf.SetLPSW(L"");//***deb possible nick here
buf.SetLPSW(lpwszMessage);
- lpszMessageConverted = mir_base64_encode(buf.Data(), (int)buf.Len());
+ lpszMessageConverted = mir_base64_encode(buf.Data(), buf.Len());
dwMessageConvertedSize = mir_strlen(lpszMessageConverted);
}
// messages with Flash
@@ -109,7 +109,7 @@ DWORD CMraProto::MraMessage(BOOL bAddToQueue, MCONTACT hContact, DWORD dwAckType DWORD dwBufSize = DWORD(buf.Len() + 128);
lpszBuf.Truncate(dwBufSize);
if (compress2((LPBYTE)(LPCSTR)lpszBuf, &dwBufSize, buf.Data(), (int)buf.Len(), Z_BEST_COMPRESSION) == Z_OK) {
- lpszMessageRTF = mir_base64_encode((LPBYTE)(LPCSTR)lpszBuf, dwBufSize);
+ lpszMessageRTF = mir_base64_encode(lpszBuf, dwBufSize);
dwMessageRTFSize = mir_strlen(lpszMessageRTF);
}
}
@@ -129,7 +129,7 @@ DWORD CMraProto::MraMessage(BOOL bAddToQueue, MCONTACT hContact, DWORD dwAckType DWORD dwRTFDataSize = lpbRTFData.GetLength();
if (compress2((LPBYTE)(LPCSTR)lpbRTFData, &dwRTFDataSize, buf.Data(), (int)buf.Len(), Z_BEST_COMPRESSION) == Z_OK) {
- lpszMessageRTF = mir_base64_encode((LPBYTE)(LPCSTR)lpbRTFData, dwRTFDataSize);
+ lpszMessageRTF = mir_base64_encode(lpbRTFData, dwRTFDataSize);
dwMessageRTFSize = mir_strlen(lpszMessageRTF);
}
}
@@ -205,7 +205,7 @@ DWORD CMraProto::MraAddContact(MCONTACT hContact, DWORD dwContactFlag, DWORD dwG buf2.SetUL(2);
buf2.SetLPSW(L"");//***deb possible nick here
buf2.SetLPSW((wszAuthMessage == NULL) ? L"" : *wszAuthMessage);
- buf.SetLPS(CMStringA(ptrA(mir_base64_encode(buf2.Data(), (int)buf2.Len()))));
+ buf.SetLPS(CMStringA(ptrA(mir_base64_encode(buf2.Data(), buf2.Len()))));
buf.SetUL(0);
diff --git a/protocols/MRA/src/Mra_functions.cpp b/protocols/MRA/src/Mra_functions.cpp index 9339d5f94c..dd1768c5c3 100644 --- a/protocols/MRA/src/Mra_functions.cpp +++ b/protocols/MRA/src/Mra_functions.cpp @@ -1337,7 +1337,7 @@ bool CMraProto::GetPassDB(CMStringA &res) dwPassSize = (*btCryptedPass);
btCryptedPass[dwPassSize + 1 + MIR_SHA1_HASH_SIZE] = 0;
- unsigned dwDecodedSize;
+ size_t dwDecodedSize;
mir_ptr<BYTE> pDecoded((PBYTE)mir_base64_decode((LPCSTR)&btCryptedPass[1 + MIR_SHA1_HASH_SIZE], &dwDecodedSize));
SHA1GetDigest(pDecoded, dwDecodedSize, btRandomData);
if (0 != memcmp(&btCryptedPass[1], btRandomData, MIR_SHA1_HASH_SIZE))
diff --git a/protocols/MRA/src/Mra_proto.cpp b/protocols/MRA/src/Mra_proto.cpp index 5f48fdac43..0cf552080d 100644 --- a/protocols/MRA/src/Mra_proto.cpp +++ b/protocols/MRA/src/Mra_proto.cpp @@ -1570,7 +1570,7 @@ DWORD CMraProto::MraRecvCommand_Message(DWORD dwTime, DWORD dwFlags, CMStringA & // pre processing - extracting/decoding
if (dwFlags & MESSAGE_FLAG_AUTHORIZE) { // extract auth message из обычного текста
- unsigned dwAuthDataSize;
+ size_t dwAuthDataSize;
LPBYTE lpbAuthData = (LPBYTE)mir_base64_decode(plpsText, &dwAuthDataSize);
if (lpbAuthData) {
BinBuffer buf(lpbAuthData, dwAuthDataSize);
@@ -1607,7 +1607,7 @@ DWORD CMraProto::MraRecvCommand_Message(DWORD dwTime, DWORD dwFlags, CMStringA & mir_ptr<BYTE> lpbRTFData((LPBYTE)mir_calloc(dwRFTBuffSize));
if (lpbRTFData) {
- unsigned dwCompressedSize;
+ size_t dwCompressedSize;
mir_ptr<BYTE> lpbCompressed((LPBYTE)mir_base64_decode(plpsRFTText, &dwCompressedSize));
DWORD dwRTFDataSize = (DWORD)dwRFTBuffSize;
if (uncompress(lpbRTFData, &dwRTFDataSize, lpbCompressed, dwCompressedSize) == Z_OK) {
diff --git a/protocols/MRA/src/version.h b/protocols/MRA/src/version.h index 6efeb18fb4..f4b3ea91c7 100644 --- a/protocols/MRA/src/version.h +++ b/protocols/MRA/src/version.h @@ -9,6 +9,5 @@ #define __FILENAME "MRA.dll"
#define __DESCRIPTION "Miranda Mail.ru Agent protocol plugin."
#define __AUTHOR "Rozhuk Ivan"
-#define __AUTHOREMAIL "Rozhuk_I@mail.ru"
#define __AUTHORWEB "https://miranda-ng.org/p/MRA/"
#define __COPYRIGHT "© 2005-17 Rozhuk Ivan"
diff --git a/protocols/MSN/src/msn.cpp b/protocols/MSN/src/msn.cpp index 5ff0f96647..00a3434bb0 100644 --- a/protocols/MSN/src/msn.cpp +++ b/protocols/MSN/src/msn.cpp @@ -47,7 +47,6 @@ static const PLUGININFOEX pluginInfo = PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
__DESCRIPTION,
__AUTHOR,
- __AUTHOREMAIL,
__COPYRIGHT,
__AUTHORWEB,
UNICODE_AWARE,
diff --git a/protocols/MSN/src/msn_auth.cpp b/protocols/MSN/src/msn_auth.cpp index df0e2542fe..228792b274 100644 --- a/protocols/MSN/src/msn_auth.cpp +++ b/protocols/MSN/src/msn_auth.cpp @@ -543,7 +543,7 @@ CMStringA CMsnProto::HotmailLogin(const char* url) unsigned char nonce[24];
Utils_GetRandom(nonce, sizeof(nonce));
- unsigned key1len;
+ size_t key1len;
mir_ptr<BYTE> key1((BYTE*)mir_base64_decode(hotSecretToken, &key1len));
static const unsigned char encdata[] = "WS-SecureConversation";
diff --git a/protocols/MSN/src/msn_links.cpp b/protocols/MSN/src/msn_links.cpp index e6bf5641b8..3be384196a 100644 --- a/protocols/MSN/src/msn_links.cpp +++ b/protocols/MSN/src/msn_links.cpp @@ -21,8 +21,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include "stdafx.h"
#include "msn_proto.h"
-#include <m_addcontact.h>
-
#include "m_assocmgr.h"
static MCONTACT GetContact(wchar_t *arg, wchar_t **pemail, CMsnProto *proto)
@@ -96,12 +94,7 @@ static INT_PTR ServiceParseMsnimLink(WPARAM, LPARAM lParam) psr.flags = PSR_UNICODE;
psr.nick.w = email;
psr.email.w = email;
-
- ADDCONTACTSTRUCT acs = { 0 };
- acs.handleType = HANDLE_SEARCHRESULT;
- acs.szProto = proto->m_szModuleName;
- acs.psr = &psr;
- CallService(MS_ADDCONTACT_SHOW, 0, (LPARAM)&acs);
+ Contact_AddBySearch(proto->m_szModuleName, &psr);
}
return 0;
}
diff --git a/protocols/MSN/src/msn_misc.cpp b/protocols/MSN/src/msn_misc.cpp index 5bf2bb2aa3..9a7f7157bf 100644 --- a/protocols/MSN/src/msn_misc.cpp +++ b/protocols/MSN/src/msn_misc.cpp @@ -119,7 +119,7 @@ char* MSN_GetAvatarHash(char* szContext, char** pszUrl) ezxml_t xmli = ezxml_parse_str(NEWSTR_ALLOCA(szContext), mir_strlen(szContext));
const char *szAvatarHash = ezxml_attr(xmli, "SHA1D");
if (szAvatarHash != nullptr) {
- unsigned hashLen;
+ size_t hashLen;
mir_ptr<BYTE> hash((BYTE*)mir_base64_decode(szAvatarHash, &hashLen));
if (hash)
res = arrayToHex(hash, hashLen);
@@ -217,7 +217,7 @@ int CMsnProto::MSN_SetMyAvatar(const wchar_t* sztFname, void* pData, size_t cbLe mir_sha1_append(&sha1ctx, (BYTE*)pData, (int)cbLen);
mir_sha1_finish(&sha1ctx, sha1d);
- ptrA szSha1d(mir_base64_encode((PBYTE)sha1d, sizeof(sha1d)));
+ ptrA szSha1d(mir_base64_encode(sha1d, sizeof(sha1d)));
mir_sha1_init(&sha1ctx);
ezxml_t xmlp = ezxml_new("msnobj");
@@ -250,7 +250,7 @@ int CMsnProto::MSN_SetMyAvatar(const wchar_t* sztFname, void* pData, size_t cbLe mir_sha1_finish(&sha1ctx, sha1c);
- ptrA szSha1c(mir_base64_encode((PBYTE)sha1c, sizeof(sha1c)));
+ ptrA szSha1c(mir_base64_encode(sha1c, sizeof(sha1c)));
// ezxml_set_attr(xmlp, "SHA1C", szSha1c);
diff --git a/protocols/MSN/src/msn_soapab.cpp b/protocols/MSN/src/msn_soapab.cpp index 2f82ab7a1c..ee13208804 100644 --- a/protocols/MSN/src/msn_soapab.cpp +++ b/protocols/MSN/src/msn_soapab.cpp @@ -812,7 +812,7 @@ bool CMsnProto::MSN_ABFind(const char* szMethod, const char* szGuid, bool deltas }
if (!msnLoggedIn && msnNsThread) {
char *szCircleTicket = ezxml_txt(ezxml_get(body, "CircleResult", 0, "CircleTicket", -1));
- ptrA szCircleTicketEnc(mir_base64_encode((PBYTE)szCircleTicket, (unsigned)mir_strlen(szCircleTicket)));
+ ptrA szCircleTicketEnc(mir_base64_encode(szCircleTicket, mir_strlen(szCircleTicket)));
if (szCircleTicketEnc)
msnNsThread->sendPacket("USR", "SHA A %s", szCircleTicketEnc);
}
@@ -858,7 +858,7 @@ bool CMsnProto::MSN_ABRefreshClist(unsigned int nTry) nlhr.headers[0].szValue = (char*)MSN_USER_AGENT;
nlhr.headers[1].szName = "Cookie";
nlhr.headers[1].szValue = authCookies;
- nlhr.szUrl = "https://people.directory.live.com/people/abcore?SerializeAs=xml&market=en-gb&appid=3C48F07D-DE71-490C-B263-A78CFB1CA351&version=W5.M2";
+ nlhr.szUrl = "https://people.directory.live.com/people/abcore?SerializeAs=xml&market=en-gb&appid=369bdc41-b51e-46e0-a40e-d4b2b5e09a7c&version=W5.M2";
// Query addressbook
mHttpsTS = clock();
diff --git a/protocols/MSN/src/msn_srv.cpp b/protocols/MSN/src/msn_srv.cpp index 35401b533a..35e35259e8 100644 --- a/protocols/MSN/src/msn_srv.cpp +++ b/protocols/MSN/src/msn_srv.cpp @@ -296,7 +296,7 @@ void CMsnProto::msn_storeAvatarThread(void* arg) ptrA szEncBuf;
if (dat)
- szEncBuf = mir_base64_encode(dat->data, (unsigned)dat->dataSize);
+ szEncBuf = mir_base64_encode(dat->data, dat->dataSize);
if (photoid[0] && dat)
MSN_StoreUpdateDocument(dat->szName, dat->szMimeType, szEncBuf);
diff --git a/protocols/MSN/src/version.h b/protocols/MSN/src/version.h index c09ba146f9..06c8468cd3 100644 --- a/protocols/MSN/src/version.h +++ b/protocols/MSN/src/version.h @@ -28,6 +28,5 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #define __PLUGIN_NAME "MSN protocol"
#define __DESCRIPTION "Microsoft Network (MSN) protocol support for Miranda NG."
#define __AUTHOR "Boris Krasnovskiy, George Hazan, Richard Hughes, leecher"
-#define __AUTHOREMAIL "borkra@miranda-im.org"
#define __COPYRIGHT "© 2001-17 Richard Hughes, George Hazan, Boris Krasnovskiy, leecher"
#define __AUTHORWEB "https://miranda-ng.org/p/MSN/"
diff --git a/protocols/MinecraftDynmap/src/main.cpp b/protocols/MinecraftDynmap/src/main.cpp index 8052741d6f..877ae13baa 100644 --- a/protocols/MinecraftDynmap/src/main.cpp +++ b/protocols/MinecraftDynmap/src/main.cpp @@ -35,7 +35,6 @@ PLUGININFOEX pluginInfo = { PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), __DESCRIPTION, __AUTHOR, - __AUTHOREMAIL, __COPYRIGHT, __AUTHORWEB, UNICODE_AWARE, diff --git a/protocols/MinecraftDynmap/src/version.h b/protocols/MinecraftDynmap/src/version.h index 91e46601e4..a35871c9ae 100644 --- a/protocols/MinecraftDynmap/src/version.h +++ b/protocols/MinecraftDynmap/src/version.h @@ -9,6 +9,5 @@ #define __FILENAME "MinecraftDynmap.dll" #define __DESCRIPTION "Minecraft Dynmap support for Miranda NG." #define __AUTHOR "Robert Pösel" -#define __AUTHOREMAIL "robyer@seznam.cz" #define __AUTHORWEB "https://miranda-ng.org/p/MinecraftDynmap/" #define __COPYRIGHT "© 2015-17 Robert Pösel" diff --git a/protocols/Omegle/src/main.cpp b/protocols/Omegle/src/main.cpp index d4fa415f4f..542a14d774 100644 --- a/protocols/Omegle/src/main.cpp +++ b/protocols/Omegle/src/main.cpp @@ -37,7 +37,6 @@ PLUGININFOEX pluginInfo = { PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
__DESCRIPTION,
__AUTHOR,
- __AUTHOREMAIL,
__COPYRIGHT,
__AUTHORWEB,
UNICODE_AWARE,
diff --git a/protocols/Omegle/src/version.h b/protocols/Omegle/src/version.h index e5ffe14f16..40ec242129 100644 --- a/protocols/Omegle/src/version.h +++ b/protocols/Omegle/src/version.h @@ -9,6 +9,5 @@ #define __FILENAME "Omegle.dll"
#define __DESCRIPTION "Omegle protocol support for Miranda NG."
#define __AUTHOR "Robert Pösel"
-#define __AUTHOREMAIL "robyer@seznam.cz"
#define __AUTHORWEB "https://miranda-ng.org/p/Omegle/"
#define __COPYRIGHT "© 2011-17 Robert Pösel"
diff --git a/protocols/Sametime/src/StdAfx.h b/protocols/Sametime/src/StdAfx.h index 3eae2826f9..5fa7d2b4d3 100644 --- a/protocols/Sametime/src/StdAfx.h +++ b/protocols/Sametime/src/StdAfx.h @@ -69,7 +69,7 @@ extern "C" { #include <m_clc.h>
#include <m_utils.h>
#include <m_idle.h>
-#include <m_addcontact.h>
+#include <m_contacts.h>
#include <m_popup.h>
#include <m_chat.h>
#include <m_genmenu.h>
diff --git a/protocols/Sametime/src/sametime.cpp b/protocols/Sametime/src/sametime.cpp index 0987008bec..978a5d6fce 100644 --- a/protocols/Sametime/src/sametime.cpp +++ b/protocols/Sametime/src/sametime.cpp @@ -10,7 +10,6 @@ PLUGININFOEX pluginInfo = PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
__DESCRIPTION,
__AUTHOR,
- __AUTHOREMAIL,
__COPYRIGHT,
__AUTHORWEB,
UNICODE_AWARE,
diff --git a/protocols/Sametime/src/version.h b/protocols/Sametime/src/version.h index fc60a0cfff..aac68342d9 100644 --- a/protocols/Sametime/src/version.h +++ b/protocols/Sametime/src/version.h @@ -9,6 +9,5 @@ #define __FILENAME "Sametime.dll"
#define __DESCRIPTION "Implementation of instant messaging for the Lotus Sametime protocol."
#define __AUTHOR "Scott Ellis, Szymon Tokarz"
-#define __AUTHOREMAIL "mail"/*antispam*/"@"/*antispam*/"scottellis.com.au, wsx22"/*antispam*/"@"/*antispam*/"o2.pl"
#define __COPYRIGHT "© 2005 Scott Ellis, 2014-2017 wsx22"
#define __AUTHORWEB "https://miranda-ng.org/p/Sametime/"
diff --git a/protocols/SkypeWeb/src/main.cpp b/protocols/SkypeWeb/src/main.cpp index 37b2ba5a97..ebc7de2a55 100644 --- a/protocols/SkypeWeb/src/main.cpp +++ b/protocols/SkypeWeb/src/main.cpp @@ -32,7 +32,6 @@ PLUGININFOEX pluginInfo = PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
__DESCRIPTION,
__AUTHOR,
- __AUTHOREMAIL,
__COPYRIGHT,
__AUTHORWEB,
UNICODE_AWARE,
diff --git a/protocols/SkypeWeb/src/skype_utils.cpp b/protocols/SkypeWeb/src/skype_utils.cpp index 6c9e1fe6cc..3317a79973 100644 --- a/protocols/SkypeWeb/src/skype_utils.cpp +++ b/protocols/SkypeWeb/src/skype_utils.cpp @@ -573,13 +573,7 @@ INT_PTR CSkypeProto::ParseSkypeUriService(WPARAM, LPARAM lParam) psr.id.w = mir_wstrdup(szJid); psr.nick.w = mir_wstrdup(szJid); psr.flags = PSR_UNICODE; - - ADDCONTACTSTRUCT acs = { 0 }; - acs.handleType = HANDLE_SEARCHRESULT; - acs.szProto = m_szModuleName; - acs.psr = &psr; - - CallService(MS_ADDCONTACT_SHOW, 0, (LPARAM)&acs); + Contact_AddBySearch(m_szModuleName, &psr); } return 0; } diff --git a/protocols/SkypeWeb/src/stdafx.h b/protocols/SkypeWeb/src/stdafx.h index eccbf4789c..dc054583da 100644 --- a/protocols/SkypeWeb/src/stdafx.h +++ b/protocols/SkypeWeb/src/stdafx.h @@ -40,7 +40,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include <m_popup.h>
#include <m_icolib.h>
#include <m_userinfo.h>
-#include <m_addcontact.h>
+#include <m_contacts.h>
#include <m_message.h>
#include <m_avatars.h>
#include <m_skin.h>
diff --git a/protocols/SkypeWeb/src/version.h b/protocols/SkypeWeb/src/version.h index aad66dc7d6..c4a396d0f3 100644 --- a/protocols/SkypeWeb/src/version.h +++ b/protocols/SkypeWeb/src/version.h @@ -9,6 +9,5 @@ #define __FILENAME "SkypeWeb.dll"
#define __DESCRIPTION "Skype protocol support for Miranda NG. Based on new Skype for Web."
#define __AUTHOR "Miranda NG Team"
-#define __AUTHOREMAIL ""
#define __AUTHORWEB "https://miranda-ng.org/p/SkypeWeb/"
#define __COPYRIGHT "© 2015-17 Miranda NG Team"
diff --git a/protocols/Steam/src/main.cpp b/protocols/Steam/src/main.cpp index 4010b9e46f..0f14e6ec0e 100644 --- a/protocols/Steam/src/main.cpp +++ b/protocols/Steam/src/main.cpp @@ -12,7 +12,6 @@ PLUGININFOEX pluginInfo = PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
__DESCRIPTION,
__AUTHOR,
- __AUTHOREMAIL,
__COPYRIGHT,
__AUTHORWEB,
UNICODE_AWARE,
diff --git a/protocols/Steam/src/steam_events.cpp b/protocols/Steam/src/steam_events.cpp index 3697689ca4..ef2d59ed40 100644 --- a/protocols/Steam/src/steam_events.cpp +++ b/protocols/Steam/src/steam_events.cpp @@ -65,8 +65,8 @@ int CSteamProto::OnIdleChanged(WPARAM, LPARAM lParam) if (idle) { // User started being idle - MIRANDA_IDLE_INFO mii = { sizeof(mii) }; - CallService(MS_IDLE_GETIDLEINFO, 0, (LPARAM)&mii); + MIRANDA_IDLE_INFO mii; + Idle_GetInfo(mii); // Compute time when user really became idle m_idleTS = time(nullptr) - mii.idleTime * 60; diff --git a/protocols/Steam/src/version.h b/protocols/Steam/src/version.h index 52650230ab..3c8a5e4a9b 100644 --- a/protocols/Steam/src/version.h +++ b/protocols/Steam/src/version.h @@ -9,6 +9,5 @@ #define __FILENAME "Steam.dll"
#define __DESCRIPTION "Steam protocol support for Miranda NG."
#define __AUTHOR "Miranda NG Team, Robert Pösel"
-#define __AUTHOREMAIL ""
#define __AUTHORWEB "https://miranda-ng.org/p/Steam/"
#define __COPYRIGHT "© 2014-17 Miranda NG team"
diff --git a/protocols/Tox/Tox.vcxproj b/protocols/Tox/Tox.vcxproj index 622d96816b..bc607b076a 100644 --- a/protocols/Tox/Tox.vcxproj +++ b/protocols/Tox/Tox.vcxproj @@ -27,20 +27,13 @@ </ImportGroup>
<ItemDefinitionGroup>
<ClCompile>
- <AdditionalIncludeDirectories>include;..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..\include;libtox\src\toxcore;libtox\src\toxdns;libtox\src\toxencryptsave;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>Winmm.lib;dnsapi.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
- <PostBuildEvent Condition="'$(Platform)'=='Win32'">
- <Command>call copydll.cmd x86 "$(OutputPath)..\Libs"</Command>
- </PostBuildEvent>
- <PostBuildEvent Condition="'$(Platform)'=='x64'">
- <Command>call copydll.cmd x64 "$(OutputPath)..\Libs"</Command>
- </PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
- <None Include="include\*.h" />
<None Include="res\Icons\*.ico" />
</ItemGroup>
<ItemDefinitionGroup>
@@ -52,5 +45,8 @@ <ProjectReference Include="..\..\libs\libjson\libjson.vcxproj">
<Project>{f6a9340e-b8d9-4c75-be30-47dc66d0abc7}</Project>
</ProjectReference>
+ <ProjectReference Include="libtox\libtox.vcxproj">
+ <Project>{a21c50cd-28a6-481a-a12b-47189fe66641}</Project>
+ </ProjectReference>
</ItemGroup>
</Project>
\ No newline at end of file diff --git a/protocols/Tox/bin/x64/libtox.dll b/protocols/Tox/bin/x64/libtox.dll Binary files differdeleted file mode 100644 index 17fde89b19..0000000000 --- a/protocols/Tox/bin/x64/libtox.dll +++ /dev/null diff --git a/protocols/Tox/bin/x86/libtox.dll b/protocols/Tox/bin/x86/libtox.dll Binary files differdeleted file mode 100644 index 7e392e4665..0000000000 --- a/protocols/Tox/bin/x86/libtox.dll +++ /dev/null diff --git a/protocols/Tox/copydll.cmd b/protocols/Tox/copydll.cmd deleted file mode 100644 index dffde39b53..0000000000 --- a/protocols/Tox/copydll.cmd +++ /dev/null @@ -1,7 +0,0 @@ -@echo off -set p1=%1 -set p2=%2 -set p3="%~2\libtox.dll" -copy /y bin\%p1%\libtox.dll %p2% -tools\cv2pdb.exe %p3% -exit 0 diff --git a/protocols/Tox/include/toxav.h b/protocols/Tox/include/toxav.h deleted file mode 100644 index 2a8b90fa5e..0000000000 --- a/protocols/Tox/include/toxav.h +++ /dev/null @@ -1,763 +0,0 @@ -/* - * Copyright © 2016-2017 The TokTok team. - * Copyright © 2013-2015 Tox project. - * - * This file is part of Tox, the free peer to peer instant messenger. - * - * Tox 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 3 of the License, or - * (at your option) any later version. - * - * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef TOXAV_H -#define TOXAV_H - -#include <msapi/stdbool.h> -#include <stddef.h> -#include <stdint.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/** \page av Public audio/video API for Tox clients. - * - * This API can handle multiple calls. Each call has its state, in very rare - * occasions the library can change the state of the call without apps knowledge. - * - */ -/** \subsection events Events and callbacks - * - * As in Core API, events are handled by callbacks. One callback can be - * registered per event. All events have a callback function type named - * `toxav_{event}_cb` and a function to register it named `toxav_callback_{event}`. - * Passing a NULL callback will result in no callback being registered for that - * event. Only one callback per event can be registered, so if a client needs - * multiple event listeners, it needs to implement the dispatch functionality - * itself. Unlike Core API, lack of some event handlers will cause the the - * library to drop calls before they are started. Hanging up call from a - * callback causes undefined behaviour. - * - */ -/** \subsection threading Threading implications - * - * Unlike the Core API, this API is fully thread-safe. The library will ensure - * the proper synchronization of parallel calls. - * - * A common way to run ToxAV (multiple or single instance) is to have a thread, - * separate from tox instance thread, running a simple toxav_iterate loop, - * sleeping for toxav_iteration_interval * milliseconds on each iteration. - * - * An important thing to note is that events are triggered from both tox and - * toxav thread (see above). Audio and video receive frame events are triggered - * from toxav thread while all the other events are triggered from tox thread. - * - * Tox thread has priority with mutex mechanisms. Any api function can - * fail if mutexes are held by tox thread in which case they will set SYNC - * error code. - */ -/** - * External Tox type. - */ -#ifndef TOX_DEFINED -#define TOX_DEFINED -typedef struct Tox Tox; -#endif /* TOX_DEFINED */ - -/** - * ToxAV. - */ -/** - * The ToxAV instance type. Each ToxAV instance can be bound to only one Tox - * instance, and Tox instance can have only one ToxAV instance. One must make - * sure to close ToxAV instance prior closing Tox instance otherwise undefined - * behaviour occurs. Upon closing of ToxAV instance, all active calls will be - * forcibly terminated without notifying peers. - * - */ -#ifndef TOXAV_DEFINED -#define TOXAV_DEFINED -typedef struct ToxAV ToxAV; -#endif /* TOXAV_DEFINED */ - - -/******************************************************************************* - * - * :: Creation and destruction - * - ******************************************************************************/ - - - -typedef enum TOXAV_ERR_NEW { - - /** - * The function returned successfully. - */ - TOXAV_ERR_NEW_OK, - - /** - * One of the arguments to the function was NULL when it was not expected. - */ - TOXAV_ERR_NEW_NULL, - - /** - * Memory allocation failure while trying to allocate structures required for - * the A/V session. - */ - TOXAV_ERR_NEW_MALLOC, - - /** - * Attempted to create a second session for the same Tox instance. - */ - TOXAV_ERR_NEW_MULTIPLE, - -} TOXAV_ERR_NEW; - - -/** - * Start new A/V session. There can only be only one session per Tox instance. - */ -ToxAV *toxav_new(Tox *tox, TOXAV_ERR_NEW *error); - -/** - * Releases all resources associated with the A/V session. - * - * If any calls were ongoing, these will be forcibly terminated without - * notifying peers. After calling this function, no other functions may be - * called and the av pointer becomes invalid. - */ -void toxav_kill(ToxAV *av); - -/** - * Returns the Tox instance the A/V object was created for. - */ -Tox *toxav_get_tox(const ToxAV *av); - - -/******************************************************************************* - * - * :: A/V event loop - * - ******************************************************************************/ - - - -/** - * Returns the interval in milliseconds when the next toxav_iterate call should - * be. If no call is active at the moment, this function returns 200. - */ -uint32_t toxav_iteration_interval(const ToxAV *av); - -/** - * Main loop for the session. This function needs to be called in intervals of - * toxav_iteration_interval() milliseconds. It is best called in the separate - * thread from tox_iterate. - */ -void toxav_iterate(ToxAV *av); - - -/******************************************************************************* - * - * :: Call setup - * - ******************************************************************************/ - - - -typedef enum TOXAV_ERR_CALL { - - /** - * The function returned successfully. - */ - TOXAV_ERR_CALL_OK, - - /** - * A resource allocation error occurred while trying to create the structures - * required for the call. - */ - TOXAV_ERR_CALL_MALLOC, - - /** - * Synchronization error occurred. - */ - TOXAV_ERR_CALL_SYNC, - - /** - * The friend number did not designate a valid friend. - */ - TOXAV_ERR_CALL_FRIEND_NOT_FOUND, - - /** - * The friend was valid, but not currently connected. - */ - TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED, - - /** - * Attempted to call a friend while already in an audio or video call with - * them. - */ - TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL, - - /** - * Audio or video bit rate is invalid. - */ - TOXAV_ERR_CALL_INVALID_BIT_RATE, - -} TOXAV_ERR_CALL; - - -/** - * Call a friend. This will start ringing the friend. - * - * It is the client's responsibility to stop ringing after a certain timeout, - * if such behaviour is desired. If the client does not stop ringing, the - * library will not stop until the friend is disconnected. Audio and video - * receiving are both enabled by default. - * - * @param friend_number The friend number of the friend that should be called. - * @param audio_bit_rate Audio bit rate in Kb/sec. Set this to 0 to disable - * audio sending. - * @param video_bit_rate Video bit rate in Kb/sec. Set this to 0 to disable - * video sending. - */ -bool toxav_call(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, - TOXAV_ERR_CALL *error); - -/** - * The function type for the call callback. - * - * @param friend_number The friend number from which the call is incoming. - * @param audio_enabled True if friend is sending audio. - * @param video_enabled True if friend is sending video. - */ -typedef void toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data); - - -/** - * Set the callback for the `call` event. Pass NULL to unset. - * - */ -void toxav_callback_call(ToxAV *av, toxav_call_cb *callback, void *user_data); - -typedef enum TOXAV_ERR_ANSWER { - - /** - * The function returned successfully. - */ - TOXAV_ERR_ANSWER_OK, - - /** - * Synchronization error occurred. - */ - TOXAV_ERR_ANSWER_SYNC, - - /** - * Failed to initialize codecs for call session. Note that codec initiation - * will fail if there is no receive callback registered for either audio or - * video. - */ - TOXAV_ERR_ANSWER_CODEC_INITIALIZATION, - - /** - * The friend number did not designate a valid friend. - */ - TOXAV_ERR_ANSWER_FRIEND_NOT_FOUND, - - /** - * The friend was valid, but they are not currently trying to initiate a call. - * This is also returned if this client is already in a call with the friend. - */ - TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING, - - /** - * Audio or video bit rate is invalid. - */ - TOXAV_ERR_ANSWER_INVALID_BIT_RATE, - -} TOXAV_ERR_ANSWER; - - -/** - * Accept an incoming call. - * - * If answering fails for any reason, the call will still be pending and it is - * possible to try and answer it later. Audio and video receiving are both - * enabled by default. - * - * @param friend_number The friend number of the friend that is calling. - * @param audio_bit_rate Audio bit rate in Kb/sec. Set this to 0 to disable - * audio sending. - * @param video_bit_rate Video bit rate in Kb/sec. Set this to 0 to disable - * video sending. - */ -bool toxav_answer(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, - TOXAV_ERR_ANSWER *error); - - -/******************************************************************************* - * - * :: Call state graph - * - ******************************************************************************/ - - - -enum TOXAV_FRIEND_CALL_STATE { - - /** - * The empty bit mask. None of the bits specified below are set. - */ - TOXAV_FRIEND_CALL_STATE_NONE = 0, - - /** - * Set by the AV core if an error occurred on the remote end or if friend - * timed out. This is the final state after which no more state - * transitions can occur for the call. This call state will never be triggered - * in combination with other call states. - */ - TOXAV_FRIEND_CALL_STATE_ERROR = 1, - - /** - * The call has finished. This is the final state after which no more state - * transitions can occur for the call. This call state will never be - * triggered in combination with other call states. - */ - TOXAV_FRIEND_CALL_STATE_FINISHED = 2, - - /** - * The flag that marks that friend is sending audio. - */ - TOXAV_FRIEND_CALL_STATE_SENDING_A = 4, - - /** - * The flag that marks that friend is sending video. - */ - TOXAV_FRIEND_CALL_STATE_SENDING_V = 8, - - /** - * The flag that marks that friend is receiving audio. - */ - TOXAV_FRIEND_CALL_STATE_ACCEPTING_A = 16, - - /** - * The flag that marks that friend is receiving video. - */ - TOXAV_FRIEND_CALL_STATE_ACCEPTING_V = 32, - -}; - - -/** - * The function type for the call_state callback. - * - * @param friend_number The friend number for which the call state changed. - * @param state The bitmask of the new call state which is guaranteed to be - * different than the previous state. The state is set to 0 when the call is - * paused. The bitmask represents all the activities currently performed by the - * friend. - */ -typedef void toxav_call_state_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data); - - -/** - * Set the callback for the `call_state` event. Pass NULL to unset. - * - */ -void toxav_callback_call_state(ToxAV *av, toxav_call_state_cb *callback, void *user_data); - - -/******************************************************************************* - * - * :: Call control - * - ******************************************************************************/ - - - -typedef enum TOXAV_CALL_CONTROL { - - /** - * Resume a previously paused call. Only valid if the pause was caused by this - * client, if not, this control is ignored. Not valid before the call is accepted. - */ - TOXAV_CALL_CONTROL_RESUME, - - /** - * Put a call on hold. Not valid before the call is accepted. - */ - TOXAV_CALL_CONTROL_PAUSE, - - /** - * Reject a call if it was not answered, yet. Cancel a call after it was - * answered. - */ - TOXAV_CALL_CONTROL_CANCEL, - - /** - * Request that the friend stops sending audio. Regardless of the friend's - * compliance, this will cause the audio_receive_frame event to stop being - * triggered on receiving an audio frame from the friend. - */ - TOXAV_CALL_CONTROL_MUTE_AUDIO, - - /** - * Calling this control will notify client to start sending audio again. - */ - TOXAV_CALL_CONTROL_UNMUTE_AUDIO, - - /** - * Request that the friend stops sending video. Regardless of the friend's - * compliance, this will cause the video_receive_frame event to stop being - * triggered on receiving a video frame from the friend. - */ - TOXAV_CALL_CONTROL_HIDE_VIDEO, - - /** - * Calling this control will notify client to start sending video again. - */ - TOXAV_CALL_CONTROL_SHOW_VIDEO, - -} TOXAV_CALL_CONTROL; - - -typedef enum TOXAV_ERR_CALL_CONTROL { - - /** - * The function returned successfully. - */ - TOXAV_ERR_CALL_CONTROL_OK, - - /** - * Synchronization error occurred. - */ - TOXAV_ERR_CALL_CONTROL_SYNC, - - /** - * The friend_number passed did not designate a valid friend. - */ - TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_FOUND, - - /** - * This client is currently not in a call with the friend. Before the call is - * answered, only CANCEL is a valid control. - */ - TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL, - - /** - * Happens if user tried to pause an already paused call or if trying to - * resume a call that is not paused. - */ - TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION, - -} TOXAV_ERR_CALL_CONTROL; - - -/** - * Sends a call control command to a friend. - * - * @param friend_number The friend number of the friend this client is in a call - * with. - * @param control The control command to send. - * - * @return true on success. - */ -bool toxav_call_control(ToxAV *av, uint32_t friend_number, TOXAV_CALL_CONTROL control, TOXAV_ERR_CALL_CONTROL *error); - - -/******************************************************************************* - * - * :: Controlling bit rates - * - ******************************************************************************/ - - - -typedef enum TOXAV_ERR_BIT_RATE_SET { - - /** - * The function returned successfully. - */ - TOXAV_ERR_BIT_RATE_SET_OK, - - /** - * Synchronization error occurred. - */ - TOXAV_ERR_BIT_RATE_SET_SYNC, - - /** - * The audio bit rate passed was not one of the supported values. - */ - TOXAV_ERR_BIT_RATE_SET_INVALID_AUDIO_BIT_RATE, - - /** - * The video bit rate passed was not one of the supported values. - */ - TOXAV_ERR_BIT_RATE_SET_INVALID_VIDEO_BIT_RATE, - - /** - * The friend_number passed did not designate a valid friend. - */ - TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_FOUND, - - /** - * This client is currently not in a call with the friend. - */ - TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_IN_CALL, - -} TOXAV_ERR_BIT_RATE_SET; - - -/** - * Set the bit rate to be used in subsequent audio/video frames. - * - * @param friend_number The friend number of the friend for which to set the - * bit rate. - * @param audio_bit_rate The new audio bit rate in Kb/sec. Set to 0 to disable - * audio sending. Set to -1 to leave unchanged. - * @param video_bit_rate The new video bit rate in Kb/sec. Set to 0 to disable - * video sending. Set to -1 to leave unchanged. - * - */ -bool toxav_bit_rate_set(ToxAV *av, uint32_t friend_number, int32_t audio_bit_rate, int32_t video_bit_rate, - TOXAV_ERR_BIT_RATE_SET *error); - -/** - * The function type for the bit_rate_status callback. The event is triggered - * when the network becomes too saturated for current bit rates at which - * point core suggests new bit rates. - * - * @param friend_number The friend number of the friend for which to set the - * bit rate. - * @param audio_bit_rate Suggested maximum audio bit rate in Kb/sec. - * @param video_bit_rate Suggested maximum video bit rate in Kb/sec. - */ -typedef void toxav_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, - uint32_t video_bit_rate, void *user_data); - - -/** - * Set the callback for the `bit_rate_status` event. Pass NULL to unset. - * - */ -void toxav_callback_bit_rate_status(ToxAV *av, toxav_bit_rate_status_cb *callback, void *user_data); - - -/******************************************************************************* - * - * :: A/V sending - * - ******************************************************************************/ - - - -typedef enum TOXAV_ERR_SEND_FRAME { - - /** - * The function returned successfully. - */ - TOXAV_ERR_SEND_FRAME_OK, - - /** - * In case of video, one of Y, U, or V was NULL. In case of audio, the samples - * data pointer was NULL. - */ - TOXAV_ERR_SEND_FRAME_NULL, - - /** - * The friend_number passed did not designate a valid friend. - */ - TOXAV_ERR_SEND_FRAME_FRIEND_NOT_FOUND, - - /** - * This client is currently not in a call with the friend. - */ - TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL, - - /** - * Synchronization error occurred. - */ - TOXAV_ERR_SEND_FRAME_SYNC, - - /** - * One of the frame parameters was invalid. E.g. the resolution may be too - * small or too large, or the audio sampling rate may be unsupported. - */ - TOXAV_ERR_SEND_FRAME_INVALID, - - /** - * Either friend turned off audio or video receiving or we turned off sending - * for the said payload. - */ - TOXAV_ERR_SEND_FRAME_PAYLOAD_TYPE_DISABLED, - - /** - * Failed to push frame through rtp interface. - */ - TOXAV_ERR_SEND_FRAME_RTP_FAILED, - -} TOXAV_ERR_SEND_FRAME; - - -/** - * Send an audio frame to a friend. - * - * The expected format of the PCM data is: [s1c1][s1c2][...][s2c1][s2c2][...]... - * Meaning: sample 1 for channel 1, sample 1 for channel 2, ... - * For mono audio, this has no meaning, every sample is subsequent. For stereo, - * this means the expected format is LRLRLR... with samples for left and right - * alternating. - * - * @param friend_number The friend number of the friend to which to send an - * audio frame. - * @param pcm An array of audio samples. The size of this array must be - * sample_count * channels. - * @param sample_count Number of samples in this frame. Valid numbers here are - * ((sample rate) * (audio length) / 1000), where audio length can be - * 2.5, 5, 10, 20, 40 or 60 millseconds. - * @param channels Number of audio channels. Supported values are 1 and 2. - * @param sampling_rate Audio sampling rate used in this frame. Valid sampling - * rates are 8000, 12000, 16000, 24000, or 48000. - */ -bool toxav_audio_send_frame(ToxAV *av, uint32_t friend_number, const int16_t *pcm, size_t sample_count, - uint8_t channels, uint32_t sampling_rate, TOXAV_ERR_SEND_FRAME *error); - -/** - * Send a video frame to a friend. - * - * Y - plane should be of size: height * width - * U - plane should be of size: (height/2) * (width/2) - * V - plane should be of size: (height/2) * (width/2) - * - * @param friend_number The friend number of the friend to which to send a video - * frame. - * @param width Width of the frame in pixels. - * @param height Height of the frame in pixels. - * @param y Y (Luminance) plane data. - * @param u U (Chroma) plane data. - * @param v V (Chroma) plane data. - */ -bool toxav_video_send_frame(ToxAV *av, uint32_t friend_number, uint16_t width, uint16_t height, const uint8_t *y, - const uint8_t *u, const uint8_t *v, TOXAV_ERR_SEND_FRAME *error); - - -/******************************************************************************* - * - * :: A/V receiving - * - ******************************************************************************/ - - - -/** - * The function type for the audio_receive_frame callback. The callback can be - * called multiple times per single iteration depending on the amount of queued - * frames in the buffer. The received format is the same as in send function. - * - * @param friend_number The friend number of the friend who sent an audio frame. - * @param pcm An array of audio samples (sample_count * channels elements). - * @param sample_count The number of audio samples per channel in the PCM array. - * @param channels Number of audio channels. - * @param sampling_rate Sampling rate used in this frame. - * - */ -typedef void toxav_audio_receive_frame_cb(ToxAV *av, uint32_t friend_number, const int16_t *pcm, size_t sample_count, - uint8_t channels, uint32_t sampling_rate, void *user_data); - - -/** - * Set the callback for the `audio_receive_frame` event. Pass NULL to unset. - * - */ -void toxav_callback_audio_receive_frame(ToxAV *av, toxav_audio_receive_frame_cb *callback, void *user_data); - -/** - * The function type for the video_receive_frame callback. - * - * The size of plane data is derived from width and height as documented - * below. - * - * Strides represent padding for each plane that may or may not be present. - * You must handle strides in your image processing code. Strides are - * negative if the image is bottom-up hence why you MUST abs() it when - * calculating plane buffer size. - * - * @param friend_number The friend number of the friend who sent a video frame. - * @param width Width of the frame in pixels. - * @param height Height of the frame in pixels. - * @param y Luminosity plane. Size = MAX(width, abs(ystride)) * height. - * @param u U chroma plane. Size = MAX(width/2, abs(ustride)) * (height/2). - * @param v V chroma plane. Size = MAX(width/2, abs(vstride)) * (height/2). - * - * @param ystride Luminosity plane stride. - * @param ustride U chroma plane stride. - * @param vstride V chroma plane stride. - */ -typedef void toxav_video_receive_frame_cb(ToxAV *av, uint32_t friend_number, uint16_t width, uint16_t height, - const uint8_t *y, const uint8_t *u, const uint8_t *v, int32_t ystride, int32_t ustride, int32_t vstride, - void *user_data); - - -/** - * Set the callback for the `video_receive_frame` event. Pass NULL to unset. - * - */ -void toxav_callback_video_receive_frame(ToxAV *av, toxav_video_receive_frame_cb *callback, void *user_data); - -/** - * NOTE Compatibility with old toxav group calls. TODO(iphydf): remove - */ -/* Create a new toxav group. - * - * return group number on success. - * return -1 on failure. - * - * Audio data callback format: - * audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata) - * - * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). - */ -int toxav_add_av_groupchat(Tox *tox, void (*audio_callback)(void *, int, int, const int16_t *, unsigned int, uint8_t, - unsigned int, void *), void *userdata); - -/* Join a AV group (you need to have been invited first.) - * - * returns group number on success - * returns -1 on failure. - * - * Audio data callback format (same as the one for toxav_add_av_groupchat()): - * audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata) - * - * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). - */ -int toxav_join_av_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length, - void (*audio_callback)(void *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *), void *userdata); - -/* Send audio to the group chat. - * - * return 0 on success. - * return -1 on failure. - * - * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). - * - * Valid number of samples are ((sample rate) * (audio length (Valid ones are: 2.5, 5, 10, 20, 40 or 60 ms)) / 1000) - * Valid number of channels are 1 or 2. - * Valid sample rates are 8000, 12000, 16000, 24000, or 48000. - * - * Recommended values are: samples = 960, channels = 1, sample_rate = 48000 - */ -int toxav_group_send_audio(Tox *tox, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels, - unsigned int sample_rate); - -#ifdef __cplusplus -} -#endif -#endif /* TOXAV_H */ diff --git a/protocols/Tox/include/vpx/vp8.h b/protocols/Tox/include/vpx/vp8.h deleted file mode 100644 index 059c9d0f65..0000000000 --- a/protocols/Tox/include/vpx/vp8.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -/*!\defgroup vp8 VP8 - * \ingroup codecs - * VP8 is vpx's newest video compression algorithm that uses motion - * compensated prediction, Discrete Cosine Transform (DCT) coding of the - * prediction error signal and context dependent entropy coding techniques - * based on arithmetic principles. It features: - * - YUV 4:2:0 image format - * - Macro-block based coding (16x16 luma plus two 8x8 chroma) - * - 1/4 (1/8) pixel accuracy motion compensated prediction - * - 4x4 DCT transform - * - 128 level linear quantizer - * - In loop deblocking filter - * - Context-based entropy coding - * - * @{ - */ -/*!\file - * \brief Provides controls common to both the VP8 encoder and decoder. - */ -#ifndef VPX_VP8_H_ -#define VPX_VP8_H_ - -#include "./vpx_codec.h" -#include "./vpx_image.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/*!\brief Control functions - * - * The set of macros define the control functions of VP8 interface - */ -enum vp8_com_control_id { - /*!\brief pass in an external frame into decoder to be used as reference frame - */ - VP8_SET_REFERENCE = 1, - VP8_COPY_REFERENCE = 2, /**< get a copy of reference frame from the decoder */ - VP8_SET_POSTPROC = 3, /**< set the decoder's post processing settings */ - VP8_SET_DBG_COLOR_REF_FRAME = 4, /**< \deprecated */ - VP8_SET_DBG_COLOR_MB_MODES = 5, /**< \deprecated */ - VP8_SET_DBG_COLOR_B_MODES = 6, /**< \deprecated */ - VP8_SET_DBG_DISPLAY_MV = 7, /**< \deprecated */ - - /* TODO(jkoleszar): The encoder incorrectly reuses some of these values (5+) - * for its control ids. These should be migrated to something like the - * VP8_DECODER_CTRL_ID_START range next time we're ready to break the ABI. - */ - VP9_GET_REFERENCE = 128, /**< get a pointer to a reference frame */ - VP8_COMMON_CTRL_ID_MAX, - VP8_DECODER_CTRL_ID_START = 256 -}; - -/*!\brief post process flags - * - * The set of macros define VP8 decoder post processing flags - */ -enum vp8_postproc_level { - VP8_NOFILTERING = 0, - VP8_DEBLOCK = 1 << 0, - VP8_DEMACROBLOCK = 1 << 1, - VP8_ADDNOISE = 1 << 2, - VP8_DEBUG_TXT_FRAME_INFO = 1 << 3, /**< print frame information */ - VP8_DEBUG_TXT_MBLK_MODES = - 1 << 4, /**< print macro block modes over each macro block */ - VP8_DEBUG_TXT_DC_DIFF = 1 << 5, /**< print dc diff for each macro block */ - VP8_DEBUG_TXT_RATE_INFO = 1 << 6, /**< print video rate info (encoder only) */ - VP8_MFQE = 1 << 10 -}; - -/*!\brief post process flags - * - * This define a structure that describe the post processing settings. For - * the best objective measure (using the PSNR metric) set post_proc_flag - * to VP8_DEBLOCK and deblocking_level to 1. - */ - -typedef struct vp8_postproc_cfg { - /*!\brief the types of post processing to be done, should be combination of - * "vp8_postproc_level" */ - int post_proc_flag; - int deblocking_level; /**< the strength of deblocking, valid range [0, 16] */ - int noise_level; /**< the strength of additive noise, valid range [0, 16] */ -} vp8_postproc_cfg_t; - -/*!\brief reference frame type - * - * The set of macros define the type of VP8 reference frames - */ -typedef enum vpx_ref_frame_type { - VP8_LAST_FRAME = 1, - VP8_GOLD_FRAME = 2, - VP8_ALTR_FRAME = 4 -} vpx_ref_frame_type_t; - -/*!\brief reference frame data struct - * - * Define the data struct to access vp8 reference frames. - */ -typedef struct vpx_ref_frame { - vpx_ref_frame_type_t frame_type; /**< which reference frame */ - vpx_image_t img; /**< reference frame data in image format */ -} vpx_ref_frame_t; - -/*!\brief VP9 specific reference frame data struct - * - * Define the data struct to access vp9 reference frames. - */ -typedef struct vp9_ref_frame { - int idx; /**< frame index to get (input) */ - vpx_image_t img; /**< img structure to populate (output) */ -} vp9_ref_frame_t; - -/*!\cond */ -/*!\brief vp8 decoder control function parameter type - * - * defines the data type for each of VP8 decoder control function requires - */ -VPX_CTRL_USE_TYPE(VP8_SET_REFERENCE, vpx_ref_frame_t *) -#define VPX_CTRL_VP8_SET_REFERENCE -VPX_CTRL_USE_TYPE(VP8_COPY_REFERENCE, vpx_ref_frame_t *) -#define VPX_CTRL_VP8_COPY_REFERENCE -VPX_CTRL_USE_TYPE(VP8_SET_POSTPROC, vp8_postproc_cfg_t *) -#define VPX_CTRL_VP8_SET_POSTPROC -VPX_CTRL_USE_TYPE_DEPRECATED(VP8_SET_DBG_COLOR_REF_FRAME, int) -#define VPX_CTRL_VP8_SET_DBG_COLOR_REF_FRAME -VPX_CTRL_USE_TYPE_DEPRECATED(VP8_SET_DBG_COLOR_MB_MODES, int) -#define VPX_CTRL_VP8_SET_DBG_COLOR_MB_MODES -VPX_CTRL_USE_TYPE_DEPRECATED(VP8_SET_DBG_COLOR_B_MODES, int) -#define VPX_CTRL_VP8_SET_DBG_COLOR_B_MODES -VPX_CTRL_USE_TYPE_DEPRECATED(VP8_SET_DBG_DISPLAY_MV, int) -#define VPX_CTRL_VP8_SET_DBG_DISPLAY_MV -VPX_CTRL_USE_TYPE(VP9_GET_REFERENCE, vp9_ref_frame_t *) -#define VPX_CTRL_VP9_GET_REFERENCE - -/*!\endcond */ -/*! @} - end defgroup vp8 */ - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // VPX_VP8_H_ diff --git a/protocols/Tox/include/vpx/vp8cx.h b/protocols/Tox/include/vpx/vp8cx.h deleted file mode 100644 index cc90159bc3..0000000000 --- a/protocols/Tox/include/vpx/vp8cx.h +++ /dev/null @@ -1,850 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ -#ifndef VPX_VP8CX_H_ -#define VPX_VP8CX_H_ - -/*!\defgroup vp8_encoder WebM VP8/VP9 Encoder - * \ingroup vp8 - * - * @{ - */ -#include "./vp8.h" -#include "./vpx_encoder.h" - -/*!\file - * \brief Provides definitions for using VP8 or VP9 encoder algorithm within the - * vpx Codec Interface. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/*!\name Algorithm interface for VP8 - * - * This interface provides the capability to encode raw VP8 streams. - * @{ - */ -extern vpx_codec_iface_t vpx_codec_vp8_cx_algo; -extern vpx_codec_iface_t *vpx_codec_vp8_cx(void); -/*!@} - end algorithm interface member group*/ - -/*!\name Algorithm interface for VP9 - * - * This interface provides the capability to encode raw VP9 streams. - * @{ - */ -extern vpx_codec_iface_t vpx_codec_vp9_cx_algo; -extern vpx_codec_iface_t *vpx_codec_vp9_cx(void); -/*!@} - end algorithm interface member group*/ - -/* - * Algorithm Flags - */ - -/*!\brief Don't reference the last frame - * - * When this flag is set, the encoder will not use the last frame as a - * predictor. When not set, the encoder will choose whether to use the - * last frame or not automatically. - */ -#define VP8_EFLAG_NO_REF_LAST (1 << 16) - -/*!\brief Don't reference the golden frame - * - * When this flag is set, the encoder will not use the golden frame as a - * predictor. When not set, the encoder will choose whether to use the - * golden frame or not automatically. - */ -#define VP8_EFLAG_NO_REF_GF (1 << 17) - -/*!\brief Don't reference the alternate reference frame - * - * When this flag is set, the encoder will not use the alt ref frame as a - * predictor. When not set, the encoder will choose whether to use the - * alt ref frame or not automatically. - */ -#define VP8_EFLAG_NO_REF_ARF (1 << 21) - -/*!\brief Don't update the last frame - * - * When this flag is set, the encoder will not update the last frame with - * the contents of the current frame. - */ -#define VP8_EFLAG_NO_UPD_LAST (1 << 18) - -/*!\brief Don't update the golden frame - * - * When this flag is set, the encoder will not update the golden frame with - * the contents of the current frame. - */ -#define VP8_EFLAG_NO_UPD_GF (1 << 22) - -/*!\brief Don't update the alternate reference frame - * - * When this flag is set, the encoder will not update the alt ref frame with - * the contents of the current frame. - */ -#define VP8_EFLAG_NO_UPD_ARF (1 << 23) - -/*!\brief Force golden frame update - * - * When this flag is set, the encoder copy the contents of the current frame - * to the golden frame buffer. - */ -#define VP8_EFLAG_FORCE_GF (1 << 19) - -/*!\brief Force alternate reference frame update - * - * When this flag is set, the encoder copy the contents of the current frame - * to the alternate reference frame buffer. - */ -#define VP8_EFLAG_FORCE_ARF (1 << 24) - -/*!\brief Disable entropy update - * - * When this flag is set, the encoder will not update its internal entropy - * model based on the entropy of this frame. - */ -#define VP8_EFLAG_NO_UPD_ENTROPY (1 << 20) - -/*!\brief VPx encoder control functions - * - * This set of macros define the control functions available for VPx - * encoder interface. - * - * \sa #vpx_codec_control - */ -enum vp8e_enc_control_id { - /*!\brief Codec control function to pass an ROI map to encoder. - * - * Supported in codecs: VP8, VP9 - */ - VP8E_SET_ROI_MAP = 8, - - /*!\brief Codec control function to pass an Active map to encoder. - * - * Supported in codecs: VP8, VP9 - */ - VP8E_SET_ACTIVEMAP, - - /*!\brief Codec control function to set encoder scaling mode. - * - * Supported in codecs: VP8, VP9 - */ - VP8E_SET_SCALEMODE = 11, - - /*!\brief Codec control function to set encoder internal speed settings. - * - * Changes in this value influences, among others, the encoder's selection - * of motion estimation methods. Values greater than 0 will increase encoder - * speed at the expense of quality. - * - * \note Valid range for VP8: -16..16 - * \note Valid range for VP9: -8..8 - * - * Supported in codecs: VP8, VP9 - */ - VP8E_SET_CPUUSED = 13, - - /*!\brief Codec control function to enable automatic set and use alf frames. - * - * Supported in codecs: VP8, VP9 - */ - VP8E_SET_ENABLEAUTOALTREF, - - /*!\brief control function to set noise sensitivity - * - * 0: off, 1: OnYOnly, 2: OnYUV, - * 3: OnYUVAggressive, 4: Adaptive - * - * Supported in codecs: VP8 - */ - VP8E_SET_NOISE_SENSITIVITY, - - /*!\brief Codec control function to set sharpness. - * - * Supported in codecs: VP8, VP9 - */ - VP8E_SET_SHARPNESS, - - /*!\brief Codec control function to set the threshold for MBs treated static. - * - * Supported in codecs: VP8, VP9 - */ - VP8E_SET_STATIC_THRESHOLD, - - /*!\brief Codec control function to set the number of token partitions. - * - * Supported in codecs: VP8 - */ - VP8E_SET_TOKEN_PARTITIONS, - - /*!\brief Codec control function to get last quantizer chosen by the encoder. - * - * Return value uses internal quantizer scale defined by the codec. - * - * Supported in codecs: VP8, VP9 - */ - VP8E_GET_LAST_QUANTIZER, - - /*!\brief Codec control function to get last quantizer chosen by the encoder. - * - * Return value uses the 0..63 scale as used by the rc_*_quantizer config - * parameters. - * - * Supported in codecs: VP8, VP9 - */ - VP8E_GET_LAST_QUANTIZER_64, - - /*!\brief Codec control function to set the max no of frames to create arf. - * - * Supported in codecs: VP8, VP9 - */ - VP8E_SET_ARNR_MAXFRAMES, - - /*!\brief Codec control function to set the filter strength for the arf. - * - * Supported in codecs: VP8, VP9 - */ - VP8E_SET_ARNR_STRENGTH, - - /*!\deprecated control function to set the filter type to use for the arf. */ - VP8E_SET_ARNR_TYPE, - - /*!\brief Codec control function to set visual tuning. - * - * Supported in codecs: VP8, VP9 - */ - VP8E_SET_TUNING, - - /*!\brief Codec control function to set constrained quality level. - * - * \attention For this value to be used vpx_codec_enc_cfg_t::g_usage must be - * set to #VPX_CQ. - * \note Valid range: 0..63 - * - * Supported in codecs: VP8, VP9 - */ - VP8E_SET_CQ_LEVEL, - - /*!\brief Codec control function to set Max data rate for Intra frames. - * - * This value controls additional clamping on the maximum size of a - * keyframe. It is expressed as a percentage of the average - * per-frame bitrate, with the special (and default) value 0 meaning - * unlimited, or no additional clamping beyond the codec's built-in - * algorithm. - * - * For example, to allocate no more than 4.5 frames worth of bitrate - * to a keyframe, set this to 450. - * - * Supported in codecs: VP8, VP9 - */ - VP8E_SET_MAX_INTRA_BITRATE_PCT, - - /*!\brief Codec control function to set reference and update frame flags. - * - * Supported in codecs: VP8 - */ - VP8E_SET_FRAME_FLAGS, - - /*!\brief Codec control function to set max data rate for Inter frames. - * - * This value controls additional clamping on the maximum size of an - * inter frame. It is expressed as a percentage of the average - * per-frame bitrate, with the special (and default) value 0 meaning - * unlimited, or no additional clamping beyond the codec's built-in - * algorithm. - * - * For example, to allow no more than 4.5 frames worth of bitrate - * to an inter frame, set this to 450. - * - * Supported in codecs: VP9 - */ - VP9E_SET_MAX_INTER_BITRATE_PCT, - - /*!\brief Boost percentage for Golden Frame in CBR mode. - * - * This value controls the amount of boost given to Golden Frame in - * CBR mode. It is expressed as a percentage of the average - * per-frame bitrate, with the special (and default) value 0 meaning - * the feature is off, i.e., no golden frame boost in CBR mode and - * average bitrate target is used. - * - * For example, to allow 100% more bits, i.e, 2X, in a golden frame - * than average frame, set this to 100. - * - * Supported in codecs: VP9 - */ - VP9E_SET_GF_CBR_BOOST_PCT, - - /*!\brief Codec control function to set the temporal layer id. - * - * For temporal scalability: this control allows the application to set the - * layer id for each frame to be encoded. Note that this control must be set - * for every frame prior to encoding. The usage of this control function - * supersedes the internal temporal pattern counter, which is now deprecated. - * - * Supported in codecs: VP8 - */ - VP8E_SET_TEMPORAL_LAYER_ID, - - /*!\brief Codec control function to set encoder screen content mode. - * - * 0: off, 1: On, 2: On with more aggressive rate control. - * - * Supported in codecs: VP8 - */ - VP8E_SET_SCREEN_CONTENT_MODE, - - /*!\brief Codec control function to set lossless encoding mode. - * - * VP9 can operate in lossless encoding mode, in which the bitstream - * produced will be able to decode and reconstruct a perfect copy of - * input source. This control function provides a mean to switch encoder - * into lossless coding mode(1) or normal coding mode(0) that may be lossy. - * 0 = lossy coding mode - * 1 = lossless coding mode - * - * By default, encoder operates in normal coding mode (maybe lossy). - * - * Supported in codecs: VP9 - */ - VP9E_SET_LOSSLESS, - - /*!\brief Codec control function to set number of tile columns. - * - * In encoding and decoding, VP9 allows an input image frame be partitioned - * into separated vertical tile columns, which can be encoded or decoded - * independently. This enables easy implementation of parallel encoding and - * decoding. This control requests the encoder to use column tiles in - * encoding an input frame, with number of tile columns (in Log2 unit) as - * the parameter: - * 0 = 1 tile column - * 1 = 2 tile columns - * 2 = 4 tile columns - * ..... - * n = 2**n tile columns - * The requested tile columns will be capped by encoder based on image size - * limitation (The minimum width of a tile column is 256 pixel, the maximum - * is 4096). - * - * By default, the value is 0, i.e. one single column tile for entire image. - * - * Supported in codecs: VP9 - */ - VP9E_SET_TILE_COLUMNS, - - /*!\brief Codec control function to set number of tile rows. - * - * In encoding and decoding, VP9 allows an input image frame be partitioned - * into separated horizontal tile rows. Tile rows are encoded or decoded - * sequentially. Even though encoding/decoding of later tile rows depends on - * earlier ones, this allows the encoder to output data packets for tile rows - * prior to completely processing all tile rows in a frame, thereby reducing - * the latency in processing between input and output. The parameter - * for this control describes the number of tile rows, which has a valid - * range [0, 2]: - * 0 = 1 tile row - * 1 = 2 tile rows - * 2 = 4 tile rows - * - * By default, the value is 0, i.e. one single row tile for entire image. - * - * Supported in codecs: VP9 - */ - VP9E_SET_TILE_ROWS, - - /*!\brief Codec control function to enable frame parallel decoding feature. - * - * VP9 has a bitstream feature to reduce decoding dependency between frames - * by turning off backward update of probability context used in encoding - * and decoding. This allows staged parallel processing of more than one - * video frames in the decoder. This control function provides a mean to - * turn this feature on or off for bitstreams produced by encoder. - * - * By default, this feature is off. - * - * Supported in codecs: VP9 - */ - VP9E_SET_FRAME_PARALLEL_DECODING, - - /*!\brief Codec control function to set adaptive quantization mode. - * - * VP9 has a segment based feature that allows encoder to adaptively change - * quantization parameter for each segment within a frame to improve the - * subjective quality. This control makes encoder operate in one of the - * several AQ_modes supported. - * - * By default, encoder operates with AQ_Mode 0(adaptive quantization off). - * - * Supported in codecs: VP9 - */ - VP9E_SET_AQ_MODE, - - /*!\brief Codec control function to enable/disable periodic Q boost. - * - * One VP9 encoder speed feature is to enable quality boost by lowering - * frame level Q periodically. This control function provides a mean to - * turn on/off this feature. - * 0 = off - * 1 = on - * - * By default, the encoder is allowed to use this feature for appropriate - * encoding modes. - * - * Supported in codecs: VP9 - */ - VP9E_SET_FRAME_PERIODIC_BOOST, - - /*!\brief Codec control function to set noise sensitivity. - * - * 0: off, 1: On(YOnly) - * - * Supported in codecs: VP9 - */ - VP9E_SET_NOISE_SENSITIVITY, - - /*!\brief Codec control function to turn on/off SVC in encoder. - * \note Return value is VPX_CODEC_INVALID_PARAM if the encoder does not - * support SVC in its current encoding mode - * 0: off, 1: on - * - * Supported in codecs: VP9 - */ - VP9E_SET_SVC, - - /*!\brief Codec control function to set parameters for SVC. - * \note Parameters contain min_q, max_q, scaling factor for each of the - * SVC layers. - * - * Supported in codecs: VP9 - */ - VP9E_SET_SVC_PARAMETERS, - - /*!\brief Codec control function to set svc layer for spatial and temporal. - * \note Valid ranges: 0..#vpx_codec_enc_cfg::ss_number_layers for spatial - * layer and 0..#vpx_codec_enc_cfg::ts_number_layers for - * temporal layer. - * - * Supported in codecs: VP9 - */ - VP9E_SET_SVC_LAYER_ID, - - /*!\brief Codec control function to set content type. - * \note Valid parameter range: - * VP9E_CONTENT_DEFAULT = Regular video content (Default) - * VP9E_CONTENT_SCREEN = Screen capture content - * - * Supported in codecs: VP9 - */ - VP9E_SET_TUNE_CONTENT, - - /*!\brief Codec control function to get svc layer ID. - * \note The layer ID returned is for the data packet from the registered - * callback function. - * - * Supported in codecs: VP9 - */ - VP9E_GET_SVC_LAYER_ID, - - /*!\brief Codec control function to register callback to get per layer packet. - * \note Parameter for this control function is a structure with a callback - * function and a pointer to private data used by the callback. - * - * Supported in codecs: VP9 - */ - VP9E_REGISTER_CX_CALLBACK, - - /*!\brief Codec control function to set color space info. - * \note Valid ranges: 0..7, default is "UNKNOWN". - * 0 = UNKNOWN, - * 1 = BT_601 - * 2 = BT_709 - * 3 = SMPTE_170 - * 4 = SMPTE_240 - * 5 = BT_2020 - * 6 = RESERVED - * 7 = SRGB - * - * Supported in codecs: VP9 - */ - VP9E_SET_COLOR_SPACE, - - /*!\brief Codec control function to set temporal layering mode. - * \note Valid ranges: 0..3, default is "0" - * (VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING). - * 0 = VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING - * 1 = VP9E_TEMPORAL_LAYERING_MODE_BYPASS - * 2 = VP9E_TEMPORAL_LAYERING_MODE_0101 - * 3 = VP9E_TEMPORAL_LAYERING_MODE_0212 - * - * Supported in codecs: VP9 - */ - VP9E_SET_TEMPORAL_LAYERING_MODE, - - /*!\brief Codec control function to set minimum interval between GF/ARF frames - * - * By default the value is set as 4. - * - * Supported in codecs: VP9 - */ - VP9E_SET_MIN_GF_INTERVAL, - - /*!\brief Codec control function to set minimum interval between GF/ARF frames - * - * By default the value is set as 16. - * - * Supported in codecs: VP9 - */ - VP9E_SET_MAX_GF_INTERVAL, - - /*!\brief Codec control function to get an Active map back from the encoder. - * - * Supported in codecs: VP9 - */ - VP9E_GET_ACTIVEMAP, - - /*!\brief Codec control function to set color range bit. - * \note Valid ranges: 0..1, default is 0 - * 0 = Limited range (16..235 or HBD equivalent) - * 1 = Full range (0..255 or HBD equivalent) - * - * Supported in codecs: VP9 - */ - VP9E_SET_COLOR_RANGE, - - /*!\brief Codec control function to set the frame flags and buffer indices - * for spatial layers. The frame flags and buffer indices are set using the - * struct #vpx_svc_ref_frame_config defined below. - * - * Supported in codecs: VP9 - */ - VP9E_SET_SVC_REF_FRAME_CONFIG, - - /*!\brief Codec control function to set intended rendering image size. - * - * By default, this is identical to the image size in pixels. - * - * Supported in codecs: VP9 - */ - VP9E_SET_RENDER_SIZE, - - /*!\brief Codec control function to set target level. - * - * 255: off (default); 0: only keep level stats; 10: target for level 1.0; - * 11: target for level 1.1; ... 62: target for level 6.2 - * - * Supported in codecs: VP9 - */ - VP9E_SET_TARGET_LEVEL, - - /*!\brief Codec control function to get bitstream level. - * - * Supported in codecs: VP9 - */ - VP9E_GET_LEVEL, - - /*!\brief Codec control function to enable/disable special mode for altref - * adaptive quantization. You can use it with --aq-mode concurrently. - * - * Enable special adaptive quantization for altref frames based on their - * expected prediction quality for the future frames. - * - * Supported in codecs: VP9 - */ - VP9E_SET_ALT_REF_AQ, - - /*!\brief Boost percentage for Golden Frame in CBR mode. - * - * This value controls the amount of boost given to Golden Frame in - * CBR mode. It is expressed as a percentage of the average - * per-frame bitrate, with the special (and default) value 0 meaning - * the feature is off, i.e., no golden frame boost in CBR mode and - * average bitrate target is used. - * - * For example, to allow 100% more bits, i.e, 2X, in a golden frame - * than average frame, set this to 100. - * - * Supported in codecs: VP8 - */ - VP8E_SET_GF_CBR_BOOST_PCT, -}; - -/*!\brief vpx 1-D scaling mode - * - * This set of constants define 1-D vpx scaling modes - */ -typedef enum vpx_scaling_mode_1d { - VP8E_NORMAL = 0, - VP8E_FOURFIVE = 1, - VP8E_THREEFIVE = 2, - VP8E_ONETWO = 3 -} VPX_SCALING_MODE; - -/*!\brief Temporal layering mode enum for VP9 SVC. - * - * This set of macros define the different temporal layering modes. - * Supported codecs: VP9 (in SVC mode) - * - */ -typedef enum vp9e_temporal_layering_mode { - /*!\brief No temporal layering. - * Used when only spatial layering is used. - */ - VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING = 0, - - /*!\brief Bypass mode. - * Used when application needs to control temporal layering. - * This will only work when the number of spatial layers equals 1. - */ - VP9E_TEMPORAL_LAYERING_MODE_BYPASS = 1, - - /*!\brief 0-1-0-1... temporal layering scheme with two temporal layers. - */ - VP9E_TEMPORAL_LAYERING_MODE_0101 = 2, - - /*!\brief 0-2-1-2... temporal layering scheme with three temporal layers. - */ - VP9E_TEMPORAL_LAYERING_MODE_0212 = 3 -} VP9E_TEMPORAL_LAYERING_MODE; - -/*!\brief vpx region of interest map - * - * These defines the data structures for the region of interest map - * - */ - -typedef struct vpx_roi_map { - /*! An id between 0 and 3 for each 16x16 region within a frame. */ - unsigned char *roi_map; - unsigned int rows; /**< Number of rows. */ - unsigned int cols; /**< Number of columns. */ - // TODO(paulwilkins): broken for VP9 which has 8 segments - // q and loop filter deltas for each segment - // (see MAX_MB_SEGMENTS) - int delta_q[4]; /**< Quantizer deltas. */ - int delta_lf[4]; /**< Loop filter deltas. */ - /*! Static breakout threshold for each segment. */ - unsigned int static_threshold[4]; -} vpx_roi_map_t; - -/*!\brief vpx active region map - * - * These defines the data structures for active region map - * - */ - -typedef struct vpx_active_map { - /*!\brief specify an on (1) or off (0) each 16x16 region within a frame */ - unsigned char *active_map; - unsigned int rows; /**< number of rows */ - unsigned int cols; /**< number of cols */ -} vpx_active_map_t; - -/*!\brief vpx image scaling mode - * - * This defines the data structure for image scaling mode - * - */ -typedef struct vpx_scaling_mode { - VPX_SCALING_MODE h_scaling_mode; /**< horizontal scaling mode */ - VPX_SCALING_MODE v_scaling_mode; /**< vertical scaling mode */ -} vpx_scaling_mode_t; - -/*!\brief VP8 token partition mode - * - * This defines VP8 partitioning mode for compressed data, i.e., the number of - * sub-streams in the bitstream. Used for parallelized decoding. - * - */ - -typedef enum { - VP8_ONE_TOKENPARTITION = 0, - VP8_TWO_TOKENPARTITION = 1, - VP8_FOUR_TOKENPARTITION = 2, - VP8_EIGHT_TOKENPARTITION = 3 -} vp8e_token_partitions; - -/*!brief VP9 encoder content type */ -typedef enum { - VP9E_CONTENT_DEFAULT, - VP9E_CONTENT_SCREEN, - VP9E_CONTENT_INVALID -} vp9e_tune_content; - -/*!\brief VP8 model tuning parameters - * - * Changes the encoder to tune for certain types of input material. - * - */ -typedef enum { VP8_TUNE_PSNR, VP8_TUNE_SSIM } vp8e_tuning; - -/*!\brief vp9 svc layer parameters - * - * This defines the spatial and temporal layer id numbers for svc encoding. - * This is used with the #VP9E_SET_SVC_LAYER_ID control to set the spatial and - * temporal layer id for the current frame. - * - */ -typedef struct vpx_svc_layer_id { - int spatial_layer_id; /**< Spatial layer id number. */ - int temporal_layer_id; /**< Temporal layer id number. */ -} vpx_svc_layer_id_t; - -/*!\brief vp9 svc frame flag parameters. - * - * This defines the frame flags and buffer indices for each spatial layer for - * svc encoding. - * This is used with the #VP9E_SET_SVC_REF_FRAME_CONFIG control to set frame - * flags and buffer indices for each spatial layer for the current (super)frame. - * - */ -typedef struct vpx_svc_ref_frame_config { - int frame_flags[VPX_TS_MAX_LAYERS]; /**< Frame flags. */ - int lst_fb_idx[VPX_TS_MAX_LAYERS]; /**< Last buffer index. */ - int gld_fb_idx[VPX_TS_MAX_LAYERS]; /**< Golden buffer index. */ - int alt_fb_idx[VPX_TS_MAX_LAYERS]; /**< Altref buffer index. */ -} vpx_svc_ref_frame_config_t; - -/*!\cond */ -/*!\brief VP8 encoder control function parameter type - * - * Defines the data types that VP8E control functions take. Note that - * additional common controls are defined in vp8.h - * - */ - -VPX_CTRL_USE_TYPE(VP8E_SET_FRAME_FLAGS, int) -#define VPX_CTRL_VP8E_SET_FRAME_FLAGS -VPX_CTRL_USE_TYPE(VP8E_SET_TEMPORAL_LAYER_ID, int) -#define VPX_CTRL_VP8E_SET_TEMPORAL_LAYER_ID -VPX_CTRL_USE_TYPE(VP8E_SET_ROI_MAP, vpx_roi_map_t *) -#define VPX_CTRL_VP8E_SET_ROI_MAP -VPX_CTRL_USE_TYPE(VP8E_SET_ACTIVEMAP, vpx_active_map_t *) -#define VPX_CTRL_VP8E_SET_ACTIVEMAP -VPX_CTRL_USE_TYPE(VP8E_SET_SCALEMODE, vpx_scaling_mode_t *) -#define VPX_CTRL_VP8E_SET_SCALEMODE - -VPX_CTRL_USE_TYPE(VP9E_SET_SVC, int) -#define VPX_CTRL_VP9E_SET_SVC -VPX_CTRL_USE_TYPE(VP9E_SET_SVC_PARAMETERS, void *) -#define VPX_CTRL_VP9E_SET_SVC_PARAMETERS -VPX_CTRL_USE_TYPE(VP9E_REGISTER_CX_CALLBACK, void *) -#define VPX_CTRL_VP9E_REGISTER_CX_CALLBACK -VPX_CTRL_USE_TYPE(VP9E_SET_SVC_LAYER_ID, vpx_svc_layer_id_t *) -#define VPX_CTRL_VP9E_SET_SVC_LAYER_ID - -VPX_CTRL_USE_TYPE(VP8E_SET_CPUUSED, int) -#define VPX_CTRL_VP8E_SET_CPUUSED -VPX_CTRL_USE_TYPE(VP8E_SET_ENABLEAUTOALTREF, unsigned int) -#define VPX_CTRL_VP8E_SET_ENABLEAUTOALTREF -VPX_CTRL_USE_TYPE(VP8E_SET_NOISE_SENSITIVITY, unsigned int) -#define VPX_CTRL_VP8E_SET_NOISE_SENSITIVITY -VPX_CTRL_USE_TYPE(VP8E_SET_SHARPNESS, unsigned int) -#define VPX_CTRL_VP8E_SET_SHARPNESS -VPX_CTRL_USE_TYPE(VP8E_SET_STATIC_THRESHOLD, unsigned int) -#define VPX_CTRL_VP8E_SET_STATIC_THRESHOLD -VPX_CTRL_USE_TYPE(VP8E_SET_TOKEN_PARTITIONS, int) /* vp8e_token_partitions */ -#define VPX_CTRL_VP8E_SET_TOKEN_PARTITIONS - -VPX_CTRL_USE_TYPE(VP8E_SET_ARNR_MAXFRAMES, unsigned int) -#define VPX_CTRL_VP8E_SET_ARNR_MAXFRAMES -VPX_CTRL_USE_TYPE(VP8E_SET_ARNR_STRENGTH, unsigned int) -#define VPX_CTRL_VP8E_SET_ARNR_STRENGTH -VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_SET_ARNR_TYPE, unsigned int) -#define VPX_CTRL_VP8E_SET_ARNR_TYPE -VPX_CTRL_USE_TYPE(VP8E_SET_TUNING, int) /* vp8e_tuning */ -#define VPX_CTRL_VP8E_SET_TUNING -VPX_CTRL_USE_TYPE(VP8E_SET_CQ_LEVEL, unsigned int) -#define VPX_CTRL_VP8E_SET_CQ_LEVEL - -VPX_CTRL_USE_TYPE(VP9E_SET_TILE_COLUMNS, int) -#define VPX_CTRL_VP9E_SET_TILE_COLUMNS -VPX_CTRL_USE_TYPE(VP9E_SET_TILE_ROWS, int) -#define VPX_CTRL_VP9E_SET_TILE_ROWS - -VPX_CTRL_USE_TYPE(VP8E_GET_LAST_QUANTIZER, int *) -#define VPX_CTRL_VP8E_GET_LAST_QUANTIZER -VPX_CTRL_USE_TYPE(VP8E_GET_LAST_QUANTIZER_64, int *) -#define VPX_CTRL_VP8E_GET_LAST_QUANTIZER_64 -VPX_CTRL_USE_TYPE(VP9E_GET_SVC_LAYER_ID, vpx_svc_layer_id_t *) -#define VPX_CTRL_VP9E_GET_SVC_LAYER_ID - -VPX_CTRL_USE_TYPE(VP8E_SET_MAX_INTRA_BITRATE_PCT, unsigned int) -#define VPX_CTRL_VP8E_SET_MAX_INTRA_BITRATE_PCT -VPX_CTRL_USE_TYPE(VP8E_SET_MAX_INTER_BITRATE_PCT, unsigned int) -#define VPX_CTRL_VP8E_SET_MAX_INTER_BITRATE_PCT - -VPX_CTRL_USE_TYPE(VP8E_SET_GF_CBR_BOOST_PCT, unsigned int) -#define VPX_CTRL_VP8E_SET_GF_CBR_BOOST_PCT - -VPX_CTRL_USE_TYPE(VP8E_SET_SCREEN_CONTENT_MODE, unsigned int) -#define VPX_CTRL_VP8E_SET_SCREEN_CONTENT_MODE - -VPX_CTRL_USE_TYPE(VP9E_SET_GF_CBR_BOOST_PCT, unsigned int) -#define VPX_CTRL_VP9E_SET_GF_CBR_BOOST_PCT - -VPX_CTRL_USE_TYPE(VP9E_SET_LOSSLESS, unsigned int) -#define VPX_CTRL_VP9E_SET_LOSSLESS - -VPX_CTRL_USE_TYPE(VP9E_SET_FRAME_PARALLEL_DECODING, unsigned int) -#define VPX_CTRL_VP9E_SET_FRAME_PARALLEL_DECODING - -VPX_CTRL_USE_TYPE(VP9E_SET_AQ_MODE, unsigned int) -#define VPX_CTRL_VP9E_SET_AQ_MODE - -VPX_CTRL_USE_TYPE(VP9E_SET_ALT_REF_AQ, int) -#define VPX_CTRL_VP9E_SET_ALT_REF_AQ - -VPX_CTRL_USE_TYPE(VP9E_SET_FRAME_PERIODIC_BOOST, unsigned int) -#define VPX_CTRL_VP9E_SET_FRAME_PERIODIC_BOOST - -VPX_CTRL_USE_TYPE(VP9E_SET_NOISE_SENSITIVITY, unsigned int) -#define VPX_CTRL_VP9E_SET_NOISE_SENSITIVITY - -VPX_CTRL_USE_TYPE(VP9E_SET_TUNE_CONTENT, int) /* vp9e_tune_content */ -#define VPX_CTRL_VP9E_SET_TUNE_CONTENT - -VPX_CTRL_USE_TYPE(VP9E_SET_COLOR_SPACE, int) -#define VPX_CTRL_VP9E_SET_COLOR_SPACE - -VPX_CTRL_USE_TYPE(VP9E_SET_MIN_GF_INTERVAL, unsigned int) -#define VPX_CTRL_VP9E_SET_MIN_GF_INTERVAL - -VPX_CTRL_USE_TYPE(VP9E_SET_MAX_GF_INTERVAL, unsigned int) -#define VPX_CTRL_VP9E_SET_MAX_GF_INTERVAL - -VPX_CTRL_USE_TYPE(VP9E_GET_ACTIVEMAP, vpx_active_map_t *) -#define VPX_CTRL_VP9E_GET_ACTIVEMAP - -VPX_CTRL_USE_TYPE(VP9E_SET_COLOR_RANGE, int) -#define VPX_CTRL_VP9E_SET_COLOR_RANGE - -VPX_CTRL_USE_TYPE(VP9E_SET_SVC_REF_FRAME_CONFIG, vpx_svc_ref_frame_config_t *) -#define VPX_CTRL_VP9E_SET_SVC_REF_FRAME_CONFIG - -VPX_CTRL_USE_TYPE(VP9E_SET_RENDER_SIZE, int *) -#define VPX_CTRL_VP9E_SET_RENDER_SIZE - -VPX_CTRL_USE_TYPE(VP9E_SET_TARGET_LEVEL, unsigned int) -#define VPX_CTRL_VP9E_SET_TARGET_LEVEL - -VPX_CTRL_USE_TYPE(VP9E_GET_LEVEL, int *) -#define VPX_CTRL_VP9E_GET_LEVEL - -/*!\endcond */ -/*! @} - end defgroup vp8_encoder */ -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // VPX_VP8CX_H_ diff --git a/protocols/Tox/include/vpx/vp8dx.h b/protocols/Tox/include/vpx/vp8dx.h deleted file mode 100644 index 0d7759eb25..0000000000 --- a/protocols/Tox/include/vpx/vp8dx.h +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -/*!\defgroup vp8_decoder WebM VP8/VP9 Decoder - * \ingroup vp8 - * - * @{ - */ -/*!\file - * \brief Provides definitions for using VP8 or VP9 within the vpx Decoder - * interface. - */ -#ifndef VPX_VP8DX_H_ -#define VPX_VP8DX_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Include controls common to both the encoder and decoder */ -#include "./vp8.h" - -/*!\name Algorithm interface for VP8 - * - * This interface provides the capability to decode VP8 streams. - * @{ - */ -extern vpx_codec_iface_t vpx_codec_vp8_dx_algo; -extern vpx_codec_iface_t *vpx_codec_vp8_dx(void); -/*!@} - end algorithm interface member group*/ - -/*!\name Algorithm interface for VP9 - * - * This interface provides the capability to decode VP9 streams. - * @{ - */ -extern vpx_codec_iface_t vpx_codec_vp9_dx_algo; -extern vpx_codec_iface_t *vpx_codec_vp9_dx(void); -/*!@} - end algorithm interface member group*/ - -/*!\enum vp8_dec_control_id - * \brief VP8 decoder control functions - * - * This set of macros define the control functions available for the VP8 - * decoder interface. - * - * \sa #vpx_codec_control - */ -enum vp8_dec_control_id { - /** control function to get info on which reference frames were updated - * by the last decode - */ - VP8D_GET_LAST_REF_UPDATES = VP8_DECODER_CTRL_ID_START, - - /** check if the indicated frame is corrupted */ - VP8D_GET_FRAME_CORRUPTED, - - /** control function to get info on which reference frames were used - * by the last decode - */ - VP8D_GET_LAST_REF_USED, - - /** decryption function to decrypt encoded buffer data immediately - * before decoding. Takes a vpx_decrypt_init, which contains - * a callback function and opaque context pointer. - */ - VPXD_SET_DECRYPTOR, - VP8D_SET_DECRYPTOR = VPXD_SET_DECRYPTOR, - - /** control function to get the dimensions that the current frame is decoded - * at. This may be different to the intended display size for the frame as - * specified in the wrapper or frame header (see VP9D_GET_DISPLAY_SIZE). */ - VP9D_GET_FRAME_SIZE, - - /** control function to get the current frame's intended display dimensions - * (as specified in the wrapper or frame header). This may be different to - * the decoded dimensions of this frame (see VP9D_GET_FRAME_SIZE). */ - VP9D_GET_DISPLAY_SIZE, - - /** control function to get the bit depth of the stream. */ - VP9D_GET_BIT_DEPTH, - - /** control function to set the byte alignment of the planes in the reference - * buffers. Valid values are power of 2, from 32 to 1024. A value of 0 sets - * legacy alignment. I.e. Y plane is aligned to 32 bytes, U plane directly - * follows Y plane, and V plane directly follows U plane. Default value is 0. - */ - VP9_SET_BYTE_ALIGNMENT, - - /** control function to invert the decoding order to from right to left. The - * function is used in a test to confirm the decoding independence of tile - * columns. The function may be used in application where this order - * of decoding is desired. - * - * TODO(yaowu): Rework the unit test that uses this control, and in a future - * release, this test-only control shall be removed. - */ - VP9_INVERT_TILE_DECODE_ORDER, - - /** control function to set the skip loop filter flag. Valid values are - * integers. The decoder will skip the loop filter when its value is set to - * nonzero. If the loop filter is skipped the decoder may accumulate decode - * artifacts. The default value is 0. - */ - VP9_SET_SKIP_LOOP_FILTER, - - /** control function to decode SVC stream up to the x spatial layers, - * where x is passed in through the control, and is 0 for base layer. - */ - VP9_DECODE_SVC_SPATIAL_LAYER, - - VP8_DECODER_CTRL_ID_MAX -}; - -/** Decrypt n bytes of data from input -> output, using the decrypt_state - * passed in VPXD_SET_DECRYPTOR. - */ -typedef void (*vpx_decrypt_cb)(void *decrypt_state, const unsigned char *input, - unsigned char *output, int count); - -/*!\brief Structure to hold decryption state - * - * Defines a structure to hold the decryption state and access function. - */ -typedef struct vpx_decrypt_init { - /*! Decrypt callback. */ - vpx_decrypt_cb decrypt_cb; - - /*! Decryption state. */ - void *decrypt_state; -} vpx_decrypt_init; - -/*!\brief A deprecated alias for vpx_decrypt_init. - */ -typedef vpx_decrypt_init vp8_decrypt_init; - -/*!\cond */ -/*!\brief VP8 decoder control function parameter type - * - * Defines the data types that VP8D control functions take. Note that - * additional common controls are defined in vp8.h - * - */ - -VPX_CTRL_USE_TYPE(VP8D_GET_LAST_REF_UPDATES, int *) -#define VPX_CTRL_VP8D_GET_LAST_REF_UPDATES -VPX_CTRL_USE_TYPE(VP8D_GET_FRAME_CORRUPTED, int *) -#define VPX_CTRL_VP8D_GET_FRAME_CORRUPTED -VPX_CTRL_USE_TYPE(VP8D_GET_LAST_REF_USED, int *) -#define VPX_CTRL_VP8D_GET_LAST_REF_USED -VPX_CTRL_USE_TYPE(VPXD_SET_DECRYPTOR, vpx_decrypt_init *) -#define VPX_CTRL_VPXD_SET_DECRYPTOR -VPX_CTRL_USE_TYPE(VP8D_SET_DECRYPTOR, vpx_decrypt_init *) -#define VPX_CTRL_VP8D_SET_DECRYPTOR -VPX_CTRL_USE_TYPE(VP9D_GET_DISPLAY_SIZE, int *) -#define VPX_CTRL_VP9D_GET_DISPLAY_SIZE -VPX_CTRL_USE_TYPE(VP9D_GET_BIT_DEPTH, unsigned int *) -#define VPX_CTRL_VP9D_GET_BIT_DEPTH -VPX_CTRL_USE_TYPE(VP9D_GET_FRAME_SIZE, int *) -#define VPX_CTRL_VP9D_GET_FRAME_SIZE -VPX_CTRL_USE_TYPE(VP9_INVERT_TILE_DECODE_ORDER, int) -#define VPX_CTRL_VP9_INVERT_TILE_DECODE_ORDER -#define VPX_CTRL_VP9_DECODE_SVC_SPATIAL_LAYER -VPX_CTRL_USE_TYPE(VP9_DECODE_SVC_SPATIAL_LAYER, int) - -/*!\endcond */ -/*! @} - end defgroup vp8_decoder */ - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // VPX_VP8DX_H_ diff --git a/protocols/Tox/include/vpx/vpx_codec.h b/protocols/Tox/include/vpx/vpx_codec.h deleted file mode 100644 index fe75d23872..0000000000 --- a/protocols/Tox/include/vpx/vpx_codec.h +++ /dev/null @@ -1,463 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -/*!\defgroup codec Common Algorithm Interface - * This abstraction allows applications to easily support multiple video - * formats with minimal code duplication. This section describes the interface - * common to all codecs (both encoders and decoders). - * @{ - */ - -/*!\file - * \brief Describes the codec algorithm interface to applications. - * - * This file describes the interface between an application and a - * video codec algorithm. - * - * An application instantiates a specific codec instance by using - * vpx_codec_init() and a pointer to the algorithm's interface structure: - * <pre> - * my_app.c: - * extern vpx_codec_iface_t my_codec; - * { - * vpx_codec_ctx_t algo; - * res = vpx_codec_init(&algo, &my_codec); - * } - * </pre> - * - * Once initialized, the instance is manged using other functions from - * the vpx_codec_* family. - */ -#ifndef VPX_VPX_CODEC_H_ -#define VPX_VPX_CODEC_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "./vpx_integer.h" -#include "./vpx_image.h" - -/*!\brief Decorator indicating a function is deprecated */ -#ifndef DEPRECATED -#if defined(__GNUC__) && __GNUC__ -#define DEPRECATED __attribute__((deprecated)) -#elif defined(_MSC_VER) -#define DEPRECATED -#else -#define DEPRECATED -#endif -#endif /* DEPRECATED */ - -#ifndef DECLSPEC_DEPRECATED -#if defined(__GNUC__) && __GNUC__ -#define DECLSPEC_DEPRECATED /**< \copydoc #DEPRECATED */ -#elif defined(_MSC_VER) -/*!\brief \copydoc #DEPRECATED */ -#define DECLSPEC_DEPRECATED __declspec(deprecated) -#else -#define DECLSPEC_DEPRECATED /**< \copydoc #DEPRECATED */ -#endif -#endif /* DECLSPEC_DEPRECATED */ - -/*!\brief Decorator indicating a function is potentially unused */ -#ifdef UNUSED -#elif defined(__GNUC__) || defined(__clang__) -#define UNUSED __attribute__((unused)) -#else -#define UNUSED -#endif - -/*!\brief Current ABI version number - * - * \internal - * If this file is altered in any way that changes the ABI, this value - * must be bumped. Examples include, but are not limited to, changing - * types, removing or reassigning enums, adding/removing/rearranging - * fields to structures - */ -#define VPX_CODEC_ABI_VERSION (3 + VPX_IMAGE_ABI_VERSION) /**<\hideinitializer*/ - -/*!\brief Algorithm return codes */ -typedef enum { - /*!\brief Operation completed without error */ - VPX_CODEC_OK, - - /*!\brief Unspecified error */ - VPX_CODEC_ERROR, - - /*!\brief Memory operation failed */ - VPX_CODEC_MEM_ERROR, - - /*!\brief ABI version mismatch */ - VPX_CODEC_ABI_MISMATCH, - - /*!\brief Algorithm does not have required capability */ - VPX_CODEC_INCAPABLE, - - /*!\brief The given bitstream is not supported. - * - * The bitstream was unable to be parsed at the highest level. The decoder - * is unable to proceed. This error \ref SHOULD be treated as fatal to the - * stream. */ - VPX_CODEC_UNSUP_BITSTREAM, - - /*!\brief Encoded bitstream uses an unsupported feature - * - * The decoder does not implement a feature required by the encoder. This - * return code should only be used for features that prevent future - * pictures from being properly decoded. This error \ref MAY be treated as - * fatal to the stream or \ref MAY be treated as fatal to the current GOP. - */ - VPX_CODEC_UNSUP_FEATURE, - - /*!\brief The coded data for this stream is corrupt or incomplete - * - * There was a problem decoding the current frame. This return code - * should only be used for failures that prevent future pictures from - * being properly decoded. This error \ref MAY be treated as fatal to the - * stream or \ref MAY be treated as fatal to the current GOP. If decoding - * is continued for the current GOP, artifacts may be present. - */ - VPX_CODEC_CORRUPT_FRAME, - - /*!\brief An application-supplied parameter is not valid. - * - */ - VPX_CODEC_INVALID_PARAM, - - /*!\brief An iterator reached the end of list. - * - */ - VPX_CODEC_LIST_END - -} vpx_codec_err_t; - -/*! \brief Codec capabilities bitfield - * - * Each codec advertises the capabilities it supports as part of its - * ::vpx_codec_iface_t interface structure. Capabilities are extra interfaces - * or functionality, and are not required to be supported. - * - * The available flags are specified by VPX_CODEC_CAP_* defines. - */ -typedef long vpx_codec_caps_t; -#define VPX_CODEC_CAP_DECODER 0x1 /**< Is a decoder */ -#define VPX_CODEC_CAP_ENCODER 0x2 /**< Is an encoder */ - -/*! \brief Initialization-time Feature Enabling - * - * Certain codec features must be known at initialization time, to allow for - * proper memory allocation. - * - * The available flags are specified by VPX_CODEC_USE_* defines. - */ -typedef long vpx_codec_flags_t; - -/*!\brief Codec interface structure. - * - * Contains function pointers and other data private to the codec - * implementation. This structure is opaque to the application. - */ -typedef const struct vpx_codec_iface vpx_codec_iface_t; - -/*!\brief Codec private data structure. - * - * Contains data private to the codec implementation. This structure is opaque - * to the application. - */ -typedef struct vpx_codec_priv vpx_codec_priv_t; - -/*!\brief Iterator - * - * Opaque storage used for iterating over lists. - */ -typedef const void *vpx_codec_iter_t; - -/*!\brief Codec context structure - * - * All codecs \ref MUST support this context structure fully. In general, - * this data should be considered private to the codec algorithm, and - * not be manipulated or examined by the calling application. Applications - * may reference the 'name' member to get a printable description of the - * algorithm. - */ -typedef struct vpx_codec_ctx { - const char *name; /**< Printable interface name */ - vpx_codec_iface_t *iface; /**< Interface pointers */ - vpx_codec_err_t err; /**< Last returned error */ - const char *err_detail; /**< Detailed info, if available */ - vpx_codec_flags_t init_flags; /**< Flags passed at init time */ - union { - /**< Decoder Configuration Pointer */ - const struct vpx_codec_dec_cfg *dec; - /**< Encoder Configuration Pointer */ - const struct vpx_codec_enc_cfg *enc; - const void *raw; - } config; /**< Configuration pointer aliasing union */ - vpx_codec_priv_t *priv; /**< Algorithm private storage */ -} vpx_codec_ctx_t; - -/*!\brief Bit depth for codec - * * - * This enumeration determines the bit depth of the codec. - */ -typedef enum vpx_bit_depth { - VPX_BITS_8 = 8, /**< 8 bits */ - VPX_BITS_10 = 10, /**< 10 bits */ - VPX_BITS_12 = 12, /**< 12 bits */ -} vpx_bit_depth_t; - -/* - * Library Version Number Interface - * - * For example, see the following sample return values: - * vpx_codec_version() (1<<16 | 2<<8 | 3) - * vpx_codec_version_str() "v1.2.3-rc1-16-gec6a1ba" - * vpx_codec_version_extra_str() "rc1-16-gec6a1ba" - */ - -/*!\brief Return the version information (as an integer) - * - * Returns a packed encoding of the library version number. This will only - * include - * the major.minor.patch component of the version number. Note that this encoded - * value should be accessed through the macros provided, as the encoding may - * change - * in the future. - * - */ -int vpx_codec_version(void); -#define VPX_VERSION_MAJOR(v) \ - ((v >> 16) & 0xff) /**< extract major from packed version */ -#define VPX_VERSION_MINOR(v) \ - ((v >> 8) & 0xff) /**< extract minor from packed version */ -#define VPX_VERSION_PATCH(v) \ - ((v >> 0) & 0xff) /**< extract patch from packed version */ - -/*!\brief Return the version major number */ -#define vpx_codec_version_major() ((vpx_codec_version() >> 16) & 0xff) - -/*!\brief Return the version minor number */ -#define vpx_codec_version_minor() ((vpx_codec_version() >> 8) & 0xff) - -/*!\brief Return the version patch number */ -#define vpx_codec_version_patch() ((vpx_codec_version() >> 0) & 0xff) - -/*!\brief Return the version information (as a string) - * - * Returns a printable string containing the full library version number. This - * may - * contain additional text following the three digit version number, as to - * indicate - * release candidates, prerelease versions, etc. - * - */ -const char *vpx_codec_version_str(void); - -/*!\brief Return the version information (as a string) - * - * Returns a printable "extra string". This is the component of the string - * returned - * by vpx_codec_version_str() following the three digit version number. - * - */ -const char *vpx_codec_version_extra_str(void); - -/*!\brief Return the build configuration - * - * Returns a printable string containing an encoded version of the build - * configuration. This may be useful to vpx support. - * - */ -const char *vpx_codec_build_config(void); - -/*!\brief Return the name for a given interface - * - * Returns a human readable string for name of the given codec interface. - * - * \param[in] iface Interface pointer - * - */ -const char *vpx_codec_iface_name(vpx_codec_iface_t *iface); - -/*!\brief Convert error number to printable string - * - * Returns a human readable string for the last error returned by the - * algorithm. The returned error will be one line and will not contain - * any newline characters. - * - * - * \param[in] err Error number. - * - */ -const char *vpx_codec_err_to_string(vpx_codec_err_t err); - -/*!\brief Retrieve error synopsis for codec context - * - * Returns a human readable string for the last error returned by the - * algorithm. The returned error will be one line and will not contain - * any newline characters. - * - * - * \param[in] ctx Pointer to this instance's context. - * - */ -const char *vpx_codec_error(vpx_codec_ctx_t *ctx); - -/*!\brief Retrieve detailed error information for codec context - * - * Returns a human readable string providing detailed information about - * the last error. - * - * \param[in] ctx Pointer to this instance's context. - * - * \retval NULL - * No detailed information is available. - */ -const char *vpx_codec_error_detail(vpx_codec_ctx_t *ctx); - -/* REQUIRED FUNCTIONS - * - * The following functions are required to be implemented for all codecs. - * They represent the base case functionality expected of all codecs. - */ - -/*!\brief Destroy a codec instance - * - * Destroys a codec context, freeing any associated memory buffers. - * - * \param[in] ctx Pointer to this instance's context - * - * \retval #VPX_CODEC_OK - * The codec algorithm initialized. - * \retval #VPX_CODEC_MEM_ERROR - * Memory allocation failed. - */ -vpx_codec_err_t vpx_codec_destroy(vpx_codec_ctx_t *ctx); - -/*!\brief Get the capabilities of an algorithm. - * - * Retrieves the capabilities bitfield from the algorithm's interface. - * - * \param[in] iface Pointer to the algorithm interface - * - */ -vpx_codec_caps_t vpx_codec_get_caps(vpx_codec_iface_t *iface); - -/*!\brief Control algorithm - * - * This function is used to exchange algorithm specific data with the codec - * instance. This can be used to implement features specific to a particular - * algorithm. - * - * This wrapper function dispatches the request to the helper function - * associated with the given ctrl_id. It tries to call this function - * transparently, but will return #VPX_CODEC_ERROR if the request could not - * be dispatched. - * - * Note that this function should not be used directly. Call the - * #vpx_codec_control wrapper macro instead. - * - * \param[in] ctx Pointer to this instance's context - * \param[in] ctrl_id Algorithm specific control identifier - * - * \retval #VPX_CODEC_OK - * The control request was processed. - * \retval #VPX_CODEC_ERROR - * The control request was not processed. - * \retval #VPX_CODEC_INVALID_PARAM - * The data was not valid. - */ -vpx_codec_err_t vpx_codec_control_(vpx_codec_ctx_t *ctx, int ctrl_id, ...); -#if defined(VPX_DISABLE_CTRL_TYPECHECKS) && VPX_DISABLE_CTRL_TYPECHECKS -#define vpx_codec_control(ctx, id, data) vpx_codec_control_(ctx, id, data) -#define VPX_CTRL_USE_TYPE(id, typ) -#define VPX_CTRL_USE_TYPE_DEPRECATED(id, typ) -#define VPX_CTRL_VOID(id, typ) - -#else -/*!\brief vpx_codec_control wrapper macro - * - * This macro allows for type safe conversions across the variadic parameter - * to vpx_codec_control_(). - * - * \internal - * It works by dispatching the call to the control function through a wrapper - * function named with the id parameter. - */ -#define vpx_codec_control(ctx, id, data) \ - vpx_codec_control_##id(ctx, id, data) /**<\hideinitializer*/ - -/*!\brief vpx_codec_control type definition macro - * - * This macro allows for type safe conversions across the variadic parameter - * to vpx_codec_control_(). It defines the type of the argument for a given - * control identifier. - * - * \internal - * It defines a static function with - * the correctly typed arguments as a wrapper to the type-unsafe internal - * function. - */ -#define VPX_CTRL_USE_TYPE(id, typ) \ - static vpx_codec_err_t vpx_codec_control_##id(vpx_codec_ctx_t *, int, typ) \ - UNUSED; \ - \ - static vpx_codec_err_t vpx_codec_control_##id(vpx_codec_ctx_t *ctx, \ - int ctrl_id, typ data) { \ - return vpx_codec_control_(ctx, ctrl_id, data); \ - } /**<\hideinitializer*/ - -/*!\brief vpx_codec_control deprecated type definition macro - * - * Like #VPX_CTRL_USE_TYPE, but indicates that the specified control is - * deprecated and should not be used. Consult the documentation for your - * codec for more information. - * - * \internal - * It defines a static function with the correctly typed arguments as a - * wrapper to the type-unsafe internal function. - */ -#define VPX_CTRL_USE_TYPE_DEPRECATED(id, typ) \ - DECLSPEC_DEPRECATED static vpx_codec_err_t vpx_codec_control_##id( \ - vpx_codec_ctx_t *, int, typ) DEPRECATED UNUSED; \ - \ - DECLSPEC_DEPRECATED static vpx_codec_err_t vpx_codec_control_##id( \ - vpx_codec_ctx_t *ctx, int ctrl_id, typ data) { \ - return vpx_codec_control_(ctx, ctrl_id, data); \ - } /**<\hideinitializer*/ - -/*!\brief vpx_codec_control void type definition macro - * - * This macro allows for type safe conversions across the variadic parameter - * to vpx_codec_control_(). It indicates that a given control identifier takes - * no argument. - * - * \internal - * It defines a static function without a data argument as a wrapper to the - * type-unsafe internal function. - */ -#define VPX_CTRL_VOID(id) \ - static vpx_codec_err_t vpx_codec_control_##id(vpx_codec_ctx_t *, int) \ - UNUSED; \ - \ - static vpx_codec_err_t vpx_codec_control_##id(vpx_codec_ctx_t *ctx, \ - int ctrl_id) { \ - return vpx_codec_control_(ctx, ctrl_id); \ - } /**<\hideinitializer*/ - -#endif - -/*!@} - end defgroup codec*/ -#ifdef __cplusplus -} -#endif -#endif // VPX_VPX_CODEC_H_ diff --git a/protocols/Tox/include/vpx/vpx_decoder.h b/protocols/Tox/include/vpx/vpx_decoder.h deleted file mode 100644 index 2ff12112bc..0000000000 --- a/protocols/Tox/include/vpx/vpx_decoder.h +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ -#ifndef VPX_VPX_DECODER_H_ -#define VPX_VPX_DECODER_H_ - -/*!\defgroup decoder Decoder Algorithm Interface - * \ingroup codec - * This abstraction allows applications using this decoder to easily support - * multiple video formats with minimal code duplication. This section describes - * the interface common to all decoders. - * @{ - */ - -/*!\file - * \brief Describes the decoder algorithm interface to applications. - * - * This file describes the interface between an application and a - * video decoder algorithm. - * - */ -#ifdef __cplusplus -extern "C" { -#endif - -#include "./vpx_codec.h" -#include "./vpx_frame_buffer.h" - -/*!\brief Current ABI version number - * - * \internal - * If this file is altered in any way that changes the ABI, this value - * must be bumped. Examples include, but are not limited to, changing - * types, removing or reassigning enums, adding/removing/rearranging - * fields to structures - */ -#define VPX_DECODER_ABI_VERSION \ - (3 + VPX_CODEC_ABI_VERSION) /**<\hideinitializer*/ - -/*! \brief Decoder capabilities bitfield - * - * Each decoder advertises the capabilities it supports as part of its - * ::vpx_codec_iface_t interface structure. Capabilities are extra interfaces - * or functionality, and are not required to be supported by a decoder. - * - * The available flags are specified by VPX_CODEC_CAP_* defines. - */ -#define VPX_CODEC_CAP_PUT_SLICE 0x10000 /**< Will issue put_slice callbacks */ -#define VPX_CODEC_CAP_PUT_FRAME 0x20000 /**< Will issue put_frame callbacks */ -#define VPX_CODEC_CAP_POSTPROC 0x40000 /**< Can postprocess decoded frame */ -/*!\brief Can conceal errors due to packet loss */ -#define VPX_CODEC_CAP_ERROR_CONCEALMENT 0x80000 -/*!\brief Can receive encoded frames one fragment at a time */ -#define VPX_CODEC_CAP_INPUT_FRAGMENTS 0x100000 - -/*! \brief Initialization-time Feature Enabling - * - * Certain codec features must be known at initialization time, to allow for - * proper memory allocation. - * - * The available flags are specified by VPX_CODEC_USE_* defines. - */ -/*!\brief Can support frame-based multi-threading */ -#define VPX_CODEC_CAP_FRAME_THREADING 0x200000 -/*!brief Can support external frame buffers */ -#define VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER 0x400000 - -#define VPX_CODEC_USE_POSTPROC 0x10000 /**< Postprocess decoded frame */ -/*!\brief Conceal errors in decoded frames */ -#define VPX_CODEC_USE_ERROR_CONCEALMENT 0x20000 -/*!\brief The input frame should be passed to the decoder one fragment at a - * time */ -#define VPX_CODEC_USE_INPUT_FRAGMENTS 0x40000 -/*!\brief Enable frame-based multi-threading */ -#define VPX_CODEC_USE_FRAME_THREADING 0x80000 - -/*!\brief Stream properties - * - * This structure is used to query or set properties of the decoded - * stream. Algorithms may extend this structure with data specific - * to their bitstream by setting the sz member appropriately. - */ -typedef struct vpx_codec_stream_info { - unsigned int sz; /**< Size of this structure */ - unsigned int w; /**< Width (or 0 for unknown/default) */ - unsigned int h; /**< Height (or 0 for unknown/default) */ - unsigned int is_kf; /**< Current frame is a keyframe */ -} vpx_codec_stream_info_t; - -/* REQUIRED FUNCTIONS - * - * The following functions are required to be implemented for all decoders. - * They represent the base case functionality expected of all decoders. - */ - -/*!\brief Initialization Configurations - * - * This structure is used to pass init time configuration options to the - * decoder. - */ -typedef struct vpx_codec_dec_cfg { - unsigned int threads; /**< Maximum number of threads to use, default 1 */ - unsigned int w; /**< Width */ - unsigned int h; /**< Height */ -} vpx_codec_dec_cfg_t; /**< alias for struct vpx_codec_dec_cfg */ - -/*!\brief Initialize a decoder instance - * - * Initializes a decoder context using the given interface. Applications - * should call the vpx_codec_dec_init convenience macro instead of this - * function directly, to ensure that the ABI version number parameter - * is properly initialized. - * - * If the library was configured with --disable-multithread, this call - * is not thread safe and should be guarded with a lock if being used - * in a multithreaded context. - * - * \param[in] ctx Pointer to this instance's context. - * \param[in] iface Pointer to the algorithm interface to use. - * \param[in] cfg Configuration to use, if known. May be NULL. - * \param[in] flags Bitfield of VPX_CODEC_USE_* flags - * \param[in] ver ABI version number. Must be set to - * VPX_DECODER_ABI_VERSION - * \retval #VPX_CODEC_OK - * The decoder algorithm initialized. - * \retval #VPX_CODEC_MEM_ERROR - * Memory allocation failed. - */ -vpx_codec_err_t vpx_codec_dec_init_ver(vpx_codec_ctx_t *ctx, - vpx_codec_iface_t *iface, - const vpx_codec_dec_cfg_t *cfg, - vpx_codec_flags_t flags, int ver); - -/*!\brief Convenience macro for vpx_codec_dec_init_ver() - * - * Ensures the ABI version parameter is properly set. - */ -#define vpx_codec_dec_init(ctx, iface, cfg, flags) \ - vpx_codec_dec_init_ver(ctx, iface, cfg, flags, VPX_DECODER_ABI_VERSION) - -/*!\brief Parse stream info from a buffer - * - * Performs high level parsing of the bitstream. Construction of a decoder - * context is not necessary. Can be used to determine if the bitstream is - * of the proper format, and to extract information from the stream. - * - * \param[in] iface Pointer to the algorithm interface - * \param[in] data Pointer to a block of data to parse - * \param[in] data_sz Size of the data buffer - * \param[in,out] si Pointer to stream info to update. The size member - * \ref MUST be properly initialized, but \ref MAY be - * clobbered by the algorithm. This parameter \ref MAY - * be NULL. - * - * \retval #VPX_CODEC_OK - * Bitstream is parsable and stream information updated - */ -vpx_codec_err_t vpx_codec_peek_stream_info(vpx_codec_iface_t *iface, - const uint8_t *data, - unsigned int data_sz, - vpx_codec_stream_info_t *si); - -/*!\brief Return information about the current stream. - * - * Returns information about the stream that has been parsed during decoding. - * - * \param[in] ctx Pointer to this instance's context - * \param[in,out] si Pointer to stream info to update. The size member - * \ref MUST be properly initialized, but \ref MAY be - * clobbered by the algorithm. This parameter \ref MAY - * be NULL. - * - * \retval #VPX_CODEC_OK - * Bitstream is parsable and stream information updated - */ -vpx_codec_err_t vpx_codec_get_stream_info(vpx_codec_ctx_t *ctx, - vpx_codec_stream_info_t *si); - -/*!\brief Decode data - * - * Processes a buffer of coded data. If the processing results in a new - * decoded frame becoming available, PUT_SLICE and PUT_FRAME events may be - * generated, as appropriate. Encoded data \ref MUST be passed in DTS (decode - * time stamp) order. Frames produced will always be in PTS (presentation - * time stamp) order. - * If the decoder is configured with VPX_CODEC_USE_INPUT_FRAGMENTS enabled, - * data and data_sz can contain a fragment of the encoded frame. Fragment - * \#n must contain at least partition \#n, but can also contain subsequent - * partitions (\#n+1 - \#n+i), and if so, fragments \#n+1, .., \#n+i must - * be empty. When no more data is available, this function should be called - * with NULL as data and 0 as data_sz. The memory passed to this function - * must be available until the frame has been decoded. - * - * \param[in] ctx Pointer to this instance's context - * \param[in] data Pointer to this block of new coded data. If - * NULL, a VPX_CODEC_CB_PUT_FRAME event is posted - * for the previously decoded frame. - * \param[in] data_sz Size of the coded data, in bytes. - * \param[in] user_priv Application specific data to associate with - * this frame. - * \param[in] deadline Soft deadline the decoder should attempt to meet, - * in us. Set to zero for unlimited. - * - * \return Returns #VPX_CODEC_OK if the coded data was processed completely - * and future pictures can be decoded without error. Otherwise, - * see the descriptions of the other error codes in ::vpx_codec_err_t - * for recoverability capabilities. - */ -vpx_codec_err_t vpx_codec_decode(vpx_codec_ctx_t *ctx, const uint8_t *data, - unsigned int data_sz, void *user_priv, - long deadline); - -/*!\brief Decoded frames iterator - * - * Iterates over a list of the frames available for display. The iterator - * storage should be initialized to NULL to start the iteration. Iteration is - * complete when this function returns NULL. - * - * The list of available frames becomes valid upon completion of the - * vpx_codec_decode call, and remains valid until the next call to - * vpx_codec_decode. - * - * \param[in] ctx Pointer to this instance's context - * \param[in,out] iter Iterator storage, initialized to NULL - * - * \return Returns a pointer to an image, if one is ready for display. Frames - * produced will always be in PTS (presentation time stamp) order. - */ -vpx_image_t *vpx_codec_get_frame(vpx_codec_ctx_t *ctx, vpx_codec_iter_t *iter); - -/*!\defgroup cap_put_frame Frame-Based Decoding Functions - * - * The following functions are required to be implemented for all decoders - * that advertise the VPX_CODEC_CAP_PUT_FRAME capability. Calling these - * functions - * for codecs that don't advertise this capability will result in an error - * code being returned, usually VPX_CODEC_ERROR - * @{ - */ - -/*!\brief put frame callback prototype - * - * This callback is invoked by the decoder to notify the application of - * the availability of decoded image data. - */ -typedef void (*vpx_codec_put_frame_cb_fn_t)(void *user_priv, - const vpx_image_t *img); - -/*!\brief Register for notification of frame completion. - * - * Registers a given function to be called when a decoded frame is - * available. - * - * \param[in] ctx Pointer to this instance's context - * \param[in] cb Pointer to the callback function - * \param[in] user_priv User's private data - * - * \retval #VPX_CODEC_OK - * Callback successfully registered. - * \retval #VPX_CODEC_ERROR - * Decoder context not initialized, or algorithm not capable of - * posting slice completion. - */ -vpx_codec_err_t vpx_codec_register_put_frame_cb(vpx_codec_ctx_t *ctx, - vpx_codec_put_frame_cb_fn_t cb, - void *user_priv); - -/*!@} - end defgroup cap_put_frame */ - -/*!\defgroup cap_put_slice Slice-Based Decoding Functions - * - * The following functions are required to be implemented for all decoders - * that advertise the VPX_CODEC_CAP_PUT_SLICE capability. Calling these - * functions - * for codecs that don't advertise this capability will result in an error - * code being returned, usually VPX_CODEC_ERROR - * @{ - */ - -/*!\brief put slice callback prototype - * - * This callback is invoked by the decoder to notify the application of - * the availability of partially decoded image data. The - */ -typedef void (*vpx_codec_put_slice_cb_fn_t)(void *user_priv, - const vpx_image_t *img, - const vpx_image_rect_t *valid, - const vpx_image_rect_t *update); - -/*!\brief Register for notification of slice completion. - * - * Registers a given function to be called when a decoded slice is - * available. - * - * \param[in] ctx Pointer to this instance's context - * \param[in] cb Pointer to the callback function - * \param[in] user_priv User's private data - * - * \retval #VPX_CODEC_OK - * Callback successfully registered. - * \retval #VPX_CODEC_ERROR - * Decoder context not initialized, or algorithm not capable of - * posting slice completion. - */ -vpx_codec_err_t vpx_codec_register_put_slice_cb(vpx_codec_ctx_t *ctx, - vpx_codec_put_slice_cb_fn_t cb, - void *user_priv); - -/*!@} - end defgroup cap_put_slice*/ - -/*!\defgroup cap_external_frame_buffer External Frame Buffer Functions - * - * The following section is required to be implemented for all decoders - * that advertise the VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER capability. - * Calling this function for codecs that don't advertise this capability - * will result in an error code being returned, usually VPX_CODEC_ERROR. - * - * \note - * Currently this only works with VP9. - * @{ - */ - -/*!\brief Pass in external frame buffers for the decoder to use. - * - * Registers functions to be called when libvpx needs a frame buffer - * to decode the current frame and a function to be called when libvpx does - * not internally reference the frame buffer. This set function must - * be called before the first call to decode or libvpx will assume the - * default behavior of allocating frame buffers internally. - * - * \param[in] ctx Pointer to this instance's context - * \param[in] cb_get Pointer to the get callback function - * \param[in] cb_release Pointer to the release callback function - * \param[in] cb_priv Callback's private data - * - * \retval #VPX_CODEC_OK - * External frame buffers will be used by libvpx. - * \retval #VPX_CODEC_INVALID_PARAM - * One or more of the callbacks were NULL. - * \retval #VPX_CODEC_ERROR - * Decoder context not initialized, or algorithm not capable of - * using external frame buffers. - * - * \note - * When decoding VP9, the application may be required to pass in at least - * #VP9_MAXIMUM_REF_BUFFERS + #VPX_MAXIMUM_WORK_BUFFERS external frame - * buffers. - */ -vpx_codec_err_t vpx_codec_set_frame_buffer_functions( - vpx_codec_ctx_t *ctx, vpx_get_frame_buffer_cb_fn_t cb_get, - vpx_release_frame_buffer_cb_fn_t cb_release, void *cb_priv); - -/*!@} - end defgroup cap_external_frame_buffer */ - -/*!@} - end defgroup decoder*/ -#ifdef __cplusplus -} -#endif -#endif // VPX_VPX_DECODER_H_ diff --git a/protocols/Tox/include/vpx/vpx_encoder.h b/protocols/Tox/include/vpx/vpx_encoder.h deleted file mode 100644 index 28fcd5f999..0000000000 --- a/protocols/Tox/include/vpx/vpx_encoder.h +++ /dev/null @@ -1,980 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ -#ifndef VPX_VPX_ENCODER_H_ -#define VPX_VPX_ENCODER_H_ - -/*!\defgroup encoder Encoder Algorithm Interface - * \ingroup codec - * This abstraction allows applications using this encoder to easily support - * multiple video formats with minimal code duplication. This section describes - * the interface common to all encoders. - * @{ - */ - -/*!\file - * \brief Describes the encoder algorithm interface to applications. - * - * This file describes the interface between an application and a - * video encoder algorithm. - * - */ -#ifdef __cplusplus -extern "C" { -#endif - -#include "./vpx_codec.h" - -/*! Temporal Scalability: Maximum length of the sequence defining frame - * layer membership - */ -#define VPX_TS_MAX_PERIODICITY 16 - -/*! Temporal Scalability: Maximum number of coding layers */ -#define VPX_TS_MAX_LAYERS 5 - -/*!\deprecated Use #VPX_TS_MAX_PERIODICITY instead. */ -#define MAX_PERIODICITY VPX_TS_MAX_PERIODICITY - -/*! Temporal+Spatial Scalability: Maximum number of coding layers */ -#define VPX_MAX_LAYERS 12 // 3 temporal + 4 spatial layers are allowed. - -/*!\deprecated Use #VPX_MAX_LAYERS instead. */ -#define MAX_LAYERS VPX_MAX_LAYERS // 3 temporal + 4 spatial layers allowed. - -/*! Spatial Scalability: Maximum number of coding layers */ -#define VPX_SS_MAX_LAYERS 5 - -/*! Spatial Scalability: Default number of coding layers */ -#define VPX_SS_DEFAULT_LAYERS 1 - -/*!\brief Current ABI version number - * - * \internal - * If this file is altered in any way that changes the ABI, this value - * must be bumped. Examples include, but are not limited to, changing - * types, removing or reassigning enums, adding/removing/rearranging - * fields to structures - */ -#define VPX_ENCODER_ABI_VERSION \ - (5 + VPX_CODEC_ABI_VERSION) /**<\hideinitializer*/ - -/*! \brief Encoder capabilities bitfield - * - * Each encoder advertises the capabilities it supports as part of its - * ::vpx_codec_iface_t interface structure. Capabilities are extra - * interfaces or functionality, and are not required to be supported - * by an encoder. - * - * The available flags are specified by VPX_CODEC_CAP_* defines. - */ -#define VPX_CODEC_CAP_PSNR 0x10000 /**< Can issue PSNR packets */ - -/*! Can output one partition at a time. Each partition is returned in its - * own VPX_CODEC_CX_FRAME_PKT, with the FRAME_IS_FRAGMENT flag set for - * every partition but the last. In this mode all frames are always - * returned partition by partition. - */ -#define VPX_CODEC_CAP_OUTPUT_PARTITION 0x20000 - -/*! Can support input images at greater than 8 bitdepth. - */ -#define VPX_CODEC_CAP_HIGHBITDEPTH 0x40000 - -/*! \brief Initialization-time Feature Enabling - * - * Certain codec features must be known at initialization time, to allow - * for proper memory allocation. - * - * The available flags are specified by VPX_CODEC_USE_* defines. - */ -#define VPX_CODEC_USE_PSNR 0x10000 /**< Calculate PSNR on each frame */ -/*!\brief Make the encoder output one partition at a time. */ -#define VPX_CODEC_USE_OUTPUT_PARTITION 0x20000 -#define VPX_CODEC_USE_HIGHBITDEPTH 0x40000 /**< Use high bitdepth */ - -/*!\brief Generic fixed size buffer structure - * - * This structure is able to hold a reference to any fixed size buffer. - */ -typedef struct vpx_fixed_buf { - void *buf; /**< Pointer to the data */ - size_t sz; /**< Length of the buffer, in chars */ -} vpx_fixed_buf_t; /**< alias for struct vpx_fixed_buf */ - -/*!\brief Time Stamp Type - * - * An integer, which when multiplied by the stream's time base, provides - * the absolute time of a sample. - */ -typedef int64_t vpx_codec_pts_t; - -/*!\brief Compressed Frame Flags - * - * This type represents a bitfield containing information about a compressed - * frame that may be useful to an application. The most significant 16 bits - * can be used by an algorithm to provide additional detail, for example to - * support frame types that are codec specific (MPEG-1 D-frames for example) - */ -typedef uint32_t vpx_codec_frame_flags_t; -#define VPX_FRAME_IS_KEY 0x1 /**< frame is the start of a GOP */ -/*!\brief frame can be dropped without affecting the stream (no future frame - * depends on this one) */ -#define VPX_FRAME_IS_DROPPABLE 0x2 -/*!\brief frame should be decoded but will not be shown */ -#define VPX_FRAME_IS_INVISIBLE 0x4 -/*!\brief this is a fragment of the encoded frame */ -#define VPX_FRAME_IS_FRAGMENT 0x8 - -/*!\brief Error Resilient flags - * - * These flags define which error resilient features to enable in the - * encoder. The flags are specified through the - * vpx_codec_enc_cfg::g_error_resilient variable. - */ -typedef uint32_t vpx_codec_er_flags_t; -/*!\brief Improve resiliency against losses of whole frames */ -#define VPX_ERROR_RESILIENT_DEFAULT 0x1 -/*!\brief The frame partitions are independently decodable by the bool decoder, - * meaning that partitions can be decoded even though earlier partitions have - * been lost. Note that intra prediction is still done over the partition - * boundary. */ -#define VPX_ERROR_RESILIENT_PARTITIONS 0x2 - -/*!\brief Encoder output packet variants - * - * This enumeration lists the different kinds of data packets that can be - * returned by calls to vpx_codec_get_cx_data(). Algorithms \ref MAY - * extend this list to provide additional functionality. - */ -enum vpx_codec_cx_pkt_kind { - VPX_CODEC_CX_FRAME_PKT, /**< Compressed video frame */ - VPX_CODEC_STATS_PKT, /**< Two-pass statistics for this frame */ - VPX_CODEC_FPMB_STATS_PKT, /**< first pass mb statistics for this frame */ - VPX_CODEC_PSNR_PKT, /**< PSNR statistics for this frame */ -// Spatial SVC is still experimental and may be removed before the next ABI -// bump. -#if VPX_ENCODER_ABI_VERSION > (5 + VPX_CODEC_ABI_VERSION) - VPX_CODEC_SPATIAL_SVC_LAYER_SIZES, /**< Sizes for each layer in this frame*/ - VPX_CODEC_SPATIAL_SVC_LAYER_PSNR, /**< PSNR for each layer in this frame*/ -#endif - VPX_CODEC_CUSTOM_PKT = 256 /**< Algorithm extensions */ -}; - -/*!\brief Encoder output packet - * - * This structure contains the different kinds of output data the encoder - * may produce while compressing a frame. - */ -typedef struct vpx_codec_cx_pkt { - enum vpx_codec_cx_pkt_kind kind; /**< packet variant */ - union { - struct { - void *buf; /**< compressed data buffer */ - size_t sz; /**< length of compressed data */ - /*!\brief time stamp to show frame (in timebase units) */ - vpx_codec_pts_t pts; - /*!\brief duration to show frame (in timebase units) */ - unsigned long duration; - vpx_codec_frame_flags_t flags; /**< flags for this frame */ - /*!\brief the partition id defines the decoding order of the partitions. - * Only applicable when "output partition" mode is enabled. First - * partition has id 0.*/ - int partition_id; - } frame; /**< data for compressed frame packet */ - vpx_fixed_buf_t twopass_stats; /**< data for two-pass packet */ - vpx_fixed_buf_t firstpass_mb_stats; /**< first pass mb packet */ - struct vpx_psnr_pkt { - unsigned int samples[4]; /**< Number of samples, total/y/u/v */ - uint64_t sse[4]; /**< sum squared error, total/y/u/v */ - double psnr[4]; /**< PSNR, total/y/u/v */ - } psnr; /**< data for PSNR packet */ - vpx_fixed_buf_t raw; /**< data for arbitrary packets */ -// Spatial SVC is still experimental and may be removed before the next -// ABI bump. -#if VPX_ENCODER_ABI_VERSION > (5 + VPX_CODEC_ABI_VERSION) - size_t layer_sizes[VPX_SS_MAX_LAYERS]; - struct vpx_psnr_pkt layer_psnr[VPX_SS_MAX_LAYERS]; -#endif - - /* This packet size is fixed to allow codecs to extend this - * interface without having to manage storage for raw packets, - * i.e., if it's smaller than 128 bytes, you can store in the - * packet list directly. - */ - char pad[128 - sizeof(enum vpx_codec_cx_pkt_kind)]; /**< fixed sz */ - } data; /**< packet data */ -} vpx_codec_cx_pkt_t; /**< alias for struct vpx_codec_cx_pkt */ - -/*!\brief Encoder return output buffer callback - * - * This callback function, when registered, returns with packets when each - * spatial layer is encoded. - */ -// putting the definitions here for now. (agrange: find if there -// is a better place for this) -typedef void (*vpx_codec_enc_output_cx_pkt_cb_fn_t)(vpx_codec_cx_pkt_t *pkt, - void *user_data); - -/*!\brief Callback function pointer / user data pair storage */ -typedef struct vpx_codec_enc_output_cx_cb_pair { - vpx_codec_enc_output_cx_pkt_cb_fn_t output_cx_pkt; /**< Callback function */ - void *user_priv; /**< Pointer to private data */ -} vpx_codec_priv_output_cx_pkt_cb_pair_t; - -/*!\brief Rational Number - * - * This structure holds a fractional value. - */ -typedef struct vpx_rational { - int num; /**< fraction numerator */ - int den; /**< fraction denominator */ -} vpx_rational_t; /**< alias for struct vpx_rational */ - -/*!\brief Multi-pass Encoding Pass */ -enum vpx_enc_pass { - VPX_RC_ONE_PASS, /**< Single pass mode */ - VPX_RC_FIRST_PASS, /**< First pass of multi-pass mode */ - VPX_RC_LAST_PASS /**< Final pass of multi-pass mode */ -}; - -/*!\brief Rate control mode */ -enum vpx_rc_mode { - VPX_VBR, /**< Variable Bit Rate (VBR) mode */ - VPX_CBR, /**< Constant Bit Rate (CBR) mode */ - VPX_CQ, /**< Constrained Quality (CQ) mode */ - VPX_Q, /**< Constant Quality (Q) mode */ -}; - -/*!\brief Keyframe placement mode. - * - * This enumeration determines whether keyframes are placed automatically by - * the encoder or whether this behavior is disabled. Older releases of this - * SDK were implemented such that VPX_KF_FIXED meant keyframes were disabled. - * This name is confusing for this behavior, so the new symbols to be used - * are VPX_KF_AUTO and VPX_KF_DISABLED. - */ -enum vpx_kf_mode { - VPX_KF_FIXED, /**< deprecated, implies VPX_KF_DISABLED */ - VPX_KF_AUTO, /**< Encoder determines optimal placement automatically */ - VPX_KF_DISABLED = 0 /**< Encoder does not place keyframes. */ -}; - -/*!\brief Encoded Frame Flags - * - * This type indicates a bitfield to be passed to vpx_codec_encode(), defining - * per-frame boolean values. By convention, bits common to all codecs will be - * named VPX_EFLAG_*, and bits specific to an algorithm will be named - * /algo/_eflag_*. The lower order 16 bits are reserved for common use. - */ -typedef long vpx_enc_frame_flags_t; -#define VPX_EFLAG_FORCE_KF (1 << 0) /**< Force this frame to be a keyframe */ - -/*!\brief Encoder configuration structure - * - * This structure contains the encoder settings that have common representations - * across all codecs. This doesn't imply that all codecs support all features, - * however. - */ -typedef struct vpx_codec_enc_cfg { - /* - * generic settings (g) - */ - - /*!\brief Algorithm specific "usage" value - * - * Algorithms may define multiple values for usage, which may convey the - * intent of how the application intends to use the stream. If this value - * is non-zero, consult the documentation for the codec to determine its - * meaning. - */ - unsigned int g_usage; - - /*!\brief Maximum number of threads to use - * - * For multi-threaded implementations, use no more than this number of - * threads. The codec may use fewer threads than allowed. The value - * 0 is equivalent to the value 1. - */ - unsigned int g_threads; - - /*!\brief Bitstream profile to use - * - * Some codecs support a notion of multiple bitstream profiles. Typically - * this maps to a set of features that are turned on or off. Often the - * profile to use is determined by the features of the intended decoder. - * Consult the documentation for the codec to determine the valid values - * for this parameter, or set to zero for a sane default. - */ - unsigned int g_profile; /**< profile of bitstream to use */ - - /*!\brief Width of the frame - * - * This value identifies the presentation resolution of the frame, - * in pixels. Note that the frames passed as input to the encoder must - * have this resolution. Frames will be presented by the decoder in this - * resolution, independent of any spatial resampling the encoder may do. - */ - unsigned int g_w; - - /*!\brief Height of the frame - * - * This value identifies the presentation resolution of the frame, - * in pixels. Note that the frames passed as input to the encoder must - * have this resolution. Frames will be presented by the decoder in this - * resolution, independent of any spatial resampling the encoder may do. - */ - unsigned int g_h; - - /*!\brief Bit-depth of the codec - * - * This value identifies the bit_depth of the codec, - * Only certain bit-depths are supported as identified in the - * vpx_bit_depth_t enum. - */ - vpx_bit_depth_t g_bit_depth; - - /*!\brief Bit-depth of the input frames - * - * This value identifies the bit_depth of the input frames in bits. - * Note that the frames passed as input to the encoder must have - * this bit-depth. - */ - unsigned int g_input_bit_depth; - - /*!\brief Stream timebase units - * - * Indicates the smallest interval of time, in seconds, used by the stream. - * For fixed frame rate material, or variable frame rate material where - * frames are timed at a multiple of a given clock (ex: video capture), - * the \ref RECOMMENDED method is to set the timebase to the reciprocal - * of the frame rate (ex: 1001/30000 for 29.970 Hz NTSC). This allows the - * pts to correspond to the frame number, which can be handy. For - * re-encoding video from containers with absolute time timestamps, the - * \ref RECOMMENDED method is to set the timebase to that of the parent - * container or multimedia framework (ex: 1/1000 for ms, as in FLV). - */ - struct vpx_rational g_timebase; - - /*!\brief Enable error resilient modes. - * - * The error resilient bitfield indicates to the encoder which features - * it should enable to take measures for streaming over lossy or noisy - * links. - */ - vpx_codec_er_flags_t g_error_resilient; - - /*!\brief Multi-pass Encoding Mode - * - * This value should be set to the current phase for multi-pass encoding. - * For single pass, set to #VPX_RC_ONE_PASS. - */ - enum vpx_enc_pass g_pass; - - /*!\brief Allow lagged encoding - * - * If set, this value allows the encoder to consume a number of input - * frames before producing output frames. This allows the encoder to - * base decisions for the current frame on future frames. This does - * increase the latency of the encoding pipeline, so it is not appropriate - * in all situations (ex: realtime encoding). - * - * Note that this is a maximum value -- the encoder may produce frames - * sooner than the given limit. Set this value to 0 to disable this - * feature. - */ - unsigned int g_lag_in_frames; - - /* - * rate control settings (rc) - */ - - /*!\brief Temporal resampling configuration, if supported by the codec. - * - * Temporal resampling allows the codec to "drop" frames as a strategy to - * meet its target data rate. This can cause temporal discontinuities in - * the encoded video, which may appear as stuttering during playback. This - * trade-off is often acceptable, but for many applications is not. It can - * be disabled in these cases. - * - * Note that not all codecs support this feature. All vpx VPx codecs do. - * For other codecs, consult the documentation for that algorithm. - * - * This threshold is described as a percentage of the target data buffer. - * When the data buffer falls below this percentage of fullness, a - * dropped frame is indicated. Set the threshold to zero (0) to disable - * this feature. - */ - unsigned int rc_dropframe_thresh; - - /*!\brief Enable/disable spatial resampling, if supported by the codec. - * - * Spatial resampling allows the codec to compress a lower resolution - * version of the frame, which is then upscaled by the encoder to the - * correct presentation resolution. This increases visual quality at - * low data rates, at the expense of CPU time on the encoder/decoder. - */ - unsigned int rc_resize_allowed; - - /*!\brief Internal coded frame width. - * - * If spatial resampling is enabled this specifies the width of the - * encoded frame. - */ - unsigned int rc_scaled_width; - - /*!\brief Internal coded frame height. - * - * If spatial resampling is enabled this specifies the height of the - * encoded frame. - */ - unsigned int rc_scaled_height; - - /*!\brief Spatial resampling up watermark. - * - * This threshold is described as a percentage of the target data buffer. - * When the data buffer rises above this percentage of fullness, the - * encoder will step up to a higher resolution version of the frame. - */ - unsigned int rc_resize_up_thresh; - - /*!\brief Spatial resampling down watermark. - * - * This threshold is described as a percentage of the target data buffer. - * When the data buffer falls below this percentage of fullness, the - * encoder will step down to a lower resolution version of the frame. - */ - unsigned int rc_resize_down_thresh; - - /*!\brief Rate control algorithm to use. - * - * Indicates whether the end usage of this stream is to be streamed over - * a bandwidth constrained link, indicating that Constant Bit Rate (CBR) - * mode should be used, or whether it will be played back on a high - * bandwidth link, as from a local disk, where higher variations in - * bitrate are acceptable. - */ - enum vpx_rc_mode rc_end_usage; - - /*!\brief Two-pass stats buffer. - * - * A buffer containing all of the stats packets produced in the first - * pass, concatenated. - */ - vpx_fixed_buf_t rc_twopass_stats_in; - - /*!\brief first pass mb stats buffer. - * - * A buffer containing all of the first pass mb stats packets produced - * in the first pass, concatenated. - */ - vpx_fixed_buf_t rc_firstpass_mb_stats_in; - - /*!\brief Target data rate - * - * Target bandwidth to use for this stream, in kilobits per second. - */ - unsigned int rc_target_bitrate; - - /* - * quantizer settings - */ - - /*!\brief Minimum (Best Quality) Quantizer - * - * The quantizer is the most direct control over the quality of the - * encoded image. The range of valid values for the quantizer is codec - * specific. Consult the documentation for the codec to determine the - * values to use. To determine the range programmatically, call - * vpx_codec_enc_config_default() with a usage value of 0. - */ - unsigned int rc_min_quantizer; - - /*!\brief Maximum (Worst Quality) Quantizer - * - * The quantizer is the most direct control over the quality of the - * encoded image. The range of valid values for the quantizer is codec - * specific. Consult the documentation for the codec to determine the - * values to use. To determine the range programmatically, call - * vpx_codec_enc_config_default() with a usage value of 0. - */ - unsigned int rc_max_quantizer; - - /* - * bitrate tolerance - */ - - /*!\brief Rate control adaptation undershoot control - * - * This value, expressed as a percentage of the target bitrate, - * controls the maximum allowed adaptation speed of the codec. - * This factor controls the maximum amount of bits that can - * be subtracted from the target bitrate in order to compensate - * for prior overshoot. - * - * Valid values in the range 0-1000. - */ - unsigned int rc_undershoot_pct; - - /*!\brief Rate control adaptation overshoot control - * - * This value, expressed as a percentage of the target bitrate, - * controls the maximum allowed adaptation speed of the codec. - * This factor controls the maximum amount of bits that can - * be added to the target bitrate in order to compensate for - * prior undershoot. - * - * Valid values in the range 0-1000. - */ - unsigned int rc_overshoot_pct; - - /* - * decoder buffer model parameters - */ - - /*!\brief Decoder Buffer Size - * - * This value indicates the amount of data that may be buffered by the - * decoding application. Note that this value is expressed in units of - * time (milliseconds). For example, a value of 5000 indicates that the - * client will buffer (at least) 5000ms worth of encoded data. Use the - * target bitrate (#rc_target_bitrate) to convert to bits/bytes, if - * necessary. - */ - unsigned int rc_buf_sz; - - /*!\brief Decoder Buffer Initial Size - * - * This value indicates the amount of data that will be buffered by the - * decoding application prior to beginning playback. This value is - * expressed in units of time (milliseconds). Use the target bitrate - * (#rc_target_bitrate) to convert to bits/bytes, if necessary. - */ - unsigned int rc_buf_initial_sz; - - /*!\brief Decoder Buffer Optimal Size - * - * This value indicates the amount of data that the encoder should try - * to maintain in the decoder's buffer. This value is expressed in units - * of time (milliseconds). Use the target bitrate (#rc_target_bitrate) - * to convert to bits/bytes, if necessary. - */ - unsigned int rc_buf_optimal_sz; - - /* - * 2 pass rate control parameters - */ - - /*!\brief Two-pass mode CBR/VBR bias - * - * Bias, expressed on a scale of 0 to 100, for determining target size - * for the current frame. The value 0 indicates the optimal CBR mode - * value should be used. The value 100 indicates the optimal VBR mode - * value should be used. Values in between indicate which way the - * encoder should "lean." - */ - unsigned int rc_2pass_vbr_bias_pct; - - /*!\brief Two-pass mode per-GOP minimum bitrate - * - * This value, expressed as a percentage of the target bitrate, indicates - * the minimum bitrate to be used for a single GOP (aka "section") - */ - unsigned int rc_2pass_vbr_minsection_pct; - - /*!\brief Two-pass mode per-GOP maximum bitrate - * - * This value, expressed as a percentage of the target bitrate, indicates - * the maximum bitrate to be used for a single GOP (aka "section") - */ - unsigned int rc_2pass_vbr_maxsection_pct; - - /* - * keyframing settings (kf) - */ - - /*!\brief Keyframe placement mode - * - * This value indicates whether the encoder should place keyframes at a - * fixed interval, or determine the optimal placement automatically - * (as governed by the #kf_min_dist and #kf_max_dist parameters) - */ - enum vpx_kf_mode kf_mode; - - /*!\brief Keyframe minimum interval - * - * This value, expressed as a number of frames, prevents the encoder from - * placing a keyframe nearer than kf_min_dist to the previous keyframe. At - * least kf_min_dist frames non-keyframes will be coded before the next - * keyframe. Set kf_min_dist equal to kf_max_dist for a fixed interval. - */ - unsigned int kf_min_dist; - - /*!\brief Keyframe maximum interval - * - * This value, expressed as a number of frames, forces the encoder to code - * a keyframe if one has not been coded in the last kf_max_dist frames. - * A value of 0 implies all frames will be keyframes. Set kf_min_dist - * equal to kf_max_dist for a fixed interval. - */ - unsigned int kf_max_dist; - - /* - * Spatial scalability settings (ss) - */ - - /*!\brief Number of spatial coding layers. - * - * This value specifies the number of spatial coding layers to be used. - */ - unsigned int ss_number_layers; - - /*!\brief Enable auto alt reference flags for each spatial layer. - * - * These values specify if auto alt reference frame is enabled for each - * spatial layer. - */ - int ss_enable_auto_alt_ref[VPX_SS_MAX_LAYERS]; - - /*!\brief Target bitrate for each spatial layer. - * - * These values specify the target coding bitrate to be used for each - * spatial layer. - */ - unsigned int ss_target_bitrate[VPX_SS_MAX_LAYERS]; - - /*!\brief Number of temporal coding layers. - * - * This value specifies the number of temporal layers to be used. - */ - unsigned int ts_number_layers; - - /*!\brief Target bitrate for each temporal layer. - * - * These values specify the target coding bitrate to be used for each - * temporal layer. - */ - unsigned int ts_target_bitrate[VPX_TS_MAX_LAYERS]; - - /*!\brief Frame rate decimation factor for each temporal layer. - * - * These values specify the frame rate decimation factors to apply - * to each temporal layer. - */ - unsigned int ts_rate_decimator[VPX_TS_MAX_LAYERS]; - - /*!\brief Length of the sequence defining frame temporal layer membership. - * - * This value specifies the length of the sequence that defines the - * membership of frames to temporal layers. For example, if the - * ts_periodicity = 8, then the frames are assigned to coding layers with a - * repeated sequence of length 8. - */ - unsigned int ts_periodicity; - - /*!\brief Template defining the membership of frames to temporal layers. - * - * This array defines the membership of frames to temporal coding layers. - * For a 2-layer encoding that assigns even numbered frames to one temporal - * layer (0) and odd numbered frames to a second temporal layer (1) with - * ts_periodicity=8, then ts_layer_id = (0,1,0,1,0,1,0,1). - */ - unsigned int ts_layer_id[VPX_TS_MAX_PERIODICITY]; - - /*!\brief Target bitrate for each spatial/temporal layer. - * - * These values specify the target coding bitrate to be used for each - * spatial/temporal layer. - * - */ - unsigned int layer_target_bitrate[VPX_MAX_LAYERS]; - - /*!\brief Temporal layering mode indicating which temporal layering scheme to - * use. - * - * The value (refer to VP9E_TEMPORAL_LAYERING_MODE) specifies the - * temporal layering mode to use. - * - */ - int temporal_layering_mode; -} vpx_codec_enc_cfg_t; /**< alias for struct vpx_codec_enc_cfg */ - -/*!\brief vp9 svc extra configure parameters - * - * This defines max/min quantizers and scale factors for each layer - * - */ -typedef struct vpx_svc_parameters { - int max_quantizers[VPX_MAX_LAYERS]; /**< Max Q for each layer */ - int min_quantizers[VPX_MAX_LAYERS]; /**< Min Q for each layer */ - int scaling_factor_num[VPX_MAX_LAYERS]; /**< Scaling factor-numerator */ - int scaling_factor_den[VPX_MAX_LAYERS]; /**< Scaling factor-denominator */ - int speed_per_layer[VPX_MAX_LAYERS]; /**< Speed setting for each sl */ - int temporal_layering_mode; /**< Temporal layering mode */ -} vpx_svc_extra_cfg_t; - -/*!\brief Initialize an encoder instance - * - * Initializes a encoder context using the given interface. Applications - * should call the vpx_codec_enc_init convenience macro instead of this - * function directly, to ensure that the ABI version number parameter - * is properly initialized. - * - * If the library was configured with --disable-multithread, this call - * is not thread safe and should be guarded with a lock if being used - * in a multithreaded context. - * - * \param[in] ctx Pointer to this instance's context. - * \param[in] iface Pointer to the algorithm interface to use. - * \param[in] cfg Configuration to use, if known. May be NULL. - * \param[in] flags Bitfield of VPX_CODEC_USE_* flags - * \param[in] ver ABI version number. Must be set to - * VPX_ENCODER_ABI_VERSION - * \retval #VPX_CODEC_OK - * The decoder algorithm initialized. - * \retval #VPX_CODEC_MEM_ERROR - * Memory allocation failed. - */ -vpx_codec_err_t vpx_codec_enc_init_ver(vpx_codec_ctx_t *ctx, - vpx_codec_iface_t *iface, - const vpx_codec_enc_cfg_t *cfg, - vpx_codec_flags_t flags, int ver); - -/*!\brief Convenience macro for vpx_codec_enc_init_ver() - * - * Ensures the ABI version parameter is properly set. - */ -#define vpx_codec_enc_init(ctx, iface, cfg, flags) \ - vpx_codec_enc_init_ver(ctx, iface, cfg, flags, VPX_ENCODER_ABI_VERSION) - -/*!\brief Initialize multi-encoder instance - * - * Initializes multi-encoder context using the given interface. - * Applications should call the vpx_codec_enc_init_multi convenience macro - * instead of this function directly, to ensure that the ABI version number - * parameter is properly initialized. - * - * \param[in] ctx Pointer to this instance's context. - * \param[in] iface Pointer to the algorithm interface to use. - * \param[in] cfg Configuration to use, if known. May be NULL. - * \param[in] num_enc Total number of encoders. - * \param[in] flags Bitfield of VPX_CODEC_USE_* flags - * \param[in] dsf Pointer to down-sampling factors. - * \param[in] ver ABI version number. Must be set to - * VPX_ENCODER_ABI_VERSION - * \retval #VPX_CODEC_OK - * The decoder algorithm initialized. - * \retval #VPX_CODEC_MEM_ERROR - * Memory allocation failed. - */ -vpx_codec_err_t vpx_codec_enc_init_multi_ver( - vpx_codec_ctx_t *ctx, vpx_codec_iface_t *iface, vpx_codec_enc_cfg_t *cfg, - int num_enc, vpx_codec_flags_t flags, vpx_rational_t *dsf, int ver); - -/*!\brief Convenience macro for vpx_codec_enc_init_multi_ver() - * - * Ensures the ABI version parameter is properly set. - */ -#define vpx_codec_enc_init_multi(ctx, iface, cfg, num_enc, flags, dsf) \ - vpx_codec_enc_init_multi_ver(ctx, iface, cfg, num_enc, flags, dsf, \ - VPX_ENCODER_ABI_VERSION) - -/*!\brief Get a default configuration - * - * Initializes a encoder configuration structure with default values. Supports - * the notion of "usages" so that an algorithm may offer different default - * settings depending on the user's intended goal. This function \ref SHOULD - * be called by all applications to initialize the configuration structure - * before specializing the configuration with application specific values. - * - * \param[in] iface Pointer to the algorithm interface to use. - * \param[out] cfg Configuration buffer to populate. - * \param[in] reserved Must set to 0 for VP8 and VP9. - * - * \retval #VPX_CODEC_OK - * The configuration was populated. - * \retval #VPX_CODEC_INCAPABLE - * Interface is not an encoder interface. - * \retval #VPX_CODEC_INVALID_PARAM - * A parameter was NULL, or the usage value was not recognized. - */ -vpx_codec_err_t vpx_codec_enc_config_default(vpx_codec_iface_t *iface, - vpx_codec_enc_cfg_t *cfg, - unsigned int reserved); - -/*!\brief Set or change configuration - * - * Reconfigures an encoder instance according to the given configuration. - * - * \param[in] ctx Pointer to this instance's context - * \param[in] cfg Configuration buffer to use - * - * \retval #VPX_CODEC_OK - * The configuration was populated. - * \retval #VPX_CODEC_INCAPABLE - * Interface is not an encoder interface. - * \retval #VPX_CODEC_INVALID_PARAM - * A parameter was NULL, or the usage value was not recognized. - */ -vpx_codec_err_t vpx_codec_enc_config_set(vpx_codec_ctx_t *ctx, - const vpx_codec_enc_cfg_t *cfg); - -/*!\brief Get global stream headers - * - * Retrieves a stream level global header packet, if supported by the codec. - * - * \param[in] ctx Pointer to this instance's context - * - * \retval NULL - * Encoder does not support global header - * \retval Non-NULL - * Pointer to buffer containing global header packet - */ -vpx_fixed_buf_t *vpx_codec_get_global_headers(vpx_codec_ctx_t *ctx); - -/*!\brief deadline parameter analogous to VPx REALTIME mode. */ -#define VPX_DL_REALTIME (1) -/*!\brief deadline parameter analogous to VPx GOOD QUALITY mode. */ -#define VPX_DL_GOOD_QUALITY (1000000) -/*!\brief deadline parameter analogous to VPx BEST QUALITY mode. */ -#define VPX_DL_BEST_QUALITY (0) -/*!\brief Encode a frame - * - * Encodes a video frame at the given "presentation time." The presentation - * time stamp (PTS) \ref MUST be strictly increasing. - * - * The encoder supports the notion of a soft real-time deadline. Given a - * non-zero value to the deadline parameter, the encoder will make a "best - * effort" guarantee to return before the given time slice expires. It is - * implicit that limiting the available time to encode will degrade the - * output quality. The encoder can be given an unlimited time to produce the - * best possible frame by specifying a deadline of '0'. This deadline - * supercedes the VPx notion of "best quality, good quality, realtime". - * Applications that wish to map these former settings to the new deadline - * based system can use the symbols #VPX_DL_REALTIME, #VPX_DL_GOOD_QUALITY, - * and #VPX_DL_BEST_QUALITY. - * - * When the last frame has been passed to the encoder, this function should - * continue to be called, with the img parameter set to NULL. This will - * signal the end-of-stream condition to the encoder and allow it to encode - * any held buffers. Encoding is complete when vpx_codec_encode() is called - * and vpx_codec_get_cx_data() returns no data. - * - * \param[in] ctx Pointer to this instance's context - * \param[in] img Image data to encode, NULL to flush. - * \param[in] pts Presentation time stamp, in timebase units. - * \param[in] duration Duration to show frame, in timebase units. - * \param[in] flags Flags to use for encoding this frame. - * \param[in] deadline Time to spend encoding, in microseconds. (0=infinite) - * - * \retval #VPX_CODEC_OK - * The configuration was populated. - * \retval #VPX_CODEC_INCAPABLE - * Interface is not an encoder interface. - * \retval #VPX_CODEC_INVALID_PARAM - * A parameter was NULL, the image format is unsupported, etc. - */ -vpx_codec_err_t vpx_codec_encode(vpx_codec_ctx_t *ctx, const vpx_image_t *img, - vpx_codec_pts_t pts, unsigned long duration, - vpx_enc_frame_flags_t flags, - unsigned long deadline); - -/*!\brief Set compressed data output buffer - * - * Sets the buffer that the codec should output the compressed data - * into. This call effectively sets the buffer pointer returned in the - * next VPX_CODEC_CX_FRAME_PKT packet. Subsequent packets will be - * appended into this buffer. The buffer is preserved across frames, - * so applications must periodically call this function after flushing - * the accumulated compressed data to disk or to the network to reset - * the pointer to the buffer's head. - * - * `pad_before` bytes will be skipped before writing the compressed - * data, and `pad_after` bytes will be appended to the packet. The size - * of the packet will be the sum of the size of the actual compressed - * data, pad_before, and pad_after. The padding bytes will be preserved - * (not overwritten). - * - * Note that calling this function does not guarantee that the returned - * compressed data will be placed into the specified buffer. In the - * event that the encoded data will not fit into the buffer provided, - * the returned packet \ref MAY point to an internal buffer, as it would - * if this call were never used. In this event, the output packet will - * NOT have any padding, and the application must free space and copy it - * to the proper place. This is of particular note in configurations - * that may output multiple packets for a single encoded frame (e.g., lagged - * encoding) or if the application does not reset the buffer periodically. - * - * Applications may restore the default behavior of the codec providing - * the compressed data buffer by calling this function with a NULL - * buffer. - * - * Applications \ref MUSTNOT call this function during iteration of - * vpx_codec_get_cx_data(). - * - * \param[in] ctx Pointer to this instance's context - * \param[in] buf Buffer to store compressed data into - * \param[in] pad_before Bytes to skip before writing compressed data - * \param[in] pad_after Bytes to skip after writing compressed data - * - * \retval #VPX_CODEC_OK - * The buffer was set successfully. - * \retval #VPX_CODEC_INVALID_PARAM - * A parameter was NULL, the image format is unsupported, etc. - */ -vpx_codec_err_t vpx_codec_set_cx_data_buf(vpx_codec_ctx_t *ctx, - const vpx_fixed_buf_t *buf, - unsigned int pad_before, - unsigned int pad_after); - -/*!\brief Encoded data iterator - * - * Iterates over a list of data packets to be passed from the encoder to the - * application. The different kinds of packets available are enumerated in - * #vpx_codec_cx_pkt_kind. - * - * #VPX_CODEC_CX_FRAME_PKT packets should be passed to the application's - * muxer. Multiple compressed frames may be in the list. - * #VPX_CODEC_STATS_PKT packets should be appended to a global buffer. - * - * The application \ref MUST silently ignore any packet kinds that it does - * not recognize or support. - * - * The data buffers returned from this function are only guaranteed to be - * valid until the application makes another call to any vpx_codec_* function. - * - * \param[in] ctx Pointer to this instance's context - * \param[in,out] iter Iterator storage, initialized to NULL - * - * \return Returns a pointer to an output data packet (compressed frame data, - * two-pass statistics, etc.) or NULL to signal end-of-list. - * - */ -const vpx_codec_cx_pkt_t *vpx_codec_get_cx_data(vpx_codec_ctx_t *ctx, - vpx_codec_iter_t *iter); - -/*!\brief Get Preview Frame - * - * Returns an image that can be used as a preview. Shows the image as it would - * exist at the decompressor. The application \ref MUST NOT write into this - * image buffer. - * - * \param[in] ctx Pointer to this instance's context - * - * \return Returns a pointer to a preview image, or NULL if no image is - * available. - * - */ -const vpx_image_t *vpx_codec_get_preview_frame(vpx_codec_ctx_t *ctx); - -/*!@} - end defgroup encoder*/ -#ifdef __cplusplus -} -#endif -#endif // VPX_VPX_ENCODER_H_ diff --git a/protocols/Tox/include/vpx/vpx_frame_buffer.h b/protocols/Tox/include/vpx/vpx_frame_buffer.h deleted file mode 100644 index ad70cdd572..0000000000 --- a/protocols/Tox/include/vpx/vpx_frame_buffer.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2014 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef VPX_VPX_FRAME_BUFFER_H_ -#define VPX_VPX_FRAME_BUFFER_H_ - -/*!\file - * \brief Describes the decoder external frame buffer interface. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "./vpx_integer.h" - -/*!\brief The maximum number of work buffers used by libvpx. - * Support maximum 4 threads to decode video in parallel. - * Each thread will use one work buffer. - * TODO(hkuang): Add support to set number of worker threads dynamically. - */ -#define VPX_MAXIMUM_WORK_BUFFERS 8 - -/*!\brief The maximum number of reference buffers that a VP9 encoder may use. - */ -#define VP9_MAXIMUM_REF_BUFFERS 8 - -/*!\brief External frame buffer - * - * This structure holds allocated frame buffers used by the decoder. - */ -typedef struct vpx_codec_frame_buffer { - uint8_t *data; /**< Pointer to the data buffer */ - size_t size; /**< Size of data in bytes */ - void *priv; /**< Frame's private data */ -} vpx_codec_frame_buffer_t; - -/*!\brief get frame buffer callback prototype - * - * This callback is invoked by the decoder to retrieve data for the frame - * buffer in order for the decode call to complete. The callback must - * allocate at least min_size in bytes and assign it to fb->data. The callback - * must zero out all the data allocated. Then the callback must set fb->size - * to the allocated size. The application does not need to align the allocated - * data. The callback is triggered when the decoder needs a frame buffer to - * decode a compressed image into. This function may be called more than once - * for every call to vpx_codec_decode. The application may set fb->priv to - * some data which will be passed back in the ximage and the release function - * call. |fb| is guaranteed to not be NULL. On success the callback must - * return 0. Any failure the callback must return a value less than 0. - * - * \param[in] priv Callback's private data - * \param[in] new_size Size in bytes needed by the buffer - * \param[in,out] fb Pointer to vpx_codec_frame_buffer_t - */ -typedef int (*vpx_get_frame_buffer_cb_fn_t)(void *priv, size_t min_size, - vpx_codec_frame_buffer_t *fb); - -/*!\brief release frame buffer callback prototype - * - * This callback is invoked by the decoder when the frame buffer is not - * referenced by any other buffers. |fb| is guaranteed to not be NULL. On - * success the callback must return 0. Any failure the callback must return - * a value less than 0. - * - * \param[in] priv Callback's private data - * \param[in] fb Pointer to vpx_codec_frame_buffer_t - */ -typedef int (*vpx_release_frame_buffer_cb_fn_t)(void *priv, - vpx_codec_frame_buffer_t *fb); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // VPX_VPX_FRAME_BUFFER_H_ diff --git a/protocols/Tox/include/vpx/vpx_image.h b/protocols/Tox/include/vpx/vpx_image.h deleted file mode 100644 index d6d3166d2f..0000000000 --- a/protocols/Tox/include/vpx/vpx_image.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -/*!\file - * \brief Describes the vpx image descriptor and associated operations - * - */ -#ifndef VPX_VPX_IMAGE_H_ -#define VPX_VPX_IMAGE_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/*!\brief Current ABI version number - * - * \internal - * If this file is altered in any way that changes the ABI, this value - * must be bumped. Examples include, but are not limited to, changing - * types, removing or reassigning enums, adding/removing/rearranging - * fields to structures - */ -#define VPX_IMAGE_ABI_VERSION (4) /**<\hideinitializer*/ - -#define VPX_IMG_FMT_PLANAR 0x100 /**< Image is a planar format. */ -#define VPX_IMG_FMT_UV_FLIP 0x200 /**< V plane precedes U in memory. */ -#define VPX_IMG_FMT_HAS_ALPHA 0x400 /**< Image has an alpha channel. */ -#define VPX_IMG_FMT_HIGHBITDEPTH 0x800 /**< Image uses 16bit framebuffer. */ - -/*!\brief List of supported image formats */ -typedef enum vpx_img_fmt { - VPX_IMG_FMT_NONE, - VPX_IMG_FMT_RGB24, /**< 24 bit per pixel packed RGB */ - VPX_IMG_FMT_RGB32, /**< 32 bit per pixel packed 0RGB */ - VPX_IMG_FMT_RGB565, /**< 16 bit per pixel, 565 */ - VPX_IMG_FMT_RGB555, /**< 16 bit per pixel, 555 */ - VPX_IMG_FMT_UYVY, /**< UYVY packed YUV */ - VPX_IMG_FMT_YUY2, /**< YUYV packed YUV */ - VPX_IMG_FMT_YVYU, /**< YVYU packed YUV */ - VPX_IMG_FMT_BGR24, /**< 24 bit per pixel packed BGR */ - VPX_IMG_FMT_RGB32_LE, /**< 32 bit packed BGR0 */ - VPX_IMG_FMT_ARGB, /**< 32 bit packed ARGB, alpha=255 */ - VPX_IMG_FMT_ARGB_LE, /**< 32 bit packed BGRA, alpha=255 */ - VPX_IMG_FMT_RGB565_LE, /**< 16 bit per pixel, gggbbbbb rrrrrggg */ - VPX_IMG_FMT_RGB555_LE, /**< 16 bit per pixel, gggbbbbb 0rrrrrgg */ - VPX_IMG_FMT_YV12 = - VPX_IMG_FMT_PLANAR | VPX_IMG_FMT_UV_FLIP | 1, /**< planar YVU */ - VPX_IMG_FMT_I420 = VPX_IMG_FMT_PLANAR | 2, - VPX_IMG_FMT_VPXYV12 = VPX_IMG_FMT_PLANAR | VPX_IMG_FMT_UV_FLIP | - 3, /** < planar 4:2:0 format with vpx color space */ - VPX_IMG_FMT_VPXI420 = VPX_IMG_FMT_PLANAR | 4, - VPX_IMG_FMT_I422 = VPX_IMG_FMT_PLANAR | 5, - VPX_IMG_FMT_I444 = VPX_IMG_FMT_PLANAR | 6, - VPX_IMG_FMT_I440 = VPX_IMG_FMT_PLANAR | 7, - VPX_IMG_FMT_444A = VPX_IMG_FMT_PLANAR | VPX_IMG_FMT_HAS_ALPHA | 6, - VPX_IMG_FMT_I42016 = VPX_IMG_FMT_I420 | VPX_IMG_FMT_HIGHBITDEPTH, - VPX_IMG_FMT_I42216 = VPX_IMG_FMT_I422 | VPX_IMG_FMT_HIGHBITDEPTH, - VPX_IMG_FMT_I44416 = VPX_IMG_FMT_I444 | VPX_IMG_FMT_HIGHBITDEPTH, - VPX_IMG_FMT_I44016 = VPX_IMG_FMT_I440 | VPX_IMG_FMT_HIGHBITDEPTH -} vpx_img_fmt_t; /**< alias for enum vpx_img_fmt */ - -/*!\brief List of supported color spaces */ -typedef enum vpx_color_space { - VPX_CS_UNKNOWN = 0, /**< Unknown */ - VPX_CS_BT_601 = 1, /**< BT.601 */ - VPX_CS_BT_709 = 2, /**< BT.709 */ - VPX_CS_SMPTE_170 = 3, /**< SMPTE.170 */ - VPX_CS_SMPTE_240 = 4, /**< SMPTE.240 */ - VPX_CS_BT_2020 = 5, /**< BT.2020 */ - VPX_CS_RESERVED = 6, /**< Reserved */ - VPX_CS_SRGB = 7 /**< sRGB */ -} vpx_color_space_t; /**< alias for enum vpx_color_space */ - -/*!\brief List of supported color range */ -typedef enum vpx_color_range { - VPX_CR_STUDIO_RANGE = 0, /**< Y [16..235], UV [16..240] */ - VPX_CR_FULL_RANGE = 1 /**< YUV/RGB [0..255] */ -} vpx_color_range_t; /**< alias for enum vpx_color_range */ - -/**\brief Image Descriptor */ -typedef struct vpx_image { - vpx_img_fmt_t fmt; /**< Image Format */ - vpx_color_space_t cs; /**< Color Space */ - vpx_color_range_t range; /**< Color Range */ - - /* Image storage dimensions */ - unsigned int w; /**< Stored image width */ - unsigned int h; /**< Stored image height */ - unsigned int bit_depth; /**< Stored image bit-depth */ - - /* Image display dimensions */ - unsigned int d_w; /**< Displayed image width */ - unsigned int d_h; /**< Displayed image height */ - - /* Image intended rendering dimensions */ - unsigned int r_w; /**< Intended rendering image width */ - unsigned int r_h; /**< Intended rendering image height */ - - /* Chroma subsampling info */ - unsigned int x_chroma_shift; /**< subsampling order, X */ - unsigned int y_chroma_shift; /**< subsampling order, Y */ - -/* Image data pointers. */ -#define VPX_PLANE_PACKED 0 /**< To be used for all packed formats */ -#define VPX_PLANE_Y 0 /**< Y (Luminance) plane */ -#define VPX_PLANE_U 1 /**< U (Chroma) plane */ -#define VPX_PLANE_V 2 /**< V (Chroma) plane */ -#define VPX_PLANE_ALPHA 3 /**< A (Transparency) plane */ - unsigned char *planes[4]; /**< pointer to the top left pixel for each plane */ - int stride[4]; /**< stride between rows for each plane */ - - int bps; /**< bits per sample (for packed formats) */ - - /*!\brief The following member may be set by the application to associate - * data with this image. - */ - void *user_priv; - - /* The following members should be treated as private. */ - unsigned char *img_data; /**< private */ - int img_data_owner; /**< private */ - int self_allocd; /**< private */ - - void *fb_priv; /**< Frame buffer data associated with the image. */ -} vpx_image_t; /**< alias for struct vpx_image */ - -/**\brief Representation of a rectangle on a surface */ -typedef struct vpx_image_rect { - unsigned int x; /**< leftmost column */ - unsigned int y; /**< topmost row */ - unsigned int w; /**< width */ - unsigned int h; /**< height */ -} vpx_image_rect_t; /**< alias for struct vpx_image_rect */ - -/*!\brief Open a descriptor, allocating storage for the underlying image - * - * Returns a descriptor for storing an image of the given format. The - * storage for the descriptor is allocated on the heap. - * - * \param[in] img Pointer to storage for descriptor. If this parameter - * is NULL, the storage for the descriptor will be - * allocated on the heap. - * \param[in] fmt Format for the image - * \param[in] d_w Width of the image - * \param[in] d_h Height of the image - * \param[in] align Alignment, in bytes, of the image buffer and - * each row in the image(stride). - * - * \return Returns a pointer to the initialized image descriptor. If the img - * parameter is non-null, the value of the img parameter will be - * returned. - */ -vpx_image_t *vpx_img_alloc(vpx_image_t *img, vpx_img_fmt_t fmt, - unsigned int d_w, unsigned int d_h, - unsigned int align); - -/*!\brief Open a descriptor, using existing storage for the underlying image - * - * Returns a descriptor for storing an image of the given format. The - * storage for descriptor has been allocated elsewhere, and a descriptor is - * desired to "wrap" that storage. - * - * \param[in] img Pointer to storage for descriptor. If this parameter - * is NULL, the storage for the descriptor will be - * allocated on the heap. - * \param[in] fmt Format for the image - * \param[in] d_w Width of the image - * \param[in] d_h Height of the image - * \param[in] align Alignment, in bytes, of each row in the image. - * \param[in] img_data Storage to use for the image - * - * \return Returns a pointer to the initialized image descriptor. If the img - * parameter is non-null, the value of the img parameter will be - * returned. - */ -vpx_image_t *vpx_img_wrap(vpx_image_t *img, vpx_img_fmt_t fmt, unsigned int d_w, - unsigned int d_h, unsigned int align, - unsigned char *img_data); - -/*!\brief Set the rectangle identifying the displayed portion of the image - * - * Updates the displayed rectangle (aka viewport) on the image surface to - * match the specified coordinates and size. - * - * \param[in] img Image descriptor - * \param[in] x leftmost column - * \param[in] y topmost row - * \param[in] w width - * \param[in] h height - * - * \return 0 if the requested rectangle is valid, nonzero otherwise. - */ -int vpx_img_set_rect(vpx_image_t *img, unsigned int x, unsigned int y, - unsigned int w, unsigned int h); - -/*!\brief Flip the image vertically (top for bottom) - * - * Adjusts the image descriptor's pointers and strides to make the image - * be referenced upside-down. - * - * \param[in] img Image descriptor - */ -void vpx_img_flip(vpx_image_t *img); - -/*!\brief Close an image descriptor - * - * Frees all allocated storage associated with an image descriptor. - * - * \param[in] img Image descriptor - */ -void vpx_img_free(vpx_image_t *img); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // VPX_VPX_IMAGE_H_ diff --git a/protocols/Tox/include/vpx/vpx_integer.h b/protocols/Tox/include/vpx/vpx_integer.h deleted file mode 100644 index 09bad9222d..0000000000 --- a/protocols/Tox/include/vpx/vpx_integer.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef VPX_VPX_INTEGER_H_ -#define VPX_VPX_INTEGER_H_ - -/* get ptrdiff_t, size_t, wchar_t, NULL */ -#include <stddef.h> - -#if defined(_MSC_VER) -#define VPX_FORCE_INLINE __forceinline -#define VPX_INLINE __inline -#else -#define VPX_FORCE_INLINE __inline__ __attribute__(always_inline) -// TODO(jbb): Allow a way to force inline off for older compilers. -#define VPX_INLINE inline -#endif - -#if defined(VPX_EMULATE_INTTYPES) -typedef signed char int8_t; -typedef signed short int16_t; -typedef signed int int32_t; - -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; - -#ifndef _UINTPTR_T_DEFINED -typedef size_t uintptr_t; -#endif - -#else - -/* Most platforms have the C99 standard integer types. */ - -#if defined(__cplusplus) -#if !defined(__STDC_FORMAT_MACROS) -#define __STDC_FORMAT_MACROS -#endif -#if !defined(__STDC_LIMIT_MACROS) -#define __STDC_LIMIT_MACROS -#endif -#endif // __cplusplus - -#include <stdint.h> - -#endif - -/* VS2010 defines stdint.h, but not inttypes.h */ -#if defined(_MSC_VER) && _MSC_VER < 1800 -#define PRId64 "I64d" -#else -#include <inttypes.h> -#endif - -#endif // VPX_VPX_INTEGER_H_ diff --git a/protocols/Tox/libtox/docs/CHANGELOG.md b/protocols/Tox/libtox/docs/CHANGELOG.md new file mode 100644 index 0000000000..e3275a16df --- /dev/null +++ b/protocols/Tox/libtox/docs/CHANGELOG.md @@ -0,0 +1,450 @@ + + +## v0.1.10 + +### Merged PRs: + +- [#564](https://github.com/TokTok/c-toxcore/pull/564) Fix Windows build +- [#542](https://github.com/TokTok/c-toxcore/pull/542) Save bandwidth by moderating onion pinging + +## v0.1.9 + +### Merged PRs: + +- [#563](https://github.com/TokTok/c-toxcore/pull/563) Release v0.1.9 +- [#561](https://github.com/TokTok/c-toxcore/pull/561) Remove unused variable +- [#560](https://github.com/TokTok/c-toxcore/pull/560) Fix non-portable zeroing out of doubles +- [#559](https://github.com/TokTok/c-toxcore/pull/559) Fix theoretical memory leaks +- [#557](https://github.com/TokTok/c-toxcore/pull/557) Document inverted mutex lock/unlock. +- [#556](https://github.com/TokTok/c-toxcore/pull/556) Build tests on appveyor, the MSVC build, but don't run them yet. +- [#555](https://github.com/TokTok/c-toxcore/pull/555) Fold hstox tests into the general linux test. +- [#554](https://github.com/TokTok/c-toxcore/pull/554) Add a monolith_test that includes all toxcore sources. +- [#553](https://github.com/TokTok/c-toxcore/pull/553) Factor out strict_abi cmake code into a separate module. +- [#552](https://github.com/TokTok/c-toxcore/pull/552) Fix formatting and spelling in version-sync script. +- [#551](https://github.com/TokTok/c-toxcore/pull/551) Forbid undefined symbols in shared libraries. +- [#546](https://github.com/TokTok/c-toxcore/pull/546) Make variable names in file saving test less cryptic +- [#539](https://github.com/TokTok/c-toxcore/pull/539) Make OSX test failures fail the Travis CI build. +- [#537](https://github.com/TokTok/c-toxcore/pull/537) Fix TokTok/c-toxcore#535 +- [#534](https://github.com/TokTok/c-toxcore/pull/534) Fix markdown formatting +- [#530](https://github.com/TokTok/c-toxcore/pull/530) Implement missing TES constant functions. +- [#511](https://github.com/TokTok/c-toxcore/pull/511) Save bandwidth by avoiding superfluous Nodes Requests to peers already on the Close List +- [#506](https://github.com/TokTok/c-toxcore/pull/506) Add test case for title change +- [#498](https://github.com/TokTok/c-toxcore/pull/498) DHT refactoring +- [#487](https://github.com/TokTok/c-toxcore/pull/487) Split daemon's logging backends in separate modules +- [#468](https://github.com/TokTok/c-toxcore/pull/468) Test for memberlist not changing after changing own name +- [#449](https://github.com/TokTok/c-toxcore/pull/449) Use new encoding of `Maybe` in msgpack results. + +### Closed issues: + +- [#482](https://github.com/TokTok/c-toxcore/issues/482) CMake can't detect and compile ToxAV on OSX + +## v0.1.8 + +### Merged PRs: + +- [#538](https://github.com/TokTok/c-toxcore/pull/538) Reverting tox_loop PR changes +- [#536](https://github.com/TokTok/c-toxcore/pull/536) Release v0.1.8 +- [#526](https://github.com/TokTok/c-toxcore/pull/526) Add TOX_NOSPAM_SIZE to the public API. +- [#525](https://github.com/TokTok/c-toxcore/pull/525) Retry autotools tests the same way as cmake tests. +- [#524](https://github.com/TokTok/c-toxcore/pull/524) Reduce ctest timeout to 2 minutes from 5 minutes. +- [#512](https://github.com/TokTok/c-toxcore/pull/512) Add test for DHT pack_nodes and unpack_nodes +- [#504](https://github.com/TokTok/c-toxcore/pull/504) CMake: install bootstrapd if it is built +- [#488](https://github.com/TokTok/c-toxcore/pull/488) Save compiled Android artifacts after CircleCI builds. +- [#473](https://github.com/TokTok/c-toxcore/pull/473) Added missing includes: <netinet/in.h> and <sys/socket.h> +- [#335](https://github.com/TokTok/c-toxcore/pull/335) Implement tox_loop + +### Closed issues: + +- [#535](https://github.com/TokTok/c-toxcore/issues/535) OS X tests failing +- [#503](https://github.com/TokTok/c-toxcore/issues/503) Undefined functions: tox_pass_salt_length, tox_pass_key_length, tox_pass_encryption_extra_length +- [#456](https://github.com/TokTok/c-toxcore/issues/456) Tox.h doesn't expose the size of the nospam. +- [#411](https://github.com/TokTok/c-toxcore/issues/411) Reduce CTest timeout to 2 minutes + +## v0.1.7 + +### Merged PRs: + +- [#523](https://github.com/TokTok/c-toxcore/pull/523) Release v0.1.7 +- [#521](https://github.com/TokTok/c-toxcore/pull/521) Fix appveyor script: install curl from chocolatey. +- [#510](https://github.com/TokTok/c-toxcore/pull/510) Fix list malloc(0) bug +- [#509](https://github.com/TokTok/c-toxcore/pull/509) Fix network malloc(0) bug +- [#497](https://github.com/TokTok/c-toxcore/pull/497) Fix network +- [#496](https://github.com/TokTok/c-toxcore/pull/496) Fix Travis always succeeding despite tests failing +- [#491](https://github.com/TokTok/c-toxcore/pull/491) Add crypto_memzero for temp buffer +- [#490](https://github.com/TokTok/c-toxcore/pull/490) Move c_sleep to helpers.h and misc_tools.h +- [#486](https://github.com/TokTok/c-toxcore/pull/486) Remove empty line in Messenger.c +- [#483](https://github.com/TokTok/c-toxcore/pull/483) Make BUILD_TOXAV an option and fail if dependencies are missing +- [#481](https://github.com/TokTok/c-toxcore/pull/481) Remove dependency on strings.h +- [#480](https://github.com/TokTok/c-toxcore/pull/480) Use VLA macro +- [#479](https://github.com/TokTok/c-toxcore/pull/479) Fix pthreads in AppVeyor build +- [#471](https://github.com/TokTok/c-toxcore/pull/471) Remove statics used in onion comparison functions. +- [#461](https://github.com/TokTok/c-toxcore/pull/461) Replace part of network functions on platform-independent implementation +- [#452](https://github.com/TokTok/c-toxcore/pull/452) Add VLA compatibility macro for C89-ish compilers. + +### Closed issues: + +- [#474](https://github.com/TokTok/c-toxcore/issues/474) TOX_VERSION_PATCH isn't in sync with the version + +## v0.1.6 + +### Merged PRs: + +- [#460](https://github.com/TokTok/c-toxcore/pull/460) Release v0.1.6. +- [#459](https://github.com/TokTok/c-toxcore/pull/459) Add Android build to CI. +- [#454](https://github.com/TokTok/c-toxcore/pull/454) Add appveyor build for native windows tests. +- [#448](https://github.com/TokTok/c-toxcore/pull/448) Only retry failed tests on Circle CI instead of all. +- [#434](https://github.com/TokTok/c-toxcore/pull/434) Replace redundant packet type check in handler with assert. +- [#432](https://github.com/TokTok/c-toxcore/pull/432) Remove some static variables +- [#385](https://github.com/TokTok/c-toxcore/pull/385) Add platform-independent Socket and IP implementation + +### Closed issues: + +- [#415](https://github.com/TokTok/c-toxcore/issues/415) Set up a native windows build on appveyor + +## v0.1.5 + +### Merged PRs: + +- [#447](https://github.com/TokTok/c-toxcore/pull/447) Release v0.1.5. +- [#446](https://github.com/TokTok/c-toxcore/pull/446) Limit number of retries to 3. +- [#445](https://github.com/TokTok/c-toxcore/pull/445) Make Travis tests slightly more robust by re-running them. +- [#443](https://github.com/TokTok/c-toxcore/pull/443) Make building `DHT_bootstrap` in cmake optional. +- [#433](https://github.com/TokTok/c-toxcore/pull/433) Add tutorial and "danger: experimental" banner to README. +- [#431](https://github.com/TokTok/c-toxcore/pull/431) Update license headers and remove redundant file name comment. +- [#424](https://github.com/TokTok/c-toxcore/pull/424) Fixed the FreeBSD build failure due to the undefined MSG_NOSIGNAL. +- [#420](https://github.com/TokTok/c-toxcore/pull/420) Setup autotools to read .so version info from a separate file +- [#418](https://github.com/TokTok/c-toxcore/pull/418) Clarify how the autotools build is done on Travis. +- [#414](https://github.com/TokTok/c-toxcore/pull/414) Explicitly check if compiler supports C99 + +## v0.1.4 + +### Merged PRs: + +- [#422](https://github.com/TokTok/c-toxcore/pull/422) Release v0.1.4. +- [#410](https://github.com/TokTok/c-toxcore/pull/410) Fix NaCl build: tar was called incorrectly. +- [#409](https://github.com/TokTok/c-toxcore/pull/409) Clarify that the pass key `new` function can fail. +- [#407](https://github.com/TokTok/c-toxcore/pull/407) Don't use `git.depth=1` anymore. +- [#404](https://github.com/TokTok/c-toxcore/pull/404) Issue 404: semicolon not found +- [#403](https://github.com/TokTok/c-toxcore/pull/403) Warn on -pedantic, don't error yet. +- [#401](https://github.com/TokTok/c-toxcore/pull/401) Add logging callback to messenger_test. +- [#400](https://github.com/TokTok/c-toxcore/pull/400) Run windows tests but ignore their failures. +- [#398](https://github.com/TokTok/c-toxcore/pull/398) Portability Fixes +- [#397](https://github.com/TokTok/c-toxcore/pull/397) Replace make_quick_sort with qsort +- [#396](https://github.com/TokTok/c-toxcore/pull/396) Add an OSX build that doesn't run tests. +- [#394](https://github.com/TokTok/c-toxcore/pull/394) CMake: Add soversion to library files to generate proper symlinks +- [#393](https://github.com/TokTok/c-toxcore/pull/393) Set up autotools build to build against vanilla NaCl. +- [#392](https://github.com/TokTok/c-toxcore/pull/392) Check that TCP connections aren't dropped in callbacks. +- [#391](https://github.com/TokTok/c-toxcore/pull/391) Minor simplification in `file_seek` code. +- [#390](https://github.com/TokTok/c-toxcore/pull/390) Always kill invalid file transfers when receiving file controls. +- [#388](https://github.com/TokTok/c-toxcore/pull/388) Fix logging condition for IPv6 client timestamp updates. +- [#387](https://github.com/TokTok/c-toxcore/pull/387) Eliminate dead return statement. +- [#386](https://github.com/TokTok/c-toxcore/pull/386) Avoid accessing uninitialised memory in `net_crypto`. +- [#381](https://github.com/TokTok/c-toxcore/pull/381) Remove `TOX_DEBUG` and have asserts always enabled. + +### Closed issues: + +- [#378](https://github.com/TokTok/c-toxcore/issues/378) Replace all uses of `make_quick_sort` with `qsort` +- [#364](https://github.com/TokTok/c-toxcore/issues/364) Delete misc_tools.h after replacing its use by qsort. +- [#363](https://github.com/TokTok/c-toxcore/issues/363) Test against NaCl in addition to libsodium on Travis. + +## v0.1.3 + +### Merged PRs: + +- [#395](https://github.com/TokTok/c-toxcore/pull/395) Revert "Portability fixes" +- [#380](https://github.com/TokTok/c-toxcore/pull/380) Test a few cmake option combinations before the build. +- [#377](https://github.com/TokTok/c-toxcore/pull/377) Fix SSL verification in coveralls. +- [#376](https://github.com/TokTok/c-toxcore/pull/376) Bring back autotools instructions +- [#373](https://github.com/TokTok/c-toxcore/pull/373) Only fetch 1 revision from git during Travis builds. +- [#369](https://github.com/TokTok/c-toxcore/pull/369) Integrate with CircleCI to build artifacts in the future +- [#366](https://github.com/TokTok/c-toxcore/pull/366) Release v0.1.3. +- [#362](https://github.com/TokTok/c-toxcore/pull/362) Remove .cabal-sandbox option from tox-spectest find line. +- [#361](https://github.com/TokTok/c-toxcore/pull/361) Simplify integration as a third-party lib in cmake projects +- [#354](https://github.com/TokTok/c-toxcore/pull/354) Add secure memcmp and memzero implementation. +- [#324](https://github.com/TokTok/c-toxcore/pull/324) Do not compile and install DHT_bootstrap if it was disabled in configure +- [#297](https://github.com/TokTok/c-toxcore/pull/297) Portability fixes + +### Closed issues: + +- [#347](https://github.com/TokTok/c-toxcore/issues/347) Implement our own secure `memcmp` and `memzero` if libsodium isn't available +- [#319](https://github.com/TokTok/c-toxcore/issues/319) toxcore installs `DHT_bootstrap` even though `--disable-daemon` is passed to `./configure` + +## v0.1.2 + +### Merged PRs: + +- [#355](https://github.com/TokTok/c-toxcore/pull/355) Release v0.1.2 +- [#353](https://github.com/TokTok/c-toxcore/pull/353) Fix toxav use after free caused by premature MSI destruction +- [#346](https://github.com/TokTok/c-toxcore/pull/346) Avoid array out of bounds read in friend saving. +- [#344](https://github.com/TokTok/c-toxcore/pull/344) Remove unused get/set salt/key functions from toxencryptsave. +- [#343](https://github.com/TokTok/c-toxcore/pull/343) Wrap all sodium/nacl functions in crypto_core.c. +- [#341](https://github.com/TokTok/c-toxcore/pull/341) Add test to check if tox_new/tox_kill leaks. +- [#336](https://github.com/TokTok/c-toxcore/pull/336) Correct TES docs to reflect how many bytes functions actually require. +- [#333](https://github.com/TokTok/c-toxcore/pull/333) Use `tox_options_set_*` instead of direct member access. + +### Closed issues: + +- [#345](https://github.com/TokTok/c-toxcore/issues/345) Array out of bounds read in "save" function +- [#342](https://github.com/TokTok/c-toxcore/issues/342) Wrap all libsodium functions we use in toxcore in `crypto_core`. +- [#278](https://github.com/TokTok/c-toxcore/issues/278) ToxAV use-after-free bug + +## v0.1.1 + +### Merged PRs: + +- [#337](https://github.com/TokTok/c-toxcore/pull/337) Release v0.1.1 +- [#332](https://github.com/TokTok/c-toxcore/pull/332) Add test for encrypted savedata. +- [#330](https://github.com/TokTok/c-toxcore/pull/330) Strengthen the note about ABI compatibility in tox.h. +- [#328](https://github.com/TokTok/c-toxcore/pull/328) Drop the broken `TOX_VERSION_REQUIRE` macro. +- [#326](https://github.com/TokTok/c-toxcore/pull/326) Fix unresolved reference in toxencryptsave API docs. +- [#309](https://github.com/TokTok/c-toxcore/pull/309) Fixed attempt to join detached threads (fixes toxav test crash) +- [#306](https://github.com/TokTok/c-toxcore/pull/306) Add option to disable local peer discovery + +### Closed issues: + +- [#327](https://github.com/TokTok/c-toxcore/issues/327) The `TOX_VERSION_REQUIRE` macro is broken. +- [#221](https://github.com/TokTok/c-toxcore/issues/221) Option to disable local peer detection + +## v0.1.0 + +### Merged PRs: + +- [#325](https://github.com/TokTok/c-toxcore/pull/325) Fix Libs line in toxcore.pc pkg-config file. +- [#322](https://github.com/TokTok/c-toxcore/pull/322) Add compatibility pkg-config modules: libtoxcore, libtoxav. +- [#318](https://github.com/TokTok/c-toxcore/pull/318) Fix `--enable-logging` flag in autotools configure script. +- [#316](https://github.com/TokTok/c-toxcore/pull/316) Release 0.1.0. +- [#315](https://github.com/TokTok/c-toxcore/pull/315) Fix version compatibility test. +- [#314](https://github.com/TokTok/c-toxcore/pull/314) Fix off by one error in saving our own status message. +- [#313](https://github.com/TokTok/c-toxcore/pull/313) Fix padding being in the wrong place in `SAVED_FRIEND` struct +- [#312](https://github.com/TokTok/c-toxcore/pull/312) Conditionally enable non-portable assert on LP64. +- [#310](https://github.com/TokTok/c-toxcore/pull/310) Add apidsl file for toxencryptsave. +- [#307](https://github.com/TokTok/c-toxcore/pull/307) Clarify toxencryptsave documentation regarding buffer sizes +- [#305](https://github.com/TokTok/c-toxcore/pull/305) Fix static builds +- [#303](https://github.com/TokTok/c-toxcore/pull/303) Don't build nTox by default. +- [#301](https://github.com/TokTok/c-toxcore/pull/301) Renamed messenger functions, prepend `m_`. +- [#299](https://github.com/TokTok/c-toxcore/pull/299) net_crypto give handle_data_packet_helper a better name +- [#294](https://github.com/TokTok/c-toxcore/pull/294) Don't error on warnings by default + +### Closed issues: + +- [#317](https://github.com/TokTok/c-toxcore/issues/317) toxcore fails to build with autotools and debugging level enabled +- [#311](https://github.com/TokTok/c-toxcore/issues/311) Incorrect padding +- [#308](https://github.com/TokTok/c-toxcore/issues/308) Review TES and port it to APIDSL +- [#293](https://github.com/TokTok/c-toxcore/issues/293) error building on ubuntu 14.04 +- [#292](https://github.com/TokTok/c-toxcore/issues/292) Don't build nTox by default with CMake +- [#290](https://github.com/TokTok/c-toxcore/issues/290) User Feed +- [#266](https://github.com/TokTok/c-toxcore/issues/266) Support all levels listed in TOX_DHT_NAT_LEVEL +- [#216](https://github.com/TokTok/c-toxcore/issues/216) When v0.1 release? + +## v0.0.5 + +### Merged PRs: + +- [#289](https://github.com/TokTok/c-toxcore/pull/289) Version Patch v0.0.4 => v0.0.5 +- [#287](https://github.com/TokTok/c-toxcore/pull/287) Add CMake knobs to suppress building tests +- [#286](https://github.com/TokTok/c-toxcore/pull/286) Support float32 and float64 in msgpack type printer. +- [#285](https://github.com/TokTok/c-toxcore/pull/285) Mark `Tox_Options` struct as deprecated. +- [#284](https://github.com/TokTok/c-toxcore/pull/284) Add NONE enumerator to bit mask. +- [#281](https://github.com/TokTok/c-toxcore/pull/281) Made save format platform-independent +- [#277](https://github.com/TokTok/c-toxcore/pull/277) Fix a memory leak in hstox interface +- [#276](https://github.com/TokTok/c-toxcore/pull/276) Fix NULL pointer dereference in log calls +- [#275](https://github.com/TokTok/c-toxcore/pull/275) Fix a memory leak in GroupAV +- [#274](https://github.com/TokTok/c-toxcore/pull/274) Options in `new_messenger()` must never be null. +- [#271](https://github.com/TokTok/c-toxcore/pull/271) Convert to and from network byte order in set/get nospam. +- [#262](https://github.com/TokTok/c-toxcore/pull/262) Add ability to disable UDP hole punching + +### Closed issues: + +- [#254](https://github.com/TokTok/c-toxcore/issues/254) Add option to disable UDP hole punching +- [#215](https://github.com/TokTok/c-toxcore/issues/215) The current tox save format is non-portable +- [#205](https://github.com/TokTok/c-toxcore/issues/205) nospam value is reversed in array returned by `tox_self_get_address()` + +## v0.0.4 + +### Merged PRs: + +- [#272](https://github.com/TokTok/c-toxcore/pull/272) v0.0.4 +- [#265](https://github.com/TokTok/c-toxcore/pull/265) Disable -Wunused-but-set-variable compiler warning flag. +- [#261](https://github.com/TokTok/c-toxcore/pull/261) Work around Travis issue that causes build failures. +- [#260](https://github.com/TokTok/c-toxcore/pull/260) Support arbitrary video resolutions in av_test +- [#257](https://github.com/TokTok/c-toxcore/pull/257) Add decode/encode PlainText test support. +- [#256](https://github.com/TokTok/c-toxcore/pull/256) Add spectest to the cmake test suite. +- [#255](https://github.com/TokTok/c-toxcore/pull/255) Disable some gcc-specific warnings. +- [#249](https://github.com/TokTok/c-toxcore/pull/249) Use apidsl for the crypto_core API. +- [#248](https://github.com/TokTok/c-toxcore/pull/248) Remove new_nonce function in favour of random_nonce. +- [#224](https://github.com/TokTok/c-toxcore/pull/224) Add DHT_create_packet, an abstraction for DHT RPC packets + +## v0.0.3 + +### Merged PRs: + +- [#251](https://github.com/TokTok/c-toxcore/pull/251) Rename log levels to remove the extra "LOG" prefix. +- [#250](https://github.com/TokTok/c-toxcore/pull/250) Release v0.0.3. +- [#245](https://github.com/TokTok/c-toxcore/pull/245) Change packet kind enum to use hex constants. +- [#243](https://github.com/TokTok/c-toxcore/pull/243) Enable address sanitizer on the cmake build. +- [#242](https://github.com/TokTok/c-toxcore/pull/242) Remove assoc +- [#241](https://github.com/TokTok/c-toxcore/pull/241) Move log callback to options. +- [#233](https://github.com/TokTok/c-toxcore/pull/233) Enable all possible C compiler warning flags. +- [#230](https://github.com/TokTok/c-toxcore/pull/230) Move packing and unpacking DHT request packets to DHT module. +- [#228](https://github.com/TokTok/c-toxcore/pull/228) Remove unimplemented "time delta" parameter. +- [#227](https://github.com/TokTok/c-toxcore/pull/227) Compile as C++ for windows builds. +- [#223](https://github.com/TokTok/c-toxcore/pull/223) TravisCI shorten IRC message +- [#220](https://github.com/TokTok/c-toxcore/pull/220) toxav renaming: group.{h,c} -> groupav.{h,c} +- [#218](https://github.com/TokTok/c-toxcore/pull/218) Rename some internal "group chat" thing to "conference". +- [#212](https://github.com/TokTok/c-toxcore/pull/212) Convert series of `NET_PACKET_*` defines into a typedef enum +- [#196](https://github.com/TokTok/c-toxcore/pull/196) Update readme, moved the roadmap to a higher position +- [#193](https://github.com/TokTok/c-toxcore/pull/193) Remove duplicate tests: split tests part 2. + +### Closed issues: + +- [#40](https://github.com/TokTok/c-toxcore/issues/40) Stateless callbacks in toxcore's public API + +## v0.0.2 + +### Merged PRs: + +- [#207](https://github.com/TokTok/c-toxcore/pull/207) docs: correct instructions for cloning & harden agains repo name changes +- [#206](https://github.com/TokTok/c-toxcore/pull/206) Corrected libsodium tag +- [#204](https://github.com/TokTok/c-toxcore/pull/204) Error if format_test can't be executed. +- [#202](https://github.com/TokTok/c-toxcore/pull/202) Version Patch v0.0.2 +- [#190](https://github.com/TokTok/c-toxcore/pull/190) Install libraries with RPATH. +- [#189](https://github.com/TokTok/c-toxcore/pull/189) Use `socklen_t` instead of `unsigned int` in call to `accept`. +- [#188](https://github.com/TokTok/c-toxcore/pull/188) Add option to set test timeout +- [#187](https://github.com/TokTok/c-toxcore/pull/187) Add option to build tox-bootstrapd +- [#185](https://github.com/TokTok/c-toxcore/pull/185) Import the hstox SUT interface from hstox. +- [#183](https://github.com/TokTok/c-toxcore/pull/183) Set log level for DEBUG=ON to LOG_DEBUG. +- [#182](https://github.com/TokTok/c-toxcore/pull/182) Remove return after no-return situation. +- [#181](https://github.com/TokTok/c-toxcore/pull/181) Minor documentation fixes. +- [#180](https://github.com/TokTok/c-toxcore/pull/180) Add the 'Tox' context object to the logger. +- [#179](https://github.com/TokTok/c-toxcore/pull/179) Remove the `_test` suffix in `auto_test` calls. +- [#178](https://github.com/TokTok/c-toxcore/pull/178) Rebuild apidsl'd headers in cmake. +- [#177](https://github.com/TokTok/c-toxcore/pull/177) docs(INSTALL): update compiling instructions for Linux +- [#176](https://github.com/TokTok/c-toxcore/pull/176) Merge irungentoo/toxcore into TokTok/c-toxcore. +- [#173](https://github.com/TokTok/c-toxcore/pull/173) Duplicate tox_test to 4 other files. + +### Closed issues: + +- [#201](https://github.com/TokTok/c-toxcore/issues/201) Logging callback was broken + +## v0.0.1 + +### Merged PRs: + +- [#174](https://github.com/TokTok/c-toxcore/pull/174) Remove redundant callback objects. +- [#171](https://github.com/TokTok/c-toxcore/pull/171) Simple Version tick to v0.0.1 +- [#170](https://github.com/TokTok/c-toxcore/pull/170) C++ the second round. +- [#166](https://github.com/TokTok/c-toxcore/pull/166) Add version-sync script. +- [#164](https://github.com/TokTok/c-toxcore/pull/164) Replace `void*` with `RingBuffer*` to avoid conversions. +- [#163](https://github.com/TokTok/c-toxcore/pull/163) Move ring buffer out of toxcore/util into toxav. +- [#162](https://github.com/TokTok/c-toxcore/pull/162) Allow the OSX build to fail on travis. +- [#161](https://github.com/TokTok/c-toxcore/pull/161) Minor cleanups: unused vars, unreachable code, static globals. +- [#160](https://github.com/TokTok/c-toxcore/pull/160) Work around bug in opencv3 headers. +- [#157](https://github.com/TokTok/c-toxcore/pull/157) Make TCP_Connections module-private. +- [#156](https://github.com/TokTok/c-toxcore/pull/156) Make TCP_Server opaque. +- [#153](https://github.com/TokTok/c-toxcore/pull/153) Fix strict-ld grep expressions to include digits. +- [#151](https://github.com/TokTok/c-toxcore/pull/151) Revert #130 "Make ToxAV stateless" +- [#148](https://github.com/TokTok/c-toxcore/pull/148) Added UB comment r/t deleting a friend w/ active call +- [#146](https://github.com/TokTok/c-toxcore/pull/146) Make group callbacks stateless +- [#145](https://github.com/TokTok/c-toxcore/pull/145) Make internal chat list function take uint32_t* as well. +- [#144](https://github.com/TokTok/c-toxcore/pull/144) Only build toxav if opus and vpx are found. +- [#143](https://github.com/TokTok/c-toxcore/pull/143) Make toxcore code C++ compatible. +- [#142](https://github.com/TokTok/c-toxcore/pull/142) Fix for windows dynamic libraries. +- [#141](https://github.com/TokTok/c-toxcore/pull/141) const-correctness in windows code. +- [#140](https://github.com/TokTok/c-toxcore/pull/140) Use C99 %zu format conversion in printf for size_t. +- [#139](https://github.com/TokTok/c-toxcore/pull/139) Clean up Travis build a bit in preparation for osx/win. +- [#138](https://github.com/TokTok/c-toxcore/pull/138) Remove format-source from travis script. +- [#135](https://github.com/TokTok/c-toxcore/pull/135) Convert old groupchats to new API format +- [#134](https://github.com/TokTok/c-toxcore/pull/134) Add some astyle options to make it do more. +- [#133](https://github.com/TokTok/c-toxcore/pull/133) Ensure that all TODOs have an owner. +- [#132](https://github.com/TokTok/c-toxcore/pull/132) Remove `else` directly after `return`. +- [#130](https://github.com/TokTok/c-toxcore/pull/130) Make ToxAV stateless +- [#129](https://github.com/TokTok/c-toxcore/pull/129) Use TokTok's apidsl instead of the iphydf one. +- [#127](https://github.com/TokTok/c-toxcore/pull/127) Use "phase" script for travis build phases. +- [#126](https://github.com/TokTok/c-toxcore/pull/126) Add option to build static libraries. +- [#125](https://github.com/TokTok/c-toxcore/pull/125) Group #include directives in 3-4 groups. +- [#123](https://github.com/TokTok/c-toxcore/pull/123) Use correct logical operator for tox_test +- [#120](https://github.com/TokTok/c-toxcore/pull/120) make the majority of the callbacks stateless and add some status to a testcase +- [#118](https://github.com/TokTok/c-toxcore/pull/118) Use `const` for version numbers. +- [#117](https://github.com/TokTok/c-toxcore/pull/117) Add STRICT_ABI cmake flag to generate export lists. +- [#116](https://github.com/TokTok/c-toxcore/pull/116) Fix potential null pointer dereference. +- [#115](https://github.com/TokTok/c-toxcore/pull/115) Fix memory leak on error paths in tox_new. +- [#114](https://github.com/TokTok/c-toxcore/pull/114) Fix compilation for Windows. +- [#111](https://github.com/TokTok/c-toxcore/pull/111) Add debugging option to autotools configuration +- [#110](https://github.com/TokTok/c-toxcore/pull/110) Comment intentional switch fallthroughs +- [#109](https://github.com/TokTok/c-toxcore/pull/109) Separate ip_port packing from pack_nodes() and unpack_nodes() +- [#108](https://github.com/TokTok/c-toxcore/pull/108) Prevent `<winsock.h>` inclusion by `<windows.h>`. +- [#107](https://github.com/TokTok/c-toxcore/pull/107) Print a message about missing astyle in format-source. +- [#104](https://github.com/TokTok/c-toxcore/pull/104) Merge with irungentoo/master +- [#103](https://github.com/TokTok/c-toxcore/pull/103) Allocate `sizeof(IP_ADAPTER_INFO)` bytes instead of `sizeof(T*)`. +- [#101](https://github.com/TokTok/c-toxcore/pull/101) Add TODO for @mannol. +- [#100](https://github.com/TokTok/c-toxcore/pull/100) Remove the packet mutation in toxav's bwcontroller. +- [#99](https://github.com/TokTok/c-toxcore/pull/99) Make packet data a ptr-to-const. +- [#97](https://github.com/TokTok/c-toxcore/pull/97) Improve static and const correctness. +- [#96](https://github.com/TokTok/c-toxcore/pull/96) Improve C standard compliance. +- [#94](https://github.com/TokTok/c-toxcore/pull/94) Rearrange fields to decrease size of structure +- [#84](https://github.com/TokTok/c-toxcore/pull/84) Remove useless casts. +- [#82](https://github.com/TokTok/c-toxcore/pull/82) Add missing #include <pthread.h> to av_test.c. +- [#81](https://github.com/TokTok/c-toxcore/pull/81) Match parameter names in declarations with their definitions. +- [#80](https://github.com/TokTok/c-toxcore/pull/80) Sort #includes in all source files. +- [#79](https://github.com/TokTok/c-toxcore/pull/79) Remove redundant `return` statements. +- [#78](https://github.com/TokTok/c-toxcore/pull/78) Do not use `else` after `return`. +- [#77](https://github.com/TokTok/c-toxcore/pull/77) Add OSX and Windows build to travis config. +- [#76](https://github.com/TokTok/c-toxcore/pull/76) Remove unused and bit-rotten friends_test. +- [#75](https://github.com/TokTok/c-toxcore/pull/75) Enable build of av_test. +- [#74](https://github.com/TokTok/c-toxcore/pull/74) Add missing #includes to headers and rename tox_old to tox_group. +- [#73](https://github.com/TokTok/c-toxcore/pull/73) Add braces to all if statements. +- [#72](https://github.com/TokTok/c-toxcore/pull/72) Add getters/setters for options. +- [#70](https://github.com/TokTok/c-toxcore/pull/70) Expose constants as functions. +- [#68](https://github.com/TokTok/c-toxcore/pull/68) Add address sanitizer option to cmake file. +- [#66](https://github.com/TokTok/c-toxcore/pull/66) Fix plane size calculation in test +- [#65](https://github.com/TokTok/c-toxcore/pull/65) Avoid large stack allocations on thread stacks. +- [#64](https://github.com/TokTok/c-toxcore/pull/64) Comment out useless TODO'd if block. +- [#63](https://github.com/TokTok/c-toxcore/pull/63) Initialise the id in assoc_test. +- [#62](https://github.com/TokTok/c-toxcore/pull/62) Reduce the timeout on travis to something much more reasonable +- [#60](https://github.com/TokTok/c-toxcore/pull/60) Make friend requests stateless +- [#59](https://github.com/TokTok/c-toxcore/pull/59) Replace uint with unsigned int in assoc.c. +- [#58](https://github.com/TokTok/c-toxcore/pull/58) Make Message received receipts stateless +- [#57](https://github.com/TokTok/c-toxcore/pull/57) Make Friend User Status stateless +- [#55](https://github.com/TokTok/c-toxcore/pull/55) docs(INSTALL.md): update instructions for Gentoo +- [#54](https://github.com/TokTok/c-toxcore/pull/54) Make typing change callback stateless +- [#53](https://github.com/TokTok/c-toxcore/pull/53) Add format-source script. +- [#52](https://github.com/TokTok/c-toxcore/pull/52) Build assoc DHT code on travis. +- [#51](https://github.com/TokTok/c-toxcore/pull/51) Fix operation sequencing in TCP_test. +- [#49](https://github.com/TokTok/c-toxcore/pull/49) Apidsl test +- [#48](https://github.com/TokTok/c-toxcore/pull/48) Make friend message callback stateless +- [#46](https://github.com/TokTok/c-toxcore/pull/46) Move logging to a callback. +- [#45](https://github.com/TokTok/c-toxcore/pull/45) Stateless friend status message +- [#43](https://github.com/TokTok/c-toxcore/pull/43) Allow NULL as argument to tox_kill. +- [#41](https://github.com/TokTok/c-toxcore/pull/41) Fix warnings +- [#39](https://github.com/TokTok/c-toxcore/pull/39) Merge irungentoo/toxcore into TokTok/c-toxcore. +- [#38](https://github.com/TokTok/c-toxcore/pull/38) Try searching for libsodium with pkg-config in ./configure. +- [#37](https://github.com/TokTok/c-toxcore/pull/37) Add missing DHT_bootstrap to CMakeLists.txt. +- [#36](https://github.com/TokTok/c-toxcore/pull/36) Make tox_callback_friend_name stateless. +- [#33](https://github.com/TokTok/c-toxcore/pull/33) Update readme with tentative roadmap, removed old todo.md +- [#32](https://github.com/TokTok/c-toxcore/pull/32) Fix a bug I introduced that would make toxcore fail to initialise a second time +- [#31](https://github.com/TokTok/c-toxcore/pull/31) 7. Travis envs +- [#30](https://github.com/TokTok/c-toxcore/pull/30) 2. Hstox test +- [#29](https://github.com/TokTok/c-toxcore/pull/29) 1. Move toxcore travis build scripts out of .travis.yml. +- [#27](https://github.com/TokTok/c-toxcore/pull/27) 8. Stateless +- [#26](https://github.com/TokTok/c-toxcore/pull/26) 6. Cmake bootstrapd +- [#25](https://github.com/TokTok/c-toxcore/pull/25) 5. Coverage clang +- [#24](https://github.com/TokTok/c-toxcore/pull/24) Silence/fix some compiler warnings. +- [#23](https://github.com/TokTok/c-toxcore/pull/23) 4. Cmake +- [#20](https://github.com/TokTok/c-toxcore/pull/20) 3. Travis astyle +- [#13](https://github.com/TokTok/c-toxcore/pull/13) Enable, and report test status +- [#12](https://github.com/TokTok/c-toxcore/pull/12) Fix readme for TokTok +- [#11](https://github.com/TokTok/c-toxcore/pull/11) Documentation: SysVInit workaround for <1024 ports +- [#2](https://github.com/TokTok/c-toxcore/pull/2) Enable toxcore logging when building on Travis. +- [#1](https://github.com/TokTok/c-toxcore/pull/1) Apidsl fixes and start tracking test coverage + +### Closed issues: + +- [#158](https://github.com/TokTok/c-toxcore/issues/158) Error while build with OpenCV 3.1 +- [#147](https://github.com/TokTok/c-toxcore/issues/147) Add comment to m_delfriend about the NULL passing to the internal conn status cb +- [#136](https://github.com/TokTok/c-toxcore/issues/136) Replace astyle by clang-format +- [#113](https://github.com/TokTok/c-toxcore/issues/113) Toxcore tests fail +- [#83](https://github.com/TokTok/c-toxcore/issues/83) Travis tests are hard to quickly parse from their output. +- [#22](https://github.com/TokTok/c-toxcore/issues/22) Make the current tests exercise both ipv4 and ipv6. +- [#9](https://github.com/TokTok/c-toxcore/issues/9) Fix the failing test +- [#8](https://github.com/TokTok/c-toxcore/issues/8) Toxcore should make more liberal use of assertions +- [#4](https://github.com/TokTok/c-toxcore/issues/4) Integrate hstox tests with toxcore Travis build diff --git a/protocols/Tox/libtox/docs/COPYING b/protocols/Tox/libtox/docs/COPYING new file mode 100644 index 0000000000..94a9ed024d --- /dev/null +++ b/protocols/Tox/libtox/docs/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. 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 +them 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 prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. 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. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey 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; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If 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 convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + 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. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +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. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + 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 +state 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 3 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/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program 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, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU 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 Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/protocols/Tox/libtox/docs/DONATORS b/protocols/Tox/libtox/docs/DONATORS new file mode 100644 index 0000000000..dcce32c869 --- /dev/null +++ b/protocols/Tox/libtox/docs/DONATORS @@ -0,0 +1,7 @@ +Minnesota > Florida +vdo <vdo@greyfaze.net> +Spitfire is best technicolor horse. +if bad people don't hate you, you're doing something wrong +Pinkie Pie is best pony. +JRS was here +qTox is so bloated it doesn't even fit in a 64-bit address space diff --git a/protocols/Tox/libtox/docs/README.md b/protocols/Tox/libtox/docs/README.md new file mode 100644 index 0000000000..7a1ffe7ffa --- /dev/null +++ b/protocols/Tox/libtox/docs/README.md @@ -0,0 +1,174 @@ +# ![Project Tox](https://raw.github.com/TokTok/toxcore/master/other/tox.png "Project Tox") + +**Current build status:** [![Build Status](https://travis-ci.org/TokTok/c-toxcore.svg?branch=master)](https://travis-ci.org/TokTok/c-toxcore) +**Current Coverage:** [![Coverage Status](https://coveralls.io/repos/github/TokTok/toxcore/badge.svg?branch=master)](https://coveralls.io/github/TokTok/toxcore?branch=master) + +[**Website**](https://tox.chat) **|** [**Wiki**](https://wiki.tox.chat/) **|** [**Blog**](https://blog.tox.chat/) **|** [**FAQ**](https://wiki.tox.chat/doku.php?id=users:faq) **|** [**Binaries/Downloads**](https://wiki.tox.chat/Binaries) **|** [**Clients**](https://wiki.tox.chat/doku.php?id=clients) **|** [**Compiling**](/INSTALL.md) + +**IRC Channels:** Users: [#tox@freenode](https://webchat.freenode.net/?channels=tox), Developers: [#toktok@freenode](https://webchat.freenode.net/?channels=toktok) + +## What is Tox + +Tox is a peer to peer (serverless) instant messenger aimed at making security +and privacy easy to obtain for regular users. It uses +[NaCl](https://nacl.cr.yp.to/) for its encryption and authentication. + +## IMPORTANT! + +### ![Danger: Experimental](other/tox-warning.png) + +This is an **experimental** cryptographic network library. It has not been +formally audited by an independent third party that specializes in +cryptography or cryptanalysis. **Use this library at your own risk.** + +The underlying crypto library [NaCl](https://nacl.cr.yp.to/install.html) +provides reliable encryption, but the security model has not yet been fully +specified. See [issue 210](https://github.com/TokTok/c-toxcore/issues/210) for +a discussion on developing a threat model. See other issues for known +weaknesses (e.g. [issue 426](https://github.com/TokTok/c-toxcore/issues/426) +describes what can happen if your secret key is stolen). + +## Toxcore Development Roadmap + +The roadmap and changelog are generated from GitHub issues. You may view them +on the website, where they are updated at least once every 24 hours: + +- Changelog: https://toktok.ltd/changelog/c-toxcore +- Roadmap: https://toktok.ltd/roadmap/c-toxcore + +## Installing toxcore + +Detailed installation instructions can be found in [INSTALL.md](INSTALL.md). + +In a nutshell, if you have [libsodium](https://github.com/jedisct1/libsodium) +or [nacl](https://nacl.cr.yp.to/install.html) installed, run: + +```sh +autoreconf -fi +mkdir _build && cd _build +../configure +make +sudo make install +``` + +If you have [libvpx](https://github.com/webmproject/libvpx) and +[opus](https://github.com/xiph/opus) installed, the above will also build the +A/V library for multimedia chats. + +## Using toxcore + +The simplest "hello world" example could be an echo bot. Here we will walk +through the implementation of a simple bot. + +### Creating the tox instance + +All toxcore API functions work with error parameters. They are enums with one +`OK` value and several error codes that describe the different situations in +which the function might fail. + +```c +TOX_ERR_NEW err_new; +Tox *tox = tox_new(NULL, &err_new); +if (err_new != TOX_ERR_NEW_OK) { + fprintf(stderr, "tox_new failed with error code %d\n", err_new); + exit(1); +} +``` + +Here, we simply exit the program, but in a real client you will probably want +to do some error handling and proper error reporting to the user. The `NULL` +argument given to the first parameter of `tox_new` is the `Tox_Options`. It +contains various write-once network settings and allows you to load a +previously serialised instance. See [toxcore/tox.h](tox.h) for details. + +### Setting up callbacks + +Toxcore works with callbacks that you can register to listen for certain +events. Examples of such events are "friend request received" or "friend sent +a message". Search the API for `tox_callback_*` to find all of them. + +Here, we will set up callbacks for receiving friend requests and receiving +messages. We will always accept any friend request (because we're a bot), and +when we receive a message, we send it back to the sender. + +```c +tox_callback_friend_request(tox, handle_friend_request); +tox_callback_friend_message(tox, handle_friend_message); +``` + +These two function calls set up the callbacks. Now we also need to implement +these "handle" functions. + +### Handle friend requests + +```c +static void handle_friend_request( + Tox *tox, const uint8_t *public_key, const uint8_t *message, size_t length, + void *user_data) { + // Accept the friend request: + TOX_ERR_FRIEND_ADD err_friend_add; + tox_friend_add_norequest(tox, public_key, &err_friend_add); + if (err_friend_add != TOX_ERR_FRIEND_ADD_OK) { + fprintf(stderr, "unable to add friend: %d\n", err_friend_add); + } +} +``` + +The `tox_friend_add_norequest` function adds the friend without sending them a +friend request. Since we already got a friend request, this is the right thing +to do. If you wanted to send a friend request yourself, you would use +`tox_friend_add`, which has an extra parameter for the message. + +### Handle messages + +Now, when the friend sends us a message, we want to respond to them by sending +them the same message back. This will be our "echo". + +```c +static void handle_friend_message( + Tox *tox, uint32_t friend_number, TOX_MESSAGE_TYPE type, + const uint8_t *message, size_t length, + void *user_data) { + TOX_ERR_FRIEND_SEND_MESSAGE err_send; + tox_friend_send_message(tox, friend_number, type, message, length, + &err_send); + if (err_send != TOX_ERR_FRIEND_SEND_MESSAGE_OK) { + fprintf(stderr, "unable to send message back to friend %d: %d\n", + friend_number, err_send); + } +} +``` + +That's it for the setup. Now we want to actually run the bot. + +### Main event loop + +Toxcore works with a main event loop function `tox_iterate` that you need to +call at a certain frequency dictated by `tox_iteration_interval`. This is a +polling function that receives new network messages and processes them. + +```c +while (true) { + usleep(1000 * tox_iteration_interval(tox)); + tox_iterate(tox, NULL); +} +``` + +That's it! Now you have a working echo bot. The only problem is that since Tox +works with public keys, and you can't really guess your bot's public key, you +can't add it as a friend in your client. For this, we need to call another API +function: `tox_self_get_address(tox, address)`. This will fill the 38 byte +friend address into the `address` buffer. You can then display that binary +string as hex and input it into your client. Writing a `bin2hex` function is +left as exercise for the reader. + +We glossed over a lot of details, such as the user data which we passed to +`tox_iterate` (passing `NULL`), bootstrapping into an actual network (this bot +will work in the LAN, but not on an internet server) and the fact that we now +have no clean way of stopping the bot (`while (true)`). If you want to write a +real bot, you will probably want to read up on all the API functions. Consult +the API documentation in [toxcore/tox.h](tox.h) for more information. + +### Other resources + +- [Another echo bot](https://wiki.tox.chat/developers/client_examples/echo_bot) diff --git a/protocols/Tox/libtox/libtox.vcxproj b/protocols/Tox/libtox/libtox.vcxproj new file mode 100644 index 0000000000..c4380e76d9 --- /dev/null +++ b/protocols/Tox/libtox/libtox.vcxproj @@ -0,0 +1,60 @@ +<?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>{A21C50CD-28A6-481A-A12B-47189FE66641}</ProjectGuid> + <ProjectName>libtox</ProjectName> + <GenerateManifest>false</GenerateManifest> + <EmbedManifest>false</EmbedManifest> + <ConfigurationType>StaticLibrary</ConfigurationType> + <OutDir Condition="'$(Platform)'=='Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</OutDir> + <OutDir Condition="'$(Platform)'=='x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</OutDir> + </PropertyGroup> + <Import Project="..\..\..\build\vc.common\common.props" /> + <ItemDefinitionGroup> + <ClCompile> + <AdditionalIncludeDirectories>..\..\..\libs\pthreads\src;..\..\..\libs\libsodium\src\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + </ClCompile> + <Link> + <ModuleDefinitionFile>src/libtox.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="src\toxcore\*.c"> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + </ClCompile> + <ClCompile Include="src\toxdns\*.c"> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + </ClCompile> + <ClCompile Include="src\toxencryptsave\*.c"> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + </ClCompile> + <ClInclude Include="src\toxcore\*.h" /> + <ClInclude Include="src\toxencryptsave*.h" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\..\libs\libsodium\libsodium.vcxproj"> + <Project>{a185b162-6cb6-4502-b03f-b56f7699a8d9}</Project> + </ProjectReference> + <ProjectReference Include="..\..\..\libs\pthreads\pthreads.vcxproj"> + <Project>{e0ebb8a5-b577-414c-a5f9-9b4e2a0a66e9}</Project> + </ProjectReference> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/protocols/AimOscar/proto_aim/Proto_AIM.vcxproj.filters b/protocols/Tox/libtox/libtox.vcxproj.filters index e39f86d5d6..5a8d37777a 100644 --- a/protocols/AimOscar/proto_aim/Proto_AIM.vcxproj.filters +++ b/protocols/Tox/libtox/libtox.vcxproj.filters @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Project="$(ProjectDir)..\..\..\build\vc.common\common.filters" />
-</Project>
\ No newline at end of file +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(ProjectDir)..\..\..\build\vc.common\common.filters" /> +</Project> diff --git a/protocols/Tox/libtox/src/libtox.def b/protocols/Tox/libtox/src/libtox.def new file mode 100644 index 0000000000..e1706ad3ae --- /dev/null +++ b/protocols/Tox/libtox/src/libtox.def @@ -0,0 +1,155 @@ +LIBRARY libtox.mir +DESCRIPTION + +EXPORTS +tox_add_tcp_relay +tox_address_size +tox_bootstrap +tox_callback_conference_invite +tox_callback_conference_message +tox_callback_conference_namelist_change +tox_callback_conference_title +tox_callback_file_chunk_request +tox_callback_file_recv +tox_callback_file_recv_chunk +tox_callback_file_recv_control +tox_callback_friend_connection_status +tox_callback_friend_lossless_packet +tox_callback_friend_lossy_packet +tox_callback_friend_message +tox_callback_friend_name +tox_callback_friend_read_receipt +tox_callback_friend_request +tox_callback_friend_status +tox_callback_friend_status_message +tox_callback_friend_typing +tox_callback_self_connection_status +tox_conference_delete +tox_conference_get_chatlist +tox_conference_get_chatlist_size +tox_conference_get_title +tox_conference_get_title_size +tox_conference_get_type +tox_conference_invite +tox_conference_join +tox_conference_new +tox_conference_peer_count +tox_conference_peer_get_name +tox_conference_peer_get_name_size +tox_conference_peer_get_public_key +tox_conference_peer_number_is_ours +tox_conference_send_message +tox_conference_set_title +tox_decrypt_dns3_TXT +tox_dns3_kill +tox_dns3_new +tox_file_control +tox_file_get_file_id +tox_file_id_length +tox_file_seek +tox_file_send +tox_file_send_chunk +tox_friend_add +tox_friend_add_norequest +tox_friend_by_public_key +tox_friend_delete +tox_friend_exists +tox_friend_get_connection_status +tox_friend_get_last_online +tox_friend_get_name +tox_friend_get_name_size +tox_friend_get_public_key +tox_friend_get_status +tox_friend_get_status_message +tox_friend_get_status_message_size +tox_friend_get_typing +tox_friend_send_lossless_packet +tox_friend_send_lossy_packet +tox_friend_send_message +tox_generate_dns3_string +tox_get_salt +tox_get_savedata +tox_get_savedata_size +tox_hash +tox_hash_length +tox_is_data_encrypted +tox_iterate +tox_iteration_interval +tox_kill +tox_max_custom_packet_size +tox_max_filename_length +tox_max_friend_request_length +tox_max_message_length +tox_max_name_length +tox_max_status_message_length +tox_new +tox_options_default +tox_options_free +tox_options_get_end_port +tox_options_get_hole_punching_enabled +tox_options_get_ipv6_enabled +tox_options_get_local_discovery_enabled +tox_options_get_log_callback +tox_options_get_log_user_data +tox_options_get_proxy_host +tox_options_get_proxy_port +tox_options_get_proxy_type +tox_options_get_savedata_data +tox_options_get_savedata_length +tox_options_get_savedata_type +tox_options_get_start_port +tox_options_get_tcp_port +tox_options_get_udp_enabled +tox_options_new +tox_options_set_end_port +tox_options_set_hole_punching_enabled +tox_options_set_ipv6_enabled +tox_options_set_local_discovery_enabled +tox_options_set_log_callback +tox_options_set_log_user_data +tox_options_set_proxy_host +tox_options_set_proxy_port +tox_options_set_proxy_type +tox_options_set_savedata_data +tox_options_set_savedata_length +tox_options_set_savedata_type +tox_options_set_start_port +tox_options_set_tcp_port +tox_options_set_udp_enabled +tox_pass_decrypt +tox_pass_encrypt +tox_pass_encryption_extra_length +tox_pass_key_decrypt +tox_pass_key_derive +tox_pass_key_derive_with_salt +tox_pass_key_encrypt +tox_pass_key_free +tox_pass_key_length +tox_pass_key_new +tox_pass_salt_length +tox_public_key_size +tox_secret_key_size +tox_self_get_address +tox_self_get_connection_status +tox_self_get_dht_id +tox_self_get_friend_list +tox_self_get_friend_list_size +tox_self_get_name +tox_self_get_name_size +tox_self_get_nospam +tox_self_get_public_key +tox_self_get_secret_key +tox_self_get_status +tox_self_get_status_message +tox_self_get_status_message_size +tox_self_get_tcp_port +tox_self_get_udp_port +tox_self_set_name +tox_self_set_nospam +tox_self_set_status +tox_self_set_status_message +tox_self_set_typing +tox_version_is_compatible +tox_version_major +tox_version_minor +tox_version_patch diff --git a/protocols/Tox/libtox/src/stdafx.cxx b/protocols/Tox/libtox/src/stdafx.cxx new file mode 100644 index 0000000000..1647228cd0 --- /dev/null +++ b/protocols/Tox/libtox/src/stdafx.cxx @@ -0,0 +1,2 @@ + +#include "stdafx.h"
\ No newline at end of file diff --git a/protocols/Tox/libtox/src/stdafx.h b/protocols/Tox/libtox/src/stdafx.h new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/protocols/Tox/libtox/src/stdafx.h diff --git a/protocols/Tox/libtox/src/toxcore/DHT.c b/protocols/Tox/libtox/src/toxcore/DHT.c new file mode 100644 index 0000000000..4ebe7f3344 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/DHT.c @@ -0,0 +1,2853 @@ +/* + * An implementation of the DHT as seen in docs/updates/DHT.md + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "DHT.h" + +#include "LAN_discovery.h" +#include "logger.h" +#include "network.h" +#include "ping.h" +#include "util.h" + +#include <assert.h> + +/* The timeout after which a node is discarded completely. */ +#define KILL_NODE_TIMEOUT (BAD_NODE_TIMEOUT + PING_INTERVAL) + +/* Ping interval in seconds for each random sending of a get nodes request. */ +#define GET_NODE_INTERVAL 20 + +#define MAX_PUNCHING_PORTS 48 + +/* Interval in seconds between punching attempts*/ +#define PUNCH_INTERVAL 3 + +/* Time in seconds after which punching parameters will be reset */ +#define PUNCH_RESET_TIME 40 + +#define MAX_NORMAL_PUNCHING_TRIES 5 + +#define NAT_PING_REQUEST 0 +#define NAT_PING_RESPONSE 1 + +/* Number of get node requests to send to quickly find close nodes. */ +#define MAX_BOOTSTRAP_TIMES 5 + +#define ASSOC_COUNT 2 + +/* Compares pk1 and pk2 with pk. + * + * return 0 if both are same distance. + * return 1 if pk1 is closer. + * return 2 if pk2 is closer. + */ +int id_closest(const uint8_t *pk, const uint8_t *pk1, const uint8_t *pk2) +{ + for (size_t i = 0; i < CRYPTO_PUBLIC_KEY_SIZE; ++i) { + + uint8_t distance1 = pk[i] ^ pk1[i]; + uint8_t distance2 = pk[i] ^ pk2[i]; + + if (distance1 < distance2) { + return 1; + } + + if (distance1 > distance2) { + return 2; + } + } + + return 0; +} + +/* Return index of first unequal bit number. + */ +static unsigned int bit_by_bit_cmp(const uint8_t *pk1, const uint8_t *pk2) +{ + unsigned int i; + unsigned int j = 0; + + for (i = 0; i < CRYPTO_PUBLIC_KEY_SIZE; ++i) { + if (pk1[i] == pk2[i]) { + continue; + } + + for (j = 0; j < 8; ++j) { + uint8_t mask = 1 << (7 - j); + + if ((pk1[i] & mask) != (pk2[i] & mask)) { + break; + } + } + + break; + } + + return i * 8 + j; +} + +/* Shared key generations are costly, it is therefor smart to store commonly used + * ones so that they can re used later without being computed again. + * + * If shared key is already in shared_keys, copy it to shared_key. + * else generate it into shared_key and copy it to shared_keys + */ +void get_shared_key(Shared_Keys *shared_keys, uint8_t *shared_key, const uint8_t *secret_key, const uint8_t *public_key) +{ + uint32_t num = ~0; + uint32_t curr = 0; + + for (uint32_t i = 0; i < MAX_KEYS_PER_SLOT; ++i) { + int index = public_key[30] * MAX_KEYS_PER_SLOT + i; + Shared_Key *key = &shared_keys->keys[index]; + + if (key->stored) { + if (id_equal(public_key, key->public_key)) { + memcpy(shared_key, key->shared_key, CRYPTO_SHARED_KEY_SIZE); + ++key->times_requested; + key->time_last_requested = unix_time(); + return; + } + + if (num != 0) { + if (is_timeout(key->time_last_requested, KEYS_TIMEOUT)) { + num = 0; + curr = index; + } else if (num > key->times_requested) { + num = key->times_requested; + curr = index; + } + } + } else if (num != 0) { + num = 0; + curr = index; + } + } + + encrypt_precompute(public_key, secret_key, shared_key); + + if (num != (uint32_t)~0) { + Shared_Key *key = &shared_keys->keys[curr]; + key->stored = 1; + key->times_requested = 1; + memcpy(key->public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(key->shared_key, shared_key, CRYPTO_SHARED_KEY_SIZE); + key->time_last_requested = unix_time(); + } +} + +/* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key + * for packets that we receive. + */ +void DHT_get_shared_key_recv(DHT *dht, uint8_t *shared_key, const uint8_t *public_key) +{ + get_shared_key(&dht->shared_keys_recv, shared_key, dht->self_secret_key, public_key); +} + +/* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key + * for packets that we send. + */ +void DHT_get_shared_key_sent(DHT *dht, uint8_t *shared_key, const uint8_t *public_key) +{ + get_shared_key(&dht->shared_keys_sent, shared_key, dht->self_secret_key, public_key); +} + +#define CRYPTO_SIZE 1 + CRYPTO_PUBLIC_KEY_SIZE * 2 + CRYPTO_NONCE_SIZE + +/* Create a request to peer. + * send_public_key and send_secret_key are the pub/secret keys of the sender. + * recv_public_key is public key of receiver. + * packet must be an array of MAX_CRYPTO_REQUEST_SIZE big. + * Data represents the data we send with the request with length being the length of the data. + * request_id is the id of the request (32 = friend request, 254 = ping request). + * + * return -1 on failure. + * return the length of the created packet on success. + */ +int create_request(const uint8_t *send_public_key, const uint8_t *send_secret_key, uint8_t *packet, + const uint8_t *recv_public_key, const uint8_t *data, uint32_t length, uint8_t request_id) +{ + if (!send_public_key || !packet || !recv_public_key || !data) { + return -1; + } + + if (MAX_CRYPTO_REQUEST_SIZE < length + CRYPTO_SIZE + 1 + CRYPTO_MAC_SIZE) { + return -1; + } + + uint8_t *nonce = packet + 1 + CRYPTO_PUBLIC_KEY_SIZE * 2; + random_nonce(nonce); + uint8_t temp[MAX_CRYPTO_REQUEST_SIZE]; + memcpy(temp + 1, data, length); + temp[0] = request_id; + int len = encrypt_data(recv_public_key, send_secret_key, nonce, temp, length + 1, + CRYPTO_SIZE + packet); + + if (len == -1) { + crypto_memzero(temp, MAX_CRYPTO_REQUEST_SIZE); + return -1; + } + + packet[0] = NET_PACKET_CRYPTO; + memcpy(packet + 1, recv_public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, send_public_key, CRYPTO_PUBLIC_KEY_SIZE); + + crypto_memzero(temp, MAX_CRYPTO_REQUEST_SIZE); + return len + CRYPTO_SIZE; +} + +/* Puts the senders public key in the request in public_key, the data from the request + * in data if a friend or ping request was sent to us and returns the length of the data. + * packet is the request packet and length is its length. + * + * return -1 if not valid request. + */ +int handle_request(const uint8_t *self_public_key, const uint8_t *self_secret_key, uint8_t *public_key, uint8_t *data, + uint8_t *request_id, const uint8_t *packet, uint16_t length) +{ + if (!self_public_key || !public_key || !data || !request_id || !packet) { + return -1; + } + + if (length <= CRYPTO_SIZE + CRYPTO_MAC_SIZE || length > MAX_CRYPTO_REQUEST_SIZE) { + return -1; + } + + if (!id_equal(packet + 1, self_public_key)) { + return -1; + } + + memcpy(public_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, CRYPTO_PUBLIC_KEY_SIZE); + const uint8_t *nonce = packet + 1 + CRYPTO_PUBLIC_KEY_SIZE * 2; + uint8_t temp[MAX_CRYPTO_REQUEST_SIZE]; + int len1 = decrypt_data(public_key, self_secret_key, nonce, + packet + CRYPTO_SIZE, length - CRYPTO_SIZE, temp); + + if (len1 == -1 || len1 == 0) { + crypto_memzero(temp, MAX_CRYPTO_REQUEST_SIZE); + return -1; + } + + request_id[0] = temp[0]; + --len1; + memcpy(data, temp + 1, len1); + crypto_memzero(temp, MAX_CRYPTO_REQUEST_SIZE); + return len1; +} + +#define PACKED_NODE_SIZE_IP4 (1 + SIZE_IP4 + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE) +#define PACKED_NODE_SIZE_IP6 (1 + SIZE_IP6 + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE) + +/* Return packet size of packed node with ip_family on success. + * Return -1 on failure. + */ +int packed_node_size(uint8_t ip_family) +{ + switch (ip_family) { + case TOX_AF_INET: + case TCP_INET: + return PACKED_NODE_SIZE_IP4; + + case TOX_AF_INET6: + case TCP_INET6: + return PACKED_NODE_SIZE_IP6; + + default: + return -1; + } +} + + +/* Packs an IP_Port structure into data of max size length. + * + * Returns size of packed IP_Port data on success + * Return -1 on failure. + */ +static int pack_ip_port(uint8_t *data, uint16_t length, const IP_Port *ip_port) +{ + if (data == NULL) { + return -1; + } + + bool is_ipv4; + uint8_t net_family; + + if (ip_port->ip.family == TOX_AF_INET) { + // TODO(irungentoo): use functions to convert endianness + is_ipv4 = true; + net_family = TOX_AF_INET; + } else if (ip_port->ip.family == TCP_INET) { + is_ipv4 = true; + net_family = TOX_TCP_INET; + } else if (ip_port->ip.family == TOX_AF_INET6) { + is_ipv4 = false; + net_family = TOX_AF_INET6; + } else if (ip_port->ip.family == TCP_INET6) { + is_ipv4 = false; + net_family = TOX_TCP_INET6; + } else { + return -1; + } + + if (is_ipv4) { + uint32_t size = 1 + SIZE_IP4 + sizeof(uint16_t); + + if (size > length) { + return -1; + } + + data[0] = net_family; + memcpy(data + 1, &ip_port->ip.ip4, SIZE_IP4); + memcpy(data + 1 + SIZE_IP4, &ip_port->port, sizeof(uint16_t)); + return size; + } else { + uint32_t size = 1 + SIZE_IP6 + sizeof(uint16_t); + + if (size > length) { + return -1; + } + + data[0] = net_family; + memcpy(data + 1, &ip_port->ip.ip6, SIZE_IP6); + memcpy(data + 1 + SIZE_IP6, &ip_port->port, sizeof(uint16_t)); + return size; + } +} + +static int DHT_create_packet(const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE], + const uint8_t *shared_key, const uint8_t type, uint8_t *plain, size_t plain_length, uint8_t *packet) +{ + VLA(uint8_t, encrypted, plain_length + CRYPTO_MAC_SIZE); + uint8_t nonce[CRYPTO_NONCE_SIZE]; + + random_nonce(nonce); + + int encrypted_length = encrypt_data_symmetric(shared_key, nonce, plain, plain_length, encrypted); + + if (encrypted_length == -1) { + return -1; + } + + packet[0] = type; + memcpy(packet + 1, public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, nonce, CRYPTO_NONCE_SIZE); + memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, encrypted, encrypted_length); + + return 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + encrypted_length; +} + +/* Unpack IP_Port structure from data of max size length into ip_port. + * + * Return size of unpacked ip_port on success. + * Return -1 on failure. + */ +static int unpack_ip_port(IP_Port *ip_port, const uint8_t *data, uint16_t length, uint8_t tcp_enabled) +{ + if (data == NULL) { + return -1; + } + + bool is_ipv4; + uint8_t host_family; + + if (data[0] == TOX_AF_INET) { + is_ipv4 = true; + host_family = TOX_AF_INET; + } else if (data[0] == TOX_TCP_INET) { + if (!tcp_enabled) { + return -1; + } + + is_ipv4 = true; + host_family = TCP_INET; + } else if (data[0] == TOX_AF_INET6) { + is_ipv4 = false; + host_family = TOX_AF_INET6; + } else if (data[0] == TOX_TCP_INET6) { + if (!tcp_enabled) { + return -1; + } + + is_ipv4 = false; + host_family = TCP_INET6; + } else { + return -1; + } + + if (is_ipv4) { + uint32_t size = 1 + SIZE_IP4 + sizeof(uint16_t); + + if (size > length) { + return -1; + } + + ip_port->ip.family = host_family; + memcpy(&ip_port->ip.ip4, data + 1, SIZE_IP4); + memcpy(&ip_port->port, data + 1 + SIZE_IP4, sizeof(uint16_t)); + return size; + } else { + uint32_t size = 1 + SIZE_IP6 + sizeof(uint16_t); + + if (size > length) { + return -1; + } + + ip_port->ip.family = host_family; + memcpy(&ip_port->ip.ip6, data + 1, SIZE_IP6); + memcpy(&ip_port->port, data + 1 + SIZE_IP6, sizeof(uint16_t)); + return size; + } +} + +/* Pack number of nodes into data of maxlength length. + * + * return length of packed nodes on success. + * return -1 on failure. + */ +int pack_nodes(uint8_t *data, uint16_t length, const Node_format *nodes, uint16_t number) +{ + uint32_t packed_length = 0; + + for (uint32_t i = 0; i < number && packed_length < length; ++i) { + int ipp_size = pack_ip_port(data + packed_length, length - packed_length, &nodes[i].ip_port); + + if (ipp_size == -1) { + return -1; + } + + packed_length += ipp_size; + + if (packed_length + CRYPTO_PUBLIC_KEY_SIZE > length) { + return -1; + } + + memcpy(data + packed_length, nodes[i].public_key, CRYPTO_PUBLIC_KEY_SIZE); + packed_length += CRYPTO_PUBLIC_KEY_SIZE; + + uint32_t increment = ipp_size + CRYPTO_PUBLIC_KEY_SIZE; + assert(increment == PACKED_NODE_SIZE_IP4 || increment == PACKED_NODE_SIZE_IP6); + } + + return packed_length; +} + +/* Unpack data of length into nodes of size max_num_nodes. + * Put the length of the data processed in processed_data_len. + * tcp_enabled sets if TCP nodes are expected (true) or not (false). + * + * return number of unpacked nodes on success. + * return -1 on failure. + */ +int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed_data_len, const uint8_t *data, + uint16_t length, uint8_t tcp_enabled) +{ + uint32_t num = 0, len_processed = 0; + + while (num < max_num_nodes && len_processed < length) { + int ipp_size = unpack_ip_port(&nodes[num].ip_port, data + len_processed, length - len_processed, tcp_enabled); + + if (ipp_size == -1) { + return -1; + } + + len_processed += ipp_size; + + if (len_processed + CRYPTO_PUBLIC_KEY_SIZE > length) { + return -1; + } + + memcpy(nodes[num].public_key, data + len_processed, CRYPTO_PUBLIC_KEY_SIZE); + len_processed += CRYPTO_PUBLIC_KEY_SIZE; + ++num; + + uint32_t increment = ipp_size + CRYPTO_PUBLIC_KEY_SIZE; + assert(increment == PACKED_NODE_SIZE_IP4 || increment == PACKED_NODE_SIZE_IP6); + } + + if (processed_data_len) { + *processed_data_len = len_processed; + } + + return num; +} + +/* Find index of ##type with public_key equal to pk. + * + * return index or UINT32_MAX if not found. + */ +#define INDEX_OF_PK \ + for (uint32_t i = 0; i < size; i++) { \ + if (id_equal(array[i].public_key, pk)) { \ + return i; \ + } \ + } \ + \ + return UINT32_MAX; + +static uint32_t index_of_client_pk(const Client_data *array, uint32_t size, const uint8_t *pk) +{ + INDEX_OF_PK +} + +static uint32_t index_of_friend_pk(const DHT_Friend *array, uint32_t size, const uint8_t *pk) +{ + INDEX_OF_PK +} + +static uint32_t index_of_node_pk(const Node_format *array, uint32_t size, const uint8_t *pk) +{ + INDEX_OF_PK +} + +/* Find index of Client_data with ip_port equal to param ip_port. + * + * return index or UINT32_MAX if not found. + */ +static uint32_t index_of_client_ip_port(const Client_data *array, uint32_t size, const IP_Port *ip_port) +{ + for (uint32_t i = 0; i < size; ++i) { + if (ip_port->ip.family == TOX_AF_INET && ipport_equal(&array[i].assoc4.ip_port, ip_port) || + ip_port->ip.family == TOX_AF_INET6 && ipport_equal(&array[i].assoc6.ip_port, ip_port)) { + return i; + } + } + + return UINT32_MAX; +} + +/* Update ip_port of client if it's needed. + */ +static void update_client(Logger *log, int index, Client_data *client, IP_Port ip_port) +{ + IPPTsPng *assoc; + int ip_version; + + if (ip_port.ip.family == TOX_AF_INET) { + assoc = &client->assoc4; + ip_version = 4; + } else if (ip_port.ip.family == TOX_AF_INET6) { + assoc = &client->assoc6; + ip_version = 6; + } else { + return; + } + + if (!ipport_equal(&assoc->ip_port, &ip_port)) { + char ip_str[IP_NTOA_LEN]; + LOGGER_TRACE(log, "coipil[%u]: switching ipv%d from %s:%u to %s:%u", + index, ip_version, + ip_ntoa(&assoc->ip_port.ip, ip_str, sizeof(ip_str)), + net_ntohs(assoc->ip_port.port), + ip_ntoa(&ip_port.ip, ip_str, sizeof(ip_str)), + net_ntohs(ip_port.port)); + } + + if (LAN_ip(assoc->ip_port.ip) != 0 && LAN_ip(ip_port.ip) == 0) { + return; + } + + assoc->ip_port = ip_port; + assoc->timestamp = unix_time(); +} + +/* Check if client with public_key is already in list of length length. + * If it is then set its corresponding timestamp to current time. + * If the id is already in the list with a different ip_port, update it. + * TODO(irungentoo): Maybe optimize this. + * + * return True(1) or False(0) + */ +static int client_or_ip_port_in_list(Logger *log, Client_data *list, uint16_t length, const uint8_t *public_key, + IP_Port ip_port) +{ + uint64_t temp_time = unix_time(); + uint32_t index = index_of_client_pk(list, length, public_key); + + /* if public_key is in list, find it and maybe overwrite ip_port */ + if (index != UINT32_MAX) { + update_client(log, index, &list[index], ip_port); + return 1; + } + + /* public_key not in list yet: see if we can find an identical ip_port, in + * that case we kill the old public_key by overwriting it with the new one + * TODO(irungentoo): maybe we SHOULDN'T do that if that public_key is in a friend_list + * and the one who is the actual friend's public_key/address set? + * MAYBE: check the other address, if valid, don't nuke? */ + index = index_of_client_ip_port(list, length, &ip_port); + + if (index == UINT32_MAX) { + return 0; + } + + IPPTsPng *assoc; + int ip_version; + + if (ip_port.ip.family == TOX_AF_INET) { + assoc = &list[index].assoc4; + ip_version = 4; + } else { + assoc = &list[index].assoc6; + ip_version = 6; + } + + /* Initialize client timestamp. */ + assoc->timestamp = temp_time; + memcpy(list[index].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + + LOGGER_DEBUG(log, "coipil[%u]: switching public_key (ipv%d)", index, ip_version); + + /* kill the other address, if it was set */ + memset(assoc, 0, sizeof(IPPTsPng)); + return 1; +} + +/* Add node to the node list making sure only the nodes closest to cmp_pk are in the list. + */ +bool add_to_list(Node_format *nodes_list, unsigned int length, const uint8_t *pk, IP_Port ip_port, + const uint8_t *cmp_pk) +{ + uint8_t pk_bak[CRYPTO_PUBLIC_KEY_SIZE]; + IP_Port ip_port_bak; + + for (size_t i = 0; i < length; ++i) { + if (id_closest(cmp_pk, nodes_list[i].public_key, pk) == 2) { + memcpy(pk_bak, nodes_list[i].public_key, CRYPTO_PUBLIC_KEY_SIZE); + ip_port_bak = nodes_list[i].ip_port; + memcpy(nodes_list[i].public_key, pk, CRYPTO_PUBLIC_KEY_SIZE); + nodes_list[i].ip_port = ip_port; + + if (i != (length - 1)) { + add_to_list(nodes_list, length, pk_bak, ip_port_bak, cmp_pk); + } + + return 1; + } + } + + return 0; +} + +/* TODO(irungentoo): change this to 7 when done*/ +#define HARDENING_ALL_OK 2 +/* return 0 if not. + * return 1 if route request are ok + * return 2 if it responds to send node packets correctly + * return 4 if it can test other nodes correctly + * return HARDENING_ALL_OK if all ok. + */ +static uint8_t hardening_correct(const Hardening *h) +{ + return h->routes_requests_ok + (h->send_nodes_ok << 1) + (h->testing_requests << 2); +} +/* + * helper for get_close_nodes(). argument list is a monster :D + */ +static void get_close_nodes_inner(const uint8_t *public_key, Node_format *nodes_list, + Family sa_family, const Client_data *client_list, uint32_t client_list_length, + uint32_t *num_nodes_ptr, uint8_t is_LAN, uint8_t want_good) +{ + if ((sa_family != TOX_AF_INET) && (sa_family != TOX_AF_INET6) && (sa_family != 0)) { + return; + } + + uint32_t num_nodes = *num_nodes_ptr; + + for (uint32_t i = 0; i < client_list_length; i++) { + const Client_data *client = &client_list[i]; + + /* node already in list? */ + if (index_of_node_pk(nodes_list, MAX_SENT_NODES, client->public_key) != UINT32_MAX) { + continue; + } + + const IPPTsPng *ipptp = NULL; + + if (sa_family == TOX_AF_INET) { + ipptp = &client->assoc4; + } else if (sa_family == TOX_AF_INET6) { + ipptp = &client->assoc6; + } else if (client->assoc4.timestamp >= client->assoc6.timestamp) { + ipptp = &client->assoc4; + } else { + ipptp = &client->assoc6; + } + + /* node not in a good condition? */ + if (is_timeout(ipptp->timestamp, BAD_NODE_TIMEOUT)) { + continue; + } + + /* don't send LAN ips to non LAN peers */ + if (LAN_ip(ipptp->ip_port.ip) == 0 && !is_LAN) { + continue; + } + + if (LAN_ip(ipptp->ip_port.ip) != 0 && want_good && hardening_correct(&ipptp->hardening) != HARDENING_ALL_OK + && !id_equal(public_key, client->public_key)) { + continue; + } + + if (num_nodes < MAX_SENT_NODES) { + memcpy(nodes_list[num_nodes].public_key, client->public_key, CRYPTO_PUBLIC_KEY_SIZE); + nodes_list[num_nodes].ip_port = ipptp->ip_port; + num_nodes++; + } else { + add_to_list(nodes_list, MAX_SENT_NODES, client->public_key, ipptp->ip_port, public_key); + } + } + + *num_nodes_ptr = num_nodes; +} + +/* Find MAX_SENT_NODES nodes closest to the public_key for the send nodes request: + * put them in the nodes_list and return how many were found. + * + * TODO(irungentoo): For the love of based <your favorite deity, in doubt use + * "love"> make this function cleaner and much more efficient. + * + * want_good : do we want only good nodes as checked with the hardening returned or not? + */ +static int get_somewhat_close_nodes(const DHT *dht, const uint8_t *public_key, Node_format *nodes_list, + Family sa_family, uint8_t is_LAN, uint8_t want_good) +{ + uint32_t num_nodes = 0; + get_close_nodes_inner(public_key, nodes_list, sa_family, + dht->close_clientlist, LCLIENT_LIST, &num_nodes, is_LAN, 0); + + /* TODO(irungentoo): uncomment this when hardening is added to close friend clients */ +#if 0 + + for (uint32_t i = 0; i < dht->num_friends; ++i) { + get_close_nodes_inner(dht, public_key, nodes_list, sa_family, + dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, + &num_nodes, is_LAN, want_good); + } + +#endif + + for (uint32_t i = 0; i < dht->num_friends; ++i) { + get_close_nodes_inner(public_key, nodes_list, sa_family, + dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, + &num_nodes, is_LAN, 0); + } + + return num_nodes; +} + +int get_close_nodes(const DHT *dht, const uint8_t *public_key, Node_format *nodes_list, Family sa_family, + uint8_t is_LAN, uint8_t want_good) +{ + memset(nodes_list, 0, MAX_SENT_NODES * sizeof(Node_format)); + return get_somewhat_close_nodes(dht, public_key, nodes_list, sa_family, is_LAN, want_good); +} + +typedef struct { + const uint8_t *base_public_key; + Client_data entry; +} DHT_Cmp_data; + +static int cmp_dht_entry(const void *a, const void *b) +{ + DHT_Cmp_data cmp1, cmp2; + memcpy(&cmp1, a, sizeof(DHT_Cmp_data)); + memcpy(&cmp2, b, sizeof(DHT_Cmp_data)); + Client_data entry1 = cmp1.entry; + Client_data entry2 = cmp2.entry; + const uint8_t *cmp_public_key = cmp1.base_public_key; + +#define ASSOC_TIMEOUT(assoc) is_timeout((assoc).timestamp, BAD_NODE_TIMEOUT) + + bool t1 = ASSOC_TIMEOUT(entry1.assoc4) && ASSOC_TIMEOUT(entry1.assoc6); + bool t2 = ASSOC_TIMEOUT(entry2.assoc4) && ASSOC_TIMEOUT(entry2.assoc6); + + if (t1 && t2) { + return 0; + } + + if (t1) { + return -1; + } + + if (t2) { + return 1; + } + +#define INCORRECT_HARDENING(assoc) hardening_correct(&(assoc).hardening) != HARDENING_ALL_OK + + t1 = INCORRECT_HARDENING(entry1.assoc4) && INCORRECT_HARDENING(entry1.assoc6); + t2 = INCORRECT_HARDENING(entry2.assoc4) && INCORRECT_HARDENING(entry2.assoc6); + + if (t1 && !t2) { + return -1; + } + + if (!t1 && t2) { + return 1; + } + + int close = id_closest(cmp_public_key, entry1.public_key, entry2.public_key); + + if (close == 1) { + return 1; + } + + if (close == 2) { + return -1; + } + + return 0; +} + +/* Is it ok to store node with public_key in client. + * + * return 0 if node can't be stored. + * return 1 if it can. + */ +static unsigned int store_node_ok(const Client_data *client, const uint8_t *public_key, const uint8_t *comp_public_key) +{ + return is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT) && + is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT) || + id_closest(comp_public_key, client->public_key, public_key) == 2; +} + +static void sort_client_list(Client_data *list, unsigned int length, const uint8_t *comp_public_key) +{ + // Pass comp_public_key to qsort with each Client_data entry, so the + // comparison function can use it as the base of comparison. + VLA(DHT_Cmp_data, cmp_list, length); + + for (uint32_t i = 0; i < length; i++) { + cmp_list[i].base_public_key = comp_public_key; + cmp_list[i].entry = list[i]; + } + + qsort(cmp_list, length, sizeof(DHT_Cmp_data), cmp_dht_entry); + + for (uint32_t i = 0; i < length; i++) { + list[i] = cmp_list[i].entry; + } +} + +static void update_client_with_reset(Client_data *client, const IP_Port *ip_port) +{ + IPPTsPng *ipptp_write = NULL; + IPPTsPng *ipptp_clear = NULL; + + if (ip_port->ip.family == TOX_AF_INET) { + ipptp_write = &client->assoc4; + ipptp_clear = &client->assoc6; + } else { + ipptp_write = &client->assoc6; + ipptp_clear = &client->assoc4; + } + + ipptp_write->ip_port = *ip_port; + ipptp_write->timestamp = unix_time(); + + ip_reset(&ipptp_write->ret_ip_port.ip); + ipptp_write->ret_ip_port.port = 0; + ipptp_write->ret_timestamp = 0; + + /* zero out other address */ + memset(ipptp_clear, 0, sizeof(*ipptp_clear)); +} + +/* Replace a first bad (or empty) node with this one + * or replace a possibly bad node (tests failed or not done yet) + * that is further than any other in the list + * from the comp_public_key + * or replace a good node that is further + * than any other in the list from the comp_public_key + * and further than public_key. + * + * Do not replace any node if the list has no bad or possibly bad nodes + * and all nodes in the list are closer to comp_public_key + * than public_key. + * + * returns True(1) when the item was stored, False(0) otherwise */ +static int replace_all(Client_data *list, + uint16_t length, + const uint8_t *public_key, + IP_Port ip_port, + const uint8_t *comp_public_key) +{ + if ((ip_port.ip.family != TOX_AF_INET) && (ip_port.ip.family != TOX_AF_INET6)) { + return 0; + } + + if (!store_node_ok(&list[1], public_key, comp_public_key) && + !store_node_ok(&list[0], public_key, comp_public_key)) { + return 0; + } + + sort_client_list(list, length, comp_public_key); + + Client_data *client = &list[0]; + id_copy(client->public_key, public_key); + + update_client_with_reset(client, &ip_port); + return 1; +} + +/* Add node to close list. + * + * simulate is set to 1 if we want to check if a node can be added to the list without adding it. + * + * return -1 on failure. + * return 0 on success. + */ +static int add_to_close(DHT *dht, const uint8_t *public_key, IP_Port ip_port, bool simulate) +{ + unsigned int index = bit_by_bit_cmp(public_key, dht->self_public_key); + + if (index >= LCLIENT_LENGTH) { + index = LCLIENT_LENGTH - 1; + } + + for (uint32_t i = 0; i < LCLIENT_NODES; ++i) { + /* TODO(iphydf): write bounds checking test to catch the case that + * index is left as >= LCLIENT_LENGTH */ + Client_data *client = &dht->close_clientlist[(index * LCLIENT_NODES) + i]; + + if (!is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT) || + !is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT)) { + continue; + } + + if (simulate) { + return 0; + } + + id_copy(client->public_key, public_key); + update_client_with_reset(client, &ip_port); + return 0; + } + + return -1; +} + +/* Return 1 if node can be added to close list, 0 if it can't. + */ +bool node_addable_to_close_list(DHT *dht, const uint8_t *public_key, IP_Port ip_port) +{ + return add_to_close(dht, public_key, ip_port, 1) == 0; +} + +static bool is_pk_in_client_list(Client_data *list, unsigned int client_list_length, const uint8_t *public_key, + IP_Port ip_port) +{ + uint32_t index = index_of_client_pk(list, client_list_length, public_key); + + if (index == UINT32_MAX) { + return 0; + } + + const IPPTsPng *assoc = ip_port.ip.family == TOX_AF_INET ? + &list[index].assoc4 : + &list[index].assoc6; + + return !is_timeout(assoc->timestamp, BAD_NODE_TIMEOUT); +} + +static bool is_pk_in_close_list(DHT *dht, const uint8_t *public_key, IP_Port ip_port) +{ + unsigned int index = bit_by_bit_cmp(public_key, dht->self_public_key); + + if (index >= LCLIENT_LENGTH) { + index = LCLIENT_LENGTH - 1; + } + + return is_pk_in_client_list(dht->close_clientlist + index * LCLIENT_NODES, LCLIENT_NODES, public_key, ip_port); +} + +/* Check if the node obtained with a get_nodes with public_key should be pinged. + * NOTE: for best results call it after addto_lists; + * + * return 0 if the node should not be pinged. + * return 1 if it should. + */ +static unsigned int ping_node_from_getnodes_ok(DHT *dht, const uint8_t *public_key, IP_Port ip_port) +{ + bool ret = 0; + + if (add_to_close(dht, public_key, ip_port, 1) == 0) { + ret = 1; + } + + unsigned int *num = &dht->num_to_bootstrap; + uint32_t index = index_of_node_pk(dht->to_bootstrap, *num, public_key); + bool in_close_list = is_pk_in_close_list(dht, public_key, ip_port); + + if (ret && index == UINT32_MAX && !in_close_list) { + if (*num < MAX_CLOSE_TO_BOOTSTRAP_NODES) { + memcpy(dht->to_bootstrap[*num].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + dht->to_bootstrap[*num].ip_port = ip_port; + ++*num; + } else { + // TODO(irungentoo): ipv6 vs v4 + add_to_list(dht->to_bootstrap, MAX_CLOSE_TO_BOOTSTRAP_NODES, public_key, ip_port, dht->self_public_key); + } + } + + for (uint32_t i = 0; i < dht->num_friends; ++i) { + bool store_ok = 0; + + DHT_Friend *dht_friend = &dht->friends_list[i]; + + if (store_node_ok(&dht_friend->client_list[1], public_key, dht_friend->public_key)) { + store_ok = 1; + } + + if (store_node_ok(&dht_friend->client_list[0], public_key, dht_friend->public_key)) { + store_ok = 1; + } + + unsigned int *friend_num = &dht_friend->num_to_bootstrap; + const uint32_t index = index_of_node_pk(dht_friend->to_bootstrap, *friend_num, public_key); + const bool pk_in_list = is_pk_in_client_list(dht_friend->client_list, MAX_FRIEND_CLIENTS, public_key, ip_port); + + if (store_ok && index == UINT32_MAX && !pk_in_list) { + if (*friend_num < MAX_SENT_NODES) { + Node_format *format = &dht_friend->to_bootstrap[*friend_num]; + memcpy(format->public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + format->ip_port = ip_port; + ++*friend_num; + } else { + add_to_list(dht_friend->to_bootstrap, MAX_SENT_NODES, public_key, ip_port, dht_friend->public_key); + } + + ret = 1; + } + } + + return ret; +} + +/* Attempt to add client with ip_port and public_key to the friends client list + * and close_clientlist. + * + * returns 1+ if the item is used in any list, 0 else + */ +uint32_t addto_lists(DHT *dht, IP_Port ip_port, const uint8_t *public_key) +{ + uint32_t used = 0; + + /* convert IPv4-in-IPv6 to IPv4 */ + if ((ip_port.ip.family == TOX_AF_INET6) && IPV6_IPV4_IN_V6(ip_port.ip.ip6)) { + ip_port.ip.family = TOX_AF_INET; + ip_port.ip.ip4.uint32 = ip_port.ip.ip6.uint32[3]; + } + + /* NOTE: Current behavior if there are two clients with the same id is + * to replace the first ip by the second. + */ + const bool in_close_list = client_or_ip_port_in_list(dht->log, dht->close_clientlist, + LCLIENT_LIST, public_key, ip_port); + + /* add_to_close should be called only if !in_list (don't extract to variable) */ + if (in_close_list || add_to_close(dht, public_key, ip_port, 0)) { + used++; + } + + DHT_Friend *friend_foundip = 0; + + for (uint32_t i = 0; i < dht->num_friends; ++i) { + const bool in_list = client_or_ip_port_in_list(dht->log, dht->friends_list[i].client_list, + MAX_FRIEND_CLIENTS, public_key, ip_port); + + /* replace_all should be called only if !in_list (don't extract to variable) */ + if (in_list || replace_all(dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, public_key, + ip_port, dht->friends_list[i].public_key)) { + DHT_Friend *dht_friend = &dht->friends_list[i]; + + if (id_equal(public_key, dht_friend->public_key)) { + friend_foundip = dht_friend; + } + + used++; + } + } + + if (!friend_foundip) { + return used; + } + + for (uint32_t i = 0; i < friend_foundip->lock_count; ++i) { + if (friend_foundip->callbacks[i].ip_callback) { + friend_foundip->callbacks[i].ip_callback(friend_foundip->callbacks[i].data, + friend_foundip->callbacks[i].number, ip_port); + } + } + + return used; +} + +static bool update_client_data(Client_data *array, size_t size, IP_Port ip_port, const uint8_t *pk) +{ + uint64_t temp_time = unix_time(); + uint32_t index = index_of_client_pk(array, size, pk); + + if (index == UINT32_MAX) { + return false; + } + + Client_data *data = &array[index]; + IPPTsPng *assoc; + + if (ip_port.ip.family == TOX_AF_INET) { + assoc = &data->assoc4; + } else if (ip_port.ip.family == TOX_AF_INET6) { + assoc = &data->assoc6; + } else { + return true; + } + + assoc->ret_ip_port = ip_port; + assoc->ret_timestamp = temp_time; + return true; +} + +/* If public_key is a friend or us, update ret_ip_port + * nodepublic_key is the id of the node that sent us this info. + */ +static void returnedip_ports(DHT *dht, IP_Port ip_port, const uint8_t *public_key, const uint8_t *nodepublic_key) +{ + /* convert IPv4-in-IPv6 to IPv4 */ + if ((ip_port.ip.family == TOX_AF_INET6) && IPV6_IPV4_IN_V6(ip_port.ip.ip6)) { + ip_port.ip.family = TOX_AF_INET; + ip_port.ip.ip4.uint32 = ip_port.ip.ip6.uint32[3]; + } + + if (id_equal(public_key, dht->self_public_key)) { + update_client_data(dht->close_clientlist, LCLIENT_LIST, ip_port, nodepublic_key); + return; + } + + for (uint32_t i = 0; i < dht->num_friends; ++i) { + if (id_equal(public_key, dht->friends_list[i].public_key)) { + Client_data *client_list = dht->friends_list[i].client_list; + + if (update_client_data(client_list, MAX_FRIEND_CLIENTS, ip_port, nodepublic_key)) { + return; + } + } + } +} + +/* Send a getnodes request. + sendback_node is the node that it will send back the response to (set to NULL to disable this) */ +static int getnodes(DHT *dht, IP_Port ip_port, const uint8_t *public_key, const uint8_t *client_id, + const Node_format *sendback_node) +{ + /* Check if packet is going to be sent to ourself. */ + if (id_equal(public_key, dht->self_public_key)) { + return -1; + } + + uint8_t plain_message[sizeof(Node_format) * 2] = {0}; + + Node_format receiver; + memcpy(receiver.public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + receiver.ip_port = ip_port; + memcpy(plain_message, &receiver, sizeof(receiver)); + + uint64_t ping_id = 0; + + if (sendback_node != NULL) { + memcpy(plain_message + sizeof(receiver), sendback_node, sizeof(Node_format)); + ping_id = ping_array_add(&dht->dht_harden_ping_array, plain_message, sizeof(plain_message)); + } else { + ping_id = ping_array_add(&dht->dht_ping_array, plain_message, sizeof(receiver)); + } + + if (ping_id == 0) { + return -1; + } + + uint8_t plain[CRYPTO_PUBLIC_KEY_SIZE + sizeof(ping_id)]; + uint8_t data[1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + sizeof(plain) + CRYPTO_MAC_SIZE]; + + memcpy(plain, client_id, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(plain + CRYPTO_PUBLIC_KEY_SIZE, &ping_id, sizeof(ping_id)); + + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + DHT_get_shared_key_sent(dht, shared_key, public_key); + + int len = DHT_create_packet(dht->self_public_key, shared_key, NET_PACKET_GET_NODES, + plain, sizeof(plain), data); + + if (len != sizeof(data)) { + return -1; + } + + return sendpacket(dht->net, ip_port, data, len); +} + +/* Send a send nodes response: message for IPv6 nodes */ +static int sendnodes_ipv6(const DHT *dht, IP_Port ip_port, const uint8_t *public_key, const uint8_t *client_id, + const uint8_t *sendback_data, uint16_t length, const uint8_t *shared_encryption_key) +{ + /* Check if packet is going to be sent to ourself. */ + if (id_equal(public_key, dht->self_public_key)) { + return -1; + } + + if (length != sizeof(uint64_t)) { + return -1; + } + + size_t Node_format_size = sizeof(Node_format); + + Node_format nodes_list[MAX_SENT_NODES]; + uint32_t num_nodes = get_close_nodes(dht, client_id, nodes_list, 0, LAN_ip(ip_port.ip) == 0, 1); + + VLA(uint8_t, plain, 1 + Node_format_size * MAX_SENT_NODES + length); + + int nodes_length = 0; + + if (num_nodes) { + nodes_length = pack_nodes(plain + 1, Node_format_size * MAX_SENT_NODES, nodes_list, num_nodes); + + if (nodes_length <= 0) { + return -1; + } + } + + plain[0] = num_nodes; + memcpy(plain + 1 + nodes_length, sendback_data, length); + + const uint32_t crypto_size = 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE; + VLA(uint8_t, data, 1 + nodes_length + length + crypto_size); + + int len = DHT_create_packet(dht->self_public_key, shared_encryption_key, NET_PACKET_SEND_NODES_IPV6, + plain, 1 + nodes_length + length, data); + + if (len != SIZEOF_VLA(data)) { + return -1; + } + + return sendpacket(dht->net, ip_port, data, len); +} + +#define CRYPTO_NODE_SIZE (CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint64_t)) + +static int handle_getnodes(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + if (length != (CRYPTO_SIZE + CRYPTO_MAC_SIZE + sizeof(uint64_t))) { + return 1; + } + + DHT *dht = (DHT *)object; + + /* Check if packet is from ourself. */ + if (id_equal(packet + 1, dht->self_public_key)) { + return 1; + } + + uint8_t plain[CRYPTO_NODE_SIZE]; + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + + DHT_get_shared_key_recv(dht, shared_key, packet + 1); + int len = decrypt_data_symmetric(shared_key, + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, + CRYPTO_NODE_SIZE + CRYPTO_MAC_SIZE, + plain); + + if (len != CRYPTO_NODE_SIZE) { + return 1; + } + + sendnodes_ipv6(dht, source, packet + 1, plain, plain + CRYPTO_PUBLIC_KEY_SIZE, sizeof(uint64_t), shared_key); + + add_to_ping(dht->ping, packet + 1, source); + + return 0; +} +/* return 0 if no + return 1 if yes */ +static uint8_t sent_getnode_to_node(DHT *dht, const uint8_t *public_key, IP_Port node_ip_port, uint64_t ping_id, + Node_format *sendback_node) +{ + uint8_t data[sizeof(Node_format) * 2]; + + if (ping_array_check(data, sizeof(data), &dht->dht_ping_array, ping_id) == sizeof(Node_format)) { + memset(sendback_node, 0, sizeof(Node_format)); + } else if (ping_array_check(data, sizeof(data), &dht->dht_harden_ping_array, ping_id) == sizeof(data)) { + memcpy(sendback_node, data + sizeof(Node_format), sizeof(Node_format)); + } else { + return 0; + } + + Node_format test; + memcpy(&test, data, sizeof(Node_format)); + + if (!ipport_equal(&test.ip_port, &node_ip_port) || !id_equal(test.public_key, public_key)) { + return 0; + } + + return 1; +} + +/* Function is needed in following functions. */ +static int send_hardening_getnode_res(const DHT *dht, const Node_format *sendto, const uint8_t *queried_client_id, + const uint8_t *nodes_data, uint16_t nodes_data_length); + +static int handle_sendnodes_core(void *object, IP_Port source, const uint8_t *packet, uint16_t length, + Node_format *plain_nodes, uint16_t size_plain_nodes, uint32_t *num_nodes_out) +{ + DHT *dht = (DHT *)object; + uint32_t cid_size = 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + 1 + sizeof(uint64_t) + CRYPTO_MAC_SIZE; + + if (length < cid_size) { /* too short */ + return 1; + } + + uint32_t data_size = length - cid_size; + + if (data_size == 0) { + return 1; + } + + if (data_size > sizeof(Node_format) * MAX_SENT_NODES) { /* invalid length */ + return 1; + } + + VLA(uint8_t, plain, 1 + data_size + sizeof(uint64_t)); + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + DHT_get_shared_key_sent(dht, shared_key, packet + 1); + int len = decrypt_data_symmetric( + shared_key, + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, + 1 + data_size + sizeof(uint64_t) + CRYPTO_MAC_SIZE, + plain); + + if ((unsigned int)len != SIZEOF_VLA(plain)) { + return 1; + } + + if (plain[0] > size_plain_nodes) { + return 1; + } + + Node_format sendback_node; + + uint64_t ping_id; + memcpy(&ping_id, plain + 1 + data_size, sizeof(ping_id)); + + if (!sent_getnode_to_node(dht, packet + 1, source, ping_id, &sendback_node)) { + return 1; + } + + uint16_t length_nodes = 0; + int num_nodes = unpack_nodes(plain_nodes, plain[0], &length_nodes, plain + 1, data_size, 0); + + if (length_nodes != data_size) { + return 1; + } + + if (num_nodes != plain[0]) { + return 1; + } + + if (num_nodes < 0) { + return 1; + } + + /* store the address the *request* was sent to */ + addto_lists(dht, source, packet + 1); + + *num_nodes_out = num_nodes; + + send_hardening_getnode_res(dht, &sendback_node, packet + 1, plain + 1, data_size); + return 0; +} + +static int handle_sendnodes_ipv6(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + DHT *dht = (DHT *)object; + Node_format plain_nodes[MAX_SENT_NODES]; + uint32_t num_nodes; + + if (handle_sendnodes_core(object, source, packet, length, plain_nodes, MAX_SENT_NODES, &num_nodes)) { + return 1; + } + + if (num_nodes == 0) { + return 0; + } + + for (uint32_t i = 0; i < num_nodes; i++) { + if (ipport_isset(&plain_nodes[i].ip_port)) { + ping_node_from_getnodes_ok(dht, plain_nodes[i].public_key, plain_nodes[i].ip_port); + returnedip_ports(dht, plain_nodes[i].ip_port, plain_nodes[i].public_key, packet + 1); + } + } + + return 0; +} + +/*----------------------------------------------------------------------------------*/ +/*------------------------END of packet handling functions--------------------------*/ + +int DHT_addfriend(DHT *dht, const uint8_t *public_key, void (*ip_callback)(void *data, int32_t number, IP_Port), + void *data, int32_t number, uint16_t *lock_count) +{ + uint32_t friend_num = index_of_friend_pk(dht->friends_list, dht->num_friends, public_key); + + uint16_t lock_num; + + if (friend_num != UINT32_MAX) { /* Is friend already in DHT? */ + DHT_Friend *dht_friend = &dht->friends_list[friend_num]; + + if (dht_friend->lock_count == DHT_FRIEND_MAX_LOCKS) { + return -1; + } + + lock_num = dht_friend->lock_count; + ++dht_friend->lock_count; + dht_friend->callbacks[lock_num].ip_callback = ip_callback; + dht_friend->callbacks[lock_num].data = data; + dht_friend->callbacks[lock_num].number = number; + + if (lock_count) { + *lock_count = lock_num + 1; + } + + return 0; + } + + DHT_Friend *temp = (DHT_Friend *)realloc(dht->friends_list, sizeof(DHT_Friend) * (dht->num_friends + 1)); + + if (temp == NULL) { + return -1; + } + + dht->friends_list = temp; + DHT_Friend *dht_friend = &dht->friends_list[dht->num_friends]; + memset(dht_friend, 0, sizeof(DHT_Friend)); + memcpy(dht_friend->public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + + dht_friend->nat.NATping_id = random_64b(); + ++dht->num_friends; + + lock_num = dht_friend->lock_count; + ++dht_friend->lock_count; + dht_friend->callbacks[lock_num].ip_callback = ip_callback; + dht_friend->callbacks[lock_num].data = data; + dht_friend->callbacks[lock_num].number = number; + + if (lock_count) { + *lock_count = lock_num + 1; + } + + dht_friend->num_to_bootstrap = get_close_nodes(dht, dht_friend->public_key, dht_friend->to_bootstrap, 0, 1, 0); + + return 0; +} + +int DHT_delfriend(DHT *dht, const uint8_t *public_key, uint16_t lock_count) +{ + uint32_t friend_num = index_of_friend_pk(dht->friends_list, dht->num_friends, public_key); + + if (friend_num == UINT32_MAX) { + return -1; + } + + DHT_Friend *dht_friend = &dht->friends_list[friend_num]; + --dht_friend->lock_count; + + if (dht_friend->lock_count && lock_count) { /* DHT friend is still in use.*/ + --lock_count; + dht_friend->callbacks[lock_count].ip_callback = NULL; + dht_friend->callbacks[lock_count].data = NULL; + dht_friend->callbacks[lock_count].number = 0; + return 0; + } + + --dht->num_friends; + + if (dht->num_friends != friend_num) { + memcpy(&dht->friends_list[friend_num], + &dht->friends_list[dht->num_friends], + sizeof(DHT_Friend)); + } + + if (dht->num_friends == 0) { + free(dht->friends_list); + dht->friends_list = NULL; + return 0; + } + + DHT_Friend *temp = (DHT_Friend *)realloc(dht->friends_list, sizeof(DHT_Friend) * (dht->num_friends)); + + if (temp == NULL) { + return -1; + } + + dht->friends_list = temp; + return 0; +} + +/* TODO(irungentoo): Optimize this. */ +int DHT_getfriendip(const DHT *dht, const uint8_t *public_key, IP_Port *ip_port) +{ + ip_reset(&ip_port->ip); + ip_port->port = 0; + + uint32_t friend_index = index_of_friend_pk(dht->friends_list, dht->num_friends, public_key); + + if (friend_index == UINT32_MAX) { + return -1; + } + + DHT_Friend *frnd = &dht->friends_list[friend_index]; + uint32_t client_index = index_of_client_pk(frnd->client_list, MAX_FRIEND_CLIENTS, public_key); + + if (client_index == -1) { + return 0; + } + + Client_data *client = &frnd->client_list[client_index]; + IPPTsPng *assocs[ASSOC_COUNT] = { &client->assoc6, &client->assoc4 }; + + for (size_t i = 0; i < ASSOC_COUNT; i++) { + IPPTsPng *assoc = assocs[i]; + + if (!is_timeout(assoc->timestamp, BAD_NODE_TIMEOUT)) { + *ip_port = assoc->ip_port; + return 1; + } + } + + return -1; +} + +/* returns number of nodes not in kill-timeout */ +static uint8_t do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, const uint8_t *public_key, + Client_data *list, uint32_t list_count, uint32_t *bootstrap_times, bool sortable) +{ + uint8_t not_kill = 0; + uint64_t temp_time = unix_time(); + + uint32_t num_nodes = 0; + VLA(Client_data *, client_list, list_count * 2); + VLA(IPPTsPng *, assoc_list, list_count * 2); + unsigned int sort = 0; + bool sort_ok = 0; + + for (uint32_t i = 0; i < list_count; i++) { + /* If node is not dead. */ + Client_data *client = &list[i]; + + IPPTsPng *assocs[ASSOC_COUNT] = { &client->assoc6, &client->assoc4 }; + + for (size_t i = 0; i < ASSOC_COUNT; i++) { + IPPTsPng *assoc = assocs[i]; + + if (!is_timeout(assoc->timestamp, KILL_NODE_TIMEOUT)) { + sort = 0; + not_kill++; + + if (is_timeout(assoc->last_pinged, PING_INTERVAL)) { + getnodes(dht, assoc->ip_port, client->public_key, public_key, NULL); + assoc->last_pinged = temp_time; + } + + /* If node is good. */ + if (!is_timeout(assoc->timestamp, BAD_NODE_TIMEOUT)) { + client_list[num_nodes] = client; + assoc_list[num_nodes] = assoc; + ++num_nodes; + } + } else { + ++sort; + + /* Timed out should be at beginning, if they are not, sort the list. */ + if (sort > 1 && sort < (((i + 1) * 2) - 1)) { + sort_ok = 1; + } + } + } + } + + if (sortable && sort_ok) { + sort_client_list(list, list_count, public_key); + } + + if ((num_nodes != 0) && (is_timeout(*lastgetnode, GET_NODE_INTERVAL) || *bootstrap_times < MAX_BOOTSTRAP_TIMES)) { + uint32_t rand_node = rand() % (num_nodes); + + if ((num_nodes - 1) != rand_node) { + rand_node += rand() % (num_nodes - (rand_node + 1)); + } + + getnodes(dht, assoc_list[rand_node]->ip_port, client_list[rand_node]->public_key, public_key, NULL); + + *lastgetnode = temp_time; + ++*bootstrap_times; + } + + return not_kill; +} + +/* Ping each client in the "friends" list every PING_INTERVAL seconds. Send a get nodes request + * every GET_NODE_INTERVAL seconds to a random good node for each "friend" in our "friends" list. + */ +static void do_DHT_friends(DHT *dht) +{ + for (size_t i = 0; i < dht->num_friends; ++i) { + DHT_Friend *dht_friend = &dht->friends_list[i]; + + for (size_t j = 0; j < dht_friend->num_to_bootstrap; ++j) { + getnodes(dht, dht_friend->to_bootstrap[j].ip_port, dht_friend->to_bootstrap[j].public_key, dht_friend->public_key, + NULL); + } + + dht_friend->num_to_bootstrap = 0; + + do_ping_and_sendnode_requests(dht, &dht_friend->lastgetnode, dht_friend->public_key, dht_friend->client_list, + MAX_FRIEND_CLIENTS, + &dht_friend->bootstrap_times, 1); + } +} + +/* Ping each client in the close nodes list every PING_INTERVAL seconds. + * Send a get nodes request every GET_NODE_INTERVAL seconds to a random good node in the list. + */ +static void do_Close(DHT *dht) +{ + for (size_t i = 0; i < dht->num_to_bootstrap; ++i) { + getnodes(dht, dht->to_bootstrap[i].ip_port, dht->to_bootstrap[i].public_key, dht->self_public_key, NULL); + } + + dht->num_to_bootstrap = 0; + + uint8_t not_killed = do_ping_and_sendnode_requests(dht, &dht->close_lastgetnodes, dht->self_public_key, + dht->close_clientlist, LCLIENT_LIST, &dht->close_bootstrap_times, 0); + + if (!not_killed) { + /* all existing nodes are at least KILL_NODE_TIMEOUT, + * which means we are mute, as we only send packets to + * nodes NOT in KILL_NODE_TIMEOUT + * + * so: reset all nodes to be BAD_NODE_TIMEOUT, but not + * KILL_NODE_TIMEOUT, so we at least keep trying pings */ + uint64_t badonly = unix_time() - BAD_NODE_TIMEOUT; + + for (size_t i = 0; i < LCLIENT_LIST; i++) { + Client_data *client = &dht->close_clientlist[i]; + + IPPTsPng *assocs[ASSOC_COUNT] = { &client->assoc6, &client->assoc4 }; + + for (size_t j = 0; j < ASSOC_COUNT; j++) { + IPPTsPng *assoc = assocs[j]; + + if (assoc->timestamp) { + assoc->timestamp = badonly; + } + } + } + } +} + +void DHT_getnodes(DHT *dht, const IP_Port *from_ipp, const uint8_t *from_id, const uint8_t *which_id) +{ + getnodes(dht, *from_ipp, from_id, which_id, NULL); +} + +void DHT_bootstrap(DHT *dht, IP_Port ip_port, const uint8_t *public_key) +{ + getnodes(dht, ip_port, public_key, dht->self_public_key, NULL); +} +int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled, + uint16_t port, const uint8_t *public_key) +{ + IP_Port ip_port_v64; + IP *ip_extra = NULL; + IP_Port ip_port_v4; + ip_init(&ip_port_v64.ip, ipv6enabled); + + if (ipv6enabled) { + /* setup for getting BOTH: an IPv6 AND an IPv4 address */ + ip_port_v64.ip.family = TOX_AF_UNSPEC; + ip_reset(&ip_port_v4.ip); + ip_extra = &ip_port_v4.ip; + } + + if (addr_resolve_or_parse_ip(address, &ip_port_v64.ip, ip_extra)) { + ip_port_v64.port = port; + DHT_bootstrap(dht, ip_port_v64, public_key); + + if ((ip_extra != NULL) && ip_isset(ip_extra)) { + ip_port_v4.port = port; + DHT_bootstrap(dht, ip_port_v4, public_key); + } + + return 1; + } + + return 0; +} + +/* Send the given packet to node with public_key + * + * return -1 if failure. + */ +int route_packet(const DHT *dht, const uint8_t *public_key, const uint8_t *packet, uint16_t length) +{ + for (uint32_t i = 0; i < LCLIENT_LIST; ++i) { + if (id_equal(public_key, dht->close_clientlist[i].public_key)) { + const Client_data *client = &dht->close_clientlist[i]; + const IPPTsPng *assocs[ASSOC_COUNT] = { &client->assoc6, &client->assoc4 }; + + for (size_t j = 0; j < ASSOC_COUNT; j++) { + const IPPTsPng *assoc = assocs[j]; + + if (ip_isset(&assoc->ip_port.ip)) { + return sendpacket(dht->net, assoc->ip_port, packet, length); + } + } + + break; + } + } + + return -1; +} + +/* Puts all the different ips returned by the nodes for a friend_num into array ip_portlist. + * ip_portlist must be at least MAX_FRIEND_CLIENTS big. + * + * return the number of ips returned. + * return 0 if we are connected to friend or if no ips were found. + * return -1 if no such friend. + */ +static int friend_iplist(const DHT *dht, IP_Port *ip_portlist, uint16_t friend_num) +{ + if (friend_num >= dht->num_friends) { + return -1; + } + + DHT_Friend *dht_friend = &dht->friends_list[friend_num]; + Client_data *client; + IP_Port ipv4s[MAX_FRIEND_CLIENTS]; + int num_ipv4s = 0; + IP_Port ipv6s[MAX_FRIEND_CLIENTS]; + int num_ipv6s = 0; + + for (size_t i = 0; i < MAX_FRIEND_CLIENTS; ++i) { + client = &(dht_friend->client_list[i]); + + /* If ip is not zero and node is good. */ + if (ip_isset(&client->assoc4.ret_ip_port.ip) && !is_timeout(client->assoc4.ret_timestamp, BAD_NODE_TIMEOUT)) { + ipv4s[num_ipv4s] = client->assoc4.ret_ip_port; + ++num_ipv4s; + } + + if (ip_isset(&client->assoc6.ret_ip_port.ip) && !is_timeout(client->assoc6.ret_timestamp, BAD_NODE_TIMEOUT)) { + ipv6s[num_ipv6s] = client->assoc6.ret_ip_port; + ++num_ipv6s; + } + + if (id_equal(client->public_key, dht_friend->public_key)) { + if (!is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT) + || !is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT)) { + return 0; /* direct connectivity */ + } + } + } + +#ifdef FRIEND_IPLIST_PAD + memcpy(ip_portlist, ipv6s, num_ipv6s * sizeof(IP_Port)); + + if (num_ipv6s == MAX_FRIEND_CLIENTS) { + return MAX_FRIEND_CLIENTS; + } + + int num_ipv4s_used = MAX_FRIEND_CLIENTS - num_ipv6s; + + if (num_ipv4s_used > num_ipv4s) { + num_ipv4s_used = num_ipv4s; + } + + memcpy(&ip_portlist[num_ipv6s], ipv4s, num_ipv4s_used * sizeof(IP_Port)); + return num_ipv6s + num_ipv4s_used; + +#else /* !FRIEND_IPLIST_PAD */ + + /* there must be some secret reason why we can't pad the longer list + * with the shorter one... + */ + if (num_ipv6s >= num_ipv4s) { + memcpy(ip_portlist, ipv6s, num_ipv6s * sizeof(IP_Port)); + return num_ipv6s; + } + + memcpy(ip_portlist, ipv4s, num_ipv4s * sizeof(IP_Port)); + return num_ipv4s; + +#endif /* !FRIEND_IPLIST_PAD */ +} + + +/* Send the following packet to everyone who tells us they are connected to friend_id. + * + * return ip for friend. + * return number of nodes the packet was sent to. (Only works if more than (MAX_FRIEND_CLIENTS / 4). + */ +int route_tofriend(const DHT *dht, const uint8_t *friend_id, const uint8_t *packet, uint16_t length) +{ + uint32_t num = index_of_friend_pk(dht->friends_list, dht->num_friends, friend_id); + + if (num == UINT32_MAX) { + return 0; + } + + uint32_t sent = 0; + uint8_t friend_sent[MAX_FRIEND_CLIENTS] = {0}; + + IP_Port ip_list[MAX_FRIEND_CLIENTS]; + int ip_num = friend_iplist(dht, ip_list, num); + + if (ip_num < (MAX_FRIEND_CLIENTS / 4)) { + return 0; /* Reason for that? */ + } + + DHT_Friend *dht_friend = &dht->friends_list[num]; + Client_data *client; + + /* extra legwork, because having the outside allocating the space for us + * is *usually* good(tm) (bites us in the behind in this case though) */ + + for (uint32_t i = 0; i < MAX_FRIEND_CLIENTS; ++i) { + if (friend_sent[i]) {/* Send one packet per client.*/ + continue; + } + + client = &dht_friend->client_list[i]; + + const IPPTsPng *assocs[ASSOC_COUNT] = { &client->assoc4, &client->assoc6 }; + + for (size_t j = 0; j < ASSOC_COUNT; j++) { + const IPPTsPng *assoc = assocs[j]; + + /* If ip is not zero and node is good. */ + if (ip_isset(&assoc->ret_ip_port.ip) && !is_timeout(assoc->ret_timestamp, BAD_NODE_TIMEOUT)) { + int retval = sendpacket(dht->net, assoc->ip_port, packet, length); + + if ((unsigned int)retval == length) { + ++sent; + friend_sent[i] = 1; + } + } + } + } + + return sent; +} + +/* Send the following packet to one random person who tells us they are connected to friend_id. + * + * return number of nodes the packet was sent to. + */ +static int routeone_tofriend(DHT *dht, const uint8_t *friend_id, const uint8_t *packet, uint16_t length) +{ + uint32_t num = index_of_friend_pk(dht->friends_list, dht->num_friends, friend_id); + + if (num == UINT32_MAX) { + return 0; + } + + DHT_Friend *dht_friend = &dht->friends_list[num]; + Client_data *client; + + IP_Port ip_list[MAX_FRIEND_CLIENTS * 2]; + int n = 0; + + /* extra legwork, because having the outside allocating the space for us + * is *usually* good(tm) (bites us in the behind in this case though) */ + + for (uint32_t i = 0; i < MAX_FRIEND_CLIENTS; ++i) { + client = &dht_friend->client_list[i]; + + const IPPTsPng *assocs[ASSOC_COUNT] = { &client->assoc4, &client->assoc6 }; + + for (size_t j = 0; j < ASSOC_COUNT; j++) { + const IPPTsPng *assoc = assocs[j]; + + /* If ip is not zero and node is good. */ + if (ip_isset(&assoc->ret_ip_port.ip) && !is_timeout(assoc->ret_timestamp, BAD_NODE_TIMEOUT)) { + ip_list[n] = assoc->ip_port; + ++n; + } + } + } + + if (n < 1) { + return 0; + } + + int retval = sendpacket(dht->net, ip_list[rand() % n], packet, length); + + if ((unsigned int)retval == length) { + return 1; + } + + return 0; +} + +/*----------------------------------------------------------------------------------*/ +/*---------------------BEGINNING OF NAT PUNCHING FUNCTIONS--------------------------*/ + +static int send_NATping(DHT *dht, const uint8_t *public_key, uint64_t ping_id, uint8_t type) +{ + uint8_t data[sizeof(uint64_t) + 1]; + uint8_t packet[MAX_CRYPTO_REQUEST_SIZE]; + + int num = 0; + + data[0] = type; + memcpy(data + 1, &ping_id, sizeof(uint64_t)); + /* 254 is NAT ping request packet id */ + int len = create_request(dht->self_public_key, dht->self_secret_key, packet, public_key, data, + sizeof(uint64_t) + 1, CRYPTO_PACKET_NAT_PING); + + if (len == -1) { + return -1; + } + + if (type == 0) { /* If packet is request use many people to route it. */ + num = route_tofriend(dht, public_key, packet, len); + } else if (type == 1) { /* If packet is response use only one person to route it */ + num = routeone_tofriend(dht, public_key, packet, len); + } + + if (num == 0) { + return -1; + } + + return num; +} + +/* Handle a received ping request for. */ +static int handle_NATping(void *object, IP_Port source, const uint8_t *source_pubkey, const uint8_t *packet, + uint16_t length, void *userdata) +{ + if (length != sizeof(uint64_t) + 1) { + return 1; + } + + DHT *dht = (DHT *)object; + uint64_t ping_id; + memcpy(&ping_id, packet + 1, sizeof(uint64_t)); + + uint32_t friendnumber = index_of_friend_pk(dht->friends_list, dht->num_friends, source_pubkey); + + if (friendnumber == UINT32_MAX) { + return 1; + } + + DHT_Friend *dht_friend = &dht->friends_list[friendnumber]; + + if (packet[0] == NAT_PING_REQUEST) { + /* 1 is reply */ + send_NATping(dht, source_pubkey, ping_id, NAT_PING_RESPONSE); + dht_friend->nat.recvNATping_timestamp = unix_time(); + return 0; + } + + if (packet[0] == NAT_PING_RESPONSE) { + if (dht_friend->nat.NATping_id == ping_id) { + dht_friend->nat.NATping_id = random_64b(); + dht_friend->nat.hole_punching = 1; + return 0; + } + } + + return 1; +} + +/* Get the most common ip in the ip_portlist. + * Only return ip if it appears in list min_num or more. + * len must not be bigger than MAX_FRIEND_CLIENTS. + * + * return ip of 0 if failure. + */ +static IP NAT_commonip(IP_Port *ip_portlist, uint16_t len, uint16_t min_num) +{ + IP zero; + ip_reset(&zero); + + if (len > MAX_FRIEND_CLIENTS) { + return zero; + } + + uint16_t numbers[MAX_FRIEND_CLIENTS] = {0}; + + for (uint32_t i = 0; i < len; ++i) { + for (uint32_t j = 0; j < len; ++j) { + if (ip_equal(&ip_portlist[i].ip, &ip_portlist[j].ip)) { + ++numbers[i]; + } + } + + if (numbers[i] >= min_num) { + return ip_portlist[i].ip; + } + } + + return zero; +} + +/* Return all the ports for one ip in a list. + * portlist must be at least len long, + * where len is the length of ip_portlist. + * + * return number of ports and puts the list of ports in portlist. + */ +static uint16_t NAT_getports(uint16_t *portlist, IP_Port *ip_portlist, uint16_t len, IP ip) +{ + uint16_t num = 0; + + for (uint32_t i = 0; i < len; ++i) { + if (ip_equal(&ip_portlist[i].ip, &ip)) { + portlist[num] = net_ntohs(ip_portlist[i].port); + ++num; + } + } + + return num; +} + +static void punch_holes(DHT *dht, IP ip, uint16_t *port_list, uint16_t numports, uint16_t friend_num) +{ + if (!dht->hole_punching_enabled) { + return; + } + + if (numports > MAX_FRIEND_CLIENTS || numports == 0) { + return; + } + + uint16_t first_port = port_list[0]; + uint32_t i; + + for (i = 0; i < numports; ++i) { + if (first_port != port_list[i]) { + break; + } + } + + if (i == numports) { /* If all ports are the same, only try that one port. */ + IP_Port pinging; + ip_copy(&pinging.ip, &ip); + pinging.port = net_htons(first_port); + send_ping_request(dht->ping, pinging, dht->friends_list[friend_num].public_key); + } else { + for (i = 0; i < MAX_PUNCHING_PORTS; ++i) { + /* TODO(irungentoo): Improve port guessing algorithm. */ + uint32_t it = i + dht->friends_list[friend_num].nat.punching_index; + int8_t sign = (it % 2) ? -1 : 1; + uint32_t delta = sign * (it / (2 * numports)); + uint32_t index = (it / 2) % numports; + uint16_t port = port_list[index] + delta; + IP_Port pinging; + ip_copy(&pinging.ip, &ip); + pinging.port = net_htons(port); + send_ping_request(dht->ping, pinging, dht->friends_list[friend_num].public_key); + } + + dht->friends_list[friend_num].nat.punching_index += i; + } + + if (dht->friends_list[friend_num].nat.tries > MAX_NORMAL_PUNCHING_TRIES) { + uint16_t port = 1024; + IP_Port pinging; + ip_copy(&pinging.ip, &ip); + + for (i = 0; i < MAX_PUNCHING_PORTS; ++i) { + uint32_t it = i + dht->friends_list[friend_num].nat.punching_index2; + pinging.port = net_htons(port + it); + send_ping_request(dht->ping, pinging, dht->friends_list[friend_num].public_key); + } + + dht->friends_list[friend_num].nat.punching_index2 += i - (MAX_PUNCHING_PORTS / 2); + } + + ++dht->friends_list[friend_num].nat.tries; +} + +static void do_NAT(DHT *dht) +{ + uint64_t temp_time = unix_time(); + + for (uint32_t i = 0; i < dht->num_friends; ++i) { + IP_Port ip_list[MAX_FRIEND_CLIENTS]; + int num = friend_iplist(dht, ip_list, i); + + /* If already connected or friend is not online don't try to hole punch. */ + if (num < MAX_FRIEND_CLIENTS / 2) { + continue; + } + + if (dht->friends_list[i].nat.NATping_timestamp + PUNCH_INTERVAL < temp_time) { + send_NATping(dht, dht->friends_list[i].public_key, dht->friends_list[i].nat.NATping_id, NAT_PING_REQUEST); + dht->friends_list[i].nat.NATping_timestamp = temp_time; + } + + if (dht->friends_list[i].nat.hole_punching == 1 && + dht->friends_list[i].nat.punching_timestamp + PUNCH_INTERVAL < temp_time && + dht->friends_list[i].nat.recvNATping_timestamp + PUNCH_INTERVAL * 2 >= temp_time) { + + IP ip = NAT_commonip(ip_list, num, MAX_FRIEND_CLIENTS / 2); + + if (!ip_isset(&ip)) { + continue; + } + + if (dht->friends_list[i].nat.punching_timestamp + PUNCH_RESET_TIME < temp_time) { + dht->friends_list[i].nat.tries = 0; + dht->friends_list[i].nat.punching_index = 0; + dht->friends_list[i].nat.punching_index2 = 0; + } + + uint16_t port_list[MAX_FRIEND_CLIENTS]; + uint16_t numports = NAT_getports(port_list, ip_list, num, ip); + punch_holes(dht, ip, port_list, numports, i); + + dht->friends_list[i].nat.punching_timestamp = temp_time; + dht->friends_list[i].nat.hole_punching = 0; + } + } +} + +/*----------------------------------------------------------------------------------*/ +/*-----------------------END OF NAT PUNCHING FUNCTIONS------------------------------*/ + +#define HARDREQ_DATA_SIZE 384 /* Attempt to prevent amplification/other attacks*/ + +#define CHECK_TYPE_ROUTE_REQ 0 +#define CHECK_TYPE_ROUTE_RES 1 +#define CHECK_TYPE_GETNODE_REQ 2 +#define CHECK_TYPE_GETNODE_RES 3 +#define CHECK_TYPE_TEST_REQ 4 +#define CHECK_TYPE_TEST_RES 5 + +#if DHT_HARDENING +static int send_hardening_req(DHT *dht, Node_format *sendto, uint8_t type, uint8_t *contents, uint16_t length) +{ + if (length > HARDREQ_DATA_SIZE - 1) { + return -1; + } + + uint8_t packet[MAX_CRYPTO_REQUEST_SIZE]; + uint8_t data[HARDREQ_DATA_SIZE] = {0}; + data[0] = type; + memcpy(data + 1, contents, length); + int len = create_request(dht->self_public_key, dht->self_secret_key, packet, sendto->public_key, data, + sizeof(data), CRYPTO_PACKET_HARDENING); + + if (len == -1) { + return -1; + } + + return sendpacket(dht->net, sendto->ip_port, packet, len); +} + +/* Send a get node hardening request */ +static int send_hardening_getnode_req(DHT *dht, Node_format *dest, Node_format *node_totest, uint8_t *search_id) +{ + uint8_t data[sizeof(Node_format) + CRYPTO_PUBLIC_KEY_SIZE]; + memcpy(data, node_totest, sizeof(Node_format)); + memcpy(data + sizeof(Node_format), search_id, CRYPTO_PUBLIC_KEY_SIZE); + return send_hardening_req(dht, dest, CHECK_TYPE_GETNODE_REQ, data, sizeof(Node_format) + CRYPTO_PUBLIC_KEY_SIZE); +} +#endif + +/* Send a get node hardening response */ +static int send_hardening_getnode_res(const DHT *dht, const Node_format *sendto, const uint8_t *queried_client_id, + const uint8_t *nodes_data, uint16_t nodes_data_length) +{ + if (!ip_isset(&sendto->ip_port.ip)) { + return -1; + } + + uint8_t packet[MAX_CRYPTO_REQUEST_SIZE]; + VLA(uint8_t, data, 1 + CRYPTO_PUBLIC_KEY_SIZE + nodes_data_length); + data[0] = CHECK_TYPE_GETNODE_RES; + memcpy(data + 1, queried_client_id, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(data + 1 + CRYPTO_PUBLIC_KEY_SIZE, nodes_data, nodes_data_length); + int len = create_request(dht->self_public_key, dht->self_secret_key, packet, sendto->public_key, data, + SIZEOF_VLA(data), CRYPTO_PACKET_HARDENING); + + if (len == -1) { + return -1; + } + + return sendpacket(dht->net, sendto->ip_port, packet, len); +} + +/* TODO(irungentoo): improve */ +static IPPTsPng *get_closelist_IPPTsPng(DHT *dht, const uint8_t *public_key, Family sa_family) +{ + for (uint32_t i = 0; i < LCLIENT_LIST; ++i) { + if (!id_equal(dht->close_clientlist[i].public_key, public_key)) { + continue; + } + + if (sa_family == TOX_AF_INET) { + return &dht->close_clientlist[i].assoc4; + } + + if (sa_family == TOX_AF_INET6) { + return &dht->close_clientlist[i].assoc6; + } + } + + return NULL; +} + +/* + * check how many nodes in nodes are also present in the closelist. + * TODO(irungentoo): make this function better. + */ +static uint32_t have_nodes_closelist(DHT *dht, Node_format *nodes, uint16_t num) +{ + uint32_t counter = 0; + + for (uint32_t i = 0; i < num; ++i) { + if (id_equal(nodes[i].public_key, dht->self_public_key)) { + ++counter; + continue; + } + + IPPTsPng *temp = get_closelist_IPPTsPng(dht, nodes[i].public_key, nodes[i].ip_port.ip.family); + + if (temp) { + if (!is_timeout(temp->timestamp, BAD_NODE_TIMEOUT)) { + ++counter; + } + } + } + + return counter; +} + +/* Interval in seconds between hardening checks */ +#define HARDENING_INTERVAL 120 +#define HARDEN_TIMEOUT 1200 + +/* Handle a received hardening packet */ +static int handle_hardening(void *object, IP_Port source, const uint8_t *source_pubkey, const uint8_t *packet, + uint16_t length, void *userdata) +{ + DHT *dht = (DHT *)object; + + if (length < 2) { + return 1; + } + + switch (packet[0]) { + case CHECK_TYPE_GETNODE_REQ: { + if (length != HARDREQ_DATA_SIZE) { + return 1; + } + + Node_format node, tocheck_node; + node.ip_port = source; + memcpy(node.public_key, source_pubkey, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(&tocheck_node, packet + 1, sizeof(Node_format)); + + if (getnodes(dht, tocheck_node.ip_port, tocheck_node.public_key, packet + 1 + sizeof(Node_format), &node) == -1) { + return 1; + } + + return 0; + } + + case CHECK_TYPE_GETNODE_RES: { + if (length <= CRYPTO_PUBLIC_KEY_SIZE + 1) { + return 1; + } + + if (length > 1 + CRYPTO_PUBLIC_KEY_SIZE + sizeof(Node_format) * MAX_SENT_NODES) { + return 1; + } + + uint16_t length_nodes = length - 1 - CRYPTO_PUBLIC_KEY_SIZE; + Node_format nodes[MAX_SENT_NODES]; + int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, 0, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, length_nodes, 0); + + /* TODO(irungentoo): MAX_SENT_NODES nodes should be returned at all times + (right now we have a small network size so it could cause problems for testing and etc..) */ + if (num_nodes <= 0) { + return 1; + } + + /* NOTE: This should work for now but should be changed to something better. */ + if (have_nodes_closelist(dht, nodes, num_nodes) < (uint32_t)((num_nodes + 2) / 2)) { + return 1; + } + + IPPTsPng *temp = get_closelist_IPPTsPng(dht, packet + 1, nodes[0].ip_port.ip.family); + + if (temp == NULL) { + return 1; + } + + if (is_timeout(temp->hardening.send_nodes_timestamp, HARDENING_INTERVAL)) { + return 1; + } + + if (!id_equal(temp->hardening.send_nodes_pingedid, source_pubkey)) { + return 1; + } + + /* If Nodes look good and the request checks out */ + temp->hardening.send_nodes_ok = 1; + return 0;/* success*/ + } + } + + return 1; +} + +#if DHT_HARDENING +/* Return a random node from all the nodes we are connected to. + * TODO(irungentoo): improve this function. + */ +static Node_format random_node(DHT *dht, Family sa_family) +{ + uint8_t id[CRYPTO_PUBLIC_KEY_SIZE]; + + for (uint32_t i = 0; i < CRYPTO_PUBLIC_KEY_SIZE / 4; ++i) { /* populate the id with pseudorandom bytes.*/ + uint32_t t = rand(); + memcpy(id + i * sizeof(t), &t, sizeof(t)); + } + + Node_format nodes_list[MAX_SENT_NODES]; + memset(nodes_list, 0, sizeof(nodes_list)); + uint32_t num_nodes = get_close_nodes(dht, id, nodes_list, sa_family, 1, 0); + + if (num_nodes == 0) { + return nodes_list[0]; + } + + return nodes_list[rand() % num_nodes]; +} +#endif + +/* Put up to max_num nodes in nodes from the closelist. + * + * return the number of nodes. + */ +static uint16_t list_nodes(Client_data *list, size_t length, Node_format *nodes, uint16_t max_num) +{ + if (max_num == 0) { + return 0; + } + + uint16_t count = 0; + + for (size_t i = length; i != 0; --i) { + IPPTsPng *assoc = NULL; + + if (!is_timeout(list[i - 1].assoc4.timestamp, BAD_NODE_TIMEOUT)) { + assoc = &list[i - 1].assoc4; + } + + if (!is_timeout(list[i - 1].assoc6.timestamp, BAD_NODE_TIMEOUT)) { + if (assoc == NULL) { + assoc = &list[i - 1].assoc6; + } else if (rand() % 2) { + assoc = &list[i - 1].assoc6; + } + } + + if (assoc != NULL) { + memcpy(nodes[count].public_key, list[i - 1].public_key, CRYPTO_PUBLIC_KEY_SIZE); + nodes[count].ip_port = assoc->ip_port; + ++count; + + if (count >= max_num) { + return count; + } + } + } + + return count; +} + +/* Put up to max_num nodes in nodes from the random friends. + * + * return the number of nodes. + */ +uint16_t randfriends_nodes(DHT *dht, Node_format *nodes, uint16_t max_num) +{ + if (max_num == 0) { + return 0; + } + + uint16_t count = 0; + unsigned int r = rand(); + + for (size_t i = 0; i < DHT_FAKE_FRIEND_NUMBER; ++i) { + count += list_nodes(dht->friends_list[(i + r) % DHT_FAKE_FRIEND_NUMBER].client_list, MAX_FRIEND_CLIENTS, nodes + count, + max_num - count); + + if (count >= max_num) { + break; + } + } + + return count; +} + +/* Put up to max_num nodes in nodes from the closelist. + * + * return the number of nodes. + */ +uint16_t closelist_nodes(DHT *dht, Node_format *nodes, uint16_t max_num) +{ + return list_nodes(dht->close_clientlist, LCLIENT_LIST, nodes, max_num); +} + +#if DHT_HARDENING +static void do_hardening(DHT *dht) +{ + for (uint32_t i = 0; i < LCLIENT_LIST * 2; ++i) { + IPPTsPng *cur_iptspng; + Family sa_family; + uint8_t *public_key = dht->close_clientlist[i / 2].public_key; + + if (i % 2 == 0) { + cur_iptspng = &dht->close_clientlist[i / 2].assoc4; + sa_family = TOX_AF_INET; + } else { + cur_iptspng = &dht->close_clientlist[i / 2].assoc6; + sa_family = TOX_AF_INET6; + } + + if (is_timeout(cur_iptspng->timestamp, BAD_NODE_TIMEOUT)) { + continue; + } + + if (cur_iptspng->hardening.send_nodes_ok == 0) { + if (is_timeout(cur_iptspng->hardening.send_nodes_timestamp, HARDENING_INTERVAL)) { + Node_format rand_node = random_node(dht, sa_family); + + if (!ipport_isset(&rand_node.ip_port)) { + continue; + } + + if (id_equal(public_key, rand_node.public_key)) { + continue; + } + + Node_format to_test; + to_test.ip_port = cur_iptspng->ip_port; + memcpy(to_test.public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + + // TODO(irungentoo): The search id should maybe not be ours? + if (send_hardening_getnode_req(dht, &rand_node, &to_test, dht->self_public_key) > 0) { + memcpy(cur_iptspng->hardening.send_nodes_pingedid, rand_node.public_key, CRYPTO_PUBLIC_KEY_SIZE); + cur_iptspng->hardening.send_nodes_timestamp = unix_time(); + } + } + } else { + if (is_timeout(cur_iptspng->hardening.send_nodes_timestamp, HARDEN_TIMEOUT)) { + cur_iptspng->hardening.send_nodes_ok = 0; + } + } + + // TODO(irungentoo): add the 2 other testers. + } +} +#endif + +/*----------------------------------------------------------------------------------*/ + +void cryptopacket_registerhandler(DHT *dht, uint8_t byte, cryptopacket_handler_callback cb, void *object) +{ + dht->cryptopackethandlers[byte].function = cb; + dht->cryptopackethandlers[byte].object = object; +} + +static int cryptopacket_handle(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + DHT *dht = (DHT *)object; + + assert(packet[0] == NET_PACKET_CRYPTO); + + if (length <= CRYPTO_PUBLIC_KEY_SIZE * 2 + CRYPTO_NONCE_SIZE + 1 + CRYPTO_MAC_SIZE || + length > MAX_CRYPTO_REQUEST_SIZE + CRYPTO_MAC_SIZE) { + return 1; + } + + // Check if request is for us. + if (id_equal(packet + 1, dht->self_public_key)) { + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t data[MAX_CRYPTO_REQUEST_SIZE]; + uint8_t number; + int len = handle_request(dht->self_public_key, dht->self_secret_key, public_key, data, &number, packet, length); + + if (len == -1 || len == 0) { + return 1; + } + + if (!dht->cryptopackethandlers[number].function) { + return 1; + } + + return dht->cryptopackethandlers[number].function(dht->cryptopackethandlers[number].object, source, public_key, + data, len, userdata); + } + + /* If request is not for us, try routing it. */ + int retval = route_packet(dht, packet + 1, packet, length); + + if ((unsigned int)retval == length) { + return 0; + } + + return 1; +} + +/*----------------------------------------------------------------------------------*/ + +DHT *new_DHT(Logger *log, Networking_Core *net, bool holepunching_enabled) +{ + /* init time */ + unix_time_update(); + + if (net == NULL) { + return NULL; + } + + DHT *dht = (DHT *)calloc(1, sizeof(DHT)); + + if (dht == NULL) { + return NULL; + } + + dht->log = log; + dht->net = net; + + dht->hole_punching_enabled = holepunching_enabled; + + dht->ping = new_ping(dht); + + if (dht->ping == NULL) { + kill_DHT(dht); + return NULL; + } + + networking_registerhandler(dht->net, NET_PACKET_GET_NODES, &handle_getnodes, dht); + networking_registerhandler(dht->net, NET_PACKET_SEND_NODES_IPV6, &handle_sendnodes_ipv6, dht); + networking_registerhandler(dht->net, NET_PACKET_CRYPTO, &cryptopacket_handle, dht); + cryptopacket_registerhandler(dht, CRYPTO_PACKET_NAT_PING, &handle_NATping, dht); + cryptopacket_registerhandler(dht, CRYPTO_PACKET_HARDENING, &handle_hardening, dht); + + new_symmetric_key(dht->secret_symmetric_key); + crypto_new_keypair(dht->self_public_key, dht->self_secret_key); + + ping_array_init(&dht->dht_ping_array, DHT_PING_ARRAY_SIZE, PING_TIMEOUT); + ping_array_init(&dht->dht_harden_ping_array, DHT_PING_ARRAY_SIZE, PING_TIMEOUT); + + for (uint32_t i = 0; i < DHT_FAKE_FRIEND_NUMBER; ++i) { + uint8_t random_key_bytes[CRYPTO_PUBLIC_KEY_SIZE]; + random_bytes(random_key_bytes, sizeof(random_key_bytes)); + + if (DHT_addfriend(dht, random_key_bytes, 0, 0, 0, 0) != 0) { + kill_DHT(dht); + return NULL; + } + } + + return dht; +} + +void do_DHT(DHT *dht) +{ + unix_time_update(); + + if (dht->last_run == unix_time()) { + return; + } + + // Load friends/clients if first call to do_DHT + if (dht->loaded_num_nodes) { + DHT_connect_after_load(dht); + } + + do_Close(dht); + do_DHT_friends(dht); + do_NAT(dht); + do_to_ping(dht->ping); +#if DHT_HARDENING + do_hardening(dht); +#endif + dht->last_run = unix_time(); +} +void kill_DHT(DHT *dht) +{ + networking_registerhandler(dht->net, NET_PACKET_GET_NODES, NULL, NULL); + networking_registerhandler(dht->net, NET_PACKET_SEND_NODES_IPV6, NULL, NULL); + cryptopacket_registerhandler(dht, CRYPTO_PACKET_NAT_PING, NULL, NULL); + cryptopacket_registerhandler(dht, CRYPTO_PACKET_HARDENING, NULL, NULL); + ping_array_free_all(&dht->dht_ping_array); + ping_array_free_all(&dht->dht_harden_ping_array); + kill_ping(dht->ping); + free(dht->friends_list); + free(dht->loaded_nodes_list); + free(dht); +} + +/* new DHT format for load/save, more robust and forward compatible */ +// TODO(irungentoo): Move this closer to Messenger. +#define DHT_STATE_COOKIE_GLOBAL 0x159000d + +#define DHT_STATE_COOKIE_TYPE 0x11ce +#define DHT_STATE_TYPE_NODES 4 + +#define MAX_SAVED_DHT_NODES (((DHT_FAKE_FRIEND_NUMBER * MAX_FRIEND_CLIENTS) + LCLIENT_LIST) * 2) + +/* Get the size of the DHT (for saving). */ +uint32_t DHT_size(const DHT *dht) +{ + uint32_t numv4 = 0, numv6 = 0; + + for (uint32_t i = 0; i < LCLIENT_LIST; ++i) { + numv4 += (dht->close_clientlist[i].assoc4.timestamp != 0); + numv6 += (dht->close_clientlist[i].assoc6.timestamp != 0); + } + + for (uint32_t i = 0; i < DHT_FAKE_FRIEND_NUMBER && i < dht->num_friends; ++i) { + DHT_Friend *fr = &dht->friends_list[i]; + + for (uint32_t j = 0; j < MAX_FRIEND_CLIENTS; ++j) { + numv4 += (fr->client_list[j].assoc4.timestamp != 0); + numv6 += (fr->client_list[j].assoc6.timestamp != 0); + } + } + + uint32_t size32 = sizeof(uint32_t), sizesubhead = size32 * 2; + + return size32 + sizesubhead + (packed_node_size(TOX_AF_INET) * numv4) + (packed_node_size(TOX_AF_INET6) * numv6); +} + +static uint8_t *DHT_save_subheader(uint8_t *data, uint32_t len, uint16_t type) +{ + host_to_lendian32(data, len); + data += sizeof(uint32_t); + host_to_lendian32(data, (host_tolendian16(DHT_STATE_COOKIE_TYPE) << 16) | host_tolendian16(type)); + data += sizeof(uint32_t); + return data; +} + + +/* Save the DHT in data where data is an array of size DHT_size(). */ +void DHT_save(DHT *dht, uint8_t *data) +{ + host_to_lendian32(data, DHT_STATE_COOKIE_GLOBAL); + data += sizeof(uint32_t); + + uint8_t *old_data = data; + + /* get right offset. we write the actual header later. */ + data = DHT_save_subheader(data, 0, 0); + + Node_format clients[MAX_SAVED_DHT_NODES]; + + uint32_t num = 0; + + for (uint32_t i = 0; i < LCLIENT_LIST; ++i) { + if (dht->close_clientlist[i].assoc4.timestamp != 0) { + memcpy(clients[num].public_key, dht->close_clientlist[i].public_key, CRYPTO_PUBLIC_KEY_SIZE); + clients[num].ip_port = dht->close_clientlist[i].assoc4.ip_port; + ++num; + } + + if (dht->close_clientlist[i].assoc6.timestamp != 0) { + memcpy(clients[num].public_key, dht->close_clientlist[i].public_key, CRYPTO_PUBLIC_KEY_SIZE); + clients[num].ip_port = dht->close_clientlist[i].assoc6.ip_port; + ++num; + } + } + + for (uint32_t i = 0; i < DHT_FAKE_FRIEND_NUMBER && i < dht->num_friends; ++i) { + DHT_Friend *fr = &dht->friends_list[i]; + + for (uint32_t j = 0; j < MAX_FRIEND_CLIENTS; ++j) { + if (fr->client_list[j].assoc4.timestamp != 0) { + memcpy(clients[num].public_key, fr->client_list[j].public_key, CRYPTO_PUBLIC_KEY_SIZE); + clients[num].ip_port = fr->client_list[j].assoc4.ip_port; + ++num; + } + + if (fr->client_list[j].assoc6.timestamp != 0) { + memcpy(clients[num].public_key, fr->client_list[j].public_key, CRYPTO_PUBLIC_KEY_SIZE); + clients[num].ip_port = fr->client_list[j].assoc6.ip_port; + ++num; + } + } + } + + DHT_save_subheader(old_data, pack_nodes(data, sizeof(Node_format) * num, clients, num), DHT_STATE_TYPE_NODES); +} + +/* Bootstrap from this number of nodes every time DHT_connect_after_load() is called */ +#define SAVE_BOOTSTAP_FREQUENCY 8 + +/* Start sending packets after DHT loaded_friends_list and loaded_clients_list are set */ +int DHT_connect_after_load(DHT *dht) +{ + if (dht == NULL) { + return -1; + } + + if (!dht->loaded_nodes_list) { + return -1; + } + + /* DHT is connected, stop. */ + if (DHT_non_lan_connected(dht)) { + free(dht->loaded_nodes_list); + dht->loaded_nodes_list = NULL; + dht->loaded_num_nodes = 0; + return 0; + } + + for (uint32_t i = 0; i < dht->loaded_num_nodes && i < SAVE_BOOTSTAP_FREQUENCY; ++i) { + unsigned int index = dht->loaded_nodes_index % dht->loaded_num_nodes; + DHT_bootstrap(dht, dht->loaded_nodes_list[index].ip_port, dht->loaded_nodes_list[index].public_key); + ++dht->loaded_nodes_index; + } + + return 0; +} + +static int dht_load_state_callback(void *outer, const uint8_t *data, uint32_t length, uint16_t type) +{ + DHT *dht = (DHT *)outer; + + switch (type) { + case DHT_STATE_TYPE_NODES: + if (length == 0) { + break; + } + + { + free(dht->loaded_nodes_list); + // Copy to loaded_clients_list + dht->loaded_nodes_list = (Node_format *)calloc(MAX_SAVED_DHT_NODES, sizeof(Node_format)); + + int num = unpack_nodes(dht->loaded_nodes_list, MAX_SAVED_DHT_NODES, NULL, data, length, 0); + + if (num > 0) { + dht->loaded_num_nodes = num; + } else { + dht->loaded_num_nodes = 0; + } + } /* localize declarations */ + + break; + + default: + LOGGER_ERROR(dht->log, "Load state (DHT): contains unrecognized part (len %u, type %u)\n", + length, type); + break; + } + + return 0; +} + +/* Load the DHT from data of size size. + * + * return -1 if failure. + * return 0 if success. + */ +int DHT_load(DHT *dht, const uint8_t *data, uint32_t length) +{ + uint32_t cookie_len = sizeof(uint32_t); + + if (length > cookie_len) { + uint32_t data32; + lendian_to_host32(&data32, data); + + if (data32 == DHT_STATE_COOKIE_GLOBAL) { + return load_state(dht_load_state_callback, dht->log, dht, data + cookie_len, + length - cookie_len, DHT_STATE_COOKIE_TYPE); + } + } + + return -1; +} + +/* return 0 if we are not connected to the DHT. + * return 1 if we are. + */ +int DHT_isconnected(const DHT *dht) +{ + unix_time_update(); + + for (uint32_t i = 0; i < LCLIENT_LIST; ++i) { + const Client_data *client = &dht->close_clientlist[i]; + + if (!is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT) || + !is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT)) { + return 1; + } + } + + return 0; +} + +/* return 0 if we are not connected or only connected to lan peers with the DHT. + * return 1 if we are. + */ +int DHT_non_lan_connected(const DHT *dht) +{ + unix_time_update(); + + for (uint32_t i = 0; i < LCLIENT_LIST; ++i) { + const Client_data *client = &dht->close_clientlist[i]; + + if (!is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT) && LAN_ip(client->assoc4.ip_port.ip) == -1) { + return 1; + } + + if (!is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT) && LAN_ip(client->assoc6.ip_port.ip) == -1) { + return 1; + } + } + + return 0; +} diff --git a/protocols/Tox/libtox/src/toxcore/DHT.h b/protocols/Tox/libtox/src/toxcore/DHT.h new file mode 100644 index 0000000000..510b3c5c92 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/DHT.h @@ -0,0 +1,448 @@ +/* + * An implementation of the DHT as seen in docs/updates/DHT.md + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef DHT_H +#define DHT_H + +#include "crypto_core.h" +#include "logger.h" +#include "network.h" +#include "ping_array.h" + +#include <stdbool.h> + +/* Maximum number of clients stored per friend. */ +#define MAX_FRIEND_CLIENTS 8 + +#define LCLIENT_NODES (MAX_FRIEND_CLIENTS) +#define LCLIENT_LENGTH 128 + +/* A list of the clients mathematically closest to ours. */ +#define LCLIENT_LIST (LCLIENT_LENGTH * LCLIENT_NODES) + +#define MAX_CLOSE_TO_BOOTSTRAP_NODES 8 + +/* The max number of nodes to send with send nodes. */ +#define MAX_SENT_NODES 4 + +/* Ping timeout in seconds */ +#define PING_TIMEOUT 5 + +/* size of DHT ping arrays. */ +#define DHT_PING_ARRAY_SIZE 512 + +/* Ping interval in seconds for each node in our lists. */ +#define PING_INTERVAL 60 + +/* The number of seconds for a non responsive node to become bad. */ +#define PINGS_MISSED_NODE_GOES_BAD 1 +#define PING_ROUNDTRIP 2 +#define BAD_NODE_TIMEOUT (PING_INTERVAL + PINGS_MISSED_NODE_GOES_BAD * (PING_INTERVAL + PING_ROUNDTRIP)) + +/* The number of "fake" friends to add (for optimization purposes and so our paths for the onion part are more random) */ +#define DHT_FAKE_FRIEND_NUMBER 2 + +#define MAX_CRYPTO_REQUEST_SIZE 1024 + +#define CRYPTO_PACKET_FRIEND_REQ 32 /* Friend request crypto packet ID. */ +#define CRYPTO_PACKET_HARDENING 48 /* Hardening crypto packet ID. */ +#define CRYPTO_PACKET_DHTPK 156 +#define CRYPTO_PACKET_NAT_PING 254 /* NAT ping crypto packet ID. */ + +/* Create a request to peer. + * send_public_key and send_secret_key are the pub/secret keys of the sender. + * recv_public_key is public key of receiver. + * packet must be an array of MAX_CRYPTO_REQUEST_SIZE big. + * Data represents the data we send with the request with length being the length of the data. + * request_id is the id of the request (32 = friend request, 254 = ping request). + * + * return -1 on failure. + * return the length of the created packet on success. + */ +int create_request(const uint8_t *send_public_key, const uint8_t *send_secret_key, uint8_t *packet, + const uint8_t *recv_public_key, const uint8_t *data, uint32_t length, uint8_t request_id); + +/* puts the senders public key in the request in public_key, the data from the request + in data if a friend or ping request was sent to us and returns the length of the data. + packet is the request packet and length is its length + return -1 if not valid request. */ +int handle_request(const uint8_t *self_public_key, const uint8_t *self_secret_key, uint8_t *public_key, uint8_t *data, + uint8_t *request_id, const uint8_t *packet, uint16_t length); + +typedef struct { + IP_Port ip_port; + uint64_t timestamp; +} IPPTs; + +typedef struct { + /* Node routes request correctly (true (1) or false/didn't check (0)) */ + uint8_t routes_requests_ok; + /* Time which we last checked this.*/ + uint64_t routes_requests_timestamp; + uint8_t routes_requests_pingedid[CRYPTO_PUBLIC_KEY_SIZE]; + /* Node sends correct send_node (true (1) or false/didn't check (0)) */ + uint8_t send_nodes_ok; + /* Time which we last checked this.*/ + uint64_t send_nodes_timestamp; + uint8_t send_nodes_pingedid[CRYPTO_PUBLIC_KEY_SIZE]; + /* Node can be used to test other nodes (true (1) or false/didn't check (0)) */ + uint8_t testing_requests; + /* Time which we last checked this.*/ + uint64_t testing_timestamp; + uint8_t testing_pingedid[CRYPTO_PUBLIC_KEY_SIZE]; +} Hardening; + +typedef struct { + IP_Port ip_port; + uint64_t timestamp; + uint64_t last_pinged; + + Hardening hardening; + /* Returned by this node. Either our friend or us. */ + IP_Port ret_ip_port; + uint64_t ret_timestamp; +} IPPTsPng; + +typedef struct { + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + IPPTsPng assoc4; + IPPTsPng assoc6; +} Client_data; + +/*----------------------------------------------------------------------------------*/ + +typedef struct { + /* 1 if currently hole punching, otherwise 0 */ + uint8_t hole_punching; + uint32_t punching_index; + uint32_t tries; + uint32_t punching_index2; + + uint64_t punching_timestamp; + uint64_t recvNATping_timestamp; + uint64_t NATping_id; + uint64_t NATping_timestamp; +} NAT; + +#define DHT_FRIEND_MAX_LOCKS 32 + +typedef struct { + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + IP_Port ip_port; +} +Node_format; + +typedef struct { + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + Client_data client_list[MAX_FRIEND_CLIENTS]; + + /* Time at which the last get_nodes request was sent. */ + uint64_t lastgetnode; + /* number of times get_node packets were sent. */ + uint32_t bootstrap_times; + + /* Symetric NAT hole punching stuff. */ + NAT nat; + + uint16_t lock_count; + struct { + void (*ip_callback)(void *, int32_t, IP_Port); + void *data; + int32_t number; + } callbacks[DHT_FRIEND_MAX_LOCKS]; + + Node_format to_bootstrap[MAX_SENT_NODES]; + unsigned int num_to_bootstrap; +} DHT_Friend; + +/* Return packet size of packed node with ip_family on success. + * Return -1 on failure. + */ +int packed_node_size(uint8_t ip_family); + +/* Pack number of nodes into data of maxlength length. + * + * return length of packed nodes on success. + * return -1 on failure. + */ +int pack_nodes(uint8_t *data, uint16_t length, const Node_format *nodes, uint16_t number); + +/* Unpack data of length into nodes of size max_num_nodes. + * Put the length of the data processed in processed_data_len. + * tcp_enabled sets if TCP nodes are expected (true) or not (false). + * + * return number of unpacked nodes on success. + * return -1 on failure. + */ +int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed_data_len, const uint8_t *data, + uint16_t length, uint8_t tcp_enabled); + + +/*----------------------------------------------------------------------------------*/ +/* struct to store some shared keys so we don't have to regenerate them for each request. */ +#define MAX_KEYS_PER_SLOT 4 +#define KEYS_TIMEOUT 600 + +typedef struct { + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + uint32_t times_requested; + uint8_t stored; /* 0 if not, 1 if is */ + uint64_t time_last_requested; +} Shared_Key; + +typedef struct { + Shared_Key keys[256 * MAX_KEYS_PER_SLOT]; +} Shared_Keys; + +/*----------------------------------------------------------------------------------*/ + +typedef int (*cryptopacket_handler_callback)(void *object, IP_Port ip_port, const uint8_t *source_pubkey, + const uint8_t *data, uint16_t len, void *userdata); + +typedef struct { + cryptopacket_handler_callback function; + void *object; +} Cryptopacket_Handles; + +typedef struct { + Logger *log; + Networking_Core *net; + + bool hole_punching_enabled; + + Client_data close_clientlist[LCLIENT_LIST]; + uint64_t close_lastgetnodes; + uint32_t close_bootstrap_times; + + /* Note: this key should not be/is not used to transmit any sensitive materials */ + uint8_t secret_symmetric_key[CRYPTO_SYMMETRIC_KEY_SIZE]; + /* DHT keypair */ + uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE]; + + DHT_Friend *friends_list; + uint16_t num_friends; + + Node_format *loaded_nodes_list; + uint32_t loaded_num_nodes; + unsigned int loaded_nodes_index; + + Shared_Keys shared_keys_recv; + Shared_Keys shared_keys_sent; + + struct PING *ping; + Ping_Array dht_ping_array; + Ping_Array dht_harden_ping_array; + uint64_t last_run; + + Cryptopacket_Handles cryptopackethandlers[256]; + + Node_format to_bootstrap[MAX_CLOSE_TO_BOOTSTRAP_NODES]; + unsigned int num_to_bootstrap; +} DHT; +/*----------------------------------------------------------------------------------*/ + +/* Shared key generations are costly, it is therefor smart to store commonly used + * ones so that they can re used later without being computed again. + * + * If shared key is already in shared_keys, copy it to shared_key. + * else generate it into shared_key and copy it to shared_keys + */ +void get_shared_key(Shared_Keys *shared_keys, uint8_t *shared_key, const uint8_t *secret_key, + const uint8_t *public_key); + +/* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key + * for packets that we receive. + */ +void DHT_get_shared_key_recv(DHT *dht, uint8_t *shared_key, const uint8_t *public_key); + +/* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key + * for packets that we send. + */ +void DHT_get_shared_key_sent(DHT *dht, uint8_t *shared_key, const uint8_t *public_key); + +void DHT_getnodes(DHT *dht, const IP_Port *from_ipp, const uint8_t *from_id, const uint8_t *which_id); + +/* Add a new friend to the friends list. + * public_key must be CRYPTO_PUBLIC_KEY_SIZE bytes long. + * + * ip_callback is the callback of a function that will be called when the ip address + * is found along with arguments data and number. + * + * lock_count will be set to a non zero number that must be passed to DHT_delfriend() + * to properly remove the callback. + * + * return 0 if success. + * return -1 if failure (friends list is full). + */ +int DHT_addfriend(DHT *dht, const uint8_t *public_key, void (*ip_callback)(void *data, int32_t number, IP_Port), + void *data, int32_t number, uint16_t *lock_count); + +/* Delete a friend from the friends list. + * public_key must be CRYPTO_PUBLIC_KEY_SIZE bytes long. + * + * return 0 if success. + * return -1 if failure (public_key not in friends list). + */ +int DHT_delfriend(DHT *dht, const uint8_t *public_key, uint16_t lock_count); + +/* Get ip of friend. + * public_key must be CRYPTO_PUBLIC_KEY_SIZE bytes long. + * ip must be 4 bytes long. + * port must be 2 bytes long. + * + * int DHT_getfriendip(DHT *dht, uint8_t *public_key, IP_Port *ip_port); + * + * return -1, -- if public_key does NOT refer to a friend + * return 0, -- if public_key refers to a friend and we failed to find the friend (yet) + * return 1, ip if public_key refers to a friend and we found him + */ +int DHT_getfriendip(const DHT *dht, const uint8_t *public_key, IP_Port *ip_port); + +/* Compares pk1 and pk2 with pk. + * + * return 0 if both are same distance. + * return 1 if pk1 is closer. + * return 2 if pk2 is closer. + */ +int id_closest(const uint8_t *pk, const uint8_t *pk1, const uint8_t *pk2); + +/* Add node to the node list making sure only the nodes closest to cmp_pk are in the list. + */ +bool add_to_list(Node_format *nodes_list, unsigned int length, const uint8_t *pk, IP_Port ip_port, + const uint8_t *cmp_pk); + +/* Return 1 if node can be added to close list, 0 if it can't. + */ +bool node_addable_to_close_list(DHT *dht, const uint8_t *public_key, IP_Port ip_port); + +/* Get the (maximum MAX_SENT_NODES) closest nodes to public_key we know + * and put them in nodes_list (must be MAX_SENT_NODES big). + * + * sa_family = family (IPv4 or IPv6) (0 if we don't care)? + * is_LAN = return some LAN ips (true or false) + * want_good = do we want tested nodes or not? (TODO(irungentoo)) + * + * return the number of nodes returned. + * + */ +int get_close_nodes(const DHT *dht, const uint8_t *public_key, Node_format *nodes_list, Family sa_family, + uint8_t is_LAN, uint8_t want_good); + + +/* Put up to max_num nodes in nodes from the random friends. + * + * return the number of nodes. + */ +uint16_t randfriends_nodes(DHT *dht, Node_format *nodes, uint16_t max_num); + +/* Put up to max_num nodes in nodes from the closelist. + * + * return the number of nodes. + */ +uint16_t closelist_nodes(DHT *dht, Node_format *nodes, uint16_t max_num); + +/* Run this function at least a couple times per second (It's the main loop). */ +void do_DHT(DHT *dht); + +/* + * Use these two functions to bootstrap the client. + */ +/* Sends a "get nodes" request to the given node with ip, port and public_key + * to setup connections + */ +void DHT_bootstrap(DHT *dht, IP_Port ip_port, const uint8_t *public_key); +/* Resolves address into an IP address. If successful, sends a "get nodes" + * request to the given node with ip, port and public_key to setup connections + * + * address can be a hostname or an IP address (IPv4 or IPv6). + * if ipv6enabled is 0 (zero), the resolving sticks STRICTLY to IPv4 addresses + * if ipv6enabled is not 0 (zero), the resolving looks for IPv6 addresses first, + * then IPv4 addresses. + * + * returns 1 if the address could be converted into an IP address + * returns 0 otherwise + */ +int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled, + uint16_t port, const uint8_t *public_key); + +/* Start sending packets after DHT loaded_friends_list and loaded_clients_list are set. + * + * returns 0 if successful + * returns -1 otherwise + */ +int DHT_connect_after_load(DHT *dht); + +/* ROUTING FUNCTIONS */ + +/* Send the given packet to node with public_key. + * + * return -1 if failure. + */ +int route_packet(const DHT *dht, const uint8_t *public_key, const uint8_t *packet, uint16_t length); + +/* Send the following packet to everyone who tells us they are connected to friend_id. + * + * return number of nodes it sent the packet to. + */ +int route_tofriend(const DHT *dht, const uint8_t *friend_id, const uint8_t *packet, uint16_t length); + +/* Function to handle crypto packets. + */ +void cryptopacket_registerhandler(DHT *dht, uint8_t byte, cryptopacket_handler_callback cb, void *object); + +/* SAVE/LOAD functions */ + +/* Get the size of the DHT (for saving). */ +uint32_t DHT_size(const DHT *dht); + +/* Save the DHT in data where data is an array of size DHT_size(). */ +void DHT_save(DHT *dht, uint8_t *data); + +/* Load the DHT from data of size size. + * + * return -1 if failure. + * return 0 if success. + */ +int DHT_load(DHT *dht, const uint8_t *data, uint32_t length); + +/* Initialize DHT. */ +DHT *new_DHT(Logger *log, Networking_Core *net, bool holepunching_enabled); + +void kill_DHT(DHT *dht); + +/* return 0 if we are not connected to the DHT. + * return 1 if we are. + */ +int DHT_isconnected(const DHT *dht); + +/* return 0 if we are not connected or only connected to lan peers with the DHT. + * return 1 if we are. + */ +int DHT_non_lan_connected(const DHT *dht); + + +uint32_t addto_lists(DHT *dht, IP_Port ip_port, const uint8_t *public_key); + +#endif diff --git a/protocols/Tox/libtox/src/toxcore/LAN_discovery.c b/protocols/Tox/libtox/src/toxcore/LAN_discovery.c new file mode 100644 index 0000000000..b95e401d05 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/LAN_discovery.c @@ -0,0 +1,410 @@ +/* + * LAN discovery implementation. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "LAN_discovery.h" + +#include "util.h" + +/* Used for get_broadcast(). */ +#ifdef __linux +#include <linux/netdevice.h> +#include <sys/ioctl.h> +#endif + +#define MAX_INTERFACES 16 + + +/* TODO: multiple threads might concurrently try to set these, and it isn't clear that this couldn't lead to undesirable + * behaviour. Consider storing the data in per-instance variables instead. */ +static int broadcast_count = -1; +static IP_Port broadcast_ip_ports[MAX_INTERFACES]; + +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + +#include <iphlpapi.h> + +static void fetch_broadcast_info(uint16_t port) +{ + IP_ADAPTER_INFO *pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO)); + unsigned long ulOutBufLen = sizeof(IP_ADAPTER_INFO); + + if (pAdapterInfo == NULL) { + return; + } + + if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) { + free(pAdapterInfo); + pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen); + + if (pAdapterInfo == NULL) { + return; + } + } + + /* We copy these to the static variables broadcast_* only at the end of fetch_broadcast_info(). + * The intention is to ensure that even if multiple threads enter fetch_broadcast_info() concurrently, only valid + * interfaces will be set to be broadcast to. + * */ + int count = 0; + IP_Port ip_ports[MAX_INTERFACES]; + + int ret; + + if ((ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) { + IP_ADAPTER_INFO *pAdapter = pAdapterInfo; + + while (pAdapter) { + IP gateway = {0}, subnet_mask = {0}; + + if (addr_parse_ip(pAdapter->IpAddressList.IpMask.String, &subnet_mask) + && addr_parse_ip(pAdapter->GatewayList.IpAddress.String, &gateway)) { + if (gateway.family == TOX_AF_INET && subnet_mask.family == TOX_AF_INET) { + IP_Port *ip_port = &ip_ports[count]; + ip_port->ip.family = TOX_AF_INET; + uint32_t gateway_ip = net_ntohl(gateway.ip4.uint32), subnet_ip = net_ntohl(subnet_mask.ip4.uint32); + uint32_t broadcast_ip = gateway_ip + ~subnet_ip - 1; + ip_port->ip.ip4.uint32 = net_htonl(broadcast_ip); + ip_port->port = port; + count++; + + if (count >= MAX_INTERFACES) { + break; + } + } + } + + pAdapter = pAdapter->Next; + } + } + + if (pAdapterInfo) { + free(pAdapterInfo); + } + + broadcast_count = count; + + for (uint32_t i = 0; i < count; i++) { + broadcast_ip_ports[i] = ip_ports[i]; + } +} + +#elif defined(__linux__) + +static void fetch_broadcast_info(uint16_t port) +{ + /* Not sure how many platforms this will run on, + * so it's wrapped in __linux for now. + * Definitely won't work like this on Windows... + */ + broadcast_count = 0; + Socket sock = 0; + + if ((sock = net_socket(TOX_AF_INET, TOX_SOCK_STREAM, 0)) < 0) { + return; + } + + /* Configure ifconf for the ioctl call. */ + struct ifreq i_faces[MAX_INTERFACES]; + memset(i_faces, 0, sizeof(struct ifreq) * MAX_INTERFACES); + + struct ifconf ifconf; + ifconf.ifc_buf = (char *)i_faces; + ifconf.ifc_len = sizeof(i_faces); + + if (ioctl(sock, SIOCGIFCONF, &ifconf) < 0) { + close(sock); + return; + } + + /* We copy these to the static variables broadcast_* only at the end of fetch_broadcast_info(). + * The intention is to ensure that even if multiple threads enter fetch_broadcast_info() concurrently, only valid + * interfaces will be set to be broadcast to. + * */ + int count = 0; + IP_Port ip_ports[MAX_INTERFACES]; + + /* ifconf.ifc_len is set by the ioctl() to the actual length used; + * on usage of the complete array the call should be repeated with + * a larger array, not done (640kB and 16 interfaces shall be + * enough, for everybody!) + */ + int i, n = ifconf.ifc_len / sizeof(struct ifreq); + + for (i = 0; i < n; i++) { + /* there are interfaces with are incapable of broadcast */ + if (ioctl(sock, SIOCGIFBRDADDR, &i_faces[i]) < 0) { + continue; + } + + /* moot check: only TOX_AF_INET returned (backwards compat.) */ + if (i_faces[i].ifr_broadaddr.sa_family != TOX_AF_INET) { + continue; + } + + struct sockaddr_in *sock4 = (struct sockaddr_in *)&i_faces[i].ifr_broadaddr; + + if (count >= MAX_INTERFACES) { + break; + } + + IP_Port *ip_port = &ip_ports[count]; + ip_port->ip.family = TOX_AF_INET; + ip_port->ip.ip4.uint32 = sock4->sin_addr.s_addr; + + if (ip_port->ip.ip4.uint32 == 0) { + continue; + } + + ip_port->port = port; + count++; + } + + close(sock); + + broadcast_count = count; + + for (uint32_t i = 0; i < count; i++) { + broadcast_ip_ports[i] = ip_ports[i]; + } +} + +#else // TODO(irungentoo): Other platforms? + +static void fetch_broadcast_info(uint16_t port) +{ + broadcast_count = 0; +} + +#endif +/* Send packet to all IPv4 broadcast addresses + * + * return 1 if sent to at least one broadcast target. + * return 0 on failure to find any valid broadcast target. + */ +static uint32_t send_broadcasts(Networking_Core *net, uint16_t port, const uint8_t *data, uint16_t length) +{ + /* fetch only once? on every packet? every X seconds? + * old: every packet, new: once */ + if (broadcast_count < 0) { + fetch_broadcast_info(port); + } + + if (!broadcast_count) { + return 0; + } + + int i; + + for (i = 0; i < broadcast_count; i++) { + sendpacket(net, broadcast_ip_ports[i], data, length); + } + + return 1; +} + +/* Return the broadcast ip. */ +static IP broadcast_ip(Family family_socket, Family family_broadcast) +{ + IP ip; + ip_reset(&ip); + + if (family_socket == TOX_AF_INET6) { + if (family_broadcast == TOX_AF_INET6) { + ip.family = TOX_AF_INET6; + /* FF02::1 is - according to RFC 4291 - multicast all-nodes link-local */ + /* FE80::*: MUST be exact, for that we would need to look over all + * interfaces and check in which status they are */ + ip.ip6.uint8[ 0] = 0xFF; + ip.ip6.uint8[ 1] = 0x02; + ip.ip6.uint8[15] = 0x01; + } else if (family_broadcast == TOX_AF_INET) { + ip.family = TOX_AF_INET6; + ip.ip6 = IP6_BROADCAST; + } + } else if (family_socket == TOX_AF_INET) { + if (family_broadcast == TOX_AF_INET) { + ip.family = TOX_AF_INET; + ip.ip4 = IP4_BROADCAST; + } + } + + return ip; +} + +/* Is IP a local ip or not. */ +bool Local_ip(IP ip) +{ + if (ip.family == TOX_AF_INET) { + IP4 ip4 = ip.ip4; + + /* Loopback. */ + if (ip4.uint8[0] == 127) { + return 1; + } + } else { + /* embedded IPv4-in-IPv6 */ + if (IPV6_IPV4_IN_V6(ip.ip6)) { + IP ip4; + ip4.family = TOX_AF_INET; + ip4.ip4.uint32 = ip.ip6.uint32[3]; + return Local_ip(ip4); + } + + /* localhost in IPv6 (::1) */ + if (ip.ip6.uint64[0] == 0 && ip.ip6.uint32[2] == 0 && ip.ip6.uint32[3] == net_htonl(1)) { + return 1; + } + } + + return 0; +} + +/* return 0 if ip is a LAN ip. + * return -1 if it is not. + */ +int LAN_ip(IP ip) +{ + if (Local_ip(ip)) { + return 0; + } + + if (ip.family == TOX_AF_INET) { + IP4 ip4 = ip.ip4; + + /* 10.0.0.0 to 10.255.255.255 range. */ + if (ip4.uint8[0] == 10) { + return 0; + } + + /* 172.16.0.0 to 172.31.255.255 range. */ + if (ip4.uint8[0] == 172 && ip4.uint8[1] >= 16 && ip4.uint8[1] <= 31) { + return 0; + } + + /* 192.168.0.0 to 192.168.255.255 range. */ + if (ip4.uint8[0] == 192 && ip4.uint8[1] == 168) { + return 0; + } + + /* 169.254.1.0 to 169.254.254.255 range. */ + if (ip4.uint8[0] == 169 && ip4.uint8[1] == 254 && ip4.uint8[2] != 0 + && ip4.uint8[2] != 255) { + return 0; + } + + /* RFC 6598: 100.64.0.0 to 100.127.255.255 (100.64.0.0/10) + * (shared address space to stack another layer of NAT) */ + if ((ip4.uint8[0] == 100) && ((ip4.uint8[1] & 0xC0) == 0x40)) { + return 0; + } + } else if (ip.family == TOX_AF_INET6) { + + /* autogenerated for each interface: FE80::* (up to FEBF::*) + FF02::1 is - according to RFC 4291 - multicast all-nodes link-local */ + if (((ip.ip6.uint8[0] == 0xFF) && (ip.ip6.uint8[1] < 3) && (ip.ip6.uint8[15] == 1)) || + ((ip.ip6.uint8[0] == 0xFE) && ((ip.ip6.uint8[1] & 0xC0) == 0x80))) { + return 0; + } + + /* embedded IPv4-in-IPv6 */ + if (IPV6_IPV4_IN_V6(ip.ip6)) { + IP ip4; + ip4.family = TOX_AF_INET; + ip4.ip4.uint32 = ip.ip6.uint32[3]; + return LAN_ip(ip4); + } + } + + return -1; +} + +static int handle_LANdiscovery(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + DHT *dht = (DHT *)object; + + if (LAN_ip(source.ip) == -1) { + return 1; + } + + if (length != CRYPTO_PUBLIC_KEY_SIZE + 1) { + return 1; + } + + char ip_str[IP_NTOA_LEN] = { 0 }; + ip_ntoa(&source.ip, ip_str, sizeof(ip_str)); + LOGGER_INFO(dht->log, "Found node in LAN: %s", ip_str); + + DHT_bootstrap(dht, source, packet + 1); + return 0; +} + + +int send_LANdiscovery(uint16_t port, DHT *dht) +{ + uint8_t data[CRYPTO_PUBLIC_KEY_SIZE + 1]; + data[0] = NET_PACKET_LAN_DISCOVERY; + id_copy(data + 1, dht->self_public_key); + + send_broadcasts(dht->net, port, data, 1 + CRYPTO_PUBLIC_KEY_SIZE); + + int res = -1; + IP_Port ip_port; + ip_port.port = port; + + /* IPv6 multicast */ + if (dht->net->family == TOX_AF_INET6) { + ip_port.ip = broadcast_ip(TOX_AF_INET6, TOX_AF_INET6); + + if (ip_isset(&ip_port.ip)) { + if (sendpacket(dht->net, ip_port, data, 1 + CRYPTO_PUBLIC_KEY_SIZE) > 0) { + res = 1; + } + } + } + + /* IPv4 broadcast (has to be IPv4-in-IPv6 mapping if socket is TOX_AF_INET6 */ + ip_port.ip = broadcast_ip(dht->net->family, TOX_AF_INET); + + if (ip_isset(&ip_port.ip)) { + if (sendpacket(dht->net, ip_port, data, 1 + CRYPTO_PUBLIC_KEY_SIZE)) { + res = 1; + } + } + + return res; +} + + +void LANdiscovery_init(DHT *dht) +{ + networking_registerhandler(dht->net, NET_PACKET_LAN_DISCOVERY, &handle_LANdiscovery, dht); +} + +void LANdiscovery_kill(DHT *dht) +{ + networking_registerhandler(dht->net, NET_PACKET_LAN_DISCOVERY, NULL, NULL); +} diff --git a/protocols/Tox/libtox/src/toxcore/LAN_discovery.h b/protocols/Tox/libtox/src/toxcore/LAN_discovery.h new file mode 100644 index 0000000000..753de5249f --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/LAN_discovery.h @@ -0,0 +1,52 @@ +/* + * LAN discovery implementation. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef LAN_DISCOVERY_H +#define LAN_DISCOVERY_H + +#include "DHT.h" + +/* Interval in seconds between LAN discovery packet sending. */ +#define LAN_DISCOVERY_INTERVAL 10 + +/* Send a LAN discovery pcaket to the broadcast address with port port. */ +int send_LANdiscovery(uint16_t port, DHT *dht); + +/* Sets up packet handlers. */ +void LANdiscovery_init(DHT *dht); + +/* Clear packet handlers. */ +void LANdiscovery_kill(DHT *dht); + +/* Is IP a local ip or not. */ +bool Local_ip(IP ip); + +/* checks if a given IP isn't routable + * + * return 0 if ip is a LAN ip. + * return -1 if it is not. + */ +int LAN_ip(IP ip); + + +#endif diff --git a/protocols/Tox/libtox/src/toxcore/Messenger.c b/protocols/Tox/libtox/src/toxcore/Messenger.c new file mode 100644 index 0000000000..e821f53530 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/Messenger.c @@ -0,0 +1,3157 @@ +/* + * An implementation of a simple text chat only messenger on the tox network core. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "Messenger.h" + +#include "logger.h" +#include "network.h" +#include "util.h" + +#include <assert.h> + +static void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status, void *userdata); +static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data, + uint32_t length, uint8_t congestion_control); + +// friend_not_valid determines if the friendnumber passed is valid in the Messenger object +static uint8_t friend_not_valid(const Messenger *m, int32_t friendnumber) +{ + if ((unsigned int)friendnumber < m->numfriends) { + if (m->friendlist[friendnumber].status != 0) { + return 0; + } + } + + return 1; +} + +/* Set the size of the friend list to numfriends. + * + * return -1 if realloc fails. + */ +static int realloc_friendlist(Messenger *m, uint32_t num) +{ + if (num == 0) { + free(m->friendlist); + m->friendlist = NULL; + return 0; + } + + Friend *newfriendlist = (Friend *)realloc(m->friendlist, num * sizeof(Friend)); + + if (newfriendlist == NULL) { + return -1; + } + + m->friendlist = newfriendlist; + return 0; +} + +/* return the friend id associated to that public key. + * return -1 if no such friend. + */ +int32_t getfriend_id(const Messenger *m, const uint8_t *real_pk) +{ + uint32_t i; + + for (i = 0; i < m->numfriends; ++i) { + if (m->friendlist[i].status > 0) { + if (id_equal(real_pk, m->friendlist[i].real_pk)) { + return i; + } + } + } + + return -1; +} + +/* Copies the public key associated to that friend id into real_pk buffer. + * Make sure that real_pk is of size CRYPTO_PUBLIC_KEY_SIZE. + * + * return 0 if success. + * return -1 if failure. + */ +int get_real_pk(const Messenger *m, int32_t friendnumber, uint8_t *real_pk) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + memcpy(real_pk, m->friendlist[friendnumber].real_pk, CRYPTO_PUBLIC_KEY_SIZE); + return 0; +} + +/* return friend connection id on success. + * return -1 if failure. + */ +int getfriendcon_id(const Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + return m->friendlist[friendnumber].friendcon_id; +} + +/* + * return a uint16_t that represents the checksum of address of length len. + */ +static uint16_t address_checksum(const uint8_t *address, uint32_t len) +{ + uint8_t checksum[2] = {0}; + uint16_t check; + uint32_t i; + + for (i = 0; i < len; ++i) { + checksum[i % 2] ^= address[i]; + } + + memcpy(&check, checksum, sizeof(check)); + return check; +} + +/* Format: [real_pk (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] + * + * return FRIEND_ADDRESS_SIZE byte address to give to others. + */ +void getaddress(const Messenger *m, uint8_t *address) +{ + id_copy(address, m->net_crypto->self_public_key); + uint32_t nospam = get_nospam(&(m->fr)); + memcpy(address + CRYPTO_PUBLIC_KEY_SIZE, &nospam, sizeof(nospam)); + uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum)); + memcpy(address + CRYPTO_PUBLIC_KEY_SIZE + sizeof(nospam), &checksum, sizeof(checksum)); +} + +static int send_online_packet(Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return 0; + } + + uint8_t packet = PACKET_ID_ONLINE; + return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id), &packet, sizeof(packet), 0) != -1; +} + +static int send_offline_packet(Messenger *m, int friendcon_id) +{ + uint8_t packet = PACKET_ID_OFFLINE; + return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, friendcon_id), &packet, + sizeof(packet), 0) != -1; +} + +static int m_handle_status(void *object, int i, uint8_t status, void *userdata); +static int m_handle_packet(void *object, int i, const uint8_t *temp, uint16_t len, void *userdata); +static int m_handle_custom_lossy_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length, + void *userdata); + +static int32_t init_new_friend(Messenger *m, const uint8_t *real_pk, uint8_t status) +{ + /* Resize the friend list if necessary. */ + if (realloc_friendlist(m, m->numfriends + 1) != 0) { + return FAERR_NOMEM; + } + + memset(&(m->friendlist[m->numfriends]), 0, sizeof(Friend)); + + int friendcon_id = new_friend_connection(m->fr_c, real_pk); + + if (friendcon_id == -1) { + return FAERR_NOMEM; + } + + uint32_t i; + + for (i = 0; i <= m->numfriends; ++i) { + if (m->friendlist[i].status == NOFRIEND) { + m->friendlist[i].status = status; + m->friendlist[i].friendcon_id = friendcon_id; + m->friendlist[i].friendrequest_lastsent = 0; + id_copy(m->friendlist[i].real_pk, real_pk); + m->friendlist[i].statusmessage_length = 0; + m->friendlist[i].userstatus = USERSTATUS_NONE; + m->friendlist[i].is_typing = 0; + m->friendlist[i].message_id = 0; + friend_connection_callbacks(m->fr_c, friendcon_id, MESSENGER_CALLBACK_INDEX, &m_handle_status, &m_handle_packet, + &m_handle_custom_lossy_packet, m, i); + + if (m->numfriends == i) { + ++m->numfriends; + } + + if (friend_con_connected(m->fr_c, friendcon_id) == FRIENDCONN_STATUS_CONNECTED) { + send_online_packet(m, i); + } + + return i; + } + } + + return FAERR_NOMEM; +} + +/* + * Add a friend. + * Set the data that will be sent along with friend request. + * Address is the address of the friend (returned by getaddress of the friend you wish to add) it must be FRIEND_ADDRESS_SIZE bytes. + * data is the data and length is the length. + * + * return the friend number if success. + * return FA_TOOLONG if message length is too long. + * return FAERR_NOMESSAGE if no message (message length must be >= 1 byte). + * return FAERR_OWNKEY if user's own key. + * return FAERR_ALREADYSENT if friend request already sent or already a friend. + * return FAERR_BADCHECKSUM if bad checksum in address. + * return FAERR_SETNEWNOSPAM if the friend was already there but the nospam was different. + * (the nospam for that friend was set to the new one). + * return FAERR_NOMEM if increasing the friend list size fails. + */ +int32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, uint16_t length) +{ + if (length > MAX_FRIEND_REQUEST_DATA_SIZE) { + return FAERR_TOOLONG; + } + + uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + id_copy(real_pk, address); + + if (!public_key_valid(real_pk)) { + return FAERR_BADCHECKSUM; + } + + uint16_t check, checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum)); + memcpy(&check, address + CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint32_t), sizeof(check)); + + if (check != checksum) { + return FAERR_BADCHECKSUM; + } + + if (length < 1) { + return FAERR_NOMESSAGE; + } + + if (id_equal(real_pk, m->net_crypto->self_public_key)) { + return FAERR_OWNKEY; + } + + int32_t friend_id = getfriend_id(m, real_pk); + + if (friend_id != -1) { + if (m->friendlist[friend_id].status >= FRIEND_CONFIRMED) { + return FAERR_ALREADYSENT; + } + + uint32_t nospam; + memcpy(&nospam, address + CRYPTO_PUBLIC_KEY_SIZE, sizeof(nospam)); + + if (m->friendlist[friend_id].friendrequest_nospam == nospam) { + return FAERR_ALREADYSENT; + } + + m->friendlist[friend_id].friendrequest_nospam = nospam; + return FAERR_SETNEWNOSPAM; + } + + int32_t ret = init_new_friend(m, real_pk, FRIEND_ADDED); + + if (ret < 0) { + return ret; + } + + m->friendlist[ret].friendrequest_timeout = FRIENDREQUEST_TIMEOUT; + memcpy(m->friendlist[ret].info, data, length); + m->friendlist[ret].info_size = length; + memcpy(&(m->friendlist[ret].friendrequest_nospam), address + CRYPTO_PUBLIC_KEY_SIZE, sizeof(uint32_t)); + + return ret; +} + +int32_t m_addfriend_norequest(Messenger *m, const uint8_t *real_pk) +{ + if (getfriend_id(m, real_pk) != -1) { + return FAERR_ALREADYSENT; + } + + if (!public_key_valid(real_pk)) { + return FAERR_BADCHECKSUM; + } + + if (id_equal(real_pk, m->net_crypto->self_public_key)) { + return FAERR_OWNKEY; + } + + return init_new_friend(m, real_pk, FRIEND_CONFIRMED); +} + +static int clear_receipts(Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + struct Receipts *receipts = m->friendlist[friendnumber].receipts_start; + + while (receipts) { + struct Receipts *temp_r = receipts->next; + free(receipts); + receipts = temp_r; + } + + m->friendlist[friendnumber].receipts_start = NULL; + m->friendlist[friendnumber].receipts_end = NULL; + return 0; +} + +static int add_receipt(Messenger *m, int32_t friendnumber, uint32_t packet_num, uint32_t msg_id) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + struct Receipts *new_receipts = (struct Receipts *)calloc(1, sizeof(struct Receipts)); + + if (!new_receipts) { + return -1; + } + + new_receipts->packet_num = packet_num; + new_receipts->msg_id = msg_id; + + if (!m->friendlist[friendnumber].receipts_start) { + m->friendlist[friendnumber].receipts_start = new_receipts; + } else { + m->friendlist[friendnumber].receipts_end->next = new_receipts; + } + + m->friendlist[friendnumber].receipts_end = new_receipts; + new_receipts->next = NULL; + return 0; +} +/* + * return -1 on failure. + * return 0 if packet was received. + */ +static int friend_received_packet(const Messenger *m, int32_t friendnumber, uint32_t number) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + return cryptpacket_received(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id), number); +} + +static int do_receipts(Messenger *m, int32_t friendnumber, void *userdata) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + struct Receipts *receipts = m->friendlist[friendnumber].receipts_start; + + while (receipts) { + if (friend_received_packet(m, friendnumber, receipts->packet_num) == -1) { + break; + } + + if (m->read_receipt) { + (*m->read_receipt)(m, friendnumber, receipts->msg_id, userdata); + } + + struct Receipts *r_next = receipts->next; + + free(receipts); + + m->friendlist[friendnumber].receipts_start = r_next; + + receipts = r_next; + } + + if (!m->friendlist[friendnumber].receipts_start) { + m->friendlist[friendnumber].receipts_end = NULL; + } + + return 0; +} + +/* Remove a friend. + * + * return 0 if success. + * return -1 if failure. + */ +int m_delfriend(Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (m->friend_connectionstatuschange_internal) { + m->friend_connectionstatuschange_internal(m, friendnumber, 0, m->friend_connectionstatuschange_internal_userdata); + } + + clear_receipts(m, friendnumber); + remove_request_received(&(m->fr), m->friendlist[friendnumber].real_pk); + friend_connection_callbacks(m->fr_c, m->friendlist[friendnumber].friendcon_id, MESSENGER_CALLBACK_INDEX, 0, 0, 0, 0, 0); + + if (friend_con_connected(m->fr_c, m->friendlist[friendnumber].friendcon_id) == FRIENDCONN_STATUS_CONNECTED) { + send_offline_packet(m, m->friendlist[friendnumber].friendcon_id); + } + + kill_friend_connection(m->fr_c, m->friendlist[friendnumber].friendcon_id); + memset(&(m->friendlist[friendnumber]), 0, sizeof(Friend)); + uint32_t i; + + for (i = m->numfriends; i != 0; --i) { + if (m->friendlist[i - 1].status != NOFRIEND) { + break; + } + } + + m->numfriends = i; + + if (realloc_friendlist(m, m->numfriends) != 0) { + return FAERR_NOMEM; + } + + return 0; +} + +int m_get_friend_connectionstatus(const Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (m->friendlist[friendnumber].status == FRIEND_ONLINE) { + bool direct_connected = 0; + unsigned int num_online_relays = 0; + int crypt_conn_id = friend_connection_crypt_connection_id(m->fr_c, m->friendlist[friendnumber].friendcon_id); + crypto_connection_status(m->net_crypto, crypt_conn_id, &direct_connected, &num_online_relays); + + if (direct_connected) { + return CONNECTION_UDP; + } + + if (num_online_relays) { + return CONNECTION_TCP; + } + + return CONNECTION_UNKNOWN; + } + + return CONNECTION_NONE; +} + +int m_friend_exists(const Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return 0; + } + + return 1; +} + +/* Send a message of type. + * + * return -1 if friend not valid. + * return -2 if too large. + * return -3 if friend not online. + * return -4 if send failed (because queue is full). + * return -5 if bad type. + * return 0 if success. + */ +int m_send_message_generic(Messenger *m, int32_t friendnumber, uint8_t type, const uint8_t *message, uint32_t length, + uint32_t *message_id) +{ + if (type > MESSAGE_ACTION) { + return -5; + } + + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (length >= MAX_CRYPTO_DATA_SIZE) { + return -2; + } + + if (m->friendlist[friendnumber].status != FRIEND_ONLINE) { + return -3; + } + + VLA(uint8_t, packet, length + 1); + packet[0] = type + PACKET_ID_MESSAGE; + + if (length != 0) { + memcpy(packet + 1, message, length); + } + + int64_t packet_num = write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id), packet, length + 1, 0); + + if (packet_num == -1) { + return -4; + } + + uint32_t msg_id = ++m->friendlist[friendnumber].message_id; + + add_receipt(m, friendnumber, packet_num, msg_id); + + if (message_id) { + *message_id = msg_id; + } + + return 0; +} + +/* Send a name packet to friendnumber. + * length is the length with the NULL terminator. + */ +static int m_sendname(const Messenger *m, int32_t friendnumber, const uint8_t *name, uint16_t length) +{ + if (length > MAX_NAME_LENGTH) { + return 0; + } + + return write_cryptpacket_id(m, friendnumber, PACKET_ID_NICKNAME, name, length, 0); +} + +/* Set the name and name_length of a friend. + * + * return 0 if success. + * return -1 if failure. + */ +int setfriendname(Messenger *m, int32_t friendnumber, const uint8_t *name, uint16_t length) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (length > MAX_NAME_LENGTH || length == 0) { + return -1; + } + + m->friendlist[friendnumber].name_length = length; + memcpy(m->friendlist[friendnumber].name, name, length); + return 0; +} + +/* Set our nickname + * name must be a string of maximum MAX_NAME_LENGTH length. + * length must be at least 1 byte. + * length is the length of name with the NULL terminator. + * + * return 0 if success. + * return -1 if failure. + */ +int setname(Messenger *m, const uint8_t *name, uint16_t length) +{ + if (length > MAX_NAME_LENGTH) { + return -1; + } + + if (m->name_length == length && (length == 0 || memcmp(name, m->name, length) == 0)) { + return 0; + } + + if (length) { + memcpy(m->name, name, length); + } + + m->name_length = length; + uint32_t i; + + for (i = 0; i < m->numfriends; ++i) { + m->friendlist[i].name_sent = 0; + } + + return 0; +} + +/* Get our nickname and put it in name. + * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes. + * + * return the length of the name. + */ +uint16_t getself_name(const Messenger *m, uint8_t *name) +{ + if (name == NULL) { + return 0; + } + + memcpy(name, m->name, m->name_length); + + return m->name_length; +} + +/* Get name of friendnumber and put it in name. + * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes. + * + * return length of name if success. + * return -1 if failure. + */ +int getname(const Messenger *m, int32_t friendnumber, uint8_t *name) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + memcpy(name, m->friendlist[friendnumber].name, m->friendlist[friendnumber].name_length); + return m->friendlist[friendnumber].name_length; +} + +int m_get_name_size(const Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + return m->friendlist[friendnumber].name_length; +} + +int m_get_self_name_size(const Messenger *m) +{ + return m->name_length; +} + +int m_set_statusmessage(Messenger *m, const uint8_t *status, uint16_t length) +{ + if (length > MAX_STATUSMESSAGE_LENGTH) { + return -1; + } + + if (m->statusmessage_length == length && (length == 0 || memcmp(m->statusmessage, status, length) == 0)) { + return 0; + } + + if (length) { + memcpy(m->statusmessage, status, length); + } + + m->statusmessage_length = length; + + uint32_t i; + + for (i = 0; i < m->numfriends; ++i) { + m->friendlist[i].statusmessage_sent = 0; + } + + return 0; +} + +int m_set_userstatus(Messenger *m, uint8_t status) +{ + if (status >= USERSTATUS_INVALID) { + return -1; + } + + if (m->userstatus == status) { + return 0; + } + + m->userstatus = (USERSTATUS)status; + uint32_t i; + + for (i = 0; i < m->numfriends; ++i) { + m->friendlist[i].userstatus_sent = 0; + } + + return 0; +} + +/* return the size of friendnumber's user status. + * Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH. + */ +int m_get_statusmessage_size(const Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + return m->friendlist[friendnumber].statusmessage_length; +} + +/* Copy the user status of friendnumber into buf, truncating if needed to maxlen + * bytes, use m_get_statusmessage_size to find out how much you need to allocate. + */ +int m_copy_statusmessage(const Messenger *m, int32_t friendnumber, uint8_t *buf, uint32_t maxlen) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + int msglen = MIN(maxlen, m->friendlist[friendnumber].statusmessage_length); + + memcpy(buf, m->friendlist[friendnumber].statusmessage, msglen); + memset(buf + msglen, 0, maxlen - msglen); + return msglen; +} + +/* return the size of friendnumber's user status. + * Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH. + */ +int m_get_self_statusmessage_size(const Messenger *m) +{ + return m->statusmessage_length; +} + +int m_copy_self_statusmessage(const Messenger *m, uint8_t *buf) +{ + memcpy(buf, m->statusmessage, m->statusmessage_length); + return m->statusmessage_length; +} + +uint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return USERSTATUS_INVALID; + } + + uint8_t status = m->friendlist[friendnumber].userstatus; + + if (status >= USERSTATUS_INVALID) { + status = USERSTATUS_NONE; + } + + return status; +} + +uint8_t m_get_self_userstatus(const Messenger *m) +{ + return m->userstatus; +} + +uint64_t m_get_last_online(const Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return UINT64_MAX; + } + + return m->friendlist[friendnumber].last_seen_time; +} + +int m_set_usertyping(Messenger *m, int32_t friendnumber, uint8_t is_typing) +{ + if (is_typing != 0 && is_typing != 1) { + return -1; + } + + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (m->friendlist[friendnumber].user_istyping == is_typing) { + return 0; + } + + m->friendlist[friendnumber].user_istyping = is_typing; + m->friendlist[friendnumber].user_istyping_sent = 0; + + return 0; +} + +int m_get_istyping(const Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + return m->friendlist[friendnumber].is_typing; +} + +static int send_statusmessage(const Messenger *m, int32_t friendnumber, const uint8_t *status, uint16_t length) +{ + return write_cryptpacket_id(m, friendnumber, PACKET_ID_STATUSMESSAGE, status, length, 0); +} + +static int send_userstatus(const Messenger *m, int32_t friendnumber, uint8_t status) +{ + return write_cryptpacket_id(m, friendnumber, PACKET_ID_USERSTATUS, &status, sizeof(status), 0); +} + +static int send_user_istyping(const Messenger *m, int32_t friendnumber, uint8_t is_typing) +{ + uint8_t typing = is_typing; + return write_cryptpacket_id(m, friendnumber, PACKET_ID_TYPING, &typing, sizeof(typing), 0); +} + +static int set_friend_statusmessage(const Messenger *m, int32_t friendnumber, const uint8_t *status, uint16_t length) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (length > MAX_STATUSMESSAGE_LENGTH) { + return -1; + } + + if (length) { + memcpy(m->friendlist[friendnumber].statusmessage, status, length); + } + + m->friendlist[friendnumber].statusmessage_length = length; + return 0; +} + +static void set_friend_userstatus(const Messenger *m, int32_t friendnumber, uint8_t status) +{ + m->friendlist[friendnumber].userstatus = (USERSTATUS)status; +} + +static void set_friend_typing(const Messenger *m, int32_t friendnumber, uint8_t is_typing) +{ + m->friendlist[friendnumber].is_typing = is_typing; +} + +void m_callback_log(Messenger *m, logger_cb *function, void *context, void *userdata) +{ + logger_callback_log(m->log, function, context, userdata); +} + +/* Set the function that will be executed when a friend request is received. */ +void m_callback_friendrequest(Messenger *m, void (*function)(Messenger *m, const uint8_t *, const uint8_t *, size_t, + void *)) +{ + callback_friendrequest(&(m->fr), (void (*)(void *, const uint8_t *, const uint8_t *, size_t, void *))function, m); +} + +/* Set the function that will be executed when a message from a friend is received. */ +void m_callback_friendmessage(Messenger *m, void (*function)(Messenger *m, uint32_t, unsigned int, const uint8_t *, + size_t, void *)) +{ + m->friend_message = function; +} + +void m_callback_namechange(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, size_t, void *)) +{ + m->friend_namechange = function; +} + +void m_callback_statusmessage(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, size_t, void *)) +{ + m->friend_statusmessagechange = function; +} + +void m_callback_userstatus(Messenger *m, void (*function)(Messenger *m, uint32_t, unsigned int, void *)) +{ + m->friend_userstatuschange = function; +} + +void m_callback_typingchange(Messenger *m, void(*function)(Messenger *m, uint32_t, bool, void *)) +{ + m->friend_typingchange = function; +} + +void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, void *)) +{ + m->read_receipt = function; +} + +void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, uint32_t, unsigned int, void *)) +{ + m->friend_connectionstatuschange = function; +} + +void m_callback_core_connection(Messenger *m, void (*function)(Messenger *m, unsigned int, void *)) +{ + m->core_connection_change = function; +} + +void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, void *), + void *userdata) +{ + m->friend_connectionstatuschange_internal = function; + m->friend_connectionstatuschange_internal_userdata = userdata; +} + +static void check_friend_tcp_udp(Messenger *m, int32_t friendnumber, void *userdata) +{ + int last_connection_udp_tcp = m->friendlist[friendnumber].last_connection_udp_tcp; + + int ret = m_get_friend_connectionstatus(m, friendnumber); + + if (ret == -1) { + return; + } + + if (ret == CONNECTION_UNKNOWN) { + if (last_connection_udp_tcp == CONNECTION_UDP) { + return; + } + + ret = CONNECTION_TCP; + } + + if (last_connection_udp_tcp != ret) { + if (m->friend_connectionstatuschange) { + m->friend_connectionstatuschange(m, friendnumber, ret, userdata); + } + } + + m->friendlist[friendnumber].last_connection_udp_tcp = ret; +} + +static void break_files(const Messenger *m, int32_t friendnumber); +static void check_friend_connectionstatus(Messenger *m, int32_t friendnumber, uint8_t status, void *userdata) +{ + if (status == NOFRIEND) { + return; + } + + const uint8_t was_online = m->friendlist[friendnumber].status == FRIEND_ONLINE; + const uint8_t is_online = status == FRIEND_ONLINE; + + if (is_online != was_online) { + if (was_online) { + break_files(m, friendnumber); + clear_receipts(m, friendnumber); + } else { + m->friendlist[friendnumber].name_sent = 0; + m->friendlist[friendnumber].userstatus_sent = 0; + m->friendlist[friendnumber].statusmessage_sent = 0; + m->friendlist[friendnumber].user_istyping_sent = 0; + } + + m->friendlist[friendnumber].status = status; + + check_friend_tcp_udp(m, friendnumber, userdata); + + if (m->friend_connectionstatuschange_internal) { + m->friend_connectionstatuschange_internal(m, friendnumber, is_online, + m->friend_connectionstatuschange_internal_userdata); + } + } +} + +void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status, void *userdata) +{ + check_friend_connectionstatus(m, friendnumber, status, userdata); + m->friendlist[friendnumber].status = status; +} + +static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data, + uint32_t length, uint8_t congestion_control) +{ + if (friend_not_valid(m, friendnumber)) { + return 0; + } + + if (length >= MAX_CRYPTO_DATA_SIZE || m->friendlist[friendnumber].status != FRIEND_ONLINE) { + return 0; + } + + VLA(uint8_t, packet, length + 1); + packet[0] = packet_id; + + if (length != 0) { + memcpy(packet + 1, data, length); + } + + return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id), packet, length + 1, congestion_control) != -1; +} + +/**********CONFERENCES************/ + + +/* Set the callback for conference invites. + * + * Function(Messenger *m, uint32_t friendnumber, uint8_t *data, uint16_t length, void *userdata) + */ +void m_callback_conference_invite(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, uint16_t, + void *)) +{ + m->conference_invite = function; +} + + +/* Send a conference invite packet. + * + * return 1 on success + * return 0 on failure + */ +int send_conference_invite_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length) +{ + return write_cryptpacket_id(m, friendnumber, PACKET_ID_INVITE_CONFERENCE, data, length, 0); +} + +/****************FILE SENDING*****************/ + + +/* Set the callback for file send requests. + * + * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint32_t filetype, uint64_t filesize, uint8_t *filename, size_t filename_length, void *userdata) + */ +void callback_file_sendrequest(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint32_t, uint64_t, + const uint8_t *, size_t, void *)) +{ + m->file_sendrequest = function; +} + +/* Set the callback for file control requests. + * + * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, unsigned int control_type, void *userdata) + * + */ +void callback_file_control(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, unsigned int, void *)) +{ + m->file_filecontrol = function; +} + +/* Set the callback for file data. + * + * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, uint8_t *data, size_t length, void *userdata) + * + */ +void callback_file_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint64_t, const uint8_t *, + size_t, void *)) +{ + m->file_filedata = function; +} + +/* Set the callback for file request chunk. + * + * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length, void *userdata) + * + */ +void callback_file_reqchunk(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint64_t, size_t, void *)) +{ + m->file_reqchunk = function; +} + +#define MAX_FILENAME_LENGTH 255 + +/* Copy the file transfer file id to file_id + * + * return 0 on success. + * return -1 if friend not valid. + * return -2 if filenumber not valid + */ +int file_get_id(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint8_t *file_id) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (m->friendlist[friendnumber].status != FRIEND_ONLINE) { + return -2; + } + + uint32_t temp_filenum; + uint8_t send_receive, file_number; + + if (filenumber >= (1 << 16)) { + send_receive = 1; + temp_filenum = (filenumber >> 16) - 1; + } else { + send_receive = 0; + temp_filenum = filenumber; + } + + if (temp_filenum >= MAX_CONCURRENT_FILE_PIPES) { + return -2; + } + + file_number = temp_filenum; + + struct File_Transfers *ft; + + if (send_receive) { + ft = &m->friendlist[friendnumber].file_receiving[file_number]; + } else { + ft = &m->friendlist[friendnumber].file_sending[file_number]; + } + + if (ft->status == FILESTATUS_NONE) { + return -2; + } + + memcpy(file_id, ft->id, FILE_ID_LENGTH); + return 0; +} + +/* Send a file send request. + * Maximum filename length is 255 bytes. + * return 1 on success + * return 0 on failure + */ +static int file_sendrequest(const Messenger *m, int32_t friendnumber, uint8_t filenumber, uint32_t file_type, + uint64_t filesize, const uint8_t *file_id, const uint8_t *filename, uint16_t filename_length) +{ + if (friend_not_valid(m, friendnumber)) { + return 0; + } + + if (filename_length > MAX_FILENAME_LENGTH) { + return 0; + } + + VLA(uint8_t, packet, 1 + sizeof(file_type) + sizeof(filesize) + FILE_ID_LENGTH + filename_length); + packet[0] = filenumber; + file_type = net_htonl(file_type); + memcpy(packet + 1, &file_type, sizeof(file_type)); + host_to_net((uint8_t *)&filesize, sizeof(filesize)); + memcpy(packet + 1 + sizeof(file_type), &filesize, sizeof(filesize)); + memcpy(packet + 1 + sizeof(file_type) + sizeof(filesize), file_id, FILE_ID_LENGTH); + + if (filename_length) { + memcpy(packet + 1 + sizeof(file_type) + sizeof(filesize) + FILE_ID_LENGTH, filename, filename_length); + } + + return write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_SENDREQUEST, packet, SIZEOF_VLA(packet), 0); +} + +/* Send a file send request. + * Maximum filename length is 255 bytes. + * return file number on success + * return -1 if friend not found. + * return -2 if filename length invalid. + * return -3 if no more file sending slots left. + * return -4 if could not send packet (friend offline). + * + */ +long int new_filesender(const Messenger *m, int32_t friendnumber, uint32_t file_type, uint64_t filesize, + const uint8_t *file_id, const uint8_t *filename, uint16_t filename_length) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (filename_length > MAX_FILENAME_LENGTH) { + return -2; + } + + uint32_t i; + + for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) { + if (m->friendlist[friendnumber].file_sending[i].status == FILESTATUS_NONE) { + break; + } + } + + if (i == MAX_CONCURRENT_FILE_PIPES) { + return -3; + } + + if (file_sendrequest(m, friendnumber, i, file_type, filesize, file_id, filename, filename_length) == 0) { + return -4; + } + + struct File_Transfers *ft = &m->friendlist[friendnumber].file_sending[i]; + + ft->status = FILESTATUS_NOT_ACCEPTED; + + ft->size = filesize; + + ft->transferred = 0; + + ft->requested = 0; + + ft->slots_allocated = 0; + + ft->paused = FILE_PAUSE_NOT; + + memcpy(ft->id, file_id, FILE_ID_LENGTH); + + ++m->friendlist[friendnumber].num_sending_files; + + return i; +} + +static int send_file_control_packet(const Messenger *m, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber, + uint8_t control_type, uint8_t *data, uint16_t data_length) +{ + if ((unsigned int)(1 + 3 + data_length) > MAX_CRYPTO_DATA_SIZE) { + return -1; + } + + VLA(uint8_t, packet, 3 + data_length); + + packet[0] = send_receive; + packet[1] = filenumber; + packet[2] = control_type; + + if (data_length) { + memcpy(packet + 3, data, data_length); + } + + return write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_CONTROL, packet, SIZEOF_VLA(packet), 0); +} + +/* Send a file control request. + * + * return 0 on success + * return -1 if friend not valid. + * return -2 if friend not online. + * return -3 if file number invalid. + * return -4 if file control is bad. + * return -5 if file already paused. + * return -6 if resume file failed because it was only paused by the other. + * return -7 if resume file failed because it wasn't paused. + * return -8 if packet failed to send. + */ +int file_control(const Messenger *m, int32_t friendnumber, uint32_t filenumber, unsigned int control) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (m->friendlist[friendnumber].status != FRIEND_ONLINE) { + return -2; + } + + uint32_t temp_filenum; + uint8_t send_receive, file_number; + + if (filenumber >= (1 << 16)) { + send_receive = 1; + temp_filenum = (filenumber >> 16) - 1; + } else { + send_receive = 0; + temp_filenum = filenumber; + } + + if (temp_filenum >= MAX_CONCURRENT_FILE_PIPES) { + return -3; + } + + file_number = temp_filenum; + + struct File_Transfers *ft; + + if (send_receive) { + ft = &m->friendlist[friendnumber].file_receiving[file_number]; + } else { + ft = &m->friendlist[friendnumber].file_sending[file_number]; + } + + if (ft->status == FILESTATUS_NONE) { + return -3; + } + + if (control > FILECONTROL_KILL) { + return -4; + } + + if (control == FILECONTROL_PAUSE && ((ft->paused & FILE_PAUSE_US) || ft->status != FILESTATUS_TRANSFERRING)) { + return -5; + } + + if (control == FILECONTROL_ACCEPT) { + if (ft->status == FILESTATUS_TRANSFERRING) { + if (!(ft->paused & FILE_PAUSE_US)) { + if (ft->paused & FILE_PAUSE_OTHER) { + return -6; + } + + return -7; + } + } else { + if (ft->status != FILESTATUS_NOT_ACCEPTED) { + return -7; + } + + if (!send_receive) { + return -6; + } + } + } + + if (send_file_control_packet(m, friendnumber, send_receive, file_number, control, 0, 0)) { + if (control == FILECONTROL_KILL) { + ft->status = FILESTATUS_NONE; + + if (send_receive == 0) { + --m->friendlist[friendnumber].num_sending_files; + } + } else if (control == FILECONTROL_PAUSE) { + ft->paused |= FILE_PAUSE_US; + } else if (control == FILECONTROL_ACCEPT) { + ft->status = FILESTATUS_TRANSFERRING; + + if (ft->paused & FILE_PAUSE_US) { + ft->paused ^= FILE_PAUSE_US; + } + } + } else { + return -8; + } + + return 0; +} + +/* Send a seek file control request. + * + * return 0 on success + * return -1 if friend not valid. + * return -2 if friend not online. + * return -3 if file number invalid. + * return -4 if not receiving file. + * return -5 if file status wrong. + * return -6 if position bad. + * return -8 if packet failed to send. + */ +int file_seek(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint64_t position) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (m->friendlist[friendnumber].status != FRIEND_ONLINE) { + return -2; + } + + if (filenumber < (1 << 16)) { + // Not receiving. + return -4; + } + + uint32_t temp_filenum = (filenumber >> 16) - 1; + + if (temp_filenum >= MAX_CONCURRENT_FILE_PIPES) { + return -3; + } + + assert(temp_filenum <= UINT8_MAX); + uint8_t file_number = temp_filenum; + + // We're always receiving at this point. + struct File_Transfers *ft = &m->friendlist[friendnumber].file_receiving[file_number]; + + if (ft->status == FILESTATUS_NONE) { + return -3; + } + + if (ft->status != FILESTATUS_NOT_ACCEPTED) { + return -5; + } + + if (position >= ft->size) { + return -6; + } + + uint64_t sending_pos = position; + host_to_net((uint8_t *)&sending_pos, sizeof(sending_pos)); + + if (send_file_control_packet(m, friendnumber, 1, file_number, FILECONTROL_SEEK, (uint8_t *)&sending_pos, + sizeof(sending_pos))) { + ft->transferred = position; + } else { + return -8; + } + + return 0; +} + +/* return packet number on success. + * return -1 on failure. + */ +static int64_t send_file_data_packet(const Messenger *m, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, + uint16_t length) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + VLA(uint8_t, packet, 2 + length); + packet[0] = PACKET_ID_FILE_DATA; + packet[1] = filenumber; + + if (length) { + memcpy(packet + 2, data, length); + } + + return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id), packet, SIZEOF_VLA(packet), 1); +} + +#define MAX_FILE_DATA_SIZE (MAX_CRYPTO_DATA_SIZE - 2) +#define MIN_SLOTS_FREE (CRYPTO_MIN_QUEUE_LENGTH / 4) +/* Send file data. + * + * return 0 on success + * return -1 if friend not valid. + * return -2 if friend not online. + * return -3 if filenumber invalid. + * return -4 if file transfer not transferring. + * return -5 if bad data size. + * return -6 if packet queue full. + * return -7 if wrong position. + */ +int file_data(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data, + uint16_t length) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (m->friendlist[friendnumber].status != FRIEND_ONLINE) { + return -2; + } + + if (filenumber >= MAX_CONCURRENT_FILE_PIPES) { + return -3; + } + + struct File_Transfers *ft = &m->friendlist[friendnumber].file_sending[filenumber]; + + if (ft->status != FILESTATUS_TRANSFERRING) { + return -4; + } + + if (length > MAX_FILE_DATA_SIZE) { + return -5; + } + + if (ft->size - ft->transferred < length) { + return -5; + } + + if (ft->size != UINT64_MAX && length != MAX_FILE_DATA_SIZE && (ft->transferred + length) != ft->size) { + return -5; + } + + if (position != ft->transferred || (ft->requested <= position && ft->size != 0)) { + return -7; + } + + /* Prevent file sending from filling up the entire buffer preventing messages from being sent. + * TODO(irungentoo): remove */ + if (crypto_num_free_sendqueue_slots(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id)) < MIN_SLOTS_FREE) { + return -6; + } + + int64_t ret = send_file_data_packet(m, friendnumber, filenumber, data, length); + + if (ret != -1) { + // TODO(irungentoo): record packet ids to check if other received complete file. + ft->transferred += length; + + if (ft->slots_allocated) { + --ft->slots_allocated; + } + + if (length != MAX_FILE_DATA_SIZE || ft->size == ft->transferred) { + ft->status = FILESTATUS_FINISHED; + ft->last_packet_number = ret; + } + + return 0; + } + + return -6; +} + +/* Give the number of bytes left to be sent/received. + * + * send_receive is 0 if we want the sending files, 1 if we want the receiving. + * + * return number of bytes remaining to be sent/received on success + * return 0 on failure + */ +uint64_t file_dataremaining(const Messenger *m, int32_t friendnumber, uint8_t filenumber, uint8_t send_receive) +{ + if (friend_not_valid(m, friendnumber)) { + return 0; + } + + if (send_receive == 0) { + if (m->friendlist[friendnumber].file_sending[filenumber].status == FILESTATUS_NONE) { + return 0; + } + + return m->friendlist[friendnumber].file_sending[filenumber].size - + m->friendlist[friendnumber].file_sending[filenumber].transferred; + } + + if (m->friendlist[friendnumber].file_receiving[filenumber].status == FILESTATUS_NONE) { + return 0; + } + + return m->friendlist[friendnumber].file_receiving[filenumber].size - + m->friendlist[friendnumber].file_receiving[filenumber].transferred; +} + +static void do_reqchunk_filecb(Messenger *m, int32_t friendnumber, void *userdata) +{ + if (!m->friendlist[friendnumber].num_sending_files) { + return; + } + + int free_slots = crypto_num_free_sendqueue_slots(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id)); + + if (free_slots < MIN_SLOTS_FREE) { + free_slots = 0; + } else { + free_slots -= MIN_SLOTS_FREE; + } + + unsigned int i, num = m->friendlist[friendnumber].num_sending_files; + + for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) { + struct File_Transfers *ft = &m->friendlist[friendnumber].file_sending[i]; + + if (ft->status != FILESTATUS_NONE) { + --num; + + if (ft->status == FILESTATUS_FINISHED) { + /* Check if file was entirely sent. */ + if (friend_received_packet(m, friendnumber, ft->last_packet_number) == 0) { + if (m->file_reqchunk) { + (*m->file_reqchunk)(m, friendnumber, i, ft->transferred, 0, userdata); + } + + ft->status = FILESTATUS_NONE; + --m->friendlist[friendnumber].num_sending_files; + } + } + + /* TODO(irungentoo): if file is too slow, switch to the next. */ + if (ft->slots_allocated > (unsigned int)free_slots) { + free_slots = 0; + } else { + free_slots -= ft->slots_allocated; + } + } + + while (ft->status == FILESTATUS_TRANSFERRING && (ft->paused == FILE_PAUSE_NOT)) { + if (max_speed_reached(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id))) { + free_slots = 0; + } + + if (free_slots == 0) { + break; + } + + uint16_t length = MAX_FILE_DATA_SIZE; + + if (ft->size == 0) { + /* Send 0 data to friend if file is 0 length. */ + file_data(m, friendnumber, i, 0, 0, 0); + break; + } + + if (ft->size == ft->requested) { + break; + } + + if (ft->size - ft->requested < length) { + length = ft->size - ft->requested; + } + + ++ft->slots_allocated; + + uint64_t position = ft->requested; + ft->requested += length; + + if (m->file_reqchunk) { + (*m->file_reqchunk)(m, friendnumber, i, position, length, userdata); + } + + --free_slots; + } + + if (num == 0) { + break; + } + } +} + +/* Run this when the friend disconnects. + * Kill all current file transfers. + */ +static void break_files(const Messenger *m, int32_t friendnumber) +{ + uint32_t i; + + // TODO(irungentoo): Inform the client which file transfers get killed with a callback? + for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) { + if (m->friendlist[friendnumber].file_sending[i].status != FILESTATUS_NONE) { + m->friendlist[friendnumber].file_sending[i].status = FILESTATUS_NONE; + } + + if (m->friendlist[friendnumber].file_receiving[i].status != FILESTATUS_NONE) { + m->friendlist[friendnumber].file_receiving[i].status = FILESTATUS_NONE; + } + } +} + +static struct File_Transfers *get_file_transfer(uint8_t receive_send, uint8_t filenumber, + uint32_t *real_filenumber, Friend *sender) +{ + struct File_Transfers *ft; + + if (receive_send == 0) { + *real_filenumber = (filenumber + 1) << 16; + ft = &sender->file_receiving[filenumber]; + } else { + *real_filenumber = filenumber; + ft = &sender->file_sending[filenumber]; + } + + if (ft->status == FILESTATUS_NONE) { + return NULL; + } + + return ft; +} + +/* return -1 on failure, 0 on success. + */ +static int handle_filecontrol(Messenger *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber, + uint8_t control_type, const uint8_t *data, uint16_t length, void *userdata) +{ + if (receive_send > 1) { + LOGGER_DEBUG(m->log, "file control (friend %d, file %d): receive_send value is invalid (should be 0 or 1): %d", + friendnumber, filenumber, receive_send); + return -1; + } + + uint32_t real_filenumber; + struct File_Transfers *ft = get_file_transfer(receive_send, filenumber, &real_filenumber, &m->friendlist[friendnumber]); + + if (ft == NULL) { + LOGGER_DEBUG(m->log, "file control (friend %d, file %d): file transfer does not exist; telling the other to kill it", + friendnumber, filenumber); + send_file_control_packet(m, friendnumber, !receive_send, filenumber, FILECONTROL_KILL, 0, 0); + return -1; + } + + switch (control_type) { + case FILECONTROL_ACCEPT: { + if (receive_send && ft->status == FILESTATUS_NOT_ACCEPTED) { + ft->status = FILESTATUS_TRANSFERRING; + } else { + if (ft->paused & FILE_PAUSE_OTHER) { + ft->paused ^= FILE_PAUSE_OTHER; + } else { + LOGGER_DEBUG(m->log, "file control (friend %d, file %d): friend told us to resume file transfer that wasn't paused", + friendnumber, filenumber); + return -1; + } + } + + if (m->file_filecontrol) { + m->file_filecontrol(m, friendnumber, real_filenumber, control_type, userdata); + } + + return 0; + } + + case FILECONTROL_PAUSE: { + if ((ft->paused & FILE_PAUSE_OTHER) || ft->status != FILESTATUS_TRANSFERRING) { + LOGGER_DEBUG(m->log, "file control (friend %d, file %d): friend told us to pause file transfer that is already paused", + friendnumber, filenumber); + return -1; + } + + ft->paused |= FILE_PAUSE_OTHER; + + if (m->file_filecontrol) { + m->file_filecontrol(m, friendnumber, real_filenumber, control_type, userdata); + } + + return 0; + } + + case FILECONTROL_KILL: { + if (m->file_filecontrol) { + m->file_filecontrol(m, friendnumber, real_filenumber, control_type, userdata); + } + + ft->status = FILESTATUS_NONE; + + if (receive_send) { + --m->friendlist[friendnumber].num_sending_files; + } + + return 0; + } + + case FILECONTROL_SEEK: { + uint64_t position; + + if (length != sizeof(position)) { + LOGGER_DEBUG(m->log, "file control (friend %d, file %d): expected payload of length %d, but got %d", + friendnumber, filenumber, (uint32_t)sizeof(position), length); + return -1; + } + + /* seek can only be sent by the receiver to seek before resuming broken transfers. */ + if (ft->status != FILESTATUS_NOT_ACCEPTED || !receive_send) { + LOGGER_DEBUG(m->log, + "file control (friend %d, file %d): seek was either sent by a sender or by the receiver after accepting", + friendnumber, filenumber); + return -1; + } + + memcpy(&position, data, sizeof(position)); + net_to_host((uint8_t *) &position, sizeof(position)); + + if (position >= ft->size) { + LOGGER_DEBUG(m->log, + "file control (friend %d, file %d): seek position %lld exceeds file size %lld", + friendnumber, filenumber, (unsigned long long)position, (unsigned long long)ft->size); + return -1; + } + + ft->transferred = ft->requested = position; + return 0; + } + + default: { + LOGGER_DEBUG(m->log, "file control (friend %d, file %d): invalid file control: %d", + friendnumber, filenumber, control_type); + return -1; + } + } +} + +/**************************************/ + +/* Set the callback for msi packets. + * + * Function(Messenger *m, int friendnumber, uint8_t *data, uint16_t length, void *userdata) + */ +void m_callback_msi_packet(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, uint16_t, void *), + void *userdata) +{ + m->msi_packet = function; + m->msi_packet_userdata = userdata; +} + +/* Send an msi packet. + * + * return 1 on success + * return 0 on failure + */ +int m_msi_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length) +{ + return write_cryptpacket_id(m, friendnumber, PACKET_ID_MSI, data, length, 0); +} + +static int m_handle_custom_lossy_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length, + void *userdata) +{ + Messenger *m = (Messenger *)object; + + if (friend_not_valid(m, friend_num)) { + return 1; + } + + if (packet[0] < (PACKET_ID_LOSSY_RANGE_START + PACKET_LOSSY_AV_RESERVED)) { + if (m->friendlist[friend_num].lossy_rtp_packethandlers[packet[0] % PACKET_LOSSY_AV_RESERVED].function) { + return m->friendlist[friend_num].lossy_rtp_packethandlers[packet[0] % PACKET_LOSSY_AV_RESERVED].function( + m, friend_num, packet, length, m->friendlist[friend_num].lossy_rtp_packethandlers[packet[0] % + PACKET_LOSSY_AV_RESERVED].object); + } + + return 1; + } + + if (m->lossy_packethandler) { + m->lossy_packethandler(m, friend_num, packet, length, userdata); + } + + return 1; +} + +void custom_lossy_packet_registerhandler(Messenger *m, void (*packet_handler_callback)(Messenger *m, + uint32_t friendnumber, const uint8_t *data, size_t len, void *object)) +{ + m->lossy_packethandler = packet_handler_callback; +} + +int m_callback_rtp_packet(Messenger *m, int32_t friendnumber, uint8_t byte, int (*packet_handler_callback)(Messenger *m, + uint32_t friendnumber, const uint8_t *data, uint16_t len, void *object), void *object) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (byte < PACKET_ID_LOSSY_RANGE_START) { + return -1; + } + + if (byte >= (PACKET_ID_LOSSY_RANGE_START + PACKET_LOSSY_AV_RESERVED)) { + return -1; + } + + m->friendlist[friendnumber].lossy_rtp_packethandlers[byte % PACKET_LOSSY_AV_RESERVED].function = + packet_handler_callback; + m->friendlist[friendnumber].lossy_rtp_packethandlers[byte % PACKET_LOSSY_AV_RESERVED].object = object; + return 0; +} + + +int m_send_custom_lossy_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) { + return -2; + } + + if (data[0] < PACKET_ID_LOSSY_RANGE_START) { + return -3; + } + + if (data[0] >= (PACKET_ID_LOSSY_RANGE_START + PACKET_ID_LOSSY_RANGE_SIZE)) { + return -3; + } + + if (m->friendlist[friendnumber].status != FRIEND_ONLINE) { + return -4; + } + + if (send_lossy_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id), data, length) == -1) { + return -5; + } + + return 0; +} + +static int handle_custom_lossless_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length, + void *userdata) +{ + Messenger *m = (Messenger *)object; + + if (friend_not_valid(m, friend_num)) { + return -1; + } + + if (packet[0] < PACKET_ID_LOSSLESS_RANGE_START) { + return -1; + } + + if (packet[0] >= (PACKET_ID_LOSSLESS_RANGE_START + PACKET_ID_LOSSLESS_RANGE_SIZE)) { + return -1; + } + + if (m->lossless_packethandler) { + m->lossless_packethandler(m, friend_num, packet, length, userdata); + } + + return 1; +} + +void custom_lossless_packet_registerhandler(Messenger *m, void (*packet_handler_callback)(Messenger *m, + uint32_t friendnumber, const uint8_t *data, size_t len, void *object)) +{ + m->lossless_packethandler = packet_handler_callback; +} + +int send_custom_lossless_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) { + return -2; + } + + if (data[0] < PACKET_ID_LOSSLESS_RANGE_START) { + return -3; + } + + if (data[0] >= (PACKET_ID_LOSSLESS_RANGE_START + PACKET_ID_LOSSLESS_RANGE_SIZE)) { + return -3; + } + + if (m->friendlist[friendnumber].status != FRIEND_ONLINE) { + return -4; + } + + if (write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id), data, length, 1) == -1) { + return -5; + } + + return 0; +} + +/* Function to filter out some friend requests*/ +static int friend_already_added(const uint8_t *real_pk, void *data) +{ + const Messenger *m = (const Messenger *)data; + + if (getfriend_id(m, real_pk) == -1) { + return 0; + } + + return -1; +} + +/* Run this at startup. */ +Messenger *new_messenger(Messenger_Options *options, unsigned int *error) +{ + if (!options) { + return NULL; + } + + Messenger *m = (Messenger *)calloc(1, sizeof(Messenger)); + + if (error) { + *error = MESSENGER_ERROR_OTHER; + } + + if (!m) { + return NULL; + } + + Logger *log = NULL; + + if (options->log_callback) { + log = logger_new(); + + if (log != NULL) { + logger_callback_log(log, options->log_callback, m, options->log_user_data); + } + } + + m->log = log; + + unsigned int net_err = 0; + + if (options->udp_disabled) { + /* this is the easiest way to completely disable UDP without changing too much code. */ + m->net = (Networking_Core *)calloc(1, sizeof(Networking_Core)); + } else { + IP ip; + ip_init(&ip, options->ipv6enabled); + m->net = new_networking_ex(log, ip, options->port_range[0], options->port_range[1], &net_err); + } + + if (m->net == NULL) { + free(m); + + if (error && net_err == 1) { + *error = MESSENGER_ERROR_PORT; + } + + return NULL; + } + + m->dht = new_DHT(m->log, m->net, options->hole_punching_enabled); + + if (m->dht == NULL) { + kill_networking(m->net); + free(m); + return NULL; + } + + m->net_crypto = new_net_crypto(m->log, m->dht, &options->proxy_info); + + if (m->net_crypto == NULL) { + kill_networking(m->net); + kill_DHT(m->dht); + free(m); + return NULL; + } + + m->onion = new_onion(m->dht); + m->onion_a = new_onion_announce(m->dht); + m->onion_c = new_onion_client(m->net_crypto); + m->fr_c = new_friend_connections(m->onion_c, options->local_discovery_enabled); + + if (!(m->onion && m->onion_a && m->onion_c)) { + kill_friend_connections(m->fr_c); + kill_onion(m->onion); + kill_onion_announce(m->onion_a); + kill_onion_client(m->onion_c); + kill_net_crypto(m->net_crypto); + kill_DHT(m->dht); + kill_networking(m->net); + free(m); + return NULL; + } + + if (options->tcp_server_port) { + m->tcp_server = new_TCP_server(options->ipv6enabled, 1, &options->tcp_server_port, m->dht->self_secret_key, m->onion); + + if (m->tcp_server == NULL) { + kill_friend_connections(m->fr_c); + kill_onion(m->onion); + kill_onion_announce(m->onion_a); + kill_onion_client(m->onion_c); + kill_net_crypto(m->net_crypto); + kill_DHT(m->dht); + kill_networking(m->net); + free(m); + + if (error) { + *error = MESSENGER_ERROR_TCP_SERVER; + } + + return NULL; + } + } + + m->options = *options; + friendreq_init(&(m->fr), m->fr_c); + set_nospam(&(m->fr), random_int()); + set_filter_function(&(m->fr), &friend_already_added, m); + + m->lastdump = 0; + + if (error) { + *error = MESSENGER_ERROR_NONE; + } + + return m; +} + +/* Run this before closing shop. */ +void kill_messenger(Messenger *m) +{ + if (!m) { + return; + } + + uint32_t i; + + if (m->tcp_server) { + kill_TCP_server(m->tcp_server); + } + + kill_friend_connections(m->fr_c); + kill_onion(m->onion); + kill_onion_announce(m->onion_a); + kill_onion_client(m->onion_c); + kill_net_crypto(m->net_crypto); + kill_DHT(m->dht); + kill_networking(m->net); + + for (i = 0; i < m->numfriends; ++i) { + clear_receipts(m, i); + } + + logger_kill(m->log); + free(m->friendlist); + free(m); +} + +/* Check for and handle a timed-out friend request. If the request has + * timed-out then the friend status is set back to FRIEND_ADDED. + * i: friendlist index of the timed-out friend + * t: time + */ +static void check_friend_request_timed_out(Messenger *m, uint32_t i, uint64_t t, void *userdata) +{ + Friend *f = &m->friendlist[i]; + + if (f->friendrequest_lastsent + f->friendrequest_timeout < t) { + set_friend_status(m, i, FRIEND_ADDED, userdata); + /* Double the default timeout every time if friendrequest is assumed + * to have been sent unsuccessfully. + */ + f->friendrequest_timeout *= 2; + } +} + +static int m_handle_status(void *object, int i, uint8_t status, void *userdata) +{ + Messenger *m = (Messenger *)object; + + if (status) { /* Went online. */ + send_online_packet(m, i); + } else { /* Went offline. */ + if (m->friendlist[i].status == FRIEND_ONLINE) { + set_friend_status(m, i, FRIEND_CONFIRMED, userdata); + } + } + + return 0; +} + +static int m_handle_packet(void *object, int i, const uint8_t *temp, uint16_t len, void *userdata) +{ + if (len == 0) { + return -1; + } + + Messenger *m = (Messenger *)object; + uint8_t packet_id = temp[0]; + const uint8_t *data = temp + 1; + uint32_t data_length = len - 1; + + if (m->friendlist[i].status != FRIEND_ONLINE) { + if (packet_id == PACKET_ID_ONLINE && len == 1) { + set_friend_status(m, i, FRIEND_ONLINE, userdata); + send_online_packet(m, i); + } else { + return -1; + } + } + + switch (packet_id) { + case PACKET_ID_OFFLINE: { + if (data_length != 0) { + break; + } + + set_friend_status(m, i, FRIEND_CONFIRMED, userdata); + break; + } + + case PACKET_ID_NICKNAME: { + if (data_length > MAX_NAME_LENGTH) { + break; + } + + /* Make sure the NULL terminator is present. */ + VLA(uint8_t, data_terminated, data_length + 1); + memcpy(data_terminated, data, data_length); + data_terminated[data_length] = 0; + + /* inform of namechange before we overwrite the old name */ + if (m->friend_namechange) { + m->friend_namechange(m, i, data_terminated, data_length, userdata); + } + + memcpy(m->friendlist[i].name, data_terminated, data_length); + m->friendlist[i].name_length = data_length; + + break; + } + + case PACKET_ID_STATUSMESSAGE: { + if (data_length > MAX_STATUSMESSAGE_LENGTH) { + break; + } + + /* Make sure the NULL terminator is present. */ + VLA(uint8_t, data_terminated, data_length + 1); + memcpy(data_terminated, data, data_length); + data_terminated[data_length] = 0; + + if (m->friend_statusmessagechange) { + m->friend_statusmessagechange(m, i, data_terminated, data_length, userdata); + } + + set_friend_statusmessage(m, i, data_terminated, data_length); + break; + } + + case PACKET_ID_USERSTATUS: { + if (data_length != 1) { + break; + } + + USERSTATUS status = (USERSTATUS)data[0]; + + if (status >= USERSTATUS_INVALID) { + break; + } + + if (m->friend_userstatuschange) { + m->friend_userstatuschange(m, i, status, userdata); + } + + set_friend_userstatus(m, i, status); + break; + } + + case PACKET_ID_TYPING: { + if (data_length != 1) { + break; + } + + bool typing = !!data[0]; + + set_friend_typing(m, i, typing); + + if (m->friend_typingchange) { + m->friend_typingchange(m, i, typing, userdata); + } + + break; + } + + case PACKET_ID_MESSAGE: // fall-through + case PACKET_ID_ACTION: { + if (data_length == 0) { + break; + } + + const uint8_t *message = data; + uint16_t message_length = data_length; + + /* Make sure the NULL terminator is present. */ + VLA(uint8_t, message_terminated, message_length + 1); + memcpy(message_terminated, message, message_length); + message_terminated[message_length] = 0; + uint8_t type = packet_id - PACKET_ID_MESSAGE; + + if (m->friend_message) { + (*m->friend_message)(m, i, type, message_terminated, message_length, userdata); + } + + break; + } + + case PACKET_ID_INVITE_CONFERENCE: { + if (data_length == 0) { + break; + } + + if (m->conference_invite) { + (*m->conference_invite)(m, i, data, data_length, userdata); + } + + break; + } + + case PACKET_ID_FILE_SENDREQUEST: { + const unsigned int head_length = 1 + sizeof(uint32_t) + sizeof(uint64_t) + FILE_ID_LENGTH; + + if (data_length < head_length) { + break; + } + + uint8_t filenumber = data[0]; + + if (filenumber >= MAX_CONCURRENT_FILE_PIPES) { + break; + } + + uint64_t filesize; + uint32_t file_type; + uint16_t filename_length = data_length - head_length; + + if (filename_length > MAX_FILENAME_LENGTH) { + break; + } + + memcpy(&file_type, data + 1, sizeof(file_type)); + file_type = net_ntohl(file_type); + + memcpy(&filesize, data + 1 + sizeof(uint32_t), sizeof(filesize)); + net_to_host((uint8_t *) &filesize, sizeof(filesize)); + struct File_Transfers *ft = &m->friendlist[i].file_receiving[filenumber]; + + if (ft->status != FILESTATUS_NONE) { + break; + } + + ft->status = FILESTATUS_NOT_ACCEPTED; + ft->size = filesize; + ft->transferred = 0; + ft->paused = FILE_PAUSE_NOT; + memcpy(ft->id, data + 1 + sizeof(uint32_t) + sizeof(uint64_t), FILE_ID_LENGTH); + + VLA(uint8_t, filename_terminated, filename_length + 1); + uint8_t *filename = NULL; + + if (filename_length) { + /* Force NULL terminate file name. */ + memcpy(filename_terminated, data + head_length, filename_length); + filename_terminated[filename_length] = 0; + filename = filename_terminated; + } + + uint32_t real_filenumber = filenumber; + real_filenumber += 1; + real_filenumber <<= 16; + + if (m->file_sendrequest) { + (*m->file_sendrequest)(m, i, real_filenumber, file_type, filesize, filename, filename_length, + userdata); + } + + break; + } + + case PACKET_ID_FILE_CONTROL: { + if (data_length < 3) { + break; + } + + uint8_t send_receive = data[0]; + uint8_t filenumber = data[1]; + uint8_t control_type = data[2]; + + if (filenumber >= MAX_CONCURRENT_FILE_PIPES) { + break; + } + + if (handle_filecontrol(m, i, send_receive, filenumber, control_type, data + 3, data_length - 3, userdata) == -1) { + // TODO(iphydf): Do something different here? Right now, this + // check is pointless. + break; + } + + break; + } + + case PACKET_ID_FILE_DATA: { + if (data_length < 1) { + break; + } + + uint8_t filenumber = data[0]; + + if (filenumber >= MAX_CONCURRENT_FILE_PIPES) { + break; + } + + struct File_Transfers *ft = &m->friendlist[i].file_receiving[filenumber]; + + if (ft->status != FILESTATUS_TRANSFERRING) { + break; + } + + uint64_t position = ft->transferred; + uint32_t real_filenumber = filenumber; + real_filenumber += 1; + real_filenumber <<= 16; + uint16_t file_data_length = (data_length - 1); + const uint8_t *file_data; + + if (file_data_length == 0) { + file_data = NULL; + } else { + file_data = data + 1; + } + + /* Prevent more data than the filesize from being passed to clients. */ + if ((ft->transferred + file_data_length) > ft->size) { + file_data_length = ft->size - ft->transferred; + } + + if (m->file_filedata) { + (*m->file_filedata)(m, i, real_filenumber, position, file_data, file_data_length, userdata); + } + + ft->transferred += file_data_length; + + if (file_data_length && (ft->transferred >= ft->size || file_data_length != MAX_FILE_DATA_SIZE)) { + file_data_length = 0; + file_data = NULL; + position = ft->transferred; + + /* Full file received. */ + if (m->file_filedata) { + (*m->file_filedata)(m, i, real_filenumber, position, file_data, file_data_length, userdata); + } + } + + /* Data is zero, filetransfer is over. */ + if (file_data_length == 0) { + ft->status = FILESTATUS_NONE; + } + + break; + } + + case PACKET_ID_MSI: { + if (data_length == 0) { + break; + } + + if (m->msi_packet) { + (*m->msi_packet)(m, i, data, data_length, m->msi_packet_userdata); + } + + break; + } + + default: { + handle_custom_lossless_packet(object, i, temp, len, userdata); + break; + } + } + + return 0; +} + +static void do_friends(Messenger *m, void *userdata) +{ + uint32_t i; + uint64_t temp_time = unix_time(); + + for (i = 0; i < m->numfriends; ++i) { + if (m->friendlist[i].status == FRIEND_ADDED) { + int fr = send_friend_request_packet(m->fr_c, m->friendlist[i].friendcon_id, m->friendlist[i].friendrequest_nospam, + m->friendlist[i].info, + m->friendlist[i].info_size); + + if (fr >= 0) { + set_friend_status(m, i, FRIEND_REQUESTED, userdata); + m->friendlist[i].friendrequest_lastsent = temp_time; + } + } + + if (m->friendlist[i].status == FRIEND_REQUESTED + || m->friendlist[i].status == FRIEND_CONFIRMED) { /* friend is not online. */ + if (m->friendlist[i].status == FRIEND_REQUESTED) { + /* If we didn't connect to friend after successfully sending him a friend request the request is deemed + * unsuccessful so we set the status back to FRIEND_ADDED and try again. + */ + check_friend_request_timed_out(m, i, temp_time, userdata); + } + } + + if (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online. */ + if (m->friendlist[i].name_sent == 0) { + if (m_sendname(m, i, m->name, m->name_length)) { + m->friendlist[i].name_sent = 1; + } + } + + if (m->friendlist[i].statusmessage_sent == 0) { + if (send_statusmessage(m, i, m->statusmessage, m->statusmessage_length)) { + m->friendlist[i].statusmessage_sent = 1; + } + } + + if (m->friendlist[i].userstatus_sent == 0) { + if (send_userstatus(m, i, m->userstatus)) { + m->friendlist[i].userstatus_sent = 1; + } + } + + if (m->friendlist[i].user_istyping_sent == 0) { + if (send_user_istyping(m, i, m->friendlist[i].user_istyping)) { + m->friendlist[i].user_istyping_sent = 1; + } + } + + check_friend_tcp_udp(m, i, userdata); + do_receipts(m, i, userdata); + do_reqchunk_filecb(m, i, userdata); + + m->friendlist[i].last_seen_time = (uint64_t) time(NULL); + } + } +} + +static void connection_status_cb(Messenger *m, void *userdata) +{ + unsigned int conn_status = onion_connection_status(m->onion_c); + + if (conn_status != m->last_connection_status) { + if (m->core_connection_change) { + (*m->core_connection_change)(m, conn_status, userdata); + } + + m->last_connection_status = conn_status; + } +} + + +#define DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS 60UL + +#define IDSTRING_LEN (CRYPTO_PUBLIC_KEY_SIZE * 2 + 1) +/* id_str should be of length at least IDSTRING_LEN */ +static char *id_to_string(const uint8_t *pk, char *id_str, size_t length) +{ + if (length < IDSTRING_LEN) { + snprintf(id_str, length, "Bad buf length"); + return id_str; + } + + for (uint32_t i = 0; i < CRYPTO_PUBLIC_KEY_SIZE; i++) { + sprintf(&id_str[i * 2], "%02X", pk[i]); + } + + id_str[CRYPTO_PUBLIC_KEY_SIZE * 2] = 0; + return id_str; +} + +/* Minimum messenger run interval in ms + TODO(mannol): A/V */ +#define MIN_RUN_INTERVAL 50 + +/* Return the time in milliseconds before do_messenger() should be called again + * for optimal performance. + * + * returns time (in ms) before the next do_messenger() needs to be run on success. + */ +uint32_t messenger_run_interval(const Messenger *m) +{ + uint32_t crypto_interval = crypto_run_interval(m->net_crypto); + + if (crypto_interval > MIN_RUN_INTERVAL) { + return MIN_RUN_INTERVAL; + } + + return crypto_interval; +} + +/* The main loop that needs to be run at least 20 times per second. */ +void do_messenger(Messenger *m, void *userdata) +{ + // Add the TCP relays, but only if this is the first time calling do_messenger + if (m->has_added_relays == 0) { + m->has_added_relays = 1; + + int i; + + for (i = 0; i < NUM_SAVED_TCP_RELAYS; ++i) { + add_tcp_relay(m->net_crypto, m->loaded_relays[i].ip_port, m->loaded_relays[i].public_key); + } + + if (m->tcp_server) { + /* Add self tcp server. */ + IP_Port local_ip_port; + local_ip_port.port = m->options.tcp_server_port; + local_ip_port.ip.family = TOX_AF_INET; + local_ip_port.ip.ip4 = get_ip4_loopback(); + add_tcp_relay(m->net_crypto, local_ip_port, + tcp_server_public_key(m->tcp_server)); + } + } + + unix_time_update(); + + if (!m->options.udp_disabled) { + networking_poll(m->net, userdata); + do_DHT(m->dht); + } + + if (m->tcp_server) { + do_TCP_server(m->tcp_server); + } + + do_net_crypto(m->net_crypto, userdata); + do_onion_client(m->onion_c); + do_friend_connections(m->fr_c, userdata); + do_friends(m, userdata); + connection_status_cb(m, userdata); + + if (unix_time() > m->lastdump + DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS) { + m->lastdump = unix_time(); + uint32_t client, last_pinged; + + for (client = 0; client < LCLIENT_LIST; client++) { + Client_data *cptr = &m->dht->close_clientlist[client]; + IPPTsPng *assoc = NULL; + uint32_t a; + + for (a = 0, assoc = &cptr->assoc4; a < 2; a++, assoc = &cptr->assoc6) { + if (ip_isset(&assoc->ip_port.ip)) { + last_pinged = m->lastdump - assoc->last_pinged; + + if (last_pinged > 999) { + last_pinged = 999; + } + + char ip_str[IP_NTOA_LEN]; + char id_str[IDSTRING_LEN]; + LOGGER_TRACE(m->log, "C[%2u] %s:%u [%3u] %s", + client, ip_ntoa(&assoc->ip_port.ip, ip_str, sizeof(ip_str)), + net_ntohs(assoc->ip_port.port), last_pinged, + id_to_string(cptr->public_key, id_str, sizeof(id_str))); + } + } + } + + + uint32_t friend_idx, dhtfriend; + + /* dht contains additional "friends" (requests) */ + uint32_t num_dhtfriends = m->dht->num_friends; + VLA(int32_t, m2dht, num_dhtfriends); + VLA(int32_t, dht2m, num_dhtfriends); + + for (friend_idx = 0; friend_idx < num_dhtfriends; friend_idx++) { + m2dht[friend_idx] = -1; + dht2m[friend_idx] = -1; + + if (friend_idx >= m->numfriends) { + continue; + } + + for (dhtfriend = 0; dhtfriend < m->dht->num_friends; dhtfriend++) { + if (id_equal(m->friendlist[friend_idx].real_pk, m->dht->friends_list[dhtfriend].public_key)) { + m2dht[friend_idx] = dhtfriend; + break; + } + } + } + + for (friend_idx = 0; friend_idx < num_dhtfriends; friend_idx++) { + if (m2dht[friend_idx] >= 0) { + dht2m[m2dht[friend_idx]] = friend_idx; + } + } + + if (m->numfriends != m->dht->num_friends) { + LOGGER_TRACE(m->log, "Friend num in DHT %u != friend num in msger %u\n", m->dht->num_friends, m->numfriends); + } + + Friend *msgfptr; + DHT_Friend *dhtfptr; + + for (friend_idx = 0; friend_idx < num_dhtfriends; friend_idx++) { + if (dht2m[friend_idx] >= 0) { + msgfptr = &m->friendlist[dht2m[friend_idx]]; + } else { + msgfptr = NULL; + } + + dhtfptr = &m->dht->friends_list[friend_idx]; + + if (msgfptr) { + char id_str[IDSTRING_LEN]; + LOGGER_TRACE(m->log, "F[%2u:%2u] <%s> %s", + dht2m[friend_idx], friend_idx, msgfptr->name, + id_to_string(msgfptr->real_pk, id_str, sizeof(id_str))); + } else { + char id_str[IDSTRING_LEN]; + LOGGER_TRACE(m->log, "F[--:%2u] %s", friend_idx, + id_to_string(dhtfptr->public_key, id_str, sizeof(id_str))); + } + + for (client = 0; client < MAX_FRIEND_CLIENTS; client++) { + Client_data *cptr = &dhtfptr->client_list[client]; + IPPTsPng *assoc = NULL; + uint32_t a; + + for (a = 0, assoc = &cptr->assoc4; a < 2; a++, assoc = &cptr->assoc6) { + if (ip_isset(&assoc->ip_port.ip)) { + last_pinged = m->lastdump - assoc->last_pinged; + + if (last_pinged > 999) { + last_pinged = 999; + } + + char ip_str[IP_NTOA_LEN]; + char id_str[IDSTRING_LEN]; + LOGGER_TRACE(m->log, "F[%2u] => C[%2u] %s:%u [%3u] %s", + friend_idx, client, ip_ntoa(&assoc->ip_port.ip, ip_str, sizeof(ip_str)), + net_ntohs(assoc->ip_port.port), last_pinged, + id_to_string(cptr->public_key, id_str, sizeof(id_str))); + } + } + } + } + } +} + +/* new messenger format for load/save, more robust and forward compatible */ + +#define MESSENGER_STATE_COOKIE_GLOBAL 0x15ed1b1f + +#define MESSENGER_STATE_COOKIE_TYPE 0x01ce +#define MESSENGER_STATE_TYPE_NOSPAMKEYS 1 +#define MESSENGER_STATE_TYPE_DHT 2 +#define MESSENGER_STATE_TYPE_FRIENDS 3 +#define MESSENGER_STATE_TYPE_NAME 4 +#define MESSENGER_STATE_TYPE_STATUSMESSAGE 5 +#define MESSENGER_STATE_TYPE_STATUS 6 +#define MESSENGER_STATE_TYPE_TCP_RELAY 10 +#define MESSENGER_STATE_TYPE_PATH_NODE 11 +#define MESSENGER_STATE_TYPE_END 255 + +#define SAVED_FRIEND_REQUEST_SIZE 1024 +#define NUM_SAVED_PATH_NODES 8 + +struct SAVED_FRIEND { + uint8_t status; + uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t info[SAVED_FRIEND_REQUEST_SIZE]; // the data that is sent during the friend requests we do. + uint16_t info_size; // Length of the info. + uint8_t name[MAX_NAME_LENGTH]; + uint16_t name_length; + uint8_t statusmessage[MAX_STATUSMESSAGE_LENGTH]; + uint16_t statusmessage_length; + uint8_t userstatus; + uint32_t friendrequest_nospam; + uint64_t last_seen_time; +}; + +static uint32_t friend_size() +{ + uint32_t data = 0; + const struct SAVED_FRIEND temp = { 0 }; + +#define VALUE_MEMBER(NAME) data += sizeof(temp.NAME) +#define ARRAY_MEMBER(NAME) data += sizeof(temp.NAME) + + // Exactly the same in friend_load, friend_save, and friend_size + VALUE_MEMBER(status); + ARRAY_MEMBER(real_pk); + ARRAY_MEMBER(info); + data++; // padding + VALUE_MEMBER(info_size); + ARRAY_MEMBER(name); + VALUE_MEMBER(name_length); + ARRAY_MEMBER(statusmessage); + data++; // padding + VALUE_MEMBER(statusmessage_length); + VALUE_MEMBER(userstatus); + data += 3; // padding + VALUE_MEMBER(friendrequest_nospam); + VALUE_MEMBER(last_seen_time); + +#undef VALUE_MEMBER +#undef ARRAY_MEMBER + + return data; +} + +static uint32_t saved_friendslist_size(const Messenger *m) +{ + return count_friendlist(m) * friend_size(); +} + +static uint8_t *friend_save(const struct SAVED_FRIEND *temp, uint8_t *data) +{ +#define VALUE_MEMBER(NAME) \ + memcpy(data, &temp->NAME, sizeof(temp->NAME)); \ + data += sizeof(temp->NAME) + +#define ARRAY_MEMBER(NAME) \ + memcpy(data, temp->NAME, sizeof(temp->NAME)); \ + data += sizeof(temp->NAME) + + // Exactly the same in friend_load, friend_save, and friend_size + VALUE_MEMBER(status); + ARRAY_MEMBER(real_pk); + ARRAY_MEMBER(info); + data++; // padding + VALUE_MEMBER(info_size); + ARRAY_MEMBER(name); + VALUE_MEMBER(name_length); + ARRAY_MEMBER(statusmessage); + data++; // padding + VALUE_MEMBER(statusmessage_length); + VALUE_MEMBER(userstatus); + data += 3; // padding + VALUE_MEMBER(friendrequest_nospam); + VALUE_MEMBER(last_seen_time); + +#undef VALUE_MEMBER +#undef ARRAY_MEMBER + + return data; +} + +static uint32_t friends_list_save(const Messenger *m, uint8_t *data) +{ + uint32_t i; + uint32_t num = 0; + uint8_t *cur_data = data; + + for (i = 0; i < m->numfriends; i++) { + if (m->friendlist[i].status > 0) { + struct SAVED_FRIEND temp = { 0 }; + temp.status = m->friendlist[i].status; + memcpy(temp.real_pk, m->friendlist[i].real_pk, CRYPTO_PUBLIC_KEY_SIZE); + + if (temp.status < 3) { + const size_t friendrequest_length = + MIN(m->friendlist[i].info_size, + MIN(SAVED_FRIEND_REQUEST_SIZE, MAX_FRIEND_REQUEST_DATA_SIZE)); + memcpy(temp.info, m->friendlist[i].info, friendrequest_length); + + temp.info_size = net_htons(m->friendlist[i].info_size); + temp.friendrequest_nospam = m->friendlist[i].friendrequest_nospam; + } else { + memcpy(temp.name, m->friendlist[i].name, m->friendlist[i].name_length); + temp.name_length = net_htons(m->friendlist[i].name_length); + memcpy(temp.statusmessage, m->friendlist[i].statusmessage, m->friendlist[i].statusmessage_length); + temp.statusmessage_length = net_htons(m->friendlist[i].statusmessage_length); + temp.userstatus = m->friendlist[i].userstatus; + + uint8_t last_seen_time[sizeof(uint64_t)]; + memcpy(last_seen_time, &m->friendlist[i].last_seen_time, sizeof(uint64_t)); + host_to_net(last_seen_time, sizeof(uint64_t)); + memcpy(&temp.last_seen_time, last_seen_time, sizeof(uint64_t)); + } + + uint8_t *next_data = friend_save(&temp, cur_data); + assert(next_data - cur_data == friend_size()); +#ifdef __LP64__ + assert(memcmp(cur_data, &temp, friend_size()) == 0); +#endif + cur_data = next_data; + num++; + } + } + + assert(cur_data - data == num * friend_size()); + return cur_data - data; +} + +static const uint8_t *friend_load(struct SAVED_FRIEND *temp, const uint8_t *data) +{ +#define VALUE_MEMBER(NAME) \ + memcpy(&temp->NAME, data, sizeof(temp->NAME)); \ + data += sizeof(temp->NAME) + +#define ARRAY_MEMBER(NAME) \ + memcpy(temp->NAME, data, sizeof(temp->NAME)); \ + data += sizeof(temp->NAME) + + // Exactly the same in friend_load, friend_save, and friend_size + VALUE_MEMBER(status); + ARRAY_MEMBER(real_pk); + ARRAY_MEMBER(info); + data++; // padding + VALUE_MEMBER(info_size); + ARRAY_MEMBER(name); + VALUE_MEMBER(name_length); + ARRAY_MEMBER(statusmessage); + data++; // padding + VALUE_MEMBER(statusmessage_length); + VALUE_MEMBER(userstatus); + data += 3; // padding + VALUE_MEMBER(friendrequest_nospam); + VALUE_MEMBER(last_seen_time); + +#undef VALUE_MEMBER +#undef ARRAY_MEMBER + + return data; +} + +static int friends_list_load(Messenger *m, const uint8_t *data, uint32_t length) +{ + if (length % friend_size() != 0) { + return -1; + } + + uint32_t num = length / friend_size(); + uint32_t i; + const uint8_t *cur_data = data; + + for (i = 0; i < num; ++i) { + struct SAVED_FRIEND temp = { 0 }; + const uint8_t *next_data = friend_load(&temp, cur_data); + assert(next_data - cur_data == friend_size()); +#ifdef __LP64__ + assert(memcmp(&temp, cur_data, friend_size()) == 0); +#endif + cur_data = next_data; + + if (temp.status >= 3) { + int fnum = m_addfriend_norequest(m, temp.real_pk); + + if (fnum < 0) { + continue; + } + + setfriendname(m, fnum, temp.name, net_ntohs(temp.name_length)); + set_friend_statusmessage(m, fnum, temp.statusmessage, net_ntohs(temp.statusmessage_length)); + set_friend_userstatus(m, fnum, temp.userstatus); + uint8_t last_seen_time[sizeof(uint64_t)]; + memcpy(last_seen_time, &temp.last_seen_time, sizeof(uint64_t)); + net_to_host(last_seen_time, sizeof(uint64_t)); + memcpy(&m->friendlist[fnum].last_seen_time, last_seen_time, sizeof(uint64_t)); + } else if (temp.status != 0) { + /* TODO(irungentoo): This is not a good way to do this. */ + uint8_t address[FRIEND_ADDRESS_SIZE]; + id_copy(address, temp.real_pk); + memcpy(address + CRYPTO_PUBLIC_KEY_SIZE, &(temp.friendrequest_nospam), sizeof(uint32_t)); + uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum)); + memcpy(address + CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint32_t), &checksum, sizeof(checksum)); + m_addfriend(m, address, temp.info, net_ntohs(temp.info_size)); + } + } + + return num; +} + +/* return size of the messenger data (for saving) */ +uint32_t messenger_size(const Messenger *m) +{ + uint32_t size32 = sizeof(uint32_t), sizesubhead = size32 * 2; + return size32 * 2 // global cookie + + sizesubhead + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SECRET_KEY_SIZE + + sizesubhead + DHT_size(m->dht) // DHT + + sizesubhead + saved_friendslist_size(m) // Friendlist itself. + + sizesubhead + m->name_length // Own nickname. + + sizesubhead + m->statusmessage_length // status message + + sizesubhead + 1 // status + + sizesubhead + NUM_SAVED_TCP_RELAYS * packed_node_size(TCP_INET6) //TCP relays + + sizesubhead + NUM_SAVED_PATH_NODES * packed_node_size(TCP_INET6) //saved path nodes + + sizesubhead; +} + +static uint8_t *messenger_save_subheader(uint8_t *data, uint32_t len, uint16_t type) +{ + host_to_lendian32(data, len); + data += sizeof(uint32_t); + host_to_lendian32(data, (host_tolendian16(MESSENGER_STATE_COOKIE_TYPE) << 16) | host_tolendian16(type)); + data += sizeof(uint32_t); + return data; +} + +/* Save the messenger in data of size Messenger_size(). */ +void messenger_save(const Messenger *m, uint8_t *data) +{ + memset(data, 0, messenger_size(m)); + + uint32_t len; + uint16_t type; + uint32_t size32 = sizeof(uint32_t); + + memset(data, 0, size32); + data += size32; + host_to_lendian32(data, MESSENGER_STATE_COOKIE_GLOBAL); + data += size32; + + assert(sizeof(get_nospam(&m->fr)) == sizeof(uint32_t)); + len = size32 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SECRET_KEY_SIZE; + type = MESSENGER_STATE_TYPE_NOSPAMKEYS; + data = messenger_save_subheader(data, len, type); + *(uint32_t *)data = get_nospam(&(m->fr)); + save_keys(m->net_crypto, data + size32); + data += len; + + len = saved_friendslist_size(m); + type = MESSENGER_STATE_TYPE_FRIENDS; + data = messenger_save_subheader(data, len, type); + friends_list_save(m, data); + data += len; + + len = m->name_length; + type = MESSENGER_STATE_TYPE_NAME; + data = messenger_save_subheader(data, len, type); + memcpy(data, m->name, len); + data += len; + + len = m->statusmessage_length; + type = MESSENGER_STATE_TYPE_STATUSMESSAGE; + data = messenger_save_subheader(data, len, type); + memcpy(data, m->statusmessage, len); + data += len; + + len = 1; + type = MESSENGER_STATE_TYPE_STATUS; + data = messenger_save_subheader(data, len, type); + *data = m->userstatus; + data += len; + + len = DHT_size(m->dht); + type = MESSENGER_STATE_TYPE_DHT; + data = messenger_save_subheader(data, len, type); + DHT_save(m->dht, data); + data += len; + + Node_format relays[NUM_SAVED_TCP_RELAYS]; + type = MESSENGER_STATE_TYPE_TCP_RELAY; + uint8_t *temp_data = data; + data = messenger_save_subheader(temp_data, 0, type); + unsigned int num = copy_connected_tcp_relays(m->net_crypto, relays, NUM_SAVED_TCP_RELAYS); + int l = pack_nodes(data, NUM_SAVED_TCP_RELAYS * packed_node_size(TCP_INET6), relays, num); + + if (l > 0) { + len = l; + data = messenger_save_subheader(temp_data, len, type); + data += len; + } + + Node_format nodes[NUM_SAVED_PATH_NODES]; + type = MESSENGER_STATE_TYPE_PATH_NODE; + temp_data = data; + data = messenger_save_subheader(data, 0, type); + memset(nodes, 0, sizeof(nodes)); + num = onion_backup_nodes(m->onion_c, nodes, NUM_SAVED_PATH_NODES); + l = pack_nodes(data, NUM_SAVED_PATH_NODES * packed_node_size(TCP_INET6), nodes, num); + + if (l > 0) { + len = l; + data = messenger_save_subheader(temp_data, len, type); + data += len; + } + + messenger_save_subheader(data, 0, MESSENGER_STATE_TYPE_END); +} + +static int messenger_load_state_callback(void *outer, const uint8_t *data, uint32_t length, uint16_t type) +{ + Messenger *m = (Messenger *)outer; + + switch (type) { + case MESSENGER_STATE_TYPE_NOSPAMKEYS: + if (length == CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SECRET_KEY_SIZE + sizeof(uint32_t)) { + set_nospam(&(m->fr), *(const uint32_t *)data); + load_secret_key(m->net_crypto, (&data[sizeof(uint32_t)]) + CRYPTO_PUBLIC_KEY_SIZE); + + if (public_key_cmp((&data[sizeof(uint32_t)]), m->net_crypto->self_public_key) != 0) { + return -1; + } + } else { + return -1; /* critical */ + } + + break; + + case MESSENGER_STATE_TYPE_DHT: + DHT_load(m->dht, data, length); + break; + + case MESSENGER_STATE_TYPE_FRIENDS: + friends_list_load(m, data, length); + break; + + case MESSENGER_STATE_TYPE_NAME: + if ((length > 0) && (length <= MAX_NAME_LENGTH)) { + setname(m, data, length); + } + + break; + + case MESSENGER_STATE_TYPE_STATUSMESSAGE: + if ((length > 0) && (length <= MAX_STATUSMESSAGE_LENGTH)) { + m_set_statusmessage(m, data, length); + } + + break; + + case MESSENGER_STATE_TYPE_STATUS: + if (length == 1) { + m_set_userstatus(m, *data); + } + + break; + + case MESSENGER_STATE_TYPE_TCP_RELAY: { + if (length == 0) { + break; + } + + unpack_nodes(m->loaded_relays, NUM_SAVED_TCP_RELAYS, 0, data, length, 1); + m->has_added_relays = 0; + + break; + } + + case MESSENGER_STATE_TYPE_PATH_NODE: { + Node_format nodes[NUM_SAVED_PATH_NODES]; + + if (length == 0) { + break; + } + + int i, num = unpack_nodes(nodes, NUM_SAVED_PATH_NODES, 0, data, length, 0); + + for (i = 0; i < num; ++i) { + onion_add_bs_path_node(m->onion_c, nodes[i].ip_port, nodes[i].public_key); + } + + break; + } + + case MESSENGER_STATE_TYPE_END: { + if (length != 0) { + return -1; + } + + return -2; + } + + default: + LOGGER_ERROR(m->log, "Load state: contains unrecognized part (len %u, type %u)\n", + length, type); + break; + } + + return 0; +} + +/* Load the messenger from data of size length. */ +int messenger_load(Messenger *m, const uint8_t *data, uint32_t length) +{ + uint32_t data32[2]; + uint32_t cookie_len = sizeof(data32); + + if (length < cookie_len) { + return -1; + } + + memcpy(data32, data, sizeof(uint32_t)); + lendian_to_host32(data32 + 1, data + sizeof(uint32_t)); + + if (!data32[0] && (data32[1] == MESSENGER_STATE_COOKIE_GLOBAL)) { + return load_state(messenger_load_state_callback, m->log, m, data + cookie_len, + length - cookie_len, MESSENGER_STATE_COOKIE_TYPE); + } + + return -1; +} + +/* Return the number of friends in the instance m. + * You should use this to determine how much memory to allocate + * for copy_friendlist. */ +uint32_t count_friendlist(const Messenger *m) +{ + uint32_t ret = 0; + uint32_t i; + + for (i = 0; i < m->numfriends; i++) { + if (m->friendlist[i].status > 0) { + ret++; + } + } + + return ret; +} + +/* Copy a list of valid friend IDs into the array out_list. + * If out_list is NULL, returns 0. + * Otherwise, returns the number of elements copied. + * If the array was too small, the contents + * of out_list will be truncated to list_size. */ +uint32_t copy_friendlist(Messenger const *m, uint32_t *out_list, uint32_t list_size) +{ + if (!out_list) { + return 0; + } + + if (m->numfriends == 0) { + return 0; + } + + uint32_t i; + uint32_t ret = 0; + + for (i = 0; i < m->numfriends; i++) { + if (ret >= list_size) { + break; /* Abandon ship */ + } + + if (m->friendlist[i].status > 0) { + out_list[ret] = i; + ret++; + } + } + + return ret; +} diff --git a/protocols/Tox/libtox/src/toxcore/Messenger.h b/protocols/Tox/libtox/src/toxcore/Messenger.h new file mode 100644 index 0000000000..e1dba69886 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/Messenger.h @@ -0,0 +1,777 @@ +/* + * An implementation of a simple text chat only messenger on the tox network + * core. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef MESSENGER_H +#define MESSENGER_H + +#include "friend_connection.h" +#include "friend_requests.h" +#include "logger.h" + +#define MAX_NAME_LENGTH 128 +/* TODO(irungentoo): this must depend on other variable. */ +#define MAX_STATUSMESSAGE_LENGTH 1007 +/* Used for TCP relays in Messenger struct (may need to be % 2 == 0)*/ +#define NUM_SAVED_TCP_RELAYS 8 +/* This cannot be bigger than 256 */ +#define MAX_CONCURRENT_FILE_PIPES 256 + + +#define FRIEND_ADDRESS_SIZE (CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint32_t) + sizeof(uint16_t)) + +enum { + MESSAGE_NORMAL, + MESSAGE_ACTION +}; + +/* NOTE: Packet ids below 24 must never be used. */ +#define PACKET_ID_ONLINE 24 +#define PACKET_ID_OFFLINE 25 +#define PACKET_ID_NICKNAME 48 +#define PACKET_ID_STATUSMESSAGE 49 +#define PACKET_ID_USERSTATUS 50 +#define PACKET_ID_TYPING 51 +#define PACKET_ID_MESSAGE 64 +#define PACKET_ID_ACTION (PACKET_ID_MESSAGE + MESSAGE_ACTION) /* 65 */ +#define PACKET_ID_MSI 69 +#define PACKET_ID_FILE_SENDREQUEST 80 +#define PACKET_ID_FILE_CONTROL 81 +#define PACKET_ID_FILE_DATA 82 +#define PACKET_ID_INVITE_CONFERENCE 96 +#define PACKET_ID_ONLINE_PACKET 97 +#define PACKET_ID_DIRECT_CONFERENCE 98 +#define PACKET_ID_MESSAGE_CONFERENCE 99 +#define PACKET_ID_LOSSY_CONFERENCE 199 + +/* All packets starting with a byte in this range can be used for anything. */ +#define PACKET_ID_LOSSLESS_RANGE_START 160 +#define PACKET_ID_LOSSLESS_RANGE_SIZE 32 +#define PACKET_LOSSY_AV_RESERVED 8 /* Number of lossy packet types at start of range reserved for A/V. */ + +typedef struct { + uint8_t ipv6enabled; + uint8_t udp_disabled; + TCP_Proxy_Info proxy_info; + uint16_t port_range[2]; + uint16_t tcp_server_port; + + uint8_t hole_punching_enabled; + bool local_discovery_enabled; + + logger_cb *log_callback; + void *log_user_data; +} Messenger_Options; + + +struct Receipts { + uint32_t packet_num; + uint32_t msg_id; + struct Receipts *next; +}; + +/* Status definitions. */ +enum { + NOFRIEND, + FRIEND_ADDED, + FRIEND_REQUESTED, + FRIEND_CONFIRMED, + FRIEND_ONLINE, +}; + +/* Errors for m_addfriend + * FAERR - Friend Add Error + */ +enum { + FAERR_TOOLONG = -1, + FAERR_NOMESSAGE = -2, + FAERR_OWNKEY = -3, + FAERR_ALREADYSENT = -4, + FAERR_BADCHECKSUM = -6, + FAERR_SETNEWNOSPAM = -7, + FAERR_NOMEM = -8 +}; + + +/* Default start timeout in seconds between friend requests. */ +#define FRIENDREQUEST_TIMEOUT 5; + +enum { + CONNECTION_NONE, + CONNECTION_TCP, + CONNECTION_UDP, + CONNECTION_UNKNOWN +}; + +/* USERSTATUS - + * Represents userstatuses someone can have. + */ + +typedef enum { + USERSTATUS_NONE, + USERSTATUS_AWAY, + USERSTATUS_BUSY, + USERSTATUS_INVALID +} +USERSTATUS; + +#define FILE_ID_LENGTH 32 + +struct File_Transfers { + uint64_t size; + uint64_t transferred; + uint8_t status; /* 0 == no transfer, 1 = not accepted, 3 = transferring, 4 = broken, 5 = finished */ + uint8_t paused; /* 0: not paused, 1 = paused by us, 2 = paused by other, 3 = paused by both. */ + uint32_t last_packet_number; /* number of the last packet sent. */ + uint64_t requested; /* total data requested by the request chunk callback */ + unsigned int slots_allocated; /* number of slots allocated to this transfer. */ + uint8_t id[FILE_ID_LENGTH]; +}; +enum { + FILESTATUS_NONE, + FILESTATUS_NOT_ACCEPTED, + FILESTATUS_TRANSFERRING, + //FILESTATUS_BROKEN, + FILESTATUS_FINISHED +}; + +enum { + FILE_PAUSE_NOT, + FILE_PAUSE_US, + FILE_PAUSE_OTHER, + FILE_PAUSE_BOTH +}; + +enum { + FILECONTROL_ACCEPT, + FILECONTROL_PAUSE, + FILECONTROL_KILL, + FILECONTROL_SEEK +}; + +enum { + FILEKIND_DATA, + FILEKIND_AVATAR +}; + + +typedef struct Messenger Messenger; + +typedef struct { + uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + int friendcon_id; + + uint64_t friendrequest_lastsent; // Time at which the last friend request was sent. + uint32_t friendrequest_timeout; // The timeout between successful friendrequest sending attempts. + uint8_t status; // 0 if no friend, 1 if added, 2 if friend request sent, 3 if confirmed friend, 4 if online. + uint8_t info[MAX_FRIEND_REQUEST_DATA_SIZE]; // the data that is sent during the friend requests we do. + uint8_t name[MAX_NAME_LENGTH]; + uint16_t name_length; + uint8_t name_sent; // 0 if we didn't send our name to this friend 1 if we have. + uint8_t statusmessage[MAX_STATUSMESSAGE_LENGTH]; + uint16_t statusmessage_length; + uint8_t statusmessage_sent; + USERSTATUS userstatus; + uint8_t userstatus_sent; + uint8_t user_istyping; + uint8_t user_istyping_sent; + uint8_t is_typing; + uint16_t info_size; // Length of the info. + uint32_t message_id; // a semi-unique id used in read receipts. + uint32_t friendrequest_nospam; // The nospam number used in the friend request. + uint64_t last_seen_time; + uint8_t last_connection_udp_tcp; + struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES]; + unsigned int num_sending_files; + struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; + + struct { + int (*function)(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t len, void *object); + void *object; + } lossy_rtp_packethandlers[PACKET_LOSSY_AV_RESERVED]; + + struct Receipts *receipts_start; + struct Receipts *receipts_end; +} Friend; + +struct Messenger { + Logger *log; + + Networking_Core *net; + Net_Crypto *net_crypto; + DHT *dht; + + Onion *onion; + Onion_Announce *onion_a; + Onion_Client *onion_c; + + Friend_Connections *fr_c; + + TCP_Server *tcp_server; + Friend_Requests fr; + uint8_t name[MAX_NAME_LENGTH]; + uint16_t name_length; + + uint8_t statusmessage[MAX_STATUSMESSAGE_LENGTH]; + uint16_t statusmessage_length; + + USERSTATUS userstatus; + + Friend *friendlist; + uint32_t numfriends; + + time_t lastdump; + + uint8_t has_added_relays; // If the first connection has occurred in do_messenger + Node_format loaded_relays[NUM_SAVED_TCP_RELAYS]; // Relays loaded from config + + void (*friend_message)(struct Messenger *m, uint32_t, unsigned int, const uint8_t *, size_t, void *); + void (*friend_namechange)(struct Messenger *m, uint32_t, const uint8_t *, size_t, void *); + void (*friend_statusmessagechange)(struct Messenger *m, uint32_t, const uint8_t *, size_t, void *); + void (*friend_userstatuschange)(struct Messenger *m, uint32_t, unsigned int, void *); + void (*friend_typingchange)(struct Messenger *m, uint32_t, bool, void *); + void (*read_receipt)(struct Messenger *m, uint32_t, uint32_t, void *); + void (*friend_connectionstatuschange)(struct Messenger *m, uint32_t, unsigned int, void *); + void (*friend_connectionstatuschange_internal)(struct Messenger *m, uint32_t, uint8_t, void *); + void *friend_connectionstatuschange_internal_userdata; + + void *conferences_object; /* Set by new_groupchats()*/ + void (*conference_invite)(struct Messenger *m, uint32_t, const uint8_t *, uint16_t, void *); + + void (*file_sendrequest)(struct Messenger *m, uint32_t, uint32_t, uint32_t, uint64_t, const uint8_t *, size_t, + void *); + void (*file_filecontrol)(struct Messenger *m, uint32_t, uint32_t, unsigned int, void *); + void (*file_filedata)(struct Messenger *m, uint32_t, uint32_t, uint64_t, const uint8_t *, size_t, void *); + void (*file_reqchunk)(struct Messenger *m, uint32_t, uint32_t, uint64_t, size_t, void *); + + void (*msi_packet)(struct Messenger *m, uint32_t, const uint8_t *, uint16_t, void *); + void *msi_packet_userdata; + + void (*lossy_packethandler)(struct Messenger *m, uint32_t, const uint8_t *, size_t, void *); + void (*lossless_packethandler)(struct Messenger *m, uint32_t, const uint8_t *, size_t, void *); + + void (*core_connection_change)(struct Messenger *m, unsigned int, void *); + unsigned int last_connection_status; + + Messenger_Options options; +}; + +/* Format: [real_pk (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] + * + * return FRIEND_ADDRESS_SIZE byte address to give to others. + */ +void getaddress(const Messenger *m, uint8_t *address); + +/* Add a friend. + * Set the data that will be sent along with friend request. + * address is the address of the friend (returned by getaddress of the friend + * you wish to add) it must be FRIEND_ADDRESS_SIZE bytes. + * TODO(irungentoo): add checksum. + * data is the data and length is the length. + * + * return the friend number if success. + * return -1 if message length is too long. + * return -2 if no message (message length must be >= 1 byte). + * return -3 if user's own key. + * return -4 if friend request already sent or already a friend. + * return -6 if bad checksum in address. + * return -7 if the friend was already there but the nospam was different. + * (the nospam for that friend was set to the new one). + * return -8 if increasing the friend list size fails. + */ +int32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, uint16_t length); + + +/* Add a friend without sending a friendrequest. + * return the friend number if success. + * return -3 if user's own key. + * return -4 if friend request already sent or already a friend. + * return -6 if bad checksum in address. + * return -8 if increasing the friend list size fails. + */ +int32_t m_addfriend_norequest(Messenger *m, const uint8_t *real_pk); + +/* return the friend number associated to that client id. + * return -1 if no such friend. + */ +int32_t getfriend_id(const Messenger *m, const uint8_t *real_pk); + +/* Copies the public key associated to that friend id into real_pk buffer. + * Make sure that real_pk is of size CRYPTO_PUBLIC_KEY_SIZE. + * + * return 0 if success + * return -1 if failure + */ +int get_real_pk(const Messenger *m, int32_t friendnumber, uint8_t *real_pk); + +/* return friend connection id on success. + * return -1 if failure. + */ +int getfriendcon_id(const Messenger *m, int32_t friendnumber); + +/* Remove a friend. + * + * return 0 if success + * return -1 if failure + */ +int m_delfriend(Messenger *m, int32_t friendnumber); + +/* Checks friend's connecting status. + * + * return CONNECTION_UDP (2) if friend is directly connected to us (Online UDP). + * return CONNECTION_TCP (1) if friend is connected to us (Online TCP). + * return CONNECTION_NONE (0) if friend is not connected to us (Offline). + * return -1 on failure. + */ +int m_get_friend_connectionstatus(const Messenger *m, int32_t friendnumber); + +/* Checks if there exists a friend with given friendnumber. + * + * return 1 if friend exists. + * return 0 if friend doesn't exist. + */ +int m_friend_exists(const Messenger *m, int32_t friendnumber); + +/* Send a message of type to an online friend. + * + * return -1 if friend not valid. + * return -2 if too large. + * return -3 if friend not online. + * return -4 if send failed (because queue is full). + * return -5 if bad type. + * return 0 if success. + * + * the value in message_id will be passed to your read_receipt callback when the other receives the message. + */ +int m_send_message_generic(Messenger *m, int32_t friendnumber, uint8_t type, const uint8_t *message, uint32_t length, + uint32_t *message_id); + + +/* Set the name and name_length of a friend. + * name must be a string of maximum MAX_NAME_LENGTH length. + * length must be at least 1 byte. + * length is the length of name with the NULL terminator. + * + * return 0 if success. + * return -1 if failure. + */ +int setfriendname(Messenger *m, int32_t friendnumber, const uint8_t *name, uint16_t length); + +/* Set our nickname. + * name must be a string of maximum MAX_NAME_LENGTH length. + * length must be at least 1 byte. + * length is the length of name with the NULL terminator. + * + * return 0 if success. + * return -1 if failure. + */ +int setname(Messenger *m, const uint8_t *name, uint16_t length); + +/* + * Get your nickname. + * m - The messenger context to use. + * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes. + * + * return length of the name. + * return 0 on error. + */ +uint16_t getself_name(const Messenger *m, uint8_t *name); + +/* Get name of friendnumber and put it in name. + * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes. + * + * return length of name if success. + * return -1 if failure. + */ +int getname(const Messenger *m, int32_t friendnumber, uint8_t *name); + +/* return the length of name, including null on success. + * return -1 on failure. + */ +int m_get_name_size(const Messenger *m, int32_t friendnumber); +int m_get_self_name_size(const Messenger *m); + +/* Set our user status. + * You are responsible for freeing status after. + * + * returns 0 on success. + * returns -1 on failure. + */ +int m_set_statusmessage(Messenger *m, const uint8_t *status, uint16_t length); +int m_set_userstatus(Messenger *m, uint8_t status); + +/* return the length of friendnumber's status message, including null on success. + * return -1 on failure. + */ +int m_get_statusmessage_size(const Messenger *m, int32_t friendnumber); +int m_get_self_statusmessage_size(const Messenger *m); + +/* Copy friendnumber's status message into buf, truncating if size is over maxlen. + * Get the size you need to allocate from m_get_statusmessage_size. + * The self variant will copy our own status message. + * + * returns the length of the copied data on success + * retruns -1 on failure. + */ +int m_copy_statusmessage(const Messenger *m, int32_t friendnumber, uint8_t *buf, uint32_t maxlen); +int m_copy_self_statusmessage(const Messenger *m, uint8_t *buf); + +/* return one of USERSTATUS values. + * Values unknown to your application should be represented as USERSTATUS_NONE. + * As above, the self variant will return our own USERSTATUS. + * If friendnumber is invalid, this shall return USERSTATUS_INVALID. + */ +uint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber); +uint8_t m_get_self_userstatus(const Messenger *m); + + +/* returns timestamp of last time friendnumber was seen online or 0 if never seen. + * if friendnumber is invalid this function will return UINT64_MAX. + */ +uint64_t m_get_last_online(const Messenger *m, int32_t friendnumber); + +/* Set our typing status for a friend. + * You are responsible for turning it on or off. + * + * returns 0 on success. + * returns -1 on failure. + */ +int m_set_usertyping(Messenger *m, int32_t friendnumber, uint8_t is_typing); + +/* Get the typing status of a friend. + * + * returns 0 if friend is not typing. + * returns 1 if friend is typing. + */ +int m_get_istyping(const Messenger *m, int32_t friendnumber); + +/* Set the logger callback. + */ +void m_callback_log(Messenger *m, logger_cb *function, void *context, void *userdata); + +/* Set the function that will be executed when a friend request is received. + * Function format is function(uint8_t * public_key, uint8_t * data, size_t length) + */ +void m_callback_friendrequest(Messenger *m, void (*function)(Messenger *m, const uint8_t *, const uint8_t *, size_t, + void *)); + +/* Set the function that will be executed when a message from a friend is received. + * Function format is: function(uint32_t friendnumber, unsigned int type, uint8_t * message, uint32_t length) + */ +void m_callback_friendmessage(Messenger *m, void (*function)(Messenger *m, uint32_t, unsigned int, const uint8_t *, + size_t, void *)); + +/* Set the callback for name changes. + * Function(uint32_t friendnumber, uint8_t *newname, size_t length) + * You are not responsible for freeing newname. + */ +void m_callback_namechange(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, size_t, void *)); + +/* Set the callback for status message changes. + * Function(uint32_t friendnumber, uint8_t *newstatus, size_t length) + * + * You are not responsible for freeing newstatus + */ +void m_callback_statusmessage(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, size_t, void *)); + +/* Set the callback for status type changes. + * Function(uint32_t friendnumber, USERSTATUS kind) + */ +void m_callback_userstatus(Messenger *m, void (*function)(Messenger *m, uint32_t, unsigned int, void *)); + +/* Set the callback for typing changes. + * Function(uint32_t friendnumber, uint8_t is_typing) + */ +void m_callback_typingchange(Messenger *m, void(*function)(Messenger *m, uint32_t, bool, void *)); + +/* Set the callback for read receipts. + * Function(uint32_t friendnumber, uint32_t receipt) + * + * If you are keeping a record of returns from m_sendmessage, + * receipt might be one of those values, meaning the message + * has been received on the other side. + * Since core doesn't track ids for you, receipt may not correspond to any message. + * In that case, you should discard it. + */ +void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, void *)); + +/* Set the callback for connection status changes. + * function(uint32_t friendnumber, uint8_t status) + * + * Status: + * 0 -- friend went offline after being previously online. + * 1 -- friend went online. + * + * Note that this callback is not called when adding friends, thus the "after + * being previously online" part. + * It's assumed that when adding friends, their connection status is offline. + */ +void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, uint32_t, unsigned int, void *)); + +/* Same as previous but for internal A/V core usage only */ +void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, void *), + void *userdata); + + +/* Set the callback for typing changes. + * Function(unsigned int connection_status (0 = not connected, 1 = TCP only, 2 = UDP + TCP)) + */ +void m_callback_core_connection(Messenger *m, void (*function)(Messenger *m, unsigned int, void *)); + +/**********CONFERENCES************/ + +/* Set the callback for conference invites. + * + * Function(Messenger *m, uint32_t friendnumber, uint8_t *data, uint16_t length, void *userdata) + */ +void m_callback_conference_invite(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, uint16_t, + void *)); + +/* Send a conference invite packet. + * + * return 1 on success + * return 0 on failure + */ +int send_conference_invite_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length); + +/****************FILE SENDING*****************/ + + +/* Set the callback for file send requests. + * + * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint32_t filetype, uint64_t filesize, uint8_t *filename, size_t filename_length, void *userdata) + */ +void callback_file_sendrequest(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint32_t, uint64_t, + const uint8_t *, size_t, void *)); + + +/* Set the callback for file control requests. + * + * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, unsigned int control_type, void *userdata) + * + */ +void callback_file_control(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, unsigned int, void *)); + +/* Set the callback for file data. + * + * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, uint8_t *data, size_t length, void *userdata) + * + */ +void callback_file_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint64_t, const uint8_t *, + size_t, void *)); + +/* Set the callback for file request chunk. + * + * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length, void *userdata) + * + */ +void callback_file_reqchunk(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint64_t, size_t, void *)); + + +/* Copy the file transfer file id to file_id + * + * return 0 on success. + * return -1 if friend not valid. + * return -2 if filenumber not valid + */ +int file_get_id(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint8_t *file_id); + +/* Send a file send request. + * Maximum filename length is 255 bytes. + * return file number on success + * return -1 if friend not found. + * return -2 if filename length invalid. + * return -3 if no more file sending slots left. + * return -4 if could not send packet (friend offline). + * + */ +long int new_filesender(const Messenger *m, int32_t friendnumber, uint32_t file_type, uint64_t filesize, + const uint8_t *file_id, const uint8_t *filename, uint16_t filename_length); + +/* Send a file control request. + * + * return 0 on success + * return -1 if friend not valid. + * return -2 if friend not online. + * return -3 if file number invalid. + * return -4 if file control is bad. + * return -5 if file already paused. + * return -6 if resume file failed because it was only paused by the other. + * return -7 if resume file failed because it wasn't paused. + * return -8 if packet failed to send. + */ +int file_control(const Messenger *m, int32_t friendnumber, uint32_t filenumber, unsigned int control); + +/* Send a seek file control request. + * + * return 0 on success + * return -1 if friend not valid. + * return -2 if friend not online. + * return -3 if file number invalid. + * return -4 if not receiving file. + * return -5 if file status wrong. + * return -6 if position bad. + * return -8 if packet failed to send. + */ +int file_seek(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint64_t position); + +/* Send file data. + * + * return 0 on success + * return -1 if friend not valid. + * return -2 if friend not online. + * return -3 if filenumber invalid. + * return -4 if file transfer not transferring. + * return -5 if bad data size. + * return -6 if packet queue full. + * return -7 if wrong position. + */ +int file_data(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data, + uint16_t length); + +/* Give the number of bytes left to be sent/received. + * + * send_receive is 0 if we want the sending files, 1 if we want the receiving. + * + * return number of bytes remaining to be sent/received on success + * return 0 on failure + */ +uint64_t file_dataremaining(const Messenger *m, int32_t friendnumber, uint8_t filenumber, uint8_t send_receive); + +/*************** A/V related ******************/ + +/* Set the callback for msi packets. + * + * Function(Messenger *m, uint32_t friendnumber, uint8_t *data, uint16_t length, void *userdata) + */ +void m_callback_msi_packet(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, uint16_t, void *), + void *userdata); + +/* Send an msi packet. + * + * return 1 on success + * return 0 on failure + */ +int m_msi_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length); + +/* Set handlers for lossy rtp packets. + * + * return -1 on failure. + * return 0 on success. + */ +int m_callback_rtp_packet(Messenger *m, int32_t friendnumber, uint8_t byte, int (*packet_handler_callback)(Messenger *m, + uint32_t friendnumber, const uint8_t *data, uint16_t len, void *object), void *object); + +/**********************************************/ + +/* Set handlers for custom lossy packets. + * + */ +void custom_lossy_packet_registerhandler(Messenger *m, void (*packet_handler_callback)(Messenger *m, + uint32_t friendnumber, const uint8_t *data, size_t len, void *object)); + +/* High level function to send custom lossy packets. + * + * return -1 if friend invalid. + * return -2 if length wrong. + * return -3 if first byte invalid. + * return -4 if friend offline. + * return -5 if packet failed to send because of other error. + * return 0 on success. + */ +int m_send_custom_lossy_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length); + + +/* Set handlers for custom lossless packets. + * + */ +void custom_lossless_packet_registerhandler(Messenger *m, void (*packet_handler_callback)(Messenger *m, + uint32_t friendnumber, const uint8_t *data, size_t len, void *object)); + +/* High level function to send custom lossless packets. + * + * return -1 if friend invalid. + * return -2 if length wrong. + * return -3 if first byte invalid. + * return -4 if friend offline. + * return -5 if packet failed to send because of other error. + * return 0 on success. + */ +int send_custom_lossless_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length); + +/**********************************************/ + +enum { + MESSENGER_ERROR_NONE, + MESSENGER_ERROR_PORT, + MESSENGER_ERROR_TCP_SERVER, + MESSENGER_ERROR_OTHER +}; + +/* Run this at startup. + * return allocated instance of Messenger on success. + * return 0 if there are problems. + * + * if error is not NULL it will be set to one of the values in the enum above. + */ +Messenger *new_messenger(Messenger_Options *options, unsigned int *error); + +/* Run this before closing shop + * Free all datastructures. + */ +void kill_messenger(Messenger *m); + +/* The main loop that needs to be run at least 20 times per second. */ +void do_messenger(Messenger *m, void *userdata); + +/* Return the time in milliseconds before do_messenger() should be called again + * for optimal performance. + * + * returns time (in ms) before the next do_messenger() needs to be run on success. + */ +uint32_t messenger_run_interval(const Messenger *m); + +/* SAVING AND LOADING FUNCTIONS: */ + +/* return size of the messenger data (for saving). */ +uint32_t messenger_size(const Messenger *m); + +/* Save the messenger in data (must be allocated memory of size Messenger_size()) */ +void messenger_save(const Messenger *m, uint8_t *data); + +/* Load the messenger from data of size length. */ +int messenger_load(Messenger *m, const uint8_t *data, uint32_t length); + +/* Return the number of friends in the instance m. + * You should use this to determine how much memory to allocate + * for copy_friendlist. */ +uint32_t count_friendlist(const Messenger *m); + +/* Copy a list of valid friend IDs into the array out_list. + * If out_list is NULL, returns 0. + * Otherwise, returns the number of elements copied. + * If the array was too small, the contents + * of out_list will be truncated to list_size. */ +uint32_t copy_friendlist(const Messenger *m, uint32_t *out_list, uint32_t list_size); + +#endif diff --git a/protocols/Tox/libtox/src/toxcore/TCP_client.c b/protocols/Tox/libtox/src/toxcore/TCP_client.c new file mode 100644 index 0000000000..8a14c7cd70 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/TCP_client.c @@ -0,0 +1,991 @@ +/* + * Implementation of the TCP relay client part of Tox. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "TCP_client.h" + +#include "util.h" + +#if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32) +#include <sys/ioctl.h> +#endif + +/* return 1 on success + * return 0 on failure + */ +static int connect_sock_to(Socket sock, IP_Port ip_port, TCP_Proxy_Info *proxy_info) +{ + if (proxy_info->proxy_type != TCP_PROXY_NONE) { + ip_port = proxy_info->ip_port; + } + + /* nonblocking socket, connect will never return success */ + net_connect(sock, ip_port); + return 1; +} + +/* return 1 on success. + * return 0 on failure. + */ +static int proxy_http_generate_connection_request(TCP_Client_Connection *TCP_conn) +{ + char one[] = "CONNECT "; + char two[] = " HTTP/1.1\nHost: "; + char three[] = "\r\n\r\n"; + + char ip[TOX_INET6_ADDRSTRLEN]; + + if (!ip_parse_addr(&TCP_conn->ip_port.ip, ip, sizeof(ip))) { + return 0; + } + + const uint16_t port = net_ntohs(TCP_conn->ip_port.port); + const int written = snprintf((char *)TCP_conn->last_packet, MAX_PACKET_SIZE, "%s%s:%hu%s%s:%hu%s", one, ip, port, two, + ip, port, three); + + if (written < 0 || MAX_PACKET_SIZE < written) { + return 0; + } + + TCP_conn->last_packet_length = written; + TCP_conn->last_packet_sent = 0; + + return 1; +} + +/* return 1 on success. + * return 0 if no data received. + * return -1 on failure (connection refused). + */ +static int proxy_http_read_connection_response(TCP_Client_Connection *TCP_conn) +{ + char success[] = "200"; + uint8_t data[16]; // draining works the best if the length is a power of 2 + + int ret = read_TCP_packet(TCP_conn->sock, data, sizeof(data) - 1); + + if (ret == -1) { + return 0; + } + + data[sizeof(data) - 1] = 0; + + if (strstr((char *)data, success)) { + // drain all data + unsigned int data_left = TCP_socket_data_recv_buffer(TCP_conn->sock); + + if (data_left) { + VLA(uint8_t, temp_data, data_left); + read_TCP_packet(TCP_conn->sock, temp_data, data_left); + } + + return 1; + } + + return -1; +} + +static void proxy_socks5_generate_handshake(TCP_Client_Connection *TCP_conn) +{ + TCP_conn->last_packet[0] = 5; /* SOCKSv5 */ + TCP_conn->last_packet[1] = 1; /* number of authentication methods supported */ + TCP_conn->last_packet[2] = 0; /* No authentication */ + + TCP_conn->last_packet_length = 3; + TCP_conn->last_packet_sent = 0; +} + +/* return 1 on success. + * return 0 if no data received. + * return -1 on failure (connection refused). + */ +static int socks5_read_handshake_response(TCP_Client_Connection *TCP_conn) +{ + uint8_t data[2]; + int ret = read_TCP_packet(TCP_conn->sock, data, sizeof(data)); + + if (ret == -1) { + return 0; + } + + if (data[0] == 5 && data[1] == 0) { // TODO(irungentoo): magic numbers + return 1; + } + + return -1; +} + +static void proxy_socks5_generate_connection_request(TCP_Client_Connection *TCP_conn) +{ + TCP_conn->last_packet[0] = 5; /* SOCKSv5 */ + TCP_conn->last_packet[1] = 1; /* command code: establish a TCP/IP stream connection */ + TCP_conn->last_packet[2] = 0; /* reserved, must be 0 */ + uint16_t length = 3; + + if (TCP_conn->ip_port.ip.family == TOX_AF_INET) { + TCP_conn->last_packet[3] = 1; /* IPv4 address */ + ++length; + memcpy(TCP_conn->last_packet + length, TCP_conn->ip_port.ip.ip4.uint8, sizeof(IP4)); + length += sizeof(IP4); + } else { + TCP_conn->last_packet[3] = 4; /* IPv6 address */ + ++length; + memcpy(TCP_conn->last_packet + length, TCP_conn->ip_port.ip.ip6.uint8, sizeof(IP6)); + length += sizeof(IP6); + } + + memcpy(TCP_conn->last_packet + length, &TCP_conn->ip_port.port, sizeof(uint16_t)); + length += sizeof(uint16_t); + + TCP_conn->last_packet_length = length; + TCP_conn->last_packet_sent = 0; +} + +/* return 1 on success. + * return 0 if no data received. + * return -1 on failure (connection refused). + */ +static int proxy_socks5_read_connection_response(TCP_Client_Connection *TCP_conn) +{ + if (TCP_conn->ip_port.ip.family == TOX_AF_INET) { + uint8_t data[4 + sizeof(IP4) + sizeof(uint16_t)]; + int ret = read_TCP_packet(TCP_conn->sock, data, sizeof(data)); + + if (ret == -1) { + return 0; + } + + if (data[0] == 5 && data[1] == 0) { + return 1; + } + } else { + uint8_t data[4 + sizeof(IP6) + sizeof(uint16_t)]; + int ret = read_TCP_packet(TCP_conn->sock, data, sizeof(data)); + + if (ret == -1) { + return 0; + } + + if (data[0] == 5 && data[1] == 0) { + return 1; + } + } + + return -1; +} + +/* return 0 on success. + * return -1 on failure. + */ +static int generate_handshake(TCP_Client_Connection *TCP_conn) +{ + uint8_t plain[CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE]; + crypto_new_keypair(plain, TCP_conn->temp_secret_key); + random_nonce(TCP_conn->sent_nonce); + memcpy(plain + CRYPTO_PUBLIC_KEY_SIZE, TCP_conn->sent_nonce, CRYPTO_NONCE_SIZE); + memcpy(TCP_conn->last_packet, TCP_conn->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + random_nonce(TCP_conn->last_packet + CRYPTO_PUBLIC_KEY_SIZE); + int len = encrypt_data_symmetric(TCP_conn->shared_key, TCP_conn->last_packet + CRYPTO_PUBLIC_KEY_SIZE, plain, + sizeof(plain), TCP_conn->last_packet + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); + + if (len != sizeof(plain) + CRYPTO_MAC_SIZE) { + return -1; + } + + TCP_conn->last_packet_length = CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + sizeof(plain) + CRYPTO_MAC_SIZE; + TCP_conn->last_packet_sent = 0; + return 0; +} + +/* data must be of length TCP_SERVER_HANDSHAKE_SIZE + * + * return 0 on success. + * return -1 on failure. + */ +static int handle_handshake(TCP_Client_Connection *TCP_conn, const uint8_t *data) +{ + uint8_t plain[CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE]; + int len = decrypt_data_symmetric(TCP_conn->shared_key, data, data + CRYPTO_NONCE_SIZE, + TCP_SERVER_HANDSHAKE_SIZE - CRYPTO_NONCE_SIZE, plain); + + if (len != sizeof(plain)) { + return -1; + } + + memcpy(TCP_conn->recv_nonce, plain + CRYPTO_PUBLIC_KEY_SIZE, CRYPTO_NONCE_SIZE); + encrypt_precompute(plain, TCP_conn->temp_secret_key, TCP_conn->shared_key); + crypto_memzero(TCP_conn->temp_secret_key, CRYPTO_SECRET_KEY_SIZE); + return 0; +} + +/* return 0 if pending data was sent completely + * return -1 if it wasn't + */ +static int client_send_pending_data_nonpriority(TCP_Client_Connection *con) +{ + if (con->last_packet_length == 0) { + return 0; + } + + uint16_t left = con->last_packet_length - con->last_packet_sent; + const char *data = (const char *)(con->last_packet + con->last_packet_sent); + int len = send(con->sock, data, left, MSG_NOSIGNAL); + + if (len <= 0) { + return -1; + } + + if (len == left) { + con->last_packet_length = 0; + con->last_packet_sent = 0; + return 0; + } + + con->last_packet_sent += len; + return -1; +} + +/* return 0 if pending data was sent completely + * return -1 if it wasn't + */ +static int client_send_pending_data(TCP_Client_Connection *con) +{ + /* finish sending current non-priority packet */ + if (client_send_pending_data_nonpriority(con) == -1) { + return -1; + } + + TCP_Priority_List *p = con->priority_queue_start; + + while (p) { + uint16_t left = p->size - p->sent; + int len = send(con->sock, (const char *)(p->data + p->sent), left, MSG_NOSIGNAL); + + if (len != left) { + if (len > 0) { + p->sent += len; + } + + break; + } + + TCP_Priority_List *pp = p; + p = p->next; + free(pp); + } + + con->priority_queue_start = p; + + if (!p) { + con->priority_queue_end = NULL; + return 0; + } + + return -1; +} + +/* return 0 on failure (only if malloc fails) + * return 1 on success + */ +static bool client_add_priority(TCP_Client_Connection *con, const uint8_t *packet, uint16_t size, uint16_t sent) +{ + TCP_Priority_List *p = con->priority_queue_end; + TCP_Priority_List *new_list = (TCP_Priority_List *)malloc(sizeof(TCP_Priority_List) + size); + + if (!new_list) { + return 0; + } + + new_list->next = NULL; + new_list->size = size; + new_list->sent = sent; + memcpy(new_list->data, packet, size); + + if (p) { + p->next = new_list; + } else { + con->priority_queue_start = new_list; + } + + con->priority_queue_end = new_list; + return 1; +} + +static void wipe_priority_list(TCP_Client_Connection *con) +{ + TCP_Priority_List *p = con->priority_queue_start; + + while (p) { + TCP_Priority_List *pp = p; + p = p->next; + free(pp); + } +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +static int write_packet_TCP_client_secure_connection(TCP_Client_Connection *con, const uint8_t *data, uint16_t length, + bool priority) +{ + if (length + CRYPTO_MAC_SIZE > MAX_PACKET_SIZE) { + return -1; + } + + bool sendpriority = 1; + + if (client_send_pending_data(con) == -1) { + if (priority) { + sendpriority = 0; + } else { + return 0; + } + } + + VLA(uint8_t, packet, sizeof(uint16_t) + length + CRYPTO_MAC_SIZE); + + uint16_t c_length = net_htons(length + CRYPTO_MAC_SIZE); + memcpy(packet, &c_length, sizeof(uint16_t)); + int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t)); + + if ((unsigned int)len != (SIZEOF_VLA(packet) - sizeof(uint16_t))) { + return -1; + } + + if (priority) { + len = sendpriority ? send(con->sock, (const char *)packet, SIZEOF_VLA(packet), MSG_NOSIGNAL) : 0; + + if (len <= 0) { + len = 0; + } + + increment_nonce(con->sent_nonce); + + if ((unsigned int)len == SIZEOF_VLA(packet)) { + return 1; + } + + return client_add_priority(con, packet, SIZEOF_VLA(packet), len); + } + + len = send(con->sock, (const char *)packet, SIZEOF_VLA(packet), MSG_NOSIGNAL); + + if (len <= 0) { + return 0; + } + + increment_nonce(con->sent_nonce); + + if ((unsigned int)len == SIZEOF_VLA(packet)) { + return 1; + } + + memcpy(con->last_packet, packet, SIZEOF_VLA(packet)); + con->last_packet_length = SIZEOF_VLA(packet); + con->last_packet_sent = len; + return 1; +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +int send_routing_request(TCP_Client_Connection *con, uint8_t *public_key) +{ + uint8_t packet[1 + CRYPTO_PUBLIC_KEY_SIZE]; + packet[0] = TCP_PACKET_ROUTING_REQUEST; + memcpy(packet + 1, public_key, CRYPTO_PUBLIC_KEY_SIZE); + return write_packet_TCP_client_secure_connection(con, packet, sizeof(packet), 1); +} + +void routing_response_handler(TCP_Client_Connection *con, int (*response_callback)(void *object, uint8_t connection_id, + const uint8_t *public_key), void *object) +{ + con->response_callback = response_callback; + con->response_callback_object = object; +} + +void routing_status_handler(TCP_Client_Connection *con, int (*status_callback)(void *object, uint32_t number, + uint8_t connection_id, uint8_t status), void *object) +{ + con->status_callback = status_callback; + con->status_callback_object = object; +} + +static int tcp_send_ping_response(TCP_Client_Connection *con); +static int tcp_send_ping_request(TCP_Client_Connection *con); + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure. + */ +int send_data(TCP_Client_Connection *con, uint8_t con_id, const uint8_t *data, uint16_t length) +{ + if (con_id >= NUM_CLIENT_CONNECTIONS) { + return -1; + } + + if (con->connections[con_id].status != 2) { + return -1; + } + + if (tcp_send_ping_response(con) == 0 || tcp_send_ping_request(con) == 0) { + return 0; + } + + VLA(uint8_t, packet, 1 + length); + packet[0] = con_id + NUM_RESERVED_PORTS; + memcpy(packet + 1, data, length); + return write_packet_TCP_client_secure_connection(con, packet, SIZEOF_VLA(packet), 0); +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure. + */ +int send_oob_packet(TCP_Client_Connection *con, const uint8_t *public_key, const uint8_t *data, uint16_t length) +{ + if (length == 0 || length > TCP_MAX_OOB_DATA_LENGTH) { + return -1; + } + + VLA(uint8_t, packet, 1 + CRYPTO_PUBLIC_KEY_SIZE + length); + packet[0] = TCP_PACKET_OOB_SEND; + memcpy(packet + 1, public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, data, length); + return write_packet_TCP_client_secure_connection(con, packet, SIZEOF_VLA(packet), 0); +} + + +/* Set the number that will be used as an argument in the callbacks related to con_id. + * + * When not set by this function, the number is ~0. + * + * return 0 on success. + * return -1 on failure. + */ +int set_tcp_connection_number(TCP_Client_Connection *con, uint8_t con_id, uint32_t number) +{ + if (con_id >= NUM_CLIENT_CONNECTIONS) { + return -1; + } + + if (con->connections[con_id].status == 0) { + return -1; + } + + con->connections[con_id].number = number; + return 0; +} + +void routing_data_handler(TCP_Client_Connection *con, int (*data_callback)(void *object, uint32_t number, + uint8_t connection_id, const uint8_t *data, uint16_t length, void *userdata), void *object) +{ + con->data_callback = data_callback; + con->data_callback_object = object; +} + +void oob_data_handler(TCP_Client_Connection *con, int (*oob_data_callback)(void *object, const uint8_t *public_key, + const uint8_t *data, uint16_t length, void *userdata), void *object) +{ + con->oob_data_callback = oob_data_callback; + con->oob_data_callback_object = object; +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +static int client_send_disconnect_notification(TCP_Client_Connection *con, uint8_t id) +{ + uint8_t packet[1 + 1]; + packet[0] = TCP_PACKET_DISCONNECT_NOTIFICATION; + packet[1] = id; + return write_packet_TCP_client_secure_connection(con, packet, sizeof(packet), 1); +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +static int tcp_send_ping_request(TCP_Client_Connection *con) +{ + if (!con->ping_request_id) { + return 1; + } + + uint8_t packet[1 + sizeof(uint64_t)]; + packet[0] = TCP_PACKET_PING; + memcpy(packet + 1, &con->ping_request_id, sizeof(uint64_t)); + int ret; + + if ((ret = write_packet_TCP_client_secure_connection(con, packet, sizeof(packet), 1)) == 1) { + con->ping_request_id = 0; + } + + return ret; +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +static int tcp_send_ping_response(TCP_Client_Connection *con) +{ + if (!con->ping_response_id) { + return 1; + } + + uint8_t packet[1 + sizeof(uint64_t)]; + packet[0] = TCP_PACKET_PONG; + memcpy(packet + 1, &con->ping_response_id, sizeof(uint64_t)); + int ret; + + if ((ret = write_packet_TCP_client_secure_connection(con, packet, sizeof(packet), 1)) == 1) { + con->ping_response_id = 0; + } + + return ret; +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +int send_disconnect_request(TCP_Client_Connection *con, uint8_t con_id) +{ + if (con_id >= NUM_CLIENT_CONNECTIONS) { + return -1; + } + + con->connections[con_id].status = 0; + con->connections[con_id].number = 0; + return client_send_disconnect_notification(con, con_id + NUM_RESERVED_PORTS); +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +int send_onion_request(TCP_Client_Connection *con, const uint8_t *data, uint16_t length) +{ + VLA(uint8_t, packet, 1 + length); + packet[0] = TCP_PACKET_ONION_REQUEST; + memcpy(packet + 1, data, length); + return write_packet_TCP_client_secure_connection(con, packet, SIZEOF_VLA(packet), 0); +} + +void onion_response_handler(TCP_Client_Connection *con, int (*onion_callback)(void *object, const uint8_t *data, + uint16_t length, void *userdata), void *object) +{ + con->onion_callback = onion_callback; + con->onion_callback_object = object; +} + +/* Create new TCP connection to ip_port/public_key + */ +TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, const uint8_t *public_key, const uint8_t *self_public_key, + const uint8_t *self_secret_key, TCP_Proxy_Info *proxy_info) +{ + if (networking_at_startup() != 0) { + return NULL; + } + + if (ip_port.ip.family != TOX_AF_INET && ip_port.ip.family != TOX_AF_INET6) { + return NULL; + } + + TCP_Proxy_Info default_proxyinfo; + + if (proxy_info == NULL) { + default_proxyinfo.proxy_type = TCP_PROXY_NONE; + proxy_info = &default_proxyinfo; + } + + uint8_t family = ip_port.ip.family; + + if (proxy_info->proxy_type != TCP_PROXY_NONE) { + family = proxy_info->ip_port.ip.family; + } + + Socket sock = net_socket(family, TOX_SOCK_STREAM, TOX_PROTO_TCP); + + if (!sock_valid(sock)) { + return NULL; + } + + if (!set_socket_nosigpipe(sock)) { + kill_sock(sock); + return 0; + } + + if (!(set_socket_nonblock(sock) && connect_sock_to(sock, ip_port, proxy_info))) { + kill_sock(sock); + return NULL; + } + + TCP_Client_Connection *temp = (TCP_Client_Connection *)calloc(sizeof(TCP_Client_Connection), 1); + + if (temp == NULL) { + kill_sock(sock); + return NULL; + } + + temp->sock = sock; + memcpy(temp->public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(temp->self_public_key, self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + encrypt_precompute(temp->public_key, self_secret_key, temp->shared_key); + temp->ip_port = ip_port; + temp->proxy_info = *proxy_info; + + switch (proxy_info->proxy_type) { + case TCP_PROXY_HTTP: + temp->status = TCP_CLIENT_PROXY_HTTP_CONNECTING; + proxy_http_generate_connection_request(temp); + break; + + case TCP_PROXY_SOCKS5: + temp->status = TCP_CLIENT_PROXY_SOCKS5_CONNECTING; + proxy_socks5_generate_handshake(temp); + break; + + case TCP_PROXY_NONE: + temp->status = TCP_CLIENT_CONNECTING; + + if (generate_handshake(temp) == -1) { + kill_sock(sock); + free(temp); + return NULL; + } + + break; + } + + temp->kill_at = unix_time() + TCP_CONNECTION_TIMEOUT; + + return temp; +} + +/* return 0 on success + * return -1 on failure + */ +static int handle_TCP_client_packet(TCP_Client_Connection *conn, const uint8_t *data, uint16_t length, void *userdata) +{ + if (length <= 1) { + return -1; + } + + switch (data[0]) { + case TCP_PACKET_ROUTING_RESPONSE: { + if (length != 1 + 1 + CRYPTO_PUBLIC_KEY_SIZE) { + return -1; + } + + if (data[1] < NUM_RESERVED_PORTS) { + return 0; + } + + uint8_t con_id = data[1] - NUM_RESERVED_PORTS; + + if (conn->connections[con_id].status != 0) { + return 0; + } + + conn->connections[con_id].status = 1; + conn->connections[con_id].number = ~0; + memcpy(conn->connections[con_id].public_key, data + 2, CRYPTO_PUBLIC_KEY_SIZE); + + if (conn->response_callback) { + conn->response_callback(conn->response_callback_object, con_id, conn->connections[con_id].public_key); + } + + return 0; + } + + case TCP_PACKET_CONNECTION_NOTIFICATION: { + if (length != 1 + 1) { + return -1; + } + + if (data[1] < NUM_RESERVED_PORTS) { + return -1; + } + + uint8_t con_id = data[1] - NUM_RESERVED_PORTS; + + if (conn->connections[con_id].status != 1) { + return 0; + } + + conn->connections[con_id].status = 2; + + if (conn->status_callback) { + conn->status_callback(conn->status_callback_object, conn->connections[con_id].number, con_id, + conn->connections[con_id].status); + } + + return 0; + } + + case TCP_PACKET_DISCONNECT_NOTIFICATION: { + if (length != 1 + 1) { + return -1; + } + + if (data[1] < NUM_RESERVED_PORTS) { + return -1; + } + + uint8_t con_id = data[1] - NUM_RESERVED_PORTS; + + if (conn->connections[con_id].status == 0) { + return 0; + } + + if (conn->connections[con_id].status != 2) { + return 0; + } + + conn->connections[con_id].status = 1; + + if (conn->status_callback) { + conn->status_callback(conn->status_callback_object, conn->connections[con_id].number, con_id, + conn->connections[con_id].status); + } + + return 0; + } + + case TCP_PACKET_PING: { + if (length != 1 + sizeof(uint64_t)) { + return -1; + } + + uint64_t ping_id; + memcpy(&ping_id, data + 1, sizeof(uint64_t)); + conn->ping_response_id = ping_id; + tcp_send_ping_response(conn); + return 0; + } + + case TCP_PACKET_PONG: { + if (length != 1 + sizeof(uint64_t)) { + return -1; + } + + uint64_t ping_id; + memcpy(&ping_id, data + 1, sizeof(uint64_t)); + + if (ping_id) { + if (ping_id == conn->ping_id) { + conn->ping_id = 0; + } + + return 0; + } + + return -1; + } + + case TCP_PACKET_OOB_RECV: { + if (length <= 1 + CRYPTO_PUBLIC_KEY_SIZE) { + return -1; + } + + if (conn->oob_data_callback) { + conn->oob_data_callback(conn->oob_data_callback_object, data + 1, data + 1 + CRYPTO_PUBLIC_KEY_SIZE, + length - (1 + CRYPTO_PUBLIC_KEY_SIZE), userdata); + } + + return 0; + } + + case TCP_PACKET_ONION_RESPONSE: { + conn->onion_callback(conn->onion_callback_object, data + 1, length - 1, userdata); + return 0; + } + + default: { + if (data[0] < NUM_RESERVED_PORTS) { + return -1; + } + + uint8_t con_id = data[0] - NUM_RESERVED_PORTS; + + if (conn->data_callback) { + conn->data_callback(conn->data_callback_object, conn->connections[con_id].number, con_id, data + 1, length - 1, + userdata); + } + } + } + + return 0; +} + +static int do_confirmed_TCP(TCP_Client_Connection *conn, void *userdata) +{ + client_send_pending_data(conn); + tcp_send_ping_response(conn); + tcp_send_ping_request(conn); + + uint8_t packet[MAX_PACKET_SIZE]; + int len; + + if (is_timeout(conn->last_pinged, TCP_PING_FREQUENCY)) { + uint64_t ping_id = random_64b(); + + if (!ping_id) { + ++ping_id; + } + + conn->ping_request_id = conn->ping_id = ping_id; + tcp_send_ping_request(conn); + conn->last_pinged = unix_time(); + } + + if (conn->ping_id && is_timeout(conn->last_pinged, TCP_PING_TIMEOUT)) { + conn->status = TCP_CLIENT_DISCONNECTED; + return 0; + } + + while ((len = read_packet_TCP_secure_connection(conn->sock, &conn->next_packet_length, conn->shared_key, + conn->recv_nonce, packet, sizeof(packet)))) { + if (len == -1) { + conn->status = TCP_CLIENT_DISCONNECTED; + break; + } + + if (handle_TCP_client_packet(conn, packet, len, userdata) == -1) { + conn->status = TCP_CLIENT_DISCONNECTED; + break; + } + } + + return 0; +} + +/* Run the TCP connection + */ +void do_TCP_connection(TCP_Client_Connection *TCP_connection, void *userdata) +{ + unix_time_update(); + + if (TCP_connection->status == TCP_CLIENT_DISCONNECTED) { + return; + } + + if (TCP_connection->status == TCP_CLIENT_PROXY_HTTP_CONNECTING) { + if (client_send_pending_data(TCP_connection) == 0) { + int ret = proxy_http_read_connection_response(TCP_connection); + + if (ret == -1) { + TCP_connection->kill_at = 0; + TCP_connection->status = TCP_CLIENT_DISCONNECTED; + } + + if (ret == 1) { + generate_handshake(TCP_connection); + TCP_connection->status = TCP_CLIENT_CONNECTING; + } + } + } + + if (TCP_connection->status == TCP_CLIENT_PROXY_SOCKS5_CONNECTING) { + if (client_send_pending_data(TCP_connection) == 0) { + int ret = socks5_read_handshake_response(TCP_connection); + + if (ret == -1) { + TCP_connection->kill_at = 0; + TCP_connection->status = TCP_CLIENT_DISCONNECTED; + } + + if (ret == 1) { + proxy_socks5_generate_connection_request(TCP_connection); + TCP_connection->status = TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED; + } + } + } + + if (TCP_connection->status == TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED) { + if (client_send_pending_data(TCP_connection) == 0) { + int ret = proxy_socks5_read_connection_response(TCP_connection); + + if (ret == -1) { + TCP_connection->kill_at = 0; + TCP_connection->status = TCP_CLIENT_DISCONNECTED; + } + + if (ret == 1) { + generate_handshake(TCP_connection); + TCP_connection->status = TCP_CLIENT_CONNECTING; + } + } + } + + if (TCP_connection->status == TCP_CLIENT_CONNECTING) { + if (client_send_pending_data(TCP_connection) == 0) { + TCP_connection->status = TCP_CLIENT_UNCONFIRMED; + } + } + + if (TCP_connection->status == TCP_CLIENT_UNCONFIRMED) { + uint8_t data[TCP_SERVER_HANDSHAKE_SIZE]; + int len = read_TCP_packet(TCP_connection->sock, data, sizeof(data)); + + if (sizeof(data) == len) { + if (handle_handshake(TCP_connection, data) == 0) { + TCP_connection->kill_at = ~0; + TCP_connection->status = TCP_CLIENT_CONFIRMED; + } else { + TCP_connection->kill_at = 0; + TCP_connection->status = TCP_CLIENT_DISCONNECTED; + } + } + } + + if (TCP_connection->status == TCP_CLIENT_CONFIRMED) { + do_confirmed_TCP(TCP_connection, userdata); + } + + if (TCP_connection->kill_at <= unix_time()) { + TCP_connection->status = TCP_CLIENT_DISCONNECTED; + } +} + +/* Kill the TCP connection + */ +void kill_TCP_connection(TCP_Client_Connection *TCP_connection) +{ + if (TCP_connection == NULL) { + return; + } + + wipe_priority_list(TCP_connection); + kill_sock(TCP_connection->sock); + crypto_memzero(TCP_connection, sizeof(TCP_Client_Connection)); + free(TCP_connection); +} diff --git a/protocols/Tox/libtox/src/toxcore/TCP_client.h b/protocols/Tox/libtox/src/toxcore/TCP_client.h new file mode 100644 index 0000000000..212543147c --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/TCP_client.h @@ -0,0 +1,167 @@ +/* + * Implementation of the TCP relay client part of Tox. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef TCP_CLIENT_H +#define TCP_CLIENT_H + +#include "TCP_server.h" +#include "crypto_core.h" + +#define TCP_CONNECTION_TIMEOUT 10 + +typedef enum { + TCP_PROXY_NONE, + TCP_PROXY_HTTP, + TCP_PROXY_SOCKS5 +} TCP_PROXY_TYPE; + +typedef struct { + IP_Port ip_port; + uint8_t proxy_type; // a value from TCP_PROXY_TYPE +} TCP_Proxy_Info; + +enum { + TCP_CLIENT_NO_STATUS, + TCP_CLIENT_PROXY_HTTP_CONNECTING, + TCP_CLIENT_PROXY_SOCKS5_CONNECTING, + TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED, + TCP_CLIENT_CONNECTING, + TCP_CLIENT_UNCONFIRMED, + TCP_CLIENT_CONFIRMED, + TCP_CLIENT_DISCONNECTED, +}; +typedef struct { + uint8_t status; + Socket sock; + uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* our public key */ + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* public key of the server */ + IP_Port ip_port; /* The ip and port of the server */ + TCP_Proxy_Info proxy_info; + uint8_t recv_nonce[CRYPTO_NONCE_SIZE]; /* Nonce of received packets. */ + uint8_t sent_nonce[CRYPTO_NONCE_SIZE]; /* Nonce of sent packets. */ + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + uint16_t next_packet_length; + + uint8_t temp_secret_key[CRYPTO_SECRET_KEY_SIZE]; + + uint8_t last_packet[2 + MAX_PACKET_SIZE]; + uint16_t last_packet_length; + uint16_t last_packet_sent; + + TCP_Priority_List *priority_queue_start, *priority_queue_end; + + uint64_t kill_at; + + uint64_t last_pinged; + uint64_t ping_id; + + uint64_t ping_response_id; + uint64_t ping_request_id; + + struct { + uint8_t status; /* 0 if not used, 1 if other is offline, 2 if other is online. */ + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint32_t number; + } connections[NUM_CLIENT_CONNECTIONS]; + int (*response_callback)(void *object, uint8_t connection_id, const uint8_t *public_key); + void *response_callback_object; + int (*status_callback)(void *object, uint32_t number, uint8_t connection_id, uint8_t status); + void *status_callback_object; + int (*data_callback)(void *object, uint32_t number, uint8_t connection_id, const uint8_t *data, uint16_t length, + void *userdata); + void *data_callback_object; + int (*oob_data_callback)(void *object, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata); + void *oob_data_callback_object; + + int (*onion_callback)(void *object, const uint8_t *data, uint16_t length, void *userdata); + void *onion_callback_object; + + /* Can be used by user. */ + void *custom_object; + uint32_t custom_uint; +} TCP_Client_Connection; + +/* Create new TCP connection to ip_port/public_key + */ +TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, const uint8_t *public_key, const uint8_t *self_public_key, + const uint8_t *self_secret_key, TCP_Proxy_Info *proxy_info); + +/* Run the TCP connection + */ +void do_TCP_connection(TCP_Client_Connection *TCP_connection, void *userdata); + +/* Kill the TCP connection + */ +void kill_TCP_connection(TCP_Client_Connection *TCP_connection); + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +int send_onion_request(TCP_Client_Connection *con, const uint8_t *data, uint16_t length); +void onion_response_handler(TCP_Client_Connection *con, int (*onion_callback)(void *object, const uint8_t *data, + uint16_t length, void *userdata), void *object); + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +int send_routing_request(TCP_Client_Connection *con, uint8_t *public_key); +void routing_response_handler(TCP_Client_Connection *con, int (*response_callback)(void *object, uint8_t connection_id, + const uint8_t *public_key), void *object); +void routing_status_handler(TCP_Client_Connection *con, int (*status_callback)(void *object, uint32_t number, + uint8_t connection_id, uint8_t status), void *object); + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +int send_disconnect_request(TCP_Client_Connection *con, uint8_t con_id); + +/* Set the number that will be used as an argument in the callbacks related to con_id. + * + * When not set by this function, the number is ~0. + * + * return 0 on success. + * return -1 on failure. + */ +int set_tcp_connection_number(TCP_Client_Connection *con, uint8_t con_id, uint32_t number); + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure. + */ +int send_data(TCP_Client_Connection *con, uint8_t con_id, const uint8_t *data, uint16_t length); +void routing_data_handler(TCP_Client_Connection *con, int (*data_callback)(void *object, uint32_t number, + uint8_t connection_id, const uint8_t *data, uint16_t length, void *userdata), void *object); + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure. + */ +int send_oob_packet(TCP_Client_Connection *con, const uint8_t *public_key, const uint8_t *data, uint16_t length); +void oob_data_handler(TCP_Client_Connection *con, int (*oob_data_callback)(void *object, const uint8_t *public_key, + const uint8_t *data, uint16_t length, void *userdata), void *object); + + +#endif diff --git a/protocols/Tox/libtox/src/toxcore/TCP_connection.c b/protocols/Tox/libtox/src/toxcore/TCP_connection.c new file mode 100644 index 0000000000..251594912a --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/TCP_connection.c @@ -0,0 +1,1491 @@ +/* + * Handles TCP relay connections between two Tox clients. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2015 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "TCP_connection.h" + +#include "util.h" + +#include <assert.h> + + +struct TCP_Connections { + DHT *dht; + + uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE]; + + TCP_Connection_to *connections; + uint32_t connections_length; /* Length of connections array. */ + + TCP_con *tcp_connections; + uint32_t tcp_connections_length; /* Length of tcp_connections array. */ + + int (*tcp_data_callback)(void *object, int id, const uint8_t *data, uint16_t length, void *userdata); + void *tcp_data_callback_object; + + int (*tcp_oob_callback)(void *object, const uint8_t *public_key, unsigned int tcp_connections_number, + const uint8_t *data, uint16_t length, void *userdata); + void *tcp_oob_callback_object; + + int (*tcp_onion_callback)(void *object, const uint8_t *data, uint16_t length, void *userdata); + void *tcp_onion_callback_object; + + TCP_Proxy_Info proxy_info; + + bool onion_status; + uint16_t onion_num_conns; +}; + + +const uint8_t *tcp_connections_public_key(const TCP_Connections *tcp_c) +{ + return tcp_c->self_public_key; +} + + +/* Set the size of the array to num. + * + * return -1 if realloc fails. + * return 0 if it succeeds. + */ +#define realloc_tox_array(array, element_type, num, temp_pointer) \ + (num \ + ? (temp_pointer = (element_type *)realloc( \ + array, \ + (num) * sizeof(element_type)), \ + temp_pointer ? (array = temp_pointer, 0) : -1) \ + : (free(array), array = NULL, 0)) + + +/* return 1 if the connections_number is not valid. + * return 0 if the connections_number is valid. + */ +static bool connections_number_not_valid(const TCP_Connections *tcp_c, int connections_number) +{ + if ((unsigned int)connections_number >= tcp_c->connections_length) { + return 1; + } + + if (tcp_c->connections == NULL) { + return 1; + } + + if (tcp_c->connections[connections_number].status == TCP_CONN_NONE) { + return 1; + } + + return 0; +} + +/* return 1 if the tcp_connections_number is not valid. + * return 0 if the tcp_connections_number is valid. + */ +static bool tcp_connections_number_not_valid(const TCP_Connections *tcp_c, int tcp_connections_number) +{ + if ((unsigned int)tcp_connections_number >= tcp_c->tcp_connections_length) { + return 1; + } + + if (tcp_c->tcp_connections == NULL) { + return 1; + } + + if (tcp_c->tcp_connections[tcp_connections_number].status == TCP_CONN_NONE) { + return 1; + } + + return 0; +} + +/* Create a new empty connection. + * + * return -1 on failure. + * return connections_number on success. + */ +static int create_connection(TCP_Connections *tcp_c) +{ + uint32_t i; + + for (i = 0; i < tcp_c->connections_length; ++i) { + if (tcp_c->connections[i].status == TCP_CONN_NONE) { + return i; + } + } + + int id = -1; + + TCP_Connection_to *temp_pointer; + + if (realloc_tox_array(tcp_c->connections, TCP_Connection_to, tcp_c->connections_length + 1, + temp_pointer) == 0) { + id = tcp_c->connections_length; + ++tcp_c->connections_length; + memset(&(tcp_c->connections[id]), 0, sizeof(TCP_Connection_to)); + } + + return id; +} + +/* Create a new empty tcp connection. + * + * return -1 on failure. + * return tcp_connections_number on success. + */ +static int create_tcp_connection(TCP_Connections *tcp_c) +{ + uint32_t i; + + for (i = 0; i < tcp_c->tcp_connections_length; ++i) { + if (tcp_c->tcp_connections[i].status == TCP_CONN_NONE) { + return i; + } + } + + int id = -1; + + TCP_con *temp_pointer; + + if (realloc_tox_array(tcp_c->tcp_connections, TCP_con, tcp_c->tcp_connections_length + 1, temp_pointer) == 0) { + id = tcp_c->tcp_connections_length; + ++tcp_c->tcp_connections_length; + memset(&(tcp_c->tcp_connections[id]), 0, sizeof(TCP_con)); + } + + return id; +} + +/* Wipe a connection. + * + * return -1 on failure. + * return 0 on success. + */ +static int wipe_connection(TCP_Connections *tcp_c, int connections_number) +{ + if (connections_number_not_valid(tcp_c, connections_number)) { + return -1; + } + + uint32_t i; + memset(&(tcp_c->connections[connections_number]), 0 , sizeof(TCP_Connection_to)); + + for (i = tcp_c->connections_length; i != 0; --i) { + if (tcp_c->connections[i - 1].status != TCP_CONN_NONE) { + break; + } + } + + if (tcp_c->connections_length != i) { + tcp_c->connections_length = i; + TCP_Connection_to *temp_pointer; + realloc_tox_array(tcp_c->connections, TCP_Connection_to, tcp_c->connections_length, temp_pointer); + } + + return 0; +} + +/* Wipe a connection. + * + * return -1 on failure. + * return 0 on success. + */ +static int wipe_tcp_connection(TCP_Connections *tcp_c, int tcp_connections_number) +{ + if (tcp_connections_number_not_valid(tcp_c, tcp_connections_number)) { + return -1; + } + + uint32_t i; + memset(&(tcp_c->tcp_connections[tcp_connections_number]), 0 , sizeof(TCP_con)); + + for (i = tcp_c->tcp_connections_length; i != 0; --i) { + if (tcp_c->tcp_connections[i - 1].status != TCP_CONN_NONE) { + break; + } + } + + if (tcp_c->tcp_connections_length != i) { + tcp_c->tcp_connections_length = i; + TCP_con *temp_pointer; + realloc_tox_array(tcp_c->tcp_connections, TCP_con, tcp_c->tcp_connections_length, temp_pointer); + } + + return 0; +} + +static TCP_Connection_to *get_connection(const TCP_Connections *tcp_c, int connections_number) +{ + if (connections_number_not_valid(tcp_c, connections_number)) { + return 0; + } + + return &tcp_c->connections[connections_number]; +} + +static TCP_con *get_tcp_connection(const TCP_Connections *tcp_c, int tcp_connections_number) +{ + if (tcp_connections_number_not_valid(tcp_c, tcp_connections_number)) { + return 0; + } + + return &tcp_c->tcp_connections[tcp_connections_number]; +} + +/* Send a packet to the TCP connection. + * + * return -1 on failure. + * return 0 on success. + */ +int send_packet_tcp_connection(TCP_Connections *tcp_c, int connections_number, const uint8_t *packet, uint16_t length) +{ + TCP_Connection_to *con_to = get_connection(tcp_c, connections_number); + + if (!con_to) { + return -1; + } + + // TODO(irungentoo): detect and kill bad relays. + // TODO(irungentoo): thread safety? + unsigned int i; + int ret = -1; + + bool limit_reached = 0; + + for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) { + uint32_t tcp_con_num = con_to->connections[i].tcp_connection; + uint8_t status = con_to->connections[i].status; + uint8_t connection_id = con_to->connections[i].connection_id; + + if (tcp_con_num && status == TCP_CONNECTIONS_STATUS_ONLINE) { + tcp_con_num -= 1; + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_con_num); + + if (!tcp_con) { + continue; + } + + ret = send_data(tcp_con->connection, connection_id, packet, length); + + if (ret == 0) { + limit_reached = 1; + } + + if (ret == 1) { + break; + } + } + } + + if (ret == 1) { + return 0; + } + + if (!limit_reached) { + ret = 0; + + /* Send oob packets to all relays tied to the connection. */ + for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) { + uint32_t tcp_con_num = con_to->connections[i].tcp_connection; + uint8_t status = con_to->connections[i].status; + + if (tcp_con_num && status == TCP_CONNECTIONS_STATUS_REGISTERED) { + tcp_con_num -= 1; + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_con_num); + + if (!tcp_con) { + continue; + } + + if (send_oob_packet(tcp_con->connection, con_to->public_key, packet, length) == 1) { + ret += 1; + } + } + } + + if (ret >= 1) { + return 0; + } + + return -1; + } + + return -1; +} + +/* Return a random TCP connection number for use in send_tcp_onion_request. + * + * TODO(irungentoo): This number is just the index of an array that the elements + * can change without warning. + * + * return TCP connection number on success. + * return -1 on failure. + */ +int get_random_tcp_onion_conn_number(TCP_Connections *tcp_c) +{ + unsigned int i, r = rand(); + + for (i = 0; i < tcp_c->tcp_connections_length; ++i) { + unsigned int index = ((i + r) % tcp_c->tcp_connections_length); + + if (tcp_c->tcp_connections[index].onion && tcp_c->tcp_connections[index].status == TCP_CONN_CONNECTED) { + return index; + } + } + + return -1; +} + +/* Send an onion packet via the TCP relay corresponding to tcp_connections_number. + * + * return 0 on success. + * return -1 on failure. + */ +int tcp_send_onion_request(TCP_Connections *tcp_c, unsigned int tcp_connections_number, const uint8_t *data, + uint16_t length) +{ + if (tcp_connections_number >= tcp_c->tcp_connections_length) { + return -1; + } + + if (tcp_c->tcp_connections[tcp_connections_number].status == TCP_CONN_CONNECTED) { + int ret = send_onion_request(tcp_c->tcp_connections[tcp_connections_number].connection, data, length); + + if (ret == 1) { + return 0; + } + } + + return -1; +} + +/* Send an oob packet via the TCP relay corresponding to tcp_connections_number. + * + * return 0 on success. + * return -1 on failure. + */ +int tcp_send_oob_packet(TCP_Connections *tcp_c, unsigned int tcp_connections_number, const uint8_t *public_key, + const uint8_t *packet, uint16_t length) +{ + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + if (tcp_con->status != TCP_CONN_CONNECTED) { + return -1; + } + + int ret = send_oob_packet(tcp_con->connection, public_key, packet, length); + + if (ret == 1) { + return 0; + } + + return -1; +} + +/* Set the callback for TCP data packets. + */ +void set_packet_tcp_connection_callback(TCP_Connections *tcp_c, int (*tcp_data_callback)(void *object, int id, + const uint8_t *data, uint16_t length, void *userdata), void *object) +{ + tcp_c->tcp_data_callback = tcp_data_callback; + tcp_c->tcp_data_callback_object = object; +} + +/* Set the callback for TCP onion packets. + */ +void set_oob_packet_tcp_connection_callback(TCP_Connections *tcp_c, int (*tcp_oob_callback)(void *object, + const uint8_t *public_key, unsigned int tcp_connections_number, const uint8_t *data, uint16_t length, void *userdata), + void *object) +{ + tcp_c->tcp_oob_callback = tcp_oob_callback; + tcp_c->tcp_oob_callback_object = object; +} + +/* Set the callback for TCP oob data packets. + */ +void set_onion_packet_tcp_connection_callback(TCP_Connections *tcp_c, int (*tcp_onion_callback)(void *object, + const uint8_t *data, uint16_t length, void *userdata), void *object) +{ + tcp_c->tcp_onion_callback = tcp_onion_callback; + tcp_c->tcp_onion_callback_object = object; +} + + +/* Find the TCP connection with public_key. + * + * return connections_number on success. + * return -1 on failure. + */ +static int find_tcp_connection_to(TCP_Connections *tcp_c, const uint8_t *public_key) +{ + unsigned int i; + + for (i = 0; i < tcp_c->connections_length; ++i) { + TCP_Connection_to *con_to = get_connection(tcp_c, i); + + if (con_to) { + if (public_key_cmp(con_to->public_key, public_key) == 0) { + return i; + } + } + } + + return -1; +} + +/* Find the TCP connection to a relay with relay_pk. + * + * return connections_number on success. + * return -1 on failure. + */ +static int find_tcp_connection_relay(TCP_Connections *tcp_c, const uint8_t *relay_pk) +{ + unsigned int i; + + for (i = 0; i < tcp_c->tcp_connections_length; ++i) { + TCP_con *tcp_con = get_tcp_connection(tcp_c, i); + + if (tcp_con) { + if (tcp_con->status == TCP_CONN_SLEEPING) { + if (public_key_cmp(tcp_con->relay_pk, relay_pk) == 0) { + return i; + } + } else { + if (public_key_cmp(tcp_con->connection->public_key, relay_pk) == 0) { + return i; + } + } + } + } + + return -1; +} + +/* Create a new TCP connection to public_key. + * + * public_key must be the counterpart to the secret key that the other peer used with new_tcp_connections(). + * + * id is the id in the callbacks for that connection. + * + * return connections_number on success. + * return -1 on failure. + */ +int new_tcp_connection_to(TCP_Connections *tcp_c, const uint8_t *public_key, int id) +{ + if (find_tcp_connection_to(tcp_c, public_key) != -1) { + return -1; + } + + int connections_number = create_connection(tcp_c); + + if (connections_number == -1) { + return -1; + } + + TCP_Connection_to *con_to = &tcp_c->connections[connections_number]; + + con_to->status = TCP_CONN_VALID; + memcpy(con_to->public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + con_to->id = id; + + return connections_number; +} + +/* return 0 on success. + * return -1 on failure. + */ +int kill_tcp_connection_to(TCP_Connections *tcp_c, int connections_number) +{ + TCP_Connection_to *con_to = get_connection(tcp_c, connections_number); + + if (!con_to) { + return -1; + } + + unsigned int i; + + for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) { + if (con_to->connections[i].tcp_connection) { + unsigned int tcp_connections_number = con_to->connections[i].tcp_connection - 1; + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + continue; + } + + if (tcp_con->status == TCP_CONN_CONNECTED) { + send_disconnect_request(tcp_con->connection, con_to->connections[i].connection_id); + } + + if (con_to->connections[i].status == TCP_CONNECTIONS_STATUS_ONLINE) { + --tcp_con->lock_count; + + if (con_to->status == TCP_CONN_SLEEPING) { + --tcp_con->sleep_count; + } + } + } + } + + return wipe_connection(tcp_c, connections_number); +} + +/* Set connection status. + * + * status of 1 means we are using the connection. + * status of 0 means we are not using it. + * + * Unused tcp connections will be disconnected from but kept in case they are needed. + * + * return 0 on success. + * return -1 on failure. + */ +int set_tcp_connection_to_status(TCP_Connections *tcp_c, int connections_number, bool status) +{ + TCP_Connection_to *con_to = get_connection(tcp_c, connections_number); + + if (!con_to) { + return -1; + } + + if (status) { + /* Connection is unsleeping. */ + if (con_to->status != TCP_CONN_SLEEPING) { + return -1; + } + + unsigned int i; + + for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) { + if (con_to->connections[i].tcp_connection) { + unsigned int tcp_connections_number = con_to->connections[i].tcp_connection - 1; + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + continue; + } + + if (tcp_con->status == TCP_CONN_SLEEPING) { + tcp_con->unsleep = 1; + } + } + } + + con_to->status = TCP_CONN_VALID; + return 0; + } + + /* Connection is going to sleep. */ + if (con_to->status != TCP_CONN_VALID) { + return -1; + } + + unsigned int i; + + for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) { + if (con_to->connections[i].tcp_connection) { + unsigned int tcp_connections_number = con_to->connections[i].tcp_connection - 1; + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + continue; + } + + if (con_to->connections[i].status == TCP_CONNECTIONS_STATUS_ONLINE) { + ++tcp_con->sleep_count; + } + } + } + + con_to->status = TCP_CONN_SLEEPING; + return 0; +} + +static bool tcp_connection_in_conn(TCP_Connection_to *con_to, unsigned int tcp_connections_number) +{ + unsigned int i; + + for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) { + if (con_to->connections[i].tcp_connection == (tcp_connections_number + 1)) { + return 1; + } + } + + return 0; +} + +/* return index on success. + * return -1 on failure. + */ +static int add_tcp_connection_to_conn(TCP_Connection_to *con_to, unsigned int tcp_connections_number) +{ + unsigned int i; + + if (tcp_connection_in_conn(con_to, tcp_connections_number)) { + return -1; + } + + for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) { + if (con_to->connections[i].tcp_connection == 0) { + con_to->connections[i].tcp_connection = tcp_connections_number + 1; + con_to->connections[i].status = TCP_CONNECTIONS_STATUS_NONE; + con_to->connections[i].connection_id = 0; + return i; + } + } + + return -1; +} + +/* return index on success. + * return -1 on failure. + */ +static int rm_tcp_connection_from_conn(TCP_Connection_to *con_to, unsigned int tcp_connections_number) +{ + unsigned int i; + + for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) { + if (con_to->connections[i].tcp_connection == (tcp_connections_number + 1)) { + con_to->connections[i].tcp_connection = 0; + con_to->connections[i].status = TCP_CONNECTIONS_STATUS_NONE; + con_to->connections[i].connection_id = 0; + return i; + } + } + + return -1; +} + +/* return number of online connections on success. + * return -1 on failure. + */ +static unsigned int online_tcp_connection_from_conn(TCP_Connection_to *con_to) +{ + unsigned int i, count = 0; + + for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) { + if (con_to->connections[i].tcp_connection) { + if (con_to->connections[i].status == TCP_CONNECTIONS_STATUS_ONLINE) { + ++count; + } + } + } + + return count; +} + +/* return index on success. + * return -1 on failure. + */ +static int set_tcp_connection_status(TCP_Connection_to *con_to, unsigned int tcp_connections_number, + unsigned int status, uint8_t connection_id) +{ + unsigned int i; + + for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) { + if (con_to->connections[i].tcp_connection == (tcp_connections_number + 1)) { + + if (con_to->connections[i].status == status) { + return -1; + } + + con_to->connections[i].status = status; + con_to->connections[i].connection_id = connection_id; + return i; + } + } + + return -1; +} + +/* Kill a TCP relay connection. + * + * return 0 on success. + * return -1 on failure. + */ +static int kill_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connections_number) +{ + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + unsigned int i; + + for (i = 0; i < tcp_c->connections_length; ++i) { + TCP_Connection_to *con_to = get_connection(tcp_c, i); + + if (con_to) { + rm_tcp_connection_from_conn(con_to, tcp_connections_number); + } + } + + if (tcp_con->onion) { + --tcp_c->onion_num_conns; + } + + kill_TCP_connection(tcp_con->connection); + + return wipe_tcp_connection(tcp_c, tcp_connections_number); +} + +static int reconnect_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connections_number) +{ + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + if (tcp_con->status == TCP_CONN_SLEEPING) { + return -1; + } + + IP_Port ip_port = tcp_con->connection->ip_port; + uint8_t relay_pk[CRYPTO_PUBLIC_KEY_SIZE]; + memcpy(relay_pk, tcp_con->connection->public_key, CRYPTO_PUBLIC_KEY_SIZE); + kill_TCP_connection(tcp_con->connection); + tcp_con->connection = new_TCP_connection(ip_port, relay_pk, tcp_c->self_public_key, tcp_c->self_secret_key, + &tcp_c->proxy_info); + + if (!tcp_con->connection) { + kill_tcp_relay_connection(tcp_c, tcp_connections_number); + return -1; + } + + unsigned int i; + + for (i = 0; i < tcp_c->connections_length; ++i) { + TCP_Connection_to *con_to = get_connection(tcp_c, i); + + if (con_to) { + set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_NONE, 0); + } + } + + if (tcp_con->onion) { + --tcp_c->onion_num_conns; + tcp_con->onion = 0; + } + + tcp_con->lock_count = 0; + tcp_con->sleep_count = 0; + tcp_con->connected_time = 0; + tcp_con->status = TCP_CONN_VALID; + tcp_con->unsleep = 0; + + return 0; +} + +static int sleep_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connections_number) +{ + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + if (tcp_con->status != TCP_CONN_CONNECTED) { + return -1; + } + + if (tcp_con->lock_count != tcp_con->sleep_count) { + return -1; + } + + tcp_con->ip_port = tcp_con->connection->ip_port; + memcpy(tcp_con->relay_pk, tcp_con->connection->public_key, CRYPTO_PUBLIC_KEY_SIZE); + + kill_TCP_connection(tcp_con->connection); + tcp_con->connection = NULL; + + unsigned int i; + + for (i = 0; i < tcp_c->connections_length; ++i) { + TCP_Connection_to *con_to = get_connection(tcp_c, i); + + if (con_to) { + set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_NONE, 0); + } + } + + if (tcp_con->onion) { + --tcp_c->onion_num_conns; + tcp_con->onion = 0; + } + + tcp_con->lock_count = 0; + tcp_con->sleep_count = 0; + tcp_con->connected_time = 0; + tcp_con->status = TCP_CONN_SLEEPING; + tcp_con->unsleep = 0; + + return 0; +} + +static int unsleep_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connections_number) +{ + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + if (tcp_con->status != TCP_CONN_SLEEPING) { + return -1; + } + + tcp_con->connection = new_TCP_connection(tcp_con->ip_port, tcp_con->relay_pk, tcp_c->self_public_key, + tcp_c->self_secret_key, &tcp_c->proxy_info); + + if (!tcp_con->connection) { + kill_tcp_relay_connection(tcp_c, tcp_connections_number); + return -1; + } + + tcp_con->lock_count = 0; + tcp_con->sleep_count = 0; + tcp_con->connected_time = 0; + tcp_con->status = TCP_CONN_VALID; + tcp_con->unsleep = 0; + return 0; +} + +/* Send a TCP routing request. + * + * return 0 on success. + * return -1 on failure. + */ +static int send_tcp_relay_routing_request(TCP_Connections *tcp_c, int tcp_connections_number, uint8_t *public_key) +{ + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + if (tcp_con->status == TCP_CONN_SLEEPING) { + return -1; + } + + if (send_routing_request(tcp_con->connection, public_key) != 1) { + return -1; + } + + return 0; +} + +static int tcp_response_callback(void *object, uint8_t connection_id, const uint8_t *public_key) +{ + TCP_Client_Connection *TCP_client_con = (TCP_Client_Connection *)object; + TCP_Connections *tcp_c = (TCP_Connections *)TCP_client_con->custom_object; + + unsigned int tcp_connections_number = TCP_client_con->custom_uint; + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + int connections_number = find_tcp_connection_to(tcp_c, public_key); + + if (connections_number == -1) { + return -1; + } + + TCP_Connection_to *con_to = get_connection(tcp_c, connections_number); + + if (con_to == NULL) { + return -1; + } + + if (set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_REGISTERED, connection_id) == -1) { + return -1; + } + + set_tcp_connection_number(tcp_con->connection, connection_id, connections_number); + + return 0; +} + +static int tcp_status_callback(void *object, uint32_t number, uint8_t connection_id, uint8_t status) +{ + TCP_Client_Connection *TCP_client_con = (TCP_Client_Connection *)object; + TCP_Connections *tcp_c = (TCP_Connections *)TCP_client_con->custom_object; + + unsigned int tcp_connections_number = TCP_client_con->custom_uint; + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + TCP_Connection_to *con_to = get_connection(tcp_c, number); + + if (!con_to || !tcp_con) { + return -1; + } + + if (status == 1) { + if (set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_REGISTERED, connection_id) == -1) { + return -1; + } + + --tcp_con->lock_count; + + if (con_to->status == TCP_CONN_SLEEPING) { + --tcp_con->sleep_count; + } + } else if (status == 2) { + if (set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_ONLINE, connection_id) == -1) { + return -1; + } + + ++tcp_con->lock_count; + + if (con_to->status == TCP_CONN_SLEEPING) { + ++tcp_con->sleep_count; + } + } + + return 0; +} + +static int tcp_conn_data_callback(void *object, uint32_t number, uint8_t connection_id, const uint8_t *data, + uint16_t length, void *userdata) +{ + if (length == 0) { + return -1; + } + + TCP_Client_Connection *TCP_client_con = (TCP_Client_Connection *)object; + TCP_Connections *tcp_c = (TCP_Connections *)TCP_client_con->custom_object; + + unsigned int tcp_connections_number = TCP_client_con->custom_uint; + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + TCP_Connection_to *con_to = get_connection(tcp_c, number); + + if (!con_to) { + return -1; + } + + if (tcp_c->tcp_data_callback) { + tcp_c->tcp_data_callback(tcp_c->tcp_data_callback_object, con_to->id, data, length, userdata); + } + + return 0; +} + +static int tcp_conn_oob_callback(void *object, const uint8_t *public_key, const uint8_t *data, uint16_t length, + void *userdata) +{ + if (length == 0) { + return -1; + } + + TCP_Client_Connection *TCP_client_con = (TCP_Client_Connection *)object; + TCP_Connections *tcp_c = (TCP_Connections *)TCP_client_con->custom_object; + + unsigned int tcp_connections_number = TCP_client_con->custom_uint; + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + /* TODO(irungentoo): optimize */ + int connections_number = find_tcp_connection_to(tcp_c, public_key); + + TCP_Connection_to *con_to = get_connection(tcp_c, connections_number); + + if (con_to && tcp_connection_in_conn(con_to, tcp_connections_number)) { + return tcp_conn_data_callback(object, connections_number, 0, data, length, userdata); + } + + if (tcp_c->tcp_oob_callback) { + tcp_c->tcp_oob_callback(tcp_c->tcp_oob_callback_object, public_key, tcp_connections_number, data, length, userdata); + } + + return 0; +} + +static int tcp_onion_callback(void *object, const uint8_t *data, uint16_t length, void *userdata) +{ + TCP_Connections *tcp_c = (TCP_Connections *)object; + + if (tcp_c->tcp_onion_callback) { + tcp_c->tcp_onion_callback(tcp_c->tcp_onion_callback_object, data, length, userdata); + } + + return 0; +} + +/* Set callbacks for the TCP relay connection. + * + * return 0 on success. + * return -1 on failure. + */ +static int tcp_relay_set_callbacks(TCP_Connections *tcp_c, int tcp_connections_number) +{ + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + TCP_Client_Connection *con = tcp_con->connection; + + con->custom_object = tcp_c; + con->custom_uint = tcp_connections_number; + onion_response_handler(con, &tcp_onion_callback, tcp_c); + routing_response_handler(con, &tcp_response_callback, con); + routing_status_handler(con, &tcp_status_callback, con); + routing_data_handler(con, &tcp_conn_data_callback, con); + oob_data_handler(con, &tcp_conn_oob_callback, con); + + return 0; +} + +static int tcp_relay_on_online(TCP_Connections *tcp_c, int tcp_connections_number) +{ + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + unsigned int i, sent = 0; + + for (i = 0; i < tcp_c->connections_length; ++i) { + TCP_Connection_to *con_to = get_connection(tcp_c, i); + + if (con_to) { + if (tcp_connection_in_conn(con_to, tcp_connections_number)) { + if (send_tcp_relay_routing_request(tcp_c, tcp_connections_number, con_to->public_key) == 0) { + ++sent; + } + } + } + } + + tcp_relay_set_callbacks(tcp_c, tcp_connections_number); + tcp_con->status = TCP_CONN_CONNECTED; + + /* If this connection isn't used by any connection, we don't need to wait for them to come online. */ + if (sent) { + tcp_con->connected_time = unix_time(); + } else { + tcp_con->connected_time = 0; + } + + if (tcp_c->onion_status && tcp_c->onion_num_conns < NUM_ONION_TCP_CONNECTIONS) { + tcp_con->onion = 1; + ++tcp_c->onion_num_conns; + } + + return 0; +} + +static int add_tcp_relay_instance(TCP_Connections *tcp_c, IP_Port ip_port, const uint8_t *relay_pk) +{ + if (ip_port.ip.family == TCP_INET) { + ip_port.ip.family = TOX_AF_INET; + } else if (ip_port.ip.family == TCP_INET6) { + ip_port.ip.family = TOX_AF_INET6; + } + + if (ip_port.ip.family != TOX_AF_INET && ip_port.ip.family != TOX_AF_INET6) { + return -1; + } + + int tcp_connections_number = create_tcp_connection(tcp_c); + + if (tcp_connections_number == -1) { + return -1; + } + + TCP_con *tcp_con = &tcp_c->tcp_connections[tcp_connections_number]; + + tcp_con->connection = new_TCP_connection(ip_port, relay_pk, tcp_c->self_public_key, tcp_c->self_secret_key, + &tcp_c->proxy_info); + + if (!tcp_con->connection) { + return -1; + } + + tcp_con->status = TCP_CONN_VALID; + + return tcp_connections_number; +} + +/* Add a TCP relay to the TCP_Connections instance. + * + * return 0 on success. + * return -1 on failure. + */ +int add_tcp_relay_global(TCP_Connections *tcp_c, IP_Port ip_port, const uint8_t *relay_pk) +{ + int tcp_connections_number = find_tcp_connection_relay(tcp_c, relay_pk); + + if (tcp_connections_number != -1) { + return -1; + } + + if (add_tcp_relay_instance(tcp_c, ip_port, relay_pk) == -1) { + return -1; + } + + return 0; +} + +/* Add a TCP relay tied to a connection. + * + * return 0 on success. + * return -1 on failure. + */ +int add_tcp_number_relay_connection(TCP_Connections *tcp_c, int connections_number, unsigned int tcp_connections_number) +{ + TCP_Connection_to *con_to = get_connection(tcp_c, connections_number); + + if (!con_to) { + return -1; + } + + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + if (con_to->status != TCP_CONN_SLEEPING && tcp_con->status == TCP_CONN_SLEEPING) { + tcp_con->unsleep = 1; + } + + if (add_tcp_connection_to_conn(con_to, tcp_connections_number) == -1) { + return -1; + } + + if (tcp_con->status == TCP_CONN_CONNECTED) { + if (send_tcp_relay_routing_request(tcp_c, tcp_connections_number, con_to->public_key) == 0) { + tcp_con->connected_time = unix_time(); + } + } + + return 0; +} + +/* Add a TCP relay tied to a connection. + * + * This should be called with the same relay by two peers who want to create a TCP connection with each other. + * + * return 0 on success. + * return -1 on failure. + */ +int add_tcp_relay_connection(TCP_Connections *tcp_c, int connections_number, IP_Port ip_port, const uint8_t *relay_pk) +{ + TCP_Connection_to *con_to = get_connection(tcp_c, connections_number); + + if (!con_to) { + return -1; + } + + int tcp_connections_number = find_tcp_connection_relay(tcp_c, relay_pk); + + if (tcp_connections_number != -1) { + return add_tcp_number_relay_connection(tcp_c, connections_number, tcp_connections_number); + } + + if (online_tcp_connection_from_conn(con_to) >= RECOMMENDED_FRIEND_TCP_CONNECTIONS) { + return -1; + } + + tcp_connections_number = add_tcp_relay_instance(tcp_c, ip_port, relay_pk); + + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + if (add_tcp_connection_to_conn(con_to, tcp_connections_number) == -1) { + return -1; + } + + return 0; +} + +/* return number of online tcp relays tied to the connection on success. + * return 0 on failure. + */ +unsigned int tcp_connection_to_online_tcp_relays(TCP_Connections *tcp_c, int connections_number) +{ + TCP_Connection_to *con_to = get_connection(tcp_c, connections_number); + + if (!con_to) { + return 0; + } + + return online_tcp_connection_from_conn(con_to); +} + +/* Copy a maximum of max_num TCP relays we are connected to to tcp_relays. + * NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6. + * + * return number of relays copied to tcp_relays on success. + * return 0 on failure. + */ +unsigned int tcp_copy_connected_relays(TCP_Connections *tcp_c, Node_format *tcp_relays, uint16_t max_num) +{ + unsigned int i, copied = 0, r = rand(); + + for (i = 0; (i < tcp_c->tcp_connections_length) && (copied < max_num); ++i) { + TCP_con *tcp_con = get_tcp_connection(tcp_c, (i + r) % tcp_c->tcp_connections_length); + + if (!tcp_con) { + continue; + } + + if (tcp_con->status == TCP_CONN_CONNECTED) { + memcpy(tcp_relays[copied].public_key, tcp_con->connection->public_key, CRYPTO_PUBLIC_KEY_SIZE); + tcp_relays[copied].ip_port = tcp_con->connection->ip_port; + + if (tcp_relays[copied].ip_port.ip.family == TOX_AF_INET) { + tcp_relays[copied].ip_port.ip.family = TCP_INET; + } else if (tcp_relays[copied].ip_port.ip.family == TOX_AF_INET6) { + tcp_relays[copied].ip_port.ip.family = TCP_INET6; + } + + ++copied; + } + } + + return copied; +} + +/* Set if we want TCP_connection to allocate some connection for onion use. + * + * If status is 1, allocate some connections. if status is 0, don't. + * + * return 0 on success. + * return -1 on failure. + */ +int set_tcp_onion_status(TCP_Connections *tcp_c, bool status) +{ + if (tcp_c->onion_status == status) { + return -1; + } + + if (status) { + unsigned int i; + + for (i = 0; i < tcp_c->tcp_connections_length; ++i) { + TCP_con *tcp_con = get_tcp_connection(tcp_c, i); + + if (tcp_con) { + if (tcp_con->status == TCP_CONN_CONNECTED && !tcp_con->onion) { + ++tcp_c->onion_num_conns; + tcp_con->onion = 1; + } + } + + if (tcp_c->onion_num_conns >= NUM_ONION_TCP_CONNECTIONS) { + break; + } + } + + if (tcp_c->onion_num_conns < NUM_ONION_TCP_CONNECTIONS) { + unsigned int wakeup = NUM_ONION_TCP_CONNECTIONS - tcp_c->onion_num_conns; + + for (i = 0; i < tcp_c->tcp_connections_length; ++i) { + TCP_con *tcp_con = get_tcp_connection(tcp_c, i); + + if (tcp_con) { + if (tcp_con->status == TCP_CONN_SLEEPING) { + tcp_con->unsleep = 1; + } + } + + if (!wakeup) { + break; + } + } + } + + tcp_c->onion_status = 1; + } else { + unsigned int i; + + for (i = 0; i < tcp_c->tcp_connections_length; ++i) { + TCP_con *tcp_con = get_tcp_connection(tcp_c, i); + + if (tcp_con) { + if (tcp_con->onion) { + --tcp_c->onion_num_conns; + tcp_con->onion = 0; + } + } + } + + tcp_c->onion_status = 0; + } + + return 0; +} + +/* Returns a new TCP_Connections object associated with the secret_key. + * + * In order for others to connect to this instance new_tcp_connection_to() must be called with the + * public_key associated with secret_key. + * + * Returns NULL on failure. + */ +TCP_Connections *new_tcp_connections(const uint8_t *secret_key, TCP_Proxy_Info *proxy_info) +{ + if (secret_key == NULL) { + return NULL; + } + + TCP_Connections *temp = (TCP_Connections *)calloc(1, sizeof(TCP_Connections)); + + if (temp == NULL) { + return NULL; + } + + memcpy(temp->self_secret_key, secret_key, CRYPTO_SECRET_KEY_SIZE); + crypto_derive_public_key(temp->self_public_key, temp->self_secret_key); + temp->proxy_info = *proxy_info; + + return temp; +} + +static void do_tcp_conns(TCP_Connections *tcp_c, void *userdata) +{ + unsigned int i; + + for (i = 0; i < tcp_c->tcp_connections_length; ++i) { + TCP_con *tcp_con = get_tcp_connection(tcp_c, i); + + if (tcp_con) { + if (tcp_con->status != TCP_CONN_SLEEPING) { + do_TCP_connection(tcp_con->connection, userdata); + + /* callbacks can change TCP connection address. */ + tcp_con = get_tcp_connection(tcp_c, i); + + // Make sure the TCP connection wasn't dropped in any of the callbacks. + assert(tcp_con != NULL); + + if (tcp_con->connection->status == TCP_CLIENT_DISCONNECTED) { + if (tcp_con->status == TCP_CONN_CONNECTED) { + reconnect_tcp_relay_connection(tcp_c, i); + } else { + kill_tcp_relay_connection(tcp_c, i); + } + + continue; + } + + if (tcp_con->status == TCP_CONN_VALID && tcp_con->connection->status == TCP_CLIENT_CONFIRMED) { + tcp_relay_on_online(tcp_c, i); + } + + if (tcp_con->status == TCP_CONN_CONNECTED && !tcp_con->onion && tcp_con->lock_count + && tcp_con->lock_count == tcp_con->sleep_count + && is_timeout(tcp_con->connected_time, TCP_CONNECTION_ANNOUNCE_TIMEOUT)) { + sleep_tcp_relay_connection(tcp_c, i); + } + } + + if (tcp_con->status == TCP_CONN_SLEEPING && tcp_con->unsleep) { + unsleep_tcp_relay_connection(tcp_c, i); + } + } + } +} + +static void kill_nonused_tcp(TCP_Connections *tcp_c) +{ + if (tcp_c->tcp_connections_length == 0) { + return; + } + + unsigned int i; + unsigned int num_online = 0; + unsigned int num_kill = 0; + VLA(unsigned int, to_kill, tcp_c->tcp_connections_length); + + for (i = 0; i < tcp_c->tcp_connections_length; ++i) { + TCP_con *tcp_con = get_tcp_connection(tcp_c, i); + + if (tcp_con) { + if (tcp_con->status == TCP_CONN_CONNECTED) { + if (!tcp_con->onion && !tcp_con->lock_count && is_timeout(tcp_con->connected_time, TCP_CONNECTION_ANNOUNCE_TIMEOUT)) { + to_kill[num_kill] = i; + ++num_kill; + } + + ++num_online; + } + } + } + + if (num_online <= RECOMMENDED_FRIEND_TCP_CONNECTIONS) { + return; + } + + unsigned int n = num_online - RECOMMENDED_FRIEND_TCP_CONNECTIONS; + + if (n < num_kill) { + num_kill = n; + } + + for (i = 0; i < num_kill; ++i) { + kill_tcp_relay_connection(tcp_c, to_kill[i]); + } +} + +void do_tcp_connections(TCP_Connections *tcp_c, void *userdata) +{ + do_tcp_conns(tcp_c, userdata); + kill_nonused_tcp(tcp_c); +} + +void kill_tcp_connections(TCP_Connections *tcp_c) +{ + unsigned int i; + + for (i = 0; i < tcp_c->tcp_connections_length; ++i) { + kill_TCP_connection(tcp_c->tcp_connections[i].connection); + } + + free(tcp_c->tcp_connections); + free(tcp_c->connections); + free(tcp_c); +} diff --git a/protocols/Tox/libtox/src/toxcore/TCP_connection.h b/protocols/Tox/libtox/src/toxcore/TCP_connection.h new file mode 100644 index 0000000000..a45129a7e8 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/TCP_connection.h @@ -0,0 +1,223 @@ +/* + * Handles TCP relay connections between two Tox clients. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2015 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef TCP_CONNECTION_H +#define TCP_CONNECTION_H + +#include "TCP_client.h" + +#define TCP_CONN_NONE 0 +#define TCP_CONN_VALID 1 + +/* NOTE: only used by TCP_con */ +#define TCP_CONN_CONNECTED 2 + +/* Connection is not connected but can be quickly reconnected in case it is needed. */ +#define TCP_CONN_SLEEPING 3 + +#define TCP_CONNECTIONS_STATUS_NONE 0 +#define TCP_CONNECTIONS_STATUS_REGISTERED 1 +#define TCP_CONNECTIONS_STATUS_ONLINE 2 + +#define MAX_FRIEND_TCP_CONNECTIONS 6 + +/* Time until connection to friend gets killed (if it doesn't get locked within that time) */ +#define TCP_CONNECTION_ANNOUNCE_TIMEOUT (TCP_CONNECTION_TIMEOUT) + +/* The amount of recommended connections for each friend + NOTE: Must be at most (MAX_FRIEND_TCP_CONNECTIONS / 2) */ +#define RECOMMENDED_FRIEND_TCP_CONNECTIONS (MAX_FRIEND_TCP_CONNECTIONS / 2) + +/* Number of TCP connections used for onion purposes. */ +#define NUM_ONION_TCP_CONNECTIONS RECOMMENDED_FRIEND_TCP_CONNECTIONS + +typedef struct { + uint8_t status; + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The dht public key of the peer */ + + struct { + uint32_t tcp_connection; + unsigned int status; + unsigned int connection_id; + } connections[MAX_FRIEND_TCP_CONNECTIONS]; + + int id; /* id used in callbacks. */ +} TCP_Connection_to; + +typedef struct { + uint8_t status; + TCP_Client_Connection *connection; + uint64_t connected_time; + uint32_t lock_count; + uint32_t sleep_count; + bool onion; + + /* Only used when connection is sleeping. */ + IP_Port ip_port; + uint8_t relay_pk[CRYPTO_PUBLIC_KEY_SIZE]; + bool unsleep; /* set to 1 to unsleep connection. */ +} TCP_con; + +typedef struct TCP_Connections TCP_Connections; + +const uint8_t *tcp_connections_public_key(const TCP_Connections *tcp_c); + +/* Send a packet to the TCP connection. + * + * return -1 on failure. + * return 0 on success. + */ +int send_packet_tcp_connection(TCP_Connections *tcp_c, int connections_number, const uint8_t *packet, uint16_t length); + +/* Return a random TCP connection number for use in send_tcp_onion_request. + * + * TODO(irungentoo): This number is just the index of an array that the elements + * can change without warning. + * + * return TCP connection number on success. + * return -1 on failure. + */ +int get_random_tcp_onion_conn_number(TCP_Connections *tcp_c); + +/* Send an onion packet via the TCP relay corresponding to tcp_connections_number. + * + * return 0 on success. + * return -1 on failure. + */ +int tcp_send_onion_request(TCP_Connections *tcp_c, unsigned int tcp_connections_number, const uint8_t *data, + uint16_t length); + +/* Set if we want TCP_connection to allocate some connection for onion use. + * + * If status is 1, allocate some connections. if status is 0, don't. + * + * return 0 on success. + * return -1 on failure. + */ +int set_tcp_onion_status(TCP_Connections *tcp_c, bool status); + +/* Send an oob packet via the TCP relay corresponding to tcp_connections_number. + * + * return 0 on success. + * return -1 on failure. + */ +int tcp_send_oob_packet(TCP_Connections *tcp_c, unsigned int tcp_connections_number, const uint8_t *public_key, + const uint8_t *packet, uint16_t length); + +/* Set the callback for TCP data packets. + */ +void set_packet_tcp_connection_callback(TCP_Connections *tcp_c, int (*tcp_data_callback)(void *object, int id, + const uint8_t *data, uint16_t length, void *userdata), void *object); + +/* Set the callback for TCP onion packets. + */ +void set_onion_packet_tcp_connection_callback(TCP_Connections *tcp_c, int (*tcp_onion_callback)(void *object, + const uint8_t *data, uint16_t length, void *userdata), void *object); + +/* Set the callback for TCP oob data packets. + */ +void set_oob_packet_tcp_connection_callback(TCP_Connections *tcp_c, int (*tcp_oob_callback)(void *object, + const uint8_t *public_key, unsigned int tcp_connections_number, const uint8_t *data, uint16_t length, void *userdata), + void *object); + +/* Create a new TCP connection to public_key. + * + * public_key must be the counterpart to the secret key that the other peer used with new_tcp_connections(). + * + * id is the id in the callbacks for that connection. + * + * return connections_number on success. + * return -1 on failure. + */ +int new_tcp_connection_to(TCP_Connections *tcp_c, const uint8_t *public_key, int id); + +/* return 0 on success. + * return -1 on failure. + */ +int kill_tcp_connection_to(TCP_Connections *tcp_c, int connections_number); + +/* Set connection status. + * + * status of 1 means we are using the connection. + * status of 0 means we are not using it. + * + * Unused tcp connections will be disconnected from but kept in case they are needed. + * + * return 0 on success. + * return -1 on failure. + */ +int set_tcp_connection_to_status(TCP_Connections *tcp_c, int connections_number, bool status); + +/* return number of online tcp relays tied to the connection on success. + * return 0 on failure. + */ +unsigned int tcp_connection_to_online_tcp_relays(TCP_Connections *tcp_c, int connections_number); + +/* Add a TCP relay tied to a connection. + * + * NOTE: This can only be used during the tcp_oob_callback. + * + * return 0 on success. + * return -1 on failure. + */ +int add_tcp_number_relay_connection(TCP_Connections *tcp_c, int connections_number, + unsigned int tcp_connections_number); + +/* Add a TCP relay tied to a connection. + * + * This should be called with the same relay by two peers who want to create a TCP connection with each other. + * + * return 0 on success. + * return -1 on failure. + */ +int add_tcp_relay_connection(TCP_Connections *tcp_c, int connections_number, IP_Port ip_port, const uint8_t *relay_pk); + +/* Add a TCP relay to the instance. + * + * return 0 on success. + * return -1 on failure. + */ +int add_tcp_relay_global(TCP_Connections *tcp_c, IP_Port ip_port, const uint8_t *relay_pk); + +/* Copy a maximum of max_num TCP relays we are connected to to tcp_relays. + * NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6. + * + * return number of relays copied to tcp_relays on success. + * return 0 on failure. + */ +unsigned int tcp_copy_connected_relays(TCP_Connections *tcp_c, Node_format *tcp_relays, uint16_t max_num); + +/* Returns a new TCP_Connections object associated with the secret_key. + * + * In order for others to connect to this instance new_tcp_connection_to() must be called with the + * public_key associated with secret_key. + * + * Returns NULL on failure. + */ +TCP_Connections *new_tcp_connections(const uint8_t *secret_key, TCP_Proxy_Info *proxy_info); + +void do_tcp_connections(TCP_Connections *tcp_c, void *userdata); +void kill_tcp_connections(TCP_Connections *tcp_c); + +#endif + diff --git a/protocols/Tox/libtox/src/toxcore/TCP_server.c b/protocols/Tox/libtox/src/toxcore/TCP_server.c new file mode 100644 index 0000000000..9b94667aa1 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/TCP_server.c @@ -0,0 +1,1417 @@ +/* + * Implementation of the TCP relay server part of Tox. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "TCP_server.h" + +#include "util.h" + +#if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32) +#include <sys/ioctl.h> +#endif + +struct TCP_Server { + Onion *onion; + +#ifdef TCP_SERVER_USE_EPOLL + int efd; + uint64_t last_run_pinged; +#endif + Socket *socks_listening; + unsigned int num_listening_socks; + + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t secret_key[CRYPTO_SECRET_KEY_SIZE]; + TCP_Secure_Connection incoming_connection_queue[MAX_INCOMING_CONNECTIONS]; + uint16_t incoming_connection_queue_index; + TCP_Secure_Connection unconfirmed_connection_queue[MAX_INCOMING_CONNECTIONS]; + uint16_t unconfirmed_connection_queue_index; + + TCP_Secure_Connection *accepted_connection_array; + uint32_t size_accepted_connections; + uint32_t num_accepted_connections; + + uint64_t counter; + + BS_LIST accepted_key_list; +}; + +const uint8_t *tcp_server_public_key(const TCP_Server *tcp_server) +{ + return tcp_server->public_key; +} + +size_t tcp_server_listen_count(const TCP_Server *tcp_server) +{ + return tcp_server->num_listening_socks; +} + +/* This is needed to compile on Android below API 21 + */ +#ifndef EPOLLRDHUP +#define EPOLLRDHUP 0x2000 +#endif + +/* Set the size of the connection list to numfriends. + * + * return -1 if realloc fails. + * return 0 if it succeeds. + */ +static int realloc_connection(TCP_Server *TCP_server, uint32_t num) +{ + if (num == 0) { + free(TCP_server->accepted_connection_array); + TCP_server->accepted_connection_array = NULL; + TCP_server->size_accepted_connections = 0; + return 0; + } + + if (num == TCP_server->size_accepted_connections) { + return 0; + } + + TCP_Secure_Connection *new_connections = (TCP_Secure_Connection *)realloc( + TCP_server->accepted_connection_array, + num * sizeof(TCP_Secure_Connection)); + + if (new_connections == NULL) { + return -1; + } + + if (num > TCP_server->size_accepted_connections) { + uint32_t old_size = TCP_server->size_accepted_connections; + uint32_t size_new_entries = (num - old_size) * sizeof(TCP_Secure_Connection); + memset(new_connections + old_size, 0, size_new_entries); + } + + TCP_server->accepted_connection_array = new_connections; + TCP_server->size_accepted_connections = num; + return 0; +} + +/* return index corresponding to connection with peer on success + * return -1 on failure. + */ +static int get_TCP_connection_index(const TCP_Server *TCP_server, const uint8_t *public_key) +{ + return bs_list_find(&TCP_server->accepted_key_list, public_key); +} + + +static int kill_accepted(TCP_Server *TCP_server, int index); + +/* Add accepted TCP connection to the list. + * + * return index on success + * return -1 on failure + */ +static int add_accepted(TCP_Server *TCP_server, const TCP_Secure_Connection *con) +{ + int index = get_TCP_connection_index(TCP_server, con->public_key); + + if (index != -1) { /* If an old connection to the same public key exists, kill it. */ + kill_accepted(TCP_server, index); + index = -1; + } + + if (TCP_server->size_accepted_connections == TCP_server->num_accepted_connections) { + if (realloc_connection(TCP_server, TCP_server->size_accepted_connections + 4) == -1) { + return -1; + } + + index = TCP_server->num_accepted_connections; + } else { + uint32_t i; + + for (i = TCP_server->size_accepted_connections; i != 0; --i) { + if (TCP_server->accepted_connection_array[i - 1].status == TCP_STATUS_NO_STATUS) { + index = i - 1; + break; + } + } + } + + if (index == -1) { + fprintf(stderr, "FAIL index is -1\n"); + return -1; + } + + if (!bs_list_add(&TCP_server->accepted_key_list, con->public_key, index)) { + return -1; + } + + memcpy(&TCP_server->accepted_connection_array[index], con, sizeof(TCP_Secure_Connection)); + TCP_server->accepted_connection_array[index].status = TCP_STATUS_CONFIRMED; + ++TCP_server->num_accepted_connections; + TCP_server->accepted_connection_array[index].identifier = ++TCP_server->counter; + TCP_server->accepted_connection_array[index].last_pinged = unix_time(); + TCP_server->accepted_connection_array[index].ping_id = 0; + + return index; +} + +/* Delete accepted connection from list. + * + * return 0 on success + * return -1 on failure + */ +static int del_accepted(TCP_Server *TCP_server, int index) +{ + if ((uint32_t)index >= TCP_server->size_accepted_connections) { + return -1; + } + + if (TCP_server->accepted_connection_array[index].status == TCP_STATUS_NO_STATUS) { + return -1; + } + + if (!bs_list_remove(&TCP_server->accepted_key_list, TCP_server->accepted_connection_array[index].public_key, index)) { + return -1; + } + + crypto_memzero(&TCP_server->accepted_connection_array[index], sizeof(TCP_Secure_Connection)); + --TCP_server->num_accepted_connections; + + if (TCP_server->num_accepted_connections == 0) { + realloc_connection(TCP_server, 0); + } + + return 0; +} + +/* return the amount of data in the tcp recv buffer. + * return 0 on failure. + */ +unsigned int TCP_socket_data_recv_buffer(Socket sock) +{ +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + unsigned long count = 0; + ioctlsocket(sock, FIONREAD, &count); +#else + int count = 0; + ioctl(sock, FIONREAD, &count); +#endif + + return count; +} + +/* Read the next two bytes in TCP stream then convert them to + * length (host byte order). + * + * return length on success + * return 0 if nothing has been read from socket. + * return ~0 on failure. + */ +uint16_t read_TCP_length(Socket sock) +{ + unsigned int count = TCP_socket_data_recv_buffer(sock); + + if (count >= sizeof(uint16_t)) { + uint16_t length; + int len = recv(sock, (char *)&length, sizeof(uint16_t), MSG_NOSIGNAL); + + if (len != sizeof(uint16_t)) { + fprintf(stderr, "FAIL recv packet\n"); + return 0; + } + + length = net_ntohs(length); + + if (length > MAX_PACKET_SIZE) { + return ~0; + } + + return length; + } + + return 0; +} + +/* Read length bytes from socket. + * + * return length on success + * return -1 on failure/no data in buffer. + */ +int read_TCP_packet(Socket sock, uint8_t *data, uint16_t length) +{ + unsigned int count = TCP_socket_data_recv_buffer(sock); + + if (count >= length) { + int len = recv(sock, (char *)data, length, MSG_NOSIGNAL); + + if (len != length) { + fprintf(stderr, "FAIL recv packet\n"); + return -1; + } + + return len; + } + + return -1; +} + +/* return length of received packet on success. + * return 0 if could not read any packet. + * return -1 on failure (connection must be killed). + */ +int read_packet_TCP_secure_connection(Socket sock, uint16_t *next_packet_length, const uint8_t *shared_key, + uint8_t *recv_nonce, uint8_t *data, uint16_t max_len) +{ + if (*next_packet_length == 0) { + uint16_t len = read_TCP_length(sock); + + if (len == (uint16_t)~0) { + return -1; + } + + if (len == 0) { + return 0; + } + + *next_packet_length = len; + } + + if (max_len + CRYPTO_MAC_SIZE < *next_packet_length) { + return -1; + } + + VLA(uint8_t, data_encrypted, *next_packet_length); + int len_packet = read_TCP_packet(sock, data_encrypted, *next_packet_length); + + if (len_packet != *next_packet_length) { + return 0; + } + + *next_packet_length = 0; + + int len = decrypt_data_symmetric(shared_key, recv_nonce, data_encrypted, len_packet, data); + + if (len + CRYPTO_MAC_SIZE != len_packet) { + return -1; + } + + increment_nonce(recv_nonce); + + return len; +} + +/* return 0 if pending data was sent completely + * return -1 if it wasn't + */ +static int send_pending_data_nonpriority(TCP_Secure_Connection *con) +{ + if (con->last_packet_length == 0) { + return 0; + } + + uint16_t left = con->last_packet_length - con->last_packet_sent; + int len = send(con->sock, (const char *)(con->last_packet + con->last_packet_sent), left, MSG_NOSIGNAL); + + if (len <= 0) { + return -1; + } + + if (len == left) { + con->last_packet_length = 0; + con->last_packet_sent = 0; + return 0; + } + + con->last_packet_sent += len; + return -1; +} + +/* return 0 if pending data was sent completely + * return -1 if it wasn't + */ +static int send_pending_data(TCP_Secure_Connection *con) +{ + /* finish sending current non-priority packet */ + if (send_pending_data_nonpriority(con) == -1) { + return -1; + } + + TCP_Priority_List *p = con->priority_queue_start; + + while (p) { + uint16_t left = p->size - p->sent; + int len = send(con->sock, (const char *)(p->data + p->sent), left, MSG_NOSIGNAL); + + if (len != left) { + if (len > 0) { + p->sent += len; + } + + break; + } + + TCP_Priority_List *pp = p; + p = p->next; + free(pp); + } + + con->priority_queue_start = p; + + if (!p) { + con->priority_queue_end = NULL; + return 0; + } + + return -1; +} + +/* return 0 on failure (only if malloc fails) + * return 1 on success + */ +static bool add_priority(TCP_Secure_Connection *con, const uint8_t *packet, uint16_t size, uint16_t sent) +{ + TCP_Priority_List *p = con->priority_queue_end; + TCP_Priority_List *new_list = (TCP_Priority_List *)malloc(sizeof(TCP_Priority_List) + size); + + if (!new_list) { + return 0; + } + + new_list->next = NULL; + new_list->size = size; + new_list->sent = sent; + memcpy(new_list->data, packet, size); + + if (p) { + p->next = new_list; + } else { + con->priority_queue_start = new_list; + } + + con->priority_queue_end = new_list; + return 1; +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +static int write_packet_TCP_secure_connection(TCP_Secure_Connection *con, const uint8_t *data, uint16_t length, + bool priority) +{ + if (length + CRYPTO_MAC_SIZE > MAX_PACKET_SIZE) { + return -1; + } + + bool sendpriority = 1; + + if (send_pending_data(con) == -1) { + if (priority) { + sendpriority = 0; + } else { + return 0; + } + } + + VLA(uint8_t, packet, sizeof(uint16_t) + length + CRYPTO_MAC_SIZE); + + uint16_t c_length = net_htons(length + CRYPTO_MAC_SIZE); + memcpy(packet, &c_length, sizeof(uint16_t)); + int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t)); + + if ((unsigned int)len != (SIZEOF_VLA(packet) - sizeof(uint16_t))) { + return -1; + } + + if (priority) { + len = sendpriority ? send(con->sock, (const char *)packet, SIZEOF_VLA(packet), MSG_NOSIGNAL) : 0; + + if (len <= 0) { + len = 0; + } + + increment_nonce(con->sent_nonce); + + if ((unsigned int)len == SIZEOF_VLA(packet)) { + return 1; + } + + return add_priority(con, packet, SIZEOF_VLA(packet), len); + } + + len = send(con->sock, (const char *)packet, SIZEOF_VLA(packet), MSG_NOSIGNAL); + + if (len <= 0) { + return 0; + } + + increment_nonce(con->sent_nonce); + + if ((unsigned int)len == SIZEOF_VLA(packet)) { + return 1; + } + + memcpy(con->last_packet, packet, SIZEOF_VLA(packet)); + con->last_packet_length = SIZEOF_VLA(packet); + con->last_packet_sent = len; + return 1; +} + +/* Kill a TCP_Secure_Connection + */ +static void kill_TCP_secure_connection(TCP_Secure_Connection *con) +{ + kill_sock(con->sock); + crypto_memzero(con, sizeof(TCP_Secure_Connection)); +} + +static int rm_connection_index(TCP_Server *TCP_server, TCP_Secure_Connection *con, uint8_t con_number); + +/* Kill an accepted TCP_Secure_Connection + * + * return -1 on failure. + * return 0 on success. + */ +static int kill_accepted(TCP_Server *TCP_server, int index) +{ + if ((uint32_t)index >= TCP_server->size_accepted_connections) { + return -1; + } + + uint32_t i; + + for (i = 0; i < NUM_CLIENT_CONNECTIONS; ++i) { + rm_connection_index(TCP_server, &TCP_server->accepted_connection_array[index], i); + } + + Socket sock = TCP_server->accepted_connection_array[index].sock; + + if (del_accepted(TCP_server, index) != 0) { + return -1; + } + + kill_sock(sock); + return 0; +} + +/* return 1 if everything went well. + * return -1 if the connection must be killed. + */ +static int handle_TCP_handshake(TCP_Secure_Connection *con, const uint8_t *data, uint16_t length, + const uint8_t *self_secret_key) +{ + if (length != TCP_CLIENT_HANDSHAKE_SIZE) { + return -1; + } + + if (con->status != TCP_STATUS_CONNECTED) { + return -1; + } + + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + encrypt_precompute(data, self_secret_key, shared_key); + uint8_t plain[TCP_HANDSHAKE_PLAIN_SIZE]; + int len = decrypt_data_symmetric(shared_key, data + CRYPTO_PUBLIC_KEY_SIZE, + data + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, TCP_HANDSHAKE_PLAIN_SIZE + CRYPTO_MAC_SIZE, plain); + + if (len != TCP_HANDSHAKE_PLAIN_SIZE) { + return -1; + } + + memcpy(con->public_key, data, CRYPTO_PUBLIC_KEY_SIZE); + uint8_t temp_secret_key[CRYPTO_SECRET_KEY_SIZE]; + uint8_t resp_plain[TCP_HANDSHAKE_PLAIN_SIZE]; + crypto_new_keypair(resp_plain, temp_secret_key); + random_nonce(con->sent_nonce); + memcpy(resp_plain + CRYPTO_PUBLIC_KEY_SIZE, con->sent_nonce, CRYPTO_NONCE_SIZE); + memcpy(con->recv_nonce, plain + CRYPTO_PUBLIC_KEY_SIZE, CRYPTO_NONCE_SIZE); + + uint8_t response[TCP_SERVER_HANDSHAKE_SIZE]; + random_nonce(response); + + len = encrypt_data_symmetric(shared_key, response, resp_plain, TCP_HANDSHAKE_PLAIN_SIZE, + response + CRYPTO_NONCE_SIZE); + + if (len != TCP_HANDSHAKE_PLAIN_SIZE + CRYPTO_MAC_SIZE) { + return -1; + } + + if (TCP_SERVER_HANDSHAKE_SIZE != send(con->sock, (const char *)response, TCP_SERVER_HANDSHAKE_SIZE, MSG_NOSIGNAL)) { + return -1; + } + + encrypt_precompute(plain, temp_secret_key, con->shared_key); + con->status = TCP_STATUS_UNCONFIRMED; + return 1; +} + +/* return 1 if connection handshake was handled correctly. + * return 0 if we didn't get it yet. + * return -1 if the connection must be killed. + */ +static int read_connection_handshake(TCP_Secure_Connection *con, const uint8_t *self_secret_key) +{ + uint8_t data[TCP_CLIENT_HANDSHAKE_SIZE]; + int len = 0; + + if ((len = read_TCP_packet(con->sock, data, TCP_CLIENT_HANDSHAKE_SIZE)) != -1) { + return handle_TCP_handshake(con, data, len, self_secret_key); + } + + return 0; +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +static int send_routing_response(TCP_Secure_Connection *con, uint8_t rpid, const uint8_t *public_key) +{ + uint8_t data[1 + 1 + CRYPTO_PUBLIC_KEY_SIZE]; + data[0] = TCP_PACKET_ROUTING_RESPONSE; + data[1] = rpid; + memcpy(data + 2, public_key, CRYPTO_PUBLIC_KEY_SIZE); + + return write_packet_TCP_secure_connection(con, data, sizeof(data), 1); +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +static int send_connect_notification(TCP_Secure_Connection *con, uint8_t id) +{ + uint8_t data[2] = {TCP_PACKET_CONNECTION_NOTIFICATION, (uint8_t)(id + NUM_RESERVED_PORTS)}; + return write_packet_TCP_secure_connection(con, data, sizeof(data), 1); +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +static int send_disconnect_notification(TCP_Secure_Connection *con, uint8_t id) +{ + uint8_t data[2] = {TCP_PACKET_DISCONNECT_NOTIFICATION, (uint8_t)(id + NUM_RESERVED_PORTS)}; + return write_packet_TCP_secure_connection(con, data, sizeof(data), 1); +} + +/* return 0 on success. + * return -1 on failure (connection must be killed). + */ +static int handle_TCP_routing_req(TCP_Server *TCP_server, uint32_t con_id, const uint8_t *public_key) +{ + uint32_t i; + uint32_t index = ~0; + TCP_Secure_Connection *con = &TCP_server->accepted_connection_array[con_id]; + + /* If person tries to cennect to himself we deny the request*/ + if (public_key_cmp(con->public_key, public_key) == 0) { + if (send_routing_response(con, 0, public_key) == -1) { + return -1; + } + + return 0; + } + + for (i = 0; i < NUM_CLIENT_CONNECTIONS; ++i) { + if (con->connections[i].status != 0) { + if (public_key_cmp(public_key, con->connections[i].public_key) == 0) { + if (send_routing_response(con, i + NUM_RESERVED_PORTS, public_key) == -1) { + return -1; + } + + return 0; + } + } else if (index == (uint32_t)~0) { + index = i; + } + } + + if (index == (uint32_t)~0) { + if (send_routing_response(con, 0, public_key) == -1) { + return -1; + } + + return 0; + } + + int ret = send_routing_response(con, index + NUM_RESERVED_PORTS, public_key); + + if (ret == 0) { + return 0; + } + + if (ret == -1) { + return -1; + } + + con->connections[index].status = 1; + memcpy(con->connections[index].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + int other_index = get_TCP_connection_index(TCP_server, public_key); + + if (other_index != -1) { + uint32_t other_id = ~0; + TCP_Secure_Connection *other_conn = &TCP_server->accepted_connection_array[other_index]; + + for (i = 0; i < NUM_CLIENT_CONNECTIONS; ++i) { + if (other_conn->connections[i].status == 1 + && public_key_cmp(other_conn->connections[i].public_key, con->public_key) == 0) { + other_id = i; + break; + } + } + + if (other_id != (uint32_t)~0) { + con->connections[index].status = 2; + con->connections[index].index = other_index; + con->connections[index].other_id = other_id; + other_conn->connections[other_id].status = 2; + other_conn->connections[other_id].index = con_id; + other_conn->connections[other_id].other_id = index; + // TODO(irungentoo): return values? + send_connect_notification(con, index); + send_connect_notification(other_conn, other_id); + } + } + + return 0; +} + +/* return 0 on success. + * return -1 on failure (connection must be killed). + */ +static int handle_TCP_oob_send(TCP_Server *TCP_server, uint32_t con_id, const uint8_t *public_key, const uint8_t *data, + uint16_t length) +{ + if (length == 0 || length > TCP_MAX_OOB_DATA_LENGTH) { + return -1; + } + + TCP_Secure_Connection *con = &TCP_server->accepted_connection_array[con_id]; + + int other_index = get_TCP_connection_index(TCP_server, public_key); + + if (other_index != -1) { + VLA(uint8_t, resp_packet, 1 + CRYPTO_PUBLIC_KEY_SIZE + length); + resp_packet[0] = TCP_PACKET_OOB_RECV; + memcpy(resp_packet + 1, con->public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(resp_packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, data, length); + write_packet_TCP_secure_connection(&TCP_server->accepted_connection_array[other_index], resp_packet, + SIZEOF_VLA(resp_packet), 0); + } + + return 0; +} + +/* Remove connection with con_number from the connections array of con. + * + * return -1 on failure. + * return 0 on success. + */ +static int rm_connection_index(TCP_Server *TCP_server, TCP_Secure_Connection *con, uint8_t con_number) +{ + if (con_number >= NUM_CLIENT_CONNECTIONS) { + return -1; + } + + if (con->connections[con_number].status) { + uint32_t index = con->connections[con_number].index; + uint8_t other_id = con->connections[con_number].other_id; + + if (con->connections[con_number].status == 2) { + + if (index >= TCP_server->size_accepted_connections) { + return -1; + } + + TCP_server->accepted_connection_array[index].connections[other_id].other_id = 0; + TCP_server->accepted_connection_array[index].connections[other_id].index = 0; + TCP_server->accepted_connection_array[index].connections[other_id].status = 1; + // TODO(irungentoo): return values? + send_disconnect_notification(&TCP_server->accepted_connection_array[index], other_id); + } + + con->connections[con_number].index = 0; + con->connections[con_number].other_id = 0; + con->connections[con_number].status = 0; + return 0; + } + + return -1; +} + +static int handle_onion_recv_1(void *object, IP_Port dest, const uint8_t *data, uint16_t length) +{ + TCP_Server *TCP_server = (TCP_Server *)object; + uint32_t index = dest.ip.ip6.uint32[0]; + + if (index >= TCP_server->size_accepted_connections) { + return 1; + } + + TCP_Secure_Connection *con = &TCP_server->accepted_connection_array[index]; + + if (con->identifier != dest.ip.ip6.uint64[1]) { + return 1; + } + + VLA(uint8_t, packet, 1 + length); + memcpy(packet + 1, data, length); + packet[0] = TCP_PACKET_ONION_RESPONSE; + + if (write_packet_TCP_secure_connection(con, packet, SIZEOF_VLA(packet), 0) != 1) { + return 1; + } + + return 0; +} + +/* return 0 on success + * return -1 on failure + */ +static int handle_TCP_packet(TCP_Server *TCP_server, uint32_t con_id, const uint8_t *data, uint16_t length) +{ + if (length == 0) { + return -1; + } + + TCP_Secure_Connection *con = &TCP_server->accepted_connection_array[con_id]; + + switch (data[0]) { + case TCP_PACKET_ROUTING_REQUEST: { + if (length != 1 + CRYPTO_PUBLIC_KEY_SIZE) { + return -1; + } + + return handle_TCP_routing_req(TCP_server, con_id, data + 1); + } + + case TCP_PACKET_CONNECTION_NOTIFICATION: { + if (length != 2) { + return -1; + } + + break; + } + + case TCP_PACKET_DISCONNECT_NOTIFICATION: { + if (length != 2) { + return -1; + } + + return rm_connection_index(TCP_server, con, data[1] - NUM_RESERVED_PORTS); + } + + case TCP_PACKET_PING: { + if (length != 1 + sizeof(uint64_t)) { + return -1; + } + + uint8_t response[1 + sizeof(uint64_t)]; + response[0] = TCP_PACKET_PONG; + memcpy(response + 1, data + 1, sizeof(uint64_t)); + write_packet_TCP_secure_connection(con, response, sizeof(response), 1); + return 0; + } + + case TCP_PACKET_PONG: { + if (length != 1 + sizeof(uint64_t)) { + return -1; + } + + uint64_t ping_id; + memcpy(&ping_id, data + 1, sizeof(uint64_t)); + + if (ping_id) { + if (ping_id == con->ping_id) { + con->ping_id = 0; + } + + return 0; + } + + return -1; + } + + case TCP_PACKET_OOB_SEND: { + if (length <= 1 + CRYPTO_PUBLIC_KEY_SIZE) { + return -1; + } + + return handle_TCP_oob_send(TCP_server, con_id, data + 1, data + 1 + CRYPTO_PUBLIC_KEY_SIZE, + length - (1 + CRYPTO_PUBLIC_KEY_SIZE)); + } + + case TCP_PACKET_ONION_REQUEST: { + if (TCP_server->onion) { + if (length <= 1 + CRYPTO_NONCE_SIZE + ONION_SEND_BASE * 2) { + return -1; + } + + IP_Port source; + source.port = 0; // dummy initialise + source.ip.family = TCP_ONION_FAMILY; + source.ip.ip6.uint32[0] = con_id; + source.ip.ip6.uint32[1] = 0; + source.ip.ip6.uint64[1] = con->identifier; + onion_send_1(TCP_server->onion, data + 1 + CRYPTO_NONCE_SIZE, length - (1 + CRYPTO_NONCE_SIZE), source, + data + 1); + } + + return 0; + } + + case TCP_PACKET_ONION_RESPONSE: { + return -1; + } + + default: { + if (data[0] < NUM_RESERVED_PORTS) { + return -1; + } + + uint8_t c_id = data[0] - NUM_RESERVED_PORTS; + + if (c_id >= NUM_CLIENT_CONNECTIONS) { + return -1; + } + + if (con->connections[c_id].status == 0) { + return -1; + } + + if (con->connections[c_id].status != 2) { + return 0; + } + + uint32_t index = con->connections[c_id].index; + uint8_t other_c_id = con->connections[c_id].other_id + NUM_RESERVED_PORTS; + VLA(uint8_t, new_data, length); + memcpy(new_data, data, length); + new_data[0] = other_c_id; + int ret = write_packet_TCP_secure_connection(&TCP_server->accepted_connection_array[index], new_data, length, 0); + + if (ret == -1) { + return -1; + } + + return 0; + } + } + + return 0; +} + + +static int confirm_TCP_connection(TCP_Server *TCP_server, TCP_Secure_Connection *con, const uint8_t *data, + uint16_t length) +{ + int index = add_accepted(TCP_server, con); + + if (index == -1) { + kill_TCP_secure_connection(con); + return -1; + } + + crypto_memzero(con, sizeof(TCP_Secure_Connection)); + + if (handle_TCP_packet(TCP_server, index, data, length) == -1) { + kill_accepted(TCP_server, index); + return -1; + } + + return index; +} + +/* return index on success + * return -1 on failure + */ +static int accept_connection(TCP_Server *TCP_server, Socket sock) +{ + if (!sock_valid(sock)) { + return -1; + } + + if (!set_socket_nonblock(sock)) { + kill_sock(sock); + return -1; + } + + if (!set_socket_nosigpipe(sock)) { + kill_sock(sock); + return -1; + } + + uint16_t index = TCP_server->incoming_connection_queue_index % MAX_INCOMING_CONNECTIONS; + + TCP_Secure_Connection *conn = &TCP_server->incoming_connection_queue[index]; + + if (conn->status != TCP_STATUS_NO_STATUS) { + kill_TCP_secure_connection(conn); + } + + conn->status = TCP_STATUS_CONNECTED; + conn->sock = sock; + conn->next_packet_length = 0; + + ++TCP_server->incoming_connection_queue_index; + return index; +} + +static Socket new_listening_TCP_socket(int family, uint16_t port) +{ + Socket sock = net_socket(family, TOX_SOCK_STREAM, TOX_PROTO_TCP); + + if (!sock_valid(sock)) { + return ~0; + } + + int ok = set_socket_nonblock(sock); + + if (ok && family == TOX_AF_INET6) { + ok = set_socket_dualstack(sock); + } + + if (ok) { + ok = set_socket_reuseaddr(sock); + } + + ok = ok && bind_to_port(sock, family, port) && (listen(sock, TCP_MAX_BACKLOG) == 0); + + if (!ok) { + kill_sock(sock); + return ~0; + } + + return sock; +} + +TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, const uint16_t *ports, const uint8_t *secret_key, + Onion *onion) +{ + if (num_sockets == 0 || ports == NULL) { + return NULL; + } + + if (networking_at_startup() != 0) { + return NULL; + } + + TCP_Server *temp = (TCP_Server *)calloc(1, sizeof(TCP_Server)); + + if (temp == NULL) { + return NULL; + } + + temp->socks_listening = (Socket *)calloc(num_sockets, sizeof(Socket)); + + if (temp->socks_listening == NULL) { + free(temp); + return NULL; + } + +#ifdef TCP_SERVER_USE_EPOLL + temp->efd = epoll_create(8); + + if (temp->efd == -1) { + free(temp->socks_listening); + free(temp); + return NULL; + } + +#endif + + uint8_t family; + + if (ipv6_enabled) { + family = TOX_AF_INET6; + } else { + family = TOX_AF_INET; + } + + uint32_t i; +#ifdef TCP_SERVER_USE_EPOLL + struct epoll_event ev; +#endif + + for (i = 0; i < num_sockets; ++i) { + Socket sock = new_listening_TCP_socket(family, ports[i]); + + if (sock_valid(sock)) { +#ifdef TCP_SERVER_USE_EPOLL + ev.events = EPOLLIN | EPOLLET; + ev.data.u64 = sock | ((uint64_t)TCP_SOCKET_LISTENING << 32); + + if (epoll_ctl(temp->efd, EPOLL_CTL_ADD, sock, &ev) == -1) { + continue; + } + +#endif + + temp->socks_listening[temp->num_listening_socks] = sock; + ++temp->num_listening_socks; + } + } + + if (temp->num_listening_socks == 0) { + free(temp->socks_listening); + free(temp); + return NULL; + } + + if (onion) { + temp->onion = onion; + set_callback_handle_recv_1(onion, &handle_onion_recv_1, temp); + } + + memcpy(temp->secret_key, secret_key, CRYPTO_SECRET_KEY_SIZE); + crypto_derive_public_key(temp->public_key, temp->secret_key); + + bs_list_init(&temp->accepted_key_list, CRYPTO_PUBLIC_KEY_SIZE, 8); + + return temp; +} + +static void do_TCP_accept_new(TCP_Server *TCP_server) +{ + uint32_t i; + + for (i = 0; i < TCP_server->num_listening_socks; ++i) { + struct sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + Socket sock; + + do { + sock = accept(TCP_server->socks_listening[i], (struct sockaddr *)&addr, &addrlen); + } while (accept_connection(TCP_server, sock) != -1); + } +} + +static int do_incoming(TCP_Server *TCP_server, uint32_t i) +{ + if (TCP_server->incoming_connection_queue[i].status != TCP_STATUS_CONNECTED) { + return -1; + } + + int ret = read_connection_handshake(&TCP_server->incoming_connection_queue[i], TCP_server->secret_key); + + if (ret == -1) { + kill_TCP_secure_connection(&TCP_server->incoming_connection_queue[i]); + } else if (ret == 1) { + int index_new = TCP_server->unconfirmed_connection_queue_index % MAX_INCOMING_CONNECTIONS; + TCP_Secure_Connection *conn_old = &TCP_server->incoming_connection_queue[i]; + TCP_Secure_Connection *conn_new = &TCP_server->unconfirmed_connection_queue[index_new]; + + if (conn_new->status != TCP_STATUS_NO_STATUS) { + kill_TCP_secure_connection(conn_new); + } + + memcpy(conn_new, conn_old, sizeof(TCP_Secure_Connection)); + crypto_memzero(conn_old, sizeof(TCP_Secure_Connection)); + ++TCP_server->unconfirmed_connection_queue_index; + + return index_new; + } + + return -1; +} + +static int do_unconfirmed(TCP_Server *TCP_server, uint32_t i) +{ + TCP_Secure_Connection *conn = &TCP_server->unconfirmed_connection_queue[i]; + + if (conn->status != TCP_STATUS_UNCONFIRMED) { + return -1; + } + + uint8_t packet[MAX_PACKET_SIZE]; + int len = read_packet_TCP_secure_connection(conn->sock, &conn->next_packet_length, conn->shared_key, conn->recv_nonce, + packet, sizeof(packet)); + + if (len == 0) { + return -1; + } + + if (len == -1) { + kill_TCP_secure_connection(conn); + return -1; + } + + return confirm_TCP_connection(TCP_server, conn, packet, len); +} + +static void do_confirmed_recv(TCP_Server *TCP_server, uint32_t i) +{ + TCP_Secure_Connection *conn = &TCP_server->accepted_connection_array[i]; + + uint8_t packet[MAX_PACKET_SIZE]; + int len; + + while ((len = read_packet_TCP_secure_connection(conn->sock, &conn->next_packet_length, conn->shared_key, + conn->recv_nonce, packet, sizeof(packet)))) { + if (len == -1) { + kill_accepted(TCP_server, i); + break; + } + + if (handle_TCP_packet(TCP_server, i, packet, len) == -1) { + kill_accepted(TCP_server, i); + break; + } + } +} + +static void do_TCP_incoming(TCP_Server *TCP_server) +{ + uint32_t i; + + for (i = 0; i < MAX_INCOMING_CONNECTIONS; ++i) { + do_incoming(TCP_server, i); + } +} + +static void do_TCP_unconfirmed(TCP_Server *TCP_server) +{ + uint32_t i; + + for (i = 0; i < MAX_INCOMING_CONNECTIONS; ++i) { + do_unconfirmed(TCP_server, i); + } +} + +static void do_TCP_confirmed(TCP_Server *TCP_server) +{ +#ifdef TCP_SERVER_USE_EPOLL + + if (TCP_server->last_run_pinged == unix_time()) { + return; + } + + TCP_server->last_run_pinged = unix_time(); +#endif + uint32_t i; + + for (i = 0; i < TCP_server->size_accepted_connections; ++i) { + TCP_Secure_Connection *conn = &TCP_server->accepted_connection_array[i]; + + if (conn->status != TCP_STATUS_CONFIRMED) { + continue; + } + + if (is_timeout(conn->last_pinged, TCP_PING_FREQUENCY)) { + uint8_t ping[1 + sizeof(uint64_t)]; + ping[0] = TCP_PACKET_PING; + uint64_t ping_id = random_64b(); + + if (!ping_id) { + ++ping_id; + } + + memcpy(ping + 1, &ping_id, sizeof(uint64_t)); + int ret = write_packet_TCP_secure_connection(conn, ping, sizeof(ping), 1); + + if (ret == 1) { + conn->last_pinged = unix_time(); + conn->ping_id = ping_id; + } else { + if (is_timeout(conn->last_pinged, TCP_PING_FREQUENCY + TCP_PING_TIMEOUT)) { + kill_accepted(TCP_server, i); + continue; + } + } + } + + if (conn->ping_id && is_timeout(conn->last_pinged, TCP_PING_TIMEOUT)) { + kill_accepted(TCP_server, i); + continue; + } + + send_pending_data(conn); + +#ifndef TCP_SERVER_USE_EPOLL + + do_confirmed_recv(TCP_server, i); + +#endif + } +} + +#ifdef TCP_SERVER_USE_EPOLL +static void do_TCP_epoll(TCP_Server *TCP_server) +{ +#define MAX_EVENTS 16 + struct epoll_event events[MAX_EVENTS]; + int nfds; + + while ((nfds = epoll_wait(TCP_server->efd, events, MAX_EVENTS, 0)) > 0) { + int n; + + for (n = 0; n < nfds; ++n) { + Socket sock = events[n].data.u64 & 0xFFFFFFFF; + int status = (events[n].data.u64 >> 32) & 0xFF, index = (events[n].data.u64 >> 40); + + if ((events[n].events & EPOLLERR) || (events[n].events & EPOLLHUP) || (events[n].events & EPOLLRDHUP)) { + switch (status) { + case TCP_SOCKET_LISTENING: { + //should never happen + break; + } + + case TCP_SOCKET_INCOMING: { + kill_TCP_secure_connection(&TCP_server->incoming_connection_queue[index]); + break; + } + + case TCP_SOCKET_UNCONFIRMED: { + kill_TCP_secure_connection(&TCP_server->unconfirmed_connection_queue[index]); + break; + } + + case TCP_SOCKET_CONFIRMED: { + kill_accepted(TCP_server, index); + break; + } + } + + continue; + } + + + if (!(events[n].events & EPOLLIN)) { + continue; + } + + switch (status) { + case TCP_SOCKET_LISTENING: { + //socket is from socks_listening, accept connection + struct sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + + while (1) { + Socket sock_new = accept(sock, (struct sockaddr *)&addr, &addrlen); + + if (!sock_valid(sock_new)) { + break; + } + + int index_new = accept_connection(TCP_server, sock_new); + + if (index_new == -1) { + continue; + } + + struct epoll_event ev = { + .events = EPOLLIN | EPOLLET | EPOLLRDHUP, + .data.u64 = sock_new | ((uint64_t)TCP_SOCKET_INCOMING << 32) | ((uint64_t)index_new << 40) + }; + + if (epoll_ctl(TCP_server->efd, EPOLL_CTL_ADD, sock_new, &ev) == -1) { + kill_TCP_secure_connection(&TCP_server->incoming_connection_queue[index_new]); + continue; + } + } + + break; + } + + case TCP_SOCKET_INCOMING: { + int index_new; + + if ((index_new = do_incoming(TCP_server, index)) != -1) { + events[n].events = EPOLLIN | EPOLLET | EPOLLRDHUP; + events[n].data.u64 = sock | ((uint64_t)TCP_SOCKET_UNCONFIRMED << 32) | ((uint64_t)index_new << 40); + + if (epoll_ctl(TCP_server->efd, EPOLL_CTL_MOD, sock, &events[n]) == -1) { + kill_TCP_secure_connection(&TCP_server->unconfirmed_connection_queue[index_new]); + break; + } + } + + break; + } + + case TCP_SOCKET_UNCONFIRMED: { + int index_new; + + if ((index_new = do_unconfirmed(TCP_server, index)) != -1) { + events[n].events = EPOLLIN | EPOLLET | EPOLLRDHUP; + events[n].data.u64 = sock | ((uint64_t)TCP_SOCKET_CONFIRMED << 32) | ((uint64_t)index_new << 40); + + if (epoll_ctl(TCP_server->efd, EPOLL_CTL_MOD, sock, &events[n]) == -1) { + //remove from confirmed connections + kill_accepted(TCP_server, index_new); + break; + } + } + + break; + } + + case TCP_SOCKET_CONFIRMED: { + do_confirmed_recv(TCP_server, index); + break; + } + } + } + } + +#undef MAX_EVENTS +} +#endif + +void do_TCP_server(TCP_Server *TCP_server) +{ + unix_time_update(); + +#ifdef TCP_SERVER_USE_EPOLL + do_TCP_epoll(TCP_server); + +#else + do_TCP_accept_new(TCP_server); + do_TCP_incoming(TCP_server); + do_TCP_unconfirmed(TCP_server); +#endif + + do_TCP_confirmed(TCP_server); +} + +void kill_TCP_server(TCP_Server *TCP_server) +{ + uint32_t i; + + for (i = 0; i < TCP_server->num_listening_socks; ++i) { + kill_sock(TCP_server->socks_listening[i]); + } + + if (TCP_server->onion) { + set_callback_handle_recv_1(TCP_server->onion, NULL, NULL); + } + + bs_list_free(&TCP_server->accepted_key_list); + +#ifdef TCP_SERVER_USE_EPOLL + close(TCP_server->efd); +#endif + + free(TCP_server->socks_listening); + free(TCP_server->accepted_connection_array); + free(TCP_server); +} diff --git a/protocols/Tox/libtox/src/toxcore/TCP_server.h b/protocols/Tox/libtox/src/toxcore/TCP_server.h new file mode 100644 index 0000000000..f213c078e6 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/TCP_server.h @@ -0,0 +1,167 @@ +/* + * Implementation of the TCP relay server part of Tox. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef TCP_SERVER_H +#define TCP_SERVER_H + +#include "crypto_core.h" +#include "list.h" +#include "onion.h" + +#ifdef TCP_SERVER_USE_EPOLL +#include <sys/epoll.h> +#endif + +// Disable MSG_NOSIGNAL on systems not supporting it, e.g. Windows, FreeBSD +#if !defined(MSG_NOSIGNAL) +#define MSG_NOSIGNAL 0 +#endif + +#define MAX_INCOMING_CONNECTIONS 256 + +#define TCP_MAX_BACKLOG MAX_INCOMING_CONNECTIONS + +#define MAX_PACKET_SIZE 2048 + +#define TCP_HANDSHAKE_PLAIN_SIZE (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE) +#define TCP_SERVER_HANDSHAKE_SIZE (CRYPTO_NONCE_SIZE + TCP_HANDSHAKE_PLAIN_SIZE + CRYPTO_MAC_SIZE) +#define TCP_CLIENT_HANDSHAKE_SIZE (CRYPTO_PUBLIC_KEY_SIZE + TCP_SERVER_HANDSHAKE_SIZE) +#define TCP_MAX_OOB_DATA_LENGTH 1024 + +#define NUM_RESERVED_PORTS 16 +#define NUM_CLIENT_CONNECTIONS (256 - NUM_RESERVED_PORTS) + +#define TCP_PACKET_ROUTING_REQUEST 0 +#define TCP_PACKET_ROUTING_RESPONSE 1 +#define TCP_PACKET_CONNECTION_NOTIFICATION 2 +#define TCP_PACKET_DISCONNECT_NOTIFICATION 3 +#define TCP_PACKET_PING 4 +#define TCP_PACKET_PONG 5 +#define TCP_PACKET_OOB_SEND 6 +#define TCP_PACKET_OOB_RECV 7 +#define TCP_PACKET_ONION_REQUEST 8 +#define TCP_PACKET_ONION_RESPONSE 9 + +#define ARRAY_ENTRY_SIZE 6 + +/* frequency to ping connected nodes and timeout in seconds */ +#define TCP_PING_FREQUENCY 30 +#define TCP_PING_TIMEOUT 10 + +#ifdef TCP_SERVER_USE_EPOLL +#define TCP_SOCKET_LISTENING 0 +#define TCP_SOCKET_INCOMING 1 +#define TCP_SOCKET_UNCONFIRMED 2 +#define TCP_SOCKET_CONFIRMED 3 +#endif + +enum { + TCP_STATUS_NO_STATUS, + TCP_STATUS_CONNECTED, + TCP_STATUS_UNCONFIRMED, + TCP_STATUS_CONFIRMED, +}; + +typedef struct TCP_Priority_List TCP_Priority_List; + +struct TCP_Priority_List { + TCP_Priority_List *next; + uint16_t size, sent; + uint8_t data[]; +}; + +typedef struct TCP_Secure_Connection { + Socket sock; + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t recv_nonce[CRYPTO_NONCE_SIZE]; /* Nonce of received packets. */ + uint8_t sent_nonce[CRYPTO_NONCE_SIZE]; /* Nonce of sent packets. */ + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + uint16_t next_packet_length; + struct { + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint32_t index; + uint8_t status; /* 0 if not used, 1 if other is offline, 2 if other is online. */ + uint8_t other_id; + } connections[NUM_CLIENT_CONNECTIONS]; + uint8_t last_packet[2 + MAX_PACKET_SIZE]; + uint8_t status; + uint16_t last_packet_length; + uint16_t last_packet_sent; + + TCP_Priority_List *priority_queue_start, *priority_queue_end; + + uint64_t identifier; + + uint64_t last_pinged; + uint64_t ping_id; +} TCP_Secure_Connection; + + +typedef struct TCP_Server TCP_Server; + +const uint8_t *tcp_server_public_key(const TCP_Server *tcp_server); +size_t tcp_server_listen_count(const TCP_Server *tcp_server); + +/* Create new TCP server instance. + */ +TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, const uint16_t *ports, const uint8_t *secret_key, + Onion *onion); + +/* Run the TCP_server + */ +void do_TCP_server(TCP_Server *TCP_server); + +/* Kill the TCP server + */ +void kill_TCP_server(TCP_Server *TCP_server); + +/* return the amount of data in the tcp recv buffer. + * return 0 on failure. + */ +unsigned int TCP_socket_data_recv_buffer(Socket sock); + +/* Read the next two bytes in TCP stream then convert them to + * length (host byte order). + * + * return length on success + * return 0 if nothing has been read from socket. + * return ~0 on failure. + */ +uint16_t read_TCP_length(Socket sock); + +/* Read length bytes from socket. + * + * return length on success + * return -1 on failure/no data in buffer. + */ +int read_TCP_packet(Socket sock, uint8_t *data, uint16_t length); + +/* return length of received packet on success. + * return 0 if could not read any packet. + * return -1 on failure (connection must be killed). + */ +int read_packet_TCP_secure_connection(Socket sock, uint16_t *next_packet_length, const uint8_t *shared_key, + uint8_t *recv_nonce, uint8_t *data, uint16_t max_len); + + +#endif diff --git a/protocols/Tox/libtox/src/toxcore/ccompat.h b/protocols/Tox/libtox/src/toxcore/ccompat.h new file mode 100644 index 0000000000..e72e66ae58 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/ccompat.h @@ -0,0 +1,43 @@ +/* + * C language compatibility macros for varying compiler support. + */ +#ifndef CCOMPAT_H +#define CCOMPAT_H + +// Marking GNU extensions to avoid warnings. +#if defined(__GNUC__) +#define GNU_EXTENSION __extension__ +#else +#define GNU_EXTENSION +#endif + +// Variable length arrays. +// VLA(type, name, size) allocates a variable length array with automatic +// storage duration. VLA_SIZE(name) evaluates to the runtime size of that array +// in bytes. +// +// If C99 VLAs are not available, an emulation using alloca (stack allocation +// "function") is used. Note the semantic difference: alloca'd memory does not +// get freed at the end of the declaration's scope. Do not use VLA() in loops or +// you may run out of stack space. +#if !defined(_MSC_VER) && __STDC_VERSION__ >= 199901L +// C99 VLAs. +#define VLA(type, name, size) type name[size] +#define SIZEOF_VLA sizeof +#else + +// Emulation using alloca. +#ifdef _WIN32 +#include <malloc.h> +#else +#include <alloca.h> +#endif + +#define VLA(type, name, size) \ + const size_t name##_size = (size) * sizeof(type); \ + type *const name = (type *)alloca(name##_size) +#define SIZEOF_VLA(name) name##_size + +#endif + +#endif /* CCOMPAT_H */ diff --git a/protocols/Tox/libtox/src/toxcore/crypto_core.api.h b/protocols/Tox/libtox/src/toxcore/crypto_core.api.h new file mode 100644 index 0000000000..cef1a52c14 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/crypto_core.api.h @@ -0,0 +1,246 @@ +%{ +/* + * Functions for the core crypto. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef CRYPTO_CORE_H +#define CRYPTO_CORE_H + +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +%} + +/** + * The number of bytes in a Tox public key. + */ +const CRYPTO_PUBLIC_KEY_SIZE = 32; + +/** + * The number of bytes in a Tox secret key. + */ +const CRYPTO_SECRET_KEY_SIZE = 32; + +/** + * The number of bytes in a shared key computed from public and secret keys. + */ +const CRYPTO_SHARED_KEY_SIZE = 32; + +/** + * The number of bytes in a symmetric key. + */ +const CRYPTO_SYMMETRIC_KEY_SIZE = CRYPTO_SHARED_KEY_SIZE; + +/** + * The number of bytes needed for the MAC (message authentication code) in an + * encrypted message. + */ +const CRYPTO_MAC_SIZE = 16; + +/** + * The number of bytes in a nonce used for encryption/decryption. + */ +const CRYPTO_NONCE_SIZE = 24; + +/** + * The number of bytes in a SHA256 hash. + */ +const CRYPTO_SHA256_SIZE = 32; + +/** + * The number of bytes in a SHA512 hash. + */ +const CRYPTO_SHA512_SIZE = 64; + +/** + * A `memcmp`-like function whose running time does not depend on the input + * bytes, only on the input length. Useful to compare sensitive data where + * timing attacks could reveal that data. + * + * This means for instance that comparing "aaaa" and "aaaa" takes 4 time, and + * "aaaa" and "baaa" also takes 4 time. With a regular `memcmp`, the latter may + * take 1 time, because it immediately knows that the two strings are not equal. + */ +static int32_t crypto_memcmp(const void *p1, const void *p2, size_t length); + +/** + * A `bzero`-like function which won't be optimised away by the compiler. Some + * compilers will inline `bzero` or `memset` if they can prove that there will + * be no reads to the written data. Use this function if you want to be sure the + * memory is indeed zeroed. + */ +static void crypto_memzero(void *data, size_t length); + +/** + * Compute a SHA256 hash (32 bytes). + */ +static void crypto_sha256(uint8_t[CRYPTO_SHA256_SIZE] hash, const uint8_t[length] data); + +/** + * Compute a SHA512 hash (64 bytes). + */ +static void crypto_sha512(uint8_t[CRYPTO_SHA512_SIZE] hash, const uint8_t[length] data); + +/** + * Compare 2 public keys of length CRYPTO_PUBLIC_KEY_SIZE, not vulnerable to + * timing attacks. + * + * @return 0 if both mem locations of length are equal, -1 if they are not. + */ +static int32_t public_key_cmp( + const uint8_t[CRYPTO_PUBLIC_KEY_SIZE] pk1, + const uint8_t[CRYPTO_PUBLIC_KEY_SIZE] pk2); + +/** + * Return a random 32 bit integer. + */ +static uint32_t random_int(); + +/** + * Return a random 64 bit integer. + */ +static uint64_t random_64b(); + +/** + * Check if a Tox public key CRYPTO_PUBLIC_KEY_SIZE is valid or not. This + * should only be used for input validation. + * + * @return false if it isn't, true if it is. + */ +static bool public_key_valid(const uint8_t[CRYPTO_PUBLIC_KEY_SIZE] public_key); + +/** + * Generate a new random keypair. Every call to this function is likely to + * generate a different keypair. + */ +static int32_t crypto_new_keypair( + uint8_t[CRYPTO_PUBLIC_KEY_SIZE] public_key, + uint8_t[CRYPTO_SECRET_KEY_SIZE] secret_key); + +/** + * Derive the public key from a given secret key. + */ +static void crypto_derive_public_key( + uint8_t[CRYPTO_PUBLIC_KEY_SIZE] public_key, + const uint8_t[CRYPTO_SECRET_KEY_SIZE] secret_key); + +/** + * Encrypt plain text of the given length to encrypted of length + + * $CRYPTO_MAC_SIZE using the public key ($CRYPTO_PUBLIC_KEY_SIZE bytes) of the + * receiver and the secret key of the sender and a $CRYPTO_NONCE_SIZE byte + * nonce. + * + * @return -1 if there was a problem, length of encrypted data if everything + * was fine. + */ +static int32_t encrypt_data( + const uint8_t[CRYPTO_PUBLIC_KEY_SIZE] public_key, + const uint8_t[CRYPTO_SECRET_KEY_SIZE] secret_key, + const uint8_t[CRYPTO_NONCE_SIZE] nonce, + const uint8_t[length] plain, + uint8_t *encrypted); + + +/** + * Decrypt encrypted text of the given length to plain text of the given length + * - $CRYPTO_MAC_SIZE using the public key ($CRYPTO_PUBLIC_KEY_SIZE bytes) of + * the sender, the secret key of the receiver and a $CRYPTO_NONCE_SIZE byte + * nonce. + * + * @return -1 if there was a problem (decryption failed), length of plain text + * data if everything was fine. + */ +static int32_t decrypt_data( + const uint8_t[CRYPTO_PUBLIC_KEY_SIZE] public_key, + const uint8_t[CRYPTO_SECRET_KEY_SIZE] secret_key, + const uint8_t[CRYPTO_NONCE_SIZE] nonce, + const uint8_t[length] encrypted, + uint8_t *plain); + +/** + * Fast encrypt/decrypt operations. Use if this is not a one-time communication. + * $encrypt_precompute does the shared-key generation once so it does not have + * to be preformed on every encrypt/decrypt. + */ +static int32_t encrypt_precompute( + const uint8_t[CRYPTO_PUBLIC_KEY_SIZE] public_key, + const uint8_t[CRYPTO_SECRET_KEY_SIZE] secret_key, + uint8_t[CRYPTO_SHARED_KEY_SIZE] shared_key); + +/** + * Encrypts plain of length length to encrypted of length + $CRYPTO_MAC_SIZE + * using a shared key $CRYPTO_SYMMETRIC_KEY_SIZE big and a $CRYPTO_NONCE_SIZE + * byte nonce. + * + * @return -1 if there was a problem, length of encrypted data if everything + * was fine. + */ +static int32_t encrypt_data_symmetric( + const uint8_t[CRYPTO_SHARED_KEY_SIZE] shared_key, + const uint8_t[CRYPTO_NONCE_SIZE] nonce, + const uint8_t[length] plain, + uint8_t *encrypted); + +/** + * Decrypts encrypted of length length to plain of length length - + * $CRYPTO_MAC_SIZE using a shared key CRYPTO_SHARED_KEY_SIZE big and a + * $CRYPTO_NONCE_SIZE byte nonce. + * + * @return -1 if there was a problem (decryption failed), length of plain data + * if everything was fine. + */ +static int32_t decrypt_data_symmetric( + const uint8_t[CRYPTO_SHARED_KEY_SIZE] shared_key, + const uint8_t[CRYPTO_NONCE_SIZE] nonce, + const uint8_t[length] encrypted, + uint8_t *plain); + +/** + * Increment the given nonce by 1 in big endian (rightmost byte incremented + * first). + */ +static void increment_nonce(uint8_t[CRYPTO_NONCE_SIZE] nonce); + +/** + * Increment the given nonce by a given number. The number should be in host + * byte order. + */ +static void increment_nonce_number(uint8_t[CRYPTO_NONCE_SIZE] nonce, uint32_t host_order_num); + +/** + * Fill the given nonce with random bytes. + */ +static void random_nonce(uint8_t[CRYPTO_NONCE_SIZE] nonce); + +/** + * Fill a key CRYPTO_SYMMETRIC_KEY_SIZE big with random bytes. + */ +static void new_symmetric_key(uint8_t[CRYPTO_SYMMETRIC_KEY_SIZE] key); + +/** + * Fill an array of bytes with random values. + */ +static void random_bytes(uint8_t[length] bytes); + +%{ +#endif /* CRYPTO_CORE_H */ +%} diff --git a/protocols/Tox/libtox/src/toxcore/crypto_core.c b/protocols/Tox/libtox/src/toxcore/crypto_core.c new file mode 100644 index 0000000000..8e34b5876a --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/crypto_core.c @@ -0,0 +1,287 @@ +/* + * Functions for the core crypto. + * + * NOTE: This code has to be perfect. We don't mess around with encryption. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ccompat.h" +#include "crypto_core.h" + +#include <string.h> + +#ifndef VANILLA_NACL +/* We use libsodium by default. */ +#include <sodium.h> +#else +#include <crypto_box.h> +#include <crypto_hash_sha256.h> +#include <crypto_hash_sha512.h> +#include <crypto_scalarmult_curve25519.h> +#include <crypto_verify_16.h> +#include <crypto_verify_32.h> +#include <randombytes.h> +#define crypto_box_MACBYTES (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES) +#endif + +#if CRYPTO_PUBLIC_KEY_SIZE != crypto_box_PUBLICKEYBYTES +#error CRYPTO_PUBLIC_KEY_SIZE should be equal to crypto_box_PUBLICKEYBYTES +#endif + +#if CRYPTO_SECRET_KEY_SIZE != crypto_box_SECRETKEYBYTES +#error CRYPTO_SECRET_KEY_SIZE should be equal to crypto_box_SECRETKEYBYTES +#endif + +#if CRYPTO_SHARED_KEY_SIZE != crypto_box_BEFORENMBYTES +#error CRYPTO_SHARED_KEY_SIZE should be equal to crypto_box_BEFORENMBYTES +#endif + +#if CRYPTO_SYMMETRIC_KEY_SIZE != crypto_box_BEFORENMBYTES +#error CRYPTO_SYMMETRIC_KEY_SIZE should be equal to crypto_box_BEFORENMBYTES +#endif + +#if CRYPTO_MAC_SIZE != crypto_box_MACBYTES +#error CRYPTO_MAC_SIZE should be equal to crypto_box_MACBYTES +#endif + +#if CRYPTO_NONCE_SIZE != crypto_box_NONCEBYTES +#error CRYPTO_NONCE_SIZE should be equal to crypto_box_NONCEBYTES +#endif + +#if CRYPTO_SHA256_SIZE != crypto_hash_sha256_BYTES +#error CRYPTO_SHA256_SIZE should be equal to crypto_hash_sha256_BYTES +#endif + +#if CRYPTO_SHA512_SIZE != crypto_hash_sha512_BYTES +#error CRYPTO_SHA512_SIZE should be equal to crypto_hash_sha512_BYTES +#endif + +int32_t public_key_cmp(const uint8_t *pk1, const uint8_t *pk2) +{ +#if CRYPTO_PUBLIC_KEY_SIZE != 32 +#error CRYPTO_PUBLIC_KEY_SIZE is required to be 32 bytes for public_key_cmp to work, +#endif + return crypto_verify_32(pk1, pk2); +} + +uint32_t random_int(void) +{ + uint32_t randnum; + randombytes((uint8_t *)&randnum , sizeof(randnum)); + return randnum; +} + +uint64_t random_64b(void) +{ + uint64_t randnum; + randombytes((uint8_t *)&randnum, sizeof(randnum)); + return randnum; +} + +bool public_key_valid(const uint8_t *public_key) +{ + if (public_key[31] >= 128) { /* Last bit of key is always zero. */ + return 0; + } + + return 1; +} + +/* Precomputes the shared key from their public_key and our secret_key. + * This way we can avoid an expensive elliptic curve scalar multiply for each + * encrypt/decrypt operation. + * shared_key has to be crypto_box_BEFORENMBYTES bytes long. + */ +int32_t encrypt_precompute(const uint8_t *public_key, const uint8_t *secret_key, uint8_t *shared_key) +{ + return crypto_box_beforenm(shared_key, public_key, secret_key); +} + +int32_t encrypt_data_symmetric(const uint8_t *secret_key, const uint8_t *nonce, const uint8_t *plain, size_t length, + uint8_t *encrypted) +{ + if (length == 0 || !secret_key || !nonce || !plain || !encrypted) { + return -1; + } + + VLA(uint8_t, temp_plain, length + crypto_box_ZEROBYTES); + VLA(uint8_t, temp_encrypted, length + crypto_box_MACBYTES + crypto_box_BOXZEROBYTES); + + memset(temp_plain, 0, crypto_box_ZEROBYTES); + memcpy(temp_plain + crypto_box_ZEROBYTES, plain, length); // Pad the message with 32 0 bytes. + + if (crypto_box_afternm(temp_encrypted, temp_plain, length + crypto_box_ZEROBYTES, nonce, secret_key) != 0) { + return -1; + } + + /* Unpad the encrypted message. */ + memcpy(encrypted, temp_encrypted + crypto_box_BOXZEROBYTES, length + crypto_box_MACBYTES); + return length + crypto_box_MACBYTES; +} + +int32_t decrypt_data_symmetric(const uint8_t *secret_key, const uint8_t *nonce, const uint8_t *encrypted, size_t length, + uint8_t *plain) +{ + if (length <= crypto_box_BOXZEROBYTES || !secret_key || !nonce || !encrypted || !plain) { + return -1; + } + + VLA(uint8_t, temp_plain, length + crypto_box_ZEROBYTES); + VLA(uint8_t, temp_encrypted, length + crypto_box_BOXZEROBYTES); + + memset(temp_encrypted, 0, crypto_box_BOXZEROBYTES); + memcpy(temp_encrypted + crypto_box_BOXZEROBYTES, encrypted, length); // Pad the message with 16 0 bytes. + + if (crypto_box_open_afternm(temp_plain, temp_encrypted, length + crypto_box_BOXZEROBYTES, nonce, secret_key) != 0) { + return -1; + } + + memcpy(plain, temp_plain + crypto_box_ZEROBYTES, length - crypto_box_MACBYTES); + return length - crypto_box_MACBYTES; +} + +int32_t encrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce, + const uint8_t *plain, size_t length, uint8_t *encrypted) +{ + if (!public_key || !secret_key) { + return -1; + } + + uint8_t k[crypto_box_BEFORENMBYTES]; + encrypt_precompute(public_key, secret_key, k); + int ret = encrypt_data_symmetric(k, nonce, plain, length, encrypted); + crypto_memzero(k, sizeof k); + return ret; +} + +int32_t decrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce, + const uint8_t *encrypted, size_t length, uint8_t *plain) +{ + if (!public_key || !secret_key) { + return -1; + } + + uint8_t k[crypto_box_BEFORENMBYTES]; + encrypt_precompute(public_key, secret_key, k); + int ret = decrypt_data_symmetric(k, nonce, encrypted, length, plain); + crypto_memzero(k, sizeof k); + return ret; +} + + +/* Increment the given nonce by 1. */ +void increment_nonce(uint8_t *nonce) +{ + /* TODO(irungentoo): use increment_nonce_number(nonce, 1) or sodium_increment (change to little endian) + * NOTE don't use breaks inside this loop + * In particular, make sure, as far as possible, + * that loop bounds and their potential underflow or overflow + * are independent of user-controlled input (you may have heard of the Heartbleed bug). + */ + uint32_t i = crypto_box_NONCEBYTES; + uint_fast16_t carry = 1U; + + for (; i != 0; --i) { + carry += (uint_fast16_t) nonce[i - 1]; + nonce[i - 1] = (uint8_t) carry; + carry >>= 8; + } +} + +static uint32_t host_to_network(uint32_t x) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + return + ((x >> 24) & 0x000000FF) | // move byte 3 to byte 0 + ((x >> 8) & 0x0000FF00) | // move byte 2 to byte 1 + ((x << 8) & 0x00FF0000) | // move byte 1 to byte 2 + ((x << 24) & 0xFF000000); // move byte 0 to byte 3 +#else + return x; +#endif +} + +/* increment the given nonce by num */ +void increment_nonce_number(uint8_t *nonce, uint32_t host_order_num) +{ + /* NOTE don't use breaks inside this loop + * In particular, make sure, as far as possible, + * that loop bounds and their potential underflow or overflow + * are independent of user-controlled input (you may have heard of the Heartbleed bug). + */ + const uint32_t big_endian_num = host_to_network(host_order_num); + const uint8_t *const num_vec = (const uint8_t *) &big_endian_num; + uint8_t num_as_nonce[crypto_box_NONCEBYTES] = {0}; + num_as_nonce[crypto_box_NONCEBYTES - 4] = num_vec[0]; + num_as_nonce[crypto_box_NONCEBYTES - 3] = num_vec[1]; + num_as_nonce[crypto_box_NONCEBYTES - 2] = num_vec[2]; + num_as_nonce[crypto_box_NONCEBYTES - 1] = num_vec[3]; + + uint32_t i = crypto_box_NONCEBYTES; + uint_fast16_t carry = 0U; + + for (; i != 0; --i) { + carry += (uint_fast16_t) nonce[i - 1] + (uint_fast16_t) num_as_nonce[i - 1]; + nonce[i - 1] = (unsigned char) carry; + carry >>= 8; + } +} + +/* Fill the given nonce with random bytes. */ +void random_nonce(uint8_t *nonce) +{ + randombytes(nonce, crypto_box_NONCEBYTES); +} + +/* Fill a key CRYPTO_SYMMETRIC_KEY_SIZE big with random bytes */ +void new_symmetric_key(uint8_t *key) +{ + randombytes(key, CRYPTO_SYMMETRIC_KEY_SIZE); +} + +int32_t crypto_new_keypair(uint8_t *public_key, uint8_t *secret_key) +{ + return crypto_box_keypair(public_key, secret_key); +} + +void crypto_derive_public_key(uint8_t *public_key, const uint8_t *secret_key) +{ + crypto_scalarmult_curve25519_base(public_key, secret_key); +} + +void crypto_sha256(uint8_t *hash, const uint8_t *data, size_t length) +{ + crypto_hash_sha256(hash, data, length); +} + +void crypto_sha512(uint8_t *hash, const uint8_t *data, size_t length) +{ + crypto_hash_sha512(hash, data, length); +} + +void random_bytes(uint8_t *data, size_t length) +{ + randombytes(data, length); +} diff --git a/protocols/Tox/libtox/src/toxcore/crypto_core.h b/protocols/Tox/libtox/src/toxcore/crypto_core.h new file mode 100644 index 0000000000..fc5756c1d2 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/crypto_core.h @@ -0,0 +1,234 @@ +/* + * Functions for the core crypto. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef CRYPTO_CORE_H +#define CRYPTO_CORE_H + +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> + +/** + * The number of bytes in a Tox public key. + */ +#define CRYPTO_PUBLIC_KEY_SIZE 32 + +uint32_t crypto_public_key_size(void); + +/** + * The number of bytes in a Tox secret key. + */ +#define CRYPTO_SECRET_KEY_SIZE 32 + +uint32_t crypto_secret_key_size(void); + +/** + * The number of bytes in a shared key computed from public and secret keys. + */ +#define CRYPTO_SHARED_KEY_SIZE 32 + +uint32_t crypto_shared_key_size(void); + +/** + * The number of bytes in a symmetric key. + */ +#define CRYPTO_SYMMETRIC_KEY_SIZE CRYPTO_SHARED_KEY_SIZE + +uint32_t crypto_symmetric_key_size(void); + +/** + * The number of bytes needed for the MAC (message authentication code) in an + * encrypted message. + */ +#define CRYPTO_MAC_SIZE 16 + +uint32_t crypto_mac_size(void); + +/** + * The number of bytes in a nonce used for encryption/decryption. + */ +#define CRYPTO_NONCE_SIZE 24 + +uint32_t crypto_nonce_size(void); + +/** + * The number of bytes in a SHA256 hash. + */ +#define CRYPTO_SHA256_SIZE 32 + +uint32_t crypto_sha256_size(void); + +/** + * The number of bytes in a SHA512 hash. + */ +#define CRYPTO_SHA512_SIZE 64 + +uint32_t crypto_sha512_size(void); + +/** + * A `memcmp`-like function whose running time does not depend on the input + * bytes, only on the input length. Useful to compare sensitive data where + * timing attacks could reveal that data. + * + * This means for instance that comparing "aaaa" and "aaaa" takes 4 time, and + * "aaaa" and "baaa" also takes 4 time. With a regular `memcmp`, the latter may + * take 1 time, because it immediately knows that the two strings are not equal. + */ +int32_t crypto_memcmp(const void *p1, const void *p2, size_t length); + +/** + * A `bzero`-like function which won't be optimised away by the compiler. Some + * compilers will inline `bzero` or `memset` if they can prove that there will + * be no reads to the written data. Use this function if you want to be sure the + * memory is indeed zeroed. + */ +void crypto_memzero(void *data, size_t length); + +/** + * Compute a SHA256 hash (32 bytes). + */ +void crypto_sha256(uint8_t *hash, const uint8_t *data, size_t length); + +/** + * Compute a SHA512 hash (64 bytes). + */ +void crypto_sha512(uint8_t *hash, const uint8_t *data, size_t length); + +/** + * Compare 2 public keys of length CRYPTO_PUBLIC_KEY_SIZE, not vulnerable to + * timing attacks. + * + * @return 0 if both mem locations of length are equal, -1 if they are not. + */ +int32_t public_key_cmp(const uint8_t *pk1, const uint8_t *pk2); + +/** + * Return a random 32 bit integer. + */ +uint32_t random_int(void); + +/** + * Return a random 64 bit integer. + */ +uint64_t random_64b(void); + +/** + * Check if a Tox public key CRYPTO_PUBLIC_KEY_SIZE is valid or not. This + * should only be used for input validation. + * + * @return false if it isn't, true if it is. + */ +bool public_key_valid(const uint8_t *public_key); + +/** + * Generate a new random keypair. Every call to this function is likely to + * generate a different keypair. + */ +int32_t crypto_new_keypair(uint8_t *public_key, uint8_t *secret_key); + +/** + * Derive the public key from a given secret key. + */ +void crypto_derive_public_key(uint8_t *public_key, const uint8_t *secret_key); + +/** + * Encrypt plain text of the given length to encrypted of length + + * CRYPTO_MAC_SIZE using the public key (CRYPTO_PUBLIC_KEY_SIZE bytes) of the + * receiver and the secret key of the sender and a CRYPTO_NONCE_SIZE byte + * nonce. + * + * @return -1 if there was a problem, length of encrypted data if everything + * was fine. + */ +int32_t encrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce, const uint8_t *plain, + size_t length, uint8_t *encrypted); + +/** + * Decrypt encrypted text of the given length to plain text of the given length + * - CRYPTO_MAC_SIZE using the public key (CRYPTO_PUBLIC_KEY_SIZE bytes) of + * the sender, the secret key of the receiver and a CRYPTO_NONCE_SIZE byte + * nonce. + * + * @return -1 if there was a problem (decryption failed), length of plain text + * data if everything was fine. + */ +int32_t decrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce, + const uint8_t *encrypted, size_t length, uint8_t *plain); + +/** + * Fast encrypt/decrypt operations. Use if this is not a one-time communication. + * encrypt_precompute does the shared-key generation once so it does not have + * to be preformed on every encrypt/decrypt. + */ +int32_t encrypt_precompute(const uint8_t *public_key, const uint8_t *secret_key, uint8_t *shared_key); + +/** + * Encrypts plain of length length to encrypted of length + CRYPTO_MAC_SIZE + * using a shared key CRYPTO_SYMMETRIC_KEY_SIZE big and a CRYPTO_NONCE_SIZE + * byte nonce. + * + * @return -1 if there was a problem, length of encrypted data if everything + * was fine. + */ +int32_t encrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce, const uint8_t *plain, size_t length, + uint8_t *encrypted); + +/** + * Decrypts encrypted of length length to plain of length length - + * CRYPTO_MAC_SIZE using a shared key CRYPTO_SHARED_KEY_SIZE big and a + * CRYPTO_NONCE_SIZE byte nonce. + * + * @return -1 if there was a problem (decryption failed), length of plain data + * if everything was fine. + */ +int32_t decrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce, const uint8_t *encrypted, size_t length, + uint8_t *plain); + +/** + * Increment the given nonce by 1 in big endian (rightmost byte incremented + * first). + */ +void increment_nonce(uint8_t *nonce); + +/** + * Increment the given nonce by a given number. The number should be in host + * byte order. + */ +void increment_nonce_number(uint8_t *nonce, uint32_t host_order_num); + +/** + * Fill the given nonce with random bytes. + */ +void random_nonce(uint8_t *nonce); + +/** + * Fill a key CRYPTO_SYMMETRIC_KEY_SIZE big with random bytes. + */ +void new_symmetric_key(uint8_t *key); + +/** + * Fill an array of bytes with random values. + */ +void random_bytes(uint8_t *bytes, size_t length); + +#endif /* CRYPTO_CORE_H */ diff --git a/protocols/Tox/libtox/src/toxcore/crypto_core_mem.c b/protocols/Tox/libtox/src/toxcore/crypto_core_mem.c new file mode 100644 index 0000000000..b8f4223e65 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/crypto_core_mem.c @@ -0,0 +1,87 @@ +/* + * ISC License + * + * Copyright (c) 2013-2016 + * Frank Denis <j at pureftpd dot org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "crypto_core.h" + +#ifndef VANILLA_NACL +/* We use libsodium by default. */ +#include <sodium.h> +#else +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +#include <windows.h> +#include <wincrypt.h> +#endif +#endif + + +void crypto_memzero(void *data, size_t length) +{ +#ifndef VANILLA_NACL + sodium_memzero(data, length); +#else +#ifdef _WIN32 + SecureZeroMemory(data, length); +#elif defined(HAVE_MEMSET_S) + + if (length > 0U) { + errno_t code = memset_s(data, (rsize_t) length, 0, (rsize_t) length); + + if (code != 0) { + abort(); /* LCOV_EXCL_LINE */ + } + } + +#elif defined(HAVE_EXPLICIT_BZERO) + explicit_bzero(data, length); +#else + volatile unsigned char *volatile pnt = + (volatile unsigned char *volatile) data; + size_t i = (size_t) 0U; + + while (i < length) { + pnt[i++] = 0U; + } + +#endif +#endif +} + +int32_t crypto_memcmp(const void *p1, const void *p2, size_t length) +{ +#ifndef VANILLA_NACL + return sodium_memcmp(p1, p2, length); +#else + const volatile unsigned char *volatile b1 = + (const volatile unsigned char *volatile) p1; + const volatile unsigned char *volatile b2 = + (const volatile unsigned char *volatile) p2; + + size_t i; + unsigned char d = (unsigned char) 0U; + + for (i = 0U; i < length; i++) { + d |= b1[i] ^ b2[i]; + } + + return (1 & ((d - 1) >> 8)) - 1; +#endif +} diff --git a/protocols/Tox/libtox/src/toxcore/friend_connection.c b/protocols/Tox/libtox/src/toxcore/friend_connection.c new file mode 100644 index 0000000000..9f0677b109 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/friend_connection.c @@ -0,0 +1,937 @@ +/* + * Connection to friends. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "friend_connection.h" + +#include "util.h" + +#define PORTS_PER_DISCOVERY 10 + +/* return 1 if the friendcon_id is not valid. + * return 0 if the friendcon_id is valid. + */ +static uint8_t friendconn_id_not_valid(const Friend_Connections *fr_c, int friendcon_id) +{ + if ((unsigned int)friendcon_id >= fr_c->num_cons) { + return 1; + } + + if (fr_c->conns == NULL) { + return 1; + } + + if (fr_c->conns[friendcon_id].status == FRIENDCONN_STATUS_NONE) { + return 1; + } + + return 0; +} + + +/* Set the size of the friend connections list to num. + * + * return -1 if realloc fails. + * return 0 if it succeeds. + */ +static int realloc_friendconns(Friend_Connections *fr_c, uint32_t num) +{ + if (num == 0) { + free(fr_c->conns); + fr_c->conns = NULL; + return 0; + } + + Friend_Conn *newgroup_cons = (Friend_Conn *)realloc(fr_c->conns, num * sizeof(Friend_Conn)); + + if (newgroup_cons == NULL) { + return -1; + } + + fr_c->conns = newgroup_cons; + return 0; +} + +/* Create a new empty friend connection. + * + * return -1 on failure. + * return friendcon_id on success. + */ +static int create_friend_conn(Friend_Connections *fr_c) +{ + uint32_t i; + + for (i = 0; i < fr_c->num_cons; ++i) { + if (fr_c->conns[i].status == FRIENDCONN_STATUS_NONE) { + return i; + } + } + + int id = -1; + + if (realloc_friendconns(fr_c, fr_c->num_cons + 1) == 0) { + id = fr_c->num_cons; + ++fr_c->num_cons; + memset(&(fr_c->conns[id]), 0, sizeof(Friend_Conn)); + } + + return id; +} + +/* Wipe a friend connection. + * + * return -1 on failure. + * return 0 on success. + */ +static int wipe_friend_conn(Friend_Connections *fr_c, int friendcon_id) +{ + if (friendconn_id_not_valid(fr_c, friendcon_id)) { + return -1; + } + + uint32_t i; + memset(&(fr_c->conns[friendcon_id]), 0 , sizeof(Friend_Conn)); + + for (i = fr_c->num_cons; i != 0; --i) { + if (fr_c->conns[i - 1].status != FRIENDCONN_STATUS_NONE) { + break; + } + } + + if (fr_c->num_cons != i) { + fr_c->num_cons = i; + realloc_friendconns(fr_c, fr_c->num_cons); + } + + return 0; +} + +static Friend_Conn *get_conn(const Friend_Connections *fr_c, int friendcon_id) +{ + if (friendconn_id_not_valid(fr_c, friendcon_id)) { + return 0; + } + + return &fr_c->conns[friendcon_id]; +} + +/* return friendcon_id corresponding to the real public key on success. + * return -1 on failure. + */ +int getfriend_conn_id_pk(Friend_Connections *fr_c, const uint8_t *real_pk) +{ + uint32_t i; + + for (i = 0; i < fr_c->num_cons; ++i) { + Friend_Conn *friend_con = get_conn(fr_c, i); + + if (friend_con) { + if (public_key_cmp(friend_con->real_public_key, real_pk) == 0) { + return i; + } + } + } + + return -1; +} + +/* Add a TCP relay associated to the friend. + * + * return -1 on failure. + * return 0 on success. + */ +int friend_add_tcp_relay(Friend_Connections *fr_c, int friendcon_id, IP_Port ip_port, const uint8_t *public_key) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return -1; + } + + /* Local ip and same pk means that they are hosting a TCP relay. */ + if (Local_ip(ip_port.ip) && public_key_cmp(friend_con->dht_temp_pk, public_key) == 0) { + if (friend_con->dht_ip_port.ip.family != 0) { + ip_port.ip = friend_con->dht_ip_port.ip; + } else { + friend_con->hosting_tcp_relay = 0; + } + } + + unsigned int i; + + uint16_t index = friend_con->tcp_relay_counter % FRIEND_MAX_STORED_TCP_RELAYS; + + for (i = 0; i < FRIEND_MAX_STORED_TCP_RELAYS; ++i) { + if (friend_con->tcp_relays[i].ip_port.ip.family != 0 + && public_key_cmp(friend_con->tcp_relays[i].public_key, public_key) == 0) { + memset(&friend_con->tcp_relays[i], 0, sizeof(Node_format)); + } + } + + friend_con->tcp_relays[index].ip_port = ip_port; + memcpy(friend_con->tcp_relays[index].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + ++friend_con->tcp_relay_counter; + + return add_tcp_relay_peer(fr_c->net_crypto, friend_con->crypt_connection_id, ip_port, public_key); +} + +/* Connect to number saved relays for friend. */ +static void connect_to_saved_tcp_relays(Friend_Connections *fr_c, int friendcon_id, unsigned int number) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return; + } + + unsigned int i; + + for (i = 0; (i < FRIEND_MAX_STORED_TCP_RELAYS) && (number != 0); ++i) { + uint16_t index = (friend_con->tcp_relay_counter - (i + 1)) % FRIEND_MAX_STORED_TCP_RELAYS; + + if (friend_con->tcp_relays[index].ip_port.ip.family) { + if (add_tcp_relay_peer(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->tcp_relays[index].ip_port, + friend_con->tcp_relays[index].public_key) == 0) { + --number; + } + } + } +} + +static unsigned int send_relays(Friend_Connections *fr_c, int friendcon_id) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return 0; + } + + Node_format nodes[MAX_SHARED_RELAYS]; + uint8_t data[1024]; + int n, length; + + n = copy_connected_tcp_relays(fr_c->net_crypto, nodes, MAX_SHARED_RELAYS); + + int i; + + for (i = 0; i < n; ++i) { + /* Associated the relays being sent with this connection. + On receiving the peer will do the same which will establish the connection. */ + friend_add_tcp_relay(fr_c, friendcon_id, nodes[i].ip_port, nodes[i].public_key); + } + + length = pack_nodes(data + 1, sizeof(data) - 1, nodes, n); + + if (length <= 0) { + return 0; + } + + data[0] = PACKET_ID_SHARE_RELAYS; + ++length; + + if (write_cryptpacket(fr_c->net_crypto, friend_con->crypt_connection_id, data, length, 0) != -1) { + friend_con->share_relays_lastsent = unix_time(); + return 1; + } + + return 0; +} + +/* callback for recv TCP relay nodes. */ +static int tcp_relay_node_callback(void *object, uint32_t number, IP_Port ip_port, const uint8_t *public_key) +{ + Friend_Connections *fr_c = (Friend_Connections *)object; + Friend_Conn *friend_con = get_conn(fr_c, number); + + if (!friend_con) { + return -1; + } + + if (friend_con->crypt_connection_id != -1) { + return friend_add_tcp_relay(fr_c, number, ip_port, public_key); + } + + return add_tcp_relay(fr_c->net_crypto, ip_port, public_key); +} + +static int friend_new_connection(Friend_Connections *fr_c, int friendcon_id); +/* Callback for DHT ip_port changes. */ +static void dht_ip_callback(void *object, int32_t number, IP_Port ip_port) +{ + Friend_Connections *fr_c = (Friend_Connections *)object; + Friend_Conn *friend_con = get_conn(fr_c, number); + + if (!friend_con) { + return; + } + + if (friend_con->crypt_connection_id == -1) { + friend_new_connection(fr_c, number); + } + + set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, ip_port, 1); + friend_con->dht_ip_port = ip_port; + friend_con->dht_ip_port_lastrecv = unix_time(); + + if (friend_con->hosting_tcp_relay) { + friend_add_tcp_relay(fr_c, number, ip_port, friend_con->dht_temp_pk); + friend_con->hosting_tcp_relay = 0; + } +} + +static void change_dht_pk(Friend_Connections *fr_c, int friendcon_id, const uint8_t *dht_public_key) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return; + } + + friend_con->dht_pk_lastrecv = unix_time(); + + if (friend_con->dht_lock) { + if (DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock) != 0) { + printf("a. Could not delete dht peer. Please report this.\n"); + return; + } + + friend_con->dht_lock = 0; + } + + DHT_addfriend(fr_c->dht, dht_public_key, dht_ip_callback, fr_c, friendcon_id, &friend_con->dht_lock); + memcpy(friend_con->dht_temp_pk, dht_public_key, CRYPTO_PUBLIC_KEY_SIZE); +} + +static int handle_status(void *object, int number, uint8_t status, void *userdata) +{ + Friend_Connections *fr_c = (Friend_Connections *)object; + Friend_Conn *friend_con = get_conn(fr_c, number); + + if (!friend_con) { + return -1; + } + + bool call_cb = 0; + + if (status) { /* Went online. */ + call_cb = 1; + friend_con->status = FRIENDCONN_STATUS_CONNECTED; + friend_con->ping_lastrecv = unix_time(); + friend_con->share_relays_lastsent = 0; + onion_set_friend_online(fr_c->onion_c, friend_con->onion_friendnum, status); + } else { /* Went offline. */ + if (friend_con->status != FRIENDCONN_STATUS_CONNECTING) { + call_cb = 1; + friend_con->dht_pk_lastrecv = unix_time(); + onion_set_friend_online(fr_c->onion_c, friend_con->onion_friendnum, status); + } + + friend_con->status = FRIENDCONN_STATUS_CONNECTING; + friend_con->crypt_connection_id = -1; + friend_con->hosting_tcp_relay = 0; + } + + if (call_cb) { + unsigned int i; + + for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) { + if (friend_con->callbacks[i].status_callback) { + friend_con->callbacks[i].status_callback( + friend_con->callbacks[i].callback_object, + friend_con->callbacks[i].callback_id, status, userdata); + } + } + } + + return 0; +} + +/* Callback for dht public key changes. */ +static void dht_pk_callback(void *object, int32_t number, const uint8_t *dht_public_key, void *userdata) +{ + Friend_Connections *fr_c = (Friend_Connections *)object; + Friend_Conn *friend_con = get_conn(fr_c, number); + + if (!friend_con) { + return; + } + + if (public_key_cmp(friend_con->dht_temp_pk, dht_public_key) == 0) { + return; + } + + change_dht_pk(fr_c, number, dht_public_key); + + /* if pk changed, create a new connection.*/ + if (friend_con->crypt_connection_id != -1) { + crypto_kill(fr_c->net_crypto, friend_con->crypt_connection_id); + friend_con->crypt_connection_id = -1; + handle_status(object, number, 0, userdata); /* Going offline. */ + } + + friend_new_connection(fr_c, number); + onion_set_friend_DHT_pubkey(fr_c->onion_c, friend_con->onion_friendnum, dht_public_key); +} + +static int handle_packet(void *object, int number, const uint8_t *data, uint16_t length, void *userdata) +{ + if (length == 0) { + return -1; + } + + Friend_Connections *fr_c = (Friend_Connections *)object; + Friend_Conn *friend_con = get_conn(fr_c, number); + + if (!friend_con) { + return -1; + } + + if (data[0] == PACKET_ID_FRIEND_REQUESTS) { + if (fr_c->fr_request_callback) { + fr_c->fr_request_callback(fr_c->fr_request_object, friend_con->real_public_key, data, length, userdata); + } + + return 0; + } + + if (data[0] == PACKET_ID_ALIVE) { + friend_con->ping_lastrecv = unix_time(); + return 0; + } + + if (data[0] == PACKET_ID_SHARE_RELAYS) { + Node_format nodes[MAX_SHARED_RELAYS]; + int n; + + if ((n = unpack_nodes(nodes, MAX_SHARED_RELAYS, NULL, data + 1, length - 1, 1)) == -1) { + return -1; + } + + int j; + + for (j = 0; j < n; j++) { + friend_add_tcp_relay(fr_c, number, nodes[j].ip_port, nodes[j].public_key); + } + + return 0; + } + + unsigned int i; + + for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) { + if (friend_con->callbacks[i].data_callback) { + friend_con->callbacks[i].data_callback( + friend_con->callbacks[i].callback_object, + friend_con->callbacks[i].callback_id, data, length, userdata); + } + + friend_con = get_conn(fr_c, number); + + if (!friend_con) { + return -1; + } + } + + return 0; +} + +static int handle_lossy_packet(void *object, int number, const uint8_t *data, uint16_t length, void *userdata) +{ + if (length == 0) { + return -1; + } + + Friend_Connections *fr_c = (Friend_Connections *)object; + Friend_Conn *friend_con = get_conn(fr_c, number); + + if (!friend_con) { + return -1; + } + + unsigned int i; + + for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) { + if (friend_con->callbacks[i].lossy_data_callback) { + friend_con->callbacks[i].lossy_data_callback( + friend_con->callbacks[i].callback_object, + friend_con->callbacks[i].callback_id, data, length, userdata); + } + + friend_con = get_conn(fr_c, number); + + if (!friend_con) { + return -1; + } + } + + return 0; +} + +static int handle_new_connections(void *object, New_Connection *n_c) +{ + Friend_Connections *fr_c = (Friend_Connections *)object; + int friendcon_id = getfriend_conn_id_pk(fr_c, n_c->public_key); + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (friend_con) { + + if (friend_con->crypt_connection_id != -1) { + return -1; + } + + int id = accept_crypto_connection(fr_c->net_crypto, n_c); + + if (id == -1) { + return -1; + } + + connection_status_handler(fr_c->net_crypto, id, &handle_status, fr_c, friendcon_id); + connection_data_handler(fr_c->net_crypto, id, &handle_packet, fr_c, friendcon_id); + connection_lossy_data_handler(fr_c->net_crypto, id, &handle_lossy_packet, fr_c, friendcon_id); + friend_con->crypt_connection_id = id; + + if (n_c->source.ip.family != TOX_AF_INET && n_c->source.ip.family != TOX_AF_INET6) { + set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->dht_ip_port, 0); + } else { + friend_con->dht_ip_port = n_c->source; + friend_con->dht_ip_port_lastrecv = unix_time(); + } + + if (public_key_cmp(friend_con->dht_temp_pk, n_c->dht_public_key) != 0) { + change_dht_pk(fr_c, friendcon_id, n_c->dht_public_key); + } + + nc_dht_pk_callback(fr_c->net_crypto, id, &dht_pk_callback, fr_c, friendcon_id); + return 0; + } + + return -1; +} + +static int friend_new_connection(Friend_Connections *fr_c, int friendcon_id) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return -1; + } + + if (friend_con->crypt_connection_id != -1) { + return -1; + } + + /* If dht_temp_pk does not contains a pk. */ + if (!friend_con->dht_lock) { + return -1; + } + + int id = new_crypto_connection(fr_c->net_crypto, friend_con->real_public_key, friend_con->dht_temp_pk); + + if (id == -1) { + return -1; + } + + friend_con->crypt_connection_id = id; + connection_status_handler(fr_c->net_crypto, id, &handle_status, fr_c, friendcon_id); + connection_data_handler(fr_c->net_crypto, id, &handle_packet, fr_c, friendcon_id); + connection_lossy_data_handler(fr_c->net_crypto, id, &handle_lossy_packet, fr_c, friendcon_id); + nc_dht_pk_callback(fr_c->net_crypto, id, &dht_pk_callback, fr_c, friendcon_id); + + return 0; +} + +static int send_ping(const Friend_Connections *fr_c, int friendcon_id) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return -1; + } + + uint8_t ping = PACKET_ID_ALIVE; + int64_t ret = write_cryptpacket(fr_c->net_crypto, friend_con->crypt_connection_id, &ping, sizeof(ping), 0); + + if (ret != -1) { + friend_con->ping_lastsent = unix_time(); + return 0; + } + + return -1; +} + +/* Increases lock_count for the connection with friendcon_id by 1. + * + * return 0 on success. + * return -1 on failure. + */ +int friend_connection_lock(Friend_Connections *fr_c, int friendcon_id) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return -1; + } + + ++friend_con->lock_count; + return 0; +} + +/* return FRIENDCONN_STATUS_CONNECTED if the friend is connected. + * return FRIENDCONN_STATUS_CONNECTING if the friend isn't connected. + * return FRIENDCONN_STATUS_NONE on failure. + */ +unsigned int friend_con_connected(Friend_Connections *fr_c, int friendcon_id) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return 0; + } + + return friend_con->status; +} + +/* Copy public keys associated to friendcon_id. + * + * return 0 on success. + * return -1 on failure. + */ +int get_friendcon_public_keys(uint8_t *real_pk, uint8_t *dht_temp_pk, Friend_Connections *fr_c, int friendcon_id) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return -1; + } + + if (real_pk) { + memcpy(real_pk, friend_con->real_public_key, CRYPTO_PUBLIC_KEY_SIZE); + } + + if (dht_temp_pk) { + memcpy(dht_temp_pk, friend_con->dht_temp_pk, CRYPTO_PUBLIC_KEY_SIZE); + } + + return 0; +} + +/* Set temp dht key for connection. + */ +void set_dht_temp_pk(Friend_Connections *fr_c, int friendcon_id, const uint8_t *dht_temp_pk, void *userdata) +{ + dht_pk_callback(fr_c, friendcon_id, dht_temp_pk, userdata); +} + +/* Set the callbacks for the friend connection. + * index is the index (0 to (MAX_FRIEND_CONNECTION_CALLBACKS - 1)) we want the callback to set in the array. + * + * return 0 on success. + * return -1 on failure + */ +int friend_connection_callbacks(Friend_Connections *fr_c, int friendcon_id, unsigned int index, + int (*status_callback)(void *object, int id, uint8_t status, void *userdata), + int (*data_callback)(void *object, int id, const uint8_t *data, uint16_t len, void *userdata), + int (*lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length, void *userdata), + void *object, int number) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return -1; + } + + if (index >= MAX_FRIEND_CONNECTION_CALLBACKS) { + return -1; + } + + friend_con->callbacks[index].status_callback = status_callback; + friend_con->callbacks[index].data_callback = data_callback; + friend_con->callbacks[index].lossy_data_callback = lossy_data_callback; + + friend_con->callbacks[index].callback_object = object; + friend_con->callbacks[index].callback_id = number; + + return 0; +} + +/* return the crypt_connection_id for the connection. + * + * return crypt_connection_id on success. + * return -1 on failure. + */ +int friend_connection_crypt_connection_id(Friend_Connections *fr_c, int friendcon_id) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return -1; + } + + return friend_con->crypt_connection_id; +} + +/* Create a new friend connection. + * If one to that real public key already exists, increase lock count and return it. + * + * return -1 on failure. + * return connection id on success. + */ +int new_friend_connection(Friend_Connections *fr_c, const uint8_t *real_public_key) +{ + int friendcon_id = getfriend_conn_id_pk(fr_c, real_public_key); + + if (friendcon_id != -1) { + ++fr_c->conns[friendcon_id].lock_count; + return friendcon_id; + } + + friendcon_id = create_friend_conn(fr_c); + + if (friendcon_id == -1) { + return -1; + } + + int32_t onion_friendnum = onion_addfriend(fr_c->onion_c, real_public_key); + + if (onion_friendnum == -1) { + return -1; + } + + Friend_Conn *friend_con = &fr_c->conns[friendcon_id]; + + friend_con->crypt_connection_id = -1; + friend_con->status = FRIENDCONN_STATUS_CONNECTING; + memcpy(friend_con->real_public_key, real_public_key, CRYPTO_PUBLIC_KEY_SIZE); + friend_con->onion_friendnum = onion_friendnum; + + recv_tcp_relay_handler(fr_c->onion_c, onion_friendnum, &tcp_relay_node_callback, fr_c, friendcon_id); + onion_dht_pk_callback(fr_c->onion_c, onion_friendnum, &dht_pk_callback, fr_c, friendcon_id); + + return friendcon_id; +} + +/* Kill a friend connection. + * + * return -1 on failure. + * return 0 on success. + */ +int kill_friend_connection(Friend_Connections *fr_c, int friendcon_id) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return -1; + } + + if (friend_con->lock_count) { + --friend_con->lock_count; + return 0; + } + + onion_delfriend(fr_c->onion_c, friend_con->onion_friendnum); + crypto_kill(fr_c->net_crypto, friend_con->crypt_connection_id); + + if (friend_con->dht_lock) { + DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock); + } + + return wipe_friend_conn(fr_c, friendcon_id); +} + + +/* Set friend request callback. + * + * This function will be called every time a friend request packet is received. + */ +void set_friend_request_callback(Friend_Connections *fr_c, int (*fr_request_callback)(void *, const uint8_t *, + const uint8_t *, uint16_t, void *), void *object) +{ + fr_c->fr_request_callback = fr_request_callback; + fr_c->fr_request_object = object; + oniondata_registerhandler(fr_c->onion_c, CRYPTO_PACKET_FRIEND_REQ, fr_request_callback, object); +} + +/* Send a Friend request packet. + * + * return -1 if failure. + * return 0 if it sent the friend request directly to the friend. + * return the number of peers it was routed through if it did not send it directly. + */ +int send_friend_request_packet(Friend_Connections *fr_c, int friendcon_id, uint32_t nospam_num, const uint8_t *data, + uint16_t length) +{ + if (1 + sizeof(nospam_num) + length > ONION_CLIENT_MAX_DATA_SIZE || length == 0) { + return -1; + } + + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return -1; + } + + VLA(uint8_t, packet, 1 + sizeof(nospam_num) + length); + memcpy(packet + 1, &nospam_num, sizeof(nospam_num)); + memcpy(packet + 1 + sizeof(nospam_num), data, length); + + if (friend_con->status == FRIENDCONN_STATUS_CONNECTED) { + packet[0] = PACKET_ID_FRIEND_REQUESTS; + return write_cryptpacket(fr_c->net_crypto, friend_con->crypt_connection_id, packet, SIZEOF_VLA(packet), 0) != -1; + } + + packet[0] = CRYPTO_PACKET_FRIEND_REQ; + int num = send_onion_data(fr_c->onion_c, friend_con->onion_friendnum, packet, SIZEOF_VLA(packet)); + + if (num <= 0) { + return -1; + } + + return num; +} + +/* Create new friend_connections instance. */ +Friend_Connections *new_friend_connections(Onion_Client *onion_c, bool local_discovery_enabled) +{ + if (!onion_c) { + return NULL; + } + + Friend_Connections *temp = (Friend_Connections *)calloc(1, sizeof(Friend_Connections)); + + if (temp == NULL) { + return NULL; + } + + temp->dht = onion_c->dht; + temp->net_crypto = onion_c->c; + temp->onion_c = onion_c; + temp->local_discovery_enabled = local_discovery_enabled; + // Don't include default port in port range + temp->next_LANport = TOX_PORTRANGE_FROM + 1; + + new_connection_handler(temp->net_crypto, &handle_new_connections, temp); + + if (temp->local_discovery_enabled) { + LANdiscovery_init(temp->dht); + } + + return temp; +} + +/* Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds. */ +static void LANdiscovery(Friend_Connections *fr_c) +{ + if (fr_c->last_LANdiscovery + LAN_DISCOVERY_INTERVAL < unix_time()) { + const uint16_t first = fr_c->next_LANport; + uint16_t last = first + PORTS_PER_DISCOVERY; + last = last > TOX_PORTRANGE_TO ? TOX_PORTRANGE_TO : last; + + // Always send to default port + send_LANdiscovery(net_htons(TOX_PORT_DEFAULT), fr_c->dht); + + // And check some extra ports + for (uint16_t port = first; port < last; port++) { + send_LANdiscovery(net_htons(port), fr_c->dht); + } + + // Don't include default port in port range + fr_c->next_LANport = last != TOX_PORTRANGE_TO ? last : TOX_PORTRANGE_FROM + 1; + fr_c->last_LANdiscovery = unix_time(); + } +} + +/* main friend_connections loop. */ +void do_friend_connections(Friend_Connections *fr_c, void *userdata) +{ + uint32_t i; + uint64_t temp_time = unix_time(); + + for (i = 0; i < fr_c->num_cons; ++i) { + Friend_Conn *friend_con = get_conn(fr_c, i); + + if (friend_con) { + if (friend_con->status == FRIENDCONN_STATUS_CONNECTING) { + if (friend_con->dht_pk_lastrecv + FRIEND_DHT_TIMEOUT < temp_time) { + if (friend_con->dht_lock) { + DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock); + friend_con->dht_lock = 0; + memset(friend_con->dht_temp_pk, 0, CRYPTO_PUBLIC_KEY_SIZE); + } + } + + if (friend_con->dht_ip_port_lastrecv + FRIEND_DHT_TIMEOUT < temp_time) { + friend_con->dht_ip_port.ip.family = 0; + } + + if (friend_con->dht_lock) { + if (friend_new_connection(fr_c, i) == 0) { + set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->dht_ip_port, 0); + connect_to_saved_tcp_relays(fr_c, i, (MAX_FRIEND_TCP_CONNECTIONS / 2)); /* Only fill it half up. */ + } + } + } else if (friend_con->status == FRIENDCONN_STATUS_CONNECTED) { + if (friend_con->ping_lastsent + FRIEND_PING_INTERVAL < temp_time) { + send_ping(fr_c, i); + } + + if (friend_con->share_relays_lastsent + SHARE_RELAYS_INTERVAL < temp_time) { + send_relays(fr_c, i); + } + + if (friend_con->ping_lastrecv + FRIEND_CONNECTION_TIMEOUT < temp_time) { + /* If we stopped receiving ping packets, kill it. */ + crypto_kill(fr_c->net_crypto, friend_con->crypt_connection_id); + friend_con->crypt_connection_id = -1; + handle_status(fr_c, i, 0, userdata); /* Going offline. */ + } + } + } + } + + if (fr_c->local_discovery_enabled) { + LANdiscovery(fr_c); + } +} + +/* Free everything related with friend_connections. */ +void kill_friend_connections(Friend_Connections *fr_c) +{ + if (!fr_c) { + return; + } + + uint32_t i; + + for (i = 0; i < fr_c->num_cons; ++i) { + kill_friend_connection(fr_c, i); + } + + if (fr_c->local_discovery_enabled) { + LANdiscovery_kill(fr_c->dht); + } + + free(fr_c); +} diff --git a/protocols/Tox/libtox/src/toxcore/friend_connection.h b/protocols/Tox/libtox/src/toxcore/friend_connection.h new file mode 100644 index 0000000000..e993a103d3 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/friend_connection.h @@ -0,0 +1,210 @@ +/* + * Connection to friends. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef FRIEND_CONNECTION_H +#define FRIEND_CONNECTION_H + +#include "DHT.h" +#include "LAN_discovery.h" +#include "net_crypto.h" +#include "onion_client.h" + +#define MAX_FRIEND_CONNECTION_CALLBACKS 2 +#define MESSENGER_CALLBACK_INDEX 0 +#define GROUPCHAT_CALLBACK_INDEX 1 + +#define PACKET_ID_ALIVE 16 +#define PACKET_ID_SHARE_RELAYS 17 +#define PACKET_ID_FRIEND_REQUESTS 18 + +/* Interval between the sending of ping packets. */ +#define FRIEND_PING_INTERVAL 8 + +/* If no packets are received from friend in this time interval, kill the connection. */ +#define FRIEND_CONNECTION_TIMEOUT (FRIEND_PING_INTERVAL * 4) + +/* Time before friend is removed from the DHT after last hearing about him. */ +#define FRIEND_DHT_TIMEOUT BAD_NODE_TIMEOUT + +#define FRIEND_MAX_STORED_TCP_RELAYS (MAX_FRIEND_TCP_CONNECTIONS * 4) + +/* Max number of tcp relays sent to friends */ +#define MAX_SHARED_RELAYS (RECOMMENDED_FRIEND_TCP_CONNECTIONS) + +/* Interval between the sending of tcp relay information */ +#define SHARE_RELAYS_INTERVAL (5 * 60) + + +enum { + FRIENDCONN_STATUS_NONE, + FRIENDCONN_STATUS_CONNECTING, + FRIENDCONN_STATUS_CONNECTED +}; + +typedef struct { + uint8_t status; + + uint8_t real_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t dht_temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint16_t dht_lock; + IP_Port dht_ip_port; + uint64_t dht_pk_lastrecv, dht_ip_port_lastrecv; + + int onion_friendnum; + int crypt_connection_id; + + uint64_t ping_lastrecv, ping_lastsent; + uint64_t share_relays_lastsent; + + struct { + int (*status_callback)(void *object, int id, uint8_t status, void *userdata); + int (*data_callback)(void *object, int id, const uint8_t *data, uint16_t length, void *userdata); + int (*lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length, void *userdata); + + void *callback_object; + int callback_id; + } callbacks[MAX_FRIEND_CONNECTION_CALLBACKS]; + + uint16_t lock_count; + + Node_format tcp_relays[FRIEND_MAX_STORED_TCP_RELAYS]; + uint16_t tcp_relay_counter; + + bool hosting_tcp_relay; +} Friend_Conn; + + +typedef struct { + Net_Crypto *net_crypto; + DHT *dht; + Onion_Client *onion_c; + + Friend_Conn *conns; + uint32_t num_cons; + + int (*fr_request_callback)(void *object, const uint8_t *source_pubkey, const uint8_t *data, uint16_t len, + void *userdata); + void *fr_request_object; + + uint64_t last_LANdiscovery; + uint16_t next_LANport; + + bool local_discovery_enabled; +} Friend_Connections; + +/* return friendcon_id corresponding to the real public key on success. + * return -1 on failure. + */ +int getfriend_conn_id_pk(Friend_Connections *fr_c, const uint8_t *real_pk); + +/* Increases lock_count for the connection with friendcon_id by 1. + * + * return 0 on success. + * return -1 on failure. + */ +int friend_connection_lock(Friend_Connections *fr_c, int friendcon_id); + +/* return FRIENDCONN_STATUS_CONNECTED if the friend is connected. + * return FRIENDCONN_STATUS_CONNECTING if the friend isn't connected. + * return FRIENDCONN_STATUS_NONE on failure. + */ +unsigned int friend_con_connected(Friend_Connections *fr_c, int friendcon_id); + +/* Copy public keys associated to friendcon_id. + * + * return 0 on success. + * return -1 on failure. + */ +int get_friendcon_public_keys(uint8_t *real_pk, uint8_t *dht_temp_pk, Friend_Connections *fr_c, int friendcon_id); + +/* Set temp dht key for connection. + */ +void set_dht_temp_pk(Friend_Connections *fr_c, int friendcon_id, const uint8_t *dht_temp_pk, void *userdata); + +/* Add a TCP relay associated to the friend. + * + * return -1 on failure. + * return 0 on success. + */ +int friend_add_tcp_relay(Friend_Connections *fr_c, int friendcon_id, IP_Port ip_port, const uint8_t *public_key); + +/* Set the callbacks for the friend connection. + * index is the index (0 to (MAX_FRIEND_CONNECTION_CALLBACKS - 1)) we want the callback to set in the array. + * + * return 0 on success. + * return -1 on failure + */ +int friend_connection_callbacks(Friend_Connections *fr_c, int friendcon_id, unsigned int index, + int (*status_callback)(void *object, int id, uint8_t status, void *userdata), + int (*data_callback)(void *object, int id, const uint8_t *data, uint16_t len, void *userdata), + int (*lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length, void *userdata), + void *object, int number); + +/* return the crypt_connection_id for the connection. + * + * return crypt_connection_id on success. + * return -1 on failure. + */ +int friend_connection_crypt_connection_id(Friend_Connections *fr_c, int friendcon_id); + +/* Create a new friend connection. + * If one to that real public key already exists, increase lock count and return it. + * + * return -1 on failure. + * return connection id on success. + */ +int new_friend_connection(Friend_Connections *fr_c, const uint8_t *real_public_key); + +/* Kill a friend connection. + * + * return -1 on failure. + * return 0 on success. + */ +int kill_friend_connection(Friend_Connections *fr_c, int friendcon_id); + +/* Send a Friend request packet. + * + * return -1 if failure. + * return 0 if it sent the friend request directly to the friend. + * return the number of peers it was routed through if it did not send it directly. + */ +int send_friend_request_packet(Friend_Connections *fr_c, int friendcon_id, uint32_t nospam_num, const uint8_t *data, + uint16_t length); + +/* Set friend request callback. + * + * This function will be called every time a friend request is received. + */ +void set_friend_request_callback(Friend_Connections *fr_c, int (*fr_request_callback)(void *, const uint8_t *, + const uint8_t *, uint16_t, void *), void *object); + +/* Create new friend_connections instance. */ +Friend_Connections *new_friend_connections(Onion_Client *onion_c, bool local_discovery_enabled); + +/* main friend_connections loop. */ +void do_friend_connections(Friend_Connections *fr_c, void *userdata); + +/* Free everything related with friend_connections. */ +void kill_friend_connections(Friend_Connections *fr_c); + +#endif diff --git a/protocols/Tox/libtox/src/toxcore/friend_requests.c b/protocols/Tox/libtox/src/toxcore/friend_requests.c new file mode 100644 index 0000000000..ba782e2b01 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/friend_requests.c @@ -0,0 +1,152 @@ +/* + * Handle friend requests. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "friend_requests.h" + +#include "util.h" + +/* Set and get the nospam variable used to prevent one type of friend request spam. */ +void set_nospam(Friend_Requests *fr, uint32_t num) +{ + fr->nospam = num; +} + +uint32_t get_nospam(const Friend_Requests *fr) +{ + return fr->nospam; +} + + +/* Set the function that will be executed when a friend request is received. */ +void callback_friendrequest(Friend_Requests *fr, void (*function)(void *, const uint8_t *, const uint8_t *, size_t, + void *), void *object) +{ + fr->handle_friendrequest = function; + fr->handle_friendrequest_isset = 1; + fr->handle_friendrequest_object = object; +} +/* Set the function used to check if a friend request should be displayed to the user or not. */ +void set_filter_function(Friend_Requests *fr, int (*function)(const uint8_t *, void *), void *userdata) +{ + fr->filter_function = function; + fr->filter_function_userdata = userdata; +} + +/* Add to list of received friend requests. */ +static void addto_receivedlist(Friend_Requests *fr, const uint8_t *real_pk) +{ + if (fr->received_requests_index >= MAX_RECEIVED_STORED) { + fr->received_requests_index = 0; + } + + id_copy(fr->received_requests[fr->received_requests_index], real_pk); + ++fr->received_requests_index; +} + +/* Check if a friend request was already received. + * + * return 0 if it did not. + * return 1 if it did. + */ +static int request_received(Friend_Requests *fr, const uint8_t *real_pk) +{ + uint32_t i; + + for (i = 0; i < MAX_RECEIVED_STORED; ++i) { + if (id_equal(fr->received_requests[i], real_pk)) { + return 1; + } + } + + return 0; +} + +/* Remove real pk from received_requests list. + * + * return 0 if it removed it successfully. + * return -1 if it didn't find it. + */ +int remove_request_received(Friend_Requests *fr, const uint8_t *real_pk) +{ + uint32_t i; + + for (i = 0; i < MAX_RECEIVED_STORED; ++i) { + if (id_equal(fr->received_requests[i], real_pk)) { + crypto_memzero(fr->received_requests[i], CRYPTO_PUBLIC_KEY_SIZE); + return 0; + } + } + + return -1; +} + + +static int friendreq_handlepacket(void *object, const uint8_t *source_pubkey, const uint8_t *packet, uint16_t length, + void *userdata) +{ + Friend_Requests *fr = (Friend_Requests *)object; + + if (length <= 1 + sizeof(fr->nospam) || length > ONION_CLIENT_MAX_DATA_SIZE) { + return 1; + } + + ++packet; + --length; + + if (fr->handle_friendrequest_isset == 0) { + return 1; + } + + if (request_received(fr, source_pubkey)) { + return 1; + } + + if (memcmp(packet, &fr->nospam, sizeof(fr->nospam)) != 0) { + return 1; + } + + if (fr->filter_function) { + if ((*fr->filter_function)(source_pubkey, fr->filter_function_userdata) != 0) { + return 1; + } + } + + addto_receivedlist(fr, source_pubkey); + + uint32_t message_len = length - sizeof(fr->nospam); + VLA(uint8_t, message, message_len + 1); + memcpy(message, packet + sizeof(fr->nospam), message_len); + message[SIZEOF_VLA(message) - 1] = 0; /* Be sure the message is null terminated. */ + + (*fr->handle_friendrequest)(fr->handle_friendrequest_object, source_pubkey, message, message_len, userdata); + return 0; +} + +void friendreq_init(Friend_Requests *fr, Friend_Connections *fr_c) +{ + set_friend_request_callback(fr_c, &friendreq_handlepacket, fr); +} diff --git a/protocols/Tox/libtox/src/toxcore/friend_requests.h b/protocols/Tox/libtox/src/toxcore/friend_requests.h new file mode 100644 index 0000000000..316e1c671f --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/friend_requests.h @@ -0,0 +1,76 @@ +/* + * Handle friend requests. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef FRIEND_REQUESTS_H +#define FRIEND_REQUESTS_H + +#include "friend_connection.h" + +#define MAX_FRIEND_REQUEST_DATA_SIZE (ONION_CLIENT_MAX_DATA_SIZE - (1 + sizeof(uint32_t))) + +typedef struct { + uint32_t nospam; + void (*handle_friendrequest)(void *, const uint8_t *, const uint8_t *, size_t, void *); + uint8_t handle_friendrequest_isset; + void *handle_friendrequest_object; + + int (*filter_function)(const uint8_t *, void *); + void *filter_function_userdata; + /* NOTE: The following is just a temporary fix for the multiple friend requests received at the same time problem. + * TODO(irungentoo): Make this better (This will most likely tie in with the way we will handle spam.) + */ + +#define MAX_RECEIVED_STORED 32 + + uint8_t received_requests[MAX_RECEIVED_STORED][CRYPTO_PUBLIC_KEY_SIZE]; + uint16_t received_requests_index; +} Friend_Requests; + +/* Set and get the nospam variable used to prevent one type of friend request spam. */ +void set_nospam(Friend_Requests *fr, uint32_t num); +uint32_t get_nospam(const Friend_Requests *fr); + +/* Remove real_pk from received_requests list. + * + * return 0 if it removed it successfully. + * return -1 if it didn't find it. + */ +int remove_request_received(Friend_Requests *fr, const uint8_t *real_pk); + +/* Set the function that will be executed when a friend request for us is received. + * Function format is function(uint8_t * public_key, uint8_t * data, size_t length, void * userdata) + */ +void callback_friendrequest(Friend_Requests *fr, void (*function)(void *, const uint8_t *, const uint8_t *, size_t, + void *), void *object); + +/* Set the function used to check if a friend request should be displayed to the user or not. + * Function format is int function(uint8_t * public_key, void * userdata) + * It must return 0 if the request is ok (anything else if it is bad.) + */ +void set_filter_function(Friend_Requests *fr, int (*function)(const uint8_t *, void *), void *userdata); + +/* Sets up friendreq packet handlers. */ +void friendreq_init(Friend_Requests *fr, Friend_Connections *fr_c); + + +#endif diff --git a/protocols/Tox/libtox/src/toxcore/group.c b/protocols/Tox/libtox/src/toxcore/group.c new file mode 100644 index 0000000000..d3f068dfce --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/group.c @@ -0,0 +1,2544 @@ +/* + * Slightly better groupchats implementation. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "group.h" + +#include "util.h" + +/* return 1 if the groupnumber is not valid. + * return 0 if the groupnumber is valid. + */ +static uint8_t groupnumber_not_valid(const Group_Chats *g_c, int groupnumber) +{ + if ((unsigned int)groupnumber >= g_c->num_chats) { + return 1; + } + + if (g_c->chats == NULL) { + return 1; + } + + if (g_c->chats[groupnumber].status == GROUPCHAT_STATUS_NONE) { + return 1; + } + + return 0; +} + + +/* Set the size of the groupchat list to num. + * + * return -1 if realloc fails. + * return 0 if it succeeds. + */ +static int realloc_groupchats(Group_Chats *g_c, uint32_t num) +{ + if (num == 0) { + free(g_c->chats); + g_c->chats = NULL; + return 0; + } + + Group_c *newgroup_chats = (Group_c *)realloc(g_c->chats, num * sizeof(Group_c)); + + if (newgroup_chats == NULL) { + return -1; + } + + g_c->chats = newgroup_chats; + return 0; +} + + +/* Create a new empty groupchat connection. + * + * return -1 on failure. + * return groupnumber on success. + */ +static int create_group_chat(Group_Chats *g_c) +{ + uint32_t i; + + for (i = 0; i < g_c->num_chats; ++i) { + if (g_c->chats[i].status == GROUPCHAT_STATUS_NONE) { + return i; + } + } + + int id = -1; + + if (realloc_groupchats(g_c, g_c->num_chats + 1) == 0) { + id = g_c->num_chats; + ++g_c->num_chats; + memset(&(g_c->chats[id]), 0, sizeof(Group_c)); + } + + return id; +} + + +/* Wipe a groupchat. + * + * return -1 on failure. + * return 0 on success. + */ +static int wipe_group_chat(Group_Chats *g_c, int groupnumber) +{ + if (groupnumber_not_valid(g_c, groupnumber)) { + return -1; + } + + uint32_t i; + crypto_memzero(&(g_c->chats[groupnumber]), sizeof(Group_c)); + + for (i = g_c->num_chats; i != 0; --i) { + if (g_c->chats[i - 1].status != GROUPCHAT_STATUS_NONE) { + break; + } + } + + if (g_c->num_chats != i) { + g_c->num_chats = i; + realloc_groupchats(g_c, g_c->num_chats); + } + + return 0; +} + +static Group_c *get_group_c(const Group_Chats *g_c, int groupnumber) +{ + if (groupnumber_not_valid(g_c, groupnumber)) { + return 0; + } + + return &g_c->chats[groupnumber]; +} + +/* + * check if peer with real_pk is in peer array. + * + * return peer index if peer is in chat. + * return -1 if peer is not in chat. + * + * TODO(irungentoo): make this more efficient. + */ + +static int peer_in_chat(const Group_c *chat, const uint8_t *real_pk) +{ + uint32_t i; + + for (i = 0; i < chat->numpeers; ++i) { + if (id_equal(chat->group[i].real_pk, real_pk)) { + return i; + } + } + + return -1; +} + +/* + * check if group with identifier is in group array. + * + * return group number if peer is in list. + * return -1 if group is not in list. + * + * TODO(irungentoo): make this more efficient and maybe use constant time comparisons? + */ +static int get_group_num(const Group_Chats *g_c, const uint8_t *identifier) +{ + uint32_t i; + + for (i = 0; i < g_c->num_chats; ++i) { + if (crypto_memcmp(g_c->chats[i].identifier, identifier, GROUP_IDENTIFIER_LENGTH) == 0) { + return i; + } + } + + return -1; +} + +/* + * check if peer with peer_number is in peer array. + * + * return peer number if peer is in chat. + * return -1 if peer is not in chat. + * + * TODO(irungentoo): make this more efficient. + */ +static int get_peer_index(Group_c *g, uint16_t peer_number) +{ + uint32_t i; + + for (i = 0; i < g->numpeers; ++i) { + if (g->group[i].peer_number == peer_number) { + return i; + } + } + + return -1; +} + + +static uint64_t calculate_comp_value(const uint8_t *pk1, const uint8_t *pk2) +{ + uint64_t cmp1 = 0, cmp2 = 0; + + unsigned int i; + + for (i = 0; i < sizeof(uint64_t); ++i) { + cmp1 = (cmp1 << 8) + (uint64_t)pk1[i]; + cmp2 = (cmp2 << 8) + (uint64_t)pk2[i]; + } + + return (cmp1 - cmp2); +} + +enum { + GROUPCHAT_CLOSEST_NONE, + GROUPCHAT_CLOSEST_ADDED, + GROUPCHAT_CLOSEST_REMOVED +}; + +static int friend_in_close(Group_c *g, int friendcon_id); +static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, int groupnumber, uint8_t closest, uint8_t lock); + +static int add_to_closest(Group_Chats *g_c, int groupnumber, const uint8_t *real_pk, const uint8_t *temp_pk) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if (public_key_cmp(g->real_pk, real_pk) == 0) { + return -1; + } + + unsigned int i; + unsigned int index = DESIRED_CLOSE_CONNECTIONS; + + for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { + if (g->closest_peers[i].entry && public_key_cmp(real_pk, g->closest_peers[i].real_pk) == 0) { + return 0; + } + } + + for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { + if (g->closest_peers[i].entry == 0) { + index = i; + break; + } + } + + if (index == DESIRED_CLOSE_CONNECTIONS) { + uint64_t comp_val = calculate_comp_value(g->real_pk, real_pk); + uint64_t comp_d = 0; + + for (i = 0; i < (DESIRED_CLOSE_CONNECTIONS / 2); ++i) { + uint64_t comp; + comp = calculate_comp_value(g->real_pk, g->closest_peers[i].real_pk); + + if (comp > comp_val && comp > comp_d) { + index = i; + comp_d = comp; + } + } + + comp_val = calculate_comp_value(real_pk, g->real_pk); + + for (i = (DESIRED_CLOSE_CONNECTIONS / 2); i < DESIRED_CLOSE_CONNECTIONS; ++i) { + uint64_t comp = calculate_comp_value(g->closest_peers[i].real_pk, g->real_pk); + + if (comp > comp_val && comp > comp_d) { + index = i; + comp_d = comp; + } + } + } + + if (index == DESIRED_CLOSE_CONNECTIONS) { + return -1; + } + + uint8_t old_real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t old_temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t old = 0; + + if (g->closest_peers[index].entry) { + memcpy(old_real_pk, g->closest_peers[index].real_pk, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(old_temp_pk, g->closest_peers[index].temp_pk, CRYPTO_PUBLIC_KEY_SIZE); + old = 1; + } + + g->closest_peers[index].entry = 1; + memcpy(g->closest_peers[index].real_pk, real_pk, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(g->closest_peers[index].temp_pk, temp_pk, CRYPTO_PUBLIC_KEY_SIZE); + + if (old) { + add_to_closest(g_c, groupnumber, old_real_pk, old_temp_pk); + } + + if (!g->changed) { + g->changed = GROUPCHAT_CLOSEST_ADDED; + } + + return 0; +} + +static unsigned int pk_in_closest_peers(Group_c *g, uint8_t *real_pk) +{ + unsigned int i; + + for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { + if (!g->closest_peers[i].entry) { + continue; + } + + if (public_key_cmp(g->closest_peers[i].real_pk, real_pk) == 0) { + return 1; + } + } + + return 0; +} + +static int send_packet_online(Friend_Connections *fr_c, int friendcon_id, uint16_t group_num, uint8_t *identifier); + +static int connect_to_closest(Group_Chats *g_c, int groupnumber, void *userdata) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if (!g->changed) { + return 0; + } + + unsigned int i; + + if (g->changed == GROUPCHAT_CLOSEST_REMOVED) { + for (i = 0; i < g->numpeers; ++i) { + add_to_closest(g_c, groupnumber, g->group[i].real_pk, g->group[i].temp_pk); + } + } + + for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { + if (g->close[i].type == GROUPCHAT_CLOSE_NONE) { + continue; + } + + if (!g->close[i].closest) { + continue; + } + + uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t dht_temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; + get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[i].number); + + if (!pk_in_closest_peers(g, real_pk)) { + g->close[i].type = GROUPCHAT_CLOSE_NONE; + kill_friend_connection(g_c->fr_c, g->close[i].number); + } + } + + for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { + if (!g->closest_peers[i].entry) { + continue; + } + + int friendcon_id = getfriend_conn_id_pk(g_c->fr_c, g->closest_peers[i].real_pk); + + uint8_t lock = 1; + + if (friendcon_id == -1) { + friendcon_id = new_friend_connection(g_c->fr_c, g->closest_peers[i].real_pk); + lock = 0; + + if (friendcon_id == -1) { + continue; + } + + set_dht_temp_pk(g_c->fr_c, friendcon_id, g->closest_peers[i].temp_pk, userdata); + } + + add_conn_to_groupchat(g_c, friendcon_id, groupnumber, 1, lock); + + if (friend_con_connected(g_c->fr_c, friendcon_id) == FRIENDCONN_STATUS_CONNECTED) { + send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->identifier); + } + } + + g->changed = GROUPCHAT_CLOSEST_NONE; + + return 0; +} + +/* Add a peer to the group chat. + * + * do_gc_callback indicates whether we want to trigger callbacks set by the client + * via the public API. This should be set to false if this function is called + * from outside of the tox_iterate() loop. + * + * return peer_index if success or peer already in chat. + * return -1 if error. + */ +static int addpeer(Group_Chats *g_c, int groupnumber, const uint8_t *real_pk, const uint8_t *temp_pk, + uint16_t peer_number, void *userdata, bool do_gc_callback) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + // TODO(irungentoo): + int peer_index = peer_in_chat(g, real_pk); + + if (peer_index != -1) { + id_copy(g->group[peer_index].temp_pk, temp_pk); + + if (g->group[peer_index].peer_number != peer_number) { + return -1; + } + + return peer_index; + } + + peer_index = get_peer_index(g, peer_number); + + if (peer_index != -1) { + return -1; + } + + Group_Peer *temp = (Group_Peer *)realloc(g->group, sizeof(Group_Peer) * (g->numpeers + 1)); + + if (temp == NULL) { + return -1; + } + + memset(&(temp[g->numpeers]), 0, sizeof(Group_Peer)); + g->group = temp; + + id_copy(g->group[g->numpeers].real_pk, real_pk); + id_copy(g->group[g->numpeers].temp_pk, temp_pk); + g->group[g->numpeers].peer_number = peer_number; + + g->group[g->numpeers].last_recv = unix_time(); + ++g->numpeers; + + add_to_closest(g_c, groupnumber, real_pk, temp_pk); + + if (do_gc_callback && g_c->group_namelistchange) { + g_c->group_namelistchange(g_c->m, groupnumber, g->numpeers - 1, CHAT_CHANGE_PEER_ADD, userdata); + } + + if (g->peer_on_join) { + g->peer_on_join(g->object, groupnumber, g->numpeers - 1); + } + + return (g->numpeers - 1); +} + +static int remove_close_conn(Group_Chats *g_c, int groupnumber, int friendcon_id) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + uint32_t i; + + for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { + if (g->close[i].type == GROUPCHAT_CLOSE_NONE) { + continue; + } + + if (g->close[i].number == (unsigned int)friendcon_id) { + g->close[i].type = GROUPCHAT_CLOSE_NONE; + kill_friend_connection(g_c->fr_c, friendcon_id); + return 0; + } + } + + return -1; +} + + +/* + * Delete a peer from the group chat. + * + * return 0 if success + * return -1 if error. + */ +static int delpeer(Group_Chats *g_c, int groupnumber, int peer_index, void *userdata) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + uint32_t i; + + for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { /* If peer is in closest_peers list, remove it. */ + if (g->closest_peers[i].entry && id_equal(g->closest_peers[i].real_pk, g->group[peer_index].real_pk)) { + g->closest_peers[i].entry = 0; + g->changed = GROUPCHAT_CLOSEST_REMOVED; + break; + } + } + + int friendcon_id = getfriend_conn_id_pk(g_c->fr_c, g->group[peer_index].real_pk); + + if (friendcon_id != -1) { + remove_close_conn(g_c, groupnumber, friendcon_id); + } + + --g->numpeers; + + void *peer_object = g->group[peer_index].object; + + if (g->numpeers == 0) { + free(g->group); + g->group = NULL; + } else { + if (g->numpeers != (uint32_t)peer_index) { + memcpy(&g->group[peer_index], &g->group[g->numpeers], sizeof(Group_Peer)); + } + + Group_Peer *temp = (Group_Peer *)realloc(g->group, sizeof(Group_Peer) * (g->numpeers)); + + if (temp == NULL) { + return -1; + } + + g->group = temp; + } + + if (g_c->group_namelistchange) { + g_c->group_namelistchange(g_c->m, groupnumber, peer_index, CHAT_CHANGE_PEER_DEL, userdata); + } + + if (g->peer_on_leave) { + g->peer_on_leave(g->object, groupnumber, peer_index, peer_object); + } + + return 0; +} + +/* Set the nick for a peer. + * + * do_gc_callback indicates whether we want to trigger callbacks set by the client + * via the public API. This should be set to false if this function is called + * from outside of the tox_iterate() loop. + * + * return 0 on success. + * return -1 if error. + */ +static int setnick(Group_Chats *g_c, int groupnumber, int peer_index, const uint8_t *nick, uint16_t nick_len, + void *userdata, bool do_gc_callback) +{ + if (nick_len > MAX_NAME_LENGTH) { + return -1; + } + + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + /* same name as already stored? */ + if (g->group[peer_index].nick_len == nick_len) { + if (nick_len == 0 || !memcmp(g->group[peer_index].nick, nick, nick_len)) { + return 0; + } + } + + if (nick_len) { + memcpy(g->group[peer_index].nick, nick, nick_len); + } + + g->group[peer_index].nick_len = nick_len; + + if (do_gc_callback && g_c->group_namelistchange) { + g_c->group_namelistchange(g_c->m, groupnumber, peer_index, CHAT_CHANGE_PEER_NAME, userdata); + } + + return 0; +} + +static int settitle(Group_Chats *g_c, int groupnumber, int peer_index, const uint8_t *title, uint8_t title_len, + void *userdata) +{ + if (title_len > MAX_NAME_LENGTH || title_len == 0) { + return -1; + } + + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + /* same as already set? */ + if (g->title_len == title_len && !memcmp(g->title, title, title_len)) { + return 0; + } + + memcpy(g->title, title, title_len); + g->title_len = title_len; + + if (g_c->title_callback) { + g_c->title_callback(g_c->m, groupnumber, peer_index, title, title_len, userdata); + } + + return 0; +} + +static void set_conns_type_close(Group_Chats *g_c, int groupnumber, int friendcon_id, uint8_t type) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return; + } + + uint32_t i; + + for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { + if (g->close[i].type == GROUPCHAT_CLOSE_NONE) { + continue; + } + + if (g->close[i].number != (unsigned int)friendcon_id) { + continue; + } + + if (type == GROUPCHAT_CLOSE_ONLINE) { + send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->identifier); + } else { + g->close[i].type = type; + } + } +} +/* Set the type for all close connections with friendcon_id */ +static void set_conns_status_groups(Group_Chats *g_c, int friendcon_id, uint8_t type) +{ + uint32_t i; + + for (i = 0; i < g_c->num_chats; ++i) { + set_conns_type_close(g_c, i, friendcon_id, type); + } +} + +static int g_handle_status(void *object, int friendcon_id, uint8_t status, void *userdata) +{ + Group_Chats *g_c = (Group_Chats *)object; + + if (status) { /* Went online */ + set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_ONLINE); + } else { /* Went offline */ + set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_CONNECTION); + // TODO(irungentoo): remove timedout connections? + } + + return 0; +} + +static int g_handle_packet(void *object, int friendcon_id, const uint8_t *data, uint16_t length, void *userdata); +static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uint16_t length, void *userdata); + +/* Add friend to group chat. + * + * return close index on success + * return -1 on failure. + */ +static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, int groupnumber, uint8_t closest, uint8_t lock) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + uint16_t i, ind = MAX_GROUP_CONNECTIONS; + + for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { + if (g->close[i].type == GROUPCHAT_CLOSE_NONE) { + ind = i; + continue; + } + + if (g->close[i].number == (uint32_t)friendcon_id) { + g->close[i].closest = closest; + return i; /* Already in list. */ + } + } + + if (ind == MAX_GROUP_CONNECTIONS) { + return -1; + } + + if (lock) { + friend_connection_lock(g_c->fr_c, friendcon_id); + } + + g->close[ind].type = GROUPCHAT_CLOSE_CONNECTION; + g->close[ind].number = friendcon_id; + g->close[ind].closest = closest; + // TODO(irungentoo): + friend_connection_callbacks(g_c->m->fr_c, friendcon_id, GROUPCHAT_CALLBACK_INDEX, &g_handle_status, &g_handle_packet, + &handle_lossy, g_c, friendcon_id); + + return ind; +} + +/* Creates a new groupchat and puts it in the chats array. + * + * type is one of GROUPCHAT_TYPE_* + * + * return group number on success. + * return -1 on failure. + */ +int add_groupchat(Group_Chats *g_c, uint8_t type) +{ + int groupnumber = create_group_chat(g_c); + + if (groupnumber == -1) { + return -1; + } + + Group_c *g = &g_c->chats[groupnumber]; + + g->status = GROUPCHAT_STATUS_CONNECTED; + g->number_joined = -1; + new_symmetric_key(g->identifier + 1); + g->identifier[0] = type; + g->peer_number = 0; /* Founder is peer 0. */ + memcpy(g->real_pk, g_c->m->net_crypto->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + int peer_index = addpeer(g_c, groupnumber, g->real_pk, g_c->m->dht->self_public_key, 0, NULL, false); + + if (peer_index == -1) { + return -1; + } + + setnick(g_c, groupnumber, peer_index, g_c->m->name, g_c->m->name_length, NULL, false); + + return groupnumber; +} + +static int group_kill_peer_send(const Group_Chats *g_c, int groupnumber, uint16_t peer_num); +/* Delete a groupchat from the chats array. + * + * return 0 on success. + * return -1 if groupnumber is invalid. + */ +int del_groupchat(Group_Chats *g_c, int groupnumber) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + group_kill_peer_send(g_c, groupnumber, g->peer_number); + + unsigned int i; + + for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { + if (g->close[i].type == GROUPCHAT_CLOSE_NONE) { + continue; + } + + g->close[i].type = GROUPCHAT_CLOSE_NONE; + kill_friend_connection(g_c->fr_c, g->close[i].number); + } + + for (i = 0; i < g->numpeers; ++i) { + if (g->peer_on_leave) { + g->peer_on_leave(g->object, groupnumber, i, g->group[i].object); + } + } + + free(g->group); + + if (g->group_on_delete) { + g->group_on_delete(g->object, groupnumber); + } + + return wipe_group_chat(g_c, groupnumber); +} + +/* Copy the public key of peernumber who is in groupnumber to pk. + * pk must be CRYPTO_PUBLIC_KEY_SIZE long. + * + * return 0 on success + * return -1 if groupnumber is invalid. + * return -2 if peernumber is invalid. + */ +int group_peer_pubkey(const Group_Chats *g_c, int groupnumber, int peernumber, uint8_t *pk) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if ((uint32_t)peernumber >= g->numpeers) { + return -2; + } + + memcpy(pk, g->group[peernumber].real_pk, CRYPTO_PUBLIC_KEY_SIZE); + return 0; +} + +/* + * Return the size of peernumber's name. + * + * return -1 if groupnumber is invalid. + * return -2 if peernumber is invalid. + */ +int group_peername_size(const Group_Chats *g_c, int groupnumber, int peernumber) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if ((uint32_t)peernumber >= g->numpeers) { + return -2; + } + + if (g->group[peernumber].nick_len == 0) { + return 8; + } + + return g->group[peernumber].nick_len; +} + +/* Copy the name of peernumber who is in groupnumber to name. + * name must be at least MAX_NAME_LENGTH long. + * + * return length of name if success + * return -1 if groupnumber is invalid. + * return -2 if peernumber is invalid. + */ +int group_peername(const Group_Chats *g_c, int groupnumber, int peernumber, uint8_t *name) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if ((uint32_t)peernumber >= g->numpeers) { + return -2; + } + + if (g->group[peernumber].nick_len == 0) { + memcpy(name, "Tox User", 8); + return 8; + } + + memcpy(name, g->group[peernumber].nick, g->group[peernumber].nick_len); + return g->group[peernumber].nick_len; +} + +/* List all the peers in the group chat. + * + * Copies the names of the peers to the name[length][MAX_NAME_LENGTH] array. + * + * Copies the lengths of the names to lengths[length] + * + * returns the number of peers on success. + * + * return -1 on failure. + */ +int group_names(const Group_Chats *g_c, int groupnumber, uint8_t names[][MAX_NAME_LENGTH], uint16_t lengths[], + uint16_t length) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + unsigned int i; + + for (i = 0; i < g->numpeers && i < length; ++i) { + lengths[i] = group_peername(g_c, groupnumber, i, names[i]); + } + + return i; +} + +/* Return the number of peers in the group chat on success. + * return -1 if groupnumber is invalid. + */ +int group_number_peers(const Group_Chats *g_c, int groupnumber) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + return g->numpeers; +} + +/* return 1 if the peernumber corresponds to ours. + * return 0 if the peernumber is not ours. + * return -1 if groupnumber is invalid. + * return -2 if peernumber is invalid. + * return -3 if we are not connected to the group chat. + */ +int group_peernumber_is_ours(const Group_Chats *g_c, int groupnumber, int peernumber) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if ((uint32_t)peernumber >= g->numpeers) { + return -2; + } + + if (g->status != GROUPCHAT_STATUS_CONNECTED) { + return -3; + } + + return g->peer_number == g->group[peernumber].peer_number; +} + +/* return the type of groupchat (GROUPCHAT_TYPE_) that groupnumber is. + * + * return -1 on failure. + * return type on success. + */ +int group_get_type(const Group_Chats *g_c, int groupnumber) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + return g->identifier[0]; +} + +/* Send a group packet to friendcon_id. + * + * return 1 on success + * return 0 on failure + */ +static unsigned int send_packet_group_peer(Friend_Connections *fr_c, int friendcon_id, uint8_t packet_id, + uint16_t group_num, const uint8_t *data, uint16_t length) +{ + if (1 + sizeof(uint16_t) + length > MAX_CRYPTO_DATA_SIZE) { + return 0; + } + + group_num = net_htons(group_num); + VLA(uint8_t, packet, 1 + sizeof(uint16_t) + length); + packet[0] = packet_id; + memcpy(packet + 1, &group_num, sizeof(uint16_t)); + memcpy(packet + 1 + sizeof(uint16_t), data, length); + return write_cryptpacket(fr_c->net_crypto, friend_connection_crypt_connection_id(fr_c, friendcon_id), packet, + SIZEOF_VLA(packet), 0) != -1; +} + +/* Send a group lossy packet to friendcon_id. + * + * return 1 on success + * return 0 on failure + */ +static unsigned int send_lossy_group_peer(Friend_Connections *fr_c, int friendcon_id, uint8_t packet_id, + uint16_t group_num, const uint8_t *data, uint16_t length) +{ + if (1 + sizeof(uint16_t) + length > MAX_CRYPTO_DATA_SIZE) { + return 0; + } + + group_num = net_htons(group_num); + VLA(uint8_t, packet, 1 + sizeof(uint16_t) + length); + packet[0] = packet_id; + memcpy(packet + 1, &group_num, sizeof(uint16_t)); + memcpy(packet + 1 + sizeof(uint16_t), data, length); + return send_lossy_cryptpacket(fr_c->net_crypto, friend_connection_crypt_connection_id(fr_c, friendcon_id), packet, + SIZEOF_VLA(packet)) != -1; +} + +#define INVITE_PACKET_SIZE (1 + sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH) +#define INVITE_ID 0 + +#define INVITE_RESPONSE_PACKET_SIZE (1 + sizeof(uint16_t) * 2 + GROUP_IDENTIFIER_LENGTH) +#define INVITE_RESPONSE_ID 1 + +/* invite friendnumber to groupnumber. + * + * return 0 on success. + * return -1 if groupnumber is invalid. + * return -2 if invite packet failed to send. + */ +int invite_friend(Group_Chats *g_c, int32_t friendnumber, int groupnumber) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + uint8_t invite[INVITE_PACKET_SIZE]; + invite[0] = INVITE_ID; + uint16_t groupchat_num = net_htons((uint16_t)groupnumber); + memcpy(invite + 1, &groupchat_num, sizeof(groupchat_num)); + memcpy(invite + 1 + sizeof(groupchat_num), g->identifier, GROUP_IDENTIFIER_LENGTH); + + if (send_conference_invite_packet(g_c->m, friendnumber, invite, sizeof(invite))) { + return 0; + } + + wipe_group_chat(g_c, groupnumber); + return -2; +} + +static unsigned int send_peer_query(Group_Chats *g_c, int friendcon_id, uint16_t group_num); + +/* Join a group (you need to have been invited first.) + * + * expected_type is the groupchat type we expect the chat we are joining is. + * + * return group number on success. + * return -1 if data length is invalid. + * return -2 if group is not the expected type. + * return -3 if friendnumber is invalid. + * return -4 if client is already in this group. + * return -5 if group instance failed to initialize. + * return -6 if join packet fails to send. + */ +int join_groupchat(Group_Chats *g_c, int32_t friendnumber, uint8_t expected_type, const uint8_t *data, uint16_t length) +{ + if (length != sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH) { + return -1; + } + + if (data[sizeof(uint16_t)] != expected_type) { + return -2; + } + + int friendcon_id = getfriendcon_id(g_c->m, friendnumber); + + if (friendcon_id == -1) { + return -3; + } + + if (get_group_num(g_c, data + sizeof(uint16_t)) != -1) { + return -4; + } + + int groupnumber = create_group_chat(g_c); + + if (groupnumber == -1) { + return -5; + } + + Group_c *g = &g_c->chats[groupnumber]; + + uint16_t group_num = net_htons(groupnumber); + g->status = GROUPCHAT_STATUS_VALID; + g->number_joined = -1; + memcpy(g->real_pk, g_c->m->net_crypto->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + + uint8_t response[INVITE_RESPONSE_PACKET_SIZE]; + response[0] = INVITE_RESPONSE_ID; + memcpy(response + 1, &group_num, sizeof(uint16_t)); + memcpy(response + 1 + sizeof(uint16_t), data, sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH); + + if (send_conference_invite_packet(g_c->m, friendnumber, response, sizeof(response))) { + uint16_t other_groupnum; + memcpy(&other_groupnum, data, sizeof(other_groupnum)); + other_groupnum = net_ntohs(other_groupnum); + memcpy(g->identifier, data + sizeof(uint16_t), GROUP_IDENTIFIER_LENGTH); + int close_index = add_conn_to_groupchat(g_c, friendcon_id, groupnumber, 0, 1); + + if (close_index != -1) { + g->close[close_index].group_number = other_groupnum; + g->close[close_index].type = GROUPCHAT_CLOSE_ONLINE; + g->number_joined = friendcon_id; + } + + send_peer_query(g_c, friendcon_id, other_groupnum); + return groupnumber; + } + + g->status = GROUPCHAT_STATUS_NONE; + return -6; +} + +/* Set handlers for custom lossy packets. + * + * NOTE: Handler must return 0 if packet is to be relayed, -1 if the packet should not be relayed. + * + * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber, void *group peer object (set with group_peer_set_object), const uint8_t *packet, uint16_t length) + */ +void group_lossy_packet_registerhandler(Group_Chats *g_c, uint8_t byte, int (*function)(void *, int, int, void *, + const uint8_t *, uint16_t)) +{ + g_c->lossy_packethandlers[byte].function = function; +} + +/* Set the callback for group invites. + * + * Function(Group_Chats *g_c, int32_t friendnumber, uint8_t type, uint8_t *data, uint16_t length, void *userdata) + * + * data of length is what needs to be passed to join_groupchat(). + */ +void g_callback_group_invite(Group_Chats *g_c, void (*function)(Messenger *m, uint32_t, int, const uint8_t *, + size_t, void *)) +{ + g_c->invite_callback = function; +} + +/* Set the callback for group messages. + * + * Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) + */ +void g_callback_group_message(Group_Chats *g_c, void (*function)(Messenger *m, uint32_t, uint32_t, int, const uint8_t *, + size_t, void *)) +{ + g_c->message_callback = function; +} + +/* Set callback function for peer name list changes. + * + * It gets called every time the name list changes(new peer/name, deleted peer) + * Function(Group_Chats *g_c, int groupnumber, int peernumber, TOX_CHAT_CHANGE change, void *userdata) + */ +void g_callback_group_namelistchange(Group_Chats *g_c, void (*function)(Messenger *m, int, int, uint8_t, void *)) +{ + g_c->group_namelistchange = function; +} + +/* Set callback function for title changes. + * + * Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * title, uint8_t length, void *userdata) + * if friendgroupnumber == -1, then author is unknown (e.g. initial joining the group) + */ +void g_callback_group_title(Group_Chats *g_c, void (*function)(Messenger *m, uint32_t, uint32_t, const uint8_t *, + size_t, void *)) +{ + g_c->title_callback = function; +} + +/* Set a function to be called when a new peer joins a group chat. + * + * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber) + * + * return 0 on success. + * return -1 on failure. + */ +int callback_groupchat_peer_new(const Group_Chats *g_c, int groupnumber, void (*function)(void *, int, int)) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + g->peer_on_join = function; + return 0; +} + +/* Set a function to be called when a peer leaves a group chat. + * + * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber, void *group peer object (set with group_peer_set_object)) + * + * return 0 on success. + * return -1 on failure. + */ +int callback_groupchat_peer_delete(Group_Chats *g_c, int groupnumber, void (*function)(void *, int, int, void *)) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + g->peer_on_leave = function; + return 0; +} + +/* Set a function to be called when the group chat is deleted. + * + * Function(void *group object (set with group_set_object), int groupnumber) + * + * return 0 on success. + * return -1 on failure. + */ +int callback_groupchat_delete(Group_Chats *g_c, int groupnumber, void (*function)(void *, int)) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + g->group_on_delete = function; + return 0; +} + +static int send_message_group(const Group_Chats *g_c, int groupnumber, uint8_t message_id, const uint8_t *data, + uint16_t len); + +#define GROUP_MESSAGE_PING_ID 0 +static int group_ping_send(const Group_Chats *g_c, int groupnumber) +{ + if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_PING_ID, 0, 0) > 0) { + return 0; + } + + return -1; +} + +#define GROUP_MESSAGE_NEW_PEER_ID 16 +#define GROUP_MESSAGE_NEW_PEER_LENGTH (sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE * 2) +/* send a new_peer message + * return 0 on success + * return -1 on failure + */ +static int group_new_peer_send(const Group_Chats *g_c, int groupnumber, uint16_t peer_num, const uint8_t *real_pk, + uint8_t *temp_pk) +{ + uint8_t packet[GROUP_MESSAGE_NEW_PEER_LENGTH]; + + peer_num = net_htons(peer_num); + memcpy(packet, &peer_num, sizeof(uint16_t)); + memcpy(packet + sizeof(uint16_t), real_pk, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(packet + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE, temp_pk, CRYPTO_PUBLIC_KEY_SIZE); + + if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_NEW_PEER_ID, packet, sizeof(packet)) > 0) { + return 0; + } + + return -1; +} + +#define GROUP_MESSAGE_KILL_PEER_ID 17 +#define GROUP_MESSAGE_KILL_PEER_LENGTH (sizeof(uint16_t)) + +/* send a kill_peer message + * return 0 on success + * return -1 on failure + */ +static int group_kill_peer_send(const Group_Chats *g_c, int groupnumber, uint16_t peer_num) +{ + uint8_t packet[GROUP_MESSAGE_KILL_PEER_LENGTH]; + + peer_num = net_htons(peer_num); + memcpy(packet, &peer_num, sizeof(uint16_t)); + + if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_KILL_PEER_ID, packet, sizeof(packet)) > 0) { + return 0; + } + + return -1; +} + +#define GROUP_MESSAGE_NAME_ID 48 + +/* send a name message + * return 0 on success + * return -1 on failure + */ +static int group_name_send(const Group_Chats *g_c, int groupnumber, const uint8_t *nick, uint16_t nick_len) +{ + if (nick_len > MAX_NAME_LENGTH) { + return -1; + } + + if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_NAME_ID, nick, nick_len) > 0) { + return 0; + } + + return -1; +} + +#define GROUP_MESSAGE_TITLE_ID 49 + +/* set the group's title, limited to MAX_NAME_LENGTH + * return 0 on success + * return -1 if groupnumber is invalid. + * return -2 if title is too long or empty. + * return -3 if packet fails to send. + */ +int group_title_send(const Group_Chats *g_c, int groupnumber, const uint8_t *title, uint8_t title_len) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if (title_len > MAX_NAME_LENGTH || title_len == 0) { + return -2; + } + + /* same as already set? */ + if (g->title_len == title_len && !memcmp(g->title, title, title_len)) { + return 0; + } + + memcpy(g->title, title, title_len); + g->title_len = title_len; + + if (g->numpeers == 1) { + return 0; + } + + if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_TITLE_ID, title, title_len) > 0) { + return 0; + } + + return -3; +} + +/* return the group's title size. + * return -1 of groupnumber is invalid. + * return -2 if title is too long or empty. + */ +int group_title_get_size(const Group_Chats *g_c, int groupnumber) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if (g->title_len == 0 || g->title_len > MAX_NAME_LENGTH) { + return -2; + } + + return g->title_len; +} + +/* Get group title from groupnumber and put it in title. + * Title needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes. + * + * return length of copied title if success. + * return -1 if groupnumber is invalid. + * return -2 if title is too long or empty. + */ +int group_title_get(const Group_Chats *g_c, int groupnumber, uint8_t *title) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if (g->title_len == 0 || g->title_len > MAX_NAME_LENGTH) { + return -2; + } + + memcpy(title, g->title, g->title_len); + return g->title_len; +} + +static void handle_friend_invite_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, + void *userdata) +{ + Group_Chats *g_c = (Group_Chats *)m->conferences_object; + + if (length <= 1) { + return; + } + + const uint8_t *invite_data = data + 1; + uint16_t invite_length = length - 1; + + switch (data[0]) { + case INVITE_ID: { + if (length != INVITE_PACKET_SIZE) { + return; + } + + int groupnumber = get_group_num(g_c, data + 1 + sizeof(uint16_t)); + + if (groupnumber == -1) { + if (g_c->invite_callback) { + g_c->invite_callback(m, friendnumber, *(invite_data + sizeof(uint16_t)), invite_data, invite_length, userdata); + } + + return; + } + + break; + } + + case INVITE_RESPONSE_ID: { + if (length != INVITE_RESPONSE_PACKET_SIZE) { + return; + } + + uint16_t other_groupnum, groupnum; + memcpy(&groupnum, data + 1 + sizeof(uint16_t), sizeof(uint16_t)); + groupnum = net_ntohs(groupnum); + + Group_c *g = get_group_c(g_c, groupnum); + + if (!g) { + return; + } + + if (crypto_memcmp(data + 1 + sizeof(uint16_t) * 2, g->identifier, GROUP_IDENTIFIER_LENGTH) != 0) { + return; + } + + /* TODO(irungentoo): what if two people enter the group at the same time and + are given the same peer_number by different nodes? */ + uint16_t peer_number = rand(); + + unsigned int tries = 0; + + while (get_peer_index(g, peer_number) != -1) { + peer_number = rand(); + ++tries; + + if (tries > 32) { + return; + } + } + + memcpy(&other_groupnum, data + 1, sizeof(uint16_t)); + other_groupnum = net_ntohs(other_groupnum); + + int friendcon_id = getfriendcon_id(m, friendnumber); + uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE], temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; + get_friendcon_public_keys(real_pk, temp_pk, g_c->fr_c, friendcon_id); + + addpeer(g_c, groupnum, real_pk, temp_pk, peer_number, userdata, true); + int close_index = add_conn_to_groupchat(g_c, friendcon_id, groupnum, 0, 1); + + if (close_index != -1) { + g->close[close_index].group_number = other_groupnum; + g->close[close_index].type = GROUPCHAT_CLOSE_ONLINE; + } + + group_new_peer_send(g_c, groupnum, peer_number, real_pk, temp_pk); + break; + } + + default: + return; + } +} + +/* Find index of friend in the close list; + * + * returns index on success + * returns -1 on failure. + */ +static int friend_in_close(Group_c *g, int friendcon_id) +{ + unsigned int i; + + for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { + if (g->close[i].type == GROUPCHAT_CLOSE_NONE) { + continue; + } + + if (g->close[i].number != (uint32_t)friendcon_id) { + continue; + } + + return i; + } + + return -1; +} + +/* return number of connected close connections. + */ +static unsigned int count_close_connected(Group_c *g) +{ + unsigned int i, count = 0; + + for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { + if (g->close[i].type == GROUPCHAT_CLOSE_ONLINE) { + ++count; + } + } + + return count; +} + +#define ONLINE_PACKET_DATA_SIZE (sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH) + +static int send_packet_online(Friend_Connections *fr_c, int friendcon_id, uint16_t group_num, uint8_t *identifier) +{ + uint8_t packet[1 + ONLINE_PACKET_DATA_SIZE]; + group_num = net_htons(group_num); + packet[0] = PACKET_ID_ONLINE_PACKET; + memcpy(packet + 1, &group_num, sizeof(uint16_t)); + memcpy(packet + 1 + sizeof(uint16_t), identifier, GROUP_IDENTIFIER_LENGTH); + return write_cryptpacket(fr_c->net_crypto, friend_connection_crypt_connection_id(fr_c, friendcon_id), packet, + sizeof(packet), 0) != -1; +} + +static unsigned int send_peer_kill(Group_Chats *g_c, int friendcon_id, uint16_t group_num); + +static int handle_packet_online(Group_Chats *g_c, int friendcon_id, const uint8_t *data, uint16_t length) +{ + if (length != ONLINE_PACKET_DATA_SIZE) { + return -1; + } + + int groupnumber = get_group_num(g_c, data + sizeof(uint16_t)); + uint16_t other_groupnum; + memcpy(&other_groupnum, data, sizeof(uint16_t)); + other_groupnum = net_ntohs(other_groupnum); + + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + int index = friend_in_close(g, friendcon_id); + + if (index == -1) { + return -1; + } + + if (g->close[index].type == GROUPCHAT_CLOSE_ONLINE) { + return -1; + } + + if (count_close_connected(g) == 0) { + send_peer_query(g_c, friendcon_id, other_groupnum); + } + + g->close[index].group_number = other_groupnum; + g->close[index].type = GROUPCHAT_CLOSE_ONLINE; + send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->identifier); + + if (g->number_joined != -1 && count_close_connected(g) >= DESIRED_CLOSE_CONNECTIONS) { + int fr_close_index = friend_in_close(g, g->number_joined); + + if (fr_close_index == -1) { + return -1; + } + + if (!g->close[fr_close_index].closest) { + g->close[fr_close_index].type = GROUPCHAT_CLOSE_NONE; + send_peer_kill(g_c, g->close[fr_close_index].number, g->close[fr_close_index].group_number); + kill_friend_connection(g_c->fr_c, g->close[fr_close_index].number); + g->number_joined = -1; + } + } + + return 0; +} + +#define PEER_KILL_ID 1 +#define PEER_QUERY_ID 8 +#define PEER_RESPONSE_ID 9 +#define PEER_TITLE_ID 10 +// we could send title with invite, but then if it changes between sending and accepting inv, joinee won't see it + +/* return 1 on success. + * return 0 on failure + */ +static unsigned int send_peer_kill(Group_Chats *g_c, int friendcon_id, uint16_t group_num) +{ + uint8_t packet[1]; + packet[0] = PEER_KILL_ID; + return send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_CONFERENCE, group_num, packet, sizeof(packet)); +} + + +/* return 1 on success. + * return 0 on failure + */ +static unsigned int send_peer_query(Group_Chats *g_c, int friendcon_id, uint16_t group_num) +{ + uint8_t packet[1]; + packet[0] = PEER_QUERY_ID; + return send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_CONFERENCE, group_num, packet, sizeof(packet)); +} + +/* return number of peers sent on success. + * return 0 on failure. + */ +static unsigned int send_peers(Group_Chats *g_c, int groupnumber, int friendcon_id, uint16_t group_num) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + uint8_t packet[MAX_CRYPTO_DATA_SIZE - (1 + sizeof(uint16_t))]; + packet[0] = PEER_RESPONSE_ID; + uint8_t *p = packet + 1; + + uint16_t sent = 0; + unsigned int i; + + for (i = 0; i < g->numpeers; ++i) { + if ((p - packet) + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE * 2 + 1 + g->group[i].nick_len > sizeof(packet)) { + if (send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_CONFERENCE, group_num, packet, (p - packet))) { + sent = i; + } else { + return sent; + } + + p = packet + 1; + } + + uint16_t peer_num = net_htons(g->group[i].peer_number); + memcpy(p, &peer_num, sizeof(peer_num)); + p += sizeof(peer_num); + memcpy(p, g->group[i].real_pk, CRYPTO_PUBLIC_KEY_SIZE); + p += CRYPTO_PUBLIC_KEY_SIZE; + memcpy(p, g->group[i].temp_pk, CRYPTO_PUBLIC_KEY_SIZE); + p += CRYPTO_PUBLIC_KEY_SIZE; + *p = g->group[i].nick_len; + p += 1; + memcpy(p, g->group[i].nick, g->group[i].nick_len); + p += g->group[i].nick_len; + } + + if (sent != i) { + if (send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_CONFERENCE, group_num, packet, (p - packet))) { + sent = i; + } + } + + if (g->title_len) { + VLA(uint8_t, Packet, 1 + g->title_len); + Packet[0] = PEER_TITLE_ID; + memcpy(Packet + 1, g->title, g->title_len); + send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_CONFERENCE, group_num, Packet, SIZEOF_VLA(Packet)); + } + + return sent; +} + +static int handle_send_peers(Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length, void *userdata) +{ + if (length == 0) { + return -1; + } + + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + const uint8_t *d = data; + + while ((unsigned int)(length - (d - data)) >= sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE * 2 + 1) { + uint16_t peer_num; + memcpy(&peer_num, d, sizeof(peer_num)); + peer_num = net_ntohs(peer_num); + d += sizeof(uint16_t); + int peer_index = addpeer(g_c, groupnumber, d, d + CRYPTO_PUBLIC_KEY_SIZE, peer_num, userdata, true); + + if (peer_index == -1) { + return -1; + } + + if (g->status == GROUPCHAT_STATUS_VALID + && public_key_cmp(d, g_c->m->net_crypto->self_public_key) == 0) { + g->peer_number = peer_num; + g->status = GROUPCHAT_STATUS_CONNECTED; + group_name_send(g_c, groupnumber, g_c->m->name, g_c->m->name_length); + } + + d += CRYPTO_PUBLIC_KEY_SIZE * 2; + uint8_t name_length = *d; + d += 1; + + if (name_length > (length - (d - data)) || name_length > MAX_NAME_LENGTH) { + return -1; + } + + setnick(g_c, groupnumber, peer_index, d, name_length, userdata, true); + d += name_length; + } + + return 0; +} + +static void handle_direct_packet(Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length, + int close_index, void *userdata) +{ + if (length == 0) { + return; + } + + switch (data[0]) { + case PEER_KILL_ID: { + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return; + } + + if (!g->close[close_index].closest) { + g->close[close_index].type = GROUPCHAT_CLOSE_NONE; + kill_friend_connection(g_c->fr_c, g->close[close_index].number); + } + } + + break; + + case PEER_QUERY_ID: { + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return; + } + + send_peers(g_c, groupnumber, g->close[close_index].number, g->close[close_index].group_number); + } + + break; + + case PEER_RESPONSE_ID: { + handle_send_peers(g_c, groupnumber, data + 1, length - 1, userdata); + } + + break; + + case PEER_TITLE_ID: { + settitle(g_c, groupnumber, -1, data + 1, length - 1, userdata); + } + + break; + } +} + +#define MIN_MESSAGE_PACKET_LEN (sizeof(uint16_t) * 2 + sizeof(uint32_t) + 1) + +/* Send message to all close except receiver (if receiver isn't -1) + * NOTE: this function appends the group chat number to the data passed to it. + * + * return number of messages sent. + */ +static unsigned int send_message_all_close(const Group_Chats *g_c, int groupnumber, const uint8_t *data, + uint16_t length, int receiver) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return 0; + } + + uint16_t i, sent = 0; + + for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { + if (g->close[i].type != GROUPCHAT_CLOSE_ONLINE) { + continue; + } + + if ((int)i == receiver) { + continue; + } + + if (send_packet_group_peer(g_c->fr_c, g->close[i].number, PACKET_ID_MESSAGE_CONFERENCE, g->close[i].group_number, data, + length)) { + ++sent; + } + } + + return sent; +} + +/* Send lossy message to all close except receiver (if receiver isn't -1) + * NOTE: this function appends the group chat number to the data passed to it. + * + * return number of messages sent. + */ +static unsigned int send_lossy_all_close(const Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length, + int receiver) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return 0; + } + + unsigned int i, sent = 0, num_connected_closest = 0, connected_closest[DESIRED_CLOSE_CONNECTIONS]; + + for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { + if (g->close[i].type != GROUPCHAT_CLOSE_ONLINE) { + continue; + } + + if ((int)i == receiver) { + continue; + } + + if (g->close[i].closest) { + connected_closest[num_connected_closest] = i; + ++num_connected_closest; + continue; + } + + if (send_lossy_group_peer(g_c->fr_c, g->close[i].number, PACKET_ID_LOSSY_CONFERENCE, g->close[i].group_number, data, + length)) { + ++sent; + } + } + + if (!num_connected_closest) { + return sent; + } + + unsigned int to_send = 0; + uint64_t comp_val_old = ~0; + + for (i = 0; i < num_connected_closest; ++i) { + uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t dht_temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; + get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[connected_closest[i]].number); + uint64_t comp_val = calculate_comp_value(g->real_pk, real_pk); + + if (comp_val < comp_val_old) { + to_send = connected_closest[i]; + comp_val_old = comp_val; + } + } + + if (send_lossy_group_peer(g_c->fr_c, g->close[to_send].number, PACKET_ID_LOSSY_CONFERENCE, + g->close[to_send].group_number, data, length)) { + ++sent; + } + + unsigned int to_send_other = 0; + comp_val_old = ~0; + + for (i = 0; i < num_connected_closest; ++i) { + uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t dht_temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; + get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[connected_closest[i]].number); + uint64_t comp_val = calculate_comp_value(real_pk, g->real_pk); + + if (comp_val < comp_val_old) { + to_send_other = connected_closest[i]; + comp_val_old = comp_val; + } + } + + if (to_send_other == to_send) { + return sent; + } + + if (send_lossy_group_peer(g_c->fr_c, g->close[to_send_other].number, PACKET_ID_LOSSY_CONFERENCE, + g->close[to_send_other].group_number, data, length)) { + ++sent; + } + + return sent; +} + +#define MAX_GROUP_MESSAGE_DATA_LEN (MAX_CRYPTO_DATA_SIZE - (1 + MIN_MESSAGE_PACKET_LEN)) + +/* Send data of len with message_id to groupnumber. + * + * return number of peers it was sent to on success. + * return -1 if groupnumber is invalid. + * return -2 if message is too long. + * return -3 if we are not connected to the group. + * reutrn -4 if message failed to send. + */ +static int send_message_group(const Group_Chats *g_c, int groupnumber, uint8_t message_id, const uint8_t *data, + uint16_t len) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if (len > MAX_GROUP_MESSAGE_DATA_LEN) { + return -2; + } + + if (g->status != GROUPCHAT_STATUS_CONNECTED) { + return -3; + } + + VLA(uint8_t, packet, sizeof(uint16_t) + sizeof(uint32_t) + 1 + len); + uint16_t peer_num = net_htons(g->peer_number); + memcpy(packet, &peer_num, sizeof(peer_num)); + + ++g->message_number; + + if (!g->message_number) { + ++g->message_number; + } + + uint32_t message_num = net_htonl(g->message_number); + memcpy(packet + sizeof(uint16_t), &message_num, sizeof(message_num)); + + packet[sizeof(uint16_t) + sizeof(uint32_t)] = message_id; + + if (len) { + memcpy(packet + sizeof(uint16_t) + sizeof(uint32_t) + 1, data, len); + } + + unsigned int ret = send_message_all_close(g_c, groupnumber, packet, SIZEOF_VLA(packet), -1); + + return (ret == 0) ? -4 : ret; +} + +/* send a group message + * return 0 on success + * see: send_message_group() for error codes. + */ +int group_message_send(const Group_Chats *g_c, int groupnumber, const uint8_t *message, uint16_t length) +{ + int ret = send_message_group(g_c, groupnumber, PACKET_ID_MESSAGE, message, length); + + if (ret > 0) { + return 0; + } + + return ret; +} + +/* send a group action + * return 0 on success + * see: send_message_group() for error codes. + */ +int group_action_send(const Group_Chats *g_c, int groupnumber, const uint8_t *action, uint16_t length) +{ + int ret = send_message_group(g_c, groupnumber, PACKET_ID_ACTION, action, length); + + if (ret > 0) { + return 0; + } + + return ret; +} + +/* High level function to send custom lossy packets. + * + * return -1 on failure. + * return 0 on success. + */ +int send_group_lossy_packet(const Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length) +{ + // TODO(irungentoo): length check here? + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + VLA(uint8_t, packet, sizeof(uint16_t) * 2 + length); + uint16_t peer_number = net_htons(g->peer_number); + memcpy(packet, &peer_number, sizeof(uint16_t)); + uint16_t message_num = net_htons(g->lossy_message_number); + memcpy(packet + sizeof(uint16_t), &message_num, sizeof(uint16_t)); + memcpy(packet + sizeof(uint16_t) * 2, data, length); + + if (send_lossy_all_close(g_c, groupnumber, packet, SIZEOF_VLA(packet), -1) == 0) { + return -1; + } + + ++g->lossy_message_number; + return 0; +} + +static void handle_message_packet_group(Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length, + int close_index, void *userdata) +{ + if (length < sizeof(uint16_t) + sizeof(uint32_t) + 1) { + return; + } + + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return; + } + + uint16_t peer_number; + memcpy(&peer_number, data, sizeof(uint16_t)); + peer_number = net_ntohs(peer_number); + + int index = get_peer_index(g, peer_number); + + if (index == -1) { + /* We don't know the peer this packet came from so we query the list of peers from that peer. + (They would not have relayed it if they didn't know the peer.) */ + send_peer_query(g_c, g->close[close_index].number, g->close[close_index].group_number); + return; + } + + uint32_t message_number; + memcpy(&message_number, data + sizeof(uint16_t), sizeof(message_number)); + message_number = net_ntohl(message_number); + + if (g->group[index].last_message_number == 0) { + g->group[index].last_message_number = message_number; + } else if (message_number - g->group[index].last_message_number > 64 || + message_number == g->group[index].last_message_number) { + return; + } + + g->group[index].last_message_number = message_number; + + uint8_t message_id = data[sizeof(uint16_t) + sizeof(message_number)]; + const uint8_t *msg_data = data + sizeof(uint16_t) + sizeof(message_number) + 1; + uint16_t msg_data_len = length - (sizeof(uint16_t) + sizeof(message_number) + 1); + + switch (message_id) { + case GROUP_MESSAGE_PING_ID: { + if (msg_data_len != 0) { + return; + } + + g->group[index].last_recv = unix_time(); + } + break; + + case GROUP_MESSAGE_NEW_PEER_ID: { + if (msg_data_len != GROUP_MESSAGE_NEW_PEER_LENGTH) { + return; + } + + uint16_t new_peer_number; + memcpy(&new_peer_number, msg_data, sizeof(uint16_t)); + new_peer_number = net_ntohs(new_peer_number); + addpeer(g_c, groupnumber, msg_data + sizeof(uint16_t), msg_data + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE, + new_peer_number, userdata, true); + } + break; + + case GROUP_MESSAGE_KILL_PEER_ID: { + if (msg_data_len != GROUP_MESSAGE_KILL_PEER_LENGTH) { + return; + } + + uint16_t kill_peer_number; + memcpy(&kill_peer_number, msg_data, sizeof(uint16_t)); + kill_peer_number = net_ntohs(kill_peer_number); + + if (peer_number == kill_peer_number) { + delpeer(g_c, groupnumber, index, userdata); + } else { + return; + // TODO(irungentoo): + } + } + break; + + case GROUP_MESSAGE_NAME_ID: { + if (setnick(g_c, groupnumber, index, msg_data, msg_data_len, userdata, true) == -1) { + return; + } + } + break; + + case GROUP_MESSAGE_TITLE_ID: { + if (settitle(g_c, groupnumber, index, msg_data, msg_data_len, userdata) == -1) { + return; + } + } + break; + + case PACKET_ID_MESSAGE: { + if (msg_data_len == 0) { + return; + } + + VLA(uint8_t, newmsg, msg_data_len + 1); + memcpy(newmsg, msg_data, msg_data_len); + newmsg[msg_data_len] = 0; + + // TODO(irungentoo): + if (g_c->message_callback) { + g_c->message_callback(g_c->m, groupnumber, index, 0, newmsg, msg_data_len, userdata); + } + + break; + } + + case PACKET_ID_ACTION: { + if (msg_data_len == 0) { + return; + } + + VLA(uint8_t, newmsg, msg_data_len + 1); + memcpy(newmsg, msg_data, msg_data_len); + newmsg[msg_data_len] = 0; + + // TODO(irungentoo): + if (g_c->message_callback) { + g_c->message_callback(g_c->m, groupnumber, index, 1, newmsg, msg_data_len, userdata); + } + + break; + } + + default: + return; + } + + send_message_all_close(g_c, groupnumber, data, length, -1/* TODO(irungentoo) close_index */); +} + +static int g_handle_packet(void *object, int friendcon_id, const uint8_t *data, uint16_t length, void *userdata) +{ + Group_Chats *g_c = (Group_Chats *)object; + + if (length < 1 + sizeof(uint16_t) + 1) { + return -1; + } + + if (data[0] == PACKET_ID_ONLINE_PACKET) { + return handle_packet_online(g_c, friendcon_id, data + 1, length - 1); + } + + if (data[0] != PACKET_ID_DIRECT_CONFERENCE && data[0] != PACKET_ID_MESSAGE_CONFERENCE) { + return -1; + } + + uint16_t groupnumber; + memcpy(&groupnumber, data + 1, sizeof(uint16_t)); + groupnumber = net_ntohs(groupnumber); + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + int index = friend_in_close(g, friendcon_id); + + if (index == -1) { + return -1; + } + + switch (data[0]) { + case PACKET_ID_DIRECT_CONFERENCE: { + handle_direct_packet(g_c, groupnumber, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index, userdata); + break; + } + + case PACKET_ID_MESSAGE_CONFERENCE: { + handle_message_packet_group(g_c, groupnumber, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index, + userdata); + break; + } + + default: { + return 0; + } + } + + return 0; +} + +/* Did we already receive the lossy packet or not. + * + * return -1 on failure. + * return 0 if packet was not received. + * return 1 if packet was received. + * + * TODO(irungentoo): test this + */ +static unsigned int lossy_packet_not_received(Group_c *g, int peer_index, uint16_t message_number) +{ + if (peer_index == -1) { + return -1; + } + + if (g->group[peer_index].bottom_lossy_number == g->group[peer_index].top_lossy_number) { + g->group[peer_index].top_lossy_number = message_number; + g->group[peer_index].bottom_lossy_number = (message_number - MAX_LOSSY_COUNT) + 1; + g->group[peer_index].recv_lossy[message_number % MAX_LOSSY_COUNT] = 1; + return 0; + } + + if ((uint16_t)(message_number - g->group[peer_index].bottom_lossy_number) < MAX_LOSSY_COUNT) { + if (g->group[peer_index].recv_lossy[message_number % MAX_LOSSY_COUNT]) { + return 1; + } + + g->group[peer_index].recv_lossy[message_number % MAX_LOSSY_COUNT] = 1; + return 0; + } + + if ((uint16_t)(message_number - g->group[peer_index].bottom_lossy_number) > (1 << 15)) { + return -1; + } + + uint16_t top_distance = message_number - g->group[peer_index].top_lossy_number; + + if (top_distance >= MAX_LOSSY_COUNT) { + crypto_memzero(g->group[peer_index].recv_lossy, sizeof(g->group[peer_index].recv_lossy)); + g->group[peer_index].top_lossy_number = message_number; + g->group[peer_index].bottom_lossy_number = (message_number - MAX_LOSSY_COUNT) + 1; + g->group[peer_index].recv_lossy[message_number % MAX_LOSSY_COUNT] = 1; + return 0; + } + + if (top_distance < MAX_LOSSY_COUNT) { + unsigned int i; + + for (i = g->group[peer_index].bottom_lossy_number; i != (g->group[peer_index].bottom_lossy_number + top_distance); + ++i) { + g->group[peer_index].recv_lossy[i % MAX_LOSSY_COUNT] = 0; + } + + g->group[peer_index].top_lossy_number = message_number; + g->group[peer_index].bottom_lossy_number = (message_number - MAX_LOSSY_COUNT) + 1; + g->group[peer_index].recv_lossy[message_number % MAX_LOSSY_COUNT] = 1; + return 0; + } + + return -1; +} + +static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uint16_t length, void *userdata) +{ + Group_Chats *g_c = (Group_Chats *)object; + + if (length < 1 + sizeof(uint16_t) * 3 + 1) { + return -1; + } + + if (data[0] != PACKET_ID_LOSSY_CONFERENCE) { + return -1; + } + + uint16_t groupnumber, peer_number, message_number; + memcpy(&groupnumber, data + 1, sizeof(uint16_t)); + memcpy(&peer_number, data + 1 + sizeof(uint16_t), sizeof(uint16_t)); + memcpy(&message_number, data + 1 + sizeof(uint16_t) * 2, sizeof(uint16_t)); + groupnumber = net_ntohs(groupnumber); + peer_number = net_ntohs(peer_number); + message_number = net_ntohs(message_number); + + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + int index = friend_in_close(g, friendcon_id); + + if (index == -1) { + return -1; + } + + if (peer_number == g->peer_number) { + return -1; + } + + int peer_index = get_peer_index(g, peer_number); + + if (peer_index == -1) { + return -1; + } + + if (lossy_packet_not_received(g, peer_index, message_number)) { + return -1; + } + + const uint8_t *lossy_data = data + 1 + sizeof(uint16_t) * 3; + uint16_t lossy_length = length - (1 + sizeof(uint16_t) * 3); + uint8_t message_id = lossy_data[0]; + ++lossy_data; + --lossy_length; + + if (g_c->lossy_packethandlers[message_id].function) { + if (g_c->lossy_packethandlers[message_id].function(g->object, groupnumber, peer_index, g->group[peer_index].object, + lossy_data, lossy_length) == -1) { + return -1; + } + } else { + return -1; + } + + send_lossy_all_close(g_c, groupnumber, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index); + return 0; +} + +/* Set the object that is tied to the group chat. + * + * return 0 on success. + * return -1 on failure + */ +int group_set_object(const Group_Chats *g_c, int groupnumber, void *object) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + g->object = object; + return 0; +} + +/* Set the object that is tied to the group peer. + * + * return 0 on success. + * return -1 on failure + */ +int group_peer_set_object(const Group_Chats *g_c, int groupnumber, int peernumber, void *object) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if ((uint32_t)peernumber >= g->numpeers) { + return -1; + } + + g->group[peernumber].object = object; + return 0; +} + +/* Return the object tide to the group chat previously set by group_set_object. + * + * return NULL on failure. + * return object on success. + */ +void *group_get_object(const Group_Chats *g_c, int groupnumber) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return NULL; + } + + return g->object; +} + +/* Return the object tide to the group chat peer previously set by group_peer_set_object. + * + * return NULL on failure. + * return object on success. + */ +void *group_peer_get_object(const Group_Chats *g_c, int groupnumber, int peernumber) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return NULL; + } + + if ((uint32_t)peernumber >= g->numpeers) { + return NULL; + } + + return g->group[peernumber].object; +} + +/* Interval in seconds to send ping messages */ +#define GROUP_PING_INTERVAL 20 + +static int ping_groupchat(Group_Chats *g_c, int groupnumber) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if (is_timeout(g->last_sent_ping, GROUP_PING_INTERVAL)) { + if (group_ping_send(g_c, groupnumber) != -1) { /* Ping */ + g->last_sent_ping = unix_time(); + } + } + + return 0; +} + +static int groupchat_clear_timedout(Group_Chats *g_c, int groupnumber, void *userdata) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + uint32_t i; + + for (i = 0; i < g->numpeers; ++i) { + if (g->peer_number != g->group[i].peer_number && is_timeout(g->group[i].last_recv, GROUP_PING_INTERVAL * 3)) { + delpeer(g_c, groupnumber, i, userdata); + } + + if (g->group == NULL || i >= g->numpeers) { + break; + } + } + + return 0; +} + +/* Send current name (set in messenger) to all online groups. + */ +void send_name_all_groups(Group_Chats *g_c) +{ + unsigned int i; + + for (i = 0; i < g_c->num_chats; ++i) { + Group_c *g = get_group_c(g_c, i); + + if (!g) { + continue; + } + + if (g->status == GROUPCHAT_STATUS_CONNECTED) { + group_name_send(g_c, i, g_c->m->name, g_c->m->name_length); + } + } +} + +/* Create new groupchat instance. */ +Group_Chats *new_groupchats(Messenger *m) +{ + if (!m) { + return NULL; + } + + Group_Chats *temp = (Group_Chats *)calloc(1, sizeof(Group_Chats)); + + if (temp == NULL) { + return NULL; + } + + temp->m = m; + temp->fr_c = m->fr_c; + m->conferences_object = temp; + m_callback_conference_invite(m, &handle_friend_invite_packet); + + return temp; +} + +/* main groupchats loop. */ +void do_groupchats(Group_Chats *g_c, void *userdata) +{ + unsigned int i; + + for (i = 0; i < g_c->num_chats; ++i) { + Group_c *g = get_group_c(g_c, i); + + if (!g) { + continue; + } + + if (g->status == GROUPCHAT_STATUS_CONNECTED) { + connect_to_closest(g_c, i, userdata); + ping_groupchat(g_c, i); + groupchat_clear_timedout(g_c, i, userdata); + } + } + + // TODO(irungentoo): +} + +/* Free everything related with group chats. */ +void kill_groupchats(Group_Chats *g_c) +{ + unsigned int i; + + for (i = 0; i < g_c->num_chats; ++i) { + del_groupchat(g_c, i); + } + + m_callback_conference_invite(g_c->m, NULL); + g_c->m->conferences_object = NULL; + free(g_c); +} + +/* Return the number of chats in the instance m. + * You should use this to determine how much memory to allocate + * for copy_chatlist. + */ +uint32_t count_chatlist(Group_Chats *g_c) +{ + uint32_t ret = 0; + uint32_t i; + + for (i = 0; i < g_c->num_chats; i++) { + if (g_c->chats[i].status != GROUPCHAT_STATUS_NONE) { + ret++; + } + } + + return ret; +} + +/* Copy a list of valid chat IDs into the array out_list. + * If out_list is NULL, returns 0. + * Otherwise, returns the number of elements copied. + * If the array was too small, the contents + * of out_list will be truncated to list_size. */ +uint32_t copy_chatlist(Group_Chats *g_c, uint32_t *out_list, uint32_t list_size) +{ + if (!out_list) { + return 0; + } + + if (g_c->num_chats == 0) { + return 0; + } + + uint32_t i, ret = 0; + + for (i = 0; i < g_c->num_chats; ++i) { + if (ret >= list_size) { + break; /* Abandon ship */ + } + + if (g_c->chats[i].status > GROUPCHAT_STATUS_NONE) { + out_list[ret] = i; + ret++; + } + } + + return ret; +} diff --git a/protocols/Tox/libtox/src/toxcore/group.h b/protocols/Tox/libtox/src/toxcore/group.h new file mode 100644 index 0000000000..2e014da36d --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/group.h @@ -0,0 +1,395 @@ +/* + * Slightly better groupchats implementation. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef GROUP_H +#define GROUP_H + +#include "Messenger.h" + +enum { + GROUPCHAT_STATUS_NONE, + GROUPCHAT_STATUS_VALID, + GROUPCHAT_STATUS_CONNECTED +}; + +enum { + GROUPCHAT_TYPE_TEXT, + GROUPCHAT_TYPE_AV +}; + +#define MAX_LOSSY_COUNT 256 + +typedef struct { + uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; + + uint64_t last_recv; + uint32_t last_message_number; + + uint8_t nick[MAX_NAME_LENGTH]; + uint8_t nick_len; + + uint16_t peer_number; + + uint8_t recv_lossy[MAX_LOSSY_COUNT]; + uint16_t bottom_lossy_number, top_lossy_number; + + void *object; +} Group_Peer; + +#define DESIRED_CLOSE_CONNECTIONS 4 +#define MAX_GROUP_CONNECTIONS 16 +#define GROUP_IDENTIFIER_LENGTH (1 + CRYPTO_SYMMETRIC_KEY_SIZE) /* type + CRYPTO_SYMMETRIC_KEY_SIZE so we can use new_symmetric_key(...) to fill it */ + +enum { + GROUPCHAT_CLOSE_NONE, + GROUPCHAT_CLOSE_CONNECTION, + GROUPCHAT_CLOSE_ONLINE +}; + +typedef struct { + uint8_t status; + + Group_Peer *group; + uint32_t numpeers; + + struct { + uint8_t type; /* GROUPCHAT_CLOSE_* */ + uint8_t closest; + uint32_t number; + uint16_t group_number; + } close[MAX_GROUP_CONNECTIONS]; + + uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + struct { + uint8_t entry; + uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; + } closest_peers[DESIRED_CLOSE_CONNECTIONS]; + uint8_t changed; + + uint8_t identifier[GROUP_IDENTIFIER_LENGTH]; + + uint8_t title[MAX_NAME_LENGTH]; + uint8_t title_len; + + uint32_t message_number; + uint16_t lossy_message_number; + uint16_t peer_number; + + uint64_t last_sent_ping; + + int number_joined; /* friendcon_id of person that invited us to the chat. (-1 means none) */ + + void *object; + + void (*peer_on_join)(void *, int, int); + void (*peer_on_leave)(void *, int, int, void *); + void (*group_on_delete)(void *, int); +} Group_c; + +typedef struct { + Messenger *m; + Friend_Connections *fr_c; + + Group_c *chats; + uint32_t num_chats; + + void (*invite_callback)(Messenger *m, uint32_t, int, const uint8_t *, size_t, void *); + void (*message_callback)(Messenger *m, uint32_t, uint32_t, int, const uint8_t *, size_t, void *); + void (*group_namelistchange)(Messenger *m, int, int, uint8_t, void *); + void (*title_callback)(Messenger *m, uint32_t, uint32_t, const uint8_t *, size_t, void *); + + struct { + int (*function)(void *, int, int, void *, const uint8_t *, uint16_t); + } lossy_packethandlers[256]; +} Group_Chats; + +/* Set the callback for group invites. + * + * Function(Group_Chats *g_c, int32_t friendnumber, uint8_t type, uint8_t *data, uint16_t length, void *userdata) + * + * data of length is what needs to be passed to join_groupchat(). + */ +void g_callback_group_invite(Group_Chats *g_c, void (*function)(Messenger *m, uint32_t, int, const uint8_t *, + size_t, void *)); + +/* Set the callback for group messages. + * + * Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) + */ +void g_callback_group_message(Group_Chats *g_c, void (*function)(Messenger *m, uint32_t, uint32_t, int, const uint8_t *, + size_t, void *)); + + +/* Set callback function for title changes. + * + * Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * title, uint8_t length, void *userdata) + * if friendgroupnumber == -1, then author is unknown (e.g. initial joining the group) + */ +void g_callback_group_title(Group_Chats *g_c, void (*function)(Messenger *m, uint32_t, uint32_t, const uint8_t *, + size_t, void *)); + +/* Set callback function for peer name list changes. + * + * It gets called every time the name list changes(new peer/name, deleted peer) + * Function(Group_Chats *g_c, int groupnumber, int peernumber, TOX_CHAT_CHANGE change, void *userdata) + */ +enum { + CHAT_CHANGE_PEER_ADD, + CHAT_CHANGE_PEER_DEL, + CHAT_CHANGE_PEER_NAME, +}; +void g_callback_group_namelistchange(Group_Chats *g_c, void (*function)(Messenger *m, int, int, uint8_t, void *)); + +/* Creates a new groupchat and puts it in the chats array. + * + * type is one of GROUPCHAT_TYPE_* + * + * return group number on success. + * return -1 on failure. + */ +int add_groupchat(Group_Chats *g_c, uint8_t type); + +/* Delete a groupchat from the chats array. + * + * return 0 on success. + * return -1 if groupnumber is invalid. + */ +int del_groupchat(Group_Chats *g_c, int groupnumber); + +/* Copy the public key of peernumber who is in groupnumber to pk. + * pk must be CRYPTO_PUBLIC_KEY_SIZE long. + * + * return 0 on success + * return -1 if groupnumber is invalid. + * return -2 if peernumber is invalid. + */ +int group_peer_pubkey(const Group_Chats *g_c, int groupnumber, int peernumber, uint8_t *pk); + +/* + * Return the size of peernumber's name. + * + * return -1 if groupnumber is invalid. + * return -2 if peernumber is invalid. + */ +int group_peername_size(const Group_Chats *g_c, int groupnumber, int peernumber); + +/* Copy the name of peernumber who is in groupnumber to name. + * name must be at least MAX_NAME_LENGTH long. + * + * return length of name if success + * return -1 if groupnumber is invalid. + * return -2 if peernumber is invalid. + */ +int group_peername(const Group_Chats *g_c, int groupnumber, int peernumber, uint8_t *name); + +/* invite friendnumber to groupnumber + * + * return 0 on success. + * return -1 if groupnumber is invalid. + * return -2 if invite packet failed to send. + */ +int invite_friend(Group_Chats *g_c, int32_t friendnumber, int groupnumber); + +/* Join a group (you need to have been invited first.) + * + * expected_type is the groupchat type we expect the chat we are joining is. + * + * return group number on success. + * return -1 if data length is invalid. + * return -2 if group is not the expected type. + * return -3 if friendnumber is invalid. + * return -4 if client is already in this group. + * return -5 if group instance failed to initialize. + * return -6 if join packet fails to send. + */ +int join_groupchat(Group_Chats *g_c, int32_t friendnumber, uint8_t expected_type, const uint8_t *data, uint16_t length); + +/* send a group message + * return 0 on success + * see: send_message_group() for error codes. + */ +int group_message_send(const Group_Chats *g_c, int groupnumber, const uint8_t *message, uint16_t length); + +/* send a group action + * return 0 on success + * see: send_message_group() for error codes. + */ +int group_action_send(const Group_Chats *g_c, int groupnumber, const uint8_t *action, uint16_t length); + +/* set the group's title, limited to MAX_NAME_LENGTH + * return 0 on success + * return -1 if groupnumber is invalid. + * return -2 if title is too long or empty. + * return -3 if packet fails to send. + */ +int group_title_send(const Group_Chats *g_c, int groupnumber, const uint8_t *title, uint8_t title_len); + + +/* return the group's title size. + * return -1 of groupnumber is invalid. + * return -2 if title is too long or empty. + */ +int group_title_get_size(const Group_Chats *g_c, int groupnumber); + +/* Get group title from groupnumber and put it in title. + * Title needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes. + * + * return length of copied title if success. + * return -1 if groupnumber is invalid. + * return -2 if title is too long or empty. + */ +int group_title_get(const Group_Chats *g_c, int groupnumber, uint8_t *title); + +/* Return the number of peers in the group chat on success. + * return -1 if groupnumber is invalid. + */ +int group_number_peers(const Group_Chats *g_c, int groupnumber); + +/* return 1 if the peernumber corresponds to ours. + * return 0 if the peernumber is not ours. + * return -1 if groupnumber is invalid. + * return -2 if peernumber is invalid. + * return -3 if we are not connected to the group chat. + */ +int group_peernumber_is_ours(const Group_Chats *g_c, int groupnumber, int peernumber); + +/* List all the peers in the group chat. + * + * Copies the names of the peers to the name[length][MAX_NAME_LENGTH] array. + * + * Copies the lengths of the names to lengths[length] + * + * returns the number of peers on success. + * + * return -1 on failure. + */ +int group_names(const Group_Chats *g_c, int groupnumber, uint8_t names[][MAX_NAME_LENGTH], uint16_t lengths[], + uint16_t length); + +/* Set handlers for custom lossy packets. + * + * NOTE: Handler must return 0 if packet is to be relayed, -1 if the packet should not be relayed. + * + * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber, void *group peer object (set with group_peer_set_object), const uint8_t *packet, uint16_t length) + */ +void group_lossy_packet_registerhandler(Group_Chats *g_c, uint8_t byte, int (*function)(void *, int, int, void *, + const uint8_t *, uint16_t)); + +/* High level function to send custom lossy packets. + * + * return -1 on failure. + * return 0 on success. + */ +int send_group_lossy_packet(const Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length); + +/* Return the number of chats in the instance m. + * You should use this to determine how much memory to allocate + * for copy_chatlist. + */ +uint32_t count_chatlist(Group_Chats *g_c); + +/* Copy a list of valid chat IDs into the array out_list. + * If out_list is NULL, returns 0. + * Otherwise, returns the number of elements copied. + * If the array was too small, the contents + * of out_list will be truncated to list_size. */ +uint32_t copy_chatlist(Group_Chats *g_c, uint32_t *out_list, uint32_t list_size); + +/* return the type of groupchat (GROUPCHAT_TYPE_) that groupnumber is. + * + * return -1 on failure. + * return type on success. + */ +int group_get_type(const Group_Chats *g_c, int groupnumber); + +/* Send current name (set in messenger) to all online groups. + */ +void send_name_all_groups(Group_Chats *g_c); + +/* Set the object that is tied to the group chat. + * + * return 0 on success. + * return -1 on failure + */ +int group_set_object(const Group_Chats *g_c, int groupnumber, void *object); + +/* Set the object that is tied to the group peer. + * + * return 0 on success. + * return -1 on failure + */ +int group_peer_set_object(const Group_Chats *g_c, int groupnumber, int peernumber, void *object); + +/* Return the object tide to the group chat previously set by group_set_object. + * + * return NULL on failure. + * return object on success. + */ +void *group_get_object(const Group_Chats *g_c, int groupnumber); + +/* Return the object tide to the group chat peer previously set by group_peer_set_object. + * + * return NULL on failure. + * return object on success. + */ +void *group_peer_get_object(const Group_Chats *g_c, int groupnumber, int peernumber); + +/* Set a function to be called when a new peer joins a group chat. + * + * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber) + * + * return 0 on success. + * return -1 on failure. + */ +int callback_groupchat_peer_new(const Group_Chats *g_c, int groupnumber, void (*function)(void *, int, int)); + +/* Set a function to be called when a peer leaves a group chat. + * + * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber, void *group peer object (set with group_peer_set_object)) + * + * return 0 on success. + * return -1 on failure. + */ +int callback_groupchat_peer_delete(Group_Chats *g_c, int groupnumber, void (*function)(void *, int, int, void *)); + +/* Set a function to be called when the group chat is deleted. + * + * Function(void *group object (set with group_set_object), int groupnumber) + * + * return 0 on success. + * return -1 on failure. + */ +int callback_groupchat_delete(Group_Chats *g_c, int groupnumber, void (*function)(void *, int)); + +/* Create new groupchat instance. */ +Group_Chats *new_groupchats(Messenger *m); + +/* main groupchats loop. */ +void do_groupchats(Group_Chats *g_c, void *userdata); + +/* Free everything related with group chats. */ +void kill_groupchats(Group_Chats *g_c); + +#endif diff --git a/protocols/Tox/libtox/src/toxcore/list.c b/protocols/Tox/libtox/src/toxcore/list.c new file mode 100644 index 0000000000..36d609fbd1 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/list.c @@ -0,0 +1,266 @@ +/* + * Simple struct with functions to create a list which associates ids with data + * -Allows for finding ids associated with data such as IPs or public keys in a short time + * -Should only be used if there are relatively few add/remove calls to the list + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "list.h" + +/* Basically, the elements in the list are placed in order so that they can be searched for easily + * -each element is seen as a big-endian integer when ordering them + * -the ids array is maintained so that each id always matches + * -the search algorithm cuts down the time to find the id associated with a piece of data + * at the cost of slow add/remove functions for large lists + * -Starts at 1/2 of the array, compares the element in the array with the data, + * then moves +/- 1/4 of the array depending on whether the value is greater or lower, + * then +- 1/8, etc, until the value is matched or its position where it should be in the array is found + * -some considerations since the array size is never perfect + */ + +#define INDEX(i) (~i) + +/* Find data in list + * + * return value: + * >= 0 : index of data in array + * < 0 : no match, returns index (return value is INDEX(index)) where + * the data should be inserted + */ +static int find(const BS_LIST *list, const uint8_t *data) +{ + //should work well, but could be improved + if (list->n == 0) { + return INDEX(0); + } + + uint32_t i = list->n / 2; //current position in the array + uint32_t delta = i / 2; //how much we move in the array + + if (!delta) { + delta = 1; + } + + int d = -1; //used to determine if closest match is found + //closest match is found if we move back to where we have already been + + while (1) { + int r = memcmp(data, list->data + list->element_size * i, list->element_size); + + if (r == 0) { + return i; + } + + if (r > 0) { + //data is greater + //move down + i += delta; + + if (d == 0 || i == list->n) { + //reached bottom of list, or closest match + return INDEX(i); + } + + delta = (delta) / 2; + + if (delta == 0) { + delta = 1; + d = 1; + } + } else { + //data is smaller + if (d == 1 || i == 0) { + //reached top or list or closest match + return INDEX(i); + } + + //move up + i -= delta; + + delta = (delta) / 2; + + if (delta == 0) { + delta = 1; + d = 0; + } + } + } +} + +/* Resized the list list + * + * return value: + * 1 : success + * 0 : failure + */ +static int resize(BS_LIST *list, uint32_t new_size) +{ + if (new_size == 0) { + bs_list_free(list); + return 1; + } + + uint8_t *data = (uint8_t *)realloc(list->data, list->element_size * new_size); + + if (!data) { + return 0; + } + + list->data = data; + + int *ids = (int *)realloc(list->ids, sizeof(int) * new_size); + + if (!ids) { + return 0; + } + + list->ids = ids; + + return 1; +} + + +int bs_list_init(BS_LIST *list, uint32_t element_size, uint32_t initial_capacity) +{ + //set initial values + list->n = 0; + list->element_size = element_size; + list->capacity = 0; + list->data = NULL; + list->ids = NULL; + + if (initial_capacity != 0) { + if (!resize(list, initial_capacity)) { + return 0; + } + } + + list->capacity = initial_capacity; + + return 1; +} + +void bs_list_free(BS_LIST *list) +{ + //free both arrays + free(list->data); + list->data = NULL; + + free(list->ids); + list->ids = NULL; +} + +int bs_list_find(const BS_LIST *list, const uint8_t *data) +{ + int r = find(list, data); + + //return only -1 and positive values + if (r < 0) { + return -1; + } + + return list->ids[r]; +} + +int bs_list_add(BS_LIST *list, const uint8_t *data, int id) +{ + //find where the new element should be inserted + //see: return value of find() + int i = find(list, data); + + if (i >= 0) { + //already in list + return 0; + } + + i = ~i; + + //increase the size of the arrays if needed + if (list->n == list->capacity) { + // 1.5 * n + 1 + const uint32_t new_capacity = list->n + list->n / 2 + 1; + + if (!resize(list, new_capacity)) { + return 0; + } + + list->capacity = new_capacity; + } + + //insert data to element array + memmove(list->data + (i + 1) * list->element_size, list->data + i * list->element_size, + (list->n - i) * list->element_size); + memcpy(list->data + i * list->element_size, data, list->element_size); + + //insert id to id array + memmove(&list->ids[i + 1], &list->ids[i], (list->n - i) * sizeof(int)); + list->ids[i] = id; + + //increase n + list->n++; + + return 1; +} + +int bs_list_remove(BS_LIST *list, const uint8_t *data, int id) +{ + int i = find(list, data); + + if (i < 0) { + return 0; + } + + if (list->ids[i] != id) { + //this should never happen + return 0; + } + + //decrease the size of the arrays if needed + if (list->n < list->capacity / 2) { + const uint32_t new_capacity = list->capacity / 2; + + if (resize(list, new_capacity)) { + list->capacity = new_capacity; + } + } + + list->n--; + + memmove(list->data + i * list->element_size, list->data + (i + 1) * list->element_size, + (list->n - i) * list->element_size); + memmove(&list->ids[i], &list->ids[i + 1], (list->n - i) * sizeof(int)); + + return 1; +} + +int bs_list_trim(BS_LIST *list) +{ + if (!resize(list, list->n)) { + return 0; + } + + list->capacity = list->n; + return 1; +} diff --git a/protocols/Tox/libtox/src/toxcore/list.h b/protocols/Tox/libtox/src/toxcore/list.h new file mode 100644 index 0000000000..cb3b328c5a --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/list.h @@ -0,0 +1,85 @@ +/* + * Simple struct with functions to create a list which associates ids with data + * -Allows for finding ids associated with data such as IPs or public keys in a short time + * -Should only be used if there are relatively few add/remove calls to the list + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef LIST_H +#define LIST_H + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +typedef struct { + uint32_t n; //number of elements + uint32_t capacity; //number of elements memory is allocated for + uint32_t element_size; //size of the elements + uint8_t *data; //array of elements + int *ids; //array of element ids +} BS_LIST; + +/* Initialize a list, element_size is the size of the elements in the list and + * initial_capacity is the number of elements the memory will be initially allocated for + * + * return value: + * 1 : success + * 0 : failure + */ +int bs_list_init(BS_LIST *list, uint32_t element_size, uint32_t initial_capacity); + +/* Free a list initiated with list_init */ +void bs_list_free(BS_LIST *list); + +/* Retrieve the id of an element in the list + * + * return value: + * >= 0 : id associated with data + * -1 : failure + */ +int bs_list_find(const BS_LIST *list, const uint8_t *data); + +/* Add an element with associated id to the list + * + * return value: + * 1 : success + * 0 : failure (data already in list) + */ +int bs_list_add(BS_LIST *list, const uint8_t *data, int id); + +/* Remove element from the list + * + * return value: + * 1 : success + * 0 : failure (element not found or id does not match) + */ +int bs_list_remove(BS_LIST *list, const uint8_t *data, int id); + +/* Removes the memory overhead + * + * return value: + * 1 : success + * 0 : failure + */ +int bs_list_trim(BS_LIST *list); + +#endif diff --git a/protocols/Tox/libtox/src/toxcore/logger.c b/protocols/Tox/libtox/src/toxcore/logger.c new file mode 100644 index 0000000000..18b765a385 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/logger.c @@ -0,0 +1,77 @@ +/* + * Text logging abstraction. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013,2015 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "logger.h" + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> + + +struct Logger { + logger_cb *callback; + void *context; + void *userdata; +}; + + +/** + * Public Functions + */ +Logger *logger_new(void) +{ + return (Logger *)calloc(1, sizeof(Logger)); +} + +void logger_kill(Logger *log) +{ + free(log); +} + +void logger_callback_log(Logger *log, logger_cb *function, void *context, void *userdata) +{ + log->callback = function; + log->context = context; + log->userdata = userdata; +} + +void logger_write(Logger *log, LOGGER_LEVEL level, const char *file, int line, const char *func, const char *format, + ...) +{ + if (!log || !log->callback) { + return; + } + + /* Format message */ + char msg[1024]; + va_list args; + va_start(args, format); + vsnprintf(msg, sizeof msg, format, args); + va_end(args); + + log->callback(log->context, level, file, line, func, msg, log->userdata); +} diff --git a/protocols/Tox/libtox/src/toxcore/logger.h b/protocols/Tox/libtox/src/toxcore/logger.h new file mode 100644 index 0000000000..8c8a639bec --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/logger.h @@ -0,0 +1,80 @@ +/* + * Logger abstraction backed by callbacks for writing. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef TOXLOGGER_H +#define TOXLOGGER_H + +#include <stdint.h> + +#ifndef MIN_LOGGER_LEVEL +#define MIN_LOGGER_LEVEL LOG_INFO +#endif + +typedef enum { + LOG_TRACE, + LOG_DEBUG, + LOG_INFO, + LOG_WARNING, + LOG_ERROR +} LOGGER_LEVEL; + +typedef struct Logger Logger; + +typedef void logger_cb(void *context, LOGGER_LEVEL level, const char *file, int line, + const char *func, const char *message, void *userdata); + +/** + * Creates a new logger with logging disabled (callback is NULL) by default. + */ +Logger *logger_new(void); + +void logger_kill(Logger *log); + +/** + * Sets the logger callback. Disables logging if set to NULL. + * The context parameter is passed to the callback as first argument. + */ +void logger_callback_log(Logger *log, logger_cb *function, void *context, void *userdata); + +/** + * Main write function. If logging disabled does nothing. + */ +void logger_write(Logger *log, LOGGER_LEVEL level, const char *file, int line, const char *func, const char *format, + ...); + + +#define LOGGER_WRITE(log, level, ...) \ + do { \ + if (level >= MIN_LOGGER_LEVEL) { \ + logger_write(log, level, __FILE__, __LINE__, __func__, __VA_ARGS__); \ + } \ + } while (0) + +/* To log with an logger */ +#define LOGGER_TRACE(log, ...) LOGGER_WRITE(log, LOG_TRACE , __VA_ARGS__) +#define LOGGER_DEBUG(log, ...) LOGGER_WRITE(log, LOG_DEBUG , __VA_ARGS__) +#define LOGGER_INFO(log, ...) LOGGER_WRITE(log, LOG_INFO , __VA_ARGS__) +#define LOGGER_WARNING(log, ...) LOGGER_WRITE(log, LOG_WARNING, __VA_ARGS__) +#define LOGGER_ERROR(log, ...) LOGGER_WRITE(log, LOG_ERROR , __VA_ARGS__) + +#endif /* TOXLOGGER_H */ diff --git a/protocols/Tox/libtox/src/toxcore/net_crypto.c b/protocols/Tox/libtox/src/toxcore/net_crypto.c new file mode 100644 index 0000000000..440db94abd --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/net_crypto.c @@ -0,0 +1,2908 @@ +/* + * Functions for the core network crypto. + * + * NOTE: This code has to be perfect. We don't mess around with encryption. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "net_crypto.h" + +#include "util.h" + +#include <math.h> + + +static uint8_t crypt_connection_id_not_valid(const Net_Crypto *c, int crypt_connection_id) +{ + if ((uint32_t)crypt_connection_id >= c->crypto_connections_length) { + return 1; + } + + if (c->crypto_connections == NULL) { + return 1; + } + + if (c->crypto_connections[crypt_connection_id].status == CRYPTO_CONN_NO_CONNECTION) { + return 1; + } + + return 0; +} + +/* cookie timeout in seconds */ +#define COOKIE_TIMEOUT 15 +#define COOKIE_DATA_LENGTH (CRYPTO_PUBLIC_KEY_SIZE * 2) +#define COOKIE_CONTENTS_LENGTH (sizeof(uint64_t) + COOKIE_DATA_LENGTH) +#define COOKIE_LENGTH (CRYPTO_NONCE_SIZE + COOKIE_CONTENTS_LENGTH + CRYPTO_MAC_SIZE) + +#define COOKIE_REQUEST_PLAIN_LENGTH (COOKIE_DATA_LENGTH + sizeof(uint64_t)) +#define COOKIE_REQUEST_LENGTH (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + COOKIE_REQUEST_PLAIN_LENGTH + CRYPTO_MAC_SIZE) +#define COOKIE_RESPONSE_LENGTH (1 + CRYPTO_NONCE_SIZE + COOKIE_LENGTH + sizeof(uint64_t) + CRYPTO_MAC_SIZE) + +/* Create a cookie request packet and put it in packet. + * dht_public_key is the dht public key of the other + * + * packet must be of size COOKIE_REQUEST_LENGTH or bigger. + * + * return -1 on failure. + * return COOKIE_REQUEST_LENGTH on success. + */ +static int create_cookie_request(const Net_Crypto *c, uint8_t *packet, uint8_t *dht_public_key, uint64_t number, + uint8_t *shared_key) +{ + uint8_t plain[COOKIE_REQUEST_PLAIN_LENGTH]; + uint8_t padding[CRYPTO_PUBLIC_KEY_SIZE] = {0}; + + memcpy(plain, c->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(plain + CRYPTO_PUBLIC_KEY_SIZE, padding, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(plain + (CRYPTO_PUBLIC_KEY_SIZE * 2), &number, sizeof(uint64_t)); + + DHT_get_shared_key_sent(c->dht, shared_key, dht_public_key); + uint8_t nonce[CRYPTO_NONCE_SIZE]; + random_nonce(nonce); + packet[0] = NET_PACKET_COOKIE_REQUEST; + memcpy(packet + 1, c->dht->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, nonce, CRYPTO_NONCE_SIZE); + int len = encrypt_data_symmetric(shared_key, nonce, plain, sizeof(plain), + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); + + if (len != COOKIE_REQUEST_PLAIN_LENGTH + CRYPTO_MAC_SIZE) { + return -1; + } + + return (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + len); +} + +/* Create cookie of length COOKIE_LENGTH from bytes of length COOKIE_DATA_LENGTH using encryption_key + * + * return -1 on failure. + * return 0 on success. + */ +static int create_cookie(uint8_t *cookie, const uint8_t *bytes, const uint8_t *encryption_key) +{ + uint8_t contents[COOKIE_CONTENTS_LENGTH]; + uint64_t temp_time = unix_time(); + memcpy(contents, &temp_time, sizeof(temp_time)); + memcpy(contents + sizeof(temp_time), bytes, COOKIE_DATA_LENGTH); + random_nonce(cookie); + int len = encrypt_data_symmetric(encryption_key, cookie, contents, sizeof(contents), cookie + CRYPTO_NONCE_SIZE); + + if (len != COOKIE_LENGTH - CRYPTO_NONCE_SIZE) { + return -1; + } + + return 0; +} + +/* Open cookie of length COOKIE_LENGTH to bytes of length COOKIE_DATA_LENGTH using encryption_key + * + * return -1 on failure. + * return 0 on success. + */ +static int open_cookie(uint8_t *bytes, const uint8_t *cookie, const uint8_t *encryption_key) +{ + uint8_t contents[COOKIE_CONTENTS_LENGTH]; + int len = decrypt_data_symmetric(encryption_key, cookie, cookie + CRYPTO_NONCE_SIZE, + COOKIE_LENGTH - CRYPTO_NONCE_SIZE, contents); + + if (len != sizeof(contents)) { + return -1; + } + + uint64_t cookie_time; + memcpy(&cookie_time, contents, sizeof(cookie_time)); + uint64_t temp_time = unix_time(); + + if (cookie_time + COOKIE_TIMEOUT < temp_time || temp_time < cookie_time) { + return -1; + } + + memcpy(bytes, contents + sizeof(cookie_time), COOKIE_DATA_LENGTH); + return 0; +} + + +/* Create a cookie response packet and put it in packet. + * request_plain must be COOKIE_REQUEST_PLAIN_LENGTH bytes. + * packet must be of size COOKIE_RESPONSE_LENGTH or bigger. + * + * return -1 on failure. + * return COOKIE_RESPONSE_LENGTH on success. + */ +static int create_cookie_response(const Net_Crypto *c, uint8_t *packet, const uint8_t *request_plain, + const uint8_t *shared_key, const uint8_t *dht_public_key) +{ + uint8_t cookie_plain[COOKIE_DATA_LENGTH]; + memcpy(cookie_plain, request_plain, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(cookie_plain + CRYPTO_PUBLIC_KEY_SIZE, dht_public_key, CRYPTO_PUBLIC_KEY_SIZE); + uint8_t plain[COOKIE_LENGTH + sizeof(uint64_t)]; + + if (create_cookie(plain, cookie_plain, c->secret_symmetric_key) != 0) { + return -1; + } + + memcpy(plain + COOKIE_LENGTH, request_plain + COOKIE_DATA_LENGTH, sizeof(uint64_t)); + packet[0] = NET_PACKET_COOKIE_RESPONSE; + random_nonce(packet + 1); + int len = encrypt_data_symmetric(shared_key, packet + 1, plain, sizeof(plain), packet + 1 + CRYPTO_NONCE_SIZE); + + if (len != COOKIE_RESPONSE_LENGTH - (1 + CRYPTO_NONCE_SIZE)) { + return -1; + } + + return COOKIE_RESPONSE_LENGTH; +} + +/* Handle the cookie request packet of length length. + * Put what was in the request in request_plain (must be of size COOKIE_REQUEST_PLAIN_LENGTH) + * Put the key used to decrypt the request into shared_key (of size CRYPTO_SHARED_KEY_SIZE) for use in the response. + * + * return -1 on failure. + * return 0 on success. + */ +static int handle_cookie_request(const Net_Crypto *c, uint8_t *request_plain, uint8_t *shared_key, + uint8_t *dht_public_key, const uint8_t *packet, uint16_t length) +{ + if (length != COOKIE_REQUEST_LENGTH) { + return -1; + } + + memcpy(dht_public_key, packet + 1, CRYPTO_PUBLIC_KEY_SIZE); + DHT_get_shared_key_sent(c->dht, shared_key, dht_public_key); + int len = decrypt_data_symmetric(shared_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, COOKIE_REQUEST_PLAIN_LENGTH + CRYPTO_MAC_SIZE, + request_plain); + + if (len != COOKIE_REQUEST_PLAIN_LENGTH) { + return -1; + } + + return 0; +} + +/* Handle the cookie request packet (for raw UDP) + */ +static int udp_handle_cookie_request(void *object, IP_Port source, const uint8_t *packet, uint16_t length, + void *userdata) +{ + Net_Crypto *c = (Net_Crypto *)object; + uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH]; + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + + if (handle_cookie_request(c, request_plain, shared_key, dht_public_key, packet, length) != 0) { + return 1; + } + + uint8_t data[COOKIE_RESPONSE_LENGTH]; + + if (create_cookie_response(c, data, request_plain, shared_key, dht_public_key) != sizeof(data)) { + return 1; + } + + if ((uint32_t)sendpacket(c->dht->net, source, data, sizeof(data)) != sizeof(data)) { + return 1; + } + + return 0; +} + +/* Handle the cookie request packet (for TCP) + */ +static int tcp_handle_cookie_request(Net_Crypto *c, int connections_number, const uint8_t *packet, uint16_t length) +{ + uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH]; + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + + if (handle_cookie_request(c, request_plain, shared_key, dht_public_key, packet, length) != 0) { + return -1; + } + + uint8_t data[COOKIE_RESPONSE_LENGTH]; + + if (create_cookie_response(c, data, request_plain, shared_key, dht_public_key) != sizeof(data)) { + return -1; + } + + int ret = send_packet_tcp_connection(c->tcp_c, connections_number, data, sizeof(data)); + return ret; +} + +/* Handle the cookie request packet (for TCP oob packets) + */ +static int tcp_oob_handle_cookie_request(const Net_Crypto *c, unsigned int tcp_connections_number, + const uint8_t *dht_public_key, const uint8_t *packet, uint16_t length) +{ + uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH]; + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + uint8_t dht_public_key_temp[CRYPTO_PUBLIC_KEY_SIZE]; + + if (handle_cookie_request(c, request_plain, shared_key, dht_public_key_temp, packet, length) != 0) { + return -1; + } + + if (public_key_cmp(dht_public_key, dht_public_key_temp) != 0) { + return -1; + } + + uint8_t data[COOKIE_RESPONSE_LENGTH]; + + if (create_cookie_response(c, data, request_plain, shared_key, dht_public_key) != sizeof(data)) { + return -1; + } + + int ret = tcp_send_oob_packet(c->tcp_c, tcp_connections_number, dht_public_key, data, sizeof(data)); + return ret; +} + +/* Handle a cookie response packet of length encrypted with shared_key. + * put the cookie in the response in cookie + * + * cookie must be of length COOKIE_LENGTH. + * + * return -1 on failure. + * return COOKIE_LENGTH on success. + */ +static int handle_cookie_response(uint8_t *cookie, uint64_t *number, const uint8_t *packet, uint16_t length, + const uint8_t *shared_key) +{ + if (length != COOKIE_RESPONSE_LENGTH) { + return -1; + } + + uint8_t plain[COOKIE_LENGTH + sizeof(uint64_t)]; + int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE, + length - (1 + CRYPTO_NONCE_SIZE), plain); + + if (len != sizeof(plain)) { + return -1; + } + + memcpy(cookie, plain, COOKIE_LENGTH); + memcpy(number, plain + COOKIE_LENGTH, sizeof(uint64_t)); + return COOKIE_LENGTH; +} + +#define HANDSHAKE_PACKET_LENGTH (1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA512_SIZE + COOKIE_LENGTH + CRYPTO_MAC_SIZE) + +/* Create a handshake packet and put it in packet. + * cookie must be COOKIE_LENGTH bytes. + * packet must be of size HANDSHAKE_PACKET_LENGTH or bigger. + * + * return -1 on failure. + * return HANDSHAKE_PACKET_LENGTH on success. + */ +static int create_crypto_handshake(const Net_Crypto *c, uint8_t *packet, const uint8_t *cookie, const uint8_t *nonce, + const uint8_t *session_pk, const uint8_t *peer_real_pk, const uint8_t *peer_dht_pubkey) +{ + uint8_t plain[CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA512_SIZE + COOKIE_LENGTH]; + memcpy(plain, nonce, CRYPTO_NONCE_SIZE); + memcpy(plain + CRYPTO_NONCE_SIZE, session_pk, CRYPTO_PUBLIC_KEY_SIZE); + crypto_sha512(plain + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, cookie, COOKIE_LENGTH); + uint8_t cookie_plain[COOKIE_DATA_LENGTH]; + memcpy(cookie_plain, peer_real_pk, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(cookie_plain + CRYPTO_PUBLIC_KEY_SIZE, peer_dht_pubkey, CRYPTO_PUBLIC_KEY_SIZE); + + if (create_cookie(plain + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA512_SIZE, cookie_plain, + c->secret_symmetric_key) != 0) { + return -1; + } + + random_nonce(packet + 1 + COOKIE_LENGTH); + int len = encrypt_data(peer_real_pk, c->self_secret_key, packet + 1 + COOKIE_LENGTH, plain, sizeof(plain), + packet + 1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE); + + if (len != HANDSHAKE_PACKET_LENGTH - (1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE)) { + return -1; + } + + packet[0] = NET_PACKET_CRYPTO_HS; + memcpy(packet + 1, cookie, COOKIE_LENGTH); + + return HANDSHAKE_PACKET_LENGTH; +} + +/* Handle a crypto handshake packet of length. + * put the nonce contained in the packet in nonce, + * the session public key in session_pk + * the real public key of the peer in peer_real_pk + * the dht public key of the peer in dht_public_key and + * the cookie inside the encrypted part of the packet in cookie. + * + * if expected_real_pk isn't NULL it denotes the real public key + * the packet should be from. + * + * nonce must be at least CRYPTO_NONCE_SIZE + * session_pk must be at least CRYPTO_PUBLIC_KEY_SIZE + * peer_real_pk must be at least CRYPTO_PUBLIC_KEY_SIZE + * cookie must be at least COOKIE_LENGTH + * + * return -1 on failure. + * return 0 on success. + */ +static int handle_crypto_handshake(const Net_Crypto *c, uint8_t *nonce, uint8_t *session_pk, uint8_t *peer_real_pk, + uint8_t *dht_public_key, uint8_t *cookie, const uint8_t *packet, uint16_t length, const uint8_t *expected_real_pk) +{ + if (length != HANDSHAKE_PACKET_LENGTH) { + return -1; + } + + uint8_t cookie_plain[COOKIE_DATA_LENGTH]; + + if (open_cookie(cookie_plain, packet + 1, c->secret_symmetric_key) != 0) { + return -1; + } + + if (expected_real_pk) { + if (public_key_cmp(cookie_plain, expected_real_pk) != 0) { + return -1; + } + } + + uint8_t cookie_hash[CRYPTO_SHA512_SIZE]; + crypto_sha512(cookie_hash, packet + 1, COOKIE_LENGTH); + + uint8_t plain[CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA512_SIZE + COOKIE_LENGTH]; + int len = decrypt_data(cookie_plain, c->self_secret_key, packet + 1 + COOKIE_LENGTH, + packet + 1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE, + HANDSHAKE_PACKET_LENGTH - (1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE), plain); + + if (len != sizeof(plain)) { + return -1; + } + + if (crypto_memcmp(cookie_hash, plain + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, + CRYPTO_SHA512_SIZE) != 0) { + return -1; + } + + memcpy(nonce, plain, CRYPTO_NONCE_SIZE); + memcpy(session_pk, plain + CRYPTO_NONCE_SIZE, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(cookie, plain + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA512_SIZE, COOKIE_LENGTH); + memcpy(peer_real_pk, cookie_plain, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(dht_public_key, cookie_plain + CRYPTO_PUBLIC_KEY_SIZE, CRYPTO_PUBLIC_KEY_SIZE); + return 0; +} + + +static Crypto_Connection *get_crypto_connection(const Net_Crypto *c, int crypt_connection_id) +{ + if (crypt_connection_id_not_valid(c, crypt_connection_id)) { + return 0; + } + + return &c->crypto_connections[crypt_connection_id]; +} + + +/* Associate an ip_port to a connection. + * + * return -1 on failure. + * return 0 on success. + */ +static int add_ip_port_connection(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + if (ip_port.ip.family == TOX_AF_INET) { + if (!ipport_equal(&ip_port, &conn->ip_portv4) && LAN_ip(conn->ip_portv4.ip) != 0) { + if (!bs_list_add(&c->ip_port_list, (uint8_t *)&ip_port, crypt_connection_id)) { + return -1; + } + + bs_list_remove(&c->ip_port_list, (uint8_t *)&conn->ip_portv4, crypt_connection_id); + conn->ip_portv4 = ip_port; + return 0; + } + } else if (ip_port.ip.family == TOX_AF_INET6) { + if (!ipport_equal(&ip_port, &conn->ip_portv6)) { + if (!bs_list_add(&c->ip_port_list, (uint8_t *)&ip_port, crypt_connection_id)) { + return -1; + } + + bs_list_remove(&c->ip_port_list, (uint8_t *)&conn->ip_portv6, crypt_connection_id); + conn->ip_portv6 = ip_port; + return 0; + } + } + + return -1; +} + +/* Return the IP_Port that should be used to send packets to the other peer. + * + * return IP_Port with family 0 on failure. + * return IP_Port on success. + */ +static IP_Port return_ip_port_connection(Net_Crypto *c, int crypt_connection_id) +{ + const IP_Port empty = {{0}}; + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return empty; + } + + uint64_t current_time = unix_time(); + bool v6 = 0, v4 = 0; + + if ((UDP_DIRECT_TIMEOUT + conn->direct_lastrecv_timev4) > current_time) { + v4 = 1; + } + + if ((UDP_DIRECT_TIMEOUT + conn->direct_lastrecv_timev6) > current_time) { + v6 = 1; + } + + if (v4 && LAN_ip(conn->ip_portv4.ip) == 0) { + return conn->ip_portv4; + } + + if (v6 && conn->ip_portv6.ip.family == TOX_AF_INET6) { + return conn->ip_portv6; + } + + if (conn->ip_portv4.ip.family == TOX_AF_INET) { + return conn->ip_portv4; + } + + return empty; +} + +/* Sends a packet to the peer using the fastest route. + * + * return -1 on failure. + * return 0 on success. + */ +static int send_packet_to(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length) +{ +// TODO(irungentoo): TCP, etc... + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + int direct_send_attempt = 0; + + pthread_mutex_lock(&conn->mutex); + IP_Port ip_port = return_ip_port_connection(c, crypt_connection_id); + + // TODO(irungentoo): on bad networks, direct connections might not last indefinitely. + if (ip_port.ip.family != 0) { + bool direct_connected = 0; + crypto_connection_status(c, crypt_connection_id, &direct_connected, NULL); + + if (direct_connected) { + if ((uint32_t)sendpacket(c->dht->net, ip_port, data, length) == length) { + pthread_mutex_unlock(&conn->mutex); + return 0; + } + + pthread_mutex_unlock(&conn->mutex); + return -1; + } + + // TODO(irungentoo): a better way of sending packets directly to confirm the others ip. + uint64_t current_time = unix_time(); + + if ((((UDP_DIRECT_TIMEOUT / 2) + conn->direct_send_attempt_time) > current_time && length < 96) + || data[0] == NET_PACKET_COOKIE_REQUEST || data[0] == NET_PACKET_CRYPTO_HS) { + if ((uint32_t)sendpacket(c->dht->net, ip_port, data, length) == length) { + direct_send_attempt = 1; + conn->direct_send_attempt_time = unix_time(); + } + } + } + + pthread_mutex_unlock(&conn->mutex); + pthread_mutex_lock(&c->tcp_mutex); + int ret = send_packet_tcp_connection(c->tcp_c, conn->connection_number_tcp, data, length); + pthread_mutex_unlock(&c->tcp_mutex); + + pthread_mutex_lock(&conn->mutex); + + if (ret == 0) { + conn->last_tcp_sent = current_time_monotonic(); + } + + pthread_mutex_unlock(&conn->mutex); + + if (ret == 0 || direct_send_attempt) { + return 0; + } + + return -1; +} + +/** START: Array Related functions **/ + + +/* Return number of packets in array + * Note that holes are counted too. + */ +static uint32_t num_packets_array(const Packets_Array *array) +{ + return array->buffer_end - array->buffer_start; +} + +/* Add data with packet number to array. + * + * return -1 on failure. + * return 0 on success. + */ +static int add_data_to_buffer(Packets_Array *array, uint32_t number, const Packet_Data *data) +{ + if (number - array->buffer_start > CRYPTO_PACKET_BUFFER_SIZE) { + return -1; + } + + uint32_t num = number % CRYPTO_PACKET_BUFFER_SIZE; + + if (array->buffer[num]) { + return -1; + } + + Packet_Data *new_d = (Packet_Data *)malloc(sizeof(Packet_Data)); + + if (new_d == NULL) { + return -1; + } + + memcpy(new_d, data, sizeof(Packet_Data)); + array->buffer[num] = new_d; + + if ((number - array->buffer_start) >= (array->buffer_end - array->buffer_start)) { + array->buffer_end = number + 1; + } + + return 0; +} + +/* Get pointer of data with packet number. + * + * return -1 on failure. + * return 0 if data at number is empty. + * return 1 if data pointer was put in data. + */ +static int get_data_pointer(const Packets_Array *array, Packet_Data **data, uint32_t number) +{ + uint32_t num_spots = array->buffer_end - array->buffer_start; + + if (array->buffer_end - number > num_spots || number - array->buffer_start >= num_spots) { + return -1; + } + + uint32_t num = number % CRYPTO_PACKET_BUFFER_SIZE; + + if (!array->buffer[num]) { + return 0; + } + + *data = array->buffer[num]; + return 1; +} + +/* Add data to end of array. + * + * return -1 on failure. + * return packet number on success. + */ +static int64_t add_data_end_of_buffer(Packets_Array *array, const Packet_Data *data) +{ + if (num_packets_array(array) >= CRYPTO_PACKET_BUFFER_SIZE) { + return -1; + } + + Packet_Data *new_d = (Packet_Data *)malloc(sizeof(Packet_Data)); + + if (new_d == NULL) { + return -1; + } + + memcpy(new_d, data, sizeof(Packet_Data)); + uint32_t id = array->buffer_end; + array->buffer[id % CRYPTO_PACKET_BUFFER_SIZE] = new_d; + ++array->buffer_end; + return id; +} + +/* Read data from begginning of array. + * + * return -1 on failure. + * return packet number on success. + */ +static int64_t read_data_beg_buffer(Packets_Array *array, Packet_Data *data) +{ + if (array->buffer_end == array->buffer_start) { + return -1; + } + + uint32_t num = array->buffer_start % CRYPTO_PACKET_BUFFER_SIZE; + + if (!array->buffer[num]) { + return -1; + } + + memcpy(data, array->buffer[num], sizeof(Packet_Data)); + uint32_t id = array->buffer_start; + ++array->buffer_start; + free(array->buffer[num]); + array->buffer[num] = NULL; + return id; +} + +/* Delete all packets in array before number (but not number) + * + * return -1 on failure. + * return 0 on success + */ +static int clear_buffer_until(Packets_Array *array, uint32_t number) +{ + uint32_t num_spots = array->buffer_end - array->buffer_start; + + if (array->buffer_end - number >= num_spots || number - array->buffer_start > num_spots) { + return -1; + } + + uint32_t i; + + for (i = array->buffer_start; i != number; ++i) { + uint32_t num = i % CRYPTO_PACKET_BUFFER_SIZE; + + if (array->buffer[num]) { + free(array->buffer[num]); + array->buffer[num] = NULL; + } + } + + array->buffer_start = i; + return 0; +} + +static int clear_buffer(Packets_Array *array) +{ + uint32_t i; + + for (i = array->buffer_start; i != array->buffer_end; ++i) { + uint32_t num = i % CRYPTO_PACKET_BUFFER_SIZE; + + if (array->buffer[num]) { + free(array->buffer[num]); + array->buffer[num] = NULL; + } + } + + array->buffer_start = i; + return 0; +} + +/* Set array buffer end to number. + * + * return -1 on failure. + * return 0 on success. + */ +static int set_buffer_end(Packets_Array *array, uint32_t number) +{ + if ((number - array->buffer_start) > CRYPTO_PACKET_BUFFER_SIZE) { + return -1; + } + + if ((number - array->buffer_end) > CRYPTO_PACKET_BUFFER_SIZE) { + return -1; + } + + array->buffer_end = number; + return 0; +} + +/* Create a packet request packet from recv_array and send_buffer_end into + * data of length. + * + * return -1 on failure. + * return length of packet on success. + */ +static int generate_request_packet(uint8_t *data, uint16_t length, const Packets_Array *recv_array) +{ + if (length == 0) { + return -1; + } + + data[0] = PACKET_ID_REQUEST; + + uint16_t cur_len = 1; + + if (recv_array->buffer_start == recv_array->buffer_end) { + return cur_len; + } + + if (length <= cur_len) { + return cur_len; + } + + uint32_t i, n = 1; + + for (i = recv_array->buffer_start; i != recv_array->buffer_end; ++i) { + uint32_t num = i % CRYPTO_PACKET_BUFFER_SIZE; + + if (!recv_array->buffer[num]) { + data[cur_len] = n; + n = 0; + ++cur_len; + + if (length <= cur_len) { + return cur_len; + } + } else if (n == 255) { + data[cur_len] = 0; + n = 0; + ++cur_len; + + if (length <= cur_len) { + return cur_len; + } + } + + ++n; + } + + return cur_len; +} + +/* Handle a request data packet. + * Remove all the packets the other received from the array. + * + * return -1 on failure. + * return number of requested packets on success. + */ +static int handle_request_packet(Packets_Array *send_array, const uint8_t *data, uint16_t length, + uint64_t *latest_send_time, uint64_t rtt_time) +{ + if (length < 1) { + return -1; + } + + if (data[0] != PACKET_ID_REQUEST) { + return -1; + } + + if (length == 1) { + return 0; + } + + ++data; + --length; + + uint32_t i, n = 1; + uint32_t requested = 0; + + uint64_t temp_time = current_time_monotonic(); + uint64_t l_sent_time = ~0; + + for (i = send_array->buffer_start; i != send_array->buffer_end; ++i) { + if (length == 0) { + break; + } + + uint32_t num = i % CRYPTO_PACKET_BUFFER_SIZE; + + if (n == data[0]) { + if (send_array->buffer[num]) { + uint64_t sent_time = send_array->buffer[num]->sent_time; + + if ((sent_time + rtt_time) < temp_time) { + send_array->buffer[num]->sent_time = 0; + } + } + + ++data; + --length; + n = 0; + ++requested; + } else { + if (send_array->buffer[num]) { + uint64_t sent_time = send_array->buffer[num]->sent_time; + + if (l_sent_time < sent_time) { + l_sent_time = sent_time; + } + + free(send_array->buffer[num]); + send_array->buffer[num] = NULL; + } + } + + if (n == 255) { + n = 1; + + if (data[0] != 0) { + return -1; + } + + ++data; + --length; + } else { + ++n; + } + } + + if (*latest_send_time < l_sent_time) { + *latest_send_time = l_sent_time; + } + + return requested; +} + +/** END: Array Related functions **/ + +#define MAX_DATA_DATA_PACKET_SIZE (MAX_CRYPTO_PACKET_SIZE - (1 + sizeof(uint16_t) + CRYPTO_MAC_SIZE)) + +/* Creates and sends a data packet to the peer using the fastest route. + * + * return -1 on failure. + * return 0 on success. + */ +static int send_data_packet(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length) +{ + if (length == 0 || length + (1 + sizeof(uint16_t) + CRYPTO_MAC_SIZE) > MAX_CRYPTO_PACKET_SIZE) { + return -1; + } + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + pthread_mutex_lock(&conn->mutex); + VLA(uint8_t, packet, 1 + sizeof(uint16_t) + length + CRYPTO_MAC_SIZE); + packet[0] = NET_PACKET_CRYPTO_DATA; + memcpy(packet + 1, conn->sent_nonce + (CRYPTO_NONCE_SIZE - sizeof(uint16_t)), sizeof(uint16_t)); + int len = encrypt_data_symmetric(conn->shared_key, conn->sent_nonce, data, length, packet + 1 + sizeof(uint16_t)); + + if (len + 1 + sizeof(uint16_t) != SIZEOF_VLA(packet)) { + pthread_mutex_unlock(&conn->mutex); + return -1; + } + + increment_nonce(conn->sent_nonce); + pthread_mutex_unlock(&conn->mutex); + + return send_packet_to(c, crypt_connection_id, packet, SIZEOF_VLA(packet)); +} + +/* Creates and sends a data packet with buffer_start and num to the peer using the fastest route. + * + * return -1 on failure. + * return 0 on success. + */ +static int send_data_packet_helper(Net_Crypto *c, int crypt_connection_id, uint32_t buffer_start, uint32_t num, + const uint8_t *data, uint16_t length) +{ + if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) { + return -1; + } + + num = net_htonl(num); + buffer_start = net_htonl(buffer_start); + uint16_t padding_length = (MAX_CRYPTO_DATA_SIZE - length) % CRYPTO_MAX_PADDING; + VLA(uint8_t, packet, sizeof(uint32_t) + sizeof(uint32_t) + padding_length + length); + memcpy(packet, &buffer_start, sizeof(uint32_t)); + memcpy(packet + sizeof(uint32_t), &num, sizeof(uint32_t)); + memset(packet + (sizeof(uint32_t) * 2), PACKET_ID_PADDING, padding_length); + memcpy(packet + (sizeof(uint32_t) * 2) + padding_length, data, length); + + return send_data_packet(c, crypt_connection_id, packet, SIZEOF_VLA(packet)); +} + +static int reset_max_speed_reached(Net_Crypto *c, int crypt_connection_id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + /* If last packet send failed, try to send packet again. + If sending it fails we won't be able to send the new packet. */ + if (conn->maximum_speed_reached) { + Packet_Data *dt = NULL; + uint32_t packet_num = conn->send_array.buffer_end - 1; + int ret = get_data_pointer(&conn->send_array, &dt, packet_num); + + uint8_t send_failed = 0; + + if (ret == 1) { + if (!dt->sent_time) { + if (send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, packet_num, dt->data, + dt->length) != 0) { + send_failed = 1; + } else { + dt->sent_time = current_time_monotonic(); + } + } + } + + if (!send_failed) { + conn->maximum_speed_reached = 0; + } else { + return -1; + } + } + + return 0; +} + +/* return -1 if data could not be put in packet queue. + * return positive packet number if data was put into the queue. + */ +static int64_t send_lossless_packet(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length, + uint8_t congestion_control) +{ + if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) { + return -1; + } + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + /* If last packet send failed, try to send packet again. + If sending it fails we won't be able to send the new packet. */ + reset_max_speed_reached(c, crypt_connection_id); + + if (conn->maximum_speed_reached && congestion_control) { + return -1; + } + + Packet_Data dt; + dt.sent_time = 0; + dt.length = length; + memcpy(dt.data, data, length); + pthread_mutex_lock(&conn->mutex); + int64_t packet_num = add_data_end_of_buffer(&conn->send_array, &dt); + pthread_mutex_unlock(&conn->mutex); + + if (packet_num == -1) { + return -1; + } + + if (!congestion_control && conn->maximum_speed_reached) { + return packet_num; + } + + if (send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, packet_num, data, length) == 0) { + Packet_Data *dt1 = NULL; + + if (get_data_pointer(&conn->send_array, &dt1, packet_num) == 1) { + dt1->sent_time = current_time_monotonic(); + } + } else { + conn->maximum_speed_reached = 1; + LOGGER_ERROR(c->log, "send_data_packet failed\n"); + } + + return packet_num; +} + +/* Get the lowest 2 bytes from the nonce and convert + * them to host byte format before returning them. + */ +static uint16_t get_nonce_uint16(const uint8_t *nonce) +{ + uint16_t num; + memcpy(&num, nonce + (CRYPTO_NONCE_SIZE - sizeof(uint16_t)), sizeof(uint16_t)); + return net_ntohs(num); +} + +#define DATA_NUM_THRESHOLD 21845 + +/* Handle a data packet. + * Decrypt packet of length and put it into data. + * data must be at least MAX_DATA_DATA_PACKET_SIZE big. + * + * return -1 on failure. + * return length of data on success. + */ +static int handle_data_packet(const Net_Crypto *c, int crypt_connection_id, uint8_t *data, const uint8_t *packet, + uint16_t length) +{ + if (length <= (1 + sizeof(uint16_t) + CRYPTO_MAC_SIZE) || length > MAX_CRYPTO_PACKET_SIZE) { + return -1; + } + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + uint8_t nonce[CRYPTO_NONCE_SIZE]; + memcpy(nonce, conn->recv_nonce, CRYPTO_NONCE_SIZE); + uint16_t num_cur_nonce = get_nonce_uint16(nonce); + uint16_t num; + memcpy(&num, packet + 1, sizeof(uint16_t)); + num = net_ntohs(num); + uint16_t diff = num - num_cur_nonce; + increment_nonce_number(nonce, diff); + int len = decrypt_data_symmetric(conn->shared_key, nonce, packet + 1 + sizeof(uint16_t), + length - (1 + sizeof(uint16_t)), data); + + if ((unsigned int)len != length - (1 + sizeof(uint16_t) + CRYPTO_MAC_SIZE)) { + return -1; + } + + if (diff > DATA_NUM_THRESHOLD * 2) { + increment_nonce_number(conn->recv_nonce, DATA_NUM_THRESHOLD); + } + + return len; +} + +/* Send a request packet. + * + * return -1 on failure. + * return 0 on success. + */ +static int send_request_packet(Net_Crypto *c, int crypt_connection_id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + uint8_t data[MAX_CRYPTO_DATA_SIZE]; + int len = generate_request_packet(data, sizeof(data), &conn->recv_array); + + if (len == -1) { + return -1; + } + + return send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, conn->send_array.buffer_end, data, + len); +} + +/* Send up to max num previously requested data packets. + * + * return -1 on failure. + * return number of packets sent on success. + */ +static int send_requested_packets(Net_Crypto *c, int crypt_connection_id, uint32_t max_num) +{ + if (max_num == 0) { + return -1; + } + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + uint64_t temp_time = current_time_monotonic(); + uint32_t i, num_sent = 0, array_size = num_packets_array(&conn->send_array); + + for (i = 0; i < array_size; ++i) { + Packet_Data *dt; + uint32_t packet_num = (i + conn->send_array.buffer_start); + int ret = get_data_pointer(&conn->send_array, &dt, packet_num); + + if (ret == -1) { + return -1; + } + + if (ret == 0) { + continue; + } + + if (dt->sent_time) { + continue; + } + + if (send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, packet_num, dt->data, + dt->length) == 0) { + dt->sent_time = temp_time; + ++num_sent; + } + + if (num_sent >= max_num) { + break; + } + } + + return num_sent; +} + + +/* Add a new temp packet to send repeatedly. + * + * return -1 on failure. + * return 0 on success. + */ +static int new_temp_packet(const Net_Crypto *c, int crypt_connection_id, const uint8_t *packet, uint16_t length) +{ + if (length == 0 || length > MAX_CRYPTO_PACKET_SIZE) { + return -1; + } + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + uint8_t *temp_packet = (uint8_t *)malloc(length); + + if (temp_packet == 0) { + return -1; + } + + if (conn->temp_packet) { + free(conn->temp_packet); + } + + memcpy(temp_packet, packet, length); + conn->temp_packet = temp_packet; + conn->temp_packet_length = length; + conn->temp_packet_sent_time = 0; + conn->temp_packet_num_sent = 0; + return 0; +} + +/* Clear the temp packet. + * + * return -1 on failure. + * return 0 on success. + */ +static int clear_temp_packet(const Net_Crypto *c, int crypt_connection_id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + if (conn->temp_packet) { + free(conn->temp_packet); + } + + conn->temp_packet = 0; + conn->temp_packet_length = 0; + conn->temp_packet_sent_time = 0; + conn->temp_packet_num_sent = 0; + return 0; +} + + +/* Send the temp packet. + * + * return -1 on failure. + * return 0 on success. + */ +static int send_temp_packet(Net_Crypto *c, int crypt_connection_id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + if (!conn->temp_packet) { + return -1; + } + + if (send_packet_to(c, crypt_connection_id, conn->temp_packet, conn->temp_packet_length) != 0) { + return -1; + } + + conn->temp_packet_sent_time = current_time_monotonic(); + ++conn->temp_packet_num_sent; + return 0; +} + +/* Create a handshake packet and set it as a temp packet. + * cookie must be COOKIE_LENGTH. + * + * return -1 on failure. + * return 0 on success. + */ +static int create_send_handshake(Net_Crypto *c, int crypt_connection_id, const uint8_t *cookie, + const uint8_t *dht_public_key) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + uint8_t handshake_packet[HANDSHAKE_PACKET_LENGTH]; + + if (create_crypto_handshake(c, handshake_packet, cookie, conn->sent_nonce, conn->sessionpublic_key, + conn->public_key, dht_public_key) != sizeof(handshake_packet)) { + return -1; + } + + if (new_temp_packet(c, crypt_connection_id, handshake_packet, sizeof(handshake_packet)) != 0) { + return -1; + } + + send_temp_packet(c, crypt_connection_id); + return 0; +} + +/* Send a kill packet. + * + * return -1 on failure. + * return 0 on success. + */ +static int send_kill_packet(Net_Crypto *c, int crypt_connection_id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + uint8_t kill_packet = PACKET_ID_KILL; + return send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, conn->send_array.buffer_end, + &kill_packet, sizeof(kill_packet)); +} + +static void connection_kill(Net_Crypto *c, int crypt_connection_id, void *userdata) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return; + } + + if (conn->connection_status_callback) { + conn->connection_status_callback(conn->connection_status_callback_object, conn->connection_status_callback_id, 0, + userdata); + } + + crypto_kill(c, crypt_connection_id); +} + +/* Handle a received data packet. + * + * return -1 on failure. + * return 0 on success. + */ +static int handle_data_packet_core(Net_Crypto *c, int crypt_connection_id, const uint8_t *packet, uint16_t length, + bool udp, void *userdata) +{ + if (length > MAX_CRYPTO_PACKET_SIZE || length <= CRYPTO_DATA_PACKET_MIN_SIZE) { + return -1; + } + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + uint8_t data[MAX_DATA_DATA_PACKET_SIZE]; + int len = handle_data_packet(c, crypt_connection_id, data, packet, length); + + if (len <= (int)(sizeof(uint32_t) * 2)) { + return -1; + } + + uint32_t buffer_start, num; + memcpy(&buffer_start, data, sizeof(uint32_t)); + memcpy(&num, data + sizeof(uint32_t), sizeof(uint32_t)); + buffer_start = net_ntohl(buffer_start); + num = net_ntohl(num); + + uint64_t rtt_calc_time = 0; + + if (buffer_start != conn->send_array.buffer_start) { + Packet_Data *packet_time; + + if (get_data_pointer(&conn->send_array, &packet_time, conn->send_array.buffer_start) == 1) { + rtt_calc_time = packet_time->sent_time; + } + + if (clear_buffer_until(&conn->send_array, buffer_start) != 0) { + return -1; + } + } + + uint8_t *real_data = data + (sizeof(uint32_t) * 2); + uint16_t real_length = len - (sizeof(uint32_t) * 2); + + while (real_data[0] == PACKET_ID_PADDING) { /* Remove Padding */ + ++real_data; + --real_length; + + if (real_length == 0) { + return -1; + } + } + + if (real_data[0] == PACKET_ID_KILL) { + connection_kill(c, crypt_connection_id, userdata); + return 0; + } + + if (conn->status == CRYPTO_CONN_NOT_CONFIRMED) { + clear_temp_packet(c, crypt_connection_id); + conn->status = CRYPTO_CONN_ESTABLISHED; + + if (conn->connection_status_callback) { + conn->connection_status_callback(conn->connection_status_callback_object, conn->connection_status_callback_id, 1, + userdata); + } + } + + if (real_data[0] == PACKET_ID_REQUEST) { + uint64_t rtt_time; + + if (udp) { + rtt_time = conn->rtt_time; + } else { + rtt_time = DEFAULT_TCP_PING_CONNECTION; + } + + int requested = handle_request_packet(&conn->send_array, real_data, real_length, &rtt_calc_time, rtt_time); + + if (requested == -1) { + return -1; + } + + // else { /* TODO(irungentoo): ? */ } + + set_buffer_end(&conn->recv_array, num); + } else if (real_data[0] >= CRYPTO_RESERVED_PACKETS && real_data[0] < PACKET_ID_LOSSY_RANGE_START) { + Packet_Data dt; + dt.length = real_length; + memcpy(dt.data, real_data, real_length); + + if (add_data_to_buffer(&conn->recv_array, num, &dt) != 0) { + return -1; + } + + while (1) { + pthread_mutex_lock(&conn->mutex); + int ret = read_data_beg_buffer(&conn->recv_array, &dt); + pthread_mutex_unlock(&conn->mutex); + + if (ret == -1) { + break; + } + + if (conn->connection_data_callback) { + conn->connection_data_callback(conn->connection_data_callback_object, conn->connection_data_callback_id, dt.data, + dt.length, userdata); + } + + /* conn might get killed in callback. */ + conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + } + + /* Packet counter. */ + ++conn->packet_counter; + } else if (real_data[0] >= PACKET_ID_LOSSY_RANGE_START && + real_data[0] < (PACKET_ID_LOSSY_RANGE_START + PACKET_ID_LOSSY_RANGE_SIZE)) { + + set_buffer_end(&conn->recv_array, num); + + if (conn->connection_lossy_data_callback) { + conn->connection_lossy_data_callback(conn->connection_lossy_data_callback_object, + conn->connection_lossy_data_callback_id, real_data, real_length, userdata); + } + } else { + return -1; + } + + if (rtt_calc_time != 0) { + uint64_t rtt_time = current_time_monotonic() - rtt_calc_time; + + if (rtt_time < conn->rtt_time) { + conn->rtt_time = rtt_time; + } + } + + return 0; +} + +/* Handle a packet that was received for the connection. + * + * return -1 on failure. + * return 0 on success. + */ +static int handle_packet_connection(Net_Crypto *c, int crypt_connection_id, const uint8_t *packet, uint16_t length, + bool udp, void *userdata) +{ + if (length == 0 || length > MAX_CRYPTO_PACKET_SIZE) { + return -1; + } + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + switch (packet[0]) { + case NET_PACKET_COOKIE_RESPONSE: { + if (conn->status != CRYPTO_CONN_COOKIE_REQUESTING) { + return -1; + } + + uint8_t cookie[COOKIE_LENGTH]; + uint64_t number; + + if (handle_cookie_response(cookie, &number, packet, length, conn->shared_key) != sizeof(cookie)) { + return -1; + } + + if (number != conn->cookie_request_number) { + return -1; + } + + if (create_send_handshake(c, crypt_connection_id, cookie, conn->dht_public_key) != 0) { + return -1; + } + + conn->status = CRYPTO_CONN_HANDSHAKE_SENT; + return 0; + } + + case NET_PACKET_CRYPTO_HS: { + if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING || conn->status == CRYPTO_CONN_HANDSHAKE_SENT + || conn->status == CRYPTO_CONN_NOT_CONFIRMED) { + uint8_t peer_real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t cookie[COOKIE_LENGTH]; + + if (handle_crypto_handshake(c, conn->recv_nonce, conn->peersessionpublic_key, peer_real_pk, dht_public_key, cookie, + packet, length, conn->public_key) != 0) { + return -1; + } + + if (public_key_cmp(dht_public_key, conn->dht_public_key) == 0) { + encrypt_precompute(conn->peersessionpublic_key, conn->sessionsecret_key, conn->shared_key); + + if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING) { + if (create_send_handshake(c, crypt_connection_id, cookie, dht_public_key) != 0) { + return -1; + } + } + + conn->status = CRYPTO_CONN_NOT_CONFIRMED; + } else { + if (conn->dht_pk_callback) { + conn->dht_pk_callback(conn->dht_pk_callback_object, conn->dht_pk_callback_number, dht_public_key, userdata); + } + } + } else { + return -1; + } + + return 0; + } + + case NET_PACKET_CRYPTO_DATA: { + if (conn->status == CRYPTO_CONN_NOT_CONFIRMED || conn->status == CRYPTO_CONN_ESTABLISHED) { + return handle_data_packet_core(c, crypt_connection_id, packet, length, udp, userdata); + } + + return -1; + } + + default: { + return -1; + } + } +} + +/* Set the size of the friend list to numfriends. + * + * return -1 if realloc fails. + * return 0 if it succeeds. + */ +static int realloc_cryptoconnection(Net_Crypto *c, uint32_t num) +{ + if (num == 0) { + free(c->crypto_connections); + c->crypto_connections = NULL; + return 0; + } + + Crypto_Connection *newcrypto_connections = (Crypto_Connection *)realloc(c->crypto_connections, + num * sizeof(Crypto_Connection)); + + if (newcrypto_connections == NULL) { + return -1; + } + + c->crypto_connections = newcrypto_connections; + return 0; +} + + +/* Create a new empty crypto connection. + * + * return -1 on failure. + * return connection id on success. + */ +static int create_crypto_connection(Net_Crypto *c) +{ + uint32_t i; + + for (i = 0; i < c->crypto_connections_length; ++i) { + if (c->crypto_connections[i].status == CRYPTO_CONN_NO_CONNECTION) { + return i; + } + } + + while (1) { /* TODO(irungentoo): is this really the best way to do this? */ + pthread_mutex_lock(&c->connections_mutex); + + if (!c->connection_use_counter) { + break; + } + + pthread_mutex_unlock(&c->connections_mutex); + } + + int id = -1; + + if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == 0) { + id = c->crypto_connections_length; + ++c->crypto_connections_length; + memset(&(c->crypto_connections[id]), 0, sizeof(Crypto_Connection)); + // Memsetting float/double to 0 is non-portable, so we explicitly set them to 0 + c->crypto_connections[id].packet_recv_rate = 0; + c->crypto_connections[id].packet_send_rate = 0; + c->crypto_connections[id].last_packets_left_rem = 0; + c->crypto_connections[id].packet_send_rate_requested = 0; + c->crypto_connections[id].last_packets_left_requested_rem = 0; + + if (pthread_mutex_init(&c->crypto_connections[id].mutex, NULL) != 0) { + pthread_mutex_unlock(&c->connections_mutex); + return -1; + } + } + + pthread_mutex_unlock(&c->connections_mutex); + return id; +} + +/* Wipe a crypto connection. + * + * return -1 on failure. + * return 0 on success. + */ +static int wipe_crypto_connection(Net_Crypto *c, int crypt_connection_id) +{ + if (crypt_connection_id_not_valid(c, crypt_connection_id)) { + return -1; + } + + uint32_t i; + + /* Keep mutex, only destroy it when connection is realloced out. */ + pthread_mutex_t mutex = c->crypto_connections[crypt_connection_id].mutex; + crypto_memzero(&(c->crypto_connections[crypt_connection_id]), sizeof(Crypto_Connection)); + c->crypto_connections[crypt_connection_id].mutex = mutex; + + for (i = c->crypto_connections_length; i != 0; --i) { + if (c->crypto_connections[i - 1].status == CRYPTO_CONN_NO_CONNECTION) { + pthread_mutex_destroy(&c->crypto_connections[i - 1].mutex); + } else { + break; + } + } + + if (c->crypto_connections_length != i) { + c->crypto_connections_length = i; + realloc_cryptoconnection(c, c->crypto_connections_length); + } + + return 0; +} + +/* Get crypto connection id from public key of peer. + * + * return -1 if there are no connections like we are looking for. + * return id if it found it. + */ +static int getcryptconnection_id(const Net_Crypto *c, const uint8_t *public_key) +{ + uint32_t i; + + for (i = 0; i < c->crypto_connections_length; ++i) { + if (c->crypto_connections[i].status != CRYPTO_CONN_NO_CONNECTION) { + if (public_key_cmp(public_key, c->crypto_connections[i].public_key) == 0) { + return i; + } + } + } + + return -1; +} + +/* Add a source to the crypto connection. + * This is to be used only when we have received a packet from that source. + * + * return -1 on failure. + * return positive number on success. + * 0 if source was a direct UDP connection. + */ +static int crypto_connection_add_source(Net_Crypto *c, int crypt_connection_id, IP_Port source) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + if (source.ip.family == TOX_AF_INET || source.ip.family == TOX_AF_INET6) { + if (add_ip_port_connection(c, crypt_connection_id, source) != 0) { + return -1; + } + + if (source.ip.family == TOX_AF_INET) { + conn->direct_lastrecv_timev4 = unix_time(); + } else { + conn->direct_lastrecv_timev6 = unix_time(); + } + + return 0; + } + + if (source.ip.family == TCP_FAMILY) { + if (add_tcp_number_relay_connection(c->tcp_c, conn->connection_number_tcp, source.ip.ip6.uint32[0]) == 0) { + return 1; + } + } + + return -1; +} + + +/* Set function to be called when someone requests a new connection to us. + * + * The set function should return -1 on failure and 0 on success. + * + * n_c is only valid for the duration of the function call. + */ +void new_connection_handler(Net_Crypto *c, int (*new_connection_callback)(void *object, New_Connection *n_c), + void *object) +{ + c->new_connection_callback = new_connection_callback; + c->new_connection_callback_object = object; +} + +/* Handle a handshake packet by someone who wants to initiate a new connection with us. + * This calls the callback set by new_connection_handler() if the handshake is ok. + * + * return -1 on failure. + * return 0 on success. + */ +static int handle_new_connection_handshake(Net_Crypto *c, IP_Port source, const uint8_t *data, uint16_t length, + void *userdata) +{ + New_Connection n_c; + n_c.cookie = (uint8_t *)malloc(COOKIE_LENGTH); + + if (n_c.cookie == NULL) { + return -1; + } + + n_c.source = source; + n_c.cookie_length = COOKIE_LENGTH; + + if (handle_crypto_handshake(c, n_c.recv_nonce, n_c.peersessionpublic_key, n_c.public_key, n_c.dht_public_key, + n_c.cookie, data, length, 0) != 0) { + free(n_c.cookie); + return -1; + } + + int crypt_connection_id = getcryptconnection_id(c, n_c.public_key); + + if (crypt_connection_id != -1) { + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (public_key_cmp(n_c.dht_public_key, conn->dht_public_key) != 0) { + connection_kill(c, crypt_connection_id, userdata); + } else { + int ret = -1; + + if (conn && (conn->status == CRYPTO_CONN_COOKIE_REQUESTING || conn->status == CRYPTO_CONN_HANDSHAKE_SENT)) { + memcpy(conn->recv_nonce, n_c.recv_nonce, CRYPTO_NONCE_SIZE); + memcpy(conn->peersessionpublic_key, n_c.peersessionpublic_key, CRYPTO_PUBLIC_KEY_SIZE); + encrypt_precompute(conn->peersessionpublic_key, conn->sessionsecret_key, conn->shared_key); + + crypto_connection_add_source(c, crypt_connection_id, source); + + if (create_send_handshake(c, crypt_connection_id, n_c.cookie, n_c.dht_public_key) == 0) { + conn->status = CRYPTO_CONN_NOT_CONFIRMED; + ret = 0; + } + } + + free(n_c.cookie); + return ret; + } + } + + int ret = c->new_connection_callback(c->new_connection_callback_object, &n_c); + free(n_c.cookie); + return ret; +} + +/* Accept a crypto connection. + * + * return -1 on failure. + * return connection id on success. + */ +int accept_crypto_connection(Net_Crypto *c, New_Connection *n_c) +{ + if (getcryptconnection_id(c, n_c->public_key) != -1) { + return -1; + } + + int crypt_connection_id = create_crypto_connection(c); + + if (crypt_connection_id == -1) { + return -1; + } + + Crypto_Connection *conn = &c->crypto_connections[crypt_connection_id]; + + if (n_c->cookie_length != COOKIE_LENGTH) { + return -1; + } + + pthread_mutex_lock(&c->tcp_mutex); + int connection_number_tcp = new_tcp_connection_to(c->tcp_c, n_c->dht_public_key, crypt_connection_id); + pthread_mutex_unlock(&c->tcp_mutex); + + if (connection_number_tcp == -1) { + return -1; + } + + conn->connection_number_tcp = connection_number_tcp; + memcpy(conn->public_key, n_c->public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(conn->recv_nonce, n_c->recv_nonce, CRYPTO_NONCE_SIZE); + memcpy(conn->peersessionpublic_key, n_c->peersessionpublic_key, CRYPTO_PUBLIC_KEY_SIZE); + random_nonce(conn->sent_nonce); + crypto_new_keypair(conn->sessionpublic_key, conn->sessionsecret_key); + encrypt_precompute(conn->peersessionpublic_key, conn->sessionsecret_key, conn->shared_key); + conn->status = CRYPTO_CONN_NOT_CONFIRMED; + + if (create_send_handshake(c, crypt_connection_id, n_c->cookie, n_c->dht_public_key) != 0) { + pthread_mutex_lock(&c->tcp_mutex); + kill_tcp_connection_to(c->tcp_c, conn->connection_number_tcp); + pthread_mutex_unlock(&c->tcp_mutex); + conn->status = CRYPTO_CONN_NO_CONNECTION; + return -1; + } + + memcpy(conn->dht_public_key, n_c->dht_public_key, CRYPTO_PUBLIC_KEY_SIZE); + conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE; + conn->packet_send_rate_requested = CRYPTO_PACKET_MIN_RATE; + conn->packets_left = CRYPTO_MIN_QUEUE_LENGTH; + conn->rtt_time = DEFAULT_PING_CONNECTION; + crypto_connection_add_source(c, crypt_connection_id, n_c->source); + return crypt_connection_id; +} + +/* Create a crypto connection. + * If one to that real public key already exists, return it. + * + * return -1 on failure. + * return connection id on success. + */ +int new_crypto_connection(Net_Crypto *c, const uint8_t *real_public_key, const uint8_t *dht_public_key) +{ + int crypt_connection_id = getcryptconnection_id(c, real_public_key); + + if (crypt_connection_id != -1) { + return crypt_connection_id; + } + + crypt_connection_id = create_crypto_connection(c); + + if (crypt_connection_id == -1) { + return -1; + } + + Crypto_Connection *conn = &c->crypto_connections[crypt_connection_id]; + + if (conn == 0) { + return -1; + } + + pthread_mutex_lock(&c->tcp_mutex); + int connection_number_tcp = new_tcp_connection_to(c->tcp_c, dht_public_key, crypt_connection_id); + pthread_mutex_unlock(&c->tcp_mutex); + + if (connection_number_tcp == -1) { + return -1; + } + + conn->connection_number_tcp = connection_number_tcp; + memcpy(conn->public_key, real_public_key, CRYPTO_PUBLIC_KEY_SIZE); + random_nonce(conn->sent_nonce); + crypto_new_keypair(conn->sessionpublic_key, conn->sessionsecret_key); + conn->status = CRYPTO_CONN_COOKIE_REQUESTING; + conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE; + conn->packet_send_rate_requested = CRYPTO_PACKET_MIN_RATE; + conn->packets_left = CRYPTO_MIN_QUEUE_LENGTH; + conn->rtt_time = DEFAULT_PING_CONNECTION; + memcpy(conn->dht_public_key, dht_public_key, CRYPTO_PUBLIC_KEY_SIZE); + + conn->cookie_request_number = random_64b(); + uint8_t cookie_request[COOKIE_REQUEST_LENGTH]; + + if (create_cookie_request(c, cookie_request, conn->dht_public_key, conn->cookie_request_number, + conn->shared_key) != sizeof(cookie_request) + || new_temp_packet(c, crypt_connection_id, cookie_request, sizeof(cookie_request)) != 0) { + pthread_mutex_lock(&c->tcp_mutex); + kill_tcp_connection_to(c->tcp_c, conn->connection_number_tcp); + pthread_mutex_unlock(&c->tcp_mutex); + conn->status = CRYPTO_CONN_NO_CONNECTION; + return -1; + } + + return crypt_connection_id; +} + +/* Set the direct ip of the crypto connection. + * + * Connected is 0 if we are not sure we are connected to that person, 1 if we are sure. + * + * return -1 on failure. + * return 0 on success. + */ +int set_direct_ip_port(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port, bool connected) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + if (add_ip_port_connection(c, crypt_connection_id, ip_port) == 0) { + if (connected) { + if (ip_port.ip.family == TOX_AF_INET) { + conn->direct_lastrecv_timev4 = unix_time(); + } else { + conn->direct_lastrecv_timev6 = unix_time(); + } + } else { + if (ip_port.ip.family == TOX_AF_INET) { + conn->direct_lastrecv_timev4 = 0; + } else { + conn->direct_lastrecv_timev6 = 0; + } + } + + return 0; + } + + return -1; +} + + +static int tcp_data_callback(void *object, int id, const uint8_t *data, uint16_t length, void *userdata) +{ + if (length == 0 || length > MAX_CRYPTO_PACKET_SIZE) { + return -1; + } + + Net_Crypto *c = (Net_Crypto *)object; + + Crypto_Connection *conn = get_crypto_connection(c, id); + + if (conn == 0) { + return -1; + } + + if (data[0] == NET_PACKET_COOKIE_REQUEST) { + return tcp_handle_cookie_request(c, conn->connection_number_tcp, data, length); + } + + // This unlocks the mutex that at this point is locked by do_tcp before + // calling do_tcp_connections. + pthread_mutex_unlock(&c->tcp_mutex); + int ret = handle_packet_connection(c, id, data, length, 0, userdata); + pthread_mutex_lock(&c->tcp_mutex); + + if (ret != 0) { + return -1; + } + + // TODO(irungentoo): detect and kill bad TCP connections. + return 0; +} + +static int tcp_oob_callback(void *object, const uint8_t *public_key, unsigned int tcp_connections_number, + const uint8_t *data, uint16_t length, void *userdata) +{ + if (length == 0 || length > MAX_CRYPTO_PACKET_SIZE) { + return -1; + } + + Net_Crypto *c = (Net_Crypto *)object; + + if (data[0] == NET_PACKET_COOKIE_REQUEST) { + return tcp_oob_handle_cookie_request(c, tcp_connections_number, public_key, data, length); + } + + if (data[0] == NET_PACKET_CRYPTO_HS) { + IP_Port source; + source.port = 0; + source.ip.family = TCP_FAMILY; + source.ip.ip6.uint32[0] = tcp_connections_number; + + if (handle_new_connection_handshake(c, source, data, length, userdata) != 0) { + return -1; + } + + return 0; + } + + return -1; +} + +/* Add a tcp relay, associating it to a crypt_connection_id. + * + * return 0 if it was added. + * return -1 if it wasn't. + */ +int add_tcp_relay_peer(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port, const uint8_t *public_key) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + pthread_mutex_lock(&c->tcp_mutex); + int ret = add_tcp_relay_connection(c->tcp_c, conn->connection_number_tcp, ip_port, public_key); + pthread_mutex_unlock(&c->tcp_mutex); + return ret; +} + +/* Add a tcp relay to the array. + * + * return 0 if it was added. + * return -1 if it wasn't. + */ +int add_tcp_relay(Net_Crypto *c, IP_Port ip_port, const uint8_t *public_key) +{ + pthread_mutex_lock(&c->tcp_mutex); + int ret = add_tcp_relay_global(c->tcp_c, ip_port, public_key); + pthread_mutex_unlock(&c->tcp_mutex); + return ret; +} + +/* Return a random TCP connection number for use in send_tcp_onion_request. + * + * TODO(irungentoo): This number is just the index of an array that the elements can + * change without warning. + * + * return TCP connection number on success. + * return -1 on failure. + */ +int get_random_tcp_con_number(Net_Crypto *c) +{ + pthread_mutex_lock(&c->tcp_mutex); + int ret = get_random_tcp_onion_conn_number(c->tcp_c); + pthread_mutex_unlock(&c->tcp_mutex); + + return ret; +} + +/* Send an onion packet via the TCP relay corresponding to tcp_connections_number. + * + * return 0 on success. + * return -1 on failure. + */ +int send_tcp_onion_request(Net_Crypto *c, unsigned int tcp_connections_number, const uint8_t *data, uint16_t length) +{ + pthread_mutex_lock(&c->tcp_mutex); + int ret = tcp_send_onion_request(c->tcp_c, tcp_connections_number, data, length); + pthread_mutex_unlock(&c->tcp_mutex); + + return ret; +} + +/* Copy a maximum of num TCP relays we are connected to to tcp_relays. + * NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6. + * + * return number of relays copied to tcp_relays on success. + * return 0 on failure. + */ +unsigned int copy_connected_tcp_relays(Net_Crypto *c, Node_format *tcp_relays, uint16_t num) +{ + if (num == 0) { + return 0; + } + + pthread_mutex_lock(&c->tcp_mutex); + unsigned int ret = tcp_copy_connected_relays(c->tcp_c, tcp_relays, num); + pthread_mutex_unlock(&c->tcp_mutex); + + return ret; +} + +static void do_tcp(Net_Crypto *c, void *userdata) +{ + pthread_mutex_lock(&c->tcp_mutex); + do_tcp_connections(c->tcp_c, userdata); + pthread_mutex_unlock(&c->tcp_mutex); + + uint32_t i; + + for (i = 0; i < c->crypto_connections_length; ++i) { + Crypto_Connection *conn = get_crypto_connection(c, i); + + if (conn == 0) { + return; + } + + if (conn->status == CRYPTO_CONN_ESTABLISHED) { + bool direct_connected = 0; + crypto_connection_status(c, i, &direct_connected, NULL); + + if (direct_connected) { + pthread_mutex_lock(&c->tcp_mutex); + set_tcp_connection_to_status(c->tcp_c, conn->connection_number_tcp, 0); + pthread_mutex_unlock(&c->tcp_mutex); + } else { + pthread_mutex_lock(&c->tcp_mutex); + set_tcp_connection_to_status(c->tcp_c, conn->connection_number_tcp, 1); + pthread_mutex_unlock(&c->tcp_mutex); + } + } + } +} + +/* Set function to be called when connection with crypt_connection_id goes connects/disconnects. + * + * The set function should return -1 on failure and 0 on success. + * Note that if this function is set, the connection will clear itself on disconnect. + * Object and id will be passed to this function untouched. + * status is 1 if the connection is going online, 0 if it is going offline. + * + * return -1 on failure. + * return 0 on success. + */ +int connection_status_handler(const Net_Crypto *c, int crypt_connection_id, + int (*connection_status_callback)(void *object, int id, uint8_t status, void *userdata), void *object, int id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + conn->connection_status_callback = connection_status_callback; + conn->connection_status_callback_object = object; + conn->connection_status_callback_id = id; + return 0; +} + +/* Set function to be called when connection with crypt_connection_id receives a data packet of length. + * + * The set function should return -1 on failure and 0 on success. + * Object and id will be passed to this function untouched. + * + * return -1 on failure. + * return 0 on success. + */ +int connection_data_handler(const Net_Crypto *c, int crypt_connection_id, int (*connection_data_callback)(void *object, + int id, const uint8_t *data, uint16_t length, void *userdata), void *object, int id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + conn->connection_data_callback = connection_data_callback; + conn->connection_data_callback_object = object; + conn->connection_data_callback_id = id; + return 0; +} + +/* Set function to be called when connection with crypt_connection_id receives a lossy data packet of length. + * + * The set function should return -1 on failure and 0 on success. + * Object and id will be passed to this function untouched. + * + * return -1 on failure. + * return 0 on success. + */ +int connection_lossy_data_handler(Net_Crypto *c, int crypt_connection_id, + int (*connection_lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length, void *userdata), + void *object, int id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + conn->connection_lossy_data_callback = connection_lossy_data_callback; + conn->connection_lossy_data_callback_object = object; + conn->connection_lossy_data_callback_id = id; + return 0; +} + + +/* Set the function for this friend that will be callbacked with object and number if + * the friend sends us a different dht public key than we have associated to him. + * + * If this function is called, the connection should be recreated with the new public key. + * + * object and number will be passed as argument to this function. + * + * return -1 on failure. + * return 0 on success. + */ +int nc_dht_pk_callback(Net_Crypto *c, int crypt_connection_id, void (*function)(void *data, int32_t number, + const uint8_t *dht_public_key, void *userdata), void *object, uint32_t number) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + conn->dht_pk_callback = function; + conn->dht_pk_callback_object = object; + conn->dht_pk_callback_number = number; + return 0; +} + +/* Get the crypto connection id from the ip_port. + * + * return -1 on failure. + * return connection id on success. + */ +static int crypto_id_ip_port(const Net_Crypto *c, IP_Port ip_port) +{ + return bs_list_find(&c->ip_port_list, (uint8_t *)&ip_port); +} + +#define CRYPTO_MIN_PACKET_SIZE (1 + sizeof(uint16_t) + CRYPTO_MAC_SIZE) + +/* Handle raw UDP packets coming directly from the socket. + * + * Handles: + * Cookie response packets. + * Crypto handshake packets. + * Crypto data packets. + * + */ +static int udp_handle_packet(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + if (length <= CRYPTO_MIN_PACKET_SIZE || length > MAX_CRYPTO_PACKET_SIZE) { + return 1; + } + + Net_Crypto *c = (Net_Crypto *)object; + int crypt_connection_id = crypto_id_ip_port(c, source); + + if (crypt_connection_id == -1) { + if (packet[0] != NET_PACKET_CRYPTO_HS) { + return 1; + } + + if (handle_new_connection_handshake(c, source, packet, length, userdata) != 0) { + return 1; + } + + return 0; + } + + if (handle_packet_connection(c, crypt_connection_id, packet, length, 1, userdata) != 0) { + return 1; + } + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + pthread_mutex_lock(&conn->mutex); + + if (source.ip.family == TOX_AF_INET) { + conn->direct_lastrecv_timev4 = unix_time(); + } else { + conn->direct_lastrecv_timev6 = unix_time(); + } + + pthread_mutex_unlock(&conn->mutex); + return 0; +} + +/* The dT for the average packet receiving rate calculations. + Also used as the */ +#define PACKET_COUNTER_AVERAGE_INTERVAL 50 + +/* Ratio of recv queue size / recv packet rate (in seconds) times + * the number of ms between request packets to send at that ratio + */ +#define REQUEST_PACKETS_COMPARE_CONSTANT (0.125 * 100.0) + +/* Timeout for increasing speed after congestion event (in ms). */ +#define CONGESTION_EVENT_TIMEOUT 1000 + +/* If the send queue is SEND_QUEUE_RATIO times larger than the + * calculated link speed the packet send speed will be reduced + * by a value depending on this number. + */ +#define SEND_QUEUE_RATIO 2.0 + +static void send_crypto_packets(Net_Crypto *c) +{ + uint32_t i; + uint64_t temp_time = current_time_monotonic(); + double total_send_rate = 0; + uint32_t peak_request_packet_interval = ~0; + + for (i = 0; i < c->crypto_connections_length; ++i) { + Crypto_Connection *conn = get_crypto_connection(c, i); + + if (conn == 0) { + return; + } + + if (CRYPTO_SEND_PACKET_INTERVAL + conn->temp_packet_sent_time < temp_time) { + send_temp_packet(c, i); + } + + if ((conn->status == CRYPTO_CONN_NOT_CONFIRMED || conn->status == CRYPTO_CONN_ESTABLISHED) + && ((CRYPTO_SEND_PACKET_INTERVAL) + conn->last_request_packet_sent) < temp_time) { + if (send_request_packet(c, i) == 0) { + conn->last_request_packet_sent = temp_time; + } + } + + if (conn->status == CRYPTO_CONN_ESTABLISHED) { + if (conn->packet_recv_rate > CRYPTO_PACKET_MIN_RATE) { + double request_packet_interval = (REQUEST_PACKETS_COMPARE_CONSTANT / ((num_packets_array( + &conn->recv_array) + 1.0) / (conn->packet_recv_rate + 1.0))); + + double request_packet_interval2 = ((CRYPTO_PACKET_MIN_RATE / conn->packet_recv_rate) * + (double)CRYPTO_SEND_PACKET_INTERVAL) + (double)PACKET_COUNTER_AVERAGE_INTERVAL; + + if (request_packet_interval2 < request_packet_interval) { + request_packet_interval = request_packet_interval2; + } + + if (request_packet_interval < PACKET_COUNTER_AVERAGE_INTERVAL) { + request_packet_interval = PACKET_COUNTER_AVERAGE_INTERVAL; + } + + if (request_packet_interval > CRYPTO_SEND_PACKET_INTERVAL) { + request_packet_interval = CRYPTO_SEND_PACKET_INTERVAL; + } + + if (temp_time - conn->last_request_packet_sent > (uint64_t)request_packet_interval) { + if (send_request_packet(c, i) == 0) { + conn->last_request_packet_sent = temp_time; + } + } + + if (request_packet_interval < peak_request_packet_interval) { + peak_request_packet_interval = request_packet_interval; + } + } + + if ((PACKET_COUNTER_AVERAGE_INTERVAL + conn->packet_counter_set) < temp_time) { + + double dt = temp_time - conn->packet_counter_set; + + conn->packet_recv_rate = (double)conn->packet_counter / (dt / 1000.0); + conn->packet_counter = 0; + conn->packet_counter_set = temp_time; + + uint32_t packets_sent = conn->packets_sent; + conn->packets_sent = 0; + + uint32_t packets_resent = conn->packets_resent; + conn->packets_resent = 0; + + /* conjestion control + calculate a new value of conn->packet_send_rate based on some data + */ + + unsigned int pos = conn->last_sendqueue_counter % CONGESTION_QUEUE_ARRAY_SIZE; + conn->last_sendqueue_size[pos] = num_packets_array(&conn->send_array); + ++conn->last_sendqueue_counter; + + unsigned int j; + long signed int sum = 0; + sum = (long signed int)conn->last_sendqueue_size[(pos) % CONGESTION_QUEUE_ARRAY_SIZE] - + (long signed int)conn->last_sendqueue_size[(pos - (CONGESTION_QUEUE_ARRAY_SIZE - 1)) % CONGESTION_QUEUE_ARRAY_SIZE]; + + unsigned int n_p_pos = conn->last_sendqueue_counter % CONGESTION_LAST_SENT_ARRAY_SIZE; + conn->last_num_packets_sent[n_p_pos] = packets_sent; + conn->last_num_packets_resent[n_p_pos] = packets_resent; + + bool direct_connected = 0; + crypto_connection_status(c, i, &direct_connected, NULL); + + if (direct_connected && conn->last_tcp_sent + CONGESTION_EVENT_TIMEOUT > temp_time) { + /* When switching from TCP to UDP, don't change the packet send rate for CONGESTION_EVENT_TIMEOUT ms. */ + } else { + long signed int total_sent = 0, total_resent = 0; + + // TODO(irungentoo): use real delay + unsigned int delay = (unsigned int)((conn->rtt_time / PACKET_COUNTER_AVERAGE_INTERVAL) + 0.5); + unsigned int packets_set_rem_array = (CONGESTION_LAST_SENT_ARRAY_SIZE - CONGESTION_QUEUE_ARRAY_SIZE); + + if (delay > packets_set_rem_array) { + delay = packets_set_rem_array; + } + + for (j = 0; j < CONGESTION_QUEUE_ARRAY_SIZE; ++j) { + unsigned int ind = (j + (packets_set_rem_array - delay) + n_p_pos) % CONGESTION_LAST_SENT_ARRAY_SIZE; + total_sent += conn->last_num_packets_sent[ind]; + total_resent += conn->last_num_packets_resent[ind]; + } + + if (sum > 0) { + total_sent -= sum; + } else { + if (total_resent > -sum) { + total_resent = -sum; + } + } + + /* if queue is too big only allow resending packets. */ + uint32_t npackets = num_packets_array(&conn->send_array); + double min_speed = 1000.0 * (((double)(total_sent)) / ((double)(CONGESTION_QUEUE_ARRAY_SIZE) * + PACKET_COUNTER_AVERAGE_INTERVAL)); + + double min_speed_request = 1000.0 * (((double)(total_sent + total_resent)) / ((double)( + CONGESTION_QUEUE_ARRAY_SIZE) * PACKET_COUNTER_AVERAGE_INTERVAL)); + + if (min_speed < CRYPTO_PACKET_MIN_RATE) { + min_speed = CRYPTO_PACKET_MIN_RATE; + } + + double send_array_ratio = (((double)npackets) / min_speed); + + // TODO(irungentoo): Improve formula? + if (send_array_ratio > SEND_QUEUE_RATIO && CRYPTO_MIN_QUEUE_LENGTH < npackets) { + conn->packet_send_rate = min_speed * (1.0 / (send_array_ratio / SEND_QUEUE_RATIO)); + } else if (conn->last_congestion_event + CONGESTION_EVENT_TIMEOUT < temp_time) { + conn->packet_send_rate = min_speed * 1.2; + } else { + conn->packet_send_rate = min_speed * 0.9; + } + + conn->packet_send_rate_requested = min_speed_request * 1.2; + + if (conn->packet_send_rate < CRYPTO_PACKET_MIN_RATE) { + conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE; + } + + if (conn->packet_send_rate_requested < conn->packet_send_rate) { + conn->packet_send_rate_requested = conn->packet_send_rate; + } + } + } + + if (conn->last_packets_left_set == 0 || conn->last_packets_left_requested_set == 0) { + conn->last_packets_left_requested_set = conn->last_packets_left_set = temp_time; + conn->packets_left_requested = conn->packets_left = CRYPTO_MIN_QUEUE_LENGTH; + } else { + if (((uint64_t)((1000.0 / conn->packet_send_rate) + 0.5) + conn->last_packets_left_set) <= temp_time) { + double n_packets = conn->packet_send_rate * (((double)(temp_time - conn->last_packets_left_set)) / 1000.0); + n_packets += conn->last_packets_left_rem; + + uint32_t num_packets = n_packets; + double rem = n_packets - (double)num_packets; + + if (conn->packets_left > num_packets * 4 + CRYPTO_MIN_QUEUE_LENGTH) { + conn->packets_left = num_packets * 4 + CRYPTO_MIN_QUEUE_LENGTH; + } else { + conn->packets_left += num_packets; + } + + conn->last_packets_left_set = temp_time; + conn->last_packets_left_rem = rem; + } + + if (((uint64_t)((1000.0 / conn->packet_send_rate_requested) + 0.5) + conn->last_packets_left_requested_set) <= + temp_time) { + double n_packets = conn->packet_send_rate_requested * (((double)(temp_time - conn->last_packets_left_requested_set)) / + 1000.0); + n_packets += conn->last_packets_left_requested_rem; + + uint32_t num_packets = n_packets; + double rem = n_packets - (double)num_packets; + conn->packets_left_requested = num_packets; + + conn->last_packets_left_requested_set = temp_time; + conn->last_packets_left_requested_rem = rem; + } + + if (conn->packets_left > conn->packets_left_requested) { + conn->packets_left_requested = conn->packets_left; + } + } + + int ret = send_requested_packets(c, i, conn->packets_left_requested); + + if (ret != -1) { + conn->packets_left_requested -= ret; + conn->packets_resent += ret; + + if ((unsigned int)ret < conn->packets_left) { + conn->packets_left -= ret; + } else { + conn->last_congestion_event = temp_time; + conn->packets_left = 0; + } + } + + if (conn->packet_send_rate > CRYPTO_PACKET_MIN_RATE * 1.5) { + total_send_rate += conn->packet_send_rate; + } + } + } + + c->current_sleep_time = ~0; + uint32_t sleep_time = peak_request_packet_interval; + + if (c->current_sleep_time > sleep_time) { + c->current_sleep_time = sleep_time; + } + + if (total_send_rate > CRYPTO_PACKET_MIN_RATE) { + sleep_time = (1000.0 / total_send_rate); + + if (c->current_sleep_time > sleep_time) { + c->current_sleep_time = sleep_time + 1; + } + } + + sleep_time = CRYPTO_SEND_PACKET_INTERVAL; + + if (c->current_sleep_time > sleep_time) { + c->current_sleep_time = sleep_time; + } +} + +/* Return 1 if max speed was reached for this connection (no more data can be physically through the pipe). + * Return 0 if it wasn't reached. + */ +bool max_speed_reached(Net_Crypto *c, int crypt_connection_id) +{ + return reset_max_speed_reached(c, crypt_connection_id) != 0; +} + +/* returns the number of packet slots left in the sendbuffer. + * return 0 if failure. + */ +uint32_t crypto_num_free_sendqueue_slots(const Net_Crypto *c, int crypt_connection_id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return 0; + } + + uint32_t max_packets = CRYPTO_PACKET_BUFFER_SIZE - num_packets_array(&conn->send_array); + + if (conn->packets_left < max_packets) { + return conn->packets_left; + } + + return max_packets; +} + +/* Sends a lossless cryptopacket. + * + * return -1 if data could not be put in packet queue. + * return positive packet number if data was put into the queue. + * + * congestion_control: should congestion control apply to this packet? + */ +int64_t write_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length, + uint8_t congestion_control) +{ + if (length == 0) { + return -1; + } + + if (data[0] < CRYPTO_RESERVED_PACKETS) { + return -1; + } + + if (data[0] >= PACKET_ID_LOSSY_RANGE_START) { + return -1; + } + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + if (conn->status != CRYPTO_CONN_ESTABLISHED) { + return -1; + } + + if (congestion_control && conn->packets_left == 0) { + return -1; + } + + int64_t ret = send_lossless_packet(c, crypt_connection_id, data, length, congestion_control); + + if (ret == -1) { + return -1; + } + + if (congestion_control) { + --conn->packets_left; + --conn->packets_left_requested; + conn->packets_sent++; + } + + return ret; +} + +/* Check if packet_number was received by the other side. + * + * packet_number must be a valid packet number of a packet sent on this connection. + * + * return -1 on failure. + * return 0 on success. + */ +int cryptpacket_received(Net_Crypto *c, int crypt_connection_id, uint32_t packet_number) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + uint32_t num = conn->send_array.buffer_end - conn->send_array.buffer_start; + uint32_t num1 = packet_number - conn->send_array.buffer_start; + + if (num < num1) { + return 0; + } + + return -1; +} + +/* return -1 on failure. + * return 0 on success. + * + * Sends a lossy cryptopacket. (first byte must in the PACKET_ID_LOSSY_RANGE_*) + */ +int send_lossy_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length) +{ + if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) { + return -1; + } + + if (data[0] < PACKET_ID_LOSSY_RANGE_START) { + return -1; + } + + if (data[0] >= (PACKET_ID_LOSSY_RANGE_START + PACKET_ID_LOSSY_RANGE_SIZE)) { + return -1; + } + + pthread_mutex_lock(&c->connections_mutex); + ++c->connection_use_counter; + pthread_mutex_unlock(&c->connections_mutex); + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + int ret = -1; + + if (conn) { + pthread_mutex_lock(&conn->mutex); + uint32_t buffer_start = conn->recv_array.buffer_start; + uint32_t buffer_end = conn->send_array.buffer_end; + pthread_mutex_unlock(&conn->mutex); + ret = send_data_packet_helper(c, crypt_connection_id, buffer_start, buffer_end, data, length); + } + + pthread_mutex_lock(&c->connections_mutex); + --c->connection_use_counter; + pthread_mutex_unlock(&c->connections_mutex); + + return ret; +} + +/* Kill a crypto connection. + * + * return -1 on failure. + * return 0 on success. + */ +int crypto_kill(Net_Crypto *c, int crypt_connection_id) +{ + while (1) { /* TODO(irungentoo): is this really the best way to do this? */ + pthread_mutex_lock(&c->connections_mutex); + + if (!c->connection_use_counter) { + break; + } + + pthread_mutex_unlock(&c->connections_mutex); + } + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + int ret = -1; + + if (conn) { + if (conn->status == CRYPTO_CONN_ESTABLISHED) { + send_kill_packet(c, crypt_connection_id); + } + + pthread_mutex_lock(&c->tcp_mutex); + kill_tcp_connection_to(c->tcp_c, conn->connection_number_tcp); + pthread_mutex_unlock(&c->tcp_mutex); + + bs_list_remove(&c->ip_port_list, (uint8_t *)&conn->ip_portv4, crypt_connection_id); + bs_list_remove(&c->ip_port_list, (uint8_t *)&conn->ip_portv6, crypt_connection_id); + clear_temp_packet(c, crypt_connection_id); + clear_buffer(&conn->send_array); + clear_buffer(&conn->recv_array); + ret = wipe_crypto_connection(c, crypt_connection_id); + } + + pthread_mutex_unlock(&c->connections_mutex); + + return ret; +} + +/* return one of CRYPTO_CONN_* values indicating the state of the connection. + * + * sets direct_connected to 1 if connection connects directly to other, 0 if it isn't. + * sets online_tcp_relays to the number of connected tcp relays this connection has. + */ +unsigned int crypto_connection_status(const Net_Crypto *c, int crypt_connection_id, bool *direct_connected, + unsigned int *online_tcp_relays) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return CRYPTO_CONN_NO_CONNECTION; + } + + if (direct_connected) { + *direct_connected = 0; + + uint64_t current_time = unix_time(); + + if ((UDP_DIRECT_TIMEOUT + conn->direct_lastrecv_timev4) > current_time) { + *direct_connected = 1; + } + + if ((UDP_DIRECT_TIMEOUT + conn->direct_lastrecv_timev6) > current_time) { + *direct_connected = 1; + } + } + + if (online_tcp_relays) { + *online_tcp_relays = tcp_connection_to_online_tcp_relays(c->tcp_c, conn->connection_number_tcp); + } + + return conn->status; +} + +void new_keys(Net_Crypto *c) +{ + crypto_new_keypair(c->self_public_key, c->self_secret_key); +} + +/* Save the public and private keys to the keys array. + * Length must be CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SECRET_KEY_SIZE. + * + * TODO(irungentoo): Save only secret key. + */ +void save_keys(const Net_Crypto *c, uint8_t *keys) +{ + memcpy(keys, c->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(keys + CRYPTO_PUBLIC_KEY_SIZE, c->self_secret_key, CRYPTO_SECRET_KEY_SIZE); +} + +/* Load the secret key. + * Length must be CRYPTO_SECRET_KEY_SIZE. + */ +void load_secret_key(Net_Crypto *c, const uint8_t *sk) +{ + memcpy(c->self_secret_key, sk, CRYPTO_SECRET_KEY_SIZE); + crypto_derive_public_key(c->self_public_key, c->self_secret_key); +} + +/* Run this to (re)initialize net_crypto. + * Sets all the global connection variables to their default values. + */ +Net_Crypto *new_net_crypto(Logger *log, DHT *dht, TCP_Proxy_Info *proxy_info) +{ + unix_time_update(); + + if (dht == NULL) { + return NULL; + } + + Net_Crypto *temp = (Net_Crypto *)calloc(1, sizeof(Net_Crypto)); + + if (temp == NULL) { + return NULL; + } + + temp->log = log; + + temp->tcp_c = new_tcp_connections(dht->self_secret_key, proxy_info); + + if (temp->tcp_c == NULL) { + free(temp); + return NULL; + } + + set_packet_tcp_connection_callback(temp->tcp_c, &tcp_data_callback, temp); + set_oob_packet_tcp_connection_callback(temp->tcp_c, &tcp_oob_callback, temp); + + if (create_recursive_mutex(&temp->tcp_mutex) != 0 || + pthread_mutex_init(&temp->connections_mutex, NULL) != 0) { + kill_tcp_connections(temp->tcp_c); + free(temp); + return NULL; + } + + temp->dht = dht; + + new_keys(temp); + new_symmetric_key(temp->secret_symmetric_key); + + temp->current_sleep_time = CRYPTO_SEND_PACKET_INTERVAL; + + networking_registerhandler(dht->net, NET_PACKET_COOKIE_REQUEST, &udp_handle_cookie_request, temp); + networking_registerhandler(dht->net, NET_PACKET_COOKIE_RESPONSE, &udp_handle_packet, temp); + networking_registerhandler(dht->net, NET_PACKET_CRYPTO_HS, &udp_handle_packet, temp); + networking_registerhandler(dht->net, NET_PACKET_CRYPTO_DATA, &udp_handle_packet, temp); + + bs_list_init(&temp->ip_port_list, sizeof(IP_Port), 8); + + return temp; +} + +static void kill_timedout(Net_Crypto *c, void *userdata) +{ + uint32_t i; + //uint64_t temp_time = current_time_monotonic(); + + for (i = 0; i < c->crypto_connections_length; ++i) { + Crypto_Connection *conn = get_crypto_connection(c, i); + + if (conn == 0) { + return; + } + + if (conn->status == CRYPTO_CONN_NO_CONNECTION) { + continue; + } + + if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING || conn->status == CRYPTO_CONN_HANDSHAKE_SENT + || conn->status == CRYPTO_CONN_NOT_CONFIRMED) { + if (conn->temp_packet_num_sent < MAX_NUM_SENDPACKET_TRIES) { + continue; + } + + connection_kill(c, i, userdata); + } + +#if 0 + + if (conn->status == CRYPTO_CONN_ESTABLISHED) { + // TODO(irungentoo): add a timeout here? + } + +#endif + } +} + +/* return the optimal interval in ms for running do_net_crypto. + */ +uint32_t crypto_run_interval(const Net_Crypto *c) +{ + return c->current_sleep_time; +} + +/* Main loop. */ +void do_net_crypto(Net_Crypto *c, void *userdata) +{ + unix_time_update(); + kill_timedout(c, userdata); + do_tcp(c, userdata); + send_crypto_packets(c); +} + +void kill_net_crypto(Net_Crypto *c) +{ + uint32_t i; + + for (i = 0; i < c->crypto_connections_length; ++i) { + crypto_kill(c, i); + } + + pthread_mutex_destroy(&c->tcp_mutex); + pthread_mutex_destroy(&c->connections_mutex); + + kill_tcp_connections(c->tcp_c); + bs_list_free(&c->ip_port_list); + networking_registerhandler(c->dht->net, NET_PACKET_COOKIE_REQUEST, NULL, NULL); + networking_registerhandler(c->dht->net, NET_PACKET_COOKIE_RESPONSE, NULL, NULL); + networking_registerhandler(c->dht->net, NET_PACKET_CRYPTO_HS, NULL, NULL); + networking_registerhandler(c->dht->net, NET_PACKET_CRYPTO_DATA, NULL, NULL); + crypto_memzero(c, sizeof(Net_Crypto)); + free(c); +} diff --git a/protocols/Tox/libtox/src/toxcore/net_crypto.h b/protocols/Tox/libtox/src/toxcore/net_crypto.h new file mode 100644 index 0000000000..5ec5ca94fb --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/net_crypto.h @@ -0,0 +1,428 @@ +/* + * Functions for the core network crypto. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef NET_CRYPTO_H +#define NET_CRYPTO_H + +#include "DHT.h" +#include "LAN_discovery.h" +#include "TCP_connection.h" +#include "logger.h" + +#include <pthread.h> + +#define CRYPTO_CONN_NO_CONNECTION 0 +#define CRYPTO_CONN_COOKIE_REQUESTING 1 //send cookie request packets +#define CRYPTO_CONN_HANDSHAKE_SENT 2 //send handshake packets +#define CRYPTO_CONN_NOT_CONFIRMED 3 //send handshake packets, we have received one from the other +#define CRYPTO_CONN_ESTABLISHED 4 + +/* Maximum size of receiving and sending packet buffers. */ +#define CRYPTO_PACKET_BUFFER_SIZE 32768 /* Must be a power of 2 */ + +/* Minimum packet rate per second. */ +#define CRYPTO_PACKET_MIN_RATE 4.0 + +/* Minimum packet queue max length. */ +#define CRYPTO_MIN_QUEUE_LENGTH 64 + +/* Maximum total size of packets that net_crypto sends. */ +#define MAX_CRYPTO_PACKET_SIZE 1400 + +#define CRYPTO_DATA_PACKET_MIN_SIZE (1 + sizeof(uint16_t) + (sizeof(uint32_t) + sizeof(uint32_t)) + CRYPTO_MAC_SIZE) + +/* Max size of data in packets */ +#define MAX_CRYPTO_DATA_SIZE (MAX_CRYPTO_PACKET_SIZE - CRYPTO_DATA_PACKET_MIN_SIZE) + +/* Interval in ms between sending cookie request/handshake packets. */ +#define CRYPTO_SEND_PACKET_INTERVAL 1000 + +/* The maximum number of times we try to send the cookie request and handshake + before giving up. */ +#define MAX_NUM_SENDPACKET_TRIES 8 + +/* The timeout of no received UDP packets before the direct UDP connection is considered dead. */ +#define UDP_DIRECT_TIMEOUT ((MAX_NUM_SENDPACKET_TRIES * CRYPTO_SEND_PACKET_INTERVAL) / 1000) + +#define PACKET_ID_PADDING 0 /* Denotes padding */ +#define PACKET_ID_REQUEST 1 /* Used to request unreceived packets */ +#define PACKET_ID_KILL 2 /* Used to kill connection */ + +/* Packet ids 0 to CRYPTO_RESERVED_PACKETS - 1 are reserved for use by net_crypto. */ +#define CRYPTO_RESERVED_PACKETS 16 + +#define MAX_TCP_CONNECTIONS 64 +#define MAX_TCP_RELAYS_PEER 4 + +/* All packets starting with a byte in this range are considered lossy packets. */ +#define PACKET_ID_LOSSY_RANGE_START 192 +#define PACKET_ID_LOSSY_RANGE_SIZE 63 + +#define CRYPTO_MAX_PADDING 8 /* All packets will be padded a number of bytes based on this number. */ + +/* Base current transfer speed on last CONGESTION_QUEUE_ARRAY_SIZE number of points taken + at the dT defined in net_crypto.c */ +#define CONGESTION_QUEUE_ARRAY_SIZE 12 +#define CONGESTION_LAST_SENT_ARRAY_SIZE (CONGESTION_QUEUE_ARRAY_SIZE * 2) + +/* Default connection ping in ms. */ +#define DEFAULT_PING_CONNECTION 1000 +#define DEFAULT_TCP_PING_CONNECTION 500 + +typedef struct { + uint64_t sent_time; + uint16_t length; + uint8_t data[MAX_CRYPTO_DATA_SIZE]; +} Packet_Data; + +typedef struct { + Packet_Data *buffer[CRYPTO_PACKET_BUFFER_SIZE]; + uint32_t buffer_start; + uint32_t buffer_end; /* packet numbers in array: {buffer_start, buffer_end) */ +} Packets_Array; + +typedef struct { + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The real public key of the peer. */ + uint8_t recv_nonce[CRYPTO_NONCE_SIZE]; /* Nonce of received packets. */ + uint8_t sent_nonce[CRYPTO_NONCE_SIZE]; /* Nonce of sent packets. */ + uint8_t sessionpublic_key[CRYPTO_PUBLIC_KEY_SIZE]; /* Our public key for this session. */ + uint8_t sessionsecret_key[CRYPTO_SECRET_KEY_SIZE]; /* Our private key for this session. */ + uint8_t peersessionpublic_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The public key of the peer. */ + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; /* The precomputed shared key from encrypt_precompute. */ + uint8_t status; /* 0 if no connection, 1 we are sending cookie request packets, + * 2 if we are sending handshake packets + * 3 if connection is not confirmed yet (we have received a handshake but no data packets yet), + * 4 if the connection is established. + */ + uint64_t cookie_request_number; /* number used in the cookie request packets for this connection */ + uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The dht public key of the peer */ + + uint8_t *temp_packet; /* Where the cookie request/handshake packet is stored while it is being sent. */ + uint16_t temp_packet_length; + uint64_t temp_packet_sent_time; /* The time at which the last temp_packet was sent in ms. */ + uint32_t temp_packet_num_sent; + + IP_Port ip_portv4; /* The ip and port to contact this guy directly.*/ + IP_Port ip_portv6; + uint64_t direct_lastrecv_timev4; /* The Time at which we last received a direct packet in ms. */ + uint64_t direct_lastrecv_timev6; + + uint64_t last_tcp_sent; /* Time the last TCP packet was sent. */ + + Packets_Array send_array; + Packets_Array recv_array; + + int (*connection_status_callback)(void *object, int id, uint8_t status, void *userdata); + void *connection_status_callback_object; + int connection_status_callback_id; + + int (*connection_data_callback)(void *object, int id, const uint8_t *data, uint16_t length, void *userdata); + void *connection_data_callback_object; + int connection_data_callback_id; + + int (*connection_lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length, void *userdata); + void *connection_lossy_data_callback_object; + int connection_lossy_data_callback_id; + + uint64_t last_request_packet_sent; + uint64_t direct_send_attempt_time; + + uint32_t packet_counter; + double packet_recv_rate; + uint64_t packet_counter_set; + + double packet_send_rate; + uint32_t packets_left; + uint64_t last_packets_left_set; + double last_packets_left_rem; + + double packet_send_rate_requested; + uint32_t packets_left_requested; + uint64_t last_packets_left_requested_set; + double last_packets_left_requested_rem; + + uint32_t last_sendqueue_size[CONGESTION_QUEUE_ARRAY_SIZE], last_sendqueue_counter; + long signed int last_num_packets_sent[CONGESTION_LAST_SENT_ARRAY_SIZE], + last_num_packets_resent[CONGESTION_LAST_SENT_ARRAY_SIZE]; + uint32_t packets_sent, packets_resent; + uint64_t last_congestion_event; + uint64_t rtt_time; + + /* TCP_connection connection_number */ + unsigned int connection_number_tcp; + + uint8_t maximum_speed_reached; + + pthread_mutex_t mutex; + + void (*dht_pk_callback)(void *data, int32_t number, const uint8_t *dht_public_key, void *userdata); + void *dht_pk_callback_object; + uint32_t dht_pk_callback_number; +} Crypto_Connection; + +typedef struct { + IP_Port source; + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The real public key of the peer. */ + uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The dht public key of the peer. */ + uint8_t recv_nonce[CRYPTO_NONCE_SIZE]; /* Nonce of received packets. */ + uint8_t peersessionpublic_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The public key of the peer. */ + uint8_t *cookie; + uint8_t cookie_length; +} New_Connection; + +typedef struct { + Logger *log; + + DHT *dht; + TCP_Connections *tcp_c; + + Crypto_Connection *crypto_connections; + pthread_mutex_t tcp_mutex; + + pthread_mutex_t connections_mutex; + unsigned int connection_use_counter; + + uint32_t crypto_connections_length; /* Length of connections array. */ + + /* Our public and secret keys. */ + uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE]; + + /* The secret key used for cookies */ + uint8_t secret_symmetric_key[CRYPTO_SYMMETRIC_KEY_SIZE]; + + int (*new_connection_callback)(void *object, New_Connection *n_c); + void *new_connection_callback_object; + + /* The current optimal sleep time */ + uint32_t current_sleep_time; + + BS_LIST ip_port_list; +} Net_Crypto; + + +/* Set function to be called when someone requests a new connection to us. + * + * The set function should return -1 on failure and 0 on success. + * + * n_c is only valid for the duration of the function call. + */ +void new_connection_handler(Net_Crypto *c, int (*new_connection_callback)(void *object, New_Connection *n_c), + void *object); + +/* Accept a crypto connection. + * + * return -1 on failure. + * return connection id on success. + */ +int accept_crypto_connection(Net_Crypto *c, New_Connection *n_c); + +/* Create a crypto connection. + * If one to that real public key already exists, return it. + * + * return -1 on failure. + * return connection id on success. + */ +int new_crypto_connection(Net_Crypto *c, const uint8_t *real_public_key, const uint8_t *dht_public_key); + +/* Set the direct ip of the crypto connection. + * + * Connected is 0 if we are not sure we are connected to that person, 1 if we are sure. + * + * return -1 on failure. + * return 0 on success. + */ +int set_direct_ip_port(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port, bool connected); + +/* Set function to be called when connection with crypt_connection_id goes connects/disconnects. + * + * The set function should return -1 on failure and 0 on success. + * Note that if this function is set, the connection will clear itself on disconnect. + * Object and id will be passed to this function untouched. + * status is 1 if the connection is going online, 0 if it is going offline. + * + * return -1 on failure. + * return 0 on success. + */ +int connection_status_handler(const Net_Crypto *c, int crypt_connection_id, + int (*connection_status_callback)(void *object, int id, uint8_t status, void *userdata), void *object, int id); + +/* Set function to be called when connection with crypt_connection_id receives a lossless data packet of length. + * + * The set function should return -1 on failure and 0 on success. + * Object and id will be passed to this function untouched. + * + * return -1 on failure. + * return 0 on success. + */ +int connection_data_handler(const Net_Crypto *c, int crypt_connection_id, int (*connection_data_callback)(void *object, + int id, const uint8_t *data, uint16_t length, void *userdata), void *object, int id); + + +/* Set function to be called when connection with crypt_connection_id receives a lossy data packet of length. + * + * The set function should return -1 on failure and 0 on success. + * Object and id will be passed to this function untouched. + * + * return -1 on failure. + * return 0 on success. + */ +int connection_lossy_data_handler(Net_Crypto *c, int crypt_connection_id, + int (*connection_lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length, void *userdata), + void *object, + int id); + +/* Set the function for this friend that will be callbacked with object and number if + * the friend sends us a different dht public key than we have associated to him. + * + * If this function is called, the connection should be recreated with the new public key. + * + * object and number will be passed as argument to this function. + * + * return -1 on failure. + * return 0 on success. + */ +int nc_dht_pk_callback(Net_Crypto *c, int crypt_connection_id, void (*function)(void *data, int32_t number, + const uint8_t *dht_public_key, void *userdata), void *object, uint32_t number); + +/* returns the number of packet slots left in the sendbuffer. + * return 0 if failure. + */ +uint32_t crypto_num_free_sendqueue_slots(const Net_Crypto *c, int crypt_connection_id); + +/* Return 1 if max speed was reached for this connection (no more data can be physically through the pipe). + * Return 0 if it wasn't reached. + */ +bool max_speed_reached(Net_Crypto *c, int crypt_connection_id); + +/* Sends a lossless cryptopacket. + * + * return -1 if data could not be put in packet queue. + * return positive packet number if data was put into the queue. + * + * The first byte of data must be in the CRYPTO_RESERVED_PACKETS to PACKET_ID_LOSSY_RANGE_START range. + * + * congestion_control: should congestion control apply to this packet? + */ +int64_t write_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length, + uint8_t congestion_control); + +/* Check if packet_number was received by the other side. + * + * packet_number must be a valid packet number of a packet sent on this connection. + * + * return -1 on failure. + * return 0 on success. + */ +int cryptpacket_received(Net_Crypto *c, int crypt_connection_id, uint32_t packet_number); + +/* return -1 on failure. + * return 0 on success. + * + * Sends a lossy cryptopacket. (first byte must in the PACKET_ID_LOSSY_RANGE_*) + */ +int send_lossy_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length); + +/* Add a tcp relay, associating it to a crypt_connection_id. + * + * return 0 if it was added. + * return -1 if it wasn't. + */ +int add_tcp_relay_peer(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port, const uint8_t *public_key); + +/* Add a tcp relay to the array. + * + * return 0 if it was added. + * return -1 if it wasn't. + */ +int add_tcp_relay(Net_Crypto *c, IP_Port ip_port, const uint8_t *public_key); + +/* Return a random TCP connection number for use in send_tcp_onion_request. + * + * return TCP connection number on success. + * return -1 on failure. + */ +int get_random_tcp_con_number(Net_Crypto *c); + +/* Send an onion packet via the TCP relay corresponding to TCP_conn_number. + * + * return 0 on success. + * return -1 on failure. + */ +int send_tcp_onion_request(Net_Crypto *c, unsigned int tcp_connections_number, const uint8_t *data, uint16_t length); + +/* Copy a maximum of num TCP relays we are connected to to tcp_relays. + * NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6. + * + * return number of relays copied to tcp_relays on success. + * return 0 on failure. + */ +unsigned int copy_connected_tcp_relays(Net_Crypto *c, Node_format *tcp_relays, uint16_t num); + +/* Kill a crypto connection. + * + * return -1 on failure. + * return 0 on success. + */ +int crypto_kill(Net_Crypto *c, int crypt_connection_id); + +/* return one of CRYPTO_CONN_* values indicating the state of the connection. + * + * sets direct_connected to 1 if connection connects directly to other, 0 if it isn't. + * sets online_tcp_relays to the number of connected tcp relays this connection has. + */ +unsigned int crypto_connection_status(const Net_Crypto *c, int crypt_connection_id, bool *direct_connected, + unsigned int *online_tcp_relays); + +/* Generate our public and private keys. + * Only call this function the first time the program starts. + */ +void new_keys(Net_Crypto *c); + +/* Save the public and private keys to the keys array. + * Length must be CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SECRET_KEY_SIZE. + */ +void save_keys(const Net_Crypto *c, uint8_t *keys); + +/* Load the secret key. + * Length must be CRYPTO_SECRET_KEY_SIZE. + */ +void load_secret_key(Net_Crypto *c, const uint8_t *sk); + +/* Create new instance of Net_Crypto. + * Sets all the global connection variables to their default values. + */ +Net_Crypto *new_net_crypto(Logger *log, DHT *dht, TCP_Proxy_Info *proxy_info); + +/* return the optimal interval in ms for running do_net_crypto. + */ +uint32_t crypto_run_interval(const Net_Crypto *c); + +/* Main loop. */ +void do_net_crypto(Net_Crypto *c, void *userdata); + +void kill_net_crypto(Net_Crypto *c); + + + +#endif diff --git a/protocols/Tox/libtox/src/toxcore/network.c b/protocols/Tox/libtox/src/toxcore/network.c new file mode 100644 index 0000000000..5c43bf5779 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/network.c @@ -0,0 +1,1446 @@ +/* + * Functions for the core networking. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define _DARWIN_C_SOURCE +#define _XOPEN_SOURCE 600 + +#if defined(_WIN32) && _WIN32_WINNT >= _WIN32_WINNT_WINXP +#define _WIN32_WINNT 0x501 +#endif + +#include "network.h" + +#include "logger.h" +#include "util.h" + +#include <assert.h> +#ifdef __APPLE__ +#include <mach/clock.h> +#include <mach/mach.h> +#endif + +#ifndef IPV6_ADD_MEMBERSHIP +#ifdef IPV6_JOIN_GROUP +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP +#endif +#endif + +#if !(defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) + +#include <errno.h> +#include <fcntl.h> +#include <netdb.h> +#include <sys/time.h> +#include <sys/types.h> + +#else + +#ifndef IPV6_V6ONLY +#define IPV6_V6ONLY 27 +#endif + +#ifndef EWOULDBLOCK +#define EWOULDBLOCK WSAEWOULDBLOCK +#endif + +static const char *inet_ntop(Family family, const void *addr, char *buf, size_t bufsize) +{ + if (family == TOX_AF_INET) { + struct sockaddr_in saddr; + memset(&saddr, 0, sizeof(saddr)); + + saddr.sin_family = AF_INET; + saddr.sin_addr = *(const struct in_addr *)addr; + + DWORD len = bufsize; + + if (WSAAddressToString((LPSOCKADDR)&saddr, sizeof(saddr), NULL, buf, &len)) { + return NULL; + } + + return buf; + } else if (family == TOX_AF_INET6) { + struct sockaddr_in6 saddr; + memset(&saddr, 0, sizeof(saddr)); + + saddr.sin6_family = AF_INET6; + saddr.sin6_addr = *(const struct in6_addr *)addr; + + DWORD len = bufsize; + + if (WSAAddressToString((LPSOCKADDR)&saddr, sizeof(saddr), NULL, buf, &len)) { + return NULL; + } + + return buf; + } + + return NULL; +} + +static int inet_pton(Family family, const char *addrString, void *addrbuf) +{ + if (family == TOX_AF_INET) { + struct sockaddr_in saddr; + memset(&saddr, 0, sizeof(saddr)); + + INT len = sizeof(saddr); + + if (WSAStringToAddress((LPTSTR)addrString, AF_INET, NULL, (LPSOCKADDR)&saddr, &len)) { + return 0; + } + + *(struct in_addr *)addrbuf = saddr.sin_addr; + + return 1; + } else if (family == TOX_AF_INET6) { + struct sockaddr_in6 saddr; + memset(&saddr, 0, sizeof(saddr)); + + INT len = sizeof(saddr); + + if (WSAStringToAddress((LPTSTR)addrString, AF_INET6, NULL, (LPSOCKADDR)&saddr, &len)) { + return 0; + } + + *(struct in6_addr *)addrbuf = saddr.sin6_addr; + + return 1; + } + + return 0; +} + +#endif + +#if TOX_INET6_ADDRSTRLEN < INET6_ADDRSTRLEN +#error TOX_INET6_ADDRSTRLEN should be greater or equal to INET6_ADDRSTRLEN (#INET6_ADDRSTRLEN) +#endif + +#if TOX_INET_ADDRSTRLEN < INET_ADDRSTRLEN +#error TOX_INET_ADDRSTRLEN should be greater or equal to INET_ADDRSTRLEN (#INET_ADDRSTRLEN) +#endif + +static int make_proto(int proto); +static int make_socktype(int type); +static int make_family(int tox_family); +static int make_tox_family(int family); + +static void get_ip4(IP4 *result, const struct in_addr *addr) +{ + result->uint32 = addr->s_addr; +} + +static void get_ip6(IP6 *result, const struct in6_addr *addr) +{ + assert(sizeof(result->uint8) == sizeof(addr->s6_addr)); + memcpy(result->uint8, addr->s6_addr, sizeof(result->uint8)); +} + +static void fill_addr4(IP4 ip, struct in_addr *addr) +{ + addr->s_addr = ip.uint32; +} + +static void fill_addr6(IP6 ip, struct in6_addr *addr) +{ + assert(sizeof(ip.uint8) == sizeof(addr->s6_addr)); + memcpy(addr->s6_addr, ip.uint8, sizeof(ip.uint8)); +} + +#if !defined(INADDR_LOOPBACK) +#define INADDR_LOOPBACK 0x7f000001 +#endif + +const IP4 IP4_BROADCAST = { INADDR_BROADCAST }; +const IP6 IP6_BROADCAST = { + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } +}; + +IP4 get_ip4_loopback() +{ + IP4 loopback; + loopback.uint32 = htonl(INADDR_LOOPBACK); + return loopback; +} + +IP6 get_ip6_loopback() +{ + IP6 loopback; + get_ip6(&loopback, &in6addr_loopback); + return loopback; +} + +/* Check if socket is valid. + * + * return 1 if valid + * return 0 if not valid + */ +int sock_valid(Socket sock) +{ +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + + if (sock == INVALID_SOCKET) { +#else + + if (sock < 0) { +#endif + return 0; + } + + return 1; +} + +/* Close the socket. + */ +void kill_sock(Socket sock) +{ +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + closesocket(sock); +#else + close(sock); +#endif +} + +/* Set socket as nonblocking + * + * return 1 on success + * return 0 on failure + */ +int set_socket_nonblock(Socket sock) +{ +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + u_long mode = 1; + return (ioctlsocket(sock, FIONBIO, &mode) == 0); +#else + return (fcntl(sock, F_SETFL, O_NONBLOCK, 1) == 0); +#endif +} + +/* Set socket to not emit SIGPIPE + * + * return 1 on success + * return 0 on failure + */ +int set_socket_nosigpipe(Socket sock) +{ +#if defined(__MACH__) + int set = 1; + return (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (const char *)&set, sizeof(int)) == 0); +#else + return 1; +#endif +} + +/* Enable SO_REUSEADDR on socket. + * + * return 1 on success + * return 0 on failure + */ +int set_socket_reuseaddr(Socket sock) +{ + int set = 1; + return (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&set, sizeof(set)) == 0); +} + +/* Set socket to dual (IPv4 + IPv6 socket) + * + * return 1 on success + * return 0 on failure + */ +int set_socket_dualstack(Socket sock) +{ + int ipv6only = 0; + socklen_t optsize = sizeof(ipv6only); + int res = getsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&ipv6only, &optsize); + + if ((res == 0) && (ipv6only == 0)) { + return 1; + } + + ipv6only = 0; + return (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&ipv6only, sizeof(ipv6only)) == 0); +} + + +/* return current UNIX time in microseconds (us). */ +static uint64_t current_time_actual(void) +{ + uint64_t time; +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + /* This probably works fine */ + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + time = ft.dwHighDateTime; + time <<= 32; + time |= ft.dwLowDateTime; + time -= 116444736000000000ULL; + return time / 10; +#else + struct timeval a; + gettimeofday(&a, NULL); + time = 1000000ULL * a.tv_sec + a.tv_usec; + return time; +#endif +} + + +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) +static uint64_t last_monotime; +static uint64_t add_monotime; +#endif + +/* return current monotonic time in milliseconds (ms). */ +uint64_t current_time_monotonic(void) +{ + uint64_t time; +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + uint64_t old_add_monotime = add_monotime; + time = (uint64_t)GetTickCount() + add_monotime; + + /* Check if time has decreased because of 32 bit wrap from GetTickCount(), while avoiding false positives from race + * conditions when multiple threads call this function at once */ + if (time + 0x10000 < last_monotime) { + uint32_t add = ~0; + /* use old_add_monotime rather than simply incrementing add_monotime, to handle the case that many threads + * simultaneously detect an overflow */ + add_monotime = old_add_monotime + add; + time += add; + } + + last_monotime = time; +#else + struct timespec monotime; +#if defined(__linux__) && defined(CLOCK_MONOTONIC_RAW) + clock_gettime(CLOCK_MONOTONIC_RAW, &monotime); +#elif defined(__APPLE__) + clock_serv_t muhclock; + mach_timespec_t machtime; + + host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &muhclock); + clock_get_time(muhclock, &machtime); + mach_port_deallocate(mach_task_self(), muhclock); + + monotime.tv_sec = machtime.tv_sec; + monotime.tv_nsec = machtime.tv_nsec; +#else + clock_gettime(CLOCK_MONOTONIC, &monotime); +#endif + time = 1000ULL * monotime.tv_sec + (monotime.tv_nsec / 1000000ULL); +#endif + return time; +} + +static uint32_t data_0(uint16_t buflen, const uint8_t *buffer) +{ + return buflen > 4 ? net_ntohl(*(const uint32_t *)&buffer[1]) : 0; +} +static uint32_t data_1(uint16_t buflen, const uint8_t *buffer) +{ + return buflen > 7 ? net_ntohl(*(const uint32_t *)&buffer[5]) : 0; +} + +static void loglogdata(Logger *log, const char *message, const uint8_t *buffer, + uint16_t buflen, IP_Port ip_port, int res) +{ + char ip_str[IP_NTOA_LEN]; + + if (res < 0) { /* Windows doesn't necessarily know %zu */ + LOGGER_TRACE(log, "[%2u] %s %3hu%c %s:%hu (%u: %s) | %04x%04x", + buffer[0], message, (buflen < 999 ? (uint16_t)buflen : 999), 'E', + ip_ntoa(&ip_port.ip, ip_str, sizeof(ip_str)), net_ntohs(ip_port.port), errno, + strerror(errno), data_0(buflen, buffer), data_1(buflen, buffer)); + } else if ((res > 0) && ((size_t)res <= buflen)) { + LOGGER_TRACE(log, "[%2u] %s %3zu%c %s:%hu (%u: %s) | %04x%04x", + buffer[0], message, (res < 999 ? (size_t)res : 999), ((size_t)res < buflen ? '<' : '='), + ip_ntoa(&ip_port.ip, ip_str, sizeof(ip_str)), net_ntohs(ip_port.port), 0, "OK", + data_0(buflen, buffer), data_1(buflen, buffer)); + } else { /* empty or overwrite */ + LOGGER_TRACE(log, "[%2u] %s %zu%c%zu %s:%hu (%u: %s) | %04x%04x", + buffer[0], message, (size_t)res, (!res ? '!' : '>'), buflen, + ip_ntoa(&ip_port.ip, ip_str, sizeof(ip_str)), net_ntohs(ip_port.port), 0, "OK", + data_0(buflen, buffer), data_1(buflen, buffer)); + } +} + +/* Basic network functions: + * Function to send packet(data) of length length to ip_port. + */ +int sendpacket(Networking_Core *net, IP_Port ip_port, const uint8_t *data, uint16_t length) +{ + if (net->family == 0) { /* Socket not initialized */ + return -1; + } + + /* socket TOX_AF_INET, but target IP NOT: can't send */ + if ((net->family == TOX_AF_INET) && (ip_port.ip.family != TOX_AF_INET)) { + return -1; + } + + struct sockaddr_storage addr; + + size_t addrsize = 0; + + if (ip_port.ip.family == TOX_AF_INET) { + if (net->family == TOX_AF_INET6) { + /* must convert to IPV4-in-IPV6 address */ + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; + + addrsize = sizeof(struct sockaddr_in6); + addr6->sin6_family = AF_INET6; + addr6->sin6_port = ip_port.port; + + /* there should be a macro for this in a standards compliant + * environment, not found */ + IP6 ip6; + + ip6.uint32[0] = 0; + ip6.uint32[1] = 0; + ip6.uint32[2] = net_htonl(0xFFFF); + ip6.uint32[3] = ip_port.ip.ip4.uint32; + fill_addr6(ip6, &addr6->sin6_addr); + + addr6->sin6_flowinfo = 0; + addr6->sin6_scope_id = 0; + } else { + struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; + + addrsize = sizeof(struct sockaddr_in); + addr4->sin_family = AF_INET; + fill_addr4(ip_port.ip.ip4, &addr4->sin_addr); + addr4->sin_port = ip_port.port; + } + } else if (ip_port.ip.family == TOX_AF_INET6) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; + + addrsize = sizeof(struct sockaddr_in6); + addr6->sin6_family = AF_INET6; + addr6->sin6_port = ip_port.port; + fill_addr6(ip_port.ip.ip6, &addr6->sin6_addr); + + addr6->sin6_flowinfo = 0; + addr6->sin6_scope_id = 0; + } else { + /* unknown address type*/ + return -1; + } + + int res = sendto(net->sock, (const char *) data, length, 0, (struct sockaddr *)&addr, addrsize); + + loglogdata(net->log, "O=>", data, length, ip_port, res); + + return res; +} + +/* Function to receive data + * ip and port of sender is put into ip_port. + * Packet data is put into data. + * Packet length is put into length. + */ +static int receivepacket(Logger *log, Socket sock, IP_Port *ip_port, uint8_t *data, uint32_t *length) +{ + memset(ip_port, 0, sizeof(IP_Port)); + struct sockaddr_storage addr; +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + int addrlen = sizeof(addr); +#else + socklen_t addrlen = sizeof(addr); +#endif + *length = 0; + int fail_or_len = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen); + + if (fail_or_len < 0) { + + if (fail_or_len < 0 && errno != EWOULDBLOCK) { + LOGGER_ERROR(log, "Unexpected error reading from socket: %u, %s\n", errno, strerror(errno)); + } + + return -1; /* Nothing received. */ + } + + *length = (uint32_t)fail_or_len; + + if (addr.ss_family == AF_INET) { + struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr; + + ip_port->ip.family = make_tox_family(addr_in->sin_family); + get_ip4(&ip_port->ip.ip4, &addr_in->sin_addr); + ip_port->port = addr_in->sin_port; + } else if (addr.ss_family == AF_INET6) { + struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&addr; + ip_port->ip.family = make_tox_family(addr_in6->sin6_family); + get_ip6(&ip_port->ip.ip6, &addr_in6->sin6_addr); + ip_port->port = addr_in6->sin6_port; + + if (IPV6_IPV4_IN_V6(ip_port->ip.ip6)) { + ip_port->ip.family = TOX_AF_INET; + ip_port->ip.ip4.uint32 = ip_port->ip.ip6.uint32[3]; + } + } else { + return -1; + } + + loglogdata(log, "=>O", data, MAX_UDP_PACKET_SIZE, *ip_port, *length); + + return 0; +} + +void networking_registerhandler(Networking_Core *net, uint8_t byte, packet_handler_callback cb, void *object) +{ + net->packethandlers[byte].function = cb; + net->packethandlers[byte].object = object; +} + +void networking_poll(Networking_Core *net, void *userdata) +{ + if (net->family == 0) { /* Socket not initialized */ + return; + } + + unix_time_update(); + + IP_Port ip_port; + uint8_t data[MAX_UDP_PACKET_SIZE]; + uint32_t length; + + while (receivepacket(net->log, net->sock, &ip_port, data, &length) != -1) { + if (length < 1) { + continue; + } + + if (!(net->packethandlers[data[0]].function)) { + LOGGER_WARNING(net->log, "[%02u] -- Packet has no handler", data[0]); + continue; + } + + net->packethandlers[data[0]].function(net->packethandlers[data[0]].object, ip_port, data, length, userdata); + } +} + +#ifndef VANILLA_NACL +/* Used for sodium_init() */ +#include <sodium.h> +#endif + +static uint8_t at_startup_ran = 0; +int networking_at_startup(void) +{ + if (at_startup_ran != 0) { + return 0; + } + +#ifndef VANILLA_NACL + +#ifdef USE_RANDOMBYTES_STIR + randombytes_stir(); +#else + + if (sodium_init() == -1) { + return -1; + } + +#endif /*USE_RANDOMBYTES_STIR*/ + +#endif/*VANILLA_NACL*/ + +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + WSADATA wsaData; + + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR) { + return -1; + } + +#endif + srand((uint32_t)current_time_actual()); + at_startup_ran = 1; + return 0; +} + +/* TODO(irungentoo): Put this somewhere */ +#if 0 +static void at_shutdown(void) +{ +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + WSACleanup(); +#endif +} +#endif + +/* Initialize networking. + * Added for reverse compatibility with old new_networking calls. + */ +Networking_Core *new_networking(Logger *log, IP ip, uint16_t port) +{ + return new_networking_ex(log, ip, port, port + (TOX_PORTRANGE_TO - TOX_PORTRANGE_FROM), 0); +} + +/* Initialize networking. + * Bind to ip and port. + * ip must be in network order EX: 127.0.0.1 = (7F000001). + * port is in host byte order (this means don't worry about it). + * + * return Networking_Core object if no problems + * return NULL if there are problems. + * + * If error is non NULL it is set to 0 if no issues, 1 if socket related error, 2 if other. + */ +Networking_Core *new_networking_ex(Logger *log, IP ip, uint16_t port_from, uint16_t port_to, unsigned int *error) +{ + /* If both from and to are 0, use default port range + * If one is 0 and the other is non-0, use the non-0 value as only port + * If from > to, swap + */ + if (port_from == 0 && port_to == 0) { + port_from = TOX_PORTRANGE_FROM; + port_to = TOX_PORTRANGE_TO; + } else if (port_from == 0 && port_to != 0) { + port_from = port_to; + } else if (port_from != 0 && port_to == 0) { + port_to = port_from; + } else if (port_from > port_to) { + uint16_t temp = port_from; + port_from = port_to; + port_to = temp; + } + + if (error) { + *error = 2; + } + + /* maybe check for invalid IPs like 224+.x.y.z? if there is any IP set ever */ + if (ip.family != TOX_AF_INET && ip.family != TOX_AF_INET6) { + LOGGER_ERROR(log, "Invalid address family: %u\n", ip.family); + return NULL; + } + + if (networking_at_startup() != 0) { + return NULL; + } + + Networking_Core *temp = (Networking_Core *)calloc(1, sizeof(Networking_Core)); + + if (temp == NULL) { + return NULL; + } + + temp->log = log; + temp->family = ip.family; + temp->port = 0; + + /* Initialize our socket. */ + /* add log message what we're creating */ + temp->sock = net_socket(temp->family, TOX_SOCK_DGRAM, TOX_PROTO_UDP); + + /* Check for socket error. */ + if (!sock_valid(temp->sock)) { + LOGGER_ERROR(log, "Failed to get a socket?! %u, %s\n", errno, strerror(errno)); + free(temp); + + if (error) { + *error = 1; + } + + return NULL; + } + + /* Functions to increase the size of the send and receive UDP buffers. + */ + int n = 1024 * 1024 * 2; + setsockopt(temp->sock, SOL_SOCKET, SO_RCVBUF, (const char *)&n, sizeof(n)); + setsockopt(temp->sock, SOL_SOCKET, SO_SNDBUF, (const char *)&n, sizeof(n)); + + /* Enable broadcast on socket */ + int broadcast = 1; + setsockopt(temp->sock, SOL_SOCKET, SO_BROADCAST, (const char *)&broadcast, sizeof(broadcast)); + + /* iOS UDP sockets are weird and apparently can SIGPIPE */ + if (!set_socket_nosigpipe(temp->sock)) { + kill_networking(temp); + + if (error) { + *error = 1; + } + + return NULL; + } + + /* Set socket nonblocking. */ + if (!set_socket_nonblock(temp->sock)) { + kill_networking(temp); + + if (error) { + *error = 1; + } + + return NULL; + } + + /* Bind our socket to port PORT and the given IP address (usually 0.0.0.0 or ::) */ + uint16_t *portptr = NULL; + struct sockaddr_storage addr; + size_t addrsize; + + memset(&addr, 0, sizeof(struct sockaddr_storage)); + + if (temp->family == TOX_AF_INET) { + struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; + + addrsize = sizeof(struct sockaddr_in); + addr4->sin_family = AF_INET; + addr4->sin_port = 0; + fill_addr4(ip.ip4, &addr4->sin_addr); + + portptr = &addr4->sin_port; + } else if (temp->family == TOX_AF_INET6) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; + + addrsize = sizeof(struct sockaddr_in6); + addr6->sin6_family = AF_INET6; + addr6->sin6_port = 0; + fill_addr6(ip.ip6, &addr6->sin6_addr); + + addr6->sin6_flowinfo = 0; + addr6->sin6_scope_id = 0; + + portptr = &addr6->sin6_port; + } else { + free(temp); + return NULL; + } + + if (ip.family == TOX_AF_INET6) { + int is_dualstack = set_socket_dualstack(temp->sock); + LOGGER_DEBUG(log, "Dual-stack socket: %s", + is_dualstack ? "enabled" : "Failed to enable, won't be able to receive from/send to IPv4 addresses"); + /* multicast local nodes */ + struct ipv6_mreq mreq; + memset(&mreq, 0, sizeof(mreq)); + mreq.ipv6mr_multiaddr.s6_addr[ 0] = 0xFF; + mreq.ipv6mr_multiaddr.s6_addr[ 1] = 0x02; + mreq.ipv6mr_multiaddr.s6_addr[15] = 0x01; + mreq.ipv6mr_interface = 0; + int res = setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (const char *)&mreq, sizeof(mreq)); + + LOGGER_DEBUG(log, res < 0 ? "Failed to activate local multicast membership. (%u, %s)" : + "Local multicast group FF02::1 joined successfully", errno, strerror(errno)); + } + + /* a hanging program or a different user might block the standard port; + * as long as it isn't a parameter coming from the commandline, + * try a few ports after it, to see if we can find a "free" one + * + * if we go on without binding, the first sendto() automatically binds to + * a free port chosen by the system (i.e. anything from 1024 to 65535) + * + * returning NULL after bind fails has both advantages and disadvantages: + * advantage: + * we can rely on getting the port in the range 33445..33450, which + * enables us to tell joe user to open their firewall to a small range + * + * disadvantage: + * some clients might not test return of tox_new(), blindly assuming that + * it worked ok (which it did previously without a successful bind) + */ + uint16_t port_to_try = port_from; + *portptr = net_htons(port_to_try); + int tries; + + for (tries = port_from; tries <= port_to; tries++) { + int res = bind(temp->sock, (struct sockaddr *)&addr, addrsize); + + if (!res) { + temp->port = *portptr; + + char ip_str[IP_NTOA_LEN]; + LOGGER_DEBUG(log, "Bound successfully to %s:%u", ip_ntoa(&ip, ip_str, sizeof(ip_str)), + net_ntohs(temp->port)); + + /* errno isn't reset on success, only set on failure, the failed + * binds with parallel clients yield a -EPERM to the outside if + * errno isn't cleared here */ + if (tries > 0) { + errno = 0; + } + + if (error) { + *error = 0; + } + + return temp; + } + + port_to_try++; + + if (port_to_try > port_to) { + port_to_try = port_from; + } + + *portptr = net_htons(port_to_try); + } + + char ip_str[IP_NTOA_LEN]; + LOGGER_ERROR(log, "Failed to bind socket: %u, %s IP: %s port_from: %u port_to: %u", errno, strerror(errno), + ip_ntoa(&ip, ip_str, sizeof(ip_str)), port_from, port_to); + + kill_networking(temp); + + if (error) { + *error = 1; + } + + return NULL; +} + +/* Function to cleanup networking stuff. */ +void kill_networking(Networking_Core *net) +{ + if (!net) { + return; + } + + if (net->family != 0) { /* Socket not initialized */ + kill_sock(net->sock); + } + + free(net); +} + + +/* ip_equal + * compares two IPAny structures + * unset means unequal + * + * returns 0 when not equal or when uninitialized + */ +int ip_equal(const IP *a, const IP *b) +{ + if (!a || !b) { + return 0; + } + + /* same family */ + if (a->family == b->family) { + if (a->family == TOX_AF_INET || a->family == TCP_INET) { + struct in_addr addr_a; + struct in_addr addr_b; + fill_addr4(a->ip4, &addr_a); + fill_addr4(b->ip4, &addr_b); + return addr_a.s_addr == addr_b.s_addr; + } + + if (a->family == TOX_AF_INET6 || a->family == TCP_INET6) { + return a->ip6.uint64[0] == b->ip6.uint64[0] && + a->ip6.uint64[1] == b->ip6.uint64[1]; + } + + return 0; + } + + /* different family: check on the IPv6 one if it is the IPv4 one embedded */ + if ((a->family == TOX_AF_INET) && (b->family == TOX_AF_INET6)) { + if (IPV6_IPV4_IN_V6(b->ip6)) { + struct in_addr addr_a; + fill_addr4(a->ip4, &addr_a); + return addr_a.s_addr == b->ip6.uint32[3]; + } + } else if ((a->family == TOX_AF_INET6) && (b->family == TOX_AF_INET)) { + if (IPV6_IPV4_IN_V6(a->ip6)) { + struct in_addr addr_b; + fill_addr4(b->ip4, &addr_b); + return a->ip6.uint32[3] == addr_b.s_addr; + } + } + + return 0; +} + +/* ipport_equal + * compares two IPAny_Port structures + * unset means unequal + * + * returns 0 when not equal or when uninitialized + */ +int ipport_equal(const IP_Port *a, const IP_Port *b) +{ + if (!a || !b) { + return 0; + } + + if (!a->port || (a->port != b->port)) { + return 0; + } + + return ip_equal(&a->ip, &b->ip); +} + +/* nulls out ip */ +void ip_reset(IP *ip) +{ + if (!ip) { + return; + } + + memset(ip, 0, sizeof(IP)); +} + +/* nulls out ip, sets family according to flag */ +void ip_init(IP *ip, uint8_t ipv6enabled) +{ + if (!ip) { + return; + } + + memset(ip, 0, sizeof(IP)); + ip->family = ipv6enabled ? TOX_AF_INET6 : TOX_AF_INET; +} + +/* checks if ip is valid */ +int ip_isset(const IP *ip) +{ + if (!ip) { + return 0; + } + + return (ip->family != 0); +} + +/* checks if ip is valid */ +int ipport_isset(const IP_Port *ipport) +{ + if (!ipport) { + return 0; + } + + if (!ipport->port) { + return 0; + } + + return ip_isset(&ipport->ip); +} + +/* copies an ip structure (careful about direction!) */ +void ip_copy(IP *target, const IP *source) +{ + if (!source || !target) { + return; + } + + memcpy(target, source, sizeof(IP)); +} + +/* copies an ip_port structure (careful about direction!) */ +void ipport_copy(IP_Port *target, const IP_Port *source) +{ + if (!source || !target) { + return; + } + + memcpy(target, source, sizeof(IP_Port)); +} + +/* ip_ntoa + * converts ip into a string + * ip_str must be of length at least IP_NTOA_LEN + * + * IPv6 addresses are enclosed into square brackets, i.e. "[IPv6]" + * writes error message into the buffer on error + * + * returns ip_str + */ +const char *ip_ntoa(const IP *ip, char *ip_str, size_t length) +{ + if (length < IP_NTOA_LEN) { + snprintf(ip_str, length, "Bad buf length"); + return ip_str; + } + + if (ip) { + const int family = make_family(ip->family); + + if (ip->family == TOX_AF_INET) { + /* returns standard quad-dotted notation */ + struct in_addr addr; + fill_addr4(ip->ip4, &addr); + + ip_str[0] = 0; + inet_ntop(family, &addr, ip_str, length); + } else if (ip->family == TOX_AF_INET6) { + /* returns hex-groups enclosed into square brackets */ + struct in6_addr addr; + fill_addr6(ip->ip6, &addr); + + ip_str[0] = '['; + inet_ntop(family, &addr, &ip_str[1], length - 3); + size_t len = strlen(ip_str); + ip_str[len] = ']'; + ip_str[len + 1] = 0; + } else { + snprintf(ip_str, length, "(IP invalid, family %u)", ip->family); + } + } else { + snprintf(ip_str, length, "(IP invalid: NULL)"); + } + + /* brute force protection against lacking termination */ + ip_str[length - 1] = 0; + return ip_str; +} + +/* + * ip_parse_addr + * parses IP structure into an address string + * + * input + * ip: ip of TOX_AF_INET or TOX_AF_INET6 families + * length: length of the address buffer + * Must be at least INET_ADDRSTRLEN for TOX_AF_INET + * and INET6_ADDRSTRLEN for TOX_AF_INET6 + * + * output + * address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6) + * + * returns 1 on success, 0 on failure + */ +int ip_parse_addr(const IP *ip, char *address, size_t length) +{ + if (!address || !ip) { + return 0; + } + + if (ip->family == TOX_AF_INET) { + const struct in_addr *addr = (const struct in_addr *)&ip->ip4; + return inet_ntop(ip->family, addr, address, length) != NULL; + } + + if (ip->family == TOX_AF_INET6) { + const struct in6_addr *addr = (const struct in6_addr *)&ip->ip6; + return inet_ntop(ip->family, addr, address, length) != NULL; + } + + return 0; +} + +/* + * addr_parse_ip + * directly parses the input into an IP structure + * tries IPv4 first, then IPv6 + * + * input + * address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6) + * + * output + * IP: family and the value is set on success + * + * returns 1 on success, 0 on failure + */ +int addr_parse_ip(const char *address, IP *to) +{ + if (!address || !to) { + return 0; + } + + struct in_addr addr4; + + if (inet_pton(AF_INET, address, &addr4) == 1) { + to->family = TOX_AF_INET; + get_ip4(&to->ip4, &addr4); + return 1; + } + + struct in6_addr addr6; + + if (inet_pton(AF_INET6, address, &addr6) == 1) { + to->family = TOX_AF_INET6; + get_ip6(&to->ip6, &addr6); + return 1; + } + + return 0; +} + +/* + * addr_resolve(): + * uses getaddrinfo to resolve an address into an IP address + * uses the first IPv4/IPv6 addresses returned by getaddrinfo + * + * input + * address: a hostname (or something parseable to an IP address) + * to: to.family MUST be initialized, either set to a specific IP version + * (TOX_AF_INET/TOX_AF_INET6) or to the unspecified AF_UNSPEC (= 0), if both + * IP versions are acceptable + * extra can be NULL and is only set in special circumstances, see returns + * + * returns in *to a valid IPAny (v4/v6), + * prefers v6 if ip.family was AF_UNSPEC and both available + * returns in *extra an IPv4 address, if family was AF_UNSPEC and *to is TOX_AF_INET6 + * returns 0 on failure, TOX_ADDR_RESOLVE_* on success. + */ +int addr_resolve(const char *address, IP *to, IP *extra) +{ + if (!address || !to) { + return 0; + } + + Family tox_family = to->family; + Family family = make_family(tox_family); + + struct addrinfo *server = NULL; + struct addrinfo *walker = NULL; + struct addrinfo hints; + int rc; + int result = 0; + int done = 0; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_socktype = SOCK_DGRAM; // type of socket Tox uses. + + if (networking_at_startup() != 0) { + return 0; + } + + rc = getaddrinfo(address, NULL, &hints, &server); + + // Lookup failed. + if (rc != 0) { + return 0; + } + + IP ip4; + ip_init(&ip4, 0); // ipv6enabled = 0 + IP ip6; + ip_init(&ip6, 1); // ipv6enabled = 1 + + for (walker = server; (walker != NULL) && !done; walker = walker->ai_next) { + switch (walker->ai_family) { + case AF_INET: + if (walker->ai_family == family) { /* AF_INET requested, done */ + struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr; + get_ip4(&to->ip4, &addr->sin_addr); + result = TOX_ADDR_RESOLVE_INET; + done = 1; + } else if (!(result & TOX_ADDR_RESOLVE_INET)) { /* AF_UNSPEC requested, store away */ + struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr; + get_ip4(&ip4.ip4, &addr->sin_addr); + result |= TOX_ADDR_RESOLVE_INET; + } + + break; /* switch */ + + case AF_INET6: + if (walker->ai_family == family) { /* AF_INET6 requested, done */ + if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) { + struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr; + get_ip6(&to->ip6, &addr->sin6_addr); + result = TOX_ADDR_RESOLVE_INET6; + done = 1; + } + } else if (!(result & TOX_ADDR_RESOLVE_INET6)) { /* AF_UNSPEC requested, store away */ + if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) { + struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr; + get_ip6(&ip6.ip6, &addr->sin6_addr); + result |= TOX_ADDR_RESOLVE_INET6; + } + } + + break; /* switch */ + } + } + + if (family == AF_UNSPEC) { + if (result & TOX_ADDR_RESOLVE_INET6) { + ip_copy(to, &ip6); + + if ((result & TOX_ADDR_RESOLVE_INET) && (extra != NULL)) { + ip_copy(extra, &ip4); + } + } else if (result & TOX_ADDR_RESOLVE_INET) { + ip_copy(to, &ip4); + } else { + result = 0; + } + } + + freeaddrinfo(server); + return result; +} + +/* + * addr_resolve_or_parse_ip + * resolves string into an IP address + * + * address: a hostname (or something parseable to an IP address) + * to: to.family MUST be initialized, either set to a specific IP version + * (TOX_AF_INET/TOX_AF_INET6) or to the unspecified AF_UNSPEC (= 0), if both + * IP versions are acceptable + * extra can be NULL and is only set in special circumstances, see returns + * + * returns in *tro a matching address (IPv6 or IPv4) + * returns in *extra, if not NULL, an IPv4 address, if to->family was AF_UNSPEC + * returns 1 on success + * returns 0 on failure + */ +int addr_resolve_or_parse_ip(const char *address, IP *to, IP *extra) +{ + if (!addr_resolve(address, to, extra)) { + if (!addr_parse_ip(address, to)) { + return 0; + } + } + + return 1; +} + +int net_connect(Socket sock, IP_Port ip_port) +{ + struct sockaddr_storage addr = {0}; + size_t addrsize; + + if (ip_port.ip.family == TOX_AF_INET) { + struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; + + addrsize = sizeof(struct sockaddr_in); + addr4->sin_family = AF_INET; + fill_addr4(ip_port.ip.ip4, &addr4->sin_addr); + addr4->sin_port = ip_port.port; + } else if (ip_port.ip.family == TOX_AF_INET6) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; + + addrsize = sizeof(struct sockaddr_in6); + addr6->sin6_family = AF_INET6; + fill_addr6(ip_port.ip.ip6, &addr6->sin6_addr); + addr6->sin6_port = ip_port.port; + } else { + return 0; + } + + return connect(sock, (struct sockaddr *)&addr, addrsize); +} + +int32_t net_getipport(const char *node, IP_Port **res, int tox_type) +{ + struct addrinfo *infos; + int ret = getaddrinfo(node, NULL, NULL, &infos); + *res = NULL; + + if (ret != 0) { + return -1; + } + + // Used to avoid malloc parameter overflow + const size_t MAX_COUNT = MIN(SIZE_MAX, INT32_MAX) / sizeof(IP_Port); + int type = make_socktype(tox_type); + struct addrinfo *cur; + int32_t count = 0; + + for (cur = infos; count < MAX_COUNT && cur != NULL; cur = cur->ai_next) { + if (cur->ai_socktype && type > 0 && cur->ai_socktype != type) { + continue; + } + + if (cur->ai_family != AF_INET && cur->ai_family != AF_INET6) { + continue; + } + + count++; + } + + assert(count <= MAX_COUNT); + + if (count == 0) { + return 0; + } + + *res = (IP_Port *)malloc(sizeof(IP_Port) * count); + + if (*res == NULL) { + return -1; + } + + IP_Port *ip_port = *res; + + for (cur = infos; cur != NULL; cur = cur->ai_next) { + if (cur->ai_socktype && type > 0 && cur->ai_socktype != type) { + continue; + } + + if (cur->ai_family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)cur->ai_addr; + memcpy(&ip_port->ip.ip4, &addr->sin_addr, sizeof(IP4)); + } else if (cur->ai_family == AF_INET6) { + struct sockaddr_in6 *addr = (struct sockaddr_in6 *)cur->ai_addr; + memcpy(&ip_port->ip.ip6, &addr->sin6_addr, sizeof(IP6)); + } else { + continue; + } + + ip_port->ip.family = make_tox_family(cur->ai_family); + + ip_port++; + } + + freeaddrinfo(infos); + + return count; +} + +void net_freeipport(IP_Port *ip_ports) +{ + free(ip_ports); +} + +/* return 1 on success + * return 0 on failure + */ +int bind_to_port(Socket sock, int family, uint16_t port) +{ + struct sockaddr_storage addr = {0}; + size_t addrsize; + + if (family == TOX_AF_INET) { + struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; + + addrsize = sizeof(struct sockaddr_in); + addr4->sin_family = AF_INET; + addr4->sin_port = net_htons(port); + } else if (family == TOX_AF_INET6) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; + + addrsize = sizeof(struct sockaddr_in6); + addr6->sin6_family = AF_INET6; + addr6->sin6_port = net_htons(port); + } else { + return 0; + } + + return (bind(sock, (struct sockaddr *)&addr, addrsize) == 0); +} + +static int make_tox_family(int family) +{ + switch (family) { + case AF_INET: + return TOX_AF_INET; + + case AF_INET6: + return TOX_AF_INET6; + + case AF_UNSPEC: + return TOX_AF_UNSPEC; + + default: + return family; + } +} + +static int make_family(int tox_family) +{ + switch (tox_family) { + case TOX_AF_INET: + return AF_INET; + + case TOX_AF_INET6: + return AF_INET6; + + case TOX_AF_UNSPEC: + return AF_UNSPEC; + + default: + return tox_family; + } +} + +static int make_socktype(int type) +{ + switch (type) { + case TOX_SOCK_STREAM: + return SOCK_STREAM; + + case TOX_SOCK_DGRAM: + return SOCK_DGRAM; + + default: + return type; + } +} + +static int make_proto(int proto) +{ + switch (proto) { + case TOX_PROTO_TCP: + return IPPROTO_TCP; + + case TOX_PROTO_UDP: + return IPPROTO_UDP; + + default: + return proto; + } +} + +Socket net_socket(int domain, int type, int protocol) +{ + int platform_domain = make_family(domain); + int platform_type = make_socktype(type); + int platform_prot = make_proto(protocol); + return socket(platform_domain, platform_type, platform_prot); +} + +/* TODO: Remove, when tox DNS support will be removed. + * Used only by dns3_test.c + */ +size_t net_sendto_ip4(Socket sock, const char *buf, size_t n, IP_Port ip_port) +{ + struct sockaddr_in target; + size_t addrsize = sizeof(target); + target.sin_family = make_family(ip_port.ip.family); + target.sin_port = net_htons(ip_port.port); + fill_addr4(ip_port.ip.ip4, &target.sin_addr); + + return (size_t)sendto(sock, buf, n, 0, (struct sockaddr *)&target, addrsize); +} + +uint32_t net_htonl(uint32_t hostlong) +{ + return htonl(hostlong); +} + +uint16_t net_htons(uint16_t hostshort) +{ + return htons(hostshort); +} + +uint32_t net_ntohl(uint32_t hostlong) +{ + return ntohl(hostlong); +} + +uint16_t net_ntohs(uint16_t hostshort) +{ + return ntohs(hostshort); +} diff --git a/protocols/Tox/libtox/src/toxcore/network.h b/protocols/Tox/libtox/src/toxcore/network.h new file mode 100644 index 0000000000..0b9da5a40f --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/network.h @@ -0,0 +1,424 @@ +/* + * Datatypes, functions and includes for the core networking. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef NETWORK_H +#define NETWORK_H + +#ifdef PLAN9 +#include <u.h> // Plan 9 requires this is imported first +// Comment line here to avoid reordering by source code formatters. +#include <libc.h> +#endif + +#include "ccompat.h" +#include "logger.h" + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) /* Put win32 includes here */ +#ifndef WINVER +//Windows XP +#define WINVER 0x0501 +#endif + +// The mingw32/64 Windows library warns about including winsock2.h after +// windows.h even though with the above it's a valid thing to do. So, to make +// mingw32 headers happy, we include winsock2.h first. +#include <winsock2.h> + +#include <windows.h> +#include <ws2tcpip.h> + +#else // UNIX includes + +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <unistd.h> + +#endif + +typedef short Family; + +typedef int Socket; +Socket net_socket(int domain, int type, int protocol); + +#define MAX_UDP_PACKET_SIZE 2048 + +typedef enum NET_PACKET_TYPE { + NET_PACKET_PING_REQUEST = 0x00, /* Ping request packet ID. */ + NET_PACKET_PING_RESPONSE = 0x01, /* Ping response packet ID. */ + NET_PACKET_GET_NODES = 0x02, /* Get nodes request packet ID. */ + NET_PACKET_SEND_NODES_IPV6 = 0x04, /* Send nodes response packet ID for other addresses. */ + NET_PACKET_COOKIE_REQUEST = 0x18, /* Cookie request packet */ + NET_PACKET_COOKIE_RESPONSE = 0x19, /* Cookie response packet */ + NET_PACKET_CRYPTO_HS = 0x1a, /* Crypto handshake packet */ + NET_PACKET_CRYPTO_DATA = 0x1b, /* Crypto data packet */ + NET_PACKET_CRYPTO = 0x20, /* Encrypted data packet ID. */ + NET_PACKET_LAN_DISCOVERY = 0x21, /* LAN discovery packet ID. */ + + /* See: docs/Prevent_Tracking.txt and onion.{c,h} */ + NET_PACKET_ONION_SEND_INITIAL = 0x80, + NET_PACKET_ONION_SEND_1 = 0x81, + NET_PACKET_ONION_SEND_2 = 0x82, + + NET_PACKET_ANNOUNCE_REQUEST = 0x83, + NET_PACKET_ANNOUNCE_RESPONSE = 0x84, + NET_PACKET_ONION_DATA_REQUEST = 0x85, + NET_PACKET_ONION_DATA_RESPONSE = 0x86, + + NET_PACKET_ONION_RECV_3 = 0x8c, + NET_PACKET_ONION_RECV_2 = 0x8d, + NET_PACKET_ONION_RECV_1 = 0x8e, + + BOOTSTRAP_INFO_PACKET_ID = 0xf0, /* Only used for bootstrap nodes */ + + NET_PACKET_MAX = 0xff, /* This type must remain within a single uint8. */ +} NET_PACKET_TYPE; + + +#define TOX_PORTRANGE_FROM 33445 +#define TOX_PORTRANGE_TO 33545 +#define TOX_PORT_DEFAULT TOX_PORTRANGE_FROM + +/* Redefinitions of variables for safe transfer over wire. */ +#define TOX_AF_UNSPEC 0 +#define TOX_AF_INET 2 +#define TOX_AF_INET6 10 +#define TOX_TCP_INET 130 +#define TOX_TCP_INET6 138 + +#define TOX_SOCK_STREAM 1 +#define TOX_SOCK_DGRAM 2 + +#define TOX_PROTO_TCP 1 +#define TOX_PROTO_UDP 2 + +/* TCP related */ +#define TCP_ONION_FAMILY (TOX_AF_INET6 + 1) +#define TCP_INET (TOX_AF_INET6 + 2) +#define TCP_INET6 (TOX_AF_INET6 + 3) +#define TCP_FAMILY (TOX_AF_INET6 + 4) + +typedef union { + uint32_t uint32; + uint16_t uint16[2]; + uint8_t uint8[4]; +} +IP4; + +IP4 get_ip4_loopback(void); +extern const IP4 IP4_BROADCAST; + +typedef union { + uint8_t uint8[16]; + uint16_t uint16[8]; + uint32_t uint32[4]; + uint64_t uint64[2]; +} +IP6; + +IP6 get_ip6_loopback(void); +extern const IP6 IP6_BROADCAST; + +typedef struct { + uint8_t family; + GNU_EXTENSION union { + IP4 ip4; + IP6 ip6; + }; +} +IP; + +typedef struct { + IP ip; + uint16_t port; +} +IP_Port; + +/* Convert values between host and network byte order. + */ +uint32_t net_htonl(uint32_t hostlong); +uint16_t net_htons(uint16_t hostshort); +uint32_t net_ntohl(uint32_t hostlong); +uint16_t net_ntohs(uint16_t hostshort); + +/* Does the IP6 struct a contain an IPv4 address in an IPv6 one? */ +#define IPV6_IPV4_IN_V6(a) ((a.uint64[0] == 0) && (a.uint32[2] == net_htonl (0xffff))) + +#define SIZE_IP4 4 +#define SIZE_IP6 16 +#define SIZE_IP (1 + SIZE_IP6) +#define SIZE_PORT 2 +#define SIZE_IPPORT (SIZE_IP + SIZE_PORT) + +#define TOX_ENABLE_IPV6_DEFAULT 1 + +/* addr_resolve return values */ +#define TOX_ADDR_RESOLVE_INET 1 +#define TOX_ADDR_RESOLVE_INET6 2 + +#define TOX_INET6_ADDRSTRLEN 66 +#define TOX_INET_ADDRSTRLEN 22 + +/* ip_ntoa + * converts ip into a string + * ip_str must be of length at least IP_NTOA_LEN + * + * IPv6 addresses are enclosed into square brackets, i.e. "[IPv6]" + * writes error message into the buffer on error + * + * returns ip_str + */ +/* this would be TOX_INET6_ADDRSTRLEN, but it might be too short for the error message */ +#define IP_NTOA_LEN 96 // TODO(irungentoo): magic number. Why not INET6_ADDRSTRLEN ? +const char *ip_ntoa(const IP *ip, char *ip_str, size_t length); + +/* + * ip_parse_addr + * parses IP structure into an address string + * + * input + * ip: ip of TOX_AF_INET or TOX_AF_INET6 families + * length: length of the address buffer + * Must be at least TOX_INET_ADDRSTRLEN for TOX_AF_INET + * and TOX_INET6_ADDRSTRLEN for TOX_AF_INET6 + * + * output + * address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6) + * + * returns 1 on success, 0 on failure + */ +int ip_parse_addr(const IP *ip, char *address, size_t length); + +/* + * addr_parse_ip + * directly parses the input into an IP structure + * tries IPv4 first, then IPv6 + * + * input + * address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6) + * + * output + * IP: family and the value is set on success + * + * returns 1 on success, 0 on failure + */ +int addr_parse_ip(const char *address, IP *to); + +/* ip_equal + * compares two IPAny structures + * unset means unequal + * + * returns 0 when not equal or when uninitialized + */ +int ip_equal(const IP *a, const IP *b); + +/* ipport_equal + * compares two IPAny_Port structures + * unset means unequal + * + * returns 0 when not equal or when uninitialized + */ +int ipport_equal(const IP_Port *a, const IP_Port *b); + +/* nulls out ip */ +void ip_reset(IP *ip); +/* nulls out ip, sets family according to flag */ +void ip_init(IP *ip, uint8_t ipv6enabled); +/* checks if ip is valid */ +int ip_isset(const IP *ip); +/* checks if ip is valid */ +int ipport_isset(const IP_Port *ipport); +/* copies an ip structure */ +void ip_copy(IP *target, const IP *source); +/* copies an ip_port structure */ +void ipport_copy(IP_Port *target, const IP_Port *source); + +/* + * addr_resolve(): + * uses getaddrinfo to resolve an address into an IP address + * uses the first IPv4/IPv6 addresses returned by getaddrinfo + * + * input + * address: a hostname (or something parseable to an IP address) + * to: to.family MUST be initialized, either set to a specific IP version + * (TOX_AF_INET/TOX_AF_INET6) or to the unspecified TOX_AF_UNSPEC (= 0), if both + * IP versions are acceptable + * extra can be NULL and is only set in special circumstances, see returns + * + * returns in *to a valid IPAny (v4/v6), + * prefers v6 if ip.family was TOX_AF_UNSPEC and both available + * returns in *extra an IPv4 address, if family was TOX_AF_UNSPEC and *to is TOX_AF_INET6 + * returns 0 on failure + */ +int addr_resolve(const char *address, IP *to, IP *extra); + +/* + * addr_resolve_or_parse_ip + * resolves string into an IP address + * + * address: a hostname (or something parseable to an IP address) + * to: to.family MUST be initialized, either set to a specific IP version + * (TOX_AF_INET/TOX_AF_INET6) or to the unspecified TOX_AF_UNSPEC (= 0), if both + * IP versions are acceptable + * extra can be NULL and is only set in special circumstances, see returns + * + * returns in *tro a matching address (IPv6 or IPv4) + * returns in *extra, if not NULL, an IPv4 address, if to->family was TOX_AF_UNSPEC + * returns 1 on success + * returns 0 on failure + */ +int addr_resolve_or_parse_ip(const char *address, IP *to, IP *extra); + +/* Function to receive data, ip and port of sender is put into ip_port. + * Packet data is put into data. + * Packet length is put into length. + */ +typedef int (*packet_handler_callback)(void *object, IP_Port ip_port, const uint8_t *data, uint16_t len, + void *userdata); + +typedef struct { + packet_handler_callback function; + void *object; +} Packet_Handles; + +typedef struct { + Logger *log; + Packet_Handles packethandlers[256]; + + Family family; + uint16_t port; + /* Our UDP socket. */ + Socket sock; +} Networking_Core; + +/* Run this before creating sockets. + * + * return 0 on success + * return -1 on failure + */ +int networking_at_startup(void); + +/* Check if socket is valid. + * + * return 1 if valid + * return 0 if not valid + */ +int sock_valid(Socket sock); + +/* Close the socket. + */ +void kill_sock(Socket sock); + +/* Set socket as nonblocking + * + * return 1 on success + * return 0 on failure + */ +int set_socket_nonblock(Socket sock); + +/* Set socket to not emit SIGPIPE + * + * return 1 on success + * return 0 on failure + */ +int set_socket_nosigpipe(Socket sock); + +/* Enable SO_REUSEADDR on socket. + * + * return 1 on success + * return 0 on failure + */ +int set_socket_reuseaddr(Socket sock); + +/* Set socket to dual (IPv4 + IPv6 socket) + * + * return 1 on success + * return 0 on failure + */ +int set_socket_dualstack(Socket sock); + +/* return current monotonic time in milliseconds (ms). */ +uint64_t current_time_monotonic(void); + +/* Basic network functions: */ + +/* Function to send packet(data) of length length to ip_port. */ +int sendpacket(Networking_Core *net, IP_Port ip_port, const uint8_t *data, uint16_t length); + +/* Function to call when packet beginning with byte is received. */ +void networking_registerhandler(Networking_Core *net, uint8_t byte, packet_handler_callback cb, void *object); + +/* Call this several times a second. */ +void networking_poll(Networking_Core *net, void *userdata); + +/* Connect a socket to the address specified by the ip_port. */ +int net_connect(Socket sock, IP_Port ip_port); + +/* High-level getaddrinfo implementation. + * Given node, which identifies an Internet host, net_getipport() fills an array + * with one or more IP_Port structures, each of which contains an Internet + * address that can be specified by calling net_connect(), the port is ignored. + * + * Skip all addresses with socktype != type (use type = -1 to get all addresses) + * To correctly deallocate array memory use net_freeipport() + * + * return number of elements in res array + * and -1 on error. + */ +int32_t net_getipport(const char *node, IP_Port **res, int tox_type); + +/* Deallocates memory allocated by net_getipport + */ +void net_freeipport(IP_Port *ip_ports); + +/* return 1 on success + * return 0 on failure + */ +int bind_to_port(Socket sock, int family, uint16_t port); + +size_t net_sendto_ip4(Socket sock, const char *buf, size_t n, IP_Port ip_port); + +/* Initialize networking. + * bind to ip and port. + * ip must be in network order EX: 127.0.0.1 = (7F000001). + * port is in host byte order (this means don't worry about it). + * + * return Networking_Core object if no problems + * return NULL if there are problems. + * + * If error is non NULL it is set to 0 if no issues, 1 if socket related error, 2 if other. + */ +Networking_Core *new_networking(Logger *log, IP ip, uint16_t port); +Networking_Core *new_networking_ex(Logger *log, IP ip, uint16_t port_from, uint16_t port_to, unsigned int *error); + +/* Function to cleanup networking stuff (doesn't do much right now). */ +void kill_networking(Networking_Core *net); + +#endif diff --git a/protocols/Tox/libtox/src/toxcore/onion.c b/protocols/Tox/libtox/src/toxcore/onion.c new file mode 100644 index 0000000000..fbaf7205d9 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/onion.c @@ -0,0 +1,679 @@ +/* + * Implementation of the onion part of docs/Prevent_Tracking.txt + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "onion.h" + +#include "util.h" + +#define RETURN_1 ONION_RETURN_1 +#define RETURN_2 ONION_RETURN_2 +#define RETURN_3 ONION_RETURN_3 + +#define SEND_BASE ONION_SEND_BASE +#define SEND_3 ONION_SEND_3 +#define SEND_2 ONION_SEND_2 +#define SEND_1 ONION_SEND_1 + +/* Change symmetric keys every 2 hours to make paths expire eventually. */ +#define KEY_REFRESH_INTERVAL (2 * 60 * 60) +static void change_symmetric_key(Onion *onion) +{ + if (is_timeout(onion->timestamp, KEY_REFRESH_INTERVAL)) { + new_symmetric_key(onion->secret_symmetric_key); + onion->timestamp = unix_time(); + } +} + +/* packing and unpacking functions */ +static void ip_pack(uint8_t *data, IP source) +{ + data[0] = source.family; + + if (source.family == TOX_AF_INET || source.family == TOX_TCP_INET) { + memset(data + 1, 0, SIZE_IP6); + memcpy(data + 1, source.ip4.uint8, SIZE_IP4); + } else { + memcpy(data + 1, source.ip6.uint8, SIZE_IP6); + } +} + +/* return 0 on success, -1 on failure. */ +static int ip_unpack(IP *target, const uint8_t *data, unsigned int data_size, bool disable_family_check) +{ + if (data_size < (1 + SIZE_IP6)) { + return -1; + } + + target->family = data[0]; + + if (target->family == TOX_AF_INET || target->family == TOX_TCP_INET) { + memcpy(target->ip4.uint8, data + 1, SIZE_IP4); + } else { + memcpy(target->ip6.uint8, data + 1, SIZE_IP6); + } + + bool valid = disable_family_check || + target->family == TOX_AF_INET || + target->family == TOX_AF_INET6; + + return valid ? 0 : -1; +} + +static void ipport_pack(uint8_t *data, const IP_Port *source) +{ + ip_pack(data, source->ip); + memcpy(data + SIZE_IP, &source->port, SIZE_PORT); +} + +/* return 0 on success, -1 on failure. */ +static int ipport_unpack(IP_Port *target, const uint8_t *data, unsigned int data_size, bool disable_family_check) +{ + if (data_size < (SIZE_IP + SIZE_PORT)) { + return -1; + } + + if (ip_unpack(&target->ip, data, data_size, disable_family_check) == -1) { + return -1; + } + + memcpy(&target->port, data + SIZE_IP, SIZE_PORT); + return 0; +} + + +/* Create a new onion path. + * + * Create a new onion path out of nodes (nodes is a list of ONION_PATH_LENGTH nodes) + * + * new_path must be an empty memory location of atleast Onion_Path size. + * + * return -1 on failure. + * return 0 on success. + */ +int create_onion_path(const DHT *dht, Onion_Path *new_path, const Node_format *nodes) +{ + if (!new_path || !nodes) { + return -1; + } + + encrypt_precompute(nodes[0].public_key, dht->self_secret_key, new_path->shared_key1); + memcpy(new_path->public_key1, dht->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + + uint8_t random_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t random_secret_key[CRYPTO_SECRET_KEY_SIZE]; + + crypto_new_keypair(random_public_key, random_secret_key); + encrypt_precompute(nodes[1].public_key, random_secret_key, new_path->shared_key2); + memcpy(new_path->public_key2, random_public_key, CRYPTO_PUBLIC_KEY_SIZE); + + crypto_new_keypair(random_public_key, random_secret_key); + encrypt_precompute(nodes[2].public_key, random_secret_key, new_path->shared_key3); + memcpy(new_path->public_key3, random_public_key, CRYPTO_PUBLIC_KEY_SIZE); + + new_path->ip_port1 = nodes[0].ip_port; + new_path->ip_port2 = nodes[1].ip_port; + new_path->ip_port3 = nodes[2].ip_port; + + memcpy(new_path->node_public_key1, nodes[0].public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(new_path->node_public_key2, nodes[1].public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(new_path->node_public_key3, nodes[2].public_key, CRYPTO_PUBLIC_KEY_SIZE); + + return 0; +} + +/* Dump nodes in onion path to nodes of length num_nodes; + * + * return -1 on failure. + * return 0 on success. + */ +int onion_path_to_nodes(Node_format *nodes, unsigned int num_nodes, const Onion_Path *path) +{ + if (num_nodes < ONION_PATH_LENGTH) { + return -1; + } + + nodes[0].ip_port = path->ip_port1; + nodes[1].ip_port = path->ip_port2; + nodes[2].ip_port = path->ip_port3; + + memcpy(nodes[0].public_key, path->node_public_key1, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(nodes[1].public_key, path->node_public_key2, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(nodes[2].public_key, path->node_public_key3, CRYPTO_PUBLIC_KEY_SIZE); + return 0; +} + +/* Create a onion packet. + * + * Use Onion_Path path to create packet for data of length to dest. + * Maximum length of data is ONION_MAX_DATA_SIZE. + * packet should be at least ONION_MAX_PACKET_SIZE big. + * + * return -1 on failure. + * return length of created packet on success. + */ +int create_onion_packet(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, + const uint8_t *data, uint16_t length) +{ + if (1 + length + SEND_1 > max_packet_length || length == 0) { + return -1; + } + + VLA(uint8_t, step1, SIZE_IPPORT + length); + + ipport_pack(step1, &dest); + memcpy(step1 + SIZE_IPPORT, data, length); + + uint8_t nonce[CRYPTO_NONCE_SIZE]; + random_nonce(nonce); + + VLA(uint8_t, step2, SIZE_IPPORT + SEND_BASE + length); + ipport_pack(step2, &path->ip_port3); + memcpy(step2 + SIZE_IPPORT, path->public_key3, CRYPTO_PUBLIC_KEY_SIZE); + + int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, SIZEOF_VLA(step1), + step2 + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE); + + if (len != SIZE_IPPORT + length + CRYPTO_MAC_SIZE) { + return -1; + } + + VLA(uint8_t, step3, SIZE_IPPORT + SEND_BASE * 2 + length); + ipport_pack(step3, &path->ip_port2); + memcpy(step3 + SIZE_IPPORT, path->public_key2, CRYPTO_PUBLIC_KEY_SIZE); + len = encrypt_data_symmetric(path->shared_key2, nonce, step2, SIZEOF_VLA(step2), + step3 + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE); + + if (len != SIZE_IPPORT + SEND_BASE + length + CRYPTO_MAC_SIZE) { + return -1; + } + + packet[0] = NET_PACKET_ONION_SEND_INITIAL; + memcpy(packet + 1, nonce, CRYPTO_NONCE_SIZE); + memcpy(packet + 1 + CRYPTO_NONCE_SIZE, path->public_key1, CRYPTO_PUBLIC_KEY_SIZE); + + len = encrypt_data_symmetric(path->shared_key1, nonce, step3, SIZEOF_VLA(step3), + packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE); + + if (len != SIZE_IPPORT + SEND_BASE * 2 + length + CRYPTO_MAC_SIZE) { + return -1; + } + + return 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + len; +} + +/* Create a onion packet to be sent over tcp. + * + * Use Onion_Path path to create packet for data of length to dest. + * Maximum length of data is ONION_MAX_DATA_SIZE. + * packet should be at least ONION_MAX_PACKET_SIZE big. + * + * return -1 on failure. + * return length of created packet on success. + */ +int create_onion_packet_tcp(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, + const uint8_t *data, uint16_t length) +{ + if (CRYPTO_NONCE_SIZE + SIZE_IPPORT + SEND_BASE * 2 + length > max_packet_length || length == 0) { + return -1; + } + + VLA(uint8_t, step1, SIZE_IPPORT + length); + + ipport_pack(step1, &dest); + memcpy(step1 + SIZE_IPPORT, data, length); + + uint8_t nonce[CRYPTO_NONCE_SIZE]; + random_nonce(nonce); + + VLA(uint8_t, step2, SIZE_IPPORT + SEND_BASE + length); + ipport_pack(step2, &path->ip_port3); + memcpy(step2 + SIZE_IPPORT, path->public_key3, CRYPTO_PUBLIC_KEY_SIZE); + + int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, SIZEOF_VLA(step1), + step2 + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE); + + if (len != SIZE_IPPORT + length + CRYPTO_MAC_SIZE) { + return -1; + } + + ipport_pack(packet + CRYPTO_NONCE_SIZE, &path->ip_port2); + memcpy(packet + CRYPTO_NONCE_SIZE + SIZE_IPPORT, path->public_key2, CRYPTO_PUBLIC_KEY_SIZE); + len = encrypt_data_symmetric(path->shared_key2, nonce, step2, SIZEOF_VLA(step2), + packet + CRYPTO_NONCE_SIZE + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE); + + if (len != SIZE_IPPORT + SEND_BASE + length + CRYPTO_MAC_SIZE) { + return -1; + } + + memcpy(packet, nonce, CRYPTO_NONCE_SIZE); + + return CRYPTO_NONCE_SIZE + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE + len; +} + +/* Create and send a onion packet. + * + * Use Onion_Path path to send data of length to dest. + * Maximum length of data is ONION_MAX_DATA_SIZE. + * + * return -1 on failure. + * return 0 on success. + */ +int send_onion_packet(Networking_Core *net, const Onion_Path *path, IP_Port dest, const uint8_t *data, uint16_t length) +{ + uint8_t packet[ONION_MAX_PACKET_SIZE]; + int len = create_onion_packet(packet, sizeof(packet), path, dest, data, length); + + if (len == -1) { + return -1; + } + + if (sendpacket(net, path->ip_port1, packet, len) != len) { + return -1; + } + + return 0; +} + +/* Create and send a onion response sent initially to dest with. + * Maximum length of data is ONION_RESPONSE_MAX_DATA_SIZE. + * + * return -1 on failure. + * return 0 on success. + */ +int send_onion_response(Networking_Core *net, IP_Port dest, const uint8_t *data, uint16_t length, const uint8_t *ret) +{ + if (length > ONION_RESPONSE_MAX_DATA_SIZE || length == 0) { + return -1; + } + + VLA(uint8_t, packet, 1 + RETURN_3 + length); + packet[0] = NET_PACKET_ONION_RECV_3; + memcpy(packet + 1, ret, RETURN_3); + memcpy(packet + 1 + RETURN_3, data, length); + + if ((uint32_t)sendpacket(net, dest, packet, SIZEOF_VLA(packet)) != SIZEOF_VLA(packet)) { + return -1; + } + + return 0; +} + +static int handle_send_initial(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + Onion *onion = (Onion *)object; + + if (length > ONION_MAX_PACKET_SIZE) { + return 1; + } + + if (length <= 1 + SEND_1) { + return 1; + } + + change_symmetric_key(onion); + + uint8_t plain[ONION_MAX_PACKET_SIZE]; + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + get_shared_key(&onion->shared_keys_1, shared_key, onion->dht->self_secret_key, packet + 1 + CRYPTO_NONCE_SIZE); + int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, + length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE), plain); + + if (len != length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_MAC_SIZE)) { + return 1; + } + + return onion_send_1(onion, plain, len, source, packet + 1); +} + +int onion_send_1(const Onion *onion, const uint8_t *plain, uint16_t len, IP_Port source, const uint8_t *nonce) +{ + if (len > ONION_MAX_PACKET_SIZE + SIZE_IPPORT - (1 + CRYPTO_NONCE_SIZE + ONION_RETURN_1)) { + return 1; + } + + if (len <= SIZE_IPPORT + SEND_BASE * 2) { + return 1; + } + + IP_Port send_to; + + if (ipport_unpack(&send_to, plain, len, 0) == -1) { + return 1; + } + + uint8_t ip_port[SIZE_IPPORT]; + ipport_pack(ip_port, &source); + + uint8_t data[ONION_MAX_PACKET_SIZE]; + data[0] = NET_PACKET_ONION_SEND_1; + memcpy(data + 1, nonce, CRYPTO_NONCE_SIZE); + memcpy(data + 1 + CRYPTO_NONCE_SIZE, plain + SIZE_IPPORT, len - SIZE_IPPORT); + uint16_t data_len = 1 + CRYPTO_NONCE_SIZE + (len - SIZE_IPPORT); + uint8_t *ret_part = data + data_len; + random_nonce(ret_part); + len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ip_port, SIZE_IPPORT, + ret_part + CRYPTO_NONCE_SIZE); + + if (len != SIZE_IPPORT + CRYPTO_MAC_SIZE) { + return 1; + } + + data_len += CRYPTO_NONCE_SIZE + len; + + if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len) { + return 1; + } + + return 0; +} + +static int handle_send_1(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + Onion *onion = (Onion *)object; + + if (length > ONION_MAX_PACKET_SIZE) { + return 1; + } + + if (length <= 1 + SEND_2) { + return 1; + } + + change_symmetric_key(onion); + + uint8_t plain[ONION_MAX_PACKET_SIZE]; + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + get_shared_key(&onion->shared_keys_2, shared_key, onion->dht->self_secret_key, packet + 1 + CRYPTO_NONCE_SIZE); + int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, + length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_1), plain); + + if (len != length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_1 + CRYPTO_MAC_SIZE)) { + return 1; + } + + IP_Port send_to; + + if (ipport_unpack(&send_to, plain, len, 0) == -1) { + return 1; + } + + uint8_t data[ONION_MAX_PACKET_SIZE]; + data[0] = NET_PACKET_ONION_SEND_2; + memcpy(data + 1, packet + 1, CRYPTO_NONCE_SIZE); + memcpy(data + 1 + CRYPTO_NONCE_SIZE, plain + SIZE_IPPORT, len - SIZE_IPPORT); + uint16_t data_len = 1 + CRYPTO_NONCE_SIZE + (len - SIZE_IPPORT); + uint8_t *ret_part = data + data_len; + random_nonce(ret_part); + uint8_t ret_data[RETURN_1 + SIZE_IPPORT]; + ipport_pack(ret_data, &source); + memcpy(ret_data + SIZE_IPPORT, packet + (length - RETURN_1), RETURN_1); + len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ret_data, sizeof(ret_data), + ret_part + CRYPTO_NONCE_SIZE); + + if (len != RETURN_2 - CRYPTO_NONCE_SIZE) { + return 1; + } + + data_len += CRYPTO_NONCE_SIZE + len; + + if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len) { + return 1; + } + + return 0; +} + +static int handle_send_2(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + Onion *onion = (Onion *)object; + + if (length > ONION_MAX_PACKET_SIZE) { + return 1; + } + + if (length <= 1 + SEND_3) { + return 1; + } + + change_symmetric_key(onion); + + uint8_t plain[ONION_MAX_PACKET_SIZE]; + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + get_shared_key(&onion->shared_keys_3, shared_key, onion->dht->self_secret_key, packet + 1 + CRYPTO_NONCE_SIZE); + int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, + length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_2), plain); + + if (len != length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_2 + CRYPTO_MAC_SIZE)) { + return 1; + } + + IP_Port send_to; + + if (ipport_unpack(&send_to, plain, len, 0) == -1) { + return 1; + } + + uint8_t data[ONION_MAX_PACKET_SIZE]; + memcpy(data, plain + SIZE_IPPORT, len - SIZE_IPPORT); + uint16_t data_len = (len - SIZE_IPPORT); + uint8_t *ret_part = data + (len - SIZE_IPPORT); + random_nonce(ret_part); + uint8_t ret_data[RETURN_2 + SIZE_IPPORT]; + ipport_pack(ret_data, &source); + memcpy(ret_data + SIZE_IPPORT, packet + (length - RETURN_2), RETURN_2); + len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ret_data, sizeof(ret_data), + ret_part + CRYPTO_NONCE_SIZE); + + if (len != RETURN_3 - CRYPTO_NONCE_SIZE) { + return 1; + } + + data_len += RETURN_3; + + if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len) { + return 1; + } + + return 0; +} + + +static int handle_recv_3(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + Onion *onion = (Onion *)object; + + if (length > ONION_MAX_PACKET_SIZE) { + return 1; + } + + if (length <= 1 + RETURN_3) { + return 1; + } + + change_symmetric_key(onion); + + uint8_t plain[SIZE_IPPORT + RETURN_2]; + int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE, + SIZE_IPPORT + RETURN_2 + CRYPTO_MAC_SIZE, plain); + + if ((uint32_t)len != sizeof(plain)) { + return 1; + } + + IP_Port send_to; + + if (ipport_unpack(&send_to, plain, len, 0) == -1) { + return 1; + } + + uint8_t data[ONION_MAX_PACKET_SIZE]; + data[0] = NET_PACKET_ONION_RECV_2; + memcpy(data + 1, plain + SIZE_IPPORT, RETURN_2); + memcpy(data + 1 + RETURN_2, packet + 1 + RETURN_3, length - (1 + RETURN_3)); + uint16_t data_len = 1 + RETURN_2 + (length - (1 + RETURN_3)); + + if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len) { + return 1; + } + + return 0; +} + +static int handle_recv_2(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + Onion *onion = (Onion *)object; + + if (length > ONION_MAX_PACKET_SIZE) { + return 1; + } + + if (length <= 1 + RETURN_2) { + return 1; + } + + change_symmetric_key(onion); + + uint8_t plain[SIZE_IPPORT + RETURN_1]; + int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE, + SIZE_IPPORT + RETURN_1 + CRYPTO_MAC_SIZE, plain); + + if ((uint32_t)len != sizeof(plain)) { + return 1; + } + + IP_Port send_to; + + if (ipport_unpack(&send_to, plain, len, 0) == -1) { + return 1; + } + + uint8_t data[ONION_MAX_PACKET_SIZE]; + data[0] = NET_PACKET_ONION_RECV_1; + memcpy(data + 1, plain + SIZE_IPPORT, RETURN_1); + memcpy(data + 1 + RETURN_1, packet + 1 + RETURN_2, length - (1 + RETURN_2)); + uint16_t data_len = 1 + RETURN_1 + (length - (1 + RETURN_2)); + + if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len) { + return 1; + } + + return 0; +} + +static int handle_recv_1(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + Onion *onion = (Onion *)object; + + if (length > ONION_MAX_PACKET_SIZE) { + return 1; + } + + if (length <= 1 + RETURN_1) { + return 1; + } + + change_symmetric_key(onion); + + uint8_t plain[SIZE_IPPORT]; + int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE, + SIZE_IPPORT + CRYPTO_MAC_SIZE, plain); + + if ((uint32_t)len != SIZE_IPPORT) { + return 1; + } + + IP_Port send_to; + + if (ipport_unpack(&send_to, plain, len, 1) == -1) { + return 1; + } + + uint16_t data_len = length - (1 + RETURN_1); + + if (onion->recv_1_function && + send_to.ip.family != TOX_AF_INET && + send_to.ip.family != TOX_AF_INET6) { + return onion->recv_1_function(onion->callback_object, send_to, packet + (1 + RETURN_1), data_len); + } + + if ((uint32_t)sendpacket(onion->net, send_to, packet + (1 + RETURN_1), data_len) != data_len) { + return 1; + } + + return 0; +} + +void set_callback_handle_recv_1(Onion *onion, int (*function)(void *, IP_Port, const uint8_t *, uint16_t), void *object) +{ + onion->recv_1_function = function; + onion->callback_object = object; +} + +Onion *new_onion(DHT *dht) +{ + if (dht == NULL) { + return NULL; + } + + Onion *onion = (Onion *)calloc(1, sizeof(Onion)); + + if (onion == NULL) { + return NULL; + } + + onion->dht = dht; + onion->net = dht->net; + new_symmetric_key(onion->secret_symmetric_key); + onion->timestamp = unix_time(); + + networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_INITIAL, &handle_send_initial, onion); + networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_1, &handle_send_1, onion); + networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_2, &handle_send_2, onion); + + networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_3, &handle_recv_3, onion); + networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_2, &handle_recv_2, onion); + networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_1, &handle_recv_1, onion); + + return onion; +} + +void kill_onion(Onion *onion) +{ + if (onion == NULL) { + return; + } + + networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_INITIAL, NULL, NULL); + networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_1, NULL, NULL); + networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_2, NULL, NULL); + + networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_3, NULL, NULL); + networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_2, NULL, NULL); + networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_1, NULL, NULL); + + free(onion); +} diff --git a/protocols/Tox/libtox/src/toxcore/onion.h b/protocols/Tox/libtox/src/toxcore/onion.h new file mode 100644 index 0000000000..e81b3a52ae --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/onion.h @@ -0,0 +1,165 @@ +/* + * Implementation of the onion part of docs/Prevent_Tracking.txt + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef ONION_H +#define ONION_H + +#include "DHT.h" + +typedef struct { + DHT *dht; + Networking_Core *net; + uint8_t secret_symmetric_key[CRYPTO_SYMMETRIC_KEY_SIZE]; + uint64_t timestamp; + + Shared_Keys shared_keys_1; + Shared_Keys shared_keys_2; + Shared_Keys shared_keys_3; + + int (*recv_1_function)(void *, IP_Port, const uint8_t *, uint16_t); + void *callback_object; +} Onion; + +#define ONION_MAX_PACKET_SIZE 1400 + +#define ONION_RETURN_1 (CRYPTO_NONCE_SIZE + SIZE_IPPORT + CRYPTO_MAC_SIZE) +#define ONION_RETURN_2 (CRYPTO_NONCE_SIZE + SIZE_IPPORT + CRYPTO_MAC_SIZE + ONION_RETURN_1) +#define ONION_RETURN_3 (CRYPTO_NONCE_SIZE + SIZE_IPPORT + CRYPTO_MAC_SIZE + ONION_RETURN_2) + +#define ONION_SEND_BASE (CRYPTO_PUBLIC_KEY_SIZE + SIZE_IPPORT + CRYPTO_MAC_SIZE) +#define ONION_SEND_3 (CRYPTO_NONCE_SIZE + ONION_SEND_BASE + ONION_RETURN_2) +#define ONION_SEND_2 (CRYPTO_NONCE_SIZE + ONION_SEND_BASE*2 + ONION_RETURN_1) +#define ONION_SEND_1 (CRYPTO_NONCE_SIZE + ONION_SEND_BASE*3) + +#define ONION_MAX_DATA_SIZE (ONION_MAX_PACKET_SIZE - (ONION_SEND_1 + 1)) +#define ONION_RESPONSE_MAX_DATA_SIZE (ONION_MAX_PACKET_SIZE - (1 + ONION_RETURN_3)) + +#define ONION_PATH_LENGTH 3 + +typedef struct { + uint8_t shared_key1[CRYPTO_SHARED_KEY_SIZE]; + uint8_t shared_key2[CRYPTO_SHARED_KEY_SIZE]; + uint8_t shared_key3[CRYPTO_SHARED_KEY_SIZE]; + + uint8_t public_key1[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t public_key2[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t public_key3[CRYPTO_PUBLIC_KEY_SIZE]; + + IP_Port ip_port1; + uint8_t node_public_key1[CRYPTO_PUBLIC_KEY_SIZE]; + + IP_Port ip_port2; + uint8_t node_public_key2[CRYPTO_PUBLIC_KEY_SIZE]; + + IP_Port ip_port3; + uint8_t node_public_key3[CRYPTO_PUBLIC_KEY_SIZE]; + + uint32_t path_num; +} Onion_Path; + +/* Create a new onion path. + * + * Create a new onion path out of nodes (nodes is a list of ONION_PATH_LENGTH nodes) + * + * new_path must be an empty memory location of atleast Onion_Path size. + * + * return -1 on failure. + * return 0 on success. + */ +int create_onion_path(const DHT *dht, Onion_Path *new_path, const Node_format *nodes); + +/* Dump nodes in onion path to nodes of length num_nodes; + * + * return -1 on failure. + * return 0 on success. + */ +int onion_path_to_nodes(Node_format *nodes, unsigned int num_nodes, const Onion_Path *path); + +/* Create a onion packet. + * + * Use Onion_Path path to create packet for data of length to dest. + * Maximum length of data is ONION_MAX_DATA_SIZE. + * packet should be at least ONION_MAX_PACKET_SIZE big. + * + * return -1 on failure. + * return length of created packet on success. + */ +int create_onion_packet(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, + const uint8_t *data, uint16_t length); + + +/* Create a onion packet to be sent over tcp. + * + * Use Onion_Path path to create packet for data of length to dest. + * Maximum length of data is ONION_MAX_DATA_SIZE. + * packet should be at least ONION_MAX_PACKET_SIZE big. + * + * return -1 on failure. + * return length of created packet on success. + */ +int create_onion_packet_tcp(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, + const uint8_t *data, uint16_t length); + +/* Create and send a onion packet. + * + * Use Onion_Path path to send data of length to dest. + * Maximum length of data is ONION_MAX_DATA_SIZE. + * + * return -1 on failure. + * return 0 on success. + */ +int send_onion_packet(Networking_Core *net, const Onion_Path *path, IP_Port dest, const uint8_t *data, uint16_t length); + +/* Create and send a onion response sent initially to dest with. + * Maximum length of data is ONION_RESPONSE_MAX_DATA_SIZE. + * + * return -1 on failure. + * return 0 on success. + */ +int send_onion_response(Networking_Core *net, IP_Port dest, const uint8_t *data, uint16_t length, const uint8_t *ret); + +/* Function to handle/send received decrypted versions of the packet sent with send_onion_packet. + * + * return 0 on success. + * return 1 on failure. + * + * Used to handle these packets that are received in a non traditional way (by TCP for example). + * + * Source family must be set to something else than TOX_AF_INET6 or TOX_AF_INET so that the callback gets called + * when the response is received. + */ +int onion_send_1(const Onion *onion, const uint8_t *plain, uint16_t len, IP_Port source, const uint8_t *nonce); + +/* Set the callback to be called when the dest ip_port doesn't have TOX_AF_INET6 or TOX_AF_INET as the family. + * + * Format: function(void *object, IP_Port dest, uint8_t *data, uint16_t length) + */ +void set_callback_handle_recv_1(Onion *onion, int (*function)(void *, IP_Port, const uint8_t *, uint16_t), + void *object); + +Onion *new_onion(DHT *dht); + +void kill_onion(Onion *onion); + + +#endif diff --git a/protocols/Tox/libtox/src/toxcore/onion_announce.c b/protocols/Tox/libtox/src/toxcore/onion_announce.c new file mode 100644 index 0000000000..c093800719 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/onion_announce.c @@ -0,0 +1,497 @@ +/* + * Implementation of the announce part of docs/Prevent_Tracking.txt + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "onion_announce.h" + +#include "LAN_discovery.h" +#include "util.h" + +#define PING_ID_TIMEOUT ONION_ANNOUNCE_TIMEOUT + +#define ANNOUNCE_REQUEST_SIZE_RECV (ONION_ANNOUNCE_REQUEST_SIZE + ONION_RETURN_3) + +#define DATA_REQUEST_MIN_SIZE ONION_DATA_REQUEST_MIN_SIZE +#define DATA_REQUEST_MIN_SIZE_RECV (DATA_REQUEST_MIN_SIZE + ONION_RETURN_3) + +/* Create an onion announce request packet in packet of max_packet_length (recommended size ONION_ANNOUNCE_REQUEST_SIZE). + * + * dest_client_id is the public key of the node the packet will be sent to. + * public_key and secret_key is the kepair which will be used to encrypt the request. + * ping_id is the ping id that will be sent in the request. + * client_id is the client id of the node we are searching for. + * data_public_key is the public key we want others to encrypt their data packets with. + * sendback_data is the data of ONION_ANNOUNCE_SENDBACK_DATA_LENGTH length that we expect to + * receive back in the response. + * + * return -1 on failure. + * return packet length on success. + */ +int create_announce_request(uint8_t *packet, uint16_t max_packet_length, const uint8_t *dest_client_id, + const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id, + const uint8_t *data_public_key, uint64_t sendback_data) +{ + if (max_packet_length < ONION_ANNOUNCE_REQUEST_SIZE) { + return -1; + } + + uint8_t plain[ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_PUBLIC_KEY_SIZE + + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH]; + memcpy(plain, ping_id, ONION_PING_ID_SIZE); + memcpy(plain + ONION_PING_ID_SIZE, client_id, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(plain + ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE, data_public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(plain + ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_PUBLIC_KEY_SIZE, &sendback_data, + sizeof(sendback_data)); + + packet[0] = NET_PACKET_ANNOUNCE_REQUEST; + random_nonce(packet + 1); + + int len = encrypt_data(dest_client_id, secret_key, packet + 1, plain, sizeof(plain), + packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE); + + if ((uint32_t)len + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE != ONION_ANNOUNCE_REQUEST_SIZE) { + return -1; + } + + memcpy(packet + 1 + CRYPTO_NONCE_SIZE, public_key, CRYPTO_PUBLIC_KEY_SIZE); + + return ONION_ANNOUNCE_REQUEST_SIZE; +} + +/* Create an onion data request packet in packet of max_packet_length (recommended size ONION_MAX_PACKET_SIZE). + * + * public_key is the real public key of the node which we want to send the data of length length to. + * encrypt_public_key is the public key used to encrypt the data packet. + * + * nonce is the nonce to encrypt this packet with + * + * return -1 on failure. + * return 0 on success. + */ +int create_data_request(uint8_t *packet, uint16_t max_packet_length, const uint8_t *public_key, + const uint8_t *encrypt_public_key, const uint8_t *nonce, const uint8_t *data, uint16_t length) +{ + if (DATA_REQUEST_MIN_SIZE + length > max_packet_length) { + return -1; + } + + if (DATA_REQUEST_MIN_SIZE + length > ONION_MAX_DATA_SIZE) { + return -1; + } + + packet[0] = NET_PACKET_ONION_DATA_REQUEST; + memcpy(packet + 1, public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, nonce, CRYPTO_NONCE_SIZE); + + uint8_t random_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t random_secret_key[CRYPTO_SECRET_KEY_SIZE]; + crypto_new_keypair(random_public_key, random_secret_key); + + memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, random_public_key, CRYPTO_PUBLIC_KEY_SIZE); + + int len = encrypt_data(encrypt_public_key, random_secret_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, data, length, + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE); + + if (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + len != DATA_REQUEST_MIN_SIZE + + length) { + return -1; + } + + return DATA_REQUEST_MIN_SIZE + length; +} + +/* Create and send an onion announce request packet. + * + * path is the path the request will take before it is sent to dest. + * + * public_key and secret_key is the kepair which will be used to encrypt the request. + * ping_id is the ping id that will be sent in the request. + * client_id is the client id of the node we are searching for. + * data_public_key is the public key we want others to encrypt their data packets with. + * sendback_data is the data of ONION_ANNOUNCE_SENDBACK_DATA_LENGTH length that we expect to + * receive back in the response. + * + * return -1 on failure. + * return 0 on success. + */ +int send_announce_request(Networking_Core *net, const Onion_Path *path, Node_format dest, const uint8_t *public_key, + const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id, const uint8_t *data_public_key, + uint64_t sendback_data) +{ + uint8_t request[ONION_ANNOUNCE_REQUEST_SIZE]; + int len = create_announce_request(request, sizeof(request), dest.public_key, public_key, secret_key, ping_id, client_id, + data_public_key, sendback_data); + + if (len != sizeof(request)) { + return -1; + } + + uint8_t packet[ONION_MAX_PACKET_SIZE]; + len = create_onion_packet(packet, sizeof(packet), path, dest.ip_port, request, sizeof(request)); + + if (len == -1) { + return -1; + } + + if (sendpacket(net, path->ip_port1, packet, len) != len) { + return -1; + } + + return 0; +} + +/* Create and send an onion data request packet. + * + * path is the path the request will take before it is sent to dest. + * (if dest knows the person with the public_key they should + * send the packet to that person in the form of a response) + * + * public_key is the real public key of the node which we want to send the data of length length to. + * encrypt_public_key is the public key used to encrypt the data packet. + * + * nonce is the nonce to encrypt this packet with + * + * return -1 on failure. + * return 0 on success. + */ +int send_data_request(Networking_Core *net, const Onion_Path *path, IP_Port dest, const uint8_t *public_key, + const uint8_t *encrypt_public_key, const uint8_t *nonce, const uint8_t *data, uint16_t length) +{ + uint8_t request[ONION_MAX_DATA_SIZE]; + int len = create_data_request(request, sizeof(request), public_key, encrypt_public_key, nonce, data, length); + + if (len == -1) { + return -1; + } + + uint8_t packet[ONION_MAX_PACKET_SIZE]; + len = create_onion_packet(packet, sizeof(packet), path, dest, request, len); + + if (len == -1) { + return -1; + } + + if (sendpacket(net, path->ip_port1, packet, len) != len) { + return -1; + } + + return 0; +} + +/* Generate a ping_id and put it in ping_id */ +static void generate_ping_id(const Onion_Announce *onion_a, uint64_t time, const uint8_t *public_key, + IP_Port ret_ip_port, uint8_t *ping_id) +{ + time /= PING_ID_TIMEOUT; + uint8_t data[CRYPTO_SYMMETRIC_KEY_SIZE + sizeof(time) + CRYPTO_PUBLIC_KEY_SIZE + sizeof(ret_ip_port)]; + memcpy(data, onion_a->secret_bytes, CRYPTO_SYMMETRIC_KEY_SIZE); + memcpy(data + CRYPTO_SYMMETRIC_KEY_SIZE, &time, sizeof(time)); + memcpy(data + CRYPTO_SYMMETRIC_KEY_SIZE + sizeof(time), public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(data + CRYPTO_SYMMETRIC_KEY_SIZE + sizeof(time) + CRYPTO_PUBLIC_KEY_SIZE, &ret_ip_port, sizeof(ret_ip_port)); + crypto_sha256(ping_id, data, sizeof(data)); +} + +/* check if public key is in entries list + * + * return -1 if no + * return position in list if yes + */ +static int in_entries(const Onion_Announce *onion_a, const uint8_t *public_key) +{ + unsigned int i; + + for (i = 0; i < ONION_ANNOUNCE_MAX_ENTRIES; ++i) { + if (!is_timeout(onion_a->entries[i].time, ONION_ANNOUNCE_TIMEOUT) + && public_key_cmp(onion_a->entries[i].public_key, public_key) == 0) { + return i; + } + } + + return -1; +} + +typedef struct { + const uint8_t *base_public_key; + Onion_Announce_Entry entry; +} Cmp_data; + +static int cmp_entry(const void *a, const void *b) +{ + Cmp_data cmp1, cmp2; + memcpy(&cmp1, a, sizeof(Cmp_data)); + memcpy(&cmp2, b, sizeof(Cmp_data)); + Onion_Announce_Entry entry1 = cmp1.entry; + Onion_Announce_Entry entry2 = cmp2.entry; + const uint8_t *cmp_public_key = cmp1.base_public_key; + + int t1 = is_timeout(entry1.time, ONION_ANNOUNCE_TIMEOUT); + int t2 = is_timeout(entry2.time, ONION_ANNOUNCE_TIMEOUT); + + if (t1 && t2) { + return 0; + } + + if (t1) { + return -1; + } + + if (t2) { + return 1; + } + + int close = id_closest(cmp_public_key, entry1.public_key, entry2.public_key); + + if (close == 1) { + return 1; + } + + if (close == 2) { + return -1; + } + + return 0; +} + +static void sort_onion_announce_list(Onion_Announce_Entry *list, unsigned int length, const uint8_t *comp_public_key) +{ + // Pass comp_public_key to qsort with each Client_data entry, so the + // comparison function can use it as the base of comparison. + VLA(Cmp_data, cmp_list, length); + + for (uint32_t i = 0; i < length; i++) { + cmp_list[i].base_public_key = comp_public_key; + cmp_list[i].entry = list[i]; + } + + qsort(cmp_list, length, sizeof(Cmp_data), cmp_entry); + + for (uint32_t i = 0; i < length; i++) { + list[i] = cmp_list[i].entry; + } +} + +/* add entry to entries list + * + * return -1 if failure + * return position if added + */ +static int add_to_entries(Onion_Announce *onion_a, IP_Port ret_ip_port, const uint8_t *public_key, + const uint8_t *data_public_key, const uint8_t *ret) +{ + + int pos = in_entries(onion_a, public_key); + + unsigned int i; + + if (pos == -1) { + for (i = 0; i < ONION_ANNOUNCE_MAX_ENTRIES; ++i) { + if (is_timeout(onion_a->entries[i].time, ONION_ANNOUNCE_TIMEOUT)) { + pos = i; + } + } + } + + if (pos == -1) { + if (id_closest(onion_a->dht->self_public_key, public_key, onion_a->entries[0].public_key) == 1) { + pos = 0; + } + } + + if (pos == -1) { + return -1; + } + + memcpy(onion_a->entries[pos].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + onion_a->entries[pos].ret_ip_port = ret_ip_port; + memcpy(onion_a->entries[pos].ret, ret, ONION_RETURN_3); + memcpy(onion_a->entries[pos].data_public_key, data_public_key, CRYPTO_PUBLIC_KEY_SIZE); + onion_a->entries[pos].time = unix_time(); + + sort_onion_announce_list(onion_a->entries, ONION_ANNOUNCE_MAX_ENTRIES, onion_a->dht->self_public_key); + return in_entries(onion_a, public_key); +} + +static int handle_announce_request(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + Onion_Announce *onion_a = (Onion_Announce *)object; + + if (length != ANNOUNCE_REQUEST_SIZE_RECV) { + return 1; + } + + const uint8_t *packet_public_key = packet + 1 + CRYPTO_NONCE_SIZE; + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + get_shared_key(&onion_a->shared_keys_recv, shared_key, onion_a->dht->self_secret_key, packet_public_key); + + uint8_t plain[ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_PUBLIC_KEY_SIZE + + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH]; + int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, + ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_PUBLIC_KEY_SIZE + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + + CRYPTO_MAC_SIZE, plain); + + if ((uint32_t)len != sizeof(plain)) { + return 1; + } + + uint8_t ping_id1[ONION_PING_ID_SIZE]; + generate_ping_id(onion_a, unix_time(), packet_public_key, source, ping_id1); + + uint8_t ping_id2[ONION_PING_ID_SIZE]; + generate_ping_id(onion_a, unix_time() + PING_ID_TIMEOUT, packet_public_key, source, ping_id2); + + int index = -1; + + uint8_t *data_public_key = plain + ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE; + + if (crypto_memcmp(ping_id1, plain, ONION_PING_ID_SIZE) == 0 + || crypto_memcmp(ping_id2, plain, ONION_PING_ID_SIZE) == 0) { + index = add_to_entries(onion_a, source, packet_public_key, data_public_key, + packet + (ANNOUNCE_REQUEST_SIZE_RECV - ONION_RETURN_3)); + } else { + index = in_entries(onion_a, plain + ONION_PING_ID_SIZE); + } + + /*Respond with a announce response packet*/ + Node_format nodes_list[MAX_SENT_NODES]; + unsigned int num_nodes = get_close_nodes(onion_a->dht, plain + ONION_PING_ID_SIZE, nodes_list, 0, + LAN_ip(source.ip) == 0, 1); + uint8_t nonce[CRYPTO_NONCE_SIZE]; + random_nonce(nonce); + + uint8_t pl[1 + ONION_PING_ID_SIZE + sizeof(nodes_list)]; + + if (index == -1) { + pl[0] = 0; + memcpy(pl + 1, ping_id2, ONION_PING_ID_SIZE); + } else { + if (public_key_cmp(onion_a->entries[index].public_key, packet_public_key) == 0) { + if (public_key_cmp(onion_a->entries[index].data_public_key, data_public_key) != 0) { + pl[0] = 0; + memcpy(pl + 1, ping_id2, ONION_PING_ID_SIZE); + } else { + pl[0] = 2; + memcpy(pl + 1, ping_id2, ONION_PING_ID_SIZE); + } + } else { + pl[0] = 1; + memcpy(pl + 1, onion_a->entries[index].data_public_key, CRYPTO_PUBLIC_KEY_SIZE); + } + } + + int nodes_length = 0; + + if (num_nodes != 0) { + nodes_length = pack_nodes(pl + 1 + ONION_PING_ID_SIZE, sizeof(nodes_list), nodes_list, num_nodes); + + if (nodes_length <= 0) { + return 1; + } + } + + uint8_t data[ONION_ANNOUNCE_RESPONSE_MAX_SIZE]; + len = encrypt_data_symmetric(shared_key, nonce, pl, 1 + ONION_PING_ID_SIZE + nodes_length, + data + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE); + + if (len != 1 + ONION_PING_ID_SIZE + nodes_length + CRYPTO_MAC_SIZE) { + return 1; + } + + data[0] = NET_PACKET_ANNOUNCE_RESPONSE; + memcpy(data + 1, plain + ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_PUBLIC_KEY_SIZE, + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH); + memcpy(data + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH, nonce, CRYPTO_NONCE_SIZE); + + if (send_onion_response(onion_a->net, source, data, + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE + len, + packet + (ANNOUNCE_REQUEST_SIZE_RECV - ONION_RETURN_3)) == -1) { + return 1; + } + + return 0; +} + +static int handle_data_request(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + Onion_Announce *onion_a = (Onion_Announce *)object; + + if (length <= DATA_REQUEST_MIN_SIZE_RECV) { + return 1; + } + + if (length > ONION_MAX_PACKET_SIZE) { + return 1; + } + + int index = in_entries(onion_a, packet + 1); + + if (index == -1) { + return 1; + } + + VLA(uint8_t, data, length - (CRYPTO_PUBLIC_KEY_SIZE + ONION_RETURN_3)); + data[0] = NET_PACKET_ONION_DATA_RESPONSE; + memcpy(data + 1, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, length - (1 + CRYPTO_PUBLIC_KEY_SIZE + ONION_RETURN_3)); + + if (send_onion_response(onion_a->net, onion_a->entries[index].ret_ip_port, data, SIZEOF_VLA(data), + onion_a->entries[index].ret) == -1) { + return 1; + } + + return 0; +} + +Onion_Announce *new_onion_announce(DHT *dht) +{ + if (dht == NULL) { + return NULL; + } + + Onion_Announce *onion_a = (Onion_Announce *)calloc(1, sizeof(Onion_Announce)); + + if (onion_a == NULL) { + return NULL; + } + + onion_a->dht = dht; + onion_a->net = dht->net; + new_symmetric_key(onion_a->secret_bytes); + + networking_registerhandler(onion_a->net, NET_PACKET_ANNOUNCE_REQUEST, &handle_announce_request, onion_a); + networking_registerhandler(onion_a->net, NET_PACKET_ONION_DATA_REQUEST, &handle_data_request, onion_a); + + return onion_a; +} + +void kill_onion_announce(Onion_Announce *onion_a) +{ + if (onion_a == NULL) { + return; + } + + networking_registerhandler(onion_a->net, NET_PACKET_ANNOUNCE_REQUEST, NULL, NULL); + networking_registerhandler(onion_a->net, NET_PACKET_ONION_DATA_REQUEST, NULL, NULL); + free(onion_a); +} diff --git a/protocols/Tox/libtox/src/toxcore/onion_announce.h b/protocols/Tox/libtox/src/toxcore/onion_announce.h new file mode 100644 index 0000000000..548d4b798b --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/onion_announce.h @@ -0,0 +1,140 @@ +/* + * Implementation of the announce part of docs/Prevent_Tracking.txt + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef ONION_ANNOUNCE_H +#define ONION_ANNOUNCE_H + +#include "onion.h" + +#define ONION_ANNOUNCE_MAX_ENTRIES 160 +#define ONION_ANNOUNCE_TIMEOUT 300 +#define ONION_PING_ID_SIZE CRYPTO_SHA256_SIZE + +#define ONION_ANNOUNCE_SENDBACK_DATA_LENGTH (sizeof(uint64_t)) + +#define ONION_ANNOUNCE_REQUEST_SIZE (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_PUBLIC_KEY_SIZE + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_MAC_SIZE) + +#define ONION_ANNOUNCE_RESPONSE_MIN_SIZE (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE + 1 + ONION_PING_ID_SIZE + CRYPTO_MAC_SIZE) +#define ONION_ANNOUNCE_RESPONSE_MAX_SIZE (ONION_ANNOUNCE_RESPONSE_MIN_SIZE + sizeof(Node_format)*MAX_SENT_NODES) + +#define ONION_DATA_RESPONSE_MIN_SIZE (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_MAC_SIZE) + +#if ONION_PING_ID_SIZE != CRYPTO_PUBLIC_KEY_SIZE +#error announce response packets assume that ONION_PING_ID_SIZE is equal to CRYPTO_PUBLIC_KEY_SIZE +#endif + +#define ONION_DATA_REQUEST_MIN_SIZE (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_MAC_SIZE) +#define MAX_DATA_REQUEST_SIZE (ONION_MAX_DATA_SIZE - ONION_DATA_REQUEST_MIN_SIZE) + +typedef struct { + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + IP_Port ret_ip_port; + uint8_t ret[ONION_RETURN_3]; + uint8_t data_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint64_t time; +} Onion_Announce_Entry; + +typedef struct { + DHT *dht; + Networking_Core *net; + Onion_Announce_Entry entries[ONION_ANNOUNCE_MAX_ENTRIES]; + /* This is CRYPTO_SYMMETRIC_KEY_SIZE long just so we can use new_symmetric_key() to fill it */ + uint8_t secret_bytes[CRYPTO_SYMMETRIC_KEY_SIZE]; + + Shared_Keys shared_keys_recv; +} Onion_Announce; + +/* Create an onion announce request packet in packet of max_packet_length (recommended size ONION_ANNOUNCE_REQUEST_SIZE). + * + * dest_client_id is the public key of the node the packet will be sent to. + * public_key and secret_key is the kepair which will be used to encrypt the request. + * ping_id is the ping id that will be sent in the request. + * client_id is the client id of the node we are searching for. + * data_public_key is the public key we want others to encrypt their data packets with. + * sendback_data is the data of ONION_ANNOUNCE_SENDBACK_DATA_LENGTH length that we expect to + * receive back in the response. + * + * return -1 on failure. + * return packet length on success. + */ +int create_announce_request(uint8_t *packet, uint16_t max_packet_length, const uint8_t *dest_client_id, + const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id, + const uint8_t *data_public_key, uint64_t sendback_data); + +/* Create an onion data request packet in packet of max_packet_length (recommended size ONION_MAX_PACKET_SIZE). + * + * public_key is the real public key of the node which we want to send the data of length length to. + * encrypt_public_key is the public key used to encrypt the data packet. + * + * nonce is the nonce to encrypt this packet with + * + * return -1 on failure. + * return 0 on success. + */ +int create_data_request(uint8_t *packet, uint16_t max_packet_length, const uint8_t *public_key, + const uint8_t *encrypt_public_key, const uint8_t *nonce, const uint8_t *data, uint16_t length); + +/* Create and send an onion announce request packet. + * + * path is the path the request will take before it is sent to dest. + * + * public_key and secret_key is the kepair which will be used to encrypt the request. + * ping_id is the ping id that will be sent in the request. + * client_id is the client id of the node we are searching for. + * data_public_key is the public key we want others to encrypt their data packets with. + * sendback_data is the data of ONION_ANNOUNCE_SENDBACK_DATA_LENGTH length that we expect to + * receive back in the response. + * + * return -1 on failure. + * return 0 on success. + */ +int send_announce_request(Networking_Core *net, const Onion_Path *path, Node_format dest, const uint8_t *public_key, + const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id, const uint8_t *data_public_key, + uint64_t sendback_data); + +/* Create and send an onion data request packet. + * + * path is the path the request will take before it is sent to dest. + * (if dest knows the person with the public_key they should + * send the packet to that person in the form of a response) + * + * public_key is the real public key of the node which we want to send the data of length length to. + * encrypt_public_key is the public key used to encrypt the data packet. + * + * nonce is the nonce to encrypt this packet with + * + * The maximum length of data is MAX_DATA_REQUEST_SIZE. + * + * return -1 on failure. + * return 0 on success. + */ +int send_data_request(Networking_Core *net, const Onion_Path *path, IP_Port dest, const uint8_t *public_key, + const uint8_t *encrypt_public_key, const uint8_t *nonce, const uint8_t *data, uint16_t length); + + +Onion_Announce *new_onion_announce(DHT *dht); + +void kill_onion_announce(Onion_Announce *onion_a); + + +#endif diff --git a/protocols/Tox/libtox/src/toxcore/onion_client.c b/protocols/Tox/libtox/src/toxcore/onion_client.c new file mode 100644 index 0000000000..94e9c91652 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/onion_client.c @@ -0,0 +1,1771 @@ +/* + * Implementation of the client part of docs/Prevent_Tracking.txt (The part that + * uses the onion stuff to connect to the friend) + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "onion_client.h" + +#include "LAN_discovery.h" +#include "util.h" + +/* defines for the array size and + timeout for onion announce packets. */ +#define ANNOUNCE_ARRAY_SIZE 256 +#define ANNOUNCE_TIMEOUT 10 + +/* Add a node to the path_nodes bootstrap array. + * + * return -1 on failure + * return 0 on success + */ +int onion_add_bs_path_node(Onion_Client *onion_c, IP_Port ip_port, const uint8_t *public_key) +{ + if (ip_port.ip.family != TOX_AF_INET && ip_port.ip.family != TOX_AF_INET6) { + return -1; + } + + unsigned int i; + + for (i = 0; i < MAX_PATH_NODES; ++i) { + if (public_key_cmp(public_key, onion_c->path_nodes_bs[i].public_key) == 0) { + return -1; + } + } + + onion_c->path_nodes_bs[onion_c->path_nodes_index_bs % MAX_PATH_NODES].ip_port = ip_port; + memcpy(onion_c->path_nodes_bs[onion_c->path_nodes_index_bs % MAX_PATH_NODES].public_key, public_key, + CRYPTO_PUBLIC_KEY_SIZE); + + uint16_t last = onion_c->path_nodes_index_bs; + ++onion_c->path_nodes_index_bs; + + if (onion_c->path_nodes_index_bs < last) { + onion_c->path_nodes_index_bs = MAX_PATH_NODES + 1; + } + + return 0; +} + +/* Add a node to the path_nodes array. + * + * return -1 on failure + * return 0 on success + */ +static int onion_add_path_node(Onion_Client *onion_c, IP_Port ip_port, const uint8_t *public_key) +{ + if (ip_port.ip.family != TOX_AF_INET && ip_port.ip.family != TOX_AF_INET6) { + return -1; + } + + unsigned int i; + + for (i = 0; i < MAX_PATH_NODES; ++i) { + if (public_key_cmp(public_key, onion_c->path_nodes[i].public_key) == 0) { + return -1; + } + } + + onion_c->path_nodes[onion_c->path_nodes_index % MAX_PATH_NODES].ip_port = ip_port; + memcpy(onion_c->path_nodes[onion_c->path_nodes_index % MAX_PATH_NODES].public_key, public_key, + CRYPTO_PUBLIC_KEY_SIZE); + + uint16_t last = onion_c->path_nodes_index; + ++onion_c->path_nodes_index; + + if (onion_c->path_nodes_index < last) { + onion_c->path_nodes_index = MAX_PATH_NODES + 1; + } + + return 0; +} + +/* Put up to max_num nodes in nodes. + * + * return the number of nodes. + */ +uint16_t onion_backup_nodes(const Onion_Client *onion_c, Node_format *nodes, uint16_t max_num) +{ + unsigned int i; + + if (!max_num) { + return 0; + } + + unsigned int num_nodes = (onion_c->path_nodes_index < MAX_PATH_NODES) ? onion_c->path_nodes_index : MAX_PATH_NODES; + + if (num_nodes == 0) { + return 0; + } + + if (num_nodes < max_num) { + max_num = num_nodes; + } + + for (i = 0; i < max_num; ++i) { + nodes[i] = onion_c->path_nodes[(onion_c->path_nodes_index - (1 + i)) % num_nodes]; + } + + return max_num; +} + +/* Put up to max_num random nodes in nodes. + * + * return the number of nodes. + */ +static uint16_t random_nodes_path_onion(const Onion_Client *onion_c, Node_format *nodes, uint16_t max_num) +{ + unsigned int i; + + if (!max_num) { + return 0; + } + + unsigned int num_nodes = (onion_c->path_nodes_index < MAX_PATH_NODES) ? onion_c->path_nodes_index : MAX_PATH_NODES; + + //if (DHT_non_lan_connected(onion_c->dht)) { + if (DHT_isconnected(onion_c->dht)) { + if (num_nodes == 0) { + return 0; + } + + for (i = 0; i < max_num; ++i) { + nodes[i] = onion_c->path_nodes[rand() % num_nodes]; + } + } else { + int random_tcp = get_random_tcp_con_number(onion_c->c); + + if (random_tcp == -1) { + return 0; + } + + if (num_nodes >= 2) { + nodes[0].ip_port.ip.family = TCP_FAMILY; + nodes[0].ip_port.ip.ip4.uint32 = random_tcp; + + for (i = 1; i < max_num; ++i) { + nodes[i] = onion_c->path_nodes[rand() % num_nodes]; + } + } else { + unsigned int num_nodes_bs = (onion_c->path_nodes_index_bs < MAX_PATH_NODES) ? onion_c->path_nodes_index_bs : + MAX_PATH_NODES; + + if (num_nodes_bs == 0) { + return 0; + } + + nodes[0].ip_port.ip.family = TCP_FAMILY; + nodes[0].ip_port.ip.ip4.uint32 = random_tcp; + + for (i = 1; i < max_num; ++i) { + nodes[i] = onion_c->path_nodes_bs[rand() % num_nodes_bs]; + } + } + } + + return max_num; +} + +/* + * return -1 if nodes are suitable for creating a new path. + * return path number of already existing similar path if one already exists. + */ +static int is_path_used(const Onion_Client_Paths *onion_paths, const Node_format *nodes) +{ + unsigned int i; + + for (i = 0; i < NUMBER_ONION_PATHS; ++i) { + if (is_timeout(onion_paths->last_path_success[i], ONION_PATH_TIMEOUT)) { + continue; + } + + if (is_timeout(onion_paths->path_creation_time[i], ONION_PATH_MAX_LIFETIME)) { + continue; + } + + // TODO(irungentoo): do we really have to check it with the last node? + if (ipport_equal(&onion_paths->paths[i].ip_port1, &nodes[ONION_PATH_LENGTH - 1].ip_port)) { + return i; + } + } + + return -1; +} + +/* is path timed out */ +static bool path_timed_out(Onion_Client_Paths *onion_paths, uint32_t pathnum) +{ + pathnum = pathnum % NUMBER_ONION_PATHS; + + bool is_new = onion_paths->last_path_success[pathnum] == onion_paths->path_creation_time[pathnum]; + uint64_t timeout = is_new ? ONION_PATH_FIRST_TIMEOUT : ONION_PATH_TIMEOUT; + + return ((onion_paths->last_path_used_times[pathnum] >= ONION_PATH_MAX_NO_RESPONSE_USES + && is_timeout(onion_paths->last_path_used[pathnum], timeout)) + || is_timeout(onion_paths->path_creation_time[pathnum], ONION_PATH_MAX_LIFETIME)); +} + +/* should node be considered to have timed out */ +static bool onion_node_timed_out(const Onion_Node *node) +{ + return (node->timestamp == 0 + || (node->unsuccessful_pings >= ONION_NODE_MAX_PINGS + && is_timeout(node->last_pinged, ONION_NODE_TIMEOUT))); +} + +/* Create a new path or use an old suitable one (if pathnum is valid) + * or a random one from onion_paths. + * + * return -1 on failure + * return 0 on success + * + * TODO(irungentoo): Make this function better, it currently probably is + * vulnerable to some attacks that could deanonimize us. + */ +static int random_path(const Onion_Client *onion_c, Onion_Client_Paths *onion_paths, uint32_t pathnum, Onion_Path *path) +{ + if (pathnum == UINT32_MAX) { + pathnum = rand() % NUMBER_ONION_PATHS; + } else { + pathnum = pathnum % NUMBER_ONION_PATHS; + } + + if (path_timed_out(onion_paths, pathnum)) { + Node_format nodes[ONION_PATH_LENGTH]; + + if (random_nodes_path_onion(onion_c, nodes, ONION_PATH_LENGTH) != ONION_PATH_LENGTH) { + return -1; + } + + int n = is_path_used(onion_paths, nodes); + + if (n == -1) { + if (create_onion_path(onion_c->dht, &onion_paths->paths[pathnum], nodes) == -1) { + return -1; + } + + onion_paths->path_creation_time[pathnum] = unix_time(); + onion_paths->last_path_success[pathnum] = onion_paths->path_creation_time[pathnum]; + onion_paths->last_path_used_times[pathnum] = ONION_PATH_MAX_NO_RESPONSE_USES / 2; + + uint32_t path_num = rand(); + path_num /= NUMBER_ONION_PATHS; + path_num *= NUMBER_ONION_PATHS; + path_num += pathnum; + + onion_paths->paths[pathnum].path_num = path_num; + } else { + pathnum = n; + } + } + + if (onion_paths->last_path_used_times[pathnum] < ONION_PATH_MAX_NO_RESPONSE_USES) { + onion_paths->last_path_used[pathnum] = unix_time(); + } + + ++onion_paths->last_path_used_times[pathnum]; + memcpy(path, &onion_paths->paths[pathnum], sizeof(Onion_Path)); + return 0; +} + +/* Does path with path_num exist. */ +static bool path_exists(Onion_Client_Paths *onion_paths, uint32_t path_num) +{ + if (path_timed_out(onion_paths, path_num)) { + return 0; + } + + return onion_paths->paths[path_num % NUMBER_ONION_PATHS].path_num == path_num; +} + +/* Set path timeouts, return the path number. + * + */ +static uint32_t set_path_timeouts(Onion_Client *onion_c, uint32_t num, uint32_t path_num) +{ + if (num > onion_c->num_friends) { + return -1; + } + + Onion_Client_Paths *onion_paths; + + if (num == 0) { + onion_paths = &onion_c->onion_paths_self; + } else { + onion_paths = &onion_c->onion_paths_friends; + } + + if (onion_paths->paths[path_num % NUMBER_ONION_PATHS].path_num == path_num) { + onion_paths->last_path_success[path_num % NUMBER_ONION_PATHS] = unix_time(); + onion_paths->last_path_used_times[path_num % NUMBER_ONION_PATHS] = 0; + + Node_format nodes[ONION_PATH_LENGTH]; + + if (onion_path_to_nodes(nodes, ONION_PATH_LENGTH, &onion_paths->paths[path_num % NUMBER_ONION_PATHS]) == 0) { + unsigned int i; + + for (i = 0; i < ONION_PATH_LENGTH; ++i) { + onion_add_path_node(onion_c, nodes[i].ip_port, nodes[i].public_key); + } + } + + return path_num; + } + + return ~0; +} + +/* Function to send onion packet via TCP and UDP. + * + * return -1 on failure. + * return 0 on success. + */ +static int send_onion_packet_tcp_udp(const Onion_Client *onion_c, const Onion_Path *path, IP_Port dest, + const uint8_t *data, uint16_t length) +{ + if (path->ip_port1.ip.family == TOX_AF_INET || path->ip_port1.ip.family == TOX_AF_INET6) { + uint8_t packet[ONION_MAX_PACKET_SIZE]; + int len = create_onion_packet(packet, sizeof(packet), path, dest, data, length); + + if (len == -1) { + return -1; + } + + if (sendpacket(onion_c->net, path->ip_port1, packet, len) != len) { + return -1; + } + + return 0; + } + + if (path->ip_port1.ip.family == TCP_FAMILY) { + uint8_t packet[ONION_MAX_PACKET_SIZE]; + int len = create_onion_packet_tcp(packet, sizeof(packet), path, dest, data, length); + + if (len == -1) { + return -1; + } + + return send_tcp_onion_request(onion_c->c, path->ip_port1.ip.ip4.uint32, packet, len); + } + + return -1; +} + +/* Creates a sendback for use in an announce request. + * + * num is 0 if we used our secret public key for the announce + * num is 1 + friendnum if we use a temporary one. + * + * Public key is the key we will be sending it to. + * ip_port is the ip_port of the node we will be sending + * it to. + * + * sendback must be at least ONION_ANNOUNCE_SENDBACK_DATA_LENGTH big + * + * return -1 on failure + * return 0 on success + * + */ +static int new_sendback(Onion_Client *onion_c, uint32_t num, const uint8_t *public_key, IP_Port ip_port, + uint32_t path_num, uint64_t *sendback) +{ + uint8_t data[sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE + sizeof(IP_Port) + sizeof(uint32_t)]; + memcpy(data, &num, sizeof(uint32_t)); + memcpy(data + sizeof(uint32_t), public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(data + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE, &ip_port, sizeof(IP_Port)); + memcpy(data + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE + sizeof(IP_Port), &path_num, sizeof(uint32_t)); + *sendback = ping_array_add(&onion_c->announce_ping_array, data, sizeof(data)); + + if (*sendback == 0) { + return -1; + } + + return 0; +} + +/* Checks if the sendback is valid and returns the public key contained in it in ret_pubkey and the + * ip contained in it in ret_ip_port + * + * sendback is the sendback ONION_ANNOUNCE_SENDBACK_DATA_LENGTH big + * ret_pubkey must be at least CRYPTO_PUBLIC_KEY_SIZE big + * ret_ip_port must be at least 1 big + * + * return ~0 on failure + * return num (see new_sendback(...)) on success + */ +static uint32_t check_sendback(Onion_Client *onion_c, const uint8_t *sendback, uint8_t *ret_pubkey, + IP_Port *ret_ip_port, uint32_t *path_num) +{ + uint64_t sback; + memcpy(&sback, sendback, sizeof(uint64_t)); + uint8_t data[sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE + sizeof(IP_Port) + sizeof(uint32_t)]; + + if (ping_array_check(data, sizeof(data), &onion_c->announce_ping_array, sback) != sizeof(data)) { + return ~0; + } + + memcpy(ret_pubkey, data + sizeof(uint32_t), CRYPTO_PUBLIC_KEY_SIZE); + memcpy(ret_ip_port, data + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE, sizeof(IP_Port)); + memcpy(path_num, data + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE + sizeof(IP_Port), sizeof(uint32_t)); + + uint32_t num; + memcpy(&num, data, sizeof(uint32_t)); + return num; +} + +static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, IP_Port dest, const uint8_t *dest_pubkey, + const uint8_t *ping_id, uint32_t pathnum) +{ + if (num > onion_c->num_friends) { + return -1; + } + + uint64_t sendback; + Onion_Path path; + + if (num == 0) { + if (random_path(onion_c, &onion_c->onion_paths_self, pathnum, &path) == -1) { + return -1; + } + } else { + if (random_path(onion_c, &onion_c->onion_paths_friends, pathnum, &path) == -1) { + return -1; + } + } + + if (new_sendback(onion_c, num, dest_pubkey, dest, path.path_num, &sendback) == -1) { + return -1; + } + + uint8_t zero_ping_id[ONION_PING_ID_SIZE] = {0}; + + if (ping_id == NULL) { + ping_id = zero_ping_id; + } + + uint8_t request[ONION_ANNOUNCE_REQUEST_SIZE]; + int len; + + if (num == 0) { + len = create_announce_request(request, sizeof(request), dest_pubkey, onion_c->c->self_public_key, + onion_c->c->self_secret_key, ping_id, onion_c->c->self_public_key, onion_c->temp_public_key, sendback); + } else { + len = create_announce_request(request, sizeof(request), dest_pubkey, onion_c->friends_list[num - 1].temp_public_key, + onion_c->friends_list[num - 1].temp_secret_key, ping_id, onion_c->friends_list[num - 1].real_public_key, zero_ping_id, + sendback); + } + + if (len == -1) { + return -1; + } + + return send_onion_packet_tcp_udp(onion_c, &path, dest, request, len); +} + +typedef struct { + const uint8_t *base_public_key; + Onion_Node entry; +} Onion_Client_Cmp_data; + +static int onion_client_cmp_entry(const void *a, const void *b) +{ + Onion_Client_Cmp_data cmp1, cmp2; + memcpy(&cmp1, a, sizeof(Onion_Client_Cmp_data)); + memcpy(&cmp2, b, sizeof(Onion_Client_Cmp_data)); + Onion_Node entry1 = cmp1.entry; + Onion_Node entry2 = cmp2.entry; + const uint8_t *cmp_public_key = cmp1.base_public_key; + + int t1 = onion_node_timed_out(&entry1); + int t2 = onion_node_timed_out(&entry2); + + if (t1 && t2) { + return 0; + } + + if (t1) { + return -1; + } + + if (t2) { + return 1; + } + + int close = id_closest(cmp_public_key, entry1.public_key, entry2.public_key); + + if (close == 1) { + return 1; + } + + if (close == 2) { + return -1; + } + + return 0; +} + +static void sort_onion_node_list(Onion_Node *list, unsigned int length, const uint8_t *comp_public_key) +{ + // Pass comp_public_key to qsort with each Client_data entry, so the + // comparison function can use it as the base of comparison. + VLA(Onion_Client_Cmp_data, cmp_list, length); + + for (uint32_t i = 0; i < length; i++) { + cmp_list[i].base_public_key = comp_public_key; + cmp_list[i].entry = list[i]; + } + + qsort(cmp_list, length, sizeof(Onion_Client_Cmp_data), onion_client_cmp_entry); + + for (uint32_t i = 0; i < length; i++) { + list[i] = cmp_list[i].entry; + } +} + +static int client_add_to_list(Onion_Client *onion_c, uint32_t num, const uint8_t *public_key, IP_Port ip_port, + uint8_t is_stored, const uint8_t *pingid_or_key, uint32_t path_used) +{ + if (num > onion_c->num_friends) { + return -1; + } + + Onion_Node *list_nodes = NULL; + uint8_t *reference_id = NULL; + unsigned int list_length; + + if (num == 0) { + list_nodes = onion_c->clients_announce_list; + reference_id = onion_c->c->self_public_key; + list_length = MAX_ONION_CLIENTS_ANNOUNCE; + + if (is_stored == 1 && public_key_cmp(pingid_or_key, onion_c->temp_public_key) != 0) { + is_stored = 0; + } + } else { + if (is_stored >= 2) { + return -1; + } + + if (is_stored == 1) { + onion_c->friends_list[num - 1].last_reported_announced = unix_time(); + } + + list_nodes = onion_c->friends_list[num - 1].clients_list; + reference_id = onion_c->friends_list[num - 1].real_public_key; + list_length = MAX_ONION_CLIENTS; + } + + sort_onion_node_list(list_nodes, list_length, reference_id); + + int index = -1, stored = 0; + unsigned int i; + + if (onion_node_timed_out(&list_nodes[0]) + || id_closest(reference_id, list_nodes[0].public_key, public_key) == 2) { + index = 0; + } + + for (i = 0; i < list_length; ++i) { + if (public_key_cmp(list_nodes[i].public_key, public_key) == 0) { + index = i; + stored = 1; + break; + } + } + + if (index == -1) { + return 0; + } + + memcpy(list_nodes[index].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + list_nodes[index].ip_port = ip_port; + + // TODO(irungentoo): remove this and find a better source of nodes to use for paths. + onion_add_path_node(onion_c, ip_port, public_key); + + if (is_stored == 1) { + memcpy(list_nodes[index].data_public_key, pingid_or_key, CRYPTO_PUBLIC_KEY_SIZE); + } else { + memcpy(list_nodes[index].ping_id, pingid_or_key, ONION_PING_ID_SIZE); + } + + list_nodes[index].is_stored = is_stored; + list_nodes[index].timestamp = unix_time(); + list_nodes[index].unsuccessful_pings = 0; + + if (!stored) { + list_nodes[index].last_pinged = 0; + list_nodes[index].added_time = unix_time(); + } + + list_nodes[index].path_used = path_used; + return 0; +} + +static int good_to_ping(Last_Pinged *last_pinged, uint8_t *last_pinged_index, const uint8_t *public_key) +{ + unsigned int i; + + for (i = 0; i < MAX_STORED_PINGED_NODES; ++i) { + if (!is_timeout(last_pinged[i].timestamp, MIN_NODE_PING_TIME)) { + if (public_key_cmp(last_pinged[i].public_key, public_key) == 0) { + return 0; + } + } + } + + memcpy(last_pinged[*last_pinged_index % MAX_STORED_PINGED_NODES].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + last_pinged[*last_pinged_index % MAX_STORED_PINGED_NODES].timestamp = unix_time(); + ++*last_pinged_index; + return 1; +} + +static int client_ping_nodes(Onion_Client *onion_c, uint32_t num, const Node_format *nodes, uint16_t num_nodes, + IP_Port source) +{ + if (num > onion_c->num_friends) { + return -1; + } + + if (num_nodes == 0) { + return 0; + } + + Onion_Node *list_nodes = NULL; + uint8_t *reference_id = NULL; + unsigned int list_length; + + Last_Pinged *last_pinged = NULL; + uint8_t *last_pinged_index = NULL; + + if (num == 0) { + list_nodes = onion_c->clients_announce_list; + reference_id = onion_c->c->self_public_key; + list_length = MAX_ONION_CLIENTS_ANNOUNCE; + last_pinged = onion_c->last_pinged; + last_pinged_index = &onion_c->last_pinged_index; + } else { + list_nodes = onion_c->friends_list[num - 1].clients_list; + reference_id = onion_c->friends_list[num - 1].real_public_key; + list_length = MAX_ONION_CLIENTS; + last_pinged = onion_c->friends_list[num - 1].last_pinged; + last_pinged_index = &onion_c->friends_list[num - 1].last_pinged_index; + } + + unsigned int i, j; + int lan_ips_accepted = (LAN_ip(source.ip) == 0); + + for (i = 0; i < num_nodes; ++i) { + + if (!lan_ips_accepted) { + if (LAN_ip(nodes[i].ip_port.ip) == 0) { + continue; + } + } + + if (onion_node_timed_out(&list_nodes[0]) + || id_closest(reference_id, list_nodes[0].public_key, nodes[i].public_key) == 2 + || onion_node_timed_out(&list_nodes[1]) + || id_closest(reference_id, list_nodes[1].public_key, nodes[i].public_key) == 2) { + /* check if node is already in list. */ + for (j = 0; j < list_length; ++j) { + if (public_key_cmp(list_nodes[j].public_key, nodes[i].public_key) == 0) { + break; + } + } + + if (j == list_length && good_to_ping(last_pinged, last_pinged_index, nodes[i].public_key)) { + client_send_announce_request(onion_c, num, nodes[i].ip_port, nodes[i].public_key, NULL, ~0); + } + } + } + + return 0; +} + +static int handle_announce_response(void *object, IP_Port source, const uint8_t *packet, uint16_t length, + void *userdata) +{ + Onion_Client *onion_c = (Onion_Client *)object; + + if (length < ONION_ANNOUNCE_RESPONSE_MIN_SIZE || length > ONION_ANNOUNCE_RESPONSE_MAX_SIZE) { + return 1; + } + + uint16_t len_nodes = length - ONION_ANNOUNCE_RESPONSE_MIN_SIZE; + + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + IP_Port ip_port; + uint32_t path_num; + uint32_t num = check_sendback(onion_c, packet + 1, public_key, &ip_port, &path_num); + + if (num > onion_c->num_friends) { + return 1; + } + + VLA(uint8_t, plain, 1 + ONION_PING_ID_SIZE + len_nodes); + int len = -1; + + if (num == 0) { + len = decrypt_data(public_key, onion_c->c->self_secret_key, packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH, + packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE, + length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE), plain); + } else { + if (onion_c->friends_list[num - 1].status == 0) { + return 1; + } + + len = decrypt_data(public_key, onion_c->friends_list[num - 1].temp_secret_key, + packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH, + packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE, + length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE), plain); + } + + if ((uint32_t)len != SIZEOF_VLA(plain)) { + return 1; + } + + uint32_t path_used = set_path_timeouts(onion_c, num, path_num); + + if (client_add_to_list(onion_c, num, public_key, ip_port, plain[0], plain + 1, path_used) == -1) { + return 1; + } + + if (len_nodes != 0) { + Node_format nodes[MAX_SENT_NODES]; + int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, 0, plain + 1 + ONION_PING_ID_SIZE, len_nodes, 0); + + if (num_nodes <= 0) { + return 1; + } + + if (client_ping_nodes(onion_c, num, nodes, num_nodes, source) == -1) { + return 1; + } + } + + // TODO(irungentoo): LAN vs non LAN ips?, if we are connected only to LAN, are we offline? + onion_c->last_packet_recv = unix_time(); + return 0; +} + +#define DATA_IN_RESPONSE_MIN_SIZE ONION_DATA_IN_RESPONSE_MIN_SIZE + +static int handle_data_response(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + Onion_Client *onion_c = (Onion_Client *)object; + + if (length <= (ONION_DATA_RESPONSE_MIN_SIZE + DATA_IN_RESPONSE_MIN_SIZE)) { + return 1; + } + + if (length > MAX_DATA_REQUEST_SIZE) { + return 1; + } + + VLA(uint8_t, temp_plain, length - ONION_DATA_RESPONSE_MIN_SIZE); + int len = decrypt_data(packet + 1 + CRYPTO_NONCE_SIZE, onion_c->temp_secret_key, packet + 1, + packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, + length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE), temp_plain); + + if ((uint32_t)len != SIZEOF_VLA(temp_plain)) { + return 1; + } + + VLA(uint8_t, plain, SIZEOF_VLA(temp_plain) - DATA_IN_RESPONSE_MIN_SIZE); + len = decrypt_data(temp_plain, onion_c->c->self_secret_key, packet + 1, temp_plain + CRYPTO_PUBLIC_KEY_SIZE, + SIZEOF_VLA(temp_plain) - CRYPTO_PUBLIC_KEY_SIZE, plain); + + if ((uint32_t)len != SIZEOF_VLA(plain)) { + return 1; + } + + if (!onion_c->Onion_Data_Handlers[plain[0]].function) { + return 1; + } + + return onion_c->Onion_Data_Handlers[plain[0]].function(onion_c->Onion_Data_Handlers[plain[0]].object, temp_plain, plain, + SIZEOF_VLA(plain), userdata); +} + +#define DHTPK_DATA_MIN_LENGTH (1 + sizeof(uint64_t) + CRYPTO_PUBLIC_KEY_SIZE) +#define DHTPK_DATA_MAX_LENGTH (DHTPK_DATA_MIN_LENGTH + sizeof(Node_format)*MAX_SENT_NODES) +static int handle_dhtpk_announce(void *object, const uint8_t *source_pubkey, const uint8_t *data, uint16_t length, + void *userdata) +{ + Onion_Client *onion_c = (Onion_Client *)object; + + if (length < DHTPK_DATA_MIN_LENGTH) { + return 1; + } + + if (length > DHTPK_DATA_MAX_LENGTH) { + return 1; + } + + int friend_num = onion_friend_num(onion_c, source_pubkey); + + if (friend_num == -1) { + return 1; + } + + uint64_t no_replay; + memcpy(&no_replay, data + 1, sizeof(uint64_t)); + net_to_host((uint8_t *) &no_replay, sizeof(no_replay)); + + if (no_replay <= onion_c->friends_list[friend_num].last_noreplay) { + return 1; + } + + onion_c->friends_list[friend_num].last_noreplay = no_replay; + + if (onion_c->friends_list[friend_num].dht_pk_callback) { + onion_c->friends_list[friend_num].dht_pk_callback(onion_c->friends_list[friend_num].dht_pk_callback_object, + onion_c->friends_list[friend_num].dht_pk_callback_number, data + 1 + sizeof(uint64_t), userdata); + } + + onion_set_friend_DHT_pubkey(onion_c, friend_num, data + 1 + sizeof(uint64_t)); + onion_c->friends_list[friend_num].last_seen = unix_time(); + + uint16_t len_nodes = length - DHTPK_DATA_MIN_LENGTH; + + if (len_nodes != 0) { + Node_format nodes[MAX_SENT_NODES]; + int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, 0, data + 1 + sizeof(uint64_t) + CRYPTO_PUBLIC_KEY_SIZE, + len_nodes, 1); + + if (num_nodes <= 0) { + return 1; + } + + int i; + + for (i = 0; i < num_nodes; ++i) { + uint8_t family = nodes[i].ip_port.ip.family; + + if (family == TOX_AF_INET || family == TOX_AF_INET6) { + DHT_getnodes(onion_c->dht, &nodes[i].ip_port, nodes[i].public_key, onion_c->friends_list[friend_num].dht_public_key); + } else if (family == TCP_INET || family == TCP_INET6) { + if (onion_c->friends_list[friend_num].tcp_relay_node_callback) { + void *obj = onion_c->friends_list[friend_num].tcp_relay_node_callback_object; + uint32_t number = onion_c->friends_list[friend_num].tcp_relay_node_callback_number; + onion_c->friends_list[friend_num].tcp_relay_node_callback(obj, number, nodes[i].ip_port, nodes[i].public_key); + } + } + } + } + + return 0; +} + +static int handle_tcp_onion(void *object, const uint8_t *data, uint16_t length, void *userdata) +{ + if (length == 0) { + return 1; + } + + IP_Port ip_port = {{0}}; + ip_port.ip.family = TCP_FAMILY; + + if (data[0] == NET_PACKET_ANNOUNCE_RESPONSE) { + return handle_announce_response(object, ip_port, data, length, userdata); + } + + if (data[0] == NET_PACKET_ONION_DATA_RESPONSE) { + return handle_data_response(object, ip_port, data, length, userdata); + } + + return 1; +} + +/* Send data of length length to friendnum. + * This data will be received by the friend using the Onion_Data_Handlers callbacks. + * + * Even if this function succeeds, the friend might not receive any data. + * + * return the number of packets sent on success + * return -1 on failure. + */ +int send_onion_data(Onion_Client *onion_c, int friend_num, const uint8_t *data, uint16_t length) +{ + if ((uint32_t)friend_num >= onion_c->num_friends) { + return -1; + } + + if (length + DATA_IN_RESPONSE_MIN_SIZE > MAX_DATA_REQUEST_SIZE) { + return -1; + } + + if (length == 0) { + return -1; + } + + unsigned int i, good_nodes[MAX_ONION_CLIENTS], num_good = 0, num_nodes = 0; + Onion_Node *list_nodes = onion_c->friends_list[friend_num].clients_list; + + for (i = 0; i < MAX_ONION_CLIENTS; ++i) { + if (onion_node_timed_out(&list_nodes[i])) { + continue; + } + + ++num_nodes; + + if (list_nodes[i].is_stored) { + good_nodes[num_good] = i; + ++num_good; + } + } + + if (num_good < (num_nodes - 1) / 4 + 1) { + return -1; + } + + uint8_t nonce[CRYPTO_NONCE_SIZE]; + random_nonce(nonce); + + VLA(uint8_t, packet, DATA_IN_RESPONSE_MIN_SIZE + length); + memcpy(packet, onion_c->c->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + int len = encrypt_data(onion_c->friends_list[friend_num].real_public_key, onion_c->c->self_secret_key, nonce, data, + length, packet + CRYPTO_PUBLIC_KEY_SIZE); + + if ((uint32_t)len + CRYPTO_PUBLIC_KEY_SIZE != SIZEOF_VLA(packet)) { + return -1; + } + + unsigned int good = 0; + + for (i = 0; i < num_good; ++i) { + Onion_Path path; + + if (random_path(onion_c, &onion_c->onion_paths_friends, ~0, &path) == -1) { + continue; + } + + uint8_t o_packet[ONION_MAX_PACKET_SIZE]; + len = create_data_request(o_packet, sizeof(o_packet), onion_c->friends_list[friend_num].real_public_key, + list_nodes[good_nodes[i]].data_public_key, nonce, packet, SIZEOF_VLA(packet)); + + if (len == -1) { + continue; + } + + if (send_onion_packet_tcp_udp(onion_c, &path, list_nodes[good_nodes[i]].ip_port, o_packet, len) == 0) { + ++good; + } + } + + return good; +} + +/* Try to send the dht public key via the DHT instead of onion + * + * Even if this function succeeds, the friend might not receive any data. + * + * return the number of packets sent on success + * return -1 on failure. + */ +static int send_dht_dhtpk(const Onion_Client *onion_c, int friend_num, const uint8_t *data, uint16_t length) +{ + if ((uint32_t)friend_num >= onion_c->num_friends) { + return -1; + } + + if (!onion_c->friends_list[friend_num].know_dht_public_key) { + return -1; + } + + uint8_t nonce[CRYPTO_NONCE_SIZE]; + random_nonce(nonce); + + VLA(uint8_t, temp, DATA_IN_RESPONSE_MIN_SIZE + CRYPTO_NONCE_SIZE + length); + memcpy(temp, onion_c->c->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(temp + CRYPTO_PUBLIC_KEY_SIZE, nonce, CRYPTO_NONCE_SIZE); + int len = encrypt_data(onion_c->friends_list[friend_num].real_public_key, onion_c->c->self_secret_key, nonce, data, + length, temp + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); + + if ((uint32_t)len + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE != SIZEOF_VLA(temp)) { + return -1; + } + + uint8_t packet[MAX_CRYPTO_REQUEST_SIZE]; + len = create_request(onion_c->dht->self_public_key, onion_c->dht->self_secret_key, packet, + onion_c->friends_list[friend_num].dht_public_key, temp, SIZEOF_VLA(temp), CRYPTO_PACKET_DHTPK); + + if (len == -1) { + return -1; + } + + return route_tofriend(onion_c->dht, onion_c->friends_list[friend_num].dht_public_key, packet, len); +} + +static int handle_dht_dhtpk(void *object, IP_Port source, const uint8_t *source_pubkey, const uint8_t *packet, + uint16_t length, void *userdata) +{ + Onion_Client *onion_c = (Onion_Client *)object; + + if (length < DHTPK_DATA_MIN_LENGTH + DATA_IN_RESPONSE_MIN_SIZE + CRYPTO_NONCE_SIZE) { + return 1; + } + + if (length > DHTPK_DATA_MAX_LENGTH + DATA_IN_RESPONSE_MIN_SIZE + CRYPTO_NONCE_SIZE) { + return 1; + } + + uint8_t plain[DHTPK_DATA_MAX_LENGTH]; + int len = decrypt_data(packet, onion_c->c->self_secret_key, packet + CRYPTO_PUBLIC_KEY_SIZE, + packet + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, + length - (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE), plain); + + if (len != length - (DATA_IN_RESPONSE_MIN_SIZE + CRYPTO_NONCE_SIZE)) { + return 1; + } + + if (public_key_cmp(source_pubkey, plain + 1 + sizeof(uint64_t)) != 0) { + return 1; + } + + return handle_dhtpk_announce(onion_c, packet, plain, len, userdata); +} +/* Send the packets to tell our friends what our DHT public key is. + * + * if onion_dht_both is 0, use only the onion to send the packet. + * if it is 1, use only the dht. + * if it is something else, use both. + * + * return the number of packets sent on success + * return -1 on failure. + */ +static int send_dhtpk_announce(Onion_Client *onion_c, uint16_t friend_num, uint8_t onion_dht_both) +{ + if (friend_num >= onion_c->num_friends) { + return -1; + } + + uint8_t data[DHTPK_DATA_MAX_LENGTH]; + data[0] = ONION_DATA_DHTPK; + uint64_t no_replay = unix_time(); + host_to_net((uint8_t *)&no_replay, sizeof(no_replay)); + memcpy(data + 1, &no_replay, sizeof(no_replay)); + memcpy(data + 1 + sizeof(uint64_t), onion_c->dht->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + Node_format nodes[MAX_SENT_NODES]; + uint16_t num_relays = copy_connected_tcp_relays(onion_c->c, nodes, (MAX_SENT_NODES / 2)); + uint16_t num_nodes = closelist_nodes(onion_c->dht, &nodes[num_relays], MAX_SENT_NODES - num_relays); + num_nodes += num_relays; + int nodes_len = 0; + + if (num_nodes != 0) { + nodes_len = pack_nodes(data + DHTPK_DATA_MIN_LENGTH, DHTPK_DATA_MAX_LENGTH - DHTPK_DATA_MIN_LENGTH, nodes, + num_nodes); + + if (nodes_len <= 0) { + return -1; + } + } + + int num1 = -1, num2 = -1; + + if (onion_dht_both != 1) { + num1 = send_onion_data(onion_c, friend_num, data, DHTPK_DATA_MIN_LENGTH + nodes_len); + } + + if (onion_dht_both != 0) { + num2 = send_dht_dhtpk(onion_c, friend_num, data, DHTPK_DATA_MIN_LENGTH + nodes_len); + } + + if (num1 == -1) { + return num2; + } + + if (num2 == -1) { + return num1; + } + + return num1 + num2; +} + +/* Get the friend_num of a friend. + * + * return -1 on failure. + * return friend number on success. + */ +int onion_friend_num(const Onion_Client *onion_c, const uint8_t *public_key) +{ + unsigned int i; + + for (i = 0; i < onion_c->num_friends; ++i) { + if (onion_c->friends_list[i].status == 0) { + continue; + } + + if (public_key_cmp(public_key, onion_c->friends_list[i].real_public_key) == 0) { + return i; + } + } + + return -1; +} + +/* Set the size of the friend list to num. + * + * return -1 if realloc fails. + * return 0 if it succeeds. + */ +static int realloc_onion_friends(Onion_Client *onion_c, uint32_t num) +{ + if (num == 0) { + free(onion_c->friends_list); + onion_c->friends_list = NULL; + return 0; + } + + Onion_Friend *newonion_friends = (Onion_Friend *)realloc(onion_c->friends_list, num * sizeof(Onion_Friend)); + + if (newonion_friends == NULL) { + return -1; + } + + onion_c->friends_list = newonion_friends; + return 0; +} + +/* Add a friend who we want to connect to. + * + * return -1 on failure. + * return the friend number on success or if the friend was already added. + */ +int onion_addfriend(Onion_Client *onion_c, const uint8_t *public_key) +{ + int num = onion_friend_num(onion_c, public_key); + + if (num != -1) { + return num; + } + + unsigned int i, index = ~0; + + for (i = 0; i < onion_c->num_friends; ++i) { + if (onion_c->friends_list[i].status == 0) { + index = i; + break; + } + } + + if (index == (uint32_t)~0) { + if (realloc_onion_friends(onion_c, onion_c->num_friends + 1) == -1) { + return -1; + } + + index = onion_c->num_friends; + memset(&(onion_c->friends_list[onion_c->num_friends]), 0, sizeof(Onion_Friend)); + ++onion_c->num_friends; + } + + onion_c->friends_list[index].status = 1; + memcpy(onion_c->friends_list[index].real_public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + crypto_new_keypair(onion_c->friends_list[index].temp_public_key, onion_c->friends_list[index].temp_secret_key); + return index; +} + +/* Delete a friend. + * + * return -1 on failure. + * return the deleted friend number on success. + */ +int onion_delfriend(Onion_Client *onion_c, int friend_num) +{ + if ((uint32_t)friend_num >= onion_c->num_friends) { + return -1; + } + + //if (onion_c->friends_list[friend_num].know_dht_public_key) + // DHT_delfriend(onion_c->dht, onion_c->friends_list[friend_num].dht_public_key, 0); + + crypto_memzero(&(onion_c->friends_list[friend_num]), sizeof(Onion_Friend)); + unsigned int i; + + for (i = onion_c->num_friends; i != 0; --i) { + if (onion_c->friends_list[i - 1].status != 0) { + break; + } + } + + if (onion_c->num_friends != i) { + onion_c->num_friends = i; + realloc_onion_friends(onion_c, onion_c->num_friends); + } + + return friend_num; +} + +/* Set the function for this friend that will be callbacked with object and number + * when that friends gives us one of the TCP relays he is connected to. + * + * object and number will be passed as argument to this function. + * + * return -1 on failure. + * return 0 on success. + */ +int recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, int (*tcp_relay_node_callback)(void *object, + uint32_t number, IP_Port ip_port, const uint8_t *public_key), void *object, uint32_t number) +{ + if ((uint32_t)friend_num >= onion_c->num_friends) { + return -1; + } + + onion_c->friends_list[friend_num].tcp_relay_node_callback = tcp_relay_node_callback; + onion_c->friends_list[friend_num].tcp_relay_node_callback_object = object; + onion_c->friends_list[friend_num].tcp_relay_node_callback_number = number; + return 0; +} + +/* Set the function for this friend that will be callbacked with object and number + * when that friend gives us his DHT temporary public key. + * + * object and number will be passed as argument to this function. + * + * return -1 on failure. + * return 0 on success. + */ +int onion_dht_pk_callback(Onion_Client *onion_c, int friend_num, void (*function)(void *data, int32_t number, + const uint8_t *dht_public_key, void *userdata), void *object, uint32_t number) +{ + if ((uint32_t)friend_num >= onion_c->num_friends) { + return -1; + } + + onion_c->friends_list[friend_num].dht_pk_callback = function; + onion_c->friends_list[friend_num].dht_pk_callback_object = object; + onion_c->friends_list[friend_num].dht_pk_callback_number = number; + return 0; +} + +/* Set a friends DHT public key. + * + * return -1 on failure. + * return 0 on success. + */ +int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, const uint8_t *dht_key) +{ + if ((uint32_t)friend_num >= onion_c->num_friends) { + return -1; + } + + if (onion_c->friends_list[friend_num].status == 0) { + return -1; + } + + if (onion_c->friends_list[friend_num].know_dht_public_key) { + if (public_key_cmp(dht_key, onion_c->friends_list[friend_num].dht_public_key) == 0) { + return -1; + } + + onion_c->friends_list[friend_num].know_dht_public_key = 0; + } + + onion_c->friends_list[friend_num].last_seen = unix_time(); + onion_c->friends_list[friend_num].know_dht_public_key = 1; + memcpy(onion_c->friends_list[friend_num].dht_public_key, dht_key, CRYPTO_PUBLIC_KEY_SIZE); + + return 0; +} + +/* Copy friends DHT public key into dht_key. + * + * return 0 on failure (no key copied). + * return 1 on success (key copied). + */ +unsigned int onion_getfriend_DHT_pubkey(const Onion_Client *onion_c, int friend_num, uint8_t *dht_key) +{ + if ((uint32_t)friend_num >= onion_c->num_friends) { + return 0; + } + + if (onion_c->friends_list[friend_num].status == 0) { + return 0; + } + + if (!onion_c->friends_list[friend_num].know_dht_public_key) { + return 0; + } + + memcpy(dht_key, onion_c->friends_list[friend_num].dht_public_key, CRYPTO_PUBLIC_KEY_SIZE); + return 1; +} + +/* Get the ip of friend friendnum and put it in ip_port + * + * return -1, -- if public_key does NOT refer to a friend + * return 0, -- if public_key refers to a friend and we failed to find the friend (yet) + * return 1, ip if public_key refers to a friend and we found him + * + */ +int onion_getfriendip(const Onion_Client *onion_c, int friend_num, IP_Port *ip_port) +{ + uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + + if (onion_getfriend_DHT_pubkey(onion_c, friend_num, dht_public_key) == 0) { + return -1; + } + + return DHT_getfriendip(onion_c->dht, dht_public_key, ip_port); +} + + +/* Set if friend is online or not. + * NOTE: This function is there and should be used so that we don't send useless packets to the friend if he is online. + * + * is_online 1 means friend is online. + * is_online 0 means friend is offline + * + * return -1 on failure. + * return 0 on success. + */ +int onion_set_friend_online(Onion_Client *onion_c, int friend_num, uint8_t is_online) +{ + if ((uint32_t)friend_num >= onion_c->num_friends) { + return -1; + } + + if (is_online == 0 && onion_c->friends_list[friend_num].is_online == 1) { + onion_c->friends_list[friend_num].last_seen = unix_time(); + } + + onion_c->friends_list[friend_num].is_online = is_online; + + /* This should prevent some clock related issues */ + if (!is_online) { + onion_c->friends_list[friend_num].last_noreplay = 0; + onion_c->friends_list[friend_num].run_count = 0; + } + + return 0; +} + +static void populate_path_nodes(Onion_Client *onion_c) +{ + Node_format nodes_list[MAX_FRIEND_CLIENTS]; + + unsigned int num_nodes = randfriends_nodes(onion_c->dht, nodes_list, MAX_FRIEND_CLIENTS); + + unsigned int i; + + for (i = 0; i < num_nodes; ++i) { + onion_add_path_node(onion_c, nodes_list[i].ip_port, nodes_list[i].public_key); + } +} + +static void populate_path_nodes_tcp(Onion_Client *onion_c) +{ + Node_format nodes_list[MAX_SENT_NODES]; + + unsigned int num_nodes = copy_connected_tcp_relays(onion_c->c, nodes_list, MAX_SENT_NODES);; + unsigned int i; + + for (i = 0; i < num_nodes; ++i) { + onion_add_bs_path_node(onion_c, nodes_list[i].ip_port, nodes_list[i].public_key); + } +} + +#define ANNOUNCE_FRIEND (ONION_NODE_PING_INTERVAL * 6) +#define ANNOUNCE_FRIEND_BEGINNING 3 + +#define RUN_COUNT_FRIEND_ANNOUNCE_BEGINNING 17 + +#define ONION_FRIEND_BACKOFF_FACTOR 4 +#define ONION_FRIEND_MAX_PING_INTERVAL (5*60*MAX_ONION_CLIENTS) + +static void do_friend(Onion_Client *onion_c, uint16_t friendnum) +{ + if (friendnum >= onion_c->num_friends) { + return; + } + + if (onion_c->friends_list[friendnum].status == 0) { + return; + } + + unsigned int interval = ANNOUNCE_FRIEND; + + if (onion_c->friends_list[friendnum].run_count < RUN_COUNT_FRIEND_ANNOUNCE_BEGINNING) { + interval = ANNOUNCE_FRIEND_BEGINNING; + } else { + if (onion_c->friends_list[friendnum].last_reported_announced == 0) { + onion_c->friends_list[friendnum].last_reported_announced = unix_time(); + } + + uint64_t backoff_interval = (unix_time() - onion_c->friends_list[friendnum].last_reported_announced) + / ONION_FRIEND_BACKOFF_FACTOR; + + if (backoff_interval > ONION_FRIEND_MAX_PING_INTERVAL) { + backoff_interval = ONION_FRIEND_MAX_PING_INTERVAL; + } + + if (interval < backoff_interval) { + interval = backoff_interval; + } + } + + unsigned int i, count = 0; + Onion_Node *list_nodes = onion_c->friends_list[friendnum].clients_list; + + if (!onion_c->friends_list[friendnum].is_online) { + // ensure we get a response from some node roughly once per + // (interval / MAX_ONION_CLIENTS) + bool ping_random = true; + + for (i = 0; i < MAX_ONION_CLIENTS; ++i) { + if (!(is_timeout(list_nodes[i].timestamp, interval / MAX_ONION_CLIENTS) + && is_timeout(list_nodes[i].last_pinged, ONION_NODE_PING_INTERVAL))) { + ping_random = false; + break; + } + } + + for (i = 0; i < MAX_ONION_CLIENTS; ++i) { + if (onion_node_timed_out(&list_nodes[i])) { + continue; + } + + ++count; + + + if (list_nodes[i].last_pinged == 0) { + list_nodes[i].last_pinged = unix_time(); + continue; + } + + if (list_nodes[i].unsuccessful_pings >= ONION_NODE_MAX_PINGS) { + continue; + } + + if (is_timeout(list_nodes[i].last_pinged, interval) + || (ping_random && rand() % (MAX_ONION_CLIENTS - i) == 0)) { + if (client_send_announce_request(onion_c, friendnum + 1, list_nodes[i].ip_port, list_nodes[i].public_key, 0, ~0) == 0) { + list_nodes[i].last_pinged = unix_time(); + ++list_nodes[i].unsuccessful_pings; + ping_random = false; + } + } + } + + if (count != MAX_ONION_CLIENTS) { + unsigned int num_nodes = (onion_c->path_nodes_index < MAX_PATH_NODES) ? onion_c->path_nodes_index : MAX_PATH_NODES; + + unsigned int n = num_nodes; + + if (num_nodes > (MAX_ONION_CLIENTS / 2)) { + n = (MAX_ONION_CLIENTS / 2); + } + + if (count <= (uint32_t)rand() % MAX_ONION_CLIENTS) { + if (num_nodes != 0) { + unsigned int j; + + for (j = 0; j < n; ++j) { + unsigned int num = rand() % num_nodes; + client_send_announce_request(onion_c, friendnum + 1, onion_c->path_nodes[num].ip_port, + onion_c->path_nodes[num].public_key, 0, ~0); + } + + ++onion_c->friends_list[friendnum].run_count; + } + } + } else { + ++onion_c->friends_list[friendnum].run_count; + } + + /* send packets to friend telling them our DHT public key. */ + if (is_timeout(onion_c->friends_list[friendnum].last_dht_pk_onion_sent, ONION_DHTPK_SEND_INTERVAL)) { + if (send_dhtpk_announce(onion_c, friendnum, 0) >= 1) { + onion_c->friends_list[friendnum].last_dht_pk_onion_sent = unix_time(); + } + } + + if (is_timeout(onion_c->friends_list[friendnum].last_dht_pk_dht_sent, DHT_DHTPK_SEND_INTERVAL)) { + if (send_dhtpk_announce(onion_c, friendnum, 1) >= 1) { + onion_c->friends_list[friendnum].last_dht_pk_dht_sent = unix_time(); + } + } + } +} + + +/* Function to call when onion data packet with contents beginning with byte is received. */ +void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object) +{ + onion_c->Onion_Data_Handlers[byte].function = cb; + onion_c->Onion_Data_Handlers[byte].object = object; +} + +#define ANNOUNCE_INTERVAL_NOT_ANNOUNCED 3 +#define ANNOUNCE_INTERVAL_ANNOUNCED ONION_NODE_PING_INTERVAL + +#define TIME_TO_STABLE (ONION_NODE_PING_INTERVAL * 6) +#define ANNOUNCE_INTERVAL_STABLE (ONION_NODE_PING_INTERVAL * 8) + +static void do_announce(Onion_Client *onion_c) +{ + unsigned int i, count = 0; + Onion_Node *list_nodes = onion_c->clients_announce_list; + + for (i = 0; i < MAX_ONION_CLIENTS_ANNOUNCE; ++i) { + if (onion_node_timed_out(&list_nodes[i])) { + continue; + } + + ++count; + + /* Don't announce ourselves the first time this is run to new peers */ + if (list_nodes[i].last_pinged == 0) { + list_nodes[i].last_pinged = 1; + continue; + } + + if (list_nodes[i].unsuccessful_pings >= ONION_NODE_MAX_PINGS) { + continue; + } + + + unsigned int interval = ANNOUNCE_INTERVAL_NOT_ANNOUNCED; + + if (list_nodes[i].is_stored && path_exists(&onion_c->onion_paths_self, list_nodes[i].path_used)) { + interval = ANNOUNCE_INTERVAL_ANNOUNCED; + + uint32_t pathnum = list_nodes[i].path_used % NUMBER_ONION_PATHS; + + /* A node/path is considered 'stable', and can be pinged less + * aggressively, if it has survived for at least TIME_TO_STABLE + * and the latest packets sent to it are not timing out. + */ + if (is_timeout(list_nodes[i].added_time, TIME_TO_STABLE) + && !(list_nodes[i].unsuccessful_pings > 0 + && is_timeout(list_nodes[i].last_pinged, ONION_NODE_TIMEOUT)) + && is_timeout(onion_c->onion_paths_self.path_creation_time[pathnum], TIME_TO_STABLE) + && !(onion_c->onion_paths_self.last_path_used_times[pathnum] > 0 + && is_timeout(onion_c->onion_paths_self.last_path_used[pathnum], ONION_PATH_TIMEOUT))) { + interval = ANNOUNCE_INTERVAL_STABLE; + } + } + + if (is_timeout(list_nodes[i].last_pinged, interval) + || (is_timeout(onion_c->last_announce, ONION_NODE_PING_INTERVAL) + && rand() % (MAX_ONION_CLIENTS_ANNOUNCE - i) == 0)) { + uint32_t path_to_use = list_nodes[i].path_used; + + if (list_nodes[i].unsuccessful_pings == ONION_NODE_MAX_PINGS - 1 + && is_timeout(list_nodes[i].added_time, TIME_TO_STABLE)) { + /* Last chance for a long-lived node - try a random path */ + path_to_use = ~0; + } + + if (client_send_announce_request(onion_c, 0, list_nodes[i].ip_port, list_nodes[i].public_key, + list_nodes[i].ping_id, path_to_use) == 0) { + list_nodes[i].last_pinged = unix_time(); + ++list_nodes[i].unsuccessful_pings; + onion_c->last_announce = unix_time(); + } + } + } + + if (count != MAX_ONION_CLIENTS_ANNOUNCE) { + unsigned int num_nodes; + Node_format *path_nodes; + + if (rand() % 2 == 0 || onion_c->path_nodes_index == 0) { + num_nodes = (onion_c->path_nodes_index_bs < MAX_PATH_NODES) ? onion_c->path_nodes_index_bs : MAX_PATH_NODES; + path_nodes = onion_c->path_nodes_bs; + } else { + num_nodes = (onion_c->path_nodes_index < MAX_PATH_NODES) ? onion_c->path_nodes_index : MAX_PATH_NODES; + path_nodes = onion_c->path_nodes; + } + + if (count <= (uint32_t)rand() % MAX_ONION_CLIENTS_ANNOUNCE) { + if (num_nodes != 0) { + for (i = 0; i < (MAX_ONION_CLIENTS_ANNOUNCE / 2); ++i) { + unsigned int num = rand() % num_nodes; + client_send_announce_request(onion_c, 0, path_nodes[num].ip_port, path_nodes[num].public_key, 0, ~0); + } + } + } + } +} + +/* return 0 if we are not connected to the network. + * return 1 if we are. + */ +static int onion_isconnected(const Onion_Client *onion_c) +{ + unsigned int i, num = 0, announced = 0; + + if (is_timeout(onion_c->last_packet_recv, ONION_OFFLINE_TIMEOUT)) { + return 0; + } + + if (onion_c->path_nodes_index == 0) { + return 0; + } + + for (i = 0; i < MAX_ONION_CLIENTS_ANNOUNCE; ++i) { + if (!onion_node_timed_out(&onion_c->clients_announce_list[i])) { + ++num; + + if (onion_c->clients_announce_list[i].is_stored) { + ++announced; + } + } + } + + unsigned int pnodes = onion_c->path_nodes_index; + + if (pnodes > MAX_ONION_CLIENTS_ANNOUNCE) { + pnodes = MAX_ONION_CLIENTS_ANNOUNCE; + } + + /* Consider ourselves online if we are announced to half or more nodes + we are connected to */ + if (num && announced) { + if ((num / 2) <= announced && (pnodes / 2) <= num) { + return 1; + } + } + + return 0; +} + +#define ONION_CONNECTION_SECONDS 3 + +/* return 0 if we are not connected to the network. + * return 1 if we are connected with TCP only. + * return 2 if we are also connected with UDP. + */ +unsigned int onion_connection_status(const Onion_Client *onion_c) +{ + if (onion_c->onion_connected >= ONION_CONNECTION_SECONDS) { + if (onion_c->UDP_connected) { + return 2; + } + + return 1; + } + + return 0; +} + +void do_onion_client(Onion_Client *onion_c) +{ + unsigned int i; + + if (onion_c->last_run == unix_time()) { + return; + } + + if (is_timeout(onion_c->first_run, ONION_CONNECTION_SECONDS)) { + populate_path_nodes(onion_c); + do_announce(onion_c); + } + + if (onion_isconnected(onion_c)) { + if (onion_c->onion_connected < ONION_CONNECTION_SECONDS * 2) { + ++onion_c->onion_connected; + } + } else { + populate_path_nodes_tcp(onion_c); + + if (onion_c->onion_connected != 0) { + --onion_c->onion_connected; + } + } + + bool UDP_connected = DHT_non_lan_connected(onion_c->dht); + + if (is_timeout(onion_c->first_run, ONION_CONNECTION_SECONDS * 2)) { + set_tcp_onion_status(onion_c->c->tcp_c, !UDP_connected); + } + + onion_c->UDP_connected = UDP_connected + || get_random_tcp_onion_conn_number(onion_c->c->tcp_c) == -1; /* Check if connected to any TCP relays. */ + + if (onion_connection_status(onion_c)) { + for (i = 0; i < onion_c->num_friends; ++i) { + do_friend(onion_c, i); + } + } + + if (onion_c->last_run == 0) { + onion_c->first_run = unix_time(); + } + + onion_c->last_run = unix_time(); +} + +Onion_Client *new_onion_client(Net_Crypto *c) +{ + if (c == NULL) { + return NULL; + } + + Onion_Client *onion_c = (Onion_Client *)calloc(1, sizeof(Onion_Client)); + + if (onion_c == NULL) { + return NULL; + } + + if (ping_array_init(&onion_c->announce_ping_array, ANNOUNCE_ARRAY_SIZE, ANNOUNCE_TIMEOUT) != 0) { + free(onion_c); + return NULL; + } + + onion_c->dht = c->dht; + onion_c->net = c->dht->net; + onion_c->c = c; + new_symmetric_key(onion_c->secret_symmetric_key); + crypto_new_keypair(onion_c->temp_public_key, onion_c->temp_secret_key); + networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE, &handle_announce_response, onion_c); + networking_registerhandler(onion_c->net, NET_PACKET_ONION_DATA_RESPONSE, &handle_data_response, onion_c); + oniondata_registerhandler(onion_c, ONION_DATA_DHTPK, &handle_dhtpk_announce, onion_c); + cryptopacket_registerhandler(onion_c->dht, CRYPTO_PACKET_DHTPK, &handle_dht_dhtpk, onion_c); + set_onion_packet_tcp_connection_callback(onion_c->c->tcp_c, &handle_tcp_onion, onion_c); + + return onion_c; +} + +void kill_onion_client(Onion_Client *onion_c) +{ + if (onion_c == NULL) { + return; + } + + ping_array_free_all(&onion_c->announce_ping_array); + realloc_onion_friends(onion_c, 0); + networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE, NULL, NULL); + networking_registerhandler(onion_c->net, NET_PACKET_ONION_DATA_RESPONSE, NULL, NULL); + oniondata_registerhandler(onion_c, ONION_DATA_DHTPK, NULL, NULL); + cryptopacket_registerhandler(onion_c->dht, CRYPTO_PACKET_DHTPK, NULL, NULL); + set_onion_packet_tcp_connection_callback(onion_c->c->tcp_c, NULL, NULL); + crypto_memzero(onion_c, sizeof(Onion_Client)); + free(onion_c); +} + diff --git a/protocols/Tox/libtox/src/toxcore/onion_client.h b/protocols/Tox/libtox/src/toxcore/onion_client.h new file mode 100644 index 0000000000..216dbec050 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/onion_client.h @@ -0,0 +1,302 @@ +/* + * Implementation of the client part of docs/Prevent_Tracking.txt (The part that + * uses the onion stuff to connect to the friend) + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef ONION_CLIENT_H +#define ONION_CLIENT_H + +#include "net_crypto.h" +#include "onion_announce.h" +#include "ping_array.h" + +#define MAX_ONION_CLIENTS 8 +#define MAX_ONION_CLIENTS_ANNOUNCE 12 /* Number of nodes to announce ourselves to. */ +#define ONION_NODE_PING_INTERVAL 15 +#define ONION_NODE_TIMEOUT ONION_NODE_PING_INTERVAL + +/* The interval in seconds at which to tell our friends where we are */ +#define ONION_DHTPK_SEND_INTERVAL 30 +#define DHT_DHTPK_SEND_INTERVAL 20 + +#define NUMBER_ONION_PATHS 6 + +/* The timeout the first time the path is added and + then for all the next consecutive times */ +#define ONION_PATH_FIRST_TIMEOUT 4 +#define ONION_PATH_TIMEOUT 10 +#define ONION_PATH_MAX_LIFETIME 1200 +#define ONION_PATH_MAX_NO_RESPONSE_USES 4 + +#define MAX_STORED_PINGED_NODES 9 +#define MIN_NODE_PING_TIME 10 + +#define ONION_NODE_MAX_PINGS 3 + +#define MAX_PATH_NODES 32 + +/* If no announce response packets are received within this interval tox will + * be considered offline. We give time for a node to be pinged often enough + * that it times out, which leads to the network being thoroughly tested as it + * is replaced. + */ +#define ONION_OFFLINE_TIMEOUT (ONION_NODE_PING_INTERVAL * (ONION_NODE_MAX_PINGS+2)) + +/* Onion data packet ids. */ +#define ONION_DATA_FRIEND_REQ CRYPTO_PACKET_FRIEND_REQ +#define ONION_DATA_DHTPK CRYPTO_PACKET_DHTPK + +typedef struct { + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + IP_Port ip_port; + uint8_t ping_id[ONION_PING_ID_SIZE]; + uint8_t data_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t is_stored; + + uint64_t added_time; + + uint64_t timestamp; + + uint64_t last_pinged; + + uint8_t unsuccessful_pings; + + uint32_t path_used; +} Onion_Node; + +typedef struct { + Onion_Path paths[NUMBER_ONION_PATHS]; + uint64_t last_path_success[NUMBER_ONION_PATHS]; + uint64_t last_path_used[NUMBER_ONION_PATHS]; + uint64_t path_creation_time[NUMBER_ONION_PATHS]; + /* number of times used without success. */ + unsigned int last_path_used_times[NUMBER_ONION_PATHS]; +} Onion_Client_Paths; + +typedef struct { + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint64_t timestamp; +} Last_Pinged; + +typedef struct { + uint8_t status; /* 0 if friend is not valid, 1 if friend is valid.*/ + uint8_t is_online; /* Set by the onion_set_friend_status function. */ + + uint8_t know_dht_public_key; /* 0 if we don't know the dht public key of the other, 1 if we do. */ + uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t real_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + + Onion_Node clients_list[MAX_ONION_CLIENTS]; + uint8_t temp_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t temp_secret_key[CRYPTO_SECRET_KEY_SIZE]; + + uint64_t last_reported_announced; + + uint64_t last_dht_pk_onion_sent; + uint64_t last_dht_pk_dht_sent; + + uint64_t last_noreplay; + + uint64_t last_seen; + + Last_Pinged last_pinged[MAX_STORED_PINGED_NODES]; + uint8_t last_pinged_index; + + int (*tcp_relay_node_callback)(void *object, uint32_t number, IP_Port ip_port, const uint8_t *public_key); + void *tcp_relay_node_callback_object; + uint32_t tcp_relay_node_callback_number; + + void (*dht_pk_callback)(void *data, int32_t number, const uint8_t *dht_public_key, void *userdata); + void *dht_pk_callback_object; + uint32_t dht_pk_callback_number; + + uint32_t run_count; +} Onion_Friend; + +typedef int (*oniondata_handler_callback)(void *object, const uint8_t *source_pubkey, const uint8_t *data, + uint16_t len, void *userdata); + +typedef struct { + DHT *dht; + Net_Crypto *c; + Networking_Core *net; + Onion_Friend *friends_list; + uint16_t num_friends; + + Onion_Node clients_announce_list[MAX_ONION_CLIENTS_ANNOUNCE]; + uint64_t last_announce; + + Onion_Client_Paths onion_paths_self; + Onion_Client_Paths onion_paths_friends; + + uint8_t secret_symmetric_key[CRYPTO_SYMMETRIC_KEY_SIZE]; + uint64_t last_run, first_run; + + uint8_t temp_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t temp_secret_key[CRYPTO_SECRET_KEY_SIZE]; + + Last_Pinged last_pinged[MAX_STORED_PINGED_NODES]; + + Node_format path_nodes[MAX_PATH_NODES]; + uint16_t path_nodes_index; + + Node_format path_nodes_bs[MAX_PATH_NODES]; + uint16_t path_nodes_index_bs; + + Ping_Array announce_ping_array; + uint8_t last_pinged_index; + struct { + oniondata_handler_callback function; + void *object; + } Onion_Data_Handlers[256]; + + uint64_t last_packet_recv; + + unsigned int onion_connected; + bool UDP_connected; +} Onion_Client; + + +/* Add a node to the path_nodes bootstrap array. + * + * return -1 on failure + * return 0 on success + */ +int onion_add_bs_path_node(Onion_Client *onion_c, IP_Port ip_port, const uint8_t *public_key); + +/* Put up to max_num nodes in nodes. + * + * return the number of nodes. + */ +uint16_t onion_backup_nodes(const Onion_Client *onion_c, Node_format *nodes, uint16_t max_num); + +/* Add a friend who we want to connect to. + * + * return -1 on failure. + * return the friend number on success or if the friend was already added. + */ +int onion_friend_num(const Onion_Client *onion_c, const uint8_t *public_key); + +/* Add a friend who we want to connect to. + * + * return -1 on failure. + * return the friend number on success. + */ +int onion_addfriend(Onion_Client *onion_c, const uint8_t *public_key); + +/* Delete a friend. + * + * return -1 on failure. + * return the deleted friend number on success. + */ +int onion_delfriend(Onion_Client *onion_c, int friend_num); + +/* Set if friend is online or not. + * NOTE: This function is there and should be used so that we don't send useless packets to the friend if he is online. + * + * is_online 1 means friend is online. + * is_online 0 means friend is offline + * + * return -1 on failure. + * return 0 on success. + */ +int onion_set_friend_online(Onion_Client *onion_c, int friend_num, uint8_t is_online); + +/* Get the ip of friend friendnum and put it in ip_port + * + * return -1, -- if public_key does NOT refer to a friend + * return 0, -- if public_key refers to a friend and we failed to find the friend (yet) + * return 1, ip if public_key refers to a friend and we found him + * + */ +int onion_getfriendip(const Onion_Client *onion_c, int friend_num, IP_Port *ip_port); + +/* Set the function for this friend that will be callbacked with object and number + * when that friends gives us one of the TCP relays he is connected to. + * + * object and number will be passed as argument to this function. + * + * return -1 on failure. + * return 0 on success. + */ +int recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, int (*tcp_relay_node_callback)(void *object, + uint32_t number, IP_Port ip_port, const uint8_t *public_key), void *object, uint32_t number); + + +/* Set the function for this friend that will be callbacked with object and number + * when that friend gives us his DHT temporary public key. + * + * object and number will be passed as argument to this function. + * + * return -1 on failure. + * return 0 on success. + */ +int onion_dht_pk_callback(Onion_Client *onion_c, int friend_num, void (*function)(void *data, int32_t number, + const uint8_t *dht_public_key, void *userdata), void *object, uint32_t number); + +/* Set a friends DHT public key. + * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to + * the other peer. + * + * return -1 on failure. + * return 0 on success. + */ +int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, const uint8_t *dht_key); + +/* Copy friends DHT public key into dht_key. + * + * return 0 on failure (no key copied). + * return 1 on success (key copied). + */ +unsigned int onion_getfriend_DHT_pubkey(const Onion_Client *onion_c, int friend_num, uint8_t *dht_key); + +#define ONION_DATA_IN_RESPONSE_MIN_SIZE (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_MAC_SIZE) +#define ONION_CLIENT_MAX_DATA_SIZE (MAX_DATA_REQUEST_SIZE - ONION_DATA_IN_RESPONSE_MIN_SIZE) + +/* Send data of length length to friendnum. + * Maximum length of data is ONION_CLIENT_MAX_DATA_SIZE. + * This data will be received by the friend using the Onion_Data_Handlers callbacks. + * + * Even if this function succeeds, the friend might not receive any data. + * + * return the number of packets sent on success + * return -1 on failure. + */ +int send_onion_data(Onion_Client *onion_c, int friend_num, const uint8_t *data, uint16_t length); + +/* Function to call when onion data packet with contents beginning with byte is received. */ +void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object); + +void do_onion_client(Onion_Client *onion_c); + +Onion_Client *new_onion_client(Net_Crypto *c); + +void kill_onion_client(Onion_Client *onion_c); + + +/* return 0 if we are not connected to the network. + * return 1 if we are connected with TCP only. + * return 2 if we are also connected with UDP. + */ +unsigned int onion_connection_status(const Onion_Client *onion_c); + +#endif diff --git a/protocols/Tox/libtox/src/toxcore/ping.c b/protocols/Tox/libtox/src/toxcore/ping.c new file mode 100644 index 0000000000..72b3fe6259 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/ping.c @@ -0,0 +1,381 @@ +/* + * Buffered pinging using cyclic arrays. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * Copyright © 2013 plutooo + * + * This file is part of Tox, the free peer to peer instant messenger. + * This file is donated to the Tox Project. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ping.h" + +#include "DHT.h" +#include "network.h" +#include "ping_array.h" +#include "util.h" + +#include <stdint.h> + +#define PING_NUM_MAX 512 + +/* Maximum newly announced nodes to ping per TIME_TO_PING seconds. */ +#define MAX_TO_PING 32 + +/* Ping newly announced nodes to ping per TIME_TO_PING seconds*/ +#define TIME_TO_PING 2 + + +struct PING { + DHT *dht; + + Ping_Array ping_array; + Node_format to_ping[MAX_TO_PING]; + uint64_t last_to_ping; +}; + + +#define PING_PLAIN_SIZE (1 + sizeof(uint64_t)) +#define DHT_PING_SIZE (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + PING_PLAIN_SIZE + CRYPTO_MAC_SIZE) +#define PING_DATA_SIZE (CRYPTO_PUBLIC_KEY_SIZE + sizeof(IP_Port)) + +int send_ping_request(PING *ping, IP_Port ipp, const uint8_t *public_key) +{ + uint8_t pk[DHT_PING_SIZE]; + int rc; + uint64_t ping_id; + + if (id_equal(public_key, ping->dht->self_public_key)) { + return 1; + } + + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + + // generate key to encrypt ping_id with recipient privkey + DHT_get_shared_key_sent(ping->dht, shared_key, public_key); + // Generate random ping_id. + uint8_t data[PING_DATA_SIZE]; + id_copy(data, public_key); + memcpy(data + CRYPTO_PUBLIC_KEY_SIZE, &ipp, sizeof(IP_Port)); + ping_id = ping_array_add(&ping->ping_array, data, sizeof(data)); + + if (ping_id == 0) { + return 1; + } + + uint8_t ping_plain[PING_PLAIN_SIZE]; + ping_plain[0] = NET_PACKET_PING_REQUEST; + memcpy(ping_plain + 1, &ping_id, sizeof(ping_id)); + + pk[0] = NET_PACKET_PING_REQUEST; + id_copy(pk + 1, ping->dht->self_public_key); // Our pubkey + random_nonce(pk + 1 + CRYPTO_PUBLIC_KEY_SIZE); // Generate new nonce + + + rc = encrypt_data_symmetric(shared_key, + pk + 1 + CRYPTO_PUBLIC_KEY_SIZE, + ping_plain, sizeof(ping_plain), + pk + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); + + if (rc != PING_PLAIN_SIZE + CRYPTO_MAC_SIZE) { + return 1; + } + + return sendpacket(ping->dht->net, ipp, pk, sizeof(pk)); +} + +static int send_ping_response(PING *ping, IP_Port ipp, const uint8_t *public_key, uint64_t ping_id, + uint8_t *shared_encryption_key) +{ + uint8_t pk[DHT_PING_SIZE]; + int rc; + + if (id_equal(public_key, ping->dht->self_public_key)) { + return 1; + } + + uint8_t ping_plain[PING_PLAIN_SIZE]; + ping_plain[0] = NET_PACKET_PING_RESPONSE; + memcpy(ping_plain + 1, &ping_id, sizeof(ping_id)); + + pk[0] = NET_PACKET_PING_RESPONSE; + id_copy(pk + 1, ping->dht->self_public_key); // Our pubkey + random_nonce(pk + 1 + CRYPTO_PUBLIC_KEY_SIZE); // Generate new nonce + + // Encrypt ping_id using recipient privkey + rc = encrypt_data_symmetric(shared_encryption_key, + pk + 1 + CRYPTO_PUBLIC_KEY_SIZE, + ping_plain, sizeof(ping_plain), + pk + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); + + if (rc != PING_PLAIN_SIZE + CRYPTO_MAC_SIZE) { + return 1; + } + + return sendpacket(ping->dht->net, ipp, pk, sizeof(pk)); +} + +static int handle_ping_request(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + DHT *dht = (DHT *)object; + int rc; + + if (length != DHT_PING_SIZE) { + return 1; + } + + PING *ping = dht->ping; + + if (id_equal(packet + 1, ping->dht->self_public_key)) { + return 1; + } + + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + + uint8_t ping_plain[PING_PLAIN_SIZE]; + // Decrypt ping_id + DHT_get_shared_key_recv(dht, shared_key, packet + 1); + rc = decrypt_data_symmetric(shared_key, + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, + PING_PLAIN_SIZE + CRYPTO_MAC_SIZE, + ping_plain); + + if (rc != sizeof(ping_plain)) { + return 1; + } + + if (ping_plain[0] != NET_PACKET_PING_REQUEST) { + return 1; + } + + uint64_t ping_id; + memcpy(&ping_id, ping_plain + 1, sizeof(ping_id)); + // Send response + send_ping_response(ping, source, packet + 1, ping_id, shared_key); + add_to_ping(ping, packet + 1, source); + + return 0; +} + +static int handle_ping_response(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + DHT *dht = (DHT *)object; + int rc; + + if (length != DHT_PING_SIZE) { + return 1; + } + + PING *ping = dht->ping; + + if (id_equal(packet + 1, ping->dht->self_public_key)) { + return 1; + } + + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + + // generate key to encrypt ping_id with recipient privkey + DHT_get_shared_key_sent(ping->dht, shared_key, packet + 1); + + uint8_t ping_plain[PING_PLAIN_SIZE]; + // Decrypt ping_id + rc = decrypt_data_symmetric(shared_key, + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, + PING_PLAIN_SIZE + CRYPTO_MAC_SIZE, + ping_plain); + + if (rc != sizeof(ping_plain)) { + return 1; + } + + if (ping_plain[0] != NET_PACKET_PING_RESPONSE) { + return 1; + } + + uint64_t ping_id; + memcpy(&ping_id, ping_plain + 1, sizeof(ping_id)); + uint8_t data[PING_DATA_SIZE]; + + if (ping_array_check(data, sizeof(data), &ping->ping_array, ping_id) != sizeof(data)) { + return 1; + } + + if (!id_equal(packet + 1, data)) { + return 1; + } + + IP_Port ipp; + memcpy(&ipp, data + CRYPTO_PUBLIC_KEY_SIZE, sizeof(IP_Port)); + + if (!ipport_equal(&ipp, &source)) { + return 1; + } + + addto_lists(dht, source, packet + 1); + return 0; +} + +/* Check if public_key with ip_port is in the list. + * + * return 1 if it is. + * return 0 if it isn't. + */ +static int in_list(const Client_data *list, uint16_t length, const uint8_t *public_key, IP_Port ip_port) +{ + unsigned int i; + + for (i = 0; i < length; ++i) { + if (id_equal(list[i].public_key, public_key)) { + const IPPTsPng *ipptp; + + if (ip_port.ip.family == TOX_AF_INET) { + ipptp = &list[i].assoc4; + } else { + ipptp = &list[i].assoc6; + } + + if (!is_timeout(ipptp->timestamp, BAD_NODE_TIMEOUT) && ipport_equal(&ipptp->ip_port, &ip_port)) { + return 1; + } + } + } + + return 0; +} + +/* Add nodes to the to_ping list. + * All nodes in this list are pinged every TIME_TO_PING seconds + * and are then removed from the list. + * If the list is full the nodes farthest from our public_key are replaced. + * The purpose of this list is to enable quick integration of new nodes into the + * network while preventing amplification attacks. + * + * return 0 if node was added. + * return -1 if node was not added. + */ +int add_to_ping(PING *ping, const uint8_t *public_key, IP_Port ip_port) +{ + if (!ip_isset(&ip_port.ip)) { + return -1; + } + + if (!node_addable_to_close_list(ping->dht, public_key, ip_port)) { + return -1; + } + + if (in_list(ping->dht->close_clientlist, LCLIENT_LIST, public_key, ip_port)) { + return -1; + } + + IP_Port temp; + + if (DHT_getfriendip(ping->dht, public_key, &temp) == 0) { + send_ping_request(ping, ip_port, public_key); + return -1; + } + + unsigned int i; + + for (i = 0; i < MAX_TO_PING; ++i) { + if (!ip_isset(&ping->to_ping[i].ip_port.ip)) { + memcpy(ping->to_ping[i].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + ipport_copy(&ping->to_ping[i].ip_port, &ip_port); + return 0; + } + + if (public_key_cmp(ping->to_ping[i].public_key, public_key) == 0) { + return -1; + } + } + + if (add_to_list(ping->to_ping, MAX_TO_PING, public_key, ip_port, ping->dht->self_public_key)) { + return 0; + } + + return -1; +} + + +/* Ping all the valid nodes in the to_ping list every TIME_TO_PING seconds. + * This function must be run at least once every TIME_TO_PING seconds. + */ +void do_to_ping(PING *ping) +{ + if (!is_timeout(ping->last_to_ping, TIME_TO_PING)) { + return; + } + + if (!ip_isset(&ping->to_ping[0].ip_port.ip)) { + return; + } + + unsigned int i; + + for (i = 0; i < MAX_TO_PING; ++i) { + if (!ip_isset(&ping->to_ping[i].ip_port.ip)) { + break; + } + + if (!node_addable_to_close_list(ping->dht, ping->to_ping[i].public_key, ping->to_ping[i].ip_port)) { + continue; + } + + send_ping_request(ping, ping->to_ping[i].ip_port, ping->to_ping[i].public_key); + ip_reset(&ping->to_ping[i].ip_port.ip); + } + + if (i != 0) { + ping->last_to_ping = unix_time(); + } +} + + +PING *new_ping(DHT *dht) +{ + PING *ping = (PING *)calloc(1, sizeof(PING)); + + if (ping == NULL) { + return NULL; + } + + if (ping_array_init(&ping->ping_array, PING_NUM_MAX, PING_TIMEOUT) != 0) { + free(ping); + return NULL; + } + + ping->dht = dht; + networking_registerhandler(ping->dht->net, NET_PACKET_PING_REQUEST, &handle_ping_request, dht); + networking_registerhandler(ping->dht->net, NET_PACKET_PING_RESPONSE, &handle_ping_response, dht); + + return ping; +} + +void kill_ping(PING *ping) +{ + networking_registerhandler(ping->dht->net, NET_PACKET_PING_REQUEST, NULL, NULL); + networking_registerhandler(ping->dht->net, NET_PACKET_PING_RESPONSE, NULL, NULL); + ping_array_free_all(&ping->ping_array); + + free(ping); +} diff --git a/protocols/Tox/libtox/src/toxcore/ping.h b/protocols/Tox/libtox/src/toxcore/ping.h new file mode 100644 index 0000000000..cc3428c548 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/ping.h @@ -0,0 +1,54 @@ +/* + * Buffered pinging using cyclic arrays. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * Copyright © 2013 plutooo + * + * This file is part of Tox, the free peer to peer instant messenger. + * This file is donated to the Tox Project. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef PING_H +#define PING_H + +#include "DHT.h" +#include "network.h" + +#include <stdint.h> + +typedef struct PING PING; + +/* Add nodes to the to_ping list. + * All nodes in this list are pinged every TIME_TOPING seconds + * and are then removed from the list. + * If the list is full the nodes farthest from our public_key are replaced. + * The purpose of this list is to enable quick integration of new nodes into the + * network while preventing amplification attacks. + * + * return 0 if node was added. + * return -1 if node was not added. + */ +int add_to_ping(PING *ping, const uint8_t *public_key, IP_Port ip_port); +void do_to_ping(PING *ping); + +PING *new_ping(DHT *dht); +void kill_ping(PING *ping); + +int send_ping_request(PING *ping, IP_Port ipp, const uint8_t *public_key); + +#endif /* PING_H */ diff --git a/protocols/Tox/libtox/src/toxcore/ping_array.c b/protocols/Tox/libtox/src/toxcore/ping_array.c new file mode 100644 index 0000000000..ea3e5101b1 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/ping_array.c @@ -0,0 +1,172 @@ +/* + * Implementation of an efficient array to store that we pinged something. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ping_array.h" + +#include "crypto_core.h" +#include "util.h" + +static void clear_entry(Ping_Array *array, uint32_t index) +{ + free(array->entries[index].data); + array->entries[index].data = NULL; + array->entries[index].length = + array->entries[index].time = + array->entries[index].ping_id = 0; +} + +/* Clear timed out entries. + */ +static void ping_array_clear_timedout(Ping_Array *array) +{ + while (array->last_deleted != array->last_added) { + uint32_t index = array->last_deleted % array->total_size; + + if (!is_timeout(array->entries[index].time, array->timeout)) { + break; + } + + clear_entry(array, index); + ++array->last_deleted; + } +} + +/* Add a data with length to the Ping_Array list and return a ping_id. + * + * return ping_id on success. + * return 0 on failure. + */ +uint64_t ping_array_add(Ping_Array *array, const uint8_t *data, uint32_t length) +{ + ping_array_clear_timedout(array); + uint32_t index = array->last_added % array->total_size; + + if (array->entries[index].data != NULL) { + array->last_deleted = array->last_added - array->total_size; + clear_entry(array, index); + } + + array->entries[index].data = malloc(length); + + if (array->entries[index].data == NULL) { + return 0; + } + + memcpy(array->entries[index].data, data, length); + array->entries[index].length = length; + array->entries[index].time = unix_time(); + ++array->last_added; + uint64_t ping_id = random_64b(); + ping_id /= array->total_size; + ping_id *= array->total_size; + ping_id += index; + + if (ping_id == 0) { + ping_id += array->total_size; + } + + array->entries[index].ping_id = ping_id; + return ping_id; +} + + +/* Check if ping_id is valid and not timed out. + * + * On success, copies the data into data of length, + * + * return length of data copied on success. + * return -1 on failure. + */ +int ping_array_check(uint8_t *data, uint32_t length, Ping_Array *array, uint64_t ping_id) +{ + if (ping_id == 0) { + return -1; + } + + uint32_t index = ping_id % array->total_size; + + if (array->entries[index].ping_id != ping_id) { + return -1; + } + + if (is_timeout(array->entries[index].time, array->timeout)) { + return -1; + } + + if (array->entries[index].length > length) { + return -1; + } + + if (array->entries[index].data == NULL) { + return -1; + } + + memcpy(data, array->entries[index].data, array->entries[index].length); + uint32_t len = array->entries[index].length; + clear_entry(array, index); + return len; +} + +/* Initialize a Ping_Array. + * size represents the total size of the array and should be a power of 2. + * timeout represents the maximum timeout in seconds for the entry. + * + * return 0 on success. + * return -1 on failure. + */ +int ping_array_init(Ping_Array *empty_array, uint32_t size, uint32_t timeout) +{ + if (size == 0 || timeout == 0 || empty_array == NULL) { + return -1; + } + + empty_array->entries = (Ping_Array_Entry *)calloc(size, sizeof(Ping_Array_Entry)); + + if (empty_array->entries == NULL) { + return -1; + } + + empty_array->last_deleted = empty_array->last_added = 0; + empty_array->total_size = size; + empty_array->timeout = timeout; + return 0; +} + +/* Free all the allocated memory in a Ping_Array. + */ +void ping_array_free_all(Ping_Array *array) +{ + while (array->last_deleted != array->last_added) { + uint32_t index = array->last_deleted % array->total_size; + clear_entry(array, index); + ++array->last_deleted; + } + + free(array->entries); + array->entries = NULL; +} + diff --git a/protocols/Tox/libtox/src/toxcore/ping_array.h b/protocols/Tox/libtox/src/toxcore/ping_array.h new file mode 100644 index 0000000000..bdf3c6db3d --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/ping_array.h @@ -0,0 +1,76 @@ +/* + * Implementation of an efficient array to store that we pinged something. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef PING_ARRAY_H +#define PING_ARRAY_H + +#include "network.h" + +typedef struct { + void *data; + uint32_t length; + uint64_t time; + uint64_t ping_id; +} Ping_Array_Entry; + + +typedef struct { + Ping_Array_Entry *entries; + + uint32_t last_deleted; /* number representing the next entry to be deleted. */ + uint32_t last_added; /* number representing the last entry to be added. */ + uint32_t total_size; /* The length of entries */ + uint32_t timeout; /* The timeout after which entries are cleared. */ +} Ping_Array; + + +/* Add a data with length to the Ping_Array list and return a ping_id. + * + * return ping_id on success. + * return 0 on failure. + */ +uint64_t ping_array_add(Ping_Array *array, const uint8_t *data, uint32_t length); + +/* Check if ping_id is valid and not timed out. + * + * On success, copies the data into data of length, + * + * return length of data copied on success. + * return -1 on failure. + */ +int ping_array_check(uint8_t *data, uint32_t length, Ping_Array *array, uint64_t ping_id); + +/* Initialize a Ping_Array. + * size represents the total size of the array and should be a power of 2. + * timeout represents the maximum timeout in seconds for the entry. + * + * return 0 on success. + * return -1 on failure. + */ +int ping_array_init(Ping_Array *empty_array, uint32_t size, uint32_t timeout); + +/* Free all the allocated memory in a Ping_Array. + */ +void ping_array_free_all(Ping_Array *array); + +#endif diff --git a/protocols/Tox/libtox/src/toxcore/tox.api.h b/protocols/Tox/libtox/src/toxcore/tox.api.h new file mode 100644 index 0000000000..0763c7789d --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/tox.api.h @@ -0,0 +1,2583 @@ +%{ +/* + * The Tox public API. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef TOX_H +#define TOX_H + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif +%} + + +/***************************************************************************** + * `tox.h` SHOULD *NOT* BE EDITED MANUALLY – any changes should be made to * + * `tox.api.h`, located in `toxcore/`. For instructions on how to * + * generate `tox.h` from `tox.api.h` please refer to `docs/apidsl.md` * + *****************************************************************************/ + + +/** \page core Public core API for Tox clients. + * + * Every function that can fail takes a function-specific error code pointer + * that can be used to diagnose problems with the Tox state or the function + * arguments. The error code pointer can be NULL, which does not influence the + * function's behaviour, but can be done if the reason for failure is irrelevant + * to the client. + * + * The exception to this rule are simple allocation functions whose only failure + * mode is allocation failure. They return NULL in that case, and do not set an + * error code. + * + * Every error code type has an OK value to which functions will set their error + * code value on success. Clients can keep their error code uninitialised before + * passing it to a function. The library guarantees that after returning, the + * value pointed to by the error code pointer has been initialised. + * + * Functions with pointer parameters often have a NULL error code, meaning they + * could not perform any operation, because one of the required parameters was + * NULL. Some functions operate correctly or are defined as effectless on NULL. + * + * Some functions additionally return a value outside their + * return type domain, or a bool containing true on success and false on + * failure. + * + * All functions that take a Tox instance pointer will cause undefined behaviour + * when passed a NULL Tox pointer. + * + * All integer values are expected in host byte order. + * + * Functions with parameters with enum types cause unspecified behaviour if the + * enumeration value is outside the valid range of the type. If possible, the + * function will try to use a sane default, but there will be no error code, + * and one possible action for the function to take is to have no effect. + * + * Integer constants and the memory layout of publicly exposed structs are not + * part of the ABI. + */ + +/** \subsection events Events and callbacks + * + * Events are handled by callbacks. One callback can be registered per event. + * All events have a callback function type named `tox_{event}_cb` and a + * function to register it named `tox_callback_{event}`. Passing a NULL + * callback will result in no callback being registered for that event. Only + * one callback per event can be registered, so if a client needs multiple + * event listeners, it needs to implement the dispatch functionality itself. + * + * The last argument to a callback is the user data pointer. It is passed from + * ${tox.iterate} to each callback in sequence. + * + * The user data pointer is never stored or dereferenced by any library code, so + * can be any pointer, including NULL. Callbacks must all operate on the same + * object type. In the apidsl code (tox.in.h), this is denoted with `any`. The + * `any` in ${tox.iterate} must be the same `any` as in all callbacks. In C, + * lacking parametric polymorphism, this is a pointer to void. + * + * Old style callbacks that are registered together with a user data pointer + * receive that pointer as argument when they are called. They can each have + * their own user data pointer of their own type. + */ + +/** \subsection threading Threading implications + * + * It is possible to run multiple concurrent threads with a Tox instance for + * each thread. It is also possible to run all Tox instances in the same thread. + * A common way to run Tox (multiple or single instance) is to have one thread + * running a simple ${tox.iterate} loop, sleeping for ${tox.iteration_interval} + * milliseconds on each iteration. + * + * If you want to access a single Tox instance from multiple threads, access + * to the instance must be synchronised. While multiple threads can concurrently + * access multiple different Tox instances, no more than one API function can + * operate on a single instance at any given time. + * + * Functions that write to variable length byte arrays will always have a size + * function associated with them. The result of this size function is only valid + * until another mutating function (one that takes a pointer to non-const Tox) + * is called. Thus, clients must ensure that no other thread calls a mutating + * function between the call to the size function and the call to the retrieval + * function. + * + * E.g. to get the current nickname, one would write + * + * \code + * size_t length = ${tox.self.name.size}(tox); + * uint8_t *name = malloc(length); + * if (!name) abort(); + * ${tox.self.name.get}(tox, name); + * \endcode + * + * If any other thread calls ${tox.self.name.set} while this thread is allocating + * memory, the length may have become invalid, and the call to + * ${tox.self.name.get} may cause undefined behaviour. + */ + +// The rest of this file is in class tox. +class tox { + +/** + * The Tox instance type. All the state associated with a connection is held + * within the instance. Multiple instances can exist and operate concurrently. + * The maximum number of Tox instances that can exist on a single network + * device is limited. Note that this is not just a per-process limit, since the + * limiting factor is the number of usable ports on a device. + */ +struct this; + + +/******************************************************************************* + * + * :: API version + * + ******************************************************************************/ + + +/** + * The major version number. Incremented when the API or ABI changes in an + * incompatible way. + * + * The function variants of these constants return the version number of the + * library. They can be used to display the Tox library version or to check + * whether the client is compatible with the dynamically linked version of Tox. + */ +const VERSION_MAJOR = 0; + +/** + * The minor version number. Incremented when functionality is added without + * breaking the API or ABI. Set to 0 when the major version number is + * incremented. + */ +const VERSION_MINOR = 1; + +/** + * The patch or revision number. Incremented when bugfixes are applied without + * changing any functionality or API or ABI. + */ +const VERSION_PATCH = 10; + +/** + * A macro to check at preprocessing time whether the client code is compatible + * with the installed version of Tox. Leading zeros in the version number are + * ignored. E.g. 0.1.5 is to 0.1.4 what 1.5 is to 1.4, that is: it can add new + * features, but can't break the API. + */ +#define TOX_VERSION_IS_API_COMPATIBLE(MAJOR, MINOR, PATCH) \ + (TOX_VERSION_MAJOR > 0 && TOX_VERSION_MAJOR == MAJOR) && ( \ + /* 1.x.x, 2.x.x, etc. with matching major version. */ \ + TOX_VERSION_MINOR > MINOR || \ + TOX_VERSION_MINOR == MINOR && TOX_VERSION_PATCH >= PATCH \ + ) || (TOX_VERSION_MAJOR == 0 && MAJOR == 0) && ( \ + /* 0.x.x makes minor behave like major above. */ \ + (TOX_VERSION_MINOR > 0 && TOX_VERSION_MINOR == MINOR) && ( \ + TOX_VERSION_PATCH >= PATCH \ + ) || (TOX_VERSION_MINOR == 0 && MINOR == 0) && ( \ + /* 0.0.x and 0.0.y are only compatible if x == y. */ \ + TOX_VERSION_PATCH == PATCH \ + ) \ + ) + +static namespace version { + + /** + * Return whether the compiled library version is compatible with the passed + * version numbers. + */ + bool is_compatible(uint32_t major, uint32_t minor, uint32_t patch); + +} + +/** + * A convenience macro to call tox_version_is_compatible with the currently + * compiling API version. + */ +#define TOX_VERSION_IS_ABI_COMPATIBLE() \ + tox_version_is_compatible(TOX_VERSION_MAJOR, TOX_VERSION_MINOR, TOX_VERSION_PATCH) + +/******************************************************************************* + * + * :: Numeric constants + * + * The values of these are not part of the ABI. Prefer to use the function + * versions of them for code that should remain compatible with future versions + * of toxcore. + * + ******************************************************************************/ + + +/** + * The size of a Tox Public Key in bytes. + */ +const PUBLIC_KEY_SIZE = 32; + +/** + * The size of a Tox Secret Key in bytes. + */ +const SECRET_KEY_SIZE = 32; + +/** + * The size of the nospam in bytes when written in a Tox address. + */ +const NOSPAM_SIZE = sizeof(uint32_t); + +/** + * The size of a Tox address in bytes. Tox addresses are in the format + * [Public Key ($PUBLIC_KEY_SIZE bytes)][nospam (4 bytes)][checksum (2 bytes)]. + * + * The checksum is computed over the Public Key and the nospam value. The first + * byte is an XOR of all the even bytes (0, 2, 4, ...), the second byte is an + * XOR of all the odd bytes (1, 3, 5, ...) of the Public Key and nospam. + */ +const ADDRESS_SIZE = PUBLIC_KEY_SIZE + NOSPAM_SIZE + sizeof(uint16_t); + +/** + * Maximum length of a nickname in bytes. + */ +const MAX_NAME_LENGTH = 128; + +/** + * Maximum length of a status message in bytes. + */ +const MAX_STATUS_MESSAGE_LENGTH = 1007; + +/** + * Maximum length of a friend request message in bytes. + */ +const MAX_FRIEND_REQUEST_LENGTH = 1016; + +/** + * Maximum length of a single message after which it should be split. + */ +const MAX_MESSAGE_LENGTH = 1372; + +/** + * Maximum size of custom packets. TODO(iphydf): should be LENGTH? + */ +const MAX_CUSTOM_PACKET_SIZE = 1373; + +/** + * The number of bytes in a hash generated by $hash. + */ +const HASH_LENGTH = 32; + +/** + * The number of bytes in a file id. + */ +const FILE_ID_LENGTH = 32; + +/** + * Maximum file name length for file transfers. + */ +const MAX_FILENAME_LENGTH = 255; + + +/******************************************************************************* + * + * :: Global enumerations + * + ******************************************************************************/ + + +/** + * Represents the possible statuses a client can have. + */ +enum class USER_STATUS { + /** + * User is online and available. + */ + NONE, + /** + * User is away. Clients can set this e.g. after a user defined + * inactivity time. + */ + AWAY, + /** + * User is busy. Signals to other clients that this client does not + * currently wish to communicate. + */ + BUSY, +} + + +/** + * Represents message types for ${tox.friend.send.message} and conference + * messages. + */ +enum class MESSAGE_TYPE { + /** + * Normal text message. Similar to PRIVMSG on IRC. + */ + NORMAL, + /** + * A message describing an user action. This is similar to /me (CTCP ACTION) + * on IRC. + */ + ACTION, +} + + +/******************************************************************************* + * + * :: Startup options + * + ******************************************************************************/ + + +/** + * Type of proxy used to connect to TCP relays. + */ +enum class PROXY_TYPE { + /** + * Don't use a proxy. + */ + NONE, + /** + * HTTP proxy using CONNECT. + */ + HTTP, + /** + * SOCKS proxy for simple socket pipes. + */ + SOCKS5, +} + +/** + * Type of savedata to create the Tox instance from. + */ +enum class SAVEDATA_TYPE { + /** + * No savedata. + */ + NONE, + /** + * Savedata is one that was obtained from ${savedata.get}. + */ + TOX_SAVE, + /** + * Savedata is a secret key of length $SECRET_KEY_SIZE. + */ + SECRET_KEY, +} + + +/** + * Severity level of log messages. + */ +enum class LOG_LEVEL { + /** + * Very detailed traces including all network activity. + */ + TRACE, + /** + * Debug messages such as which port we bind to. + */ + DEBUG, + /** + * Informational log messages such as video call status changes. + */ + INFO, + /** + * Warnings about internal inconsistency or logic errors. + */ + WARNING, + /** + * Severe unexpected errors caused by external or internal inconsistency. + */ + ERROR, +} + +/** + * This event is triggered when the toxcore library logs an internal message. + * This is mostly useful for debugging. This callback can be called from any + * function, not just $iterate. This means the user data lifetime must at + * least extend between registering and unregistering it or $kill. + * + * Other toxcore modules such as toxav may concurrently call this callback at + * any time. Thus, user code must make sure it is equipped to handle concurrent + * execution, e.g. by employing appropriate mutex locking. + * + * @param level The severity of the log message. + * @param file The source file from which the message originated. + * @param line The source line from which the message originated. + * @param func The function from which the message originated. + * @param message The log message. + * @param user_data The user data pointer passed to $new in options. + */ +typedef void log_cb(LOG_LEVEL level, string file, uint32_t line, string func, string message, any user_data); + + +static class options { + /** + * This struct contains all the startup options for Tox. You must $new to + * allocate an object of this type. + * + * WARNING: Although this struct happens to be visible in the API, it is + * effectively private. Do not allocate this yourself or access members + * directly, as it *will* break binary compatibility frequently. + * + * @deprecated The memory layout of this struct (size, alignment, and field + * order) is not part of the ABI. To remain compatible, prefer to use $new to + * allocate the object and accessor functions to set the members. The struct + * will become opaque (i.e. the definition will become private) in v0.2.0. + */ + struct this [get, set] { + /** + * The type of socket to create. + * + * If this is set to false, an IPv4 socket is created, which subsequently + * only allows IPv4 communication. + * If it is set to true, an IPv6 socket is created, allowing both IPv4 and + * IPv6 communication. + */ + bool ipv6_enabled; + + /** + * Enable the use of UDP communication when available. + * + * Setting this to false will force Tox to use TCP only. Communications will + * need to be relayed through a TCP relay node, potentially slowing them down. + * Disabling UDP support is necessary when using anonymous proxies or Tor. + */ + bool udp_enabled; + + /** + * Enable local network peer discovery. + * + * Disabling this will cause Tox to not look for peers on the local network. + */ + bool local_discovery_enabled; + + namespace proxy { + /** + * Pass communications through a proxy. + */ + PROXY_TYPE type; + + /** + * The IP address or DNS name of the proxy to be used. + * + * If used, this must be non-NULL and be a valid DNS name. The name must not + * exceed 255 characters, and be in a NUL-terminated C string format + * (255 chars + 1 NUL byte). + * + * This member is ignored (it can be NULL) if proxy_type is ${PROXY_TYPE.NONE}. + * + * The data pointed at by this member is owned by the user, so must + * outlive the options object. + */ + string host; + + /** + * The port to use to connect to the proxy server. + * + * Ports must be in the range (1, 65535). The value is ignored if + * proxy_type is ${PROXY_TYPE.NONE}. + */ + uint16_t port; + } + + /** + * The start port of the inclusive port range to attempt to use. + * + * If both start_port and end_port are 0, the default port range will be + * used: [33445, 33545]. + * + * If either start_port or end_port is 0 while the other is non-zero, the + * non-zero port will be the only port in the range. + * + * Having start_port > end_port will yield the same behavior as if start_port + * and end_port were swapped. + */ + uint16_t start_port; + + /** + * The end port of the inclusive port range to attempt to use. + */ + uint16_t end_port; + + /** + * The port to use for the TCP server (relay). If 0, the TCP server is + * disabled. + * + * Enabling it is not required for Tox to function properly. + * + * When enabled, your Tox instance can act as a TCP relay for other Tox + * instance. This leads to increased traffic, thus when writing a client + * it is recommended to enable TCP server only if the user has an option + * to disable it. + */ + uint16_t tcp_port; + + /** + * Enables or disables UDP hole-punching in toxcore. (Default: enabled). + */ + bool hole_punching_enabled; + + namespace savedata { + /** + * The type of savedata to load from. + */ + SAVEDATA_TYPE type; + + /** + * The savedata. + * + * The data pointed at by this member is owned by the user, so must + * outlive the options object. + */ + const uint8_t[length] data; + + /** + * The length of the savedata. + */ + size_t length; + } + + namespace log { + /** + * Logging callback for the new tox instance. + */ + log_cb *callback; + + /** + * User data pointer passed to the logging callback. + */ + any user_data; + } + } + + + /** + * Initialises a $this object with the default options. + * + * The result of this function is independent of the original options. All + * values will be overwritten, no values will be read (so it is permissible + * to pass an uninitialised object). + * + * If options is NULL, this function has no effect. + * + * @param options An options object to be filled with default options. + */ + void default(); + + + /** + * Allocates a new $this object and initialises it with the default + * options. This function can be used to preserve long term ABI compatibility by + * giving the responsibility of allocation and deallocation to the Tox library. + * + * Objects returned from this function must be freed using the $free + * function. + * + * @return A new $this object with default options or NULL on failure. + */ + static this new() { + /** + * The function failed to allocate enough memory for the options struct. + */ + MALLOC, + } + + + /** + * Releases all resources associated with an options objects. + * + * Passing a pointer that was not returned by $new results in + * undefined behaviour. + */ + void free(); +} + + +/******************************************************************************* + * + * :: Creation and destruction + * + ******************************************************************************/ + + +/** + * @brief Creates and initialises a new Tox instance with the options passed. + * + * This function will bring the instance into a valid state. Running the event + * loop with a new instance will operate correctly. + * + * If loading failed or succeeded only partially, the new or partially loaded + * instance is returned and an error code is set. + * + * @param options An options object as described above. If this parameter is + * NULL, the default options are used. + * + * @see $iterate for the event loop. + * + * @return A new Tox instance pointer on success or NULL on failure. + */ +static this new(const options_t *options) { + NULL, + /** + * The function was unable to allocate enough memory to store the internal + * structures for the Tox object. + */ + MALLOC, + /** + * The function was unable to bind to a port. This may mean that all ports + * have already been bound, e.g. by other Tox instances, or it may mean + * a permission error. You may be able to gather more information from errno. + */ + PORT_ALLOC, + + namespace PROXY { + /** + * proxy_type was invalid. + */ + BAD_TYPE, + /** + * proxy_type was valid but the proxy_host passed had an invalid format + * or was NULL. + */ + BAD_HOST, + /** + * proxy_type was valid, but the proxy_port was invalid. + */ + BAD_PORT, + /** + * The proxy address passed could not be resolved. + */ + NOT_FOUND, + } + + namespace LOAD { + /** + * The byte array to be loaded contained an encrypted save. + */ + ENCRYPTED, + /** + * The data format was invalid. This can happen when loading data that was + * saved by an older version of Tox, or when the data has been corrupted. + * When loading from badly formatted data, some data may have been loaded, + * and the rest is discarded. Passing an invalid length parameter also + * causes this error. + */ + BAD_FORMAT, + } +} + + +/** + * Releases all resources associated with the Tox instance and disconnects from + * the network. + * + * After calling this function, the Tox pointer becomes invalid. No other + * functions can be called, and the pointer value can no longer be read. + */ +void kill(); + + +uint8_t[size] savedata { + /** + * Calculates the number of bytes required to store the tox instance with + * $get. This function cannot fail. The result is always greater than 0. + * + * @see threading for concurrency implications. + */ + size(); + + /** + * Store all information associated with the tox instance to a byte array. + * + * @param savedata A memory region large enough to store the tox instance + * data. Call $size to find the number of bytes required. If this parameter + * is NULL, this function has no effect. + */ + get(); +} + + +/******************************************************************************* + * + * :: Connection lifecycle and event loop + * + ******************************************************************************/ + + +/** + * Sends a "get nodes" request to the given bootstrap node with IP, port, and + * public key to setup connections. + * + * This function will attempt to connect to the node using UDP. You must use + * this function even if ${options.this.udp_enabled} was set to false. + * + * @param address The hostname or IP address (IPv4 or IPv6) of the node. + * @param port The port on the host on which the bootstrap Tox instance is + * listening. + * @param public_key The long term public key of the bootstrap node + * ($PUBLIC_KEY_SIZE bytes). + * @return true on success. + */ +bool bootstrap(string address, uint16_t port, const uint8_t[PUBLIC_KEY_SIZE] public_key) { + NULL, + /** + * The address could not be resolved to an IP address, or the IP address + * passed was invalid. + */ + BAD_HOST, + /** + * The port passed was invalid. The valid port range is (1, 65535). + */ + BAD_PORT, +} + + +/** + * Adds additional host:port pair as TCP relay. + * + * This function can be used to initiate TCP connections to different ports on + * the same bootstrap node, or to add TCP relays without using them as + * bootstrap nodes. + * + * @param address The hostname or IP address (IPv4 or IPv6) of the TCP relay. + * @param port The port on the host on which the TCP relay is listening. + * @param public_key The long term public key of the TCP relay + * ($PUBLIC_KEY_SIZE bytes). + * @return true on success. + */ +bool add_tcp_relay(string address, uint16_t port, const uint8_t[PUBLIC_KEY_SIZE] public_key) + with error for bootstrap; + + +/** + * Protocols that can be used to connect to the network or friends. + */ +enum class CONNECTION { + /** + * There is no connection. This instance, or the friend the state change is + * about, is now offline. + */ + NONE, + /** + * A TCP connection has been established. For the own instance, this means it + * is connected through a TCP relay, only. For a friend, this means that the + * connection to that particular friend goes through a TCP relay. + */ + TCP, + /** + * A UDP connection has been established. For the own instance, this means it + * is able to send UDP packets to DHT nodes, but may still be connected to + * a TCP relay. For a friend, this means that the connection to that + * particular friend was built using direct UDP packets. + */ + UDP, +} + + +inline namespace self { + + CONNECTION connection_status { + /** + * Return whether we are connected to the DHT. The return value is equal to the + * last value received through the `${event connection_status}` callback. + */ + get(); + } + + + /** + * This event is triggered whenever there is a change in the DHT connection + * state. When disconnected, a client may choose to call $bootstrap again, to + * reconnect to the DHT. Note that this state may frequently change for short + * amounts of time. Clients should therefore not immediately bootstrap on + * receiving a disconnect. + * + * TODO(iphydf): how long should a client wait before bootstrapping again? + */ + event connection_status const { + /** + * @param connection_status Whether we are connected to the DHT. + */ + typedef void(CONNECTION connection_status); + } + +} + + +/** + * Return the time in milliseconds before $iterate() should be called again + * for optimal performance. + */ +const uint32_t iteration_interval(); + + +/** + * The main loop that needs to be run in intervals of $iteration_interval() + * milliseconds. + */ +void iterate(any user_data); + + +/******************************************************************************* + * + * :: Internal client information (Tox address/id) + * + ******************************************************************************/ + + +inline namespace self { + + uint8_t[ADDRESS_SIZE] address { + /** + * Writes the Tox friend address of the client to a byte array. The address is + * not in human-readable format. If a client wants to display the address, + * formatting is required. + * + * @param address A memory region of at least $ADDRESS_SIZE bytes. If this + * parameter is NULL, this function has no effect. + * @see $ADDRESS_SIZE for the address format. + */ + get(); + } + + + uint32_t nospam { + /** + * Set the 4-byte nospam part of the address. This value is expected in host + * byte order. I.e. 0x12345678 will form the bytes [12, 34, 56, 78] in the + * nospam part of the Tox friend address. + * + * @param nospam Any 32 bit unsigned integer. + */ + set(); + + /** + * Get the 4-byte nospam part of the address. This value is returned in host + * byte order. + */ + get(); + } + + + uint8_t[PUBLIC_KEY_SIZE] public_key { + /** + * Copy the Tox Public Key (long term) from the Tox object. + * + * @param public_key A memory region of at least $PUBLIC_KEY_SIZE bytes. If + * this parameter is NULL, this function has no effect. + */ + get(); + } + + + uint8_t[SECRET_KEY_SIZE] secret_key { + /** + * Copy the Tox Secret Key from the Tox object. + * + * @param secret_key A memory region of at least $SECRET_KEY_SIZE bytes. If + * this parameter is NULL, this function has no effect. + */ + get(); + } + +} + + +/******************************************************************************* + * + * :: User-visible client information (nickname/status) + * + ******************************************************************************/ + + +/** + * Common error codes for all functions that set a piece of user-visible + * client information. + */ +error for set_info { + NULL, + /** + * Information length exceeded maximum permissible size. + */ + TOO_LONG, +} + + +inline namespace self { + + uint8_t[length <= MAX_NAME_LENGTH] name { + /** + * Set the nickname for the Tox client. + * + * Nickname length cannot exceed $MAX_NAME_LENGTH. If length is 0, the name + * parameter is ignored (it can be NULL), and the nickname is set back to empty. + * + * @param name A byte array containing the new nickname. + * @param length The size of the name byte array. + * + * @return true on success. + */ + set() with error for set_info; + + /** + * Return the length of the current nickname as passed to $set. + * + * If no nickname was set before calling this function, the name is empty, + * and this function returns 0. + * + * @see threading for concurrency implications. + */ + size(); + + /** + * Write the nickname set by $set to a byte array. + * + * If no nickname was set before calling this function, the name is empty, + * and this function has no effect. + * + * Call $size to find out how much memory to allocate for + * the result. + * + * @param name A valid memory location large enough to hold the nickname. + * If this parameter is NULL, the function has no effect. + */ + get(); + } + + + uint8_t[length <= MAX_STATUS_MESSAGE_LENGTH] status_message { + /** + * Set the client's status message. + * + * Status message length cannot exceed $MAX_STATUS_MESSAGE_LENGTH. If + * length is 0, the status parameter is ignored (it can be NULL), and the + * user status is set back to empty. + */ + set() with error for set_info; + + /** + * Return the length of the current status message as passed to $set. + * + * If no status message was set before calling this function, the status + * is empty, and this function returns 0. + * + * @see threading for concurrency implications. + */ + size(); + + /** + * Write the status message set by $set to a byte array. + * + * If no status message was set before calling this function, the status is + * empty, and this function has no effect. + * + * Call $size to find out how much memory to allocate for + * the result. + * + * @param status_message A valid memory location large enough to hold the + * status message. If this parameter is NULL, the function has no effect. + */ + get(); + } + + + USER_STATUS status { + /** + * Set the client's user status. + * + * @param status One of the user statuses listed in the enumeration above. + */ + set(); + + /** + * Returns the client's user status. + */ + get(); + } + +} + + +/******************************************************************************* + * + * :: Friend list management + * + ******************************************************************************/ + + +namespace friend { + + /** + * Add a friend to the friend list and send a friend request. + * + * A friend request message must be at least 1 byte long and at most + * $MAX_FRIEND_REQUEST_LENGTH. + * + * Friend numbers are unique identifiers used in all functions that operate on + * friends. Once added, a friend number is stable for the lifetime of the Tox + * object. After saving the state and reloading it, the friend numbers may not + * be the same as before. Deleting a friend creates a gap in the friend number + * set, which is filled by the next adding of a friend. Any pattern in friend + * numbers should not be relied on. + * + * If more than INT32_MAX friends are added, this function causes undefined + * behaviour. + * + * @param address The address of the friend (returned by ${self.address.get} of + * the friend you wish to add) it must be $ADDRESS_SIZE bytes. + * @param message The message that will be sent along with the friend request. + * @param length The length of the data byte array. + * + * @return the friend number on success, UINT32_MAX on failure. + */ + uint32_t add( + const uint8_t[ADDRESS_SIZE] address, + const uint8_t[length <= MAX_FRIEND_REQUEST_LENGTH] message + ) { + NULL, + /** + * The length of the friend request message exceeded + * $MAX_FRIEND_REQUEST_LENGTH. + */ + TOO_LONG, + /** + * The friend request message was empty. This, and the TOO_LONG code will + * never be returned from $add_norequest. + */ + NO_MESSAGE, + /** + * The friend address belongs to the sending client. + */ + OWN_KEY, + /** + * A friend request has already been sent, or the address belongs to a friend + * that is already on the friend list. + */ + ALREADY_SENT, + /** + * The friend address checksum failed. + */ + BAD_CHECKSUM, + /** + * The friend was already there, but the nospam value was different. + */ + SET_NEW_NOSPAM, + /** + * A memory allocation failed when trying to increase the friend list size. + */ + MALLOC, + } + + + /** + * Add a friend without sending a friend request. + * + * This function is used to add a friend in response to a friend request. If the + * client receives a friend request, it can be reasonably sure that the other + * client added this client as a friend, eliminating the need for a friend + * request. + * + * This function is also useful in a situation where both instances are + * controlled by the same entity, so that this entity can perform the mutual + * friend adding. In this case, there is no need for a friend request, either. + * + * @param public_key A byte array of length $PUBLIC_KEY_SIZE containing the + * Public Key (not the Address) of the friend to add. + * + * @return the friend number on success, UINT32_MAX on failure. + * @see $add for a more detailed description of friend numbers. + */ + uint32_t add_norequest(const uint8_t[PUBLIC_KEY_SIZE] public_key) + with error for add; + + + /** + * Remove a friend from the friend list. + * + * This does not notify the friend of their deletion. After calling this + * function, this client will appear offline to the friend and no communication + * can occur between the two. + * + * @param friend_number Friend number for the friend to be deleted. + * + * @return true on success. + */ + bool delete(uint32_t friend_number) { + /** + * There was no friend with the given friend number. No friends were deleted. + */ + FRIEND_NOT_FOUND, + } + +} + + +/******************************************************************************* + * + * :: Friend list queries + * + ******************************************************************************/ + +namespace friend { + + /** + * Return the friend number associated with that Public Key. + * + * @return the friend number on success, UINT32_MAX on failure. + * @param public_key A byte array containing the Public Key. + */ + const uint32_t by_public_key(const uint8_t[PUBLIC_KEY_SIZE] public_key) { + NULL, + /** + * No friend with the given Public Key exists on the friend list. + */ + NOT_FOUND, + } + + + /** + * Checks if a friend with the given friend number exists and returns true if + * it does. + */ + const bool exists(uint32_t friend_number); + +} + +inline namespace self { + + uint32_t[size] friend_list { + /** + * Return the number of friends on the friend list. + * + * This function can be used to determine how much memory to allocate for + * $get. + */ + size(); + + + /** + * Copy a list of valid friend numbers into an array. + * + * Call $size to determine the number of elements to allocate. + * + * @param friend_list A memory region with enough space to hold the friend + * list. If this parameter is NULL, this function has no effect. + */ + get(); + } + +} + + + +namespace friend { + + uint8_t[PUBLIC_KEY_SIZE] public_key { + /** + * Copies the Public Key associated with a given friend number to a byte array. + * + * @param friend_number The friend number you want the Public Key of. + * @param public_key A memory region of at least $PUBLIC_KEY_SIZE bytes. If + * this parameter is NULL, this function has no effect. + * + * @return true on success. + */ + get(uint32_t friend_number) { + /** + * No friend with the given number exists on the friend list. + */ + FRIEND_NOT_FOUND, + } + } + +} + +namespace friend { + + uint64_t last_online { + /** + * Return a unix-time timestamp of the last time the friend associated with a given + * friend number was seen online. This function will return UINT64_MAX on error. + * + * @param friend_number The friend number you want to query. + */ + get(uint32_t friend_number) { + /** + * No friend with the given number exists on the friend list. + */ + FRIEND_NOT_FOUND, + } + } + +} + +/******************************************************************************* + * + * :: Friend-specific state queries (can also be received through callbacks) + * + ******************************************************************************/ + + +namespace friend { + + /** + * Common error codes for friend state query functions. + */ + error for query { + /** + * The pointer parameter for storing the query result (name, message) was + * NULL. Unlike the `_self_` variants of these functions, which have no effect + * when a parameter is NULL, these functions return an error in that case. + */ + NULL, + /** + * The friend_number did not designate a valid friend. + */ + FRIEND_NOT_FOUND, + } + + + uint8_t[length <= MAX_NAME_LENGTH] name { + /** + * Return the length of the friend's name. If the friend number is invalid, the + * return value is unspecified. + * + * The return value is equal to the `length` argument received by the last + * `${event name}` callback. + */ + size(uint32_t friend_number) + with error for query; + + /** + * Write the name of the friend designated by the given friend number to a byte + * array. + * + * Call $size to determine the allocation size for the `name` + * parameter. + * + * The data written to `name` is equal to the data received by the last + * `${event name}` callback. + * + * @param name A valid memory region large enough to store the friend's name. + * + * @return true on success. + */ + get(uint32_t friend_number) + with error for query; + } + + + /** + * This event is triggered when a friend changes their name. + */ + event name const { + /** + * @param friend_number The friend number of the friend whose name changed. + * @param name A byte array containing the same data as + * ${name.get} would write to its `name` parameter. + * @param length A value equal to the return value of + * ${name.size}. + */ + typedef void(uint32_t friend_number, const uint8_t[length <= MAX_NAME_LENGTH] name); + } + + + uint8_t[length <= MAX_STATUS_MESSAGE_LENGTH] status_message { + /** + * Return the length of the friend's status message. If the friend number is + * invalid, the return value is SIZE_MAX. + */ + size(uint32_t friend_number) + with error for query; + + /** + * Write the status message of the friend designated by the given friend number to a byte + * array. + * + * Call $size to determine the allocation size for the `status_name` + * parameter. + * + * The data written to `status_message` is equal to the data received by the last + * `${event status_message}` callback. + * + * @param status_message A valid memory region large enough to store the friend's status message. + */ + get(uint32_t friend_number) + with error for query; + } + + + /** + * This event is triggered when a friend changes their status message. + */ + event status_message const { + /** + * @param friend_number The friend number of the friend whose status message + * changed. + * @param message A byte array containing the same data as + * ${status_message.get} would write to its `status_message` parameter. + * @param length A value equal to the return value of + * ${status_message.size}. + */ + typedef void(uint32_t friend_number, const uint8_t[length <= MAX_STATUS_MESSAGE_LENGTH] message); + } + + + USER_STATUS status { + /** + * Return the friend's user status (away/busy/...). If the friend number is + * invalid, the return value is unspecified. + * + * The status returned is equal to the last status received through the + * `${event status}` callback. + */ + get(uint32_t friend_number) + with error for query; + } + + + /** + * This event is triggered when a friend changes their user status. + */ + event status const { + /** + * @param friend_number The friend number of the friend whose user status + * changed. + * @param status The new user status. + */ + typedef void(uint32_t friend_number, USER_STATUS status); + } + + + CONNECTION connection_status { + /** + * Check whether a friend is currently connected to this client. + * + * The result of this function is equal to the last value received by the + * `${event connection_status}` callback. + * + * @param friend_number The friend number for which to query the connection + * status. + * + * @return the friend's connection status as it was received through the + * `${event connection_status}` event. + */ + get(uint32_t friend_number) + with error for query; + } + + + /** + * This event is triggered when a friend goes offline after having been online, + * or when a friend goes online. + * + * This callback is not called when adding friends. It is assumed that when + * adding friends, their connection status is initially offline. + */ + event connection_status const { + /** + * @param friend_number The friend number of the friend whose connection status + * changed. + * @param connection_status The result of calling + * ${connection_status.get} on the passed friend_number. + */ + typedef void(uint32_t friend_number, CONNECTION connection_status); + } + + + bool typing { + /** + * Check whether a friend is currently typing a message. + * + * @param friend_number The friend number for which to query the typing status. + * + * @return true if the friend is typing. + * @return false if the friend is not typing, or the friend number was + * invalid. Inspect the error code to determine which case it is. + */ + get(uint32_t friend_number) + with error for query; + } + + + /** + * This event is triggered when a friend starts or stops typing. + */ + event typing const { + /** + * @param friend_number The friend number of the friend who started or stopped + * typing. + * @param is_typing The result of calling ${typing.get} on the passed + * friend_number. + */ + typedef void(uint32_t friend_number, bool is_typing); + } + +} + + +/******************************************************************************* + * + * :: Sending private messages + * + ******************************************************************************/ + + +inline namespace self { + + bool typing { + /** + * Set the client's typing status for a friend. + * + * The client is responsible for turning it on or off. + * + * @param friend_number The friend to which the client is typing a message. + * @param typing The typing status. True means the client is typing. + * + * @return true on success. + */ + set(uint32_t friend_number) { + /** + * The friend number did not designate a valid friend. + */ + FRIEND_NOT_FOUND, + } + } + +} + + +namespace friend { + + namespace send { + + /** + * Send a text chat message to an online friend. + * + * This function creates a chat message packet and pushes it into the send + * queue. + * + * The message length may not exceed $MAX_MESSAGE_LENGTH. Larger messages + * must be split by the client and sent as separate messages. Other clients can + * then reassemble the fragments. Messages may not be empty. + * + * The return value of this function is the message ID. If a read receipt is + * received, the triggered `${event read_receipt}` event will be passed this message ID. + * + * Message IDs are unique per friend. The first message ID is 0. Message IDs are + * incremented by 1 each time a message is sent. If UINT32_MAX messages were + * sent, the next message ID is 0. + * + * @param type Message type (normal, action, ...). + * @param friend_number The friend number of the friend to send the message to. + * @param message A non-NULL pointer to the first element of a byte array + * containing the message text. + * @param length Length of the message to be sent. + */ + uint32_t message(uint32_t friend_number, MESSAGE_TYPE type, + const uint8_t[length <= MAX_MESSAGE_LENGTH] message) { + NULL, + /** + * The friend number did not designate a valid friend. + */ + FRIEND_NOT_FOUND, + /** + * This client is currently not connected to the friend. + */ + FRIEND_NOT_CONNECTED, + /** + * An allocation error occurred while increasing the send queue size. + */ + SENDQ, + /** + * Message length exceeded $MAX_MESSAGE_LENGTH. + */ + TOO_LONG, + /** + * Attempted to send a zero-length message. + */ + EMPTY, + } + + } + + + /** + * This event is triggered when the friend receives the message sent with + * ${send.message} with the corresponding message ID. + */ + event read_receipt const { + /** + * @param friend_number The friend number of the friend who received the message. + * @param message_id The message ID as returned from ${send.message} + * corresponding to the message sent. + */ + typedef void(uint32_t friend_number, uint32_t message_id); + } + +} + + +/******************************************************************************* + * + * :: Receiving private messages and friend requests + * + ******************************************************************************/ + + +namespace friend { + + /** + * This event is triggered when a friend request is received. + */ + event request const { + /** + * @param public_key The Public Key of the user who sent the friend request. + * @param message The message they sent along with the request. + * @param length The size of the message byte array. + */ + typedef void(const uint8_t[PUBLIC_KEY_SIZE] public_key, + const uint8_t[length <= MAX_MESSAGE_LENGTH] message); + } + + + /** + * This event is triggered when a message from a friend is received. + */ + event message const { + /** + * @param friend_number The friend number of the friend who sent the message. + * @param message The message data they sent. + * @param length The size of the message byte array. + */ + typedef void(uint32_t friend_number, MESSAGE_TYPE type, + const uint8_t[length <= MAX_MESSAGE_LENGTH] message); + } + +} + + +/******************************************************************************* + * + * :: File transmission: common between sending and receiving + * + ******************************************************************************/ + + +/** + * Generates a cryptographic hash of the given data. + * + * This function may be used by clients for any purpose, but is provided + * primarily for validating cached avatars. This use is highly recommended to + * avoid unnecessary avatar updates. + * + * If hash is NULL or data is NULL while length is not 0 the function returns false, + * otherwise it returns true. + * + * This function is a wrapper to internal message-digest functions. + * + * @param hash A valid memory location the hash data. It must be at least + * $HASH_LENGTH bytes in size. + * @param data Data to be hashed or NULL. + * @param length Size of the data array or 0. + * + * @return true if hash was not NULL. + */ +static bool hash(uint8_t[HASH_LENGTH] hash, const uint8_t[length] data); + + +namespace file { + + enum KIND { + /** + * Arbitrary file data. Clients can choose to handle it based on the file name + * or magic or any other way they choose. + */ + DATA, + /** + * Avatar file_id. This consists of $hash(image). + * Avatar data. This consists of the image data. + * + * Avatars can be sent at any time the client wishes. Generally, a client will + * send the avatar to a friend when that friend comes online, and to all + * friends when the avatar changed. A client can save some traffic by + * remembering which friend received the updated avatar already and only send + * it if the friend has an out of date avatar. + * + * Clients who receive avatar send requests can reject it (by sending + * ${CONTROL.CANCEL} before any other controls), or accept it (by + * sending ${CONTROL.RESUME}). The file_id of length $HASH_LENGTH bytes + * (same length as $FILE_ID_LENGTH) will contain the hash. A client can compare + * this hash with a saved hash and send ${CONTROL.CANCEL} to terminate the avatar + * transfer if it matches. + * + * When file_size is set to 0 in the transfer request it means that the client + * has no avatar. + */ + AVATAR, + } + + + enum class CONTROL { + /** + * Sent by the receiving side to accept a file send request. Also sent after a + * $PAUSE command to continue sending or receiving. + */ + RESUME, + /** + * Sent by clients to pause the file transfer. The initial state of a file + * transfer is always paused on the receiving side and running on the sending + * side. If both the sending and receiving side pause the transfer, then both + * need to send $RESUME for the transfer to resume. + */ + PAUSE, + /** + * Sent by the receiving side to reject a file send request before any other + * commands are sent. Also sent by either side to terminate a file transfer. + */ + CANCEL, + } + + + /** + * Sends a file control command to a friend for a given file transfer. + * + * @param friend_number The friend number of the friend the file is being + * transferred to or received from. + * @param file_number The friend-specific identifier for the file transfer. + * @param control The control command to send. + * + * @return true on success. + */ + bool control(uint32_t friend_number, uint32_t file_number, CONTROL control) { + /** + * The friend_number passed did not designate a valid friend. + */ + FRIEND_NOT_FOUND, + /** + * This client is currently not connected to the friend. + */ + FRIEND_NOT_CONNECTED, + /** + * No file transfer with the given file number was found for the given friend. + */ + NOT_FOUND, + /** + * A RESUME control was sent, but the file transfer is running normally. + */ + NOT_PAUSED, + /** + * A RESUME control was sent, but the file transfer was paused by the other + * party. Only the party that paused the transfer can resume it. + */ + DENIED, + /** + * A PAUSE control was sent, but the file transfer was already paused. + */ + ALREADY_PAUSED, + /** + * Packet queue is full. + */ + SENDQ, + } + + + /** + * This event is triggered when a file control command is received from a + * friend. + */ + event recv_control const { + /** + * When receiving ${CONTROL.CANCEL}, the client should release the + * resources associated with the file number and consider the transfer failed. + * + * @param friend_number The friend number of the friend who is sending the file. + * @param file_number The friend-specific file number the data received is + * associated with. + * @param control The file control command received. + */ + typedef void(uint32_t friend_number, uint32_t file_number, CONTROL control); + } + + /** + * Sends a file seek control command to a friend for a given file transfer. + * + * This function can only be called to resume a file transfer right before + * ${CONTROL.RESUME} is sent. + * + * @param friend_number The friend number of the friend the file is being + * received from. + * @param file_number The friend-specific identifier for the file transfer. + * @param position The position that the file should be seeked to. + */ + bool seek(uint32_t friend_number, uint32_t file_number, uint64_t position) { + /** + * The friend_number passed did not designate a valid friend. + */ + FRIEND_NOT_FOUND, + /** + * This client is currently not connected to the friend. + */ + FRIEND_NOT_CONNECTED, + /** + * No file transfer with the given file number was found for the given friend. + */ + NOT_FOUND, + /** + * File was not in a state where it could be seeked. + */ + DENIED, + /** + * Seek position was invalid + */ + INVALID_POSITION, + /** + * Packet queue is full. + */ + SENDQ, + } + + + error for get { + NULL, + /** + * The friend_number passed did not designate a valid friend. + */ + FRIEND_NOT_FOUND, + /** + * No file transfer with the given file number was found for the given friend. + */ + NOT_FOUND, + } + + uint8_t[FILE_ID_LENGTH] file_id { + /** + * Copy the file id associated to the file transfer to a byte array. + * + * @param friend_number The friend number of the friend the file is being + * transferred to or received from. + * @param file_number The friend-specific identifier for the file transfer. + * @param file_id A memory region of at least $FILE_ID_LENGTH bytes. If + * this parameter is NULL, this function has no effect. + * + * @return true on success. + */ + get(uint32_t friend_number, uint32_t file_number) + with error for get; + } + +} + + +/******************************************************************************* + * + * :: File transmission: sending + * + ******************************************************************************/ + + +namespace file { + + /** + * Send a file transmission request. + * + * Maximum filename length is $MAX_FILENAME_LENGTH bytes. The filename + * should generally just be a file name, not a path with directory names. + * + * If a non-UINT64_MAX file size is provided, it can be used by both sides to + * determine the sending progress. File size can be set to UINT64_MAX for streaming + * data of unknown size. + * + * File transmission occurs in chunks, which are requested through the + * `${event chunk_request}` event. + * + * When a friend goes offline, all file transfers associated with the friend are + * purged from core. + * + * If the file contents change during a transfer, the behaviour is unspecified + * in general. What will actually happen depends on the mode in which the file + * was modified and how the client determines the file size. + * + * - If the file size was increased + * - and sending mode was streaming (file_size = UINT64_MAX), the behaviour + * will be as expected. + * - and sending mode was file (file_size != UINT64_MAX), the + * ${event chunk_request} callback will receive length = 0 when Core thinks + * the file transfer has finished. If the client remembers the file size as + * it was when sending the request, it will terminate the transfer normally. + * If the client re-reads the size, it will think the friend cancelled the + * transfer. + * - If the file size was decreased + * - and sending mode was streaming, the behaviour is as expected. + * - and sending mode was file, the callback will return 0 at the new + * (earlier) end-of-file, signalling to the friend that the transfer was + * cancelled. + * - If the file contents were modified + * - at a position before the current read, the two files (local and remote) + * will differ after the transfer terminates. + * - at a position after the current read, the file transfer will succeed as + * expected. + * - In either case, both sides will regard the transfer as complete and + * successful. + * + * @param friend_number The friend number of the friend the file send request + * should be sent to. + * @param kind The meaning of the file to be sent. + * @param file_size Size in bytes of the file the client wants to send, UINT64_MAX if + * unknown or streaming. + * @param file_id A file identifier of length $FILE_ID_LENGTH that can be used to + * uniquely identify file transfers across core restarts. If NULL, a random one will + * be generated by core. It can then be obtained by using ${file_id.get}(). + * @param filename Name of the file. Does not need to be the actual name. This + * name will be sent along with the file send request. + * @param filename_length Size in bytes of the filename. + * + * @return A file number used as an identifier in subsequent callbacks. This + * number is per friend. File numbers are reused after a transfer terminates. + * On failure, this function returns UINT32_MAX. Any pattern in file numbers + * should not be relied on. + */ + uint32_t send(uint32_t friend_number, uint32_t kind, uint64_t file_size, + const uint8_t[FILE_ID_LENGTH] file_id, + const uint8_t[filename_length <= MAX_FILENAME_LENGTH] filename) { + NULL, + /** + * The friend_number passed did not designate a valid friend. + */ + FRIEND_NOT_FOUND, + /** + * This client is currently not connected to the friend. + */ + FRIEND_NOT_CONNECTED, + /** + * Filename length exceeded $MAX_FILENAME_LENGTH bytes. + */ + NAME_TOO_LONG, + /** + * Too many ongoing transfers. The maximum number of concurrent file transfers + * is 256 per friend per direction (sending and receiving). + */ + TOO_MANY, + } + + + /** + * Send a chunk of file data to a friend. + * + * This function is called in response to the `${event chunk_request}` callback. The + * length parameter should be equal to the one received though the callback. + * If it is zero, the transfer is assumed complete. For files with known size, + * Core will know that the transfer is complete after the last byte has been + * received, so it is not necessary (though not harmful) to send a zero-length + * chunk to terminate. For streams, core will know that the transfer is finished + * if a chunk with length less than the length requested in the callback is sent. + * + * @param friend_number The friend number of the receiving friend for this file. + * @param file_number The file transfer identifier returned by tox_file_send. + * @param position The file or stream position from which to continue reading. + * @return true on success. + */ + bool send_chunk(uint32_t friend_number, uint32_t file_number, uint64_t position, const uint8_t[length] data) { + /** + * The length parameter was non-zero, but data was NULL. + */ + NULL, + /** + * The friend_number passed did not designate a valid friend. + */ + FRIEND_NOT_FOUND, + /** + * This client is currently not connected to the friend. + */ + FRIEND_NOT_CONNECTED, + /** + * No file transfer with the given file number was found for the given friend. + */ + NOT_FOUND, + /** + * File transfer was found but isn't in a transferring state: (paused, done, + * broken, etc...) (happens only when not called from the request chunk callback). + */ + NOT_TRANSFERRING, + /** + * Attempted to send more or less data than requested. The requested data size is + * adjusted according to maximum transmission unit and the expected end of + * the file. Trying to send less or more than requested will return this error. + */ + INVALID_LENGTH, + /** + * Packet queue is full. + */ + SENDQ, + /** + * Position parameter was wrong. + */ + WRONG_POSITION, + } + + + /** + * This event is triggered when Core is ready to send more file data. + */ + event chunk_request const { + /** + * If the length parameter is 0, the file transfer is finished, and the client's + * resources associated with the file number should be released. After a call + * with zero length, the file number can be reused for future file transfers. + * + * If the requested position is not equal to the client's idea of the current + * file or stream position, it will need to seek. In case of read-once streams, + * the client should keep the last read chunk so that a seek back can be + * supported. A seek-back only ever needs to read from the last requested chunk. + * This happens when a chunk was requested, but the send failed. A seek-back + * request can occur an arbitrary number of times for any given chunk. + * + * In response to receiving this callback, the client should call the function + * `$send_chunk` with the requested chunk. If the number of bytes sent + * through that function is zero, the file transfer is assumed complete. A + * client must send the full length of data requested with this callback. + * + * @param friend_number The friend number of the receiving friend for this file. + * @param file_number The file transfer identifier returned by $send. + * @param position The file or stream position from which to continue reading. + * @param length The number of bytes requested for the current chunk. + */ + typedef void(uint32_t friend_number, uint32_t file_number, uint64_t position, size_t length); + } + +} + + +/******************************************************************************* + * + * :: File transmission: receiving + * + ******************************************************************************/ + + +namespace file { + + /** + * This event is triggered when a file transfer request is received. + */ + event recv const { + /** + * The client should acquire resources to be associated with the file transfer. + * Incoming file transfers start in the PAUSED state. After this callback + * returns, a transfer can be rejected by sending a ${CONTROL.CANCEL} + * control command before any other control commands. It can be accepted by + * sending ${CONTROL.RESUME}. + * + * @param friend_number The friend number of the friend who is sending the file + * transfer request. + * @param file_number The friend-specific file number the data received is + * associated with. + * @param kind The meaning of the file to be sent. + * @param file_size Size in bytes of the file the client wants to send, + * UINT64_MAX if unknown or streaming. + * @param filename Name of the file. Does not need to be the actual name. This + * name will be sent along with the file send request. + * @param filename_length Size in bytes of the filename. + */ + typedef void(uint32_t friend_number, uint32_t file_number, uint32_t kind, + uint64_t file_size, const uint8_t[filename_length <= MAX_FILENAME_LENGTH] filename); + } + + + /** + * This event is first triggered when a file transfer request is received, and + * subsequently when a chunk of file data for an accepted request was received. + */ + event recv_chunk const { + /** + * When length is 0, the transfer is finished and the client should release the + * resources it acquired for the transfer. After a call with length = 0, the + * file number can be reused for new file transfers. + * + * If position is equal to file_size (received in the file_receive callback) + * when the transfer finishes, the file was received completely. Otherwise, if + * file_size was UINT64_MAX, streaming ended successfully when length is 0. + * + * @param friend_number The friend number of the friend who is sending the file. + * @param file_number The friend-specific file number the data received is + * associated with. + * @param position The file position of the first byte in data. + * @param data A byte array containing the received chunk. + * @param length The length of the received chunk. + */ + typedef void(uint32_t friend_number, uint32_t file_number, uint64_t position, + const uint8_t[length] data); + } + +} + + +/******************************************************************************* + * + * :: Conference management + * + ******************************************************************************/ + +namespace conference { + + /** + * Conference types for the ${event invite} event. + */ + enum class TYPE { + /** + * Text-only conferences that must be accepted with the $join function. + */ + TEXT, + /** + * Video conference. The function to accept these is in toxav. + */ + AV, + } + + + /** + * This event is triggered when the client is invited to join a conference. + */ + event invite const { + /** + * The invitation will remain valid until the inviting friend goes offline + * or exits the conference. + * + * @param friend_number The friend who invited us. + * @param type The conference type (text only or audio/video). + * @param cookie A piece of data of variable length required to join the + * conference. + * @param length The length of the cookie. + */ + typedef void(uint32_t friend_number, TYPE type, const uint8_t[length] cookie); + } + + + /** + * This event is triggered when the client receives a conference message. + */ + event message const { + /** + * @param conference_number The conference number of the conference the message is intended for. + * @param peer_number The ID of the peer who sent the message. + * @param type The type of message (normal, action, ...). + * @param message The message data. + * @param length The length of the message. + */ + typedef void(uint32_t conference_number, uint32_t peer_number, MESSAGE_TYPE type, + const uint8_t[length] message); + } + + + /** + * This event is triggered when a peer changes the conference title. + * + * If peer_number == UINT32_MAX, then author is unknown (e.g. initial joining the conference). + */ + event title const { + /** + * @param conference_number The conference number of the conference the title change is intended for. + * @param peer_number The ID of the peer who changed the title. + * @param title The title data. + * @param length The title length. + */ + typedef void(uint32_t conference_number, uint32_t peer_number, const uint8_t[length] title); + } + + /** + * Peer list state change types. + */ + enum class STATE_CHANGE { + /** + * A peer has joined the conference. + */ + PEER_JOIN, + /** + * A peer has exited the conference. + */ + PEER_EXIT, + /** + * A peer has changed their name. + */ + PEER_NAME_CHANGE, + } + + /** + * This event is triggered when the peer list changes (name change, peer join, peer exit). + */ + event namelist_change const { + /** + * @param conference_number The conference number of the conference the title change is intended for. + * @param peer_number The ID of the peer who changed the title. + * @param change The type of change (one of $STATE_CHANGE). + */ + typedef void(uint32_t conference_number, uint32_t peer_number, STATE_CHANGE change); + } + + + /** + * Creates a new conference. + * + * This function creates a new text conference. + * + * @return conference number on success, or UINT32_MAX on failure. + */ + uint32_t new() { + /** + * The conference instance failed to initialize. + */ + INIT, + } + + /** + * This function deletes a conference. + * + * @param conference_number The conference number of the conference to be deleted. + * + * @return true on success. + */ + bool delete(uint32_t conference_number) { + /** + * The conference number passed did not designate a valid conference. + */ + CONFERENCE_NOT_FOUND, + } + + + namespace peer { + + /** + * Error codes for peer info queries. + */ + error for query { + /** + * The conference number passed did not designate a valid conference. + */ + CONFERENCE_NOT_FOUND, + /** + * The peer number passed did not designate a valid peer. + */ + PEER_NOT_FOUND, + /** + * The client is not connected to the conference. + */ + NO_CONNECTION, + } + + /** + * Return the number of peers in the conference. Return value is unspecified on failure. + */ + const uint32_t count(uint32_t conference_number) + with error for query; + + uint8_t[size] name { + + /** + * Return the length of the peer's name. Return value is unspecified on failure. + */ + size(uint32_t conference_number, uint32_t peer_number) + with error for query; + + /** + * Copy the name of peer_number who is in conference_number to name. + * name must be at least $MAX_NAME_LENGTH long. + * + * @return true on success. + */ + get(uint32_t conference_number, uint32_t peer_number) + with error for query; + } + + /** + * Copy the public key of peer_number who is in conference_number to public_key. + * public_key must be $PUBLIC_KEY_SIZE long. + * + * @return true on success. + */ + uint8_t[PUBLIC_KEY_SIZE] public_key { + get(uint32_t conference_number, uint32_t peer_number) + with error for query; + } + + /** + * Return true if passed peer_number corresponds to our own. + */ + const bool number_is_ours(uint32_t conference_number, uint32_t peer_number) + with error for query; + + } + + + /** + * Invites a friend to a conference. + * + * @param friend_number The friend number of the friend we want to invite. + * @param conference_number The conference number of the conference we want to invite the friend to. + * + * @return true on success. + */ + bool invite(uint32_t friend_number, uint32_t conference_number) { + /** + * The conference number passed did not designate a valid conference. + */ + CONFERENCE_NOT_FOUND, + /** + * The invite packet failed to send. + */ + FAIL_SEND, + } + + + /** + * Joins a conference that the client has been invited to. + * + * @param friend_number The friend number of the friend who sent the invite. + * @param cookie Received via the `${event invite}` event. + * @param length The size of cookie. + * + * @return conference number on success, UINT32_MAX on failure. + */ + uint32_t join(uint32_t friend_number, const uint8_t[length] cookie) { + /** + * The cookie passed has an invalid length. + */ + INVALID_LENGTH, + /** + * The conference is not the expected type. This indicates an invalid cookie. + */ + WRONG_TYPE, + /** + * The friend number passed does not designate a valid friend. + */ + FRIEND_NOT_FOUND, + /** + * Client is already in this conference. + */ + DUPLICATE, + /** + * Conference instance failed to initialize. + */ + INIT_FAIL, + /** + * The join packet failed to send. + */ + FAIL_SEND, + } + + + namespace send { + + /** + * Send a text chat message to the conference. + * + * This function creates a conference message packet and pushes it into the send + * queue. + * + * The message length may not exceed $MAX_MESSAGE_LENGTH. Larger messages + * must be split by the client and sent as separate messages. Other clients can + * then reassemble the fragments. + * + * @param conference_number The conference number of the conference the message is intended for. + * @param type Message type (normal, action, ...). + * @param message A non-NULL pointer to the first element of a byte array + * containing the message text. + * @param length Length of the message to be sent. + * + * @return true on success. + */ + bool message(uint32_t conference_number, MESSAGE_TYPE type, const uint8_t[length] message) { + /** + * The conference number passed did not designate a valid conference. + */ + CONFERENCE_NOT_FOUND, + /** + * The message is too long. + */ + TOO_LONG, + /** + * The client is not connected to the conference. + */ + NO_CONNECTION, + /** + * The message packet failed to send. + */ + FAIL_SEND, + } + } + + error for title { + /** + * The conference number passed did not designate a valid conference. + */ + CONFERENCE_NOT_FOUND, + /** + * The title is too long or empty. + */ + INVALID_LENGTH, + /** + * The title packet failed to send. + */ + FAIL_SEND, + } + + uint8_t[length <= MAX_NAME_LENGTH] title { + + /** + * Return the length of the conference title. Return value is unspecified on failure. + * + * The return value is equal to the `length` argument received by the last + * `${event title}` callback. + */ + size(uint32_t conference_number) + with error for title; + + /** + * Write the title designated by the given conference number to a byte array. + * + * Call $size to determine the allocation size for the `title` parameter. + * + * The data written to `title` is equal to the data received by the last + * `${event title}` callback. + * + * @param title A valid memory region large enough to store the title. + * If this parameter is NULL, this function has no effect. + * + * @return true on success. + */ + get(uint32_t conference_number) + with error for title; + + /** + * Set the conference title and broadcast it to the rest of the conference. + * + * Title length cannot be longer than $MAX_NAME_LENGTH. + * + * @return true on success. + */ + set(uint32_t conference_number) + with error for title; + } + + + uint32_t[size] chatlist { + /** + * Return the number of conferences in the Tox instance. + * This should be used to determine how much memory to allocate for `$get`. + */ + size(); + + /** + * Copy a list of valid conference IDs into the array chatlist. Determine how much space + * to allocate for the array with the `$size` function. + */ + get(); + } + + + /** + * Returns the type of conference ($TYPE) that conference_number is. Return value is + * unspecified on failure. + */ + TYPE type { + get(uint32_t conference_number) { + /** + * The conference number passed did not designate a valid conference. + */ + CONFERENCE_NOT_FOUND, + } + } + +} + + +/******************************************************************************* + * + * :: Low-level custom packet sending and receiving + * + ******************************************************************************/ + + +namespace friend { + + inline namespace send { + + error for custom_packet { + NULL, + /** + * The friend number did not designate a valid friend. + */ + FRIEND_NOT_FOUND, + /** + * This client is currently not connected to the friend. + */ + FRIEND_NOT_CONNECTED, + /** + * The first byte of data was not in the specified range for the packet type. + * This range is 200-254 for lossy, and 160-191 for lossless packets. + */ + INVALID, + /** + * Attempted to send an empty packet. + */ + EMPTY, + /** + * Packet data length exceeded $MAX_CUSTOM_PACKET_SIZE. + */ + TOO_LONG, + /** + * Packet queue is full. + */ + SENDQ, + } + + /** + * Send a custom lossy packet to a friend. + * + * The first byte of data must be in the range 200-254. Maximum length of a + * custom packet is $MAX_CUSTOM_PACKET_SIZE. + * + * Lossy packets behave like UDP packets, meaning they might never reach the + * other side or might arrive more than once (if someone is messing with the + * connection) or might arrive in the wrong order. + * + * Unless latency is an issue, it is recommended that you use lossless custom + * packets instead. + * + * @param friend_number The friend number of the friend this lossy packet + * should be sent to. + * @param data A byte array containing the packet data. + * @param length The length of the packet data byte array. + * + * @return true on success. + */ + bool lossy_packet(uint32_t friend_number, const uint8_t[length <= MAX_CUSTOM_PACKET_SIZE] data) + with error for custom_packet; + + + /** + * Send a custom lossless packet to a friend. + * + * The first byte of data must be in the range 160-191. Maximum length of a + * custom packet is $MAX_CUSTOM_PACKET_SIZE. + * + * Lossless packet behaviour is comparable to TCP (reliability, arrive in order) + * but with packets instead of a stream. + * + * @param friend_number The friend number of the friend this lossless packet + * should be sent to. + * @param data A byte array containing the packet data. + * @param length The length of the packet data byte array. + * + * @return true on success. + */ + bool lossless_packet(uint32_t friend_number, const uint8_t[length <= MAX_CUSTOM_PACKET_SIZE] data) + with error for custom_packet; + + } + + + event lossy_packet const { + /** + * @param friend_number The friend number of the friend who sent a lossy packet. + * @param data A byte array containing the received packet data. + * @param length The length of the packet data byte array. + */ + typedef void(uint32_t friend_number, const uint8_t[length <= MAX_CUSTOM_PACKET_SIZE] data); + } + + + event lossless_packet const { + /** + * @param friend_number The friend number of the friend who sent the packet. + * @param data A byte array containing the received packet data. + * @param length The length of the packet data byte array. + */ + typedef void(uint32_t friend_number, const uint8_t[length <= MAX_CUSTOM_PACKET_SIZE] data); + } + +} + + + +/******************************************************************************* + * + * :: Low-level network information + * + ******************************************************************************/ + + +inline namespace self { + + uint8_t[PUBLIC_KEY_SIZE] dht_id { + /** + * Writes the temporary DHT public key of this instance to a byte array. + * + * This can be used in combination with an externally accessible IP address and + * the bound port (from ${udp_port.get}) to run a temporary bootstrap node. + * + * Be aware that every time a new instance is created, the DHT public key + * changes, meaning this cannot be used to run a permanent bootstrap node. + * + * @param dht_id A memory region of at least $PUBLIC_KEY_SIZE bytes. If this + * parameter is NULL, this function has no effect. + */ + get(); + } + + + error for get_port { + /** + * The instance was not bound to any port. + */ + NOT_BOUND, + } + + + uint16_t udp_port { + /** + * Return the UDP port this Tox instance is bound to. + */ + get() with error for get_port; + } + + + uint16_t tcp_port { + /** + * Return the TCP port this Tox instance is bound to. This is only relevant if + * the instance is acting as a TCP relay. + */ + get() with error for get_port; + } + +} + +} // class tox + +%{ +#ifdef __cplusplus +} +#endif + +#endif +%} diff --git a/protocols/Tox/libtox/src/toxcore/tox.c b/protocols/Tox/libtox/src/toxcore/tox.c new file mode 100644 index 0000000000..12f3762083 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/tox.c @@ -0,0 +1,1551 @@ +/* + * The Tox public API. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define _XOPEN_SOURCE 600 + +#define TOX_DEFINED +typedef struct Messenger Tox; +#include "tox.h" + +#include "Messenger.h" +#include "group.h" +#include "logger.h" + +#include "../toxencryptsave/defines.h" + +#define SET_ERROR_PARAMETER(param, x) {if(param) {*param = x;}} + +#if TOX_HASH_LENGTH != CRYPTO_SHA256_SIZE +#error TOX_HASH_LENGTH is assumed to be equal to CRYPTO_SHA256_SIZE +#endif + +#if FILE_ID_LENGTH != CRYPTO_SYMMETRIC_KEY_SIZE +#error FILE_ID_LENGTH is assumed to be equal to CRYPTO_SYMMETRIC_KEY_SIZE +#endif + +#if TOX_FILE_ID_LENGTH != CRYPTO_SYMMETRIC_KEY_SIZE +#error TOX_FILE_ID_LENGTH is assumed to be equal to CRYPTO_SYMMETRIC_KEY_SIZE +#endif + +#if TOX_FILE_ID_LENGTH != TOX_HASH_LENGTH +#error TOX_FILE_ID_LENGTH is assumed to be equal to TOX_HASH_LENGTH +#endif + +#if TOX_PUBLIC_KEY_SIZE != CRYPTO_PUBLIC_KEY_SIZE +#error TOX_PUBLIC_KEY_SIZE is assumed to be equal to CRYPTO_PUBLIC_KEY_SIZE +#endif + +#if TOX_SECRET_KEY_SIZE != CRYPTO_SECRET_KEY_SIZE +#error TOX_SECRET_KEY_SIZE is assumed to be equal to CRYPTO_SECRET_KEY_SIZE +#endif + +#if TOX_MAX_NAME_LENGTH != MAX_NAME_LENGTH +#error TOX_MAX_NAME_LENGTH is assumed to be equal to MAX_NAME_LENGTH +#endif + +#if TOX_MAX_STATUS_MESSAGE_LENGTH != MAX_STATUSMESSAGE_LENGTH +#error TOX_MAX_STATUS_MESSAGE_LENGTH is assumed to be equal to MAX_STATUSMESSAGE_LENGTH +#endif + + +bool tox_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch) +{ + return TOX_VERSION_IS_API_COMPATIBLE(major, minor, patch); +} + + +Tox *tox_new(const struct Tox_Options *options, TOX_ERR_NEW *error) +{ + Messenger_Options m_options = {0}; + + bool load_savedata_sk = 0, load_savedata_tox = 0; + + if (options == NULL) { + m_options.ipv6enabled = TOX_ENABLE_IPV6_DEFAULT; + } else { + if (tox_options_get_savedata_type(options) != TOX_SAVEDATA_TYPE_NONE) { + if (tox_options_get_savedata_data(options) == NULL || tox_options_get_savedata_length(options) == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT); + return NULL; + } + } + + if (tox_options_get_savedata_type(options) == TOX_SAVEDATA_TYPE_SECRET_KEY) { + if (tox_options_get_savedata_length(options) != TOX_SECRET_KEY_SIZE) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT); + return NULL; + } + + load_savedata_sk = 1; + } else if (tox_options_get_savedata_type(options) == TOX_SAVEDATA_TYPE_TOX_SAVE) { + if (tox_options_get_savedata_length(options) < TOX_ENC_SAVE_MAGIC_LENGTH) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT); + return NULL; + } + + if (crypto_memcmp(tox_options_get_savedata_data(options), TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_ENCRYPTED); + return NULL; + } + + load_savedata_tox = 1; + } + + m_options.ipv6enabled = tox_options_get_ipv6_enabled(options); + m_options.udp_disabled = !tox_options_get_udp_enabled(options); + m_options.port_range[0] = tox_options_get_start_port(options); + m_options.port_range[1] = tox_options_get_end_port(options); + m_options.tcp_server_port = tox_options_get_tcp_port(options); + m_options.hole_punching_enabled = tox_options_get_hole_punching_enabled(options); + m_options.local_discovery_enabled = tox_options_get_local_discovery_enabled(options); + + m_options.log_callback = (logger_cb *)tox_options_get_log_callback(options); + m_options.log_user_data = tox_options_get_log_user_data(options); + + switch (tox_options_get_proxy_type(options)) { + case TOX_PROXY_TYPE_HTTP: + m_options.proxy_info.proxy_type = TCP_PROXY_HTTP; + break; + + case TOX_PROXY_TYPE_SOCKS5: + m_options.proxy_info.proxy_type = TCP_PROXY_SOCKS5; + break; + + case TOX_PROXY_TYPE_NONE: + m_options.proxy_info.proxy_type = TCP_PROXY_NONE; + break; + + default: + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_TYPE); + return NULL; + } + + if (m_options.proxy_info.proxy_type != TCP_PROXY_NONE) { + if (tox_options_get_proxy_port(options) == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_PORT); + return NULL; + } + + ip_init(&m_options.proxy_info.ip_port.ip, m_options.ipv6enabled); + + if (m_options.ipv6enabled) { + m_options.proxy_info.ip_port.ip.family = TOX_AF_UNSPEC; + } + + if (!addr_resolve_or_parse_ip(tox_options_get_proxy_host(options), &m_options.proxy_info.ip_port.ip, NULL)) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_HOST); + // TODO(irungentoo): TOX_ERR_NEW_PROXY_NOT_FOUND if domain. + return NULL; + } + + m_options.proxy_info.ip_port.port = net_htons(tox_options_get_proxy_port(options)); + } + } + + unsigned int m_error; + Messenger *m = new_messenger(&m_options, &m_error); + + if (!new_groupchats(m)) { + kill_messenger(m); + + if (m_error == MESSENGER_ERROR_PORT) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PORT_ALLOC); + } else if (m_error == MESSENGER_ERROR_TCP_SERVER) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PORT_ALLOC); + } else { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_MALLOC); + } + + return NULL; + } + + if (load_savedata_tox + && messenger_load(m, tox_options_get_savedata_data(options), tox_options_get_savedata_length(options)) == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT); + } else if (load_savedata_sk) { + load_secret_key(m->net_crypto, tox_options_get_savedata_data(options)); + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_OK); + } else { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_OK); + } + + return m; +} + +void tox_kill(Tox *tox) +{ + if (tox == NULL) { + return; + } + + Messenger *m = tox; + kill_groupchats((Group_Chats *)m->conferences_object); + kill_messenger(m); +} + +size_t tox_get_savedata_size(const Tox *tox) +{ + const Messenger *m = tox; + return messenger_size(m); +} + +void tox_get_savedata(const Tox *tox, uint8_t *savedata) +{ + if (savedata) { + const Messenger *m = tox; + messenger_save(m, savedata); + } +} + +bool tox_bootstrap(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key, TOX_ERR_BOOTSTRAP *error) +{ + if (!address || !public_key) { + SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_NULL); + return 0; + } + + if (port == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_PORT); + return 0; + } + + IP_Port *root; + + int32_t count = net_getipport(address, &root, TOX_SOCK_DGRAM); + + if (count == -1) { + net_freeipport(root); + SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST); + return 0; + } + + unsigned int i; + + for (i = 0; i < count; i++) { + root[i].port = net_htons(port); + + Messenger *m = tox; + onion_add_bs_path_node(m->onion_c, root[i], public_key); + DHT_bootstrap(m->dht, root[i], public_key); + } + + net_freeipport(root); + + if (count) { + SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_OK); + return 1; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST); + return 0; +} + +bool tox_add_tcp_relay(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key, + TOX_ERR_BOOTSTRAP *error) +{ + if (!address || !public_key) { + SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_NULL); + return 0; + } + + if (port == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_PORT); + return 0; + } + + IP_Port *root; + + int32_t count = net_getipport(address, &root, TOX_SOCK_STREAM); + + if (count == -1) { + net_freeipport(root); + SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST); + return 0; + } + + unsigned int i; + + for (i = 0; i < count; i++) { + root[i].port = net_htons(port); + + Messenger *m = tox; + add_tcp_relay(m->net_crypto, root[i], public_key); + } + + net_freeipport(root); + + if (count) { + SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_OK); + return 1; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST); + return 0; +} + +TOX_CONNECTION tox_self_get_connection_status(const Tox *tox) +{ + const Messenger *m = tox; + + unsigned int ret = onion_connection_status(m->onion_c); + + if (ret == 2) { + return TOX_CONNECTION_UDP; + } + + if (ret == 1) { + return TOX_CONNECTION_TCP; + } + + return TOX_CONNECTION_NONE; +} + + +void tox_callback_self_connection_status(Tox *tox, tox_self_connection_status_cb *callback) +{ + Messenger *m = tox; + m_callback_core_connection(m, (void (*)(Messenger *, unsigned int, void *))callback); +} + +uint32_t tox_iteration_interval(const Tox *tox) +{ + const Messenger *m = tox; + return messenger_run_interval(m); +} + +void tox_iterate(Tox *tox, void *user_data) +{ + Messenger *m = tox; + do_messenger(m, user_data); + do_groupchats((Group_Chats *)m->conferences_object, user_data); +} + +void tox_self_get_address(const Tox *tox, uint8_t *address) +{ + if (address) { + const Messenger *m = tox; + getaddress(m, address); + } +} + +void tox_self_set_nospam(Tox *tox, uint32_t nospam) +{ + Messenger *m = tox; + set_nospam(&(m->fr), net_htonl(nospam)); +} + +uint32_t tox_self_get_nospam(const Tox *tox) +{ + const Messenger *m = tox; + return net_ntohl(get_nospam(&(m->fr))); +} + +void tox_self_get_public_key(const Tox *tox, uint8_t *public_key) +{ + const Messenger *m = tox; + + if (public_key) { + memcpy(public_key, m->net_crypto->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + } +} + +void tox_self_get_secret_key(const Tox *tox, uint8_t *secret_key) +{ + const Messenger *m = tox; + + if (secret_key) { + memcpy(secret_key, m->net_crypto->self_secret_key, CRYPTO_SECRET_KEY_SIZE); + } +} + +bool tox_self_set_name(Tox *tox, const uint8_t *name, size_t length, TOX_ERR_SET_INFO *error) +{ + if (!name && length != 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_NULL); + return 0; + } + + Messenger *m = tox; + + if (setname(m, name, length) == 0) { + // TODO(irungentoo): function to set different per group names? + send_name_all_groups((Group_Chats *)m->conferences_object); + SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_OK); + return 1; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_TOO_LONG); + return 0; +} + +size_t tox_self_get_name_size(const Tox *tox) +{ + const Messenger *m = tox; + return m_get_self_name_size(m); +} + +void tox_self_get_name(const Tox *tox, uint8_t *name) +{ + if (name) { + const Messenger *m = tox; + getself_name(m, name); + } +} + +bool tox_self_set_status_message(Tox *tox, const uint8_t *status_message, size_t length, TOX_ERR_SET_INFO *error) +{ + if (!status_message && length != 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_NULL); + return 0; + } + + Messenger *m = tox; + + if (m_set_statusmessage(m, status_message, length) == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_OK); + return 1; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_TOO_LONG); + return 0; +} + +size_t tox_self_get_status_message_size(const Tox *tox) +{ + const Messenger *m = tox; + return m_get_self_statusmessage_size(m); +} + +void tox_self_get_status_message(const Tox *tox, uint8_t *status_message) +{ + if (status_message) { + const Messenger *m = tox; + m_copy_self_statusmessage(m, status_message); + } +} + +void tox_self_set_status(Tox *tox, TOX_USER_STATUS status) +{ + Messenger *m = tox; + m_set_userstatus(m, status); +} + +TOX_USER_STATUS tox_self_get_status(const Tox *tox) +{ + const Messenger *m = tox; + return (TOX_USER_STATUS)m_get_self_userstatus(m); +} + +static void set_friend_error(int32_t ret, TOX_ERR_FRIEND_ADD *error) +{ + switch (ret) { + case FAERR_TOOLONG: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_TOO_LONG); + break; + + case FAERR_NOMESSAGE: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_NO_MESSAGE); + break; + + case FAERR_OWNKEY: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_OWN_KEY); + break; + + case FAERR_ALREADYSENT: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_ALREADY_SENT); + break; + + case FAERR_BADCHECKSUM: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_BAD_CHECKSUM); + break; + + case FAERR_SETNEWNOSPAM: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM); + break; + + case FAERR_NOMEM: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_MALLOC); + break; + } +} + +uint32_t tox_friend_add(Tox *tox, const uint8_t *address, const uint8_t *message, size_t length, + TOX_ERR_FRIEND_ADD *error) +{ + if (!address || !message) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_NULL); + return UINT32_MAX; + } + + Messenger *m = tox; + int32_t ret = m_addfriend(m, address, message, length); + + if (ret >= 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_OK); + return ret; + } + + set_friend_error(ret, error); + return UINT32_MAX; +} + +uint32_t tox_friend_add_norequest(Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_ADD *error) +{ + if (!public_key) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_NULL); + return UINT32_MAX; + } + + Messenger *m = tox; + int32_t ret = m_addfriend_norequest(m, public_key); + + if (ret >= 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_OK); + return ret; + } + + set_friend_error(ret, error); + return UINT32_MAX; +} + +bool tox_friend_delete(Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_DELETE *error) +{ + Messenger *m = tox; + int ret = m_delfriend(m, friend_number); + + // TODO(irungentoo): handle if realloc fails? + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_DELETE_FRIEND_NOT_FOUND); + return 0; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_DELETE_OK); + return 1; +} + +uint32_t tox_friend_by_public_key(const Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_BY_PUBLIC_KEY *error) +{ + if (!public_key) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_NULL); + return UINT32_MAX; + } + + const Messenger *m = tox; + int32_t ret = getfriend_id(m, public_key); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_NOT_FOUND); + return UINT32_MAX; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_OK); + return ret; +} + +bool tox_friend_get_public_key(const Tox *tox, uint32_t friend_number, uint8_t *public_key, + TOX_ERR_FRIEND_GET_PUBLIC_KEY *error) +{ + if (!public_key) { + return 0; + } + + const Messenger *m = tox; + + if (get_real_pk(m, friend_number, public_key) == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_PUBLIC_KEY_FRIEND_NOT_FOUND); + return 0; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK); + return 1; +} + +bool tox_friend_exists(const Tox *tox, uint32_t friend_number) +{ + const Messenger *m = tox; + return m_friend_exists(m, friend_number); +} + +uint64_t tox_friend_get_last_online(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_GET_LAST_ONLINE *error) +{ + const Messenger *m = tox; + uint64_t timestamp = m_get_last_online(m, friend_number); + + if (timestamp == UINT64_MAX) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_LAST_ONLINE_FRIEND_NOT_FOUND) + return UINT64_MAX; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_LAST_ONLINE_OK); + return timestamp; +} + +size_t tox_self_get_friend_list_size(const Tox *tox) +{ + const Messenger *m = tox; + return count_friendlist(m); +} + +void tox_self_get_friend_list(const Tox *tox, uint32_t *friend_list) +{ + if (friend_list) { + const Messenger *m = tox; + // TODO(irungentoo): size parameter? + copy_friendlist(m, friend_list, tox_self_get_friend_list_size(tox)); + } +} + +size_t tox_friend_get_name_size(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error) +{ + const Messenger *m = tox; + int ret = m_get_name_size(m, friend_number); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); + return SIZE_MAX; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); + return ret; +} + +bool tox_friend_get_name(const Tox *tox, uint32_t friend_number, uint8_t *name, TOX_ERR_FRIEND_QUERY *error) +{ + if (!name) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_NULL); + return 0; + } + + const Messenger *m = tox; + int ret = getname(m, friend_number, name); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); + return 0; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); + return 1; +} + +void tox_callback_friend_name(Tox *tox, tox_friend_name_cb *callback) +{ + Messenger *m = tox; + m_callback_namechange(m, callback); +} + +size_t tox_friend_get_status_message_size(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error) +{ + const Messenger *m = tox; + int ret = m_get_statusmessage_size(m, friend_number); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); + return SIZE_MAX; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); + return ret; +} + +bool tox_friend_get_status_message(const Tox *tox, uint32_t friend_number, uint8_t *status_message, + TOX_ERR_FRIEND_QUERY *error) +{ + if (!status_message) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_NULL); + return 0; + } + + const Messenger *m = tox; + // TODO(irungentoo): size parameter? + int ret = m_copy_statusmessage(m, friend_number, status_message, m_get_statusmessage_size(m, friend_number)); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); + return 0; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); + return 1; +} + +void tox_callback_friend_status_message(Tox *tox, tox_friend_status_message_cb *callback) +{ + Messenger *m = tox; + m_callback_statusmessage(m, callback); +} + +TOX_USER_STATUS tox_friend_get_status(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error) +{ + const Messenger *m = tox; + + int ret = m_get_userstatus(m, friend_number); + + if (ret == USERSTATUS_INVALID) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); + return (TOX_USER_STATUS)(TOX_USER_STATUS_BUSY + 1); + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); + return (TOX_USER_STATUS)ret; +} + +void tox_callback_friend_status(Tox *tox, tox_friend_status_cb *callback) +{ + Messenger *m = tox; + m_callback_userstatus(m, (void (*)(Messenger *, uint32_t, unsigned int, void *))callback); +} + +TOX_CONNECTION tox_friend_get_connection_status(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error) +{ + const Messenger *m = tox; + + int ret = m_get_friend_connectionstatus(m, friend_number); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); + return TOX_CONNECTION_NONE; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); + return (TOX_CONNECTION)ret; +} + +void tox_callback_friend_connection_status(Tox *tox, tox_friend_connection_status_cb *callback) +{ + Messenger *m = tox; + m_callback_connectionstatus(m, (void (*)(Messenger *, uint32_t, unsigned int, void *))callback); +} + +bool tox_friend_get_typing(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error) +{ + const Messenger *m = tox; + int ret = m_get_istyping(m, friend_number); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); + return 0; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); + return !!ret; +} + +void tox_callback_friend_typing(Tox *tox, tox_friend_typing_cb *callback) +{ + Messenger *m = tox; + m_callback_typingchange(m, callback); +} + +bool tox_self_set_typing(Tox *tox, uint32_t friend_number, bool typing, TOX_ERR_SET_TYPING *error) +{ + Messenger *m = tox; + + if (m_set_usertyping(m, friend_number, typing) == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_SET_TYPING_FRIEND_NOT_FOUND); + return 0; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_SET_TYPING_OK); + return 1; +} + +static void set_message_error(int ret, TOX_ERR_FRIEND_SEND_MESSAGE *error) +{ + switch (ret) { + case 0: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_OK); + break; + + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_FOUND); + break; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_TOO_LONG); + break; + + case -3: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_CONNECTED); + break; + + case -4: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_SENDQ); + break; + + case -5: + /* can't happen */ + break; + } +} + +uint32_t tox_friend_send_message(Tox *tox, uint32_t friend_number, TOX_MESSAGE_TYPE type, const uint8_t *message, + size_t length, TOX_ERR_FRIEND_SEND_MESSAGE *error) +{ + if (!message) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_NULL); + return 0; + } + + if (!length) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_EMPTY); + return 0; + } + + Messenger *m = tox; + uint32_t message_id = 0; + set_message_error(m_send_message_generic(m, friend_number, type, message, length, &message_id), error); + return message_id; +} + +void tox_callback_friend_read_receipt(Tox *tox, tox_friend_read_receipt_cb *callback) +{ + Messenger *m = tox; + m_callback_read_receipt(m, callback); +} + +void tox_callback_friend_request(Tox *tox, tox_friend_request_cb *callback) +{ + Messenger *m = tox; + m_callback_friendrequest(m, callback); +} + +void tox_callback_friend_message(Tox *tox, tox_friend_message_cb *callback) +{ + Messenger *m = tox; + m_callback_friendmessage(m, (void (*)(Messenger *, uint32_t, unsigned int, const uint8_t *, size_t, void *))callback); +} + +bool tox_hash(uint8_t *hash, const uint8_t *data, size_t length) +{ + if (!hash || (length && !data)) { + return 0; + } + + crypto_sha256(hash, data, length); + return 1; +} + +bool tox_file_control(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control, + TOX_ERR_FILE_CONTROL *error) +{ + Messenger *m = tox; + int ret = file_control(m, friend_number, file_number, control); + + if (ret == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_OK); + return 1; + } + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND); + return 0; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED); + return 0; + + case -3: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_NOT_FOUND); + return 0; + + case -4: + /* can't happen */ + return 0; + + case -5: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_ALREADY_PAUSED); + return 0; + + case -6: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_DENIED); + return 0; + + case -7: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_NOT_PAUSED); + return 0; + + case -8: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_SENDQ); + return 0; + } + + /* can't happen */ + return 0; +} + +bool tox_file_seek(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, + TOX_ERR_FILE_SEEK *error) +{ + Messenger *m = tox; + int ret = file_seek(m, friend_number, file_number, position); + + if (ret == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_OK); + return 1; + } + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_FRIEND_NOT_FOUND); + return 0; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_FRIEND_NOT_CONNECTED); + return 0; + + case -3: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_NOT_FOUND); + return 0; + + case -4: // fall-through + case -5: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_DENIED); + return 0; + + case -6: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_INVALID_POSITION); + return 0; + + case -8: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_SENDQ); + return 0; + } + + /* can't happen */ + return 0; +} + +void tox_callback_file_recv_control(Tox *tox, tox_file_recv_control_cb *callback) +{ + Messenger *m = tox; + callback_file_control(m, (void (*)(Messenger *, uint32_t, uint32_t, unsigned int, void *))callback); +} + +bool tox_file_get_file_id(const Tox *tox, uint32_t friend_number, uint32_t file_number, uint8_t *file_id, + TOX_ERR_FILE_GET *error) +{ + if (!file_id) { + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_NULL); + return 0; + } + + const Messenger *m = tox; + int ret = file_get_id(m, friend_number, file_number, file_id); + + if (ret == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_OK); + return 1; + } + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_FRIEND_NOT_FOUND); + } else { + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_NOT_FOUND); + } + + return 0; +} + +uint32_t tox_file_send(Tox *tox, uint32_t friend_number, uint32_t kind, uint64_t file_size, const uint8_t *file_id, + const uint8_t *filename, size_t filename_length, TOX_ERR_FILE_SEND *error) +{ + if (filename_length && !filename) { + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_NULL); + return UINT32_MAX; + } + + uint8_t f_id[FILE_ID_LENGTH]; + + if (!file_id) { + /* Tox keys are 32 bytes like FILE_ID_LENGTH. */ + new_symmetric_key(f_id); + file_id = f_id; + } + + Messenger *m = tox; + long int file_num = new_filesender(m, friend_number, kind, file_size, file_id, filename, filename_length); + + if (file_num >= 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_OK); + return file_num; + } + + switch (file_num) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND); + return UINT32_MAX; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_NAME_TOO_LONG); + return UINT32_MAX; + + case -3: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_TOO_MANY); + return UINT32_MAX; + + case -4: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED); + return UINT32_MAX; + } + + /* can't happen */ + return UINT32_MAX; +} + +bool tox_file_send_chunk(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, const uint8_t *data, + size_t length, TOX_ERR_FILE_SEND_CHUNK *error) +{ + Messenger *m = tox; + int ret = file_data(m, friend_number, file_number, position, data, length); + + if (ret == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_OK); + return 1; + } + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_FOUND); + return 0; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_CONNECTED); + return 0; + + case -3: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_NOT_FOUND); + return 0; + + case -4: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_NOT_TRANSFERRING); + return 0; + + case -5: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_INVALID_LENGTH); + return 0; + + case -6: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_SENDQ); + return 0; + + case -7: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_WRONG_POSITION); + return 0; + } + + /* can't happen */ + return 0; +} + +void tox_callback_file_chunk_request(Tox *tox, tox_file_chunk_request_cb *callback) +{ + Messenger *m = tox; + callback_file_reqchunk(m, callback); +} + +void tox_callback_file_recv(Tox *tox, tox_file_recv_cb *callback) +{ + Messenger *m = tox; + callback_file_sendrequest(m, callback); +} + +void tox_callback_file_recv_chunk(Tox *tox, tox_file_recv_chunk_cb *callback) +{ + Messenger *m = tox; + callback_file_data(m, callback); +} + +void tox_callback_conference_invite(Tox *tox, tox_conference_invite_cb *callback) +{ + Messenger *m = tox; + g_callback_group_invite((Group_Chats *)m->conferences_object, (void (*)(Messenger * m, uint32_t, int, const uint8_t *, + size_t, + void *))callback); +} + +void tox_callback_conference_message(Tox *tox, tox_conference_message_cb *callback) +{ + Messenger *m = tox; + g_callback_group_message((Group_Chats *)m->conferences_object, (void (*)(Messenger * m, uint32_t, uint32_t, int, + const uint8_t *, + size_t, void *))callback); +} + +void tox_callback_conference_title(Tox *tox, tox_conference_title_cb *callback) +{ + Messenger *m = tox; + g_callback_group_title((Group_Chats *)m->conferences_object, callback); +} + +void tox_callback_conference_namelist_change(Tox *tox, tox_conference_namelist_change_cb *callback) +{ + Messenger *m = tox; + g_callback_group_namelistchange((Group_Chats *)m->conferences_object, (void (*)(struct Messenger *, int, int, uint8_t, + void *))callback); +} + +uint32_t tox_conference_new(Tox *tox, TOX_ERR_CONFERENCE_NEW *error) +{ + Messenger *m = tox; + int ret = add_groupchat((Group_Chats *)m->conferences_object, GROUPCHAT_TYPE_TEXT); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_NEW_INIT); + return UINT32_MAX; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_NEW_OK); + return ret; +} + +bool tox_conference_delete(Tox *tox, uint32_t conference_number, TOX_ERR_CONFERENCE_DELETE *error) +{ + Messenger *m = tox; + int ret = del_groupchat((Group_Chats *)m->conferences_object, conference_number); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_DELETE_CONFERENCE_NOT_FOUND); + return false; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_DELETE_OK); + return true; +} + +uint32_t tox_conference_peer_count(const Tox *tox, uint32_t conference_number, TOX_ERR_CONFERENCE_PEER_QUERY *error) +{ + const Messenger *m = tox; + int ret = group_number_peers((Group_Chats *)m->conferences_object, conference_number); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND); + return UINT32_MAX; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK); + return ret; +} + +size_t tox_conference_peer_get_name_size(const Tox *tox, uint32_t conference_number, uint32_t peer_number, + TOX_ERR_CONFERENCE_PEER_QUERY *error) +{ + const Messenger *m = tox; + int ret = group_peername_size((Group_Chats *)m->conferences_object, conference_number, peer_number); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND); + return -1; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND); + return -1; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK); + return ret; +} + +bool tox_conference_peer_get_name(const Tox *tox, uint32_t conference_number, uint32_t peer_number, uint8_t *name, + TOX_ERR_CONFERENCE_PEER_QUERY *error) +{ + const Messenger *m = tox; + int ret = group_peername((Group_Chats *)m->conferences_object, conference_number, peer_number, name); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND); + return false; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND); + return false; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK); + return true; +} + +bool tox_conference_peer_get_public_key(const Tox *tox, uint32_t conference_number, uint32_t peer_number, + uint8_t *public_key, TOX_ERR_CONFERENCE_PEER_QUERY *error) +{ + const Messenger *m = tox; + int ret = group_peer_pubkey((Group_Chats *)m->conferences_object, conference_number, peer_number, public_key); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND); + return false; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND); + return false; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK); + return true; +} + +bool tox_conference_peer_number_is_ours(const Tox *tox, uint32_t conference_number, uint32_t peer_number, + TOX_ERR_CONFERENCE_PEER_QUERY *error) +{ + const Messenger *m = tox; + int ret = group_peernumber_is_ours((Group_Chats *)m->conferences_object, conference_number, peer_number); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND); + return false; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND); + return false; + + case -3: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_NO_CONNECTION); + return false; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK); + return ret; +} + +bool tox_conference_invite(Tox *tox, uint32_t friend_number, uint32_t conference_number, + TOX_ERR_CONFERENCE_INVITE *error) +{ + Messenger *m = tox; + int ret = invite_friend((Group_Chats *)m->conferences_object, friend_number, conference_number); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_INVITE_CONFERENCE_NOT_FOUND); + return false; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_INVITE_FAIL_SEND); + return false; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_INVITE_OK); + return true; +} + +uint32_t tox_conference_join(Tox *tox, uint32_t friend_number, const uint8_t *cookie, size_t length, + TOX_ERR_CONFERENCE_JOIN *error) +{ + Messenger *m = tox; + int ret = join_groupchat((Group_Chats *)m->conferences_object, friend_number, GROUPCHAT_TYPE_TEXT, cookie, length); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_INVALID_LENGTH); + return UINT32_MAX; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_WRONG_TYPE); + return UINT32_MAX; + + case -3: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_FRIEND_NOT_FOUND); + return UINT32_MAX; + + case -4: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_DUPLICATE); + return UINT32_MAX; + + case -5: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_INIT_FAIL); + return UINT32_MAX; + + case -6: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_FAIL_SEND); + return UINT32_MAX; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_OK); + return ret; +} + +bool tox_conference_send_message(Tox *tox, uint32_t conference_number, TOX_MESSAGE_TYPE type, const uint8_t *message, + size_t length, TOX_ERR_CONFERENCE_SEND_MESSAGE *error) +{ + Messenger *m = tox; + int ret = 0; + + if (type == TOX_MESSAGE_TYPE_NORMAL) { + ret = group_message_send((Group_Chats *)m->conferences_object, conference_number, message, length); + } else { + ret = group_action_send((Group_Chats *)m->conferences_object, conference_number, message, length); + } + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_CONFERENCE_NOT_FOUND); + return false; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_TOO_LONG); + return false; + + case -3: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_NO_CONNECTION); + return false; + + case -4: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_FAIL_SEND); + return false; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_OK); + return true; +} + +size_t tox_conference_get_title_size(const Tox *tox, uint32_t conference_number, TOX_ERR_CONFERENCE_TITLE *error) +{ + const Messenger *m = tox; + int ret = group_title_get_size((Group_Chats *)m->conferences_object, conference_number); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_CONFERENCE_NOT_FOUND); + return -1; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_INVALID_LENGTH); + return -1; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_OK); + return ret; +} + +bool tox_conference_get_title(const Tox *tox, uint32_t conference_number, uint8_t *title, + TOX_ERR_CONFERENCE_TITLE *error) +{ + const Messenger *m = tox; + int ret = group_title_get((Group_Chats *)m->conferences_object, conference_number, title); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_CONFERENCE_NOT_FOUND); + return false; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_INVALID_LENGTH); + return false; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_OK); + return true; +} + +bool tox_conference_set_title(Tox *tox, uint32_t conference_number, const uint8_t *title, size_t length, + TOX_ERR_CONFERENCE_TITLE *error) +{ + Messenger *m = tox; + int ret = group_title_send((Group_Chats *)m->conferences_object, conference_number, title, length); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_CONFERENCE_NOT_FOUND); + return false; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_INVALID_LENGTH); + return false; + + case -3: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_FAIL_SEND); + return false; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_OK); + return true; +} + +size_t tox_conference_get_chatlist_size(const Tox *tox) +{ + const Messenger *m = tox; + return count_chatlist((Group_Chats *)m->conferences_object); +} + +void tox_conference_get_chatlist(const Tox *tox, uint32_t *chatlist) +{ + const Messenger *m = tox; + size_t list_size = tox_conference_get_chatlist_size(tox); + copy_chatlist((Group_Chats *)m->conferences_object, chatlist, list_size); +} + +TOX_CONFERENCE_TYPE tox_conference_get_type(const Tox *tox, uint32_t conference_number, + TOX_ERR_CONFERENCE_GET_TYPE *error) +{ + const Messenger *m = tox; + int ret = group_get_type((Group_Chats *)m->conferences_object, conference_number); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_GET_TYPE_CONFERENCE_NOT_FOUND); + return (TOX_CONFERENCE_TYPE)ret; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_GET_TYPE_OK); + return (TOX_CONFERENCE_TYPE)ret; +} + +static void set_custom_packet_error(int ret, TOX_ERR_FRIEND_CUSTOM_PACKET *error) +{ + switch (ret) { + case 0: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_OK); + break; + + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_FOUND); + break; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_TOO_LONG); + break; + + case -3: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_INVALID); + break; + + case -4: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_CONNECTED); + break; + + case -5: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_SENDQ); + break; + } +} + +bool tox_friend_send_lossy_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length, + TOX_ERR_FRIEND_CUSTOM_PACKET *error) +{ + if (!data) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_NULL); + return 0; + } + + Messenger *m = tox; + + if (length == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_EMPTY); + return 0; + } + + if (data[0] < (PACKET_ID_LOSSY_RANGE_START + PACKET_LOSSY_AV_RESERVED)) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_INVALID); + return 0; + } + + int ret = m_send_custom_lossy_packet(m, friend_number, data, length); + + set_custom_packet_error(ret, error); + + if (ret == 0) { + return 1; + } + + return 0; +} + +void tox_callback_friend_lossy_packet(Tox *tox, tox_friend_lossy_packet_cb *callback) +{ + Messenger *m = tox; + custom_lossy_packet_registerhandler(m, callback); +} + +bool tox_friend_send_lossless_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length, + TOX_ERR_FRIEND_CUSTOM_PACKET *error) +{ + if (!data) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_NULL); + return 0; + } + + Messenger *m = tox; + + if (length == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_EMPTY); + return 0; + } + + int ret = send_custom_lossless_packet(m, friend_number, data, length); + + set_custom_packet_error(ret, error); + + if (ret == 0) { + return 1; + } + + return 0; +} + +void tox_callback_friend_lossless_packet(Tox *tox, tox_friend_lossless_packet_cb *callback) +{ + Messenger *m = tox; + custom_lossless_packet_registerhandler(m, callback); +} + +void tox_self_get_dht_id(const Tox *tox, uint8_t *dht_id) +{ + if (dht_id) { + const Messenger *m = tox; + memcpy(dht_id, m->dht->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + } +} + +uint16_t tox_self_get_udp_port(const Tox *tox, TOX_ERR_GET_PORT *error) +{ + const Messenger *m = tox; + uint16_t port = net_htons(m->net->port); + + if (port) { + SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_OK); + } else { + SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_NOT_BOUND); + } + + return port; +} + +uint16_t tox_self_get_tcp_port(const Tox *tox, TOX_ERR_GET_PORT *error) +{ + const Messenger *m = tox; + + if (m->tcp_server) { + SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_OK); + return m->options.tcp_server_port; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_NOT_BOUND); + return 0; +} diff --git a/protocols/Tox/include/tox.h b/protocols/Tox/libtox/src/toxcore/tox.h index 373138c4eb..30bc950964 100644 --- a/protocols/Tox/include/tox.h +++ b/protocols/Tox/libtox/src/toxcore/tox.h @@ -24,7 +24,7 @@ #ifndef TOX_H #define TOX_H -#include <msapi/stdbool.h> +#include <stdbool.h> #include <stddef.h> #include <stdint.h> diff --git a/protocols/Tox/libtox/src/toxcore/tox_api.c b/protocols/Tox/libtox/src/toxcore/tox_api.c new file mode 100644 index 0000000000..b6c8c38618 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/tox_api.c @@ -0,0 +1,97 @@ +#include "tox.h" + +#include <stdlib.h> +#include <string.h> + +#define SET_ERROR_PARAMETER(param, x) {if(param) {*param = x;}} + + +#define CONST_FUNCTION(lowercase, uppercase) \ +uint32_t tox_##lowercase(void) \ +{ \ + return TOX_##uppercase; \ +} + +CONST_FUNCTION(version_major, VERSION_MAJOR) +CONST_FUNCTION(version_minor, VERSION_MINOR) +CONST_FUNCTION(version_patch, VERSION_PATCH) +CONST_FUNCTION(public_key_size, PUBLIC_KEY_SIZE) +CONST_FUNCTION(secret_key_size, SECRET_KEY_SIZE) +CONST_FUNCTION(address_size, ADDRESS_SIZE) +CONST_FUNCTION(max_name_length, MAX_NAME_LENGTH) +CONST_FUNCTION(max_status_message_length, MAX_STATUS_MESSAGE_LENGTH) +CONST_FUNCTION(max_friend_request_length, MAX_FRIEND_REQUEST_LENGTH) +CONST_FUNCTION(max_message_length, MAX_MESSAGE_LENGTH) +CONST_FUNCTION(max_custom_packet_size, MAX_CUSTOM_PACKET_SIZE) +CONST_FUNCTION(hash_length, HASH_LENGTH) +CONST_FUNCTION(file_id_length, FILE_ID_LENGTH) +CONST_FUNCTION(max_filename_length, MAX_FILENAME_LENGTH) + + +#define ACCESSORS(type, ns, name) \ +type tox_options_get_##ns##name(const struct Tox_Options *options) \ +{ \ + return options->ns##name; \ +} \ +void tox_options_set_##ns##name(struct Tox_Options *options, type name) \ +{ \ + options->ns##name = name; \ +} + +ACCESSORS(bool, , ipv6_enabled) +ACCESSORS(bool, , udp_enabled) +ACCESSORS(TOX_PROXY_TYPE, proxy_ , type) +ACCESSORS(const char *, proxy_ , host) +ACCESSORS(uint16_t, proxy_ , port) +ACCESSORS(uint16_t, , start_port) +ACCESSORS(uint16_t, , end_port) +ACCESSORS(uint16_t, , tcp_port) +ACCESSORS(bool, , hole_punching_enabled) +ACCESSORS(TOX_SAVEDATA_TYPE, savedata_, type) +ACCESSORS(size_t, savedata_, length) +ACCESSORS(tox_log_cb *, log_, callback) +ACCESSORS(void *, log_, user_data) +ACCESSORS(bool, , local_discovery_enabled) + +const uint8_t *tox_options_get_savedata_data(const struct Tox_Options *options) +{ + return options->savedata_data; +} + +void tox_options_set_savedata_data(struct Tox_Options *options, const uint8_t *data, size_t length) +{ + options->savedata_data = data; + options->savedata_length = length; +} + +void tox_options_default(struct Tox_Options *options) +{ + if (options) { + struct Tox_Options default_options = { 0 }; + *options = default_options; + tox_options_set_ipv6_enabled(options, true); + tox_options_set_udp_enabled(options, true); + tox_options_set_proxy_type(options, TOX_PROXY_TYPE_NONE); + tox_options_set_hole_punching_enabled(options, true); + tox_options_set_local_discovery_enabled(options, true); + } +} + +struct Tox_Options *tox_options_new(TOX_ERR_OPTIONS_NEW *error) +{ + struct Tox_Options *options = (struct Tox_Options *)malloc(sizeof(struct Tox_Options)); + + if (options) { + tox_options_default(options); + SET_ERROR_PARAMETER(error, TOX_ERR_OPTIONS_NEW_OK); + return options; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_OPTIONS_NEW_MALLOC); + return NULL; +} + +void tox_options_free(struct Tox_Options *options) +{ + free(options); +} diff --git a/protocols/Tox/libtox/src/toxcore/util.c b/protocols/Tox/libtox/src/toxcore/util.c new file mode 100644 index 0000000000..92bbb68c1f --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/util.c @@ -0,0 +1,195 @@ +/* + * Utilities. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * Copyright © 2013 plutooo + * + * This file is part of Tox, the free peer to peer instant messenger. + * This file is donated to the Tox Project. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define _XOPEN_SOURCE 600 + +#include "util.h" + +#include "crypto_core.h" /* for CRYPTO_PUBLIC_KEY_SIZE */ +#include "network.h" /* for current_time_monotonic */ + +#include <time.h> + + +/* don't call into system billions of times for no reason */ +static uint64_t unix_time_value; +static uint64_t unix_base_time_value; + +/* XXX: note that this is not thread-safe; if multiple threads call unix_time_update() concurrently, the return value of + * unix_time() may fail to increase monotonically with increasing time */ +void unix_time_update(void) +{ + if (unix_base_time_value == 0) { + unix_base_time_value = ((uint64_t)time(NULL) - (current_time_monotonic() / 1000ULL)); + } + + unix_time_value = (current_time_monotonic() / 1000ULL) + unix_base_time_value; +} + +uint64_t unix_time(void) +{ + return unix_time_value; +} + +int is_timeout(uint64_t timestamp, uint64_t timeout) +{ + return timestamp + timeout <= unix_time(); +} + + +/* id functions */ +bool id_equal(const uint8_t *dest, const uint8_t *src) +{ + return public_key_cmp(dest, src) == 0; +} + +uint32_t id_copy(uint8_t *dest, const uint8_t *src) +{ + memcpy(dest, src, CRYPTO_PUBLIC_KEY_SIZE); + return CRYPTO_PUBLIC_KEY_SIZE; +} + +void host_to_net(uint8_t *num, uint16_t numbytes) +{ +#ifndef WORDS_BIGENDIAN + uint32_t i; + VLA(uint8_t, buff, numbytes); + + for (i = 0; i < numbytes; ++i) { + buff[i] = num[numbytes - i - 1]; + } + + memcpy(num, buff, numbytes); +#endif +} + +uint16_t lendian_to_host16(uint16_t lendian) +{ +#ifdef WORDS_BIGENDIAN + return (lendian << 8) | (lendian >> 8); +#else + return lendian; +#endif +} + +void host_to_lendian32(uint8_t *dest, uint32_t num) +{ +#ifdef WORDS_BIGENDIAN + num = ((num << 8) & 0xFF00FF00) | ((num >> 8) & 0xFF00FF); + num = (num << 16) | (num >> 16); +#endif + memcpy(dest, &num, sizeof(uint32_t)); +} + +void lendian_to_host32(uint32_t *dest, const uint8_t *lendian) +{ + uint32_t d; + memcpy(&d, lendian, sizeof(uint32_t)); +#ifdef WORDS_BIGENDIAN + d = ((d << 8) & 0xFF00FF00) | ((d >> 8) & 0xFF00FF); + d = (d << 16) | (d >> 16); +#endif + *dest = d; +} + +/* state load/save */ +int load_state(load_state_callback_func load_state_callback, Logger *log, void *outer, + const uint8_t *data, uint32_t length, uint16_t cookie_inner) +{ + if (!load_state_callback || !data) { + LOGGER_ERROR(log, "load_state() called with invalid args.\n"); + return -1; + } + + + uint16_t type; + uint32_t length_sub, cookie_type; + uint32_t size_head = sizeof(uint32_t) * 2; + + while (length >= size_head) { + lendian_to_host32(&length_sub, data); + lendian_to_host32(&cookie_type, data + sizeof(length_sub)); + data += size_head; + length -= size_head; + + if (length < length_sub) { + /* file truncated */ + LOGGER_ERROR(log, "state file too short: %u < %u\n", length, length_sub); + return -1; + } + + if (lendian_to_host16((cookie_type >> 16)) != cookie_inner) { + /* something is not matching up in a bad way, give up */ + LOGGER_ERROR(log, "state file garbled: %04x != %04x\n", (cookie_type >> 16), cookie_inner); + return -1; + } + + type = lendian_to_host16(cookie_type & 0xFFFF); + + int ret = load_state_callback(outer, data, length_sub, type); + + if (ret == -1) { + return -1; + } + + /* -2 means end of save. */ + if (ret == -2) { + return 0; + } + + data += length_sub; + length -= length_sub; + } + + return length == 0 ? 0 : -1; +} + +int create_recursive_mutex(pthread_mutex_t *mutex) +{ + pthread_mutexattr_t attr; + + if (pthread_mutexattr_init(&attr) != 0) { + return -1; + } + + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) { + pthread_mutexattr_destroy(&attr); + return -1; + } + + /* Create queue mutex */ + if (pthread_mutex_init(mutex, &attr) != 0) { + pthread_mutexattr_destroy(&attr); + return -1; + } + + pthread_mutexattr_destroy(&attr); + + return 0; +} diff --git a/protocols/Tox/libtox/src/toxcore/util.h b/protocols/Tox/libtox/src/toxcore/util.h new file mode 100644 index 0000000000..8777e191d8 --- /dev/null +++ b/protocols/Tox/libtox/src/toxcore/util.h @@ -0,0 +1,64 @@ +/* + * Utilities. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * Copyright © 2013 plutooo + * + * This file is part of Tox, the free peer to peer instant messenger. + * This file is donated to the Tox Project. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef UTIL_H +#define UTIL_H + +#include <pthread.h> +#include <stdbool.h> +#include <stdint.h> + +#include "logger.h" + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define PAIR(TYPE1__, TYPE2__) struct { TYPE1__ first; TYPE2__ second; } + +void unix_time_update(void); +uint64_t unix_time(void); +int is_timeout(uint64_t timestamp, uint64_t timeout); + + +/* id functions */ +bool id_equal(const uint8_t *dest, const uint8_t *src); +uint32_t id_copy(uint8_t *dest, const uint8_t *src); /* return value is CLIENT_ID_SIZE */ + +void host_to_net(uint8_t *num, uint16_t numbytes); +#define net_to_host(x, y) host_to_net(x, y) + +uint16_t lendian_to_host16(uint16_t lendian); +#define host_tolendian16(x) lendian_to_host16(x) + +void host_to_lendian32(uint8_t *dest, uint32_t num); +void lendian_to_host32(uint32_t *dest, const uint8_t *lendian); + +/* state load/save */ +typedef int (*load_state_callback_func)(void *outer, const uint8_t *data, uint32_t len, uint16_t type); +int load_state(load_state_callback_func load_state_callback, Logger *log, void *outer, + const uint8_t *data, uint32_t length, uint16_t cookie_inner); + +/* Returns -1 if failed or 0 if success */ +int create_recursive_mutex(pthread_mutex_t *mutex); + +#endif /* UTIL_H */ diff --git a/protocols/Tox/libtox/src/toxdns/toxdns.c b/protocols/Tox/libtox/src/toxdns/toxdns.c new file mode 100644 index 0000000000..96f3081f80 --- /dev/null +++ b/protocols/Tox/libtox/src/toxdns/toxdns.c @@ -0,0 +1,243 @@ +/* + * Tox secure username DNS toxid resolving functions. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../toxcore/Messenger.h" +#include "../toxcore/logger.h" +#include "toxdns.h" + +static const char base32[32] = { + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', +}; + +#define _encode(a, b, c) \ +{ \ + uint8_t _i = 0; \ + while (_i != c) { \ + *a++ = base32[((b[0] >> bits) | (b[1] << (8 - bits))) & 0x1F]; \ + bits += 5; \ + if(bits >= 8) { \ + bits -= 8; \ + b++; \ + _i++; \ + } \ + } \ +} + +typedef struct { + uint8_t temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t temp_sk[CRYPTO_SECRET_KEY_SIZE]; + uint8_t server_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t shared_key[CRYPTO_SYMMETRIC_KEY_SIZE]; + uint32_t nonce; + uint32_t nonce_start; +} DNS_Object; + +static void dns_new_temp_keys(DNS_Object *d) +{ + d->nonce = d->nonce_start = random_int(); + crypto_new_keypair(d->temp_pk, d->temp_sk); + encrypt_precompute(d->server_public_key, d->temp_sk, d->shared_key); +} + +/* Create a new tox_dns3 object for server with server_public_key. + * + * return Null on failure. + * return pointer object on success. + */ +void *tox_dns3_new(uint8_t *server_public_key) +{ + DNS_Object *d = (DNS_Object *)malloc(sizeof(DNS_Object)); + + if (d == NULL) { + return NULL; + } + + memcpy(d->server_public_key, server_public_key, CRYPTO_PUBLIC_KEY_SIZE); + dns_new_temp_keys(d); + return d; +} + +/* Destroy the tox dns3 object. + */ +void tox_dns3_kill(void *dns3_object) +{ + memset(dns3_object, 0, sizeof(DNS_Object)); + free(dns3_object); +} + +/* Generate a dns3 string of string_max_len used to query the dns server referred to by to + * dns3_object for a tox id registered to user with name of name_len. + * + * the uint32_t pointed by request_id will be set to the request id which must be passed to + * tox_decrypt_dns3_TXT() to correctly decode the response. + * + * This is what the string returned looks like: + * 4haaaaipr1o3mz0bxweox541airydbovqlbju51mb4p0ebxq.rlqdj4kkisbep2ks3fj2nvtmk4daduqiueabmexqva1jc + * + * returns length of string on success. + * returns -1 on failure. + */ +int tox_generate_dns3_string(void *dns3_object, uint8_t *string, uint16_t string_max_len, uint32_t *request_id, + uint8_t *name, uint8_t name_len) +{ +#define DOT_INTERVAL (6 * 5) + int base = (sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE + name_len + CRYPTO_MAC_SIZE); + int end_len = ((base * 8) / 5) + (base / DOT_INTERVAL) + !!(base % 5); + end_len -= !(base % DOT_INTERVAL); + + if (end_len > string_max_len) { + return -1; + } + + DNS_Object *d = (DNS_Object *)dns3_object; + uint8_t buffer[1024]; + uint8_t nonce[CRYPTO_NONCE_SIZE] = {0}; + memcpy(nonce, &d->nonce, sizeof(uint32_t)); + memcpy(buffer, &d->nonce, sizeof(uint32_t)); + memcpy(buffer + sizeof(uint32_t), d->temp_pk, CRYPTO_PUBLIC_KEY_SIZE); + int len = encrypt_data_symmetric(d->shared_key, nonce, name, name_len, + buffer + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE); + + if (len == -1) { + return -1; + } + + int total_len = len + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE; + uint8_t *buff = buffer, *old_str = string; + buffer[total_len] = 0; + uint8_t bits = 0; + int i; + + for (i = !(total_len % DOT_INTERVAL); i < (total_len / DOT_INTERVAL); ++i) { + _encode(string, buff, DOT_INTERVAL); + *string = '.'; + ++string; + } + + int left = total_len - (buff - buffer); + _encode(string, buff, left); +#undef DOT_INTERVAL + *request_id = d->nonce; + ++d->nonce; + + if (d->nonce == d->nonce_start) { + dns_new_temp_keys(d); + } + + if (end_len != string - old_str) { + // TODO(iphydf): This currently has no access to a logger. + LOGGER_ERROR(NULL, "tox_generate_dns3_string Fail, %u != %lu\n", end_len, string - old_str); + return -1; + } + + return string - old_str; +} + + +static int decode(uint8_t *dest, uint8_t *src) +{ + uint8_t *p = src, *op = dest, bits = 0; + *op = 0; + + while (*p) { + uint8_t ch = *p++; + + if ('A' <= ch && ch <= 'Z') { + ch = ch - 'A'; + } else if ('a' <= ch && ch <= 'z') { + ch = ch - 'a'; + } else if ('0' <= ch && ch <= '5') { + ch = ch - '0' + 26; + } else { + return - 1; + } + + *op |= (ch << bits); + bits += 5; + + if (bits >= 8) { + bits -= 8; + ++op; + *op = (ch >> (5 - bits)); + } + } + + return op - dest; +} + +/* Decode and decrypt the id_record returned of length id_record_len into + * tox_id (needs to be at least TOX_FRIEND_ADDRESS_SIZE). + * + * request_id is the request id given by tox_generate_dns3_string() when creating the request. + * + * the id_record passed to this function should look somewhat like this: + * 2vgcxuycbuctvauik3plsv3d3aadv4zfjfhi3thaizwxinelrvigchv0ah3qjcsx5qhmaksb2lv2hm5cwbtx0yp + * + * returns -1 on failure. + * returns 0 on success. + * + */ +int tox_decrypt_dns3_TXT(void *dns3_object, uint8_t *tox_id, uint8_t *id_record, uint32_t id_record_len, + uint32_t request_id) +{ + DNS_Object *d = (DNS_Object *)dns3_object; + + if (id_record_len != 87) { + return -1; + } + +#if 0 + + if (id_record_len > 255 || id_record_len <= (sizeof(uint32_t) + CRYPTO_MAC_SIZE)) { + return -1; + } + +#endif + + VLA(uint8_t, id_record_null, id_record_len + 1); + memcpy(id_record_null, id_record, id_record_len); + id_record_null[id_record_len] = 0; + VLA(uint8_t, data, id_record_len); + int length = decode(data, id_record_null); + + if (length == -1) { + return -1; + } + + uint8_t nonce[CRYPTO_NONCE_SIZE] = {0}; + memcpy(nonce, &request_id, sizeof(uint32_t)); + nonce[sizeof(uint32_t)] = 1; + int len = decrypt_data_symmetric(d->shared_key, nonce, data, length, tox_id); + + if (len != FRIEND_ADDRESS_SIZE) { + return -1; + } + + return 0; +} diff --git a/protocols/Tox/include/toxdns.h b/protocols/Tox/libtox/src/toxdns/toxdns.h index b280925eb1..b280925eb1 100644 --- a/protocols/Tox/include/toxdns.h +++ b/protocols/Tox/libtox/src/toxdns/toxdns.h diff --git a/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h new file mode 100644 index 0000000000..5cb32f8dcf --- /dev/null +++ b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h @@ -0,0 +1,92 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +#ifndef crypto_pwhash_scryptsalsa208sha256_H +#define crypto_pwhash_scryptsalsa208sha256_H + +#include <stddef.h> +#include <stdint.h> + +#include "export.h" + +#ifdef __cplusplus +# if __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_pwhash_scryptsalsa208sha256_SALTBYTES 32U +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_saltbytes(void); + +#define crypto_pwhash_scryptsalsa208sha256_STRBYTES 102U +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_strbytes(void); + +#define crypto_pwhash_scryptsalsa208sha256_STRPREFIX "$7$" +SODIUM_EXPORT +const char *crypto_pwhash_scryptsalsa208sha256_strprefix(void); + +#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE 524288ULL +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_opslimit_interactive(void); + +#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE 16777216ULL +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_memlimit_interactive(void); + +#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE 33554432ULL +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(void); + +#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE 1073741824ULL +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(void); + +SODIUM_EXPORT +int crypto_pwhash_scryptsalsa208sha256(unsigned char * const out, + unsigned long long outlen, + const char * const passwd, + unsigned long long passwdlen, + const unsigned char * const salt, + unsigned long long opslimit, + size_t memlimit); + +SODIUM_EXPORT +int crypto_pwhash_scryptsalsa208sha256_str(char out[crypto_pwhash_scryptsalsa208sha256_STRBYTES], + const char * const passwd, + unsigned long long passwdlen, + unsigned long long opslimit, + size_t memlimit); + +SODIUM_EXPORT +int crypto_pwhash_scryptsalsa208sha256_str_verify(const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES], + const char * const passwd, + unsigned long long passwdlen); + +SODIUM_EXPORT +int crypto_pwhash_scryptsalsa208sha256_ll(const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, + uint64_t N, uint32_t r, uint32_t p, + uint8_t * buf, size_t buflen); + +#ifdef __cplusplus +} +#endif + +/* Backward compatibility with version 0.5.0 */ + +#define crypto_pwhash_scryptxsalsa208sha256_SALTBYTES crypto_pwhash_scryptsalsa208sha256_SALTBYTES +#define crypto_pwhash_scryptxsalsa208sha256_saltbytes crypto_pwhash_scryptsalsa208sha256_saltbytes +#define crypto_pwhash_scryptxsalsa208sha256_STRBYTES crypto_pwhash_scryptsalsa208sha256_STRBYTES +#define crypto_pwhash_scryptxsalsa208sha256_strbytes crypto_pwhash_scryptsalsa208sha256_strbytes +#define crypto_pwhash_scryptxsalsa208sha256 crypto_pwhash_scryptsalsa208sha256 +#define crypto_pwhash_scryptxsalsa208sha256_str crypto_pwhash_scryptsalsa208sha256_str +#define crypto_pwhash_scryptxsalsa208sha256_str_verify crypto_pwhash_scryptsalsa208sha256_str_verify + +#endif + +#endif diff --git a/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt-common.c b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt-common.c new file mode 100644 index 0000000000..5a5c5525f3 --- /dev/null +++ b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt-common.c @@ -0,0 +1,257 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +/*- + * Copyright 2013 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdint.h> +#include <string.h> + +#include "crypto_pwhash_scryptsalsa208sha256.h" +#include "crypto_scrypt.h" +#include "runtime.h" +#include "utils.h" + +static const char * const itoa64 = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static uint8_t * +encode64_uint32(uint8_t * dst, size_t dstlen, uint32_t src, uint32_t srcbits) +{ + uint32_t bit; + + for (bit = 0; bit < srcbits; bit += 6) { + if (dstlen < 1) { + return NULL; + } + *dst++ = itoa64[src & 0x3f]; + dstlen--; + src >>= 6; + } + + return dst; +} + +static uint8_t * +encode64(uint8_t * dst, size_t dstlen, const uint8_t * src, size_t srclen) +{ + size_t i; + + for (i = 0; i < srclen; ) { + uint8_t * dnext; + uint32_t value = 0, bits = 0; + do { + value |= (uint32_t)src[i++] << bits; + bits += 8; + } while (bits < 24 && i < srclen); + dnext = encode64_uint32(dst, dstlen, value, bits); + if (!dnext) { + return NULL; + } + dstlen -= dnext - dst; + dst = dnext; + } + + return dst; +} + +static int +decode64_one(uint32_t * dst, uint8_t src) +{ + const char *ptr = strchr(itoa64, src); + + if (ptr) { + *dst = ptr - itoa64; + return 0; + } + *dst = 0; + return -1; +} + +static const uint8_t * +decode64_uint32(uint32_t * dst, uint32_t dstbits, const uint8_t * src) +{ + uint32_t bit; + uint32_t value; + + value = 0; + for (bit = 0; bit < dstbits; bit += 6) { + uint32_t one; + if (decode64_one(&one, *src)) { + *dst = 0; + return NULL; + } + src++; + value |= one << bit; + } + + *dst = value; + return src; +} + +uint8_t * +escrypt_r(escrypt_local_t * local, const uint8_t * passwd, size_t passwdlen, + const uint8_t * setting, uint8_t * buf, size_t buflen) +{ + uint8_t hash[crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES]; + escrypt_kdf_t escrypt_kdf; + const uint8_t *src; + const uint8_t *salt; + uint8_t *dst; + size_t prefixlen; + size_t saltlen; + size_t need; + uint64_t N; + uint32_t N_log2; + uint32_t r; + uint32_t p; + + if (setting[0] != '$' || setting[1] != '7' || setting[2] != '$') { + return NULL; + } + src = setting + 3; + + if (decode64_one(&N_log2, *src)) { + return NULL; + } + src++; + N = (uint64_t)1 << N_log2; + + src = decode64_uint32(&r, 30, src); + if (!src) { + return NULL; + } + src = decode64_uint32(&p, 30, src); + if (!src) { + return NULL; + } + prefixlen = src - setting; + + salt = src; + src = (uint8_t *) strrchr((char *)salt, '$'); + if (src) { + saltlen = src - salt; + } else { + saltlen = strlen((char *)salt); + } + need = prefixlen + saltlen + 1 + + crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED + 1; + if (need > buflen || need < saltlen) { + return NULL; + } +#if defined(HAVE_EMMINTRIN_H) || defined(_MSC_VER) + escrypt_kdf = + sodium_runtime_has_sse2() ? escrypt_kdf_sse : escrypt_kdf_nosse; +#else + escrypt_kdf = escrypt_kdf_nosse; +#endif + if (escrypt_kdf(local, passwd, passwdlen, salt, saltlen, + N, r, p, hash, sizeof(hash))) { + return NULL; + } + + dst = buf; + memcpy(dst, setting, prefixlen + saltlen); + dst += prefixlen + saltlen; + *dst++ = '$'; + + dst = encode64(dst, buflen - (dst - buf), hash, sizeof(hash)); + sodium_memzero(hash, sizeof hash); + if (!dst || dst >= buf + buflen) { /* Can't happen */ + return NULL; + } + *dst = 0; /* NUL termination */ + + return buf; +} + +uint8_t * +escrypt_gensalt_r(uint32_t N_log2, uint32_t r, uint32_t p, + const uint8_t * src, size_t srclen, + uint8_t * buf, size_t buflen) +{ + uint8_t *dst; + size_t prefixlen = + (sizeof "$7$" - 1U) + (1U /* N_log2 */) + (5U /* r */) + (5U /* p */); + size_t saltlen = BYTES2CHARS(srclen); + size_t need; + + need = prefixlen + saltlen + 1; + if (need > buflen || need < saltlen || saltlen < srclen) { + return NULL; + } + if (N_log2 > 63 || ((uint64_t)r * (uint64_t)p >= (1U << 30))) { + return NULL; + } + dst = buf; + *dst++ = '$'; + *dst++ = '7'; + *dst++ = '$'; + + *dst++ = itoa64[N_log2]; + + dst = encode64_uint32(dst, buflen - (dst - buf), r, 30); + if (!dst) { /* Can't happen */ + return NULL; + } + dst = encode64_uint32(dst, buflen - (dst - buf), p, 30); + if (!dst) { /* Can't happen */ + return NULL; + } + dst = encode64(dst, buflen - (dst - buf), src, srclen); + if (!dst || dst >= buf + buflen) { /* Can't happen */ + return NULL; + } + *dst = 0; /* NUL termination */ + + return buf; +} + +int +crypto_pwhash_scryptsalsa208sha256_ll(const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, + uint64_t N, uint32_t r, uint32_t p, + uint8_t * buf, size_t buflen) +{ + escrypt_kdf_t escrypt_kdf; + escrypt_local_t local; + int retval; + + if (escrypt_init_local(&local)) { + return -1; + } +#if defined(HAVE_EMMINTRIN_H) || defined(_MSC_VER) + escrypt_kdf = + sodium_runtime_has_sse2() ? escrypt_kdf_sse : escrypt_kdf_nosse; +#else + escrypt_kdf = escrypt_kdf_nosse; +#endif + retval = escrypt_kdf(&local, + passwd, passwdlen, salt, saltlen, + N, r, p, buf, buflen); + if (escrypt_free_local(&local)) { + return -1; + } + return retval; +} + +#endif diff --git a/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt.h b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt.h new file mode 100644 index 0000000000..3f0b7d72f5 --- /dev/null +++ b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt.h @@ -0,0 +1,93 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +/*- + * Copyright 2009 Colin Percival + * Copyright 2013 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#ifndef _CRYPTO_SCRYPT_H_ +#define _CRYPTO_SCRYPT_H_ + +#include <stdint.h> + +#define crypto_pwhash_scryptsalsa208sha256_STRPREFIXBYTES 14 +#define crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES 57 +#define crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES 32 +#define crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES_ENCODED 43 +#define crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES 32 +#define crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED 43 + +#define BYTES2CHARS(bytes) ((((bytes) * 8) + 5) / 6) + +typedef struct { + void * base, * aligned; + size_t size; +} escrypt_region_t; + +typedef escrypt_region_t escrypt_local_t; + +extern int escrypt_init_local(escrypt_local_t * __local); + +extern int escrypt_free_local(escrypt_local_t * __local); + +extern void *alloc_region(escrypt_region_t * region, size_t size); +extern int free_region(escrypt_region_t * region); + +typedef int (*escrypt_kdf_t)(escrypt_local_t * __local, + const uint8_t * __passwd, size_t __passwdlen, + const uint8_t * __salt, size_t __saltlen, + uint64_t __N, uint32_t __r, uint32_t __p, + uint8_t * __buf, size_t __buflen); + +extern int escrypt_kdf_nosse(escrypt_local_t * __local, + const uint8_t * __passwd, size_t __passwdlen, + const uint8_t * __salt, size_t __saltlen, + uint64_t __N, uint32_t __r, uint32_t __p, + uint8_t * __buf, size_t __buflen); + +extern int escrypt_kdf_sse(escrypt_local_t * __local, + const uint8_t * __passwd, size_t __passwdlen, + const uint8_t * __salt, size_t __saltlen, + uint64_t __N, uint32_t __r, uint32_t __p, + uint8_t * __buf, size_t __buflen); + +extern uint8_t * escrypt_r(escrypt_local_t * __local, + const uint8_t * __passwd, size_t __passwdlen, + const uint8_t * __setting, + uint8_t * __buf, size_t __buflen); + +extern uint8_t * escrypt_gensalt_r( + uint32_t __N_log2, uint32_t __r, uint32_t __p, + const uint8_t * __src, size_t __srclen, + uint8_t * __buf, size_t __buflen); + +#endif /* !_CRYPTO_SCRYPT_H_ */ + +#endif diff --git a/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/export.h b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/export.h new file mode 100644 index 0000000000..ee5b30f7f1 --- /dev/null +++ b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/export.h @@ -0,0 +1,38 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +#ifndef __SODIUM_EXPORT_H__ +#define __SODIUM_EXPORT_H__ + +#ifndef __GNUC__ +# ifdef __attribute__ +# undef __attribute__ +# endif +# define __attribute__(a) +#endif + +#ifdef SODIUM_STATIC +# define SODIUM_EXPORT +#else +# if defined(_MSC_VER) +# ifdef DLL_EXPORT +# define SODIUM_EXPORT __declspec(dllexport) +# else +# define SODIUM_EXPORT __declspec(dllimport) +# endif +# else +# if defined(__SUNPRO_C) +# define SODIUM_EXPORT __attribute__ __global +# elif defined(_MSG_VER) +# define SODIUM_EXPORT extern __declspec(dllexport) +# else +# define SODIUM_EXPORT __attribute__ ((visibility ("default"))) +# endif +# endif +#endif + +#endif + +#endif diff --git a/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c new file mode 100644 index 0000000000..97d9ba6878 --- /dev/null +++ b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c @@ -0,0 +1,309 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +/*- + * Copyright 2009 Colin Percival + * Copyright 2013 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#include <errno.h> +#include <limits.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "../pbkdf2-sha256.h" +#include "../sysendian.h" +#include "../crypto_scrypt.h" + +static inline void +blkcpy(void * dest, const void * src, size_t len) +{ + size_t * D = (size_t *) dest; + const size_t * S = (const size_t *) src; + size_t L = len / sizeof(size_t); + size_t i; + + for (i = 0; i < L; i++) + D[i] = S[i]; +} + +static inline void +blkxor(void * dest, const void * src, size_t len) +{ + size_t * D = (size_t *) dest; + const size_t * S = (const size_t *) src; + size_t L = len / sizeof(size_t); + size_t i; + + for (i = 0; i < L; i++) + D[i] ^= S[i]; +} + +/** + * salsa20_8(B): + * Apply the salsa20/8 core to the provided block. + */ +static void +salsa20_8(uint32_t B[16]) +{ + uint32_t x[16]; + size_t i; + + blkcpy(x, B, 64); + for (i = 0; i < 8; i += 2) { +#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) + /* Operate on columns. */ + x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); + x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); + + x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); + x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); + + x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); + x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); + + x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); + x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); + + /* Operate on rows. */ + x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); + x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); + + x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); + x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); + + x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); + x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); + + x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); + x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); +#undef R + } + for (i = 0; i < 16; i++) + B[i] += x[i]; +} + +/** + * blockmix_salsa8(Bin, Bout, X, r): + * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r + * bytes in length; the output Bout must also be the same size. The + * temporary space X must be 64 bytes. + */ +static void +blockmix_salsa8(const uint32_t * Bin, uint32_t * Bout, uint32_t * X, size_t r) +{ + size_t i; + + /* 1: X <-- B_{2r - 1} */ + blkcpy(X, &Bin[(2 * r - 1) * 16], 64); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < 2 * r; i += 2) { + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 16], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 8], X, 64); + + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 16 + 16], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 8 + r * 16], X, 64); + } +} + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static inline uint64_t +integerify(const void * B, size_t r) +{ + const uint32_t * X = (const uint32_t *)((uintptr_t)(B) + (2 * r - 1) * 64); + + return (((uint64_t)(X[1]) << 32) + X[0]); +} + +/** + * smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; + * the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a + * multiple of 64 bytes. + */ +static void +smix(uint8_t * B, size_t r, uint64_t N, uint32_t * V, uint32_t * XY) +{ + uint32_t * X = XY; + uint32_t * Y = &XY[32 * r]; + uint32_t * Z = &XY[64 * r]; + uint64_t i; + uint64_t j; + size_t k; + + /* 1: X <-- B */ + for (k = 0; k < 32 * r; k++) + X[k] = le32dec(&B[4 * k]); + + /* 2: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 3: V_i <-- X */ + blkcpy(&V[i * (32 * r)], X, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(X, Y, Z, r); + + /* 3: V_i <-- X */ + blkcpy(&V[(i + 1) * (32 * r)], Y, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(Y, X, Z, r); + } + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(X, &V[j * (32 * r)], 128 * r); + blockmix_salsa8(X, Y, Z, r); + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(Y, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(Y, &V[j * (32 * r)], 128 * r); + blockmix_salsa8(Y, X, Z, r); + } + /* 10: B' <-- X */ + for (k = 0; k < 32 * r; k++) + le32enc(&B[4 * k], X[k]); +} + +/** + * escrypt_kdf(local, passwd, passwdlen, salt, saltlen, + * N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error. + */ +int +escrypt_kdf_nosse(escrypt_local_t * local, + const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, + uint64_t N, uint32_t _r, uint32_t _p, + uint8_t * buf, size_t buflen) +{ + size_t B_size, V_size, XY_size, need; + uint8_t * B; + uint32_t * V, * XY; + size_t r = _r, p = _p; + uint32_t i; + + /* Sanity-check parameters. */ +#if SIZE_MAX > UINT32_MAX + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + return -1; + } +#endif + if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { + errno = EFBIG; + return -1; + } + if (((N & (N - 1)) != 0) || (N < 2)) { + errno = EINVAL; + return -1; + } + if (r == 0 || p == 0) { + errno = EINVAL; + return -1; + } + if ((r > SIZE_MAX / 128 / p) || +#if SIZE_MAX / 256 <= UINT32_MAX + (r > SIZE_MAX / 256) || +#endif + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + return -1; + } + + /* Allocate memory. */ + B_size = (size_t)128 * r * p; + V_size = (size_t)128 * r * N; + need = B_size + V_size; + if (need < V_size) { + errno = ENOMEM; + return -1; + } + XY_size = (size_t)256 * r + 64; + need += XY_size; + if (need < XY_size) { + errno = ENOMEM; + return -1; + } + if (local->size < need) { + if (free_region(local)) + return -1; + if (!alloc_region(local, need)) + return -1; + } + B = (uint8_t *)local->aligned; + V = (uint32_t *)((uint8_t *)B + B_size); + XY = (uint32_t *)((uint8_t *)V + V_size); + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, B_size); + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ + smix(&B[(size_t)128 * i * r], r, N, V, XY); + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + PBKDF2_SHA256(passwd, passwdlen, B, B_size, 1, buf, buflen); + + /* Success! */ + return 0; +} + +#endif diff --git a/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/note_to_maintainers.txt b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/note_to_maintainers.txt new file mode 100644 index 0000000000..66bbfe2db9 --- /dev/null +++ b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/note_to_maintainers.txt @@ -0,0 +1,14 @@ +This folder is only meant for use with nacl, i.e. when sodium is unavailable. + + +The files in this folder were mostly copied from +https://github.com/jedisct1/libsodium/tree/0.7.0/src/libsodium/crypto_pwhash/scryptsalsa208sha256, +with #ifdef VANILLA_NACL added around each of them as required for this module. + +export.h, utils.h, and runtime.h were copied from +https://github.com/jedisct1/libsodium/tree/0.7.0/src/libsodium/include/sodium. +utils.h was significantly truncated. + +utils.c and runtime.c were copied from +https://github.com/jedisct1/libsodium/blob/0.7.0/src/libsodium/sodium. +utils.c was also significantly truncated. diff --git a/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.c b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.c new file mode 100644 index 0000000000..3dfe54db5f --- /dev/null +++ b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.c @@ -0,0 +1,97 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include <crypto_hash_sha256.h> +#include <crypto_auth_hmacsha256.h> + +#include "pbkdf2-sha256.h" +#include "sysendian.h" +#include "utils.h" + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void +PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, + size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen) +{ + uint8_t key[32] = {0}; + size_t i; + uint8_t salt_and_ivec[saltlen + 4]; + uint8_t U[32]; + uint8_t T[32]; + uint64_t j; + int k; + size_t clen; + + if (passwdlen > 32) { + /* For some reason libsodium allows 64byte keys meaning keys + * between 32byte and 64bytes are not compatible with libsodium. + toxencryptsave should only give 32byte passwds so this isn't an issue here.*/ + crypto_hash_sha256(key, passwd, passwdlen); + } else { + memcpy(key, passwd, passwdlen); + } + + memcpy(salt_and_ivec, salt, saltlen); + + for (i = 0; i * 32 < dkLen; i++) { + be32enc(salt_and_ivec + saltlen, (uint32_t)(i + 1)); + crypto_auth_hmacsha256(U, salt_and_ivec, sizeof(salt_and_ivec), key); + + memcpy(T, U, 32); + + for (j = 2; j <= c; j++) { + crypto_auth_hmacsha256(U, U, 32, key); + + for (k = 0; k < 32; k++) { + T[k] ^= U[k]; + } + } + + clen = dkLen - i * 32; + if (clen > 32) { + clen = 32; + } + memcpy(&buf[i * 32], T, clen); + } + sodium_memzero((void *) key, sizeof(key)); +} + +#endif diff --git a/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.h b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.h new file mode 100644 index 0000000000..b74bc6a340 --- /dev/null +++ b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.h @@ -0,0 +1,52 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef _SHA256_H_ +#define _SHA256_H_ + +#include <sys/types.h> + +#include <stdint.h> + +#include "crypto_auth_hmacsha256.h" + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, + uint64_t, uint8_t *, size_t); + +#endif /* !_SHA256_H_ */ + +#endif diff --git a/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c new file mode 100644 index 0000000000..52c51abc3b --- /dev/null +++ b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c @@ -0,0 +1,211 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +#include <errno.h> +#include <limits.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> +//#include <stdio.h> + +#include "crypto_pwhash_scryptsalsa208sha256.h" +#include "crypto_scrypt.h" +#include "randombytes.h" +#include "utils.h" + +#define SETTING_SIZE(saltbytes) \ + (sizeof "$7$" - 1U) + \ + (1U /* N_log2 */) + (5U /* r */) + (5U /* p */) + BYTES2CHARS(saltbytes) + +static int +pickparams(unsigned long long opslimit, const size_t memlimit, + uint32_t * const N_log2, uint32_t * const p, uint32_t * const r) +{ + unsigned long long maxN; + unsigned long long maxrp; + + if (opslimit < 32768) { + opslimit = 32768; + } + *r = 8; + if (opslimit < memlimit / 32) { + *p = 1; + maxN = opslimit / (*r * 4); + for (*N_log2 = 1; *N_log2 < 63; *N_log2 += 1) { + if ((uint64_t)(1) << *N_log2 > maxN / 2) { + break; + } + } + } else { + maxN = memlimit / (*r * 128); + for (*N_log2 = 1; *N_log2 < 63; *N_log2 += 1) { + if ((uint64_t) (1) << *N_log2 > maxN / 2) { + break; + } + } + maxrp = (opslimit / 4) / ((uint64_t) (1) << *N_log2); + if (maxrp > 0x3fffffff) { + maxrp = 0x3fffffff; + } + *p = (uint32_t) (maxrp) / *r; + } + return 0; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_saltbytes(void) +{ + return crypto_pwhash_scryptsalsa208sha256_SALTBYTES; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_strbytes(void) +{ + return crypto_pwhash_scryptsalsa208sha256_STRBYTES; +} + +const char * +crypto_pwhash_scryptsalsa208sha256_strprefix(void) +{ + return crypto_pwhash_scryptsalsa208sha256_STRPREFIX; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_opslimit_interactive(void) +{ + return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_memlimit_interactive(void) +{ + return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(void) +{ + return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(void) +{ + return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE; +} + +int +crypto_pwhash_scryptsalsa208sha256(unsigned char * const out, + unsigned long long outlen, + const char * const passwd, + unsigned long long passwdlen, + const unsigned char * const salt, + unsigned long long opslimit, + size_t memlimit) +{ + //fprintf(stderr, "Doing that dirty thang!!!!\n"); + uint32_t N_log2; + uint32_t p; + uint32_t r; + + memset(out, 0, outlen); + if (passwdlen > SIZE_MAX || outlen > SIZE_MAX) { + errno = EFBIG; + return -1; + } + if (pickparams(opslimit, memlimit, &N_log2, &p, &r) != 0) { + errno = EINVAL; + return -1; + } + return crypto_pwhash_scryptsalsa208sha256_ll((const uint8_t *) passwd, + (size_t) passwdlen, + (const uint8_t *) salt, + crypto_pwhash_scryptsalsa208sha256_SALTBYTES, + (uint64_t) (1) << N_log2, r, p, + out, (size_t) outlen); +} + +int +crypto_pwhash_scryptsalsa208sha256_str(char out[crypto_pwhash_scryptsalsa208sha256_STRBYTES], + const char * const passwd, + unsigned long long passwdlen, + unsigned long long opslimit, + size_t memlimit) +{ + uint8_t salt[crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES]; + char setting[crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES + 1U]; + escrypt_local_t escrypt_local; + uint32_t N_log2; + uint32_t p; + uint32_t r; + + memset(out, 0, crypto_pwhash_scryptsalsa208sha256_STRBYTES); + if (passwdlen > SIZE_MAX) { + errno = EFBIG; + return -1; + } + if (pickparams(opslimit, memlimit, &N_log2, &p, &r) != 0) { + errno = EINVAL; + return -1; + } + randombytes(salt, sizeof salt); + if (escrypt_gensalt_r(N_log2, r, p, salt, sizeof salt, + (uint8_t *) setting, sizeof setting) == NULL) { + errno = EINVAL; + return -1; + } + if (escrypt_init_local(&escrypt_local) != 0) { + return -1; + } + if (escrypt_r(&escrypt_local, (const uint8_t *) passwd, (size_t) passwdlen, + (const uint8_t *) setting, (uint8_t *) out, + crypto_pwhash_scryptsalsa208sha256_STRBYTES) == NULL) { + escrypt_free_local(&escrypt_local); + errno = EINVAL; + return -1; + } + escrypt_free_local(&escrypt_local); + + (void) sizeof + (int[SETTING_SIZE(crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES) + == crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES ? 1 : -1]); + (void) sizeof + (int[crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES + 1U + + crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED + 1U + == crypto_pwhash_scryptsalsa208sha256_STRBYTES ? 1 : -1]); + + return 0; +} + +int +crypto_pwhash_scryptsalsa208sha256_str_verify(const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES], + const char * const passwd, + unsigned long long passwdlen) +{ + char wanted[crypto_pwhash_scryptsalsa208sha256_STRBYTES]; + escrypt_local_t escrypt_local; + int ret = -1; + + if (memchr(str, 0, crypto_pwhash_scryptsalsa208sha256_STRBYTES) != + &str[crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1U]) { + return -1; + } + if (escrypt_init_local(&escrypt_local) != 0) { + return -1; + } + if (escrypt_r(&escrypt_local, (const uint8_t *) passwd, (size_t) passwdlen, + (const uint8_t *) str, (uint8_t *) wanted, + sizeof wanted) == NULL) { + escrypt_free_local(&escrypt_local); + return -1; + } + escrypt_free_local(&escrypt_local); + ret = sodium_memcmp(wanted, str, sizeof wanted); + sodium_memzero(wanted, sizeof wanted); + + return ret; +} + +#endif diff --git a/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.c b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.c new file mode 100644 index 0000000000..9b5c513193 --- /dev/null +++ b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.c @@ -0,0 +1,140 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +#ifdef HAVE_ANDROID_GETCPUFEATURES +# include <cpu-features.h> +#endif + +#include "runtime.h" + +typedef struct CPUFeatures_ { + int initialized; + int has_neon; + int has_sse2; + int has_sse3; +} CPUFeatures; + +static CPUFeatures _cpu_features; + +#define CPUID_SSE2 0x04000000 +#define CPUIDECX_SSE3 0x00000001 + +static int +_sodium_runtime_arm_cpu_features(CPUFeatures * const cpu_features) +{ +#ifndef __arm__ + cpu_features->has_neon = 0; + return -1; +#else +# ifdef __APPLE__ +# ifdef __ARM_NEON__ + cpu_features->has_neon = 1; +# else + cpu_features->has_neon = 0; +# endif +# elif defined(HAVE_ANDROID_GETCPUFEATURES) && defined(ANDROID_CPU_ARM_FEATURE_NEON) + cpu_features->has_neon = + (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0x0; +# else + cpu_features->has_neon = 0; +# endif + return 0; +#endif +} + +static void +_cpuid(unsigned int cpu_info[4U], const unsigned int cpu_info_type) +{ +#ifdef _MSC_VER + __cpuidex((int *) cpu_info, cpu_info_type, 0); +#elif defined(HAVE_CPUID) + cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0; +# ifdef __i386__ + __asm__ __volatile__ ("pushfl; pushfl; " + "popl %0; " + "movl %0, %1; xorl %2, %0; " + "pushl %0; " + "popfl; pushfl; popl %0; popfl" : + "=&r" (cpu_info[0]), "=&r" (cpu_info[1]) : + "i" (0x200000)); + if (((cpu_info[0] ^ cpu_info[1]) & 0x200000) == 0x0) { + return; + } +# endif +# ifdef __i386__ + __asm__ __volatile__ ("xchgl %%ebx, %k1; cpuid; xchgl %%ebx, %k1" : + "=a" (cpu_info[0]), "=&r" (cpu_info[1]), + "=c" (cpu_info[2]), "=d" (cpu_info[3]) : + "0" (cpu_info_type), "2" (0U)); +# elif defined(__x86_64__) + __asm__ __volatile__ ("xchgq %%rbx, %q1; cpuid; xchgq %%rbx, %q1" : + "=a" (cpu_info[0]), "=&r" (cpu_info[1]), + "=c" (cpu_info[2]), "=d" (cpu_info[3]) : + "0" (cpu_info_type), "2" (0U)); +# else + __asm__ __volatile__ ("cpuid" : + "=a" (cpu_info[0]), "=b" (cpu_info[1]), + "=c" (cpu_info[2]), "=d" (cpu_info[3]) : + "0" (cpu_info_type), "2" (0U)); +# endif +#else + cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0; +#endif +} + +static int +_sodium_runtime_intel_cpu_features(CPUFeatures * const cpu_features) +{ + unsigned int cpu_info[4]; + unsigned int id; + + _cpuid(cpu_info, 0x0); + if ((id = cpu_info[0]) == 0U) { + return -1; + } + _cpuid(cpu_info, 0x00000001); +#ifndef HAVE_EMMINTRIN_H + cpu_features->has_sse2 = 0; +#else + cpu_features->has_sse2 = ((cpu_info[3] & CPUID_SSE2) != 0x0); +#endif + +#ifndef HAVE_PMMINTRIN_H + cpu_features->has_sse3 = 0; +#else + cpu_features->has_sse3 = ((cpu_info[2] & CPUIDECX_SSE3) != 0x0); +#endif + + return 0; +} + +int +sodium_runtime_get_cpu_features(void) +{ + int ret = -1; + + ret &= _sodium_runtime_arm_cpu_features(&_cpu_features); + ret &= _sodium_runtime_intel_cpu_features(&_cpu_features); + _cpu_features.initialized = 1; + + return ret; +} + +int +sodium_runtime_has_neon(void) { + return _cpu_features.has_neon; +} + +int +sodium_runtime_has_sse2(void) { + return _cpu_features.has_sse2; +} + +int +sodium_runtime_has_sse3(void) { + return _cpu_features.has_sse3; +} + +#endif diff --git a/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.h b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.h new file mode 100644 index 0000000000..874915ef42 --- /dev/null +++ b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.h @@ -0,0 +1,33 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +#ifndef __SODIUM_RUNTIME_H__ +#define __SODIUM_RUNTIME_H__ 1 + +#include "export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +SODIUM_EXPORT +int sodium_runtime_get_cpu_features(void); + +SODIUM_EXPORT +int sodium_runtime_has_neon(void); + +SODIUM_EXPORT +int sodium_runtime_has_sse2(void); + +SODIUM_EXPORT +int sodium_runtime_has_sse3(void); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif diff --git a/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/scrypt_platform.c b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/scrypt_platform.c new file mode 100644 index 0000000000..5819651454 --- /dev/null +++ b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/scrypt_platform.c @@ -0,0 +1,107 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +/*- + * Copyright 2013 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_SYS_MMAN_H +# include <sys/mman.h> +#endif +#include <errno.h> +#include <stdlib.h> + +#include "crypto_scrypt.h" +#include "runtime.h" + +#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS) +# define MAP_ANON MAP_ANONYMOUS +#endif + +void * +alloc_region(escrypt_region_t * region, size_t size) +{ + uint8_t * base, * aligned; +#ifdef MAP_ANON + if ((base = (uint8_t *) mmap(NULL, size, PROT_READ | PROT_WRITE, +#ifdef MAP_NOCORE + MAP_ANON | MAP_PRIVATE | MAP_NOCORE, +#else + MAP_ANON | MAP_PRIVATE, +#endif + -1, 0)) == MAP_FAILED) + base = NULL; + aligned = base; +#elif defined(HAVE_POSIX_MEMALIGN) + if ((errno = posix_memalign((void **) &base, 64, size)) != 0) + base = NULL; + aligned = base; +#else + base = aligned = NULL; + if (size + 63 < size) + errno = ENOMEM; + else if ((base = (uint8_t *) malloc(size + 63)) != NULL) { + aligned = base + 63; + aligned -= (uintptr_t)aligned & 63; + } +#endif + region->base = base; + region->aligned = aligned; + region->size = base ? size : 0; + return aligned; +} + +static inline void +init_region(escrypt_region_t * region) +{ + region->base = region->aligned = NULL; + region->size = 0; +} + +int +free_region(escrypt_region_t * region) +{ + if (region->base) { +#ifdef MAP_ANON + if (munmap(region->base, region->size)) + return -1; +#else + free(region->base); +#endif + } + init_region(region); + return 0; +} + +int +escrypt_init_local(escrypt_local_t * local) +{ + init_region(local); + return 0; +} + +int +escrypt_free_local(escrypt_local_t * local) +{ + return free_region(local); +} + +#endif diff --git a/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c new file mode 100644 index 0000000000..856a655e3f --- /dev/null +++ b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c @@ -0,0 +1,398 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +/*- + * Copyright 2009 Colin Percival + * Copyright 2012,2013 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#if defined(HAVE_EMMINTRIN_H) || defined(_MSC_VER) +#if __GNUC__ +# pragma GCC target("sse2") +#endif +#include <emmintrin.h> +#if defined(__XOP__) && defined(DISABLED) +# include <x86intrin.h> +#endif + +#include <errno.h> +#include <limits.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "../pbkdf2-sha256.h" +#include "../sysendian.h" +#include "../crypto_scrypt.h" + +#if defined(__XOP__) && defined(DISABLED) +#define ARX(out, in1, in2, s) \ + out = _mm_xor_si128(out, _mm_roti_epi32(_mm_add_epi32(in1, in2), s)); +#else +#define ARX(out, in1, in2, s) \ + { \ + __m128i T = _mm_add_epi32(in1, in2); \ + out = _mm_xor_si128(out, _mm_slli_epi32(T, s)); \ + out = _mm_xor_si128(out, _mm_srli_epi32(T, 32-s)); \ + } +#endif + +#define SALSA20_2ROUNDS \ + /* Operate on "columns". */ \ + ARX(X1, X0, X3, 7) \ + ARX(X2, X1, X0, 9) \ + ARX(X3, X2, X1, 13) \ + ARX(X0, X3, X2, 18) \ +\ + /* Rearrange data. */ \ + X1 = _mm_shuffle_epi32(X1, 0x93); \ + X2 = _mm_shuffle_epi32(X2, 0x4E); \ + X3 = _mm_shuffle_epi32(X3, 0x39); \ +\ + /* Operate on "rows". */ \ + ARX(X3, X0, X1, 7) \ + ARX(X2, X3, X0, 9) \ + ARX(X1, X2, X3, 13) \ + ARX(X0, X1, X2, 18) \ +\ + /* Rearrange data. */ \ + X1 = _mm_shuffle_epi32(X1, 0x39); \ + X2 = _mm_shuffle_epi32(X2, 0x4E); \ + X3 = _mm_shuffle_epi32(X3, 0x93); + +/** + * Apply the salsa20/8 core to the block provided in (X0 ... X3) ^ (Z0 ... Z3). + */ +#define SALSA20_8_XOR(in, out) \ + { \ + __m128i Y0 = X0 = _mm_xor_si128(X0, (in)[0]); \ + __m128i Y1 = X1 = _mm_xor_si128(X1, (in)[1]); \ + __m128i Y2 = X2 = _mm_xor_si128(X2, (in)[2]); \ + __m128i Y3 = X3 = _mm_xor_si128(X3, (in)[3]); \ + SALSA20_2ROUNDS \ + SALSA20_2ROUNDS \ + SALSA20_2ROUNDS \ + SALSA20_2ROUNDS \ + (out)[0] = X0 = _mm_add_epi32(X0, Y0); \ + (out)[1] = X1 = _mm_add_epi32(X1, Y1); \ + (out)[2] = X2 = _mm_add_epi32(X2, Y2); \ + (out)[3] = X3 = _mm_add_epi32(X3, Y3); \ + } + +/** + * blockmix_salsa8(Bin, Bout, r): + * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r + * bytes in length; the output Bout must also be the same size. + */ +static inline void +blockmix_salsa8(const __m128i * Bin, __m128i * Bout, size_t r) +{ + __m128i X0, X1, X2, X3; + size_t i; + + /* 1: X <-- B_{2r - 1} */ + X0 = Bin[8 * r - 4]; + X1 = Bin[8 * r - 3]; + X2 = Bin[8 * r - 2]; + X3 = Bin[8 * r - 1]; + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + SALSA20_8_XOR(Bin, Bout) + + /* 2: for i = 0 to 2r - 1 do */ + r--; + for (i = 0; i < r;) { + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + SALSA20_8_XOR(&Bin[i * 8 + 4], &Bout[(r + i) * 4 + 4]) + + i++; + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + SALSA20_8_XOR(&Bin[i * 8], &Bout[i * 4]) + } + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + SALSA20_8_XOR(&Bin[i * 8 + 4], &Bout[(r + i) * 4 + 4]) +} + +#define XOR4(in) \ + X0 = _mm_xor_si128(X0, (in)[0]); \ + X1 = _mm_xor_si128(X1, (in)[1]); \ + X2 = _mm_xor_si128(X2, (in)[2]); \ + X3 = _mm_xor_si128(X3, (in)[3]); + +#define XOR4_2(in1, in2) \ + X0 = _mm_xor_si128((in1)[0], (in2)[0]); \ + X1 = _mm_xor_si128((in1)[1], (in2)[1]); \ + X2 = _mm_xor_si128((in1)[2], (in2)[2]); \ + X3 = _mm_xor_si128((in1)[3], (in2)[3]); + +static inline uint32_t +blockmix_salsa8_xor(const __m128i * Bin1, const __m128i * Bin2, __m128i * Bout, + size_t r) +{ + __m128i X0, X1, X2, X3; + size_t i; + + /* 1: X <-- B_{2r - 1} */ + XOR4_2(&Bin1[8 * r - 4], &Bin2[8 * r - 4]) + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(Bin1) + SALSA20_8_XOR(Bin2, Bout) + + /* 2: for i = 0 to 2r - 1 do */ + r--; + for (i = 0; i < r;) { + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(&Bin1[i * 8 + 4]) + SALSA20_8_XOR(&Bin2[i * 8 + 4], &Bout[(r + i) * 4 + 4]) + + i++; + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(&Bin1[i * 8]) + SALSA20_8_XOR(&Bin2[i * 8], &Bout[i * 4]) + } + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(&Bin1[i * 8 + 4]) + SALSA20_8_XOR(&Bin2[i * 8 + 4], &Bout[(r + i) * 4 + 4]) + + return _mm_cvtsi128_si32(X0); +} + +#undef ARX +#undef SALSA20_2ROUNDS +#undef SALSA20_8_XOR +#undef XOR4 +#undef XOR4_2 + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static inline uint32_t +integerify(const void * B, size_t r) +{ + return *(const uint32_t *)((uintptr_t)(B) + (2 * r - 1) * 64); +} + +/** + * smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; + * the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a + * multiple of 64 bytes. + */ +static void +smix(uint8_t * B, size_t r, uint32_t N, void * V, void * XY) +{ + size_t s = 128 * r; + __m128i * X = (__m128i *) V, * Y; + uint32_t * X32 = (uint32_t *) V; + uint32_t i, j; + size_t k; + + /* 1: X <-- B */ + /* 3: V_i <-- X */ + for (k = 0; k < 2 * r; k++) { + for (i = 0; i < 16; i++) { + X32[k * 16 + i] = + le32dec(&B[(k * 16 + (i * 5 % 16)) * 4]); + } + } + + /* 2: for i = 0 to N - 1 do */ + for (i = 1; i < N - 1; i += 2) { + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + Y = (__m128i *)((uintptr_t)(V) + i * s); + blockmix_salsa8(X, Y, r); + + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + X = (__m128i *)((uintptr_t)(V) + (i + 1) * s); + blockmix_salsa8(Y, X, r); + } + + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + Y = (__m128i *)((uintptr_t)(V) + i * s); + blockmix_salsa8(X, Y, r); + + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + X = (__m128i *) XY; + blockmix_salsa8(Y, X, r); + + X32 = (uint32_t *) XY; + Y = (__m128i *)((uintptr_t)(XY) + s); + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + __m128i * V_j = (__m128i *)((uintptr_t)(V) + j * s); + + /* 8: X <-- H(X \xor V_j) */ + /* 7: j <-- Integerify(X) mod N */ + j = blockmix_salsa8_xor(X, V_j, Y, r) & (N - 1); + V_j = (__m128i *)((uintptr_t)(V) + j * s); + + /* 8: X <-- H(X \xor V_j) */ + /* 7: j <-- Integerify(X) mod N */ + j = blockmix_salsa8_xor(Y, V_j, X, r) & (N - 1); + } + + /* 10: B' <-- X */ + for (k = 0; k < 2 * r; k++) { + for (i = 0; i < 16; i++) { + le32enc(&B[(k * 16 + (i * 5 % 16)) * 4], + X32[k * 16 + i]); + } + } +} + +/** + * escrypt_kdf(local, passwd, passwdlen, salt, saltlen, + * N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error. + */ +int +escrypt_kdf_sse(escrypt_local_t * local, + const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, + uint64_t N, uint32_t _r, uint32_t _p, + uint8_t * buf, size_t buflen) +{ + size_t B_size, V_size, XY_size, need; + uint8_t * B; + uint32_t * V, * XY; + size_t r = _r, p = _p; + uint32_t i; + + /* Sanity-check parameters. */ +#if SIZE_MAX > UINT32_MAX + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + return -1; + } +#endif + if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { + errno = EFBIG; + return -1; + } + if (N > UINT32_MAX) { + errno = EFBIG; + return -1; + } + if (((N & (N - 1)) != 0) || (N < 2)) { + errno = EINVAL; + return -1; + } + if (r == 0 || p == 0) { + errno = EINVAL; + return -1; + } + if ((r > SIZE_MAX / 128 / p) || +#if SIZE_MAX / 256 <= UINT32_MAX + (r > SIZE_MAX / 256) || +#endif + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + return -1; + } + + /* Allocate memory. */ + B_size = (size_t)128 * r * p; + V_size = (size_t)128 * r * N; + need = B_size + V_size; + if (need < V_size) { + errno = ENOMEM; + return -1; + } + XY_size = (size_t)256 * r + 64; + need += XY_size; + if (need < XY_size) { + errno = ENOMEM; + return -1; + } + if (local->size < need) { + if (free_region(local)) + return -1; + if (!alloc_region(local, need)) + return -1; + } + B = (uint8_t *)local->aligned; + V = (uint32_t *)((uint8_t *)B + B_size); + XY = (uint32_t *)((uint8_t *)V + V_size); + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, B_size); + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ + smix(&B[(size_t)128 * i * r], r, N, V, XY); + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + PBKDF2_SHA256(passwd, passwdlen, B, B_size, 1, buf, buflen); + + /* Success! */ + return 0; +} +#endif + +#endif diff --git a/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sysendian.h b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sysendian.h new file mode 100644 index 0000000000..04e5c1ed45 --- /dev/null +++ b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sysendian.h @@ -0,0 +1,153 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +#ifndef _SYSENDIAN_H_ +#define _SYSENDIAN_H_ + +#include <stdint.h> + +/* Avoid namespace collisions with BSD <sys/endian.h>. */ +#define be16dec scrypt_be16dec +#define be16enc scrypt_be16enc +#define be32dec scrypt_be32dec +#define be32enc scrypt_be32enc +#define be64dec scrypt_be64dec +#define be64enc scrypt_be64enc +#define le16dec scrypt_le16dec +#define le16enc scrypt_le16enc +#define le32dec scrypt_le32dec +#define le32enc scrypt_le32enc +#define le64dec scrypt_le64dec +#define le64enc scrypt_le64enc + +static inline uint16_t +be16dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint16_t)(p[1]) + ((uint16_t)(p[0]) << 8)); +} + +static inline void +be16enc(void *pp, uint16_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[1] = x & 0xff; + p[0] = (x >> 8) & 0xff; +} + +static inline uint32_t +be32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + + ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); +} + +static inline void +be32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[3] = x & 0xff; + p[2] = (x >> 8) & 0xff; + p[1] = (x >> 16) & 0xff; + p[0] = (x >> 24) & 0xff; +} + +static inline uint64_t +be64dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint64_t)(p[7]) + ((uint64_t)(p[6]) << 8) + + ((uint64_t)(p[5]) << 16) + ((uint64_t)(p[4]) << 24) + + ((uint64_t)(p[3]) << 32) + ((uint64_t)(p[2]) << 40) + + ((uint64_t)(p[1]) << 48) + ((uint64_t)(p[0]) << 56)); +} + +static inline void +be64enc(void *pp, uint64_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[7] = x & 0xff; + p[6] = (x >> 8) & 0xff; + p[5] = (x >> 16) & 0xff; + p[4] = (x >> 24) & 0xff; + p[3] = (x >> 32) & 0xff; + p[2] = (x >> 40) & 0xff; + p[1] = (x >> 48) & 0xff; + p[0] = (x >> 56) & 0xff; +} + +static inline uint16_t +le16dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint16_t)(p[0]) + ((uint16_t)(p[1]) << 8)); +} + +static inline void +le16enc(void *pp, uint16_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; +} + +static inline uint32_t +le32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) + + ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24)); +} + +static inline void +le32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; +} + +static inline uint64_t +le64dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint64_t)(p[0]) + ((uint64_t)(p[1]) << 8) + + ((uint64_t)(p[2]) << 16) + ((uint64_t)(p[3]) << 24) + + ((uint64_t)(p[4]) << 32) + ((uint64_t)(p[5]) << 40) + + ((uint64_t)(p[6]) << 48) + ((uint64_t)(p[7]) << 56)); +} + +static inline void +le64enc(void *pp, uint64_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; + p[4] = (x >> 32) & 0xff; + p[5] = (x >> 40) & 0xff; + p[6] = (x >> 48) & 0xff; + p[7] = (x >> 56) & 0xff; +} + +#endif /* !_SYSENDIAN_H_ */ + +#endif diff --git a/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.c b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.c new file mode 100644 index 0000000000..e61ccf3ecf --- /dev/null +++ b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.c @@ -0,0 +1,78 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +#ifndef __STDC_WANT_LIB_EXT1__ +# define __STDC_WANT_LIB_EXT1__ 1 +#endif +#include <assert.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#ifdef HAVE_SYS_MMAN_H +# include <sys/mman.h> +#endif + +#include "utils.h" + +#ifdef _WIN32 +# include <windows.h> +# include <wincrypt.h> +#else +# include <unistd.h> +#endif + +#ifdef HAVE_WEAK_SYMBOLS +__attribute__((weak)) void +__sodium_dummy_symbol_to_prevent_lto(void * const pnt, const size_t len) +{ + (void) pnt; + (void) len; +} +#endif + +void +sodium_memzero(void * const pnt, const size_t len) +{ +#ifdef _WIN32 + SecureZeroMemory(pnt, len); +#elif defined(HAVE_MEMSET_S) + if (memset_s(pnt, (rsize_t) len, 0, (rsize_t) len) != 0) { + abort(); + } +#elif defined(HAVE_EXPLICIT_BZERO) + explicit_bzero(pnt, len); +#elif HAVE_WEAK_SYMBOLS + memset(pnt, 0, len); + __sodium_dummy_symbol_to_prevent_lto(pnt, len); +#else + volatile unsigned char *pnt_ = (volatile unsigned char *) pnt; + size_t i = (size_t) 0U; + + while (i < len) { + pnt_[i++] = 0U; + } +#endif +} + +int +sodium_memcmp(const void * const b1_, const void * const b2_, size_t len) +{ + const unsigned char *b1 = (const unsigned char *) b1_; + const unsigned char *b2 = (const unsigned char *) b2_; + size_t i; + unsigned char d = (unsigned char) 0U; + + for (i = 0U; i < len; i++) { + d |= b1[i] ^ b2[i]; + } + return (int) ((1 & ((d - 1) >> 8)) - 1); +} + +#endif diff --git a/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.h b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.h new file mode 100644 index 0000000000..fb2020c35d --- /dev/null +++ b/protocols/Tox/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.h @@ -0,0 +1,40 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +#ifndef __SODIUM_UTILS_H__ +#define __SODIUM_UTILS_H__ + +#include <stddef.h> + +#include "export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__cplusplus) || !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L +# define _SODIUM_C99(X) +#else +# define _SODIUM_C99(X) X +#endif + +SODIUM_EXPORT +void sodium_memzero(void * const pnt, const size_t len); + +/* WARNING: sodium_memcmp() must be used to verify if two secret keys + * are equal, in constant time. + * It returns 0 if the keys are equal, and -1 if they differ. + * This function is not designed for lexicographical comparisons. + */ +SODIUM_EXPORT +int sodium_memcmp(const void * const b1_, const void * const b2_, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif diff --git a/protocols/Tox/libtox/src/toxencryptsave/defines.h b/protocols/Tox/libtox/src/toxencryptsave/defines.h new file mode 100644 index 0000000000..e3fca073e3 --- /dev/null +++ b/protocols/Tox/libtox/src/toxencryptsave/defines.h @@ -0,0 +1,2 @@ +#define TOX_ENC_SAVE_MAGIC_NUMBER "toxEsave" +#define TOX_ENC_SAVE_MAGIC_LENGTH 8 diff --git a/protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.api.h b/protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.api.h new file mode 100644 index 0000000000..61f685f86b --- /dev/null +++ b/protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.api.h @@ -0,0 +1,327 @@ +%{ +/* + * Batch encryption functions. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013-2016 Tox Developers. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef TOXENCRYPTSAVE_H +#define TOXENCRYPTSAVE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +%} + +/******************************************************************************* + * + * This module is organized into two parts. + * + * 1. A simple API operating on plain text/cipher text data and a password to + * encrypt or decrypt it. + * 2. A more advanced API that splits key derivation and encryption into two + * separate function calls. + * + * The first part is implemented in terms of the second part and simply calls + * the separate functions in sequence. Since key derivation is very expensive + * compared to the actual encryption, clients that do a lot of crypto should + * prefer the advanced API and reuse pass-key objects. + * + * To use the second part, first derive an encryption key from a password with + * ${tox.pass_Key.derive}, then use the derived key to encrypt the data. + * + * The encrypted data is prepended with a magic number, to aid validity + * checking (no guarantees are made of course). Any data to be decrypted must + * start with the magic number. + * + * Clients should consider alerting their users that, unlike plain data, if + * even one bit becomes corrupted, the data will be entirely unrecoverable. + * Ditto if they forget their password, there is no way to recover the data. + * + *******************************************************************************/ + +class tox { + +/** + * The size of the salt part of a pass-key. + */ +const PASS_SALT_LENGTH = 32; +/** + * The size of the key part of a pass-key. + */ +const PASS_KEY_LENGTH = 32; +/** + * The amount of additional data required to store any encrypted byte array. + * Encrypting an array of N bytes requires N + $PASS_ENCRYPTION_EXTRA_LENGTH + * bytes in the encrypted byte array. + */ +const PASS_ENCRYPTION_EXTRA_LENGTH = 80; + +error for key_derivation { + NULL, + /** + * The crypto lib was unable to derive a key from the given passphrase, + * which is usually a lack of memory issue. The functions accepting keys + * do not produce this error. + */ + FAILED, +} + +error for encryption { + NULL, + /** + * The crypto lib was unable to derive a key from the given passphrase, + * which is usually a lack of memory issue. The functions accepting keys + * do not produce this error. + */ + KEY_DERIVATION_FAILED, + /** + * The encryption itself failed. + */ + FAILED, +} + +error for decryption { + NULL, + /** + * The input data was shorter than $PASS_ENCRYPTION_EXTRA_LENGTH bytes + */ + INVALID_LENGTH, + /** + * The input data is missing the magic number (i.e. wasn't created by this + * module, or is corrupted). + */ + BAD_FORMAT, + /** + * The crypto lib was unable to derive a key from the given passphrase, + * which is usually a lack of memory issue. The functions accepting keys + * do not produce this error. + */ + KEY_DERIVATION_FAILED, + /** + * The encrypted byte array could not be decrypted. Either the data was + * corrupted or the password/key was incorrect. + */ + FAILED, +} + + +/******************************************************************************* + * + * BEGIN PART 1 + * + * The simple API is presented first. If your code spends too much time using + * these functions, consider using the advanced functions instead and caching + * the generated pass-key. + * + *******************************************************************************/ + +/** + * Encrypts the given data with the given passphrase. + * + * The output array must be at least `plaintext_len + $PASS_ENCRYPTION_EXTRA_LENGTH` + * bytes long. This delegates to ${pass_Key.derive} and + * ${pass_Key.encrypt}. + * + * @param plaintext A byte array of length `plaintext_len`. + * @param plaintext_len The length of the plain text array. Bigger than 0. + * @param passphrase The user-provided password. Can be empty. + * @param passphrase_len The length of the password. + * @param ciphertext The cipher text array to write the encrypted data to. + * + * @return true on success. + */ +static bool pass_encrypt(const uint8_t[plaintext_len] plaintext, const uint8_t[passphrase_len] passphrase, uint8_t *ciphertext) + with error for encryption; + + +/** + * Decrypts the given data with the given passphrase. + * + * The output array must be at least `ciphertext_len - $PASS_ENCRYPTION_EXTRA_LENGTH` + * bytes long. This delegates to ${pass_Key.decrypt}. + * + * @param ciphertext A byte array of length `ciphertext_len`. + * @param ciphertext_len The length of the cipher text array. At least $PASS_ENCRYPTION_EXTRA_LENGTH. + * @param passphrase The user-provided password. Can be empty. + * @param passphrase_len The length of the password. + * @param plaintext The plain text array to write the decrypted data to. + * + * @return true on success. + */ +static bool pass_decrypt(const uint8_t[ciphertext_len] ciphertext, const uint8_t[passphrase_len] passphrase, uint8_t *plaintext) + with error for decryption; + + +/******************************************************************************* + * + * BEGIN PART 2 + * + * And now part 2, which does the actual encryption, and can be used to write + * less CPU intensive client code than part one. + * + *******************************************************************************/ + +class pass_Key { + /** + * This type represents a pass-key. + * + * A pass-key and a password are two different concepts: a password is given + * by the user in plain text. A pass-key is the generated symmetric key used + * for encryption and decryption. It is derived from a salt and the user- + * provided password. + * + * The $this structure is hidden in the implementation. It can be allocated + * using $new and must be deallocated using $free. + */ + struct this; + + /** + * Create a new $this. The initial value of it is indeterminate. To + * initialise it, use one of the derive_* functions below. + * + * In case of failure, this function returns NULL. The only failure mode at + * this time is memory allocation failure, so this function has no error code. + */ + static this new(); + + /** + * Deallocate a $this. This function behaves like free(), so NULL is an + * acceptable argument value. + */ + void free(); + + /** + * Generates a secret symmetric key from the given passphrase. + * + * Be sure to not compromise the key! Only keep it in memory, do not write + * it to disk. + * + * Note that this function is not deterministic; to derive the same key from + * a password, you also must know the random salt that was used. A + * deterministic version of this function is $derive_with_salt. + * + * @param passphrase The user-provided password. Can be empty. + * @param passphrase_len The length of the password. + * + * @return true on success. + */ + bool derive(const uint8_t[passphrase_len] passphrase) + with error for key_derivation; + + /** + * Same as above, except use the given salt for deterministic key derivation. + * + * @param passphrase The user-provided password. Can be empty. + * @param passphrase_len The length of the password. + * @param salt An array of at least $PASS_SALT_LENGTH bytes. + * + * @return true on success. + */ + bool derive_with_salt(const uint8_t[passphrase_len] passphrase, const uint8_t[PASS_SALT_LENGTH] salt) + with error for key_derivation; + + /** + * Encrypt a plain text with a key produced by $derive or $derive_with_salt. + * + * The output array must be at least `plaintext_len + $PASS_ENCRYPTION_EXTRA_LENGTH` + * bytes long. + * + * @param plaintext A byte array of length `plaintext_len`. + * @param plaintext_len The length of the plain text array. Bigger than 0. + * @param ciphertext The cipher text array to write the encrypted data to. + * + * @return true on success. + */ + const bool encrypt(const uint8_t[plaintext_len] plaintext, uint8_t *ciphertext) + with error for encryption; + + /** + * This is the inverse of $encrypt, also using only keys produced by + * $derive or $derive_with_salt. + * + * @param ciphertext A byte array of length `ciphertext_len`. + * @param ciphertext_len The length of the cipher text array. At least $PASS_ENCRYPTION_EXTRA_LENGTH. + * @param plaintext The plain text array to write the decrypted data to. + * + * @return true on success. + */ + const bool decrypt(const uint8_t[ciphertext_len] ciphertext, uint8_t *plaintext) + with error for decryption; +} + +/** + * Retrieves the salt used to encrypt the given data. + * + * The retrieved salt can then be passed to ${pass_Key.derive_with_salt} to + * produce the same key as was previously used. Any data encrypted with this + * module can be used as input. + * + * The cipher text must be at least $PASS_ENCRYPTION_EXTRA_LENGTH bytes in length. + * The salt must be $PASS_SALT_LENGTH bytes in length. + * If the passed byte arrays are smaller than required, the behaviour is + * undefined. + * + * If the cipher text pointer or the salt is NULL, this function returns false. + * + * Success does not say anything about the validity of the data, only that + * data of the appropriate size was copied. + * + * @return true on success. + */ +static bool get_salt(const uint8_t *ciphertext, uint8_t[PASS_SALT_LENGTH] salt) { + NULL, + /** + * The input data is missing the magic number (i.e. wasn't created by this + * module, or is corrupted). + */ + BAD_FORMAT, +} + +/** + * Determines whether or not the given data is encrypted by this module. + * + * It does this check by verifying that the magic number is the one put in + * place by the encryption functions. + * + * The data must be at least $PASS_ENCRYPTION_EXTRA_LENGTH bytes in length. + * If the passed byte array is smaller than required, the behaviour is + * undefined. + * + * If the data pointer is NULL, the behaviour is undefined + * + * @return true if the data is encrypted by this module. + */ +static bool is_data_encrypted(const uint8_t *data); + +} + +%{ + +#ifdef __cplusplus +} +#endif + +#endif +%} diff --git a/protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.c b/protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.c new file mode 100644 index 0000000000..5640e82fc7 --- /dev/null +++ b/protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.c @@ -0,0 +1,338 @@ +/* + * Batch encryption functions. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox 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 3 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../toxcore/crypto_core.h" +#include "defines.h" +#include "toxencryptsave.h" +#define SET_ERROR_PARAMETER(param, x) {if(param) {*param = x;}} + +#ifdef VANILLA_NACL +#include <crypto_box.h> +#include <crypto_hash_sha256.h> +#include "crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h" +#define crypto_box_MACBYTES (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES) +#else +#include <sodium.h> +#endif + +#include <string.h> + +#if TOX_PASS_SALT_LENGTH != crypto_pwhash_scryptsalsa208sha256_SALTBYTES +#error TOX_PASS_SALT_LENGTH is assumed to be equal to crypto_pwhash_scryptsalsa208sha256_SALTBYTES +#endif + +#if TOX_PASS_KEY_LENGTH != CRYPTO_SHARED_KEY_SIZE +#error TOX_PASS_KEY_LENGTH is assumed to be equal to CRYPTO_SHARED_KEY_SIZE +#endif + +#if TOX_PASS_ENCRYPTION_EXTRA_LENGTH != (crypto_box_MACBYTES + crypto_box_NONCEBYTES + crypto_pwhash_scryptsalsa208sha256_SALTBYTES + TOX_ENC_SAVE_MAGIC_LENGTH) +#error TOX_PASS_ENCRYPTION_EXTRA_LENGTH is assumed to be equal to (crypto_box_MACBYTES + crypto_box_NONCEBYTES + crypto_pwhash_scryptsalsa208sha256_SALTBYTES + TOX_ENC_SAVE_MAGIC_LENGTH) +#endif + +uint32_t tox_pass_salt_length(void) +{ + return TOX_PASS_SALT_LENGTH; +} +uint32_t tox_pass_key_length(void) +{ + return TOX_PASS_KEY_LENGTH; +} +uint32_t tox_pass_encryption_extra_length(void) +{ + return TOX_PASS_ENCRYPTION_EXTRA_LENGTH; +} + +struct Tox_Pass_Key { + uint8_t salt[TOX_PASS_SALT_LENGTH]; + uint8_t key[TOX_PASS_KEY_LENGTH]; +}; + +Tox_Pass_Key *tox_pass_key_new(void) +{ + return (Tox_Pass_Key *)malloc(sizeof(Tox_Pass_Key)); +} + +void tox_pass_key_free(Tox_Pass_Key *pass_key) +{ + free(pass_key); +} + +/* Clients should consider alerting their users that, unlike plain data, if even one bit + * becomes corrupted, the data will be entirely unrecoverable. + * Ditto if they forget their password, there is no way to recover the data. + */ + +/* This retrieves the salt used to encrypt the given data, which can then be passed to + * tox_pass_key_derive_with_salt to produce the same key as was previously used. Any encrpyted + * data with this module can be used as input. + * + * returns true if magic number matches + * success does not say anything about the validity of the data, only that data of + * the appropriate size was copied + */ +bool tox_get_salt(const uint8_t *data, uint8_t *salt, TOX_ERR_GET_SALT *error) +{ + if (!data || !salt) { + SET_ERROR_PARAMETER(error, TOX_ERR_GET_SALT_NULL); + return false; + } + + if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) != 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_GET_SALT_BAD_FORMAT); + return false; + } + + data += TOX_ENC_SAVE_MAGIC_LENGTH; + memcpy(salt, data, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); + SET_ERROR_PARAMETER(error, TOX_ERR_GET_SALT_OK); + return true; +} + +/* Generates a secret symmetric key from the given passphrase. out_key must be at least + * TOX_PASS_KEY_LENGTH bytes long. + * Be sure to not compromise the key! Only keep it in memory, do not write to disk. + * The password is zeroed after key derivation. + * The key should only be used with the other functions in this module, as it + * includes a salt. + * Note that this function is not deterministic; to derive the same key from a + * password, you also must know the random salt that was used. See below. + * + * returns true on success + */ +bool tox_pass_key_derive(Tox_Pass_Key *out_key, const uint8_t *passphrase, size_t pplength, + TOX_ERR_KEY_DERIVATION *error) +{ + uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; + randombytes(salt, sizeof salt); + return tox_pass_key_derive_with_salt(out_key, passphrase, pplength, salt, error); +} + +/* Same as above, except with use the given salt for deterministic key derivation. + * The salt must be TOX_PASS_SALT_LENGTH bytes in length. + */ +bool tox_pass_key_derive_with_salt(Tox_Pass_Key *out_key, const uint8_t *passphrase, size_t pplength, + const uint8_t *salt, TOX_ERR_KEY_DERIVATION *error) +{ + if (!salt || !out_key || (!passphrase && pplength != 0)) { + SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_NULL); + return 0; + } + + uint8_t passkey[crypto_hash_sha256_BYTES]; + crypto_hash_sha256(passkey, passphrase, pplength); + + uint8_t key[CRYPTO_SHARED_KEY_SIZE]; + + /* Derive a key from the password */ + /* http://doc.libsodium.org/key_derivation/README.html */ + /* note that, according to the documentation, a generic pwhash interface will be created + * once the pwhash competition (https://password-hashing.net/) is over */ + if (crypto_pwhash_scryptsalsa208sha256( + key, sizeof(key), (char *)passkey, sizeof(passkey), salt, + crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE * 2, /* slightly stronger */ + crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) != 0) { + /* out of memory most likely */ + SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_FAILED); + return 0; + } + + sodium_memzero(passkey, crypto_hash_sha256_BYTES); /* wipe plaintext pw */ + memcpy(out_key->salt, salt, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); + memcpy(out_key->key, key, CRYPTO_SHARED_KEY_SIZE); + SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_OK); + return 1; +} + +/* Encrypt arbitrary with a key produced by tox_derive_key_*. The output + * array must be at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. + * key must be TOX_PASS_KEY_LENGTH bytes. + * If you already have a symmetric key from somewhere besides this module, simply + * call encrypt_data_symmetric in toxcore/crypto_core directly. + * + * returns true on success + */ +bool tox_pass_key_encrypt(const Tox_Pass_Key *key, const uint8_t *data, size_t data_len, uint8_t *out, + TOX_ERR_ENCRYPTION *error) +{ + if (data_len == 0 || !data || !key || !out) { + SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_NULL); + return 0; + } + + /* the output data consists of, in order: + * salt, nonce, mac, enc_data + * where the mac is automatically prepended by the encrypt() + * the salt+nonce is called the prefix + * I'm not sure what else I'm supposed to do with the salt and nonce, since we + * need them to decrypt the data + */ + + /* first add the magic number */ + memcpy(out, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH); + out += TOX_ENC_SAVE_MAGIC_LENGTH; + + /* then add the rest prefix */ + memcpy(out, key->salt, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); + out += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; + + uint8_t nonce[crypto_box_NONCEBYTES]; + random_nonce(nonce); + memcpy(out, nonce, crypto_box_NONCEBYTES); + out += crypto_box_NONCEBYTES; + + /* now encrypt */ + if (encrypt_data_symmetric(key->key, nonce, data, data_len, out) + != data_len + crypto_box_MACBYTES) { + SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_FAILED); + return 0; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_OK); + return 1; +} + +/* Encrypts the given data with the given passphrase. The output array must be + * at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. This delegates + * to tox_derive_key and tox_pass_key_encrypt. + * + * returns true on success + */ +bool tox_pass_encrypt(const uint8_t *data, size_t data_len, const uint8_t *passphrase, size_t pplength, uint8_t *out, + TOX_ERR_ENCRYPTION *error) +{ + Tox_Pass_Key key; + TOX_ERR_KEY_DERIVATION _error; + + if (!tox_pass_key_derive(&key, passphrase, pplength, &_error)) { + if (_error == TOX_ERR_KEY_DERIVATION_NULL) { + SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_NULL); + } else if (_error == TOX_ERR_KEY_DERIVATION_FAILED) { + SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_KEY_DERIVATION_FAILED); + } + + return 0; + } + + return tox_pass_key_encrypt(&key, data, data_len, out, error); +} + +/* This is the inverse of tox_pass_key_encrypt, also using only keys produced by + * tox_derive_key. + * + * the output data has size data_length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH + * + * returns true on success + */ +bool tox_pass_key_decrypt(const Tox_Pass_Key *key, const uint8_t *data, size_t length, uint8_t *out, + TOX_ERR_DECRYPTION *error) +{ + if (length <= TOX_PASS_ENCRYPTION_EXTRA_LENGTH) { + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_INVALID_LENGTH); + return 0; + } + + if (!data || !key || !out) { + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_NULL); + return 0; + } + + if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) != 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_BAD_FORMAT); + return 0; + } + + data += TOX_ENC_SAVE_MAGIC_LENGTH; + data += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; // salt only affects key derivation + + size_t decrypt_length = length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH; + + uint8_t nonce[crypto_box_NONCEBYTES]; + memcpy(nonce, data, crypto_box_NONCEBYTES); + data += crypto_box_NONCEBYTES; + + /* decrypt the data */ + if (decrypt_data_symmetric(key->key, nonce, data, decrypt_length + crypto_box_MACBYTES, out) + != decrypt_length) { + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_FAILED); + return 0; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_OK); + return 1; +} + +/* Decrypts the given data with the given passphrase. The output array must be + * at least data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. This delegates + * to tox_pass_key_decrypt. + * + * the output data has size data_length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH + * + * returns true on success + */ +bool tox_pass_decrypt(const uint8_t *data, size_t length, const uint8_t *passphrase, size_t pplength, uint8_t *out, + TOX_ERR_DECRYPTION *error) +{ + if (length <= TOX_PASS_ENCRYPTION_EXTRA_LENGTH) { + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_INVALID_LENGTH); + return 0; + } + + if (!data || !passphrase || !out) { + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_NULL); + return 0; + } + + if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) != 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_BAD_FORMAT); + return 0; + } + + uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; + memcpy(salt, data + TOX_ENC_SAVE_MAGIC_LENGTH, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); + + /* derive the key */ + Tox_Pass_Key key; + + if (!tox_pass_key_derive_with_salt(&key, passphrase, pplength, salt, NULL)) { + /* out of memory most likely */ + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_KEY_DERIVATION_FAILED); + return 0; + } + + return tox_pass_key_decrypt(&key, data, length, out, error); +} + +/* Determines whether or not the given data is encrypted (by checking the magic number) + */ +bool tox_is_data_encrypted(const uint8_t *data) +{ + if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) == 0) { + return 1; + } + + return 0; +} diff --git a/protocols/Tox/include/toxencryptsave.h b/protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.h index 738d9757cb..ef1ab15289 100644 --- a/protocols/Tox/include/toxencryptsave.h +++ b/protocols/Tox/libtox/src/toxencryptsave/toxencryptsave.h @@ -28,7 +28,7 @@ extern "C" { #endif -#include <msapi/stdbool.h> +#include <stdbool.h> #include <stddef.h> #include <stdint.h> diff --git a/protocols/Tox/res/Icons/audio_call.ico b/protocols/Tox/res/Icons/audio_call.ico Binary files differdeleted file mode 100644 index 555d0cb874..0000000000 --- a/protocols/Tox/res/Icons/audio_call.ico +++ /dev/null diff --git a/protocols/Tox/res/Icons/audio_end.ico b/protocols/Tox/res/Icons/audio_end.ico Binary files differdeleted file mode 100644 index 9698282053..0000000000 --- a/protocols/Tox/res/Icons/audio_end.ico +++ /dev/null diff --git a/protocols/Tox/res/Icons/audio_ring.ico b/protocols/Tox/res/Icons/audio_ring.ico Binary files differdeleted file mode 100644 index 77c4aa9640..0000000000 --- a/protocols/Tox/res/Icons/audio_ring.ico +++ /dev/null diff --git a/protocols/Tox/res/Icons/audio_start.ico b/protocols/Tox/res/Icons/audio_start.ico Binary files differdeleted file mode 100644 index 4863643b52..0000000000 --- a/protocols/Tox/res/Icons/audio_start.ico +++ /dev/null diff --git a/protocols/Tox/res/resource.rc b/protocols/Tox/res/resource.rc index eb42763582..b501959882 100644 --- a/protocols/Tox/res/resource.rc +++ b/protocols/Tox/res/resource.rc @@ -64,14 +64,6 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL // remains consistent on all systems.
IDI_TOX ICON "icons\\tox.ico"
-IDI_AUDIO_CALL ICON "icons\\audio_call.ico"
-
-IDI_AUDIO_END ICON "icons\\audio_end.ico"
-
-IDI_AUDIO_RING ICON "icons\\audio_ring.ico"
-
-IDI_AUDIO_START ICON "icons\\audio_start.ico"
-
/////////////////////////////////////////////////////////////////////////////
//
@@ -107,24 +99,29 @@ BEGIN EDITTEXT IDC_TOXID,81,15,217,12,ES_AUTOHSCROLL | ES_READONLY | WS_DISABLED
LTEXT "Name:",IDC_STATIC,12,48,69,11
EDITTEXT IDC_NAME,81,46,217,12,ES_AUTOHSCROLL
- LTEXT "Password:",IDC_STATIC,12,64,69,8,NOT WS_VISIBLE
- EDITTEXT IDC_PASSWORD,81,62,217,12,ES_PASSWORD | ES_AUTOHSCROLL | NOT WS_VISIBLE
LTEXT "Default group:",IDC_STATIC,12,80,69,12
EDITTEXT IDC_GROUP,81,78,217,12,ES_AUTOHSCROLL
PUSHBUTTON "Create Tox profile",IDC_PROFILE_NEW,81,30,107,13
PUSHBUTTON "Import Tox profile",IDC_PROFILE_IMPORT,191,30,107,13
PUSHBUTTON "Copy Tox ID",IDC_CLIPBOARD,81,30,107,13,NOT WS_VISIBLE
PUSHBUTTON "Export Tox profile",IDC_PROFILE_EXPORT,191,30,107,13,NOT WS_VISIBLE
- GROUPBOX "Connection settings",IDC_STATIC,7,99,296,75
+ GROUPBOX "Connection settings",IDC_STATIC,7,99,296,106
CONTROL "Enable UDP (otherwise force Tox to use TCP)",IDC_ENABLE_UDP,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,111,286,10
- CONTROL "Enable IPv6",IDC_ENABLE_IPV6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,125,286,10
- LTEXT "Max connect retries:",IDC_STATIC,12,142,121,8
- EDITTEXT IDC_MAXCONNECTRETRIES,133,139,43,14,ES_NUMBER
- CONTROL "",IDC_MAXCONNECTRETRIESSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,166,139,10,14
- EDITTEXT IDC_MAXRECONNECTRETRIES,133,155,43,14,ES_NUMBER
- CONTROL "",IDC_MAXRECONNECTRETRIESSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,166,155,10,14
- LTEXT "Max reconnect retries:",IDC_STATIC,12,158,121,8
+ CONTROL "Enable IPv6",IDC_ENABLE_IPV6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,139,286,10
+ LTEXT "Max connect retries:",IDC_STATIC,12,171,121,8
+ EDITTEXT IDC_MAXCONNECTRETRIES,133,168,43,14,ES_NUMBER
+ CONTROL "",IDC_MAXCONNECTRETRIESSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,166,168,10,14
+ EDITTEXT IDC_MAXRECONNECTRETRIES,133,184,43,14,ES_NUMBER
+ CONTROL "",IDC_MAXRECONNECTRETRIESSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,166,184,10,14
+ LTEXT "Max reconnect retries:",IDC_STATIC,12,186,121,8
+ CONTROL "Enable UDP hole-punching",IDC_ENABLE_HOLEPUNCHING,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,24,125,274,10
+ CONTROL "Enable local network peer discovery",IDC_ENABLE_LOCALDISCOVERY,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,153,286,10
+ PUSHBUTTON "Remove password",IDC_PASSWORD_REMOVE,81,62,107,13
+ PUSHBUTTON "Change password",IDC_PASSWORD_CHANGE,191,62,107,13
+ PUSHBUTTON "Set password",IDC_PASSWORD_CREATE,136,62,107,13
END
IDD_SEARCH DIALOGEX 0, 0, 109, 113
@@ -145,17 +142,16 @@ BEGIN EDITTEXT IDC_DNS_ID,2,13,217,14,ES_AUTOHSCROLL
END
-IDD_PASSWORD DIALOGEX 0, 0, 209, 75
+IDD_PASSWORD_ENTER DIALOGEX 0, 0, 211, 70
STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
-EXSTYLE WS_EX_TOOLWINDOW | WS_EX_APPWINDOW
+EXSTYLE WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT | WS_EX_APPWINDOW
CAPTION "Enter password"
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
- EDITTEXT IDC_PASSWORD,7,24,197,12,ES_PASSWORD | ES_AUTOHSCROLL
- CONTROL "Save password",IDC_SAVEPERMANENTLY,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,7,40,197,12
- DEFPUSHBUTTON "OK",IDOK,101,56,50,14
- PUSHBUTTON "Cancel",IDCANCEL,154,56,50,14
- LTEXT "Tox profile is encrypted. Enter the password to continue.",IDC_STATIC,7,5,197,18
+ EDITTEXT IDC_PASSWORD,7,24,199,12,ES_PASSWORD | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,101,51,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,156,51,50,14
+ LTEXT "Tox profile is encrypted. Enter the password to continue.",IDC_STATIC,7,5,199,18
END
IDD_OPTIONS_NODES DIALOGEX 0, 0, 310, 230
@@ -185,74 +181,36 @@ BEGIN PUSHBUTTON "Cancel",IDCANCEL,156,97,50,14
END
-IDD_OPTIONS_MULTIMEDIA DIALOGEX 0, 0, 310, 230
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
-EXSTYLE WS_EX_CONTROLPARENT
+IDD_PASSWORD_CHANGE DIALOGEX 0, 0, 209, 112
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT | WS_EX_APPWINDOW
+CAPTION "Change password"
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
- GROUPBOX "Multimedia",-1,7,7,296,89
- LTEXT "Audio input device",-1,12,17,60,8
- COMBOBOX IDC_AUDIOINPUT,12,26,286,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
- LTEXT "Audio output device",-1,12,42,65,8
- COMBOBOX IDC_AUDIOOUTPUT,12,52,286,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
- LTEXT "Video input device",-1,15,68,59,8,NOT WS_VISIBLE
- COMBOBOX IDC_COMBO_VIDEOINPUT,12,78,286,30,CBS_DROPDOWN | CBS_SORT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP
-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 contacts to chat room"
-FONT 8, "MS Shell Dlg", 0, 0, 0x0
-BEGIN
- PUSHBUTTON "&Invite",IDOK,87,158,46,14
- PUSHBUTTON "&Cancel",IDCANCEL,138,158,45,14
- CONTROL "",IDC_CCLIST,"CListControl",WS_TABSTOP | 0x16f,7,7,176,145,WS_EX_CLIENTEDGE
-END
-
-IDD_CALL DIALOGEX 0, 0, 319, 226
-STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-EXSTYLE WS_EX_TOPMOST
-CAPTION "Call"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- DEFPUSHBUTTON "End",IDCANCEL,262,204,50,15
+ EDITTEXT IDC_PASSWORD,7,14,197,12,ES_PASSWORD | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,101,93,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,154,93,50,14
+ EDITTEXT IDC_PASSWORD_NEW,7,40,197,12,ES_PASSWORD | ES_AUTOHSCROLL
+ LTEXT "Old password:",IDC_STATIC,7,4,197,8
+ LTEXT "New password:",IDC_STATIC,7,30,197,8
+ EDITTEXT IDC_PASSWORD_CONFIRM,7,65,197,12,ES_PASSWORD | ES_AUTOHSCROLL
+ LTEXT "Confirm password:",IDC_STATIC,7,55,197,8
+ LTEXT "",IDC_PASSWORD_VALIDATION,7,81,197,8
END
-IDD_CALL_RECEIVE DIALOGEX 0, 0, 239, 111
-STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-EXSTYLE WS_EX_TOPMOST
-CAPTION "Incoming call"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- DEFPUSHBUTTON "Answer",IDOK,64,89,50,15
- PUSHBUTTON "Reject",IDCANCEL,127,90,50,14
- LTEXT "From:",IDC_STATIC,8,22,24,9,SS_CENTERIMAGE
- CONTROL "",IDC_FROM,"Static",SS_SIMPLE | SS_NOPREFIX | WS_GROUP,41,23,191,9
- LTEXT "Date:",IDC_STATIC,8,37,28,9,SS_CENTERIMAGE
- CONTROL "",IDC_DATE,"Static",SS_SIMPLE | SS_NOPREFIX | WS_GROUP,41,36,191,9
- CONTROL "&User menu",IDC_USERMENU,"MButtonClass",NOT WS_VISIBLE | WS_TABSTOP,178,7,16,14,WS_EX_NOACTIVATE | 0x10000000L
- CONTROL "User &details",IDC_DETAILS,"MButtonClass",NOT WS_VISIBLE | WS_TABSTOP,197,7,16,14,WS_EX_NOACTIVATE | 0x10000000L
- CONTROL "&History",IDC_HISTORY,"MButtonClass",NOT WS_VISIBLE | WS_TABSTOP,216,7,16,14,WS_EX_NOACTIVATE | 0x10000000L
- CONTROL "",IDC_PROTOCOL,"Button",BS_OWNERDRAW | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,7,9,12,12
- LTEXT "",IDC_NAME2,21,9,137,9,SS_NOPREFIX | SS_CENTERIMAGE
-END
-
-IDD_CALL_SEND DIALOGEX 0, 0, 239, 95
-STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-EXSTYLE WS_EX_TOPMOST
-CAPTION "Outgoing call"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
+IDD_PASSWORD_CREATE DIALOGEX 0, 0, 209, 84
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT | WS_EX_APPWINDOW
+CAPTION "Set password"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
- DEFPUSHBUTTON "Call",IDOK,64,73,50,15
- PUSHBUTTON "Cancel",IDCANCEL,127,74,50,14
- LTEXT "To:",-1,8,22,24,9,SS_CENTERIMAGE
- CONTROL "",IDC_FROM,"Static",SS_SIMPLE | SS_NOPREFIX | WS_GROUP,41,23,191,9
- CONTROL "&User menu",IDC_USERMENU,"MButtonClass",NOT WS_VISIBLE | WS_TABSTOP,178,7,16,14,WS_EX_NOACTIVATE | 0x10000000L
- CONTROL "User &details",IDC_DETAILS,"MButtonClass",NOT WS_VISIBLE | WS_TABSTOP,197,7,16,14,WS_EX_NOACTIVATE | 0x10000000L
- CONTROL "&History",IDC_HISTORY,"MButtonClass",NOT WS_VISIBLE | WS_TABSTOP,216,7,16,14,WS_EX_NOACTIVATE | 0x10000000L
- CONTROL "",IDC_PROTOCOL,"Button",BS_OWNERDRAW | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,7,9,12,12
- LTEXT "",IDC_NAME2,21,9,137,9,SS_NOPREFIX | SS_CENTERIMAGE
+ DEFPUSHBUTTON "OK",IDOK,101,65,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,154,65,50,14
+ EDITTEXT IDC_PASSWORD_NEW,7,14,197,12,ES_PASSWORD | ES_AUTOHSCROLL
+ LTEXT "New password:",-1,7,4,197,8
+ EDITTEXT IDC_PASSWORD_CONFIRM,7,39,197,12,ES_PASSWORD | ES_AUTOHSCROLL
+ LTEXT "Confirm password:",-1,7,29,197,8
+ LTEXT "",IDC_PASSWORD_VALIDATION,7,55,197,8
END
@@ -276,6 +234,7 @@ BEGIN LEFTMARGIN, 7
RIGHTMARGIN, 303
VERTGUIDE, 12
+ VERTGUIDE, 24
VERTGUIDE, 81
VERTGUIDE, 133
VERTGUIDE, 298
@@ -293,11 +252,11 @@ BEGIN VERTGUIDE, 219
END
- IDD_PASSWORD, DIALOG
+ IDD_PASSWORD_ENTER, DIALOG
BEGIN
- RIGHTMARGIN, 204
+ RIGHTMARGIN, 206
VERTGUIDE, 7
- BOTTOMMARGIN, 70
+ BOTTOMMARGIN, 65
END
IDD_OPTIONS_NODES, DIALOG
@@ -319,49 +278,18 @@ BEGIN HORZGUIDE, 67
END
- IDD_OPTIONS_MULTIMEDIA, DIALOG
+ IDD_PASSWORD_CHANGE, DIALOG
BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 303
- VERTGUIDE, 12
- VERTGUIDE, 81
- VERTGUIDE, 298
- TOPMARGIN, 7
- BOTTOMMARGIN, 228
- END
-
- IDD_CHATROOM_INVITE, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 183
- TOPMARGIN, 7
- BOTTOMMARGIN, 172
- HORZGUIDE, 152
- HORZGUIDE, 158
- END
-
- IDD_CALL, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 312
- TOPMARGIN, 7
- BOTTOMMARGIN, 219
- END
-
- IDD_CALL_RECEIVE, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 232
- TOPMARGIN, 7
- BOTTOMMARGIN, 104
+ RIGHTMARGIN, 204
+ VERTGUIDE, 7
+ BOTTOMMARGIN, 107
END
- IDD_CALL_SEND, DIALOG
+ IDD_PASSWORD_CREATE, DIALOG
BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 232
- TOPMARGIN, 7
- BOTTOMMARGIN, 88
+ RIGHTMARGIN, 204
+ VERTGUIDE, 7
+ BOTTOMMARGIN, 79
END
END
#endif // APSTUDIO_INVOKED
@@ -372,17 +300,27 @@ END // AFX_DIALOG_LAYOUT
//
-IDD_OPTIONS_MULTIMEDIA AFX_DIALOG_LAYOUT
+IDD_OPTIONS_MAIN AFX_DIALOG_LAYOUT
BEGIN
0
END
-IDD_OPTIONS_MAIN AFX_DIALOG_LAYOUT
+IDD_PASSWORD_ENTER AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
+IDD_PASSWORD_CHANGE AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
+IDD_PASSWORD_CHANGE2 AFX_DIALOG_LAYOUT
BEGIN
0
END
-IDD_PASSWORD AFX_DIALOG_LAYOUT
+IDD_PASSWORD_CREATE AFX_DIALOG_LAYOUT
BEGIN
0
END
diff --git a/protocols/Tox/src/api_av.cpp b/protocols/Tox/src/api_av.cpp deleted file mode 100644 index c46e549a35..0000000000 --- a/protocols/Tox/src/api_av.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "stdafx.h"
-
-/* COMMON A/V FUNCTIONS */
-
-ToxAV *toxav_new(Tox *tox, TOXAV_ERR_NEW *error)
-{
- return CreateFunction<ToxAV*(*)(Tox*, TOXAV_ERR_NEW*)>(__FUNCTION__)(tox, error);
-}
-
-void toxav_kill(ToxAV *toxAV)
-{
- CreateFunction<void(*)(ToxAV*)>(__FUNCTION__)(toxAV);
-}
-
-Tox *toxav_get_tox(const ToxAV *toxAV)
-{
- return CreateFunction<Tox*(*)(const ToxAV*)>(__FUNCTION__)(toxAV);
-}
-
-uint32_t toxav_iteration_interval(ToxAV *toxAV)
-{
- return CreateFunction<uint32_t(*)(ToxAV*)>(__FUNCTION__)(toxAV);
-}
-
-void toxav_iterate(ToxAV *toxAV)
-{
- CreateFunction<void(*)(ToxAV*)>(__FUNCTION__)(toxAV);
-}
-
-bool toxav_call(ToxAV *toxAV, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL *error)
-{
- return CreateFunction<bool(*)(ToxAV*, int32_t, uint32_t, uint32_t, TOXAV_ERR_CALL*)>(__FUNCTION__)(toxAV, friend_number, audio_bit_rate, video_bit_rate, error);
-}
-
-void toxav_callback_call(ToxAV *toxAV, toxav_call_cb *callback, void *user_data)
-{
- CreateFunction<void(*)(ToxAV*, toxav_call_cb, void*)>(__FUNCTION__)(toxAV, callback, user_data);
-}
-
-bool toxav_answer(ToxAV *toxAV, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_ANSWER *error)
-{
- return CreateFunction<bool(*)(ToxAV*, int32_t, uint32_t, uint32_t, TOXAV_ERR_ANSWER*)>(__FUNCTION__)(toxAV, friend_number, audio_bit_rate, video_bit_rate, error);
-}
-
-void toxav_callback_call_state(ToxAV *toxAV, toxav_call_state_cb *callback, void *user_data)
-{
- CreateFunction<void(*)(ToxAV*, toxav_call_state_cb, void*)>(__FUNCTION__)(toxAV, callback, user_data);
-}
-
-bool toxav_call_control(ToxAV *toxAV, uint32_t friend_number, TOXAV_CALL_CONTROL control, TOXAV_ERR_CALL_CONTROL *error)
-{
- return CreateFunction<bool(*)(ToxAV*, uint32_t, TOXAV_CALL_CONTROL, TOXAV_ERR_CALL_CONTROL*)>(__FUNCTION__)(toxAV, friend_number, control, error);
-}
-
-bool toxav_bit_rate_set(ToxAV *toxAV, uint32_t friend_number, int32_t audio_bit_rate, int32_t video_bit_rate, TOXAV_ERR_BIT_RATE_SET *error)
-{
- return CreateFunction<bool(*)(ToxAV*, int32_t, uint32_t, uint32_t, TOXAV_ERR_BIT_RATE_SET*)>(__FUNCTION__)(toxAV, friend_number, audio_bit_rate, video_bit_rate, error);
-}
-
-void toxav_callback_bit_rate_status(ToxAV *toxAV, toxav_bit_rate_status_cb *callback, void *user_data)
-{
- CreateFunction<void(*)(ToxAV*, toxav_bit_rate_status_cb, void*)>(__FUNCTION__)(toxAV, callback, user_data);
-}
-
-bool toxav_audio_send_frame(ToxAV *toxAV, uint32_t friend_number, const int16_t *pcm, size_t sample_count, uint8_t channels, uint32_t sampling_rate, TOXAV_ERR_SEND_FRAME *error)
-{
- return CreateFunction<bool(*)(ToxAV*, int32_t, const int16_t*, size_t, uint8_t, uint32_t, TOXAV_ERR_SEND_FRAME*)>(__FUNCTION__)(toxAV, friend_number, pcm, sample_count, channels, sampling_rate, error);
-}
-
-bool toxav_video_send_frame(ToxAV *toxAV, uint32_t friend_number, uint16_t width, uint16_t height, const uint8_t *y, const uint8_t *u, const uint8_t *v, TOXAV_ERR_SEND_FRAME *error)
-{
- return CreateFunction<bool(*)(ToxAV*, int32_t, int16_t, uint16_t, const uint8_t*, const uint8_t*, const uint8_t*, TOXAV_ERR_SEND_FRAME*)>(__FUNCTION__)(toxAV, friend_number, width, height, y, u, v, error);
-}
-
-void toxav_callback_audio_receive_frame(ToxAV *toxAV, toxav_audio_receive_frame_cb *callback, void *user_data)
-{
- CreateFunction<void(*)(ToxAV*, toxav_audio_receive_frame_cb, void*)>(__FUNCTION__)(toxAV, callback, user_data);
-}
-
-void toxav_callback_video_receive_frame(ToxAV *toxAV, toxav_video_receive_frame_cb *callback, void *user_data)
-{
- CreateFunction<void(*)(ToxAV*, toxav_video_receive_frame_cb, void*)>(__FUNCTION__)(toxAV, callback, user_data);
-}
-
-int toxav_add_av_groupchat(Tox *tox, void(*audio_callback)(void *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *), void *userdata)
-{
- return CreateFunction<int(*)(Tox*, void(*)(void*, int, int, const int16_t*, unsigned int, uint8_t, unsigned int, void*), void*)>(__FUNCTION__)(tox, audio_callback, userdata);
-}
-
-int toxav_join_av_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length, void(*audio_callback)(void *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *), void *userdata)
-{
- return CreateFunction<int(*)(Tox*, int32_t, const uint8_t*, uint16_t, void(*)(void*, int, int, const int16_t*, unsigned int, uint8_t, unsigned int, void*), void*)>(__FUNCTION__)(tox, friendnumber, data, length, audio_callback, userdata);
-}
-
-int toxav_group_send_audio(Tox *tox, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate)
-{
- return CreateFunction<int(*)(Tox*, int, const int16_t*, unsigned int, uint8_t, unsigned int)>(__FUNCTION__)(tox, groupnumber, pcm, samples, channels, sample_rate);
-}
\ No newline at end of file diff --git a/protocols/Tox/src/api_avatars.cpp b/protocols/Tox/src/api_avatars.cpp deleted file mode 100644 index 658b835a68..0000000000 --- a/protocols/Tox/src/api_avatars.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "stdafx.h"
-
-/* AVATAR FUNCTIONS */
-
-void tox_callback_avatar_info(Tox *tox, void(*function)(Tox *tox, int32_t, uint8_t, uint8_t *, void *), void *userdata)
-{
- CreateFunction<int(*)(Tox*, void(*)(Tox*, int32_t, uint8_t, uint8_t*, void*), void*)>(__FUNCTION__)(tox, function, userdata);
-}
-
-void tox_callback_avatar_data(Tox *tox, void(*function)(Tox *tox, int32_t, uint8_t, uint8_t *, uint8_t *, uint32_t, void *), void *userdata)
-{
- CreateFunction<int(*)(Tox*, void(*)(Tox*, int32_t, uint8_t, uint8_t*, uint8_t*, uint32_t, void*), void*)>(__FUNCTION__)(tox, function, userdata);
-}
-
-int tox_set_avatar(Tox *tox, uint8_t format, const uint8_t *data, uint32_t length)
-{
- return CreateFunction<int(*)(Tox*, uint8_t, const uint8_t*, uint32_t)>(__FUNCTION__)(tox, format, data, length);
-}
-
-int tox_unset_avatar(Tox *tox)
-{
- return CreateFunction<int(*)(const Tox*)>(__FUNCTION__)(tox);
-}
-
-int tox_get_self_avatar(const Tox *tox, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen, uint8_t *hash)
-{
- return CreateFunction<int(*)(const Tox*, uint8_t*, uint8_t*, uint32_t*, uint32_t, uint8_t*)>(__FUNCTION__)(tox, format, buf, length, maxlen, hash);
-}
-
-int tox_request_avatar_info(const Tox *tox, const int32_t friendnumber)
-{
- return CreateFunction<int(*)(const Tox*, const int32_t)>(__FUNCTION__)(tox, friendnumber);
-}
-
-int tox_send_avatar_info(Tox *tox, const int32_t friendnumber)
-{
- return CreateFunction<int(*)(const Tox*, const int32_t)>(__FUNCTION__)(tox, friendnumber);
-}
-
-int tox_request_avatar_data(const Tox *tox, const int32_t friendnumber)
-{
- return CreateFunction<int(*)(const Tox*, const int32_t)>(__FUNCTION__)(tox, friendnumber);
-}
\ No newline at end of file diff --git a/protocols/Tox/src/api_connection.cpp b/protocols/Tox/src/api_connection.cpp deleted file mode 100644 index 1ed6b51d40..0000000000 --- a/protocols/Tox/src/api_connection.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "stdafx.h"
-
-/* CONNECTION FUNCTIONS */
-
-bool tox_bootstrap(Tox *tox, const char *host, uint16_t port, const uint8_t *public_key, TOX_ERR_BOOTSTRAP *error)
-{
- return CreateFunction<bool(*)(Tox*, const char*, uint16_t, const uint8_t*, TOX_ERR_BOOTSTRAP*)>(__FUNCTION__)(tox, host, port, public_key, error);
-}
-
-bool tox_add_tcp_relay(Tox *tox, const char *host, uint16_t port, const uint8_t *public_key, TOX_ERR_BOOTSTRAP *error)
-{
- return CreateFunction<bool(*)(Tox*, const char*, uint16_t, const uint8_t*, TOX_ERR_BOOTSTRAP*)>(__FUNCTION__)(tox, host, port, public_key, error);
-}
-
-TOX_CONNECTION tox_self_get_connection_status(const Tox *tox)
-{
- return CreateFunction<TOX_CONNECTION(*)(const Tox*)>(__FUNCTION__)(tox);
-}
-
-uint32_t tox_iteration_interval(const Tox *tox)
-{
- return CreateFunction<uint32_t(*)(const Tox*)>(__FUNCTION__)(tox);
-}
-
-void tox_iterate(Tox *tox, void *user_data)
-{
- CreateFunction<int(*)(const Tox*, void*)>(__FUNCTION__)(tox, user_data);
-}
\ No newline at end of file diff --git a/protocols/Tox/src/api_dns.cpp b/protocols/Tox/src/api_dns.cpp deleted file mode 100644 index 57db01e57c..0000000000 --- a/protocols/Tox/src/api_dns.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "stdafx.h"
-
-/* DNS TOXID RESOILVING FUNCTIONS */
-
-void *tox_dns3_new(uint8_t *server_public_key)
-{
- return CreateFunction<void*(*)(uint8_t*)>(__FUNCTION__)(server_public_key);
-}
-
-void tox_dns3_kill(void *dns3_object)
-{
- CreateFunction<void(*)(void*)>(__FUNCTION__)(dns3_object);
-}
-
-int tox_generate_dns3_string(void *dns3_object, uint8_t *string, uint16_t string_max_len, uint32_t *request_id, uint8_t *name, uint8_t name_len)
-{
- return CreateFunction<int(*)(void*, uint8_t*, uint16_t, uint32_t*, uint8_t*, uint8_t)>(__FUNCTION__)(dns3_object, string, string_max_len, request_id, name, name_len);
-}
-
-int tox_decrypt_dns3_TXT(void *dns3_object, uint8_t *tox_id, uint8_t *id_record, uint32_t id_record_len, uint32_t request_id)
-{
- return CreateFunction<int(*)(void*, uint8_t*, uint8_t*, uint32_t, uint32_t)>(__FUNCTION__)(dns3_object, tox_id, id_record, id_record_len, request_id);
-}
\ No newline at end of file diff --git a/protocols/Tox/src/api_encryption.cpp b/protocols/Tox/src/api_encryption.cpp deleted file mode 100644 index 85e77c06ad..0000000000 --- a/protocols/Tox/src/api_encryption.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "stdafx.h"
-
-/* ENCRYPTION FUNCTIONS */
-
-bool tox_pass_decrypt(const uint8_t *data, size_t length, const uint8_t *passphrase, size_t pplength, uint8_t *out, TOX_ERR_DECRYPTION *error)
-{
- return CreateFunction<bool(*)(const uint8_t *, size_t, const uint8_t*, size_t, uint8_t*, TOX_ERR_DECRYPTION*)>(__FUNCTION__)(data, length, passphrase, pplength, out, error);
-}
-
-bool tox_pass_encrypt(const uint8_t *data, size_t data_len, const uint8_t *passphrase, size_t pplength, uint8_t *out, TOX_ERR_ENCRYPTION *error)
-{
- return CreateFunction<bool(*)(const uint8_t *, size_t, const uint8_t*, size_t, uint8_t*, TOX_ERR_ENCRYPTION*)>(__FUNCTION__)(data, data_len, passphrase, pplength, out, error);
-}
-
-bool tox_is_data_encrypted(const uint8_t *data)
-{
- return CreateFunction<bool(*)(const uint8_t*)>(__FUNCTION__)(data);
-}
\ No newline at end of file diff --git a/protocols/Tox/src/api_friends.cpp b/protocols/Tox/src/api_friends.cpp deleted file mode 100644 index caa133feb7..0000000000 --- a/protocols/Tox/src/api_friends.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include "stdafx.h"
-
-/* FRIEND FUNCTIONS */
-
-uint32_t tox_friend_add(Tox *tox, const uint8_t *address, const uint8_t *message, size_t length, TOX_ERR_FRIEND_ADD *error)
-{
- return CreateFunction<uint32_t(*)(Tox*, const uint8_t*, const uint8_t*, size_t, TOX_ERR_FRIEND_ADD*)>(__FUNCTION__)(tox, address, message, length, error);
-}
-
-uint32_t tox_friend_add_norequest(Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_ADD *error)
-{
- return CreateFunction<uint32_t(*)(Tox*, const uint8_t*, TOX_ERR_FRIEND_ADD*)>(__FUNCTION__)(tox, public_key, error);
-}
-
-bool tox_friend_delete(Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_DELETE *error)
-{
- return CreateFunction<bool(*)(Tox*, uint32_t, TOX_ERR_FRIEND_DELETE*)>(__FUNCTION__)(tox, friend_number, error);
-}
-
-uint32_t tox_friend_by_public_key(const Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_BY_PUBLIC_KEY *error)
-{
- return CreateFunction<uint32_t(*)(const Tox*, const uint8_t*, TOX_ERR_FRIEND_BY_PUBLIC_KEY*)>(__FUNCTION__)(tox, public_key, error);
-}
-
-int tox_friend_exists(const Tox *tox, int32_t friendnumber)
-{
- return CreateFunction<int(*)(const Tox*, int32_t)>(__FUNCTION__)(tox, friendnumber);
-}
-
-size_t tox_self_get_friend_list_size(const Tox *tox)
-{
- return CreateFunction<size_t(*)(const Tox*)>(__FUNCTION__)(tox);
-}
-
-void tox_self_get_friend_list(const Tox *tox, uint32_t *list)
-{
- CreateFunction<void(*)(const Tox*, uint32_t*)>(__FUNCTION__)(tox, list);
-}
-
-bool tox_friend_get_public_key(const Tox *tox, uint32_t friend_number, uint8_t *public_key, TOX_ERR_FRIEND_GET_PUBLIC_KEY *error)
-{
- return CreateFunction<bool(*)(const Tox*, int32_t, uint8_t*, TOX_ERR_FRIEND_GET_PUBLIC_KEY*)>(__FUNCTION__)(tox, friend_number, public_key, error);
-}
-
-uint64_t tox_friend_get_last_online(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_GET_LAST_ONLINE *error)
-{
- return CreateFunction<uint64_t(*)(const Tox*, uint32_t, TOX_ERR_FRIEND_GET_LAST_ONLINE*)>(__FUNCTION__)(tox, friend_number, error);
-}
-
-size_t tox_friend_get_name_size(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error)
-{
- return CreateFunction<size_t(*)(const Tox*, uint32_t, TOX_ERR_FRIEND_QUERY*)>(__FUNCTION__)(tox, friend_number, error);
-}
-
-bool tox_friend_get_name(const Tox *tox, uint32_t friend_number, uint8_t *name, TOX_ERR_FRIEND_QUERY *error)
-{
- return CreateFunction<bool(*)(const Tox*, uint32_t, uint8_t*, TOX_ERR_FRIEND_QUERY*)>(__FUNCTION__)(tox, friend_number, name, error);
-}
-
-void tox_callback_friend_name(Tox *tox, tox_friend_name_cb *function)
-{
- CreateFunction<void(*)(Tox*tox, tox_friend_name_cb)>(__FUNCTION__)(tox, function);
-}
-
-size_t tox_friend_get_status_message_size(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error)
-{
- return CreateFunction<size_t(*)(const Tox*, uint32_t, TOX_ERR_FRIEND_QUERY*)>(__FUNCTION__)(tox, friend_number, error);
-}
-
-bool tox_friend_get_status_message(const Tox *tox, uint32_t friend_number, uint8_t *status_message, TOX_ERR_FRIEND_QUERY *error)
-{
- return CreateFunction<bool(*)(const Tox*, uint32_t, uint8_t*, TOX_ERR_FRIEND_QUERY*)>(__FUNCTION__)(tox, friend_number, status_message, error);
-}
-
-void tox_callback_friend_status_message(Tox *tox, tox_friend_status_message_cb *function)
-{
- CreateFunction<void(*)(Tox*, tox_friend_status_message_cb)>(__FUNCTION__)(tox, function);
-}
-
-TOX_USER_STATUS tox_friend_get_status(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error)
-{
- return CreateFunction<TOX_USER_STATUS(*)(const Tox*, uint32_t, TOX_ERR_FRIEND_QUERY*)>(__FUNCTION__)(tox, friend_number, error);
-}
-
-void tox_callback_friend_status(Tox *tox, tox_friend_status_cb *function)
-{
- CreateFunction<void(*)(Tox*, tox_friend_status_cb)>(__FUNCTION__)(tox, function);
-}
-
-TOX_CONNECTION tox_friend_get_connection_status(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error)
-{
- return CreateFunction<TOX_CONNECTION(*)(const Tox*, uint32_t, TOX_ERR_FRIEND_QUERY*)>(__FUNCTION__)(tox, friend_number, error);
-}
-
-void tox_callback_friend_connection_status(Tox *tox, tox_friend_connection_status_cb *function)
-{
- CreateFunction<void(*)(Tox*, tox_friend_connection_status_cb)>(__FUNCTION__)(tox, function);
-}
-
-bool tox_friend_get_typing(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error)
-{
- return CreateFunction<bool(*)(const Tox*, uint32_t, TOX_ERR_FRIEND_QUERY*)>(__FUNCTION__)(tox, friend_number, error);
-}
-
-void tox_callback_friend_typing(Tox *tox, tox_friend_typing_cb *function)
-{
- CreateFunction<void(*)(Tox*, tox_friend_typing_cb)>(__FUNCTION__)(tox, function);
-}
-
-/* */
-
-bool tox_self_set_typing(Tox *tox, uint32_t friend_number, bool is_typing, TOX_ERR_SET_TYPING *error)
-{
- return CreateFunction<bool(*)(Tox*, uint32_t, bool, TOX_ERR_SET_TYPING*)>(__FUNCTION__)(tox, friend_number, is_typing, error);
-}
-
-uint32_t tox_friend_send_message(Tox *tox, uint32_t friend_number, TOX_MESSAGE_TYPE type, const uint8_t *message, size_t length, TOX_ERR_FRIEND_SEND_MESSAGE *error)
-{
- return CreateFunction<uint32_t(*)(Tox*, uint32_t, TOX_MESSAGE_TYPE, const uint8_t*, size_t, TOX_ERR_FRIEND_SEND_MESSAGE*)>(__FUNCTION__)(tox, friend_number, type, message, length, error);
-}
-
-void tox_callback_friend_read_receipt(Tox *tox, tox_friend_read_receipt_cb *function)
-{
- CreateFunction<void(*)(Tox*, tox_friend_read_receipt_cb)>(__FUNCTION__)(tox, function);
-}
-
-void tox_callback_friend_request(Tox *tox, tox_friend_request_cb *function)
-{
- CreateFunction<void(*)(Tox*, tox_friend_request_cb)>(__FUNCTION__)(tox, function);
-}
-
-void tox_callback_friend_message(Tox *tox, tox_friend_message_cb *function)
-{
- CreateFunction<void(*)(Tox*, tox_friend_message_cb)>(__FUNCTION__)(tox, function);
-}
\ No newline at end of file diff --git a/protocols/Tox/src/api_groupchats.cpp b/protocols/Tox/src/api_groupchats.cpp deleted file mode 100644 index 9919eee92c..0000000000 --- a/protocols/Tox/src/api_groupchats.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "stdafx.h"
-
-/* GROUP CHAT FUNCTIONS: WARNING Group chats will be rewritten so this might change */
-
-void tox_callback_group_invite(Tox *tox, void(*function)(Tox *tox, int32_t, uint8_t, const uint8_t *, uint16_t, void *), void *userdata)
-{
- CreateFunction<int(*)(Tox*, void(*)(Tox*, int32_t, uint8_t, const uint8_t*, uint16_t, void*), void*)>(__FUNCTION__)(tox, function, userdata);
-}
-
-/*void tox_callback_group_message(Tox *tox, void(*function)(Tox *tox, int, int, const uint8_t *, uint16_t, void *), void *userdata)
-{
-}
-
-void tox_callback_group_action(Tox *tox, void(*function)(Tox *tox, int, int, const uint8_t *, uint16_t, void *), void *userdata)
-{
-}
-
-void tox_callback_group_title(Tox *tox, void(*function)(Tox *tox, int, int, const uint8_t *, uint8_t, void *), void *userdata)
-{
-}
-
-void tox_callback_group_namelist_change(Tox *tox, void(*function)(Tox *tox, int, int, uint8_t, void *), void *userdata)
-{
-}*/
-
-int tox_add_groupchat(Tox *tox)
-{
- return CreateFunction<int(*)(const Tox*)>(__FUNCTION__)(tox);
-}
-
-int tox_del_groupchat(Tox *tox, int groupnumber)
-{
- return CreateFunction<int(*)(Tox*, int)>(__FUNCTION__)(tox, groupnumber);
-}
-
-/*int tox_group_peername(const Tox *tox, int groupnumber, int peernumber, uint8_t *name)
-{
-}
-
-int tox_group_peer_pubkey(const Tox *tox, int groupnumber, int peernumber, uint8_t *pk)
-{
-}*/
-
-int tox_invite_friend(Tox *tox, int32_t friendnumber, int groupnumber)
-{
- return CreateFunction<int(*)(Tox*, int32_t, int)>(__FUNCTION__)(tox, friendnumber, groupnumber);
-}
-
-int tox_join_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length)
-{
- return CreateFunction<int(*)(Tox*, int32_t, const uint8_t*, uint32_t)>(__FUNCTION__)(tox, friendnumber, data, length);
-}
-
-/*int tox_group_message_send(Tox *tox, int groupnumber, const uint8_t *message, uint16_t length)
-{
-}
-
-int tox_group_action_send(Tox *tox, int groupnumber, const uint8_t *action, uint16_t length)
-{
-}
-
-int tox_group_set_title(Tox *tox, int groupnumber, const uint8_t *title, uint8_t length)
-{
-}*/
-
-int tox_group_get_title(Tox *tox, int groupnumber, uint8_t *title, uint32_t max_length)
-{
- return CreateFunction<int(*)(Tox*, int, uint8_t*, uint32_t)>(__FUNCTION__)(tox, groupnumber, title, max_length);
-}
-
-/*unsigned int tox_group_peernumber_is_ours(const Tox *tox, int groupnumber, int peernumber)
-{
-}
-
-int tox_group_number_peers(const Tox *tox, int groupnumber)
-{
-}
-
-int tox_group_get_names(const Tox *tox, int groupnumber, uint8_t names[][TOX_MAX_NAME_LENGTH], uint16_t lengths[], uint16_t length)
-{
-}*/
-
-uint32_t tox_count_chatlist(const Tox *tox)
-{
- return CreateFunction<int(*)(const Tox*)>(__FUNCTION__)(tox);
-}
-
-uint32_t tox_get_chatlist(const Tox *tox, int32_t *out_list, uint32_t list_size)
-{
- return CreateFunction<int(*)(const Tox*, int32_t*, uint32_t)>(__FUNCTION__)(tox, out_list, list_size);
-}
-
-int tox_group_get_type(const Tox *tox, int groupnumber)
-{
- return CreateFunction<int(*)(const Tox*, int)>(__FUNCTION__)(tox, groupnumber);
-}
\ No newline at end of file diff --git a/protocols/Tox/src/api_main.cpp b/protocols/Tox/src/api_main.cpp deleted file mode 100644 index 3d46576925..0000000000 --- a/protocols/Tox/src/api_main.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include "stdafx.h"
-
-/* MAIN FUNCTIONS */
-
-bool tox_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch)
-{
- return CreateFunction<bool(*)(uint32_t, uint32_t, uint32_t)>(__FUNCTION__)(major, minor, patch);
-}
-
-struct Tox_Options *tox_options_new(TOX_ERR_OPTIONS_NEW *error)
-{
- return CreateFunction<struct Tox_Options*(*)(TOX_ERR_OPTIONS_NEW*)>(__FUNCTION__)(error);
-}
-
-void tox_options_default(struct Tox_Options *options)
-{
- CreateFunction<void(*)(struct Tox_Options*)>(__FUNCTION__)(options);
-}
-
-void tox_options_free(struct Tox_Options *options)
-{
- CreateFunction<void(*)(struct Tox_Options*)>(__FUNCTION__)(options);
-}
-
-Tox *tox_new(const struct Tox_Options *options, TOX_ERR_NEW *error)
-{
- return CreateFunction<Tox*(*)(const struct Tox_Options*, TOX_ERR_NEW*)>(__FUNCTION__)(options, error);
-}
-
-void tox_kill(Tox *tox)
-{
- CreateFunction<int(*)(Tox*)>(__FUNCTION__)(tox);
-}
-
-void tox_self_get_address(const Tox *tox, uint8_t *address)
-{
- CreateFunction<void(*)(const Tox*, uint8_t*)>(__FUNCTION__)(tox, address);
-}
-
-bool tox_self_set_name(Tox *tox, const uint8_t *name, size_t length, TOX_ERR_SET_INFO *error)
-{
- return CreateFunction<bool(*)(Tox*, const uint8_t*, size_t, TOX_ERR_SET_INFO*)>(__FUNCTION__)(tox, name, length, error);
-}
-
-void tox_self_get_name(const Tox *tox, uint8_t *name)
-{
- CreateFunction<void(*)(const Tox*, uint8_t*)>(__FUNCTION__)(tox, name);
-}
-
-int tox_get_self_name_size(const Tox *tox)
-{
- return CreateFunction<int(*)(const Tox*)>(__FUNCTION__)(tox);
-}
-
-size_t tox_self_get_status_message_size(const Tox *tox)
-{
- return CreateFunction<size_t(*)(const Tox*)>(__FUNCTION__)(tox);
-}
-
-bool tox_self_set_status_message(Tox *tox, const uint8_t *status, size_t length, TOX_ERR_SET_INFO *error)
-{
- return CreateFunction<bool(*)(Tox*, const uint8_t*, size_t, TOX_ERR_SET_INFO*)>(__FUNCTION__)(tox, status, length, error);
-}
-
-void tox_self_set_status(Tox *tox, TOX_USER_STATUS user_status)
-{
- CreateFunction<void(*)(Tox*, TOX_USER_STATUS)>(__FUNCTION__)(tox, user_status);
-}
-
-void tox_self_get_status_message(const Tox *tox, uint8_t *status)
-{
- CreateFunction<void(*)(const Tox*, uint8_t*)>(__FUNCTION__)(tox, status);
-}
-
-int tox_get_self_status_message(const Tox *tox, uint8_t *buf, uint32_t maxlen)
-{
- return CreateFunction<int(*)(const Tox*, uint8_t*, uint32_t)>(__FUNCTION__)(tox, buf, maxlen);
-}
-
-uint8_t tox_get_self_user_status(const Tox *tox)
-{
- return CreateFunction<int(*)(const Tox*)>(__FUNCTION__)(tox);
-}
-
-/* SAVING AND LOADING FUNCTIONS */
-
-size_t tox_get_savedata_size(const Tox *tox)
-{
- return CreateFunction<size_t(*)(const Tox*)>(__FUNCTION__)(tox);
-}
-
-void tox_get_savedata(const Tox *tox, uint8_t *data)
-{
- CreateFunction<int(*)(const Tox*, uint8_t*)>(__FUNCTION__)(tox, data);
-}
-
-int tox_load(Tox *tox, const uint8_t *data, uint32_t length)
-{
- return CreateFunction<int(*)(Tox*, const uint8_t*, uint32_t)>(__FUNCTION__)(tox, data, length);
-}
-
-/* ADVANCED FUNCTIONS (If you don't know what they do you can safely ignore them.) */
-/*
-uint32_t tox_get_nospam(const Tox *tox)
-{
-}
-
-void tox_set_nospam(Tox *tox, uint32_t nospam)
-{
-}
-
-void tox_get_keys(Tox *tox, uint8_t *public_key, uint8_t *secret_key)
-{
-}
-
-int tox_lossy_packet_registerhandler(Tox *tox, int32_t friendnumber, uint8_t byte, int(*packet_handler_callback)(Tox *tox, int32_t friendnumber, const uint8_t *data, uint32_t len, void *object), void *object)
-{
-}
-
-int tox_send_lossy_packet(const Tox *tox, int32_t friendnumber, const uint8_t *data, uint32_t length)
-{
-}
-
-int tox_lossless_packet_registerhandler(Tox *tox, int32_t friendnumber, uint8_t byte, int(*packet_handler_callback)(Tox *tox, int32_t friendnumber, const uint8_t *data, uint32_t len, void *object), void *object)
-{
-}
-
-int tox_send_lossless_packet(const Tox *tox, int32_t friendnumber, const uint8_t *data, uint32_t length)
-{
-}
-*/
\ No newline at end of file diff --git a/protocols/Tox/src/api_transfer.cpp b/protocols/Tox/src/api_transfer.cpp deleted file mode 100644 index 446a2ccc80..0000000000 --- a/protocols/Tox/src/api_transfer.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "stdafx.h"
-
-/* FILE SENDING FUNCTIONS */
-
-bool tox_hash(uint8_t *hash, const uint8_t *data, size_t datalen)
-{
- return CreateFunction<bool(*)(uint8_t*, const uint8_t*, size_t)>(__FUNCTION__)(hash, data, datalen);
-}
-
-bool tox_file_get_file_id(const Tox *tox, uint32_t friend_number, uint32_t file_number, uint8_t *file_id, TOX_ERR_FILE_GET *error)
-{
- return CreateFunction<bool(*)(const Tox*, uint32_t, uint32_t, uint8_t*, TOX_ERR_FILE_GET*)>(__FUNCTION__)(tox, friend_number, file_number, file_id, error);
-}
-
-uint32_t tox_file_send(Tox *tox, uint32_t friend_number, uint32_t kind, uint64_t file_size, const uint8_t *file_id, const uint8_t *filename, size_t filename_length, TOX_ERR_FILE_SEND *error)
-{
- return CreateFunction<uint32_t(*)(Tox*, uint32_t, uint32_t, uint64_t, const uint8_t*, const uint8_t*, size_t, TOX_ERR_FILE_SEND*)>(__FUNCTION__)(tox, friend_number, kind, file_size, file_id, filename, filename_length, error);
-}
-
-bool tox_file_send_chunk(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, const uint8_t *data, size_t length, TOX_ERR_FILE_SEND_CHUNK *error)
-{
- return CreateFunction<bool(*)(Tox*, uint32_t, uint32_t, uint64_t, const uint8_t*, size_t, TOX_ERR_FILE_SEND_CHUNK*)>(__FUNCTION__)(tox, friend_number, file_number, position, data, length, error);
-}
-
-void tox_callback_file_chunk_request(Tox *tox, tox_file_chunk_request_cb *function)
-{
- CreateFunction<void(*)(Tox*, tox_file_chunk_request_cb)>(__FUNCTION__)(tox, function);
-}
-
-void tox_callback_file_recv(Tox *tox, tox_file_recv_cb *function)
-{
- CreateFunction<void(*)(Tox*, tox_file_recv_cb)>(__FUNCTION__)(tox, function);
-}
-
-void tox_callback_file_recv_control(Tox *tox, tox_file_recv_control_cb *function)
-{
- CreateFunction<void(*)(Tox*, tox_file_recv_control_cb)>(__FUNCTION__)(tox, function);
-}
-
-void tox_callback_file_recv_chunk(Tox *tox, tox_file_recv_chunk_cb *function)
-{
- CreateFunction<void(*)(Tox*, tox_file_recv_chunk_cb)>(__FUNCTION__)(tox, function);
-}
-
-bool tox_file_control(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control, TOX_ERR_FILE_CONTROL *error)
-{
- return CreateFunction<bool(*)(Tox*, uint32_t, uint32_t, TOX_FILE_CONTROL, TOX_ERR_FILE_CONTROL*)>(__FUNCTION__)(tox, friend_number, file_number, control, error);
-}
-
-int tox_file_send_data(Tox *tox, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length)
-{
- return CreateFunction<int(*)(Tox*, int32_t, uint8_t, const uint8_t*, uint16_t)>(__FUNCTION__)(tox, friendnumber, filenumber, data, length);
-}
-
-int tox_file_data_size(const Tox *tox, int32_t friendnumber)
-{
- return CreateFunction<int(*)(const Tox*, int32_t)>(__FUNCTION__)(tox, friendnumber);
-}
-
-uint64_t tox_file_data_remaining(const Tox *tox, int32_t friendnumber, uint8_t filenumber, uint8_t send_receive)
-{
- return CreateFunction<int(*)(const Tox*, int32_t, uint8_t, uint8_t)>(__FUNCTION__)(tox, friendnumber, filenumber, send_receive);
-}
\ No newline at end of file diff --git a/protocols/Tox/src/main.cpp b/protocols/Tox/src/main.cpp index de5356a18a..99cd7607a1 100644 --- a/protocols/Tox/src/main.cpp +++ b/protocols/Tox/src/main.cpp @@ -4,7 +4,7 @@ int hLangpack; CHAT_MANAGER *pci; CLIST_INTERFACE *pcli; HINSTANCE g_hInstance; -HMODULE g_hToxLibrary = nullptr; +HANDLE hProfileFolderPath; PLUGININFOEX pluginInfo = { @@ -13,7 +13,6 @@ PLUGININFOEX pluginInfo = PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), __DESCRIPTION, __AUTHOR, - __AUTHOREMAIL, __COPYRIGHT, __AUTHORWEB, UNICODE_AWARE, @@ -35,24 +34,26 @@ extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD) extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST }; -extern "C" int __declspec(dllexport) Load(void) +int OnModulesLoaded(WPARAM, LPARAM) { - g_hToxLibrary = LoadLibrary(TOX_LIBRARY); - if (g_hToxLibrary == nullptr) - return 1; + CToxProto::InitIcons(); + CToxProto::InitContactMenu(); + + hProfileFolderPath = FoldersRegisterCustomPathT("Tox", "ProfilesFolder", MIRANDA_USERDATAT, TranslateT("Profiles folder")); - if (!TOX_VERSION_IS_ABI_COMPATIBLE()) - { - wchar_t message[100]; - mir_snwprintf(message, TranslateT("Current version of plugin is support Tox API version %i.%i.%i which is incompatible with %s"), TOX_VERSION_MAJOR, TOX_VERSION_MINOR, TOX_VERSION_PATCH, TOX_LIBRARY); - CToxProto::ShowNotification(message, MB_ICONERROR); - FreeLibrary(g_hToxLibrary); - return 2; + if (ServiceExists(MS_ASSOCMGR_ADDNEWURLTYPE)) { + CreateServiceFunction(MODULE "/ParseUri", CToxProto::ParseToxUri); + AssocMgr_AddNewUrlTypeT("tox:", TranslateT("Tox URI scheme"), g_hInstance, IDI_TOX, MODULE "/ParseUri", 0); } + return 0; +} + +extern "C" int __declspec(dllexport) Load(void) +{ + mir_getLP(&pluginInfo); pci = Chat_GetInterface(); pcli = Clist_GetInterface(); - mir_getLP(&pluginInfo); PROTOCOLDESCRIPTOR pd = { 0 }; pd.cbSize = sizeof(pd); @@ -62,15 +63,12 @@ extern "C" int __declspec(dllexport) Load(void) pd.fnUninit = (pfnUninitProto)CToxProto::UninitAccount; Proto_RegisterModule(&pd); - HookEvent(ME_SYSTEM_MODULESLOADED, &CToxProto::OnModulesLoaded); + HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded); return 0; } extern "C" int __declspec(dllexport) Unload(void) { - if (g_hToxLibrary) - FreeLibrary(g_hToxLibrary); - return 0; }
\ No newline at end of file diff --git a/protocols/Tox/src/resource.h b/protocols/Tox/src/resource.h index 78d9fad660..4ea9d24d31 100644 --- a/protocols/Tox/src/resource.h +++ b/protocols/Tox/src/resource.h @@ -1,73 +1,61 @@ //{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
-// Used by C:\Users\unsane\Projects\c++\miranda-ng\protocols\Tox\res\resource.rc
+// Used by D:\Projects\c++\miranda-ng\protocols\Tox\res\resource.rc
//
#define IDI_TOX 100
#define IDD_USER_INFO 101
-#define IDD_PASSWORD 102
+#define IDD_PASSWORD_ENTER 102
+#define IDD_PASSWORD_CHANGE 103
#define IDD_ACCOUNT_MANAGER 104
#define IDD_SEARCH 105
#define IDD_OPTIONS_MAIN 106
#define IDD_OPTIONS_NODES 107
+#define IDD_PASSWORD_CHANGE2 107
#define IDD_ADDNODE 108
#define IDD_NODE_EDITOR 109
-#define IDD_OPTIONS_MULTIMEDIA 110
-#define IDD_CALL 111
-#define IDI_AUDIO_END 112
-#define IDI_AUDIO_RING 113
-#define IDI_AUDIO_START 114
-#define IDI_AUDIO_CALL 115
-#define IDD_CHATROOM_INVITE 172
-#define IDC_CCLIST 173
+#define IDD_PASSWORD_CREATE 110
#define IDC_EDITSCR 174
-#define IDD_CALL_RECEIVE 175
-#define IDD_CALL_SEND 176
#define IDC_TOXID 1001
#define IDC_CLIPBOARD 1002
#define IDC_SEARCH 1003
#define IDC_PASSWORD 1004
#define IDC_NAME 1005
-#define IDC_FROM 1005
#define IDC_GROUP 1006
-#define IDC_DATE 1006
#define IDC_ENABLE_UDP 1007
#define IDC_ENABLE_IPV6 1008
#define IDC_PROFILE_EXPORT 1009
-#define IDC_NAME2 1009
#define IDC_DNS_ID 1010
+#define IDC_ENABLE_HOLEPUNCHING 1010
#define IDC_PROFILE_NEW 1011
-#define IDC_SAVEPERMANENT 1012
+#define IDC_ENABLE_LOCALDISCOVERY 1012
#define IDC_PROFILE_IMPORT 1013
#define IDC_SAVEPERMANENTLY 1014
#define IDC_NODESLIST 1015
#define IDC_ADDNODE 1016
#define IDC_IPV4 1017
#define IDC_IPV6 1018
+#define IDC_PASSWORD_REMOVE 1018
#define IDC_PORT 1019
+#define IDC_PASSWORD_CHANGE 1019
#define IDC_PKEY 1020
-#define IDC_COMBO_AUDIOINPUT 1021
-#define IDC_AUDIOINPUT 1021
-#define IDC_COMBO_AUDIOOUTPUT 1022
-#define IDC_AUDIOOUTPUT 1022
-#define IDC_AUDIOFILTER 1023
-#define IDC_COMBO_VIDEOINPUT 1024
+#define IDC_PASSWORD_CHANGE2 1020
+#define IDC_PASSWORD_CREATE 1020
+#define IDC_UPDATENODES 1021
#define IDC_MAXCONNECTRETRIES 1025
#define IDC_MAXRECONNECTRETRIES 1026
#define IDC_MAXCONNECTRETRIESSPIN 1027
#define IDC_MAXRECONNECTRETRIESSPIN 1028
-#define IDC_DETAILS 1069
-#define IDC_USERMENU 1071
-#define IDC_HISTORY 1080
-#define IDC_UPDATENODES 1081
-#define IDC_PROTOCOL 1580
+#define IDC_PASSWORD_NEW 1029
+#define IDC_PASSWORD_CONFIRM 1030
+#define IDC_PASSWORD_VALIDATION 1031
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 117
+#define _APS_NEXT_RESOURCE_VALUE 118
#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1029
+#define _APS_NEXT_CONTROL_VALUE 1032
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
diff --git a/protocols/Tox/src/stdafx.h b/protocols/Tox/src/stdafx.h index c403b787ce..501eeb96cf 100644 --- a/protocols/Tox/src/stdafx.h +++ b/protocols/Tox/src/stdafx.h @@ -7,13 +7,6 @@ #include <commctrl.h>
#include <msapi/comptr.h>
-#include <mmreg.h>
-#include <MMDeviceAPI.h>
-
-#define EXIT_ON_ERROR(hres) if (FAILED(hres)) { goto Exit; }
-
-DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14);
-
#include <vector>
#include <regex>
#include <map>
@@ -30,7 +23,7 @@ DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0 #include <m_popup.h>
#include <m_icolib.h>
#include <m_userinfo.h>
-#include <m_addcontact.h>
+#include <m_contacts.h>
#include <m_message.h>
#include <m_avatars.h>
#include <m_skin.h>
@@ -45,7 +38,6 @@ DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0 #include <m_http.h>
#include <tox.h>
-#include <ToxAV.h>
#include <toxdns.h>
#include <toxencryptsave.h>
@@ -60,8 +52,6 @@ struct CToxProto; #include "tox_profile.h"
#include "tox_options.h"
#include "tox_transfer.h"
-#include "tox_multimedia.h"
-#include "tox_chatrooms.h"
#include "tox_proto.h"
#include "http_request.h"
@@ -79,14 +69,13 @@ extern HINSTANCE g_hInstance; #define TOX_MAX_CONNECT_RETRIES 10
#define TOX_MAX_RECONNECT_RETRIES 10
-#define TOX_MAX_CALLS 1
-
#define TOX_INI_PATH "%miranda_path%\\Plugins\\tox.ini"
#define TOX_JSON_PATH "%miranda_userdata%\\tox.json"
#define TOX_SETTINGS_ID "ToxID"
#define TOX_SETTINGS_DNS "DnsID"
#define TOX_SETTINGS_CHAT_ID "ChatID"
+#define TOX_SETTINGS_PASSWORD "Password"
#define TOX_SETTINGS_GROUP "DefaultGroup"
#define TOX_SETTINGS_AVATAR_HASH "AvatarHash"
@@ -97,23 +86,9 @@ extern HINSTANCE g_hInstance; #define TOX_SETTINGS_NODE_PKEY TOX_SETTINGS_NODE_PREFIX"%d_PubKey"
#define TOX_SETTINGS_NODE_COUNT TOX_SETTINGS_NODE_PREFIX"Count"
-enum TOX_DB_EVENT
-{
- DB_EVENT_ACTION = 10001,
- DB_EVENT_CALL = 20001
-};
-
-#define PSR_AUDIO "/RecvAudio"
-
+#define DB_EVENT_ACTION 10001
#define TOX_MAX_AVATAR_SIZE 1 << 16 // 2 ^ 16 bytes
-#define TOX_LIBRARY L"libtox.dll"
-extern HMODULE g_hToxLibrary;
-
-template<typename T>
-T CreateFunction(LPCSTR functionName)
-{
- return reinterpret_cast<T>(GetProcAddress(g_hToxLibrary, functionName));
-}
+extern HANDLE hProfileFolderPath;
#endif //_COMMON_H_
\ No newline at end of file diff --git a/protocols/Tox/src/tox_accounts.cpp b/protocols/Tox/src/tox_accounts.cpp index b1bfa58490..866a0dbd3b 100644 --- a/protocols/Tox/src/tox_accounts.cpp +++ b/protocols/Tox/src/tox_accounts.cpp @@ -36,19 +36,18 @@ int CToxProto::OnAccountLoaded(WPARAM, LPARAM) HookProtoEvent(ME_MSG_PRECREATEEVENT, &CToxProto::OnPreCreateMessage);
InitCustomDbEvents();
-
return 0;
}
int CToxProto::OnAccountRenamed(WPARAM, LPARAM)
{
- mir_cslock locker(profileLock);
+ mir_cslock lock(m_profileLock);
ptrW newPath(GetToxProfilePath());
wchar_t oldPath[MAX_PATH];
- mir_snwprintf(oldPath, MAX_PATH, L"%s\\%s.tox", VARSW(L"%miranda_userdata%"), wszAccountName);
+ mir_snwprintf(oldPath, MAX_PATH, L"%s\\%s.tox", VARSW(L"%miranda_userdata%"), m_accountName);
_wrename(oldPath, newPath);
- wszAccountName = mir_wstrdup(m_tszUserName);
+ m_accountName = mir_wstrdup(m_tszUserName);
return 0;
}
diff --git a/protocols/Tox/src/tox_avatars.cpp b/protocols/Tox/src/tox_avatars.cpp index 3e41c796f6..9d234b1dd8 100644 --- a/protocols/Tox/src/tox_avatars.cpp +++ b/protocols/Tox/src/tox_avatars.cpp @@ -77,7 +77,7 @@ void CToxProto::SetToxAvatar(const wchar_t* path) debugLogA(__FUNCTION__": send avatar to friend (%d)", friendNumber);
TOX_ERR_FILE_SEND error;
- uint32_t fileNumber = tox_file_send(toxThread->Tox(), friendNumber, TOX_FILE_KIND_AVATAR, length, hash, nullptr, 0, &error);
+ uint32_t fileNumber = tox_file_send(m_toxThread->Tox(), friendNumber, TOX_FILE_KIND_AVATAR, length, hash, nullptr, 0, &error);
if (error != TOX_ERR_FILE_SEND_OK) {
mir_free(data);
debugLogA(__FUNCTION__": failed to set new avatar (%d)", error);
@@ -173,7 +173,7 @@ INT_PTR CToxProto::SetMyAvatar(WPARAM, LPARAM lParam) debugLogA(__FUNCTION__": unset avatar for friend (%d)", friendNumber);
TOX_ERR_FILE_SEND error;
- tox_file_send(toxThread->Tox(), friendNumber, TOX_FILE_KIND_AVATAR, 0, nullptr, nullptr, 0, &error);
+ tox_file_send(m_toxThread->Tox(), friendNumber, TOX_FILE_KIND_AVATAR, 0, nullptr, nullptr, 0, &error);
if (error != TOX_ERR_FILE_SEND_OK) {
debugLogA(__FUNCTION__": failed to unset avatar (%d)", error);
return 0;
diff --git a/protocols/Tox/src/tox_bootstrap.cpp b/protocols/Tox/src/tox_bootstrap.cpp index 5f1ae93dc1..f144c0af16 100644 --- a/protocols/Tox/src/tox_bootstrap.cpp +++ b/protocols/Tox/src/tox_bootstrap.cpp @@ -2,7 +2,7 @@ void CToxProto::BootstrapUdpNode(Tox *tox, const char *address, int port, const char *hexKey) { - if (!toxThread) + if (!m_toxThread) return; if (address == nullptr || hexKey == nullptr) @@ -16,7 +16,7 @@ void CToxProto::BootstrapUdpNode(Tox *tox, const char *address, int port, const void CToxProto::BootstrapTcpRelay(Tox *tox, const char *address, int port, const char *hexKey) { - if (!toxThread) + if (!m_toxThread) return; if (address == nullptr || hexKey == nullptr) diff --git a/protocols/Tox/src/tox_chatrooms.cpp b/protocols/Tox/src/tox_chatrooms.cpp deleted file mode 100644 index 5ca9895fcb..0000000000 --- a/protocols/Tox/src/tox_chatrooms.cpp +++ /dev/null @@ -1,326 +0,0 @@ -#include "stdafx.h"
-/*
-MCONTACT CToxProto::GetChatRoom(int groupNumber)
-{
- MCONTACT hContact = NULL;
- for (hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName))
- {
- if (!isChatRoom(hContact))
- {
- continue;
- }
- int chatRoumNumber = getWord(hContact, TOX_SETTINGS_CHAT_ID, TOX_ERROR);
- if (groupNumber == chatRoumNumber)
- {
- break;
- }
- }
- return hContact;
-}
-
-MCONTACT CToxProto::AddChatRoom(int groupNumber)
-{
- MCONTACT hContact = GetChatRoom(groupNumber);
- if (!hContact)
- {
- hContact = db_add_contact();
- Proto_AddToContact(hContact, m_szModuleName);
-
- setWord(hContact, TOX_SETTINGS_CHAT_ID, groupNumber);
-
- wchar_t title[MAX_PATH];
- mir_snwprintf(title, L"%s #%d", TranslateT("Group chat"), groupNumber);
- setWString(hContact, "Nick", title);
-
- DBVARIANT dbv;
- if (!db_get_s(NULL, "Chat", "AddToGroup", &dbv, DBVT_WCHAR))
- {
- db_set_ws(hContact, "CList", "Group", dbv.ptszVal);
- db_free(&dbv);
- }
-
- setByte(hContact, "ChatRoom", 1);
- }
- return hContact;
-}
-
-void CToxProto::LoadChatRoomList(void*)
-{
- uint32_t count = tox_count_chatlist(toxThread->Tox());
- if (count == 0)
- {
- debugLogA(__FUNCTION__": your group chat list is empty");
- return;
- }
- int32_t *groupChats = (int32_t*)mir_alloc(count * sizeof(int32_t));
- tox_get_chatlist(toxThread->Tox(), groupChats, count);
- for (uint32_t i = 0; i < count; i++)
- {
- int32_t groupNumber = groupChats[i];
- int type = tox_group_get_type(toxThread->Tox(), groupNumber);
- if (type == TOX_GROUPCHAT_TYPE_AV)
- {
- continue;
- }
- MCONTACT hContact = AddChatRoom(groupNumber);
- if (hContact)
- {
- uint8_t title[TOX_MAX_NAME_LENGTH] = { 0 };
- tox_group_get_title(toxThread->Tox(), groupNumber, title, TOX_MAX_NAME_LENGTH);
- setWString(hContact, "Nick", ptrW(mir_utf8decodeW((char*)title)));
- }
- }
- mir_free(groupChats);
-}
-
-int CToxProto::OnGroupChatEventHook(WPARAM, LPARAM lParam)
-{
- GCHOOK *gch = (GCHOOK*)lParam;
- if (!gch)
- {
- return 1;
- }
- else
- return 0;
-}
-
-int CToxProto::OnGroupChatMenuHook(WPARAM, LPARAM)
-{
- return 0;
-}
-
-INT_PTR CToxProto::OnJoinChatRoom(WPARAM, LPARAM)
-{
- return 0;
-}
-
-INT_PTR CToxProto::OnLeaveChatRoom(WPARAM, LPARAM)
-{
- return 0;
-}
-
-INT_PTR CToxProto::OnCreateChatRoom(WPARAM, LPARAM)
-{
- ChatRoomInviteParam param = { this };
-
- if (DialogBoxParam(
- g_hInstance,
- MAKEINTRESOURCE(IDD_CHATROOM_INVITE),
- NULL,
- CToxProto::ChatRoomInviteProc,
- (LPARAM)¶m) == IDOK && !param.invitedContacts.empty())
- {
- int groupNumber = tox_add_groupchat(toxThread->Tox());
- if (groupNumber == TOX_ERROR)
- {
- return 1;
- }
- for (std::vector<MCONTACT>::iterator it = param.invitedContacts.begin(); it != param.invitedContacts.end(); ++it)
- {
- int32_t friendNumber = GetToxFriendNumber(*it);
- if (friendNumber == TOX_ERROR || tox_invite_friend(toxThread->Tox(), friendNumber, groupNumber) == TOX_ERROR)
- {
- return 1;
- }
- }
- MCONTACT hContact = AddChatRoom(groupNumber);
- if (!hContact)
- {
- return 1;
- }
- return 0;
- }
-
- return 1;
-}
-
-void CToxProto::InitGroupChatModule()
-{
- GCREGISTER gcr = {};
- gcr.iMaxText = 0;
- gcr.ptszDispName = this->m_tszUserName;
- gcr.pszModule = this->m_szModuleName;
- Chat_Register(&gcr);
-
- HookProtoEvent(ME_GC_EVENT, &CToxProto::OnGroupChatEventHook);
- HookProtoEvent(ME_GC_BUILDMENU, &CToxProto::OnGroupChatMenuHook);
-
- CreateProtoService(PS_JOINCHAT, &CToxProto::OnJoinChatRoom);
- CreateProtoService(PS_LEAVECHAT, &CToxProto::OnLeaveChatRoom);
-}
-
-void CToxProto::CloseAllChatChatSessions()
-{
- GC_INFO gci = { 0 };
- gci.Flags = GCF_BYINDEX | GCF_ID;
- gci.pszModule = m_szModuleName;
-
- int count = pci->SM_GetCount(m_szModuleName);
- for (int i = 0; i < count; i++)
- {
- gci.iItem = i;
- if (!Chat_GetInfo(&gci))
- {
- Chat_Control(m_szModuleName, gci.pszID, SESSION_OFFLINE);
- Chat_Terminate(m_szModuleName, gci.pszID);
- }
- }
-}
-
-void CToxProto::OnGroupChatInvite(Tox *tox, int32_t friendNumber, uint8_t type, const uint8_t *data, uint16_t length, void *arg)
-{
- CToxProto *proto = (CToxProto*)arg;
-
- if (type == TOX_GROUPCHAT_TYPE_AV)
- {
- Netlib_Logf(proto->m_hNetlibUser, __FUNCTION__": audio chat is not supported yet");
- return;
- }
-
- int groupNumber = tox_join_groupchat(tox, friendNumber, data, length);
- if (groupNumber == TOX_ERROR)
- {
- Netlib_Logf(proto->m_hNetlibUser, __FUNCTION__": failed to join to group chat");
- return;
- }
-
- MCONTACT hContact = proto->AddChatRoom(groupNumber);
- if (!hContact)
- {
- Netlib_Logf(proto->m_hNetlibUser, __FUNCTION__": failed to create group chat");
- }
-}
-
-void CToxProto::ChatValidateContact(HWND hwndList, const std::vector<MCONTACT> &contacts, MCONTACT hContact)
-{
- bool isProtoContact = mir_strcmpi(GetContactProto(hContact), m_szModuleName) == 0;
- if (isProtoContact && !isChatRoom(hContact))
- {
- if (std::find(contacts.begin(), contacts.end(), hContact) != contacts.end())
- {
- SendMessage(hwndList, CLM_DELETEITEM, (WPARAM)hContact, 0);
- }
- return;
- }
- SendMessage(hwndList, CLM_DELETEITEM, (WPARAM)hContact, 0);
-}
-
-void CToxProto::ChatPrepare(HWND hwndList, const std::vector<MCONTACT> &contacts, MCONTACT hContact)
-{
- if (hContact == NULL)
- {
- hContact = (MCONTACT)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_ROOT, 0);
- }
- while (hContact)
- {
- if (IsHContactGroup(hContact))
- {
- MCONTACT hSubContact = (MCONTACT)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hContact);
- if (hSubContact)
- {
- ChatPrepare(hwndList, contacts, hSubContact);
- }
- }
- else if (IsHContactContact(hContact))
- {
- ChatValidateContact(hwndList, contacts, hContact);
- }
- hContact = (MCONTACT)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXT, (LPARAM)hContact);
- }
-}
-
-std::vector<MCONTACT> CToxProto::GetInvitedContacts(HWND hwndList, MCONTACT hContact)
-{
- std::vector<MCONTACT> contacts;
- if (hContact == NULL)
- {
- hContact = (MCONTACT)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_ROOT, 0);
- }
- while (hContact)
- {
- if (IsHContactGroup(hContact))
- {
- MCONTACT hSubContact = (MCONTACT)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hContact);
- if (hSubContact)
- {
- std::vector<MCONTACT> subContacts = GetInvitedContacts(hwndList, hSubContact);
- contacts.insert(contacts.end(), subContacts.begin(), subContacts.end());
- }
- }
- else
- {
- int cheked = SendMessage(hwndList, CLM_GETCHECKMARK, (WPARAM)hContact, 0);
- if (cheked)
- {
- contacts.push_back(hContact);
- }
- }
- hContact = (MCONTACT)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXT, (LPARAM)hContact);
- }
- return contacts;
-}
-
-INT_PTR CALLBACK CToxProto::ChatRoomInviteProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- HWND hwndList = GetDlgItem(hwndDlg, IDC_CCLIST);
- ChatRoomInviteParam *param = (ChatRoomInviteParam*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
-
- switch (msg) {
- case WM_INITDIALOG:
- TranslateDialogDefault(hwndDlg);
- {
- param = (ChatRoomInviteParam*)lParam;
- SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
- {
- //HWND hwndClist = GetDlgItem(hwndDlg, IDC_CCLIST);
- //SetWindowLongPtr(hwndClist, GWL_STYLE, GetWindowLongPtr(hwndClist, GWL_STYLE) & ~CLS_HIDEOFFLINE);
- }
- }
- break;
-
- case WM_CLOSE:
- EndDialog(hwndDlg, 0);
- break;
-
- case WM_NOTIFY:
- {
- NMCLISTCONTROL *nmc = (NMCLISTCONTROL*)lParam;
- if (nmc->hdr.idFrom == IDC_CCLIST)
- {
- switch (nmc->hdr.code)
- {
- case CLN_NEWCONTACT:
- if ((nmc->flags & (CLNF_ISGROUP | CLNF_ISINFO)) == 0)
- {
- param->proto->ChatValidateContact(nmc->hdr.hwndFrom, param->invitedContacts, (UINT_PTR)nmc->hItem);
- }
- break;
-
- case CLN_LISTREBUILT:
- {
- param->proto->ChatPrepare(nmc->hdr.hwndFrom, param->invitedContacts);
- }
- break;
- }
- }
- }
- break;
-
- case WM_COMMAND:
- switch (LOWORD(wParam))
- {
- case IDOK:
- //SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
- param->invitedContacts = param->proto->GetInvitedContacts(hwndList);
- EndDialog(hwndDlg, IDOK);
- break;
-
- case IDCANCEL:
- EndDialog(hwndDlg, IDCANCEL);
- break;
- }
- break;
- }
- return FALSE;
-}
-*/
\ No newline at end of file diff --git a/protocols/Tox/src/tox_chatrooms.h b/protocols/Tox/src/tox_chatrooms.h deleted file mode 100644 index 0f51a7391e..0000000000 --- a/protocols/Tox/src/tox_chatrooms.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _TOX_CHATROOMS_H_
-#define _TOX_CHATROOMS_H_
-
-struct ChatRoomInviteParam
-{
- CToxProto *proto;
- std::vector<MCONTACT> invitedContacts;
-};
-
-#endif //_TOX_CHATROOMS_H_
\ No newline at end of file diff --git a/protocols/Tox/src/tox_connection.cpp b/protocols/Tox/src/tox_connection.cpp index 4c578a9696..80a84b74c0 100644 --- a/protocols/Tox/src/tox_connection.cpp +++ b/protocols/Tox/src/tox_connection.cpp @@ -2,7 +2,7 @@ bool CToxProto::IsOnline() { - return toxThread && m_iStatus >= ID_STATUS_ONLINE; + return m_toxThread && m_iStatus >= ID_STATUS_ONLINE; } void CToxProto::TryConnect(Tox *tox) @@ -99,7 +99,7 @@ void CToxProto::PollingThread(void*) } tox_options_free(options); - this->toxThread = &toxThread; + m_toxThread = &toxThread; InitToxCore(toxThread.Tox()); BootstrapNodes(toxThread.Tox()); ForkThread(&CToxProto::CheckingThread, toxThread.Tox()); @@ -113,7 +113,7 @@ void CToxProto::PollingThread(void*) } UninitToxCore(toxThread.Tox()); - this->toxThread = nullptr; + m_toxThread = nullptr; hPollingThread = nullptr; debugLogA(__FUNCTION__": leaving"); diff --git a/protocols/Tox/src/tox_contacts.cpp b/protocols/Tox/src/tox_contacts.cpp index 3b76b37407..4e1ee4abf4 100644 --- a/protocols/Tox/src/tox_contacts.cpp +++ b/protocols/Tox/src/tox_contacts.cpp @@ -96,8 +96,8 @@ MCONTACT CToxProto::AddContact(const char *address, const char *nick, const char if (mir_strlen(dnsId))
setWString(hContact, TOX_SETTINGS_DNS, ptrW(mir_utf8decodeW(dnsId)));
- if (wszGroup)
- db_set_ws(hContact, "CList", "Group", wszGroup);
+ if (m_defaultGroup)
+ db_set_ws(hContact, "CList", "Group", m_defaultGroup);
setByte(hContact, "Auth", 1);
setByte(hContact, "Grant", 1);
@@ -112,7 +112,7 @@ uint32_t CToxProto::GetToxFriendNumber(MCONTACT hContact) {
ToxBinAddress pubKey(ptrA(getStringA(hContact, TOX_SETTINGS_ID)));
TOX_ERR_FRIEND_BY_PUBLIC_KEY error;
- uint32_t friendNumber = tox_friend_by_public_key(toxThread->Tox(), pubKey.GetPubKey(), &error);
+ uint32_t friendNumber = tox_friend_by_public_key(m_toxThread->Tox(), pubKey.GetPubKey(), &error);
if (error != TOX_ERR_FRIEND_BY_PUBLIC_KEY_OK)
debugLogA(__FUNCTION__": failed to get friend number (%d)", error);
return friendNumber;
@@ -123,7 +123,7 @@ void CToxProto::LoadFriendList(Tox *tox) size_t count = tox_self_get_friend_list_size(tox);
if (count > 0) {
uint32_t *friends = (uint32_t*)mir_alloc(count * sizeof(uint32_t));
- tox_self_get_friend_list(toxThread->Tox(), friends);
+ tox_self_get_friend_list(m_toxThread->Tox(), friends);
for (size_t i = 0; i < count; i++) {
uint32_t friendNumber = friends[i];
@@ -139,13 +139,13 @@ void CToxProto::LoadFriendList(Tox *tox) TOX_ERR_FRIEND_QUERY getNameResult;
uint8_t nick[TOX_MAX_NAME_LENGTH] = { 0 };
- if (tox_friend_get_name(toxThread->Tox(), friendNumber, nick, &getNameResult))
+ if (tox_friend_get_name(m_toxThread->Tox(), friendNumber, nick, &getNameResult))
setWString(hContact, "Nick", ptrW(mir_utf8decodeW((char*)nick)));
else
debugLogA(__FUNCTION__": failed to get friend name (%d)", getNameResult);
TOX_ERR_FRIEND_GET_LAST_ONLINE getLastOnlineResult;
- uint64_t timestamp = tox_friend_get_last_online(toxThread->Tox(), friendNumber, &getLastOnlineResult);
+ uint64_t timestamp = tox_friend_get_last_online(m_toxThread->Tox(), friendNumber, &getLastOnlineResult);
if (getLastOnlineResult == TOX_ERR_FRIEND_GET_LAST_ONLINE_OK)
setDword(hContact, "LastEventDateTS", timestamp);
else
@@ -166,7 +166,7 @@ INT_PTR CToxProto::OnRequestAuth(WPARAM hContact, LPARAM lParam) ToxBinAddress address(ptrA(getStringA(hContact, TOX_SETTINGS_ID)));
TOX_ERR_FRIEND_ADD addFriendResult;
- int32_t friendNumber = tox_friend_add(toxThread->Tox(), address, (uint8_t*)reason, length, &addFriendResult);
+ int32_t friendNumber = tox_friend_add(m_toxThread->Tox(), address, (uint8_t*)reason, length, &addFriendResult);
if (addFriendResult != TOX_ERR_FRIEND_ADD_OK) {
debugLogA(__FUNCTION__": failed to request auth(%d)", addFriendResult);
return addFriendResult;
@@ -192,7 +192,7 @@ INT_PTR CToxProto::OnGrantAuth(WPARAM hContact, LPARAM) ToxBinAddress pubKey(ptrA(getStringA(hContact, TOX_SETTINGS_ID)));
TOX_ERR_FRIEND_ADD error;
- tox_friend_add_norequest(toxThread->Tox(), pubKey, &error);
+ tox_friend_add_norequest(m_toxThread->Tox(), pubKey, &error);
if (error != TOX_ERR_FRIEND_ADD_OK) {
debugLogA(__FUNCTION__": failed to grant auth (%d)", error);
return error;
@@ -201,7 +201,7 @@ INT_PTR CToxProto::OnGrantAuth(WPARAM hContact, LPARAM) db_unset(hContact, "CList", "NotOnList");
delSetting(hContact, "Grant");
- SaveToxProfile(toxThread->Tox());
+ SaveToxProfile(m_toxThread->Tox());
return 0;
}
@@ -214,21 +214,12 @@ int CToxProto::OnContactDeleted(MCONTACT hContact, LPARAM) if (!isChatRoom(hContact)) {
int32_t friendNumber = GetToxFriendNumber(hContact);
TOX_ERR_FRIEND_DELETE error;
- if (!tox_friend_delete(toxThread->Tox(), friendNumber, &error)) {
+ if (!tox_friend_delete(m_toxThread->Tox(), friendNumber, &error)) {
debugLogA(__FUNCTION__": failed to delete friend (%d)", error);
return error;
}
- SaveToxProfile(toxThread->Tox());
+ SaveToxProfile(m_toxThread->Tox());
}
- /*else
- {
- OnLeaveChatRoom(hContact, 0);
- int groupNumber = 0; // ???
- if (groupNumber == TOX_ERROR || tox_del_groupchat(tox, groupNumber) == TOX_ERROR)
- {
- return 1;
- }
- }*/
return 0;
}
@@ -339,7 +330,7 @@ void CToxProto::OnConnectionStatusChanged(Tox *tox, uint32_t friendNumber, TOX_C proto->debugLogA(__FUNCTION__": send avatar to friend (%d)", friendNumber);
TOX_ERR_FILE_SEND error;
- uint32_t fileNumber = tox_file_send(proto->toxThread->Tox(), friendNumber, TOX_FILE_KIND_AVATAR, length, hash, nullptr, 0, &error);
+ uint32_t fileNumber = tox_file_send(proto->m_toxThread->Tox(), friendNumber, TOX_FILE_KIND_AVATAR, length, hash, nullptr, 0, &error);
if (error != TOX_ERR_FILE_SEND_OK) {
Netlib_Logf(proto->m_hNetlibUser, __FUNCTION__": failed to set new avatar");
fclose(hFile);
@@ -355,7 +346,7 @@ void CToxProto::OnConnectionStatusChanged(Tox *tox, uint32_t friendNumber, TOX_C }
else {
proto->debugLogA(__FUNCTION__": unset avatar for friend (%d)", friendNumber);
- tox_file_send(proto->toxThread->Tox(), friendNumber, TOX_FILE_KIND_AVATAR, 0, nullptr, nullptr, 0, nullptr);
+ tox_file_send(proto->m_toxThread->Tox(), friendNumber, TOX_FILE_KIND_AVATAR, 0, nullptr, nullptr, 0, nullptr);
}
}
diff --git a/protocols/Tox/src/tox_core.cpp b/protocols/Tox/src/tox_core.cpp index ab2e4ceb1d..de977b090f 100644 --- a/protocols/Tox/src/tox_core.cpp +++ b/protocols/Tox/src/tox_core.cpp @@ -10,7 +10,10 @@ Tox_Options* CToxProto::GetToxOptions() }
options->udp_enabled = getBool("EnableUDP", 1);
+ if (options->udp_enabled && getBool("EnableUDPHolePunching", 1))
+ options->hole_punching_enabled = true;
options->ipv6_enabled = getBool("EnableIPv6", 0);
+ options->local_discovery_enabled = getBool("EnableLocalDiscovery", 0);
if (m_hNetlibUser != nullptr) {
NETLIBUSERSETTINGS nlus = { sizeof(nlus) };
@@ -58,22 +61,6 @@ void CToxProto::InitToxCore(Tox *tox) tox_callback_file_recv(tox, OnFriendFile);
tox_callback_file_recv_chunk(tox, OnDataReceiving);
tox_callback_file_chunk_request(tox, OnFileSendData);
- // group chats
- //tox_callback_group_invite(tox, OnGroupChatInvite, this);
- // a/v
- //if (IsWinVerVistaPlus())
- //{
- // TOXAV_ERR_NEW avInitError;
- // toxThread->Tox()AV = toxav_new(toxThread->Tox(), &avInitError);
- // if (initError != TOX_ERR_NEW_OK)
- // {
- // toxav_callback_call(toxThread->Tox()AV, OnFriendCall, this);
- // toxav_callback_call_state(toxThread->Tox()AV, OnFriendCallState, this);
- // toxav_callback_bit_rate_status(toxThread->Tox()AV, OnBitrateChanged, this);
- // toxav_callback_audio_receive_frame(toxThread->Tox()AV, OnFriendAudioFrame, this);
- // //toxav_callback_video_receive_frame(toxThread->Tox()AV, , this);
- // }
- //}
uint8_t data[TOX_ADDRESS_SIZE];
tox_self_get_address(tox, data);
diff --git a/protocols/Tox/src/tox_events.cpp b/protocols/Tox/src/tox_events.cpp deleted file mode 100644 index f0afe46dbd..0000000000 --- a/protocols/Tox/src/tox_events.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "stdafx.h"
-
-int CToxProto::OnModulesLoaded(WPARAM, LPARAM)
-{
- CToxProto::InitIcons();
- CToxProto::InitMenus();
-
- hProfileFolderPath = FoldersRegisterCustomPathT("Tox", "ProfilesFolder", MIRANDA_USERDATAT, TranslateT("Profiles folder"));
-
- if (ServiceExists(MS_ASSOCMGR_ADDNEWURLTYPE)) {
- CreateServiceFunction(MODULE "/ParseUri", CToxProto::ParseToxUri);
- AssocMgr_AddNewUrlTypeT("tox:", TranslateT("Tox URI scheme"), g_hInstance, IDI_TOX, MODULE "/ParseUri", 0);
- }
-
- return 0;
-}
-
-void CToxProto::InitCustomDbEvents()
-{
- DBEVENTTYPEDESCR dbEventType = { sizeof(dbEventType) };
- dbEventType.module = m_szModuleName;
- dbEventType.flags = DETF_HISTORY | DETF_MSGWINDOW;
-
- dbEventType.eventType = DB_EVENT_ACTION;
- dbEventType.descr = Translate("Action");
- DbEvent_RegisterType(&dbEventType);
-
- dbEventType.eventType = DB_EVENT_CALL;
- dbEventType.descr = Translate("Call");
- dbEventType.eventIcon = GetIconHandle(IDI_AUDIO_START);
- DbEvent_RegisterType(&dbEventType);
-}
diff --git a/protocols/Tox/src/tox_icons.cpp b/protocols/Tox/src/tox_icons.cpp index a96e7984d4..928685ebf3 100644 --- a/protocols/Tox/src/tox_icons.cpp +++ b/protocols/Tox/src/tox_icons.cpp @@ -3,10 +3,6 @@ IconItemT CToxProto::Icons[] =
{
{ LPGENW("Protocol icon"), "main", IDI_TOX },
- { LPGENW("Audio call"), "audio_call", IDI_AUDIO_CALL },
- { LPGENW("Audio ring"), "audio_ring", IDI_AUDIO_RING },
- { LPGENW("Audio start"), "audio_start", IDI_AUDIO_START },
- { LPGENW("Audio end"), "audio_end", IDI_AUDIO_END },
};
void CToxProto::InitIcons()
diff --git a/protocols/Tox/src/tox_menus.cpp b/protocols/Tox/src/tox_menus.cpp index ed70ad8a7b..34b3047fb4 100644 --- a/protocols/Tox/src/tox_menus.cpp +++ b/protocols/Tox/src/tox_menus.cpp @@ -21,9 +21,6 @@ int CToxProto::OnPrebuildContactMenu(WPARAM hContact, LPARAM) bool isGrantNeed = getByte(hContact, "Grant", 0) > 0;
Menu_ShowItem(ContactMenuItems[CMI_AUTH_GRANT], isCtrlPressed || isGrantNeed);
- bool isContactOnline = GetContactStatus(hContact) > ID_STATUS_OFFLINE;
- Menu_ShowItem(ContactMenuItems[CMI_AUDIO_CALL], toxThread->ToxAV() && isContactOnline);
-
return 0;
}
@@ -35,7 +32,7 @@ int CToxProto::PrebuildContactMenu(WPARAM hContact, LPARAM lParam) return proto ? proto->OnPrebuildContactMenu(hContact, lParam) : 0;
}
-void CToxProto::InitMenus()
+void CToxProto::InitContactMenu()
{
HookEvent(ME_CLIST_PREBUILDCONTACTMENU, &CToxProto::PrebuildContactMenu);
@@ -59,19 +56,29 @@ void CToxProto::InitMenus() mi.hIcolibItem = ::Skin_GetIconHandle(SKINICON_AUTH_GRANT);
ContactMenuItems[CMI_AUTH_GRANT] = Menu_AddContactMenuItem(&mi);
CreateServiceFunction(mi.pszService, GlobalService<&CToxProto::OnGrantAuth>);
+}
+
+int CToxProto::PrebuildStatusMenu(WPARAM, LPARAM)
+{
+ bool isOnline = IsOnline();
+ Menu_EnableItem(StatusMenuItems[SMI_PASSWORD], isOnline);
+ Menu_EnableItem(StatusMenuItems[SMI_PASSWORD_CREATE], isOnline);
+ Menu_EnableItem(StatusMenuItems[SMI_PASSWORD_CHANGE], isOnline);
+ Menu_EnableItem(StatusMenuItems[SMI_PASSWORD_REMOVE], isOnline);
+
+ pass_ptrW password(getWStringA(TOX_SETTINGS_PASSWORD));
+ bool passwordExists = mir_wstrlen(password) > 0;
+ Menu_ShowItem(StatusMenuItems[SMI_PASSWORD_CREATE], !passwordExists);
+ Menu_ShowItem(StatusMenuItems[SMI_PASSWORD_CHANGE], passwordExists);
+ Menu_ShowItem(StatusMenuItems[SMI_PASSWORD_REMOVE], passwordExists);
- // Start audio call
- SET_UID(mi, 0x116cb7fe, 0xce37, 0x429c, 0xb0, 0xa9, 0x7d, 0xe7, 0x70, 0x59, 0xc3, 0x95);
- mi.pszService = MODULE"/Audio/Call";
- mi.name.w = LPGENW("Call");
- mi.position = -2000020000 + CMI_AUDIO_CALL;
- mi.hIcolibItem = GetIconHandle(IDI_AUDIO_START);
- ContactMenuItems[CMI_AUDIO_CALL] = Menu_AddContactMenuItem(&mi);
- CreateServiceFunction(mi.pszService, GlobalService<&CToxProto::OnSendAudioCall>);
+ return 0;
}
int CToxProto::OnInitStatusMenu()
{
+ HookProtoEvent(ME_CLIST_PREBUILDSTATUSMENU, &CToxProto::PrebuildStatusMenu);
+
CMenuItem mi;
mi.flags = CMIF_UNICODE;
mi.root = Menu_GetProtocolRoot(this);
@@ -81,16 +88,34 @@ int CToxProto::OnInitStatusMenu() CreateProtoService(mi.pszService, &CToxProto::OnCopyToxID);
mi.name.w = LPGENW("Copy Tox ID");
mi.position = SMI_POSITION + SMI_TOXID_COPY;
- Menu_AddProtoMenuItem(&mi, m_szModuleName);
-
- // Create group chat command
- /*
- mi.pszService = "/CreateChatRoom";
- CreateProtoService(mi.pszService, &CToxProto::OnCreateChatRoom);
- mi.name.w = LPGENW("Create group chat");
- mi.position = SMI_POSITION + SMI_GROUPCHAT_CREATE;
- mi.hIcolibItem = Skin_GetIconHandle("conference");
- HGENMENU hCreateChatRoom = Menu_AddProtoMenuItem(&mi, m_szModuleName);*/
+ StatusMenuItems[SMI_TOXID_COPY] = Menu_AddProtoMenuItem(&mi, m_szModuleName);
+
+ // Password
+ mi.pszService = nullptr;
+ mi.name.w = LPGENW("Password");
+ StatusMenuItems[SMI_PASSWORD] = Menu_AddProtoMenuItem(&mi, m_szModuleName);
+ mi.root = StatusMenuItems[SMI_PASSWORD];
+
+ // Create password command
+ mi.pszService = "/CreatePassword";
+ CreateProtoService(mi.pszService, &CToxProto::OnCreatePassword);
+ mi.name.w = LPGENW("Create password");
+ mi.position = SMI_PASSWORD_CREATE;
+ StatusMenuItems[SMI_PASSWORD_CREATE] = Menu_AddProtoMenuItem(&mi, m_szModuleName);
+
+ // Change password command
+ mi.pszService = "/ChangePassword";
+ CreateProtoService(mi.pszService, &CToxProto::OnChangePassword);
+ mi.name.w = LPGENW("Change password");
+ mi.position = SMI_PASSWORD_CHANGE;
+ StatusMenuItems[SMI_PASSWORD_CHANGE] = Menu_AddProtoMenuItem(&mi, m_szModuleName);
+
+ // Remove password command
+ mi.pszService = "/RemovePassword";
+ CreateProtoService(mi.pszService, &CToxProto::OnRemovePassword);
+ mi.name.w = LPGENW("Remove password");
+ mi.position = SMI_PASSWORD_REMOVE;
+ StatusMenuItems[SMI_PASSWORD_REMOVE] = Menu_AddProtoMenuItem(&mi, m_szModuleName);
return 0;
}
diff --git a/protocols/Tox/src/tox_menus.h b/protocols/Tox/src/tox_menus.h index f4930265a2..85b9f55055 100644 --- a/protocols/Tox/src/tox_menus.h +++ b/protocols/Tox/src/tox_menus.h @@ -7,7 +7,6 @@ enum CMI_MENU_ITEMS {
CMI_AUTH_REQUEST,
CMI_AUTH_GRANT,
- CMI_AUDIO_CALL,
CMI_MAX // this item shall be the last one
};
@@ -16,7 +15,10 @@ enum CMI_MENU_ITEMS enum SMI_MENU_ITEMS
{
SMI_TOXID_COPY,
- SMI_GROUPCHAT_CREATE,
+ SMI_PASSWORD,
+ SMI_PASSWORD_CREATE,
+ SMI_PASSWORD_CHANGE,
+ SMI_PASSWORD_REMOVE,
SMI_MAX // this item shall be the last one
};
diff --git a/protocols/Tox/src/tox_messages.cpp b/protocols/Tox/src/tox_messages.cpp index 761294cbf7..0d7ad78b04 100644 --- a/protocols/Tox/src/tox_messages.cpp +++ b/protocols/Tox/src/tox_messages.cpp @@ -1,5 +1,16 @@ #include "stdafx.h"
+void CToxProto::InitCustomDbEvents()
+{
+ DBEVENTTYPEDESCR dbEventType = { sizeof(dbEventType) };
+ dbEventType.module = m_szModuleName;
+ dbEventType.flags = DETF_HISTORY | DETF_MSGWINDOW;
+
+ dbEventType.eventType = DB_EVENT_ACTION;
+ dbEventType.descr = Translate("Action");
+ DbEvent_RegisterType(&dbEventType);
+}
+
/* MESSAGE RECEIVING */
// incoming message flow
@@ -58,7 +69,7 @@ void CToxProto::SendMessageAsync(void *arg) }
TOX_ERR_FRIEND_SEND_MESSAGE sendError;
- int messageNumber = tox_friend_send_message(toxThread->Tox(), friendNumber, type, msg, msgLen, &sendError);
+ int messageNumber = tox_friend_send_message(m_toxThread->Tox(), friendNumber, type, msg, msgLen, &sendError);
if (sendError != TOX_ERR_FRIEND_SEND_MESSAGE_OK) {
debugLogA(__FUNCTION__": failed to send message for %d (%d)", friendNumber, sendError);
ProtoBroadcastAck(param->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE)param->hMessage, (LPARAM)_T2A(ToxErrorToString(sendError)));
@@ -138,7 +149,7 @@ void CToxProto::GetStatusMessageAsync(void* arg) }
TOX_ERR_FRIEND_QUERY error;
- size_t size = tox_friend_get_status_message_size(toxThread->Tox(), friendNumber, &error);
+ size_t size = tox_friend_get_status_message_size(m_toxThread->Tox(), friendNumber, &error);
if (error != TOX_ERR_FRIEND_QUERY::TOX_ERR_FRIEND_QUERY_OK) {
debugLogA(__FUNCTION__": failed to get status message for (%d) (%d)", friendNumber, error);
ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_FAILED, (HANDLE)hContact, 0);
@@ -146,7 +157,7 @@ void CToxProto::GetStatusMessageAsync(void* arg) }
ptrA statusMessage((char*)mir_calloc(size + 1));
- if (!tox_friend_get_status_message(toxThread->Tox(), friendNumber, (uint8_t*)(char*)statusMessage, &error)) {
+ if (!tox_friend_get_status_message(m_toxThread->Tox(), friendNumber, (uint8_t*)(char*)statusMessage, &error)) {
debugLogA(__FUNCTION__": failed to get status message for (%d) (%d)", friendNumber, error);
ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_FAILED, (HANDLE)hContact, 0);
return;
@@ -164,7 +175,7 @@ int CToxProto::OnUserIsTyping(MCONTACT hContact, int type) return 0;
TOX_ERR_SET_TYPING error;
- if (!tox_self_set_typing(toxThread->Tox(), friendNumber, type == PROTOTYPE_SELFTYPING_ON, &error))
+ if (!tox_self_set_typing(m_toxThread->Tox(), friendNumber, type == PROTOTYPE_SELFTYPING_ON, &error))
debugLogA(__FUNCTION__": failed to send typing (%d)", error);
return 0;
diff --git a/protocols/Tox/src/tox_multimedia.cpp b/protocols/Tox/src/tox_multimedia.cpp deleted file mode 100644 index c9c840274a..0000000000 --- a/protocols/Tox/src/tox_multimedia.cpp +++ /dev/null @@ -1,626 +0,0 @@ -#include "stdafx.h"
-
-CToxCallDlgBase::CToxCallDlgBase(CToxProto *proto, int idDialog, MCONTACT hContact) :
- CToxDlgBase(proto, idDialog, false), hContact(hContact)
-{}
-
-void CToxCallDlgBase::OnInitDialog()
-{
- WindowList_Add(m_proto->hAudioDialogs, m_hwnd, hContact);
-}
-
-void CToxCallDlgBase::OnClose()
-{
- WindowList_Remove(m_proto->hAudioDialogs, m_hwnd);
-}
-
-INT_PTR CToxCallDlgBase::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam)
-{
- if (msg == WM_CALL_END)
- if (wParam == hContact)
- Close();
-
- return CToxDlgBase::DlgProc(msg, wParam, lParam);
-}
-
-void CToxCallDlgBase::SetIcon(const char *name)
-{
- char iconName[100];
- mir_snprintf(iconName, "%s_%s", MODULE, name);
- Window_SetIcon_IcoLib(m_hwnd, IcoLib_GetIconHandle(iconName));
-}
-
-void CToxCallDlgBase::SetTitle(const wchar_t *title)
-{
- SetWindowText(m_hwnd, title);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-
-CToxIncomingCall::CToxIncomingCall(CToxProto *proto, MCONTACT hContact) :
- CToxCallDlgBase(proto, IDD_CALL_RECEIVE, hContact),
- from(this, IDC_FROM), date(this, IDC_DATE),
- answer(this, IDOK), reject(this, IDCANCEL)
-{
- answer.OnClick = Callback(this, &CToxIncomingCall::OnAnswer);
-}
-
-void CToxIncomingCall::OnInitDialog()
-{
- CToxCallDlgBase::OnInitDialog();
- Utils_RestoreWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "IncomingCallWindow_");
-
- wchar_t *nick = pcli->pfnGetContactDisplayName(hContact, 0);
- from.SetText(nick);
-
- wchar_t title[MAX_PATH];
- mir_snwprintf(title, TranslateT("Incoming call from %s"), nick);
- SetTitle(title);
- SetIcon("audio_ring");
-}
-
-void CToxIncomingCall::OnClose()
-{
- toxav_call_control(m_proto->toxThread->ToxAV(), m_proto->calls[hContact], TOXAV_CALL_CONTROL_CANCEL, nullptr);
- Utils_SaveWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "IncomingCallWindow_");
- CToxCallDlgBase::OnClose();
-}
-
-void CToxIncomingCall::OnAnswer(CCtrlBase*)
-{
- /*ToxAvCSettings *cSettings = m_proto->GetAudioCSettings();
- if (cSettings == NULL)
- return;*/
-
- int friendNumber = m_proto->GetToxFriendNumber(hContact);
- if (friendNumber == UINT32_MAX) {
- //mir_free(cSettings);
- Close();
- return;
- }
-
- TOXAV_ERR_ANSWER error;
- if (!toxav_answer(m_proto->toxThread->ToxAV(), friendNumber, 0, 0, &error)) {
- m_proto->debugLogA(__FUNCTION__": failed to answer the call (%d)", error);
- Close();
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-
-CToxOutgoingCall::CToxOutgoingCall(CToxProto *proto, MCONTACT hContact) :
- CToxCallDlgBase(proto, IDD_CALL_SEND, hContact),
- to(this, IDC_FROM), call(this, IDOK), cancel(this, IDCANCEL)
-{
- m_autoClose = CLOSE_ON_CANCEL;
- call.OnClick = Callback(this, &CToxOutgoingCall::OnCall);
- cancel.OnClick = Callback(this, &CToxOutgoingCall::OnCancel);
-}
-
-void CToxOutgoingCall::OnInitDialog()
-{
- CToxCallDlgBase::OnInitDialog();
- Utils_RestoreWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "OutgoingCallWindow_");
-
- wchar_t *nick = pcli->pfnGetContactDisplayName(hContact, 0);
- to.SetText(nick);
-
- wchar_t title[MAX_PATH];
- mir_snwprintf(title, TranslateT("Outgoing call to %s"), nick);
- SetTitle(title);
- SetIcon("audio_end");
-}
-
-void CToxOutgoingCall::OnClose()
-{
- Utils_SaveWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "OutgoingCallWindow_");
- CToxCallDlgBase::OnClose();
-}
-
-void CToxOutgoingCall::OnCall(CCtrlBase*)
-{
- /*ToxAvCSettings *cSettings = m_proto->GetAudioCSettings();
- if (cSettings == NULL)
- {
- Close();
- return;
- }*/
-
- int friendNumber = m_proto->GetToxFriendNumber(hContact);
- if (friendNumber == UINT32_MAX) {
- //mir_free(cSettings);
- Close();
- return;
- }
-
- TOXAV_ERR_CALL error;
- if (!toxav_call(m_proto->toxThread->ToxAV(), friendNumber, 0, 0, &error)) {
- //mir_free(cSettings);
- m_proto->debugLogA(__FUNCTION__": failed to make a call (%d)", error);
- return;
- }
- //mir_free(cSettings);
-
- char *message = nullptr;
- wchar_t title[MAX_PATH];
- if (GetWindowText(m_hwnd, title, _countof(title)))
- message = mir_utf8encodeW(title);
- else
- message = mir_utf8encode("Outgoing call");
- m_proto->AddEventToDb(hContact, DB_EVENT_CALL, time(nullptr), DBEF_UTF, (PBYTE)message, mir_strlen(message));
-
- call.Enable(FALSE);
- SetIcon("audio_call");
-}
-
-void CToxOutgoingCall::OnCancel(CCtrlBase*)
-{
- int friendNumber = m_proto->GetToxFriendNumber(hContact);
- if (friendNumber == UINT32_MAX) {
- //mir_free(cSettings);
- Close();
- return;
- }
-
- if (!call.Enabled())
- toxav_call_control(m_proto->toxThread->ToxAV(), friendNumber, TOXAV_CALL_CONTROL_CANCEL, nullptr);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-
-CToxCallDialog::CToxCallDialog(CToxProto *proto, MCONTACT hContact) :
- CToxCallDlgBase(proto, IDD_CALL, hContact), end(this, IDCANCEL)
-{}
-
-void CToxCallDialog::OnInitDialog()
-{
- CToxCallDlgBase::OnInitDialog();
- Utils_RestoreWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "CallWindow_");
- SetIcon("audio_start");
-}
-
-void CToxCallDialog::OnClose()
-{
- int friendNumber = m_proto->GetToxFriendNumber(hContact);
- if (friendNumber == UINT32_MAX) {
- //mir_free(cSettings);
- Close();
- return;
- }
-
- toxav_call_control(m_proto->toxThread->ToxAV(), friendNumber, TOXAV_CALL_CONTROL_CANCEL, nullptr);
- Utils_SaveWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "CallWindow_");
- CToxCallDlgBase::OnClose();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-
-/*ToxAvCSettings* CToxProto::GetAudioCSettings()
-{
- ToxAvCSettings *cSettings = (ToxAvCSettings*)mir_calloc(sizeof(ToxAvCSettings));
- cSettings->audio_frame_duration = 20;
-
- DWORD deviceId = getDword("AudioInputDeviceID", WAVE_MAPPER);
-
- WAVEINCAPS wic;
- MMRESULT error = waveInGetDevCaps(deviceId, &wic, sizeof(WAVEINCAPS));
- if (error != MMSYSERR_NOERROR)
- {
- debugLogA(__FUNCTION__": failed to get input device caps (%d)", error);
-
- wchar_t errorMessage[MAX_PATH];
- waveInGetErrorText(error, errorMessage, _countof(errorMessage));
- CToxProto::ShowNotification(
- TranslateT("Unable to find input audio device"),
- errorMessage);
-
- mir_free(cSettings);
- return NULL;
- }
-
- cSettings->audio_channels = wic.wChannels;
- if ((wic.dwFormats & WAVE_FORMAT_48S16) || (wic.dwFormats & WAVE_FORMAT_48M16))
- {
- cSettings->audio_bitrate = 16 * 1000;
- cSettings->audio_sample_rate = 48000;
- }
- else if ((wic.dwFormats & WAVE_FORMAT_48S08) || (wic.dwFormats & WAVE_FORMAT_48M08))
- {
- cSettings->audio_bitrate = 8 * 1000;
- cSettings->audio_sample_rate = 48000;
- }
- else if ((wic.dwFormats & WAVE_FORMAT_4S16) || (wic.dwFormats & WAVE_FORMAT_4M16))
- {
- cSettings->audio_bitrate = 16 * 1000;
- cSettings->audio_sample_rate = 24000;
- }
- else if ((wic.dwFormats & WAVE_FORMAT_4S08) || (wic.dwFormats & WAVE_FORMAT_4S08))
- {
- cSettings->audio_bitrate = 8 * 1000;
- cSettings->audio_sample_rate = 24000;
- }
- else if ((wic.dwFormats & WAVE_FORMAT_2M16) || (wic.dwFormats & WAVE_FORMAT_2S16))
- {
- cSettings->audio_bitrate = 16 * 1000;
- cSettings->audio_sample_rate = 16000;
- }
- else if ((wic.dwFormats & WAVE_FORMAT_2M08) || (wic.dwFormats & WAVE_FORMAT_2S08))
- {
- cSettings->audio_bitrate = 8 * 1000;
- cSettings->audio_sample_rate = 16000;
- }
- else if ((wic.dwFormats & WAVE_FORMAT_1M16) || (wic.dwFormats & WAVE_FORMAT_1S16))
- {
- cSettings->audio_bitrate = 16 * 1000;
- cSettings->audio_sample_rate = 8000;
- }
- else if ((wic.dwFormats & WAVE_FORMAT_1M08) || (wic.dwFormats & WAVE_FORMAT_1S08))
- {
- cSettings->audio_bitrate = 8 * 1000;
- cSettings->audio_sample_rate = 8000;
- }
- else
- {
- debugLogA(__FUNCTION__": failed to parse input device caps");
- mir_free(cSettings);
- return NULL;
- }
-
- return cSettings;
-}*/
-
-/* INCOMING CALL */
-
-// incoming call flow
-void CToxProto::OnFriendCall(ToxAV *toxAV, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *arg)
-{
- /*CToxProto *proto = (CToxProto*)arg;
-
- int friendNumber = toxav_get_peer_id(proto->toxThread->Tox()AV, callId, 0);
- if (friendNumber == TOX_ERROR)
- {
- proto->debugLogA(__FUNCTION__": failed to get friend number");
- toxav_reject(proto->toxThread->Tox()AV, callId, NULL);
- return;
- }
-
- MCONTACT hContact = proto->GetContact(friendNumber);
- if (hContact == NULL)
- {
- proto->debugLogA(__FUNCTION__": failed to find contact");
- toxav_reject(proto->toxThread->Tox()AV, callId, NULL);
- return;
- }
-
- ToxAvCSettings cSettings;
- if (toxav_get_peer_csettings(proto->toxThread->Tox()AV, callId, 0, &cSettings) != av_ErrorNone)
- {
- proto->debugLogA(__FUNCTION__": failed to get codec settings");
- toxav_reject(proto->toxThread->Tox()AV, callId, NULL);
- return;
- }
-
- if (cSettings.call_type != av_TypeAudio)
- {
- proto->debugLogA(__FUNCTION__": video call is unsupported");
- toxav_reject(proto->toxThread->Tox()AV, callId, Translate("Video call is unsupported"));
- return;
- }
-
- wchar_t message[MAX_PATH];
- mir_snwprintf(message, TranslateT("Incoming call from %s"), pcli->pfnGetContactDisplayName(hContact, 0));
- T2Utf szMessage(message);
-
- PROTORECVEVENT recv = { 0 };
- recv.timestamp = time(NULL);
- recv.lParam = callId;
- recv.szMessage = szMessage;
- ProtoChainRecv(hContact, PSR_AUDIO, hContact, (LPARAM)&recv);*/
-}
-
-void CToxProto::OnFriendCallState(ToxAV *toxAV, uint32_t friend_number, uint32_t state, void *user_data)
-{}
-
-void CToxProto::OnBitrateChanged(ToxAV *toxAV, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, void *arg)
-{}
-
-// save event to db
-INT_PTR CToxProto::OnRecvAudioCall(WPARAM hContact, LPARAM lParam)
-{
- PROTORECVEVENT *pre = (PROTORECVEVENT*)lParam;
-
- calls[hContact] = pre->lParam;
-
- MEVENT hEvent = AddEventToDb(hContact, DB_EVENT_CALL, pre->timestamp, DBEF_UTF, (PBYTE)pre->szMessage, mir_strlen(pre->szMessage));
-
- CLISTEVENT cle = {};
- cle.flags = CLEF_UNICODE;
- cle.hContact = hContact;
- cle.hDbEvent = hEvent;
- cle.lParam = DB_EVENT_CALL;
- cle.hIcon = IcoLib_GetIconByHandle(GetIconHandle(IDI_AUDIO_RING));
-
- wchar_t szTooltip[MAX_PATH];
- mir_snwprintf(szTooltip, TranslateT("Incoming call from %s"), pcli->pfnGetContactDisplayName(hContact, 0));
- cle.szTooltip.w = szTooltip;
-
- char szService[MAX_PATH];
- mir_snprintf(szService, "%s/Audio/Ring", GetContactProto(hContact));
- cle.pszService = szService;
- pcli->pfnAddEvent(&cle);
-
- return hEvent;
-}
-
-// react on clist event click
-INT_PTR CToxProto::OnAudioRing(WPARAM, LPARAM lParam)
-{
- CLISTEVENT *cle = (CLISTEVENT*)lParam;
- CDlgBase *incomingCallDlg = new CToxIncomingCall(this, cle->hContact);
- incomingCallDlg->Show();
-
- return 0;
-}
-
-/*void CToxProto::OnAvCancel(void*, int32_t callId, void *arg)
-{
- CToxProto *proto = (CToxProto*)arg;
-
- int friendNumber = toxav_get_peer_id(proto->toxThread->Tox()AV, callId, 0);
- if (friendNumber == TOX_ERROR)
- {
- proto->debugLogA(__FUNCTION__": failed to get friend number");
- return;
- }
-
- MCONTACT hContact = proto->GetContact(friendNumber);
- if (hContact == NULL)
- {
- proto->debugLogA(__FUNCTION__": failed to find contact");
- return;
- }
-
- CLISTEVENT *cle = NULL;
- while ((cle = (CLISTEVENT*)CallService(MS_CLIST_GETEVENT, hContact, 0)))
- {
- if (cle->lParam == DB_EVENT_CALL)
- {
- CallService(MS_CLIST_REMOVEEVENT, hContact, cle->hDbEvent);
- break;
- }
- }
-
- char *message = mir_utf8encodeW(TranslateT("Call canceled"));
- proto->AddEventToDb(hContact, DB_EVENT_CALL, time(NULL), DBEF_UTF, (PBYTE)message, mir_strlen(message));
-
- WindowList_Broadcast(proto->hAudioDialogs, WM_CALL_END, hContact, 0);
-}*/
-
-/* OUTGOING CALL */
-
-// outcoming audio flow
-INT_PTR CToxProto::OnSendAudioCall(WPARAM hContact, LPARAM)
-{
- CDlgBase *outgoingCallDlg = new CToxOutgoingCall(this, hContact);
- outgoingCallDlg->Show();
-
- return 0;
-}
-
-/*void CToxProto::OnAvReject(void*, int32_t callId, void *arg)
-{
- CToxProto *proto = (CToxProto*)arg;
-
- int friendNumber = toxav_get_peer_id(proto->toxThread->Tox()AV, callId, 0);
- if (friendNumber == TOX_ERROR)
- {
- proto->debugLogA(__FUNCTION__": failed to get friend number");
- return;
- }
-
- MCONTACT hContact = proto->GetContact(friendNumber);
- if (hContact == NULL)
- {
- proto->debugLogA(__FUNCTION__": failed to find contact");
- return;
- }
-
- char *message = mir_utf8encodeW(TranslateT("Call canceled"));
- proto->AddEventToDb(hContact, DB_EVENT_CALL, time(NULL), DBEF_UTF, (PBYTE)message, mir_strlen(message));
-
- WindowList_Broadcast(proto->hAudioDialogs, WM_CALL_END, hContact, 0);
-}
-
-void CToxProto::OnAvCallTimeout(void*, int32_t callId, void *arg)
-{
- CToxProto *proto = (CToxProto*)arg;
-
- int friendNumber = toxav_get_peer_id(proto->toxThread->Tox()AV, callId, 0);
- if (friendNumber == TOX_ERROR)
- {
- proto->debugLogA(__FUNCTION__": failed to get friend number");
- return;
- }
-
- MCONTACT hContact = proto->GetContact(friendNumber);
- if (hContact == NULL)
- {
- proto->debugLogA(__FUNCTION__": failed to find contact");
- return;
- }
-
- char *message = mir_utf8encodeW(TranslateT("Call canceled"));
- proto->AddEventToDb(hContact, DB_EVENT_CALL, time(NULL), DBEF_UTF, (PBYTE)message, mir_strlen(message));
-
- WindowList_Broadcast(proto->hAudioDialogs, WM_CALL_END, hContact, 0);
-}*/
-
-/* --- */
-
-static void CALLBACK WaveOutCallback(HWAVEOUT hOutDevice, UINT uMsg, DWORD/* dwInstance*/, DWORD dwParam1, DWORD/* dwParam2*/)
-{
- if (uMsg == WOM_DONE) {
- WAVEHDR *header = (WAVEHDR*)dwParam1;
- if (header->dwFlags & WHDR_PREPARED)
- waveOutUnprepareHeader(hOutDevice, header, sizeof(WAVEHDR));
- mir_free(header->lpData);
- mir_free(header);
- }
-}
-
-static void CALLBACK ToxShowDialogApcProc(void *arg)
-{
- CDlgBase *callDlg = (CDlgBase*)arg;
- callDlg->Show();
-}
-
-/*void CToxProto::OnAvStart(void*, int32_t callId, void *arg)
-{
- CToxProto *proto = (CToxProto*)arg;
-
- ToxAvCSettings cSettings;
- int cSettingsError = toxav_get_peer_csettings(proto->toxThread->Tox()AV, callId, 0, &cSettings);
- if (cSettingsError != av_ErrorNone)
- {
- proto->debugLogA(__FUNCTION__": failed to get codec settings (%d)", cSettingsError);
- toxav_hangup(proto->toxThread->Tox()AV, callId);
- return;
- }
-
- if (cSettings.call_type != av_TypeAudio)
- {
- proto->debugLogA(__FUNCTION__": video call is unsupported");
- toxav_hangup(proto->toxThread->Tox()AV, callId);
- return;
- }
-
- WAVEFORMATEX wfx = { 0 };
- wfx.wFormatTag = WAVE_FORMAT_PCM;
- wfx.nChannels = cSettings.audio_channels;
- wfx.wBitsPerSample = cSettings.audio_bitrate / 1000;
- wfx.nSamplesPerSec = cSettings.audio_sample_rate;
- wfx.nBlockAlign = wfx.nChannels * wfx.wBitsPerSample / 8;
- wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
-
- DWORD deviceId = proto->getDword("AudioOutputDeviceID", WAVE_MAPPER);
- MMRESULT error = waveOutOpen(&proto->hOutDevice, deviceId, &wfx, (DWORD_PTR)WaveOutCallback, (DWORD_PTR)proto, CALLBACK_FUNCTION);
- if (error != MMSYSERR_NOERROR)
- {
- proto->debugLogA(__FUNCTION__": failed to open audio device (%d)", error);
- toxav_hangup(proto->toxThread->Tox()AV, callId);
-
- wchar_t errorMessage[MAX_PATH];
- waveInGetErrorText(error, errorMessage, _countof(errorMessage));
- CToxProto::ShowNotification(
- TranslateT("Unable to find output audio device"),
- errorMessage);
-
- return;
- }
-
- int friendNumber = toxav_get_peer_id(proto->toxThread->Tox()AV, callId, 0);
- if (friendNumber == TOX_ERROR)
- {
- proto->debugLogA(__FUNCTION__": failed to get friend number");
- toxav_hangup(proto->toxThread->Tox()AV, callId);
- return;
- }
-
- MCONTACT hContact = proto->GetContact(friendNumber);
- if (hContact == NULL)
- {
- proto->debugLogA(__FUNCTION__": failed to find contact");
- toxav_hangup(proto->toxThread->Tox()AV, callId);
- return;
- }
-
- if (toxav_prepare_transmission(proto->toxThread->Tox()AV, callId, false) == TOX_ERROR)
- {
- proto->debugLogA(__FUNCTION__": failed to prepare audio transmition");
- toxav_hangup(proto->toxThread->Tox()AV, callId);
- return;
- }
-
- char *message = mir_utf8encodeW(TranslateT("Call started"));
- proto->AddEventToDb(hContact, DB_EVENT_CALL, time(NULL), DBEF_UTF, (PBYTE)message, mir_strlen(message));
-
-
- WindowList_Broadcast(proto->hAudioDialogs, WM_CALL_END, hContact, 0);
- CDlgBase *callDlg = new CToxCallDialog(proto, hContact);
- CallFunctionAsync(ToxShowDialogApcProc, callDlg);
-}
-
-void CToxProto::OnAvEnd(void*, int32_t callId, void *arg)
-{
- CToxProto *proto = (CToxProto*)arg;
-
- waveOutReset(proto->hOutDevice);
- waveOutClose(proto->hOutDevice);
- toxav_kill_transmission(proto->toxThread->Tox()AV, callId);
-
- int friendNumber = toxav_get_peer_id(proto->toxThread->Tox()AV, callId, 0);
- if (friendNumber == TOX_ERROR)
- {
- proto->debugLogA(__FUNCTION__": failed to get friend number");
- return;
- }
-
- MCONTACT hContact = proto->GetContact(friendNumber);
- if (hContact == NULL)
- {
- proto->debugLogA(__FUNCTION__": failed to find contact");
- return;
- }
-
- char *message = mir_utf8encodeW(TranslateT("Call ended"));
- proto->AddEventToDb(hContact, DB_EVENT_CALL, time(NULL), DBEF_UTF, (PBYTE)message, mir_strlen(message));
-
- WindowList_Broadcast(proto->hAudioDialogs, WM_CALL_END, hContact, 0);
-}
-
-void CToxProto::OnAvPeerTimeout(void *av, int32_t callId, void *arg)
-{
- CToxProto *proto = (CToxProto*)arg;
-
- ToxAvCallState callState = toxav_get_call_state(proto->toxThread->Tox()AV, callId);
- switch (callState)
- {
- case av_CallStarting:
- proto->OnAvCancel(av, callId, arg);
- return;
-
- case av_CallActive:
- proto->OnAvEnd(av, callId, arg);
- return;
-
- default:
- proto->debugLogA(__FUNCTION__": failed to handle callState");
- break;
- }
-}*/
-
-//////
-
-void CToxProto::OnFriendAudioFrame(ToxAV *toxAV, uint32_t friend_number, const int16_t *pcm, size_t sample_count, uint8_t channels, uint32_t sampling_rate, void *user_data)
-{
- /*CToxProto *proto = (CToxProto*)arg;
-
- WAVEHDR *header = (WAVEHDR*)mir_calloc(sizeof(WAVEHDR));
- header->dwBufferLength = size * sizeof(int16_t);
- header->lpData = (LPSTR)mir_alloc(header->dwBufferLength);
- memcpy(header->lpData, (PBYTE)PCM, header->dwBufferLength);
-
- MMRESULT error = waveOutPrepareHeader(proto->hOutDevice, header, sizeof(WAVEHDR));
- if (error != MMSYSERR_NOERROR)
- {
- proto->debugLogA(__FUNCTION__": failed to prepare audio buffer (%d)", error);
- return;
- }
-
- error = waveOutWrite(proto->hOutDevice, header, sizeof(WAVEHDR));
- if (error != MMSYSERR_NOERROR)
- {
- proto->debugLogA(__FUNCTION__": failed to play audio samples (%d)", error);
- return;
- }*/
-}
diff --git a/protocols/Tox/src/tox_multimedia.h b/protocols/Tox/src/tox_multimedia.h deleted file mode 100644 index 922b9b406f..0000000000 --- a/protocols/Tox/src/tox_multimedia.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef _TOX_MULTIMEDIA_H_
-#define _TOX_MULTIMEDIA_H_
-
-#define WM_CALL_END (WM_PROTO_LAST + 100)
-
-class CToxCallDlgBase : public CToxDlgBase
-{
-protected:
- MCONTACT hContact;
-
- virtual void OnInitDialog();
- virtual void OnClose();
-
- INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam);
-
- void SetIcon(const char *name);
- void SetTitle(const wchar_t *title);
-
-public:
- CToxCallDlgBase(CToxProto *proto, int idDialog, MCONTACT hContact);
-};
-
-///////////////////////////////////////////////
-
-class CToxIncomingCall : public CToxCallDlgBase
-{
-private:
- CCtrlLabel from;
- CCtrlLabel date;
-
- CCtrlButton answer;
- CCtrlButton reject;
-
-protected:
- void OnInitDialog();
- void OnClose();
-
- void OnAnswer(CCtrlBase*);
-
-public:
- CToxIncomingCall(CToxProto *proto, MCONTACT hContact);
-};
-
-///////////////////////////////////////////////
-
-class CToxOutgoingCall : public CToxCallDlgBase
-{
-private:
- CCtrlLabel to;
- CCtrlButton call;
- CCtrlButton cancel;
-
-protected:
- void OnInitDialog();
- void OnClose();
-
- void OnCall(CCtrlBase*);
- void OnCancel(CCtrlBase*);
-
-public:
- CToxOutgoingCall(CToxProto *proto, MCONTACT hContact);
-};
-
-///////////////////////////////////////////////
-
-struct ToxCallDialogParam
-{
- CToxProto *proto;
- MCONTACT hContact;
-};
-
-class CToxCallDialog : public CToxCallDlgBase
-{
-protected:
- CCtrlButton end;
-
- void OnInitDialog();
- void OnClose();
-
-public:
- CToxCallDialog(CToxProto *proto, MCONTACT hContact);
-};
-
-#endif //_TOX_MULTIMEDIA_H_
\ No newline at end of file diff --git a/protocols/Tox/src/tox_options.cpp b/protocols/Tox/src/tox_options.cpp index bf4aeea940..71353d3263 100644 --- a/protocols/Tox/src/tox_options.cpp +++ b/protocols/Tox/src/tox_options.cpp @@ -5,23 +5,33 @@ CToxOptionsMain::CToxOptionsMain(CToxProto *proto, int idDialog) m_toxAddress(this, IDC_TOXID), m_toxAddressCopy(this, IDC_CLIPBOARD),
m_profileCreate(this, IDC_PROFILE_NEW), m_profileImport(this, IDC_PROFILE_IMPORT),
m_profileExport(this, IDC_PROFILE_EXPORT), m_nickname(this, IDC_NAME),
- m_password(this, IDC_PASSWORD), m_group(this, IDC_GROUP),
- m_enableUdp(this, IDC_ENABLE_UDP), m_enableIPv6(this, IDC_ENABLE_IPV6),
+ m_passwordCreate(this, IDC_PASSWORD_CREATE), m_passwordChange(this, IDC_PASSWORD_CHANGE),
+ m_passwordRemove(this, IDC_PASSWORD_REMOVE), m_group(this, IDC_GROUP),
+ m_enableUdp(this, IDC_ENABLE_UDP), m_enableUdpHolePunching(this, IDC_ENABLE_HOLEPUNCHING),
+ m_enableIPv6(this, IDC_ENABLE_IPV6), m_enableLocalDiscovery(this, IDC_ENABLE_LOCALDISCOVERY),
m_maxConnectRetries(this, IDC_MAXCONNECTRETRIES), m_maxConnectRetriesSpin(this, IDC_MAXCONNECTRETRIESSPIN),
m_maxReconnectRetries(this, IDC_MAXRECONNECTRETRIES), m_maxReconnectRetriesSpin(this, IDC_MAXRECONNECTRETRIESSPIN)
{
CreateLink(m_toxAddress, TOX_SETTINGS_ID, L"");
CreateLink(m_nickname, "Nick", L"");
- CreateLink(m_password, "Password", L"");
CreateLink(m_group, TOX_SETTINGS_GROUP, L"Tox");
CreateLink(m_enableUdp, "EnableUDP", DBVT_BYTE, TRUE);
+ CreateLink(m_enableUdpHolePunching, "EnableUDPHolePunching", DBVT_BYTE, TRUE);
CreateLink(m_enableIPv6, "EnableIPv6", DBVT_BYTE, FALSE);
+ CreateLink(m_enableLocalDiscovery, "EnableLocalDiscovery", DBVT_BYTE, FALSE);
if (idDialog == IDD_OPTIONS_MAIN) {
CreateLink(m_maxConnectRetries, "MaxConnectRetries", DBVT_BYTE, TOX_MAX_CONNECT_RETRIES);
CreateLink(m_maxReconnectRetries, "MaxReconnectRetries", DBVT_BYTE, TOX_MAX_RECONNECT_RETRIES);
}
+ m_passwordCreate.OnClick = Callback(this, &CToxOptionsMain::PasswordCreate_OnClick);
+ m_passwordChange.OnClick = Callback(this, &CToxOptionsMain::PasswordChange_OnClick);
+ m_passwordRemove.OnClick = Callback(this, &CToxOptionsMain::PasswordRemove_OnClick);
+
+ m_enableUdp.OnChange = Callback(this, &CToxOptionsMain::EnableUdp_OnClick);
+ m_enableUdpHolePunching.Enable(m_enableUdp.GetState());
+
m_toxAddressCopy.OnClick = Callback(this, &CToxOptionsMain::ToxAddressCopy_OnClick);
m_profileCreate.OnClick = Callback(this, &CToxOptionsMain::ProfileCreate_OnClick);
m_profileImport.OnClick = Callback(this, &CToxOptionsMain::ProfileImport_OnClick);
@@ -36,17 +46,26 @@ void CToxOptionsMain::OnInitDialog() if (CToxProto::IsFileExists(profilePath)) {
m_toxAddress.Enable();
- ShowWindow(m_profileCreate.GetHwnd(), FALSE);
- ShowWindow(m_profileImport.GetHwnd(), FALSE);
+ m_profileCreate.Hide();
+ m_profileImport.Hide();
- ShowWindow(m_toxAddressCopy.GetHwnd(), TRUE);
- ShowWindow(m_profileExport.GetHwnd(), TRUE);
+ m_toxAddressCopy.Show();
+ m_profileExport.Show();
}
- SendMessage(m_toxAddress.GetHwnd(), EM_LIMITTEXT, TOX_ADDRESS_SIZE * 2, 0);
- SendMessage(m_nickname.GetHwnd(), EM_LIMITTEXT, TOX_MAX_NAME_LENGTH, 0);
- SendMessage(m_password.GetHwnd(), EM_LIMITTEXT, 32, 0);
- SendMessage(m_group.GetHwnd(), EM_LIMITTEXT, 64, 0);
+ m_passwordCreate.Enable(m_proto->IsOnline());
+ m_passwordChange.Enable(m_proto->IsOnline());
+ m_passwordRemove.Enable(m_proto->IsOnline());
+
+ pass_ptrW password(m_proto->getWStringA(TOX_SETTINGS_PASSWORD));
+ bool passwordExists = mir_wstrlen(password) > 0;
+ m_passwordCreate.Show(!passwordExists);
+ m_passwordChange.Show(passwordExists);
+ m_passwordRemove.Show(passwordExists);
+
+ m_toxAddress.SetMaxLength(TOX_ADDRESS_SIZE * 2);
+ m_nickname.SetMaxLength(TOX_MAX_NAME_LENGTH);
+ m_group.SetMaxLength(64);
m_maxConnectRetriesSpin.SetRange(255, 1);
m_maxConnectRetriesSpin.SetPosition(m_proto->getByte("MaxConnectRetries", TOX_MAX_CONNECT_RETRIES));
@@ -54,6 +73,31 @@ void CToxOptionsMain::OnInitDialog() m_maxReconnectRetriesSpin.SetPosition(m_proto->getByte("MaxReconnectRetries", TOX_MAX_RECONNECT_RETRIES));
}
+void CToxOptionsMain::PasswordCreate_OnClick(CCtrlButton*)
+{
+ m_proto->OnCreatePassword(0, 0);
+}
+
+void CToxOptionsMain::PasswordChange_OnClick(CCtrlButton*)
+{
+ m_proto->OnChangePassword(0, 0);
+}
+
+void CToxOptionsMain::PasswordRemove_OnClick(CCtrlButton*)
+{
+ m_proto->OnRemovePassword(0, 0);
+ pass_ptrW password(m_proto->getWStringA(TOX_SETTINGS_PASSWORD));
+ bool passwordExists = mir_wstrlen(password) > 0;
+ m_passwordCreate.Show(!passwordExists);
+ m_passwordChange.Show(passwordExists);
+ m_passwordRemove.Show(passwordExists);
+}
+
+void CToxOptionsMain::EnableUdp_OnClick(CCtrlBase*)
+{
+ m_enableUdpHolePunching.Enable(m_enableUdp.GetState());
+}
+
void CToxOptionsMain::ToxAddressCopy_OnClick(CCtrlButton*)
{
char *toxAddress = m_toxAddress.GetTextA();
@@ -94,7 +138,6 @@ void CToxOptionsMain::ProfileCreate_OnClick(CCtrlButton*) m_toxAddress.SetTextA(ptrA(m_proto->getStringA(TOX_SETTINGS_ID)));
m_nickname.SetText(ptrW(m_proto->getWStringA("Nick")));
- m_password.SetText(ptrW(m_proto->getWStringA("Password")));
ShowWindow(m_profileCreate.GetHwnd(), FALSE);
ShowWindow(m_profileImport.GetHwnd(), FALSE);
@@ -189,8 +232,8 @@ void CToxOptionsMain::ProfileExport_OnClick(CCtrlButton*) void CToxOptionsMain::OnApply()
{
ptrW group(m_group.GetText());
- if (mir_wstrcmp(group, m_proto->wszGroup)) {
- m_proto->wszGroup = mir_wstrdup(group);
+ if (mir_wstrcmp(group, m_proto->m_defaultGroup)) {
+ m_proto->m_defaultGroup = mir_wstrdup(group);
Clist_GroupCreate(0, group);
}
@@ -198,111 +241,9 @@ void CToxOptionsMain::OnApply() CallProtoService(m_proto->m_szModuleName, PS_SETMYNICKNAME, SMNN_UNICODE, (LPARAM)ptrW(m_nickname.GetText()));
// todo: add checkbox
- m_proto->setWString("Password", pass_ptrT(m_password.GetText()));
-
- m_proto->SaveToxProfile(m_proto->toxThread->Tox());
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////
-
-CToxOptionsMultimedia::CToxOptionsMultimedia(CToxProto *proto)
- : CToxDlgBase(proto, IDD_OPTIONS_MULTIMEDIA, false),
- m_audioInput(this, IDC_AUDIOINPUT),
- m_audioOutput(this, IDC_AUDIOOUTPUT)
-{}
-
-void CToxOptionsMultimedia::EnumDevices(CCtrlCombo &combo, IMMDeviceEnumerator *pEnumerator, EDataFlow dataFlow, const char* setting)
-{
- LPWSTR pwszDefID = nullptr;
- ptrW wszDefID(m_proto->getWStringA(setting));
- if (wszDefID != NULL) {
- size_t len = mir_wstrlen(wszDefID) + 1;
- pwszDefID = (LPWSTR)CoTaskMemAlloc(len * 2);
- mir_wstrncpy(pwszDefID, wszDefID, len);
- }
- else {
- CComPtr<IMMDevice> pDevice = nullptr;
- if (FAILED(pEnumerator->GetDefaultAudioEndpoint(dataFlow, eConsole, &pDevice))) return;
- if (FAILED(pDevice->GetId(&pwszDefID))) return;
- }
-
- CComPtr<IMMDeviceCollection> pDevices = nullptr;
- EXIT_ON_ERROR(pEnumerator->EnumAudioEndpoints(dataFlow, DEVICE_STATE_ACTIVE, &pDevices));
-
- UINT count;
- EXIT_ON_ERROR(pDevices->GetCount(&count));
-
- for (UINT i = 0; i < count; i++) {
- CComPtr<IMMDevice> pDevice = nullptr;
- EXIT_ON_ERROR(pDevices->Item(i, &pDevice));
-
- CComPtr<IPropertyStore> pProperties = nullptr;
- EXIT_ON_ERROR(pDevice->OpenPropertyStore(STGM_READ, &pProperties));
-
- PROPVARIANT varName;
- PropVariantInit(&varName);
- EXIT_ON_ERROR(pProperties->GetValue(PKEY_Device_FriendlyName, &varName));
-
- LPWSTR pwszID = nullptr;
- EXIT_ON_ERROR(pDevice->GetId(&pwszID));
- combo.InsertString(varName.pwszVal, i, (LPARAM)mir_wstrdup(pwszID));
- if (mir_wstrcmpi(pwszID, pwszDefID) == 0)
- combo.SetCurSel(i);
- CoTaskMemFree(pwszID);
-
- PropVariantClear(&varName);
- }
-
-Exit:
- CoTaskMemFree(pwszDefID);
-}
-
-void CToxOptionsMultimedia::OnInitDialog()
-{
- CToxDlgBase::OnInitDialog();
-
- CComPtr<IMMDeviceEnumerator> pEnumerator = nullptr;
- if (FAILED(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator)))
- return;
-
- EnumDevices(m_audioInput, pEnumerator, eCapture, "AudioInputDeviceID");
- EnumDevices(m_audioOutput, pEnumerator, eRender, "AudioOutputDeviceID");
-}
-
-void CToxOptionsMultimedia::OnApply()
-{
- int i = m_audioInput.GetCurSel();
- if (i == -1)
- m_proto->delSetting("AudioInputDeviceID");
- else {
- wchar_t* data = (wchar_t*)m_audioInput.GetItemData(i);
- m_proto->setWString("AudioInputDeviceID", data);
- }
-
- i = m_audioOutput.GetCurSel();
- if (i == -1)
- m_proto->delSetting("AudioOutputDeviceID");
- else {
- wchar_t* data = (wchar_t*)m_audioOutput.GetItemData(i);
- m_proto->setWString("AudioOutputDeviceID", data);
- }
-}
-
-void CToxOptionsMultimedia::OnDestroy()
-{
- int count = m_audioInput.GetCount();
- for (int i = 0; i < count; i++) {
- wchar_t* data = (wchar_t*)m_audioInput.GetItemData(i);
- mir_free(data);
-
- }
-
- count = m_audioOutput.GetCount();
- for (int i = 0; i < count; i++) {
- wchar_t* data = (wchar_t*)m_audioOutput.GetItemData(i);
- mir_free(data);
+ //m_proto->setWString("Password", pass_ptrW(m_password.GetText()));
+ m_proto->SaveToxProfile(m_proto->m_toxThread->Tox());
}
}
diff --git a/protocols/Tox/src/tox_options.h b/protocols/Tox/src/tox_options.h index f134e3d554..5a85edea61 100644 --- a/protocols/Tox/src/tox_options.h +++ b/protocols/Tox/src/tox_options.h @@ -13,11 +13,16 @@ private: CCtrlButton m_profileExport;
CCtrlEdit m_nickname;
- CCtrlEdit m_password;
CCtrlEdit m_group;
+ CCtrlButton m_passwordCreate;
+ CCtrlButton m_passwordChange;
+ CCtrlButton m_passwordRemove;
+
CCtrlCheck m_enableUdp;
+ CCtrlCheck m_enableUdpHolePunching;
CCtrlCheck m_enableIPv6;
+ CCtrlCheck m_enableLocalDiscovery;
CCtrlEdit m_maxConnectRetries;
CCtrlSpin m_maxConnectRetriesSpin;
@@ -27,6 +32,12 @@ private: protected:
void OnInitDialog();
+ void PasswordCreate_OnClick(CCtrlButton*);
+ void PasswordChange_OnClick(CCtrlButton*);
+ void PasswordRemove_OnClick(CCtrlButton*);
+
+ void EnableUdp_OnClick(CCtrlBase*);
+
void ToxAddressCopy_OnClick(CCtrlButton*);
void ProfileCreate_OnClick(CCtrlButton*);
void ProfileImport_OnClick(CCtrlButton*);
@@ -50,29 +61,6 @@ public: /////////////////////////////////////////////////////////////////////////////////
-class CToxOptionsMultimedia : public CToxDlgBase
-{
-private:
- typedef CToxDlgBase CSuper;
-
- CCtrlCombo m_audioInput;
- CCtrlCombo m_audioOutput;
-
-protected:
- void EnumDevices(CCtrlCombo &combo, IMMDeviceEnumerator *pEnumerator, EDataFlow dataFlow, const char* setting);
-
- void OnInitDialog();
- void OnApply();
- void OnDestroy();
-
-public:
- CToxOptionsMultimedia(CToxProto *proto);
-
- static CDlgBase *CreateOptionsPage(void *param) { return new CToxOptionsMultimedia((CToxProto*)param); }
-};
-
-/////////////////////////////////////////////////////////////////////////////////
-
class CToxNodeEditor : public CDlgBase
{
private:
diff --git a/protocols/Tox/src/tox_profile.cpp b/protocols/Tox/src/tox_profile.cpp index a144eebee2..77f9285050 100644 --- a/protocols/Tox/src/tox_profile.cpp +++ b/protocols/Tox/src/tox_profile.cpp @@ -16,11 +16,25 @@ wchar_t* CToxProto::GetToxProfilePath(const wchar_t *accountName) return profilePath;
}
+static INT_PTR CALLBACK EnterPassword(void *param)
+{
+ CToxProto *proto = (CToxProto*)param;
+
+ pass_ptrW password(proto->getWStringA(TOX_SETTINGS_PASSWORD));
+ if (mir_wstrlen(password) == 0) {
+ CToxEnterPasswordDlg passwordDlg(proto);
+ if (!passwordDlg.DoModal())
+ return 0;
+ password = proto->getWStringA(TOX_SETTINGS_PASSWORD);
+ }
+ return (INT_PTR)password.detach();
+}
+
bool CToxProto::LoadToxProfile(Tox_Options *options)
{
debugLogA(__FUNCTION__": loading tox profile");
- mir_cslock locker(profileLock);
+ mir_cslock lock(m_profileLock);
ptrW profilePath(GetToxProfilePath());
if (!IsFileExists(profilePath))
@@ -57,25 +71,25 @@ bool CToxProto::LoadToxProfile(Tox_Options *options) fclose(profile);
if (tox_is_data_encrypted(data)) {
- pass_ptrA password(mir_utf8encodeW(pass_ptrT(getWStringA("Password"))));
- if (password == NULL || mir_strlen(password) == 0) {
- CToxPasswordEditor passwordEditor(this);
- if (!passwordEditor.DoModal()) {
- mir_free(data);
- return false;
- }
+ pass_ptrA password(mir_utf8encodeW(pass_ptrW((wchar_t*)CallFunctionSync(EnterPassword, this))));
+ if (mir_strlen(password) == 0) {
+ mir_free(data);
+ return false;
}
- uint8_t *encryptedData = (uint8_t*)mir_calloc(size - TOX_PASS_ENCRYPTION_EXTRA_LENGTH);
+
+ size_t decryptedSize = size - TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
+ uint8_t *decryptedData = (uint8_t*)mir_calloc(decryptedSize);
TOX_ERR_DECRYPTION coreDecryptError;
- if (!tox_pass_decrypt(data, size, (uint8_t*)(char*)password, mir_strlen(password), encryptedData, &coreDecryptError)) {
+ if (!tox_pass_decrypt(data, size, (uint8_t*)(char*)password, mir_strlen(password), decryptedData, &coreDecryptError)) {
ShowNotification(TranslateT("Unable to decrypt Tox profile"), MB_ICONERROR);
debugLogA(__FUNCTION__": failed to decrypt tox profile (%d)", coreDecryptError);
+ delSetting(TOX_SETTINGS_PASSWORD);
mir_free(data);
return false;
}
mir_free(data);
- data = encryptedData;
- size -= TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
+ data = decryptedData;
+ size = decryptedSize;
}
if (data) {
@@ -90,24 +104,29 @@ bool CToxProto::LoadToxProfile(Tox_Options *options) void CToxProto::SaveToxProfile(Tox *tox)
{
- mir_cslock locker(profileLock);
+ mir_cslock lock(m_profileLock);
size_t size = tox_get_savedata_size(tox);
- uint8_t *data = (uint8_t*)mir_calloc(size + TOX_PASS_ENCRYPTION_EXTRA_LENGTH);
+ uint8_t *data = (uint8_t*)mir_calloc(size);
tox_get_savedata(tox, data);
- /*pass_ptrA password(mir_utf8encodeW(pass_ptrT(getWStringA("Password"))));
+ pass_ptrA password(mir_utf8encodeW(pass_ptrW(getWStringA(TOX_SETTINGS_PASSWORD))));
if (password && mir_strlen(password))
{
TOX_ERR_ENCRYPTION coreEncryptError;
- if (!tox_pass_encrypt(data, size, (uint8_t*)(char*)password, mir_strlen(password), data, &coreEncryptError))
+ size_t encryptedSize = size + TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
+ uint8_t *encryptedData = (uint8_t*)mir_calloc(encryptedSize);
+ if (!tox_pass_encrypt(data, size, (uint8_t*)(char*)password, mir_strlen(password), encryptedData, &coreEncryptError))
{
debugLogA(__FUNCTION__": failed to encrypt tox profile");
mir_free(data);
+ mir_free(encryptedData);
return;
}
- size += TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
- }*/
+ mir_free(data);
+ data = encryptedData;
+ size = encryptedSize;
+ }
ptrW profilePath(GetToxProfilePath());
FILE *profile = _wfopen(profilePath, L"wb");
@@ -125,6 +144,13 @@ void CToxProto::SaveToxProfile(Tox *tox) mir_free(data);
}
+int CToxProto::OnDeleteToxProfile()
+{
+ ptrW profilePath(GetToxProfilePath());
+ _wunlink(profilePath);
+ return 0;
+}
+
INT_PTR CToxProto::OnCopyToxID(WPARAM, LPARAM)
{
ptrA address(getStringA(TOX_SETTINGS_ID));
@@ -140,18 +166,169 @@ INT_PTR CToxProto::OnCopyToxID(WPARAM, LPARAM) return 0;
}
-CToxPasswordEditor::CToxPasswordEditor(CToxProto *proto) :
- CToxDlgBase(proto, IDD_PASSWORD, false), ok(this, IDOK),
- password(this, IDC_PASSWORD), savePermanently(this, IDC_SAVEPERMANENTLY)
+INT_PTR CToxProto::OnCreatePassword(WPARAM, LPARAM)
+{
+ pass_ptrW password(getWStringA(TOX_SETTINGS_PASSWORD));
+ CToxCreatePasswordDlg passwordDlg(this);
+ passwordDlg.DoModal();
+ return 0;
+}
+
+INT_PTR CToxProto::OnChangePassword(WPARAM, LPARAM)
+{
+ CToxChangePasswordDlg passwordDlg(this);
+ passwordDlg.DoModal();
+ return 0;
+}
+
+INT_PTR CToxProto::OnRemovePassword(WPARAM, LPARAM)
+{
+ const wchar_t *message = TranslateT("Removing the password will lead to decryption of the profile.\r\nAre you sure to remove password?");
+ int result = MessageBox(NULL, message, TranslateT("Remove password"), MB_YESNO | MB_ICONQUESTION);
+ if (result == IDYES) {
+ delSetting(TOX_SETTINGS_PASSWORD);
+ SaveToxProfile(m_toxThread->Tox());
+ }
+ return 0;
+}
+
+/* ENTER PASSWORD */
+
+CToxEnterPasswordDlg::CToxEnterPasswordDlg(CToxProto *proto)
+ : CToxDlgBase(proto, IDD_PASSWORD_ENTER, false),
+ m_password(this, IDC_PASSWORD),
+ m_ok(this, IDOK)
+{
+ m_password.OnChange = Callback(this, &CToxEnterPasswordDlg::Password_OnChange);
+ m_ok.OnClick = Callback(this, &CToxEnterPasswordDlg::OnOk);
+}
+
+void CToxEnterPasswordDlg::OnInitDialog()
+{
+ m_ok.Disable();
+}
+
+void CToxEnterPasswordDlg::Password_OnChange(CCtrlBase*)
+{
+ m_ok.Enable(GetWindowTextLength(m_password.GetHwnd()) != 0);
+}
+
+void CToxEnterPasswordDlg::OnOk(CCtrlButton*)
{
- ok.OnClick = Callback(this, &CToxPasswordEditor::OnOk);
+ m_proto->setWString(TOX_SETTINGS_PASSWORD, pass_ptrW(m_password.GetText()));
+ EndDialog(m_hwnd, 1);
+}
+
+/* CREATE PASSWORD */
+
+CToxCreatePasswordDlg::CToxCreatePasswordDlg(CToxProto *proto)
+ : CToxDlgBase(proto, IDD_PASSWORD_CREATE, false),
+ m_newPassword(this, IDC_PASSWORD_NEW),
+ m_confirmPassword(this, IDC_PASSWORD_CONFIRM),
+ m_passwordValidation(this, IDC_PASSWORD_VALIDATION),
+ m_ok(this, IDOK)
+{
+ m_newPassword.OnChange = Callback(this, &CToxCreatePasswordDlg::Password_OnChange);
+ m_confirmPassword.OnChange = Callback(this, &CToxCreatePasswordDlg::Password_OnChange);
+ m_ok.OnClick = Callback(this, &CToxCreatePasswordDlg::OnOk);
}
-void CToxPasswordEditor::OnOk(CCtrlButton*)
+void CToxCreatePasswordDlg::OnInitDialog()
{
- pass_ptrT tszPassword(password.GetText());
- if (savePermanently.Enabled())
- m_proto->setWString("Password", tszPassword);
+ LOGFONT lf;
+ HFONT hFont = (HFONT)m_passwordValidation.SendMsg(WM_GETFONT, 0, 0);
+ GetObject(hFont, sizeof(lf), &lf);
+ lf.lfWeight = FW_BOLD;
+ m_passwordValidation.SendMsg(WM_SETFONT, (WPARAM)CreateFontIndirect(&lf), 0);
+
+ m_ok.Disable();
+}
+
+void CToxCreatePasswordDlg::Password_OnChange(CCtrlBase*)
+{
+ pass_ptrW newPassword(m_newPassword.GetText());
+ if (mir_wstrlen(newPassword) == 0) {
+ m_ok.Disable();
+ m_passwordValidation.SetText(TranslateT("New password is empty"));
+ return;
+ }
+
+ pass_ptrW confirmPassword(m_confirmPassword.GetText());
+ if (mir_wstrcmp(newPassword, confirmPassword) != 0) {
+ m_ok.Disable();
+ m_passwordValidation.SetText(TranslateT("New password is not equal to confirmation"));
+ return;
+ }
+
+ m_passwordValidation.SetText(L"");
+ m_ok.Enable();
+}
+
+void CToxCreatePasswordDlg::OnOk(CCtrlButton*)
+{
+ m_proto->setWString(TOX_SETTINGS_PASSWORD, pass_ptrW(m_newPassword.GetText()));
+ m_proto->SaveToxProfile(m_proto->m_toxThread->Tox());
+ EndDialog(m_hwnd, 1);
+}
+
+/* CHANGE PASSWORD */
+CToxChangePasswordDlg::CToxChangePasswordDlg(CToxProto *proto)
+ : CToxDlgBase(proto, IDD_PASSWORD_CHANGE, false),
+ m_oldPassword(this, IDC_PASSWORD),
+ m_newPassword(this, IDC_PASSWORD_NEW),
+ m_confirmPassword(this, IDC_PASSWORD_CONFIRM),
+ m_passwordValidation(this, IDC_PASSWORD_VALIDATION),
+ m_ok(this, IDOK)
+{
+ m_oldPassword.OnChange = Callback(this, &CToxChangePasswordDlg::Password_OnChange);
+ m_newPassword.OnChange = Callback(this, &CToxChangePasswordDlg::Password_OnChange);
+ m_confirmPassword.OnChange = Callback(this, &CToxChangePasswordDlg::Password_OnChange);
+ m_ok.OnClick = Callback(this, &CToxChangePasswordDlg::OnOk);
+}
+
+void CToxChangePasswordDlg::OnInitDialog()
+{
+ LOGFONT lf;
+ HFONT hFont = (HFONT)m_passwordValidation.SendMsg(WM_GETFONT, 0, 0);
+ GetObject(hFont, sizeof(lf), &lf);
+ lf.lfWeight = FW_BOLD;
+ m_passwordValidation.SendMsg(WM_SETFONT, (WPARAM)CreateFontIndirect(&lf), 0);
+
+ m_ok.Disable();
+}
+
+void CToxChangePasswordDlg::Password_OnChange(CCtrlBase*)
+{
+ pass_ptrW dbPassword(m_proto->getWStringA(TOX_SETTINGS_PASSWORD));
+ pass_ptrW oldPassword(m_oldPassword.GetText());
+ if (mir_wstrlen(dbPassword) > 0 && mir_wstrcmp(dbPassword, oldPassword) != 0) {
+ m_ok.Disable();
+ m_passwordValidation.SetText(TranslateT("Old password is not valid"));
+ return;
+ }
+
+ pass_ptrW newPassword(m_newPassword.GetText());
+ if (mir_wstrlen(newPassword) == 0) {
+ m_ok.Disable();
+ m_passwordValidation.SetText(TranslateT("New password is empty"));
+ return;
+ }
+
+ pass_ptrW confirmPassword(m_confirmPassword.GetText());
+ if (mir_wstrcmp(newPassword, confirmPassword) != 0) {
+ m_ok.Disable();
+ m_passwordValidation.SetText(TranslateT("New password is not equal to confirmation"));
+ return;
+ }
+
+ m_passwordValidation.SetText(L"");
+ m_ok.Enable();
+}
+
+void CToxChangePasswordDlg::OnOk(CCtrlButton*)
+{
+ m_proto->setWString(TOX_SETTINGS_PASSWORD, pass_ptrW(m_newPassword.GetText()));
+ m_proto->SaveToxProfile(m_proto->m_toxThread->Tox());
EndDialog(m_hwnd, 1);
}
diff --git a/protocols/Tox/src/tox_profile.h b/protocols/Tox/src/tox_profile.h index 796f264d5b..4aedae071f 100644 --- a/protocols/Tox/src/tox_profile.h +++ b/protocols/Tox/src/tox_profile.h @@ -1,19 +1,66 @@ #ifndef _TOX_PROFILE_H_
#define _TOX_PROFILE_H_
-class CToxPasswordEditor : public CToxDlgBase
+/* ENTER PASSWORD */
+
+class CToxEnterPasswordDlg : public CToxDlgBase
{
private:
- CCtrlEdit password;
- CCtrlCheck savePermanently;
+ CCtrlEdit m_password;
+
+ CCtrlButton m_ok;
+
+protected:
+ void OnInitDialog();
+ void Password_OnChange(CCtrlBase*);
+ void OnOk(CCtrlButton*);
+
+public:
+ CToxEnterPasswordDlg(CToxProto *proto);
+};
+
+/* CREATE PASSWORD */
+
+class CToxCreatePasswordDlg : public CToxDlgBase
+{
+private:
+ CCtrlEdit m_newPassword;
+ CCtrlEdit m_confirmPassword;
+
+ CCtrlBase m_passwordValidation;
+
+ CCtrlButton m_ok;
+
+protected:
+ void OnInitDialog();
+ void Password_OnChange(CCtrlBase*);
+ void OnOk(CCtrlButton*);
+
+public:
+ CToxCreatePasswordDlg(CToxProto *proto);
+};
+
+/* CHANGE PASSWORD */
+
+class CToxChangePasswordDlg : public CToxDlgBase
+{
+private:
+ CCtrlEdit m_oldPassword;
+
+ CCtrlEdit m_newPassword;
+ CCtrlEdit m_confirmPassword;
- CCtrlButton ok;
+ CCtrlBase m_passwordValidation;
+
+ CCtrlButton m_ok;
protected:
+ void OnInitDialog();
+ void Password_OnChange(CCtrlBase*);
void OnOk(CCtrlButton*);
public:
- CToxPasswordEditor(CToxProto *proto);
+ CToxChangePasswordDlg(CToxProto *proto);
};
#endif //_TOX_PROFILE_H_
\ No newline at end of file diff --git a/protocols/Tox/src/tox_proto.cpp b/protocols/Tox/src/tox_proto.cpp index 5b6d345c9c..60864594e7 100644 --- a/protocols/Tox/src/tox_proto.cpp +++ b/protocols/Tox/src/tox_proto.cpp @@ -2,26 +2,22 @@ CToxProto::CToxProto(const char* protoName, const wchar_t* userName)
: PROTO<CToxProto>(protoName, userName),
- toxThread(nullptr), isTerminated(false),
+ m_toxThread(nullptr), isTerminated(false),
hCheckingThread(nullptr), hPollingThread(nullptr),
hMessageProcess(1)
{
InitNetlib();
- wszAccountName = mir_wstrdup(userName);
- wszGroup = getWStringA(TOX_SETTINGS_GROUP);
- if (wszGroup == nullptr)
- wszGroup = mir_wstrdup(L"Tox");
- Clist_GroupCreate(0, wszGroup);
+ m_accountName = mir_wstrdup(userName);
+ m_defaultGroup = getWStringA(TOX_SETTINGS_GROUP);
+ if (m_defaultGroup == nullptr)
+ m_defaultGroup = mir_wstrdup(L"Tox");
+ Clist_GroupCreate(0, m_defaultGroup);
CreateProtoService(PS_CREATEACCMGRUI, &CToxProto::OnAccountManagerInit);
SetAllContactsStatus(ID_STATUS_OFFLINE);
- // services
- CreateProtoService(PSR_AUDIO, &CToxProto::OnRecvAudioCall);
- CreateProtoService("/Audio/Ring", &CToxProto::OnAudioRing);
-
// avatars
CreateProtoService(PS_GETAVATARCAPS, &CToxProto::GetAvatarCaps);
CreateProtoService(PS_GETAVATARINFO, &CToxProto::GetAvatarInfo);
@@ -31,15 +27,11 @@ CToxProto::CToxProto(const char* protoName, const wchar_t* userName) // nick
CreateProtoService(PS_SETMYNICKNAME, &CToxProto::SetMyNickname);
- // hAudioDialogs = WindowList_Create();
-
hTerminateEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
}
CToxProto::~CToxProto()
{
- WindowList_Destroy(hAudioDialogs);
-
UninitNetlib();
}
@@ -151,15 +143,13 @@ int CToxProto::SetStatus(int iNewStatus) int old_status = m_iStatus;
m_iDesiredStatus = iNewStatus;
+ // logout
if (iNewStatus == ID_STATUS_OFFLINE) {
- // logout
isTerminated = true;
SetEvent(hTerminateEvent);
- if (!Miranda_IsTerminated()) {
+ if (!Miranda_IsTerminated())
SetAllContactsStatus(ID_STATUS_OFFLINE);
- //CloseAllChatChatSessions();
- }
m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
@@ -169,19 +159,20 @@ int CToxProto::SetStatus(int iNewStatus) if (old_status >= ID_STATUS_CONNECTING && old_status < ID_STATUS_OFFLINE)
return 0;
+ // login
if (old_status == ID_STATUS_OFFLINE && !IsOnline()) {
- // login
isTerminated = false;
m_iStatus = ID_STATUS_CONNECTING;
hPollingThread = ForkThreadEx(&CToxProto::PollingThread, nullptr, nullptr);
+ ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
+ return 0;
}
- else {
- // set tox status
- m_iStatus = iNewStatus;
- tox_self_set_status(toxThread->Tox(), MirandaToToxStatus(iNewStatus));
- }
-
+
+ // change status
+ m_iStatus = iNewStatus;
+ tox_self_set_status(m_toxThread->Tox(), MirandaToToxStatus(iNewStatus));
ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
+
return 0;
}
@@ -200,7 +191,7 @@ int CToxProto::SetAwayMsg(int, const wchar_t *msg) if (IsOnline()) {
T2Utf statusMessage(msg);
TOX_ERR_SET_INFO error;
- if (!tox_self_set_status_message(toxThread->Tox(), (uint8_t*)(char*)statusMessage, min(TOX_MAX_STATUS_MESSAGE_LENGTH, mir_strlen(statusMessage)), &error))
+ if (!tox_self_set_status_message(m_toxThread->Tox(), (uint8_t*)(char*)statusMessage, min(TOX_MAX_STATUS_MESSAGE_LENGTH, mir_strlen(statusMessage)), &error))
debugLogA(__FUNCTION__": failed to set status status message %s (%d)", msg, error);
}
@@ -228,9 +219,7 @@ int CToxProto::OnEvent(PROTOEVENTTYPE iEventType, WPARAM wParam, LPARAM lParam) return OnInitStatusMenu();
case EV_PROTO_ONERASE:
- ptrW profilePath(GetToxProfilePath());
- _wunlink(profilePath);
- break;
+ return OnDeleteToxProfile();
}
return 1;
diff --git a/protocols/Tox/src/tox_proto.h b/protocols/Tox/src/tox_proto.h index 810479ab30..24896724d7 100644 --- a/protocols/Tox/src/tox_proto.h +++ b/protocols/Tox/src/tox_proto.h @@ -3,13 +3,11 @@ struct CToxProto : public PROTO<CToxProto>
{
- friend CToxPasswordEditor;
+ friend CToxEnterPasswordDlg;
+ friend CToxCreatePasswordDlg;
+ friend CToxChangePasswordDlg;
friend CToxOptionsMain;
friend CToxOptionsNodeList;
- friend CToxCallDlgBase;
- friend CToxIncomingCall;
- friend CToxOutgoingCall;
- friend CToxCallDialog;
public:
//////////////////////////////////////////////////////////////////////////////////////
@@ -58,20 +56,18 @@ public: static void InitIcons();
// menus
- static void InitMenus();
-
- // events
- void InitCustomDbEvents();
-
- static int OnModulesLoaded(WPARAM, LPARAM);
+ static void InitContactMenu();
// utils
static void ShowNotification(const wchar_t *message, int flags = 0, MCONTACT hContact = NULL);
+ static INT_PTR ParseToxUri(WPARAM, LPARAM lParam);
+
private:
- CToxThread *toxThread;
- mir_cs profileLock;
- ptrW wszAccountName, wszGroup;
+ CToxThread *m_toxThread;
+ mir_cs m_profileLock;
+ ptrW m_accountName;
+ ptrW m_defaultGroup;
CTransferList transfers;
ULONG hMessageProcess;
@@ -90,8 +86,12 @@ private: bool LoadToxProfile(Tox_Options *options);
void SaveToxProfile(Tox *tox);
+ int OnDeleteToxProfile();
INT_PTR __cdecl OnCopyToxID(WPARAM, LPARAM);
+ INT_PTR __cdecl OnCreatePassword(WPARAM, LPARAM);
+ INT_PTR __cdecl OnChangePassword(WPARAM, LPARAM);
+ INT_PTR __cdecl OnRemovePassword(WPARAM, LPARAM);
// tox core
Tox_Options* GetToxOptions();
@@ -141,7 +141,9 @@ private: int OnPrebuildContactMenu(WPARAM hContact, LPARAM);
static int PrebuildContactMenu(WPARAM hContact, LPARAM lParam);
+ HGENMENU StatusMenuItems[SMI_MAX];
int OnInitStatusMenu();
+ int __cdecl PrebuildStatusMenu(WPARAM, LPARAM);
//services
INT_PTR __cdecl SetMyNickname(WPARAM wParam, LPARAM lParam);
@@ -149,8 +151,6 @@ private: // options
int __cdecl OnOptionsInit(WPARAM wParam, LPARAM lParam);
- // events
-
// userinfo
static INT_PTR CALLBACK UserInfoProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int __cdecl OnUserInfoInit(WPARAM wParam, LPARAM lParam);
@@ -193,35 +193,11 @@ private: HWND __cdecl OnSearchAdvanced(HWND owner);
HWND __cdecl OnCreateExtendedSearchUI(HWND owner);
- // chat rooms
- //MCONTACT GetChatRoom(const char *pubKey);
- MCONTACT GetChatRoom(int groupNumber);
-
- //MCONTACT GetChatRoom(const char *pubKey);
- MCONTACT AddChatRoom(int groupNumber);
-
- void __cdecl LoadChatRoomList(void*);
-
- int __cdecl OnGroupChatEventHook(WPARAM, LPARAM lParam);
- int __cdecl OnGroupChatMenuHook(WPARAM, LPARAM lParam);
-
- INT_PTR __cdecl OnJoinChatRoom(WPARAM hContact, LPARAM);
- INT_PTR __cdecl OnLeaveChatRoom(WPARAM hContact, LPARAM);
- INT_PTR __cdecl OnCreateChatRoom(WPARAM, LPARAM);
-
- //void InitGroupChatModule();
- //void CloseAllChatChatSessions();
-
- static void OnGroupChatInvite(Tox *tox, int32_t friendNumber, uint8_t type, const uint8_t *data, const uint16_t length, void *arg);
-
- void ChatValidateContact(HWND hwndList, const std::vector<MCONTACT> &contacts, MCONTACT hContact = NULL);
- void ChatPrepare(HWND hwndList, const std::vector<MCONTACT> &contacts, MCONTACT hContact = NULL);
- static std::vector<MCONTACT> GetInvitedContacts(HWND hwndList, MCONTACT hContact = NULL);
- static INT_PTR CALLBACK ChatRoomInviteProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
-
// messages
std::map<uint64_t, UINT> messages;
+ void InitCustomDbEvents();
+
void __cdecl SendMessageAsync(void *arg);
int OnSendMessage(MCONTACT hContact, const char *message);
@@ -266,30 +242,6 @@ private: void OnGotFriendAvatarInfo(AvatarTransferParam *transfer);
void OnGotFriendAvatarData(AvatarTransferParam *transfer);
- // multimedia
- MWindowList hAudioDialogs;
- HWAVEOUT hOutDevice;
- std::map<MCONTACT, int32_t> calls;
-
- //ToxAvCSettings* GetAudioCSettings();
-
-
- INT_PTR __cdecl OnRecvAudioCall(WPARAM wParam, LPARAM lParam);
- INT_PTR __cdecl OnAudioRing(WPARAM wParam, LPARAM lParam);
-
- INT_PTR __cdecl OnSendAudioCall(WPARAM wParam, LPARAM);
-
- static void OnFriendCall(ToxAV *toxAV, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *arg);
- static void OnFriendCallState(ToxAV *toxAV, uint32_t friend_number, uint32_t state, void *user_data);
- static void OnBitrateChanged(ToxAV *toxAV, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, void *arg);
- static void OnFriendAudioFrame(ToxAV *toxAV, uint32_t friend_number, const int16_t *pcm, size_t sample_count, uint8_t channels, uint32_t sampling_rate, void *user_data);
-
- //static void OnAvEnd(void*, int32_t callId, void *arg);
- //static void OnAvReject(void*, int32_t callId, void *arg);
- //static void OnAvCancel(void*, int32_t callId, void *arg);
- //static void OnAvCallTimeout(void*, int32_t callId, void *arg);
- //static void OnAvPeerTimeout(void*, int32_t callId, void *arg);
-
// utils
static int MapStatus(int status);
static TOX_USER_STATUS MirandaToToxStatus(int status);
@@ -298,15 +250,12 @@ private: static wchar_t* ToxErrorToString(TOX_ERR_NEW error);
static wchar_t* ToxErrorToString(TOX_ERR_FRIEND_SEND_MESSAGE error);
-
static void ShowNotification(const wchar_t *caption, const wchar_t *message, int flags = 0, MCONTACT hContact = NULL);
static bool IsFileExists(const wchar_t* path);
MEVENT AddEventToDb(MCONTACT hContact, WORD type, DWORD timestamp, DWORD flags, PBYTE pBlob, size_t cbBlob);
- static INT_PTR ParseToxUri(WPARAM, LPARAM lParam);
-
template<INT_PTR(__cdecl CToxProto::*Service)(WPARAM, LPARAM)>
static INT_PTR __cdecl GlobalService(WPARAM wParam, LPARAM lParam)
{
diff --git a/protocols/Tox/src/tox_search.cpp b/protocols/Tox/src/tox_search.cpp index d03d3a091a..d8077fedd1 100644 --- a/protocols/Tox/src/tox_search.cpp +++ b/protocols/Tox/src/tox_search.cpp @@ -226,12 +226,7 @@ HWND CToxProto::OnSearchAdvanced(HWND owner) PROTOSEARCHRESULT psr = { sizeof(psr) };
psr.flags = PSR_UTF8;
psr.id.a = mir_strdup(query.c_str());
-
- ADDCONTACTSTRUCT acs = { HANDLE_SEARCHRESULT };
- acs.szProto = m_szModuleName;
- acs.psr = &psr;
-
- CallService(MS_ADDCONTACT_SHOW, (WPARAM)owner, (LPARAM)&acs);
+ Contact_AddBySearch(m_szModuleName, &psr, owner);
ForkThread(&CToxProto::SearchFailedAsync, nullptr);
}
diff --git a/protocols/Tox/src/tox_services.cpp b/protocols/Tox/src/tox_services.cpp index 532eef79d7..a2c9e549a9 100644 --- a/protocols/Tox/src/tox_services.cpp +++ b/protocols/Tox/src/tox_services.cpp @@ -8,7 +8,7 @@ INT_PTR CToxProto::SetMyNickname(WPARAM wParam, LPARAM lParam) if (IsOnline()) {
T2Utf szNick8(nickname);
TOX_ERR_SET_INFO error;
- if (!tox_self_set_name(toxThread->Tox(), szNick8, mir_strlen(szNick8), &error))
+ if (!tox_self_set_name(m_toxThread->Tox(), szNick8, mir_strlen(szNick8), &error))
debugLogA(__FUNCTION__": failed to set nick name");
}
diff --git a/protocols/Tox/src/tox_thread.h b/protocols/Tox/src/tox_thread.h index ae0f4225f8..37372177dc 100644 --- a/protocols/Tox/src/tox_thread.h +++ b/protocols/Tox/src/tox_thread.h @@ -5,22 +5,16 @@ class CToxThread {
private:
Tox *tox;
- ToxAV *toxAV;
public:
CToxThread(Tox_Options *options, TOX_ERR_NEW *error = NULL)
- : tox(NULL), toxAV(NULL)
+ : tox(NULL)
{
tox = tox_new(options, error);
}
~CToxThread()
{
- if (toxAV)
- {
- toxav_kill(toxAV);
- toxAV = NULL;
- }
if (tox)
{
@@ -33,11 +27,6 @@ public: {
return tox;
}
-
- ToxAV* ToxAV()
- {
- return toxAV;
- }
};
#endif //_TOX_THREAD_H_
\ No newline at end of file diff --git a/protocols/Tox/src/tox_transfer.cpp b/protocols/Tox/src/tox_transfer.cpp index 3fb9ad77b7..6becdc1a26 100644 --- a/protocols/Tox/src/tox_transfer.cpp +++ b/protocols/Tox/src/tox_transfer.cpp @@ -96,7 +96,7 @@ int CToxProto::OnFileResume(HANDLE hTransfer, int *action, const wchar_t **szFil FileTransferParam *transfer = (FileTransferParam*)hTransfer;
if (*action == FILERESUME_SKIP) {
- tox_file_control(toxThread->Tox(), transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, nullptr);
+ tox_file_control(m_toxThread->Tox(), transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, nullptr);
transfers.Remove(transfer);
return 0;
}
@@ -104,22 +104,22 @@ int CToxProto::OnFileResume(HANDLE hTransfer, int *action, const wchar_t **szFil if (*action == FILERESUME_RENAME)
transfer->ChangeName(*szFilename);
- ToxHexAddress pubKey = GetContactPublicKey(toxThread->Tox(), transfer->friendNumber);
+ ToxHexAddress pubKey = GetContactPublicKey(m_toxThread->Tox(), transfer->friendNumber);
wchar_t *mode = *action == FILERESUME_OVERWRITE ? L"wb" : L"ab";
if (!transfer->OpenFile(mode)) {
debugLogA(__FUNCTION__": failed to open file (%d) from %s(%d)", transfer->fileNumber, (const char*)pubKey, transfer->friendNumber);
- tox_file_control(toxThread->Tox(), transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, nullptr);
+ tox_file_control(m_toxThread->Tox(), transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, nullptr);
transfers.Remove(transfer);
return NULL;
}
TOX_ERR_FILE_CONTROL error;
debugLogA(__FUNCTION__": start receiving file (%d) from %s(%d)", transfer->fileNumber, (const char*)pubKey, transfer->friendNumber);
- if (!tox_file_control(toxThread->Tox(), transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_RESUME, &error)) {
+ if (!tox_file_control(m_toxThread->Tox(), transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_RESUME, &error)) {
debugLogA(__FUNCTION__": failed to start receiving of file(%d) from %s(%d) cause (%d)", transfer->fileNumber, (const char*)pubKey, transfer->friendNumber, error);
ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)transfer, 0);
- tox_file_control(toxThread->Tox(), transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, nullptr);
+ tox_file_control(m_toxThread->Tox(), transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, nullptr);
transfers.Remove(transfer);
}
@@ -128,7 +128,7 @@ int CToxProto::OnFileResume(HANDLE hTransfer, int *action, const wchar_t **szFil void CToxProto::OnTransferCompleted(FileTransferParam *transfer)
{
- ToxHexAddress pubKey = GetContactPublicKey(toxThread->Tox(), transfer->friendNumber);
+ ToxHexAddress pubKey = GetContactPublicKey(m_toxThread->Tox(), transfer->friendNumber);
debugLogA(__FUNCTION__": finised the transfer of file (%d) from %s(%d)", transfer->fileNumber, (const char*)pubKey, transfer->friendNumber);
bool isFileFullyTransfered = transfer->pfts.currentFileProgress == transfer->pfts.currentFileSize;
@@ -177,7 +177,7 @@ void CToxProto::OnDataReceiving(Tox *tox, uint32_t friendNumber, uint32_t fileNu if (fwrite(data, sizeof(uint8_t), length, transfer->hFile) != length) {
proto->debugLogA(__FUNCTION__": failed write to file (%d)", fileNumber);
proto->ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)transfer, 0);
- tox_file_control(proto->toxThread->Tox(), friendNumber, fileNumber, TOX_FILE_CONTROL_CANCEL, nullptr);
+ tox_file_control(proto->m_toxThread->Tox(), friendNumber, fileNumber, TOX_FILE_CONTROL_CANCEL, nullptr);
return;
}
@@ -210,11 +210,11 @@ HANDLE CToxProto::OnSendFile(MCONTACT hContact, const wchar_t*, wchar_t **ppszFi uint64_t fileSize = _ftelli64(hFile);
rewind(hFile);
- ToxHexAddress pubKey = GetContactPublicKey(toxThread->Tox(), friendNumber);
+ ToxHexAddress pubKey = GetContactPublicKey(m_toxThread->Tox(), friendNumber);
char *name = mir_utf8encodeW(fileName);
TOX_ERR_FILE_SEND sendError;
- uint32_t fileNumber = tox_file_send(toxThread->Tox(), friendNumber, TOX_FILE_KIND_DATA, fileSize, nullptr, (uint8_t*)name, mir_strlen(name), &sendError);
+ uint32_t fileNumber = tox_file_send(m_toxThread->Tox(), friendNumber, TOX_FILE_KIND_DATA, fileSize, nullptr, (uint8_t*)name, mir_strlen(name), &sendError);
if (sendError != TOX_ERR_FILE_SEND_OK) {
debugLogA(__FUNCTION__": failed to send file (%d) to %s(%d) cause (%d)", fileNumber, (const char*)pubKey, friendNumber, sendError);
mir_free(fileDir);
@@ -272,14 +272,14 @@ void CToxProto::OnFileSendData(Tox *tox, uint32_t friendNumber, uint32_t fileNum }
TOX_ERR_FILE_SEND_CHUNK error;
- if (!tox_file_send_chunk(proto->toxThread->Tox(), friendNumber, fileNumber, position, data, length, &error)) {
+ if (!tox_file_send_chunk(proto->m_toxThread->Tox(), friendNumber, fileNumber, position, data, length, &error)) {
if (error == TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_CONNECTED) {
mir_free(data);
return;
}
proto->debugLogA(__FUNCTION__": failed to send file chunk (%d) to %s(%d) cause (%d)", fileNumber, (const char*)pubKey, friendNumber, error);
proto->ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)transfer, 0);
- tox_file_control(proto->toxThread->Tox(), transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, nullptr);
+ tox_file_control(proto->m_toxThread->Tox(), transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, nullptr);
mir_free(data);
return;
}
@@ -296,7 +296,7 @@ int CToxProto::CancelTransfer(MCONTACT, HANDLE hTransfer) {
FileTransferParam *transfer = (FileTransferParam*)hTransfer;
debugLogA(__FUNCTION__": Transfer (%d) is canceled", transfer->fileNumber);
- tox_file_control(toxThread->Tox(), transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, nullptr);
+ tox_file_control(m_toxThread->Tox(), transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, nullptr);
transfers.Remove(transfer);
return 0;
@@ -308,13 +308,13 @@ void CToxProto::PauseOutgoingTransfers(uint32_t friendNumber) // only for sending
FileTransferParam *transfer = transfers.GetAt(i);
if (transfer->friendNumber == friendNumber && transfer->GetDirection() == 0) {
- ToxHexAddress pubKey = GetContactPublicKey(toxThread->Tox(), friendNumber);
+ ToxHexAddress pubKey = GetContactPublicKey(m_toxThread->Tox(), friendNumber);
debugLogA(__FUNCTION__": sending ask to pause the transfer of file (%d) to %s(%d)", transfer->fileNumber, (const char*)pubKey, transfer->friendNumber);
TOX_ERR_FILE_CONTROL error;
- if (!tox_file_control(toxThread->Tox(), transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_PAUSE, &error)) {
+ if (!tox_file_control(m_toxThread->Tox(), transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_PAUSE, &error)) {
debugLogA(__FUNCTION__": failed to pause the transfer (%d) to %s(%d) cause(%d)", transfer->fileNumber, (const char*)pubKey, transfer->friendNumber, error);
- tox_file_control(toxThread->Tox(), transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, nullptr);
+ tox_file_control(m_toxThread->Tox(), transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, nullptr);
}
}
}
@@ -326,11 +326,11 @@ void CToxProto::ResumeIncomingTransfers(uint32_t friendNumber) // only for receiving
FileTransferParam *transfer = transfers.GetAt(i);
if (transfer->friendNumber == friendNumber && transfer->GetDirection() == 1) {
- ToxHexAddress pubKey = GetContactPublicKey(toxThread->Tox(), friendNumber);
+ ToxHexAddress pubKey = GetContactPublicKey(m_toxThread->Tox(), friendNumber);
debugLogA(__FUNCTION__": sending ask to resume the transfer of file (%d) from %s(%d) cause(%d)", transfer->fileNumber, (const char*)pubKey, transfer->friendNumber);
TOX_ERR_FILE_CONTROL error;
- if (!tox_file_control(toxThread->Tox(), transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_RESUME, &error)) {
+ if (!tox_file_control(m_toxThread->Tox(), transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_RESUME, &error)) {
debugLogA(__FUNCTION__": failed to resume the transfer (%d) from %s(%d) cause(%d)", transfer->fileNumber, (const char*)pubKey, transfer->friendNumber, error);
CancelTransfer(NULL, transfer);
}
diff --git a/protocols/Tox/src/tox_utils.cpp b/protocols/Tox/src/tox_utils.cpp index 722517c427..130e08eaec 100644 --- a/protocols/Tox/src/tox_utils.cpp +++ b/protocols/Tox/src/tox_utils.cpp @@ -165,11 +165,6 @@ INT_PTR CToxProto::ParseToxUri(WPARAM, LPARAM lParam) PROTOSEARCHRESULT psr = { sizeof(psr) };
psr.flags = PSR_UTF8;
psr.id.a = mir_u2a(&uri[4]);
-
- ADDCONTACTSTRUCT acs = { HANDLE_SEARCHRESULT };
- acs.szProto = proto->m_szModuleName;
- acs.psr = &psr;
-
- CallService(MS_ADDCONTACT_SHOW, 0, (LPARAM)&acs);
+ Contact_AddBySearch(proto->m_szModuleName, &psr);
return 0;
}
diff --git a/protocols/Tox/src/version.h b/protocols/Tox/src/version.h index ba58f1f238..9e50bf1249 100644 --- a/protocols/Tox/src/version.h +++ b/protocols/Tox/src/version.h @@ -1,7 +1,7 @@ #define __MAJOR_VERSION 0
#define __MINOR_VERSION 11
-#define __RELEASE_NUM 1
-#define __BUILD_NUM 26
+#define __RELEASE_NUM 3
+#define __BUILD_NUM 0
#include <stdver.h>
@@ -9,6 +9,5 @@ #define __FILENAME "Tox.dll"
#define __DESCRIPTION "Tox protocol support for Miranda NG."
#define __AUTHOR "Miranda NG Team"
-#define __AUTHOREMAIL ""
#define __AUTHORWEB "https://miranda-ng.org/p/Tox/"
#define __COPYRIGHT "© 2014-17 Miranda NG Team"
diff --git a/protocols/Tox/tools/CHANGES b/protocols/Tox/tools/CHANGES deleted file mode 100644 index c2f308e980..0000000000 --- a/protocols/Tox/tools/CHANGES +++ /dev/null @@ -1,266 +0,0 @@ - -This is the CHANGES file for cv2pdb, a -converter of DMD CodeView/DWARF debug information to PDB files - -Copyright (c) 2009-2012 by Rainer Schuetze, All Rights Reserved - -Version history ---------------- - -2009-05-08 Version 0.1 - - * initial release - -2009-05-16 Version 0.2 - - * replace .debug section in executable rather than rename it. (only works - if it is the last section). - * support for field type LF_VFUNCTAB and symbol type S_CONSTANT used by DMC. - * added stringview to autoexp.dat for full length text display. - -2009-06-04 Version 0.3 - - * static members' debug info was not correctly converted, causing debugger confusion - * now works on executables compiled by DMC - - added command line switch -C to disable some D feature and - to remove function name from local variables - - added support for type LF_BITFIELD. - * added fields __viewhelper to classes string and object - * new addin dviewhelper.dll to display correctly terminated strings - and derived object type - -2009-06-05 Version 0.4 - - * fixed crash when long is used as index or element type of dynamic or - associative arrays - -2009-06-06 Version 0.5 - - * fixed error in __viewhelper field of string type, that could screw up type info - * added support for wstring and dstring - * fixed problems with debug info inside library by combining debug info of different modules - into a single pseudo-module - * now also replaces '.' by '@' in enumerator types for more consistent debug info - -2009-06-07 Version 0.6 - - * removed LF_DERIVED info from debug info, as it is inconsistent in DMD generated info - with more than 4096 type entries - -2009-06-08 Version 0.7 - - * corrected number of field entries in classes or struct, because DMD miscounts private members - -2009-06-11 Version 0.8 - - * tweaked visualizer macros to detect uninitialized associative arrays and to limit expansion - to arrays with less than 1024 entries - * renamed data pointer member of dynamic arrays to "ptr" to be consistent with the array property - in D. - -2009-06-19 Version 0.9 - - * fixed line number info at the end of a segment or when switching to another file - because of inline expansion - * fixed line numbers > 32767 and sections with 0 line number entries - -2009-08-12 Version 0.10 - - * better support for DMC: - - entries LF_FRIENDFCN removed - - entries LF_FRIENDCLS, LF_VBCLASS and LF_IVBCLASS converted - thanks to Andrew. - * derived-classes info in class entry now cleared to be consistent with removal of LF_DERIVED - -2009-12-29 Version 0.11 - - * basic types now show with their D names, not as C types - * "enum" prefix removed from type names of enumerator types - * added type information for complex data types - * dmd-patch needed for long/ulong support (http://d.puremagic.com/issues/show_bug.cgi?id=3373) - * experimental hack to add lexical scope to local variables (dmd patch in - http://d.puremagic.com/issues/show_bug.cgi?id=3657 needed) - -2010-04-13 Version 0.12 - - * added patch to convert binaries produced by Metroworks CodeWarrior - * names of local function are now demangled - * dmd 2.041 fixes long/ulong support (patch http://d.puremagic.com/issues/show_bug.cgi?id=3373 - no longer needed) - * added managed C++ project to integrate cv2pdb with CLR (thanks to Alexander Bothe) - * dmd 2.043 uses different implementation of associative arrays, use command line - option -D 2.043 or above to produce the respective debug info - -2010-06-03 Version 0.13 - - * adapted to mspdb100.dll which comes with VS2010 - * tweaked autoexp.dat modifications to be more stable with uninitialized data - * autoexp.snippet now split into two files: autoexp.expand and autoexp.visualizer - -2010-06-23 Version 0.14 - - * 64-integer types are now displayed as "dlong" and "ulong" instead of "__int64" and - "unsigned __int64" - * improved support for long and ulong for DMD versions before 1.057 and 2.041 - * DMC also emits D-types for "long long" and "unsigned long long", these are - translated back to the correct types if command option -C is used - * now adding properties "has nested type" and "is nested type" to class/struct/union/enum types - * better support for enumerators: now added as user defined types (DMD patch needed) - -2010-08-08 Version 0.15 - - * thanks to patches by Z3N, the resulting pdb is now usable by more debuggers - * now uses shared file access to executable - * incomplete structs/classes are now added as user defined types to avoid confusing - debugger for following symbols - * fixed name demangling of very long names - * added name demangling support for @safe/@trusted/@property/pure/nothrow/ref - * base classes are added to D/cpp-interfaces to allow viewing the virtual function - table pointer - * structs, classes and interfaces now have an internal qualifier attached that allows - the preview in autoexp.dat to show better info for structs and interfaces - -2010-08-10 Version 0.16 - - * fixed crash when working with -C (introduced in last version) - -2010-09-04 Version 0.17 - - * fixed crash that could occur for user-defined types longer than 90 characters - -2010-10-24 Version 0.18 - - * fixed error with nested types longer than 255 characters - * more fixes for names longer than 300 characters - -2010-12-10 Version 0.19 - - * now converting only class pointers to references, not pointers to structs or void - * changed default D-version to 2.043 to create correct associative array type - information for recent compilers by default - -2010-12-30 Version 0.20 - - * fixed another issue with user defined type names longer than 300 characters - * now corrects the debug info when dmc/optlink emits multiple struct definitions, - but only one UDT record. - -2010-05-08 Version 0.21 - - * fixed decoding of compressed symbols - * added command line switch -n to disable symbol demangling - * fixed crash with more than 32767 types - -unreleased Version 0.22 - - * added command line switch -s to specify the replacement character for '.' in symbols - * fixed another crash where compressed symbols expand to more than 4096 characters - -2012-02-12 Version 0.23 - - * disabled named enumerator for D basic types to avoid debugger troubles displaying arrays - * added command line switch -e to enable using named enumerator for D basic types - * added DWARF support - * added x64 support - * tweaked visualizer for associative array element to just show key and value - -2012-05-01 Version 0.24 - - * supports unicode characters in file names - * improve interpretation of DWARF location expression - -2012-06-18 Version 0.25 - - * new option -p allows to specify the embedded PDB reference in the binary - * added support for VS2012 - -2012-11-09 Version 0.26 - - * now iterating over multiple entries in the debug directory to find CV info - -2013-05-11 Version 0.27 - - * fixed crash when converting DWARF locations using 8 bytes or more - -2013-11-16 Version 0.28 - - * added searching mspdb120.dll for VS 2013 - * changed search order for mspdb*.dll: trying to load through PATH first - newest VS versions preferred, then trying through installation paths for VS 2013-2005 - * dviewhelper.dll now avoids being reloaded for every expression - -2014-02-19 Version 0.29 - - * fix DWARF conversion for newer gcc versions (4.8.0 or even earlier) - -2014-02-25 Version 0.30 - - * fixed crash when converting DWARF for executables without .reloc segment - -2014-03-01 Version 0.31 - - * added support for local variables accessed through esp - -2014-09-24 Version 0.32 - - * DWARF: fixed relocations in .debug_line section - * tweaked visualizer macros to display void[], limit array preview to 64 entries - -2014-12-19 Version 0.33 - - * DWARF: revamped location expression evaluator by Vadim Chugunov - -2015-02-17 Version 0.34 - - * DWARF: fixed issues with DW_FORM_strp, DW_AT_upper_bound and DW_AT_lower_bound - * DWARF: translate __int128 to CV code 0x14, just a wild guesss - - * DWARF: add support for DW_ATE_UTF, remove bad assert - -2015-05-08 Version 0.35 - - * new tool dumplines to display the debug line number info - -2015-06-03 Version 0.36 - - * last version introduced a regression that could cause DWARF conversion to crash - * DWARF sections now stripped from image (if last sections) - * add support for VS 2015 - -2015-06-17 Version 0.37 - - * DWARF: improved support for gcc 4.9.0 and clang 3.6 - * DWARF: support debug_frame (CFA) and debug_loc (for frame base) for better support for locals - * write correct machine type for x64 to PDB - -2016-08-09 Version 0.38 - - * allow anonymous typedefs - * cv2pdb now builds as x64 application - * truncate symbols that are to long - * better support for symbols that contain non-ascii characters: do not uncompress names in field lists - * copy symbol unmodified if uncompression fails - -2017-01-20 Version 0.39 - - * do not assume sorted line numbers per segment - -2017-05-13 Version 0.40 - - * set source language 'D' in compilation unit - * for D version >= 2.068, write AA debug info compatible with dmd COFF output - * prefer struct over class for internal structs - * handle class/struct property "uniquename" - -2017-05-13 Version 0.41 - - * when using mspdb120.dll (VS2013) or later, do not emit view helpers - * remove method declarations from struct or class records (they confuse mspdb*.dll if having forward references?) - -2017-09-02 Version 0.42 - - * search VS2017 registry entries to find mspdb140.dll - * when using mspdb140.dll (VS2015) or later, use symbols to emit line numbers - * translate S_UDT_V1 to V3 version - * translate S_BLOCK_V1 to V3 version - * remove "this" from delegate parameter list if inconsistent with procedure type diff --git a/protocols/Tox/tools/FEATURES b/protocols/Tox/tools/FEATURES deleted file mode 100644 index d6767e3bc8..0000000000 --- a/protocols/Tox/tools/FEATURES +++ /dev/null @@ -1,33 +0,0 @@ -Main Features - -* conversion of DMD/DMC CodeView information to PDB file -* converted line number info allows setting breakpoints -* display of variables, fields and objects in watch, local and auto - window and in data tooltips -* convenient display of dynamic and associative arrays in watch windows -* demangled function names for convenient display of callstack - -More features - -This list is a bit more technical and shows what is actually done to -achieve the desired functionality: - -* replaces '.' in class names with '@' to avoid confusing debugger -* converts class pointers to reference for "clss.field" syntax -* converts the type of member function, so that "this" is an object - pointer, allowing the debugger to display fields without "this." -* generates generic debug info for dynamic arrays, associative arrays - and delegates -* creates readable type names for display of D specific types -* autoexp.dat formats output for dynamic and associative arrays in - watch windows -* autoexp.dat filters display of null references -* adds object class debug info -* "char[]", "wchar[]" and "dchar[]" (D1) or "const char[]", - "const wchar[]" and "const dchar[]" (D2) translated to "string", - "wstring" and "dstring", respectively -* converts type delegate<void*,int> to __int64 -* addin dviewhelper.dll allows correct display of D style strings - and derived object type -* maps D basic types to enumerators to overload C style names -* add struct definitions for complex data types diff --git a/protocols/Tox/tools/INSTALL b/protocols/Tox/tools/INSTALL deleted file mode 100644 index 93863dd740..0000000000 --- a/protocols/Tox/tools/INSTALL +++ /dev/null @@ -1,71 +0,0 @@ - -This is the INSTALL file for cv2pdb, a -converter of DMD CodeView/DWARF debug information to PDB files - -Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved - -Prerequisites -------------- - -For this program to be useful, you should have you should have the -Digital Mars D Compiler (http://www.digitalmars.com/d/2.0/dmd-windows.html) -and either Microsoft Visual Studio 2005, 2008 or 2010 or one of the Express -versions installed. cv2pdb uses one of the Microsoft DLLs to actually -write the PDB file. - -If you are using some other program, you'll still need some -files from one of the distributions. These are mspdb80.dll, mspdbsrv.exe, -msobj80.dll, mspdbcore.dll and msvcr90.dll from the VS2008 installation or -mspdb100.dll, mspdbsrv.exe, msobj100.dll, mspdbcore.dll and msvcr100.dll -from VS2010. They should be accessible through the PATH environment variable. -(The VS Shell is missing the msobj80.dll/msobj100.dll only). - -Installation ------------- -You might want to consider installing Visual D (www.dsource.org/projects/visuald) -instead of cv2pdb. Visual D provides both project and language integration -into Visual Studio and comes with an installer that includes cv2pdb. - -There is no full featured installer available for cv2pdb, you'll have -to do some simple manual steps to use cv2pdb. - -1. The binary package of cv2pdb contains an executable cv2pdb.exe, which -should be copied somewhere accessible through your PATH environment -variable. - -2. cv2pdb.exe must be able to locate the DLL mspdb80.dll/mspdb100.dll from the Visual -Studio installation. It tries to read the installation path of the latter from the registry, but -if this fails, mspdb80.dll/mspdb100.dll should also be accessible through your PATH -environment variable. - -3. For best debugging experience, you should configure Visual Studio -to use C/C++ syntax highlighting for D files. This is done by -navigating to the file extensions option page (found in Tools -> Options --> Text editor -> File Extensions) and adding extensions "d" and "di" -with editor "Microsoft Visual C++". This will also enable display of -variables in the "Auto" watch window. - -4. You should also add the contents of the files autoexp.expand and -autoexp.visualizer to the respective [AutoExpand] and [Visualizer] -sections of the file autoexp.dat found in -<Visual Studio Installation Path>\Common7\Packages\Debugger. -Please note that in a standard installation of Visual Studio, the -section [AutoExpand] is at the beginning of that file, followed by -the section [Visualizer], which extends to the bottom of the file but a few lines -for the section [hresult]. -These lines will enable a convenient display of strings, dynamic arrays, -associative arrays, object types and null references. - -5. The file dviewhelper.dll must be copied into a directory where -the debugger can find it. This can be any directory accessible through your -PATH variable or <Visual Studio Installation Path>\Common7\IDE. Alternatively, -the full path can be specified in the corresponding entries in the -[AutoExpand] section of autoexp.dat. - - -Building from source --------------------- -The source package comes with a Visual Studio 2008 project and solution -that work with both the Standard and the Express version. These won't -work in VS2005, but creating VS2005 projects should be easy. - diff --git a/protocols/Tox/tools/LICENSE b/protocols/Tox/tools/LICENSE deleted file mode 100644 index 32efefcf63..0000000000 --- a/protocols/Tox/tools/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - The Artistic License 2.0 - - Copyright (c) 2000-2006, The Perl Foundation. - - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -Preamble - -This license establishes the terms under which a given free software -Package may be copied, modified, distributed, and/or redistributed. -The intent is that the Copyright Holder maintains some artistic -control over the development of that Package while still keeping the -Package available as open source and free software. - -You are always permitted to make arrangements wholly outside of this -license directly with the Copyright Holder of a given Package. If the -terms of this license do not permit the full use that you propose to -make of the Package, you should contact the Copyright Holder and seek -a different licensing arrangement. - -Definitions - - "Copyright Holder" means the individual(s) or organization(s) - named in the copyright notice for the entire Package. - - "Contributor" means any party that has contributed code or other - material to the Package, in accordance with the Copyright Holder's - procedures. - - "You" and "your" means any person who would like to copy, - distribute, or modify the Package. - - "Package" means the collection of files distributed by the - Copyright Holder, and derivatives of that collection and/or of - those files. A given Package may consist of either the Standard - Version, or a Modified Version. - - "Distribute" means providing a copy of the Package or making it - accessible to anyone else, or in the case of a company or - organization, to others outside of your company or organization. - - "Distributor Fee" means any fee that you charge for Distributing - this Package or providing support for this Package to another - party. It does not mean licensing fees. - - "Standard Version" refers to the Package if it has not been - modified, or has been modified only in ways explicitly requested - by the Copyright Holder. - - "Modified Version" means the Package, if it has been changed, and - such changes were not explicitly requested by the Copyright - Holder. - - "Original License" means this Artistic License as Distributed with - the Standard Version of the Package, in its current version or as - it may be modified by The Perl Foundation in the future. - - "Source" form means the source code, documentation source, and - configuration files for the Package. - - "Compiled" form means the compiled bytecode, object code, binary, - or any other form resulting from mechanical transformation or - translation of the Source form. - - -Permission for Use and Modification Without Distribution - -(1) You are permitted to use the Standard Version and create and use -Modified Versions for any purpose without restriction, provided that -you do not Distribute the Modified Version. - - -Permissions for Redistribution of the Standard Version - -(2) You may Distribute verbatim copies of the Source form of the -Standard Version of this Package in any medium without restriction, -either gratis or for a Distributor Fee, provided that you duplicate -all of the original copyright notices and associated disclaimers. At -your discretion, such verbatim copies may or may not include a -Compiled form of the Package. - -(3) You may apply any bug fixes, portability changes, and other -modifications made available from the Copyright Holder. The resulting -Package will still be considered the Standard Version, and as such -will be subject to the Original License. - - -Distribution of Modified Versions of the Package as Source - -(4) You may Distribute your Modified Version as Source (either gratis -or for a Distributor Fee, and with or without a Compiled form of the -Modified Version) provided that you clearly document how it differs -from the Standard Version, including, but not limited to, documenting -any non-standard features, executables, or modules, and provided that -you do at least ONE of the following: - - (a) make the Modified Version available to the Copyright Holder - of the Standard Version, under the Original License, so that the - Copyright Holder may include your modifications in the Standard - Version. - - (b) ensure that installation of your Modified Version does not - prevent the user installing or running the Standard Version. In - addition, the Modified Version must bear a name that is different - from the name of the Standard Version. - - (c) allow anyone who receives a copy of the Modified Version to - make the Source form of the Modified Version available to others - under - - (i) the Original License or - - (ii) a license that permits the licensee to freely copy, - modify and redistribute the Modified Version using the same - licensing terms that apply to the copy that the licensee - received, and requires that the Source form of the Modified - Version, and of any works derived from it, be made freely - available in that license fees are prohibited but Distributor - Fees are allowed. - - -Distribution of Compiled Forms of the Standard Version -or Modified Versions without the Source - -(5) You may Distribute Compiled forms of the Standard Version without -the Source, provided that you include complete instructions on how to -get the Source of the Standard Version. Such instructions must be -valid at the time of your distribution. If these instructions, at any -time while you are carrying out such distribution, become invalid, you -must provide new instructions on demand or cease further distribution. -If you provide valid instructions or cease distribution within thirty -days after you become aware that the instructions are invalid, then -you do not forfeit any of your rights under this license. - -(6) You may Distribute a Modified Version in Compiled form without -the Source, provided that you comply with Section 4 with respect to -the Source of the Modified Version. - - -Aggregating or Linking the Package - -(7) You may aggregate the Package (either the Standard Version or -Modified Version) with other packages and Distribute the resulting -aggregation provided that you do not charge a licensing fee for the -Package. Distributor Fees are permitted, and licensing fees for other -components in the aggregation are permitted. The terms of this license -apply to the use and Distribution of the Standard or Modified Versions -as included in the aggregation. - -(8) You are permitted to link Modified and Standard Versions with -other works, to embed the Package in a larger work of your own, or to -build stand-alone binary or bytecode versions of applications that -include the Package, and Distribute the result without restriction, -provided the result does not expose a direct interface to the Package. - - -Items That are Not Considered Part of a Modified Version - -(9) Works (including, but not limited to, modules and scripts) that -merely extend or make use of the Package, do not, by themselves, cause -the Package to be a Modified Version. In addition, such works are not -considered parts of the Package itself, and are not subject to the -terms of this license. - - -General Provisions - -(10) Any use, modification, and distribution of the Standard or -Modified Versions is governed by this Artistic License. By using, -modifying or distributing the Package, you accept this license. Do not -use, modify, or distribute the Package, if you do not accept this -license. - -(11) If your Modified Version has been derived from a Modified -Version made by someone other than you, you are nevertheless required -to ensure that your Modified Version complies with the requirements of -this license. - -(12) This license does not grant you the right to use any trademark, -service mark, tradename, or logo of the Copyright Holder. - -(13) This license includes the non-exclusive, worldwide, -free-of-charge patent license to make, have made, use, offer to sell, -sell, import and otherwise transfer the Package with respect to any -patent claims licensable by the Copyright Holder that are necessarily -infringed by the Package. If you institute patent litigation -(including a cross-claim or counterclaim) against any party alleging -that the Package constitutes direct or contributory patent -infringement, then this Artistic License to you shall terminate on the -date that such litigation is filed. - -(14) Disclaimer of Warranty: -THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS -IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED -WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR -NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL -LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/protocols/Tox/tools/README b/protocols/Tox/tools/README deleted file mode 100644 index 25fe632c74..0000000000 --- a/protocols/Tox/tools/README +++ /dev/null @@ -1,139 +0,0 @@ - -This is the README file for cv2pdb, a -converter of DMD CodeView/DWARF debug information to PDB files - -Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved - -The goal of this project is to make debugging of D applications that -were created with the Digital Mars DMD compiler, as seamless as possible -in current versions of Visual Studio (i.e Visual Studio 2008 and -VCExpress). -As a side effect, other applications might also benefit from the -converted debug information, like WinDbg or DMC. - -Features --------- -* conversion of DMD CodeView information to PDB file -* conversion of DWARF information to PDB file -* converted line number info allows setting breakpoints -* display of variables, fields and objects in watch, local and auto window and in data tooltips -* generates generic debug info for dynamic arrays, associative arrays and delegates -* autoexp.dat allows convenient display of dynamic and associative arrays in watch windows -* demangles function names for convenient display of callstack -* also works debugging executables built with the Digital Mars C/C++ compiler DMC - -License information -------------------- - -This code is distributed under the term of the Artistic License 2.0. -For more details, see the full text of the license in the file LICENSE. - -The file demangle.cpp is an adaption of denangle.d to C++ distributed with -the DMD compiler. It is placed into the Public Domain. - -The file mscvpdb.h is taken from the WINE-project (http://www.winehq.org) -and is distributed under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. -See the file header for more details and -http://www.gnu.org/licenses/lgpl.html for the full license. - -The file dwarf.h is taken from the libdwarf project -(http://reality.sgiweb.org/davea/dwarf.html) -and is distributed under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. -See the file header for more details and -http://www.gnu.org/licenses/lgpl.html for the full license. - -Installation ------------- -Sorry, there is no full featured installer available yet, you'll have -to do some simple manual steps to use cv2pdb. - -See the file INSTALL for further details. - -Usage ------ - -Quick start: - -Simply run - - cv2pdb debuggee.exe - -on your executable to debug and start the debugger, e.g. - - devenv debuggee.exe -or - vcexpress debuggee.exe - -Description: - -cv2pdb.exe is a command line tool which outputs its usage information -if run without arguments: - - usage: cv2pdb [-Dversion|-C] <exe-file> [new-exe-file] [pdb-file] - -With the -D option, you can specify the version of the DMD compiler -you are using. Unfortunately, this information is not embedded into -the debug information. The default is -D2. So far, this information -is only needed to determine whether "char[]" or "const char[]" is -translated to "string". - -Starting with DMD 2.043, assoiciative arrays have a slightly different -implementation, so debug information needs to be adjusted aswell. -Use -D 2.043 or higher to produce the matching debug info. - -Option -C tells the program, that you want to debug a program compiled -with DMC, the Digital Mars C/C++ compiler. It will disable some of the -D specific functions and will enable adjustment of stack variable names. - -The first file name on the command line is expected to be the executable -or dynamic library compiled by the DMD compiler and containing the -CodeView debug information (-g option used when running dmd). - -If no further file name is given, a PDB file will be created with the -same base name as the executable, but with extension "pdb", and the -executable will be modified to redirect debuggers to this pdb-file instead -of the original debug information. - -Example: - cv2pdb debuggee.exe - -In an environment using make-like tools, it is often useful to create -a new file instead of modifying existing files. That way the file -modification time can be used to continue the build process at the -correct step. -If another file name is specified, the new executable is written -to this file and leaves the input executable unmodified.. The naming -of the pdb-file will use the base name of the output file. - -Example: - cv2pdb debuggee.exe debuggee_pdb.exe - -Last but not least, the resulting pdb-file can be renamed by specifying -a third file name. - -Example: - cv2pdb debuggee.exe debuggee_pdb.exe debug.pdb - - - -Changes -------- - -For documentation on the changes between this version and -previous versions, please see the file CHANGES. - -Feedback --------- -The project home for cv2pdb is here: - - http://www.dsource.org/projects/cv2pdb - https://github.com/rainers/cv2pdb - -There's also a forum, where you can leave your comments and suggestions. - -Have fun, -Rainer Schuetze diff --git a/protocols/Tox/tools/TODO b/protocols/Tox/tools/TODO deleted file mode 100644 index 7cc2fff3c0..0000000000 --- a/protocols/Tox/tools/TODO +++ /dev/null @@ -1,28 +0,0 @@ - -This is the TODO file for cv2pdb, a -converter of DMD CodeView/DWARF debug information to PDB files - -Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved - -There are some quirks that you might run into when using -Visual Studio to debug D programs. These will hopefully be removed -in the future, but not all have a known solution. - -* has to use '@' instead of '.' in class names to avoid confusing debugger, - but it looks ugly -* "this.var" is not a valid debugger expression, you have to use - "var" or "this->var" -* global/static vars have to be watched with full module and class name - specified (e.g. module@globvar) -* type of associative arrays is displayed as aa<*> to allow overload - in autoexp.dat -* DMD does not emit different debug information for const and invariant, - type info is the same -* DMD does not emit different debug information for float and ifloat, - type info is the same -* type display of delegate does not have arguments -* assoc_array.length cannot be displayed (it is assoc_array.a->nodes) -* enum values not displayed -* watch incorrect if same variable name used in different parts of a function -* line number in templates sometimes off by 1 or 2 -* call to other function jumps to called function while pushing default arguments diff --git a/protocols/Tox/tools/VERSION b/protocols/Tox/tools/VERSION deleted file mode 100644 index 2b70a49ad0..0000000000 --- a/protocols/Tox/tools/VERSION +++ /dev/null @@ -1 +0,0 @@ -VERSION = 0.42 diff --git a/protocols/Tox/tools/cv2pdb.exe b/protocols/Tox/tools/cv2pdb.exe Binary files differdeleted file mode 100644 index f65cd291bc..0000000000 --- a/protocols/Tox/tools/cv2pdb.exe +++ /dev/null diff --git a/protocols/Twitter/src/main.cpp b/protocols/Twitter/src/main.cpp index c31101f22b..b806c042db 100644 --- a/protocols/Twitter/src/main.cpp +++ b/protocols/Twitter/src/main.cpp @@ -33,7 +33,6 @@ PLUGININFOEX pluginInfo = { PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
__DESCRIPTION,
__AUTHOR,
- __AUTHOREMAIL,
__COPYRIGHT,
__AUTHORWEB,
UNICODE_AWARE,
diff --git a/protocols/Twitter/src/utility.cpp b/protocols/Twitter/src/utility.cpp index 29c93ecf72..9a7aca80ae 100644 --- a/protocols/Twitter/src/utility.cpp +++ b/protocols/Twitter/src/utility.cpp @@ -23,7 +23,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. std::string b64encode(const std::string &s)
{
- return std::string(ptrA(mir_base64_encode((BYTE*)s.c_str(), (unsigned)s.length())));
+ return std::string(ptrA(mir_base64_encode(s.c_str(), s.length())));
}
std::string int2str(int32_t iVal)
diff --git a/protocols/Twitter/src/version.h b/protocols/Twitter/src/version.h index 7f9840db58..7dc8be558b 100644 --- a/protocols/Twitter/src/version.h +++ b/protocols/Twitter/src/version.h @@ -9,6 +9,5 @@ #define __FILENAME "Twitter.dll"
#define __DESCRIPTION "Twitter protocol support for Miranda NG."
#define __AUTHOR "dentist, omniwolf, Thief"
-#define __AUTHOREMAIL ""
#define __AUTHORWEB "https://miranda-ng.org/p/Twitter/"
#define __COPYRIGHT "© 2009-2010 dentist, 2010-2012 omniwolf and Thief"
diff --git a/protocols/VKontakte/src/main.cpp b/protocols/VKontakte/src/main.cpp index 60a765103f..19f0c50655 100644 --- a/protocols/VKontakte/src/main.cpp +++ b/protocols/VKontakte/src/main.cpp @@ -30,7 +30,6 @@ PLUGININFOEX pluginInfo = PLUGIN_MAKE_VERSION(__MAJOR_VERSION,__MINOR_VERSION,__RELEASE_NUM,__BUILD_NUM),
__DESCRIPTION,
__AUTHOR,
- __AUTHOREMAIL,
__COPYRIGHT,
__AUTHORWEB,
UNICODE_AWARE,
diff --git a/protocols/VKontakte/src/misc.cpp b/protocols/VKontakte/src/misc.cpp index 67c1ff428a..27a8a8a8a2 100644 --- a/protocols/VKontakte/src/misc.cpp +++ b/protocols/VKontakte/src/misc.cpp @@ -343,6 +343,9 @@ bool CVkProto::CheckJsonResult(AsyncHttpRequest *pReq, const JSONNode &jnNode) case VKERR_CANT_SEND_YOU_ON_BLACKLIST:
MsgPopup(TranslateT("Can't send messages to this user due to their privacy settings"), TranslateT("Error"), true);
break;
+ case VKERR_MESSAGE_IS_TOO_LONG:
+ MsgPopup(TranslateT("Message is too long"), TranslateT("Error"), true);
+ break;
case VKERR_COULD_NOT_SAVE_FILE:
case VKERR_INVALID_ALBUM_ID:
case VKERR_INVALID_SERVER:
@@ -1515,6 +1518,41 @@ void CVkProto::AddVkDeactivateEvent(MCONTACT hContact, CMStringW& wszType) db_event_add(hContact, &dbei);
}
+MEVENT CVkProto::GetMessageFromDb(MCONTACT hContact, const char *messageId, UINT ×tamp, CMStringW &msg)
+{
+ if (messageId == nullptr)
+ return 0;
+
+ size_t messageIdLength = mir_strlen(messageId);
+
+ for (MEVENT hDbEvent = db_event_last(hContact); hDbEvent; hDbEvent = db_event_prev(hContact, hDbEvent)) {
+ DBEVENTINFO dbei = {};
+ dbei.cbBlob = db_event_getBlobSize(hDbEvent);
+
+ if (dbei.cbBlob < messageIdLength)
+ continue;
+
+ mir_ptr<BYTE> blob((PBYTE)mir_alloc(dbei.cbBlob));
+ dbei.pBlob = blob;
+ db_event_get(hDbEvent, &dbei);
+
+ size_t cbLen = mir_strlen((char*)dbei.pBlob);
+ if ((dbei.eventType != EVENTTYPE_MESSAGE) || (cbLen + messageIdLength + 1 > dbei.cbBlob))
+ continue;
+
+ if (memcmp(&dbei.pBlob[cbLen + 1], messageId, messageIdLength) == 0) {
+ msg = ptrW(mir_utf8decodeW((char*)dbei.pBlob));
+ timestamp = dbei.timestamp;
+ return hDbEvent;
+ }
+
+ if (dbei.timestamp < timestamp)
+ break;
+ }
+
+ return 0;
+}
+
int CVkProto::DeleteContact(MCONTACT hContact)
{
setByte(hContact, "SilentDelete", 1);
diff --git a/protocols/VKontakte/src/version.h b/protocols/VKontakte/src/version.h index ec86aa73d0..9cbd3b1713 100644 --- a/protocols/VKontakte/src/version.h +++ b/protocols/VKontakte/src/version.h @@ -1,6 +1,6 @@ #define __MAJOR_VERSION 0
#define __MINOR_VERSION 1
-#define __RELEASE_NUM 3
+#define __RELEASE_NUM 4
#define __BUILD_NUM 0
#include <stdver.h>
@@ -9,6 +9,5 @@ #define __FILENAME "VKontakte.dll"
#define __DESCRIPTION "VKontakte protocol support for Miranda NG."
#define __AUTHOR "Miranda NG Team"
-#define __AUTHOREMAIL ""
#define __AUTHORWEB "https://miranda-ng.org/p/VKontakte/"
#define __COPYRIGHT "© 2013-17 Miranda NG Team"
diff --git a/protocols/VKontakte/src/vk.h b/protocols/VKontakte/src/vk.h index 148ffc5799..e4cbd127a6 100644 --- a/protocols/VKontakte/src/vk.h +++ b/protocols/VKontakte/src/vk.h @@ -25,6 +25,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #define VKPOLL_MSG_ADDFLAGS 2
#define VKPOLL_MSG_DELFLAGS 3
#define VKPOLL_MSG_ADDED 4
+#define VKPOLL_MSG_EDITED 5
#define VKPOLL_READ_ALL_IN 6
#define VKPOLL_READ_ALL_OUT 7
#define VKPOLL_USR_ONLINE 8
@@ -74,6 +75,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #define VKERR_CANT_SEND_USER_ON_BLACKLIST 900 // Can't send messages for users from blacklist
#define VKERR_CANT_SEND_USER_WITHOUT_DIALOGS 901 // Can't send messages for users without dialogs
#define VKERR_CANT_SEND_YOU_ON_BLACKLIST 902 // Can't send messages to this user due to their privacy settings
+#define VKERR_MESSAGE_IS_TOO_LONG 914 // Message is too long
+
// File upload custom error
#define VKERR_FILE_NOT_EXIST 10100 // File does not exist
#define VKERR_FTYPE_NOT_SUPPORTED 10101 // File type not supported
@@ -85,7 +88,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #define VK_USER_DEACTIVATE_ACTION 9321
-#define VK_API_VER "5.68"
+#define VK_API_VER "5.69"
#define VER_API CHAR_PARAM("v", VK_API_VER)
#define VK_FEED_USER 2147483647L
diff --git a/protocols/VKontakte/src/vk_messages.cpp b/protocols/VKontakte/src/vk_messages.cpp index 56d3b4edda..2c0bead07c 100644 --- a/protocols/VKontakte/src/vk_messages.cpp +++ b/protocols/VKontakte/src/vk_messages.cpp @@ -250,7 +250,7 @@ void CVkProto::OnReceiveMessages(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pRe UINT mid = jnMsg["id"].as_int();
CMStringW wszBody(jnMsg["body"].as_mstring());
- int datetime = jnMsg["date"].as_int();
+ UINT datetime = jnMsg["date"].as_int();
int isOut = jnMsg["out"].as_int();
int isRead = jnMsg["read_state"].as_int();
int uid = jnMsg["user_id"].as_int();
@@ -313,8 +313,21 @@ void CVkProto::OnReceiveMessages(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pRe else if (m_vkOptions.bUserForceInvisibleOnActivity && time(nullptr) - datetime < 60 * m_vkOptions.iInvisibleInterval)
SetInvisible(hContact);
+ bool bEdited = CheckMid(m_editedIds, mid);
+ if (bEdited) {
+ CMStringW wszOldMsg;
+ MEVENT hDbEvent = GetMessageFromDb(hContact, szMid, datetime, wszOldMsg);
+ if (hDbEvent) {
+ wszBody = SetBBCString(TranslateT("Edited message:\n"), m_vkOptions.BBCForAttachments(), vkbbcB) +
+ wszBody +
+ SetBBCString(TranslateT("\nOriginal message:\n"), m_vkOptions.BBCForAttachments(), vkbbcB) +
+ wszOldMsg;
+ db_event_delete(hContact, hDbEvent);
+ }
+ }
+
T2Utf pszBody(wszBody);
- recv.timestamp = m_vkOptions.bUseLocalTime ? time(nullptr) : datetime;
+ recv.timestamp = bEdited ? datetime : (m_vkOptions.bUseLocalTime ? time(nullptr) : datetime);
recv.szMessage = pszBody;
recv.lParam = isOut;
recv.pCustomData = szMid;
diff --git a/protocols/VKontakte/src/vk_pollserver.cpp b/protocols/VKontakte/src/vk_pollserver.cpp index 56a9d85715..af49875118 100644 --- a/protocols/VKontakte/src/vk_pollserver.cpp +++ b/protocols/VKontakte/src/vk_pollserver.cpp @@ -78,6 +78,7 @@ void CVkProto::PollUpdates(const JSONNode &jnUpdates) debugLogA("CVkProto::PollUpdates");
CMStringA mids;
int msgid, uid, flags, platform;
+ bool bNonEdited = true;
MCONTACT hContact;
for (auto it = jnUpdates.begin(); it != jnUpdates.end(); ++it) {
@@ -106,17 +107,25 @@ void CVkProto::PollUpdates(const JSONNode &jnUpdates) }
break;
+ case VKPOLL_MSG_EDITED:
+ bNonEdited = false;
+
case VKPOLL_MSG_ADDED: // new message
msgid = jnChild[1].as_int();
// skip outgoing messages sent from a client
flags = jnChild[2].as_int();
- if (flags & VKFLAG_MSGOUTBOX && !(flags & VKFLAG_MSGCHAT) && !m_vkOptions.bSendVKLinksAsAttachments && CheckMid(m_sendIds, msgid))
+ if (bNonEdited && (flags & VKFLAG_MSGOUTBOX && !(flags & VKFLAG_MSGCHAT) && !m_vkOptions.bSendVKLinksAsAttachments && CheckMid(m_sendIds, msgid)))
break;
if (!mids.IsEmpty())
mids.AppendChar(',');
mids.AppendFormat("%d", msgid);
+
+ if(!bNonEdited)
+ m_editedIds.insert((HANDLE)msgid);
+
+ bNonEdited = true;
break;
case VKPOLL_READ_ALL_OUT:
diff --git a/protocols/VKontakte/src/vk_proto.cpp b/protocols/VKontakte/src/vk_proto.cpp index 85b403de7a..1c60842c5a 100644 --- a/protocols/VKontakte/src/vk_proto.cpp +++ b/protocols/VKontakte/src/vk_proto.cpp @@ -36,6 +36,7 @@ CVkProto::CVkProto(const char *szModuleName, const wchar_t *pwszUserName) : PROTO<CVkProto>(szModuleName, pwszUserName),
m_arRequestsQueue(10, sttCompareAsyncHttpRequest),
m_sendIds(3, PtrKeySortT),
+ m_editedIds(1, PtrKeySortT),
m_incIds(3, PtrKeySortT),
m_cookies(5),
m_msgId(1),
diff --git a/protocols/VKontakte/src/vk_proto.h b/protocols/VKontakte/src/vk_proto.h index d1e00cdb6e..90f5f1ece3 100644 --- a/protocols/VKontakte/src/vk_proto.h +++ b/protocols/VKontakte/src/vk_proto.h @@ -212,6 +212,7 @@ private: LIST<void>
m_sendIds,
+ m_editedIds,
m_incIds;
OBJLIST<CVkChatInfo> m_chats;
@@ -358,6 +359,7 @@ private: void SetInvisible(MCONTACT hContact);
CMStringW RemoveBBC(CMStringW& wszSrc);
void AddVkDeactivateEvent(MCONTACT hContact, CMStringW & wszType);
+ MEVENT GetMessageFromDb(MCONTACT hContact, const char * messageId, UINT ×tamp, CMStringW &msg);
int DeleteContact(MCONTACT hContact);
void InitQueue();
void UninitQueue();
diff --git a/protocols/VKontakte/src/vk_struct.h b/protocols/VKontakte/src/vk_struct.h index b687018bcf..54a1f4b623 100644 --- a/protocols/VKontakte/src/vk_struct.h +++ b/protocols/VKontakte/src/vk_struct.h @@ -45,38 +45,8 @@ struct AsyncHttpRequest : public NETLIBHTTPREQUEST, public MZeroedObject bool bNeedsRestart, bIsMainConn;
};
-struct PARAM
-{
- LPCSTR szName;
- __forceinline PARAM(LPCSTR _name) : szName(_name)
- {}
-};
-
-struct INT_PARAM : public PARAM
-{
- long iValue;
- __forceinline INT_PARAM(LPCSTR _name, long _value) :
- PARAM(_name), iValue(_value)
- {}
-};
AsyncHttpRequest* operator<<(AsyncHttpRequest*, const INT_PARAM&);
-
-struct CHAR_PARAM : public PARAM
-{
- LPCSTR szValue;
- __forceinline CHAR_PARAM(LPCSTR _name, LPCSTR _value) :
- PARAM(_name), szValue(_value)
- {}
-};
AsyncHttpRequest* operator<<(AsyncHttpRequest*, const CHAR_PARAM&);
-
-struct WCHAR_PARAM : public PARAM
-{
- LPCWSTR wszValue;
- __forceinline WCHAR_PARAM(LPCSTR _name, LPCWSTR _value) :
- PARAM(_name), wszValue(_value)
- {}
-};
AsyncHttpRequest* operator<<(AsyncHttpRequest*, const WCHAR_PARAM&);
struct CVkFileUploadParam : public MZeroedObject {
|