pax_global_header00006660000000000000000000000064134643337260014525gustar00rootroot0000000000000052 comment=e73432bdfb36ec32bf89d400382f9b152153b9d3 yowsup-3.2.3/000077500000000000000000000000001346433372600131005ustar00rootroot00000000000000yowsup-3.2.3/.gitignore000066400000000000000000000000751346433372600150720ustar00rootroot00000000000000*.pyc *.class todo *.egg-info tp tests dist build .idea .tox yowsup-3.2.3/.travis.yml000066400000000000000000000012731346433372600152140ustar00rootroot00000000000000language: python python: '3.6' # command to install dependencies env: global: - LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so - SEGFAULT_SIGNALS=all matrix: - TOXENV=py27 - TOXENV=py33 - TOXENV=py34 - TOXENV=py35 - TOXENV=py36 - TOXENV=py37 before_install: - python --version - uname -a - lsb_release -a install: - pip install tox - virtualenv --version - easy_install --version - pip --version - tox --version # command to run tests script: - tox -v after_failure: - more .tox/log/* | cat - more .tox/*/log/* | cat before_cache: - rm -rf $HOME/.cache/pip/log cache: directories: - $HOME/.cache/pip branches: only: - master yowsup-3.2.3/CHANGELOG.md000066400000000000000000000256031346433372600147170ustar00rootroot00000000000000# Changelog The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project (kinda) adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [3.2.3] 2019-05-07 ### Changed - Fixed incoming message output format in cli demo ## [3.2.2] 2019-05-07 ### Changed - Updated python-axolotl to 0.2.2, fixes possible variable referenced before assignment error ## [3.2.1] 2019-05-07 ### Changed - Updated python-axolotl to 0.2.1 - Fixed encoding errors when communicating in group - Fixed messages not delivered to groups, showing a "Waiting for this message, this may take a while" - Fixed bug where getKeys for multiple jids would invoke the callback multiple times - Fixes in RequestUpload and media classes in preparation for media sending ### Added - More log output in AxolotlSendLayer ## [3.2.0] 2019-05-04 ### Changed - Set min protobuf version to fix an error - Use WhatsApp version set by env in noise layer - Fixed error when mcc,mnc and fdid were missing from config - Don't crash when received an unrecognized ib node - Don't crash when received an unrecognized media type and send receipt - Don't crash when received an unrecognized notification type and send receipt - Asyncore is now used as default ConnectionDispatcher - Received protobuf messages are now handled in upper layers rather than Axolotl ### Added - MediaCipher for encrypting and decrypting media files - "media" yowsup-cli action with encrypt and decrypt media commands - Receive Audio, Video, Image, Document, Contact, Location, GIF, URL message support - MediaSink demo, access by yowsup-cli demos --mediasink ### Removed - unused -w flag from yowsup-cli config ## [3.1.0] 2019-04-25 ### Changed - Network layer prevents createConnection if already connected - Fixed crash when config path does not exist - yowsup-cli will interpret -c as phone if load_path fails - Allow keypair in credentials to be bytes - Noise layer now uses credential's client_static_keypair if set, instead of loading it from stored config - Improved config type detection logic, refs #2664 - Fixed some python2-related problems (long-type phone numbers, missing list.clear() method), refs #2664 - Updated consonance to fix dissononce's machine.next and enforce cryptography>=0.25 - Fixed some demos not shutting down properly ### Added - Complete asyncore dispatcher implementation. - Support for decoding deflate compressed data, fixes #2671 - Specifying a connection dispatcher (asyncore/socket) using YowNetworkLayer.PROP_DISPATCHER - --layer-network-dispatcher to cli demos ### Removed - threading from socket dispatcher, connecting application should ensure the connection is not blocking, for example by triggering connect in a bg thread. ## [3.0.0] 2019-04-23 ### Changed - Changed default env to android - Updated whatsapp version in env to 2.19.51 - Updated logs formatting to be more compact - Changed storage dir on linux to ~/.config/yowsup - yowsup-cli -p is now used for preview requests rather than specifying phone number - Decoupled Axolotl management from Axolotl layer - Fixed Python3.7 support - Updated device details in Env to be of Samsung S9+ - Changed generated signed prekeys ids to be sequential - Fixed some notifications getting redundant acks - Fixed outgoing ack in a group now requiring participant to be specified ### Added - WhatsApp Protocol 2.1 support - Noise layer - Login using Consonance; a new dependency - New Registration parameters - Encryption of registration parameters - Auto saving of Config at registration - Log which endpoint we are connecting to - Support superadmin and multiple admins in group create notification - Better Config management and JSON config files support - AxolotlManager - Any Config property overriding in yowsup-cli - yowsup-cli config - yowsup-cli --log-dissononce - yowsup-cli --log-dissononce - Preview only registration and other http requests ### Removed - Optional axolotl/e2e enc enabling, it's now forced. - S40 env - Password from Config - Outdated http parameters in registration - TimeTools along with python-dateutil dependency. ## [2.5.7] - 2017-12-30 ### Changed - Changed Token - Fixed Python2 support - Fixed #1842: Bug in protocol_groups RemoveGroupsNotificationProtocolEntity ## [2.5.2] - 2017-03-23 ### Changed - Fixed xml-not-well-formed when data is sent from multiple threads simultaneously - Updated S40 Token ## [2.5.0] - 2016-05-22 ### Changed - Fixed python 2.6 support - Fixed block detection in exists request, initiated by code request - Fixed crash when node data is string - Updated s40 token to 2.16.7 - Fixed timestamp in authentication not being UTC - Fixed handling variant decrypt/encr fail scenarios ### Added - Allowing autotrust changed identities via an exposed layer property - Auto-reconnect on stream:error - WA1.6 support - Fully working group encryption support ## [2.4.103] - 2016-04-24 ### Changed - Updated token ## [2.4.102] - 2016-04-01 ### Added - Simpler env select using YowsupEnv.setEnv("env_name"), get using YowsupEnv.getCurrent() - yowsup-cli allows setting preferred env using -E/--env argument ## [2.4.98] - 2016-03-31 ### Changed - Minor README update ## [2.4.97] - 2016-03-31 ### Changed - pillow, axolotl and ffvideo as optional modules - Improved mimetypes detection in media sending - Fixed some group Iqs callbacks getting swallowed and never invoked - Fixed python3 compat in iq_statuses_result - Fixed asyncore initialization - Updated tokens and fixed registration - Skip encryption of group messages - Improved video sending support - Fixed URL to country codes in yowsup-cli help ### Added - New optional modules interface - New @EventCallback decoration to replace layer's onEvent method - echo and send clients now enable encryption by default - Can now send videos from cli demo - Added *BSD installation instructions ## [2.4.48] - 2015-12-14 ### Changed - Fixed bug that avoid some acks from being sent - Check fields in video message before parsing - Fixed image scaling in Palette mode - Fixed image preview - Fixed erroneous method in LiteAxolotlStore - Fixed YowParallelLayer returning layer instead of the layer's interface - Fixed login - Updated registration token - Updated android env data - Fixed Warning that demos are not using YowParallelLayer ### Added - Send read receipts for received messages in cli demo - Can now get status of users - new profile privacy options ## [2.4.0] - 2015-09-07 ### Changed - Updated S40 env to 2.12.96 - Fixed message forwarding - Don't panic on try send something when offline - Fixed interface not forwarding to upper layers unhandled protocolenties - Don't crash on UntrustedIdentityException, will silently ignore the message - E2E enc is now enabled by default, remove -m/--moxie switch ### Added - Support sending receipt for multiple messages - Layers can now expose an InterfaceLayer for outside interaction - YowNetworkLayer and Auth Layer now expose an InterfaceLayer - Allow setting props on stackbuilder, it passed them to the instantiated stack - Handle DuplicateMessageException - Added stack.send/receive - Opt-out E2E enc using -M/--unmoxie ### Removed - yowsup-cli's -m/--moxie switch ## [2.3.185] - 2015-08-01 ### Changed - Recover from possible no session/no prekey in a received message ### Added - Send/receive v2 enc messages ## [2.3.183] - 2015-07-27 ### Changed - Fixed audio send - improved cli demo usage display ### Added - random endpoints selection - Handle account ib - "/audio send" to cli demo - support for image caption in cli demo ## [2.3.167] - 2015-07-21 ### Changed - Updated to e16 serv - Fixed callbacks for group info iq - Use s40 env by default - Updated to s40 v2.12.189 - Fixed error in android env with python 2.6 - Deprecated --moxie - Fixed error when axolotl is not installed ### Added - Added contact sync notification - Optional arguments support in yowsup demo ### Removed - "av" from enc nodes ## [2.3.124] - 2015-07-06 ### Changed - Fixed forward in groups ## [2.3.123] - 2015-06-22 ### Changed - Some code clean ups - Fixed set status and set picture not triggering callbacks - Handle multiple items in receipt ### Added - Create an ack or a forwarded message directly from receipt message - Allow getting Id of set profile picture - Get contact's last seen time - Notifications for participants add,remove in a group - Receipts from participants in a group - Promote,demote participants and rest of groups version 2 support - New contacts sync demo - New groups commands: /group promote, /group demote - New contacts commands: /contact lastseen ## [2.3.84] - 2015-05-26 ### Changed - Updated s40 tokens - Updated android token - Fixed receive presence - Fixed ack errors - Propagate StreamFeaturesProtocolEntity to upper layers - Fixes to incoming receipt - Don't stream error on web notifications - Fixed keys_get in cli demo - Fixed invite to group in cli demo ### Added - Allowing to specify ping interval - Connect behind http proxy support - Audio and video receive support - Get contact's profile picture - Handle calls - Group info v2 - Kick from group in cli demo ## [2.2.78] - 2015-02-17 ### Changed - Fixed problem reading identity which caused reg error - Keep connection alive through periodic pinging - Fixed compatibility with the whole python 2.6-3.4 spectrum - Distinguish received delivered and read receipt - Fixed leave groups - Fixes to registration - Updated S40 registration token - Fixed groups jid handling in sendclient - Fixed readline redundant dependency in linux ### Added - StackBuilder to make stack construction easier - Profile Layer - participants to a group - Save next challenge and use in next auth - Get contact profile picture - group_invite in cli demo to add participants to a group - leave_group in cli demo ## [2.2.15] - 2015-01-12 ### Changed - As of January 2015, Yowsup is GPLv3 licensed (previouly was MIT) - Fixed broadcast - Fixed registration no_routes error - Updated registration token ### Added - Experimental Axolotl support (end-to-end encryption) - Upload and send images - Initial support for groups v2 - Easy switch/ add new enviornment (S40/Android ..etc) - _sendIq in YowProtocolLayer and YowInterfaceLayer with callbacks for Iq result and error - new send and exit demo - E2E encryption in yowsup and echo client demos - image_send to yowsup demo ## [2.0.53] - 2014-12-15 ### Changed - Upgraded to WA 1.5 - Fixed previews in images - Write date to socket as they come - Fixed readline/pyreadline dependency problem ### Added - Add chatstate support (typing/ paused) - support for send/recv location - support for send/recv vcards - potential fix for not receiving registration sms - Pass pongs to upper layers - Ack notifications - Parallels layers now get events sent by siblings - Broadcast event on login - send typing/paused state to cli demo - Echo demo now echoes images - Echo demo now echoes vcards ## [2.0.1] - 2014-12-01 ### Changed - Minor bug fixes ## [2.0] - 2014-11-28 yowsup 2.0 initial release yowsup-3.2.3/LICENSE000066400000000000000000001044621346433372600141140ustar00rootroot00000000000000GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. 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 . 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: {project} Copyright (C) {year} {fullname} 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 . 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 . yowsup-3.2.3/MANIFEST.in000066400000000000000000000000411346433372600146310ustar00rootroot00000000000000include yowsup/common/mime.types yowsup-3.2.3/README.md000066400000000000000000000056451346433372600143710ustar00rootroot00000000000000# yowsup [![Build Status](https://travis-ci.org/tgalal/yowsup.svg?branch=master)](https://travis-ci.org/tgalal/yowsup) yowsup is a python library that enables building applications that can communicate with WhatsApp users. The project started as the protocol engine behind [Wazapp for Meego](https://wiki.maemo.org/Wazapp) and [OpenWA for BB10](https://www.lowyat.net/2013/5896/try-this-openwhatsapp-for-blackberry-10/). Now as a standalone library it can be used to power any custom WhatsApp client. ``` updated: 2019-05-07 yowsup version: 3.2.3 yowsup-cli version: 3.2.0 requires: - python>=2.7,<=3.7 - consonance==0.1.2 - python-axolotl==0.2.2 - protobuf>=3.6.0 - six==1.10 uses: - argparse [yowsup-cli] - readline [yowsup-cli] - pillow [send images] - tqdm [mediasink demo] - requests [mediasink demo] ``` ## See also During maintenance of yowsup, several projects have been spawned out in order to support different features that get introduced by WhatsApp. Some of those features are not necessarily exclusive to WhatsApp and therefore it only made sense to maintain some parts as standalone projects: - [python-axolotl](https://github.com/tgalal/python-axolotl): Python port of [libsignal-protocol-java](https://github.com/signalapp/libsignal-protocol-java), providing E2E encryption - [consonance](https://github.com/tgalal/consonance/): WhatsApp's handshake implementation using Noise Protocol - [dissononce](https://github.com/tgalal/dissononce): A python implementation for [Noise Protocol Framework](https://noiseprotocol.org/) ## Quickstart * **[Installation](#installation)** * **[yowsup's architecture](https://github.com/tgalal/yowsup/wiki/Architecture)** * **[Create a sample app](https://github.com/tgalal/yowsup/wiki/Sample-Application)** * **[yowsup-cli](https://github.com/tgalal/yowsup/wiki/yowsup-cli)** ## Installation Install using setup.py to pull all Python dependencies, or pip: ``` pip install yowsup ``` ### Linux You need to have installed Python headers (probably from python-dev package) and ncurses-dev, then run ``` python setup.py install ``` ### FreeBSD (*BSD) You need to have installed: py27-pip-7.1.2(+), py27-sqlite3-2.7.11_7(+), then run ``` pip install yowsup ``` ### Mac OS ``` python setup.py install ``` Administrators privileges might be required, if so then run with 'sudo' ### Windows - Install [mingw](http://www.mingw.org/) compiler - Add mingw to your PATH - In PYTHONPATH\Lib\distutils create a file called distutils.cfg and add these lines: ``` [build] compiler=mingw32 ``` - Install gcc: ```mingw-get.exe install gcc``` - Install [zlib](http://www.zlib.net/) - ```python setup.py install``` # License: As of January 1, 2015 yowsup is licensed under the GPLv3+: http://www.gnu.org/licenses/gpl-3.0.html. yowsup-3.2.3/setup.py000077500000000000000000000030071346433372600146150ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function from setuptools import setup, find_packages import yowsup import platform import sys deps = ['consonance==0.1.2', 'argparse', 'python-axolotl==0.2.2', 'six==1.10', 'appdirs', 'protobuf>=3.6.0'] if sys.version_info < (2, 7): deps.append('importlib') if platform.system().lower() == "windows": deps.append('pyreadline') else: try: import readline except ImportError: deps.append('readline') setup( name='yowsup', version=yowsup.__version__, url='http://github.com/tgalal/yowsup/', license='GPL-3+', author='Tarek Galal', tests_require=[], install_requires = deps, scripts = ['yowsup-cli'], #cmdclass={'test': PyTest}, author_email='tare2.galal@gmail.com', description='The WhatsApp lib', #long_description=long_description, packages= find_packages(), include_package_data=True, data_files = [('yowsup/common', ['yowsup/common/mime.types'])], platforms='any', #test_suite='', classifiers = [ 'Programming Language :: Python', 'Development Status :: 4 - Beta', 'Natural Language :: English', #'Environment :: Web Environment', 'Intended Audience :: Developers', 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)', 'Operating System :: OS Independent', 'Topic :: Software Development :: Libraries :: Python Modules' ], #extras_require={ # 'testing': ['pytest'], #} ) yowsup-3.2.3/tox.ini000066400000000000000000000010141346433372600144070ustar00rootroot00000000000000# Tox (http://tox.testrun.org/) is a tool for running tests # in multiple virtualenvs. This configuration file will run the # test suite on all supported python versions. To use it, "pip install tox" # and then run "tox" from this directory. [tox] skip_missing_interpreters = true envlist = py27, py32, py33, py34, py35, py36, py37 [testenv] commands = nosetests --exclude demos yowsup deps = py26: importlib nose python-dateutil appdirs python-axolotl==0.2.2 protobuf>=3.6.0 consonance==0.1.2 yowsup-3.2.3/yowsup-cli000077500000000000000000000651061346433372600151510ustar00rootroot00000000000000#!/usr/bin/env python __version__ = "3.2.0" __author__ = "Tarek Galal" from yowsup.env import YowsupEnv from yowsup.config.manager import ConfigManager from yowsup.config.v1.config import Config from yowsup import logger as yowlogger, formatter from yowsup.layers.network.layer import YowNetworkLayer from yowsup.layers.protocol_media.mediacipher import MediaCipher from consonance.structs.publickey import PublicKey from consonance.structs.keypair import KeyPair import sys, argparse, yowsup, logging import base64 HELP_CONFIG = """ ############# Yowsup Configuration Sample ########### # # ==================== # The file contains info about your WhatsApp account. This is used during registration and login. # You can define or override all fields in the command line args as well. # # Country code. See http://www.ipipi.com/help/telephone-country-codes.htm. This is now required. cc=49 # # Your full phone number including the country code you defined in 'cc', without preceding '+' or '00' phone=491234567890 # # Your pushname, this name is displayed to users when they're notified with your messages. pushname=yowsup # # This keypair is generated during registration. client_static_keypair=YJa8Vd9pG0KV2tDYi5V+DMOtSvCEFzRGCzOlGZkvBHzJvBE5C3oC2Fruniw0GBGo7HHgR4TjvjI3C9AihStsVg==" ####################################################### For the full list of configuration options run "yowsup-cli config -h" """ CR_TEXT = """yowsup-cli v{cliVersion} yowsup v{yowsupVersion} Copyright (c) 2012-2019 Tarek Galal http://www.openwhatsapp.org This software is provided free of charge. Copying and redistribution is encouraged. If you appreciate this software and you would like to support future development please consider donating: http://openwhatsapp.org/yowsup/donate """ logger = logging.getLogger('yowsup-cli') ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) # add formatter to ch ch.setFormatter(formatter) # add ch to logger logger.addHandler(ch) class YowArgParser(argparse.ArgumentParser): def __init__(self, *args, **kwargs): if "no_config" in kwargs: self._no_config = kwargs["no_config"] is True del kwargs["no_config"] else: self._no_config = False super(YowArgParser, self).__init__(*args, **kwargs) self._config_manager = ConfigManager() if not self._no_config else None self.add_argument("-v", "--version", action="store_true", help="Print version info and exit" ) self.add_argument("-d", "--debug", action="store_true", help="Show debug messages" ) self.add_argument("-E", "--env", action="store", help="Set the environment yowsup simulates", choices=YowsupEnv.getRegisteredEnvs() ) self.add_argument("--help-config", help="Prints a config file sample", action="store_true") if not self._no_config: config_group = self.add_argument_group( "Configuration options", description="Only some of the configuration parameters are required depending on the action being " "performed using yowsup" ) config_group.add_argument( "-c", '--config', metavar="path", action="store", help="(optional) Path to config file. Other configuration arguments have higher priority if given, and " "will override those specified in the config file." ) config_group.add_argument( '--config-phone', '--phone', action="store", help="Your full phone number including the country code you defined in 'cc'," " without preceeding '+' or '00'" ) config_group.add_argument( '--config-cc', '--cc', action="store", help="Country code. See http://www.ipipi.com/networkList.do." ) config_group.add_argument( '--config-pushname', action="store", help="Push/Display name to use " ) config_group.add_argument( '--config-id', action="store", help="Base64 encoded Identity/Recovery token, typically generated and used during registration or account " "recovery." ) config_group.add_argument( '--config-mcc', '--mcc', action="store", help="Mobile Country Code. Check your mcc here: https://en.wikipedia.org/wiki/Mobile_country_code" ) config_group.add_argument( '--config-mnc', '--mnc', action="store", help="Mobile Network Code. Check your mnc from https://en.wikipedia.org/wiki/Mobile_country_code" ) config_group.add_argument( '--config-sim_mcc', action="store", help="Mobile Country Code. Check your mcc here: https://en.wikipedia.org/wiki/Mobile_country_code" ) config_group.add_argument( '--config-sim_mnc', action="store", help="Mobile Network Code. Check your mnc from https://en.wikipedia.org/wiki/Mobile_country_code" ) config_group.add_argument( '--config-client_static_keypair', action="store", help="Base64 encoded concatenation of user keypair's private bytes and public bytes" ) config_group.add_argument( '--config-server_static_public', action="store", help="Base64 encoded server's public key bytes" ) config_group.add_argument( '--config-expid', action="store", help="Base64 encoded expid, typically generated and used during registration" ) config_group.add_argument( '--config-fdid', action="store", help="Device UUID, typically generated for registration and used at login" ) config_group.add_argument( '--config-edge_routing_info', action="store", help="Base64 encoded edge_routing_info, normally received and persisted right after a successful login" ) config_group.add_argument( '--config-chat_dns_domain', action="store", help="Chat DNS domain, normally received and persisted right after a successful login" ) self.args = {} self._config = None # type: Config def getArgs(self): return self.parse_args() def process(self): self.args = vars(self.parse_args()) if self.args["debug"]: logger.setLevel(logging.DEBUG) yowlogger.setLevel(level=logging.DEBUG) else: logger.setLevel(logging.INFO) yowlogger.setLevel(level=logging.INFO) if self.args["env"]: YowsupEnv.setEnv(self.args["env"]) if not self._no_config: config_phone = self.args["config_phone"] if self.args["config"]: self._config = self._config_manager.load_path(self.args["config"]) if self._config is None: self._config = self._config_manager.load(self.args["config"]) elif config_phone: self._config = self._config_manager.load(config_phone) else: raise ValueError("Must specify either --config or --config-phone") if self._config is None: self._config = Config() if config_phone is not None: self._config.phone = config_phone if self.args["config_cc"]: self._config.cc = self.args["config_cc"] if self.args["config_pushname"]: self._config.pushname = self.args["config_pushname"] if self.args["config_id"]: self._config.id = base64.b64decode(self.args["config_id"]) if self.args["config_mcc"]: self._config.mcc = self.args["config_mcc"] if self.args["config_mnc"]: self._config.mnc = self.args["config_mnc"] if self.args["config_sim_mcc"]: self._config.sim_mcc = self.args["config_sim_mcc"] if self.args["config_sim_mnc"]: self._config.sim_mnc = self.args["config_sim_mnc"] if self.args["config_client_static_keypair"]: self._config.client_static_keypair = KeyPair.from_bytes( base64.b64decode(self.args["config_client_static_keypair"]) ) if self.args["config_server_static_public"]: self._config.server_static_public = PublicKey( base64.b64decode(self.args["config_server_static_public"]) ) if self.args["config_expid"]: self._config.expid = base64.b64decode(self.args["config_expid"]) if self.args["config_fdid"]: self._config.fdid = self.args["config_fdid"] if self.args["config_edge_routing_info"]: self._config.edge_routing_info = base64.b64decode(self.args["config_edge_routing_info"]) if self.args["config_chat_dns_domain"]: self._config.chat_dns_domain = self.args["config_chat_dns_domain"] if self.args["config"]: # config file was explicitly specified, load internal config and override values internal_config = self._config_manager.load(self._config.phone) if internal_config is not None: for property in self._config.keys(): if property != "version" and self._config[property] is not None: internal_config[property] = self._config[property] self._config = internal_config if self.args["version"]: print("yowsup-cli v%s\nUsing yowsup v%s" % (__version__, yowsup.__version__)) sys.exit(0) if self.args["help_config"]: print(HELP_CONFIG) sys.exit(0) def printInfoText(self): print(CR_TEXT.format(cliVersion=__version__, yowsupVersion=yowsup.__version__)) class ConfigArgParser(YowArgParser): def __init__(self, *args, **kwargs): super(ConfigArgParser, self).__init__(*args, **kwargs) self.description = "Yowsup configuration actions" gp = self.add_argument_group("Yowsup Config Actions") exgp = gp.add_mutually_exclusive_group() exgp.add_argument("-p", '--preview-config', help='Preview yowsup config', action="store", choices=("json", "keyval"), required=False) def process(self): super(ConfigArgParser, self).process() preview_format = self.args["preview_config"] if preview_format == "json": print(self._config_manager.config_to_str(self._config, ConfigManager.TYPE_JSON)) elif preview_format == "keyval": print(self._config_manager.config_to_str(self._config, ConfigManager.TYPE_KEYVAL)) elif preview_format == None: pass return True class RegistrationArgParser(YowArgParser): def __init__(self, *args, **kwargs): super(RegistrationArgParser, self).__init__(*args, **kwargs) self.description = "WhatsApp Registration options" self.add_argument('--no-encrypt', action="store_true", help="Don't encrypt request parameters before sending") self.add_argument('-p', '--preview', action="store_true", help="Preview requests only, will not attempt to connect and send") regSteps = self.add_argument_group("Modes") regSteps = regSteps.add_mutually_exclusive_group() regSteps.add_argument("-r", '--requestcode', help='Request the digit registration code from Whatsapp.', action="store", required=False, metavar="(sms|voice)") regSteps.add_argument("-R", '--register', help='Register account on Whatsapp using the code you previously received', action="store", required=False, metavar="code") self._encrypt = True self._preview = False def process(self): super(RegistrationArgParser, self).process() config = self._config self._encrypt = not self.args["no_encrypt"] self._preview = self.args["preview"] if not "mcc" in config: config["mcc"] = "000" if not "mnc" in config: config["mnc"] = "000" if not "sim_mcc" in config: config["sim_mcc"] = "000" if not "sim_mnc" in config: config["sim_mnc"] = "000" try: assert self.args["requestcode"] or self.args["register"], "Must specify one of the modes -r/-R" assert "cc" in config, "Must set --config-cc (country code)" assert "phone" in config, "Must set --config-phone" except AssertionError as e: print(e) print("\n") return False if not str(config.phone).startswith(str(config.cc)): print("Error, phone number does not start with the specified country code\n") return False if self.args["requestcode"]: self.handleRequestCode(self.args["requestcode"], config) elif self.args["register"]: self.handleRegister(self.args["register"], config) else: return False return True def handleRequestCode(self, method, config): from yowsup.registration import WACodeRequest self.printInfoText() codeReq = WACodeRequest(method, config) result = codeReq.send(encrypt=self._encrypt, preview=self._preview) if not self._preview: if result["status"] in ("sent", "ok"): if "edge_routing_info" in result: self._config.edge_routing_info = base64.b64decode(result["edge_routing_info"]) if "chat_dns_domain" in result: self._config.chat_dns_domain = result["chat_dns_domain"] self._config_manager.save(self._config) print(self.resultToString(result)) else: print(config) def handleRegister(self, code, config): from yowsup.registration import WARegRequest self.printInfoText() code = code.replace('-', '') req = WARegRequest(config, code) result = req.send(preview=self._preview) print(config) if not self._preview: if result["status"] == "ok": if "edge_routing_info" in result: self._config.edge_routing_info = base64.b64decode(result["edge_routing_info"]) if "chat_dns_domain" in result: self._config.chat_dns_domain = result["chat_dns_domain"] self._config_manager.save(self._config) print(self.resultToString(result)) def resultToString(self, result): unistr = str if sys.version_info >= (3, 0) else unicode out = [] for k, v in result.items(): if v is None: continue out.append("%s: %s" % (k, v.encode("utf-8") if type(v) is unistr else v)) return "\n".join(out) class MediaToolsArgParser(YowArgParser): MEDIA_INFO = { "image": MediaCipher.INFO_IMAGE, "video": MediaCipher.INFO_VIDEO, "gif": MediaCipher.INFO_VIDEO, "document": MediaCipher.INFO_DOCUM, "doc": MediaCipher.INFO_DOCUM } def __init__(self, *args, **kwargs): kwargs["no_config"] = True super(MediaToolsArgParser, self).__init__(*args, **kwargs) self.description = "Yowsup tools" gp = self.add_argument_group("Media Tools") gp.add_argument( '--media-type', choices=('image', 'video', 'gif', 'document', 'doc'), required=True ) exgp = gp.add_mutually_exclusive_group() exgp.add_argument( '--encrypt', nargs=3, metavar=('path', 'b64key', 'output'), help='Encrypt a media file. Example: yowsup-cli media --media-type image --encrypt /path/to/media.enc ' 'AAAA /path/to/out', action="store", required=False ) exgp.add_argument( '--encrypt2', metavar='b64key', help='Encrypt a media file using stdin and stdout for input and output. Example:\nyowsup-cli media ' '--media-type image --encrypt2 AAAA < /path/to/media.enc > /path/to/out', action="store", required=False ) exgp.add_argument( '--decrypt', nargs=3, metavar=('path', 'b64key', 'output'), help='Decrypt a media file. Example: yowsup-cli media --media-type image --decrypt /path/to/media.enc ' 'AAAA /path/to/out', action="store", required=False ) exgp.add_argument( '--decrypt2', metavar='b64key', help='Decrypt a media file using stdin and stdout for input and output. Example:\nyowsup-cli media ' '--media-type image --decrypt2 AAAA < /path/to/media.enc > /path/to/out', action="store", required=False ) def _decrypt_media(self, media_type, b64key, fin, fout): decrypted = MediaCipher().decrypt( fin.read(), base64.b64decode(b64key), self.MEDIA_INFO[media_type] ) fout.write(decrypted) def _encrypt_media(self, media_type, b64key, fin, fout): encrypted = MediaCipher().encrypt( fin.read(), base64.b64decode(b64key), self.MEDIA_INFO[media_type] ) fout.write(encrypted) def process(self): super(MediaToolsArgParser, self).process() if self.args["decrypt"]: path, key, output = self.args["decrypt"] with open(path, 'rb') as input_media: with open(output, 'wb') as output_media: self._decrypt_media(self.args["media_type"], key, input_media, output_media) elif self.args["decrypt2"]: fin, fout = sys.stdin, sys.stdout if sys.version_info >= (3, 0): fin, fout = fin.buffer, fout.buffer self._decrypt_media(self.args["media_type"], self.args["decrypt2"], fin, fout) elif self.args["encrypt"]: path, key, output = self.args["encrypt"] with open(path, 'rb') as input_media: with open(output, 'wb') as output_media: self._encrypt_media(self.args["media_type"], key, input_media, output_media) elif self.args["encrypt2"]: fin, fout = sys.stdin, sys.stdout if sys.version_info >= (3, 0): fin, fout = fin.buffer, fout.buffer self._encrypt_media(self.args["media_type"], self.args["encrypt2"], fin, fout) return True class DemosArgParser(YowArgParser): LAYER_NETWORK_DISPATCHERS_MAP = { "socket": YowNetworkLayer.DISPATCHER_SOCKET, "asyncore": YowNetworkLayer.DISPATCHER_ASYNCORE } def __init__(self, *args, **kwargs): super(DemosArgParser, self).__init__(*args, **kwargs) self.description = "Run a yowsup demo" net_layer_opts = self.add_argument_group("Network layer props") net_layer_opts.add_argument( '--layer-network-dispatcher', action="store", choices=("asyncore", "socket"), help="Specify which connection dispatcher to use" ) cmdopts = self.add_argument_group("Command line interface demo") cmdopts.add_argument('-y', '--yowsup', action="store_true", help="Start the Yowsup command line client") echoOpts = self.add_argument_group("Echo client demo") echoOpts.add_argument('-e', '--echo', action="store_true", help="Start the Yowsup Echo client") sendOpts = self.add_argument_group("Send client demo") sendOpts.add_argument('-s', '--send', action="store", help="Send a message to specified phone number, " "wait for server receipt and exit", metavar=("phone", "message"), nargs=2) syncContacts = self.add_argument_group("Sync contacts") syncContacts.add_argument('-S', '--sync', action="store", help="Sync ( check valid ) whatsapp contacts", metavar=("contacts")) mediasinkOpts = self.add_argument_group("Media sink demo") mediasinkOpts.add_argument('-m', '--mediasink', action="store_true", help="Start the Media Sink client") mediasinkOpts.add_argument('--media-store-dir', action="store", required=False, help="Specify where to download incoming media files, if not set " "will download to a temporary directory.") logging = self.add_argument_group("Logging options") logging.add_argument("--log-dissononce", action="store_true", help="Configure logging for dissononce/noise") logging.add_argument("--log-consonance", action="store_true", help="Configure logging for consonance") self._layer_network_dispatcher = None def process(self): super(DemosArgParser, self).process() if self.args["log_dissononce"]: from dissononce import logger as dissononce_logger, ch as dissononce_ch dissononce_logger.setLevel(logger.level) dissononce_ch.setFormatter(formatter) if self.args["log_consonance"]: from consonance import logger as consonance_logger, ch as consonance_ch consonance_logger.setLevel(logger.level) consonance_ch.setFormatter(formatter) if self.args["layer_network_dispatcher"] is not None: self._layer_network_dispatcher = self.LAYER_NETWORK_DISPATCHERS_MAP[ self.args["layer_network_dispatcher"] ] if self.args["yowsup"]: self.startCmdline() elif self.args["echo"]: self.startEcho() elif self.args["send"]: self.startSendClient() elif self.args["sync"]: self.startSyncContacts() elif self.args["mediasink"]: self.startMediaSink(self.args["media_store_dir"]) else: return False return True def startCmdline(self): logger.debug("starting cmd") from yowsup.demos import cli credentials = self._config.phone, self._config.client_static_keypair if not credentials: print("Error: You must specify a configuration method") sys.exit(1) self.printInfoText() stack = cli.YowsupCliStack(credentials) if self._layer_network_dispatcher is not None: stack.set_prop(YowNetworkLayer.PROP_DISPATCHER, self._layer_network_dispatcher) stack.start() def startEcho(self): from yowsup.demos import echoclient credentials = self._config.phone, self._config.client_static_keypair if not credentials: print("Error: You must specify a configuration method") sys.exit(1) try: self.printInfoText() stack = echoclient.YowsupEchoStack(credentials) if self._layer_network_dispatcher is not None: stack.set_prop(YowNetworkLayer.PROP_DISPATCHER, self._layer_network_dispatcher) stack.start() except KeyboardInterrupt: print("\nYowsdown") sys.exit(0) def startSendClient(self): from yowsup.demos import sendclient credentials = self._config.phone, self._config.client_static_keypair if not credentials: print("Error: You must specify a configuration method") sys.exit(1) try: self.printInfoText() stack = sendclient.YowsupSendStack(credentials, [([self.args["send"][0], self.args["send"][1]])]) if self._layer_network_dispatcher is not None: stack.set_prop(YowNetworkLayer.PROP_DISPATCHER, self._layer_network_dispatcher) stack.start() except KeyboardInterrupt: print("\nYowsdown") sys.exit(0) def startSyncContacts(self): from yowsup.demos import contacts credentials = self._config.phone, self._config.client_static_keypair if not credentials: print("Error: You must specify a configuration method") sys.exit(1) try: self.printInfoText() stack = contacts.YowsupSyncStack(credentials, self.args["sync"].split(',')) if self._layer_network_dispatcher is not None: stack.set_prop(YowNetworkLayer.PROP_DISPATCHER, self._layer_network_dispatcher) stack.start() except KeyboardInterrupt: print("\nYowsdown") sys.exit(0) def startMediaSink(self, storage_dir): from yowsup.demos import mediasink credentials = self._config.phone, self._config.client_static_keypair if not credentials: print("Error: You must specify a configuration method") sys.exit(1) self.printInfoText() stack = mediasink.MediaSinkStack(credentials, storage_dir) if self._layer_network_dispatcher is not None: stack.set_prop(YowNetworkLayer.PROP_DISPATCHER, self._layer_network_dispatcher) try: stack.start() except KeyboardInterrupt: print("\nYowsdown") sys.exit(0) if __name__ == "__main__": args = sys.argv if (len(args) > 1): del args[0] modeDict = { "demos": DemosArgParser, "registration": RegistrationArgParser, "config": ConfigArgParser, "media": MediaToolsArgParser, "version": None } if (len(args) == 0 or args[0] not in modeDict): print("Available commands:\n===================") print(", ".join(modeDict.keys())) sys.exit(1) mode = args[0] if mode == "version": print("yowsup-cli v%s\nUsing yowsup v%s" % (__version__, yowsup.__version__)) sys.exit(0) else: parser = modeDict[mode]() if not parser.process(): parser.print_help() yowsup-3.2.3/yowsup/000077500000000000000000000000001346433372600144465ustar00rootroot00000000000000yowsup-3.2.3/yowsup/__init__.py000066400000000000000000000006251346433372600165620ustar00rootroot00000000000000import logging __version__ = "3.2.3" __author__ = "Tarek Galal" logger = logging.getLogger(__name__) # create console handler and set level to debug ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) # create formatter formatter = logging.Formatter('%(levelname).1s %(asctime)s %(name)s - %(message)s') # add formatter to ch ch.setFormatter(formatter) # add ch to logger logger.addHandler(ch) yowsup-3.2.3/yowsup/axolotl/000077500000000000000000000000001346433372600161305ustar00rootroot00000000000000yowsup-3.2.3/yowsup/axolotl/__init__.py000066400000000000000000000000651346433372600202420ustar00rootroot00000000000000import logging logger = logging.getLogger(__name__) yowsup-3.2.3/yowsup/axolotl/exceptions.py000066400000000000000000000007671346433372600206750ustar00rootroot00000000000000class NoSessionException(Exception): pass class UntrustedIdentityException(Exception): def __init__(self, name, identity_key): self._name = name self._identity_key = identity_key @property def name(self): return self._name @property def identity_key(self): return self._identity_key class InvalidMessageException(Exception): pass class InvalidKeyIdException(Exception): pass class DuplicateMessageException(Exception): pass yowsup-3.2.3/yowsup/axolotl/factory.py000066400000000000000000000010241346433372600201460ustar00rootroot00000000000000from yowsup.axolotl.manager import AxolotlManager from yowsup.common.tools import StorageTools from yowsup.axolotl.store.sqlite.liteaxolotlstore import LiteAxolotlStore import logging logger = logging.getLogger(__name__) class AxolotlManagerFactory(object): DB = "axolotl.db" def get_manager(self, username): logger.debug("get_manager(username=%s)" % username) dbpath = StorageTools.constructPath(username, self.DB) store = LiteAxolotlStore(dbpath) return AxolotlManager(store, username) yowsup-3.2.3/yowsup/axolotl/manager.py000066400000000000000000000267171346433372600201310ustar00rootroot00000000000000from axolotl.util.keyhelper import KeyHelper from axolotl.identitykeypair import IdentityKeyPair from axolotl.groups.senderkeyname import SenderKeyName from axolotl.axolotladdress import AxolotlAddress from axolotl.sessioncipher import SessionCipher from axolotl.groups.groupcipher import GroupCipher from axolotl.groups.groupsessionbuilder import GroupSessionBuilder from axolotl.sessionbuilder import SessionBuilder from axolotl.protocol.prekeywhispermessage import PreKeyWhisperMessage from axolotl.protocol.whispermessage import WhisperMessage from axolotl.state.prekeybundle import PreKeyBundle from axolotl.untrustedidentityexception import UntrustedIdentityException from axolotl.invalidmessageexception import InvalidMessageException from axolotl.duplicatemessagexception import DuplicateMessageException from axolotl.invalidkeyidexception import InvalidKeyIdException from axolotl.nosessionexception import NoSessionException from axolotl.protocol.senderkeydistributionmessage import SenderKeyDistributionMessage from axolotl.state.axolotlstore import AxolotlStore from yowsup.axolotl.store.sqlite.liteaxolotlstore import LiteAxolotlStore from yowsup.axolotl import exceptions import random import logging import sys logger = logging.getLogger(__name__) class AxolotlManager(object): COUNT_GEN_PREKEYS = 812 THRESHOLD_REGEN = 10 MAX_SIGNED_PREKEY_ID = 16777215 def __init__(self, store, username): """ :param store: :type store: AxolotlStore :param username: :type username: str """ self._username = username # type: str self._store = store # type: LiteAxolotlStore self._identity = self._store.getIdentityKeyPair() # type: IdentityKeyPair self._registration_id = self._store.getLocalRegistrationId() # type: int | None assert self._registration_id is not None assert self._identity is not None self._group_session_builder = GroupSessionBuilder(self._store) # type: GroupSessionBuilder self._session_ciphers = {} # type: dict[str, SessionCipher] self._group_ciphers = {} # type: dict[str, GroupCipher] logger.debug("Initialized AxolotlManager [username=%s, db=%s]" % (self._username, store)) @property def registration_id(self): return self._registration_id @property def identity(self): return self._identity def level_prekeys(self, force=False): logger.debug("level_prekeys(force=%s)" % force) pending_prekeys = self._store.loadPreKeys() logger.debug("len(pending_prekeys) = %d" % len(pending_prekeys)) if force or len(pending_prekeys) < self.THRESHOLD_REGEN: count_gen = self.COUNT_GEN_PREKEYS - len(pending_prekeys) logger.info("Generating %d prekeys" % count_gen) ## arbitrary, should keep track of generated prekey ids and create from there prekeys = KeyHelper.generatePreKeys(KeyHelper.getRandomSequence(2**32 // 2), count_gen) logger.info("Storing %d prekeys" % len(prekeys)) for i in range(0, len(prekeys)): key = prekeys[i] if logger.level <= logging.DEBUG: sys.stdout.write("Storing prekey %d/%d \r" % (i + 1, len(prekeys))) sys.stdout.flush() self._store.storePreKey(key.getId(), key) return prekeys return [] def load_unsent_prekeys(self): logger.debug("load_unsent_prekeys") unsent = self._store.preKeyStore.loadUnsentPendingPreKeys() if len(unsent) > 0: logger.info("Loaded %d unsent prekeys" % len(unsent)) return unsent def set_prekeys_as_sent(self, prekeyIds): """ :param prekeyIds: :type prekeyIds: list :return: :rtype: """ logger.debug("set_prekeys_as_sent(prekeyIds=[%d prekeyIds])" % len(prekeyIds)) self._store.preKeyStore.setAsSent([prekey.getId() for prekey in prekeyIds]) def generate_signed_prekey(self): logger.debug("generate_signed_prekey") latest_signed_prekey = self.load_latest_signed_prekey(generate=False) if latest_signed_prekey is not None: if latest_signed_prekey.getId() == self.MAX_SIGNED_PREKEY_ID: new_signed_prekey_id = (self.MAX_SIGNED_PREKEY_ID / 2) + 1 else: new_signed_prekey_id = latest_signed_prekey.getId() + 1 else: new_signed_prekey_id = 0 signed_prekey = KeyHelper.generateSignedPreKey(self._identity, new_signed_prekey_id) self._store.storeSignedPreKey(signed_prekey.getId(), signed_prekey) return signed_prekey def load_latest_signed_prekey(self, generate=False): logger.debug("load_latest_signed_prekey") signed_prekeys = self._store.loadSignedPreKeys() if len(signed_prekeys): return signed_prekeys[-1] return self.generate_signed_prekey() if generate else None def _get_session_cipher(self, recipientid): logger.debug("get_session_cipher(recipientid=%s)" % recipientid) if recipientid in self._session_ciphers: session_cipher = self._session_ciphers[recipientid] else: session_cipher= SessionCipher(self._store, self._store, self._store, self._store, recipientid, 1) self._session_ciphers[recipientid] = session_cipher return session_cipher def _get_group_cipher(self, groupid, username): logger.debug("get_group_cipher(groupid=%s, username=%s)" % (groupid, username)) senderkeyname = SenderKeyName(groupid, AxolotlAddress(username, 0)) if senderkeyname in self._group_ciphers: group_cipher = self._group_ciphers[senderkeyname] else: group_cipher = GroupCipher(self._store.senderKeyStore, senderkeyname) self._group_ciphers[senderkeyname] = group_cipher return group_cipher def _generate_random_padding(self): logger.debug("generate_random_padding") num = random.randint(1,255) return bytes(bytearray([num] * num)) def _unpad(self, data): padding_byte = data[-1] if type(data[-1]) is int else ord(data[-1]) # bec inconsistent API? padding = padding_byte & 0xFF return data[:-padding] def encrypt(self, recipient_id, message): logger.debug("encrypt(recipientid=%s, message=%s)" % (recipient_id, message)) """ :param recipient_id: :type recipient_id: str :param data: :type data: bytes :return: :rtype: """ cipher = self._get_session_cipher(recipient_id) return cipher.encrypt(message + self._generate_random_padding()) def decrypt_pkmsg(self, senderid, data, unpad): logger.debug("decrypt_pkmsg(senderid=%s, data=(omitted), unpad=%s)" % (senderid, unpad)) pkmsg = PreKeyWhisperMessage(serialized=data) try: plaintext = self._get_session_cipher(senderid).decryptPkmsg(pkmsg) return self._unpad(plaintext) if unpad else plaintext except NoSessionException: raise exceptions.NoSessionException() except InvalidKeyIdException: raise exceptions.InvalidKeyIdException() except InvalidMessageException: raise exceptions.InvalidMessageException() except DuplicateMessageException: raise exceptions.DuplicateMessageException() def decrypt_msg(self, senderid, data, unpad): logger.debug("decrypt_msg(senderid=%s, data=[omitted], unpad=%s)" % (senderid, unpad)) msg = WhisperMessage(serialized=data) try: plaintext = self._get_session_cipher(senderid).decryptMsg(msg) return self._unpad(plaintext) if unpad else plaintext except NoSessionException: raise exceptions.NoSessionException() except InvalidKeyIdException: raise exceptions.InvalidKeyIdException() except InvalidMessageException: raise exceptions.InvalidMessageException() except DuplicateMessageException: raise exceptions.DuplicateMessageException() def group_encrypt(self, groupid, message): """ :param groupid: :type groupid: str :param message: :type message: bytes :return: :rtype: """ logger.debug("group_encrypt(groupid=%s, message=%s)" % (groupid, message)) group_cipher = self._get_group_cipher(groupid, self._username) return group_cipher.encrypt(message + self._generate_random_padding()) def group_decrypt(self, groupid, participantid, data): logger.debug("group_decrypt(groupid=%s, participantid=%s, data=[omitted])" % (groupid, participantid)) group_cipher = self._get_group_cipher(groupid, participantid) try: plaintext = group_cipher.decrypt(data) plaintext = self._unpad(plaintext) return plaintext except NoSessionException: raise exceptions.NoSessionException() except DuplicateMessageException: raise exceptions.DuplicateMessageException() def group_create_skmsg(self, groupid): logger.debug("group_create_skmsg(groupid=%s)" % groupid) senderKeyName = SenderKeyName(groupid, AxolotlAddress(self._username, 0)) return self._group_session_builder.create(senderKeyName) def group_create_session(self, groupid, participantid, skmsgdata): """ :param groupid: :type groupid: str :param participantid: :type participantid: str :param skmsgdata: :type skmsgdata: bytearray :return: :rtype: """ logger.debug("group_create_session(groupid=%s, participantid=%s, skmsgdata=[omitted])" % (groupid, participantid)) senderKeyName = SenderKeyName(groupid, AxolotlAddress(participantid, 0)) senderkeydistributionmessage = SenderKeyDistributionMessage(serialized=skmsgdata) self._group_session_builder.process(senderKeyName, senderkeydistributionmessage) def create_session(self, username, prekeybundle, autotrust=False): """ :param username: :type username: str :param prekeybundle: :type prekeybundle: PreKeyBundle :return: :rtype: """ logger.debug("create_session(username=%s, prekeybundle=[omitted], autotrust=%s)" % (username, autotrust)) session_builder = SessionBuilder(self._store, self._store, self._store, self._store, username, 1) try: session_builder.processPreKeyBundle(prekeybundle) except UntrustedIdentityException as ex: if autotrust: self.trust_identity(ex.getName(), ex.getIdentityKey()) else: raise exceptions.UntrustedIdentityException(ex.getName(), ex.getIdentityKey()) def session_exists(self, username): """ :param username: :type username: str :return: :rtype: """ logger.debug("session_exists(%s)?" % username) return self._store.containsSession(username, 1) def load_senderkey(self, groupid): logger.debug("load_senderkey(groupid=%s)" % groupid) senderkeyname = SenderKeyName(groupid, AxolotlAddress(self._username, 0)) return self._store.loadSenderKey(senderkeyname) def trust_identity(self, recipientid, identitykey): logger.debug("trust_identity(recipientid=%s, identitykey=[omitted])" % recipientid) self._store.saveIdentity(recipientid, identitykey) yowsup-3.2.3/yowsup/axolotl/store/000077500000000000000000000000001346433372600172645ustar00rootroot00000000000000yowsup-3.2.3/yowsup/axolotl/store/__init__.py000066400000000000000000000000001346433372600213630ustar00rootroot00000000000000yowsup-3.2.3/yowsup/axolotl/store/sqlite/000077500000000000000000000000001346433372600205655ustar00rootroot00000000000000yowsup-3.2.3/yowsup/axolotl/store/sqlite/__init__.py000066400000000000000000000000001346433372600226640ustar00rootroot00000000000000yowsup-3.2.3/yowsup/axolotl/store/sqlite/liteaxolotlstore.py000066400000000000000000000064171346433372600245640ustar00rootroot00000000000000from axolotl.state.axolotlstore import AxolotlStore from .liteidentitykeystore import LiteIdentityKeyStore from .liteprekeystore import LitePreKeyStore from .litesessionstore import LiteSessionStore from .litesignedprekeystore import LiteSignedPreKeyStore from .litesenderkeystore import LiteSenderKeyStore import sqlite3 class LiteAxolotlStore(AxolotlStore): def __init__(self, db): conn = sqlite3.connect(db, check_same_thread=False) conn.text_factory = bytes self._db = db self.identityKeyStore = LiteIdentityKeyStore(conn) self.preKeyStore = LitePreKeyStore(conn) self.signedPreKeyStore = LiteSignedPreKeyStore(conn) self.sessionStore = LiteSessionStore(conn) self.senderKeyStore = LiteSenderKeyStore(conn) def __str__(self): return self._db def getIdentityKeyPair(self): return self.identityKeyStore.getIdentityKeyPair() def getLocalRegistrationId(self): return self.identityKeyStore.getLocalRegistrationId() def saveIdentity(self, recepientId, identityKey): self.identityKeyStore.saveIdentity(recepientId, identityKey) def isTrustedIdentity(self, recepientId, identityKey): return self.identityKeyStore.isTrustedIdentity(recepientId, identityKey) def loadPreKey(self, preKeyId): return self.preKeyStore.loadPreKey(preKeyId) def loadPreKeys(self): return self.preKeyStore.loadPendingPreKeys() def storePreKey(self, preKeyId, preKeyRecord): self.preKeyStore.storePreKey(preKeyId, preKeyRecord) def containsPreKey(self, preKeyId): return self.preKeyStore.containsPreKey(preKeyId) def removePreKey(self, preKeyId): self.preKeyStore.removePreKey(preKeyId) def loadSession(self, recepientId, deviceId): return self.sessionStore.loadSession(recepientId, deviceId) def getSubDeviceSessions(self, recepientId): return self.sessionStore.getSubDeviceSessions(recepientId) def storeSession(self, recepientId, deviceId, sessionRecord): self.sessionStore.storeSession(recepientId, deviceId, sessionRecord) def containsSession(self, recepientId, deviceId): return self.sessionStore.containsSession(recepientId, deviceId) def deleteSession(self, recepientId, deviceId): self.sessionStore.deleteSession(recepientId, deviceId) def deleteAllSessions(self, recepientId): self.sessionStore.deleteAllSessions(recepientId) def loadSignedPreKey(self, signedPreKeyId): return self.signedPreKeyStore.loadSignedPreKey(signedPreKeyId) def loadSignedPreKeys(self): return self.signedPreKeyStore.loadSignedPreKeys() def storeSignedPreKey(self, signedPreKeyId, signedPreKeyRecord): self.signedPreKeyStore.storeSignedPreKey(signedPreKeyId, signedPreKeyRecord) def containsSignedPreKey(self, signedPreKeyId): return self.signedPreKeyStore.containsSignedPreKey(signedPreKeyId) def removeSignedPreKey(self, signedPreKeyId): self.signedPreKeyStore.removeSignedPreKey(signedPreKeyId) def loadSenderKey(self, senderKeyName): return self.senderKeyStore.loadSenderKey(senderKeyName) def storeSenderKey(self, senderKeyName, senderKeyRecord): self.senderKeyStore.storeSenderKey(senderKeyName, senderKeyRecord) yowsup-3.2.3/yowsup/axolotl/store/sqlite/liteidentitykeystore.py000066400000000000000000000061331346433372600254370ustar00rootroot00000000000000from axolotl.state.identitykeystore import IdentityKeyStore from axolotl.identitykey import IdentityKey from axolotl.identitykeypair import IdentityKeyPair from axolotl.util.keyhelper import KeyHelper from axolotl.ecc.djbec import * import sys class LiteIdentityKeyStore(IdentityKeyStore): def __init__(self, dbConn): """ :type dbConn: Connection """ self.dbConn = dbConn dbConn.execute("CREATE TABLE IF NOT EXISTS identities (_id INTEGER PRIMARY KEY AUTOINCREMENT," "recipient_id INTEGER UNIQUE," "registration_id INTEGER, public_key BLOB, private_key BLOB," "next_prekey_id INTEGER, timestamp INTEGER);") if self.getLocalRegistrationId() is None or self.getIdentityKeyPair() is None: identity = KeyHelper.generateIdentityKeyPair() registration_id = KeyHelper.generateRegistrationId(True) self._storeLocalData(registration_id, identity) def getIdentityKeyPair(self): q = "SELECT public_key, private_key FROM identities WHERE recipient_id = -1" c = self.dbConn.cursor() c.execute(q) result = c.fetchone() if result: publicKey, privateKey = result return IdentityKeyPair(IdentityKey(DjbECPublicKey(publicKey[1:])), DjbECPrivateKey(privateKey)) return None def getLocalRegistrationId(self): q = "SELECT registration_id FROM identities WHERE recipient_id = -1" c = self.dbConn.cursor() c.execute(q) result = c.fetchone() return result[0] if result else None def _storeLocalData(self, registrationId, identityKeyPair): q = "INSERT INTO identities(recipient_id, registration_id, public_key, private_key) VALUES(-1, ?, ?, ?)" c = self.dbConn.cursor() pubKey = identityKeyPair.getPublicKey().getPublicKey().serialize() privKey = identityKeyPair.getPrivateKey().serialize() if sys.version_info < (2,7): pubKey = buffer(pubKey) privKey = buffer(privKey) c.execute(q, (registrationId, pubKey, privKey)) self.dbConn.commit() def saveIdentity(self, recipientId, identityKey): q = "DELETE FROM identities WHERE recipient_id=?" self.dbConn.cursor().execute(q, (recipientId,)) self.dbConn.commit() q = "INSERT INTO identities (recipient_id, public_key) VALUES(?, ?)" c = self.dbConn.cursor() pubKey = identityKey.getPublicKey().serialize() c.execute(q, (recipientId, buffer(pubKey) if sys.version_info < (2,7) else pubKey)) self.dbConn.commit() def isTrustedIdentity(self, recipientId, identityKey): q = "SELECT public_key from identities WHERE recipient_id = ?" c = self.dbConn.cursor() c.execute(q, (recipientId,)) result = c.fetchone() if not result: return True pubKey = identityKey.getPublicKey().serialize() if sys.version_info < (2, 7): pubKey = buffer(pubKey) return result[0] == pubKeyyowsup-3.2.3/yowsup/axolotl/store/sqlite/liteprekeystore.py000066400000000000000000000050551346433372600243760ustar00rootroot00000000000000from axolotl.state.prekeystore import PreKeyStore from axolotl.state.prekeyrecord import PreKeyRecord from yowsup.axolotl.exceptions import InvalidKeyIdException import sys class LitePreKeyStore(PreKeyStore): def __init__(self, dbConn): """ :type dbConn: Connection """ self.dbConn = dbConn dbConn.execute("CREATE TABLE IF NOT EXISTS prekeys (_id INTEGER PRIMARY KEY AUTOINCREMENT," "prekey_id INTEGER UNIQUE, sent_to_server BOOLEAN, record BLOB);") def loadPreKey(self, preKeyId): q = "SELECT record FROM prekeys WHERE prekey_id = ?" cursor = self.dbConn.cursor() cursor.execute(q, (preKeyId,)) result = cursor.fetchone() if not result: raise InvalidKeyIdException("No such prekeyrecord!") return PreKeyRecord(serialized = result[0]) def loadUnsentPendingPreKeys(self): q = "SELECT record FROM prekeys WHERE sent_to_server is NULL or sent_to_server = ?" cursor = self.dbConn.cursor() cursor.execute(q, (0,)) result = cursor.fetchall() return [PreKeyRecord(serialized=result[0]) for result in result] def setAsSent(self, prekeyIds): """ :param preKeyIds: :type preKeyIds: list :return: :rtype: """ for prekeyId in prekeyIds: q = "UPDATE prekeys SET sent_to_server = ? WHERE prekey_id = ?" cursor = self.dbConn.cursor() cursor.execute(q, (1, prekeyId)) self.dbConn.commit() def loadPendingPreKeys(self): q = "SELECT record FROM prekeys" cursor = self.dbConn.cursor() cursor.execute(q) result = cursor.fetchall() return [PreKeyRecord(serialized=result[0]) for result in result] def storePreKey(self, preKeyId, preKeyRecord): #self.removePreKey(preKeyId) q = "INSERT INTO prekeys (prekey_id, record) VALUES(?,?)" cursor = self.dbConn.cursor() serialized = preKeyRecord.serialize() cursor.execute(q, (preKeyId, buffer(serialized) if sys.version_info < (2,7) else serialized)) self.dbConn.commit() def containsPreKey(self, preKeyId): q = "SELECT record FROM prekeys WHERE prekey_id = ?" cursor = self.dbConn.cursor() cursor.execute(q, (preKeyId,)) return cursor.fetchone() is not None def removePreKey(self, preKeyId): q = "DELETE FROM prekeys WHERE prekey_id = ?" cursor = self.dbConn.cursor() cursor.execute(q, (preKeyId,)) self.dbConn.commit() yowsup-3.2.3/yowsup/axolotl/store/sqlite/litesenderkeystore.py000066400000000000000000000037511346433372600250710ustar00rootroot00000000000000from axolotl.groups.state.senderkeystore import SenderKeyStore from axolotl.groups.state.senderkeyrecord import SenderKeyRecord import sqlite3 import sys class LiteSenderKeyStore(SenderKeyStore): def __init__(self, dbConn): """ :type dbConn: Connection """ self.dbConn = dbConn dbConn.execute("CREATE TABLE IF NOT EXISTS sender_keys (_id INTEGER PRIMARY KEY AUTOINCREMENT," "group_id TEXT NOT NULL," "sender_id INTEGER NOT NULL, record BLOB);") dbConn.execute("CREATE UNIQUE INDEX IF NOT EXISTS sender_keys_idx ON sender_keys (group_id, sender_id);") def storeSenderKey(self, senderKeyName, senderKeyRecord): """ :type senderKeyName: SenderKeName :type senderKeyRecord: SenderKeyRecord """ q = "INSERT INTO sender_keys (group_id, sender_id, record) VALUES(?,?, ?)" cursor = self.dbConn.cursor() serialized = senderKeyRecord.serialize() if sys.version_info < (2,7): serialized = buffer(serialized) try: cursor.execute(q, (senderKeyName.getGroupId(), senderKeyName.getSender().getName(), serialized)) self.dbConn.commit() except sqlite3.IntegrityError as e: q = "UPDATE sender_keys set record = ? WHERE group_id = ? and sender_id = ?" cursor = self.dbConn.cursor() cursor.execute(q, (serialized, senderKeyName.getGroupId(), senderKeyName.getSender().getName())) self.dbConn.commit() def loadSenderKey(self, senderKeyName): """ :type senderKeyName: SenderKeyName """ q = "SELECT record FROM sender_keys WHERE group_id = ? and sender_id = ?" cursor = self.dbConn.cursor() cursor.execute(q, (senderKeyName.getGroupId(), senderKeyName.getSender().getName())) result = cursor.fetchone() if not result: return SenderKeyRecord() return SenderKeyRecord(serialized = result[0]) yowsup-3.2.3/yowsup/axolotl/store/sqlite/litesessionstore.py000066400000000000000000000043121346433372600245550ustar00rootroot00000000000000from axolotl.state.sessionstore import SessionStore from axolotl.state.sessionrecord import SessionRecord import sys class LiteSessionStore(SessionStore): def __init__(self, dbConn): """ :type dbConn: Connection """ self.dbConn = dbConn dbConn.execute("CREATE TABLE IF NOT EXISTS sessions (_id INTEGER PRIMARY KEY AUTOINCREMENT," "recipient_id INTEGER UNIQUE, device_id INTEGER, record BLOB, timestamp INTEGER);") def loadSession(self, recipientId, deviceId): q = "SELECT record FROM sessions WHERE recipient_id = ? AND device_id = ?" c = self.dbConn.cursor() c.execute(q, (recipientId, deviceId)) result = c.fetchone() if result: return SessionRecord(serialized=result[0]) else: return SessionRecord() def getSubDeviceSessions(self, recipientId): q = "SELECT device_id from sessions WHERE recipient_id = ?" c = self.dbConn.cursor() c.execute(q, (recipientId,)) result = c.fetchall() deviceIds = [r[0] for r in result] return deviceIds def storeSession(self, recipientId, deviceId, sessionRecord): self.deleteSession(recipientId, deviceId) q = "INSERT INTO sessions(recipient_id, device_id, record) VALUES(?,?,?)" c = self.dbConn.cursor() serialized = sessionRecord.serialize() c.execute(q, (recipientId, deviceId, buffer(serialized) if sys.version_info < (2,7) else serialized)) self.dbConn.commit() def containsSession(self, recipientId, deviceId): q = "SELECT record FROM sessions WHERE recipient_id = ? AND device_id = ?" c = self.dbConn.cursor() c.execute(q, (recipientId, deviceId)) result = c.fetchone() return result is not None def deleteSession(self, recipientId, deviceId): q = "DELETE FROM sessions WHERE recipient_id = ? AND device_id = ?" self.dbConn.cursor().execute(q, (recipientId, deviceId)) self.dbConn.commit() def deleteAllSessions(self, recipientId): q = "DELETE FROM sessions WHERE recipient_id = ?" self.dbConn.cursor().execute(q, (recipientId,)) self.dbConn.commit() yowsup-3.2.3/yowsup/axolotl/store/sqlite/litesignedprekeystore.py000066400000000000000000000043421346433372600255660ustar00rootroot00000000000000from axolotl.state.signedprekeystore import SignedPreKeyStore from axolotl.state.signedprekeyrecord import SignedPreKeyRecord from axolotl.invalidkeyidexception import InvalidKeyIdException import sys class LiteSignedPreKeyStore(SignedPreKeyStore): def __init__(self, dbConn): """ :type dbConn: Connection """ self.dbConn = dbConn dbConn.execute("CREATE TABLE IF NOT EXISTS signed_prekeys (_id INTEGER PRIMARY KEY AUTOINCREMENT," "prekey_id INTEGER UNIQUE, timestamp INTEGER, record BLOB);") def loadSignedPreKey(self, signedPreKeyId): q = "SELECT record FROM signed_prekeys WHERE prekey_id = ?" cursor = self.dbConn.cursor() cursor.execute(q, (signedPreKeyId,)) result = cursor.fetchone() if not result: raise InvalidKeyIdException("No such signedprekeyrecord! %s " % signedPreKeyId) return SignedPreKeyRecord(serialized=result[0]) def loadSignedPreKeys(self): q = "SELECT record FROM signed_prekeys" cursor = self.dbConn.cursor() cursor.execute(q,) result = cursor.fetchall() results = [] for row in result: results.append(SignedPreKeyRecord(serialized=row[0])) return results def storeSignedPreKey(self, signedPreKeyId, signedPreKeyRecord): #q = "DELETE FROM signed_prekeys WHERE prekey_id = ?" #self.dbConn.cursor().execute(q, (signedPreKeyId,)) #self.dbConn.commit() q = "INSERT INTO signed_prekeys (prekey_id, record) VALUES(?,?)" cursor = self.dbConn.cursor() record = signedPreKeyRecord.serialize() cursor.execute(q, (signedPreKeyId, buffer(record) if sys.version_info < (2,7) else record)) self.dbConn.commit() def containsSignedPreKey(self, signedPreKeyId): q = "SELECT record FROM signed_prekeys WHERE prekey_id = ?" cursor = self.dbConn.cursor() cursor.execute(q, (signedPreKeyId,)) return cursor.fetchone() is not None def removeSignedPreKey(self, signedPreKeyId): q = "DELETE FROM signed_prekeys WHERE prekey_id = ?" cursor = self.dbConn.cursor() cursor.execute(q, (signedPreKeyId,)) self.dbConn.commit() yowsup-3.2.3/yowsup/common/000077500000000000000000000000001346433372600157365ustar00rootroot00000000000000yowsup-3.2.3/yowsup/common/__init__.py000066400000000000000000000000431346433372600200440ustar00rootroot00000000000000from .constants import YowConstantsyowsup-3.2.3/yowsup/common/constants.py000066400000000000000000000014211346433372600203220ustar00rootroot00000000000000class YowConstants: DOMAIN = "s.whatsapp.net" ENDPOINTS = ( ("e1.whatsapp.net", 443), ("e2.whatsapp.net", 443), ("e3.whatsapp.net", 443), ("e4.whatsapp.net", 443), ("e5.whatsapp.net", 443), ("e6.whatsapp.net", 443), ("e7.whatsapp.net", 443), ("e8.whatsapp.net", 443), ("e9.whatsapp.net", 443), ("e10.whatsapp.net", 443), ("e11.whatsapp.net", 443), ("e12.whatsapp.net", 443), ("e13.whatsapp.net", 443), ("e14.whatsapp.net", 443), ("e15.whatsapp.net", 443), ("e16.whatsapp.net", 443), ) WHATSAPP_SERVER = "s.whatsapp.net" WHATSAPP_GROUP_SERVER = "g.us" YOWSUP = "yowsup" PREVIEW_WIDTH = 64 PREVIEW_HEIGHT = 64 yowsup-3.2.3/yowsup/common/http/000077500000000000000000000000001346433372600167155ustar00rootroot00000000000000yowsup-3.2.3/yowsup/common/http/__init__.py000066400000000000000000000001621346433372600210250ustar00rootroot00000000000000from .httpproxy import HttpProxy from .warequest import WARequest from .waresponseparser import JSONResponseParseryowsup-3.2.3/yowsup/common/http/httpproxy.py000066400000000000000000000063231346433372600213540ustar00rootroot00000000000000''' Copyright (c) <2012> Tarek Galal Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ''' import os, base64 try: from urllib.parse import urlparse except ImportError: from urlparse import urlparse class HttpProxy: def __init__(self, address, username = None, password = None): self.address = address self.username = username self.password = password def __repr__(self): return repr(self.address) def handler(self): return HttpProxyHandler(self) @staticmethod def getFromEnviron(): url = None for key in ('http_proxy', 'https_proxy'): url = os.environ.get(key) if url: break if not url: return None dat = urlparse(url) port = 80 if dat.scheme == 'http' else 443 if dat.port != None: port = int(dat.port) host = dat.hostname return HttpProxy((host, port), dat.username, dat.password) class HttpProxyHandler: def __init__(self, proxy): self.state = 'init' self.proxy = proxy def onConnect(self): pass def connect(self, socket, pair): proxy = self.proxy authHeader = None if proxy.username and proxy.password: key = bytes(proxy.username, 'ascii') + b':' + bytes(proxy.password, 'ascii') if (bytes != str) else bytes(proxy.username) + b':' + proxy.password auth = base64.b64encode(key) authHeader = b'Proxy-Authorization: Basic ' + auth + b'\r\n' data = bytearray('CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n' % (2 * pair), 'ascii') if authHeader: data += authHeader data += b'\r\n' self.state = 'connect' self.data = data socket.connect(proxy.address) def send(self, socket): if self.state == 'connect': socket.send(self.data) self.state = 'sent' def recv(self, socket, size): if self.state == 'sent': data = socket.recv(size) data = data.decode('ascii') status = data.split(' ', 2) if status[1] != '200': raise Exception('%s' % (data[:data.index('\r\n')])) self.state = 'end' self.onConnect() return datayowsup-3.2.3/yowsup/common/http/test_warequest.py000066400000000000000000000000621346433372600223440ustar00rootroot00000000000000from yowsup.common.http.warequest import WARequestyowsup-3.2.3/yowsup/common/http/warequest.py000066400000000000000000000233671346433372600213220ustar00rootroot00000000000000from .waresponseparser import ResponseParser from yowsup.env import YowsupEnv import sys import logging from axolotl.ecc.curve import Curve from axolotl.ecc.ec import ECPublicKey from yowsup.common.tools import WATools from cryptography.hazmat.primitives.ciphers.aead import AESGCM from yowsup.axolotl.factory import AxolotlManagerFactory import struct import random import base64 if sys.version_info < (3, 0): import httplib from urllib import quote as urllib_quote if sys.version_info >= (2, 7, 9): # see https://github.com/tgalal/yowsup/issues/677 import ssl ssl._create_default_https_context = ssl._create_unverified_context else: from http import client as httplib from urllib.parse import quote as urllib_quote logger = logging.getLogger(__name__) class WARequest(object): OK = 200 ENC_PUBKEY = Curve.decodePoint( bytearray([ 5, 142, 140, 15, 116, 195, 235, 197, 215, 166, 134, 92, 108, 60, 132, 56, 86, 176, 97, 33, 204, 232, 234, 119, 77, 34, 251, 111, 18, 37, 18, 48, 45 ]) ) def __init__(self, config): """ :type method: str :param config: :type config: yowsup.config.v1.config.Config """ self.pvars = [] self.port = 443 self.type = "GET" self.parser = None self.params = [] self.headers = {} self.sent = False self.response = None self._config = config self._p_in = str(config.phone)[len(str(config.cc)):] self._axolotlmanager = AxolotlManagerFactory() \ .get_manager(self._config.phone) # type: yowsup.axolotl.manager.Axolotlmanager if config.expid is None: config.expid = WATools.generateDeviceId() if config.fdid is None: config.fdid = WATools.generatePhoneId() if config.client_static_keypair is None: config.client_static_keypair = WATools.generateKeyPair() self.addParam("cc", config.cc) self.addParam("in", self._p_in) self.addParam("lg", "en") self.addParam("lc", "GB") self.addParam("mistyped", "6") self.addParam("authkey", self.b64encode(config.client_static_keypair.public.data)) self.addParam("e_regid", self.b64encode(struct.pack('>I', self._axolotlmanager.registration_id))) self.addParam("e_keytype", self.b64encode(b"\x05")) self.addParam("e_ident", self.b64encode(self._axolotlmanager.identity.publicKey.serialize()[1:])) signedprekey = self._axolotlmanager.load_latest_signed_prekey(generate=True) self.addParam("e_skey_id", self.b64encode(struct.pack('>I', signedprekey.getId())[1:])) self.addParam("e_skey_val", self.b64encode(signedprekey.getKeyPair().publicKey.serialize()[1:])) self.addParam("e_skey_sig", self.b64encode(signedprekey.getSignature())) self.addParam("fdid", config.fdid) self.addParam("expid", self.b64encode(config.expid)) self.addParam("network_radio_type", "1") self.addParam("simnum", "1") self.addParam("hasinrc", "1") self.addParam("pid", int(random.uniform(100, 9999))) self.addParam("rc", 0) if self._config.id: self.addParam("id", self._config.id) def setParsableVariables(self, pvars): self.pvars = pvars def onResponse(self, name, value): if name == "status": self.status = value elif name == "result": self.result = value def addParam(self, name, value): self.params.append((name, value)) def removeParam(self, name): for i in range(0, len(self.params)): if self.params[i][0] == name: del self.params[i] def addHeaderField(self, name, value): self.headers[name] = value def clearParams(self): self.params = [] def getUserAgent(self): return YowsupEnv.getCurrent().getUserAgent() def send(self, parser=None, encrypt=True, preview=False): logger.debug("send(parser=%s, encrypt=%s, preview=%s)" % ( None if parser is None else "[omitted]", encrypt, preview )) if self.type == "POST": return self.sendPostRequest(parser) return self.sendGetRequest(parser, encrypt, preview=preview) def setParser(self, parser): if isinstance(parser, ResponseParser): self.parser = parser else: logger.error("Invalid parser") def getConnectionParameters(self): if not self.url: return "", "", self.port try: url = self.url.split("://", 1) url = url[0] if len(url) == 1 else url[1] host, path = url.split('/', 1) except ValueError: host = url path = "" path = "/" + path return host, self.port, path def encryptParams(self, params, key): """ :param params: :type params: list :param key: :type key: ECPublicKey :return: :rtype: list """ keypair = Curve.generateKeyPair() encodedparams = self.urlencodeParams(params) cipher = AESGCM(Curve.calculateAgreement(key, keypair.privateKey)) ciphertext = cipher.encrypt(b'\x00\x00\x00\x00' + struct.pack('>Q', 0), encodedparams.encode(), b'') payload = base64.b64encode(keypair.publicKey.serialize()[1:] + ciphertext) return [('ENC', payload)] def sendGetRequest(self, parser=None, encrypt_params=True, preview=False): logger.debug("sendGetRequest(parser=%s, encrypt_params=%s, preview=%s)" % ( None if parser is None else "[omitted]", encrypt_params, preview )) self.response = None if encrypt_params: logger.debug("Encrypting parameters") if logger.level <= logging.DEBUG: logger.debug("pre-encrypt (encoded) parameters = \n%s", (self.urlencodeParams(self.params))) params = self.encryptParams(self.params, self.ENC_PUBKEY) else: ## params will be logged right before sending params = self.params parser = parser or self.parser or ResponseParser() headers = dict( list( { "User-Agent": self.getUserAgent(), "Accept": parser.getMeta() }.items() ) + list(self.headers.items())) host, port, path = self.getConnectionParameters() self.response = WARequest.sendRequest(host, port, path, headers, params, "GET", preview=preview) if preview: logger.info("Preview request, skip response handling and return None") return None if not self.response.status == WARequest.OK: logger.error("Request not success, status was %s" % self.response.status) return {} data = self.response.read() logger.info(data) self.sent = True return parser.parse(data.decode(), self.pvars) def sendPostRequest(self, parser=None): self.response = None params = self.params # [param.items()[0] for param in self.params]; parser = parser or self.parser or ResponseParser() headers = dict(list({"User-Agent": self.getUserAgent(), "Accept": parser.getMeta(), "Content-Type": "application/x-www-form-urlencoded" }.items()) + list(self.headers.items())) host, port, path = self.getConnectionParameters() self.response = WARequest.sendRequest(host, port, path, headers, params, "POST") if not self.response.status == WARequest.OK: logger.error("Request not success, status was %s" % self.response.status) return {} data = self.response.read() logger.info(data) self.sent = True return parser.parse(data.decode(), self.pvars) def b64encode(self, value): return base64.urlsafe_b64encode(value).replace(b'=', b'') @classmethod def urlencode(cls, value): if type(value) not in (str, bytes): value = str(value) out = "" for char in value: if type(char) is int: char = bytearray([char]) quoted = urllib_quote(char, safe='') out += quoted if quoted[0] != '%' else quoted.lower() return out \ .replace('-', '%2d') \ .replace('_', '%5f') \ .replace('~', '%7e') @classmethod def urlencodeParams(cls, params): merged = [] for k, v in params: merged.append( "%s=%s" % (k, cls.urlencode(v)) ) return "&".join(merged) @classmethod def sendRequest(cls, host, port, path, headers, params, reqType="GET", preview=False): logger.debug("sendRequest(host=%s, port=%s, path=%s, headers=%s, params=%s, reqType=%s, preview=%s)" % ( host, port, path, headers, params, reqType, preview )) params = cls.urlencodeParams(params) path = path + "?" + params if reqType == "GET" and params else path if not preview: logger.debug("Opening connection to %s" % host) conn = httplib.HTTPSConnection(host, port) if port == 443 else httplib.HTTPConnection(host, port) else: logger.debug("Should open connection to %s, but this is a preview" % host) conn = None if not preview: logger.debug("Sending %s request to %s" % (reqType, path)) conn.request(reqType, path, params, headers) else: logger.debug("Should send %s request to %s, but this is a preview" % (reqType, path)) return None response = conn.getresponse() return response yowsup-3.2.3/yowsup/common/http/waresponseparser.py000066400000000000000000000103201346433372600226660ustar00rootroot00000000000000import json, sys from xml.dom import minidom import plistlib import logging logger = logging.getLogger(__name__) class ResponseParser(object): def __init__(self): self.meta = "*" def parse(self, text, pvars): return text def getMeta(self): return self.meta def getVars(self, pvars): if type(pvars) is dict: return pvars if type(pvars) is list: out = {} for p in pvars: out[p] = p return out class XMLResponseParser(ResponseParser): def __init__(self): try: import libxml2 except ImportError: print("libxml2 XMLResponseParser requires libxml2") sys.exit(1) self.meta = "text/xml"; def parse(self, xml, pvars): import libxml2 doc = libxml2.parseDoc(xml) pvars = self.getVars(pvars) vals = {} for k, v in pvars.items(): res = doc.xpathEval(v) vals[k] = [] for r in res: #if not vals.has_key(r.name): # vals[r.name] = [] if r.type == 'element': #vals[r.name].append(self.xmlToDict(minidom.parseString(str(r)))[r.name]) vals[k].append(self.xmlToDict(minidom.parseString(str(r)))[r.name]) elif r.type == 'attribute': vals[k].append(r.content) else: logger.error("UNKNOWN TYPE") if len(vals[k]) == 1: vals[k] = vals[k][0] elif len(vals[k]) == 0: vals[k] = None return vals def xmlToDict(self, xmlNode): if xmlNode.nodeName == "#document": node = {xmlNode.firstChild.nodeName:{}} node[xmlNode.firstChild.nodeName] = self.xmlToDict(xmlNode.firstChild) return node node = {} curr = node if xmlNode.attributes: for name, value in xmlNode.attributes.items(): curr[name] = value for n in xmlNode.childNodes: if n.nodeType == n.TEXT_NODE: curr["__TEXT__"] = n.data continue if not n.nodeName in curr: curr[n.nodeName] = [] if len(xmlNode.getElementsByTagName(n.nodeName)) > 1: #curr[n.nodeName] = [] curr[n.nodeName].append(self.xmlToDict(n)) else: curr[n.nodeName] = self.xmlToDict(n) return node class JSONResponseParser(ResponseParser): def __init__(self): self.meta = "text/json" def parse(self, jsonData, pvars): d = json.loads(jsonData) pvars = self.getVars(pvars) parsed = {} for k,v in pvars.items(): parsed[k] = self.query(d, v) return parsed def query(self, d, key): keys = key.split('.', 1) currKey = keys[0] if(currKey in d): item = d[currKey] if len(keys) == 1: return item if type(item) is dict: return self.query(item, keys[1]) elif type(item) is list: output = [] for i in item: output.append(self.query(i, keys[1])) return output else: return None class PListResponseParser(ResponseParser): def __init__(self): self.meta = "text/xml" def parse(self, xml, pvars): #tmp = minidom.parseString(xml) if sys.version_info >= (3, 0): pl = plistlib.readPlistFromBytes(xml.encode()); else: pl = plistlib.readPlistFromString(xml); parsed= {} pvars = self.getVars(pvars) for k,v in pvars.items(): parsed[k] = pl[k] if k in pl else None return parsed; yowsup-3.2.3/yowsup/common/mime.types000066400000000000000000000006651346433372600177620ustar00rootroot00000000000000audio/3gpp 3gpp audio/aac aac audio/aiff aif audio/amr amr audio/mp4 m4a audio/mpeg mp3 mp2 mpga mpega audio/ogg oga ogg opus spx audio/qcelp qcp audio/wav wav audio/webm webm audio/x-caf caf audio/x-ms-wma wma audio/ogg ogg image/gif gif image/jpeg jpe jpg jpeg image/png png video/3gpp 3gp video/avi avi video/mp4 mp4 video/mpeg m1v mpeg mpa mpg mpe video/quicktime mov qt video/x-flv flv video/x-ms-asf asf asx yowsup-3.2.3/yowsup/common/optionalmodules.py000066400000000000000000000024761346433372600215370ustar00rootroot00000000000000import importlib import logging logger = logging.getLogger(__name__) class OptionalModule(object): def __init__(self, modulename, failMessage = None, require = False): self.modulename = modulename self.require = require self.failMessage = failMessage def __enter__(self): return self.importFn def importFn(self, what = None): imp = self.modulename if not what else ("%s.%s" % (self.modulename, what)) return importlib.import_module(imp) def __exit__(self, exc_type, exc_val, exc_tb): if isinstance(exc_val, ImportError): failMessage = self.failMessage if self.failMessage is not None else ("%s import failed" % self.modulename) if failMessage: logger.error(failMessage) if self.require: raise return True class PILOptionalModule(OptionalModule): def __init__(self, failMessage = None, require = False): super(PILOptionalModule, self).__init__("PIL", failMessage= failMessage, require = require) class FFVideoOptionalModule(OptionalModule): def __init__(self, failMessage = None, require = False): super(FFVideoOptionalModule, self).__init__("ffvideo", failMessage=failMessage, require=require) yowsup-3.2.3/yowsup/common/tools.py000066400000000000000000000137651346433372600174640ustar00rootroot00000000000000import os from .constants import YowConstants import codecs, sys import logging import tempfile import base64 import hashlib import os.path, mimetypes import uuid from consonance.structs.keypair import KeyPair from appdirs import user_config_dir from .optionalmodules import PILOptionalModule, FFVideoOptionalModule logger = logging.getLogger(__name__) class Jid: @staticmethod def normalize(number): if '@' in number: return number elif "-" in number: return "%s@%s" % (number, YowConstants.WHATSAPP_GROUP_SERVER) return "%s@%s" % (number, YowConstants.WHATSAPP_SERVER) class HexTools: decode_hex = codecs.getdecoder("hex_codec") @staticmethod def decodeHex(hexString): result = HexTools.decode_hex(hexString)[0] if sys.version_info >= (3,0): result = result.decode('latin-1') return result class WATools: @staticmethod def generateIdentity(): return os.urandom(20) @classmethod def generatePhoneId(cls): """ :return: :rtype: str """ return str(cls.generateUUID()) @classmethod def generateDeviceId(cls): """ :return: :rtype: bytes """ return cls.generateUUID().bytes @classmethod def generateUUID(cls): """ :return: :rtype: uuid.UUID """ return uuid.uuid4() @classmethod def generateKeyPair(cls): """ :return: :rtype: KeyPair """ return KeyPair.generate() @staticmethod def getFileHashForUpload(filePath): sha1 = hashlib.sha256() f = open(filePath, 'rb') try: sha1.update(f.read()) finally: f.close() b64Hash = base64.b64encode(sha1.digest()) return b64Hash if type(b64Hash) is str else b64Hash.decode() class StorageTools: NAME_CONFIG = "config.json" @staticmethod def constructPath(*path): path = os.path.join(*path) fullPath = os.path.join(user_config_dir(YowConstants.YOWSUP), path) if not os.path.exists(os.path.dirname(fullPath)): os.makedirs(os.path.dirname(fullPath)) return fullPath @staticmethod def getStorageForPhone(phone): if type(phone) is not str: phone = str(phone) return StorageTools.constructPath(phone + '/') @staticmethod def writePhoneData(phone, name, val): logger.debug("writePhoneData(phone=%s, name=%s, val=[omitted])" % (phone, name)) path = os.path.join(StorageTools.getStorageForPhone(phone), name) logger.debug("Writing %s" % path) with open(path, 'w' if type(val) is str else 'wb') as attrFile: attrFile.write(val) @staticmethod def readPhoneData(phone, name, default=None): logger.debug("readPhoneData(phone=%s, name=%s)" % (phone, name)) path = StorageTools.getStorageForPhone(phone) dataFilePath = os.path.join(path, name) if os.path.isfile(dataFilePath): logger.debug("Reading %s" % dataFilePath) with open(dataFilePath, 'rb') as attrFile: return attrFile.read() else: logger.debug("%s does not exist" % dataFilePath) return default @classmethod def writeIdentity(cls, phone, identity): cls.writePhoneData(phone, 'id', identity) @classmethod def getIdentity(cls, phone): return cls.readPhoneData(phone, 'id') @classmethod def writePhoneConfig(cls, phone, config): cls.writePhoneData(phone, cls.NAME_CONFIG, config) @classmethod def readPhoneConfig(cls, phone, config): return cls.readPhoneData(phone, cls.NAME_CONFIG) class ImageTools: @staticmethod def scaleImage(infile, outfile, imageFormat, width, height): with PILOptionalModule() as imp: Image = imp("Image") im = Image.open(infile) #Convert P mode images if im.mode != "RGB": im = im.convert("RGB") im.thumbnail((width, height)) im.save(outfile, imageFormat) return True return False @staticmethod def getImageDimensions(imageFile): with PILOptionalModule() as imp: Image = imp("Image") im = Image.open(imageFile) return im.size @staticmethod def generatePreviewFromImage(image): fd, path = tempfile.mkstemp() preview = None if ImageTools.scaleImage(image, path, "JPEG", YowConstants.PREVIEW_WIDTH, YowConstants.PREVIEW_HEIGHT): fileObj = os.fdopen(fd, "rb+") fileObj.seek(0) preview = fileObj.read() fileObj.close() os.remove(path) return preview class MimeTools: MIME_FILE = os.path.join(os.path.dirname(__file__), 'mime.types') mimetypes.init() # Load default mime.types try: mimetypes.init([MIME_FILE]) # Append whatsapp mime.types except exception as e: logger.warning("Mime types supported can't be read. System mimes will be used. Cause: " + e.message) @staticmethod def getMIME(filepath): mimeType = mimetypes.guess_type(filepath)[0] if mimeType is None: raise Exception("Unsupported/unrecognized file type for: "+filepath); return mimeType class VideoTools: @staticmethod def getVideoProperties(videoFile): with FFVideoOptionalModule() as imp: VideoStream = imp("VideoStream") s = VideoStream(videoFile) return s.width, s.height, s.bitrate, s.duration #, s.codec_name @staticmethod def generatePreviewFromVideo(videoFile): with FFVideoOptionalModule() as imp: VideoStream = imp("VideoStream") fd, path = tempfile.mkstemp('.jpg') stream = VideoStream(videoFile) stream.get_frame_at_sec(0).image().save(path) preview = ImageTools.generatePreviewFromImage(path) os.remove(path) return preview yowsup-3.2.3/yowsup/config/000077500000000000000000000000001346433372600157135ustar00rootroot00000000000000yowsup-3.2.3/yowsup/config/__init__.py000066400000000000000000000000001346433372600200120ustar00rootroot00000000000000yowsup-3.2.3/yowsup/config/base/000077500000000000000000000000001346433372600166255ustar00rootroot00000000000000yowsup-3.2.3/yowsup/config/base/__init__.py000066400000000000000000000000001346433372600207240ustar00rootroot00000000000000yowsup-3.2.3/yowsup/config/base/config.py000066400000000000000000000006761346433372600204550ustar00rootroot00000000000000class Config(object): def __init__(self, version): self._version = version def __contains__(self, item): return self[item] is not None def __getitem__(self, item): return getattr(self, "_%s" % item) def __setitem__(self, key, value): setattr(self, key, value) def keys(self): return [var[1:] for var in vars(self)] @property def version(self): return self._version yowsup-3.2.3/yowsup/config/base/serialize.py000066400000000000000000000012761346433372600211740ustar00rootroot00000000000000class ConfigSerialize(object): def __init__(self, transforms): self._transforms = transforms def serialize(self, config): """ :param config: :type config: yowsup.config.base.config.Config :return: :rtype: bytes """ for transform in self._transforms: config = transform.transform(config) return config def deserialize(self, data): """ :type cls: type :param data: :type data: bytes :return: :rtype: yowsup.config.base.config.Config """ for transform in self._transforms[::-1]: data = transform.reverse(data) return data yowsup-3.2.3/yowsup/config/base/transform.py000066400000000000000000000005551346433372600212170ustar00rootroot00000000000000class ConfigTransform(object): def transform(self, config): """ :param config: :type config: yowsup.config.base.config.Config :return: dict :rtype: """ def reverse(self, data): """ :param data: :type data: :return: :rtype: yowsup.config.base.config.Config """ yowsup-3.2.3/yowsup/config/manager.py000066400000000000000000000110111346433372600176710ustar00rootroot00000000000000from yowsup.config.v1.config import Config from yowsup.config.transforms.dict_keyval import DictKeyValTransform from yowsup.config.transforms.dict_json import DictJsonTransform from yowsup.config.v1.serialize import ConfigSerialize from yowsup.common.tools import StorageTools import logging import os logger = logging.getLogger(__name__) class ConfigManager(object): NAME_FILE_CONFIG = "config" TYPE_KEYVAL = 1 TYPE_JSON = 2 TYPE_NAMES = { TYPE_KEYVAL: "keyval", TYPE_JSON: "json" } MAP_EXT = { "yo": TYPE_KEYVAL, "json": TYPE_JSON, } TYPES = { TYPE_KEYVAL: DictKeyValTransform, TYPE_JSON: DictJsonTransform } def load(self, username): """ :param username: :type username: :return: :rtype: """ config_dir = StorageTools.getStorageForPhone(username) logger.debug("Detecting config for username=%s, dir=%s" % (username, config_dir)) exhausted = [] for ftype in self.MAP_EXT: if len(ftype): fname = (self.NAME_FILE_CONFIG + "." + ftype) else: fname = self.NAME_FILE_CONFIG fpath = os.path.join(config_dir, fname) logger.debug("Trying %s" % fpath) if os.path.isfile(fpath): return self.load_path(fpath) exhausted.append(fpath) logger.error("Could not find a config for username=%s, paths checked: %s" % (username, ":".join(exhausted))) def _type_to_str(self, type): """ :param type: :type type: int :return: :rtype: """ for key, val in self.TYPE_NAMES.items(): if key == type: return val def load_path(self, path): """ :param path: :type path: :return: :rtype: """ logger.debug("load_path(path=%s)" % path) if os.path.isfile(path): configtype = self.guess_type(path) logger.debug("Detected config type: %s" % self._type_to_str(configtype)) if configtype in self.TYPES: logger.debug("Opening config for reading") with open(path, 'r') as f: data = f.read() datadict = self.TYPES[configtype]().reverse(data) return self.load_data(datadict) else: raise ValueError("Unsupported config type") else: logger.warn("load_path couldn't find the path: %s" % path) def load_data(self, datadict): logger.debug("Loading config") return ConfigSerialize(Config).deserialize(datadict) def guess_type(self, config_path): dissected = os.path.splitext(config_path) if len(dissected) > 1: ext = dissected[1][1:].lower() config_type = self.MAP_EXT[ext] if ext in self.MAP_EXT else None else: config_type = None if config_type is not None: return config_type else: logger.debug("Trying auto detect config type by parsing") with open(config_path, 'r') as f: data = f.read() for config_type, transform in self.TYPES.items(): config_type_str = self.TYPE_NAMES[config_type] try: logger.debug("Trying to parse as %s" % config_type_str) if transform().reverse(data): logger.debug("Successfully detected %s as config type for %s" % (config_type_str, config_path)) return config_type except Exception as ex: logger.debug("%s was not parseable as %s, reason: %s" % (config_path, config_type_str, ex)) def get_str_transform(self, serialize_type): if serialize_type in self.TYPES: return self.TYPES[serialize_type]() def config_to_str(self, config, serialize_type=TYPE_JSON): transform = self.get_str_transform(serialize_type) if transform is not None: return transform.transform(ConfigSerialize(config.__class__).serialize(config)) raise ValueError("unrecognized serialize_type=%d" % serialize_type) def save(self, config, serialize_type=TYPE_JSON, dest=None): outputdata = self.config_to_str(config, serialize_type) if dest is None: StorageTools.writePhoneConfig(config.phone, outputdata) else: with open(dest, 'wb') as outputfile: outputfile.write(outputdata) yowsup-3.2.3/yowsup/config/transforms/000077500000000000000000000000001346433372600201115ustar00rootroot00000000000000yowsup-3.2.3/yowsup/config/transforms/__init__.py000066400000000000000000000000001346433372600222100ustar00rootroot00000000000000yowsup-3.2.3/yowsup/config/transforms/config_dict.py000066400000000000000000000011731346433372600227350ustar00rootroot00000000000000from yowsup.config.base.transform import ConfigTransform class ConfigDictTransform(ConfigTransform): def __init__(self, cls): self._cls = cls def transform(self, config): """ :param config: :type config: dict :return: :rtype: yowsup.config.config.Config """ out = {} for prop in vars(config): out[prop] = getattr(config, prop) return out def reverse(self, data): """ :param data: :type data: yowsup,config.config.Config :return: :rtype: dict """ return self._cls(**data) yowsup-3.2.3/yowsup/config/transforms/dict_json.py000066400000000000000000000004411346433372600224360ustar00rootroot00000000000000from yowsup.config.base.transform import ConfigTransform import json class DictJsonTransform(ConfigTransform): def transform(self, data): return json.dumps(data, sort_keys=True, indent=4, separators=(',', ': ')) def reverse(self, data): return json.loads(data) yowsup-3.2.3/yowsup/config/transforms/dict_keyval.py000066400000000000000000000014151346433372600227620ustar00rootroot00000000000000from yowsup.config.base.transform import ConfigTransform class DictKeyValTransform(ConfigTransform): def transform(self, data): """ :param data: :type data: dict :return: :rtype: """ out=[] keys = sorted(data.keys()) for k in keys: out.append("%s=%s" % (k, data[k])) return "\n".join(out) def reverse(self, data): out = {} for l in data.split('\n'): line = l.strip() if len(line) and line[0] not in ('#',';'): prep = line.split('#', 1)[0].split(';', 1)[0].split('=', 1) varname = prep[0].strip() val = prep[1].strip() out[varname.replace('-', '_')] = val return out yowsup-3.2.3/yowsup/config/transforms/filter.py000066400000000000000000000020141346433372600217450ustar00rootroot00000000000000from yowsup.config.base.transform import ConfigTransform class FilterTransform(ConfigTransform): def __init__(self, transform_filter=None, reverse_filter=None): """ :param transform_filter: :type transform_filter: function | None :param reverse_filter: :type reverse_filter: function | None """ self._transform_filter = transform_filter # type: function | None self._reverse_filter = reverse_filter # type: function | None def transform(self, data): if self._transform_filter is not None: out = {} for key, val in data.items(): if self._transform_filter(key, val): out[key] = val return out return data def reverse(self, data): if self._reverse_filter is not None: out = {} for key, val in data.items(): if self._reverse_filter(key, val): out[key] = val return out return data yowsup-3.2.3/yowsup/config/transforms/map.py000066400000000000000000000017451346433372600212470ustar00rootroot00000000000000from yowsup.config.base.transform import ConfigTransform class MapTransform(ConfigTransform): def __init__(self, transform_map=None, reverse_map=None): """ :param transform_map: :type transform_map: function | None :param reverse_map: :type reverse_map: function | None """ self._transform_map = transform_map # type: function | None self._reverse_map = reverse_map # type: function | None def transform(self, data): if self._transform_map is not None: out = {} for key, val in data.items(): key, val = self._transform_map(key, val) out[key] = val return out return data def reverse(self, data): if self._reverse_map is not None: out = {} for key, val in data.items(): key, val = self._reverse_map(key, val) out[key] = val return out return data yowsup-3.2.3/yowsup/config/transforms/meta.py000066400000000000000000000015671346433372600214220ustar00rootroot00000000000000from yowsup.config.base.transform import ConfigTransform from yowsup.config.transforms.props import PropsTransform class MetaPropsTransform(ConfigTransform): META_FORMAT = "__%s__" def __init__(self, meta_props=None, meta_format=META_FORMAT): meta_props = meta_props or () meta_format = meta_format transform_map = {} reverse_map = {} for prop in meta_props: formatted = meta_format % prop transform_map[prop] = lambda key, val, formatted=formatted: (formatted, val) reverse_map[formatted] = lambda key, val, prop=prop: (prop, val) self._props_transform = PropsTransform(transform_map=transform_map, reverse_map=reverse_map) def transform(self, data): return self._props_transform.transform(data) def reverse(self, data): return self._props_transform.reverse(data) yowsup-3.2.3/yowsup/config/transforms/props.py000066400000000000000000000020561346433372600216310ustar00rootroot00000000000000from yowsup.config.base.transform import ConfigTransform import types class PropsTransform(ConfigTransform): def __init__(self, transform_map=None, reverse_map=None): self._transform_map = transform_map or {} self._reverse_map = reverse_map or {} def transform(self, data): """ :param data: :type data: dict :return: :rtype: dict """ out = {} for key, val in data.items(): if key in self._transform_map: target = self._transform_map[key] key, val = target(key, val) if type(target) == types.FunctionType else (key, target) out[key] = val return out def reverse(self, data): transformed_dict = {} for key, val in data.items(): if key in self._reverse_map: target = self._reverse_map[key] key, val = target(key, val) if type(target) == types.FunctionType else (key, target) transformed_dict[key] = val return transformed_dict yowsup-3.2.3/yowsup/config/transforms/serialize.py000066400000000000000000000012161346433372600224520ustar00rootroot00000000000000from yowsup.config.transforms.props import PropsTransform class SerializeTransform(PropsTransform): def __init__(self, serialize_map): """ { "keystore": serializer } :param serialize_map: :type serialize_map: """ transform_map = {} reverse_map = {} for key, val in serialize_map: transform_map[key] = lambda key, val: key, serialize_map[key].serialize(val) reverse_map[key] = lambda key, val: key, serialize_map[key].deserialize(val) super(SerializeTransform, self).__init__(transform_map=transform_map, reverse_map=reverse_map) yowsup-3.2.3/yowsup/config/v1/000077500000000000000000000000001346433372600162415ustar00rootroot00000000000000yowsup-3.2.3/yowsup/config/v1/__init__.py000066400000000000000000000000001346433372600203400ustar00rootroot00000000000000yowsup-3.2.3/yowsup/config/v1/config.py000066400000000000000000000102111346433372600200530ustar00rootroot00000000000000from yowsup.config.base import config import logging logger = logging.getLogger(__name__) class Config(config.Config): def __init__( self, phone=None, cc=None, password=None, pushname=None, id=None, mcc=None, mnc=None, sim_mcc=None, sim_mnc=None, client_static_keypair=None, server_static_public=None, expid=None, fdid=None, edge_routing_info=None, chat_dns_domain=None ): super(Config, self).__init__(1) self._phone = str(phone) if phone is not None else None # type: str self._cc = cc # type: int self._password = password # type: str self._pushname = pushname # type: str self._id = id self._client_static_keypair = client_static_keypair self._server_static_public = server_static_public self._expid = expid self._fdid = fdid self._mcc = mcc self._mnc = mnc self._sim_mcc = sim_mcc self._sim_mnc = sim_mnc self._edge_routing_info = edge_routing_info self._chat_dns_domain = chat_dns_domain if self._password is not None: logger.warn("Setting a password in Config is deprecated and not used anymore. " "client_static_keypair is used instead") def __str__(self): from yowsup.config.v1.serialize import ConfigSerialize from yowsup.config.transforms.dict_json import DictJsonTransform return DictJsonTransform().transform(ConfigSerialize(self.__class__).serialize(self)) @property def phone(self): return self._phone @phone.setter def phone(self, value): self._phone = str(value) if value is not None else None @property def cc(self): return self._cc @cc.setter def cc(self, value): self._cc = value @property def password(self): return self._password @password.setter def password(self, value): self._password = value if value is not None: logger.warn("Setting a password in Config is deprecated and not used anymore. " "client_static_keypair is used instead") @property def pushname(self): return self._pushname @pushname.setter def pushname(self, value): self._pushname = value @property def mcc(self): return self._mcc @mcc.setter def mcc(self, value): self._mcc = value @property def mnc(self): return self._mnc @mnc.setter def mnc(self, value): self._mnc = value @property def sim_mcc(self): return self._sim_mcc @sim_mcc.setter def sim_mcc(self, value): self._sim_mcc = value @property def sim_mnc(self): return self._sim_mnc @sim_mnc.setter def sim_mnc(self, value): self._sim_mnc = value @property def id(self): return self._id @id.setter def id(self, value): self._id = value @property def client_static_keypair(self): return self._client_static_keypair @client_static_keypair.setter def client_static_keypair(self, value): self._client_static_keypair = value @property def server_static_public(self): return self._server_static_public @server_static_public.setter def server_static_public(self, value): self._server_static_public = value @property def expid(self): return self._expid @expid.setter def expid(self, value): self._expid = value @property def fdid(self): return self._fdid @fdid.setter def fdid(self, value): self._fdid = value @property def edge_routing_info(self): return self._edge_routing_info @edge_routing_info.setter def edge_routing_info(self, value): self._edge_routing_info = value @property def chat_dns_domain(self): return self._chat_dns_domain @chat_dns_domain.setter def chat_dns_domain(self, value): self._chat_dns_domain = value yowsup-3.2.3/yowsup/config/v1/serialize.py000066400000000000000000000042041346433372600206020ustar00rootroot00000000000000from yowsup.config.base import serialize from yowsup.config.transforms.filter import FilterTransform from yowsup.config.transforms.meta import MetaPropsTransform from yowsup.config.transforms.map import MapTransform from yowsup.config.transforms.config_dict import ConfigDictTransform from yowsup.config.transforms.props import PropsTransform from consonance.structs.keypair import KeyPair from consonance.structs.publickey import PublicKey import base64 class ConfigSerialize(serialize.ConfigSerialize): def __init__(self, config_class): super(ConfigSerialize, self).__init__( transforms=( ConfigDictTransform(config_class), FilterTransform( transform_filter=lambda key, val: val is not None, reverse_filter=lambda key, val: key != "version" ), MapTransform(transform_map=lambda key, val: (key[1:], val)), PropsTransform( transform_map={ "server_static_public": lambda key, val: (key, base64.b64encode(val.data).decode()), "client_static_keypair": lambda key, val: (key, base64.b64encode(val.private.data + val.public.data).decode()), "id": lambda key, val: (key, base64.b64encode(val).decode()), "expid": lambda key, val: (key, base64.b64encode(val).decode()), "edge_routing_info": lambda key, val: (key, base64.b64encode(val).decode()) }, reverse_map={ "server_static_public": lambda key, val: (key, PublicKey(base64.b64decode(val))), "client_static_keypair": lambda key, val: (key, KeyPair.from_bytes(base64.b64decode(val))), "id": lambda key, val: (key, base64.b64decode(val)), "expid": lambda key, val: (key, base64.b64decode(val)), "edge_routing_info": lambda key, val: (key, base64.b64decode(val)) } ), MetaPropsTransform(meta_props=("version", )), ) ) yowsup-3.2.3/yowsup/demos/000077500000000000000000000000001346433372600155555ustar00rootroot00000000000000yowsup-3.2.3/yowsup/demos/__init__.py000066400000000000000000000000001346433372600176540ustar00rootroot00000000000000yowsup-3.2.3/yowsup/demos/cli/000077500000000000000000000000001346433372600163245ustar00rootroot00000000000000yowsup-3.2.3/yowsup/demos/cli/__init__.py000066400000000000000000000000421346433372600204310ustar00rootroot00000000000000from .stack import YowsupCliStack yowsup-3.2.3/yowsup/demos/cli/cli.py000066400000000000000000000136071346433372600174540ustar00rootroot00000000000000import threading, inspect, shlex try: import Queue except ImportError: import queue as Queue try: import readline except ImportError: import pyreadline as readline class clicmd(object): def __init__(self, desc, order = 0): self.desc = desc self.order = order def __call__(self, fn): fn.clidesc = self.desc fn.cliorder = self.order return fn class Cli(object): def __init__(self): self.sentCache = {} self.commands = {} self.acceptingInput = False self.lastPrompt = True self.blockingQueue = Queue.Queue() self._queuedCmds = [] readline.set_completer(self.complete) readline.parse_and_bind('tab: complete') members = inspect.getmembers(self, predicate = inspect.ismethod) for m in members: if hasattr(m[1], "clidesc"): fname = m[0] fn = m[1] try: cmd, subcommand = fname.split('_') except ValueError: cmd = fname subcommand = "_" if not cmd in self.commands: self.commands[cmd] = {} self.commands[cmd][subcommand] = { "args": inspect.getargspec(fn)[0][1:], "optional": len(inspect.getargspec(fn)[3]) if inspect.getargspec(fn)[3] else 0, "desc": fn.clidesc, "fn": fn, "order": fn.cliorder } #self.cv = threading.Condition() self.inputThread = threading.Thread(target = self.startInputThread) self.inputThread.daemon = True def queueCmd(self, cmd): self._queuedCmds.append(cmd) def startInput(self): self.inputThread.start() ################### cmd input parsing #################### def print_usage(self): line_width = 100 outArr = [] def addToOut(ind, cmd): if ind >= len(outArr): outArr.extend([None] * (ind - len(outArr) + 1)) if outArr[ind] != None: for i in range(len(outArr) - 1, 0, -1): if outArr[i] is None: outArr[i] = outArr[ind] outArr[ind] = cmd return outArr.append(cmd) else: outArr[ind] = cmd for cmd, subcommands in self.commands.items(): for subcmd, subcmdDetails in subcommands.items(): out = "" out += ("/%s " % cmd).ljust(15) out += ("%s " % subcmd if subcmd != "_" else "").ljust(15) args = ("%s " % " ".join(["<%s>" % c for c in subcmdDetails["args"][0:len(subcmdDetails["args"])-subcmdDetails["optional"]]])) args += ("%s " % " ".join(["[%s]" % c for c in subcmdDetails["args"][len(subcmdDetails["args"])-subcmdDetails["optional"]:]])) out += args.ljust(30) out += subcmdDetails["desc"].ljust(20) addToOut(subcmdDetails["order"], out) print("----------------------------------------------") print("\n" . join(outArr)) print("----------------------------------------------") def execCmd(self, cmdInput): cmdInput = cmdInput.rstrip() if not len(cmdInput) > 1: return if cmdInput.startswith("/"): cmdInput = cmdInput[1:] else: self.print_usage() return cmdInputDissect = [c for c in shlex.split(cmdInput) if c] cmd = cmdInputDissect[0] if not cmd in self.commands: return self.print_usage() cmdData = self.commands[cmd] if len(cmdData) == 1 and "_" in cmdData: subcmdData = cmdData["_"] args = cmdInputDissect[1:] if len(cmdInputDissect) > 1 else [] else: args = cmdInputDissect[2:] if len(cmdInputDissect) > 2 else [] subcmd = cmdInputDissect[1] if len(cmdInputDissect) > 1 else "" if subcmd not in cmdData: return self.print_usage() subcmdData = cmdData[subcmd] targetFn = subcmdData["fn"] if len(subcmdData["args"]) < len(args) or len(subcmdData["args"]) - subcmdData["optional"] > len(args): return self.print_usage() return self.doExecCmd(lambda :targetFn(*args)) def doExecCmd(self, fn): return fn() def startInputThread(self): #cv.acquire() # Fix Python 2.x. global input try: input = raw_input except NameError: pass while(True): cmd = self._queuedCmds.pop(0) if len(self._queuedCmds) else input(self.getPrompt()).strip() wait = self.execCmd(cmd) if wait: self.acceptingInput = False self.blockingQueue.get(True) #cv.wait() #self.inputThread.wait() self.acceptingInput = True #cv.release() def getPrompt(self): return "[%s]:" % ("connected" if self.connected else "offline") def printPrompt(self): #return "Enter Message or command: (/%s)" % ", /".join(self.commandMappings) print(self.getPrompt()) def output(self, message, tag = "general", prompt = True): if self.acceptingInput == True and self.lastPrompt is True: print("") self.lastPrompt = prompt if tag is not None: print("%s: %s" % (tag, message)) else: print(message) if prompt: self.printPrompt() def complete(self, text, state): if state == 0: for cmd in self.commands: if cmd.startswith(text) and cmd != text: return cmd def notifyInputThread(self): self.blockingQueue.put(1) if __name__ == "__main__": c = Cli() c.print_usage() yowsup-3.2.3/yowsup/demos/cli/layer.py000066400000000000000000000600131346433372600200120ustar00rootroot00000000000000from .cli import Cli, clicmd from yowsup.layers.interface import YowInterfaceLayer, ProtocolEntityCallback from yowsup.layers.auth import YowAuthenticationProtocolLayer from yowsup.layers import YowLayerEvent, EventCallback from yowsup.layers.network import YowNetworkLayer import sys from yowsup.common import YowConstants import datetime import os import logging import threading import base64 from yowsup.layers.protocol_groups.protocolentities import * from yowsup.layers.protocol_presence.protocolentities import * from yowsup.layers.protocol_messages.protocolentities import * from yowsup.layers.protocol_ib.protocolentities import * from yowsup.layers.protocol_iq.protocolentities import * from yowsup.layers.protocol_contacts.protocolentities import * from yowsup.layers.protocol_chatstate.protocolentities import * from yowsup.layers.protocol_privacy.protocolentities import * from yowsup.layers.protocol_media.protocolentities import * from yowsup.layers.protocol_media.mediauploader import MediaUploader from yowsup.layers.protocol_profiles.protocolentities import * from yowsup.common.tools import Jid from yowsup.common.optionalmodules import PILOptionalModule from yowsup.layers.axolotl.protocolentities.iq_key_get import GetKeysIqProtocolEntity logger = logging.getLogger(__name__) class YowsupCliLayer(Cli, YowInterfaceLayer): PROP_RECEIPT_AUTO = "org.openwhatsapp.yowsup.prop.cli.autoreceipt" PROP_RECEIPT_KEEPALIVE = "org.openwhatsapp.yowsup.prop.cli.keepalive" PROP_CONTACT_JID = "org.openwhatsapp.yowsup.prop.cli.contact.jid" EVENT_LOGIN = "org.openwhatsapp.yowsup.event.cli.login" EVENT_START = "org.openwhatsapp.yowsup.event.cli.start" EVENT_SENDANDEXIT = "org.openwhatsapp.yowsup.event.cli.sendandexit" MESSAGE_FORMAT = "[%s(%s)]:[%s]\t %s" FAIL_OPT_PILLOW = "No PIL library installed, try install pillow" FAIL_OPT_AXOLOTL = "axolotl is not installed, try install python-axolotl" DISCONNECT_ACTION_PROMPT = 0 DISCONNECT_ACTION_EXIT = 1 ACCOUNT_DEL_WARNINGS = 4 def __init__(self): super(YowsupCliLayer, self).__init__() YowInterfaceLayer.__init__(self) self.accountDelWarnings = 0 self.connected = False self.username = None self.sendReceipts = True self.sendRead = True self.disconnectAction = self.__class__.DISCONNECT_ACTION_PROMPT self.credentials = None #add aliases to make it user to use commands. for example you can then do: # /message send foobar "HI" # and then it will get automaticlaly mapped to foobar's jid self.jidAliases = { # "NAME": "PHONE@s.whatsapp.net" } def aliasToJid(self, calias): for alias, ajid in self.jidAliases.items(): if calias.lower() == alias.lower(): return Jid.normalize(ajid) return Jid.normalize(calias) def jidToAlias(self, jid): for alias, ajid in self.jidAliases.items(): if ajid == jid: return alias return jid def setCredentials(self, username, keypair): self.getLayerInterface(YowAuthenticationProtocolLayer).setCredentials(username, keypair) return "%s@s.whatsapp.net" % username @EventCallback(EVENT_START) def onStart(self, layerEvent): self.startInput() return True @EventCallback(EVENT_SENDANDEXIT) def onSendAndExit(self, layerEvent): credentials = layerEvent.getArg("credentials") target = layerEvent.getArg("target") message = layerEvent.getArg("message") self.sendMessageAndDisconnect(credentials, target, message) return True @EventCallback(YowNetworkLayer.EVENT_STATE_DISCONNECTED) def onStateDisconnected(self,layerEvent): self.output("Disconnected: %s" % layerEvent.getArg("reason")) if self.disconnectAction == self.__class__.DISCONNECT_ACTION_PROMPT: self.connected = False self.notifyInputThread() else: os._exit(os.EX_OK) def assertConnected(self): if self.connected: return True else: self.output("Not connected", tag = "Error", prompt = False) return False #### batch cmds ##### def sendMessageAndDisconnect(self, credentials, jid, message): self.disconnectAction = self.__class__.DISCONNECT_ACTION_EXIT self.queueCmd("/login %s %s" % credentials) self.queueCmd("/message send %s \"%s\" wait" % (jid, message)) self.queueCmd("/disconnect") self.startInput() ########## PRESENCE ############### @clicmd("Set presence name") def presence_name(self, name): if self.assertConnected(): entity = PresenceProtocolEntity(name = name) self.toLower(entity) @clicmd("Set presence as available") def presence_available(self): if self.assertConnected(): entity = AvailablePresenceProtocolEntity() self.toLower(entity) @clicmd("Set presence as unavailable") def presence_unavailable(self): if self.assertConnected(): entity = UnavailablePresenceProtocolEntity() self.toLower(entity) @clicmd("Unsubscribe from contact's presence updates") def presence_unsubscribe(self, contact): if self.assertConnected(): entity = UnsubscribePresenceProtocolEntity(self.aliasToJid(contact)) self.toLower(entity) @clicmd("Subscribe to contact's presence updates") def presence_subscribe(self, contact): if self.assertConnected(): entity = SubscribePresenceProtocolEntity(self.aliasToJid(contact)) self.toLower(entity) ########### END PRESENCE ############# ########### ib ####################### @clicmd("Send clean dirty") def ib_clean(self, dirtyType): if self.assertConnected(): entity = CleanIqProtocolEntity("groups", YowConstants.DOMAIN) self.toLower(entity) @clicmd("Ping server") def ping(self): if self.assertConnected(): entity = PingIqProtocolEntity(to = YowConstants.DOMAIN) self.toLower(entity) ###################################### ####### contacts/ profiles #################### @clicmd("Set status text") def profile_setStatus(self, text): if self.assertConnected(): def onSuccess(resultIqEntity, originalIqEntity): self.output("Status updated successfully") def onError(errorIqEntity, originalIqEntity): logger.error("Error updating status") entity = SetStatusIqProtocolEntity(text) self._sendIq(entity, onSuccess, onError) @clicmd("Get profile picture for contact") def contact_picture(self, jid): if self.assertConnected(): entity = GetPictureIqProtocolEntity(self.aliasToJid(jid), preview=False) self._sendIq(entity, self.onGetContactPictureResult) @clicmd("Get profile picture preview for contact") def contact_picturePreview(self, jid): if self.assertConnected(): entity = GetPictureIqProtocolEntity(self.aliasToJid(jid), preview=True) self._sendIq(entity, self.onGetContactPictureResult) @clicmd("Get lastseen for contact") def contact_lastseen(self, jid): if self.assertConnected(): def onSuccess(resultIqEntity, originalIqEntity): self.output("%s lastseen %s seconds ago" % (resultIqEntity.getFrom(), resultIqEntity.getSeconds())) def onError(errorIqEntity, originalIqEntity): logger.error("Error getting lastseen information for %s" % originalIqEntity.getTo()) entity = LastseenIqProtocolEntity(self.aliasToJid(jid)) self._sendIq(entity, onSuccess, onError) @clicmd("Set profile picture") def profile_setPicture(self, path): if self.assertConnected(): with PILOptionalModule(failMessage = "No PIL library installed, try install pillow") as imp: Image = imp("Image") def onSuccess(resultIqEntity, originalIqEntity): self.output("Profile picture updated successfully") def onError(errorIqEntity, originalIqEntity): logger.error("Error updating profile picture") #example by @aesedepece in https://github.com/tgalal/yowsup/pull/781 #modified to support python3 src = Image.open(path) pictureData = src.resize((640, 640)).tobytes("jpeg", "RGB") picturePreview = src.resize((96, 96)).tobytes("jpeg", "RGB") iq = SetPictureIqProtocolEntity(self.getOwnJid(), picturePreview, pictureData) self._sendIq(iq, onSuccess, onError) @clicmd("Get profile privacy") def profile_getPrivacy(self): if self.assertConnected(): def onSuccess(resultIqEntity, originalIqEntity): self.output("Profile privacy is: %s" %(resultIqEntity)) def onError(errorIqEntity, originalIqEntity): logger.error("Error getting profile privacy") iq = GetPrivacyIqProtocolEntity() self._sendIq(iq, onSuccess, onError) @clicmd("Profile privacy. value=all|contacts|none names=profile|status|last. Names are comma separated, defaults to all.") def profile_setPrivacy(self, value="all", names=None): if self.assertConnected(): def onSuccess(resultIqEntity, originalIqEntity): self.output("Profile privacy set to: %s" %(resultIqEntity)) def onError(errorIqEntity, originalIqEntity): logger.error("Error setting profile privacy") try: names = [name for name in names.split(',')] if names else None iq = SetPrivacyIqProtocolEntity(value, names) self._sendIq(iq, onSuccess, onError) except Exception as inst: self.output(inst.message) return self.print_usage() ########### groups @clicmd("List all groups you belong to", 5) def groups_list(self): if self.assertConnected(): entity = ListGroupsIqProtocolEntity() self.toLower(entity) @clicmd("Leave a group you belong to", 4) def group_leave(self, group_jid): if self.assertConnected(): entity = LeaveGroupsIqProtocolEntity([self.aliasToJid(group_jid)]) self.toLower(entity) @clicmd("Create a new group with the specified subject and participants. Jids are a comma separated list but optional.", 3) def groups_create(self, subject, jids = None): if self.assertConnected(): jids = [self.aliasToJid(jid) for jid in jids.split(',')] if jids else [] entity = CreateGroupsIqProtocolEntity(subject, participants=jids) self.toLower(entity) @clicmd("Invite to group. Jids are a comma separated list") def group_invite(self, group_jid, jids): if self.assertConnected(): jids = [self.aliasToJid(jid) for jid in jids.split(',')] entity = AddParticipantsIqProtocolEntity(self.aliasToJid(group_jid), jids) self.toLower(entity) @clicmd("Promote admin of a group. Jids are a comma separated list") def group_promote(self, group_jid, jids): if self.assertConnected(): jids = [self.aliasToJid(jid) for jid in jids.split(',')] entity = PromoteParticipantsIqProtocolEntity(self.aliasToJid(group_jid), jids) self.toLower(entity) @clicmd("Remove admin of a group. Jids are a comma separated list") def group_demote(self, group_jid, jids): if self.assertConnected(): jids = [self.aliasToJid(jid) for jid in jids.split(',')] entity = DemoteParticipantsIqProtocolEntity(self.aliasToJid(group_jid), jids) self.toLower(entity) @clicmd("Kick from group. Jids are a comma separated list") def group_kick(self, group_jid, jids): if self.assertConnected(): jids = [self.aliasToJid(jid) for jid in jids.split(',')] entity = RemoveParticipantsIqProtocolEntity(self.aliasToJid(group_jid), jids) self.toLower(entity) @clicmd("Change group subject") def group_setSubject(self, group_jid, subject): if self.assertConnected(): entity = SubjectGroupsIqProtocolEntity(self.aliasToJid(group_jid), subject) self.toLower(entity) @clicmd("Set group picture") def group_picture(self, group_jid, path): if self.assertConnected(): with PILOptionalModule(failMessage = self.__class__.FAIL_OPT_PILLOW) as imp: Image = imp("Image") def onSuccess(resultIqEntity, originalIqEntity): self.output("Group picture updated successfully") def onError(errorIqEntity, originalIqEntity): logger.error("Error updating Group picture") #example by @aesedepece in https://github.com/tgalal/yowsup/pull/781 #modified to support python3 src = Image.open(path) pictureData = src.resize((640, 640)).tobytes("jpeg", "RGB") picturePreview = src.resize((96, 96)).tobytes("jpeg", "RGB") iq = SetPictureIqProtocolEntity(self.aliasToJid(group_jid), picturePreview, pictureData) self._sendIq(iq, onSuccess, onError) @clicmd("Get group info") def group_info(self, group_jid): if self.assertConnected(): entity = InfoGroupsIqProtocolEntity(self.aliasToJid(group_jid)) self.toLower(entity) @clicmd("Get shared keys") def keys_get(self, jids): if self.assertConnected(): jids = [self.aliasToJid(jid) for jid in jids.split(',')] entity = GetKeysIqProtocolEntity(jids) self.toLower(entity) @clicmd("Send init seq") def seq(self): priv = PrivacyListIqProtocolEntity() self.toLower(priv) push = PushIqProtocolEntity() self.toLower(push) props = PropsIqProtocolEntity() self.toLower(props) crypto = CryptoIqProtocolEntity() self.toLower(crypto) @clicmd("Delete your account") def account_delete(self): if self.assertConnected(): if self.accountDelWarnings < self.__class__.ACCOUNT_DEL_WARNINGS: self.accountDelWarnings += 1 remaining = self.__class__.ACCOUNT_DEL_WARNINGS - self.accountDelWarnings self.output("Repeat delete command another %s times to send the delete request" % remaining, tag="Account delete Warning !!", prompt = False) else: entity = UnregisterIqProtocolEntity() self.toLower(entity) @clicmd("Send message to a friend") def message_send(self, number, content): if self.assertConnected(): outgoingMessage = TextMessageProtocolEntity(content, to=self.aliasToJid(number)) self.toLower(outgoingMessage) @clicmd("Broadcast message. numbers should comma separated phone numbers") def message_broadcast(self, numbers, content): if self.assertConnected(): jids = [self.aliasToJid(number) for number in numbers.split(',')] outgoingMessage = BroadcastTextMessage(jids, content) self.toLower(outgoingMessage) #@clicmd("Send read receipt") def message_read(self, message_id): pass #@clicmd("Send delivered receipt") def message_delivered(self, message_id): pass @clicmd("Send a video with optional caption") def video_send(self, number, path, caption = None): self.media_send(number, path, RequestUploadIqProtocolEntity.MEDIA_TYPE_VIDEO) @clicmd("Send an image with optional caption") def image_send(self, number, path, caption = None): self.media_send(number, path, RequestUploadIqProtocolEntity.MEDIA_TYPE_IMAGE) @clicmd("Send audio file") def audio_send(self, number, path): self.media_send(number, path, RequestUploadIqProtocolEntity.MEDIA_TYPE_AUDIO) def media_send(self, number, path, mediaType, caption = None): if self.assertConnected(): jid = self.aliasToJid(number) entity = RequestUploadIqProtocolEntity(mediaType, filePath=path) successFn = lambda successEntity, originalEntity: self.onRequestUploadResult(jid, mediaType, path, successEntity, originalEntity, caption) errorFn = lambda errorEntity, originalEntity: self.onRequestUploadError(jid, path, errorEntity, originalEntity) self._sendIq(entity, successFn, errorFn) @clicmd("Send typing state") def state_typing(self, jid): if self.assertConnected(): entity = OutgoingChatstateProtocolEntity(ChatstateProtocolEntity.STATE_TYPING, self.aliasToJid(jid)) self.toLower(entity) @clicmd("Request contacts statuses") def statuses_get(self, contacts): if self.assertConnected(): entity = GetStatusesIqProtocolEntity([self.aliasToJid(c) for c in contacts.split(',')]) self.toLower(entity) @clicmd("Send paused state") def state_paused(self, jid): if self.assertConnected(): entity = OutgoingChatstateProtocolEntity(ChatstateProtocolEntity.STATE_PAUSED, self.aliasToJid(jid)) self.toLower(entity) @clicmd("Sync contacts, contacts should be comma separated phone numbers, with no spaces") def contacts_sync(self, contacts): if self.assertConnected(): entity = GetSyncIqProtocolEntity(contacts.split(',')) self.toLower(entity) @clicmd("Disconnect") def disconnect(self): if self.assertConnected(): self.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_DISCONNECT)) @clicmd("Quick login") def L(self): if self.connected: return self.output("Already connected, disconnect first") threading.Thread(target=lambda: self.getLayerInterface(YowNetworkLayer).connect()).start() return True ######## receive ######### @ProtocolEntityCallback("chatstate") def onChatstate(self, entity): print(entity) @ProtocolEntityCallback("iq") def onIq(self, entity): print(entity) @ProtocolEntityCallback("receipt") def onReceipt(self, entity): self.toLower(entity.ack()) @ProtocolEntityCallback("ack") def onAck(self, entity): #formattedDate = datetime.datetime.fromtimestamp(self.sentCache[entity.getId()][0]).strftime('%d-%m-%Y %H:%M') #print("%s [%s]:%s"%(self.username, formattedDate, self.sentCache[entity.getId()][1])) if entity.getClass() == "message": self.output(entity.getId(), tag = "Sent") #self.notifyInputThread() @ProtocolEntityCallback("success") def onSuccess(self, entity): self.connected = True self.output("Logged in!", "Auth", prompt = False) self.notifyInputThread() @ProtocolEntityCallback("failure") def onFailure(self, entity): self.connected = False self.output("Login Failed, reason: %s" % entity.getReason(), prompt = False) @ProtocolEntityCallback("notification") def onNotification(self, notification): notificationData = notification.__str__() if notificationData: self.output(notificationData, tag = "Notification") else: self.output("From :%s, Type: %s" % (self.jidToAlias(notification.getFrom()), notification.getType()), tag = "Notification") @ProtocolEntityCallback("message") def onMessage(self, message): messageOut = "" if message.getType() == "text": #self.output(message.getBody(), tag = "%s [%s]"%(message.getFrom(), formattedDate)) messageOut = self.getTextMessageBody(message) elif message.getType() == "media": messageOut = self.getMediaMessageBody(message) else: messageOut = "Unknown message type %s " % message.getType() print(messageOut.toProtocolTreeNode()) formattedDate = datetime.datetime.fromtimestamp(message.getTimestamp()).strftime('%d-%m-%Y %H:%M') sender = message.getFrom() if not message.isGroupMessage() else "%s/%s" % (message.getParticipant(False), message.getFrom()) output = self.__class__.MESSAGE_FORMAT % (sender, formattedDate, message.getId(), messageOut) self.output(output, tag = None, prompt = not self.sendReceipts) if self.sendReceipts: self.toLower(message.ack(self.sendRead)) self.output("Sent delivered receipt"+" and Read" if self.sendRead else "", tag = "Message %s" % message.getId()) def getTextMessageBody(self, message): return message.getBody() def getMediaMessageBody(self, message): if message.media_type in ("image", "audio", "video", "document"): return self.getDownloadableMediaMessageBody(message) else: return "[Media Type: %s]" % message.media_type def getDownloadableMediaMessageBody(self, message): return "[media_type={media_type}, length={media_size}, url={media_url}, key={media_key}]".format( media_type=message.media_type, media_size=message.file_length, media_url=message.url, media_key=base64.b64encode(message.media_key) ) def doSendMedia(self, mediaType, filePath, url, to, ip = None, caption = None): if mediaType == RequestUploadIqProtocolEntity.MEDIA_TYPE_IMAGE: entity = ImageDownloadableMediaMessageProtocolEntity.fromFilePath(filePath, url, ip, to, caption = caption) elif mediaType == RequestUploadIqProtocolEntity.MEDIA_TYPE_AUDIO: entity = AudioDownloadableMediaMessageProtocolEntity.fromFilePath(filePath, url, ip, to) elif mediaType == RequestUploadIqProtocolEntity.MEDIA_TYPE_VIDEO: entity = VideoDownloadableMediaMessageProtocolEntity.fromFilePath(filePath, url, ip, to, caption = caption) self.toLower(entity) def __str__(self): return "CLI Interface Layer" ########### callbacks ############ def onRequestUploadResult(self, jid, mediaType, filePath, resultRequestUploadIqProtocolEntity, requestUploadIqProtocolEntity, caption = None): if resultRequestUploadIqProtocolEntity.isDuplicate(): self.doSendMedia(mediaType, filePath, resultRequestUploadIqProtocolEntity.getUrl(), jid, resultRequestUploadIqProtocolEntity.getIp(), caption) else: successFn = lambda filePath, jid, url: self.doSendMedia(mediaType, filePath, url, jid, resultRequestUploadIqProtocolEntity.getIp(), caption) mediaUploader = MediaUploader(jid, self.getOwnJid(), filePath, resultRequestUploadIqProtocolEntity.getUrl(), resultRequestUploadIqProtocolEntity.getResumeOffset(), successFn, self.onUploadError, self.onUploadProgress, asynchronous=False) mediaUploader.start() def onRequestUploadError(self, jid, path, errorRequestUploadIqProtocolEntity, requestUploadIqProtocolEntity): logger.error("Request upload for file %s for %s failed" % (path, jid)) def onUploadError(self, filePath, jid, url): logger.error("Upload file %s to %s for %s failed!" % (filePath, url, jid)) def onUploadProgress(self, filePath, jid, url, progress): sys.stdout.write("%s => %s, %d%% \r" % (os.path.basename(filePath), jid, progress)) sys.stdout.flush() def onGetContactPictureResult(self, resultGetPictureIqProtocolEntiy, getPictureIqProtocolEntity): # do here whatever you want # write to a file # or open # or do nothing # write to file example: #resultGetPictureIqProtocolEntiy.writeToFile("/tmp/yowpics/%s_%s.jpg" % (getPictureIqProtocolEntity.getTo(), "preview" if resultGetPictureIqProtocolEntiy.isPreview() else "full")) pass def __str__(self): return "CLI Interface Layer" @clicmd("Print this message") def help(self): self.print_usage() yowsup-3.2.3/yowsup/demos/cli/stack.py000066400000000000000000000016531346433372600200100ustar00rootroot00000000000000from yowsup.stacks import YowStackBuilder from .layer import YowsupCliLayer from yowsup.layers import YowLayerEvent from yowsup.layers.axolotl.props import PROP_IDENTITY_AUTOTRUST import sys class YowsupCliStack(object): def __init__(self, credentials): stackBuilder = YowStackBuilder() self._stack = stackBuilder\ .pushDefaultLayers()\ .push(YowsupCliLayer)\ .build() self._stack.setCredentials(credentials) self._stack.setProp(PROP_IDENTITY_AUTOTRUST, True) def set_prop(self, prop, val): self._stack.setProp(prop, val) def start(self): print("Yowsup Cli client\n==================\nType /help for available commands\n") self._stack.broadcastEvent(YowLayerEvent(YowsupCliLayer.EVENT_START)) try: self._stack.loop() except KeyboardInterrupt: print("\nYowsdown") sys.exit(0) yowsup-3.2.3/yowsup/demos/common/000077500000000000000000000000001346433372600170455ustar00rootroot00000000000000yowsup-3.2.3/yowsup/demos/common/__init__.py000066400000000000000000000000001346433372600211440ustar00rootroot00000000000000yowsup-3.2.3/yowsup/demos/common/sink_worker.py000066400000000000000000000145251346433372600217630ustar00rootroot00000000000000from yowsup.layers.protocol_media.mediacipher import MediaCipher from yowsup.layers.protocol_media.protocolentities \ import ImageDownloadableMediaMessageProtocolEntity, AudioDownloadableMediaMessageProtocolEntity,\ VideoDownloadableMediaMessageProtocolEntity, DocumentDownloadableMediaMessageProtocolEntity, \ ContactMediaMessageProtocolEntity, DownloadableMediaMessageProtocolEntity import threading from tqdm import tqdm import requests import logging import math import sys import os import base64 if sys.version_info >= (3, 0): from queue import Queue else: from Queue import Queue logger = logging.getLogger(__name__) class SinkWorker(threading.Thread): def __init__(self, storage_dir): super(SinkWorker, self).__init__() self.daemon = True self._storage_dir = storage_dir self._jobs = Queue() self._media_cipher = MediaCipher() def enqueue(self, media_message_protocolentity): self._jobs.put(media_message_protocolentity) def _create_progress_iterator(self, iterable, niterations, desc): return tqdm( iterable, total=niterations, unit='KB', dynamic_ncols=True, unit_scale=True, leave=True, desc=desc, ascii=True) def _download(self, url): response = requests.get(url, stream=True) total_size = int(response.headers.get('content-length', 0)) logger.debug("%s total size is %s, downloading" % (url, total_size)) block_size = 1024 wrote = 0 enc_data = b"" for data in self._create_progress_iterator( response.iter_content(block_size), math.ceil(total_size // block_size) + 1, "Download ", ): wrote = wrote + len(data) enc_data = enc_data + data if total_size != 0 and wrote != total_size: logger.error("Something went wrong") return None return enc_data def _decrypt(self, ciphertext, ref_key, media_info): length_kb = int(math.ceil(len(ciphertext) / 1024)) progress = self._create_progress_iterator(range(length_kb), length_kb, "Decrypt ") try: plaintext = self._media_cipher.decrypt(ciphertext, ref_key, media_info) progress.update(length_kb) return plaintext except Exception as e: progress.set_description("Decrypt Error ") logger.error(e) return None def _write(self, data, filename): length_kb = int(math.ceil(len(data) / 1024)) progress = self._create_progress_iterator(range(length_kb), length_kb, "Write ") try: with open(filename, 'wb') as f: f.write(data) progress.update(length_kb) return filename except Exception as e: progress.set_description("Write error ") logger.error(e) return None def _create_unique_filepath(self, filepath): file_dir = os.path.dirname(filepath) filename = os.path.basename(filepath) result_filename = filename dissected = os.path.splitext(filename) count = 0 while os.path.exists(os.path.join(file_dir, result_filename)): count += 1 result_filename = "%s_%d%s" % (dissected[0], count, dissected[1]) return os.path.join(file_dir, result_filename) def run(self): logger.debug( "SinkWorker started, storage_dir=%s" % self._storage_dir ) while True: media_message_protocolentity = self._jobs.get() if media_message_protocolentity is None: sys.exit(0) if isinstance(media_message_protocolentity, DownloadableMediaMessageProtocolEntity): logger.info( "Processing [url=%s, media_key=%s]" % (media_message_protocolentity.url, base64.b64encode(media_message_protocolentity.media_key)) ) else: logger.info("Processing %s" % media_message_protocolentity.media_type) filedata = None fileext = None if isinstance(media_message_protocolentity, ImageDownloadableMediaMessageProtocolEntity): media_info = MediaCipher.INFO_IMAGE filename = "image" elif isinstance(media_message_protocolentity, AudioDownloadableMediaMessageProtocolEntity): media_info = MediaCipher.INFO_AUDIO filename = "ptt" if media_message_protocolentity.ptt else "audio" elif isinstance(media_message_protocolentity, VideoDownloadableMediaMessageProtocolEntity): media_info = MediaCipher.INFO_VIDEO filename = "video" elif isinstance(media_message_protocolentity, DocumentDownloadableMediaMessageProtocolEntity): media_info = MediaCipher.INFO_DOCUM filename = media_message_protocolentity.file_name elif isinstance(media_message_protocolentity, ContactMediaMessageProtocolEntity): filename = media_message_protocolentity.display_name filedata = media_message_protocolentity.vcard fileext = "vcard" else: logger.error("Unsupported Media type: %s" % media_message_protocolentity.__class__) sys.exit(1) if filedata is None: enc_data = self._download(media_message_protocolentity.url) if enc_data is None: logger.error("Download failed") sys.exit(1) filedata = self._decrypt(enc_data, media_message_protocolentity.media_key, media_info) if filedata is None: logger.error("Decrypt failed") sys.exit(1) if not isinstance(media_message_protocolentity, DocumentDownloadableMediaMessageProtocolEntity): if fileext is None: fileext = media_message_protocolentity.mimetype.split('/')[1].split(';')[0] filename_full = "%s.%s" % (filename, fileext) else: filename_full = filename filepath = self._create_unique_filepath(os.path.join(self._storage_dir, filename_full)) if self._write(filedata, filepath): logger.info("Wrote %s" % filepath) else: sys.exit(1) yowsup-3.2.3/yowsup/demos/contacts/000077500000000000000000000000001346433372600173735ustar00rootroot00000000000000yowsup-3.2.3/yowsup/demos/contacts/__init__.py000066400000000000000000000000431346433372600215010ustar00rootroot00000000000000from .stack import YowsupSyncStack yowsup-3.2.3/yowsup/demos/contacts/layer.py000066400000000000000000000023161346433372600210630ustar00rootroot00000000000000from yowsup.layers.interface import YowInterfaceLayer, ProtocolEntityCallback from yowsup.layers.protocol_contacts.protocolentities import GetSyncIqProtocolEntity, ResultSyncIqProtocolEntity from yowsup.layers.protocol_iq.protocolentities import ErrorIqProtocolEntity import threading import logging logger = logging.getLogger(__name__) class SyncLayer(YowInterfaceLayer): PROP_CONTACTS = "org.openwhatsapp.yowsup.prop.syncdemo.contacts" def __init__(self): super(SyncLayer, self).__init__() #call back function when there is a successful connection to whatsapp server @ProtocolEntityCallback("success") def onSuccess(self, successProtocolEntity): contacts= self.getProp(self.__class__.PROP_CONTACTS, []) contactEntity = GetSyncIqProtocolEntity(contacts) self._sendIq(contactEntity, self.onGetSyncResult, self.onGetSyncError) def onGetSyncResult(self, resultSyncIqProtocolEntity, originalIqProtocolEntity): print(resultSyncIqProtocolEntity) raise KeyboardInterrupt() def onGetSyncError(self, errorSyncIqProtocolEntity, originalIqProtocolEntity): print(errorSyncIqProtocolEntity) raise KeyboardInterrupt() yowsup-3.2.3/yowsup/demos/contacts/stack.py000066400000000000000000000017241346433372600210560ustar00rootroot00000000000000from .layer import SyncLayer from yowsup.stacks import YowStackBuilder from yowsup.layers import YowLayerEvent from yowsup.layers.auth import YowAuthenticationProtocolLayer from yowsup.layers.network import YowNetworkLayer class YowsupSyncStack(object): def __init__(self, credentials, contacts): """ :param credentials: :param contacts: list of [jid ] :return: """ stackBuilder = YowStackBuilder() self._stack = stackBuilder \ .pushDefaultLayers() \ .push(SyncLayer) \ .build() self._stack.setProp(SyncLayer.PROP_CONTACTS, contacts) self._stack.setProp(YowAuthenticationProtocolLayer.PROP_PASSIVE, True) self._stack.setCredentials(credentials) def set_prop(self, key, val): self._stack.setProp(key, val) def start(self): self._stack.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT)) self._stack.loop() yowsup-3.2.3/yowsup/demos/echoclient/000077500000000000000000000000001346433372600176725ustar00rootroot00000000000000yowsup-3.2.3/yowsup/demos/echoclient/__init__.py000066400000000000000000000000421346433372600217770ustar00rootroot00000000000000from .stack import YowsupEchoStackyowsup-3.2.3/yowsup/demos/echoclient/layer.py000066400000000000000000000031461346433372600213640ustar00rootroot00000000000000from yowsup.layers.interface import YowInterfaceLayer, ProtocolEntityCallback class EchoLayer(YowInterfaceLayer): @ProtocolEntityCallback("message") def onMessage(self, messageProtocolEntity): if messageProtocolEntity.getType() == 'text': self.onTextMessage(messageProtocolEntity) elif messageProtocolEntity.getType() == 'media': self.onMediaMessage(messageProtocolEntity) self.toLower(messageProtocolEntity.forward(messageProtocolEntity.getFrom())) self.toLower(messageProtocolEntity.ack()) self.toLower(messageProtocolEntity.ack(True)) @ProtocolEntityCallback("receipt") def onReceipt(self, entity): self.toLower(entity.ack()) def onTextMessage(self,messageProtocolEntity): # just print info print("Echoing %s to %s" % (messageProtocolEntity.getBody(), messageProtocolEntity.getFrom(False))) def onMediaMessage(self, messageProtocolEntity): # just print info if messageProtocolEntity.media_type == "image": print("Echoing image %s to %s" % (messageProtocolEntity.url, messageProtocolEntity.getFrom(False))) elif messageProtocolEntity.media_type == "location": print("Echoing location (%s, %s) to %s" % (messageProtocolEntity.getLatitude(), messageProtocolEntity.getLongitude(), messageProtocolEntity.getFrom(False))) elif messageProtocolEntity.media_type == "contact": print("Echoing contact (%s, %s) to %s" % (messageProtocolEntity.getName(), messageProtocolEntity.getCardData(), messageProtocolEntity.getFrom(False))) yowsup-3.2.3/yowsup/demos/echoclient/stack.py000066400000000000000000000012151346433372600213500ustar00rootroot00000000000000from yowsup.stacks import YowStackBuilder from .layer import EchoLayer from yowsup.layers import YowLayerEvent from yowsup.layers.network import YowNetworkLayer class YowsupEchoStack(object): def __init__(self, credentials): stackBuilder = YowStackBuilder() self._stack = stackBuilder\ .pushDefaultLayers()\ .push(EchoLayer)\ .build() self._stack.setCredentials(credentials) def set_prop(self, key, val): self._stack.setProp(key, val) def start(self): self._stack.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT)) self._stack.loop() yowsup-3.2.3/yowsup/demos/mediasink/000077500000000000000000000000001346433372600175215ustar00rootroot00000000000000yowsup-3.2.3/yowsup/demos/mediasink/__init__.py000066400000000000000000000000411346433372600216250ustar00rootroot00000000000000from .stack import MediaSinkStackyowsup-3.2.3/yowsup/demos/mediasink/layer.py000066400000000000000000000037571346433372600212230ustar00rootroot00000000000000from yowsup.layers.interface import YowInterfaceLayer, ProtocolEntityCallback from yowsup.layers.protocol_media.protocolentities import * from yowsup.layers.network.layer import YowNetworkLayer from yowsup.layers import EventCallback import sys try: from tqdm import tqdm import requests except ImportError: print("This demo requires the python packages 'tqdm' and 'requests' to be installed, exiting.") sys.exit(1) from ..common.sink_worker import SinkWorker import tempfile import logging import os logger = logging.getLogger(__name__) class MediaSinkLayer(YowInterfaceLayer): PROP_STORAGE_DIR = "org.openwhatsapp.yowsup.prop.demos.mediasink.storage_dir" def __init__(self): super(MediaSinkLayer, self).__init__() self._sink_worker = None @EventCallback(YowNetworkLayer.EVENT_STATE_CONNECTED) def on_connected(self, event): logger.info("Connected, starting SinkWorker") storage_dir = self.getProp(self.PROP_STORAGE_DIR) if storage_dir is None: logger.debug("No storage dir specified, creating tempdir") storage_dir = tempfile.mkdtemp("yowsup_mediasink") if not os.path.exists(storage_dir): logger.debug("%s does not exist, creating" % storage_dir) os.makedirs(storage_dir) logger.info("Storing incoming media to %s" % storage_dir) self._sink_worker = SinkWorker(storage_dir) self._sink_worker.start() @ProtocolEntityCallback("message") def on_message(self, message_protocolentity): self.toLower(message_protocolentity.ack()) self.toLower(message_protocolentity.ack(True)) if isinstance(message_protocolentity, MediaMessageProtocolEntity): self.on_media_message(message_protocolentity) @ProtocolEntityCallback("receipt") def on_receipt(self, entity): self.toLower(entity.ack()) def on_media_message(self, media_message_protocolentity): self._sink_worker.enqueue(media_message_protocolentity) yowsup-3.2.3/yowsup/demos/mediasink/stack.py000066400000000000000000000013611346433372600212010ustar00rootroot00000000000000from yowsup.stacks import YowStackBuilder from .layer import MediaSinkLayer from yowsup.layers import YowLayerEvent from yowsup.layers.network import YowNetworkLayer class MediaSinkStack(object): def __init__(self, credentials, storage_dir=None): stackBuilder = YowStackBuilder() self._stack = stackBuilder\ .pushDefaultLayers()\ .push(MediaSinkLayer)\ .build() self._stack.setProp(MediaSinkLayer.PROP_STORAGE_DIR, storage_dir) self._stack.setCredentials(credentials) def set_prop(self, key, val): self._stack.setProp(key, val) def start(self): self._stack.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT)) self._stack.loop() yowsup-3.2.3/yowsup/demos/sendclient/000077500000000000000000000000001346433372600177055ustar00rootroot00000000000000yowsup-3.2.3/yowsup/demos/sendclient/__init__.py000066400000000000000000000000421346433372600220120ustar00rootroot00000000000000from .stack import YowsupSendStackyowsup-3.2.3/yowsup/demos/sendclient/layer.py000066400000000000000000000037411346433372600214000ustar00rootroot00000000000000from yowsup.layers.interface import YowInterfaceLayer, ProtocolEntityCallback from yowsup.layers.protocol_messages.protocolentities import TextMessageProtocolEntity from yowsup.common.tools import Jid import threading import logging logger = logging.getLogger(__name__) class SendLayer(YowInterfaceLayer): #This message is going to be replaced by the @param message in YowsupSendStack construction #i.e. list of (jid, message) tuples PROP_MESSAGES = "org.openwhatsapp.yowsup.prop.sendclient.queue" def __init__(self): super(SendLayer, self).__init__() self.ackQueue = [] self.lock = threading.Condition() #call back function when there is a successful connection to whatsapp server @ProtocolEntityCallback("success") def onSuccess(self, successProtocolEntity): self.lock.acquire() for target in self.getProp(self.__class__.PROP_MESSAGES, []): #getProp() is trying to retreive the list of (jid, message) tuples, if none exist, use the default [] phone, message = target messageEntity = TextMessageProtocolEntity(message, to = Jid.normalize(phone)) #append the id of message to ackQueue list #which the id of message will be deleted when ack is received. self.ackQueue.append(messageEntity.getId()) self.toLower(messageEntity) self.lock.release() #after receiving the message from the target number, target number will send a ack to sender(us) @ProtocolEntityCallback("ack") def onAck(self, entity): self.lock.acquire() #if the id match the id in ackQueue, then pop the id of the message out if entity.getId() in self.ackQueue: self.ackQueue.pop(self.ackQueue.index(entity.getId())) if not len(self.ackQueue): self.lock.release() logger.info("Message sent") raise KeyboardInterrupt() self.lock.release() yowsup-3.2.3/yowsup/demos/sendclient/stack.py000066400000000000000000000017371346433372600213740ustar00rootroot00000000000000from yowsup.stacks import YowStackBuilder from .layer import SendLayer from yowsup.layers import YowLayerEvent from yowsup.layers.auth import YowAuthenticationProtocolLayer from yowsup.layers.network import YowNetworkLayer class YowsupSendStack(object): def __init__(self, credentials, messages): """ :param credentials: :param messages: list of (jid, message) tuples :return: """ stackBuilder = YowStackBuilder() self._stack = stackBuilder\ .pushDefaultLayers()\ .push(SendLayer)\ .build() self._stack.setProp(SendLayer.PROP_MESSAGES, messages) self._stack.setProp(YowAuthenticationProtocolLayer.PROP_PASSIVE, True) self._stack.setCredentials(credentials) def set_prop(self, key, val): self._stack.setProp(key, val) def start(self): self._stack.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT)) self._stack.loop() yowsup-3.2.3/yowsup/env/000077500000000000000000000000001346433372600152365ustar00rootroot00000000000000yowsup-3.2.3/yowsup/env/__init__.py000066400000000000000000000001051346433372600173430ustar00rootroot00000000000000from .env import YowsupEnv from .env_android import AndroidYowsupEnv yowsup-3.2.3/yowsup/env/env.py000066400000000000000000000046351346433372600164100ustar00rootroot00000000000000import abc import logging from six import with_metaclass logger = logging.getLogger(__name__) DEFAULT = "android" class YowsupEnvType(abc.ABCMeta): def __init__(cls, name, bases, dct): if name != "YowsupEnv": YowsupEnv.registerEnv(cls) super(YowsupEnvType, cls).__init__(name, bases, dct) class YowsupEnv(with_metaclass(YowsupEnvType, object)): __metaclass__ = YowsupEnvType __ENVS = {} __CURR = None _USERAGENT_STRING = "WhatsApp/{WHATSAPP_VERSION} {OS_NAME}/{OS_VERSION} Device/{MANUFACTURER}-{DEVICE_NAME}" @classmethod def registerEnv(cls, envCls): envName = envCls.__name__.lower().replace("yowsupenv", "") cls.__ENVS[envName] = envCls logger.debug("registered env %s => %s" % (envName, envCls)) @classmethod def setEnv(cls, envName): if not envName in cls.__ENVS: raise ValueError("%s env does not exist" % envName) logger.debug("Current env changed to %s " % envName) cls.__CURR = cls.__ENVS[envName]() @classmethod def getEnv(cls, envName): if not envName in cls.__ENVS: raise ValueError("%s env does not exist" % envName) return cls.__ENVS[envName]() @classmethod def getRegisteredEnvs(cls): return list(cls.__ENVS.keys()) @classmethod def getCurrent(cls): """ :rtype: YowsupEnv """ if cls.__CURR is None: env = DEFAULT envs = cls.getRegisteredEnvs() if env not in envs: env = envs[0] logger.debug("Env not set, setting it to %s" % env) cls.setEnv(env) return cls.__CURR @abc.abstractmethod def getToken(self, phoneNumber): pass @abc.abstractmethod def getVersion(self): pass @abc.abstractmethod def getOSVersion(self): pass @abc.abstractmethod def getOSName(self): pass @abc.abstractmethod def getDeviceName(self): pass @abc.abstractmethod def getManufacturer(self): pass def getBuildVersion(self): pass def getUserAgent(self): return self.__class__._USERAGENT_STRING.format( WHATSAPP_VERSION=self.getVersion(), OS_NAME=self.getOSName(), OS_VERSION=self.getOSVersion(), MANUFACTURER=self.getManufacturer(), DEVICE_NAME=self.getDeviceName() ) yowsup-3.2.3/yowsup/env/env_android.py000066400000000000000000000060351346433372600201040ustar00rootroot00000000000000from .env import YowsupEnv import base64 import hashlib class AndroidYowsupEnv(YowsupEnv): _SIGNATURE = "MIIDMjCCAvCgAwIBAgIETCU2pDALBgcqhkjOOAQDBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFDASBgNV" \ "BAcTC1NhbnRhIENsYXJhMRYwFAYDVQQKEw1XaGF0c0FwcCBJbmMuMRQwEgYDVQQLEwtFbmdpbmVlcmluZzEUMBIGA1UEAxMLQnJ" \ "pYW4gQWN0b24wHhcNMTAwNjI1MjMwNzE2WhcNNDQwMjE1MjMwNzE2WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5" \ "pYTEUMBIGA1UEBxMLU2FudGEgQ2xhcmExFjAUBgNVBAoTDVdoYXRzQXBwIEluYy4xFDASBgNVBAsTC0VuZ2luZWVyaW5nMRQwEg" \ "YDVQQDEwtCcmlhbiBBY3RvbjCCAbgwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEm" \ "aUVdQCJR+1k9jVj6v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX58aophUPBPuD9tPFHsMCN" \ "VQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvMspK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jr" \ "qgvlXTAs9B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1kW6jfwv6ITVi8ftiegEkO" \ "8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqA4GFAAKBgQDRGYtLgWh7zyRtQainJfCpiaUbzjJuhMgo4fVWZIvXHaS" \ "HBU1t5w//S0lDK2hiqkj8KpMWGywVov9eZxZy37V26dEqr/c2m5qZ0E+ynSu7sqUD7kGx/zeIcGT0H+KAVgkGNQCo5Uc0koLRW" \ "YHNtYoIvt5R3X6YZylbPftF/8ayWTALBgcqhkjOOAQDBQADLwAwLAIUAKYCp0d6z4QQdyN74JDfQ2WCyi8CFDUM4CaNB+ceVXd" \ "KtOrNTQcc0e+t" _MD5_CLASSES = "bdZVQh58MKZaaeiYnh7wkw==" _KEY = "eQV5aq/Cg63Gsq1sshN9T3gh+UUp0wIw0xgHYT1bnCjEqOJQKCRrWxdAe2yvsDeCJL+Y4G3PRD2HUF7oUgiGo8vGlNJOaux26k+A2F3hj8A=" _VERSION = "2.19.51" _OS_NAME = "Android" _OS_VERSION = "8.0.0" _DEVICE_NAME = "star2lte" _MANUFACTURER = "samsung" _BUILD_VERSION = "star2ltexx-user 8.0.0 R16NW G965FXXU1ARCC release-keys" _AXOLOTL = True def getVersion(self): return self.__class__._VERSION def getOSName(self): return self.__class__._OS_NAME def getOSVersion(self): return self.__class__._OS_VERSION def getDeviceName(self): return self.__class__._DEVICE_NAME def getBuildVersion(self): return self.__class__._BUILD_VERSION def getManufacturer(self): return self.__class__._MANUFACTURER def isAxolotlEnabled(self): return self.__class__._AXOLOTL def getToken(self, phoneNumber): keyDecoded = bytearray(base64.b64decode(self.__class__._KEY)) sigDecoded = base64.b64decode(self.__class__._SIGNATURE) clsDecoded = base64.b64decode(self.__class__._MD5_CLASSES) data = sigDecoded + clsDecoded + phoneNumber.encode() opad = bytearray() ipad = bytearray() for i in range(0, 64): opad.append(0x5C ^ keyDecoded[i]) ipad.append(0x36 ^ keyDecoded[i]) hash = hashlib.sha1() subHash = hashlib.sha1() try: subHash.update(ipad + data) hash.update(opad + subHash.digest()) except TypeError: subHash.update(bytes(ipad + data)) hash.update(bytes(opad + subHash.digest())) result = base64.b64encode(hash.digest()) return result yowsup-3.2.3/yowsup/layers/000077500000000000000000000000001346433372600157455ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/__init__.py000066400000000000000000000207751346433372600200710ustar00rootroot00000000000000import unittest import inspect import threading try: import Queue except ImportError: import queue as Queue class YowLayerEvent: def __init__(self, name, **kwargs): self.name = name self.detached = False if "detached" in kwargs: del kwargs["detached"] self.detached = True self.args = kwargs def isDetached(self): return self.detached def getName(self): return self.name def getArg(self, name): return self.args[name] if name in self.args else None class EventCallback(object): def __init__(self, eventName): self.eventName = eventName def __call__(self, fn): fn.event_callback = self.eventName return fn class YowLayer(object): __upper = None __lower = None _props = {} __detachedQueue = Queue.Queue() # def __init__(self, upperLayer, lowerLayer): # self.setLayers(upperLayer, lowerLayer) def __init__(self): self.setLayers(None, None) self.interface = None self.event_callbacks = {} self.__stack = None self.lock = threading.Lock() members = inspect.getmembers(self, predicate=inspect.ismethod) for m in members: if hasattr(m[1], "event_callback"): fname = m[0] fn = m[1] self.event_callbacks[fn.event_callback] = getattr(self, fname) def getLayerInterface(self, YowLayerClass = None): return self.interface if YowLayerClass is None else self.__stack.getLayerInterface(YowLayerClass) def setStack(self, stack): self.__stack = stack def getStack(self): return self.__stack def setLayers(self, upper, lower): self.__upper = upper self.__lower = lower def send(self, data): self.toLower(data) def receive(self, data): self.toUpper(data) def toUpper(self, data): if self.__upper: self.__upper.receive(data) def toLower(self, data): self.lock.acquire() if self.__lower: self.__lower.send(data) self.lock.release() def emitEvent(self, yowLayerEvent): if self.__upper and not self.__upper.onEvent(yowLayerEvent): if yowLayerEvent.isDetached(): yowLayerEvent.detached = False self.getStack().execDetached(lambda : self.__upper.emitEvent(yowLayerEvent)) else: self.__upper.emitEvent(yowLayerEvent) def broadcastEvent(self, yowLayerEvent): if self.__lower and not self.__lower.onEvent(yowLayerEvent): if yowLayerEvent.isDetached(): yowLayerEvent.detached = False self.getStack().execDetached(lambda:self.__lower.broadcastEvent(yowLayerEvent)) else: self.__lower.broadcastEvent(yowLayerEvent) '''return true to stop propagating the event''' def onEvent(self, yowLayerEvent): eventName = yowLayerEvent.getName() if eventName in self.event_callbacks: return self.event_callbacks[eventName](yowLayerEvent) return False def getProp(self, key, default = None): return self.getStack().getProp(key, default) def setProp(self, key, val): return self.getStack().setProp(key, val) class YowProtocolLayer(YowLayer): def __init__(self, handleMap = None): super(YowProtocolLayer, self).__init__() self.handleMap = handleMap or {} self.iqRegistry = {} def receive(self, node): if not self.processIqRegistry(node): if node.tag in self.handleMap: recv, _ = self.handleMap[node.tag] if recv: recv(node) def send(self, entity): if entity.getTag() in self.handleMap: _, send = self.handleMap[entity.getTag()] if send: send(entity) def entityToLower(self, entity): #super(YowProtocolLayer, self).toLower(entity.toProtocolTreeNode()) self.toLower(entity.toProtocolTreeNode()) def isGroupJid(self, jid): return "-" in jid def raiseErrorForNode(self, node): raise ValueError("Unimplemented notification type %s " % node) def _sendIq(self, iqEntity, onSuccess = None, onError = None): self.iqRegistry[iqEntity.getId()] = (iqEntity, onSuccess, onError) self.toLower(iqEntity.toProtocolTreeNode()) def processIqRegistry(self, protocolTreeNode): if protocolTreeNode.tag == "iq": iq_id = protocolTreeNode["id"] if iq_id in self.iqRegistry: originalIq, successClbk, errorClbk = self.iqRegistry[iq_id] del self.iqRegistry[iq_id] if protocolTreeNode["type"] == "result" and successClbk: successClbk(protocolTreeNode, originalIq) elif protocolTreeNode["type"] == "error" and errorClbk: errorClbk(protocolTreeNode, originalIq) return True return False class YowParallelLayer(YowLayer): def __init__(self, sublayers = None): super(YowParallelLayer, self).__init__() self.sublayers = sublayers or [] self.sublayers = tuple([sublayer() for sublayer in sublayers]) for s in self.sublayers: #s.setLayers(self, self) s.toLower = self.toLower s.toUpper = self.toUpper s.broadcastEvent = self.subBroadcastEvent s.emitEvent = self.subEmitEvent def getLayerInterface(self, YowLayerClass): for s in self.sublayers: if s.__class__ == YowLayerClass: return s.getLayerInterface() def setStack(self, stack): super(YowParallelLayer, self).setStack(stack) for s in self.sublayers: s.setStack(self.getStack()) def receive(self, data): for s in self.sublayers: s.receive(data) def send(self, data): for s in self.sublayers: s.send(data) def subBroadcastEvent(self, yowLayerEvent): self.onEvent(yowLayerEvent) self.broadcastEvent(yowLayerEvent) def subEmitEvent(self, yowLayerEvent): self.onEvent(yowLayerEvent) self.emitEvent(yowLayerEvent) def onEvent(self, yowLayerEvent): stopEvent = False for s in self.sublayers: stopEvent = stopEvent or s.onEvent(yowLayerEvent) return stopEvent def __str__(self): return " - ".join([l.__str__() for l in self.sublayers]) class YowLayerInterface(object): def __init__(self, layer): self._layer = layer class YowLayerTest(unittest.TestCase): def __init__(self, *args): super(YowLayerTest, self).__init__(*args) self.upperSink = [] self.lowerSink = [] self.toUpper = self.receiveOverrider self.toLower = self.sendOverrider self.upperEventSink = [] self.lowerEventSink = [] self.emitEvent = self.emitEventOverrider self.broadcastEvent = self.broadcastEventOverrider def receiveOverrider(self, data): self.upperSink.append(data) def sendOverrider(self, data): self.lowerSink.append(data) def emitEventOverrider(self, event): self.upperEventSink.append(event) def broadcastEventOverrider(self, event): self.lowerEventSink.append(event) def assert_emitEvent(self, event): self.emitEvent(event) try: self.assertEqual(event, self.upperEventSink.pop()) except IndexError: raise AssertionError("Event '%s' was not emited through this layer" % (event.getName())) def assert_broadcastEvent(self, event): self.broadcastEvent(event) try: self.assertEqual(event, self.lowerEventSink.pop()) except IndexError: raise AssertionError("Event '%s' was not broadcasted through this layer" % (event.getName())) class YowProtocolLayerTest(YowLayerTest): def assertSent(self, entity): self.send(entity) try: self.assertEqual(entity.toProtocolTreeNode(), self.lowerSink.pop()) except IndexError: raise AssertionError("Entity '%s' was not sent through this layer" % (entity.getTag())) def assertReceived(self, entity): node = entity.toProtocolTreeNode() self.receive(node) try: self.assertEqual(node, self.upperSink.pop().toProtocolTreeNode()) except IndexError: raise AssertionError("'%s' was not received through this layer" % (entity.getTag())) yowsup-3.2.3/yowsup/layers/auth/000077500000000000000000000000001346433372600167065ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/auth/__init__.py000066400000000000000000000001011346433372600210070ustar00rootroot00000000000000from .layer_authentication import YowAuthenticationProtocolLayer yowsup-3.2.3/yowsup/layers/auth/layer_authentication.py000066400000000000000000000060071346433372600234760ustar00rootroot00000000000000from yowsup.common import YowConstants from yowsup.layers import YowLayerEvent, YowProtocolLayer, EventCallback from yowsup.layers.network import YowNetworkLayer from .protocolentities import * from .layer_interface_authentication import YowAuthenticationProtocolLayerInterface from .protocolentities import StreamErrorProtocolEntity class YowAuthenticationProtocolLayer(YowProtocolLayer): EVENT_AUTHED = "org.openwhatsapp.yowsup.event.auth.authed" EVENT_AUTH = "org.openwhatsapp.yowsup.event.auth" PROP_CREDENTIALS = "org.openwhatsapp.yowsup.prop.auth.credentials" PROP_PASSIVE = "org.openwhatsapp.yowsup.prop.auth.passive" def __init__(self): handleMap = { "stream:features": (self.handleStreamFeatures, None), "failure": (self.handleFailure, None), "success": (self.handleSuccess, None), "stream:error": (self.handleStreamError, None), } super(YowAuthenticationProtocolLayer, self).__init__(handleMap) self.interface = YowAuthenticationProtocolLayerInterface(self) self.credentials = None #left for backwards-compat self._credentials = None #new style set def __str__(self): return "Authentication Layer" @EventCallback(YowNetworkLayer.EVENT_STATE_CONNECTED) def on_connected(self, event): self.broadcastEvent( YowLayerEvent( self.EVENT_AUTH, credentials=self.getProp(self.PROP_CREDENTIALS), passive=self.getProp(self.PROP_PASSIVE, False) ) ) def setCredentials(self, credentials): self.setProp(self.PROP_CREDENTIALS, credentials) #keep for now self._credentials = credentials # def getUsername(self, full = False): if self._credentials: return self._credentials[0] if not full else ("%s@%s" % (self._credentials[0], YowConstants.WHATSAPP_SERVER)) else: prop = self.getProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS) return prop[0] if prop else None def handleStreamFeatures(self, node): nodeEntity = StreamFeaturesProtocolEntity.fromProtocolTreeNode(node) self.toUpper(nodeEntity) def handleSuccess(self, node): successEvent = YowLayerEvent(self.__class__.EVENT_AUTHED, passive = self.getProp(self.__class__.PROP_PASSIVE)) self.broadcastEvent(successEvent) nodeEntity = SuccessProtocolEntity.fromProtocolTreeNode(node) self.toUpper(nodeEntity) def handleFailure(self, node): nodeEntity = FailureProtocolEntity.fromProtocolTreeNode(node) self.toUpper(nodeEntity) self.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_DISCONNECT, reason = "Authentication Failure")) def handleStreamError(self, node): nodeEntity = StreamErrorProtocolEntity.fromProtocolTreeNode(node) errorType = nodeEntity.getErrorType() if not errorType: raise NotImplementedError("Unhandled stream:error node:\n%s" % node) self.toUpper(nodeEntity) yowsup-3.2.3/yowsup/layers/auth/layer_interface_authentication.py000066400000000000000000000004511346433372600255130ustar00rootroot00000000000000from yowsup.layers import YowLayerInterface class YowAuthenticationProtocolLayerInterface(YowLayerInterface): def setCredentials(self, phone, keypair): self._layer.setCredentials((phone, keypair)) def getUsername(self, full = False): return self._layer.getUsername(full) yowsup-3.2.3/yowsup/layers/auth/protocolentities/000077500000000000000000000000001346433372600223145ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/auth/protocolentities/__init__.py000066400000000000000000000005051346433372600244250ustar00rootroot00000000000000from .auth import AuthProtocolEntity from .challenge import ChallengeProtocolEntity from .response import ResponseProtocolEntity from .stream_features import StreamFeaturesProtocolEntity from .success import SuccessProtocolEntity from .failure import FailureProtocolEntity from .stream_error import StreamErrorProtocolEntity yowsup-3.2.3/yowsup/layers/auth/protocolentities/auth.py000066400000000000000000000016741346433372600236370ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode class AuthProtocolEntity(ProtocolEntity): def __init__(self, user, mechanism = "WAUTH-2", passive = False, nonce = None): super(AuthProtocolEntity, self).__init__("auth") self.user = user self.mechanism = mechanism self.passive = passive self.nonce = nonce def toProtocolTreeNode(self): attributes = { "user" : self.user, "mechanism" : self.mechanism, "passive" : "true" if self.passive else "false" } return self._createProtocolTreeNode(attributes, children = None, data = self.nonce) @staticmethod def fromProtocolTreeNode(node): return AuthProtocolEntity( node.getAttributeValue("user"), node.getAttributeValue("mechanism"), node.getAttributeValue("passive") != "false", node.getData() )yowsup-3.2.3/yowsup/layers/auth/protocolentities/challenge.py000066400000000000000000000014431346433372600246120ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode class ChallengeProtocolEntity(ProtocolEntity): def __init__(self, nonce): super(ChallengeProtocolEntity, self).__init__("challenge") self.nonce = nonce def getNonce(self): return self.nonce def toProtocolTreeNode(self): #return self._createProtocolTreeNode({}, children = None, data = self.nonce) return self._createProtocolTreeNode({}, children = [], data = "".join(map(chr, self.nonce))) def __str__(self): out = "Challenge\n" out += "Nonce: %s\n" % self.nonce return out @staticmethod def fromProtocolTreeNode(node): nonce = list(map(ord,node.getData())) entity = ChallengeProtocolEntity(bytearray(nonce)) return entity yowsup-3.2.3/yowsup/layers/auth/protocolentities/failure.py000066400000000000000000000011441346433372600243150ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode class FailureProtocolEntity(ProtocolEntity): def __init__(self, reason): super(FailureProtocolEntity, self).__init__("failure") self.reason = reason def __str__(self): out = "Failure:\n" out += "Reason: %s\n" % self.reason return out def getReason(self): return self.reason def toProtocolTreeNode(self): return self._createProtocolTreeNode({"reason": self.reason}) @staticmethod def fromProtocolTreeNode(node): return FailureProtocolEntity( node["reason"] ) yowsup-3.2.3/yowsup/layers/auth/protocolentities/response.py000066400000000000000000000011031346433372600245170ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode class ResponseProtocolEntity(ProtocolEntity): def __init__(self, data, xmlns = "urn:ietf:params:xml:ns:xmpp-sasl"): super(ResponseProtocolEntity, self).__init__("response") self.xmlns = xmlns self.data = data def toProtocolTreeNode(self): return self._createProtocolTreeNode({"xmlns": self.xmlns}, children = None, data = self.data) @staticmethod def fromProtocolTreeNode(node): return ResponseProtocolEntity(node.getData(), node.getAttributeValue("xmlns"))yowsup-3.2.3/yowsup/layers/auth/protocolentities/stream_error.py000066400000000000000000000033661346433372600254020ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode class StreamErrorProtocolEntity(ProtocolEntity): TYPE_CONFLICT = "conflict" ''' Replaced by new connection ''' TYPE_ACK = "ack" ''' ''' TYPE_XML_NOT_WELL_FORMED = "xml-not-well-formed" ''' ''' TYPES = (TYPE_CONFLICT, TYPE_ACK, TYPE_XML_NOT_WELL_FORMED) def __init__(self, data = None): super(StreamErrorProtocolEntity, self).__init__("stream:error") data = data or {} self.setErrorData(data) def setErrorData(self, data): self.data = data def getErrorData(self): return self.data def getErrorType(self): for k in self.data.keys(): if k in self.__class__.TYPES: return k def __str__(self): out = "Stream Error type: %s\n" % self.getErrorType() out += "%s" % self.getErrorData() out += "\n" return out def toProtocolTreeNode(self): node = super(StreamErrorProtocolEntity, self).toProtocolTreeNode() type = self.getErrorType() node.addChild(ProtocolTreeNode(type)) if type == self.__class__.TYPE_CONFLICT and "text" in self.data: node.addChild(ProtocolTreeNode("text", data=self.data["text"])) return node @staticmethod def fromProtocolTreeNode(protocolTreeNode): data = {} for child in protocolTreeNode.getAllChildren(): data[child.tag] = child.data return StreamErrorProtocolEntity(data) yowsup-3.2.3/yowsup/layers/auth/protocolentities/stream_features.py000066400000000000000000000012731346433372600260620ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode class StreamFeaturesProtocolEntity(ProtocolEntity): def __init__(self, features = None): super(StreamFeaturesProtocolEntity, self).__init__("stream:features") self.setFeatures(features) def setFeatures(self, features = None): self.features = features or [] def toProtocolTreeNode(self): featureNodes = [ProtocolTreeNode(feature) for feature in self.features] return self._createProtocolTreeNode({}, children = featureNodes, data = None) @staticmethod def fromProtocolTreeNode(node): return StreamFeaturesProtocolEntity([fnode.tag for fnode in node.getAllChildren()])yowsup-3.2.3/yowsup/layers/auth/protocolentities/success.py000066400000000000000000000022621346433372600243400ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode class SuccessProtocolEntity(ProtocolEntity): def __init__(self, creation, props, t, location): super(SuccessProtocolEntity, self).__init__("success") self.location = location self.creation = int(creation) self.props = props self.t = int(t) ##whatever that is ! def __str__(self): out = "Account:\n" out += "Location: %s\n" % self.location out += "Creation: %s\n" % self.creation out += "Props: %s\n" % self.props out += "t: %s\n" % self.t return out def toProtocolTreeNode(self): attributes = { "location" : self.location, "creation" : str(self.creation), "props" : self.props, "t" : str(self.t) } return self._createProtocolTreeNode(attributes) @staticmethod def fromProtocolTreeNode(node): return SuccessProtocolEntity( node.getAttributeValue("creation"), node.getAttributeValue("props"), node.getAttributeValue("t"), node.getAttributeValue("location") )yowsup-3.2.3/yowsup/layers/auth/protocolentities/test_failure.py000066400000000000000000000006501346433372600253550ustar00rootroot00000000000000from yowsup.layers.auth.protocolentities.failure import FailureProtocolEntity from yowsup.structs import ProtocolTreeNode from yowsup.structs.protocolentity import ProtocolEntityTest import unittest class FailureProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): self.ProtocolEntity = FailureProtocolEntity self.node = ProtocolTreeNode("failure", {"reason": "not-authorized"}) yowsup-3.2.3/yowsup/layers/auth/protocolentities/test_success.py000066400000000000000000000010501346433372600253710ustar00rootroot00000000000000from yowsup.layers.auth.protocolentities.success import SuccessProtocolEntity from yowsup.structs import ProtocolTreeNode from yowsup.structs.protocolentity import ProtocolEntityTest import unittest class SuccessProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): self.ProtocolEntity = SuccessProtocolEntity attribs = { "creation": "1234", "location": "atn", "props": "2", "t": "1415470561" } self.node = ProtocolTreeNode("success", attribs) yowsup-3.2.3/yowsup/layers/axolotl/000077500000000000000000000000001346433372600174275ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/axolotl/__init__.py000066400000000000000000000002071346433372600215370ustar00rootroot00000000000000from .layer_send import AxolotlSendLayer from .layer_control import AxolotlControlLayer from .layer_receive import AxolotlReceivelayer yowsup-3.2.3/yowsup/layers/axolotl/layer_base.py000066400000000000000000000054261346433372600221160ustar00rootroot00000000000000from yowsup.layers import YowProtocolLayer from yowsup.layers.auth.layer_authentication import YowAuthenticationProtocolLayer from yowsup.layers.axolotl.protocolentities import * from yowsup.axolotl.factory import AxolotlManagerFactory, AxolotlManager from yowsup.layers.network.layer import YowNetworkLayer from yowsup.layers import EventCallback from yowsup.axolotl import exceptions from yowsup.layers.axolotl.props import PROP_IDENTITY_AUTOTRUST import logging logger = logging.getLogger(__name__) class AxolotlBaseLayer(YowProtocolLayer): def __init__(self): super(AxolotlBaseLayer, self).__init__() self._manager = None # type: AxolotlManager | None self.skipEncJids = [] def send(self, node): pass def receive(self, node): self.processIqRegistry(node) @property def manager(self): """ :return: :rtype: AxolotlManager """ return self._manager @EventCallback(YowNetworkLayer.EVENT_STATE_CONNECTED) def on_connected(self, yowLayerEvent): self._manager = AxolotlManagerFactory().get_manager( self.getProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS)[0] ) @EventCallback(YowNetworkLayer.EVENT_STATE_DISCONNECTED) def on_disconnected(self, yowLayerEvent): self._manager = None def getKeysFor(self, jids, resultClbk, errorClbk = None, reason=None): logger.debug("getKeysFor(jids=%s, resultClbk=[omitted], errorClbk=[omitted], reason=%s)" % (jids, reason)) def onSuccess(resultNode, getKeysEntity): entity = ResultGetKeysIqProtocolEntity.fromProtocolTreeNode(resultNode) resultJids = entity.getJids() successJids = [] errorJids = {} #jid -> exception for jid in getKeysEntity.jids: if jid not in resultJids: self.skipEncJids.append(jid) continue recipient_id = jid.split('@')[0] preKeyBundle = entity.getPreKeyBundleFor(jid) try: self.manager.create_session(recipient_id, preKeyBundle, autotrust=self.getProp(PROP_IDENTITY_AUTOTRUST, False)) successJids.append(jid) except exceptions.UntrustedIdentityException as e: errorJids[jid] = e logger.error(e) logger.warning("Ignoring message with untrusted identity") resultClbk(successJids, errorJids) def onError(errorNode, getKeysEntity): if errorClbk: errorClbk(errorNode, getKeysEntity) entity = GetKeysIqProtocolEntity(jids, reason=reason) self._sendIq(entity, onSuccess, onError=onError) yowsup-3.2.3/yowsup/layers/axolotl/layer_control.py000066400000000000000000000130011346433372600226500ustar00rootroot00000000000000from .layer_base import AxolotlBaseLayer from yowsup.layers import YowLayerEvent, EventCallback from yowsup.layers.network.layer import YowNetworkLayer from yowsup.layers.axolotl.protocolentities import * from yowsup.layers.auth.layer_authentication import YowAuthenticationProtocolLayer from yowsup.layers.protocol_acks.protocolentities import OutgoingAckProtocolEntity from axolotl.util.hexutil import HexUtil from axolotl.ecc.curve import Curve import logging import binascii logger = logging.getLogger(__name__) class AxolotlControlLayer(AxolotlBaseLayer): def __init__(self): super(AxolotlControlLayer, self).__init__() self._unsent_prekeys = [] self._reboot_connection = False def send(self, node): self.toLower(node) def receive(self, protocolTreeNode): """ :type protocolTreeNode: ProtocolTreeNode """ if not self.processIqRegistry(protocolTreeNode): if protocolTreeNode.tag == "notification" and protocolTreeNode["type"] == "encrypt": if protocolTreeNode.getChild("count") is not None: return self.onRequestKeysEncryptNotification(protocolTreeNode) elif protocolTreeNode.getChild("identity") is not None: return self.onIdentityChangeEncryptNotification(protocolTreeNode) self.toUpper(protocolTreeNode) def onIdentityChangeEncryptNotification(self, protocoltreenode): entity = IdentityChangeEncryptNotification.fromProtocolTreeNode(protocoltreenode) ack = OutgoingAckProtocolEntity( protocoltreenode["id"], "notification", protocoltreenode["type"], protocoltreenode["from"] ) self.toLower(ack.toProtocolTreeNode()) self.getKeysFor([entity.getFrom(True)], resultClbk=lambda _,__: None, reason="identity") def onRequestKeysEncryptNotification(self, protocolTreeNode): entity = RequestKeysEncryptNotification.fromProtocolTreeNode(protocolTreeNode) ack = OutgoingAckProtocolEntity(protocolTreeNode["id"], "notification", protocolTreeNode["type"], protocolTreeNode["from"]) self.toLower(ack.toProtocolTreeNode()) self.flush_keys( self.manager.generate_signed_prekey(), self.manager.level_prekeys(force=True) ) @EventCallback(YowNetworkLayer.EVENT_STATE_CONNECTED) def on_connected(self, yowLayerEvent): super(AxolotlControlLayer, self).on_connected(yowLayerEvent) self.manager.level_prekeys() self._unsent_prekeys.extend(self.manager.load_unsent_prekeys()) if len(self._unsent_prekeys): self.setProp(YowAuthenticationProtocolLayer.PROP_PASSIVE, True) @EventCallback(YowAuthenticationProtocolLayer.EVENT_AUTHED) def onAuthed(self, yowLayerEvent): if yowLayerEvent.getArg("passive") and len(self._unsent_prekeys): logger.debug("SHOULD FLUSH KEYS %d NOW!!" % len(self._unsent_prekeys)) self.flush_keys( self.manager.load_latest_signed_prekey(generate=True), self._unsent_prekeys[:], reboot_connection=True ) self._unsent_prekeys = [] @EventCallback(YowNetworkLayer.EVENT_STATE_DISCONNECTED) def on_disconnected(self, yowLayerEvent): super(AxolotlControlLayer, self).on_disconnected(yowLayerEvent) logger.debug(("Disconnected, reboot_connect? = %s" % self._reboot_connection)) if self._reboot_connection: self._reboot_connection = False #we requested this disconnect in this layer to switch off passive #no need to traverse it to upper layers? self.setProp(YowAuthenticationProtocolLayer.PROP_PASSIVE, False) self.getLayerInterface(YowNetworkLayer).connect() def flush_keys(self, signed_prekey, prekeys, reboot_connection=False): """ sends prekeys :return: :rtype: """ preKeysDict = {} for prekey in prekeys: keyPair = prekey.getKeyPair() preKeysDict[self.adjustId(prekey.getId())] = self.adjustArray(keyPair.getPublicKey().serialize()[1:]) signedKeyTuple = (self.adjustId(signed_prekey.getId()), self.adjustArray(signed_prekey.getKeyPair().getPublicKey().serialize()[1:]), self.adjustArray(signed_prekey.getSignature())) setKeysIq = SetKeysIqProtocolEntity( self.adjustArray( self.manager.identity.getPublicKey().serialize()[1:] ), signedKeyTuple, preKeysDict, Curve.DJB_TYPE, self.adjustId(self.manager.registration_id) ) onResult = lambda _, __: self.on_keys_flushed(prekeys, reboot_connection=reboot_connection) self._sendIq(setKeysIq, onResult, self.onSentKeysError) def on_keys_flushed(self, prekeys, reboot_connection): self.manager.set_prekeys_as_sent(prekeys) if reboot_connection: self._reboot_connection = True self.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_DISCONNECT)) def onSentKeysError(self, errorNode, keysEntity): raise Exception("Sent keys were not accepted") def adjustArray(self, arr): return HexUtil.decodeHex(binascii.hexlify(arr)) def adjustId(self, _id): _id = format(_id, 'x') zfiller = len(_id) if len(_id) % 2 == 0 else len(_id) + 1 _id = _id.zfill(zfiller if zfiller > 6 else 6) # if len(_id) % 2: # _id = "0" + _id return binascii.unhexlify(_id) yowsup-3.2.3/yowsup/layers/axolotl/layer_receive.py000066400000000000000000000213521346433372600226220ustar00rootroot00000000000000from .layer_base import AxolotlBaseLayer from yowsup.layers.protocol_receipts.protocolentities import OutgoingReceiptProtocolEntity from yowsup.layers.protocol_messages.proto.e2e_pb2 import * from yowsup.layers.axolotl.protocolentities import * from yowsup.structs import ProtocolTreeNode from yowsup.layers.protocol_messages.protocolentities.proto import ProtoProtocolEntity from yowsup.layers.axolotl.props import PROP_IDENTITY_AUTOTRUST from yowsup.axolotl import exceptions from axolotl.untrustedidentityexception import UntrustedIdentityException import logging logger = logging.getLogger(__name__) class AxolotlReceivelayer(AxolotlBaseLayer): def __init__(self): super(AxolotlReceivelayer, self).__init__() self.v2Jids = [] #people we're going to send v2 enc messages self.sessionCiphers = {} self.groupCiphers = {} self.pendingIncomingMessages = {} #(jid, participantJid?) => message def receive(self, protocolTreeNode): """ :type protocolTreeNode: ProtocolTreeNode """ if not self.processIqRegistry(protocolTreeNode): if protocolTreeNode.tag == "message": self.onMessage(protocolTreeNode) elif not protocolTreeNode.tag == "receipt": #receipts will be handled by send layer self.toUpper(protocolTreeNode) # elif protocolTreeNode.tag == "iq": # if protocolTreeNode.getChild("encr_media"): # protocolTreeNode.addChild("media", { # "url": protocolTreeNode["url"], # "ip": protocolTreeNode["ip"], # }) # self.toUpper(protocolTreeNode) # return ###### def onEncrMediaResult(self, resultNode): pass def processPendingIncomingMessages(self, jid, participantJid = None): conversationIdentifier = (jid, participantJid) if conversationIdentifier in self.pendingIncomingMessages: for messageNode in self.pendingIncomingMessages[conversationIdentifier]: self.onMessage(messageNode) del self.pendingIncomingMessages[conversationIdentifier] ##### handling received data ##### def onMessage(self, protocolTreeNode): encNode = protocolTreeNode.getChild("enc") if encNode: self.handleEncMessage(protocolTreeNode) else: self.toUpper(protocolTreeNode) def handleEncMessage(self, node): encMessageProtocolEntity = EncryptedMessageProtocolEntity.fromProtocolTreeNode(node) isGroup = node["participant"] is not None senderJid = node["participant"] if isGroup else node["from"] if node.getChild("enc")["v"] == "2" and node["from"] not in self.v2Jids: self.v2Jids.append(node["from"]) try: if encMessageProtocolEntity.getEnc(EncProtocolEntity.TYPE_PKMSG): self.handlePreKeyWhisperMessage(node) elif encMessageProtocolEntity.getEnc(EncProtocolEntity.TYPE_MSG): self.handleWhisperMessage(node) if encMessageProtocolEntity.getEnc(EncProtocolEntity.TYPE_SKMSG): self.handleSenderKeyMessage(node) except (exceptions.InvalidMessageException, exceptions.InvalidKeyIdException) as e: logger.warning("InvalidMessage or KeyId for %s, going to send a retry", encMessageProtocolEntity.getAuthor(False)) retry = RetryOutgoingReceiptProtocolEntity.fromMessageNode(node, self.manager.registration_id) self.toLower(retry.toProtocolTreeNode()) except exceptions.NoSessionException: logger.warning("No session for %s, getting their keys now", encMessageProtocolEntity.getAuthor(False)) conversationIdentifier = (node["from"], node["participant"]) if conversationIdentifier not in self.pendingIncomingMessages: self.pendingIncomingMessages[conversationIdentifier] = [] self.pendingIncomingMessages[conversationIdentifier].append(node) successFn = lambda successJids, b: self.processPendingIncomingMessages(*conversationIdentifier) if len(successJids) else None self.getKeysFor([senderJid], successFn) except exceptions.DuplicateMessageException: logger.warning("Received a message that we've previously decrypted, goint to send the delivery receipt myself") self.toLower(OutgoingReceiptProtocolEntity(node["id"], node["from"], participant=node["participant"]).toProtocolTreeNode()) except UntrustedIdentityException as e: if self.getProp(PROP_IDENTITY_AUTOTRUST, False): logger.warning("Autotrusting identity for %s", e.getName()) self.manager.trust_identity(e.getName(), e.getIdentityKey()) return self.handleEncMessage(node) else: logger.error("Ignoring message with untrusted identity") def handlePreKeyWhisperMessage(self, node): pkMessageProtocolEntity = EncryptedMessageProtocolEntity.fromProtocolTreeNode(node) enc = pkMessageProtocolEntity.getEnc(EncProtocolEntity.TYPE_PKMSG) plaintext = self.manager.decrypt_pkmsg(pkMessageProtocolEntity.getAuthor(False), enc.getData(), enc.getVersion() == 2) if enc.getVersion() == 2: self.parseAndHandleMessageProto(pkMessageProtocolEntity, plaintext) node = pkMessageProtocolEntity.toProtocolTreeNode() node.addChild((ProtoProtocolEntity(plaintext, enc.getMediaType())).toProtocolTreeNode()) self.toUpper(node) def handleWhisperMessage(self, node): encMessageProtocolEntity = EncryptedMessageProtocolEntity.fromProtocolTreeNode(node) enc = encMessageProtocolEntity.getEnc(EncProtocolEntity.TYPE_MSG) plaintext = self.manager.decrypt_msg(encMessageProtocolEntity.getAuthor(False), enc.getData(), enc.getVersion() == 2) if enc.getVersion() == 2: self.parseAndHandleMessageProto(encMessageProtocolEntity, plaintext) node = encMessageProtocolEntity.toProtocolTreeNode() node.addChild((ProtoProtocolEntity(plaintext, enc.getMediaType())).toProtocolTreeNode()) self.toUpper(node) def handleSenderKeyMessage(self, node): encMessageProtocolEntity = EncryptedMessageProtocolEntity.fromProtocolTreeNode(node) enc = encMessageProtocolEntity.getEnc(EncProtocolEntity.TYPE_SKMSG) try: plaintext = self.manager.group_decrypt ( groupid=encMessageProtocolEntity.getFrom(True), participantid=encMessageProtocolEntity.getParticipant(False), data=enc.getData() ) self.parseAndHandleMessageProto(encMessageProtocolEntity, plaintext) node = encMessageProtocolEntity.toProtocolTreeNode() node.addChild((ProtoProtocolEntity(plaintext, enc.getMediaType())).toProtocolTreeNode()) self.toUpper(node) except exceptions.NoSessionException: logger.warning("No session for %s, going to send a retry", encMessageProtocolEntity.getAuthor(False)) retry = RetryOutgoingReceiptProtocolEntity.fromMessageNode(node, self.manager.registration_id) self.toLower(retry.toProtocolTreeNode()) except exceptions.DuplicateMessageException: logger.warning( "Received a message that we've previously decrypted, goint to send the delivery receipt myself" ) self.toLower( OutgoingReceiptProtocolEntity( node["id"], node["from"], participant=node["participant"] ).toProtocolTreeNode() ) def parseAndHandleMessageProto(self, encMessageProtocolEntity, serializedData): m = Message() try: m.ParseFromString(serializedData) except: print("DUMP:") print(serializedData) print([s for s in serializedData]) # print([ord(s) for s in serializedData]) raise if not m or not serializedData: raise ValueError("Empty message") if m.HasField("sender_key_distribution_message"): self.handleSenderKeyDistributionMessage( m.sender_key_distribution_message, encMessageProtocolEntity.getParticipant(False) ) def handleSenderKeyDistributionMessage(self, senderKeyDistributionMessage, participantId): groupId = senderKeyDistributionMessage.group_id self.manager.group_create_session( groupid=groupId, participantid=participantId, skmsgdata=senderKeyDistributionMessage.axolotl_sender_key_distribution_message ) yowsup-3.2.3/yowsup/layers/axolotl/layer_send.py000066400000000000000000000251141346433372600221310ustar00rootroot00000000000000from yowsup.layers.protocol_messages.proto.e2e_pb2 import Message from yowsup.layers.axolotl.protocolentities import * from yowsup.layers.auth.layer_authentication import YowAuthenticationProtocolLayer from yowsup.layers.protocol_groups.protocolentities import InfoGroupsIqProtocolEntity, InfoGroupsResultIqProtocolEntity from axolotl.protocol.whispermessage import WhisperMessage from yowsup.layers.protocol_messages.protocolentities.message import MessageAttributes from .layer_base import AxolotlBaseLayer import logging logger = logging.getLogger(__name__) class AxolotlSendLayer(AxolotlBaseLayer): MAX_SENT_QUEUE = 100 def __init__(self): super(AxolotlSendLayer, self).__init__() self.sessionCiphers = {} self.groupCiphers = {} ''' Sent messages will be put in Queue until we receive a receipt for them. This is for handling retry receipts which requires re-encrypting and resend of the original message As the receipt for a sent message might arrive at a different yowsup instance, ideally the original message should be fetched from a persistent storage. Therefore, if the original message is not in sentQueue for any reason, we will notify the upper layers and let them handle it. ''' self.sentQueue = [] def __str__(self): return "Axolotl Layer" def send(self, node): if node.tag == "message" and node["to"] not in self.skipEncJids: self.processPlaintextNodeAndSend(node) else: self.toLower(node) def receive(self, protocolTreeNode): if not self.processIqRegistry(protocolTreeNode): if protocolTreeNode.tag == "receipt": ''' Going to keep all group message enqueued, as we get receipts from each participant So can't just remove it on first receipt. Therefore, the MAX queue length mechanism should better be working ''' messageNode = self.getEnqueuedMessageNode(protocolTreeNode["id"], protocolTreeNode["participant"] is not None) if not messageNode: logger.debug("Axolotl layer does not have the message, bubbling it upwards") self.toUpper(protocolTreeNode) elif protocolTreeNode["type"] == "retry": logger.info("Got retry to for message %s, and Axolotl layer has the message" % protocolTreeNode["id"]) retryReceiptEntity = RetryIncomingReceiptProtocolEntity.fromProtocolTreeNode(protocolTreeNode) self.toLower(retryReceiptEntity.ack().toProtocolTreeNode()) self.getKeysFor( [protocolTreeNode["participant"] or protocolTreeNode["from"]], lambda successJids, b: self.processPlaintextNodeAndSend(messageNode, retryReceiptEntity) if len(successJids) == 1 else None ) else: #not interested in any non retry receipts, bubble upwards self.toUpper(protocolTreeNode) def processPlaintextNodeAndSend(self, node, retryReceiptEntity = None): recipient_id = node["to"].split('@')[0] isGroup = "-" in recipient_id if isGroup: self.sendToGroup(node, retryReceiptEntity) elif self.manager.session_exists(recipient_id): self.sendToContact(node) else: self.getKeysFor([node["to"]], lambda successJids, b: self.sendToContact(node) if len(successJids) == 1 else self.toLower(node), lambda: self.toLower(node)) def enqueueSent(self, node): logger.debug("enqueueSent(node=[omitted])") if len(self.sentQueue) >= self.__class__.MAX_SENT_QUEUE: logger.warn("Discarding queued node without receipt") self.sentQueue.pop(0) self.sentQueue.append(node) def getEnqueuedMessageNode(self, messageId, keepEnqueued = False): for i in range(0, len(self.sentQueue)): if self.sentQueue[i]["id"] == messageId: if keepEnqueued: return self.sentQueue[i] return self.sentQueue.pop(i) def sendEncEntities(self, node, encEntities, participant=None): logger.debug("sendEncEntities(node=[omitted], encEntities=[omitted], participant=%s)" % participant) message_attrs = MessageAttributes.from_message_protocoltreenode(node) message_attrs.participant = participant messageEntity = EncryptedMessageProtocolEntity( encEntities, node["type"], message_attrs ) # if participant is set, this message is directed to that specific participant as a result of a retry, therefore # we already have the original group message and there is no need to store it again. if participant is None: self.enqueueSent(node) self.toLower(messageEntity.toProtocolTreeNode()) def sendToContact(self, node): recipient_id = node["to"].split('@')[0] protoNode = node.getChild("proto") messageData = protoNode.getData() ciphertext = self.manager.encrypt( recipient_id, messageData ) mediaType = protoNode["mediatype"] return self.sendEncEntities(node, [EncProtocolEntity(EncProtocolEntity.TYPE_MSG if ciphertext.__class__ == WhisperMessage else EncProtocolEntity.TYPE_PKMSG, 2, ciphertext.serialize(), mediaType)]) def sendToGroupWithSessions(self, node, jidsNeedSenderKey = None, retryCount=0): """ For each jid in jidsNeedSenderKey will create a pkmsg enc node with the associated jid. If retryCount > 0 and we have only one jidsNeedSenderKey, this is a retry requested by a specific participant and this message is to be directed at specific at that participant indicated by jidsNeedSenderKey[0]. In this case the participant's jid would go in the parent's EncryptedMessage and not into the enc node. """ logger.debug( "sendToGroupWithSessions(node=[omitted], jidsNeedSenderKey=%s, retryCount=%d)" % (jidsNeedSenderKey, retryCount) ) jidsNeedSenderKey = jidsNeedSenderKey or [] groupJid = node["to"] protoNode = node.getChild("proto") encEntities = [] participant = jidsNeedSenderKey[0] if len(jidsNeedSenderKey) == 1 and retryCount > 0 else None if len(jidsNeedSenderKey): senderKeyDistributionMessage = self.manager.group_create_skmsg(groupJid) for jid in jidsNeedSenderKey: message = self.serializeSenderKeyDistributionMessageToProtobuf(node["to"], senderKeyDistributionMessage) if retryCount > 0: message.MergeFromString(protoNode.getData()) ciphertext = self.manager.encrypt(jid.split('@')[0], message.SerializeToString()) encEntities.append( EncProtocolEntity( EncProtocolEntity.TYPE_MSG if ciphertext.__class__ == WhisperMessage else EncProtocolEntity.TYPE_PKMSG , 2, ciphertext.serialize(), protoNode["mediatype"], jid=None if participant else jid ) ) if not retryCount: messageData = protoNode.getData() ciphertext = self.manager.group_encrypt(groupJid, messageData) mediaType = protoNode["mediatype"] encEntities.append(EncProtocolEntity(EncProtocolEntity.TYPE_SKMSG, 2, ciphertext, mediaType)) self.sendEncEntities(node, encEntities, participant) def ensureSessionsAndSendToGroup(self, node, jids): logger.debug("ensureSessionsAndSendToGroup(node=[omitted], jids=%s)" % jids) jidsNoSession = [] for jid in jids: if not self.manager.session_exists(jid.split('@')[0]): jidsNoSession.append(jid) if len(jidsNoSession): self.getKeysFor(jidsNoSession, lambda successJids, b: self.sendToGroupWithSessions(node, successJids)) else: self.sendToGroupWithSessions(node, jids) def sendToGroup(self, node, retryReceiptEntity = None): """ Group send sequence: check if senderkeyrecord exists no: - create, - get group jids from info request - for each jid without a session, get keys to create the session - send message with dist key for all participants yes: - send skmsg without any dist key received retry for a participant - request participants keys - send message with dist key only + conversation, only for this participat """ logger.debug("sendToGroup(node=[omitted], retryReceiptEntity=[%s])" % ("[retry_count=%s, retry_jid=%s]" % ( retryReceiptEntity.getRetryCount(), retryReceiptEntity.getRetryJid()) ) if retryReceiptEntity is not None else None) groupJid = node["to"] ownJid = self.getLayerInterface(YowAuthenticationProtocolLayer).getUsername(True) senderKeyRecord = self.manager.load_senderkey(node["to"]) def sendToGroup(resultNode, requestEntity): groupInfo = InfoGroupsResultIqProtocolEntity.fromProtocolTreeNode(resultNode) jids = list(groupInfo.getParticipants().keys()) #keys in py3 returns dict_keys if ownJid in jids: jids.remove(ownJid) return self.ensureSessionsAndSendToGroup(node, jids) if senderKeyRecord.isEmpty(): logger.debug("senderKeyRecord is empty, requesting group info") groupInfoIq = InfoGroupsIqProtocolEntity(groupJid) self._sendIq(groupInfoIq, sendToGroup) else: logger.debug("We have a senderKeyRecord") retryCount = 0 jidsNeedSenderKey = [] if retryReceiptEntity is not None: retryCount = retryReceiptEntity.getRetryCount() jidsNeedSenderKey.append(retryReceiptEntity.getRetryJid()) self.sendToGroupWithSessions(node, jidsNeedSenderKey, retryCount) def serializeSenderKeyDistributionMessageToProtobuf(self, groupId, senderKeyDistributionMessage, message = None): m = message or Message() m.sender_key_distribution_message.group_id = groupId m.sender_key_distribution_message.axolotl_sender_key_distribution_message = senderKeyDistributionMessage.serialize() m.sender_key_distribution_message.axolotl_sender_key_distribution_message = senderKeyDistributionMessage.serialize() # m.conversation = text return m yowsup-3.2.3/yowsup/layers/axolotl/props.py000066400000000000000000000001251346433372600211420ustar00rootroot00000000000000PROP_IDENTITY_AUTOTRUST = "org.openwhatsapp.yowsup.prop.axolotl.INDENTITY_AUTOTRUST"yowsup-3.2.3/yowsup/layers/axolotl/protocolentities/000077500000000000000000000000001346433372600230355ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/axolotl/protocolentities/__init__.py000066400000000000000000000010561346433372600251500ustar00rootroot00000000000000from .iq_key_get import GetKeysIqProtocolEntity from .iq_keys_set import SetKeysIqProtocolEntity from .iq_keys_get_result import ResultGetKeysIqProtocolEntity from .message_encrypted import EncryptedMessageProtocolEntity from .enc import EncProtocolEntity from .receipt_outgoing_retry import RetryOutgoingReceiptProtocolEntity from .receipt_incoming_retry import RetryIncomingReceiptProtocolEntity from .notification_encrypt_identitychange import IdentityChangeEncryptNotification from .notification_encrypt_requestkeys import RequestKeysEncryptNotification yowsup-3.2.3/yowsup/layers/axolotl/protocolentities/enc.py000066400000000000000000000026101346433372600241530ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode import sys class EncProtocolEntity(ProtocolEntity): TYPE_PKMSG = "pkmsg" TYPE_MSG = "msg" TYPE_SKMSG = "skmsg" TYPES = (TYPE_PKMSG, TYPE_MSG, TYPE_SKMSG) def __init__(self, type, version, data, mediaType = None, jid = None): assert type in self.__class__.TYPES, "Unknown message enc type %s" % type super(EncProtocolEntity, self).__init__("enc") self.type = type self.version = int(version) self.data = data self.mediaType = mediaType self.jid = jid def getType(self): return self.type def getVersion(self): return self.version def getData(self): return self.data def getMediaType(self): return self.mediaType def getJid(self): return self.jid def toProtocolTreeNode(self): attribs = {"type": self.type, "v": str(self.version)} if self.mediaType: attribs["mediatype"] = self.mediaType encNode = ProtocolTreeNode("enc", attribs, data = self.data) if self.jid: return ProtocolTreeNode("to", {"jid": self.jid}, [encNode]) return encNode @staticmethod def fromProtocolTreeNode(node): return EncProtocolEntity(node["type"], node["v"], node.data.encode('latin-1') if sys.version_info >= (3,0) else node.data, node["mediatype"]) yowsup-3.2.3/yowsup/layers/axolotl/protocolentities/iq_key_get.py000066400000000000000000000024771346433372600255410ustar00rootroot00000000000000from yowsup.common import YowConstants from yowsup.layers.protocol_iq.protocolentities import IqProtocolEntity from yowsup.structs import ProtocolTreeNode class GetKeysIqProtocolEntity(IqProtocolEntity): def __init__(self, jids, reason=None): super(GetKeysIqProtocolEntity, self).__init__("encrypt", _type="get", to=YowConstants.WHATSAPP_SERVER) self.jids = jids self.reason = reason @property def reason(self): # type: () -> str return self._reason @reason.setter def reason(self, value): # type: (str) -> None self._reason = value @property def jids(self): # type: () -> list[str] return self._jids @jids.setter def jids(self, value): # type: (list[str]) -> None assert type(value) is list, "expected list of jids, got %s" % type(value) self._jids = value def toProtocolTreeNode(self): node = super(GetKeysIqProtocolEntity, self).toProtocolTreeNode() keyNode = ProtocolTreeNode("key") for jid in self.jids: attrs = { "jid": jid } if self.reason is not None: attrs["reason"] = self.reason userNode = ProtocolTreeNode("user", attrs) keyNode.addChild(userNode) node.addChild(keyNode) return node yowsup-3.2.3/yowsup/layers/axolotl/protocolentities/iq_keys_get_result.py000066400000000000000000000130771346433372600273200ustar00rootroot00000000000000from yowsup.common import YowConstants from yowsup.layers.protocol_iq.protocolentities import ResultIqProtocolEntity from yowsup.structs import ProtocolTreeNode from axolotl.state.prekeybundle import PreKeyBundle from axolotl.identitykey import IdentityKey from axolotl.ecc.curve import Curve from axolotl.ecc.djbec import DjbECPublicKey import binascii import sys class ResultGetKeysIqProtocolEntity(ResultIqProtocolEntity): """ HEX:7a9cec4b HEX:05 HEX:eeb668c8d062c99b43560c811acfe6e492798b496767eb060d99e011d3862369 HEX:000000 HEX:a1b5216ce4678143fb20aaaa2711a8c2b647230164b79414f0550b4e611ccd6c HEX:94c231327fcd664b34603838b5e9ba926718d71c206e92b2b400f5cf4ae7bf17d83557bf328c1be6d51efdbd731a26d000adb8f38f140b1ea2a5fd3df2688085 HEX:36b545 HEX:c20826f622bec24b349ced38f1854bdec89ba098ef4c06b2402800d33e9aff61 """ def __init__(self, _id, preKeyBundleMap = None): super(ResultGetKeysIqProtocolEntity, self).__init__(_from = YowConstants.WHATSAPP_SERVER, _id=_id) self.setPreKeyBundleMap(preKeyBundleMap) def getJids(self): return self.preKeyBundleMap.keys() def setPreKeyBundleMap(self, preKeyBundleMap = None): self.preKeyBundleMap = preKeyBundleMap or {} def setPreKeyBundleFor(self, jid, preKeyBundle): self.preKeyBundleMap[jid] = preKeyBundle def getPreKeyBundleFor(self, jid): if jid in self.preKeyBundleMap: return self.preKeyBundleMap[jid] @staticmethod def _intToBytes(val): return binascii.unhexlify(format(val, 'x').zfill(8).encode()) @staticmethod def _bytesToInt(val): if sys.version_info >= (3,0): valEnc = val.encode('latin-1') if type(val) is str else val else: valEnc = val return int(binascii.hexlify(valEnc), 16) @staticmethod def encStr(string): if sys.version_info >= (3,0) and type(string) is str: return string.encode('latin-1') return string @staticmethod def fromProtocolTreeNode(node): entity = ResultIqProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = ResultGetKeysIqProtocolEntity entity.setPreKeyBundleMap() userNodes = node.getChild("list").getAllChildren() for userNode in userNodes: preKeyNode = userNode.getChild("key") signedPreKeyNode = userNode.getChild("skey") registrationId = ResultGetKeysIqProtocolEntity._bytesToInt(userNode.getChild("registration").getData()) identityKey = IdentityKey(DjbECPublicKey(ResultGetKeysIqProtocolEntity.encStr(userNode.getChild("identity").getData()))) preKeyId = ResultGetKeysIqProtocolEntity._bytesToInt(preKeyNode.getChild("id").getData()) preKeyPublic = DjbECPublicKey(ResultGetKeysIqProtocolEntity.encStr(preKeyNode.getChild("value").getData())) signedPreKeyId = ResultGetKeysIqProtocolEntity._bytesToInt(signedPreKeyNode.getChild("id").getData()) signedPreKeySig = ResultGetKeysIqProtocolEntity.encStr(signedPreKeyNode.getChild("signature").getData()) signedPreKeyPub = DjbECPublicKey(ResultGetKeysIqProtocolEntity.encStr(signedPreKeyNode.getChild("value").getData())) preKeyBundle = PreKeyBundle(registrationId, 1, preKeyId, preKeyPublic, signedPreKeyId, signedPreKeyPub, signedPreKeySig, identityKey) entity.setPreKeyBundleFor(userNode["jid"], preKeyBundle) return entity def toProtocolTreeNode(self): node = super(ResultGetKeysIqProtocolEntity, self).toProtocolTreeNode() listNode = ProtocolTreeNode("list") node.addChild(listNode) for jid, preKeyBundle in self.preKeyBundleMap.items(): userNode = ProtocolTreeNode("user", {"jid": jid}) registrationNode = ProtocolTreeNode("registration", data = self.__class__._intToBytes(preKeyBundle.getRegistrationId())) typeNode = ProtocolTreeNode("type", data = self.__class__._intToBytes(Curve.DJB_TYPE)) identityNode = ProtocolTreeNode("identity", data = preKeyBundle.getIdentityKey().getPublicKey().getPublicKey()) skeyNode = ProtocolTreeNode("skey") skeyNode_idNode = ProtocolTreeNode("id", data=self.__class__._intToBytes(preKeyBundle.getSignedPreKeyId())) skeyNode_valueNode = ProtocolTreeNode("value", data=preKeyBundle.getSignedPreKey().getPublicKey()) skeyNode_signatureNode = ProtocolTreeNode("signature", data=preKeyBundle.getSignedPreKeySignature()) skeyNode.addChildren([skeyNode_idNode, skeyNode_valueNode, skeyNode_signatureNode]) preKeyNode = ProtocolTreeNode("key") preKeyNode_idNode = ProtocolTreeNode("id", data = self.__class__._intToBytes(preKeyBundle.getPreKeyId())) preKeyNode_valueNode = ProtocolTreeNode("value", data= preKeyBundle.getPreKey().getPublicKey()) preKeyNode.addChildren([preKeyNode_idNode, preKeyNode_valueNode]) userNode.addChildren([ registrationNode, typeNode, identityNode, skeyNode, preKeyNode ]) listNode.addChild(userNode) return node yowsup-3.2.3/yowsup/layers/axolotl/protocolentities/iq_keys_set.py000066400000000000000000000055041346433372600257320ustar00rootroot00000000000000from yowsup.common import YowConstants from yowsup.layers.protocol_iq.protocolentities import IqProtocolEntity from yowsup.structs import ProtocolTreeNode import os, time class SetKeysIqProtocolEntity(IqProtocolEntity): def __init__(self, identityKey, signedPreKey, preKeys, djbType, registrationId = None): super(SetKeysIqProtocolEntity, self).__init__("encrypt", _type = "set", to = YowConstants.WHATSAPP_SERVER) self.setProps(identityKey, signedPreKey, preKeys, djbType, registrationId) def setProps(self, identityKey, signedPreKey, preKeys, djbType, registrationId = None): assert type(preKeys) is dict, "Expected keys to be a dict key_id -> public_key" assert type(signedPreKey) is tuple, "Exception signed pre key to be tuple id,key,signature" self.preKeys = preKeys self.identityKey = identityKey self.registration = registrationId or os.urandom(4) self.djbType = int(djbType) self.signedPreKey = signedPreKey @staticmethod def fromProtocolTreeNode(node): entity = IqProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = SetKeysIqProtocolEntity regVal = node.getChild("registration").data typeVal = node.getChild("type").data idVal = node.getChild("identity").data preKeys = {} for keyNode in node.getChild("list").getAllChildren(): preKeys[keyNode.getChild("id").data] = keyNode.getChild("value").data skeyNode = node.getChild("skey") entity.setProps(idVal, (skeyNode.getChild("id").data, skeyNode.getChild("value").data, skeyNode.getChild("signature").data), preKeys, typeVal, regVal) return entity def toProtocolTreeNode(self): node = super(SetKeysIqProtocolEntity, self).toProtocolTreeNode() identityNode = ProtocolTreeNode("identity", data = self.identityKey) listNode = ProtocolTreeNode("list") keyNodes = [] for keyId, pk in self.preKeys.items(): keyNode = ProtocolTreeNode("key") keyNode.addChild(ProtocolTreeNode("id", data = keyId)) keyNode.addChild(ProtocolTreeNode("value", data = pk)) keyNodes.append(keyNode) listNode.addChildren(keyNodes) regNode = ProtocolTreeNode("registration", data = self.registration) typeNode = ProtocolTreeNode("type", data = chr(self.djbType)) _id, val, signature = self.signedPreKey skeyNode = ProtocolTreeNode("skey", children = [ ProtocolTreeNode("id", data = _id), ProtocolTreeNode("value", data = val), ProtocolTreeNode("signature", data = signature) ]) node.addChildren([ listNode, identityNode, regNode, typeNode, skeyNode ]) return node yowsup-3.2.3/yowsup/layers/axolotl/protocolentities/message_encrypted.py000066400000000000000000000043731346433372600271170ustar00rootroot00000000000000from yowsup.layers.protocol_messages.protocolentities import MessageProtocolEntity from yowsup.structs import ProtocolTreeNode from yowsup.layers.axolotl.protocolentities.enc import EncProtocolEntity class EncryptedMessageProtocolEntity(MessageProtocolEntity): ''' HEX:33089eb3c90312210510e0196be72fe65913c6a84e75a54f40a3ee290574d6a23f408df990e718da761a210521f1a3f3d5cb87fde19fadf618d3001b64941715efd3e0f36bba48c23b08c82f2242330a21059b0ce2c4720ec79719ba862ee3cda6d6332746d05689af13aabf43ea1c8d747f100018002210d31cd6ebea79e441c4935f72398c772e2ee21447eb675cfa28b99de8d2013000 ''' def __init__(self, encEntities, _type, messageAttributes): super(EncryptedMessageProtocolEntity, self).__init__(_type, messageAttributes) self.setEncEntities(encEntities) def setEncEntities(self, encEntities = None): assert type(encEntities) is list and len(encEntities) \ , "Must have at least a list of minumum 1 enc entity" self.encEntities = encEntities def getEnc(self, encType): for enc in self.encEntities: if enc.type == encType: return enc def getEncEntities(self): return self.encEntities def toProtocolTreeNode(self): node = super(EncryptedMessageProtocolEntity, self).toProtocolTreeNode() participantsNode = ProtocolTreeNode("participants") for enc in self.encEntities: encNode = enc.toProtocolTreeNode() if encNode.tag == "to": participantsNode.addChild(encNode) else: node.addChild(encNode) if len(participantsNode.getAllChildren()): node.addChild(participantsNode) return node @staticmethod def fromProtocolTreeNode(node): entity = MessageProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = EncryptedMessageProtocolEntity entity.setEncEntities( [EncProtocolEntity.fromProtocolTreeNode(encNode) for encNode in node.getAllChildren("enc")] ) return entity yowsup-3.2.3/yowsup/layers/axolotl/protocolentities/notification_encrypt_identitychange.py000066400000000000000000000020041346433372600327140ustar00rootroot00000000000000from yowsup.common import YowConstants from yowsup.layers.protocol_notifications.protocolentities import NotificationProtocolEntity from yowsup.structs import ProtocolTreeNode class IdentityChangeEncryptNotification(NotificationProtocolEntity): """ """ def __init__(self, timestamp, _id = None, notify = None, offline = None): super(IdentityChangeEncryptNotification, self).__init__( "encrypt", _id, YowConstants.WHATSAPP_SERVER, timestamp, notify, offline ) def toProtocolTreeNode(self): node = super(IdentityChangeEncryptNotification, self).toProtocolTreeNode() node.addChild(ProtocolTreeNode("identity")) return node @staticmethod def fromProtocolTreeNode(node): entity = NotificationProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = IdentityChangeEncryptNotification return entity yowsup-3.2.3/yowsup/layers/axolotl/protocolentities/notification_encrypt_requestkeys.py000066400000000000000000000024531346433372600323110ustar00rootroot00000000000000from yowsup.common import YowConstants from yowsup.layers.protocol_notifications.protocolentities import NotificationProtocolEntity from yowsup.structs import ProtocolTreeNode class RequestKeysEncryptNotification(NotificationProtocolEntity): """ """ def __init__(self, count, timestamp, _id = None, notify = None, offline = None): super(RequestKeysEncryptNotification, self).__init__( "encrypt", _id, YowConstants.WHATSAPP_SERVER, timestamp, notify, offline ) self._count = count @property def count(self): return self._count @count.setter def count(self, value): self._count = value def toProtocolTreeNode(self): node = super(RequestKeysEncryptNotification, self).toProtocolTreeNode() count_node = ProtocolTreeNode("count", {"value": str(self.count)}) node.addChild(count_node) return node @staticmethod def fromProtocolTreeNode(node): entity = NotificationProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = RequestKeysEncryptNotification entity.count = node.getChild("count")["value"] return entity yowsup-3.2.3/yowsup/layers/axolotl/protocolentities/receipt_incoming_retry.py000066400000000000000000000045611346433372600301600ustar00rootroot00000000000000from yowsup.structs import ProtocolTreeNode from yowsup.layers.protocol_receipts.protocolentities import IncomingReceiptProtocolEntity from yowsup.layers.axolotl.protocolentities.iq_keys_get_result import ResultGetKeysIqProtocolEntity class RetryIncomingReceiptProtocolEntity(IncomingReceiptProtocolEntity): ''' HEX:xxxxxxxxx ''' def __init__(self, _id, jid, remoteRegistrationId, receiptTimestamp, retryTimestamp, v = 1, count = 1, participant = None, offline = None): super(RetryIncomingReceiptProtocolEntity, self).__init__(_id, jid, receiptTimestamp, offline=offline, type="retry", participant=participant) self.setRetryData(remoteRegistrationId, v,count, retryTimestamp) def setRetryData(self, remoteRegistrationId, v, count, retryTimestamp): self.remoteRegistrationId = remoteRegistrationId self.v = int(v) self.count = int(count) self.retryTimestamp = int(retryTimestamp) def toProtocolTreeNode(self): node = super(RetryIncomingReceiptProtocolEntity, self).toProtocolTreeNode() retry = ProtocolTreeNode("retry", { "count": str(self.count), "id": self.getId(), "v": str(self.v), "t": str(self.retryTimestamp) }) node.addChild(retry) registration = ProtocolTreeNode("registration", data=ResultGetKeysIqProtocolEntity._intToBytes(self.remoteRegistrationId)) node.addChild(registration) return node def getRetryCount(self): return self.count def getRetryJid(self): return self.getParticipant() or self.getFrom() def __str__(self): out = super(RetryIncomingReceiptProtocolEntity, self).__str__() return out @staticmethod def fromProtocolTreeNode(node): entity = IncomingReceiptProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = RetryIncomingReceiptProtocolEntity retryNode = node.getChild("retry") entity.setRetryData(ResultGetKeysIqProtocolEntity._bytesToInt(node.getChild("registration").data), retryNode["v"], retryNode["count"], retryNode["t"]) return entity yowsup-3.2.3/yowsup/layers/axolotl/protocolentities/receipt_outgoing_retry.py000066400000000000000000000054311346433372600302050ustar00rootroot00000000000000from yowsup.structs import ProtocolTreeNode from yowsup.layers.protocol_receipts.protocolentities import OutgoingReceiptProtocolEntity from yowsup.layers.axolotl.protocolentities.iq_keys_get_result import ResultGetKeysIqProtocolEntity class RetryOutgoingReceiptProtocolEntity(OutgoingReceiptProtocolEntity): ''' HEX:xxxxxxxxx ''' def __init__(self, _id, jid, localRegistrationId, retryTimestamp, v = 1, count = 1, participant = None): super(RetryOutgoingReceiptProtocolEntity, self).__init__(_id, jid, participant=participant) ''' Note to self: Android clients won't retry sending if the retry node didn't contain the message timestamp ''' self.setRetryData(localRegistrationId, v,count, retryTimestamp) def setRetryData(self, localRegistrationId, v, count, retryTimestamp): self.localRegistrationId = localRegistrationId self.v = v self.count = count self.retryTimestamp = int(retryTimestamp) def toProtocolTreeNode(self): node = super(RetryOutgoingReceiptProtocolEntity, self).toProtocolTreeNode() node.setAttribute("type", "retry") retryAttribs = { "count": str(self.count), "id":self.getId(), "v":str(self.v), "t": str(self.retryTimestamp) } retry = ProtocolTreeNode("retry", retryAttribs) node.addChild(retry) registration = ProtocolTreeNode("registration", data=ResultGetKeysIqProtocolEntity._intToBytes(self.localRegistrationId)) node.addChild(registration) return node def __str__(self): out = super(RetryOutgoingReceiptProtocolEntity, self).__str__() return out @staticmethod def fromProtocolTreeNode(node): entity = OutgoingReceiptProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = RetryOutgoingReceiptProtocolEntity retryNode = node.getChild("retry") entity.setRetryData(ResultGetKeysIqProtocolEntity._bytesToInt(node.getChild("registration").data), retryNode["v"], retryNode["count"], retryNode["t"]) return entity @staticmethod def fromMessageNode(messageNodeToBeRetried, localRegistrationId): return RetryOutgoingReceiptProtocolEntity( messageNodeToBeRetried.getAttributeValue("id"), messageNodeToBeRetried.getAttributeValue("from"), localRegistrationId, messageNodeToBeRetried.getAttributeValue("t"), participant=messageNodeToBeRetried.getAttributeValue("participant") ) yowsup-3.2.3/yowsup/layers/axolotl/protocolentities/test_iq_keys_get_result.py000066400000000000000000000054441346433372600303560ustar00rootroot00000000000000from yowsup.common import YowConstants from yowsup.layers.protocol_iq.protocolentities.test_iq_result import ResultIqProtocolEntityTest from yowsup.layers.axolotl.protocolentities import ResultGetKeysIqProtocolEntity from yowsup.structs import ProtocolTreeNode from axolotl.util.keyhelper import KeyHelper from axolotl.ecc.curve import Curve class ResultGetKeysIqProtocolEntityTest(ResultIqProtocolEntityTest): def setUp(self): super(ResultIqProtocolEntityTest, self).setUp() self.ProtocolEntity = ResultGetKeysIqProtocolEntity listNode = ProtocolTreeNode("list") self.node.addChild(listNode) for i in range(0, 1): userNode = ProtocolTreeNode("user", {"jid": "user_%s@%s" % (i, YowConstants.WHATSAPP_SERVER)}) listNode.addChild(userNode) registrationNode = ProtocolTreeNode("registration", data = ResultGetKeysIqProtocolEntity._intToBytes( KeyHelper.generateRegistrationId())) typeNode = ProtocolTreeNode("type", data = ResultGetKeysIqProtocolEntity._intToBytes(Curve.DJB_TYPE)) identityKeyPair = KeyHelper.generateIdentityKeyPair() identityNode = ProtocolTreeNode("identity", data=identityKeyPair.getPublicKey().getPublicKey().getPublicKey()) signedPreKey = KeyHelper.generateSignedPreKey(identityKeyPair, i) signedPreKeyNode = ProtocolTreeNode("skey") signedPreKeyNode_idNode = ProtocolTreeNode("id", data = ResultGetKeysIqProtocolEntity._intToBytes( signedPreKey.getId())) signedPreKeyNode_valueNode = ProtocolTreeNode("value", data = signedPreKey.getKeyPair().getPublicKey().getPublicKey()) signedPreKeyNode_sigNode = ProtocolTreeNode("signature", data = signedPreKey.getSignature()) signedPreKeyNode.addChildren([signedPreKeyNode_idNode, signedPreKeyNode_valueNode, signedPreKeyNode_sigNode]) preKey = KeyHelper.generatePreKeys(i * 10, 1)[0] preKeyNode = ProtocolTreeNode("key") preKeyNode_idNode = ProtocolTreeNode("id", data = ResultGetKeysIqProtocolEntity._intToBytes(preKey.getId())) preKeyNode_valNode = ProtocolTreeNode("value", data = preKey.getKeyPair().getPublicKey().getPublicKey()) preKeyNode.addChildren([preKeyNode_idNode, preKeyNode_valNode]) userNode.addChildren([ registrationNode, typeNode, identityNode, signedPreKeyNode, preKeyNode ]) yowsup-3.2.3/yowsup/layers/axolotl/protocolentities/test_iq_keys_set.py000066400000000000000000000017471346433372600267760ustar00rootroot00000000000000from yowsup.layers.protocol_iq.protocolentities.test_iq import IqProtocolEntityTest from yowsup.layers.axolotl.protocolentities import SetKeysIqProtocolEntity from yowsup.structs import ProtocolTreeNode class SetKeysIqProtocolEntityTest(IqProtocolEntityTest): def setUp(self): super(SetKeysIqProtocolEntityTest, self).setUp() # self.ProtocolEntity = SetKeysIqProtocolEntity # # regNode = ProtocolTreeNode("registration", data = "abcd") # idNode = ProtocolTreeNode("identity", data = "efgh") # typeNode = ProtocolTreeNode("type", data = "ijkl") # listNode = ProtocolTreeNode("list") # for i in range(0, 2): # keyNode = ProtocolTreeNode("key", children=[ # ProtocolTreeNode("id", data = "id_%s" % i), # ProtocolTreeNode("value", data = "val_%s" % i) # ]) # listNode.addChild(keyNode) # # self.node.addChildren([regNode, idNode, typeNode, listNode]) yowsup-3.2.3/yowsup/layers/axolotl/protocolentities/test_notification_encrypt_requestkeys.py000066400000000000000000000010241346433372600333410ustar00rootroot00000000000000from yowsup.layers.protocol_notifications.protocolentities.test_notification import NotificationProtocolEntityTest from yowsup.layers.axolotl.protocolentities import RequestKeysEncryptNotification from yowsup.structs import ProtocolTreeNode class TestRequestKeysEncryptNotification(NotificationProtocolEntityTest): def setUp(self): super(TestRequestKeysEncryptNotification, self).setUp() self.ProtocolEntity = RequestKeysEncryptNotification self.node.addChild(ProtocolTreeNode("count", {"value": "9"}))yowsup-3.2.3/yowsup/layers/coder/000077500000000000000000000000001346433372600170415ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/coder/__init__.py000066400000000000000000000000401346433372600211440ustar00rootroot00000000000000from .layer import YowCoderLayeryowsup-3.2.3/yowsup/layers/coder/decoder.py000066400000000000000000000213361346433372600210250ustar00rootroot00000000000000from yowsup.structs import ProtocolTreeNode import math import binascii import sys import zlib class ReadDecoder: def __init__(self, tokenDictionary): self.tokenDictionary = tokenDictionary def getProtocolTreeNode(self, data): if type(data) is list: data = bytearray(data) if data[0] & self.tokenDictionary.FLAG_DEFLATE != 0: data = bytearray(b'\x00' + zlib.decompress(bytes(data[1:]))) if data[0] & self.tokenDictionary.FLAG_SEGMENTED != 0: raise ValueError("server to client stanza fragmentation not supported") return self.nextTreeInternal(data[1:]) def getToken(self, index, data): token = self.tokenDictionary.getToken(index) if not token: index = self.readInt8(data) token = self.tokenDictionary.getToken(index, True) if not token: raise ValueError("Invalid token %s" % token) return token def getTokenDouble(self, n, n2): pos = n2 + n * 256 token = self.tokenDictionary.getToken(pos, True) if not token: raise ValueError("Invalid token %s" % pos) return token def streamStart(self, data): self.streamStarted = True tag = data.pop(0) size = self.readListSize(tag, data) tag = data.pop(0) if tag != 1: if tag == 236: tag = data.pop(0) + 237 token = self.getToken(tag, data)#self.tokenDictionary.getToken(tag) raise Exception("expecting STREAM_START in streamStart, instead got token: %s" % token) attribCount = (size - 2 + size % 2) / 2 self.readAttributes(attribCount, data) def readNibble(self, data): _byte = self.readInt8(data) ignoreLastNibble = bool(_byte & 0x80) size = (_byte & 0x7f) nrOfNibbles = size * 2 - int(ignoreLastNibble) dataArr = self.readArray(size, data) string = '' for i in range(0, nrOfNibbles): _byte = dataArr[int(math.floor(i/2))] _shift = 4 * (1 - i % 2) dec = (_byte & (15 << _shift)) >> _shift if dec in (0,1,2,3,4,5,6,7,8,9): string += str(dec) elif dec in (10, 11): string += chr(dec - 10 + 45) else: raise Exception("Bad nibble %s" % dec) return string def readPacked8(self, n, data): size = self.readInt8(data) remove = 0 if (size & 0x80) != 0 and n == 251: remove = 1 size = size & 0x7F text = bytearray(self.readArray(size, data)) hexData = binascii.hexlify(str(text) if sys.version_info < (2,7) else text).upper() dataSize = len(hexData) out = [] if remove == 0: for i in range(0, dataSize): char = chr(hexData[i]) if type(hexData[i]) is int else hexData[i] #python2/3 compat val = ord(binascii.unhexlify("0%s" % char)) if i == (dataSize - 1) and val > 11 and n != 251: continue out.append(self.unpackByte(n, val)) else: out = map(ord, list(hexData[0: -remove])) if sys.version_info < (3,0) else list(hexData[0: -remove]) return out def unpackByte(self, n, n2): if n == 251: return self.unpackHex(n2) if n == 255: return self.unpackNibble(n2) raise ValueError("bad packed type %s" % n) def unpackHex(self, n): if n in range(0, 10): return n + 48 if n in range(10, 16): return 65 + (n - 10) raise ValueError("bad hex %s" % n) def unpackNibble(self, n): if n in range(0, 10): return n + 48 if n in (10, 11): return 45 + (n - 10) raise ValueError("bad nibble %s" % n) def readHeader(self, data, offset = 0): ret = 0 if len(data) >= (3 + offset): b0 = data[offset] b1 = data[offset + 1] b2 = data[offset + 2] ret = b0 + (b1 << 16) + (b2 << 8) return ret def readInt8(self, data): return data.pop(0); def readInt16(self, data): intTop = data.pop(0) intBot = data.pop(0) value = (intTop << 8) + intBot if value is not None: return value else: return "" def readInt20(self, data): int1 = data.pop(0) int2 = data.pop(0) int3 = data.pop(0) return ((int1 & 0xF) << 16) | (int2 << 8) | int3 def readInt24(self, data): int1 = data.pop(0) int2 = data.pop(0) int3 = data.pop(0) value = (int1 << 16) + (int2 << 8) + (int3 << 0) return value def readInt31(self, data): data.pop(0) int1 = data.pop(0) int2 = data.pop(0) int3 = data.pop(0) return (int1 << 24) | (int1 << 16) | int2 << 8 | int3 def readListSize(self,token, data): size = 0 if token == 0: size = 0 else: if token == 248: size = self.readInt8(data) else: if token == 249: size = self.readInt16(data) else: raise Exception("invalid list size in readListSize: token " + str(token)) return size def readAttributes(self, attribCount, data): attribs = {} for i in range(0, int(attribCount)): key = self.readString(self.readInt8(data), data) value = self.readString(self.readInt8(data), data) attribs[key]=value return attribs def readString(self,token, data): if token == -1: raise Exception("-1 token in readString") if 2 < token < 236: return self.getToken(token, data) if token == 0: return None if token in (236, 237, 238, 239): return self.getTokenDouble(token - 236, self.readInt8(data)) if token == 250: user = self.readString(data.pop(0), data) server = self.readString(data.pop(0), data) if user is not None and server is not None: return user + "@" + server if server is not None: return server raise Exception("readString couldn't reconstruct jid") if token in (251, 255): return "".join(map(chr, self.readPacked8(token, data))) if token == 252: size8 = self.readInt8(data) buf8 = self.readArray(size8, data) return "".join(map(chr, buf8)) if token == 253: size20 = self.readInt20(data) buf20 = self.readArray(size20, data) return "".join(map(chr, buf20)) if token == 254: size31 = self.readInt31() buf31 = self.readArray(size31, data) return "".join(map(chr, buf31)) raise Exception("readString couldn't match token "+str(token)) def readArray(self, length, data): out = [] for i in range(0, length): out.append(data.pop(0)) return out def nextTreeInternal(self, data): size = self.readListSize(self.readInt8(data), data) token = self.readInt8(data) if token == 1: token = self.readInt8(data) if token == 2: return None tag = self.readString(token, data) if size == 0 or tag is None: raise ValueError("nextTree sees 0 list or null tag") attribCount = (size - 2 + size % 2)/2 attribs = self.readAttributes(attribCount, data) if size % 2 ==1: return ProtocolTreeNode(tag, attribs) read2 = self.readInt8(data) nodeData = None nodeChildren = None if self.isListTag(read2): nodeChildren = self.readList(read2, data) elif read2 == 252: size = self.readInt8(data) nodeData = self.readArray(size, data) elif read2 == 253: size = self.readInt20(data) nodeData = self.readArray(size, data) elif read2 == 254: size = self.readInt31(data) nodeData = self.readArray(size, data) elif read2 in (255, 251): nodeData = self.readPacked8(read2, data) else: nodeData = self.readString(read2, data) if nodeData and type(nodeData) is not str: nodeData = "".join(map(chr, nodeData)) return ProtocolTreeNode(tag, attribs, nodeChildren, nodeData) def readList(self,token, data): size = self.readListSize(token, data) listx = [] for i in range(0,size): listx.append(self.nextTreeInternal(data)) return listx; def isListTag(self, b): return b in (248, 0, 249) yowsup-3.2.3/yowsup/layers/coder/encoder.py000066400000000000000000000126331346433372600210370ustar00rootroot00000000000000class WriteEncoder: def __init__(self, tokenDictionary): self.tokenDictionary = tokenDictionary def protocolTreeNodeToBytes(self, node): outBytes = [0] # flags self.writeInternal(node, outBytes) return outBytes def writeInternal(self, node, data): x = 1 + \ (0 if node.attributes is None else len(node.attributes) * 2) + \ (0 if not node.hasChildren() else 1) + \ (0 if node.data is None else 1) self.writeListStart(x, data) self.writeString(node.tag, data) self.writeAttributes(node.attributes, data); if node.data is not None: self.writeBytes(node.data, data) if node.hasChildren(): self.writeListStart(len(node.children), data); for c in node.children: self.writeInternal(c, data); def writeAttributes(self, attributes, data): if attributes is not None: for key, value in attributes.items(): self.writeString(key, data); self.writeString(value, data, True); def writeBytes(self, bytes_, data, packed = False): bytes__ = [] for b in bytes_: if type(b) is int: bytes__.append(b) else: bytes__.append(ord(b)) size = len(bytes__) toWrite = bytes__ if size >= 0x100000: data.append(254) self.writeInt31(size, data) elif size >= 0x100: data.append(253) self.writeInt20(size, data) else: r = None if packed: if size < 128: r = self.tryPackAndWriteHeader(255, bytes__, data) if r is None: r = self.tryPackAndWriteHeader(251, bytes__, data) if r is None: data.append(252) self.writeInt8(size, data) else: toWrite = r data.extend(toWrite) def writeInt8(self, v, data): data.append(v & 0xFF) def writeInt16(self, v, data): data.append((v & 0xFF00) >> 8); data.append((v & 0xFF) >> 0); def writeInt20(self, v, data): data.append((0xF0000 & v) >> 16) data.append((0xFF00 & v) >> 8) data.append((v & 0xFF) >> 0) def writeInt24(self, v, data): data.append((v & 0xFF0000) >> 16) data.append((v & 0xFF00) >> 8) data.append((v & 0xFF) >> 0) def writeInt31(self, v, data): data.append((0x7F000000 & v) >> 24) data.append((0xFF0000 & v) >> 16) data.append((0xFF00 & v) >> 8) data.append((v & 0xFF) >> 0) def writeListStart(self, i, data): if i == 0: data.append(0) elif i < 256: data.append(248) self.writeInt8(i, data) else: data.append(249) self.writeInt16(i, data) def writeToken(self, token, data): if token <= 255 and token >=0: data.append(token) else: raise ValueError("Invalid token: %s" % token) def writeString(self, tag, data, packed = False): tok = self.tokenDictionary.getIndex(tag) if tok: index, secondary = tok if secondary: self.writeToken(236, data) self.writeToken(index, data) else: at = '@'.encode() if type(tag) == bytes else '@' try: atIndex = tag.index(at) if atIndex < 1: raise ValueError("atIndex < 1") else: server = tag[atIndex+1:] user = tag[0:atIndex] self.writeJid(user, server, data) except ValueError: self.writeBytes(self.encodeString(tag), data, packed) def encodeString(self, string): res = [] if type(string) == bytes: for char in string: res.append(char) else: for char in string: res.append(ord(char)) return res; def writeJid(self, user, server, data): data.append(250) if user is not None: self.writeString(user, data, True) else: self.writeToken(0, data) self.writeString(server, data) def tryPackAndWriteHeader(self, v, headerData, data): size = len(headerData) if size >= 128: return None arr = [0] * int((size + 1) / 2) for i in range(0, size): packByte = self.packByte(v, headerData[i]) if packByte == -1: arr = [] break n2 = int(i / 2) arr[n2] |= (packByte << 4 * (1 - i % 2)) if len(arr) > 0: if size % 2 == 1: arr[-1] |= 15 #0xF data.append(v) self.writeInt8(size %2 << 7 | len(arr), data) return arr return None def packByte(self, v, n2): if v == 251: return self.packHex(n2) if v == 255: return self.packNibble(n2) return -1 def packHex(self, n): if n in range(48, 58): return n - 48 if n in range(65, 71): return 10 + (n - 65) return -1 def packNibble(self, n): if n in (45, 46): return 10 + (n - 45) if n in range(48, 58): return n - 48 return -1 yowsup-3.2.3/yowsup/layers/coder/layer.py000066400000000000000000000014741346433372600205350ustar00rootroot00000000000000from yowsup.layers import YowLayer from .encoder import WriteEncoder from .decoder import ReadDecoder from .tokendictionary import TokenDictionary class YowCoderLayer(YowLayer): def __init__(self): YowLayer.__init__(self) tokenDictionary = TokenDictionary() self.writer = WriteEncoder(tokenDictionary) self.reader = ReadDecoder(tokenDictionary) def send(self, data): self.write(self.writer.protocolTreeNodeToBytes(data)) def receive(self, data): node = self.reader.getProtocolTreeNode(bytearray(data)) if node: self.toUpper(node) def write(self, i): if(type(i) in(list, tuple)): self.toLower(bytearray(i)) else: self.toLower(bytearray([i])) def __str__(self): return "Coder Layer" yowsup-3.2.3/yowsup/layers/coder/test_decoder.py000066400000000000000000000014311346433372600220560ustar00rootroot00000000000000import unittest from yowsup.layers.coder.decoder import ReadDecoder from yowsup.layers.coder.tokendictionary import TokenDictionary from yowsup.structs import ProtocolTreeNode class DecoderTest(unittest.TestCase): def setUp(self): self.decoder = ReadDecoder(TokenDictionary()) self.decoder.streamStarted = True def test_decode(self): data = [0, 248, 6, 95, 179, 252, 3, 120, 121, 122, 252, 4, 102, 111, 114, 109, 252, 3, 97, 98, 99, 248, 1, 248, 4, 93, 236, 104, 255, 130, 18, 63, 252, 6, 49, 50, 51, 52, 53, 54] node = self.decoder.getProtocolTreeNode(data) targetNode = ProtocolTreeNode("message", {"form": "abc", "to":"xyz"}, [ProtocolTreeNode("media", {"width" : "123"}, data="123456")]) self.assertEqual(node, targetNode) yowsup-3.2.3/yowsup/layers/coder/test_encoder.py000066400000000000000000000017421346433372600220750ustar00rootroot00000000000000import unittest from yowsup.structs import ProtocolTreeNode from yowsup.layers.coder.encoder import WriteEncoder from yowsup.layers.coder.tokendictionary import TokenDictionary class EncoderTest(unittest.TestCase): def setUp(self): self.res = [] self.encoder = WriteEncoder(TokenDictionary()) def test_encode(self): node = ProtocolTreeNode("message", {"form": "abc", "to":"xyz"}, [ProtocolTreeNode("media", {"width" : "123"}, data="123456")]) result = self.encoder.protocolTreeNodeToBytes(node) self.assertTrue(result in ( [0, 248, 6, 95, 179, 252, 3, 120, 121, 122, 252, 4, 102, 111, 114, 109, 252, 3, 97, 98, 99, 248, 1, 248, 4, 93, 236, 104, 255, 130, 18, 63, 252, 6, 49, 50, 51, 52, 53, 54], [0, 248, 6, 95, 252, 4, 102, 111, 114, 109, 252, 3, 97, 98, 99, 179, 252, 3, 120, 121, 122, 248, 1, 248, 4, 93, 236, 104, 255, 130, 18, 63, 252, 6, 49, 50, 51, 52, 53, 54] ) ) yowsup-3.2.3/yowsup/layers/coder/test_tokendictionary.py000066400000000000000000000013431346433372600236610ustar00rootroot00000000000000from yowsup.layers.coder.tokendictionary import TokenDictionary import unittest class TokenDictionaryTest(unittest.TestCase): def setUp(self): self.tokenDictionary = TokenDictionary() def test_getToken(self): self.assertEqual(self.tokenDictionary.getToken(80), "iq") def test_getIndex(self): self.assertEqual(self.tokenDictionary.getIndex("iq"), (80, False)) def test_getSecondaryToken(self): self.assertEqual(self.tokenDictionary.getToken(238), "amrnb") def test_getSecondaryTokenExplicit(self): self.assertEqual(self.tokenDictionary.getToken(11, True), "wmv") def test_getSecondaryIndex(self): self.assertEqual(self.tokenDictionary.getIndex("wmv"), (11, True))yowsup-3.2.3/yowsup/layers/coder/tokendictionary.py000066400000000000000000000307541346433372600226320ustar00rootroot00000000000000class TokenDictionary: FLAG_SEGMENTED = 0x1 FLAG_DEFLATE = 0x2 def __init__(self): self.dictionary = [ '', '', '', 'account', 'ack', 'action', 'active', 'add', 'after', 'all', 'allow', 'apple', 'audio', 'auth', 'author', 'available', 'bad-protocol', 'bad-request', 'before', 'bits', 'body', 'broadcast', 'cancel', 'category', 'challenge', 'chat', 'clean', 'code', 'composing', 'config', 'contacts', 'count', 'create', 'creation', 'debug', 'default', 'delete', 'delivery', 'delta', 'deny', 'digest', 'dirty', 'duplicate', 'elapsed', 'enable', 'encoding', 'encrypt', 'error', 'event', 'expiration', 'expired', 'fail', 'failure', 'false', 'favorites', 'feature', 'features', 'feature-not-implemented', 'field', 'file', 'filehash', 'first', 'free', 'from', 'g.us', 'gcm', 'get', 'google', 'group', 'groups', 'groups_v2', 'http://etherx.jabber.org/streams', 'http://jabber.org/protocol/chatstates', 'ib', 'id', 'image', 'img', 'index', 'internal-server-error', 'ip', 'iq', 'item-not-found', 'item', 'jabber:iq:last', 'jabber:iq:privacy', 'jabber:x:event', 'jid', 'kind', 'last', 'leave', 'list', 'max', 'mechanism', 'media', 'message_acks', 'message', 'method', 'microsoft', 'mimetype', 'missing', 'modify', 'msg', 'mute', 'name', 'nokia', 'none', 'not-acceptable', 'not-allowed', 'not-authorized', 'notification', 'notify', 'off', 'offline', 'order', 'owner', 'owning', 'p_o', 'p_t', 'paid', 'participant', 'participants', 'participating', 'paused', 'picture', 'pin', 'ping', 'pkmsg', 'platform', 'port', 'presence', 'preview', 'probe', 'prop', 'props', 'qcount', 'query', 'raw', 'read', 'readreceipts', 'reason', 'receipt', 'relay', 'remote-server-timeout', 'remove', 'request', 'required', 'resource-constraint', 'resource', 'response', 'result', 'retry', 'rim', 's_o', 's_t', 's.us', 's.whatsapp.net', 'seconds', 'server-error', 'server', 'service-unavailable', 'set', 'show', 'silent', 'size', 'skmsg', 'stat', 'state', 'status', 'stream:error', 'stream:features', 'subject', 'subscribe', 'success', 'sync', 't', 'text', 'timeout', 'timestamp', 'tizen', 'to', 'true', 'type', 'unavailable', 'unsubscribe', 'upgrade', 'uri', 'url', 'urn:ietf:params:xml:ns:xmpp-sasl', 'urn:ietf:params:xml:ns:xmpp-stanzas', 'urn:ietf:params:xml:ns:xmpp-streams', 'urn:xmpp:ping', 'urn:xmpp:whatsapp:account', 'urn:xmpp:whatsapp:dirty', 'urn:xmpp:whatsapp:mms', 'urn:xmpp:whatsapp:push', 'urn:xmpp:whatsapp', 'user', 'user-not-found', 'v', 'value', 'version', 'voip', 'w:g', 'w:p:r', 'w:p', 'w:profile:picture', 'w', 'wait', 'WAUTH-2', 'xmlns:stream', 'xmlns', '1', 'chatstate', 'crypto', 'phash', 'enc', 'class', 'off_cnt', 'w:g2', 'promote', 'demote', 'creator', 'background', 'backoff', 'chunked', 'context', 'full', 'in', 'interactive', 'out', 'registration', 'sid', 'urn:xmpp:whatsapp:sync', 'flt', 's16', 'u8', ] self.secondaryDictionary = [ 'adpcm', 'amrnb', 'amrwb', 'mp3', 'pcm', 'qcelp', 'wma', 'h263', 'h264', 'jpeg', 'mpeg4', 'wmv', 'audio/3gpp', 'audio/aac', 'audio/amr', 'audio/mp4', 'audio/mpeg', 'audio/ogg', 'audio/qcelp', 'audio/wav', 'audio/webm', 'audio/x-caf', 'audio/x-ms-wma', 'image/gif', 'image/jpeg', 'image/png', 'video/3gpp', 'video/avi', 'video/mp4', 'video/mpeg', 'video/quicktime', 'video/x-flv', 'video/x-ms-asf', '302', '400', '401', '402', '403', '404', '405', '406', '407', '409', '410', '500', '501', '503', '504', 'abitrate', 'acodec', 'app_uptime', 'asampfmt', 'asampfreq', 'clear', 'conflict', 'conn_no_nna', 'cost', 'currency', 'duration', 'extend', 'fps', 'g_notify', 'g_sound', 'gone', 'google_play', 'hash', 'height', 'invalid', 'jid-malformed', 'latitude', 'lc', 'lg', 'live', 'location', 'log', 'longitude', 'max_groups', 'max_participants', 'max_subject', 'mode', 'napi_version', 'normalize', 'orighash', 'origin', 'passive', 'password', 'played', 'policy-violation', 'pop_mean_time', 'pop_plus_minus', 'price', 'pricing', 'redeem', 'Replaced by new connection', 'resume', 'signature', 'sound', 'source', 'system-shutdown', 'username', 'vbitrate', 'vcard', 'vcodec', 'video', 'width', 'xml-not-well-formed', 'checkmarks', 'image_max_edge', 'image_max_kbytes', 'image_quality', 'ka', 'ka_grow', 'ka_shrink', 'newmedia', 'library', 'caption', 'forward', 'c0', 'c1', 'c2', 'c3', 'clock_skew', 'cts', 'k0', 'k1', 'login_rtt', 'm_id', 'nna_msg_rtt', 'nna_no_off_count', 'nna_offline_ratio', 'nna_push_rtt', 'no_nna_con_count', 'off_msg_rtt', 'on_msg_rtt', 'stat_name', 'sts', 'suspect_conn', 'lists', 'self', 'qr', 'web', 'w:b', 'recipient', 'w:stats', 'forbidden', 'max_list_recipients', 'en-AU', 'en-GB', 'es-MX', 'pt-PT', 'zh-Hans', 'zh-Hant', 'relayelection', 'relaylatency', 'interruption', 'Bell.caf', 'Boing.caf', 'Glass.caf', 'Harp.caf', 'TimePassing.caf', 'Tri-tone.caf', 'Xylophone.caf', 'aurora.m4r', 'bamboo.m4r', 'chord.m4r', 'circles.m4r', 'complete.m4r', 'hello.m4r', 'input.m4r', 'keys.m4r', 'note.m4r', 'popcorn.m4r', 'pulse.m4r', 'synth.m4r', 'Apex.m4r', 'Beacon.m4r', 'Bulletin.m4r', 'By The Seaside.m4r', 'Chimes.m4r', 'Circuit.m4r', 'Constellation.m4r', 'Cosmic.m4r', 'Crystals.m4r', 'Hillside.m4r', 'Illuminate.m4r', 'Night Owl.m4r', 'Opening.m4r', 'Playtime.m4r', 'Presto.m4r', 'Radar.m4r', 'Radiate.m4r', 'Ripples.m4r', 'Sencha.m4r', 'Signal.m4r', 'Silk.m4r', 'Slow Rise.m4r', 'Stargaze.m4r', 'Summit.m4r', 'Twinkle.m4r', 'Uplift.m4r', 'Waves.m4r', 'eligible', 'planned', 'current', 'future', 'disable', 'expire', 'start', 'stop', 'accuracy', 'speed', 'bearing', 'recording', 'key', 'identity', 'w:gp2', 'admin', 'locked', 'unlocked', 'new', 'battery', 'archive', 'adm', 'plaintext_size', 'plaintext_disabled', 'plaintext_reenable_threshold', 'compressed_size', 'delivered', 'everyone', 'transport', 'mspes', 'e2e_groups', 'e2e_images', 'encr_media', 'encrypt_v2', 'encrypt_image', 'encrypt_sends_push', 'force_long_connect', 'audio_opus', 'video_max_edge', 'call-id', 'call', 'preaccept', 'accept', 'offer', 'reject', 'busy', 'te', 'terminate', 'begin', 'end', 'opus', 'rtt', 'token', 'priority', 'p2p', 'rate', 'amr', 'ptt', 'srtp', 'os', 'browser', 'encrypt_group_gen2', "encrypt_audio", "encrypt_blist", "encrypt_contact", "encrypt_location", "encrypt_url", "encrypt_video", "doc_types", "upload_oom_hprof_enabled", "tos", "client", "e2e_audio", "e2e_blists", "e2e_video", "document", "contact", "file_max_size", "small_call_btn", "enable_mp4_operations_mux", "android_vacuuming_enabled", "android_vacuum_experiment_enabled", "aec", "agc", "options", "encode", "bwe", "rc", "ns", "ec_threshold", "ec_off_threshold", "algorithm", "targetlevel", "compressiongain", "limiterenable", "cbr", "complexity", "minfpp", "maxrtt", "low_data_usage_bitrate", "usync", "refresh", "media_max_autodownload" ] def getToken(self, index, secondary = False): targetDict = self.dictionary if secondary: targetDict = self.secondaryDictionary elif index > 236 and index < (236 + len(self.secondaryDictionary)): targetDict = self.secondaryDictionary index = index - 237 if index < 0 or index > len(targetDict) - 1: return None return targetDict[index] def getIndex(self, token): if token in self.dictionary: return (self.dictionary.index(token), False) elif token in self.secondaryDictionary: return (self.secondaryDictionary.index(token), True) return None yowsup-3.2.3/yowsup/layers/interface/000077500000000000000000000000001346433372600177055ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/interface/__init__.py000066400000000000000000000001001346433372600220050ustar00rootroot00000000000000from .interface import YowInterfaceLayer, ProtocolEntityCallbackyowsup-3.2.3/yowsup/layers/interface/interface.py000066400000000000000000000144531346433372600222260ustar00rootroot00000000000000from yowsup.layers import YowLayer, YowLayerEvent from yowsup.layers.protocol_iq.protocolentities import IqProtocolEntity from yowsup.layers.auth import YowAuthenticationProtocolLayer from yowsup.layers.protocol_media.protocolentities.iq_requestupload import RequestUploadIqProtocolEntity from yowsup.layers.protocol_media.mediauploader import MediaUploader from yowsup.layers.network.layer import YowNetworkLayer from yowsup.layers.auth.protocolentities import StreamErrorProtocolEntity from yowsup.layers import EventCallback import inspect import logging logger = logging.getLogger(__name__) class ProtocolEntityCallback(object): def __init__(self, entityType): self.entityType = entityType def __call__(self, fn): fn.entity_callback = self.entityType return fn class YowInterfaceLayer(YowLayer): PROP_RECONNECT_ON_STREAM_ERR = "org.openwhatsapp.yowsup.prop.interface.reconnect_on_stream_error" def __init__(self): super(YowInterfaceLayer, self).__init__() self.reconnect = False self.entity_callbacks = {} self.iqRegistry = {} # self.receiptsRegistry = {} members = inspect.getmembers(self, predicate=inspect.ismethod) for m in members: if hasattr(m[1], "entity_callback"): fname = m[0] fn = m[1] self.entity_callbacks[fn.entity_callback] = getattr(self, fname) def _sendIq(self, iqEntity, onSuccess=None, onError=None): assert iqEntity.getTag() == "iq", "Expected *IqProtocolEntity in _sendIq, got %s" % iqEntity.getTag() self.iqRegistry[iqEntity.getId()] = (iqEntity, onSuccess, onError) self.toLower(iqEntity) def processIqRegistry(self, entity): """ :type entity: IqProtocolEntity """ if entity.getTag() == "iq": iq_id = entity.getId() if iq_id in self.iqRegistry: originalIq, successClbk, errorClbk = self.iqRegistry[iq_id] del self.iqRegistry[iq_id] if entity.getType() == IqProtocolEntity.TYPE_RESULT and successClbk: successClbk(entity, originalIq) elif entity.getType() == IqProtocolEntity.TYPE_ERROR and errorClbk: errorClbk(entity, originalIq) return True return False def getOwnJid(self, full=True): return self.getLayerInterface(YowAuthenticationProtocolLayer).getUsername(full) def connect(self): self.getLayerInterface(YowNetworkLayer).connect() def disconnect(self): disconnectEvent = YowLayerEvent(YowNetworkLayer.EVENT_STATE_DISCONNECT) self.broadcastEvent(disconnectEvent) def send(self, data): self.toLower(data) def receive(self, entity): if not self.processIqRegistry(entity): entityType = entity.getTag() if entityType in self.entity_callbacks: self.entity_callbacks[entityType](entity) else: self.toUpper(entity) @ProtocolEntityCallback("stream:error") def onStreamError(self, streamErrorEntity): logger.error(streamErrorEntity) if self.getProp(self.__class__.PROP_RECONNECT_ON_STREAM_ERR, True): if streamErrorEntity.getErrorType() == StreamErrorProtocolEntity.TYPE_CONFLICT: logger.warn("Not reconnecting because you signed in in another location") else: logger.info("Initiating reconnect") self.reconnect = True else: logger.warn("Not reconnecting because property %s is not set" % self.__class__.PROP_RECONNECT_ON_STREAM_ERR) self.toUpper(streamErrorEntity) self.disconnect() @EventCallback(YowNetworkLayer.EVENT_STATE_CONNECTED) def onConnected(self, yowLayerEvent): self.reconnect = False @EventCallback(YowNetworkLayer.EVENT_STATE_DISCONNECTED) def onDisconnected(self, yowLayerEvent): if self.reconnect: self.reconnect = False self.connect() def _sendMediaMessage(self, builder, success, error=None, progress=None): # axolotlIface = self.getLayerInterface(YowAxolotlLayer) # if axolotlIface: # axolotlIface.encryptMedia(builder) iq = RequestUploadIqProtocolEntity( builder.mediaType, filePath=builder.getFilepath(), encrypted=builder.isEncrypted()) def successFn(resultEntity, requestUploadEntity): return self.__onRequestUploadSuccess( resultEntity, requestUploadEntity, builder, success, error, progress) def errorFn(errorEntity, requestUploadEntity): return self.__onRequestUploadError( errorEntity, requestUploadEntity, error) self._sendIq(iq, successFn, errorFn) def __onRequestUploadSuccess(self, resultRequestUploadIqProtocolEntity, requestUploadEntity, builder, success, error=None, progress=None): if(resultRequestUploadIqProtocolEntity.isDuplicate()): return success(builder.build(resultRequestUploadIqProtocolEntity.getUrl(), resultRequestUploadIqProtocolEntity.getIp())) else: def successFn(path, jid, url): return self.__onMediaUploadSuccess( builder, url, resultRequestUploadIqProtocolEntity.getIp(), success) def errorFn(path, jid, errorText): return self.__onMediaUploadError( builder, errorText, error) mediaUploader = MediaUploader(builder.jid, self.getOwnJid(), builder.getFilepath(), resultRequestUploadIqProtocolEntity.getUrl(), resultRequestUploadIqProtocolEntity.getResumeOffset(), successFn, errorFn, progress, asynchronous=True) mediaUploader.start() def __onRequestUploadError(self, errorEntity, requestUploadEntity, builder, error=None): if error: return error(errorEntity.code, errorEntity.text, errorEntity.backoff) def __onMediaUploadSuccess(self, builder, url, ip, successClbk): messageNode = builder.build(url, ip) return successClbk(messageNode) def __onMediaUploadError(self, builder, errorText, errorClbk=None): if errorClbk: return errorClbk(0, errorText, 0) def __str__(self): return "Interface Layer" yowsup-3.2.3/yowsup/layers/logger/000077500000000000000000000000001346433372600172245ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/logger/__init__.py000066400000000000000000000000421346433372600213310ustar00rootroot00000000000000from .layer import YowLoggerLayer yowsup-3.2.3/yowsup/layers/logger/layer.py000066400000000000000000000007531346433372600207170ustar00rootroot00000000000000from yowsup.layers import YowLayer import logging logger = logging.getLogger(__name__) class YowLoggerLayer(YowLayer): def send(self, data): ldata = list(data) if type(data) is bytearray else data logger.debug("tx:\n%s" % ldata) self.toLower(data) def receive(self, data): ldata = list(data) if type(data) is bytearray else data logger.debug("rx:\n%s" % ldata) self.toUpper(data) def __str__(self): return "Logger Layer"yowsup-3.2.3/yowsup/layers/network/000077500000000000000000000000001346433372600174365ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/network/__init__.py000066400000000000000000000000431346433372600215440ustar00rootroot00000000000000from .layer import YowNetworkLayer yowsup-3.2.3/yowsup/layers/network/dispatcher/000077500000000000000000000000001346433372600215645ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/network/dispatcher/__init__.py000066400000000000000000000000001346433372600236630ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/network/dispatcher/dispatcher.py000066400000000000000000000011241346433372600242620ustar00rootroot00000000000000class ConnectionCallbacks(object): def onConnected(self): pass def onDisconnected(self): pass def onRecvData(self, data): pass def onConnecting(self): pass def onConnectionError(self, error): pass class YowConnectionDispatcher(object): def __init__(self, connectionCallbacks): assert isinstance(connectionCallbacks, ConnectionCallbacks) self.connectionCallbacks = connectionCallbacks def connect(self, host): pass def disconnect(self): pass def sendData(self, data): passyowsup-3.2.3/yowsup/layers/network/dispatcher/dispatcher_asyncore.py000066400000000000000000000032111346433372600261640ustar00rootroot00000000000000from yowsup.layers.network.dispatcher.dispatcher import YowConnectionDispatcher import asyncore import logging import socket import traceback logger = logging.getLogger(__name__) class AsyncoreConnectionDispatcher(YowConnectionDispatcher, asyncore.dispatcher_with_send): def __init__(self, connectionCallbacks): super(AsyncoreConnectionDispatcher, self).__init__(connectionCallbacks) asyncore.dispatcher_with_send.__init__(self) self._connected = False def sendData(self, data): if self._connected: self.out_buffer = self.out_buffer + data self.initiate_send() else: logger.warn("Attempted to send %d bytes while still not connected" % len(data)) def connect(self, host): logger.debug("connect(%s)" % str(host)) self.connectionCallbacks.onConnecting() self.create_socket(socket.AF_INET, socket.SOCK_STREAM) asyncore.dispatcher_with_send.connect(self, host) asyncore.loop(timeout=1) def handle_connect(self): logger.debug("handle_connect") if not self._connected: self._connected = True self.connectionCallbacks.onConnected() def handle_close(self): logger.debug("handle_close") self.close() self._connected = False self.connectionCallbacks.onDisconnected() def handle_error(self): logger.error(traceback.format_exc()) self.handle_close() def handle_read(self): data = self.recv(1024) self.connectionCallbacks.onRecvData(data) def disconnect(self): logger.debug("disconnect") self.handle_close() yowsup-3.2.3/yowsup/layers/network/dispatcher/dispatcher_socket.py000066400000000000000000000033471346433372600256430ustar00rootroot00000000000000from yowsup.layers.network.dispatcher.dispatcher import YowConnectionDispatcher import socket import logging logger = logging.getLogger(__name__) class SocketConnectionDispatcher(YowConnectionDispatcher): def __init__(self, connectionCallbacks): super(SocketConnectionDispatcher, self).__init__(connectionCallbacks) self.socket = None def connect(self, host): if not self.socket: self.socket = socket.socket() self.connectAndLoop(host) else: logger.error("Already connected?") def disconnect(self): if self.socket: try: self.socket.shutdown(socket.SHUT_WR) self.socket.close() except socket.error as e: logger.error(e) self.socket = None self.connectionCallbacks.onDisconnected() else: logger.error("Not connected?") def connectAndLoop(self, host): socket = self.socket self.connectionCallbacks.onConnecting() try: socket.connect(host) self.connectionCallbacks.onConnected() while True: data = socket.recv(1024) if len(data): self.connectionCallbacks.onRecvData(data) else: break self.connectionCallbacks.onDisconnected() except Exception as e: logger.error(e) self.connectionCallbacks.onConnectionError(e) finally: self.socket = None socket.close() def sendData(self, data): try: self.socket.send(data) except socket.error as e: logger.error(e) self.disconnect() yowsup-3.2.3/yowsup/layers/network/layer.py000066400000000000000000000102351346433372600211250ustar00rootroot00000000000000from yowsup.layers import YowLayer, YowLayerEvent, EventCallback from yowsup.layers.network.layer_interface import YowNetworkLayerInterface from yowsup.layers.network.dispatcher.dispatcher import ConnectionCallbacks from yowsup.layers.network.dispatcher.dispatcher import YowConnectionDispatcher from yowsup.layers.network.dispatcher.dispatcher_socket import SocketConnectionDispatcher from yowsup.layers.network.dispatcher.dispatcher_asyncore import AsyncoreConnectionDispatcher import logging logger = logging.getLogger(__name__) class YowNetworkLayer(YowLayer, ConnectionCallbacks): """This layer wraps a connection dispatcher that provides connection and a communication channel to remote endpoints. Unless explicitly configured, applications should not make assumption about the dispatcher being used as the default dispatcher could be changed across versions""" EVENT_STATE_CONNECT = "org.openwhatsapp.yowsup.event.network.connect" EVENT_STATE_DISCONNECT = "org.openwhatsapp.yowsup.event.network.disconnect" EVENT_STATE_CONNECTED = "org.openwhatsapp.yowsup.event.network.connected" EVENT_STATE_DISCONNECTED = "org.openwhatsapp.yowsup.event.network.disconnected" PROP_ENDPOINT = "org.openwhatsapp.yowsup.prop.endpoint" PROP_NET_READSIZE = "org.openwhatsapp.yowsup.prop.net.readSize" PROP_DISPATCHER = "org.openwhatsapp.yowsup.prop.net.dispatcher" STATE_DISCONNECTED = 0 STATE_CONNECTING = 1 STATE_CONNECTED = 2 STATE_DISCONNECTING = 3 DISPATCHER_SOCKET = 0 DISPATCHER_ASYNCORE = 1 DISPATCHER_DEFAULT = DISPATCHER_ASYNCORE def __init__(self): self.state = self.__class__.STATE_DISCONNECTED YowLayer.__init__(self) ConnectionCallbacks.__init__(self) self.interface = YowNetworkLayerInterface(self) self.connected = False self._dispatcher = None # type: YowConnectionDispatcher def __create_dispatcher(self, dispatcher_type): if dispatcher_type == self.DISPATCHER_ASYNCORE: logger.debug("Created asyncore dispatcher") return AsyncoreConnectionDispatcher(self) else: logger.debug("Created socket dispatcher") return SocketConnectionDispatcher(self) def onConnected(self): logger.debug("Connected") self.state = self.__class__.STATE_CONNECTED self.connected = True self.emitEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECTED)) def onDisconnected(self): if self.state != self.__class__.STATE_DISCONNECTED: self.state = self.__class__.STATE_DISCONNECTED self.connected = False logger.debug("Disconnected") self.emitEvent(YowLayerEvent(self.__class__.EVENT_STATE_DISCONNECTED, reason="", detached=True)) def onConnecting(self): pass def onConnectionError(self, error): self.onDisconnected() @EventCallback(EVENT_STATE_CONNECT) def onConnectLayerEvent(self, ev): if not self.connected: self.createConnection() else: logger.warn("Received connect event while already connected") return True @EventCallback(EVENT_STATE_DISCONNECT) def onDisconnectLayerEvent(self, ev): self.destroyConnection(ev.getArg("reason")) return True def createConnection(self): self._dispatcher = self.__create_dispatcher(self.getProp(self.PROP_DISPATCHER, self.DISPATCHER_DEFAULT)) self.state = self.__class__.STATE_CONNECTING endpoint = self.getProp(self.__class__.PROP_ENDPOINT) logger.info("Connecting to %s:%s" % endpoint) self._dispatcher.connect(endpoint) def destroyConnection(self, reason = None): self.state = self.__class__.STATE_DISCONNECTING self._dispatcher.disconnect() def getStatus(self): return self.connected def send(self, data): if self.connected: self._dispatcher.sendData(data) def onRecvData(self, data): self.receive(data) def receive(self, data): self.toUpper(data) def __str__(self): return "Network Layer" yowsup-3.2.3/yowsup/layers/network/layer_interface.py000066400000000000000000000004401346433372600231420ustar00rootroot00000000000000from yowsup.layers import YowLayerInterface class YowNetworkLayerInterface(YowLayerInterface): def connect(self): self._layer.createConnection() def disconnect(self): self._layer.destroyConnection() def getStatus(self): return self._layer.getStatus()yowsup-3.2.3/yowsup/layers/noise/000077500000000000000000000000001346433372600170625ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/noise/__init__.py000066400000000000000000000000001346433372600211610ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/noise/layer.py000066400000000000000000000134331346433372600205540ustar00rootroot00000000000000from yowsup.layers.noise.workers.handshake import WANoiseProtocolHandshakeWorker from yowsup.layers import YowLayer, EventCallback from yowsup.layers.auth.layer_authentication import YowAuthenticationProtocolLayer from yowsup.layers.network.layer import YowNetworkLayer from yowsup.layers.noise.layer_noise_segments import YowNoiseSegmentsLayer from yowsup.config.manager import ConfigManager from yowsup.env.env import YowsupEnv from consonance.protocol import WANoiseProtocol from consonance.config.client import ClientConfig from consonance.config.useragent import UserAgentConfig from consonance.streams.segmented.blockingqueue import BlockingQueueSegmentedStream from consonance.structs.keypair import KeyPair import threading import logging logger = logging.getLogger(__name__) try: import Queue except ImportError: import queue as Queue class YowNoiseLayer(YowLayer): DEFAULT_PUSHNAME = "yowsup" HEADER = b'WA\x02\x01' EDGE_HEADER = b'ED\x00\x01' def __init__(self): super(YowNoiseLayer, self).__init__() self._wa_noiseprotocol = WANoiseProtocol( 2, 1, protocol_state_callbacks=self._on_protocol_state_changed ) # type: WANoiseProtocol self._handshake_worker = None self._stream = BlockingQueueSegmentedStream() # type: BlockingQueueSegmentedStream self._read_buffer = bytearray() self._flush_lock = threading.Lock() self._incoming_segments_queue = Queue.Queue() self._config_manager = ConfigManager() self._username = None self._rs = None def __str__(self): return "Noise Layer" @EventCallback(YowNetworkLayer.EVENT_STATE_DISCONNECTED) def on_disconnected(self, event): self._wa_noiseprotocol.reset() @EventCallback(YowAuthenticationProtocolLayer.EVENT_AUTH) def on_auth(self, event): logger.debug("Received auth event") credentials = event.getArg("credentials") self._username, local_static = int(credentials[0]), credentials[1] config = self._config_manager.load(self._username) # type: yowsup.config.v1.config.Config # event's keypair will override config's keypair local_static = local_static or config.client_static_keypair if type(local_static) is bytes: local_static = KeyPair.from_bytes(local_static) assert type(local_static) is KeyPair passive = event.getArg('passive') self.setProp(YowNoiseSegmentsLayer.PROP_ENABLED, False) if config.edge_routing_info: self.toLower(self.EDGE_HEADER) self.setProp(YowNoiseSegmentsLayer.PROP_ENABLED, True) self.toLower(config.edge_routing_info) self.setProp(YowNoiseSegmentsLayer.PROP_ENABLED, False) self.toLower(self.HEADER) self.setProp(YowNoiseSegmentsLayer.PROP_ENABLED, True) remote_static = config.server_static_public self._rs = remote_static yowsupenv = YowsupEnv.getCurrent() client_config = ClientConfig( username=self._username, passive=passive, useragent=UserAgentConfig( platform=0, app_version=yowsupenv.getVersion(), mcc=config.mcc or "000", mnc=config.mnc or "000", os_version=yowsupenv.getOSVersion(), manufacturer=yowsupenv.getManufacturer(), device=yowsupenv.getDeviceName(), os_build_number=yowsupenv.getOSVersion(), phone_id=config.fdid or "", locale_lang="en", locale_country="US" ), pushname=config.pushname or self.DEFAULT_PUSHNAME, short_connect=True ) if not self._in_handshake(): logger.debug("Performing handshake [username= %d, passive=%s]" % (self._username, passive) ) self._handshake_worker = WANoiseProtocolHandshakeWorker( self._wa_noiseprotocol, self._stream, client_config, local_static, remote_static, ) logger.debug("Starting handshake worker") self._stream.set_events_callback(self._handle_stream_event) self._handshake_worker.start() def _in_handshake(self): """ :return: :rtype: bool """ return self._wa_noiseprotocol.state == WANoiseProtocol.STATE_HANDSHAKE def _on_protocol_state_changed(self, state): if state == WANoiseProtocol.STATE_TRANSPORT: if self._rs != self._wa_noiseprotocol.rs: config = self._config_manager.load(self._username) config.server_static_public = self._wa_noiseprotocol.rs self._config_manager.save(config) self._rs = self._wa_noiseprotocol.rs self._flush_incoming_buffer() def _handle_stream_event(self, event): if event == BlockingQueueSegmentedStream.EVENT_WRITE: self.toLower(self._stream.get_write_segment()) elif event == BlockingQueueSegmentedStream.EVENT_READ: self._stream.put_read_segment(self._incoming_segments_queue.get(block=True)) def send(self, data): """ :param data: :type data: bytearray | bytes :return: :rtype: """ data = bytes(data) if type(data) is not bytes else data self._wa_noiseprotocol.send(data) def _flush_incoming_buffer(self): self._flush_lock.acquire() while self._incoming_segments_queue.qsize(): self.toUpper(self._wa_noiseprotocol.receive()) self._flush_lock.release() def receive(self, data): """ :param data: :type data: bytes :return: :rtype: """ self._incoming_segments_queue.put(data) if not self._in_handshake(): self._flush_incoming_buffer() yowsup-3.2.3/yowsup/layers/noise/layer_noise_segments.py000066400000000000000000000024021346433372600236500ustar00rootroot00000000000000from yowsup.layers import YowLayer import logging import struct logger = logging.getLogger(__name__) class YowNoiseSegmentsLayer(YowLayer): PROP_ENABLED = "org.openwhatsapp.yowsup.prop.noise.segmented_enabled" def __init__(self): super(YowNoiseSegmentsLayer, self).__init__() self._read_buffer = bytearray() def __str__(self): return "Noise Segments Layer" def send(self, data): if len(data) >= 16777216: raise ValueError("data too large to write; length=%d" % len(data)) if self.getProp(self.PROP_ENABLED, False): self.toLower(struct.pack('>I', len(data))[1:]) self.toLower(data) def receive(self, data): if self.getProp(self.PROP_ENABLED, False): self._read_buffer.extend(data) while len(self._read_buffer) > 3: read_size = struct.unpack('>I', b"\x00" + self._read_buffer[:3])[0] # type: int if len(self._read_buffer) >= (3 + read_size): data = self._read_buffer[3:read_size+3] self._read_buffer = self._read_buffer[3 + read_size:] self.toUpper(bytes(data)) else: break else: self.toUpper(data) yowsup-3.2.3/yowsup/layers/noise/workers/000077500000000000000000000000001346433372600205565ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/noise/workers/__init__.py000066400000000000000000000000001346433372600226550ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/noise/workers/handshake.py000066400000000000000000000025431346433372600230620ustar00rootroot00000000000000from consonance.protocol import WANoiseProtocol from consonance.streams.segmented.segmented import SegmentedStream from consonance.config.client import ClientConfig from dissononce.dh.keypair import KeyPair from dissononce.dh.x25519.x25519 import PublicKey import threading class WANoiseProtocolHandshakeWorker(threading.Thread): def __init__(self, wanoiseprotocol, stream, client_config, s, rs=None, finish_callback=None): """ :param wanoiseprotocol: :type wanoiseprotocol: WANoiseProtocol :param stream: :type stream: SegmentedStream :param client_config: :type client_config: ClientConfig :param s: :type s: KeyPair :param rs: :type rs: PublicKey | None """ super(WANoiseProtocolHandshakeWorker, self).__init__() self.daemon = True self._protocol = wanoiseprotocol # type: WANoiseProtocol self._stream = stream # type: SegmentedStream self._client_config = client_config # type: ClientConfig self._s = s # type: KeyPair self._rs = rs # type: PublicKey self._finish_callback = finish_callback def run(self): self._protocol.reset() self._protocol.start(self._stream, self._client_config, self._s, self._rs) if self._finish_callback is not None: self._finish_callback() yowsup-3.2.3/yowsup/layers/protocol_acks/000077500000000000000000000000001346433372600206075ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_acks/__init__.py000066400000000000000000000000471346433372600227210ustar00rootroot00000000000000from .layer import YowAckProtocolLayer yowsup-3.2.3/yowsup/layers/protocol_acks/layer.py000066400000000000000000000010211346433372600222670ustar00rootroot00000000000000from yowsup.layers import YowProtocolLayer from .protocolentities import * class YowAckProtocolLayer(YowProtocolLayer): def __init__(self): handleMap = { "ack": (self.recvAckNode, self.sendAckEntity) } super(YowAckProtocolLayer, self).__init__(handleMap) def __str__(self): return "Ack Layer" def sendAckEntity(self, entity): self.entityToLower(entity) def recvAckNode(self, node): self.toUpper(IncomingAckProtocolEntity.fromProtocolTreeNode(node)) yowsup-3.2.3/yowsup/layers/protocol_acks/protocolentities/000077500000000000000000000000001346433372600242155ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_acks/protocolentities/__init__.py000066400000000000000000000002121346433372600263210ustar00rootroot00000000000000from .ack import AckProtocolEntity from .ack_incoming import IncomingAckProtocolEntity from .ack_outgoing import OutgoingAckProtocolEntityyowsup-3.2.3/yowsup/layers/protocol_acks/protocolentities/ack.py000066400000000000000000000017431346433372600253320ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode class AckProtocolEntity(ProtocolEntity): ''' ''' def __init__(self, _id, _class): super(AckProtocolEntity, self).__init__("ack") self._id = _id self._class = _class def getId(self): return self._id def getClass(self): return self._class def toProtocolTreeNode(self): attribs = { "id" : self._id, "class" : self._class, } return self._createProtocolTreeNode(attribs, None, data = None) def __str__(self): out = "ACK:\n" out += "ID: %s\n" % self._id out += "Class: %s\n" % self._class return out @staticmethod def fromProtocolTreeNode(node): return AckProtocolEntity( node.getAttributeValue("id"), node.getAttributeValue("class") ) yowsup-3.2.3/yowsup/layers/protocol_acks/protocolentities/ack_incoming.py000066400000000000000000000024301346433372600272070ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .ack import AckProtocolEntity class IncomingAckProtocolEntity(AckProtocolEntity): ''' ''' def __init__(self, _id, _class, _from, timestamp): super(IncomingAckProtocolEntity, self).__init__(_id, _class) self.setIncomingData(_from, timestamp) def setIncomingData(self, _from, timestamp): self._from = _from self.timestamp = timestamp def toProtocolTreeNode(self): node = super(IncomingAckProtocolEntity, self).toProtocolTreeNode() node.setAttribute("from", self._from) node.setAttribute("t", self.timestamp) return node def __str__(self): out = super(IncomingAckProtocolEntity, self).__str__() out += "From: %s\n" % self._from out += "timestamp: %s\n" % self.timestamp return out @staticmethod def fromProtocolTreeNode(node): entity = AckProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = IncomingAckProtocolEntity entity.setIncomingData( node.getAttributeValue("from"), node.getAttributeValue("t") ) return entity yowsup-3.2.3/yowsup/layers/protocol_acks/protocolentities/ack_outgoing.py000066400000000000000000000031761346433372600272470ustar00rootroot00000000000000from .ack import AckProtocolEntity class OutgoingAckProtocolEntity(AckProtocolEntity): ''' ''' def __init__(self, _id, _class, _type, to, participant = None): super(OutgoingAckProtocolEntity, self).__init__(_id, _class) self.setOutgoingData(_type, to, participant) def setOutgoingData(self, _type, _to, _participant): self._type = _type self._to = _to self._participant = _participant def toProtocolTreeNode(self): node = super(OutgoingAckProtocolEntity, self).toProtocolTreeNode() if self._type: node.setAttribute("type", self._type) node.setAttribute("to", self._to) if self._participant: node.setAttribute("participant", self._participant) return node def __str__(self): out = super(OutgoingAckProtocolEntity, self).__str__() out += "Type: %s\n" % self._type out += "To: %s\n" % self._to if self._participant: out += "Participant: %s\n" % self._participant return out @staticmethod def fromProtocolTreeNode(node): entity = AckProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = OutgoingAckProtocolEntity entity.setOutgoingData( node.getAttributeValue("type"), node.getAttributeValue("to"), node.getAttributeValue("participant") ) return entity yowsup-3.2.3/yowsup/layers/protocol_acks/protocolentities/test_ack_incoming.py000066400000000000000000000007461346433372600302560ustar00rootroot00000000000000from yowsup.layers.protocol_acks.protocolentities.ack_incoming import IncomingAckProtocolEntity from yowsup.structs.protocolentity import ProtocolEntityTest import unittest import time entity = IncomingAckProtocolEntity("12345", "message", "sender@s.whatsapp.com", int(time.time())) class IncomingAckProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): self.ProtocolEntity = IncomingAckProtocolEntity self.node = entity.toProtocolTreeNode() yowsup-3.2.3/yowsup/layers/protocol_acks/protocolentities/test_ack_outgoing.py000066400000000000000000000007051346433372600303010ustar00rootroot00000000000000from yowsup.layers.protocol_acks.protocolentities.ack_outgoing import OutgoingAckProtocolEntity from yowsup.structs.protocolentity import ProtocolEntityTest import unittest entity = OutgoingAckProtocolEntity("12345", "receipt", "delivery", "to_jid") class OutgoingAckProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): self.ProtocolEntity = OutgoingAckProtocolEntity self.node = entity.toProtocolTreeNode() yowsup-3.2.3/yowsup/layers/protocol_acks/test_layer.py000066400000000000000000000011241346433372600233320ustar00rootroot00000000000000from yowsup.layers import YowProtocolLayerTest from yowsup.layers.protocol_acks import YowAckProtocolLayer from yowsup.layers.protocol_acks.protocolentities.test_ack_incoming import entity as incomingAckEntity from yowsup.layers.protocol_acks.protocolentities.test_ack_outgoing import entity as outgoingAckEntity class YowAckProtocolLayerTest(YowProtocolLayerTest, YowAckProtocolLayer): def setUp(self): YowAckProtocolLayer.__init__(self) def test_receive(self): self.assertReceived(incomingAckEntity) def test_send(self): self.assertSent(outgoingAckEntity) yowsup-3.2.3/yowsup/layers/protocol_calls/000077500000000000000000000000001346433372600207645ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_calls/__init__.py000066400000000000000000000000511346433372600230710ustar00rootroot00000000000000from .layer import YowCallsProtocolLayer yowsup-3.2.3/yowsup/layers/protocol_calls/layer.py000066400000000000000000000021371346433372600224550ustar00rootroot00000000000000from yowsup.layers import YowProtocolLayer from .protocolentities import * from yowsup.layers.protocol_acks.protocolentities import OutgoingAckProtocolEntity from yowsup.layers.protocol_receipts.protocolentities import OutgoingReceiptProtocolEntity class YowCallsProtocolLayer(YowProtocolLayer): def __init__(self): handleMap = { "call": (self.recvCall, self.sendCall) } super(YowCallsProtocolLayer, self).__init__(handleMap) def __str__(self): return "call Layer" def sendCall(self, entity): if entity.getTag() == "call": self.toLower(entity.toProtocolTreeNode()) def recvCall(self, node): entity = CallProtocolEntity.fromProtocolTreeNode(node) if entity.getType() == "offer": receipt = OutgoingReceiptProtocolEntity(node["id"], node["from"], callId = entity.getCallId()) self.toLower(receipt.toProtocolTreeNode()) else: ack = OutgoingAckProtocolEntity(node["id"], "call", None, node["from"]) self.toLower(ack.toProtocolTreeNode()) self.toUpper(entity) yowsup-3.2.3/yowsup/layers/protocol_calls/protocolentities/000077500000000000000000000000001346433372600243725ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_calls/protocolentities/__init__.py000066400000000000000000000000661346433372600265050ustar00rootroot00000000000000from .call import CallProtocolEntity yowsup-3.2.3/yowsup/layers/protocol_calls/protocolentities/call.py000066400000000000000000000073651346433372600256720ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode class CallProtocolEntity(ProtocolEntity): ''' ''' def __init__(self, _id, _type, timestamp, notify = None, offline = None, retry = None, e = None, callId = None, _from = None, _to = None): super(CallProtocolEntity, self).__init__("call") self._id = _id or self._generateId() self._type = _type self._from = _from self._to = _to self.timestamp = int(timestamp) self.notify = notify self.offline = offline == "1" self.retry = retry self.e = e self.callId = callId def __str__(self): out = "Call\n" if self.getFrom() is not None: out += "From: %s\n" % self.getFrom() if self.getTo() is not None: out += "To: %s\n" % self.getTo() if self.getType() is not None: out += "Type: %s\n" % self.getType() if self.getCallId() is not None: out += "Call ID: %s\n" % self.getCallId() return out def getFrom(self, full = True): return self._from if full else self._from.split('@')[0] def getTo(self): return self._to def getId(self): return self._id def getType(self): return self._type def getCallId(self): return self.callId def getTimestamp(self): return self.timestamp def toProtocolTreeNode(self): children = [] attribs = { "t" : str(self.timestamp), "offline" : "1" if self.offline else "0", "id" : self._id, } if self._from is not None: attribs["from"] = self._from if self._to is not None: attribs["to"] = self._to if self.retry is not None: attribs["retry"] = self.retry if self.e is not None: attribs["e"] = self.e if self.notify is not None: attribs["notify"] = self.notify if self._type in ["offer", "transport", "relaylatency", "reject", "terminate"]: child = ProtocolTreeNode(self._type, {"call-id": self.callId}) children.append(child) return self._createProtocolTreeNode(attribs, children = children, data = None) @staticmethod def fromProtocolTreeNode(node): (_type, callId) = [None] * 2 offer = node.getChild("offer") transport = node.getChild("transport") relaylatency = node.getChild("relaylatency") reject = node.getChild("reject") terminate = node.getChild("terminate") if offer: _type = "offer" callId = offer.getAttributeValue("call-id") elif transport: _type = "transport" callId = transport.getAttributeValue("call-id") elif relaylatency: _type = "relaylatency" callId = relaylatency.getAttributeValue("call-id") elif reject: _type = "reject" callId = reject.getAttributeValue("call-id") elif terminate: _type = "terminate" callId = terminate.getAttributeValue("call-id") return CallProtocolEntity( node.getAttributeValue("id"), _type, node.getAttributeValue("t"), node.getAttributeValue("notify"), node.getAttributeValue("offline"), node.getAttributeValue("retry"), node.getAttributeValue("e"), callId, node.getAttributeValue("from"), node.getAttributeValue("to") ) yowsup-3.2.3/yowsup/layers/protocol_calls/protocolentities/test_call.py000066400000000000000000000012261346433372600267170ustar00rootroot00000000000000from yowsup.layers.protocol_calls.protocolentities.call import CallProtocolEntity from yowsup.structs import ProtocolTreeNode from yowsup.structs.protocolentity import ProtocolEntityTest import unittest class CallProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): self.ProtocolEntity = CallProtocolEntity children = [ProtocolTreeNode("offer", {"call-id": "call_id"})] attribs = { "t": "12345", "from": "from_jid", "offline": "0", "id": "message_id", "notify": "notify_name" } self.node = ProtocolTreeNode("call", attribs, children) yowsup-3.2.3/yowsup/layers/protocol_chatstate/000077500000000000000000000000001346433372600216465ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_chatstate/__init__.py000066400000000000000000000000551346433372600237570ustar00rootroot00000000000000from .layer import YowChatstateProtocolLayer yowsup-3.2.3/yowsup/layers/protocol_chatstate/layer.py000066400000000000000000000011401346433372600233300ustar00rootroot00000000000000from yowsup.layers import YowLayer, YowLayerEvent, YowProtocolLayer from .protocolentities import * class YowChatstateProtocolLayer(YowProtocolLayer): def __init__(self): handleMap = { "chatstate": (self.recvChatstateNode, self.sendChatstateEntity) } super(YowChatstateProtocolLayer, self).__init__(handleMap) def __str__(self): return "Chatstate Layer" def sendChatstateEntity(self, entity): self.entityToLower(entity) def recvChatstateNode(self, node): self.toUpper(IncomingChatstateProtocolEntity.fromProtocolTreeNode(node)) yowsup-3.2.3/yowsup/layers/protocol_chatstate/protocolentities/000077500000000000000000000000001346433372600252545ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_chatstate/protocolentities/__init__.py000066400000000000000000000002571346433372600273710ustar00rootroot00000000000000from .chatstate import ChatstateProtocolEntity from .chatstate_incoming import IncomingChatstateProtocolEntity from .chatstate_outgoing import OutgoingChatstateProtocolEntity yowsup-3.2.3/yowsup/layers/protocol_chatstate/protocolentities/chatstate.py000066400000000000000000000023221346433372600276050ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode class ChatstateProtocolEntity(ProtocolEntity): ''' INCOMING <{{composing|paused}}> OUTGOING <{{composing|paused}}> ''' STATE_TYPING = "composing" STATE_PAUSED = "paused" STATES = (STATE_TYPING, STATE_PAUSED) def __init__(self, _state): super(ChatstateProtocolEntity, self).__init__("chatstate") assert _state in self.__class__.STATES, "Expected chat state to be in %s, got %s" % (self.__class__.STATES, _state) self._state = _state def getState(self): return self._state def toProtocolTreeNode(self): node = self._createProtocolTreeNode({}, None, data = None) node.addChild(ProtocolTreeNode(self._state)) return node def __str__(self): out = "CHATSTATE:\n" out += "State: %s\n" % self._state return out @staticmethod def fromProtocolTreeNode(node): return ChatstateProtocolEntity( node.getAllChildren()[0].tag, ) yowsup-3.2.3/yowsup/layers/protocol_chatstate/protocolentities/chatstate_incoming.py000066400000000000000000000023161346433372600314730ustar00rootroot00000000000000from .chatstate import ChatstateProtocolEntity class IncomingChatstateProtocolEntity(ChatstateProtocolEntity): ''' INCOMING <{{composing|paused}}> OUTGOING <{{composing|paused}}> ''' def __init__(self, _state, _from): super(IncomingChatstateProtocolEntity, self).__init__(_state) self.setIncomingData(_from) def setIncomingData(self, _from): self._from = _from def toProtocolTreeNode(self): node = super(IncomingChatstateProtocolEntity, self).toProtocolTreeNode() node.setAttribute("from", self._from) return node def __str__(self): out = super(IncomingChatstateProtocolEntity, self).__str__() out += "From: %s\n" % self._from return out @staticmethod def fromProtocolTreeNode(node): entity = ChatstateProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = IncomingChatstateProtocolEntity entity.setIncomingData( node.getAttributeValue("from"), ) return entity yowsup-3.2.3/yowsup/layers/protocol_chatstate/protocolentities/chatstate_outgoing.py000066400000000000000000000022721346433372600315240ustar00rootroot00000000000000from .chatstate import ChatstateProtocolEntity class OutgoingChatstateProtocolEntity(ChatstateProtocolEntity): ''' INCOMING <{{composing|paused}}> OUTGOING <{{composing|paused}}> ''' def __init__(self, _state, _to): super(OutgoingChatstateProtocolEntity, self).__init__(_state) self.setOutgoingData(_to) def setOutgoingData(self, _to): self._to = _to def toProtocolTreeNode(self): node = super(OutgoingChatstateProtocolEntity, self).toProtocolTreeNode() node.setAttribute("to", self._to) return node def __str__(self): out = super(OutgoingChatstateProtocolEntity, self).__str__() out += "To: %s\n" % self._to return out @staticmethod def fromProtocolTreeNode(node): entity = ChatstateProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = OutgoingChatstateProtocolEntity entity.setOutgoingData( node.getAttributeValue("to"), ) return entity yowsup-3.2.3/yowsup/layers/protocol_chatstate/protocolentities/test_chatstate_incoming.py000066400000000000000000000010021346433372600325210ustar00rootroot00000000000000from yowsup.layers.protocol_chatstate.protocolentities.chatstate_incoming import IncomingChatstateProtocolEntity from yowsup.structs.protocolentity import ProtocolEntityTest import unittest entity = IncomingChatstateProtocolEntity(IncomingChatstateProtocolEntity.STATE_TYPING, "jid@s.whatsapp.net") class IncomingChatstateProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): self.ProtocolEntity = IncomingChatstateProtocolEntity self.node = entity.toProtocolTreeNode() yowsup-3.2.3/yowsup/layers/protocol_chatstate/protocolentities/test_chatstate_outgoing.py000066400000000000000000000010021346433372600325510ustar00rootroot00000000000000from yowsup.layers.protocol_chatstate.protocolentities.chatstate_outgoing import OutgoingChatstateProtocolEntity from yowsup.structs.protocolentity import ProtocolEntityTest import unittest entity = OutgoingChatstateProtocolEntity(OutgoingChatstateProtocolEntity.STATE_PAUSED, "jid@s.whatsapp.net") class OutgoingChatstateProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): self.ProtocolEntity = OutgoingChatstateProtocolEntity self.node = entity.toProtocolTreeNode() yowsup-3.2.3/yowsup/layers/protocol_chatstate/test_layer.py000066400000000000000000000013661346433372600244010ustar00rootroot00000000000000from yowsup.layers import YowProtocolLayerTest from yowsup.layers.protocol_chatstate import YowChatstateProtocolLayer from yowsup.layers.protocol_chatstate.protocolentities import IncomingChatstateProtocolEntity, OutgoingChatstateProtocolEntity class YowChatStateProtocolLayerTest(YowProtocolLayerTest, YowChatstateProtocolLayer): def setUp(self): YowChatstateProtocolLayer.__init__(self) def test_send(self): entity = OutgoingChatstateProtocolEntity(OutgoingChatstateProtocolEntity.STATE_PAUSED, "jid@s.whatsapp.net") self.assertSent(entity) def test_receive(self): entity = IncomingChatstateProtocolEntity(IncomingChatstateProtocolEntity.STATE_TYPING, "jid@s.whatsapp.net") self.assertReceived(entity)yowsup-3.2.3/yowsup/layers/protocol_contacts/000077500000000000000000000000001346433372600215045ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_contacts/__init__.py000066400000000000000000000000551346433372600236150ustar00rootroot00000000000000from .layer import YowContactsIqProtocolLayeryowsup-3.2.3/yowsup/layers/protocol_contacts/layer.py000066400000000000000000000033201346433372600231700ustar00rootroot00000000000000from yowsup.layers import YowLayer, YowLayerEvent, YowProtocolLayer from yowsup.common import YowConstants from .protocolentities import * class YowContactsIqProtocolLayer(YowProtocolLayer): def __init__(self): handleMap = { "iq": (self.recvIq, self.sendIq), "notification": (self.recvNotification, None) } super(YowContactsIqProtocolLayer, self).__init__(handleMap) def __str__(self): return "Iq Layer" def recvNotification(self, node): if node["type"] == "contacts": if node.getChild("remove"): self.toUpper(RemoveContactNotificationProtocolEntity.fromProtocolTreeNode(node)) elif node.getChild("add"): self.toUpper(AddContactNotificationProtocolEntity.fromProtocolTreeNode(node)) elif node.getChild("update"): self.toUpper(UpdateContactNotificationProtocolEntity.fromProtocolTreeNode(node)) elif node.getChild("sync"): self.toUpper(ContactsSyncNotificationProtocolEntity.fromProtocolTreeNode(node)) else: self.raiseErrorForNode(node) def recvIq(self, node): if node["type"] == "result" and node.getChild("sync"): self.toUpper(ResultSyncIqProtocolEntity.fromProtocolTreeNode(node)) elif node["type"] == "result" and node.getChild("status"): self.toUpper(ResultStatusesIqProtocolEntity.fromProtocolTreeNode(node)) def sendIq(self, entity): if entity.getXmlns() == "urn:xmpp:whatsapp:sync": self.toLower(entity.toProtocolTreeNode()) elif entity.getXmlns() == GetStatusesIqProtocolEntity.XMLNS: self.toLower(entity.toProtocolTreeNode()) yowsup-3.2.3/yowsup/layers/protocol_contacts/protocolentities/000077500000000000000000000000001346433372600251125ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_contacts/protocolentities/__init__.py000066400000000000000000000011071346433372600272220ustar00rootroot00000000000000from .iq_sync import SyncIqProtocolEntity from .iq_sync_get import GetSyncIqProtocolEntity from .iq_sync_result import ResultSyncIqProtocolEntity from .notification_contact_add import AddContactNotificationProtocolEntity from .notification_contact_remove import RemoveContactNotificationProtocolEntity from .notification_contact_update import UpdateContactNotificationProtocolEntity from .notificiation_contacts_sync import ContactsSyncNotificationProtocolEntity from .iq_statuses_get import GetStatusesIqProtocolEntity from .iq_statuses_result import ResultStatusesIqProtocolEntity yowsup-3.2.3/yowsup/layers/protocol_contacts/protocolentities/iq_statuses_get.py000066400000000000000000000031671346433372600306760ustar00rootroot00000000000000from yowsup.common import YowConstants from yowsup.layers.protocol_iq.protocolentities import IqProtocolEntity from yowsup.structs import ProtocolTreeNode class GetStatusesIqProtocolEntity(IqProtocolEntity): XMLNS = "status" def __init__(self, jids, _id = None): """ Request the statuses of users. Should be sent once after login. Args: - jids: A list of jids representing the users whose statuses you are trying to get. """ super(GetStatusesIqProtocolEntity, self).__init__(self.__class__.XMLNS, _id, _type = "get", to = YowConstants.WHATSAPP_SERVER) self.setGetStatusesProps(jids) def setGetStatusesProps(self, jids): assert type(jids) is list, "jids must be a list of jids" self.jids = jids def __str__(self): out = super(GetStatusesIqProtocolEntity, self).__str__() out += "Numbers: %s\n" % (",".join(self.numbers)) return out def toProtocolTreeNode(self): users = [ProtocolTreeNode("user", {'jid': jid}) for jid in self.jids] node = super(GetStatusesIqProtocolEntity, self).toProtocolTreeNode() statusNode = ProtocolTreeNode("status", None, users) node.addChild(statusNode) return node @staticmethod def fromProtocolTreeNode(node): entity = IqProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = GetStatusesIqProtocolEntity statusNode = node.getChild("status") userNodes = statusNode.getAllChildren() jids = [user['jid'] for user in userNodes] entity.setGetStatusesProps(jids) return entity yowsup-3.2.3/yowsup/layers/protocol_contacts/protocolentities/iq_statuses_result.py000066400000000000000000000037711346433372600314360ustar00rootroot00000000000000from yowsup.structs import ProtocolTreeNode from .iq_sync import SyncIqProtocolEntity from yowsup.layers.protocol_iq.protocolentities import IqProtocolEntity class ResultStatusesIqProtocolEntity(IqProtocolEntity): ''' {status message} HEX:{status message in hex} {status message} HEX:{status message in hex} ''' XMLNS = 'status' def __init__(self, _id, _from, statuses): super(ResultStatusesIqProtocolEntity, self).__init__(self.__class__.XMLNS, _id, 'result', _from=_from) self.setResultStatusesProps(statuses) def setResultStatusesProps(self, statuses): assert type(statuses) is dict, "statuses must be dict" self.statuses = statuses def __str__(self): out = super(ResultStatusesIqProtocolEntity, self).__str__() out += "Statuses: %s\n" % ','.join(jid + '(' + str(v) + ')' for jid, v in self.statuses.items()) return out def toProtocolTreeNode(self): node = super(ResultStatusesIqProtocolEntity, self).toProtocolTreeNode() users = [ProtocolTreeNode('user', {'jid': jid, 't': t}, None, status) for jid, (status, t) in self.statuses.items()] statusNode = ProtocolTreeNode('status', None, users) node.addChild(statusNode) return node @staticmethod def fromProtocolTreeNode(node): statusNode = node.getChild('status') users = statusNode.getAllChildren() statuses = dict() for user in users: statuses[user['jid']] = (user.getData(), user['t']) entity = IqProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = ResultStatusesIqProtocolEntity entity.setResultStatusesProps(statuses) return entity yowsup-3.2.3/yowsup/layers/protocol_contacts/protocolentities/iq_sync.py000066400000000000000000000035571346433372600271430ustar00rootroot00000000000000from yowsup.structs import ProtocolTreeNode from yowsup.layers.protocol_iq.protocolentities import IqProtocolEntity import time class SyncIqProtocolEntity(IqProtocolEntity): ''' ''' def __init__(self, _type, _id = None, sid = None, index = 0, last = True): super(SyncIqProtocolEntity, self).__init__("urn:xmpp:whatsapp:sync", _id = _id, _type = _type) self.setSyncProps(sid, index, last) def setSyncProps(self, sid, index, last): self.sid = sid if sid else str((int(time.time()) + 11644477200) * 10000000) self.index = int(index) self.last = last def __str__(self): out = super(SyncIqProtocolEntity, self).__str__() out += "sid: %s\n" % self.sid out += "index: %s\n" % self.index out += "last: %s\n" % self.last return out def toProtocolTreeNode(self): syncNodeAttrs = { "sid": self.sid, "index": str(self.index), "last": "true" if self.last else "false" } syncNode = ProtocolTreeNode("sync", syncNodeAttrs) node = super(SyncIqProtocolEntity, self).toProtocolTreeNode() node.addChild(syncNode) return node @staticmethod def fromProtocolTreeNode(node): syncNode = node.getChild("sync") entity = IqProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = SyncIqProtocolEntity entity.setSyncProps( syncNode.getAttributeValue("sid"), syncNode.getAttributeValue("index"), syncNode.getAttributeValue("last") ) return entity yowsup-3.2.3/yowsup/layers/protocol_contacts/protocolentities/iq_sync_get.py000066400000000000000000000052741346433372600300000ustar00rootroot00000000000000from yowsup.structs import ProtocolTreeNode from yowsup.layers.protocol_iq.protocolentities import IqProtocolEntity from .iq_sync import SyncIqProtocolEntity class GetSyncIqProtocolEntity(SyncIqProtocolEntity): MODE_FULL = "full" MODE_DELTA = "delta" CONTEXT_REGISTRATION = "registration" CONTEXT_INTERACTIVE = "interactive" CONTEXTS = (CONTEXT_REGISTRATION, CONTEXT_INTERACTIVE) MODES = (MODE_FULL, MODE_DELTA) ''' {{num1}} {{num2}} ''' def __init__(self, numbers, mode = MODE_FULL, context = CONTEXT_INTERACTIVE, sid = None, index = 0, last = True): super(GetSyncIqProtocolEntity, self).__init__("get", sid = sid, index = index, last = last) self.setGetSyncProps(numbers, mode, context) def setGetSyncProps(self, numbers, mode, context): assert type(numbers) is list, "numbers must be a list" assert mode in self.__class__.MODES, "mode must be in %s" % self.__class__.MODES assert context in self.__class__.CONTEXTS, "context must be in %s" % self.__class__.CONTEXTS self.numbers = numbers self.mode = mode self.context = context def __str__(self): out = super(GetSyncIqProtocolEntity, self).__str__() out += "Mode: %s\n" % self.mode out += "Context: %s\n" % self.context out += "numbers: %s\n" % (",".join(self.numbers)) return out def toProtocolTreeNode(self): users = [ProtocolTreeNode("user", {}, None, number) for number in self.numbers] node = super(GetSyncIqProtocolEntity, self).toProtocolTreeNode() syncNode = node.getChild("sync") syncNode.setAttribute("mode", self.mode) syncNode.setAttribute("context", self.context) syncNode.addChildren(users) return node @staticmethod def fromProtocolTreeNode(node): syncNode = node.getChild("sync") userNodes = syncNode.getAllChildren() numbers = [userNode.data for userNode in userNodes] entity = SyncIqProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = GetSyncIqProtocolEntity entity.setGetSyncProps(numbers, syncNode.getAttributeValue("mode"), syncNode.getAttributeValue("context"), ) return entity yowsup-3.2.3/yowsup/layers/protocol_contacts/protocolentities/iq_sync_result.py000066400000000000000000000076321346433372600305370ustar00rootroot00000000000000from yowsup.structs import ProtocolTreeNode from .iq_sync import SyncIqProtocolEntity class ResultSyncIqProtocolEntity(SyncIqProtocolEntity): ''' {{number}} abcdefgh ''' def __init__(self,_id, sid, index, last, version, inNumbers, outNumbers, invalidNumbers, wait = None): super(ResultSyncIqProtocolEntity, self).__init__("result", _id, sid, index, last) self.setResultSyncProps(version, inNumbers, outNumbers, invalidNumbers, wait) def setResultSyncProps(self, version, inNumbers, outNumbers, invalidNumbers, wait = None): assert type(inNumbers) is dict, "in numbers must be a dict {number -> jid}" assert type(outNumbers) is dict, "out numbers must be a dict {number -> jid}" assert type(invalidNumbers) is list, "invalid numbers must be a list" self.inNumbers = inNumbers self.outNumbers = outNumbers self.invalidNumbers = invalidNumbers self.wait = int(wait) if wait is not None else None self.version = version def __str__(self): out = super(SyncIqProtocolEntity, self).__str__() if self.wait is not None: out += "Wait: %s\n" % self.wait out += "Version: %s\n" % self.version out += "In Numbers: %s\n" % (",".join(self.inNumbers)) out += "Out Numbers: %s\n" % (",".join(self.outNumbers)) out += "Invalid Numbers: %s\n" % (",".join(self.invalidNumbers)) return out def toProtocolTreeNode(self): outUsers = [ProtocolTreeNode("user", {"jid": jid}, None, number) for number, jid in self.outNumbers.items()] inUsers = [ProtocolTreeNode("user", {"jid": jid}, None, number) for number, jid in self.inNumbers.items()] invalidUsers = [ProtocolTreeNode("user", {}, None, number) for number in self.invalidNumbers] node = super(ResultSyncIqProtocolEntity, self).toProtocolTreeNode() syncNode = node.getChild("sync") syncNode.setAttribute("version", self.version) if self.wait is not None: syncNode.setAttribute("wait", str(self.wait)) if len(outUsers): syncNode.addChild(ProtocolTreeNode("out", children = outUsers)) if len(inUsers): syncNode.addChild(ProtocolTreeNode("in", children = inUsers)) if len(invalidUsers): syncNode.addChildren([ProtocolTreeNode("invalid", children = invalidUsers)]) return node @staticmethod def fromProtocolTreeNode(node): syncNode = node.getChild("sync") outNode = syncNode.getChild("out") inNode = syncNode.getChild("in") invalidNode = syncNode.getChild("invalid") outUsers = outNode.getAllChildren() if outNode else [] inUsers = inNode.getAllChildren() if inNode else [] invalidUsers = [inode.data for inode in invalidNode.getAllChildren()] if invalidNode else [] outUsersDict = {} for u in outUsers: outUsersDict[u.data] = u.getAttributeValue("jid") inUsersDict = {} for u in inUsers: inUsersDict[u.data] = u.getAttributeValue("jid") entity = SyncIqProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = ResultSyncIqProtocolEntity entity.setResultSyncProps(syncNode.getAttributeValue("version"), inUsersDict, outUsersDict, invalidUsers, syncNode.getAttributeValue("wait") ) return entity yowsup-3.2.3/yowsup/layers/protocol_contacts/protocolentities/notification_contact.py000066400000000000000000000014541346433372600316710ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from yowsup.layers.protocol_notifications.protocolentities import NotificationProtocolEntity class ContactNotificationProtocolEntity(NotificationProtocolEntity): ''' ''' def __init__(self, _id, _from, timestamp, notify, offline = False): super(ContactNotificationProtocolEntity, self).__init__("contacts", _id, _from, timestamp, notify, offline) @staticmethod def fromProtocolTreeNode(node): entity = NotificationProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = ContactNotificationProtocolEntity return entityyowsup-3.2.3/yowsup/layers/protocol_contacts/protocolentities/notification_contact_add.py000066400000000000000000000023671346433372600325050ustar00rootroot00000000000000from yowsup.structs import ProtocolTreeNode from .notification_contact import ContactNotificationProtocolEntity class AddContactNotificationProtocolEntity(ContactNotificationProtocolEntity): ''' ''' def __init__(self, _id, _from, timestamp, notify, offline, contactJid): super(AddContactNotificationProtocolEntity, self).__init__(_id, _from, timestamp, notify, offline) self.setData(contactJid) def setData(self, jid): self.contactJid = jid def toProtocolTreeNode(self): node = super(AddContactNotificationProtocolEntity, self).toProtocolTreeNode() removeNode = ProtocolTreeNode("add", {"jid": self.contactJid}, None, None) node.addChild(removeNode) return node @staticmethod def fromProtocolTreeNode(node): entity = ContactNotificationProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = AddContactNotificationProtocolEntity removeNode = node.getChild("add") entity.setData(removeNode.getAttributeValue("jid")) return entityyowsup-3.2.3/yowsup/layers/protocol_contacts/protocolentities/notification_contact_remove.py000066400000000000000000000024171346433372600332460ustar00rootroot00000000000000from yowsup.structs import ProtocolTreeNode from .notification_contact import ContactNotificationProtocolEntity class RemoveContactNotificationProtocolEntity(ContactNotificationProtocolEntity): ''' ''' def __init__(self, _id, _from, timestamp, notify, offline, contactJid): super(RemoveContactNotificationProtocolEntity, self).__init__(_id, _from, timestamp, notify, offline) self.setData(contactJid) def setData(self, jid): self.contactJid = jid def toProtocolTreeNode(self): node = super(RemoveContactNotificationProtocolEntity, self).toProtocolTreeNode() removeNode = ProtocolTreeNode("remove", {"jid": self.contactJid}, None, None) node.addChild(removeNode) return node @staticmethod def fromProtocolTreeNode(node): entity = ContactNotificationProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = RemoveContactNotificationProtocolEntity removeNode = node.getChild("remove") entity.setData(removeNode.getAttributeValue("jid")) return entityyowsup-3.2.3/yowsup/layers/protocol_contacts/protocolentities/notification_contact_update.py000066400000000000000000000024171346433372600332330ustar00rootroot00000000000000from yowsup.structs import ProtocolTreeNode from .notification_contact import ContactNotificationProtocolEntity class UpdateContactNotificationProtocolEntity(ContactNotificationProtocolEntity): ''' ''' def __init__(self, _id, _from, timestamp, notify, offline, contactJid): super(UpdateContactNotificationProtocolEntity, self).__init__(_id, _from, timestamp, notify, offline) self.setData(contactJid) def setData(self, jid): self.contactJid = jid def toProtocolTreeNode(self): node = super(UpdateContactNotificationProtocolEntity, self).toProtocolTreeNode() removeNode = ProtocolTreeNode("update", {"jid": self.contactJid}, None, None) node.addChild(removeNode) return node @staticmethod def fromProtocolTreeNode(node): entity = ContactNotificationProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = UpdateContactNotificationProtocolEntity removeNode = node.getChild("update") entity.setData(removeNode.getAttributeValue("jid")) return entityyowsup-3.2.3/yowsup/layers/protocol_contacts/protocolentities/notificiation_contacts_sync.py000066400000000000000000000023251346433372600332570ustar00rootroot00000000000000from yowsup.structs import ProtocolTreeNode from .notification_contact import ContactNotificationProtocolEntity class ContactsSyncNotificationProtocolEntity(ContactNotificationProtocolEntity): ''' ''' def __init__(self, _id, _from, timestamp, notify, offline, after): super(ContactsSyncNotificationProtocolEntity, self).__init__(_id, _from, timestamp, notify, offline) self.setData(after) def setData(self, after): self.after = int(after) def toProtocolTreeNode(self): node = super(ContactsSyncNotificationProtocolEntity, self).toProtocolTreeNode() syncNode = ProtocolTreeNode("sync", {"after": str(self.after)}, None, None) node.addChild(syncNode) return node @staticmethod def fromProtocolTreeNode(node): entity = ContactNotificationProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = ContactsSyncNotificationProtocolEntity syncNode = node.getChild("sync") entity.setData(syncNode.getAttributeValue("after")) return entityyowsup-3.2.3/yowsup/layers/protocol_contacts/protocolentities/test_iq_sync_get.py000066400000000000000000000006611346433372600310320ustar00rootroot00000000000000from yowsup.layers.protocol_contacts.protocolentities.iq_sync_get import GetSyncIqProtocolEntity from yowsup.structs.protocolentity import ProtocolEntityTest import unittest entity = GetSyncIqProtocolEntity(["12345678", "8764543121"]) class GetSyncIqProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): self.ProtocolEntity = GetSyncIqProtocolEntity self.node = entity.toProtocolTreeNode()yowsup-3.2.3/yowsup/layers/protocol_contacts/protocolentities/test_iq_sync_result.py000066400000000000000000000013701346433372600315670ustar00rootroot00000000000000from yowsup.layers.protocol_contacts.protocolentities.iq_sync_result import ResultSyncIqProtocolEntity from yowsup.structs.protocolentity import ProtocolEntityTest import unittest entity = ResultSyncIqProtocolEntity("123", "1.30615237617e+17", 0, True, "123456", {"12345678": "12345678@s.whatsapp.net"}, {"12345678": "12345678@s.whatsapp.net"}, ["1234"]) class ResultSyncIqProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): self.ProtocolEntity = ResultSyncIqProtocolEntity self.node = entity.toProtocolTreeNode() def test_delta_result(self): del self.node.getChild("sync")["wait"] self.test_generation() yowsup-3.2.3/yowsup/layers/protocol_contacts/protocolentities/test_notification_contact_add.py000066400000000000000000000012401346433372600335310ustar00rootroot00000000000000from yowsup.layers.protocol_contacts.protocolentities import AddContactNotificationProtocolEntity from yowsup.structs.protocolentity import ProtocolEntityTest import time import unittest entity = AddContactNotificationProtocolEntity("1234", "jid@s.whatsapp.net", int(time.time()), "notify", False, "sender@s.whatsapp.net") class AddContactNotificationProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): super(AddContactNotificationProtocolEntityTest, self).setUp() self.ProtocolEntity = AddContactNotificationProtocolEntity self.node = entity.toProtocolTreeNode() yowsup-3.2.3/yowsup/layers/protocol_contacts/protocolentities/test_notification_contact_remove.py000066400000000000000000000011451346433372600343020ustar00rootroot00000000000000from yowsup.layers.protocol_contacts.protocolentities import RemoveContactNotificationProtocolEntity from yowsup.structs.protocolentity import ProtocolEntityTest import time import unittest entity = RemoveContactNotificationProtocolEntity("1234", "jid@s.whatsapp.net", int(time.time()), "notify", False, "contactjid@s.whatsapp.net") class RemoveContactNotificationProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): self.ProtocolEntity = RemoveContactNotificationProtocolEntity self.node = entity.toProtocolTreeNode() yowsup-3.2.3/yowsup/layers/protocol_contacts/protocolentities/test_notification_contact_update.py000066400000000000000000000011441346433372600342660ustar00rootroot00000000000000from yowsup.layers.protocol_contacts.protocolentities import UpdateContactNotificationProtocolEntity from yowsup.structs.protocolentity import ProtocolEntityTest import time import unittest entity = UpdateContactNotificationProtocolEntity("1234", "jid@s.whatsapp.net", int(time.time()), "notify", False,"contactjid@s.whatsapp.net") class UpdateContactNotificationProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): self.ProtocolEntity = UpdateContactNotificationProtocolEntity self.node = entity.toProtocolTreeNode() yowsup-3.2.3/yowsup/layers/protocol_contacts/test_layer.py000066400000000000000000000023001346433372600242240ustar00rootroot00000000000000from yowsup.layers import YowProtocolLayerTest from yowsup.layers.protocol_contacts import YowContactsIqProtocolLayer from yowsup.layers.protocol_contacts.protocolentities.test_notification_contact_add import entity as addEntity from yowsup.layers.protocol_contacts.protocolentities.test_notification_contact_update import entity as updateEntity from yowsup.layers.protocol_contacts.protocolentities.test_notification_contact_remove import entity as removeEntity from yowsup.layers.protocol_contacts.protocolentities.test_iq_sync_result import entity as syncResultEntity from yowsup.layers.protocol_contacts.protocolentities.test_iq_sync_get import entity as syncGetEntity class YowContactsIqProtocolLayerTest(YowProtocolLayerTest, YowContactsIqProtocolLayer): def setUp(self): YowContactsIqProtocolLayer.__init__(self) def test_sync(self): self.assertSent(syncGetEntity) def test_syncResult(self): self.assertReceived(syncResultEntity) def test_notificationAdd(self): self.assertReceived(addEntity) def test_notificationUpdate(self): self.assertReceived(updateEntity) def test_notificationRemove(self): self.assertReceived(removeEntity) yowsup-3.2.3/yowsup/layers/protocol_groups/000077500000000000000000000000001346433372600212055ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_groups/__init__.py000066400000000000000000000000521346433372600233130ustar00rootroot00000000000000from .layer import YowGroupsProtocolLayer yowsup-3.2.3/yowsup/layers/protocol_groups/layer.py000066400000000000000000000151611346433372600226770ustar00rootroot00000000000000from yowsup.layers import YowLayer, YowLayerEvent, YowProtocolLayer from yowsup.layers.protocol_iq.protocolentities import ErrorIqProtocolEntity from yowsup.layers.protocol_iq.protocolentities.iq_result import ResultIqProtocolEntity from .protocolentities import * import logging logger = logging.getLogger(__name__) class YowGroupsProtocolLayer(YowProtocolLayer): HANDLE = ( CreateGroupsIqProtocolEntity, InfoGroupsIqProtocolEntity, LeaveGroupsIqProtocolEntity, ListGroupsIqProtocolEntity, SubjectGroupsIqProtocolEntity, ParticipantsGroupsIqProtocolEntity, AddParticipantsIqProtocolEntity, PromoteParticipantsIqProtocolEntity, DemoteParticipantsIqProtocolEntity, RemoveParticipantsIqProtocolEntity ) def __init__(self): handleMap = { "iq": (None, self.sendIq), "notification": (self.recvNotification, None) } super(YowGroupsProtocolLayer, self).__init__(handleMap) def __str__(self): return "Groups Iq Layer" def sendIq(self, entity): if entity.__class__ in self.__class__.HANDLE: if entity.__class__ == SubjectGroupsIqProtocolEntity: self._sendIq(entity, self.onSetSubjectSuccess, self.onSetSubjectFailed) elif entity.__class__ == CreateGroupsIqProtocolEntity: self._sendIq(entity, self.onCreateGroupSuccess, self.onCreateGroupFailed) elif entity.__class__ == ParticipantsGroupsIqProtocolEntity: self._sendIq(entity, self.onGetParticipantsResult) elif entity.__class__ == AddParticipantsIqProtocolEntity: self._sendIq(entity, self.onAddParticipantsSuccess, self.onAddParticipantsFailed) elif entity.__class__ == PromoteParticipantsIqProtocolEntity: self._sendIq(entity, self.onPromoteParticipantsSuccess, self.onPromoteParticipantsFailed) elif entity.__class__ == DemoteParticipantsIqProtocolEntity: self._sendIq(entity, self.onDemoteParticipantsSuccess, self.onDemoteParticipantsFailed) elif entity.__class__ == RemoveParticipantsIqProtocolEntity: self._sendIq(entity, self.onRemoveParticipantsSuccess, self.onRemoveParticipantsFailed) elif entity.__class__ == ListGroupsIqProtocolEntity: self._sendIq(entity, self.onListGroupsResult) elif entity.__class__ == LeaveGroupsIqProtocolEntity: self._sendIq(entity, self.onLeaveGroupSuccess, self.onLeaveGroupFailed) elif entity.__class__ == InfoGroupsIqProtocolEntity: self._sendIq(entity, self.onInfoGroupSuccess, self.onInfoGroupFailed) else: self.entityToLower(entity) def onCreateGroupSuccess(self, node, originalIqEntity): logger.info("Group create success") self.toUpper(SuccessCreateGroupsIqProtocolEntity.fromProtocolTreeNode(node)) def onCreateGroupFailed(self, node, originalIqEntity): logger.error("Group create failed") self.toUpper(ErrorIqProtocolEntity.fromProtocolTreeNode(node)) def onSetSubjectSuccess(self, node, originalIqEntity): logger.info("Group subject change success") self.toUpper(ResultIqProtocolEntity.fromProtocolTreeNode(node)) def onSetSubjectFailed(self, node, originalIqEntity): logger.error("Group subject change failed") self.toUpper(ErrorIqProtocolEntity.fromProtocolTreeNode(node)) def onGetParticipantsResult(self, node, originalIqEntity): self.toUpper(ListParticipantsResultIqProtocolEntity.fromProtocolTreeNode(node)) def onAddParticipantsSuccess(self, node, originalIqEntity): logger.info("Group add participants success") self.toUpper(SuccessAddParticipantsIqProtocolEntity.fromProtocolTreeNode(node)) def onRemoveParticipantsFailed(self, node, originalIqEntity): logger.error("Group remove participants failed") self.toUpper(ErrorIqProtocolEntity.fromProtocolTreeNode(node)) def onRemoveParticipantsSuccess(self, node, originalIqEntity): logger.info("Group remove participants success") self.toUpper(SuccessRemoveParticipantsIqProtocolEntity.fromProtocolTreeNode(node)) def onPromoteParticipantsFailed(self, node, originalIqEntity): logger.error("Group promote participants failed") self.toUpper(ErrorIqProtocolEntity.fromProtocolTreeNode(node)) def onPromoteParticipantsSuccess(self, node, originalIqEntity): logger.info("Group promote participants success") self.toUpper(ResultIqProtocolEntity.fromProtocolTreeNode(node)) def onDemoteParticipantsFailed(self, node, originalIqEntity): logger.error("Group demote participants failed") self.toUpper(ErrorIqProtocolEntity.fromProtocolTreeNode(node)) def onDemoteParticipantsSuccess(self, node, originalIqEntity): logger.info("Group demote participants success") self.toUpper(ResultIqProtocolEntity.fromProtocolTreeNode(node)) def onAddParticipantsFailed(self, node, originalIqEntity): logger.error("Group add participants failed") self.toUpper(FailureAddParticipantsIqProtocolEntity.fromProtocolTreeNode(node)) def onListGroupsResult(self, node, originalIqEntity): self.toUpper(ListGroupsResultIqProtocolEntity.fromProtocolTreeNode(node)) def onLeaveGroupSuccess(self, node, originalIqEntity): logger.info("Group leave success") self.toUpper(SuccessLeaveGroupsIqProtocolEntity.fromProtocolTreeNode(node)) def onLeaveGroupFailed(self, node, originalIqEntity): logger.error("Group leave failed") self.toUpper(ErrorIqProtocolEntity.fromProtocolTreeNode(node)) def onInfoGroupSuccess(self, node, originalIqEntity): logger.info("Group info success") self.toUpper(InfoGroupsResultIqProtocolEntity.fromProtocolTreeNode(node)) def onInfoGroupFailed(self, node, originalIqEntity): logger.error("Group info failed") self.toUpper(ErrorIqProtocolEntity.fromProtocolTreeNode(node)) def recvNotification(self, node): if node["type"] == "w:gp2": if node.getChild("subject"): self.toUpper(SubjectGroupsNotificationProtocolEntity.fromProtocolTreeNode(node)) elif node.getChild("create"): self.toUpper(CreateGroupsNotificationProtocolEntity.fromProtocolTreeNode(node)) elif node.getChild("remove"): self.toUpper(RemoveGroupsNotificationProtocolEntity.fromProtocolTreeNode(node)) elif node.getChild("add"): self.toUpper(AddGroupsNotificationProtocolEntity.fromProtocolTreeNode(node)) yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/000077500000000000000000000000001346433372600246135ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/__init__.py000066400000000000000000000032521346433372600267260ustar00rootroot00000000000000from .iq_groups_create import CreateGroupsIqProtocolEntity from .iq_groups_create_success import SuccessCreateGroupsIqProtocolEntity from .iq_groups_leave import LeaveGroupsIqProtocolEntity from .iq_groups_leave_success import SuccessLeaveGroupsIqProtocolEntity from .iq_groups_list import ListGroupsIqProtocolEntity from .iq_groups_info import InfoGroupsIqProtocolEntity from .iq_groups_subject import SubjectGroupsIqProtocolEntity from .iq_groups_participants import ParticipantsGroupsIqProtocolEntity from .iq_groups_participants_add import AddParticipantsIqProtocolEntity from .iq_groups_participants_promote import PromoteParticipantsIqProtocolEntity from .iq_groups_participants_demote import DemoteParticipantsIqProtocolEntity from .iq_groups_participants_add_success import SuccessAddParticipantsIqProtocolEntity from .iq_groups_participants_add_failure import FailureAddParticipantsIqProtocolEntity from .iq_groups_participants_remove import RemoveParticipantsIqProtocolEntity from .iq_groups_participants_remove_success import SuccessRemoveParticipantsIqProtocolEntity from .iq_result_groups_list import ListGroupsResultIqProtocolEntity from .iq_result_participants_list import ListParticipantsResultIqProtocolEntity from .iq_result_groups_info import InfoGroupsResultIqProtocolEntity from .notification_groups import GroupsNotificationProtocolEntity from .notification_groups_subject import SubjectGroupsNotificationProtocolEntity from .notification_groups_create import CreateGroupsNotificationProtocolEntity from .notification_groups_add import AddGroupsNotificationProtocolEntity from .notification_groups_remove import RemoveGroupsNotificationProtocolEntity yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/iq_groups.py000066400000000000000000000007071346433372600272010ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from yowsup.layers.protocol_iq.protocolentities import IqProtocolEntity class GroupsIqProtocolEntity(IqProtocolEntity): ''' ''' def __init__(self, to = None, _from = None, _id = None, _type = None): super(GroupsIqProtocolEntity, self).__init__("w:g2", _id, _type, to = to, _from = _from) yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/iq_groups_create.py000066400000000000000000000034411346433372600305220ustar00rootroot00000000000000from yowsup.common import YowConstants from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .iq_groups import GroupsIqProtocolEntity class CreateGroupsIqProtocolEntity(GroupsIqProtocolEntity): ''' ''' def __init__(self, subject, _id = None, participants = None): super(CreateGroupsIqProtocolEntity, self).__init__(to = YowConstants.WHATSAPP_GROUP_SERVER, _id = _id, _type = "set") self.setProps(subject) self.setParticipants(participants or []) def setProps(self, subject): self.subject = subject def setParticipants(self, participants): self.participantList = participants def toProtocolTreeNode(self): node = super(CreateGroupsIqProtocolEntity, self).toProtocolTreeNode() cnode = ProtocolTreeNode("create",{ "subject": self.subject}) participantNodes = [ ProtocolTreeNode("participant", { "jid": participant }) for participant in self.participantList ] cnode.addChildren(participantNodes) node.addChild(cnode) return node @staticmethod def fromProtocolTreeNode(node): entity = super(CreateGroupsIqProtocolEntity,CreateGroupsIqProtocolEntity).fromProtocolTreeNode(node) entity.__class__ = CreateGroupsIqProtocolEntity entity.setProps(node.getChild("create").getAttributeValue("subject")) participantList = [] for participantNode in node.getChild("create").getAllChildren(): participantList.append(participantNode["jid"]) entity.setParticipants(participantList) return entity yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/iq_groups_create_success.py000066400000000000000000000021671346433372600322560ustar00rootroot00000000000000from yowsup.common import YowConstants from yowsup.structs import ProtocolTreeNode from yowsup.layers.protocol_iq.protocolentities import ResultIqProtocolEntity class SuccessCreateGroupsIqProtocolEntity(ResultIqProtocolEntity): ''' ''' def __init__(self, _id, groupId): super(SuccessCreateGroupsIqProtocolEntity, self).__init__(_from = YowConstants.WHATSAPP_GROUP_SERVER, _id = _id) self.setProps(groupId) def setProps(self, groupId): self.groupId = groupId def toProtocolTreeNode(self): node = super(SuccessCreateGroupsIqProtocolEntity, self).toProtocolTreeNode() node.addChild(ProtocolTreeNode("group",{"id": self.groupId})) return node @staticmethod def fromProtocolTreeNode(node): entity = super(SuccessCreateGroupsIqProtocolEntity, SuccessCreateGroupsIqProtocolEntity).fromProtocolTreeNode(node) entity.__class__ = SuccessCreateGroupsIqProtocolEntity entity.setProps(node.getChild("group").getAttributeValue("id")) return entity yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/iq_groups_info.py000066400000000000000000000024211346433372600302070ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .iq_groups import GroupsIqProtocolEntity class InfoGroupsIqProtocolEntity(GroupsIqProtocolEntity): ''' ''' def __init__(self, group_jid, _id=None): super(InfoGroupsIqProtocolEntity, self).__init__(to = group_jid, _id = _id, _type = "get") self.setProps(group_jid) def setProps(self, group_jid): self.group_jid = group_jid def __str__(self): out = super(InfoGroupsIqProtocolEntity, self).__str__() out += "Group JID: %s\n" % self.group_jid return out def toProtocolTreeNode(self): node = super(InfoGroupsIqProtocolEntity, self).toProtocolTreeNode() node.addChild(ProtocolTreeNode("query", {"request": "interactive"})) return node @staticmethod def fromProtocolTreeNode(node): assert node.getChild("query") is not None, "Not a groups info iq node %s" % node entity = super(InfoGroupsIqProtocolEntity, InfoGroupsIqProtocolEntity).fromProtocolTreeNode(node) entity.__class__ = InfoGroupsIqProtocolEntity entity.setProps(node.getAttributeValue("to")) return entity yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/iq_groups_leave.py000066400000000000000000000033171346433372600303550ustar00rootroot00000000000000from yowsup.common import YowConstants from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .iq_groups import GroupsIqProtocolEntity class LeaveGroupsIqProtocolEntity(GroupsIqProtocolEntity): ''' ''' def __init__(self, groupList): super(LeaveGroupsIqProtocolEntity, self).__init__(to = YowConstants.WHATSAPP_GROUP_SERVER, _type = "set") self.setProps(groupList if type(groupList) is list else [groupList]) def setProps(self, groupList): assert type(groupList) is list and len(groupList), "Must specify a list of group jids to leave" self.groupList = groupList def toProtocolTreeNode(self): node = super(LeaveGroupsIqProtocolEntity, self).toProtocolTreeNode() groupNodes = [ ProtocolTreeNode("group", { "id": groupid }) for groupid in self.groupList ] node.addChild(ProtocolTreeNode("leave", {"action": "delete"}, groupNodes)) return node @staticmethod def fromProtocolTreeNode(node): assert node.getChild("leave") is not None, "Not a group leave iq node %s" % node assert node.getChild("leave").getAttributeValue("action") == "delete", "Not a group leave action %s" % node entity = super(LeaveGroupsIqProtocolEntity, LeaveGroupsIqProtocolEntity).fromProtocolTreeNode(node) entity.__class__ = LeaveGroupsIqProtocolEntity entity.setProps([group.getAttributeValue("id") for group in node.getChild("leave").getAllChildren()] ) return entity yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/iq_groups_leave_success.py000066400000000000000000000027231346433372600321050ustar00rootroot00000000000000from yowsup.common import YowConstants from yowsup.structs import ProtocolTreeNode from yowsup.layers.protocol_iq.protocolentities import ResultIqProtocolEntity class SuccessLeaveGroupsIqProtocolEntity(ResultIqProtocolEntity): ''' ''' def __init__(self, _id, groupId): super(SuccessLeaveGroupsIqProtocolEntity, self).\ __init__(_from=YowConstants.WHATSAPP_GROUP_SERVER, _id=_id) self.setProps(groupId) def setProps(self, groupId): self.groupId = groupId def __str__(self): out = super(SuccessLeaveGroupsIqProtocolEntity, self).__str__() out += "Group Id: %s\n" % self.groupId return out def toProtocolTreeNode(self): node = super(SuccessLeaveGroupsIqProtocolEntity, self).\ toProtocolTreeNode() leaveNode = ProtocolTreeNode( "leave", {}, [ProtocolTreeNode("group", {"id": self.groupId})] ) node.addChild(leaveNode) return node @staticmethod def fromProtocolTreeNode(node): entity = super(SuccessLeaveGroupsIqProtocolEntity, SuccessLeaveGroupsIqProtocolEntity).fromProtocolTreeNode(node) entity.__class__ = SuccessLeaveGroupsIqProtocolEntity entity.setProps( node.getChild("leave").getChild("group").getAttributeValue("id") ) return entity yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/iq_groups_list.py000066400000000000000000000042071346433372600302330ustar00rootroot00000000000000from yowsup.common import YowConstants from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .iq_groups import GroupsIqProtocolEntity class ListGroupsIqProtocolEntity(GroupsIqProtocolEntity): ''' <"{{participating | owning}}"> result (processed in iq_result_groups_list.py): ''' GROUP_TYPE_PARTICIPATING = "participating" GROUP_TYPE_OWNING = "owning" GROUPS_TYPES = (GROUP_TYPE_PARTICIPATING, GROUP_TYPE_OWNING) def __init__(self, groupsType = GROUP_TYPE_PARTICIPATING, _id = None): super(ListGroupsIqProtocolEntity, self).__init__(_id=_id, to = YowConstants.WHATSAPP_GROUP_SERVER, _type = "get") self.setProps(groupsType) def setProps(self, groupsType): assert groupsType in self.__class__.GROUPS_TYPES,\ "Groups type must be %s, not %s" % (" or ".join(self.__class__.GROUPS_TYPES), groupsType) self.groupsType = groupsType def toProtocolTreeNode(self): node = super(ListGroupsIqProtocolEntity, self).toProtocolTreeNode() node.addChild(ProtocolTreeNode(self.groupsType)) return node @staticmethod def fromProtocolTreeNode(node): entity = super(ListGroupsIqProtocolEntity, ListGroupsIqProtocolEntity).fromProtocolTreeNode(node) entity.__class__ = ListGroupsIqProtocolEntity entity.setProps(node.getChild(0).tag) return entity yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/iq_groups_participants.py000066400000000000000000000031511346433372600317560ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .iq_groups import GroupsIqProtocolEntity class ParticipantsGroupsIqProtocolEntity(GroupsIqProtocolEntity): ''' ''' modes=["add","promote","remove","demote"] def __init__(self, jid, participantList, _mode, _id = None): super(ParticipantsGroupsIqProtocolEntity, self).__init__(to = jid, _id = _id, _type = "set") self.setProps(group_jid = jid, participantList = participantList, mode = _mode) def setProps(self, group_jid, participantList, mode): assert type(participantList) is list, "Must be a list of jids, got %s instead." % type(participantList) assert mode in self.modes, "Mode should be in: '" + "', '".join(self.modes) + "' but is '" + mode + "'" self.group_jid = group_jid self.participantList = participantList self.mode = mode def toProtocolTreeNode(self): node = super(ParticipantsGroupsIqProtocolEntity, self).toProtocolTreeNode() participantNodes = [ ProtocolTreeNode("participant", { "jid": participant }) for participant in self.participantList ] node.addChild(ProtocolTreeNode(self.mode,{}, participantNodes)) return node @staticmethod def fromProtocolTreeNode(node): entity = super(ParticipantsGroupsIqProtocolEntity, ParticipantsGroupsIqProtocolEntity).fromProtocolTreeNode(node) entity.__class__ = ParticipantsGroupsIqProtocolEntity return entity yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/iq_groups_participants_add.py000066400000000000000000000021011346433372600325600ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .iq_groups_participants import ParticipantsGroupsIqProtocolEntity class AddParticipantsIqProtocolEntity(ParticipantsGroupsIqProtocolEntity): ''' ''' def __init__(self, group_jid, participantList, _id = None): super(AddParticipantsIqProtocolEntity, self).__init__(group_jid, participantList, "add", _id = _id) @staticmethod def fromProtocolTreeNode(node): entity = super(AddParticipantsIqProtocolEntity, AddParticipantsIqProtocolEntity).fromProtocolTreeNode(node) entity.__class__ = AddParticipantsIqProtocolEntity participantList = [] for participantNode in node.getChild("add").getAllChildren(): participantList.append(participantNode["jid"]) entity.setProps(node.getAttributeValue("to"), participantList) return entity yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/iq_groups_participants_add_failure.py000066400000000000000000000015161346433372600343000ustar00rootroot00000000000000from yowsup.layers.protocol_iq.protocolentities import ErrorIqProtocolEntity class FailureAddParticipantsIqProtocolEntity(ErrorIqProtocolEntity): ''' ''' def __init__(self, _id, _from, _code, _text, _backoff= 0 ): super(FailureAddParticipantsIqProtocolEntity, self).__init__(_from = _from, _id = _id, code = _code, text = _text, backoff = _backoff) @staticmethod def fromProtocolTreeNode(node): entity = ErrorIqProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = FailureAddParticipantsIqProtocolEntity return entityyowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/iq_groups_participants_add_success.py000066400000000000000000000033711346433372600343220ustar00rootroot00000000000000from yowsup.structs import ProtocolTreeNode from yowsup.layers.protocol_iq.protocolentities import ResultIqProtocolEntity class SuccessAddParticipantsIqProtocolEntity(ResultIqProtocolEntity): ''' ''' def __init__(self, _id, groupId, participantList): super(SuccessAddParticipantsIqProtocolEntity, self).__init__(_from = groupId, _id = _id) self.setProps(groupId, participantList) def setProps(self, groupId, participantList): self.groupId = groupId self.participantList = participantList self.action = 'add' def getAction(self): return self.action def toProtocolTreeNode(self): node = super(SuccessAddParticipantsIqProtocolEntity, self).toProtocolTreeNode() participantNodes = [ ProtocolTreeNode("add", { "type": "success", "participant": participant }) for participant in self.participantList ] node.addChildren(participantNodes) return node @staticmethod def fromProtocolTreeNode(node): entity = super(SuccessAddParticipantsIqProtocolEntity, SuccessAddParticipantsIqProtocolEntity).fromProtocolTreeNode(node) entity.__class__ = SuccessAddParticipantsIqProtocolEntity participantList = [] for participantNode in node.getAllChildren(): if participantNode["type"]=="success": participantList.append(participantNode["participant"]) entity.setProps(node.getAttributeValue("from"), participantList) return entity yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/iq_groups_participants_demote.py000066400000000000000000000021411346433372600333110ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .iq_groups_participants import ParticipantsGroupsIqProtocolEntity class DemoteParticipantsIqProtocolEntity(ParticipantsGroupsIqProtocolEntity): ''' ''' def __init__(self, group_jid, participantList, _id = None): super(DemoteParticipantsIqProtocolEntity, self).__init__(group_jid, participantList, "demote", _id = _id) @staticmethod def fromProtocolTreeNode(node): entity = super(DemoteParticipantsIqProtocolEntity, DemoteParticipantsIqProtocolEntity).fromProtocolTreeNode(node) entity.__class__ = DemoteParticipantsIqProtocolEntity participantList = [] for participantNode in node.getChild("demote").getAllChildren(): participantList.append(participantNode["jid"]) entity.setProps(node.getAttributeValue("to"), participantList) return entity yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/iq_groups_participants_promote.py000066400000000000000000000021521346433372600335230ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .iq_groups_participants import ParticipantsGroupsIqProtocolEntity class PromoteParticipantsIqProtocolEntity(ParticipantsGroupsIqProtocolEntity): ''' ''' def __init__(self, group_jid, participantList, _id = None): super(PromoteParticipantsIqProtocolEntity, self).__init__(group_jid, participantList, "promote", _id = _id) @staticmethod def fromProtocolTreeNode(node): entity = super(PromoteParticipantsIqProtocolEntity, PromoteParticipantsIqProtocolEntity).fromProtocolTreeNode(node) entity.__class__ = PromoteParticipantsIqProtocolEntity participantList = [] for participantNode in node.getChild("promote").getAllChildren(): participantList.append(participantNode["jid"]) entity.setProps(node.getAttributeValue("to"), participantList) return entity yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/iq_groups_participants_remove.py000066400000000000000000000021501346433372600333310ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .iq_groups_participants import ParticipantsGroupsIqProtocolEntity class RemoveParticipantsIqProtocolEntity(ParticipantsGroupsIqProtocolEntity): ''' ''' def __init__(self, group_jid, participantList, _id = None): super(RemoveParticipantsIqProtocolEntity, self).__init__(group_jid, participantList, "remove", _id = _id) @staticmethod def fromProtocolTreeNode(node): entity = super(RemoveParticipantsIqProtocolEntity, RemoveParticipantsIqProtocolEntity).fromProtocolTreeNode(node) entity.__class__ = RemoveParticipantsIqProtocolEntity participantList = [] for participantNode in node.getChild("remove").getAllChildren(): participantList.append(participantNode["jid"]) entity.setProps(node.getAttributeValue("to"), participantList) return entity yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/iq_groups_participants_remove_success.py000066400000000000000000000034351346433372600350700ustar00rootroot00000000000000from yowsup.structs import ProtocolTreeNode from yowsup.layers.protocol_iq.protocolentities import ResultIqProtocolEntity class SuccessRemoveParticipantsIqProtocolEntity(ResultIqProtocolEntity): ''' ''' def __init__(self, _id, groupId, participantList): super(SuccessRemoveParticipantsIqProtocolEntity, self).__init__(_from = groupId, _id = _id) self.setProps(groupId, participantList) def setProps(self, groupId, participantList): self.groupId = groupId self.participantList = participantList self.action = 'remove' def getAction(self): return self.action def toProtocolTreeNode(self): node = super(SuccessRemoveParticipantsIqProtocolEntity, self).toProtocolTreeNode() participantNodes = [ ProtocolTreeNode("remove", { "type": "success", "participant": participant }) for participant in self.participantList ] node.addChildren(participantNodes) return node @staticmethod def fromProtocolTreeNode(node): entity = super(SuccessRemoveParticipantsIqProtocolEntity, SuccessRemoveParticipantsIqProtocolEntity).fromProtocolTreeNode(node) entity.__class__ = SuccessRemoveParticipantsIqProtocolEntity participantList = [] for participantNode in node.getAllChildren(): if participantNode["type"]=="success": participantList.append(participantNode["participant"]) entity.setProps(node.getAttributeValue("from"), participantList) return entity yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/iq_groups_subject.py000066400000000000000000000020641346433372600307160ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .iq_groups import GroupsIqProtocolEntity class SubjectGroupsIqProtocolEntity(GroupsIqProtocolEntity): ''' {{NEW_VAL}} ''' def __init__(self, jid, subject, _id = None): super(SubjectGroupsIqProtocolEntity, self).__init__(to = jid, _id = _id, _type = "set") self.setProps(subject) def setProps(self, subject): self.subject = subject def toProtocolTreeNode(self): node = super(SubjectGroupsIqProtocolEntity, self).toProtocolTreeNode() node.addChild(ProtocolTreeNode("subject",{}, None, self.subject)) return node @staticmethod def fromProtocolTreeNode(node): entity = super(SubjectGroupsIqProtocolEntity, SubjectGroupsIqProtocolEntity).fromProtocolTreeNode(node) entity.__class__ = SubjectGroupsIqProtocolEntity entity.setProps(node.getChild("subject").getData()) return entity yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/iq_result_groups_info.py000066400000000000000000000102401346433372600316030ustar00rootroot00000000000000from yowsup.structs import ProtocolTreeNode from yowsup.layers.protocol_iq.protocolentities import ResultIqProtocolEntity class InfoGroupsResultIqProtocolEntity(ResultIqProtocolEntity): ''' ''' TYPE_PARTICIPANT_ADMIN = "admin" def __init__(self, _id, _from, groupId, creationTimestamp, creatorJid, subject, subjectTime, subjectOwnerJid, participants): super(InfoGroupsResultIqProtocolEntity, self).__init__(_id = _id, _from = _from) self.setGroupProps(groupId, creationTimestamp, creatorJid, subject, subjectTime, subjectOwnerJid, participants) def setGroupProps(self, groupId, creationTimestamp, creatorJid, subject, subjectTime, subjectOwnerJid, participants): assert type(participants) is dict, "Participants must be a dict {jid => type?}" self.groupId = groupId self.creationTimestamp = int(creationTimestamp) self.creatorJid = creatorJid self.subject = subject self.subjectTime = int(subjectTime) self.subjectOwnerJid = subjectOwnerJid self.participants = participants def getParticipants(self): return self.participants def getSubject(self): return self.subject def getGroupId(self): return self.groupId def getCreationTimestamp(self): return self.creationTimestamp def getCreatorJid(self, full = True): return self.creatorJid if full else self.creatorJid.split('@')[0] def getSubjectTimestamp(self): return self.subjectTime def getSubjectOwnerJid(self, full = True): return self.subjectOwnerJid if full else self.subjectOwnerJid.split('@')[0] def getGroupAdmins(self, full = True): admins = [] for jid, _type in self.participants.items(): if _type == self.__class__.TYPE_PARTICIPANT_ADMIN: admins.append(jid if full else jid.split('@')[0]) return admins def __str__(self): out = super(InfoGroupsResultIqProtocolEntity, self).__str__() out += "Group ID: %s\n" % self.groupId out += "Created: %s\n" % self.creationTimestamp out += "Creator JID: %s\n" % self.creatorJid out += "Subject: %s\n" % self.subject out += "Subject Timestamp: %s\n" % self.subjectTime out += "Subject owner JID: %s\n" % self.subjectOwnerJid out += "Participants: %s\n" % self.participants return out def toProtocolTreeNode(self): node = super(InfoGroupsResultIqProtocolEntity, self).toProtocolTreeNode() groupNode = ProtocolTreeNode("group", { "subject": self.getSubject(), "creation": str(self.getCreationTimestamp()), "creator": self.getCreatorJid(), "s_t": self.getSubjectTimestamp(), "s_o": self.getSubjectOwnerJid(), "id": self.getGroupId() }) participants = [] for jid, _type in self.getParticipants().items(): pnode = ProtocolTreeNode("participant", {"jid": jid}) if _type: pnode["type"] = _type participants.append(pnode) groupNode.addChildren(participants) node.addChild(groupNode) return node @staticmethod def fromProtocolTreeNode(node): groupNode = node.getChild("group") participants = {} for p in groupNode.getAllChildren("participant"): participants[p["jid"]] = p["type"] return InfoGroupsResultIqProtocolEntity( node["id"], node["from"], groupNode["id"], groupNode["creation"], groupNode["creator"], groupNode["subject"], groupNode["s_t"], groupNode["s_o"], participants ) yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/iq_result_groups_list.py000066400000000000000000000064751346433372600316420ustar00rootroot00000000000000from yowsup.common import YowConstants from yowsup.structs import ProtocolEntity, ProtocolTreeNode from yowsup.layers.protocol_iq.protocolentities import ResultIqProtocolEntity from ..structs import Group class ListGroupsResultIqProtocolEntity(ResultIqProtocolEntity): ''' ''' def __init__(self, groupsList): super(ListGroupsResultIqProtocolEntity, self).__init__(_from = YowConstants.WHATSAPP_GROUP_SERVER) self.setProps(groupsList) def __str__(self): out = super(ListGroupsResultIqProtocolEntity, self).__str__() out += "Groups:\n" for g in self.groupsList: out += "%s\n" % g return out def getGroups(self): return self.groupsList def setProps(self, groupsList): assert type(groupsList) is list and (len(groupsList) == 0 or groupsList[0].__class__ is Group),\ "groupList must be a list of Group instances" self.groupsList = groupsList def toProtocolTreeNode(self): node = super(ListGroupsResultIqProtocolEntity, self).toProtocolTreeNode() groupsNodes = [] for group in self.groupsList: groupNode = ProtocolTreeNode("group", { "id": group.getId(), "creator": group.getCreator(), "subject": group.getSubject(), "s_o": group.getSubjectOwner(), "s_t": str(group.getSubjectTime()), "creation": str(group.getCreationTime()) }, ) participants = [] for jid, _type in group.getParticipants().items(): pnode = ProtocolTreeNode("participant", {"jid": jid}) if _type: pnode["type"] = _type participants.append(pnode) groupNode.addChildren(participants) groupsNodes.append(groupNode) node.addChild(ProtocolTreeNode("groups", children = groupsNodes)) return node @staticmethod def fromProtocolTreeNode(node): entity = super(ListGroupsResultIqProtocolEntity, ListGroupsResultIqProtocolEntity).fromProtocolTreeNode(node) entity.__class__ = ListGroupsResultIqProtocolEntity groups = [] for groupNode in node.getChild("groups").getAllChildren(): participants = {} for p in groupNode.getAllChildren("participant"): participants[p["jid"]] = p["type"] groups.append( Group(groupNode["id"], groupNode["creator"], groupNode["subject"], groupNode["s_o"], groupNode["s_t"], groupNode["creation"], participants) ) entity.setProps(groups) return entity yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/iq_result_participants_list.py000066400000000000000000000031341346433372600330110ustar00rootroot00000000000000from yowsup.structs import ProtocolTreeNode from yowsup.layers.protocol_iq.protocolentities import ResultIqProtocolEntity class ListParticipantsResultIqProtocolEntity(ResultIqProtocolEntity): ''' ''' def __init__(self, _from, participantList): super(ListParticipantsResultIqProtocolEntity, self).__init__(_from = _from) self.setParticipants(participantList) def __str__(self): out = super(ListParticipantsResultIqProtocolEntity, self).__str__() out += "Participants: %s\n" % " ".join(self.participantList) return out def getParticipants(self): return self.participantList def setParticipants(self, participants): self.participantList = participants def toProtocolTreeNode(self): node = super(ListParticipantsResultIqProtocolEntity, self).toProtocolTreeNode() participantNodes = [ ProtocolTreeNode("participant", { "jid": participant }) for participant in self.participantList ] node.addChildren(participantNodes) return node @staticmethod def fromProtocolTreeNode(node): entity = super(ListParticipantsResultIqProtocolEntity, ListParticipantsResultIqProtocolEntity).fromProtocolTreeNode(node) entity.__class__ = ListParticipantsResultIqProtocolEntity entity.setParticipants([ pNode.getAttributeValue("jid") for pNode in node.getAllChildren() ]) return entity yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/notification_groups.py000066400000000000000000000033141346433372600312530ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from yowsup.layers.protocol_notifications.protocolentities import NotificationProtocolEntity class GroupsNotificationProtocolEntity(NotificationProtocolEntity): ''' ''' def __init__(self, _id, _from, timestamp, notify, participant, offline): super(GroupsNotificationProtocolEntity, self).__init__("w:gp2", _id, _from, timestamp, notify, offline) self.setParticipant(participant) self.setGroupId(_from) def setParticipant(self, participant): self._participant = participant def getParticipant(self, full = True): return self._participant if full else self._participant.split('@')[0] def getGroupId(self): return self.groupId def setGroupId(self, groupId): self.groupId = groupId def __str__(self): out = super(GroupsNotificationProtocolEntity, self).__str__() out += "Participant: %s\n" % self.getParticipant() return out def toProtocolTreeNode(self): node = super(GroupsNotificationProtocolEntity, self).toProtocolTreeNode() node.setAttribute("participant", self.getParticipant()) return node @staticmethod def fromProtocolTreeNode(node): entity = super(GroupsNotificationProtocolEntity, GroupsNotificationProtocolEntity).fromProtocolTreeNode(node) entity.__class__ = GroupsNotificationProtocolEntity entity.setParticipant(node.getAttributeValue("participant")) entity.setGroupId(node.getAttributeValue("from")) return entity yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/notification_groups_add.py000066400000000000000000000036321346433372600320660ustar00rootroot00000000000000from .notification_groups import GroupsNotificationProtocolEntity from yowsup.structs import ProtocolTreeNode class AddGroupsNotificationProtocolEntity(GroupsNotificationProtocolEntity): ''' ''' def __init__(self, _id, _from, timestamp, notify, participant, offline, participants): super(AddGroupsNotificationProtocolEntity, self).__init__(_id, _from, timestamp, notify, participant, offline) self.setParticipants(participants) def setParticipants(self, participants): assert type(participants) is list, "Must be a list of jids, got %s instead." % type(participants) self.participants = participants def getParticipants(self): return self.participants def __str__(self): out = super(AddGroupsNotificationProtocolEntity, self).__str__() out += "Participants: %s\n" % " ".join(self.getParticipants()) return out def toProtocolTreeNode(self): node = super(AddGroupsNotificationProtocolEntity, self).toProtocolTreeNode() addNode = ProtocolTreeNode("add") participants = [] for jid in self.getParticipants(): pnode = ProtocolTreeNode("participant", {"jid": jid}) participants.append(pnode) addNode.addChildren(participants) node.addChild(addNode) return node @staticmethod def fromProtocolTreeNode(node): addNode = node.getChild("add") participants = [] for p in addNode.getAllChildren("participant"): participants.append(p["jid"]) return AddGroupsNotificationProtocolEntity( node["id"], node["from"], node["t"], node["notify"], node["participant"], node["offline"], participants )yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/notification_groups_create.py000066400000000000000000000125021346433372600325750ustar00rootroot00000000000000from .notification_groups import GroupsNotificationProtocolEntity from yowsup.structs import ProtocolTreeNode class CreateGroupsNotificationProtocolEntity(GroupsNotificationProtocolEntity): """ """ TYPE_CREATE_NEW = "new" TYPE_PARTICIPANT_ADMIN = "admin" TYPE_PARTICIPANT_SUPERADMIN = "superadmin" def __init__(self, _id, _from, timestamp, notify, participant, offline, createType, key, groupId, creationTimestamp, creatorJid, subject, subjectTime, subjectOwnerJid, participants): super(CreateGroupsNotificationProtocolEntity, self).__init__(_id, _from, timestamp, notify, participant, offline) self.setGroupProps(createType, key, groupId, creationTimestamp, creatorJid, subject, subjectTime, subjectOwnerJid, participants) def setGroupProps(self, createType, key, groupId, creationTimestamp, creatorJid, subject, subjectTime, subjectOwnerJid, participants): assert type(participants) is dict, "Participants must be a dict {jid => type?}" self.createType = createType self.groupId = groupId self.creationTimestamp = int(creationTimestamp) self.creatorJid = creatorJid self.subject = subject self.subjectTime = int(subjectTime) self.subjectOwnerJid = subjectOwnerJid self.participants = participants self._key = key @property def key(self): return self._key def getParticipants(self): return self.participants def getSubject(self): return self.subject def getGroupId(self): return self.groupId def getCreationTimestamp(self): return self.creationTimestamp def getCreatorJid(self, full = True): return self.creatorJid if full else self.creatorJid.split('@')[0] def getSubjectTimestamp(self): return self.subjectTime def getSubjectOwnerJid(self, full = True): return self.subjectOwnerJid if full else self.subjectOwnerJid.split('@')[0] def getCreatetype(self): return self.createType def getGroupSuperAdmin(self, full = True): for jid, _type in self.participants.items(): if _type == self.__class__.TYPE_PARTICIPANT_SUPERADMIN: return jid if full else jid.split('@')[0] def getGroupAdmins(self, full = True): out = [] for jid, _type in self.participants.items(): if _type == self.__class__.TYPE_PARTICIPANT_ADMIN: out.append(jid if full else jid.split('@')[0]) return out def __str__(self): out = super(CreateGroupsNotificationProtocolEntity, self).__str__() out += "Creator: %s\n" % self.getCreatorJid() out += "Create type: %s\n" % self.getCreatetype() out += "Creation timestamp: %s\n" % self.getCreationTimestamp() out += "Subject: %s\n" % self.getSubject() out += "Subject owner: %s\n" % self.getSubjectOwnerJid() out += "Subject timestamp: %s\n" % self.getSubjectTimestamp() out += "Participants: %s\n" % self.getParticipants() out += "Key: %s\n" % self.key return out def toProtocolTreeNode(self): node = super(CreateGroupsNotificationProtocolEntity, self).toProtocolTreeNode() createNode = ProtocolTreeNode("create", {"type": self.getCreatetype(), "key": self.key}) groupNode = ProtocolTreeNode("group", { "subject": self.getSubject(), "creation": str(self.getCreationTimestamp()), "creator": self.getCreatorJid(), "s_t": self.getSubjectTimestamp(), "s_o": self.getSubjectOwnerJid(), "id": self.getGroupId() }) participants = [] for jid, _type in self.getParticipants().items(): pnode = ProtocolTreeNode("participant", {"jid": jid}) if _type: pnode["type"] = _type participants.append(pnode) groupNode.addChildren(participants) createNode.addChild(groupNode) node.addChild(createNode) return node @staticmethod def fromProtocolTreeNode(node): createNode = node.getChild("create") groupNode = createNode.getChild("group") participants = {} for p in groupNode.getAllChildren("participant"): participants[p["jid"]] = p["type"] return CreateGroupsNotificationProtocolEntity( node["id"], node["from"], node["t"], node["notify"], node["participant"], node["offline"], createNode["type"], createNode["key"], groupNode["id"], groupNode["creation"], groupNode["creator"], groupNode["subject"], groupNode["s_t"], groupNode["s_o"], participants ) yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/notification_groups_remove.py000066400000000000000000000041161346433372600326310ustar00rootroot00000000000000from .notification_groups import GroupsNotificationProtocolEntity from yowsup.structs import ProtocolTreeNode class RemoveGroupsNotificationProtocolEntity(GroupsNotificationProtocolEntity): ''' ''' TYPE_PARTICIPANT_ADMIN = "admin" def __init__(self, _id, _from, timestamp, notify, participant, offline, subject, participants): super(RemoveGroupsNotificationProtocolEntity, self).__init__(_id, _from, timestamp, notify, participant, offline) self.setGroupProps(subject, participants) def setGroupProps(self, subject, participants): assert type(participants) is list, "Must be a list of jids, got %s instead." % type(participants) self.subject = subject self.participants = participants def getParticipants(self): return self.participants def getSubject(self): return self.subject def toProtocolTreeNode(self): node = super(RemoveGroupsNotificationProtocolEntity, self).toProtocolTreeNode() removeNode = ProtocolTreeNode("remove", {"subject": self.subject}) participants = [] for jid in self.getParticipants(): pnode = ProtocolTreeNode("participant", {"jid": jid}) participants.append(pnode) removeNode.addChildren(participants) node.addChild(removeNode) return node @staticmethod def fromProtocolTreeNode(node): removeNode = node.getChild("remove") participants = [] for p in removeNode.getAllChildren("participant"): participants.append(p["jid"]) return RemoveGroupsNotificationProtocolEntity( node["id"], node["from"], node["t"], node["notify"], node["participant"], node["offline"], removeNode["subject"], participants ) yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/notification_groups_subject.py000066400000000000000000000044001346433372600327670ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from yowsup.layers.protocol_notifications.protocolentities import NotificationProtocolEntity from .notification_groups import GroupsNotificationProtocolEntity class SubjectGroupsNotificationProtocolEntity(GroupsNotificationProtocolEntity): ''' ''' def __init__(self, _type, _id, _from, timestamp, notify, participant, subject): super(SubjectGroupsNotificationProtocolEntity, self).__init__(_id, _from, timestamp, notify, participant) self.setSubjectData(subject) def setSubjectData(self, subject, subjectOwner, subjectTimestamp): self.subject = subject self.subjectOwner = subjectOwner self.subjectTimestamp = int(subjectTimestamp) def getSubject(self): return self.subject def getSubjectOwner(self, full = True): return self.subjectOwner if full else self.subjectOwner.split('@')[0] def getSubjectTimestamp(self): return self.subjectTimestamp def __str__(self): out = super(SubjectGroupsNotificationProtocolEntity, self).__str__() out += "New subject: %s\n" % self.getSubject() out += "Set by: %s\n" % self.getSubjectOwner() return out def toProtocolTreeNode(self): node = super(SubjectGroupsNotificationProtocolEntity, self).toProtocolTreeNode() subjectNode = ProtocolTreeNode("subject", { "s_t": str(self.getSubjectTimestamp()), "s_o": self.getSubjectOwner(), "subject": self.getSubject() }) node.addChild(subjectNode) return node @staticmethod def fromProtocolTreeNode(node): entity = super(SubjectGroupsNotificationProtocolEntity, SubjectGroupsNotificationProtocolEntity).fromProtocolTreeNode(node) entity.__class__ = SubjectGroupsNotificationProtocolEntity subjectNode = node.getChild("subject") entity.setSubjectData(subjectNode["subject"], subjectNode["s_o"], subjectNode["s_t"]) return entity yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/test_iq_groups.py000066400000000000000000000002261346433372600302340ustar00rootroot00000000000000from yowsup.layers.protocol_iq.protocolentities.test_iq import IqProtocolEntityTest class GroupsIqProtocolEntityTest(IqProtocolEntityTest): pass yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/test_iq_groups_create.py000066400000000000000000000006761346433372600315700ustar00rootroot00000000000000from yowsup.layers.protocol_groups.protocolentities.iq_groups_create import CreateGroupsIqProtocolEntity from yowsup.structs.protocolentity import ProtocolEntityTest import unittest entity = CreateGroupsIqProtocolEntity("group subject") class CreateGroupsIqProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): self.ProtocolEntity = CreateGroupsIqProtocolEntity self.node = entity.toProtocolTreeNode() yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/test_iq_groups_create_success.py000066400000000000000000000007161346433372600333130ustar00rootroot00000000000000from yowsup.structs.protocolentity import ProtocolEntityTest from yowsup.layers.protocol_groups.protocolentities import SuccessCreateGroupsIqProtocolEntity import unittest entity = SuccessCreateGroupsIqProtocolEntity("123-456", "431-123") class SuccessCreateGroupsIqProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): self.ProtocolEntity = SuccessCreateGroupsIqProtocolEntity self.node = entity.toProtocolTreeNode() yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/test_iq_groups_list.py000066400000000000000000000006451346433372600312740ustar00rootroot00000000000000from yowsup.layers.protocol_groups.protocolentities.iq_groups_list import ListGroupsIqProtocolEntity from yowsup.structs.protocolentity import ProtocolEntityTest import unittest entity = ListGroupsIqProtocolEntity() class ListGroupsIqProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): self.ProtocolEntity = ListGroupsIqProtocolEntity self.node = entity.toProtocolTreeNode() yowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/test_iq_result_groups.py000066400000000000000000000002561346433372600316350ustar00rootroot00000000000000from yowsup.layers.protocol_iq.protocolentities.test_iq_result import ResultIqProtocolEntityTest class GroupsResultIqProtocolEntityTest(ResultIqProtocolEntityTest): passyowsup-3.2.3/yowsup/layers/protocol_groups/protocolentities/test_iq_result_groups_list.py000066400000000000000000000014201346433372600326620ustar00rootroot00000000000000from yowsup.layers.protocol_groups.protocolentities.iq_result_groups_list import ListGroupsResultIqProtocolEntity from yowsup.structs.protocolentity import ProtocolEntityTest from yowsup.layers.protocol_groups.structs import Group import unittest import time entity = ListGroupsResultIqProtocolEntity( [ Group("1234-456", "owner@s.whatsapp.net", "subject", "sOwnerJid@s.whatsapp.net", int(time.time()), int(time.time())), Group("4321-456", "owner@s.whatsapp.net", "subject", "sOwnerJid@s.whatsapp.net", int(time.time()), int(time.time())) ] ) class ListGroupsResultIqProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): self.ProtocolEntity = ListGroupsResultIqProtocolEntity self.node = entity.toProtocolTreeNode() yowsup-3.2.3/yowsup/layers/protocol_groups/structs/000077500000000000000000000000001346433372600227145ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_groups/structs/__init__.py000066400000000000000000000000301346433372600250160ustar00rootroot00000000000000from .group import Groupyowsup-3.2.3/yowsup/layers/protocol_groups/structs/group.py000066400000000000000000000024071346433372600244250ustar00rootroot00000000000000class Group(object): def __init__(self, groupId, creatorJid, subject, subjectOwnerJid, subjectTime, creationTime, participants=None): self._groupId = groupId self._creatorJid = creatorJid self._subject = subject self._subjectOwnerJid = subjectOwnerJid self._subjectTime = int(subjectTime) self._creationTime = int(creationTime) self._participants = participants or {} def getId(self): return self._groupId def getCreator(self): return self._creatorJid def getOwner(self): return self.getCreator() def getSubject(self): return self._subject def getSubjectOwner(self): return self._subjectOwnerJid def getSubjectTime(self): return self._subjectTime def getCreationTime(self): return self._creationTime def __str__(self): return "ID: %s, Subject: %s, Creation: %s, Creator: %s, Subject Owner: %s, Subject Time: %s\nParticipants: %s" %\ (self.getId(), self.getSubject(), self.getCreationTime(), self.getCreator(), self.getSubjectOwner(), self.getSubjectTime(), ", ".join(self._participants.keys())) def getParticipants(self): return self._participants yowsup-3.2.3/yowsup/layers/protocol_ib/000077500000000000000000000000001346433372600202605ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_ib/__init__.py000066400000000000000000000000471346433372600223720ustar00rootroot00000000000000from .layer import YowIbProtocolLayer yowsup-3.2.3/yowsup/layers/protocol_ib/layer.py000066400000000000000000000025021346433372600217450ustar00rootroot00000000000000from yowsup.layers import YowLayer, YowLayerEvent, YowProtocolLayer from .protocolentities import * import logging logger = logging.getLogger(__name__) class YowIbProtocolLayer(YowProtocolLayer): def __init__(self): handleMap = { "ib": (self.recvIb, self.sendIb), "iq": (None, self.sendIb) } super(YowIbProtocolLayer, self).__init__(handleMap) def __str__(self): return "Ib Layer" def sendIb(self, entity): if entity.__class__ == CleanIqProtocolEntity: self.toLower(entity.toProtocolTreeNode()) def recvIb(self, node): if node.getChild("dirty"): self.toUpper(DirtyIbProtocolEntity.fromProtocolTreeNode(node)) elif node.getChild("offline"): self.toUpper(OfflineIbProtocolEntity.fromProtocolTreeNode(node)) elif node.getChild("account"): self.toUpper(AccountIbProtocolEntity.fromProtocolTreeNode(node)) elif node.getChild("edge_routing"): logger.debug("ignoring edge_routing ib node for now") elif node.getChild("attestation"): logger.debug("ignoring attestation ib node for now") elif node.getChild("fbip"): logger.debug("ignoring fbip ib node for now") else: logger.warning("Unsupported ib node: %s" % node) yowsup-3.2.3/yowsup/layers/protocol_ib/protocolentities/000077500000000000000000000000001346433372600236665ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_ib/protocolentities/__init__.py000066400000000000000000000002671346433372600260040ustar00rootroot00000000000000from .clean_iq import CleanIqProtocolEntity from .dirty_ib import DirtyIbProtocolEntity from .offline_ib import OfflineIbProtocolEntity from .account_ib import AccountIbProtocolEntityyowsup-3.2.3/yowsup/layers/protocol_ib/protocolentities/account_ib.py000066400000000000000000000037141346433372600263530ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .ib import IbProtocolEntity class AccountIbProtocolEntity(IbProtocolEntity): ''' ''' STATUS_ACTIVE = "active" KIND_PAD = "paid" def __init__(self, status, kind, creation, expiration): super(AccountIbProtocolEntity, self).__init__() self.setProps(status, kind, creation, expiration) def setProps(self, status, kind, creation, expiration): self.status = status self.creation = int(creation) self.kind = kind self.expiration= int(expiration) def toProtocolTreeNode(self): node = super(AccountIbProtocolEntity, self).toProtocolTreeNode() accountChild = ProtocolTreeNode("account", { "status": self.status, "kind": self.kind, "creation": int(self.creation), "expiration": int(self.expiration) }) node.addChild(accountChild) return node def __str__(self): out = super(AccountIbProtocolEntity, self).__str__() out += "Status: %s\n" % self.status out += "Kind: %s\n" % self.kind out += "Creation: %s\n" % self.creation out += "Expiration: %s\n" % self.expiration return out @staticmethod def fromProtocolTreeNode(node): entity = IbProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = AccountIbProtocolEntity accountNode = node.getChild("account") entity.setProps( accountNode["status"], accountNode["kind"], accountNode["creation"], accountNode["expiration"] )yowsup-3.2.3/yowsup/layers/protocol_ib/protocolentities/clean_iq.py000066400000000000000000000024211346433372600260120ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from yowsup.layers.protocol_iq.protocolentities import IqProtocolEntity class CleanIqProtocolEntity(IqProtocolEntity): ''' ''' def __init__(self, cleanType, to, _id = None): super(CleanIqProtocolEntity, self).__init__( "urn:xmpp:whatsapp:dirty", _id = _id, _type = "set", to = to ) self.setProps(cleanType) def setProps(self, cleanType): self.cleanType = cleanType def __str__(self): out = super(CleanIqProtocolEntity, self).__str__() out += "Clean Type: %s\n" % self.cleanType return out def toProtocolTreeNode(self): node = super(CleanIqProtocolEntity, self).toProtocolTreeNode() cleanNode = ProtocolTreeNode("clean", {"type": self.cleanType}) node.addChild(cleanNode) return node @staticmethod def fromProtocolTreeNode(node): entity = IqProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = CleanIqProtocolEntity entity.setProps(node.getChild("clean").getAttributeValue("type")) return entityyowsup-3.2.3/yowsup/layers/protocol_ib/protocolentities/dirty_ib.py000066400000000000000000000024011346433372600260420ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .ib import IbProtocolEntity class DirtyIbProtocolEntity(IbProtocolEntity): ''' ''' def __init__(self, timestamp, _type): super(DirtyIbProtocolEntity, self).__init__() self.setProps(timestamp, _type) def setProps(self, timestamp, _type): self.timestamp = int(timestamp) self._type = _type def toProtocolTreeNode(self): node = super(DirtyIbProtocolEntity, self).toProtocolTreeNode() dirtyNode = ProtocolTreeNode("dirty") dirtyNode["timestamp"] = str(self.timestamp) dirtyNode["type"] = self._type node.addChild(dirtyNode) return node def __str__(self): out = super(DirtyIbProtocolEntity, self).__str__() out += "Type: %s\n" % self._type out += "Timestamp: %s\n" % self.timestamp return out @staticmethod def fromProtocolTreeNode(node): entity = IbProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = DirtyIbProtocolEntity dirtyChild = node.getChild("dirty") entity.setProps(dirtyChild["timestamp"], dirtyChild["type"]) return entity yowsup-3.2.3/yowsup/layers/protocol_ib/protocolentities/ib.py000066400000000000000000000007151346433372600246350ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode class IbProtocolEntity(ProtocolEntity): ''' ''' def __init__(self): super(IbProtocolEntity, self).__init__("ib") def toProtocolTreeNode(self): return self._createProtocolTreeNode({}, None, None) def __str__(self): out = "Ib:\n" return out @staticmethod def fromProtocolTreeNode(node): return IbProtocolEntity() yowsup-3.2.3/yowsup/layers/protocol_ib/protocolentities/offline_ib.py000066400000000000000000000020501346433372600263310ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .ib import IbProtocolEntity class OfflineIbProtocolEntity(IbProtocolEntity): ''' ''' def __init__(self, count): super(IbProtocolEntity, self).__init__() self.setProps(count) def setProps(self, count): self.count = int(count) def toProtocolTreeNode(self): node = super(OfflineIbProtocolEntity, self).toProtocolTreeNode() offlineChild = ProtocolTreeNode("offline", {"count": str(self.count)}) node.addChild(offlineChild) return node def __str__(self): out = super(OfflineIbProtocolEntity, self).__str__() out += "Offline count: %s\n" % self.count return out @staticmethod def fromProtocolTreeNode(node): entity = IbProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = OfflineIbProtocolEntity entity.setProps(node.getChild("offline")["count"]) return entity yowsup-3.2.3/yowsup/layers/protocol_ib/protocolentities/test_clean_iq.py000066400000000000000000000007651346433372600270620ustar00rootroot00000000000000from yowsup.structs import ProtocolTreeNode from yowsup.layers.protocol_ib.protocolentities.clean_iq import CleanIqProtocolEntity from yowsup.layers.protocol_iq.protocolentities.test_iq import IqProtocolEntityTest class CleanIqProtocolEntityTest(IqProtocolEntityTest): def setUp(self): super(CleanIqProtocolEntityTest, self).setUp() self.ProtocolEntity = CleanIqProtocolEntity cleanNode = ProtocolTreeNode("clean", {"type": "groups"}) self.node.addChild(cleanNode)yowsup-3.2.3/yowsup/layers/protocol_ib/protocolentities/test_dirty_ib.py000066400000000000000000000010571346433372600271070ustar00rootroot00000000000000from yowsup.layers.protocol_ib.protocolentities.test_ib import IbProtocolEntityTest from yowsup.layers.protocol_ib.protocolentities.dirty_ib import DirtyIbProtocolEntity from yowsup.structs import ProtocolTreeNode class DirtyIbProtocolEntityTest(IbProtocolEntityTest): def setUp(self): super(DirtyIbProtocolEntityTest, self).setUp() self.ProtocolEntity = DirtyIbProtocolEntity dirtyNode = ProtocolTreeNode("dirty") dirtyNode["timestamp"] = "123456" dirtyNode["type"] = "groups" self.node.addChild(dirtyNode)yowsup-3.2.3/yowsup/layers/protocol_ib/protocolentities/test_ib.py000066400000000000000000000005671346433372600257010ustar00rootroot00000000000000from yowsup.layers.protocol_ib.protocolentities.ib import IbProtocolEntity from yowsup.structs import ProtocolTreeNode from yowsup.structs.protocolentity import ProtocolEntityTest import unittest class IbProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): self.ProtocolEntity = IbProtocolEntity self.node = ProtocolTreeNode("ib") yowsup-3.2.3/yowsup/layers/protocol_ib/protocolentities/test_offline_iq.py000066400000000000000000000007361346433372600274200ustar00rootroot00000000000000from yowsup.layers.protocol_ib.protocolentities.test_ib import IbProtocolEntityTest from yowsup.layers.protocol_ib.protocolentities.offline_ib import OfflineIbProtocolEntity from yowsup.structs import ProtocolTreeNode class OfflineIbProtocolEntityTest(IbProtocolEntityTest): def setUp(self): super(OfflineIbProtocolEntityTest, self).setUp() self.ProtocolEntity = OfflineIbProtocolEntity self.node.addChild(ProtocolTreeNode("offline", {"count": "5"}))yowsup-3.2.3/yowsup/layers/protocol_iq/000077500000000000000000000000001346433372600202775ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_iq/__init__.py000066400000000000000000000000451346433372600224070ustar00rootroot00000000000000from .layer import YowIqProtocolLayeryowsup-3.2.3/yowsup/layers/protocol_iq/layer.py000066400000000000000000000075341346433372600217760ustar00rootroot00000000000000import time import logging from threading import Thread, Lock from yowsup.layers import YowProtocolLayer, YowLayerEvent, EventCallback from yowsup.common import YowConstants from yowsup.layers.network import YowNetworkLayer from yowsup.layers.auth import YowAuthenticationProtocolLayer from .protocolentities import * class YowIqProtocolLayer(YowProtocolLayer): PROP_PING_INTERVAL = "org.openwhatsapp.yowsup.prop.pinginterval" def __init__(self): handleMap = { "iq": (self.recvIq, self.sendIq) } self._pingThread = None self._pingQueue = {} self._pingQueueLock = Lock() self.__logger = logging.getLogger(__name__) super(YowIqProtocolLayer, self).__init__(handleMap) def __str__(self): return "Iq Layer" def onPong(self, protocolTreeNode, pingEntity): self.gotPong(pingEntity.getId()) self.toUpper(ResultIqProtocolEntity.fromProtocolTreeNode(protocolTreeNode)) def sendIq(self, entity): if entity.getXmlns() == "w:p": self._sendIq(entity, self.onPong) elif entity.getXmlns() in ("urn:xmpp:whatsapp:push", "w", "urn:xmpp:whatsapp:account", "encrypt"): self.toLower(entity.toProtocolTreeNode()) def recvIq(self, node): if node["xmlns"] == "urn:xmpp:ping": entity = PongResultIqProtocolEntity(YowConstants.DOMAIN, node["id"]) self.toLower(entity.toProtocolTreeNode()) def gotPong(self, pingId): self._pingQueueLock.acquire() if pingId in self._pingQueue: self._pingQueue = {} self._pingQueueLock.release() def waitPong(self, id): self._pingQueueLock.acquire() self._pingQueue[id] = None pingQueueSize = len(self._pingQueue) self._pingQueueLock.release() self.__logger.debug("ping queue size: %d" % pingQueueSize) if pingQueueSize >= 2: self.getStack().broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_DISCONNECT, reason = "Ping Timeout")) @EventCallback(YowAuthenticationProtocolLayer.EVENT_AUTHED) def onAuthed(self, event): interval = self.getProp(self.__class__.PROP_PING_INTERVAL, 50) if not self._pingThread and interval > 0: self._pingQueue = {} self._pingThread = YowPingThread(self, interval) self.__logger.debug("starting ping thread.") self._pingThread.start() def stop_thread(self): if self._pingThread: self.__logger.debug("stopping ping thread") if self._pingThread: self._pingThread.stop() self._pingThread = None self._pingQueue = {} @EventCallback(YowNetworkLayer.EVENT_STATE_DISCONNECT) def onDisconnect(self, event): self.stop_thread() @EventCallback(YowNetworkLayer.EVENT_STATE_DISCONNECTED) def onDisconnected(self, event): self.stop_thread() class YowPingThread(Thread): def __init__(self, layer, interval): assert type(layer) is YowIqProtocolLayer, "layer must be a YowIqProtocolLayer, got %s instead." % type(layer) self._layer = layer self._interval = interval self._stop = False self.__logger = logging.getLogger(__name__) super(YowPingThread, self).__init__() self.daemon = True self.name = "YowPing%s" % self.name def run(self): while not self._stop: for i in range(0, self._interval): time.sleep(1) if self._stop: self.__logger.debug("%s - ping thread stopped" % self.name) return ping = PingIqProtocolEntity() self._layer.waitPong(ping.getId()) if not self._stop: self._layer.sendIq(ping) def stop(self): self._stop = True yowsup-3.2.3/yowsup/layers/protocol_iq/protocolentities/000077500000000000000000000000001346433372600237055ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_iq/protocolentities/__init__.py000066400000000000000000000005401346433372600260150ustar00rootroot00000000000000from .iq import IqProtocolEntity from .iq_result import ResultIqProtocolEntity from .iq_ping import PingIqProtocolEntity from .iq_result_pong import PongResultIqProtocolEntity from .iq_error import ErrorIqProtocolEntity from .iq_push import PushIqProtocolEntity from .iq_props import PropsIqProtocolEntity from .iq_crypto import CryptoIqProtocolEntity yowsup-3.2.3/yowsup/layers/protocol_iq/protocolentities/iq.py000066400000000000000000000043311346433372600246710ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode class IqProtocolEntity(ProtocolEntity): ''' ''' TYPE_SET = "set" TYPE_GET = "get" TYPE_ERROR = "error" TYPE_RESULT = "result" TYPES = (TYPE_SET, TYPE_GET, TYPE_RESULT, TYPE_ERROR) def __init__(self, xmlns = None, _id = None, _type = None, to = None, _from = None): super(IqProtocolEntity, self).__init__("iq") assert _type in self.__class__.TYPES, "Iq of type %s is not implemented, can accept only (%s)" % (_type," | ".join(self.__class__.TYPES)) assert not to or not _from, "Can't set from and to at the same time" self._id = self._generateId(True) if _id is None else _id self._from = _from self._type = _type self.xmlns = xmlns self.to = to def getId(self): return self._id def getType(self): return self._type def getXmlns(self): return self.xmlns def getFrom(self, full = True): return self._from if full else self._from.split('@')[0] def getTo(self): return self.to def toProtocolTreeNode(self): attribs = { "id" : self._id, "type" : self._type } if self.xmlns: attribs["xmlns"] = self.xmlns if self.to: attribs["to"] = self.to elif self._from: attribs["from"] = self._from return self._createProtocolTreeNode(attribs, None, data = None) def __str__(self): out = "Iq:\n" out += "ID: %s\n" % self._id out += "Type: %s\n" % self._type if self.xmlns: out += "xmlns: %s\n" % self.xmlns if self.to: out += "to: %s\n" % self.to elif self._from: out += "from: %s\n" % self._from return out @staticmethod def fromProtocolTreeNode(node): return IqProtocolEntity( node.getAttributeValue("xmlns"), node.getAttributeValue("id"), node.getAttributeValue("type"), node.getAttributeValue("to"), node.getAttributeValue("from") ) yowsup-3.2.3/yowsup/layers/protocol_iq/protocolentities/iq_crypto.py000066400000000000000000000012131346433372600262650ustar00rootroot00000000000000from .iq import IqProtocolEntity from yowsup.structs import ProtocolTreeNode class CryptoIqProtocolEntity(IqProtocolEntity): def __init__(self): super(CryptoIqProtocolEntity, self).__init__("urn:xmpp:whatsapp:account", _type="get") def toProtocolTreeNode(self): node = super(CryptoIqProtocolEntity, self).toProtocolTreeNode() cryptoNode = ProtocolTreeNode("crypto", {"action": "create"}) googleNode = ProtocolTreeNode("google", data = "fe5cf90c511fb899781bbed754577098e460d048312c8b36c11c91ca4b49ca34".decode('hex')) cryptoNode.addChild(googleNode) node.addChild(cryptoNode) return nodeyowsup-3.2.3/yowsup/layers/protocol_iq/protocolentities/iq_error.py000066400000000000000000000031551346433372600261050ustar00rootroot00000000000000from yowsup.structs import ProtocolTreeNode from .iq import IqProtocolEntity class ErrorIqProtocolEntity(IqProtocolEntity): ''' ''' def __init__(self, _id, _from, code, text, backoff= 0 ): super(ErrorIqProtocolEntity, self).__init__(xmlns = None, _id = _id, _type = "error", _from = _from) self.setErrorProps(code, text, backoff) def setErrorProps(self, code, text, backoff): self.code = code self.text = text self.backoff = int(backoff) if backoff else 0 def toProtocolTreeNode(self): node = super(ErrorIqProtocolEntity, self).toProtocolTreeNode() errorNode = ProtocolTreeNode("error", {"text": self.text, "code": self.code}) if self.backoff: errorNode.setAttribute("backoff", str(self.backoff)) node.addChild(errorNode) return node def __str__(self): out = super(ErrorIqProtocolEntity, self).__str__() out += "Code: %s\n" % self.code out += "Text: %s\n" % self.text out += "Backoff: %s\n" % self.backoff return out @staticmethod def fromProtocolTreeNode(node): entity = IqProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = ErrorIqProtocolEntity errorNode = node.getChild("error") entity.setErrorProps(errorNode.getAttributeValue("code"), errorNode.getAttributeValue("text"), errorNode.getAttributeValue("backoff")) return entity yowsup-3.2.3/yowsup/layers/protocol_iq/protocolentities/iq_ping.py000066400000000000000000000010531346433372600257040ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .iq import IqProtocolEntity class PingIqProtocolEntity(IqProtocolEntity): ''' Receive Send ''' def __init__(self, _from = None, to = None, _id = None): super(PingIqProtocolEntity, self).__init__("urn:xmpp:ping" if _from else "w:p", _id = _id, _type = "get", _from = _from, to = to) yowsup-3.2.3/yowsup/layers/protocol_iq/protocolentities/iq_props.py000066400000000000000000000006101346433372600261100ustar00rootroot00000000000000from .iq import IqProtocolEntity from yowsup.structs import ProtocolTreeNode class PropsIqProtocolEntity(IqProtocolEntity): def __init__(self): super(PropsIqProtocolEntity, self).__init__("w", _type="get") def toProtocolTreeNode(self): node = super(PropsIqProtocolEntity, self).toProtocolTreeNode() node.addChild(ProtocolTreeNode("props")) return nodeyowsup-3.2.3/yowsup/layers/protocol_iq/protocolentities/iq_push.py000066400000000000000000000006331346433372600257310ustar00rootroot00000000000000from .iq import IqProtocolEntity from yowsup.structs import ProtocolTreeNode class PushIqProtocolEntity(IqProtocolEntity): def __init__(self): super(PushIqProtocolEntity, self).__init__("urn:xmpp:whatsapp:push", _type="get") def toProtocolTreeNode(self): node = super(PushIqProtocolEntity, self).toProtocolTreeNode() node.addChild(ProtocolTreeNode("config")) return nodeyowsup-3.2.3/yowsup/layers/protocol_iq/protocolentities/iq_result.py000066400000000000000000000006411346433372600262670ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .iq import IqProtocolEntity class ResultIqProtocolEntity(IqProtocolEntity): ''' ''' def __init__(self, xmlns = None, _id = None, to = None, _from = None): super(ResultIqProtocolEntity, self).__init__(xmlns = xmlns, _id = _id, _type = "result", to = to, _from = _from) yowsup-3.2.3/yowsup/layers/protocol_iq/protocolentities/iq_result_pong.py000066400000000000000000000006041346433372600273110ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .iq_result import ResultIqProtocolEntity class PongResultIqProtocolEntity(ResultIqProtocolEntity): ''' ''' def __init__(self, to, _id = None): super(PongResultIqProtocolEntity, self).__init__("w:p", _id = _id, to = to) yowsup-3.2.3/yowsup/layers/protocol_iq/protocolentities/test_iq.py000066400000000000000000000006711346433372600257330ustar00rootroot00000000000000from yowsup.layers.protocol_iq.protocolentities.iq import IqProtocolEntity from yowsup.structs import ProtocolTreeNode from yowsup.structs.protocolentity import ProtocolEntityTest import unittest class IqProtocolEntityTest(unittest.TestCase, ProtocolEntityTest): def setUp(self): self.ProtocolEntity = IqProtocolEntity self.node = ProtocolTreeNode("iq", {"id": "test_id", "type": "get", "xmlns": "iq_xmlns"}, None, None)yowsup-3.2.3/yowsup/layers/protocol_iq/protocolentities/test_iq_error.py000066400000000000000000000007711346433372600271450ustar00rootroot00000000000000from yowsup.layers.protocol_iq.protocolentities.test_iq import IqProtocolEntityTest from yowsup.layers.protocol_iq.protocolentities import ErrorIqProtocolEntity from yowsup.structs import ProtocolTreeNode class ErrorIqProtocolEntityTest(IqProtocolEntityTest): def setUp(self): super(ErrorIqProtocolEntityTest, self).setUp() self.ProtocolEntity = ErrorIqProtocolEntity errorNode = ProtocolTreeNode("error", {"code": "123", "text": "abc"}) self.node.addChild(errorNode) yowsup-3.2.3/yowsup/layers/protocol_iq/protocolentities/test_iq_result.py000066400000000000000000000004111346433372600273210ustar00rootroot00000000000000from yowsup.layers.protocol_iq.protocolentities.test_iq import IqProtocolEntityTest class ResultIqProtocolEntityTest(IqProtocolEntityTest): def setUp(self): super(ResultIqProtocolEntityTest, self).setUp() self.node.setAttribute("type", "result")yowsup-3.2.3/yowsup/layers/protocol_media/000077500000000000000000000000001346433372600207455ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_media/__init__.py000066400000000000000000000000521346433372600230530ustar00rootroot00000000000000from .layer import YowMediaProtocolLayer yowsup-3.2.3/yowsup/layers/protocol_media/layer.py000066400000000000000000000073101346433372600224340ustar00rootroot00000000000000from yowsup.layers import YowProtocolLayer from .protocolentities import ImageDownloadableMediaMessageProtocolEntity from .protocolentities import AudioDownloadableMediaMessageProtocolEntity from .protocolentities import VideoDownloadableMediaMessageProtocolEntity from .protocolentities import DocumentDownloadableMediaMessageProtocolEntity from .protocolentities import LocationMediaMessageProtocolEntity from .protocolentities import ContactMediaMessageProtocolEntity from .protocolentities import ResultRequestUploadIqProtocolEntity from .protocolentities import MediaMessageProtocolEntity from .protocolentities import ExtendedTextMediaMessageProtocolEntity from yowsup.layers.protocol_iq.protocolentities import IqProtocolEntity, ErrorIqProtocolEntity import logging logger = logging.getLogger(__name__) class YowMediaProtocolLayer(YowProtocolLayer): def __init__(self): handleMap = { "message": (self.recvMessageStanza, self.sendMessageEntity), "iq": (self.recvIq, self.sendIq) } super(YowMediaProtocolLayer, self).__init__(handleMap) def __str__(self): return "Media Layer" def sendMessageEntity(self, entity): if entity.getType() == "media": self.entityToLower(entity) def recvMessageStanza(self, node): if node.getAttributeValue("type") == "media": mediaNode = node.getChild("proto") if mediaNode.getAttributeValue("mediatype") == "image": entity = ImageDownloadableMediaMessageProtocolEntity.fromProtocolTreeNode(node) self.toUpper(entity) elif mediaNode.getAttributeValue("mediatype") in ("audio", "ptt"): entity = AudioDownloadableMediaMessageProtocolEntity.fromProtocolTreeNode(node) self.toUpper(entity) elif mediaNode.getAttributeValue("mediatype") in ("video", "gif"): entity = VideoDownloadableMediaMessageProtocolEntity.fromProtocolTreeNode(node) self.toUpper(entity) elif mediaNode.getAttributeValue("mediatype") == "location": entity = LocationMediaMessageProtocolEntity.fromProtocolTreeNode(node) self.toUpper(entity) elif mediaNode.getAttributeValue("mediatype") == "contact": entity = ContactMediaMessageProtocolEntity.fromProtocolTreeNode(node) self.toUpper(entity) elif mediaNode.getAttributeValue("mediatype") == "document": entity = DocumentDownloadableMediaMessageProtocolEntity.fromProtocolTreeNode(node) self.toUpper(entity) elif mediaNode.getAttributeValue("mediatype") == "url": entity = ExtendedTextMediaMessageProtocolEntity.fromProtocolTreeNode(node) self.toUpper(entity) else: logger.warn("Unsupported mediatype: %s, will send receipts" % mediaNode.getAttributeValue("mediatype")) self.toLower(MediaMessageProtocolEntity.fromProtocolTreeNode(node).ack(True).toProtocolTreeNode()) def sendIq(self, entity): """ :type entity: IqProtocolEntity """ if entity.getType() == IqProtocolEntity.TYPE_SET and entity.getXmlns() == "w:m": #media upload! self._sendIq(entity, self.onRequestUploadSuccess, self.onRequestUploadError) def recvIq(self, node): """ :type node: ProtocolTreeNode """ def onRequestUploadSuccess(self, resultNode, requestUploadEntity): self.toUpper(ResultRequestUploadIqProtocolEntity.fromProtocolTreeNode(resultNode)) def onRequestUploadError(self, errorNode, requestUploadEntity): self.toUpper(ErrorIqProtocolEntity.fromProtocolTreeNode(errorNode)) yowsup-3.2.3/yowsup/layers/protocol_media/mediacipher.py000066400000000000000000000061211346433372600235710ustar00rootroot00000000000000from axolotl.kdf.hkdfv3 import HKDFv3 from axolotl.util.byteutil import ByteUtil from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import padding import hmac import hashlib class MediaCipher(object): INFO_IMAGE = b"WhatsApp Image Keys" INFO_AUDIO = b"WhatsApp Audio Keys" INFO_VIDEO = b"WhatsApp Video Keys" INFO_DOCUM = b"WhatsApp Document Keys" def encrypt_image(self, plaintext, ref_key): return self.encrypt(plaintext, ref_key, self.INFO_IMAGE) def encrypt_audio(self, ciphertext, ref_key): return self.encrypt(ciphertext, ref_key, self.INFO_AUDIO) def encrypt_video(self, ciphertext, ref_key): return self.encrypt(ciphertext, ref_key, self.INFO_VIDEO) def encrypt_document(self, ciphertext, ref_key): return self.encrypt(ciphertext, ref_key, self.INFO_DOCUM) def decrypt_image(self, ciphertext, ref_key): return self.decrypt(ciphertext, ref_key, self.INFO_IMAGE) def decrypt_audio(self, ciphertext, ref_key): return self.decrypt(ciphertext, ref_key, self.INFO_AUDIO) def decrypt_video(self, ciphertext, ref_key): return self.decrypt(ciphertext, ref_key, self.INFO_VIDEO) def decrypt_document(self, ciphertext, ref_key): return self.decrypt(ciphertext, ref_key, self.INFO_DOCUM) def encrypt(self, plaintext, ref_key, media_info): derived = HKDFv3().deriveSecrets(ref_key, media_info, 112) parts = ByteUtil.split(derived, 16, 32) iv = parts[0] key = parts[1] mac_key = derived[48:80] cipher_encryptor = Cipher( algorithms.AES(key), modes.CBC(iv), backend=default_backend() ).encryptor() if len(plaintext) % 16 != 0: padder = padding.PKCS7(128).padder() padded_plaintext = padder.update(plaintext) + padder.finalize() else: padded_plaintext = plaintext ciphertext = cipher_encryptor.update(padded_plaintext) + cipher_encryptor.finalize() mac = hmac.new(mac_key, digestmod=hashlib.sha256) mac.update(iv) mac.update(ciphertext) return ciphertext + mac.digest()[:10] def decrypt(self, ciphertext, ref_key, media_info): derived = HKDFv3().deriveSecrets(ref_key, media_info, 112) parts = ByteUtil.split(derived, 16, 32) iv = parts[0] key = parts[1] mac_key = derived[48:80] media_ciphertext = ciphertext[:-10] mac_value = ciphertext[-10:] mac = hmac.new(mac_key, digestmod=hashlib.sha256) mac.update(iv) mac.update(media_ciphertext) if mac_value != mac.digest()[:10]: raise ValueError("Invalid MAC") cipher_decryptor = Cipher( algorithms.AES(key), modes.CBC(iv), backend=default_backend() ).decryptor() decrypted = cipher_decryptor.update(media_ciphertext) + cipher_decryptor.finalize() unpadder = padding.PKCS7(128).unpadder() return unpadder.update(decrypted) + unpadder.finalize() yowsup-3.2.3/yowsup/layers/protocol_media/mediadownloader.py000066400000000000000000000040131346433372600244530ustar00rootroot00000000000000import sys, tempfile, logging logger = logging.getLogger(__name__) if sys.version_info >= (3, 0): from urllib.request import urlopen from urllib.parse import urlencode else: from urllib2 import urlopen from urllib import urlencode class MediaDownloader: def __init__(self, successClbk = None, errorClbk = None, progressCallback = None): self.successCallback = successClbk self.errorCallback = errorClbk self.progressCallback = progressCallback def download(self, url = ""): try: if not url: if self.url: url = "https://" if self.port == 443 else "http://" url = url + self.url url = url + "?" + urlencode(self.params) logger.debug("URL is %s" % url) else: raise Exception("No url specified for fetching") u = urlopen(url) path = tempfile.mkstemp()[1] with open(path, "wb") as f: meta = u.info() if sys.version_info >= (3, 0): fileSize = int(u.getheader("Content-Length")) else: fileSize = int(meta.getheaders("Content-Length")[0]) fileSizeDl = 0 blockSz = 8192 lastEmit = 0 while True: buf = u.read(blockSz) if not buf: break fileSizeDl += len(buf) f.write(buf) status = (fileSizeDl * 100 / fileSize) if self.progressCallback and lastEmit != status: self.progressCallback(int(status)) lastEmit = status; if self.successCallback: self.successCallback(path) except: logger.exception("Error occured at transfer") if self.errorCallback: self.errorCallback();yowsup-3.2.3/yowsup/layers/protocol_media/mediauploader.py000066400000000000000000000121521346433372600241330ustar00rootroot00000000000000from yowsup.common.http.warequest import WARequest from yowsup.common.http.waresponseparser import JSONResponseParser import socket import ssl import os import hashlib import sys from time import sleep import threading import logging from yowsup.common.tools import MimeTools logger = logging.getLogger(__name__) class MediaUploader(WARequest, threading.Thread): def __init__(self, jid, accountJid, sourcePath, uploadUrl, resumeOffset=0, successClbk=None, errorClbk=None, progressCallback=None, asynchronous=True): WARequest.__init__(self) self.asynchronous = asynchronous self.jid = jid self.accountJid = accountJid self.sourcePath = sourcePath self.uploadUrl = uploadUrl self.resumeOffset = resumeOffset self.successCallback = successClbk self.errorCallback = errorClbk self.progressCallback = progressCallback self.pvars = ["name", "type", "size", "url", "error", "mimetype", "filehash", "width", "height"] self.setParser(JSONResponseParser()) self.sock = socket.socket() def start(self): if self.asynchronous: threading.Thread.__init__(self) super(MediaUploader, self).start() else: self.run() def run(self): sourcePath = self.sourcePath uploadUrl = self.uploadUrl _host = uploadUrl.replace("https://", "") self.url = _host[:_host.index('/')] try: filename = os.path.basename(sourcePath) filetype = MimeTools.getMIME(filename) filesize = os.path.getsize(sourcePath) self.sock.connect((self.url, self.port)) ssl_sock = ssl.wrap_socket(self.sock) m = hashlib.md5() m.update(filename.encode()) crypto = m.hexdigest() + os.path.splitext(filename)[1] boundary = "zzXXzzYYzzXXzzQQ" # "-------" + m.hexdigest() #"zzXXzzYYzzXXzzQQ" contentLength = 0 hBAOS = "--" + boundary + "\r\n" hBAOS += "Content-Disposition: form-data; name=\"to\"\r\n\r\n" hBAOS += self.jid + "\r\n" hBAOS += "--" + boundary + "\r\n" hBAOS += "Content-Disposition: form-data; name=\"from\"\r\n\r\n" hBAOS += self.accountJid.replace("@whatsapp.net", "") + "\r\n" hBAOS += "--" + boundary + "\r\n" hBAOS += "Content-Disposition: form-data; name=\"file\"; filename=\"" + crypto + "\"\r\n" hBAOS += "Content-Type: " + filetype + "\r\n\r\n" fBAOS = "\r\n--" + boundary + "--\r\n" contentLength += len(hBAOS) contentLength += len(fBAOS) contentLength += filesize POST = "POST %s\r\n" % uploadUrl POST += "Content-Type: multipart/form-data; boundary=" + boundary + "\r\n" POST += "Host: %s\r\n" % self.url POST += "User-Agent: %s\r\n" % self.getUserAgent() POST += "Content-Length: " + str(contentLength) + "\r\n\r\n" ssl_sock.write(bytearray(POST.encode())) ssl_sock.write(bytearray(hBAOS.encode())) totalsent = 0 buf = 1024 f = open(sourcePath, 'rb') stream = f.read() f.close() status = 0 lastEmit = 0 while totalsent < int(filesize): ssl_sock.write(stream[:buf]) status = totalsent * 100 / filesize if lastEmit != status and status != 100 and filesize > 12288: if self.progressCallback: self.progressCallback(self.sourcePath, self.jid, uploadUrl, int(status)) lastEmit = status stream = stream[buf:] totalsent = totalsent + buf ssl_sock.write(bytearray(fBAOS.encode())) sleep(1) data = ssl_sock.recv(8192) data += ssl_sock.recv(8192) data += ssl_sock.recv(8192) data += ssl_sock.recv(8192) data += ssl_sock.recv(8192) data += ssl_sock.recv(8192) data += ssl_sock.recv(8192) if self.progressCallback: self.progressCallback(self.sourcePath, self.jid, uploadUrl, 100) lines = data.decode().splitlines() result = None for l in lines: if l.startswith("{"): result = self.parser.parse(l, self.pvars) break if not result: raise Exception("json data not found") if result["url"] is not None: if self.successCallback: self.successCallback(sourcePath, self.jid, result["url"]) else: logger.exception("uploadUrl: %s, result of uploading media has no url" % uploadUrl) if self.errorCallback: self.errorCallback(sourcePath, self.jid, uploadUrl) except: logger.exception("Error occured at transfer %s" % sys.exc_info()[1]) if self.errorCallback: self.errorCallback(sourcePath, self.jid, uploadUrl) yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/000077500000000000000000000000001346433372600243535ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/__init__.py000066400000000000000000000015231346433372600264650ustar00rootroot00000000000000from .message_media import MediaMessageProtocolEntity from .message_media_downloadable import DownloadableMediaMessageProtocolEntity from .message_media_downloadable_image import ImageDownloadableMediaMessageProtocolEntity from .message_media_downloadable_audio import AudioDownloadableMediaMessageProtocolEntity from .message_media_downloadable_video import VideoDownloadableMediaMessageProtocolEntity from .message_media_downloadable_document import DocumentDownloadableMediaMessageProtocolEntity from .message_media_location import LocationMediaMessageProtocolEntity from .message_media_contact import ContactMediaMessageProtocolEntity from .message_media_extendedtext import ExtendedTextMediaMessageProtocolEntity from .iq_requestupload import RequestUploadIqProtocolEntity from .iq_requestupload_result import ResultRequestUploadIqProtocolEntity yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/attributes/000077500000000000000000000000001346433372600265415ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/attributes/__init__.py000066400000000000000000000000001346433372600306400ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/attributes/attributes_audio.py000066400000000000000000000007521346433372600324660ustar00rootroot00000000000000class AudioAttributes(object): def __init__(self, seconds, ptt): """ :param seconds: duration of audio playback in seconds :type seconds: int :param ptt: indicates whether this is a push-to-talk audio message :type ptt: bool """ self._seconds = seconds # type: int self._ptt = ptt # type: bool @property def seconds(self): return self._seconds @property def ptt(self): return self._ptt yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/attributes/attributes_contact.py000066400000000000000000000004401346433372600330120ustar00rootroot00000000000000class ContactAttributes(object): def __init__(self, display_name, vcard): self._display_name = display_name self._vcard = vcard @property def display_name(self): return self._display_name @property def vcard(self): return self._vcard yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/attributes/attributes_document.py000066400000000000000000000015461346433372600332050ustar00rootroot00000000000000import os class DocumentAttributes(object): def __init__(self, file_name, file_length, title=None, page_count=None, jpeg_thumbnail=None): self._file_name = file_name self._file_length = file_length self._title = title self._page_count = page_count self._jpeg_thumbnail = jpeg_thumbnail @property def file_name(self): return self._file_name @property def file_length(self): return self._file_length @property def title(self): return self._title @property def page_count(self): return self._page_count @property def jpeg_thumbnail(self): return self._jpeg_thumbnail @staticmethod def from_filepath(filepath): return DocumentAttributes( os.path.basename(filepath), os.path.getsize(filepath) ) attributes_downloadablemedia.py000066400000000000000000000034461346433372600347440ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/attributesfrom yowsup.layers.protocol_media.protocolentities.attributes.attributes_media import MediaAttributes from yowsup.common.tools import MimeTools import base64 import hashlib import os class DownloadableMediaMessageAttributes(MediaAttributes): def __init__(self, mimetype, file_length, file_sha256, url=None, media_key=None, context_info=None): super(DownloadableMediaMessageAttributes, self).__init__(context_info) self._mimetype = mimetype self._file_length = file_length self._file_sha256 = file_sha256 self._url = url self._media_key = media_key def __str__(self): return "[url=%s, mimetype=%s, file_length=%d, file_sha256=%s, media_key=%s]" % ( self.url,self.mimetype, self.file_length, base64.b64encode(self.file_sha256), base64.b64encode(self.media_key) ) @property def url(self): return self._url @property def mimetype(self): return self._mimetype @property def file_length(self): return self._file_length @property def file_sha256(self): return self._file_sha256 @property def media_key(self): return self._media_key @staticmethod def from_file( filepath, mimetype=None, file_length=None, file_sha256=None, url=None, media_key=None, context_info=None ): mimetype = MimeTools.getMIME(filepath) if mimetype is None else mimetype file_length = os.path.getsize(filepath) if file_length is None else file_length if file_sha256 is None: with open(filepath, 'rb') as f: file_sha256 = hashlib.sha256(f.read()).digest() return DownloadableMediaMessageAttributes( mimetype, file_length, file_sha256, url, media_key, context_info ) yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/attributes/attributes_extendedtext.py000066400000000000000000000014761346433372600340760ustar00rootroot00000000000000class ExtendedTextAttributes(object): def __init__(self, text, matched_text, canonical_url, description, title, jpeg_thumbnail ): self._text = text self._matched_text = matched_text self._canonical_url = canonical_url self._description = description self._title = title self._jpeg_thumbnail = jpeg_thumbnail @property def text(self): return self._text @property def matched_text(self): return self._matched_text @property def canonical_url(self): return self._canonical_url @property def description(self): return self._description @property def title(self): return self._title @property def jpeg_thumbnail(self): return self._jpeg_thumbnail yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/attributes/attributes_image.py000066400000000000000000000015361346433372600324500ustar00rootroot00000000000000from yowsup.common.tools import ImageTools import os class ImageAttributes(object): def __init__(self, width, height, caption=None, jpeg_thumbnail=None): self.width = width self.height = height self.caption = caption self.jpeg_thumbnail = jpeg_thumbnail @staticmethod def from_filepath(filepath, dimensions=None, caption=None, jpeg_thumbnail=None): assert os.path.exists(filepath) if not jpeg_thumbnail: jpeg_thumbnail = ImageTools.generatePreviewFromImage(filepath) dimensions = dimensions or ImageTools.getImageDimensions(filepath) width, height = dimensions if dimensions else (None, None) assert width and height, "Could not determine image dimensions, install pillow or pass dimensions" return ImageAttributes(width, height, caption, jpeg_thumbnail)yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/attributes/attributes_location.py000066400000000000000000000044241346433372600331750ustar00rootroot00000000000000class LocationAttributes(object): def __init__(self, degrees_latitude, degrees_longitude, name=None, address=None, url=None, duration=None, accuracy_in_meters=None, speed_in_mps=None, degrees_clockwise_from_magnetic_north=None, axolotl_sender_key_distribution_message=None, jpeg_thumbnail=None): """ :param degrees_latitude: Actual location, Place :param degrees_longitude: Actual location, Place :param name: Place :param address: Place :param url: Place :param duration: :param accuracy_in_meters: :param speed_in_mps: :param degrees_clockwise_from_magnetic_north: :param axolotl_sender_key_distribution_message: :param jpeg_thumbnail: Actual location, Place """ self._degrees_latitude = degrees_latitude self._degrees_longitude = degrees_longitude self._name = name self._address = address self._url = url self._duration = duration self._accuracy_in_meters = accuracy_in_meters self._speed_in_mps = speed_in_mps self._degrees_clockwise_from_magnetic_north = degrees_clockwise_from_magnetic_north self._axolotl_sender_key_distribution_message = axolotl_sender_key_distribution_message self._jpeg_thumbnail = jpeg_thumbnail @property def degrees_latitude(self): return self._degrees_latitude @property def degrees_longitude(self): return self._degrees_longitude @property def name(self): return self._name @property def address(self): return self._address @property def url(self): return self._url @property def duration(self): return self._duration @property def accuracy_in_meters(self): return self._accuracy_in_meters @property def speed_in_mps(self): return self._speed_in_mps @property def degrees_clockwise_from_magnetic_north(self): return self._degrees_clockwise_from_magnetic_north @property def axolotl_sender_key_distribution_message(self): return self._axolotl_sender_key_distribution_message @property def jpeg_thumbnail(self): return self._jpeg_thumbnail yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/attributes/attributes_media.py000066400000000000000000000007221346433372600324410ustar00rootroot00000000000000from yowsup.layers.protocol_media.protocolentities.attributes.context_info import ContextInfo class MediaAttributes(object): def __init__(self, context_info=None): """ :type context_info: ContextInfo | None """ if context_info: assert type(context_info) is ContextInfo self._context_info = context_info # type: ContextInfo | None @property def context_info(self): return self._context_info yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/attributes/attributes_video.py000066400000000000000000000021101346433372600324610ustar00rootroot00000000000000class VideoAttributes(object): def __init__(self, width, height, seconds, gif_playback=None, jpeg_thumbnail=None, gif_attribution=None, caption=None, streaming_sidecar=None): self._width = width self._height = height self._seconds = seconds self._gif_playback = gif_playback self._jpeg_thumbnail = jpeg_thumbnail self._gif_attribution = gif_attribution self._caption = caption self._streaming_sidecar = streaming_sidecar @property def width(self): return self._width @property def height(self): return self._height @property def seconds(self): return self._seconds @property def gif_playback(self): return self._gif_playback @property def jpeg_thumbnail(self): return self._jpeg_thumbnail @property def gif_attribution(self): return self._gif_attribution @property def caption(self): return self._caption @property def streaming_sidecar(self): return self._streaming_sidecar yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/attributes/context_info.py000066400000000000000000000021741346433372600316160ustar00rootroot00000000000000class ContextInfo(object): def __init__(self, stanza_id=None, participant=None, quoted_message=None, remote_jid=None, mentioned_jid=None, edit_version=None, revoke_message=None ): self._stanza_id= stanza_id self._participant = participant self._quoted_message = quoted_message self._remote_jid = remote_jid self._mentioned_jid = mentioned_jid self._edit_version = edit_version self._revoke_message = revoke_message @property def stanza_id(self): return self._stanza_id @property def participant(self): return self._participant @property def quoted_message(self): return self._quoted_message @property def remote_jid(self): return self._remote_jid @property def mentioned_jid(self): return self._mentioned_jid @property def edit_version(self): return self._edit_version @property def revoke_message(self): return self._revoke_message yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/iq_requestupload.py000066400000000000000000000062741346433372600303240ustar00rootroot00000000000000from yowsup.common import YowConstants from yowsup.layers.protocol_iq.protocolentities import IqProtocolEntity from yowsup.structs import ProtocolTreeNode import hashlib import base64 import os from yowsup.common.tools import WATools class RequestUploadIqProtocolEntity(IqProtocolEntity): ''' ''' MEDIA_TYPE_IMAGE = "image" MEDIA_TYPE_VIDEO = "video" MEDIA_TYPE_AUDIO = "audio" MEDIA_TYPE_DOCUM = "document" XMLNS = "w:m" TYPES_MEDIA = (MEDIA_TYPE_AUDIO, MEDIA_TYPE_IMAGE, MEDIA_TYPE_VIDEO, MEDIA_TYPE_DOCUM) def __init__(self, mediaType, b64Hash = None, size = None, origHash = None, filePath = None ): super(RequestUploadIqProtocolEntity, self).__init__("w:m", _type = "set", to = YowConstants.WHATSAPP_SERVER) assert (b64Hash and size) or filePath, "Either specify hash and size, or specify filepath and let me generate the rest" if filePath: assert os.path.exists(filePath), "Either specified path does not exist, or yowsup doesn't have permission to read: %s" % filePath b64Hash = self.__class__.getFileHashForUpload(filePath) size = os.path.getsize(filePath) self.setRequestArguments(mediaType, b64Hash, size, origHash) def setRequestArguments(self, mediaType, b64Hash, size, origHash = None): assert mediaType in self.__class__.TYPES_MEDIA, "Expected media type to be in %s, got %s" % (self.__class__.TYPES_MEDIA, mediaType) self.mediaType = mediaType self.b64Hash = b64Hash self.size = int(size) self.origHash = origHash @staticmethod def getFileHashForUpload(filePath): return WATools.getFileHashForUpload(filePath) def __str__(self): out = super(RequestUploadIqProtocolEntity, self).__str__() out += "Media Type: %s\n" % self.mediaType out += "B64Hash: %s\n" % self.b64Hash out += "Size: %s\n" % self.size if self.origHash: out += "OrigHash: %s\n" % self.origHash return out def toProtocolTreeNode(self): node = super(RequestUploadIqProtocolEntity, self).toProtocolTreeNode() attribs = { "hash": self.b64Hash, "type": self.mediaType, "size": str(self.size) } if self.origHash: attribs["orighash"] = self.origHash mediaNode = ProtocolTreeNode("encr_media", attribs) node.addChild(mediaNode) return node @staticmethod def fromProtocolTreeNode(node): assert node.getAttributeValue("type") == "set", "Expected set as iq type in request upload, got %s" % node.getAttributeValue("type") entity = IqProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = RequestUploadIqProtocolEntity mediaNode = node.getChild("encr_media") entity.setRequestArguments( mediaNode.getAttributeValue("type"), mediaNode.getAttributeValue("hash"), mediaNode.getAttributeValue("size"), mediaNode.getAttributeValue("orighash") ) return entity yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/iq_requestupload_result.py000066400000000000000000000042561346433372600317200ustar00rootroot00000000000000from yowsup.common import YowConstants from yowsup.layers.protocol_iq.protocolentities import ResultIqProtocolEntity from yowsup.structs import ProtocolTreeNode class ResultRequestUploadIqProtocolEntity(ResultIqProtocolEntity): def __init__(self, _id, url, ip = None, resumeOffset = 0, duplicate = False): super(ResultRequestUploadIqProtocolEntity, self).__init__(_id = _id, _from = YowConstants.WHATSAPP_SERVER) self.setUploadProps(url, ip, resumeOffset, duplicate) def setUploadProps(self, url ,ip = None, resumeOffset = 0, duplicate = False): self.url = url self.ip = ip self.resumeOffset = resumeOffset or 0 self.duplicate = duplicate def isDuplicate(self): return self.duplicate def getUrl(self): return self.url def getResumeOffset(self): return self.resumeOffset def getIp(self): return self.ip def __str__(self): out = super(ResultRequestUploadIqProtocolEntity, self).__str__() out += "URL: %s\n" % self.url if self.ip: out += "IP: %s\n" % self.ip return out def toProtocolTreeNode(self): node = super(ResultRequestUploadIqProtocolEntity, self).toProtocolTreeNode() if not self.isDuplicate(): mediaNode = ProtocolTreeNode("encr_media", {"url": self.url}) if self.ip: mediaNode["ip"] = self.ip if self.resumeOffset: mediaNode["resume"] = str(self.resumeOffset) else: mediaNode = ProtocolTreeNode("duplicate", {"url": self.url}) node.addChild(mediaNode) return node @staticmethod def fromProtocolTreeNode(node): entity= ResultIqProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = ResultRequestUploadIqProtocolEntity mediaNode = node.getChild("encr_media") if mediaNode: entity.setUploadProps(mediaNode["url"], mediaNode["ip"], mediaNode["resume"]) else: duplicateNode = node.getChild("duplicate") if duplicateNode: entity.setUploadProps(duplicateNode["url"], duplicateNode["ip"], duplicate = True) return entity yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/message_media.py000066400000000000000000000105441346433372600275140ustar00rootroot00000000000000from yowsup.layers.protocol_messages.protocolentities.protomessage import ProtomessageProtocolEntity from yowsup.layers.protocol_media.protocolentities.attributes.attributes_media import MediaAttributes from yowsup.layers.protocol_messages.protocolentities.attributes.attributes_message import MessageAttributes import logging logger = logging.getLogger(__name__) class MediaMessageProtocolEntity(ProtomessageProtocolEntity): TYPE_MEDIA_IMAGE = "image" TYPE_MEDIA_VIDEO = "video" TYPE_MEDIA_AUDIO = "audio" TYPE_MEDIA_CONTACT = "contact" TYPE_MEDIA_LOCATION = "location" TYPE_MEDIA_DOCUMENT = "document" TYPE_MEDIA_GIF = "gif" TYPE_MEDIA_PTT = "ptt" TYPE_MEDIA_URL = "url" TYPES_MEDIA = ( TYPE_MEDIA_IMAGE, TYPE_MEDIA_AUDIO, TYPE_MEDIA_VIDEO, TYPE_MEDIA_CONTACT, TYPE_MEDIA_LOCATION, TYPE_MEDIA_DOCUMENT, TYPE_MEDIA_GIF, TYPE_MEDIA_PTT, TYPE_MEDIA_URL ) def __init__(self, media_type, media_message_attrs, message_attrs): """ :type media_type: str :type media_message_attrs: MediaAttributes :type message_attrs: MessageAttributes """ super(MediaMessageProtocolEntity, self).__init__("media", message_attrs) self.media_type = media_type # type: str if media_message_attrs.context_info: self.context_stanza_id = media_message_attrs.context_info.stanza_id self.context_participant = media_message_attrs.context_info.participant self.context_quoted_message = media_message_attrs.context_info.quoted_message self.context_edit_version = media_message_attrs.context_info.edit_version self.context_remote_jid = media_message_attrs.context_info.remote_jid self.context_mentioned_jid = media_message_attrs.context_info.mentioned_jid self.context_revoke_message = media_message_attrs.context_info.revoke_message def __str__(self): out = super(MediaMessageProtocolEntity, self).__str__() out += "\nmediatype=%s" % self.media_type return out @property def context_stanza_id(self): return self.proto.stanza_id @context_stanza_id.setter def context_stanza_id(self, value): self.proto.context_info.stanza_id = value @property def context_participant(self): return self.proto.context_info.participant @context_participant.setter def context_participant(self, value): self.proto.context_info = value @property def context_quoted_message(self): return self.proto.context_info.quoted_message @context_quoted_message.setter def context_quoted_message(self, value): self.proto.context_info.quoted_message = value @property def context_edit_version(self): return self.proto.context_info.edit_version @context_edit_version.setter def context_edit_version(self, value): self.proto.context_info.edit_version = value @property def context_remote_jid(self): return self.proto.context_info.remote_jid @context_remote_jid.setter def context_remote_jid(self, value): self.proto.context_info.remote_jid = value @property def context_mentioned_jid(self): return self.proto.context_info.mentioned_jid @context_mentioned_jid.setter def context_mentioned_jid(self, value): self.proto.context_info.mentioned_jid = value @property def context_revoke_message(self): return self.proto.context_info.revoke_message @context_revoke_message.setter def context_revoke_message(self, value): self.proto.context_info.revoke_message = value @property def media_type(self): return self._media_type @media_type.setter def media_type(self, value): if value not in MediaMessageProtocolEntity.TYPES_MEDIA: logger.warn("media type: '%s' is not supported" % value) self._media_type = value def toProtocolTreeNode(self): node = super(MediaMessageProtocolEntity, self).toProtocolTreeNode() protoNode = node.getChild("proto") protoNode["mediatype"] = self.media_type return node @classmethod def fromProtocolTreeNode(cls, node): entity = ProtomessageProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = cls entity.media_type = node.getChild("proto")["mediatype"] return entity yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/message_media_contact.py000066400000000000000000000021241346433372600312220ustar00rootroot00000000000000from yowsup.layers.protocol_messages.protocolentities.attributes.attributes_message import MessageAttributes from .message_media import MediaMessageProtocolEntity from .attributes.attributes_contact import ContactAttributes from .attributes.attributes_media import MediaAttributes class ContactMediaMessageProtocolEntity(MediaMessageProtocolEntity): def __init__(self, contact_attrs, media_attrs, message_attrs): # type: (ContactAttributes, MediaAttributes, MessageAttributes) -> None super(ContactMediaMessageProtocolEntity, self).__init__("contact", media_attrs, message_attrs) self.display_name = contact_attrs.display_name self.vcard = contact_attrs.vcard @property def proto(self): return self._proto.contact_message @property def display_name(self): return self.proto.display_name @display_name.setter def display_name(self, value): self.proto.display_name = value @property def vcard(self): return self.proto.vcard @vcard.setter def vcard(self, value): self.proto.vcard = value yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/message_media_downloadable.py000066400000000000000000000034731346433372600322320ustar00rootroot00000000000000from .message_media import MediaMessageProtocolEntity from yowsup.layers.protocol_messages.protocolentities.attributes.attributes_message import MessageAttributes from yowsup.layers.protocol_media.protocolentities.attributes.attributes_downloadablemedia \ import DownloadableMediaMessageAttributes class DownloadableMediaMessageProtocolEntity(MediaMessageProtocolEntity): def __init__(self, media_type, downloadable_media_message_attrs, message_attrs): # type: (str, DownloadableMediaMessageAttributes, MessageAttributes) super(DownloadableMediaMessageProtocolEntity, self).__init__( media_type, downloadable_media_message_attrs, message_attrs ) self.url = downloadable_media_message_attrs.url self.mimetype = downloadable_media_message_attrs.mimetype self.file_sha256 = downloadable_media_message_attrs.file_sha256 self.file_length = downloadable_media_message_attrs.file_length self.media_key = downloadable_media_message_attrs.media_key @property def url(self): return self.proto.url @url.setter def url(self, value): self.proto.url = value @property def mimetype(self): return self.proto.mimetype @mimetype.setter def mimetype(self, value): self.proto.mimetype = value @property def file_sha256(self): return self.proto.file_sha256 @file_sha256.setter def file_sha256(self, value): self.proto.file_sha256 = value @property def file_length(self): return self.proto.file_length @file_length.setter def file_length(self, value): self.proto.file_length = value @property def media_key(self): return self.proto.media_key @media_key.setter def media_key(self, value): self.proto.media_key = value yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/message_media_downloadable_audio.py000066400000000000000000000027201346433372600334050ustar00rootroot00000000000000from .message_media_downloadable import DownloadableMediaMessageProtocolEntity from yowsup.layers.protocol_media.protocolentities.attributes.attributes_downloadablemedia \ import DownloadableMediaMessageAttributes from yowsup.layers.protocol_media.protocolentities.attributes.attributes_audio \ import AudioAttributes from yowsup.layers.protocol_messages.protocolentities.attributes.attributes_message import MessageAttributes class AudioDownloadableMediaMessageProtocolEntity(DownloadableMediaMessageProtocolEntity): def __init__(self, audio_attrs, downloadablemedia_attrs, message_attrs): """ :type audio_attrs: AudioAttributes :type downloadablemedia_attrs: DownloadableMediaMessageAttributes :type message_attrs: MessageAttributes """ super(AudioDownloadableMediaMessageProtocolEntity, self).__init__( "audio", downloadablemedia_attrs, message_attrs ) self.seconds = audio_attrs.seconds self.ptt = audio_attrs.ptt @property def proto(self): return self._proto.audio_message @property def seconds(self): return self.proto.seconds @seconds.setter def seconds(self, value): """ :type value: int """ self.proto.seconds = value @property def ptt(self): return self.proto.ptt @ptt.setter def ptt(self, value): """ :type value: bool """ self.proto.ptt = value yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/message_media_downloadable_document.py000066400000000000000000000044551346433372600341310ustar00rootroot00000000000000from .message_media_downloadable import DownloadableMediaMessageProtocolEntity from yowsup.layers.protocol_media.protocolentities.attributes.attributes_downloadablemedia \ import DownloadableMediaMessageAttributes from yowsup.layers.protocol_media.protocolentities.attributes.attributes_document \ import DocumentAttributes from yowsup.layers.protocol_messages.protocolentities.attributes.attributes_message import MessageAttributes class DocumentDownloadableMediaMessageProtocolEntity(DownloadableMediaMessageProtocolEntity): def __init__(self, document_attrs, downloadablemedia_attrs, message_attrs): """ :type document_attrs: DocumentAttributes :type downloadablemedia_attrs: DownloadableMediaMessageAttributes :type message_attrs: MessageAttributes """ super(DocumentDownloadableMediaMessageProtocolEntity, self).__init__( "document", downloadablemedia_attrs, message_attrs ) self.file_name = document_attrs.file_name self.file_length = document_attrs.file_length if document_attrs.title is not None: self.title = document_attrs.title if document_attrs.page_count is not None: self.page_count = document_attrs.page_count if document_attrs.jpeg_thumbnail is not None: self.jpeg_thumbnail = document_attrs.jpeg_thumbnail @property def proto(self): return self._proto.document_message @property def file_name(self): return self.proto.file_name @file_name.setter def file_name(self, value): self.proto.file_name = value @property def file_length(self): return self.proto.file_length @file_length.setter def file_length(self, value): self.proto.file_length = value @property def title(self): return self.proto.title @title.setter def title(self, value): self.proto.title = value @property def page_count(self): return self.proto.page_count @page_count.setter def page_count(self, value): self.proto.page_count = value @property def jpeg_thumbnail(self): return self.proto.image_message.jpeg_thumbnail @jpeg_thumbnail.setter def jpeg_thumbnail(self, value): self.proto.image_message.jpeg_thumbnail = value yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/message_media_downloadable_image.py000066400000000000000000000034211346433372600333650ustar00rootroot00000000000000from .message_media_downloadable import DownloadableMediaMessageProtocolEntity from yowsup.layers.protocol_media.protocolentities.attributes.attributes_downloadablemedia \ import DownloadableMediaMessageAttributes from yowsup.layers.protocol_media.protocolentities.attributes.attributes_image import ImageAttributes from yowsup.layers.protocol_messages.protocolentities.attributes.attributes_message import MessageAttributes class ImageDownloadableMediaMessageProtocolEntity(DownloadableMediaMessageProtocolEntity): def __init__(self, image_attrs, downloadablemedia_attrs, message_attrs): # type: (ImageAttributes, DownloadableMediaMessageAttributes, MessageAttributes) -> None super(ImageDownloadableMediaMessageProtocolEntity, self).__init__( "image", downloadablemedia_attrs, message_attrs ) self.width = image_attrs.width self.height = image_attrs.height self.caption = image_attrs.caption self.jpeg_thumbnail = image_attrs.jpeg_thumbnail @property def proto(self): return self._proto.image_message @property def width(self): return self.proto.width @width.setter def width(self, value): self.proto.width = value @property def height(self): return self.proto.height @height.setter def height(self, value): self.proto.height = value @property def jpeg_thumbnail(self): return self.proto.jpeg_thumbnail @jpeg_thumbnail.setter def jpeg_thumbnail(self, value): self.proto.jpeg_thumbnail = value if value is not None else b"" @property def caption(self): return self.proto.caption @caption.setter def caption(self, value): self.proto.caption = value if value is not None else "" yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/message_media_downloadable_video.py000066400000000000000000000057711346433372600334230ustar00rootroot00000000000000from .message_media_downloadable import DownloadableMediaMessageProtocolEntity from yowsup.layers.protocol_media.protocolentities.attributes.attributes_downloadablemedia \ import DownloadableMediaMessageAttributes from yowsup.layers.protocol_media.protocolentities.attributes.attributes_video import VideoAttributes from yowsup.layers.protocol_messages.protocolentities.attributes.attributes_message import MessageAttributes class VideoDownloadableMediaMessageProtocolEntity(DownloadableMediaMessageProtocolEntity): def __init__(self, video_attrs, downloadablemedia_attrs, message_attrs): """ :type video_attrs: VideoAttributes :type downloadablemedia_attrs: DownloadableMediaMessageAttributes :type message_attrs: MessageAttributes """ super(VideoDownloadableMediaMessageProtocolEntity, self).__init__( "video", downloadablemedia_attrs, message_attrs ) self.width = video_attrs.width self.height = video_attrs.height self.seconds = video_attrs.seconds if video_attrs.caption is not None: self.caption = video_attrs.caption self.gif_playback = video_attrs.gif_playback if video_attrs.gif_playback else False if video_attrs.jpeg_thumbnail is not None: self.jpeg_thumbnail = video_attrs.jpeg_thumbnail if video_attrs.gif_attribution is not None: self.gif_attribution = video_attrs.gif_attribution if video_attrs.streaming_sidecar is not None: self.streaming_sidecar = video_attrs.streaming_sidecar @property def proto(self): return self._proto.video_message @property def width(self): return self._proto.width @width.setter def width(self, value): self.proto.width = value @property def height(self): return self.proto.height @height.setter def height(self, value): self.proto.height = value @property def seconds(self): return self.proto.seconds @seconds.setter def seconds(self, value): self.proto.seconds = value @property def gif_playback(self): return self.proto.gif_playback @gif_playback.setter def gif_playback(self, value): self.proto.gif_playback = value @property def jpeg_thumbnail(self): return self._proto.jpeg_thumbnail @jpeg_thumbnail.setter def jpeg_thumbnail(self, value): self.proto.jpeg_thumbnail = value @property def caption(self): return self.proto.caption @caption.setter def caption(self, value): self.proto.caption = value @property def gif_attribution(self): return self.proto.gif_attribution @gif_attribution.setter def gif_attribution(self, value): self.proto.gif_attributions = value @property def streaming_sidecar(self): return self.proto.streaming_sidecar @streaming_sidecar.setter def streaming_sidecar(self, value): self.proto.streaming_sidecar = value yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/message_media_extendedtext.py000066400000000000000000000040471346433372600323020ustar00rootroot00000000000000from yowsup.layers.protocol_messages.protocolentities.attributes.attributes_message import MessageAttributes from .message_media import MediaMessageProtocolEntity from .attributes.attributes_extendedtext import ExtendedTextAttributes from .attributes.attributes_media import MediaAttributes class ExtendedTextMediaMessageProtocolEntity(MediaMessageProtocolEntity): def __init__(self, extended_text_attrs, media_attrs, message_attrs): # type: (ExtendedTextAttributes, MediaAttributes, MessageAttributes) -> None super(ExtendedTextMediaMessageProtocolEntity, self).__init__("url", media_attrs, message_attrs) self.text = extended_text_attrs.text self.matched_text = extended_text_attrs.matched_text self.canonical_url = extended_text_attrs.canonical_url self.description = extended_text_attrs.description self.title = extended_text_attrs.title self.jpeg_thumbnail = extended_text_attrs.jpeg_thumbnail @property def proto(self): return self._proto.extended_text_message @property def text(self): return self.proto.text @text.setter def text(self, value): self.proto.text = value @property def matched_text(self): return self.proto.matched_text @matched_text.setter def matched_text(self, value): self.proto.matched_text = value @property def canonical_url(self): return self.proto.canonical_url @canonical_url.setter def canonical_url(self, value): self.proto.canonical_url = value @property def description(self): return self.proto.description @description.setter def description(self, value): self.proto.description = value @property def title(self): return self.proto.title @title.setter def title(self, value): self.proto.title = value @property def jpeg_thumbnail(self): return self.proto.jpeg_thumbnail @jpeg_thumbnail.setter def jpeg_thumbnail(self, value): self.proto.jpeg_thumbnail = value yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/message_media_location.py000066400000000000000000000070631346433372600314060ustar00rootroot00000000000000from yowsup.layers.protocol_messages.protocolentities.attributes.attributes_message import MessageAttributes from .message_media import MediaMessageProtocolEntity from .attributes.attributes_location import LocationAttributes from .attributes.attributes_media import MediaAttributes class LocationMediaMessageProtocolEntity(MediaMessageProtocolEntity): def __init__(self, location_attrs, media_message_attrs, message_attrs): # type: (LocationAttributes, MediaAttributes, MessageAttributes) -> None super(LocationMediaMessageProtocolEntity, self).__init__("location", media_message_attrs, message_attrs) self.degrees_latitude = location_attrs.degrees_latitude self.degrees_longitude = location_attrs.degrees_longitude self.name = location_attrs.name self.address = location_attrs.address self.url = location_attrs.url self.duration = location_attrs.duration self.accuracy_in_meters = location_attrs.accuracy_in_meters self.speed_in_mps = location_attrs.speed_in_mps self.degrees_clockwise_from_magnetic_north = location_attrs.degrees_clockwise_from_magnetic_north self.axolotl_sender_key_distribution_message = location_attrs.axolotl_sender_key_distribution_message self.jpeg_thumbnail = location_attrs.jpeg_thumbnail @property def proto(self): return self._proto.location_message @property def degrees_latitude(self): return self.proto.degrees_latitude @degrees_latitude.setter def degrees_latitude(self, value): self.proto.degrees_latitude = value @property def degrees_longitude(self): return self.proto.degrees_longitude @degrees_longitude.setter def degrees_longitude(self, value): self.proto.degrees_longitude = value @property def name(self): return self.proto.name @name.setter def name(self, value): self.proto.name = value @property def address(self): return self.proto.addrees @address.setter def address(self, value): self.proto.address = value @property def url(self): return self.proto.url @url.setter def url(self, value): self.proto.url = value @property def duration(self): return self.proto.duration @duration.setter def duration(self, value): self.proto.duration = value @property def accuracy_in_meters(self): return self.proto.accuracy_in_meters @accuracy_in_meters.setter def accuracy_in_meters(self, value): self.proto.accuracy_in_meters = value @property def speed_in_mps(self): return self.proto.speed_in_mps @speed_in_mps.setter def speed_in_mps(self, value): self.proto.speed_in_mps = value @property def degrees_clockwise_from_magnetic_north(self): return self.proto.degrees_clockwise_from_magnetic_north @degrees_clockwise_from_magnetic_north.setter def degrees_clockwise_from_magnetic_north(self, value): self.proto.degrees_clockwise_from_magnetic_north = value @property def axolotl_sender_key_distribution_message(self): return self.proto.axolotl_sender_key_distribution_message @axolotl_sender_key_distribution_message.setter def axolotl_sender_key_distribution_message(self, value): self.proto.axolotl_sender_key_distribution_message = value @property def jpeg_thumbnail(self): return self.proto.jpeg_thumbnail @jpeg_thumbnail.setter def jpeg_thumbnail(self, value): self.proto.jpeg_thumbnail = value yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/test_iq_requestupload.py000066400000000000000000000011701346433372600313510ustar00rootroot00000000000000from yowsup.layers.protocol_iq.protocolentities.test_iq import IqProtocolEntityTest from yowsup.layers.protocol_media.protocolentities import RequestUploadIqProtocolEntity from yowsup.structs import ProtocolTreeNode class RequestUploadIqProtocolEntityTest(IqProtocolEntityTest): def setUp(self): super(RequestUploadIqProtocolEntityTest, self).setUp() mediaNode = ProtocolTreeNode("encr_media", {"hash": "hash", "size": "1234", "orighash": "orighash", "type": "image"}) self.ProtocolEntity = RequestUploadIqProtocolEntity self.node.setAttribute("type", "set") self.node.addChild(mediaNode)yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/test_iq_requestupload_result.py000066400000000000000000000011131346433372600327440ustar00rootroot00000000000000from yowsup.layers.protocol_iq.protocolentities.test_iq_result import ResultIqProtocolEntityTest from yowsup.layers.protocol_media.protocolentities import ResultRequestUploadIqProtocolEntity from yowsup.structs import ProtocolTreeNode class ResultRequestUploadIqProtocolEntityTest(ResultIqProtocolEntityTest): def setUp(self): super(ResultRequestUploadIqProtocolEntityTest, self).setUp() mediaNode = ProtocolTreeNode("encr_media", {"url": "url", "ip": "1.2.3.4"}) self.ProtocolEntity = ResultRequestUploadIqProtocolEntity self.node.addChild(mediaNode)yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/test_message_media.py000066400000000000000000000012251346433372600305470ustar00rootroot00000000000000from yowsup.layers.protocol_media.protocolentities.message_media import MediaMessageProtocolEntity from yowsup.layers.protocol_messages.protocolentities.test_message import MessageProtocolEntityTest from yowsup.structs import ProtocolTreeNode from yowsup.layers.protocol_messages.proto.e2e_pb2 import Message class MediaMessageProtocolEntityTest(MessageProtocolEntityTest): def setUp(self): super(MediaMessageProtocolEntityTest, self).setUp() self.ProtocolEntity = MediaMessageProtocolEntity proto_node = ProtocolTreeNode("proto", {"mediatype": "image"}, None, Message().SerializeToString()) self.node.addChild(proto_node) yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/test_message_media_contact.py000066400000000000000000000015311346433372600322620ustar00rootroot00000000000000from yowsup.layers.protocol_media.protocolentities.test_message_media import MediaMessageProtocolEntityTest from yowsup.layers.protocol_media.protocolentities import ContactMediaMessageProtocolEntity from yowsup.layers.protocol_messages.proto.e2e_pb2 import Message class ContactMediaMessageProtocolEntityTest(MediaMessageProtocolEntityTest): def setUp(self): super(ContactMediaMessageProtocolEntityTest, self).setUp() self.ProtocolEntity = ContactMediaMessageProtocolEntity m = Message() contact_message = Message.ContactMessage() contact_message.display_name = "abc" contact_message.vcard = b"VCARD_DATA" m.contact_message.MergeFrom(contact_message) proto_node = self.node.getChild("proto") proto_node["mediatype"] = "contact" proto_node.setData(m.SerializeToString()) yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/test_message_media_downloadable_audio.py000066400000000000000000000017761346433372600344560ustar00rootroot00000000000000from yowsup.layers.protocol_media.protocolentities.message_media_downloadable_audio import AudioDownloadableMediaMessageProtocolEntity from yowsup.layers.protocol_messages.proto.e2e_pb2 import Message from .test_message_media import MediaMessageProtocolEntityTest class AudioDownloadableMediaMessageProtocolEntityTest(MediaMessageProtocolEntityTest): def setUp(self): super(AudioDownloadableMediaMessageProtocolEntityTest, self).setUp() self.ProtocolEntity = AudioDownloadableMediaMessageProtocolEntity proto_node = self.node.getChild("proto") m = Message() media_message = Message.AudioMessage() media_message.url = "url" media_message.mimetype = "audio/ogg" media_message.file_sha256 = b"SHA256" media_message.file_length = 123 media_message.media_key = b"MEDIA_KEY" media_message.seconds = 24 media_message.ptt = True m.audio_message.MergeFrom(media_message) proto_node.setData(m.SerializeToString()) yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/test_message_media_downloadable_image.py000066400000000000000000000021421346433372600344230ustar00rootroot00000000000000from yowsup.layers.protocol_media.protocolentities.message_media_downloadable_image \ import ImageDownloadableMediaMessageProtocolEntity from .test_message_media import MediaMessageProtocolEntityTest from yowsup.layers.protocol_messages.proto.e2e_pb2 import Message class ImageDownloadableMediaMessageProtocolEntityTest(MediaMessageProtocolEntityTest): def setUp(self): super(ImageDownloadableMediaMessageProtocolEntityTest, self).setUp() self.ProtocolEntity = ImageDownloadableMediaMessageProtocolEntity proto_node = self.node.getChild("proto") m = Message() media_message = Message.ImageMessage() media_message.url = "url" media_message.mimetype = "image/jpeg" media_message.caption = "caption" media_message.file_sha256 = b"SHA256" media_message.file_length = 123 media_message.height = 20 media_message.width = 20 media_message.media_key = b"MEDIA_KEY" media_message.jpeg_thumbnail = b"THUMBNAIL" m.image_message.MergeFrom(media_message) proto_node.setData(m.SerializeToString()) yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/test_message_media_downloadable_video.py000066400000000000000000000021411346433372600344460ustar00rootroot00000000000000from yowsup.layers.protocol_media.protocolentities.message_media_downloadable_video \ import VideoDownloadableMediaMessageProtocolEntity from yowsup.layers.protocol_messages.proto.e2e_pb2 import Message from .test_message_media import MediaMessageProtocolEntityTest class VideoDownloadableMediaMessageProtocolEntityTest(MediaMessageProtocolEntityTest): def setUp(self): super(VideoDownloadableMediaMessageProtocolEntityTest, self).setUp() self.ProtocolEntity = VideoDownloadableMediaMessageProtocolEntity proto_node = self.node.getChild("proto") m = Message() media_message = Message.VideoMessage() media_message.url = "url" media_message.mimetype = "video/mp4" media_message.caption = "caption" media_message.file_sha256 = b"SHA256" media_message.file_length = 123 media_message.height = 20 media_message.width = 20 media_message.media_key = b"MEDIA_KEY" media_message.jpeg_thumbnail = b"THUMBNAIL" m.video_message.MergeFrom(media_message) proto_node.setData(m.SerializeToString()) yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/test_message_media_extendedtext.py000066400000000000000000000030761346433372600333420ustar00rootroot00000000000000from yowsup.layers.protocol_media.protocolentities.test_message_media import MediaMessageProtocolEntityTest from yowsup.layers.protocol_media.protocolentities import ExtendedTextMediaMessageProtocolEntity from yowsup.layers.protocol_messages.proto.e2e_pb2 import Message class ExtendedTextMediaMessageProtocolEntityTest(MediaMessageProtocolEntityTest): def setUp(self): super(ExtendedTextMediaMessageProtocolEntityTest, self).setUp() self.ProtocolEntity = ExtendedTextMediaMessageProtocolEntity m = Message() media_message = Message.ExtendedTextMessage() media_message.canonical_url = "url" media_message.text = "text" media_message.matched_text = "matched_text" media_message.description = "desc" media_message.title = "title" media_message.jpeg_thumbnail = b"thumb" m.extended_text_message.MergeFrom(media_message) proto_node = self.node.getChild("proto") proto_node["mediatype"] = "url" proto_node.setData(m.SerializeToString()) self._entity = ExtendedTextMediaMessageProtocolEntity\ .fromProtocolTreeNode(self.node) # type: ExtendedTextMediaMessageProtocolEntity def test_properties(self): self.assertEqual("url", self._entity.canonical_url) self.assertEqual("text", self._entity.text) self.assertEqual("matched_text", self._entity.matched_text) self.assertEqual("desc", self._entity.description) self.assertEqual("title", self._entity.title) self.assertEqual(b"thumb", self._entity.jpeg_thumbnail) yowsup-3.2.3/yowsup/layers/protocol_media/protocolentities/test_message_media_location.py000066400000000000000000000017071346433372600324440ustar00rootroot00000000000000from yowsup.layers.protocol_media.protocolentities.test_message_media import MediaMessageProtocolEntityTest from yowsup.layers.protocol_media.protocolentities import LocationMediaMessageProtocolEntity from yowsup.layers.protocol_messages.proto.e2e_pb2 import Message class LocationMediaMessageProtocolEntityTest(MediaMessageProtocolEntityTest): def setUp(self): super(LocationMediaMessageProtocolEntityTest, self).setUp() self.ProtocolEntity = LocationMediaMessageProtocolEntity m = Message() location_message = Message.LocationMessage() location_message.degrees_latitude = 30.089037 location_message.degrees_longitude = 31.319488 location_message.name = "kaos" location_message.url = "kaos_url" m.location_message.MergeFrom(location_message) proto_node = self.node.getChild("proto") proto_node["mediatype"] = "location" proto_node.setData(m.SerializeToString())yowsup-3.2.3/yowsup/layers/protocol_media/test_mediacipher.py000066400000000000000000000053161346433372600246350ustar00rootroot00000000000000from yowsup.layers.protocol_media.mediacipher import MediaCipher import base64 import unittest class MediaCipherTest(unittest.TestCase): IMAGE = ( b'EOnnZIBu1vTSI51IeJvaKR+8W1FqBETATI2Ikl6nVQ8=', b'/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8M' b'CgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQ' b'EBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAABAAEDAREAAhEBAxEB/8QAHwAAAQUBAQEB' b'AQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKB' b'kaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1' b'dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl' b'5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcF' b'BAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5' b'OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0' b'tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD9U6AP/9k' b'==', b'dT9YPFSz4dprkH6uiXPEVERGZVIZbGYHzwue21WoLP1RCE2wmu11M8n6ysfROPtI39DCRFQhBBEVGFCT/nfV' b'pt+fouIENBSXY44mR2en4HGvRR//dlM5OBLz2WuEOf01iKPazGtfacy6lnV0X5JagL4r1mKeyuSXJEV81kxj' b'Vd3OArpLKt13XM36PcnTd/U6DHOV6Vf982Wc1UjR7kMb5JT+HlWrvz9CCGMTX5mqBYWEr3InCFyrmaZu8DXC' b'60YUZCPLTHJP0hFQA1ooKQks4f3F39tzVL3dbX3io7XPQiSgHN6nuPCD0PF7dWINep+amk+ODjeQd/o2guqx' b'O/AngNIxfFWq3915jMQWAXeARUFw7x+9Qx93UWC/sfQ72nTqdQaH5W4vsMUKaocZcAJ7YWudKo5Y15uo3ulP' b'744Cyo54tvxUSV0zLC90LYCe8fJefREjreO73RlVqoynTyFHuVS7/YMnesO5lCHZJ2NpHuzpGKCU08RgCuSr' b'K/wh4SLXZ1nhZEYX/xY4cDO7swrA3Y3Qt0gjFzNBfUT9aABQaU+WHY8pBS/oVfJsuj2iod2fsW8UoplImoOk' b'bosYlMkdZSIfwBQ5kt3On2d+HPUNt7HVZWRECFj0C4IHhZCZIJw0wFmPMOiIHyzittXGb45uJA2Sd1gnRbw0' b'1XFuoIyvS7z0MtW0QUiD6kaJFBkpTo7hxN/HyN8xQwOkeBcKORdpeSp62iPBuRvel9I2p07it7UyYhzas+Jv' b'tl6i+hIz6Z5nzQEZ+zPAYxDmoy4h9GQuXUivTzU9I0/Sd4QvM3rfewGeXsNSjWI1CLVZG+4wL1TPCbQGaHEB' b'NF8zmpTMYV+NvCzv/2DwYuYoiUI=' ) def setUp(self): self._cipher = MediaCipher() # type: MediaCipher def test_decrypt_image(self): media_key, media_plaintext, media_ciphertext = map(base64.b64decode, self.IMAGE) self.assertEqual(media_plaintext, self._cipher.decrypt_image(media_ciphertext, media_key)) def test_encrypt_image(self): media_key, media_plaintext, media_ciphertext = map(base64.b64decode, self.IMAGE) encrypted = self._cipher.encrypt(media_plaintext, media_key, MediaCipher.INFO_IMAGE) self.assertEqual(media_ciphertext, encrypted) yowsup-3.2.3/yowsup/layers/protocol_messages/000077500000000000000000000000001346433372600214755ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_messages/__init__.py000066400000000000000000000000541346433372600236050ustar00rootroot00000000000000from .layer import YowMessagesProtocolLayer yowsup-3.2.3/yowsup/layers/protocol_messages/layer.py000066400000000000000000000014471346433372600231710ustar00rootroot00000000000000from yowsup.layers import YowProtocolLayer from .protocolentities import TextMessageProtocolEntity class YowMessagesProtocolLayer(YowProtocolLayer): def __init__(self): handleMap = { "message": (self.recvMessageStanza, self.sendMessageEntity) } super(YowMessagesProtocolLayer, self).__init__(handleMap) def __str__(self): return "Messages Layer" def sendMessageEntity(self, entity): if entity.getType() == "text": self.entityToLower(entity) ###recieved node handlers handlers def recvMessageStanza(self, node): protoNode = node.getChild("proto") if protoNode: if protoNode and protoNode["mediatype"] is None: self.toUpper(TextMessageProtocolEntity.fromProtocolTreeNode(node)) yowsup-3.2.3/yowsup/layers/protocol_messages/proto/000077500000000000000000000000001346433372600226405ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_messages/proto/__init__.py000066400000000000000000000000001346433372600247370ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_messages/proto/e2e_pb2.py000066400000000000000000001647311346433372600244440ustar00rootroot00000000000000# Generated by the protocol buffer compiler. DO NOT EDIT! # source: e2e.proto import sys _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() from . import protocol_pb2 as protocol__pb2 DESCRIPTOR = _descriptor.FileDescriptor( name='e2e.proto', package='', syntax='proto2', serialized_options=None, serialized_pb=_b('\n\te2e.proto\x1a\x0eprotocol.proto\"\xb0\x01\n\x0b\x43ontextInfo\x12\x11\n\tstanza_id\x18\x01 \x01(\t\x12\x13\n\x0bparticipant\x18\x02 \x01(\t\x12 \n\x0equoted_message\x18\x03 \x01(\x0b\x32\x08.Message\x12\x12\n\nremote_jid\x18\x04 \x01(\t\x12\x15\n\rmentioned_jid\x18\x0f \x03(\t\x12\x14\n\x0c\x65\x64it_version\x18\x10 \x01(\r\x12\x16\n\x0erevoke_message\x18\x11 \x01(\x08\"\xce\x16\n\x07Message\x12\x14\n\x0c\x63onversation\x18\x01 \x01(\t\x12N\n\x1fsender_key_distribution_message\x18\x02 \x01(\x0b\x32%.Message.SenderKeyDistributionMessage\x12,\n\rimage_message\x18\x03 \x01(\x0b\x32\x15.Message.ImageMessage\x12\x30\n\x0f\x63ontact_message\x18\x04 \x01(\x0b\x32\x17.Message.ContactMessage\x12\x32\n\x10location_message\x18\x05 \x01(\x0b\x32\x18.Message.LocationMessage\x12;\n\x15\x65xtended_text_message\x18\x06 \x01(\x0b\x32\x1c.Message.ExtendedTextMessage\x12\x32\n\x10\x64ocument_message\x18\x07 \x01(\x0b\x32\x18.Message.DocumentMessage\x12,\n\raudio_message\x18\x08 \x01(\x0b\x32\x15.Message.AudioMessage\x12,\n\rvideo_message\x18\t \x01(\x0b\x32\x15.Message.VideoMessage\x12\x1b\n\x04\x63\x61ll\x18\n \x01(\x0b\x32\r.Message.Call\x12\x1b\n\x04\x63hat\x18\x0b \x01(\x0b\x32\r.Message.Chat\x12\x32\n\x10protocol_message\x18\x0c \x01(\x0b\x32\x18.Message.ProtocolMessage\x12=\n\x16\x63ontacts_array_message\x18\r \x01(\x0b\x32\x1d.Message.ContactsArrayMessage\x12\x43\n\x19highly_structured_message\x18\x0e \x01(\x0b\x32 .Message.HighlyStructuredMessage\x1a\x61\n\x1cSenderKeyDistributionMessage\x12\x10\n\x08group_id\x18\x01 \x01(\t\x12/\n\'axolotl_sender_key_distribution_message\x18\x02 \x01(\x0c\x1a\xd6\x01\n\x0cImageMessage\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x10\n\x08mimetype\x18\x02 \x01(\t\x12\x0f\n\x07\x63\x61ption\x18\x03 \x01(\t\x12\x13\n\x0b\x66ile_sha256\x18\x04 \x01(\x0c\x12\x13\n\x0b\x66ile_length\x18\x05 \x01(\x04\x12\x0e\n\x06height\x18\x06 \x01(\r\x12\r\n\x05width\x18\x07 \x01(\r\x12\x11\n\tmedia_key\x18\x08 \x01(\x0c\x12\x16\n\x0ejpeg_thumbnail\x18\x10 \x01(\x0c\x12\"\n\x0c\x63ontext_info\x18\x11 \x01(\x0b\x32\x0c.ContextInfo\x1aY\n\x0e\x43ontactMessage\x12\x14\n\x0c\x64isplay_name\x18\x01 \x01(\t\x12\r\n\x05vcard\x18\x10 \x01(\x0c\x12\"\n\x0c\x63ontext_info\x18\x11 \x01(\x0b\x32\x0c.ContextInfo\x1a\xd2\x02\n\x0fLocationMessage\x12\x18\n\x10\x64\x65grees_latitude\x18\x01 \x01(\x01\x12\x19\n\x11\x64\x65grees_longitude\x18\x02 \x01(\x01\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\x0f\n\x07\x61\x64\x64ress\x18\x04 \x01(\t\x12\x0b\n\x03url\x18\x05 \x01(\t\x12\x10\n\x08\x64uration\x18\x06 \x01(\x02\x12\x1a\n\x12\x61\x63\x63uracy_in_meters\x18\x07 \x01(\r\x12\x14\n\x0cspeed_in_mps\x18\x08 \x01(\x02\x12-\n%degrees_clockwise_from_magnetic_north\x18\t \x01(\r\x12/\n\'axolotl_sender_key_distribution_message\x18\n \x01(\x0c\x12\x16\n\x0ejpeg_thumbnail\x18\x10 \x01(\x0c\x12\"\n\x0c\x63ontext_info\x18\x11 \x01(\x0b\x32\x0c.ContextInfo\x1a\xb0\x01\n\x13\x45xtendedTextMessage\x12\x0c\n\x04text\x18\x01 \x01(\t\x12\x14\n\x0cmatched_text\x18\x02 \x01(\t\x12\x15\n\rcanonical_url\x18\x04 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x05 \x01(\t\x12\r\n\x05title\x18\x06 \x01(\t\x12\x16\n\x0ejpeg_thumbnail\x18\x10 \x01(\x0c\x12\"\n\x0c\x63ontext_info\x18\x11 \x01(\x0b\x32\x0c.ContextInfo\x1a\xdf\x01\n\x0f\x44ocumentMessage\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x10\n\x08mimetype\x18\x02 \x01(\t\x12\r\n\x05title\x18\x03 \x01(\t\x12\x13\n\x0b\x66ile_sha256\x18\x04 \x01(\x0c\x12\x13\n\x0b\x66ile_length\x18\x05 \x01(\x04\x12\x12\n\npage_count\x18\x06 \x01(\r\x12\x11\n\tmedia_key\x18\x07 \x01(\x0c\x12\x11\n\tfile_name\x18\x08 \x01(\t\x12\x16\n\x0ejpeg_thumbnail\x18\x10 \x01(\x0c\x12\"\n\x0c\x63ontext_info\x18\x11 \x01(\x0b\x32\x0c.ContextInfo\x1a\xc7\x01\n\x0c\x41udioMessage\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x10\n\x08mimetype\x18\x02 \x01(\t\x12\x13\n\x0b\x66ile_sha256\x18\x03 \x01(\x0c\x12\x13\n\x0b\x66ile_length\x18\x04 \x01(\x04\x12\x0f\n\x07seconds\x18\x05 \x01(\r\x12\x0b\n\x03ptt\x18\x06 \x01(\x08\x12\x11\n\tmedia_key\x18\x07 \x01(\x0c\x12\"\n\x0c\x63ontext_info\x18\x11 \x01(\x0b\x32\x0c.ContextInfo\x12\x19\n\x11streaming_sidecar\x18\x12 \x01(\x0c\x1a\x89\x03\n\x0cVideoMessage\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x10\n\x08mimetype\x18\x02 \x01(\t\x12\x13\n\x0b\x66ile_sha256\x18\x03 \x01(\x0c\x12\x13\n\x0b\x66ile_length\x18\x04 \x01(\x04\x12\x0f\n\x07seconds\x18\x05 \x01(\r\x12\x11\n\tmedia_key\x18\x06 \x01(\x0c\x12\x0f\n\x07\x63\x61ption\x18\x07 \x01(\t\x12\x14\n\x0cgif_playback\x18\x08 \x01(\x08\x12\x0e\n\x06height\x18\t \x01(\r\x12\r\n\x05width\x18\n \x01(\r\x12\x16\n\x0ejpeg_thumbnail\x18\x10 \x01(\x0c\x12\"\n\x0c\x63ontext_info\x18\x11 \x01(\x0b\x32\x0c.ContextInfo\x12\x19\n\x11streaming_sidecar\x18\x12 \x01(\x0c\x12@\n\x0fgif_attribution\x18\x13 \x01(\x0e\x32!.Message.VideoMessage.Attribution:\x04NONE\"-\n\x0b\x41ttribution\x12\x08\n\x04NONE\x10\x00\x12\t\n\x05GIPHY\x10\x01\x12\t\n\x05TENOR\x10\x02\x1a\x18\n\x04\x43\x61ll\x12\x10\n\x08\x63\x61ll_key\x18\x01 \x01(\x0c\x1a(\n\x04\x43hat\x12\x14\n\x0c\x64isplay_name\x18\x01 \x01(\t\x12\n\n\x02id\x18\x02 \x01(\t\x1at\n\x0fProtocolMessage\x12\x18\n\x03key\x18\x01 \x01(\x0b\x32\x0b.MessageKey\x12\x33\n\x04type\x18\x02 \x01(\x0e\x32\x1d.Message.ProtocolMessage.Type:\x06REVOKE\"\x12\n\x04Type\x12\n\n\x06REVOKE\x10\x00\x1a{\n\x14\x43ontactsArrayMessage\x12\x14\n\x0c\x64isplay_name\x18\x01 \x01(\t\x12)\n\x08\x63ontacts\x18\x02 \x03(\x0b\x32\x17.Message.ContactMessage\x12\"\n\x0c\x63ontext_info\x18\x11 \x01(\x0b\x32\x0c.ContextInfo\x1a|\n\x17HighlyStructuredMessage\x12\x11\n\tnamespace\x18\x01 \x01(\t\x12\x14\n\x0c\x65lement_name\x18\x02 \x01(\t\x12\x0e\n\x06params\x18\x03 \x03(\t\x12\x13\n\x0b\x66\x61llback_lg\x18\x04 \x01(\t\x12\x13\n\x0b\x66\x61llback_lc\x18\x05 \x01(\t') , dependencies=[protocol__pb2.DESCRIPTOR,]) _MESSAGE_VIDEOMESSAGE_ATTRIBUTION = _descriptor.EnumDescriptor( name='Attribution', full_name='Message.VideoMessage.Attribution', filename=None, file=DESCRIPTOR, values=[ _descriptor.EnumValueDescriptor( name='NONE', index=0, number=0, serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='GIPHY', index=1, number=1, serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='TENOR', index=2, number=2, serialized_options=None, type=None), ], containing_type=None, serialized_options=None, serialized_start=2621, serialized_end=2666, ) _sym_db.RegisterEnumDescriptor(_MESSAGE_VIDEOMESSAGE_ATTRIBUTION) _MESSAGE_PROTOCOLMESSAGE_TYPE = _descriptor.EnumDescriptor( name='Type', full_name='Message.ProtocolMessage.Type', filename=None, file=DESCRIPTOR, values=[ _descriptor.EnumValueDescriptor( name='REVOKE', index=0, number=0, serialized_options=None, type=None), ], containing_type=None, serialized_options=None, serialized_start=2834, serialized_end=2852, ) _sym_db.RegisterEnumDescriptor(_MESSAGE_PROTOCOLMESSAGE_TYPE) _CONTEXTINFO = _descriptor.Descriptor( name='ContextInfo', full_name='ContextInfo', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='stanza_id', full_name='ContextInfo.stanza_id', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='participant', full_name='ContextInfo.participant', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='quoted_message', full_name='ContextInfo.quoted_message', index=2, number=3, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='remote_jid', full_name='ContextInfo.remote_jid', index=3, number=4, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='mentioned_jid', full_name='ContextInfo.mentioned_jid', index=4, number=15, type=9, cpp_type=9, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='edit_version', full_name='ContextInfo.edit_version', index=5, number=16, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='revoke_message', full_name='ContextInfo.revoke_message', index=6, number=17, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], serialized_options=None, is_extendable=False, syntax='proto2', extension_ranges=[], oneofs=[ ], serialized_start=30, serialized_end=206, ) _MESSAGE_SENDERKEYDISTRIBUTIONMESSAGE = _descriptor.Descriptor( name='SenderKeyDistributionMessage', full_name='Message.SenderKeyDistributionMessage', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='group_id', full_name='Message.SenderKeyDistributionMessage.group_id', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='axolotl_sender_key_distribution_message', full_name='Message.SenderKeyDistributionMessage.axolotl_sender_key_distribution_message', index=1, number=2, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], serialized_options=None, is_extendable=False, syntax='proto2', extension_ranges=[], oneofs=[ ], serialized_start=917, serialized_end=1014, ) _MESSAGE_IMAGEMESSAGE = _descriptor.Descriptor( name='ImageMessage', full_name='Message.ImageMessage', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='url', full_name='Message.ImageMessage.url', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='mimetype', full_name='Message.ImageMessage.mimetype', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='caption', full_name='Message.ImageMessage.caption', index=2, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='file_sha256', full_name='Message.ImageMessage.file_sha256', index=3, number=4, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='file_length', full_name='Message.ImageMessage.file_length', index=4, number=5, type=4, cpp_type=4, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='height', full_name='Message.ImageMessage.height', index=5, number=6, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='width', full_name='Message.ImageMessage.width', index=6, number=7, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='media_key', full_name='Message.ImageMessage.media_key', index=7, number=8, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='jpeg_thumbnail', full_name='Message.ImageMessage.jpeg_thumbnail', index=8, number=16, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='context_info', full_name='Message.ImageMessage.context_info', index=9, number=17, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], serialized_options=None, is_extendable=False, syntax='proto2', extension_ranges=[], oneofs=[ ], serialized_start=1017, serialized_end=1231, ) _MESSAGE_CONTACTMESSAGE = _descriptor.Descriptor( name='ContactMessage', full_name='Message.ContactMessage', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='display_name', full_name='Message.ContactMessage.display_name', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='vcard', full_name='Message.ContactMessage.vcard', index=1, number=16, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='context_info', full_name='Message.ContactMessage.context_info', index=2, number=17, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], serialized_options=None, is_extendable=False, syntax='proto2', extension_ranges=[], oneofs=[ ], serialized_start=1233, serialized_end=1322, ) _MESSAGE_LOCATIONMESSAGE = _descriptor.Descriptor( name='LocationMessage', full_name='Message.LocationMessage', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='degrees_latitude', full_name='Message.LocationMessage.degrees_latitude', index=0, number=1, type=1, cpp_type=5, label=1, has_default_value=False, default_value=float(0), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='degrees_longitude', full_name='Message.LocationMessage.degrees_longitude', index=1, number=2, type=1, cpp_type=5, label=1, has_default_value=False, default_value=float(0), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='name', full_name='Message.LocationMessage.name', index=2, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='address', full_name='Message.LocationMessage.address', index=3, number=4, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='url', full_name='Message.LocationMessage.url', index=4, number=5, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='duration', full_name='Message.LocationMessage.duration', index=5, number=6, type=2, cpp_type=6, label=1, has_default_value=False, default_value=float(0), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='accuracy_in_meters', full_name='Message.LocationMessage.accuracy_in_meters', index=6, number=7, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='speed_in_mps', full_name='Message.LocationMessage.speed_in_mps', index=7, number=8, type=2, cpp_type=6, label=1, has_default_value=False, default_value=float(0), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='degrees_clockwise_from_magnetic_north', full_name='Message.LocationMessage.degrees_clockwise_from_magnetic_north', index=8, number=9, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='axolotl_sender_key_distribution_message', full_name='Message.LocationMessage.axolotl_sender_key_distribution_message', index=9, number=10, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='jpeg_thumbnail', full_name='Message.LocationMessage.jpeg_thumbnail', index=10, number=16, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='context_info', full_name='Message.LocationMessage.context_info', index=11, number=17, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], serialized_options=None, is_extendable=False, syntax='proto2', extension_ranges=[], oneofs=[ ], serialized_start=1325, serialized_end=1663, ) _MESSAGE_EXTENDEDTEXTMESSAGE = _descriptor.Descriptor( name='ExtendedTextMessage', full_name='Message.ExtendedTextMessage', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='text', full_name='Message.ExtendedTextMessage.text', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='matched_text', full_name='Message.ExtendedTextMessage.matched_text', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='canonical_url', full_name='Message.ExtendedTextMessage.canonical_url', index=2, number=4, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='description', full_name='Message.ExtendedTextMessage.description', index=3, number=5, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='title', full_name='Message.ExtendedTextMessage.title', index=4, number=6, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='jpeg_thumbnail', full_name='Message.ExtendedTextMessage.jpeg_thumbnail', index=5, number=16, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='context_info', full_name='Message.ExtendedTextMessage.context_info', index=6, number=17, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], serialized_options=None, is_extendable=False, syntax='proto2', extension_ranges=[], oneofs=[ ], serialized_start=1666, serialized_end=1842, ) _MESSAGE_DOCUMENTMESSAGE = _descriptor.Descriptor( name='DocumentMessage', full_name='Message.DocumentMessage', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='url', full_name='Message.DocumentMessage.url', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='mimetype', full_name='Message.DocumentMessage.mimetype', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='title', full_name='Message.DocumentMessage.title', index=2, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='file_sha256', full_name='Message.DocumentMessage.file_sha256', index=3, number=4, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='file_length', full_name='Message.DocumentMessage.file_length', index=4, number=5, type=4, cpp_type=4, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='page_count', full_name='Message.DocumentMessage.page_count', index=5, number=6, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='media_key', full_name='Message.DocumentMessage.media_key', index=6, number=7, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='file_name', full_name='Message.DocumentMessage.file_name', index=7, number=8, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='jpeg_thumbnail', full_name='Message.DocumentMessage.jpeg_thumbnail', index=8, number=16, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='context_info', full_name='Message.DocumentMessage.context_info', index=9, number=17, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], serialized_options=None, is_extendable=False, syntax='proto2', extension_ranges=[], oneofs=[ ], serialized_start=1845, serialized_end=2068, ) _MESSAGE_AUDIOMESSAGE = _descriptor.Descriptor( name='AudioMessage', full_name='Message.AudioMessage', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='url', full_name='Message.AudioMessage.url', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='mimetype', full_name='Message.AudioMessage.mimetype', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='file_sha256', full_name='Message.AudioMessage.file_sha256', index=2, number=3, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='file_length', full_name='Message.AudioMessage.file_length', index=3, number=4, type=4, cpp_type=4, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='seconds', full_name='Message.AudioMessage.seconds', index=4, number=5, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='ptt', full_name='Message.AudioMessage.ptt', index=5, number=6, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='media_key', full_name='Message.AudioMessage.media_key', index=6, number=7, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='context_info', full_name='Message.AudioMessage.context_info', index=7, number=17, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='streaming_sidecar', full_name='Message.AudioMessage.streaming_sidecar', index=8, number=18, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], serialized_options=None, is_extendable=False, syntax='proto2', extension_ranges=[], oneofs=[ ], serialized_start=2071, serialized_end=2270, ) _MESSAGE_VIDEOMESSAGE = _descriptor.Descriptor( name='VideoMessage', full_name='Message.VideoMessage', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='url', full_name='Message.VideoMessage.url', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='mimetype', full_name='Message.VideoMessage.mimetype', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='file_sha256', full_name='Message.VideoMessage.file_sha256', index=2, number=3, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='file_length', full_name='Message.VideoMessage.file_length', index=3, number=4, type=4, cpp_type=4, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='seconds', full_name='Message.VideoMessage.seconds', index=4, number=5, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='media_key', full_name='Message.VideoMessage.media_key', index=5, number=6, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='caption', full_name='Message.VideoMessage.caption', index=6, number=7, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='gif_playback', full_name='Message.VideoMessage.gif_playback', index=7, number=8, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='height', full_name='Message.VideoMessage.height', index=8, number=9, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='width', full_name='Message.VideoMessage.width', index=9, number=10, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='jpeg_thumbnail', full_name='Message.VideoMessage.jpeg_thumbnail', index=10, number=16, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='context_info', full_name='Message.VideoMessage.context_info', index=11, number=17, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='streaming_sidecar', full_name='Message.VideoMessage.streaming_sidecar', index=12, number=18, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='gif_attribution', full_name='Message.VideoMessage.gif_attribution', index=13, number=19, type=14, cpp_type=8, label=1, has_default_value=True, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ _MESSAGE_VIDEOMESSAGE_ATTRIBUTION, ], serialized_options=None, is_extendable=False, syntax='proto2', extension_ranges=[], oneofs=[ ], serialized_start=2273, serialized_end=2666, ) _MESSAGE_CALL = _descriptor.Descriptor( name='Call', full_name='Message.Call', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='call_key', full_name='Message.Call.call_key', index=0, number=1, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], serialized_options=None, is_extendable=False, syntax='proto2', extension_ranges=[], oneofs=[ ], serialized_start=2668, serialized_end=2692, ) _MESSAGE_CHAT = _descriptor.Descriptor( name='Chat', full_name='Message.Chat', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='display_name', full_name='Message.Chat.display_name', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='id', full_name='Message.Chat.id', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], serialized_options=None, is_extendable=False, syntax='proto2', extension_ranges=[], oneofs=[ ], serialized_start=2694, serialized_end=2734, ) _MESSAGE_PROTOCOLMESSAGE = _descriptor.Descriptor( name='ProtocolMessage', full_name='Message.ProtocolMessage', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='key', full_name='Message.ProtocolMessage.key', index=0, number=1, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='type', full_name='Message.ProtocolMessage.type', index=1, number=2, type=14, cpp_type=8, label=1, has_default_value=True, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ _MESSAGE_PROTOCOLMESSAGE_TYPE, ], serialized_options=None, is_extendable=False, syntax='proto2', extension_ranges=[], oneofs=[ ], serialized_start=2736, serialized_end=2852, ) _MESSAGE_CONTACTSARRAYMESSAGE = _descriptor.Descriptor( name='ContactsArrayMessage', full_name='Message.ContactsArrayMessage', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='display_name', full_name='Message.ContactsArrayMessage.display_name', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='contacts', full_name='Message.ContactsArrayMessage.contacts', index=1, number=2, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='context_info', full_name='Message.ContactsArrayMessage.context_info', index=2, number=17, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], serialized_options=None, is_extendable=False, syntax='proto2', extension_ranges=[], oneofs=[ ], serialized_start=2854, serialized_end=2977, ) _MESSAGE_HIGHLYSTRUCTUREDMESSAGE = _descriptor.Descriptor( name='HighlyStructuredMessage', full_name='Message.HighlyStructuredMessage', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='namespace', full_name='Message.HighlyStructuredMessage.namespace', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='element_name', full_name='Message.HighlyStructuredMessage.element_name', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='params', full_name='Message.HighlyStructuredMessage.params', index=2, number=3, type=9, cpp_type=9, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='fallback_lg', full_name='Message.HighlyStructuredMessage.fallback_lg', index=3, number=4, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='fallback_lc', full_name='Message.HighlyStructuredMessage.fallback_lc', index=4, number=5, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], serialized_options=None, is_extendable=False, syntax='proto2', extension_ranges=[], oneofs=[ ], serialized_start=2979, serialized_end=3103, ) _MESSAGE = _descriptor.Descriptor( name='Message', full_name='Message', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='conversation', full_name='Message.conversation', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='sender_key_distribution_message', full_name='Message.sender_key_distribution_message', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='image_message', full_name='Message.image_message', index=2, number=3, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='contact_message', full_name='Message.contact_message', index=3, number=4, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='location_message', full_name='Message.location_message', index=4, number=5, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='extended_text_message', full_name='Message.extended_text_message', index=5, number=6, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='document_message', full_name='Message.document_message', index=6, number=7, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='audio_message', full_name='Message.audio_message', index=7, number=8, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='video_message', full_name='Message.video_message', index=8, number=9, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='call', full_name='Message.call', index=9, number=10, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='chat', full_name='Message.chat', index=10, number=11, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='protocol_message', full_name='Message.protocol_message', index=11, number=12, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='contacts_array_message', full_name='Message.contacts_array_message', index=12, number=13, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='highly_structured_message', full_name='Message.highly_structured_message', index=13, number=14, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[_MESSAGE_SENDERKEYDISTRIBUTIONMESSAGE, _MESSAGE_IMAGEMESSAGE, _MESSAGE_CONTACTMESSAGE, _MESSAGE_LOCATIONMESSAGE, _MESSAGE_EXTENDEDTEXTMESSAGE, _MESSAGE_DOCUMENTMESSAGE, _MESSAGE_AUDIOMESSAGE, _MESSAGE_VIDEOMESSAGE, _MESSAGE_CALL, _MESSAGE_CHAT, _MESSAGE_PROTOCOLMESSAGE, _MESSAGE_CONTACTSARRAYMESSAGE, _MESSAGE_HIGHLYSTRUCTUREDMESSAGE, ], enum_types=[ ], serialized_options=None, is_extendable=False, syntax='proto2', extension_ranges=[], oneofs=[ ], serialized_start=209, serialized_end=3103, ) _CONTEXTINFO.fields_by_name['quoted_message'].message_type = _MESSAGE _MESSAGE_SENDERKEYDISTRIBUTIONMESSAGE.containing_type = _MESSAGE _MESSAGE_IMAGEMESSAGE.fields_by_name['context_info'].message_type = _CONTEXTINFO _MESSAGE_IMAGEMESSAGE.containing_type = _MESSAGE _MESSAGE_CONTACTMESSAGE.fields_by_name['context_info'].message_type = _CONTEXTINFO _MESSAGE_CONTACTMESSAGE.containing_type = _MESSAGE _MESSAGE_LOCATIONMESSAGE.fields_by_name['context_info'].message_type = _CONTEXTINFO _MESSAGE_LOCATIONMESSAGE.containing_type = _MESSAGE _MESSAGE_EXTENDEDTEXTMESSAGE.fields_by_name['context_info'].message_type = _CONTEXTINFO _MESSAGE_EXTENDEDTEXTMESSAGE.containing_type = _MESSAGE _MESSAGE_DOCUMENTMESSAGE.fields_by_name['context_info'].message_type = _CONTEXTINFO _MESSAGE_DOCUMENTMESSAGE.containing_type = _MESSAGE _MESSAGE_AUDIOMESSAGE.fields_by_name['context_info'].message_type = _CONTEXTINFO _MESSAGE_AUDIOMESSAGE.containing_type = _MESSAGE _MESSAGE_VIDEOMESSAGE.fields_by_name['context_info'].message_type = _CONTEXTINFO _MESSAGE_VIDEOMESSAGE.fields_by_name['gif_attribution'].enum_type = _MESSAGE_VIDEOMESSAGE_ATTRIBUTION _MESSAGE_VIDEOMESSAGE.containing_type = _MESSAGE _MESSAGE_VIDEOMESSAGE_ATTRIBUTION.containing_type = _MESSAGE_VIDEOMESSAGE _MESSAGE_CALL.containing_type = _MESSAGE _MESSAGE_CHAT.containing_type = _MESSAGE _MESSAGE_PROTOCOLMESSAGE.fields_by_name['key'].message_type = protocol__pb2._MESSAGEKEY _MESSAGE_PROTOCOLMESSAGE.fields_by_name['type'].enum_type = _MESSAGE_PROTOCOLMESSAGE_TYPE _MESSAGE_PROTOCOLMESSAGE.containing_type = _MESSAGE _MESSAGE_PROTOCOLMESSAGE_TYPE.containing_type = _MESSAGE_PROTOCOLMESSAGE _MESSAGE_CONTACTSARRAYMESSAGE.fields_by_name['contacts'].message_type = _MESSAGE_CONTACTMESSAGE _MESSAGE_CONTACTSARRAYMESSAGE.fields_by_name['context_info'].message_type = _CONTEXTINFO _MESSAGE_CONTACTSARRAYMESSAGE.containing_type = _MESSAGE _MESSAGE_HIGHLYSTRUCTUREDMESSAGE.containing_type = _MESSAGE _MESSAGE.fields_by_name['sender_key_distribution_message'].message_type = _MESSAGE_SENDERKEYDISTRIBUTIONMESSAGE _MESSAGE.fields_by_name['image_message'].message_type = _MESSAGE_IMAGEMESSAGE _MESSAGE.fields_by_name['contact_message'].message_type = _MESSAGE_CONTACTMESSAGE _MESSAGE.fields_by_name['location_message'].message_type = _MESSAGE_LOCATIONMESSAGE _MESSAGE.fields_by_name['extended_text_message'].message_type = _MESSAGE_EXTENDEDTEXTMESSAGE _MESSAGE.fields_by_name['document_message'].message_type = _MESSAGE_DOCUMENTMESSAGE _MESSAGE.fields_by_name['audio_message'].message_type = _MESSAGE_AUDIOMESSAGE _MESSAGE.fields_by_name['video_message'].message_type = _MESSAGE_VIDEOMESSAGE _MESSAGE.fields_by_name['call'].message_type = _MESSAGE_CALL _MESSAGE.fields_by_name['chat'].message_type = _MESSAGE_CHAT _MESSAGE.fields_by_name['protocol_message'].message_type = _MESSAGE_PROTOCOLMESSAGE _MESSAGE.fields_by_name['contacts_array_message'].message_type = _MESSAGE_CONTACTSARRAYMESSAGE _MESSAGE.fields_by_name['highly_structured_message'].message_type = _MESSAGE_HIGHLYSTRUCTUREDMESSAGE DESCRIPTOR.message_types_by_name['ContextInfo'] = _CONTEXTINFO DESCRIPTOR.message_types_by_name['Message'] = _MESSAGE _sym_db.RegisterFileDescriptor(DESCRIPTOR) ContextInfo = _reflection.GeneratedProtocolMessageType('ContextInfo', (_message.Message,), dict( DESCRIPTOR = _CONTEXTINFO, __module__ = 'e2e_pb2' # @@protoc_insertion_point(class_scope:ContextInfo) )) _sym_db.RegisterMessage(ContextInfo) Message = _reflection.GeneratedProtocolMessageType('Message', (_message.Message,), dict( SenderKeyDistributionMessage = _reflection.GeneratedProtocolMessageType('SenderKeyDistributionMessage', (_message.Message,), dict( DESCRIPTOR = _MESSAGE_SENDERKEYDISTRIBUTIONMESSAGE, __module__ = 'e2e_pb2' # @@protoc_insertion_point(class_scope:Message.SenderKeyDistributionMessage) )) , ImageMessage = _reflection.GeneratedProtocolMessageType('ImageMessage', (_message.Message,), dict( DESCRIPTOR = _MESSAGE_IMAGEMESSAGE, __module__ = 'e2e_pb2' # @@protoc_insertion_point(class_scope:Message.ImageMessage) )) , ContactMessage = _reflection.GeneratedProtocolMessageType('ContactMessage', (_message.Message,), dict( DESCRIPTOR = _MESSAGE_CONTACTMESSAGE, __module__ = 'e2e_pb2' # @@protoc_insertion_point(class_scope:Message.ContactMessage) )) , LocationMessage = _reflection.GeneratedProtocolMessageType('LocationMessage', (_message.Message,), dict( DESCRIPTOR = _MESSAGE_LOCATIONMESSAGE, __module__ = 'e2e_pb2' # @@protoc_insertion_point(class_scope:Message.LocationMessage) )) , ExtendedTextMessage = _reflection.GeneratedProtocolMessageType('ExtendedTextMessage', (_message.Message,), dict( DESCRIPTOR = _MESSAGE_EXTENDEDTEXTMESSAGE, __module__ = 'e2e_pb2' # @@protoc_insertion_point(class_scope:Message.ExtendedTextMessage) )) , DocumentMessage = _reflection.GeneratedProtocolMessageType('DocumentMessage', (_message.Message,), dict( DESCRIPTOR = _MESSAGE_DOCUMENTMESSAGE, __module__ = 'e2e_pb2' # @@protoc_insertion_point(class_scope:Message.DocumentMessage) )) , AudioMessage = _reflection.GeneratedProtocolMessageType('AudioMessage', (_message.Message,), dict( DESCRIPTOR = _MESSAGE_AUDIOMESSAGE, __module__ = 'e2e_pb2' # @@protoc_insertion_point(class_scope:Message.AudioMessage) )) , VideoMessage = _reflection.GeneratedProtocolMessageType('VideoMessage', (_message.Message,), dict( DESCRIPTOR = _MESSAGE_VIDEOMESSAGE, __module__ = 'e2e_pb2' # @@protoc_insertion_point(class_scope:Message.VideoMessage) )) , Call = _reflection.GeneratedProtocolMessageType('Call', (_message.Message,), dict( DESCRIPTOR = _MESSAGE_CALL, __module__ = 'e2e_pb2' # @@protoc_insertion_point(class_scope:Message.Call) )) , Chat = _reflection.GeneratedProtocolMessageType('Chat', (_message.Message,), dict( DESCRIPTOR = _MESSAGE_CHAT, __module__ = 'e2e_pb2' # @@protoc_insertion_point(class_scope:Message.Chat) )) , ProtocolMessage = _reflection.GeneratedProtocolMessageType('ProtocolMessage', (_message.Message,), dict( DESCRIPTOR = _MESSAGE_PROTOCOLMESSAGE, __module__ = 'e2e_pb2' # @@protoc_insertion_point(class_scope:Message.ProtocolMessage) )) , ContactsArrayMessage = _reflection.GeneratedProtocolMessageType('ContactsArrayMessage', (_message.Message,), dict( DESCRIPTOR = _MESSAGE_CONTACTSARRAYMESSAGE, __module__ = 'e2e_pb2' # @@protoc_insertion_point(class_scope:Message.ContactsArrayMessage) )) , HighlyStructuredMessage = _reflection.GeneratedProtocolMessageType('HighlyStructuredMessage', (_message.Message,), dict( DESCRIPTOR = _MESSAGE_HIGHLYSTRUCTUREDMESSAGE, __module__ = 'e2e_pb2' # @@protoc_insertion_point(class_scope:Message.HighlyStructuredMessage) )) , DESCRIPTOR = _MESSAGE, __module__ = 'e2e_pb2' # @@protoc_insertion_point(class_scope:Message) )) _sym_db.RegisterMessage(Message) _sym_db.RegisterMessage(Message.SenderKeyDistributionMessage) _sym_db.RegisterMessage(Message.ImageMessage) _sym_db.RegisterMessage(Message.ContactMessage) _sym_db.RegisterMessage(Message.LocationMessage) _sym_db.RegisterMessage(Message.ExtendedTextMessage) _sym_db.RegisterMessage(Message.DocumentMessage) _sym_db.RegisterMessage(Message.AudioMessage) _sym_db.RegisterMessage(Message.VideoMessage) _sym_db.RegisterMessage(Message.Call) _sym_db.RegisterMessage(Message.Chat) _sym_db.RegisterMessage(Message.ProtocolMessage) _sym_db.RegisterMessage(Message.ContactsArrayMessage) _sym_db.RegisterMessage(Message.HighlyStructuredMessage) # @@protoc_insertion_point(module_scope) yowsup-3.2.3/yowsup/layers/protocol_messages/proto/protocol_pb2.py000066400000000000000000000057521346433372600256270ustar00rootroot00000000000000# Generated by the protocol buffer compiler. DO NOT EDIT! # source: protocol.proto import sys _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor.FileDescriptor( name='protocol.proto', package='', syntax='proto2', serialized_options=None, serialized_pb=_b('\n\x0eprotocol.proto\"R\n\nMessageKey\x12\x12\n\nremote_jid\x18\x01 \x01(\t\x12\x0f\n\x07\x66rom_me\x18\x02 \x01(\x08\x12\n\n\x02id\x18\x03 \x01(\t\x12\x13\n\x0bparticipant\x18\x04 \x01(\t') ) _MESSAGEKEY = _descriptor.Descriptor( name='MessageKey', full_name='MessageKey', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='remote_jid', full_name='MessageKey.remote_jid', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='from_me', full_name='MessageKey.from_me', index=1, number=2, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='id', full_name='MessageKey.id', index=2, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='participant', full_name='MessageKey.participant', index=3, number=4, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], serialized_options=None, is_extendable=False, syntax='proto2', extension_ranges=[], oneofs=[ ], serialized_start=18, serialized_end=100, ) DESCRIPTOR.message_types_by_name['MessageKey'] = _MESSAGEKEY _sym_db.RegisterFileDescriptor(DESCRIPTOR) MessageKey = _reflection.GeneratedProtocolMessageType('MessageKey', (_message.Message,), dict( DESCRIPTOR = _MESSAGEKEY, __module__ = 'protocol_pb2' # @@protoc_insertion_point(class_scope:MessageKey) )) _sym_db.RegisterMessage(MessageKey) # @@protoc_insertion_point(module_scope) yowsup-3.2.3/yowsup/layers/protocol_messages/protocolentities/000077500000000000000000000000001346433372600251035ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_messages/protocolentities/__init__.py000066400000000000000000000002301346433372600272070ustar00rootroot00000000000000from .message_text import TextMessageProtocolEntity from .message import MessageProtocolEntity from .message_text_broadcast import BroadcastTextMessage yowsup-3.2.3/yowsup/layers/protocol_messages/protocolentities/attributes/000077500000000000000000000000001346433372600272715ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_messages/protocolentities/attributes/__init__.py000066400000000000000000000000001346433372600313700ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_messages/protocolentities/attributes/attributes_message.py000066400000000000000000000020621346433372600335350ustar00rootroot00000000000000class MessageAttributes(object): def __init__( self, id=None, sender=None, recipient=None, notify=None, timestamp=None, participant=None, offline=None, retry=None ): assert (sender or recipient), "Must specify either sender or recipient " \ "jid to create the message " assert not (sender and recipient), "Can't set both attributes to message at same " \ "time (sender, recipient) " self.id = id self.sender = sender self.recipient = recipient self.notify = notify self.timestamp = int(timestamp) if timestamp else None self.participant = participant self.offline = offline in ("1", True) self.retry = int(retry) if retry else None @staticmethod def from_message_protocoltreenode(node): return MessageAttributes( node["id"], node["from"], node["to"], node["notify"], node["t"], node["participant"], node["offline"], node["retry"] ) yowsup-3.2.3/yowsup/layers/protocol_messages/protocolentities/message.py000066400000000000000000000075731346433372600271150ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity from yowsup.layers.protocol_receipts.protocolentities import OutgoingReceiptProtocolEntity from yowsup.layers.protocol_messages.protocolentities.attributes.attributes_message import MessageAttributes from copy import deepcopy class MessageProtocolEntity(ProtocolEntity): MESSAGE_TYPE_TEXT = "text" MESSAGE_TYPE_MEDIA = "media" def __init__(self, messageType, messageAttributes): """ :type messageType: str :type messageAttributes: MessageAttributes """ super(MessageProtocolEntity, self).__init__("message") assert type(messageAttributes) is MessageAttributes self._type = messageType self._id = messageAttributes.id or self._generateId() self._from = messageAttributes.sender self.to = messageAttributes.recipient self.timestamp = messageAttributes.timestamp or self._getCurrentTimestamp() self.notify = messageAttributes.notify self.offline = messageAttributes.offline self.retry = messageAttributes.retry self.participant= messageAttributes.participant def getType(self): return self._type def getId(self): return self._id def getTimestamp(self): return self.timestamp def getFrom(self, full = True): return self._from if full else self._from.split('@')[0] def isBroadcast(self): return False def getTo(self, full = True): return self.to if full else self.to.split('@')[0] def getParticipant(self, full = True): return self.participant if full else self.participant.split('@')[0] def getAuthor(self, full = True): return self.getParticipant(full) if self.isGroupMessage() else self.getFrom(full) def getNotify(self): return self.notify def toProtocolTreeNode(self): attribs = { "type" : self._type, "id" : self._id, } if self.participant: attribs["participant"] = self.participant if self.isOutgoing(): attribs["to"] = self.to else: attribs["from"] = self._from attribs["t"] = str(self.timestamp) if self.offline is not None: attribs["offline"] = "1" if self.offline else "0" if self.notify: attribs["notify"] = self.notify if self.retry: attribs["retry"] = str(self.retry) xNode = None #if self.isOutgoing(): # serverNode = ProtocolTreeNode("server", {}) # xNode = ProtocolTreeNode("x", {"xmlns": "jabber:x:event"}, [serverNode]) return self._createProtocolTreeNode(attribs, children = [xNode] if xNode else None, data = None) def isOutgoing(self): return self._from is None def isGroupMessage(self): if self.isOutgoing(): return "-" in self.to return self.participant != None def __str__(self): out = "Message:\n" out += "ID: %s\n" % self._id out += "To: %s\n" % self.to if self.isOutgoing() else "From: %s\n" % self._from out += "Type: %s\n" % self._type out += "Timestamp: %s\n" % self.timestamp if self.participant: out += "Participant: %s\n" % self.participant return out def ack(self, read=False): return OutgoingReceiptProtocolEntity(self.getId(), self.getFrom(), read, participant=self.getParticipant()) def forward(self, to, _id = None): OutgoingMessage = deepcopy(self) OutgoingMessage.to = to OutgoingMessage._from = None OutgoingMessage._id = self._generateId() if _id is None else _id return OutgoingMessage @staticmethod def fromProtocolTreeNode(node): return MessageProtocolEntity( node["type"], MessageAttributes.from_message_protocoltreenode(node) ) yowsup-3.2.3/yowsup/layers/protocol_messages/protocolentities/message_text.py000066400000000000000000000016071346433372600301510ustar00rootroot00000000000000from .protomessage import ProtomessageProtocolEntity from .message import MessageAttributes class TextMessageProtocolEntity(ProtomessageProtocolEntity): def __init__(self, body, messageAttributes=None, to=None): #flexible attributes for temp backwards compat assert(bool(messageAttributes) ^ bool(to)), "Either set messageAttributes, or to, and not both" if to: messageAttributes = MessageAttributes(recipient=to) super(TextMessageProtocolEntity, self).__init__("text", messageAttributes) self.setBody(body) @property def conversation(self): return self.proto.conversation @conversation.setter def conversation(self, value): self.proto.conversation = value def getBody(self): #obsolete return self.conversation def setBody(self, body): #obsolete self.conversation = body yowsup-3.2.3/yowsup/layers/protocol_messages/protocolentities/message_text_broadcast.py000066400000000000000000000022411346433372600321660ustar00rootroot00000000000000from .message_text import TextMessageProtocolEntity from yowsup.structs import ProtocolTreeNode import time class BroadcastTextMessage(TextMessageProtocolEntity): def __init__(self, jids, body): broadcastTime = int(time.time() * 1000) super(BroadcastTextMessage, self).__init__(body, to = "%s@broadcast" % broadcastTime) self.setBroadcastProps(jids) def setBroadcastProps(self, jids): assert type(jids) is list, "jids must be a list, got %s instead." % type(jids) self.jids = jids def toProtocolTreeNode(self): node = super(BroadcastTextMessage, self).toProtocolTreeNode() toNodes = [ProtocolTreeNode("to", {"jid": jid}) for jid in self.jids] broadcastNode = ProtocolTreeNode("broadcast", children = toNodes) node.addChild(broadcastNode) return node @staticmethod def fromProtocolTreeNode(node): entity = TextMessageProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = BroadcastTextMessage jids = [toNode.getAttributeValue("jid") for toNode in node.getChild("broadcast").getAllChildren()] entity.setBroadcastProps(jids) return entity yowsup-3.2.3/yowsup/layers/protocol_messages/protocolentities/proto.py000066400000000000000000000013271346433372600266230ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode class ProtoProtocolEntity(ProtocolEntity): def __init__(self, protoData, mediaType = None): super(ProtoProtocolEntity, self).__init__("proto") self.mediaType = mediaType self.protoData = protoData def getProtoData(self): return self.protoData def getMediaType(self): return self.mediaType def toProtocolTreeNode(self): attribs = {} if self.mediaType: attribs["mediatype"] = self.mediaType return ProtocolTreeNode("proto", attribs, data=self.protoData) @staticmethod def fromProtocolTreeNode(node): return ProtoProtocolEntity(node.data, node["mediatype"])yowsup-3.2.3/yowsup/layers/protocol_messages/protocolentities/protomessage.py000066400000000000000000000030711346433372600301660ustar00rootroot00000000000000from .message import MessageProtocolEntity from .proto import ProtoProtocolEntity from yowsup.layers.protocol_messages.proto.e2e_pb2 import Message import logging logger = logging.getLogger(__name__) class ProtomessageProtocolEntity(MessageProtocolEntity): ''' {{SERIALIZE_PROTO_DATA}} ''' def __init__(self, messageType, messageAttributes): super(ProtomessageProtocolEntity, self).__init__(messageType, messageAttributes) self._proto = Message() def __str__(self): out = super(ProtomessageProtocolEntity, self).__str__() return "%s\nproto=%s" % (out, self._proto) @property def proto(self): return self._proto def deserializeProtoData(self, protoData): m = Message() m.ParseFromString(protoData) return m def toProtocolTreeNode(self): node = super(ProtomessageProtocolEntity, self).toProtocolTreeNode() node.addChild(ProtoProtocolEntity(self._proto.SerializeToString()).toProtocolTreeNode()) return node def setProtoFromData(self, protoData): self._proto = self.deserializeProtoData(protoData) @classmethod def fromProtocolTreeNode(cls, node): entity = MessageProtocolEntity.fromProtocolTreeNode(node) entity.__class__= cls entity.setProtoFromData(node.getChild("proto").getData()) return entityyowsup-3.2.3/yowsup/layers/protocol_messages/protocolentities/test_message.py000066400000000000000000000013171346433372600301420ustar00rootroot00000000000000from yowsup.layers.protocol_messages.protocolentities.message import MessageProtocolEntity from yowsup.structs import ProtocolTreeNode from yowsup.structs.protocolentity import ProtocolEntityTest import unittest class MessageProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): self.ProtocolEntity = MessageProtocolEntity # ORDER_MATTERS for node.toString() to output return attribs in same order attribs = { "type": "message_type", "id": "message-id", "t": "12345", "offline": "0", "from": "from_jid", "notify": "notify_name" } self.node = ProtocolTreeNode("message", attribs) yowsup-3.2.3/yowsup/layers/protocol_messages/protocolentities/test_message_text.py000066400000000000000000000012621346433372600312050ustar00rootroot00000000000000from yowsup.layers.protocol_messages.protocolentities.message_text import TextMessageProtocolEntity from yowsup.structs import ProtocolTreeNode from yowsup.layers.protocol_messages.protocolentities.test_message import MessageProtocolEntityTest from yowsup.layers.protocol_messages.proto.e2e_pb2 import Message class TextMessageProtocolEntityTest(MessageProtocolEntityTest): def setUp(self): super(TextMessageProtocolEntityTest, self).setUp() self.ProtocolEntity = TextMessageProtocolEntity m = Message() m.conversation = "body_data" proto_node = ProtocolTreeNode("proto", {}, None, m.SerializeToString()) self.node.addChild(proto_node) yowsup-3.2.3/yowsup/layers/protocol_messages/protocolentities/test_message_text_broadcast.py000066400000000000000000000012661346433372600332330ustar00rootroot00000000000000from yowsup.layers.protocol_messages.protocolentities.test_message_text import TextMessageProtocolEntityTest from yowsup.layers.protocol_messages.protocolentities.message_text_broadcast import BroadcastTextMessage from yowsup.structs import ProtocolTreeNode class BroadcastTextMessageTest(TextMessageProtocolEntityTest): def setUp(self): super(BroadcastTextMessageTest, self).setUp() self.ProtocolEntity = BroadcastTextMessage broadcastNode = ProtocolTreeNode("broadcast") jids = ["jid1", "jid2"] toNodes = [ProtocolTreeNode("to", {"jid" : jid}) for jid in jids] broadcastNode.addChildren(toNodes) self.node.addChild(broadcastNode) yowsup-3.2.3/yowsup/layers/protocol_notifications/000077500000000000000000000000001346433372600225375ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_notifications/__init__.py000066400000000000000000000000601346433372600246440ustar00rootroot00000000000000from .layer import YowNotificationsProtocolLayeryowsup-3.2.3/yowsup/layers/protocol_notifications/layer.py000066400000000000000000000033251346433372600242300ustar00rootroot00000000000000from yowsup.layers import YowLayer, YowLayerEvent, YowProtocolLayer from .protocolentities import * from yowsup.layers.protocol_acks.protocolentities import OutgoingAckProtocolEntity import logging logger = logging.getLogger(__name__) class YowNotificationsProtocolLayer(YowProtocolLayer): def __init__(self): handleMap = { "notification": (self.recvNotification, self.sendNotification) } super(YowNotificationsProtocolLayer, self).__init__(handleMap) def __str__(self): return "notification Ib Layer" def sendNotification(self, entity): if entity.getTag() == "notification": self.toLower(entity.toProtocolTreeNode()) def recvNotification(self, node): if node["type"] == "picture": if node.getChild("set"): self.toUpper(SetPictureNotificationProtocolEntity.fromProtocolTreeNode(node)) elif node.getChild("delete"): self.toUpper(DeletePictureNotificationProtocolEntity.fromProtocolTreeNode(node)) else: self.raiseErrorForNode(node) elif node["type"] == "status": self.toUpper(StatusNotificationProtocolEntity.fromProtocolTreeNode(node)) elif node["type"] in ["contacts", "subject", "w:gp2"]: # Implemented in respectively the protocol_contacts and protocol_groups layer pass else: logger.warn("Unsupported notification type: %s " % node["type"]) logger.debug("Unsupported notification node: %s" % node) ack = OutgoingAckProtocolEntity(node["id"], "notification", node["type"], node["from"], participant=node["participant"]) self.toLower(ack.toProtocolTreeNode()) yowsup-3.2.3/yowsup/layers/protocol_notifications/protocolentities/000077500000000000000000000000001346433372600261455ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_notifications/protocolentities/__init__.py000066400000000000000000000006051346433372600302570ustar00rootroot00000000000000from .notification import NotificationProtocolEntity from .notification_picture import PictureNotificationProtocolEntity from .notification_picture_set import SetPictureNotificationProtocolEntity from .notification_picture_delete import DeletePictureNotificationProtocolEntity from .notification_status import StatusNotificationProtocolEntity yowsup-3.2.3/yowsup/layers/protocol_notifications/protocolentities/notification.py000066400000000000000000000036611346433372600312130ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from yowsup.layers.protocol_receipts.protocolentities import OutgoingReceiptProtocolEntity class NotificationProtocolEntity(ProtocolEntity): ''' ''' def __init__(self, _type, _id, _from, timestamp, notify, offline): super(NotificationProtocolEntity, self).__init__("notification") self._type = _type self._id = _id self._from =_from self.timestamp = int(timestamp) self.notify = notify self.offline = offline == "1" def __str__(self): out = "Notification\n" out += "From: %s\n" % self.getFrom() out += "Type: %s\n" % self.getType() return out def getFrom(self, full = True): return self._from if full else self._from.split('@')[0] def getType(self): return self._type def getId(self): return self._id def getTimestamp(self): return self.timestamp def toProtocolTreeNode(self): attribs = { "t" : str(self.timestamp), "from" : self._from, "offline" : "1" if self.offline else "0", "type" : self._type, "id" : self._id, "notify" : self.notify } return self._createProtocolTreeNode(attribs, children = None, data = None) @staticmethod def fromProtocolTreeNode(node): return NotificationProtocolEntity( node.getAttributeValue("type"), node.getAttributeValue("id"), node.getAttributeValue("from"), node.getAttributeValue("t"), node.getAttributeValue("notify"), node.getAttributeValue("offline") ) yowsup-3.2.3/yowsup/layers/protocol_notifications/protocolentities/notification_picture.py000066400000000000000000000014571346433372600327470ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .notification import NotificationProtocolEntity class PictureNotificationProtocolEntity(NotificationProtocolEntity): ''' ''' def __init__(self, _id, _from, status, timestamp, notify, offline, setJid, setId): super(PictureNotificationProtocolEntity, self).__init__("picture", _id, _from, timestamp, notify, offline) self.setData(setJid, setId) @staticmethod def fromProtocolTreeNode(node): entity = NotificationProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = PictureNotificationProtocolEntity return entityyowsup-3.2.3/yowsup/layers/protocol_notifications/protocolentities/notification_picture_delete.py000066400000000000000000000027261346433372600342710ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .notification_picture import PictureNotificationProtocolEntity class DeletePictureNotificationProtocolEntity(PictureNotificationProtocolEntity): ''' ''' def __init__(self, _id, _from, status, timestamp, notify, offline, deleteJid): super(DeletePictureNotificationProtocolEntity, self).__init__(_id, _from, timestamp, notify, offline) self.setData(deleteJid) def setData(self, deleteJid): self.deleteJid = deleteJid def __str__(self): out = super(DeletePictureNotificationProtocolEntity, self).__str__() out += "Type: Delete" return out def toProtocolTreeNode(self): node = super(DeletePictureNotificationProtocolEntity, self).toProtocolTreeNode() deleteNode = ProtocolTreeNode("delete", {"jid": self.deleteJid}, None, None) node.addChild(deleteNode) return node @staticmethod def fromProtocolTreeNode(node): entity = PictureNotificationProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = DeletePictureNotificationProtocolEntity deleteNode = node.getChild("delete") entity.setData(deleteNode.getAttributeValue("jid")) return entity yowsup-3.2.3/yowsup/layers/protocol_notifications/protocolentities/notification_picture_set.py000066400000000000000000000025751346433372600336240ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .notification_picture import PictureNotificationProtocolEntity class SetPictureNotificationProtocolEntity(PictureNotificationProtocolEntity): ''' ''' def __init__(self, _id, _from, status, timestamp, notify, offline, setJid, setId): super(SetPictureNotificationProtocolEntity, self).__init__(_id, _from, timestamp, notify, offline) self.setData(setJid, setId) def setData(self, setJid, setId): self.setId = setId self.setJid = setJid def toProtocolTreeNode(self): node = super(SetPictureNotificationProtocolEntity, self).toProtocolTreeNode() setNode = ProtocolTreeNode("set", {"jid": self.setJid, "id": self.setId}, None, None) node.addChild(setNode) return node @staticmethod def fromProtocolTreeNode(node): entity = PictureNotificationProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = SetPictureNotificationProtocolEntity setNode = node.getChild("set") entity.setData(setNode.getAttributeValue("jid"), setNode.getAttributeValue("id")) return entityyowsup-3.2.3/yowsup/layers/protocol_notifications/protocolentities/notification_status.py000066400000000000000000000023031346433372600326060ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .notification import NotificationProtocolEntity class StatusNotificationProtocolEntity(NotificationProtocolEntity): ''' {{STATUS}} ''' def __init__(self, _type, _id, _from, status, timestamp, notify, offline = False): super(StatusNotificationProtocolEntity, self).__init__("status", _id, _from, timestamp, notify, offline) self.setStatus(status) def setStatus(self, status): self.status = status def toProtocolTreeNode(self): node = super(StatusNotificationProtocolEntity, self).toProtocolTreeNode() setNode = ProtocolTreeNode("set", {}, None, self.status) node.addChild(setNode) return node @staticmethod def fromProtocolTreeNode(node): entity = NotificationProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = StatusNotificationProtocolEntity entity.setStatus(node.getChild("set").getData()) return entityyowsup-3.2.3/yowsup/layers/protocol_notifications/protocolentities/test_notification.py000066400000000000000000000012261346433372600322450ustar00rootroot00000000000000from yowsup.layers.protocol_notifications.protocolentities.notification import NotificationProtocolEntity from yowsup.structs import ProtocolTreeNode from yowsup.structs.protocolentity import ProtocolEntityTest import unittest class NotificationProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): self.ProtocolEntity = NotificationProtocolEntity attribs = { "t": "12345", "from": "from_jid", "offline": "0", "type": "notif_type", "id": "message-id", "notify": "notify_name" } self.node = ProtocolTreeNode("notification", attribs)yowsup-3.2.3/yowsup/layers/protocol_notifications/protocolentities/test_notification_picture.py000066400000000000000000000007221346433372600340000ustar00rootroot00000000000000from yowsup.layers.protocol_notifications.protocolentities.notification_picture import PictureNotificationProtocolEntity from yowsup.layers.protocol_notifications.protocolentities.test_notification import NotificationProtocolEntityTest class PictureNotificationProtocolEntityTest(NotificationProtocolEntityTest): def setUp(self): super(PictureNotificationProtocolEntityTest, self).setUp() self.ProtocolEntity = PictureNotificationProtocolEntity test_notification_picture_delete.py000066400000000000000000000012551346433372600352450ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_notifications/protocolentitiesfrom yowsup.layers.protocol_notifications.protocolentities.notification_picture_delete import DeletePictureNotificationProtocolEntity from yowsup.structs import ProtocolTreeNode from yowsup.layers.protocol_notifications.protocolentities.test_notification_picture import PictureNotificationProtocolEntityTest class DeletePictureNotificationProtocolEntityTest(PictureNotificationProtocolEntityTest): def setUp(self): super(DeletePictureNotificationProtocolEntityTest, self).setUp() self.ProtocolEntity = DeletePictureNotificationProtocolEntity deleteNode = ProtocolTreeNode("delete", {"jid": "DELETE_JID"}, None, None) self.node.addChild(deleteNode) yowsup-3.2.3/yowsup/layers/protocol_notifications/protocolentities/test_notification_picture_set.py000066400000000000000000000012371346433372600346550ustar00rootroot00000000000000from yowsup.layers.protocol_notifications.protocolentities.notification_picture_set import SetPictureNotificationProtocolEntity from yowsup.structs import ProtocolTreeNode from yowsup.layers.protocol_notifications.protocolentities.test_notification_picture import PictureNotificationProtocolEntityTest class SetPictureNotificationProtocolEntityTest(PictureNotificationProtocolEntityTest): def setUp(self): super(SetPictureNotificationProtocolEntityTest, self).setUp() self.ProtocolEntity = SetPictureNotificationProtocolEntity setNode = ProtocolTreeNode("set", {"jid": "SET_JID", "id": "123"}, None, None) self.node.addChild(setNode) yowsup-3.2.3/yowsup/layers/protocol_notifications/protocolentities/test_notification_status.py000066400000000000000000000011361346433372600336500ustar00rootroot00000000000000from yowsup.layers.protocol_notifications.protocolentities.notification_status import StatusNotificationProtocolEntity from yowsup.structs import ProtocolTreeNode from yowsup.layers.protocol_notifications.protocolentities.test_notification import NotificationProtocolEntityTest class StatusNotificationProtocolEntityTest(NotificationProtocolEntityTest): def setUp(self): super(StatusNotificationProtocolEntityTest, self).setUp() self.ProtocolEntity = StatusNotificationProtocolEntity setNode = ProtocolTreeNode("set", {}, [], "status_data") self.node.addChild(setNode) yowsup-3.2.3/yowsup/layers/protocol_presence/000077500000000000000000000000001346433372600214725ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_presence/__init__.py000066400000000000000000000000541346433372600236020ustar00rootroot00000000000000from .layer import YowPresenceProtocolLayer yowsup-3.2.3/yowsup/layers/protocol_presence/layer.py000066400000000000000000000022271346433372600231630ustar00rootroot00000000000000from yowsup.layers import YowLayer, YowLayerEvent, YowProtocolLayer from .protocolentities import * from yowsup.layers.protocol_iq.protocolentities import ErrorIqProtocolEntity class YowPresenceProtocolLayer(YowProtocolLayer): def __init__(self): handleMap = { "presence": (self.recvPresence, self.sendPresence), "iq": (None, self.sendIq) } super(YowPresenceProtocolLayer, self).__init__(handleMap) def __str__(self): return "Presence Layer" def sendPresence(self, entity): self.entityToLower(entity) def recvPresence(self, node): self.toUpper(PresenceProtocolEntity.fromProtocolTreeNode(node)) def sendIq(self, entity): if entity.getXmlns() == LastseenIqProtocolEntity.XMLNS: self._sendIq(entity, self.onLastSeenSuccess, self.onLastSeenError) def onLastSeenSuccess(self, protocolTreeNode, lastSeenEntity): self.toUpper(ResultLastseenIqProtocolEntity.fromProtocolTreeNode(protocolTreeNode)) def onLastSeenError(self, protocolTreeNode, lastSeenEntity): self.toUpper(ErrorIqProtocolEntity.fromProtocolTreeNode(protocolTreeNode)) yowsup-3.2.3/yowsup/layers/protocol_presence/protocolentities/000077500000000000000000000000001346433372600251005ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_presence/protocolentities/__init__.py000066400000000000000000000007101346433372600272070ustar00rootroot00000000000000from .presence import PresenceProtocolEntity from .presence_available import AvailablePresenceProtocolEntity from .presence_unavailable import UnavailablePresenceProtocolEntity from .presence_subscribe import SubscribePresenceProtocolEntity from .presence_unsubscribe import UnsubscribePresenceProtocolEntity from .iq_lastseen import LastseenIqProtocolEntity from .iq_lastseen_result import ResultLastseenIqProtocolEntity yowsup-3.2.3/yowsup/layers/protocol_presence/protocolentities/iq_lastseen.py000066400000000000000000000013071346433372600277620ustar00rootroot00000000000000from yowsup.layers.protocol_iq.protocolentities.iq import IqProtocolEntity from yowsup.structs.protocoltreenode import ProtocolTreeNode class LastseenIqProtocolEntity(IqProtocolEntity): XMLNS = "jabber:iq:last" def __init__(self, jid, _id = None): super(LastseenIqProtocolEntity, self).__init__(self.__class__.XMLNS, _type = "get", to = jid, _id = _id) @staticmethod def fromProtocolTreeNode(node): return LastseenIqProtocolEntity(node["to"]) def toProtocolTreeNode(self): node = super(LastseenIqProtocolEntity, self).toProtocolTreeNode() node.setAttribute("xmlns", self.__class__.XMLNS) node.addChild(ProtocolTreeNode("query")) return node yowsup-3.2.3/yowsup/layers/protocol_presence/protocolentities/iq_lastseen_result.py000066400000000000000000000020041346433372600313530ustar00rootroot00000000000000from yowsup.layers.protocol_iq.protocolentities.iq_result import ResultIqProtocolEntity from yowsup.structs.protocoltreenode import ProtocolTreeNode class ResultLastseenIqProtocolEntity(ResultIqProtocolEntity): def __init__(self, jid, seconds, _id = None): super(ResultLastseenIqProtocolEntity, self).__init__(_from=jid, _id=_id) self.setSeconds(seconds) def setSeconds(self, seconds): self.seconds = int(seconds) def getSeconds(self): return self.seconds def __str__(self): out = super(ResultIqProtocolEntity, self).__str__() out += "Seconds: %s\n" % self.seconds return out def toProtocolTreeNode(self): node = super(ResultLastseenIqProtocolEntity, self).toProtocolTreeNode() node.addChild(ProtocolTreeNode("query", {"seconds": str(self.seconds)})) return node @staticmethod def fromProtocolTreeNode(node): return ResultLastseenIqProtocolEntity(node["from"], node.getChild("query")["seconds"], node["id"])yowsup-3.2.3/yowsup/layers/protocol_presence/protocolentities/presence.py000066400000000000000000000036111346433372600272570ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode class PresenceProtocolEntity(ProtocolEntity): ''' Should normally be either type or name when contact goes offline: when contact goes online: ''' def __init__(self, _type = None, name = None, _from = None, last = None): super(PresenceProtocolEntity, self).__init__("presence") self._type = _type self.name = name self._from = _from self.last = last def getType(self): return self._type def getName(self): return self.name def getFrom(self, full = True): return self._from if full else self._from.split('@')[0] def getLast(self): return self.last def toProtocolTreeNode(self): attribs = {} if self._type: attribs["type"] = self._type if self.name: attribs["name"] = self.name if self._from: attribs["from"] = self._from if self.last: attribs["last"] = self.last return self._createProtocolTreeNode(attribs, None, None) def __str__(self): out = "Presence:\n" if self._type: out += "Type: %s\n" % self._type if self.name: out += "Name: %s\n" % self.name if self._from: out += "From: %s\n" % self._from if self.last: out += "Last seen: %s\n" % self.last return out @staticmethod def fromProtocolTreeNode(node): return PresenceProtocolEntity( node.getAttributeValue("type"), node.getAttributeValue("name"), node.getAttributeValue("from"), node.getAttributeValue("last") ) yowsup-3.2.3/yowsup/layers/protocol_presence/protocolentities/presence_available.py000066400000000000000000000006031346433372600312550ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .presence import PresenceProtocolEntity class AvailablePresenceProtocolEntity(PresenceProtocolEntity): ''' response: ''' def __init__(self): super(AvailablePresenceProtocolEntity, self).__init__("available")yowsup-3.2.3/yowsup/layers/protocol_presence/protocolentities/presence_subscribe.py000066400000000000000000000020111346433372600313110ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .presence import PresenceProtocolEntity class SubscribePresenceProtocolEntity(PresenceProtocolEntity): ''' ''' def __init__(self, jid): super(SubscribePresenceProtocolEntity, self).__init__("subscribe") self.setProps(jid) def setProps(self, jid): self.jid = jid def toProtocolTreeNode(self): node = super(SubscribePresenceProtocolEntity, self).toProtocolTreeNode() node.setAttribute("to", self.jid) return node def __str__(self): out = super(SubscribePresenceProtocolEntity, self).__str__() out += "To: %s\n" % self.jid return out @staticmethod def fromProtocolTreeNode(node): entity = PresenceProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = SubscribePresenceProtocolEntity entity.setProps( node.getAttributeValue("to") ) return entity yowsup-3.2.3/yowsup/layers/protocol_presence/protocolentities/presence_unavailable.py000066400000000000000000000006351346433372600316250ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .presence import PresenceProtocolEntity class UnavailablePresenceProtocolEntity(PresenceProtocolEntity): ''' response: ''' def __init__(self): super(UnavailablePresenceProtocolEntity, self).__init__("unavailable")yowsup-3.2.3/yowsup/layers/protocol_presence/protocolentities/presence_unsubscribe.py000066400000000000000000000020271346433372600316630ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .presence import PresenceProtocolEntity class UnsubscribePresenceProtocolEntity(PresenceProtocolEntity): ''' ''' def __init__(self, jid): super(UnsubscribePresenceProtocolEntity, self).__init__("unsubscribe") self.setProps(jid) def setProps(self, jid): self.jid = jid def toProtocolTreeNode(self): node = super(UnsubscribePresenceProtocolEntity, self).toProtocolTreeNode() node.setAttribute("to", self.jid) return node def __str__(self): out = super(UnsubscribePresenceProtocolEntity, self).__str__() out += "To: %s\n" % self.jid return out @staticmethod def fromProtocolTreeNode(node): entity = PresenceProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = UnsubscribePresenceProtocolEntity entity.setProps( node.getAttributeValue("to") ) return entity yowsup-3.2.3/yowsup/layers/protocol_presence/protocolentities/test_presence.py000066400000000000000000000007331346433372600303200ustar00rootroot00000000000000from yowsup.layers.protocol_presence.protocolentities.presence import PresenceProtocolEntity from yowsup.structs import ProtocolTreeNode from yowsup.structs.protocolentity import ProtocolEntityTest import unittest class PresenceProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): self.ProtocolEntity = PresenceProtocolEntity self.node = ProtocolTreeNode("presence", {"type": "presence_type", "name": "presence_name"}, None, None) yowsup-3.2.3/yowsup/layers/protocol_presence/protocolentities/test_presence_available.py000066400000000000000000000007461346433372600323240ustar00rootroot00000000000000from yowsup.layers.protocol_presence.protocolentities.presence_available import AvailablePresenceProtocolEntity from yowsup.layers.protocol_presence.protocolentities.test_presence import PresenceProtocolEntityTest class AvailablePresenceProtocolEntityTest(PresenceProtocolEntityTest): def setUp(self): super(AvailablePresenceProtocolEntityTest, self).setUp() self.ProtocolEntity = AvailablePresenceProtocolEntity self.node.setAttribute("type", "available") yowsup-3.2.3/yowsup/layers/protocol_presence/protocolentities/test_presence_subscribe.py000066400000000000000000000010331346433372600323530ustar00rootroot00000000000000from yowsup.layers.protocol_presence.protocolentities.presence_subscribe import SubscribePresenceProtocolEntity from yowsup.layers.protocol_presence.protocolentities.test_presence import PresenceProtocolEntityTest class SubscribePresenceProtocolEntityTest(PresenceProtocolEntityTest): def setUp(self): super(SubscribePresenceProtocolEntityTest, self).setUp() self.ProtocolEntity = SubscribePresenceProtocolEntity self.node.setAttribute("type", "subscribe") self.node.setAttribute("to", "subscribe_jid")yowsup-3.2.3/yowsup/layers/protocol_presence/protocolentities/test_presence_unavailable.py000066400000000000000000000007621346433372600326650ustar00rootroot00000000000000from yowsup.layers.protocol_presence.protocolentities.presence_unavailable import UnavailablePresenceProtocolEntity from yowsup.layers.protocol_presence.protocolentities.test_presence import PresenceProtocolEntityTest class UnavailablePresenceProtocolEntityTest(PresenceProtocolEntityTest): def setUp(self): super(UnavailablePresenceProtocolEntityTest, self).setUp() self.ProtocolEntity = UnavailablePresenceProtocolEntity self.node.setAttribute("type", "unavailable") yowsup-3.2.3/yowsup/layers/protocol_presence/protocolentities/test_presence_unsubscribe.py000066400000000000000000000010421346433372600327160ustar00rootroot00000000000000from yowsup.layers.protocol_presence.protocolentities.presence_unsubscribe import UnsubscribePresenceProtocolEntity from yowsup.layers.protocol_presence.protocolentities.test_presence import PresenceProtocolEntityTest class UnsubscribePresenceProtocolEntityTest(PresenceProtocolEntityTest): def setUp(self): super(UnsubscribePresenceProtocolEntityTest, self).setUp() self.ProtocolEntity = UnsubscribePresenceProtocolEntity self.node.setAttribute("type", "unsubscribe") self.node.setAttribute("to", "some_jid")yowsup-3.2.3/yowsup/layers/protocol_privacy/000077500000000000000000000000001346433372600213435ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_privacy/__init__.py000066400000000000000000000000521346433372600234510ustar00rootroot00000000000000from .layer import YowPrivacyProtocolLayeryowsup-3.2.3/yowsup/layers/protocol_privacy/layer.py000066400000000000000000000010271346433372600230310ustar00rootroot00000000000000from yowsup.layers import YowLayer, YowLayerEvent, YowProtocolLayer from .protocolentities import * class YowPrivacyProtocolLayer(YowProtocolLayer): def __init__(self): handleMap = { "iq": (self.recvIq, self.sendIq) } super(YowPrivacyProtocolLayer, self).__init__(handleMap) def __str__(self): return "Privacy Layer" def sendIq(self, entity): if entity.getXmlns() == "jabber:iq:privacy": self.entityToLower(entity) def recvIq(self, node): pass yowsup-3.2.3/yowsup/layers/protocol_privacy/protocolentities/000077500000000000000000000000001346433372600247515ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_privacy/protocolentities/__init__.py000066400000000000000000000000671346433372600270650ustar00rootroot00000000000000from .privacylist_iq import PrivacyListIqProtocolEntityyowsup-3.2.3/yowsup/layers/protocol_privacy/protocolentities/privacylist_iq.py000066400000000000000000000017271346433372600303740ustar00rootroot00000000000000from yowsup.layers.protocol_iq.protocolentities import IqProtocolEntity from yowsup.structs import ProtocolTreeNode class PrivacyListIqProtocolEntity(IqProtocolEntity): def __init__(self, name = "default"): super(PrivacyListIqProtocolEntity, self).__init__("jabber:iq:privacy", _type="get") self.setListName(name) def setListName(self, name): self.listName = name def toProtocolTreeNode(self): node = super(PrivacyListIqProtocolEntity, self).toProtocolTreeNode() queryNode = ProtocolTreeNode("query") listNode = ProtocolTreeNode("list", {"name": self.listName}) queryNode.addChild(listNode) node.addChild(queryNode) return node @staticmethod def fromProtocolTreeNode(node): entity = IqProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = PrivacyListIqProtocolEntity entity.setListName(node.getChild("query").getChild("list")["name"]) return entity yowsup-3.2.3/yowsup/layers/protocol_profiles/000077500000000000000000000000001346433372600215115ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_profiles/__init__.py000066400000000000000000000000531346433372600236200ustar00rootroot00000000000000from .layer import YowProfilesProtocolLayeryowsup-3.2.3/yowsup/layers/protocol_profiles/layer.py000066400000000000000000000052371346433372600232060ustar00rootroot00000000000000from yowsup.layers import YowProtocolLayer from .protocolentities import * from yowsup.layers.protocol_iq.protocolentities import ErrorIqProtocolEntity, ResultIqProtocolEntity class YowProfilesProtocolLayer(YowProtocolLayer): def __init__(self): handleMap = { "iq": (self.recvIq, self.sendIq) } super(YowProfilesProtocolLayer, self).__init__(handleMap) def __str__(self): return "Profiles Layer" def sendIq(self, entity): if entity.getXmlns() == "w:profile:picture": if entity.getType() == "get": self._sendIq(entity, self.onGetPictureResult, self.onGetPictureError) elif entity.getType() == "set": self._sendIq(entity, self.onSetPictureResult, self.onSetPictureError) elif entity.getType() == "delete": self._sendIq(entity, self.onDeletePictureResult, self.onDeletePictureError) elif entity.getXmlns() == "status": self._sendIq(entity, self.onSetStatusResult, self.onSetStatusError) elif entity.getXmlns() == "privacy": self._sendIq(entity, self.onPrivacyResult, self.onPrivacyError) def recvIq(self, node): pass def onPrivacyResult(self, resultNode, originIqRequestEntity): self.toUpper(ResultPrivacyIqProtocolEntity.fromProtocolTreeNode(resultNode)) def onPrivacyError(self, errorNode, originalIqRequestEntity): self.toUpper(ErrorIqProtocolEntity.fromProtocolTreeNode(errorNode)) def onSetStatusResult(self, resultNode, originIqRequestEntity): self.toUpper(ResultIqProtocolEntity.fromProtocolTreeNode(resultNode)) def onSetStatusError(self, errorNode, originalIqRequestEntity): self.toUpper(ErrorIqProtocolEntity.fromProtocolTreeNode(errorNode)) def onGetPictureResult(self, resultNode, originalIqRequestEntity): self.toUpper(ResultGetPictureIqProtocolEntity.fromProtocolTreeNode(resultNode)) def onGetPictureError(self, errorNode, originalIqRequestEntity): self.toUpper(ErrorIqProtocolEntity.fromProtocolTreeNode(errorNode)) def onSetPictureResult(self, resultNode, originalIqRequestEntity): self.toUpper(ResultGetPictureIqProtocolEntity.fromProtocolTreeNode(resultNode)) def onSetPictureError(self, errorNode, originalIqRequestEntity): self.toUpper(ErrorIqProtocolEntity.fromProtocolTreeNode(errorNode)) def onDeletePictureResult(self, resultNode, originalIqRequestEntity): self.toUpper(ResultIqProtocolEntity.fromProtocolTreeNode(resultNode)) def onDeletePictureError(self, errorNode, originalIqRequestEntity): self.toUpper(ErrorIqProtocolEntity.fromProtocolTreeNode(errorNode)) yowsup-3.2.3/yowsup/layers/protocol_profiles/protocolentities/000077500000000000000000000000001346433372600251175ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_profiles/protocolentities/__init__.py000066400000000000000000000010031346433372600272220ustar00rootroot00000000000000from .iq_unregister import UnregisterIqProtocolEntity from .iq_status_set import SetStatusIqProtocolEntity from .iq_picture_get import GetPictureIqProtocolEntity from .iq_picture_get_result import ResultGetPictureIqProtocolEntity from .iq_pictures_list import ListPicturesIqProtocolEntity from .iq_picture_set import SetPictureIqProtocolEntity from .iq_privacy_set import SetPrivacyIqProtocolEntity from .iq_privacy_get import GetPrivacyIqProtocolEntity from .iq_privacy_result import ResultPrivacyIqProtocolEntity yowsup-3.2.3/yowsup/layers/protocol_profiles/protocolentities/iq_picture.py000066400000000000000000000010361346433372600276350ustar00rootroot00000000000000from yowsup.layers.protocol_iq.protocolentities import IqProtocolEntity class PictureIqProtocolEntity(IqProtocolEntity): ''' When receiving a profile picture: {{Binary bytes of the picture.}} ''' XMLNS = "w:profile:picture" def __init__(self, jid, _id = None, type = "get"): super(PictureIqProtocolEntity, self).__init__(self.__class__.XMLNS, _id = _id, _type=type, to = jid)yowsup-3.2.3/yowsup/layers/protocol_profiles/protocolentities/iq_picture_get.py000066400000000000000000000022161346433372600304750ustar00rootroot00000000000000from .iq_picture import PictureIqProtocolEntity from yowsup.structs import ProtocolTreeNode class GetPictureIqProtocolEntity(PictureIqProtocolEntity): ''' ''' def __init__(self, jid, preview = True, _id = None): super(GetPictureIqProtocolEntity, self).__init__(jid, _id, "get") self.setGetPictureProps(preview) def setGetPictureProps(self, preview = True): self.preview = preview def isPreview(self): return self.preview def toProtocolTreeNode(self): node = super(GetPictureIqProtocolEntity, self).toProtocolTreeNode() pictureNode = ProtocolTreeNode("picture", {"type": "preview" if self.isPreview() else "image" }) node.addChild(pictureNode) return node @staticmethod def fromProtocolTreeNode(node): entity = PictureIqProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = GetPictureIqProtocolEntity entity.setGetPictureProps(node.getChild("picture").getAttributeValue("type")) return entityyowsup-3.2.3/yowsup/layers/protocol_profiles/protocolentities/iq_picture_get_result.py000066400000000000000000000033461346433372600321000ustar00rootroot00000000000000from .iq_picture import PictureIqProtocolEntity from yowsup.structs import ProtocolTreeNode class ResultGetPictureIqProtocolEntity(PictureIqProtocolEntity): ''' {{Binary bytes of the picture.}} ''' def __init__(self, jid, pictureData, pictureId, preview = True, _id = None): super(ResultGetPictureIqProtocolEntity, self).__init__(jid, _id, "result") self.setResultPictureProps(pictureData, pictureId, preview) def setResultPictureProps(self, pictureData, pictureId, preview = True): self.preview = preview self.pictureData = pictureData self.pictureId = pictureId def isPreview(self): return self.preview def getPictureData(self): return self.pictureData def getPictureId(self): return self.pictureId def writeToFile(self, path): with open(path, "wb") as outFile: outFile.write(self.getPictureData()) def toProtocolTreeNode(self): node = super(ResultGetPictureIqProtocolEntity, self).toProtocolTreeNode() pictureNode = ProtocolTreeNode({"type": "preview" if self.isPreview() else "image" }, data = self.getPictureData()) node.addChild(pictureNode) return node @staticmethod def fromProtocolTreeNode(node): entity = PictureIqProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = ResultGetPictureIqProtocolEntity pictureNode = node.getChild("picture") entity.setResultPictureProps(pictureNode.getData(), pictureNode.getAttributeValue("id"), pictureNode.getAttributeValue("type") == "preview") return entityyowsup-3.2.3/yowsup/layers/protocol_profiles/protocolentities/iq_picture_set.py000066400000000000000000000044401346433372600305120ustar00rootroot00000000000000from .iq_picture import PictureIqProtocolEntity from yowsup.structs import ProtocolTreeNode import time class SetPictureIqProtocolEntity(PictureIqProtocolEntity): ''' {{Binary bytes of the picture when type is set.}} ''' def __init__(self, jid, previewData, pictureData, pictureId = None, _id = None): super(SetPictureIqProtocolEntity, self).__init__(jid, _id, "set") self.setSetPictureProps(previewData, pictureData, pictureId) def setSetPictureProps(self, previewData, pictureData, pictureId = None): self.setPictureData(pictureData) self.setPictureId(pictureId or str(int(time.time()))) self.setPreviewData(previewData) def setPictureData(self, pictureData): self.pictureData = pictureData def getPictureData(self): return self.pictureData def setPreviewData(self, previewData): self.previewData = previewData def getPreviewData(self): return self.previewData def setPictureId(self, pictureId): self.pictureId = pictureId def getPictureId(self): return self.pictureId def toProtocolTreeNode(self): node = super(PictureIqProtocolEntity, self).toProtocolTreeNode() attribs = {"type": "image", "id": self.pictureId} pictureNode = ProtocolTreeNode("picture", attribs, None, self.getPictureData()) previewNode = ProtocolTreeNode("picture", {"type": "preview"}, None, self.getPreviewData()) node.addChild(pictureNode) node.addChild(previewNode) return node @staticmethod def fromProtocolTreeNode(node): entity = PictureIqProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = SetPictureIqProtocolEntity pictureNode = None previewNode = None for child in node.getAllChildren("picture"): nodeType = child.getAttributeValue("type") if nodeType == "image": pictureNode = child elif nodeType == "preview": previewNode = child entity.setSetPictureProps(previewNode.getData(), pictureNode.getData(), pictureNode.getAttributeValue("id")) return entityyowsup-3.2.3/yowsup/layers/protocol_profiles/protocolentities/iq_pictures_list.py000066400000000000000000000025021346433372600310520ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .iq_picture import PictureIqProtocolEntity class ListPicturesIqProtocolEntity(PictureIqProtocolEntity): ''' ''' def __init__(self, selfJid, jids): super(ListPicturesIqProtocolEntity, self).__init__(jid = selfJid, type = "get") self.setProps(jids) def setProps(self, jids): assert type(jids) is list and len(jids), "Must specify a list of jids to get the pictures for" self.jids = jids def toProtocolTreeNode(self): node = super(ListPicturesIqProtocolEntity, self).toProtocolTreeNode() userNodes = [ProtocolTreeNode("user", {"jid": jid}) for jid in self.jids] listNode = ProtocolTreeNode("list", {}, userNodes) node.addChild(listNode) return node @staticmethod def fromProtocolTreeNode(node): entity = PictureIqProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = ListPicturesIqProtocolEntity jids = [userNode.getAttributeValue("jid") for userNode in node.getChild("list").getAllChildren()] entity.setProps(jids) return entityyowsup-3.2.3/yowsup/layers/protocol_profiles/protocolentities/iq_privacy_get.py000066400000000000000000000016271346433372600305040ustar00rootroot00000000000000from yowsup.layers.protocol_iq.protocolentities import IqProtocolEntity from yowsup.structs import ProtocolTreeNode ''' ''' class GetPrivacyIqProtocolEntity(IqProtocolEntity): XMLNS = "privacy" def __init__(self): super(GetPrivacyIqProtocolEntity, self).__init__(self.__class__.XMLNS, _type="get") def toProtocolTreeNode(self): node = super(GetPrivacyIqProtocolEntity, self).toProtocolTreeNode() queryNode = ProtocolTreeNode(self.__class__.XMLNS) node.addChild(queryNode) return node @staticmethod def fromProtocolTreeNode(node): assert node.getChild(GetPrivacyIqProtocolEntity.XMLNS) is not None, "Not a get privacy iq node %s" % node entity = IqProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = GetPrivacyIqProtocolEntity return entity yowsup-3.2.3/yowsup/layers/protocol_profiles/protocolentities/iq_privacy_result.py000066400000000000000000000032671346433372600312450ustar00rootroot00000000000000from yowsup.structs import ProtocolTreeNode from yowsup.layers.protocol_iq.protocolentities import ResultIqProtocolEntity ''' ''' class ResultPrivacyIqProtocolEntity(ResultIqProtocolEntity): NODE_PRIVACY="privacy" def __init__(self, privacy): super(ResultPrivacyIqProtocolEntity, self).__init__() self.setProps(privacy) def setProps(self, privacy): assert type(privacy) is dict, "Privacy must be a dict {name => value}" self.privacy = privacy def __str__(self): out = super(ResultPrivacyIqProtocolEntity, self).__str__() out += "Privacy settings\n" for name, value in self.privacy.items(): out += "Category %s --> %s\n" % (name, value) return out def toProtocolTreeNode(self): node = super(ResultPrivacyIqProtocolEntity, self).toProtocolTreeNode() queryNode = ProtocolTreeNode(self.__class__.NODE_PRIVACY) node.addChild(queryNode) return node @staticmethod def fromProtocolTreeNode(node): entity = super(ResultPrivacyIqProtocolEntity, ResultPrivacyIqProtocolEntity).fromProtocolTreeNode(node) entity.__class__ = ResultPrivacyIqProtocolEntity privacyNode = node.getChild(ResultPrivacyIqProtocolEntity.NODE_PRIVACY) privacy = {} for categoryNode in privacyNode.getAllChildren(): privacy[categoryNode["name"]] = categoryNode["value"] entity.setProps(privacy) return entity yowsup-3.2.3/yowsup/layers/protocol_profiles/protocolentities/iq_privacy_set.py000066400000000000000000000050021346433372600305070ustar00rootroot00000000000000from yowsup.layers.protocol_iq.protocolentities import IqProtocolEntity from yowsup.structs import ProtocolTreeNode ''' ''' class SetPrivacyIqProtocolEntity(IqProtocolEntity): NAMES = ["status", "profile", "last"] VALUES = ["all", "contacts", "none"] XMLNS = "privacy" def __init__(self, value="all", names = None): # names can be a string with some element in VALUES or an array with strings with elements in VALUES # by default, all names are used super(SetPrivacyIqProtocolEntity, self).__init__(self.__class__.XMLNS, _type="set") self.setNames(names) self.setValue(value) @staticmethod def checkValidNames(names): names = names if names else SetPrivacyIqProtocolEntity.NAMES if not type(names) is list: names = [names] for name in names: if not name in SetPrivacyIqProtocolEntity.NAMES: raise Exception("Name should be in: '" + "', '".join(SetPrivacyIqProtocolEntity.NAMES) + "' but is '" + name + "'") return names @staticmethod def checkValidValue(value): if not value in SetPrivacyIqProtocolEntity.VALUES: raise Exception("Value should be in: '" + "', '".join(SetPrivacyIqProtocolEntity.VALUES) + "' but is '" + value + "'") return value def setNames(self, names): self.names = SetPrivacyIqProtocolEntity.checkValidNames(names) def setValue(self, value): self.value = SetPrivacyIqProtocolEntity.checkValidValue(value) def toProtocolTreeNode(self): node = super(SetPrivacyIqProtocolEntity, self).toProtocolTreeNode() queryNode = ProtocolTreeNode(self.__class__.XMLNS) for name in self.names: listNode = ProtocolTreeNode("category", {"name": name, "value": self.value}) queryNode.addChild(listNode) node.addChild(queryNode) return node @staticmethod def fromProtocolTreeNode(node): entity = IqProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = SetPrivacyIqProtocolEntity privacyNode = node.getChild(SetPrivacyIqProtocolEntity.XMLNS) names = [] for categoryNode in privacyNode.getAllChildren(): names.append(categoryNode["name"]) entity.setNames(names) entity.setValue("all") return entity yowsup-3.2.3/yowsup/layers/protocol_profiles/protocolentities/iq_status_set.py000066400000000000000000000021771346433372600303670ustar00rootroot00000000000000from yowsup.common import YowConstants from yowsup.layers.protocol_iq.protocolentities import IqProtocolEntity from yowsup.structs import ProtocolTreeNode class SetStatusIqProtocolEntity(IqProtocolEntity): ''' {{MSG}} ''' XMLNS = "status" def __init__(self, text = None, _id = None): super(SetStatusIqProtocolEntity, self).__init__(self.__class__.XMLNS, _id, _type = "set", to = YowConstants.WHATSAPP_SERVER) self.setData(text) def setData(self, text): self.text = text def toProtocolTreeNode(self): node = super(SetStatusIqProtocolEntity, self).toProtocolTreeNode() statusNode = ProtocolTreeNode("status", {}, [], self.text) node.addChild(statusNode) return node @staticmethod def fromProtocolTreeNode(node): entity = IqProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = SetStatusIqProtocolEntity statusNode = node.getChild("status") entity.setData(statusNode.getData()) return entity yowsup-3.2.3/yowsup/layers/protocol_profiles/protocolentities/iq_unregister.py000066400000000000000000000017341346433372600303560ustar00rootroot00000000000000from yowsup.common import YowConstants from yowsup.layers.protocol_iq.protocolentities import IqProtocolEntity from yowsup.structs import ProtocolTreeNode class UnregisterIqProtocolEntity(IqProtocolEntity): XMLNS = "urn:xmpp:whatsapp:account" def __init__(self): super(UnregisterIqProtocolEntity, self).__init__(_type = "get", to = YowConstants.WHATSAPP_SERVER) def toProtocolTreeNode(self): node = super(UnregisterIqProtocolEntity, self).toProtocolTreeNode() rmNode = ProtocolTreeNode("remove", {"xmlns": self.__class__.XMLNS}) node.addChild(rmNode) return node @staticmethod def fromProtocolTreeNode(node): entity = IqProtocolEntity.fromProtocolTreeNode(node) entity.__class__ = UnregisterIqProtocolEntity removeNode = node.getChild("remove") assert removeNode["xmlns"] == UnregisterIqProtocolEntity.XMLNS, "Not an account delete xmlns, got %s" % removeNode["xmlns"] return entityyowsup-3.2.3/yowsup/layers/protocol_profiles/protocolentities/test_iq_privacy_get.py000066400000000000000000000007661346433372600315460ustar00rootroot00000000000000from yowsup.layers.protocol_iq.protocolentities.test_iq import IqProtocolEntityTest from yowsup.layers.protocol_profiles.protocolentities import GetPrivacyIqProtocolEntity from yowsup.structs import ProtocolTreeNode entity = GetPrivacyIqProtocolEntity() class GetPrivacyIqProtocolEntityTest(IqProtocolEntityTest): def setUp(self): super(GetPrivacyIqProtocolEntityTest, self).setUp() self.ProtocolEntity = GetPrivacyIqProtocolEntity self.node = entity.toProtocolTreeNode() yowsup-3.2.3/yowsup/layers/protocol_profiles/protocolentities/test_iq_privacy_result.py000066400000000000000000000010701346433372600322720ustar00rootroot00000000000000from yowsup.layers.protocol_iq.protocolentities.test_iq import IqProtocolEntityTest from yowsup.layers.protocol_profiles.protocolentities import ResultPrivacyIqProtocolEntity from yowsup.structs import ProtocolTreeNode entity = ResultPrivacyIqProtocolEntity({"profile":"all","last":"none","status":"contacts"}) class ResultPrivacyIqProtocolEntityTest(IqProtocolEntityTest): def setUp(self): super(ResultPrivacyIqProtocolEntityTest, self).setUp() self.ProtocolEntity = ResultPrivacyIqProtocolEntity self.node = entity.toProtocolTreeNode() yowsup-3.2.3/yowsup/layers/protocol_profiles/protocolentities/test_iq_privacy_set.py000066400000000000000000000010301346433372600315430ustar00rootroot00000000000000from yowsup.layers.protocol_iq.protocolentities.test_iq import IqProtocolEntityTest from yowsup.layers.protocol_profiles.protocolentities import SetPrivacyIqProtocolEntity from yowsup.structs import ProtocolTreeNode entity = SetPrivacyIqProtocolEntity("all", ["profile","last","status"]) class SetPrivacyIqProtocolEntityTest(IqProtocolEntityTest): def setUp(self): super(SetPrivacyIqProtocolEntityTest, self).setUp() self.ProtocolEntity = SetPrivacyIqProtocolEntity self.node = entity.toProtocolTreeNode() yowsup-3.2.3/yowsup/layers/protocol_profiles/protocolentities/test_iq_status_set.py000066400000000000000000000010331346433372600314140ustar00rootroot00000000000000from yowsup.layers.protocol_iq.protocolentities.test_iq import IqProtocolEntityTest from yowsup.layers.protocol_profiles.protocolentities import SetStatusIqProtocolEntity from yowsup.structs import ProtocolTreeNode class SetStatusIqProtocolEntityTest(IqProtocolEntityTest): def setUp(self): super(SetStatusIqProtocolEntityTest, self).setUp() self.ProtocolEntity = SetStatusIqProtocolEntity statusNode = ProtocolTreeNode("status", {}, [], "Hey there, I'm using WhatsApp") self.node.addChild(statusNode) yowsup-3.2.3/yowsup/layers/protocol_profiles/protocolentities/test_iq_unregister.py000066400000000000000000000007751346433372600314210ustar00rootroot00000000000000from yowsup.layers.protocol_iq.protocolentities.test_iq import IqProtocolEntityTest from yowsup.layers.protocol_profiles.protocolentities import UnregisterIqProtocolEntity from yowsup.structs import ProtocolTreeNode class UnregisterIqProtocolEntityTest(IqProtocolEntityTest): def setUp(self): super(UnregisterIqProtocolEntityTest, self).setUp() self.ProtocolEntity = UnregisterIqProtocolEntity self.node.addChild(ProtocolTreeNode("remove", {"xmlns": "urn:xmpp:whatsapp:account"}))yowsup-3.2.3/yowsup/layers/protocol_receipts/000077500000000000000000000000001346433372600215045ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_receipts/__init__.py000066400000000000000000000000541346433372600236140ustar00rootroot00000000000000from .layer import YowReceiptProtocolLayer yowsup-3.2.3/yowsup/layers/protocol_receipts/layer.py000066400000000000000000000011171346433372600231720ustar00rootroot00000000000000from yowsup.layers import YowLayer, YowLayerEvent, YowProtocolLayer from .protocolentities import * class YowReceiptProtocolLayer(YowProtocolLayer): def __init__(self): handleMap = { "receipt": (self.recvReceiptNode, self.sendReceiptEntity) } super(YowReceiptProtocolLayer, self).__init__(handleMap) def __str__(self): return "Receipt Layer" def sendReceiptEntity(self, entity): self.entityToLower(entity) def recvReceiptNode(self, node): self.toUpper(IncomingReceiptProtocolEntity.fromProtocolTreeNode(node)) yowsup-3.2.3/yowsup/layers/protocol_receipts/protocolentities/000077500000000000000000000000001346433372600251125ustar00rootroot00000000000000yowsup-3.2.3/yowsup/layers/protocol_receipts/protocolentities/__init__.py000066400000000000000000000002421346433372600272210ustar00rootroot00000000000000from .receipt import ReceiptProtocolEntity from .receipt_incoming import IncomingReceiptProtocolEntity from .receipt_outgoing import OutgoingReceiptProtocolEntityyowsup-3.2.3/yowsup/layers/protocol_receipts/protocolentities/receipt.py000066400000000000000000000020331346433372600271150ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode class ReceiptProtocolEntity(ProtocolEntity): ''' delivered: read INCOMING ''' def __init__(self, _id): super(ReceiptProtocolEntity, self).__init__("receipt") self._id = _id def getId(self): return self._id def toProtocolTreeNode(self): attribs = { "id" : self._id } return self._createProtocolTreeNode(attribs, None, data = None) def __str__(self): out = "Receipt:\n" out += "ID: %s\n" % self._id return out @staticmethod def fromProtocolTreeNode(node): return ReceiptProtocolEntity( node.getAttributeValue("id") ) yowsup-3.2.3/yowsup/layers/protocol_receipts/protocolentities/receipt_incoming.py000066400000000000000000000111221346433372600307770ustar00rootroot00000000000000from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .receipt import ReceiptProtocolEntity from yowsup.layers.protocol_acks.protocolentities import OutgoingAckProtocolEntity class IncomingReceiptProtocolEntity(ReceiptProtocolEntity): ''' delivered: read delivered to participant in group: read by participant in group: multiple items: multiple items to group: INCOMING ''' def __init__(self, _id, _from, timestamp, offline = None, type = None, participant = None, items = None): super(IncomingReceiptProtocolEntity, self).__init__(_id) self.setIncomingData(_from, timestamp, offline, type, participant, items) def getType(self): return self.type def getParticipant(self, full=True): if self.participant: return self.participant if full else self.participant.split('@')[0] def getFrom(self, full = True): return self._from if full else self._from.split('@')[0] def setIncomingData(self, _from, timestamp, offline, type = None, participant = None, items = None): self._from = _from self.timestamp = timestamp self.type = type self.participant = participant if offline is not None: self.offline = True if offline == "1" else False else: self.offline = None self.items = items def toProtocolTreeNode(self): node = super(IncomingReceiptProtocolEntity, self).toProtocolTreeNode() node.setAttribute("from", self._from) node.setAttribute("t", str(self.timestamp)) if self.offline is not None: node.setAttribute("offline", "1" if self.offline else "0") if self.type is not None: node.setAttribute("type", self.type) if self.participant is not None: node.setAttribute("participant", self.participant) if self.items is not None: inodes = [] for item in self.items: inode = ProtocolTreeNode("item", {"id": item}) inodes.append(inode) lnode = ProtocolTreeNode("list") lnode.addChildren(inodes) node.addChild(lnode) return node def __str__(self): out = super(IncomingReceiptProtocolEntity, self).__str__() out += "From: %s\n" % self._from out += "Timestamp: %s\n" % self.timestamp if self.offline is not None: out += "Offline: %s\n" % ("1" if self.offline else "0") if self.type is not None: out += "Type: %s\n" % (self.type) if self.participant is not None: out += "Participant: %s\n" % (self.participant) if self.items is not None: out += "Items: %s\n" % " ".join(self.items) return out def ack(self): return OutgoingAckProtocolEntity(self.getId(), "receipt", self.getType(), self.getFrom(), participant = self.participant) @staticmethod def fromProtocolTreeNode(node): items = None listNode = node.getChild("list") if listNode is not None: items = [] for inode in listNode.getAllChildren("item"): items.append(inode["id"]) return IncomingReceiptProtocolEntity( node.getAttributeValue("id"), node.getAttributeValue("from"), node.getAttributeValue("t"), node.getAttributeValue("offline"), node.getAttributeValue("type"), node.getAttributeValue("participant"), items ) yowsup-3.2.3/yowsup/layers/protocol_receipts/protocolentities/receipt_outgoing.py000066400000000000000000000055741346433372600310450ustar00rootroot00000000000000import time from yowsup.structs import ProtocolEntity, ProtocolTreeNode from .receipt import ReceiptProtocolEntity class OutgoingReceiptProtocolEntity(ReceiptProtocolEntity): ''' delivered: If we send the following without "to" specified, whatsapp will consider the message delivered, but will not notify the sender. read multiple items: ''' def __init__(self, messageIds, to, read = False, participant = None, callId = None): if type(messageIds) in (list, tuple): if len(messageIds) > 1: receiptId = self._generateId() else: receiptId = messageIds[0] else: receiptId = messageIds messageIds = [messageIds] super(OutgoingReceiptProtocolEntity, self).__init__(receiptId) self.setOutgoingData(messageIds, to, read, participant, callId) def setOutgoingData(self, messageIds, to, read, participant, callId): self.messageIds = messageIds self.to = to self.read = read self.participant = participant self.callId = callId def getMessageIds(self): return self.messageIds def toProtocolTreeNode(self): node = super(OutgoingReceiptProtocolEntity, self).toProtocolTreeNode() if self.read: node.setAttribute("type", "read") if self.participant: node.setAttribute("participant", self.participant) if self.callId: offer = ProtocolTreeNode("offer", {"call-id": self.callId}) node.addChild(offer) node.setAttribute("to", self.to) if len(self.messageIds) > 1: listNode = ProtocolTreeNode("list") listNode.addChildren([ProtocolTreeNode("item", {"id": mId}) for mId in self.messageIds]) node.addChild(listNode) return node def __str__(self): out = super(OutgoingReceiptProtocolEntity, self).__str__() out += "To: \n%s" % self.to if self.read: out += "Type: \n%s" % "read" out += "For: \n%s" % self.messageIds return out @staticmethod def fromProtocolTreeNode(node): listNode = node.getChild("list") messageIds = [] if listNode: messageIds = [child["id"] for child in listNode.getChildren()] else: messageIds = [node["id"]] return OutgoingReceiptProtocolEntity( messageIds, node["to"], node["type"] == "read", node["participant"] ) yowsup-3.2.3/yowsup/layers/protocol_receipts/protocolentities/test_receipt_incoming.py000066400000000000000000000007001346433372600320360ustar00rootroot00000000000000from yowsup.layers.protocol_receipts.protocolentities import IncomingReceiptProtocolEntity from yowsup.structs.protocolentity import ProtocolEntityTest import unittest import time class IncomingReceiptProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): self.ProtocolEntity = IncomingReceiptProtocolEntity self.node = IncomingReceiptProtocolEntity("123", "sender", int(time.time())).toProtocolTreeNode() yowsup-3.2.3/yowsup/layers/protocol_receipts/protocolentities/test_receipt_outgoing.py000066400000000000000000000006511346433372600320730ustar00rootroot00000000000000from yowsup.layers.protocol_receipts.protocolentities import OutgoingReceiptProtocolEntity from yowsup.structs.protocolentity import ProtocolEntityTest import unittest class OutgoingReceiptProtocolEntityTest(ProtocolEntityTest, unittest.TestCase): def setUp(self): self.ProtocolEntity = OutgoingReceiptProtocolEntity self.node = OutgoingReceiptProtocolEntity("123", "target", "read").toProtocolTreeNode()yowsup-3.2.3/yowsup/registration/000077500000000000000000000000001346433372600171605ustar00rootroot00000000000000yowsup-3.2.3/yowsup/registration/__init__.py000066400000000000000000000001661346433372600212740ustar00rootroot00000000000000from .coderequest import WACodeRequest from .existsrequest import WAExistsRequest from .regrequest import WARegRequestyowsup-3.2.3/yowsup/registration/coderequest.py000066400000000000000000000035011346433372600220540ustar00rootroot00000000000000from yowsup.common.http.warequest import WARequest from yowsup.common.http.waresponseparser import JSONResponseParser from yowsup.common.tools import WATools from yowsup.registration.existsrequest import WAExistsRequest from yowsup.env import YowsupEnv class WACodeRequest(WARequest): def __init__(self, method, config): """ :type method: str :param config: :type config: yowsup.config.v1.config.Config """ super(WACodeRequest,self).__init__(config) self.addParam("mcc", config.mcc.zfill(3)) self.addParam("mnc", config.mnc.zfill(3)) self.addParam("sim_mcc", config.sim_mcc.zfill(3)) self.addParam("sim_mnc", config.sim_mnc.zfill(3)) self.addParam("method", method) self.addParam("reason", "") self.addParam("token", YowsupEnv.getCurrent().getToken(self._p_in)) self.addParam("hasav", "1") self.url = "v.whatsapp.net/v2/code" self.pvars = ["status","reason","length", "method", "retry_after", "code", "param"] +\ ["login", "type", "sms_wait", "voice_wait"] self.setParser(JSONResponseParser()) def send(self, parser = None, encrypt=True, preview=False): if self. _config.id is not None: request = WAExistsRequest(self._config) result = request.send(encrypt=encrypt, preview=preview) if result: if result["status"] == "ok": return result elif result["status"] == "fail" and "reason" in result and result["reason"] == "blocked": return result else: self._config.id = WATools.generateIdentity() self.addParam("id", self._config.id) res = super(WACodeRequest, self).send(parser, encrypt=encrypt, preview=preview) return res yowsup-3.2.3/yowsup/registration/existsrequest.py000066400000000000000000000014651346433372600224700ustar00rootroot00000000000000from yowsup.common.http.warequest import WARequest from yowsup.common.http.waresponseparser import JSONResponseParser from yowsup.env import YowsupEnv class WAExistsRequest(WARequest): def __init__(self, config): """ :param config: :type config: yowsup.config.v1.config.Config """ super(WAExistsRequest,self).__init__(config) if config.id is None: raise ValueError("Config does not contain id") self.url = "v.whatsapp.net/v2/exist" self.pvars = ["status", "reason", "sms_length", "voice_length", "result","param", "login", "type", "chat_dns_domain", "edge_routing_info" ] self.setParser(JSONResponseParser()) self.addParam("token", YowsupEnv.getCurrent().getToken(self._p_in)) yowsup-3.2.3/yowsup/registration/regrequest.py000066400000000000000000000034431346433372600217240ustar00rootroot00000000000000''' Copyright (c) <2012> Tarek Galal Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ''' from yowsup.common.http.warequest import WARequest from yowsup.common.http.waresponseparser import JSONResponseParser class WARegRequest(WARequest): def __init__(self, config, code): """ :param config: :type config: yowsup.config.vx.config.Config :param code: :type code: str """ super(WARegRequest,self).__init__(config) if config.id is None: raise ValueError("config.id is not set.") self.addParam("code", code) self.url = "v.whatsapp.net/v2/register" self.pvars = ["status", "login", "type", "edge_routing_info", "chat_dns_domain" "reason","retry_after"] self.setParser(JSONResponseParser()) yowsup-3.2.3/yowsup/stacks/000077500000000000000000000000001346433372600157365ustar00rootroot00000000000000yowsup-3.2.3/yowsup/stacks/__init__.py000066400000000000000000000051741346433372600200560ustar00rootroot00000000000000from .yowstack import YowStack, YowStackBuilder from yowsup.layers.auth import YowAuthenticationProtocolLayer from yowsup.layers.coder import YowCoderLayer from yowsup.layers.logger import YowLoggerLayer from yowsup.layers.network import YowNetworkLayer from yowsup.layers.protocol_messages import YowMessagesProtocolLayer from yowsup.layers.protocol_media import YowMediaProtocolLayer from yowsup.layers.protocol_acks import YowAckProtocolLayer from yowsup.layers.protocol_receipts import YowReceiptProtocolLayer from yowsup.layers.protocol_groups import YowGroupsProtocolLayer from yowsup.layers.protocol_presence import YowPresenceProtocolLayer from yowsup.layers.protocol_ib import YowIbProtocolLayer from yowsup.layers.protocol_notifications import YowNotificationsProtocolLayer from yowsup.layers.protocol_iq import YowIqProtocolLayer from yowsup.layers.protocol_contacts import YowContactsIqProtocolLayer from yowsup.layers.protocol_chatstate import YowChatstateProtocolLayer from yowsup.layers.protocol_privacy import YowPrivacyProtocolLayer from yowsup.layers.protocol_profiles import YowProfilesProtocolLayer from yowsup.layers.protocol_calls import YowCallsProtocolLayer from yowsup.layers.noise.layer import YowNoiseLayer from yowsup.layers.noise.layer_noise_segments import YowNoiseSegmentsLayer YOWSUP_CORE_LAYERS = ( YowLoggerLayer, YowCoderLayer, YowNoiseLayer, YowNoiseSegmentsLayer, YowNetworkLayer ) YOWSUP_PROTOCOL_LAYERS_BASIC = ( YowAuthenticationProtocolLayer, YowMessagesProtocolLayer, YowReceiptProtocolLayer, YowAckProtocolLayer, YowPresenceProtocolLayer, YowIbProtocolLayer, YowIqProtocolLayer, YowNotificationsProtocolLayer, YowContactsIqProtocolLayer, YowChatstateProtocolLayer ) YOWSUP_PROTOCOL_LAYERS_GROUPS = (YowGroupsProtocolLayer,) + YOWSUP_PROTOCOL_LAYERS_BASIC YOWSUP_PROTOCOL_LAYERS_MEDIA = (YowMediaProtocolLayer,) + YOWSUP_PROTOCOL_LAYERS_BASIC YOWSUP_PROTOCOL_LAYERS_PROFILES = (YowProfilesProtocolLayer,) + YOWSUP_PROTOCOL_LAYERS_BASIC YOWSUP_PROTOCOL_LAYERS_CALLS = (YowCallsProtocolLayer,) + YOWSUP_PROTOCOL_LAYERS_BASIC YOWSUP_PROTOCOL_LAYERS_FULL = (YowGroupsProtocolLayer, YowMediaProtocolLayer, YowPrivacyProtocolLayer, YowProfilesProtocolLayer, YowCallsProtocolLayer)\ + YOWSUP_PROTOCOL_LAYERS_BASIC YOWSUP_FULL_STACK = (YOWSUP_PROTOCOL_LAYERS_FULL,) +\ YOWSUP_CORE_LAYERS yowsup-3.2.3/yowsup/stacks/yowstack.py000066400000000000000000000200761346433372600201610ustar00rootroot00000000000000from yowsup.layers import YowParallelLayer import time, logging, random from yowsup.layers import YowLayer from yowsup.layers.noise.layer import YowNoiseLayer from yowsup.layers.noise.layer_noise_segments import YowNoiseSegmentsLayer from yowsup.layers.auth import YowAuthenticationProtocolLayer from yowsup.layers.coder import YowCoderLayer from yowsup.layers.logger import YowLoggerLayer from yowsup.layers.network import YowNetworkLayer from yowsup.layers.protocol_messages import YowMessagesProtocolLayer from yowsup.layers.protocol_media import YowMediaProtocolLayer from yowsup.layers.protocol_acks import YowAckProtocolLayer from yowsup.layers.protocol_receipts import YowReceiptProtocolLayer from yowsup.layers.protocol_groups import YowGroupsProtocolLayer from yowsup.layers.protocol_presence import YowPresenceProtocolLayer from yowsup.layers.protocol_ib import YowIbProtocolLayer from yowsup.layers.protocol_notifications import YowNotificationsProtocolLayer from yowsup.layers.protocol_iq import YowIqProtocolLayer from yowsup.layers.protocol_contacts import YowContactsIqProtocolLayer from yowsup.layers.protocol_chatstate import YowChatstateProtocolLayer from yowsup.layers.protocol_privacy import YowPrivacyProtocolLayer from yowsup.layers.protocol_profiles import YowProfilesProtocolLayer from yowsup.layers.protocol_calls import YowCallsProtocolLayer from yowsup.env import YowsupEnv from yowsup.common.constants import YowConstants from yowsup.layers.axolotl import AxolotlSendLayer, AxolotlControlLayer, AxolotlReceivelayer import inspect try: import Queue except ImportError: import queue as Queue logger = logging.getLogger(__name__) YOWSUP_PROTOCOL_LAYERS_BASIC = ( YowAuthenticationProtocolLayer, YowMessagesProtocolLayer, YowReceiptProtocolLayer, YowAckProtocolLayer, YowPresenceProtocolLayer, YowIbProtocolLayer, YowIqProtocolLayer, YowNotificationsProtocolLayer, YowContactsIqProtocolLayer, YowChatstateProtocolLayer, YowCallsProtocolLayer ) class YowStackBuilder(object): def __init__(self): self.layers = () self._props = {} def setProp(self, key, value): self._props[key] = value return self def pushDefaultLayers(self): defaultLayers = YowStackBuilder.getDefaultLayers() self.layers += defaultLayers return self def push(self, yowLayer): self.layers += (yowLayer,) return self def pop(self): self.layers = self.layers[:-1] return self def build(self): return YowStack(self.layers, reversed = False, props = self._props) @staticmethod def getDefaultLayers(groups = True, media = True, privacy = True, profiles = True): coreLayers = YowStackBuilder.getCoreLayers() protocolLayers = YowStackBuilder.getProtocolLayers(groups = groups, media=media, privacy=privacy, profiles=profiles) allLayers = coreLayers allLayers += (AxolotlControlLayer,) allLayers += (YowParallelLayer((AxolotlSendLayer, AxolotlReceivelayer)),) allLayers += (YowParallelLayer(protocolLayers),) return allLayers @staticmethod def getDefaultStack(layer = None, axolotl = False, groups = True, media = True, privacy = True, profiles = True): """ :param layer: An optional layer to put on top of default stack :param axolotl: E2E encryption enabled/ disabled :return: YowStack """ allLayers = YowStackBuilder.getDefaultLayers(axolotl, groups = groups, media=media,privacy=privacy, profiles=profiles) if layer: allLayers = allLayers + (layer,) return YowStack(allLayers, reversed = False) @staticmethod def getCoreLayers(): return ( YowLoggerLayer, YowCoderLayer, YowNoiseLayer, YowNoiseSegmentsLayer, YowNetworkLayer )[::-1] @staticmethod def getProtocolLayers(groups = True, media = True, privacy = True, profiles = True): layers = YOWSUP_PROTOCOL_LAYERS_BASIC if groups: layers += (YowGroupsProtocolLayer,) if media: layers += (YowMediaProtocolLayer, ) if privacy: layers += (YowPrivacyProtocolLayer, ) if profiles: layers += (YowProfilesProtocolLayer, ) return layers class YowStack(object): __stack = [] __stackInstances = [] __detachedQueue = Queue.Queue() def __init__(self, stackClassesArr = None, reversed = True, props = None): stackClassesArr = stackClassesArr or () self.__stack = stackClassesArr[::-1] if reversed else stackClassesArr self.__stackInstances = [] self._props = props or {} self.setProp(YowNetworkLayer.PROP_ENDPOINT, YowConstants.ENDPOINTS[random.randint(0,len(YowConstants.ENDPOINTS)-1)]) self._construct() def getLayerInterface(self, YowLayerClass): for inst in self.__stackInstances: if inst.__class__ == YowLayerClass: return inst.getLayerInterface() elif inst.__class__ == YowParallelLayer: res = inst.getLayerInterface(YowLayerClass) if res: return res def send(self, data): self.__stackInstances[-1].send(data) def receive(self, data): self.__stackInstances[0].receive(data) def setCredentials(self, credentials): self.getLayerInterface(YowAuthenticationProtocolLayer).setCredentials(*credentials) def addLayer(self, layerClass): self.__stack.push(layerClass) def addPostConstructLayer(self, layer): self.__stackInstances[-1].setLayers(layer, self.__stackInstances[-2]) layer.setLayers(None, self.__stackInstances[-1]) self.__stackInstances.append(layer) def setProp(self, key, value): self._props[key] = value def getProp(self, key, default = None): return self._props[key] if key in self._props else default def emitEvent(self, yowLayerEvent): if not self.__stackInstances[0].onEvent(yowLayerEvent): self.__stackInstances[0].emitEvent(yowLayerEvent) def broadcastEvent(self, yowLayerEvent): if not self.__stackInstances[-1].onEvent(yowLayerEvent): self.__stackInstances[-1].broadcastEvent(yowLayerEvent) def execDetached(self, fn): self.__class__.__detachedQueue.put(fn) def loop(self, *args, **kwargs): while True: try: callback = self.__class__.__detachedQueue.get(False) #doesn't block callback() except Queue.Empty: pass time.sleep(0.1) def _construct(self): logger.debug("Initializing stack") for s in self.__stack: if type(s) is tuple: logger.warn("Implicit declaration of parallel layers in a tuple is deprecated, pass a YowParallelLayer instead") inst = YowParallelLayer(s) else: if inspect.isclass(s): if issubclass(s, YowLayer): inst = s() else: raise ValueError("Stack must contain only subclasses of YowLayer") elif issubclass(s.__class__, YowLayer): inst = s else: raise ValueError("Stack must contain only subclasses of YowLayer") #inst = s() logger.debug("Constructed %s" % inst) inst.setStack(self) self.__stackInstances.append(inst) for i in range(0, len(self.__stackInstances)): upperLayer = self.__stackInstances[i + 1] if (i + 1) < len(self.__stackInstances) else None lowerLayer = self.__stackInstances[i - 1] if i > 0 else None self.__stackInstances[i].setLayers(upperLayer, lowerLayer) def getLayer(self, layerIndex): return self.__stackInstances[layerIndex] yowsup-3.2.3/yowsup/structs/000077500000000000000000000000001346433372600161555ustar00rootroot00000000000000yowsup-3.2.3/yowsup/structs/__init__.py000066400000000000000000000001311346433372600202610ustar00rootroot00000000000000from .protocolentity import ProtocolEntity from .protocoltreenode import ProtocolTreeNodeyowsup-3.2.3/yowsup/structs/protocolentity.py000066400000000000000000000027021346433372600216260ustar00rootroot00000000000000from .protocoltreenode import ProtocolTreeNode import unittest, time class ProtocolEntity(object): __ID_GEN = 0 def __init__(self, tag): self.tag = tag def getTag(self): return self.tag def isType(self, typ): return self.tag == typ def _createProtocolTreeNode(self, attributes, children = None, data = None): return ProtocolTreeNode(self.getTag(), attributes, children, data) def _getCurrentTimestamp(self): return int(time.time()) def _generateId(self, short = False): ProtocolEntity.__ID_GEN += 1 return str(ProtocolEntity.__ID_GEN) if short else str(int(time.time())) + "-" + str(ProtocolEntity.__ID_GEN) def toProtocolTreeNode(self): pass @staticmethod def fromProtocolTreeNode(self, protocolTreeNode): pass class ProtocolEntityTest(object): def setUp(self): self.ProtocolEntity = None self.node = None # def assertEqual(self, entity, node): # raise AssertionError("Should never execute that") def test_generation(self): if self.ProtocolEntity is None: raise ValueError("Test case not setup!") entity = self.ProtocolEntity.fromProtocolTreeNode(self.node) try: self.assertEqual(entity.toProtocolTreeNode(), self.node) except: print(entity.toProtocolTreeNode()) print("\nNOTEQ\n") print(self.node) raise yowsup-3.2.3/yowsup/structs/protocoltreenode.py000066400000000000000000000112621346433372600221200ustar00rootroot00000000000000import binascii import sys class ProtocolTreeNode(object): def __init__(self, tag, attributes = None, children = None, data = None): self.tag = tag self.attributes = attributes or {} self.children = children or [] self.data = data assert type(self.children) is list, "Children must be a list, got %s" % type(self.children) def __eq__(self, protocolTreeNode): """ :param protocolTreeNode: ProtocolTreeNode :return: bool """ # if protocolTreeNode.__class__ == ProtocolTreeNode\ and self.tag == protocolTreeNode.tag\ and self.data == protocolTreeNode.data\ and self.attributes == protocolTreeNode.attributes\ and len(self.getAllChildren()) == len(protocolTreeNode.getAllChildren()): found = False for c in self.getAllChildren(): for c2 in protocolTreeNode.getAllChildren(): if c == c2: found = True break if not found: return False found = False for c in protocolTreeNode.getAllChildren(): for c2 in self.getAllChildren(): if c == c2: found = True break if not found: return False return True return False def __hash__(self): return hash(self.tag) ^ hash(tuple(self.attributes.items())) ^ hash(self.data) def toString(self): out = "<"+self.tag if self.attributes is not None: for key,val in self.attributes.items(): if val is None: raise ValueError("value is none for attr %s" % key) out+= " "+key+'="'+val+'"' out+= ">\n" if self.data is not None: if type(self.data) is bytearray: try: out += "%s" % self.data.decode() except UnicodeDecodeError: out += binascii.hexlify(self.data) else: try: out += "%s" % self.data except UnicodeDecodeError: try: out += "%s" % self.data.decode() except UnicodeDecodeError: out += binascii.hexlify(self.data) if type(self.data) is str and sys.version_info >= (3,0): out += "\nHEX3:%s\n" % binascii.hexlify(self.data.encode('latin-1')) else: out += "\nHEX:%s\n" % binascii.hexlify(self.data) for c in self.children: try: out += c.toString() except UnicodeDecodeError: out += "[ENCODED DATA]\n" out+= "\n" return out def __str__(self): return self.toString() def getData(self): return self.data def setData(self, data): self.data = data @staticmethod def tagEquals(node,string): return node is not None and node.tag is not None and node.tag == string @staticmethod def require(node,string): if not ProtocolTreeNode.tagEquals(node,string): raise Exception("failed require. string: "+string); def __getitem__(self, key): return self.getAttributeValue(key) def __setitem__(self, key, val): self.setAttribute(key, val) def __delitem__(self, key): self.removeAttribute(key) def getChild(self,identifier): if type(identifier) == int: if len(self.children) > identifier: return self.children[identifier] else: return None for c in self.children: if identifier == c.tag: return c return None def hasChildren(self): return len(self.children) > 0 def addChild(self, childNode): self.children.append(childNode) def addChildren(self, children): for c in children: self.addChild(c) def getAttributeValue(self,string): try: return self.attributes[string] except KeyError: return None def removeAttribute(self, key): if key in self.attributes: del self.attributes[key] def setAttribute(self, key, value): self.attributes[key] = value def getAllChildren(self,tag = None): ret = [] if tag is None: return self.children for c in self.children: if tag == c.tag: ret.append(c) return ret