commit
cd44b01e94
674
COPYING.gpl3
674
COPYING.gpl3
|
@ -1,674 +0,0 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
596
COPYING.md
Normal file
596
COPYING.md
Normal file
|
@ -0,0 +1,596 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
==========================
|
||||
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright © 2007 Free Software Foundation, Inc. <<http://fsf.org/>>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this license
|
||||
document, but changing it is not allowed.
|
||||
|
||||
## Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for software and other
|
||||
kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed to take away
|
||||
your freedom to share and change the works. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change all versions of a
|
||||
program--to make sure it remains free software for all its users. We, the Free
|
||||
Software Foundation, use the GNU General Public License for most of our software; it
|
||||
applies also to any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not price. Our General
|
||||
Public Licenses are designed to make sure that you have the freedom to distribute
|
||||
copies of free software (and charge for them if you wish), that you receive source
|
||||
code or can get it if you want it, that you can change the software or use pieces of
|
||||
it in new free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you these rights or
|
||||
asking you to surrender the rights. Therefore, you have certain responsibilities if
|
||||
you distribute copies of the software, or if you modify it: responsibilities to
|
||||
respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether gratis or for a fee,
|
||||
you must pass on to the recipients the same freedoms that you received. You must make
|
||||
sure that they, too, receive or can get the source code. And you must show them these
|
||||
terms so they know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps: (1) assert
|
||||
copyright on the software, and (2) offer you this License giving you legal permission
|
||||
to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains that there is
|
||||
no warranty for this free software. For both users' and authors' sake, the GPL
|
||||
requires that modified versions be marked as changed, so that their problems will not
|
||||
be attributed erroneously to authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run modified versions of
|
||||
the software inside them, although the manufacturer can do so. This is fundamentally
|
||||
incompatible with the aim of protecting users' freedom to change the software. The
|
||||
systematic pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we have designed
|
||||
this version of the GPL to prohibit the practice for those products. If such problems
|
||||
arise substantially in other domains, we stand ready to extend this provision to
|
||||
those domains in future versions of the GPL, as needed to protect the freedom of
|
||||
users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents. States should
|
||||
not allow patents to restrict development and use of software on general-purpose
|
||||
computers, but in those that do, we wish to avoid the special danger that patents
|
||||
applied to a free program could make it effectively proprietary. To prevent this, the
|
||||
GPL assures that patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and modification follow.
|
||||
|
||||
## TERMS AND CONDITIONS
|
||||
|
||||
### 0. Definitions.
|
||||
|
||||
“This License” refers to version 3 of the GNU General Public License.
|
||||
|
||||
“Copyright” also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
“The Program” refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as “you”. “Licensees” and
|
||||
“recipients” may be individuals or organizations.
|
||||
|
||||
To “modify” a work means to copy from or adapt all or part of the work in
|
||||
a fashion requiring copyright permission, other than the making of an exact copy. The
|
||||
resulting work is called a “modified version” of the earlier work or a
|
||||
work “based on” the earlier work.
|
||||
|
||||
A “covered work” means either the unmodified Program or a work based on
|
||||
the Program.
|
||||
|
||||
To “propagate” a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for infringement under
|
||||
applicable copyright law, except executing it on a computer or modifying a private
|
||||
copy. Propagation includes copying, distribution (with or without modification),
|
||||
making available to the public, and in some countries other activities as well.
|
||||
|
||||
To “convey” a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through a computer
|
||||
network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays “Appropriate Legal Notices” to the
|
||||
extent that it includes a convenient and prominently visible feature that (1)
|
||||
displays an appropriate copyright notice, and (2) tells the user that there is no
|
||||
warranty for the work (except to the extent that warranties are provided), that
|
||||
licensees may convey the work under this License, and how to view a copy of this
|
||||
License. If the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
### 1. Source Code.
|
||||
|
||||
The “source code” for a work means the preferred form of the work for
|
||||
making modifications to it. “Object code” means any non-source form of a
|
||||
work.
|
||||
|
||||
A “Standard Interface” means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of interfaces
|
||||
specified for a particular programming language, one that is widely used among
|
||||
developers working in that language.
|
||||
|
||||
The “System Libraries” of an executable work include anything, other than
|
||||
the work as a whole, that (a) is included in the normal form of packaging a Major
|
||||
Component, but which is not part of that Major Component, and (b) serves only to
|
||||
enable use of the work with that Major Component, or to implement a Standard
|
||||
Interface for which an implementation is available to the public in source code form.
|
||||
A “Major Component”, in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system (if any) on which
|
||||
the executable work runs, or a compiler used to produce the work, or an object code
|
||||
interpreter used to run it.
|
||||
|
||||
The “Corresponding Source” for a work in object code form means all the
|
||||
source code needed to generate, install, and (for an executable work) run the object
|
||||
code and to modify the work, including scripts to control those activities. However,
|
||||
it does not include the work's System Libraries, or general-purpose tools or
|
||||
generally available free programs which are used unmodified in performing those
|
||||
activities but which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for the work, and
|
||||
the source code for shared libraries and dynamically linked subprograms that the work
|
||||
is specifically designed to require, such as by intimate data communication or
|
||||
control flow between those subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users can regenerate
|
||||
automatically from other parts of the Corresponding Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that same work.
|
||||
|
||||
### 2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of copyright on the
|
||||
Program, and are irrevocable provided the stated conditions are met. This License
|
||||
explicitly affirms your unlimited permission to run the unmodified Program. The
|
||||
output from running a covered work is covered by this License only if the output,
|
||||
given its content, constitutes a covered work. This License acknowledges your rights
|
||||
of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not convey, without
|
||||
conditions so long as your license otherwise remains in force. You may convey covered
|
||||
works to others for the sole purpose of having them make modifications exclusively
|
||||
for you, or provide you with facilities for running those works, provided that you
|
||||
comply with the terms of this License in conveying all material for which you do not
|
||||
control copyright. Those thus making or running the covered works for you must do so
|
||||
exclusively on your behalf, under your direction and control, on terms that prohibit
|
||||
them from making any copies of your copyrighted material outside their relationship
|
||||
with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under the conditions
|
||||
stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
|
||||
|
||||
### 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological measure under any
|
||||
applicable law fulfilling obligations under article 11 of the WIPO copyright treaty
|
||||
adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention
|
||||
of such measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid circumvention of
|
||||
technological measures to the extent such circumvention is effected by exercising
|
||||
rights under this License with respect to the covered work, and you disclaim any
|
||||
intention to limit operation or modification of the work as a means of enforcing,
|
||||
against the work's users, your or third parties' legal rights to forbid circumvention
|
||||
of technological measures.
|
||||
|
||||
### 4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you receive it, in any
|
||||
medium, provided that you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice; keep intact all notices stating that this License and
|
||||
any non-permissive terms added in accord with section 7 apply to the code; keep
|
||||
intact all notices of the absence of any warranty; and give all recipients a copy of
|
||||
this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey, and you may offer
|
||||
support or warranty protection for a fee.
|
||||
|
||||
### 5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to produce it from
|
||||
the Program, in the form of source code under the terms of section 4, provided that
|
||||
you also meet all of these conditions:
|
||||
|
||||
* **a)** The work must carry prominent notices stating that you modified it, and giving a
|
||||
relevant date.
|
||||
* **b)** The work must carry prominent notices stating that it is released under this
|
||||
License and any conditions added under section 7. This requirement modifies the
|
||||
requirement in section 4 to “keep intact all notices”.
|
||||
* **c)** You must license the entire work, as a whole, under this License to anyone who
|
||||
comes into possession of a copy. This License will therefore apply, along with any
|
||||
applicable section 7 additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no permission to license the
|
||||
work in any other way, but it does not invalidate such permission if you have
|
||||
separately received it.
|
||||
* **d)** If the work has interactive user interfaces, each must display Appropriate Legal
|
||||
Notices; however, if the Program has interactive interfaces that do not display
|
||||
Appropriate Legal Notices, your work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent works, which are
|
||||
not by their nature extensions of the covered work, and which are not combined with
|
||||
it such as to form a larger program, in or on a volume of a storage or distribution
|
||||
medium, is called an “aggregate” if the compilation and its resulting
|
||||
copyright are not used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work in an aggregate
|
||||
does not cause this License to apply to the other parts of the aggregate.
|
||||
|
||||
### 6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms of sections 4 and
|
||||
5, provided that you also convey the machine-readable Corresponding Source under the
|
||||
terms of this License, in one of these ways:
|
||||
|
||||
* **a)** Convey the object code in, or embodied in, a physical product (including a
|
||||
physical distribution medium), accompanied by the Corresponding Source fixed on a
|
||||
durable physical medium customarily used for software interchange.
|
||||
* **b)** Convey the object code in, or embodied in, a physical product (including a
|
||||
physical distribution medium), accompanied by a written offer, valid for at least
|
||||
three years and valid for as long as you offer spare parts or customer support for
|
||||
that product model, to give anyone who possesses the object code either (1) a copy of
|
||||
the Corresponding Source for all the software in the product that is covered by this
|
||||
License, on a durable physical medium customarily used for software interchange, for
|
||||
a price no more than your reasonable cost of physically performing this conveying of
|
||||
source, or (2) access to copy the Corresponding Source from a network server at no
|
||||
charge.
|
||||
* **c)** Convey individual copies of the object code with a copy of the written offer to
|
||||
provide the Corresponding Source. This alternative is allowed only occasionally and
|
||||
noncommercially, and only if you received the object code with such an offer, in
|
||||
accord with subsection 6b.
|
||||
* **d)** Convey the object code by offering access from a designated place (gratis or for
|
||||
a charge), and offer equivalent access to the Corresponding Source in the same way
|
||||
through the same place at no further charge. You need not require recipients to copy
|
||||
the Corresponding Source along with the object code. If the place to copy the object
|
||||
code is a network server, the Corresponding Source may be on a different server
|
||||
(operated by you or a third party) that supports equivalent copying facilities,
|
||||
provided you maintain clear directions next to the object code saying where to find
|
||||
the Corresponding Source. Regardless of what server hosts the Corresponding Source,
|
||||
you remain obligated to ensure that it is available for as long as needed to satisfy
|
||||
these requirements.
|
||||
* **e)** Convey the object code using peer-to-peer transmission, provided you inform
|
||||
other peers where the object code and Corresponding Source of the work are being
|
||||
offered to the general public at no charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded from the
|
||||
Corresponding Source as a System Library, need not be included in conveying the
|
||||
object code work.
|
||||
|
||||
A “User Product” is either (1) a “consumer product”, which
|
||||
means any tangible personal property which is normally used for personal, family, or
|
||||
household purposes, or (2) anything designed or sold for incorporation into a
|
||||
dwelling. In determining whether a product is a consumer product, doubtful cases
|
||||
shall be resolved in favor of coverage. For a particular product received by a
|
||||
particular user, “normally used” refers to a typical or common use of
|
||||
that class of product, regardless of the status of the particular user or of the way
|
||||
in which the particular user actually uses, or expects or is expected to use, the
|
||||
product. A product is a consumer product regardless of whether the product has
|
||||
substantial commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
“Installation Information” for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install and execute
|
||||
modified versions of a covered work in that User Product from a modified version of
|
||||
its Corresponding Source. The information must suffice to ensure that the continued
|
||||
functioning of the modified object code is in no case prevented or interfered with
|
||||
solely because modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or specifically for
|
||||
use in, a User Product, and the conveying occurs as part of a transaction in which
|
||||
the right of possession and use of the User Product is transferred to the recipient
|
||||
in perpetuity or for a fixed term (regardless of how the transaction is
|
||||
characterized), the Corresponding Source conveyed under this section must be
|
||||
accompanied by the Installation Information. But this requirement does not apply if
|
||||
neither you nor any third party retains the ability to install modified object code
|
||||
on the User Product (for example, the work has been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a requirement to
|
||||
continue to provide support service, warranty, or updates for a work that has been
|
||||
modified or installed by the recipient, or for the User Product in which it has been
|
||||
modified or installed. Access to a network may be denied when the modification itself
|
||||
materially and adversely affects the operation of the network or violates the rules
|
||||
and protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided, in accord with
|
||||
this section must be in a format that is publicly documented (and with an
|
||||
implementation available to the public in source code form), and must require no
|
||||
special password or key for unpacking, reading or copying.
|
||||
|
||||
### 7. Additional Terms.
|
||||
|
||||
“Additional permissions” are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions. Additional
|
||||
permissions that are applicable to the entire Program shall be treated as though they
|
||||
were included in this License, to the extent that they are valid under applicable
|
||||
law. If additional permissions apply only to part of the Program, that part may be
|
||||
used separately under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option remove any
|
||||
additional permissions from that copy, or from any part of it. (Additional
|
||||
permissions may be written to require their own removal in certain cases when you
|
||||
modify the work.) You may place additional permissions on material, added by you to a
|
||||
covered work, for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you add to a
|
||||
covered work, you may (if authorized by the copyright holders of that material)
|
||||
supplement the terms of this License with terms:
|
||||
|
||||
* **a)** Disclaiming warranty or limiting liability differently from the terms of
|
||||
sections 15 and 16 of this License; or
|
||||
* **b)** Requiring preservation of specified reasonable legal notices or author
|
||||
attributions in that material or in the Appropriate Legal Notices displayed by works
|
||||
containing it; or
|
||||
* **c)** Prohibiting misrepresentation of the origin of that material, or requiring that
|
||||
modified versions of such material be marked in reasonable ways as different from the
|
||||
original version; or
|
||||
* **d)** Limiting the use for publicity purposes of names of licensors or authors of the
|
||||
material; or
|
||||
* **e)** Declining to grant rights under trademark law for use of some trade names,
|
||||
trademarks, or service marks; or
|
||||
* **f)** Requiring indemnification of licensors and authors of that material by anyone
|
||||
who conveys the material (or modified versions of it) with contractual assumptions of
|
||||
liability to the recipient, for any liability that these contractual assumptions
|
||||
directly impose on those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered “further
|
||||
restrictions” within the meaning of section 10. If the Program as you received
|
||||
it, or any part of it, contains a notice stating that it is governed by this License
|
||||
along with a term that is a further restriction, you may remove that term. If a
|
||||
license document contains a further restriction but permits relicensing or conveying
|
||||
under this License, you may add to a covered work material governed by the terms of
|
||||
that license document, provided that the further restriction does not survive such
|
||||
relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you must place, in
|
||||
the relevant source files, a statement of the additional terms that apply to those
|
||||
files, or a notice indicating where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the form of a
|
||||
separately written license, or stated as exceptions; the above requirements apply
|
||||
either way.
|
||||
|
||||
### 8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly provided under
|
||||
this License. Any attempt otherwise to propagate or modify it is void, and will
|
||||
automatically terminate your rights under this License (including any patent licenses
|
||||
granted under the third paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your license from a
|
||||
particular copyright holder is reinstated (a) provisionally, unless and until the
|
||||
copyright holder explicitly and finally terminates your license, and (b) permanently,
|
||||
if the copyright holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is reinstated permanently
|
||||
if the copyright holder notifies you of the violation by some reasonable means, this
|
||||
is the first time you have received notice of violation of this License (for any
|
||||
work) from that copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the licenses of
|
||||
parties who have received copies or rights from you under this License. If your
|
||||
rights have been terminated and not permanently reinstated, you do not qualify to
|
||||
receive new licenses for the same material under section 10.
|
||||
|
||||
### 9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or run a copy of the
|
||||
Program. Ancillary propagation of a covered work occurring solely as a consequence of
|
||||
using peer-to-peer transmission to receive a copy likewise does not require
|
||||
acceptance. However, nothing other than this License grants you permission to
|
||||
propagate or modify any covered work. These actions infringe copyright if you do not
|
||||
accept this License. Therefore, by modifying or propagating a covered work, you
|
||||
indicate your acceptance of this License to do so.
|
||||
|
||||
### 10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically receives a license
|
||||
from the original licensors, to run, modify and propagate that work, subject to this
|
||||
License. You are not responsible for enforcing compliance by third parties with this
|
||||
License.
|
||||
|
||||
An “entity transaction” is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an organization, or
|
||||
merging organizations. If propagation of a covered work results from an entity
|
||||
transaction, each party to that transaction who receives a copy of the work also
|
||||
receives whatever licenses to the work the party's predecessor in interest had or
|
||||
could give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if the predecessor
|
||||
has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the rights granted or
|
||||
affirmed under this License. For example, you may not impose a license fee, royalty,
|
||||
or other charge for exercise of rights granted under this License, and you may not
|
||||
initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that any patent claim is infringed by making, using, selling, offering for sale, or
|
||||
importing the Program or any portion of it.
|
||||
|
||||
### 11. Patents.
|
||||
|
||||
A “contributor” is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The work thus
|
||||
licensed is called the contributor's “contributor version”.
|
||||
|
||||
A contributor's “essential patent claims” are all patent claims owned or
|
||||
controlled by the contributor, whether already acquired or hereafter acquired, that
|
||||
would be infringed by some manner, permitted by this License, of making, using, or
|
||||
selling its contributor version, but do not include claims that would be infringed
|
||||
only as a consequence of further modification of the contributor version. For
|
||||
purposes of this definition, “control” includes the right to grant patent
|
||||
sublicenses in a manner consistent with the requirements of this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free patent license
|
||||
under the contributor's essential patent claims, to make, use, sell, offer for sale,
|
||||
import and otherwise run, modify and propagate the contents of its contributor
|
||||
version.
|
||||
|
||||
In the following three paragraphs, a “patent license” is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent (such as an
|
||||
express permission to practice a patent or covenant not to sue for patent
|
||||
infringement). To “grant” such a patent license to a party means to make
|
||||
such an agreement or commitment not to enforce a patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license, and the
|
||||
Corresponding Source of the work is not available for anyone to copy, free of charge
|
||||
and under the terms of this License, through a publicly available network server or
|
||||
other readily accessible means, then you must either (1) cause the Corresponding
|
||||
Source to be so available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner consistent with
|
||||
the requirements of this License, to extend the patent license to downstream
|
||||
recipients. “Knowingly relying” means you have actual knowledge that, but
|
||||
for the patent license, your conveying the covered work in a country, or your
|
||||
recipient's use of the covered work in a country, would infringe one or more
|
||||
identifiable patents in that country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or arrangement, you
|
||||
convey, or propagate by procuring conveyance of, a covered work, and grant a patent
|
||||
license to some of the parties receiving the covered work authorizing them to use,
|
||||
propagate, modify or convey a specific copy of the covered work, then the patent
|
||||
license you grant is automatically extended to all recipients of the covered work and
|
||||
works based on it.
|
||||
|
||||
A patent license is “discriminatory” if it does not include within the
|
||||
scope of its coverage, prohibits the exercise of, or is conditioned on the
|
||||
non-exercise of one or more of the rights that are specifically granted under this
|
||||
License. You may not convey a covered work if you are a party to an arrangement with
|
||||
a third party that is in the business of distributing software, under which you make
|
||||
payment to the third party based on the extent of your activity of conveying the
|
||||
work, and under which the third party grants, to any of the parties who would receive
|
||||
the covered work from you, a discriminatory patent license (a) in connection with
|
||||
copies of the covered work conveyed by you (or copies made from those copies), or (b)
|
||||
primarily for and in connection with specific products or compilations that contain
|
||||
the covered work, unless you entered into that arrangement, or that patent license
|
||||
was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting any implied
|
||||
license or other defenses to infringement that may otherwise be available to you
|
||||
under applicable patent law.
|
||||
|
||||
### 12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or otherwise)
|
||||
that contradict the conditions of this License, they do not excuse you from the
|
||||
conditions of this License. If you cannot convey a covered work so as to satisfy
|
||||
simultaneously your obligations under this License and any other pertinent
|
||||
obligations, then as a consequence you may not convey it at all. For example, if you
|
||||
agree to terms that obligate you to collect a royalty for further conveying from
|
||||
those to whom you convey the Program, the only way you could satisfy both those terms
|
||||
and this License would be to refrain entirely from conveying the Program.
|
||||
|
||||
### 13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have permission to link or
|
||||
combine any covered work with a work licensed under version 3 of the GNU Affero
|
||||
General Public License into a single combined work, and to convey the resulting work.
|
||||
The terms of this License will continue to apply to the part which is the covered
|
||||
work, but the special requirements of the GNU Affero General Public License, section
|
||||
13, concerning interaction through a network will apply to the combination as such.
|
||||
|
||||
### 14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of the GNU
|
||||
General Public License from time to time. Such new versions will be similar in spirit
|
||||
to the present version, but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program specifies that
|
||||
a certain numbered version of the GNU General Public License “or any later
|
||||
version” applies to it, you have the option of following the terms and
|
||||
conditions either of that numbered version or of any later version published by the
|
||||
Free Software Foundation. If the Program does not specify a version number of the GNU
|
||||
General Public License, you may choose any version ever published by the Free
|
||||
Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future versions of the GNU
|
||||
General Public License can be used, that proxy's public statement of acceptance of a
|
||||
version permanently authorizes you to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different permissions. However, no
|
||||
additional obligations are imposed on any author or copyright holder as a result of
|
||||
your choosing to follow a later version.
|
||||
|
||||
### 15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE
|
||||
QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
|
||||
DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
### 16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY
|
||||
COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS
|
||||
PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
|
||||
INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE
|
||||
OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE
|
||||
WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
### 17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided above cannot be
|
||||
given local legal effect according to their terms, reviewing courts shall apply local
|
||||
law that most closely approximates an absolute waiver of all civil liability in
|
||||
connection with the Program, unless a warranty or assumption of liability accompanies
|
||||
a copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
## How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest possible use to
|
||||
the public, the best way to achieve this is to make it free software which everyone
|
||||
can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest to attach them
|
||||
to the start of each source file to most effectively state the exclusion of warranty;
|
||||
and each file should have at least the “copyright” line and a pointer to
|
||||
where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type 'show c' for details.
|
||||
|
||||
The hypothetical commands 'show w' and 'show c' should show the appropriate parts of
|
||||
the General Public License. Of course, your program's commands might be different;
|
||||
for a GUI interface, you would use an “about box”.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school, if any, to
|
||||
sign a “copyright disclaimer” for the program, if necessary. For more
|
||||
information on this, and how to apply and follow the GNU GPL, see
|
||||
<<http://www.gnu.org/licenses/>>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may consider it
|
||||
more useful to permit linking proprietary applications with the library. If this is
|
||||
what you want to do, use the GNU Lesser General Public License instead of this
|
||||
License. But first, please read
|
||||
<<http://www.gnu.org/philosophy/why-not-lgpl.html>>.
|
80
INSTALL.md
Normal file
80
INSTALL.md
Normal file
|
@ -0,0 +1,80 @@
|
|||
# Installation and configuration guide
|
||||
|
||||
I assume that you have a basic understanding of XMPP and the the concept of a XMPP component / transport. If not, please get a book about Jabber or read the standards.
|
||||
|
||||
transWhat is a XMPP transport. By this means it extends the functionallity of an existing XMPP server. It acts as a gateway between the XMPP and WhatsApp networks. It receives WhatsApp messages and forwards them to your XMPP client (and vice-versa).
|
||||
|
||||
The implementation of transWhat is based on the [Spectrum 2](http://www.spectrum.im) framework and the [Yowsup 2](https://github.com/tgalal/yowsup) library to interface with WhatsApp.
|
||||
|
||||
The following chart summarizes the involved components and the protocols they use to communicate.
|
||||
|
||||
## Prosody
|
||||
|
||||
### Installation
|
||||
|
||||
I will not cover the installation of Prosody in this guide. Please look for some other tutorials on how to do that.
|
||||
|
||||
### Configuration
|
||||
|
||||
The only important thing for us is the configuration of a XMPP component (Spectrum 2 in our case).
|
||||
See http://prosody.im/doc/components.
|
||||
|
||||
Append the following at the end of `/etc/prosody/prosody.cfg.lua`
|
||||
|
||||
Component "whatsapp.0l.de"
|
||||
component_secret = "whatsappsucks"
|
||||
component_ports = { 5221 }
|
||||
component_interface = "127.0.0.1"
|
||||
|
||||
## Spectrum 2
|
||||
|
||||
#### Installation
|
||||
|
||||
Manual compile latest version from [Github](https://github.com/hanzz/libtransport).
|
||||
You can use the following guide: http://spectrum.im/documentation/installation/from_source_code.html.
|
||||
|
||||
#### Configuration
|
||||
|
||||
Create a new file `/etc/spectrum2/transports/whatsapp.cfg` with the following content:
|
||||
|
||||
[service]
|
||||
user = spectrum
|
||||
group = spectrum
|
||||
|
||||
jid = whatsapp.0l.de
|
||||
|
||||
server = localhost
|
||||
password = whatsappsucks
|
||||
port = 5221
|
||||
|
||||
backend_host = localhost
|
||||
backend = /location/to/transwhat/transwhat.py
|
||||
|
||||
users_per_backend = 10
|
||||
more_resources = 1
|
||||
|
||||
admin_jid = your@jid.example
|
||||
|
||||
[identity]
|
||||
name = transWhat
|
||||
type = xmpp
|
||||
category = gateway
|
||||
|
||||
[logging]
|
||||
config = /etc/spectrum2/logging.cfg
|
||||
backend_config = /etc/spectrum2/backend-logging.cfg
|
||||
|
||||
## transWhat
|
||||
|
||||
### Installation
|
||||
|
||||
Checkout the latest version of transWhat from GitHub:
|
||||
|
||||
$ git clone git@github.com:stv0g/transwhat.git
|
||||
|
||||
Install required dependencies:
|
||||
|
||||
$ pip install --pre e4u protobuf python-dateutil yowsup
|
||||
|
||||
- **e4u**: is a simple emoji4unicode python bindings
|
||||
- [**yowsup**](https://github.com/tgalal/yowsup): is a python library that enables you build application which use WhatsApp service.
|
35
README.md
35
README.md
|
@ -2,20 +2,16 @@
|
|||
|
||||
transWhat is a WhatsApp XMPP Gateway based on [Spectrum 2](http://www.spectrum.im) and [Yowsup 2](https://github.com/tgalal/yowsup).
|
||||
|
||||
## Dependencies
|
||||
## [Installation](INSTALL.md)
|
||||
## [Usage](USAGE.md)
|
||||
|
||||
#### Python packages
|
||||
## Features
|
||||
|
||||
pip install e4u protobuf mysql dateutil
|
||||
|
||||
- **e4u**: is a simple emoji4unicode python bindings
|
||||
- [**yowsup**](https://github.com/tgalal/yowsup): is a python library that enables you build application which use WhatsApp service.
|
||||
- **mysqldb**: MySQL client python bindings
|
||||
|
||||
#### Spectrum 2
|
||||
is a XMPP transport
|
||||
|
||||
Manual compile latest version from https://github.com/hanzz/libtransport.
|
||||
* Typing notifications
|
||||
* Receive images, audio & video
|
||||
* Set/get online status
|
||||
* Set status message
|
||||
* Groupchats
|
||||
|
||||
## Contributors
|
||||
|
||||
|
@ -23,11 +19,18 @@ Pull requests, bug reports etc. are welcome. Help us to provide a open implement
|
|||
|
||||
The following persons have contributed major parts of this code:
|
||||
|
||||
- **Steffen Vogel** (@stv0g): Idea and initial implementation based on Yowsup 1
|
||||
- **Mohammed Yaseen Mowzer** (@moyamo): Port to Yowsup 2
|
||||
- @stv0g (Steffen Vogel): Idea and initial implementation based on Yowsup 1
|
||||
- @moyamo (Mohammed Yaseen Mowzer): Port to Yowsup 2
|
||||
- @DaZZZl: Improvements to group chats, media & message receipts
|
||||
|
||||
## Documentation
|
||||
## [License](COPYING.md)
|
||||
|
||||
A project wiki is available [here](https://dev.0l.de/wiki/projects/transwhat/).
|
||||
transWhat 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.
|
||||
|
||||
Foobar 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.
|
||||
|
||||
## Links
|
||||
|
||||
An *outdated* project wiki is available [here](https://dev.0l.de/wiki/projects/transwhat/).
|
||||
|
||||
An *outdated* writeup of this project is also availabe at my [blog](http://www.steffenvogel.de/2013/06/29/transwhat/).
|
||||
|
|
|
@ -19,6 +19,7 @@ class SpectrumBackend:
|
|||
@param host: Host where Spectrum2 NetworkPluginServer runs.
|
||||
@param port: Port.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.m_pingReceived = False
|
||||
self.m_data = ""
|
||||
|
@ -344,6 +345,14 @@ class SpectrumBackend:
|
|||
groups = [g for g in payload.group]
|
||||
self.handleBuddyRemovedRequest(payload.userName, payload.buddyName, groups);
|
||||
|
||||
def handleBuddiesPayload(self, data):
|
||||
payload = protocol_pb2.Buddies()
|
||||
if (payload.ParseFromString(data) == False):
|
||||
#TODO: ERROR
|
||||
return
|
||||
|
||||
self.handleBuddies(payload);
|
||||
|
||||
def handleChatStatePayload(self, data, msgType):
|
||||
payload = protocol_pb2.Buddy()
|
||||
if (payload.ParseFromString(data) == False):
|
||||
|
@ -364,10 +373,10 @@ class SpectrumBackend:
|
|||
if (len(self.m_data) >= 4):
|
||||
expected_size = struct.unpack('!I', self.m_data[0:4])[0]
|
||||
if (len(self.m_data) - 4 < expected_size):
|
||||
self.logger.error("Expected Data Size Error")
|
||||
self.logger.debug("Data packet incomplete")
|
||||
return
|
||||
else:
|
||||
self.logger.error("Data too small")
|
||||
self.logger.debug("Data packet incomplete")
|
||||
return
|
||||
|
||||
packet = self.m_data[4:4+expected_size]
|
||||
|
@ -376,17 +385,15 @@ class SpectrumBackend:
|
|||
parseFromString = wrapper.ParseFromString(packet)
|
||||
except:
|
||||
self.m_data = self.m_data[expected_size+4:]
|
||||
self.logger.error("Parse from String exception")
|
||||
self.logger.error("Parse from String exception. Skipping packet.")
|
||||
return
|
||||
|
||||
if parseFromString == False:
|
||||
self.m_data = self.m_data[expected_size+4:]
|
||||
self.logger.error("Parse from String failed")
|
||||
self.logger.error("Parse from String failed. Skipping packet.")
|
||||
return
|
||||
|
||||
self.m_data = self.m_data[4+expected_size:]
|
||||
#self.logger.error("Data Type: %s",wrapper.type)
|
||||
|
||||
|
||||
if wrapper.type == protocol_pb2.WrapperMessage.TYPE_LOGIN:
|
||||
self.handleLoginPayload(wrapper.payload)
|
||||
|
@ -430,6 +437,8 @@ class SpectrumBackend:
|
|||
self.handleConvMessageAckPayload(wrapper.payload)
|
||||
elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_RAW_XML:
|
||||
self.handleRawXmlRequest(wrapper.payload)
|
||||
elif wrapper.type == protocol_pb2.WrapperMessage.TYPE_BUDDIES:
|
||||
self.handleBuddiesPayload(wrapper.payload)
|
||||
|
||||
def send(self, data):
|
||||
header = struct.pack('!I',len(data))
|
||||
|
@ -490,6 +499,9 @@ class SpectrumBackend:
|
|||
|
||||
raise NotImplementedError, "Implement me"
|
||||
|
||||
def handleBuddies(self, buddies):
|
||||
pass
|
||||
|
||||
def handleLogoutRequest(self, user, legacyName):
|
||||
"""
|
||||
Called when XMPP user wants to disconnect legacy network.
|
||||
|
|
|
@ -63,6 +63,10 @@ message Buddy {
|
|||
optional bool blocked = 8;
|
||||
}
|
||||
|
||||
message Buddies {
|
||||
repeated Buddy buddy = 1;
|
||||
}
|
||||
|
||||
message ConversationMessage {
|
||||
required string userName = 1;
|
||||
required string buddyName = 2;
|
||||
|
@ -182,6 +186,7 @@ message WrapperMessage {
|
|||
TYPE_ROOM_LIST = 32;
|
||||
TYPE_CONV_MESSAGE_ACK = 33;
|
||||
TYPE_RAW_XML = 34;
|
||||
TYPE_BUDDIES = 35;
|
||||
}
|
||||
required Type type = 1;
|
||||
optional bytes payload = 2;
|
||||
|
|
File diff suppressed because one or more lines are too long
73
USAGE.md
Normal file
73
USAGE.md
Normal file
|
@ -0,0 +1,73 @@
|
|||
# Usage
|
||||
|
||||
## Starting/stopping service
|
||||
|
||||
The `transwhat.py` script gets started as a backend by Spectrum. You should not try to run it manually.
|
||||
To simplify the management of multiple transports (WhatsApp, IRC, Facebook, libpurple, ...), Spectrum provides a little helper tool called `spectrum_manager`:
|
||||
|
||||
To start transwhat run
|
||||
|
||||
```
|
||||
spectrum_manager start whatsapp
|
||||
|
||||
```
|
||||
|
||||
To stop transwhat run
|
||||
|
||||
```
|
||||
spectrum_manager stop whatsapp
|
||||
```
|
||||
|
||||
## Bot
|
||||
|
||||
You might want to talk to bot if you're feeling lonely ;-P
|
||||
|
||||
The bot is one of the contacts every user has in its contact list. It offers you a simple way to interact with the server:
|
||||
|
||||
| **Command** | **Description** |
|
||||
| ------------ | --------------- |
|
||||
| `\help` | show this message |
|
||||
| `\prune` | clear your buddylist |
|
||||
| `\sync` | sync your imported contacts with WhatsApp |
|
||||
| `\lastseen` | request last online timestamp from buddy |
|
||||
| `\leave` | permanently leave group chat |
|
||||
| `\groups` | print all attended groups |
|
||||
| `\getgroups` | get current groups from WA |
|
||||
|
||||
<note tip>All commands start with a **back**slash!</note>
|
||||
|
||||
## Login
|
||||
|
||||
To login to the transWhat, you should use the service discovery option in your XMPP client.
|
||||
|
||||
When asked about the login credentials, enter your data as described below:
|
||||
|
||||
| **Setting** | **Value** | **Example** |
|
||||
| ----------- | ------------------------- | --------------- |
|
||||
| User | CountryCode + PhoneNumber | 4917634911387 |
|
||||
| Password | WhatsApp password | [*Base64 string*](https://github.com/davidgfnet/whatsapp-purple#how-do-i-get-my-user-name-and-password)|
|
||||
|
||||
|
||||
### Buddies
|
||||
|
||||
WhatsApp does not store your contacts on their servers. Thus you need to import your contacts manually with your XMPP Client or use [[.:bot|our bot]] to Import your contacts from Google (preferred).
|
||||
|
||||
(In Pidgin: Menu => Buddys => Add Buddy)
|
||||
|
||||
Just use the same JID format as for your login:
|
||||
|
||||
CountryCode + PhoneNumber + "@whatsapp.example.org"
|
||||
|
||||
### Groups
|
||||
|
||||
To chat with groups you need to add them manually to your XMPP client.
|
||||
|
||||
To get a list of your WhatsApp groups, you can use the Auto Discovery functionality of your XMPP client.
|
||||
|
||||
(In Pidgin: Menu => Buddys => Join Chat => RoomList)
|
||||
|
||||
### Smileys / Emojis
|
||||
|
||||
To be able to see smileys, you will need an [Unicode Emoji font](https://github.com/stv0g/unicode-emoji/raw/master/symbola/Symbola.ttf).
|
||||
|
||||
When using Pidgin, you might want to check out my [stv0g's Unicode emoji theme](https://github.com/stv0g/unicode-emoji)].
|
110
bot.py
110
bot.py
|
@ -1,9 +1,8 @@
|
|||
__author__ = "Steffen Vogel"
|
||||
__copyright__ = "Copyright 2013, Steffen Vogel"
|
||||
__copyright__ = "Copyright 2015, Steffen Vogel"
|
||||
__license__ = "GPLv3"
|
||||
__maintainer__ = "Steffen Vogel"
|
||||
__email__ = "post@steffenvogel.de"
|
||||
__status__ = "Prototype"
|
||||
|
||||
"""
|
||||
This file is part of transWhat
|
||||
|
@ -30,24 +29,14 @@ import time
|
|||
import os
|
||||
import utils
|
||||
|
||||
from constants import *
|
||||
#from googleclient import GoogleClient
|
||||
|
||||
#from Yowsup.Contacts.contacts import WAContactsSyncRequest
|
||||
|
||||
class Bot():
|
||||
def __init__(self, session, name = "Bot"):
|
||||
self.session = session
|
||||
self.name = name
|
||||
|
||||
#self.google = GoogleClient()
|
||||
|
||||
self.commands = {
|
||||
"import": self._import,
|
||||
"help": self._help,
|
||||
"prune": self._prune,
|
||||
"welcome": self._welcome,
|
||||
"fortune": self._fortune,
|
||||
"sync": self._sync,
|
||||
"groups": self._groups,
|
||||
"getgroups": self._getgroups
|
||||
|
@ -81,81 +70,7 @@ class Bot():
|
|||
def send(self, message):
|
||||
self.session.backend.handleMessage(self.session.user, self.name, message)
|
||||
|
||||
def __do_import(self, token):
|
||||
# Google
|
||||
google = self.google.getContacts(token)
|
||||
self.send("%d buddies imported from google" % len(google))
|
||||
|
||||
result = { }
|
||||
for number, name in google.iteritems():
|
||||
number = re.sub("[^0-9]", "", number)
|
||||
number = number if number[0] == "0" else "+" + number
|
||||
|
||||
result[number] = { 'nick': name, 'state': 0 }
|
||||
|
||||
# WhatsApp
|
||||
user = self.session.legacyName
|
||||
password = self.session.password
|
||||
sync = WAContactsSyncRequest(user, password, result.keys())
|
||||
whatsapp = sync.send()['c']
|
||||
|
||||
for w in whatsapp:
|
||||
result[w['p']]['state'] = w['w']
|
||||
result[w['p']]['number'] = w['n']
|
||||
|
||||
self.send("%d buddies are using whatsapp" % len(filter(lambda w: w['w'], whatsapp)))
|
||||
|
||||
for r in result.values():
|
||||
if r['nick']:
|
||||
self.session.buddies.add(
|
||||
number = r['number'],
|
||||
nick = r['nick'],
|
||||
groups = [u'Google'],
|
||||
state = r['state']
|
||||
)
|
||||
|
||||
self.send("%d buddies imported" % len(whatsapp))
|
||||
|
||||
def __get_token(self, filename, timeout = 30):
|
||||
file = open(filename, 'r')
|
||||
file.seek(-1, 2) # look at the end
|
||||
|
||||
count = 0
|
||||
while count < timeout:
|
||||
line = file.readline()
|
||||
|
||||
if line in ["", "\n"]:
|
||||
time.sleep(1)
|
||||
count += 1
|
||||
continue
|
||||
else:
|
||||
timestamp, number, token = line[:-1].split("\t")
|
||||
if (number == self.session.legacyName):
|
||||
file.close()
|
||||
return token
|
||||
|
||||
file.close()
|
||||
|
||||
# commands
|
||||
def _import(self, token = None):
|
||||
if not token:
|
||||
token_url = self.google.getTokenUrl("http://whatsapp.0l.de/auth.py")
|
||||
auth_url = "http://whatsapp.0l.de/auth.py?number=%s&auth_url=%s" % (self.session.legacyName, urllib.quote(token_url))
|
||||
short_url = utils.shorten(auth_url)
|
||||
self.send("please visit this url to auth: %s" % short_url)
|
||||
|
||||
self.send("waiting for authorization...")
|
||||
token = self.__get_token(TOKEN_FILE)
|
||||
if token:
|
||||
self.send("got token: %s" % token)
|
||||
self.__do_import(token)
|
||||
self.session.updateRoster()
|
||||
else:
|
||||
self.send("timeout! please use \"\\import [token]\"")
|
||||
else:
|
||||
self.__do_import(token)
|
||||
self.session.updateRoster()
|
||||
|
||||
def _sync(self):
|
||||
user = self.session.legacyName
|
||||
password = self.session.password
|
||||
|
@ -172,31 +87,21 @@ class Bot():
|
|||
self.send("""following bot commands are available:
|
||||
\\help show this message
|
||||
\\prune clear your buddylist
|
||||
\\import [token] import buddies from Google
|
||||
\\sync sync your imported contacts with WhatsApp
|
||||
\\fortune [database] give me a quote
|
||||
\\groups print all attended groups
|
||||
\\getgroups get current groups from WA
|
||||
|
||||
following user commands are available:
|
||||
\\lastseen request last online timestamp from buddy""")
|
||||
\\lastseen request last online timestamp from buddy
|
||||
|
||||
def _fortune(self, database = '', prefix=''):
|
||||
if os.path.exists("/usr/share/fortune/%s" % database):
|
||||
fortune = os.popen('/usr/bin/fortune %s' % database).read()
|
||||
self.send(prefix + fortune[:-1])
|
||||
else:
|
||||
self.send("invalid database")
|
||||
|
||||
def _welcome(self):
|
||||
motd = open(MOTD_FILE, "r").read()
|
||||
self.send(motd[:-1])
|
||||
self.call("fortune", ("disclaimer", "Disclaimer: "))
|
||||
following group commands are available
|
||||
\\leave permanently leave group chat
|
||||
\\groups print all attended groups
|
||||
\\getgroups get current groups from WA""")
|
||||
|
||||
def _prune(self):
|
||||
self.session.buddies.prune()
|
||||
self.session.updateRoster()
|
||||
self.send("buddy list cleared")
|
||||
|
||||
def _groups(self):
|
||||
for group in self.session.groups:
|
||||
buddy = self.session.groups[group].owner
|
||||
|
@ -206,6 +111,7 @@ following user commands are available:
|
|||
nick = buddy
|
||||
|
||||
self.send(self.session.groups[group].id + "@" + self.session.backend.spectrum_jid + " " + self.session.groups[group].subject + " Owner: " + nick )
|
||||
|
||||
def _getgroups(self):
|
||||
#self.session.call("group_getGroups", ("participating",))
|
||||
self.session.requestGroupsList(self.session._updateGroups)
|
||||
|
|
204
buddy.py
204
buddy.py
|
@ -1,9 +1,8 @@
|
|||
__author__ = "Steffen Vogel"
|
||||
__copyright__ = "Copyright 2013, Steffen Vogel"
|
||||
__copyright__ = "Copyright 2015, Steffen Vogel"
|
||||
__license__ = "GPLv3"
|
||||
__maintainer__ = "Steffen Vogel"
|
||||
__email__ = "post@steffenvogel.de"
|
||||
__status__ = "Prototype"
|
||||
|
||||
"""
|
||||
This file is part of transWhat
|
||||
|
@ -25,39 +24,15 @@ __status__ = "Prototype"
|
|||
from Spectrum2 import protocol_pb2
|
||||
|
||||
import logging
|
||||
import threading
|
||||
|
||||
|
||||
class Number():
|
||||
|
||||
def __init__(self, number, state, db):
|
||||
self.number = number
|
||||
self.db = db
|
||||
self.state = state
|
||||
|
||||
cur = self.db.cursor()
|
||||
cur.execute("SELECT id FROM numbers WHERE number = %s AND state = %s", (self.number, self.state))
|
||||
if (cur.rowcount):
|
||||
self.id = cur.fetchone()[0]
|
||||
else:
|
||||
cur.execute("REPLACE numbers (number, state) VALUES (%s, %s)", (self.number, self.state))
|
||||
self.db.commit()
|
||||
self.id = cur.lastrowid
|
||||
|
||||
def __str__(self):
|
||||
return "%s (id=%s)" % (self.number, self.id)
|
||||
|
||||
|
||||
class Buddy():
|
||||
def __init__(self, owner, number, nick, groups, image_hash, id, db):
|
||||
self.id = id
|
||||
self.db = db
|
||||
|
||||
def __init__(self, owner, number, nick, statusMsg, groups, image_hash):
|
||||
self.nick = nick
|
||||
self.owner = owner
|
||||
self.number = number
|
||||
self.groups = groups
|
||||
self.image_hash = image_hash
|
||||
self.image_hash = image_hash if image_hash is not None else ""
|
||||
self.statusMsg = ""
|
||||
self.lastseen = 0
|
||||
self.presence = 0
|
||||
|
@ -69,121 +44,100 @@ class Buddy():
|
|||
if image_hash is not None:
|
||||
self.image_hash = image_hash
|
||||
|
||||
groups = u",".join(groups).encode("latin-1")
|
||||
cur = self.db.cursor()
|
||||
cur.execute("UPDATE buddies SET nick = %s, groups = %s, image_hash = %s WHERE owner_id = %s AND buddy_id = %s", (self.nick, groups, self.image_hash, self.owner.id, self.number.id))
|
||||
self.db.commit()
|
||||
|
||||
def delete(self):
|
||||
cur = self.db.cursor()
|
||||
cur.execute("DELETE FROM buddies WHERE owner_id = %s AND buddy_id = %s", (self.owner.id, self.number.id))
|
||||
self.db.commit()
|
||||
self.id = None
|
||||
|
||||
@staticmethod
|
||||
def create(owner, number, nick, groups, image_hash, db):
|
||||
groups = u",".join(groups).encode("latin-1")
|
||||
cur = db.cursor()
|
||||
cur.execute("REPLACE buddies (owner_id, buddy_id, nick, groups, image_hash) VALUES (%s, %s, %s, %s, %s)", (owner.id, number.id, nick, groups, image_hash))
|
||||
db.commit()
|
||||
|
||||
return Buddy(owner, number, nick, groups, image_hash, cur.lastrowid, db)
|
||||
|
||||
def __str__(self):
|
||||
return "%s (nick=%s, id=%s)" % (self.number, self.nick, self.id)
|
||||
return "%s (nick=%s)" % (self.number, self.nick)
|
||||
|
||||
class BuddyList(dict):
|
||||
|
||||
def __init__(self, owner, db):
|
||||
self.db = db
|
||||
self.owner = Number(owner, 1, db)
|
||||
self.lock = threading.Lock()
|
||||
def __init__(self, owner, backend, user, session):
|
||||
self.owner = owner
|
||||
self.backend = backend
|
||||
self.session = session
|
||||
self.user = user
|
||||
self.logger = logging.getLogger(self.__class__.__name__)
|
||||
self.synced = False
|
||||
|
||||
def _load(self, buddies):
|
||||
for buddy in buddies:
|
||||
number = buddy.buddyName
|
||||
nick = buddy.alias
|
||||
statusMsg = buddy.statusMessage
|
||||
groups = [g for g in buddy.group]
|
||||
image_hash = buddy.iconHash
|
||||
self[number] = Buddy(self.owner, number, nick, statusMsg,
|
||||
groups, image_hash)
|
||||
|
||||
self.logger.debug("Update roster")
|
||||
|
||||
# old = self.buddies.keys()
|
||||
# self.buddies.load()
|
||||
# new = self.buddies.keys()
|
||||
# contacts = new
|
||||
contacts = self.keys()
|
||||
|
||||
if self.synced == False:
|
||||
self.session.sendSync(contacts, delta = False, interactive = True)
|
||||
self.synced = True
|
||||
|
||||
# add = set(new) - set(old)
|
||||
# remove = set(old) - set(new)
|
||||
|
||||
# self.logger.debug("Roster remove: %s", str(list(remove)))
|
||||
self.logger.debug("Roster add: %s", str(list(contacts)))
|
||||
|
||||
# for number in remove:
|
||||
# self.backend.handleBuddyChanged(self.user, number, "", [],
|
||||
# protocol_pb2.STATUS_NONE)
|
||||
# self.backend.handleBuddyRemoved(self.user, number)
|
||||
# self.unsubscribePresence(number)
|
||||
#
|
||||
for number in contacts:
|
||||
buddy = self[number]
|
||||
if number != 'bot':
|
||||
self.backend.handleBuddyChanged(self.user, number, buddy.nick,
|
||||
buddy.groups, protocol_pb2.STATUS_NONE,
|
||||
iconHash = buddy.image_hash if buddy.image_hash is not None else "")
|
||||
self.session.subscribePresence(number)
|
||||
|
||||
|
||||
def load(self):
|
||||
self.clear()
|
||||
self.lock.acquire()
|
||||
|
||||
cur = self.db.cursor()
|
||||
cur.execute("""SELECT
|
||||
b.id AS id,
|
||||
n.number AS number,
|
||||
b.nick AS nick,
|
||||
b.groups AS groups,
|
||||
n.state AS state,
|
||||
b.image_hash AS image_hash
|
||||
FROM buddies AS b
|
||||
LEFT JOIN numbers AS n
|
||||
ON b.buddy_id = n.id
|
||||
WHERE
|
||||
b.owner_id IN (%s, 0)
|
||||
AND n.state >= 1
|
||||
ORDER BY b.owner_id DESC""", self.owner.id)
|
||||
|
||||
for i in range(cur.rowcount):
|
||||
id, number, nick, groups, state, image_hash = cur.fetchone()
|
||||
self[number] = Buddy(self.owner, Number(number, state, self.db), nick.decode('latin1'), groups.split(","), image_hash, id, self.db)
|
||||
self.lock.release()
|
||||
|
||||
def load(self, buddies):
|
||||
if self.session.loggedIn:
|
||||
self._load(buddies)
|
||||
else:
|
||||
self.session.loginQueue.append(lambda: self._load(buddies))
|
||||
|
||||
def update(self, number, nick, groups, image_hash):
|
||||
self.lock.acquire()
|
||||
if number in self:
|
||||
buddy = self[number]
|
||||
buddy.update(nick, groups, image_hash)
|
||||
else:
|
||||
buddy = self.add(number, nick, groups, 1, image_hash)
|
||||
self.lock.release()
|
||||
self.session.sendSync([number], delta = True, interactive = True)
|
||||
self.session.subscribePresence(number)
|
||||
buddy = Buddy(self.owner, number, nick, "", groups, image_hash)
|
||||
self[number] = buddy
|
||||
self.logger.debug("Roster add: %s", buddy)
|
||||
|
||||
if buddy.presence == 0:
|
||||
status = protocol_pb2.STATUS_NONE
|
||||
elif buddy.presence == 'unavailable':
|
||||
status = protocol_pb2.STATUS_AWAY
|
||||
else:
|
||||
status = protocol_pb2.STATUS_ONLINE
|
||||
self.backend.handleBuddyChanged(self.user, number, buddy.nick,
|
||||
buddy.groups, status,
|
||||
iconHash = buddy.image_hash if buddy.image_hash is not None else "")
|
||||
|
||||
return buddy
|
||||
|
||||
def add(self, number, nick, groups = [], state = 0, image_hash = ""):
|
||||
return Buddy.create(self.owner, Number(number, state, self.db), nick, groups, image_hash, self.db)
|
||||
|
||||
def remove(self, number):
|
||||
try:
|
||||
buddy = self[number]
|
||||
self.lock.acquire()
|
||||
buddy.delete()
|
||||
self.lock.release()
|
||||
del self[number]
|
||||
self.backend.handleBuddyChanged(self.user, number, "", [],
|
||||
protocol_pb2.STATUS_NONE)
|
||||
self.backend.handleBuddyRemoved(self.user, number)
|
||||
self.session.unsubscribePresence(number)
|
||||
# TODO Sync remove
|
||||
return buddy
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
def prune(self):
|
||||
self.lock.acquire()
|
||||
|
||||
cur = self.db.cursor()
|
||||
cur.execute("DELETE FROM buddies WHERE owner_id = %s", self.owner.id)
|
||||
self.db.commit()
|
||||
self.lock.release()
|
||||
|
||||
|
||||
def sync(self, user, password):
|
||||
self.lock.acquire()
|
||||
cur = self.db.cursor()
|
||||
cur.execute("""SELECT
|
||||
n.number AS number,
|
||||
n.state AS state
|
||||
FROM buddies AS r
|
||||
LEFT JOIN numbers AS n
|
||||
ON r.buddy_id = n.id
|
||||
WHERE
|
||||
r.owner_id = %s""", self.owner.id)
|
||||
|
||||
# prefix every number with leading 0 to force internation format
|
||||
numbers = dict([("+" + number, state) for number, state in cur.fetchall()])
|
||||
|
||||
if len(numbers) == 0:
|
||||
return 0
|
||||
|
||||
result = WAContactsSyncRequest(user, password, numbers.keys()).send()
|
||||
|
||||
using = 0
|
||||
for number in result['c']:
|
||||
cur = self.db.cursor()
|
||||
cur.execute("UPDATE numbers SET state = %s WHERE number = %s", (number['w'], number['n']))
|
||||
self.db.commit()
|
||||
using += number['w']
|
||||
self.lock.release()
|
||||
return using
|
||||
|
|
11
conf/motd
11
conf/motd
|
@ -1,11 +0,0 @@
|
|||
Welcome to transWhat!
|
||||
|
||||
===== NEWS ====
|
||||
- 03.06.13 transWhat service is born
|
||||
- 18.06.13 major deployment of development version
|
||||
- 07.09.15 transWhat is alive again. Now running with new Yowsup 2 library
|
||||
|
||||
Type "\help" for a list of available commands.
|
||||
|
||||
Visit http://github.com/stv0g/transwhat/ for more details.
|
||||
Join xmpp://transwhat@conference.jabber.ccc.de to hangout and discuss.
|
|
@ -1,31 +0,0 @@
|
|||
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
|
||||
SET time_zone = "+00:00";
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
/*!40101 SET NAMES utf8 */;
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `buddies` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`owner_id` int(11) NOT NULL,
|
||||
`buddy_id` int(11) NOT NULL,
|
||||
`nick` varchar(255) NOT NULL,
|
||||
`groups` varchar(255) NOT NULL,
|
||||
`image_hash` varchar(40),
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `numbers` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`number` varchar(32) NOT NULL,
|
||||
`picture` blob NOT NULL,
|
||||
`state` int(11) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `number` (`number`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
|
@ -1,29 +0,0 @@
|
|||
[service]
|
||||
server_mode = 1
|
||||
|
||||
user = spectrum
|
||||
group = spectrum
|
||||
|
||||
jid = whatsapp-dev.0l.de
|
||||
|
||||
server = 0.0.0.0
|
||||
port = 5221
|
||||
|
||||
cert = /home/stv0g/files/whatsapp/transwhat/conf/spectrum_cert.p12
|
||||
|
||||
backend_host = localhost
|
||||
backend = /home/stv0g/files/whatsapp/transwhat/transwhat.py
|
||||
users_per_backend = 10
|
||||
more_resources = 1
|
||||
|
||||
admin_jid = 4917696978528@whatsapp.0l.de
|
||||
|
||||
[identity]
|
||||
name = transWhat
|
||||
|
||||
type = xmpp
|
||||
category = gateway
|
||||
|
||||
[logging]
|
||||
config = /etc/spectrum2/logging.cfg
|
||||
backend_config = /etc/spectrum2/backend-logging.cfg
|
|
@ -1,28 +0,0 @@
|
|||
[service]
|
||||
server_mode = 1
|
||||
|
||||
user = spectrum
|
||||
group = spectrum
|
||||
|
||||
jid = whatsapp.0l.de
|
||||
|
||||
server = 0.0.0.0
|
||||
port = 5222
|
||||
|
||||
cert = /opt/transwhat/conf/spectrum_cert.p12
|
||||
|
||||
backend_host = localhost
|
||||
backend = /opt/transwhat/transwhat.py
|
||||
users_per_backend = 10
|
||||
|
||||
admin_jid = 4917696978528@whatsapp.0l.de
|
||||
|
||||
[identity]
|
||||
name = transWhat
|
||||
|
||||
type = xmpp
|
||||
category = gateway
|
||||
|
||||
[logging]
|
||||
config = /etc/spectrum2/logging.cfg
|
||||
backend_config = /etc/spectrum2/backend-logging.cfg
|
|
@ -1,34 +0,0 @@
|
|||
__author__ = "Steffen Vogel"
|
||||
__copyright__ = "Copyright 2013, Steffen Vogel"
|
||||
__license__ = "GPLv3"
|
||||
__maintainer__ = "Steffen Vogel"
|
||||
__email__ = "post@steffenvogel.de"
|
||||
__status__ = "Prototype"
|
||||
|
||||
"""
|
||||
This file is part of transWhat
|
||||
|
||||
transWhat 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
|
||||
any later version.
|
||||
|
||||
transwhat 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 transWhat. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
DB_HOST = "localhost"
|
||||
DB_USER = ""
|
||||
DB_PASS = ""
|
||||
DB_TABLE = "transwhat"
|
||||
|
||||
BASE_PATH = "/opt/transwhat"
|
||||
|
||||
TOKEN_FILE = BASE_PATH + "/logs/tokens"
|
||||
MOTD_FILE = BASE_PATH + "/conf/motd"
|
||||
REQUESTS_FILE = BASE_PATH + "/logs/requests"
|
6
group.py
6
group.py
|
@ -1,9 +1,8 @@
|
|||
__author__ = "Steffen Vogel"
|
||||
__copyright__ = "Copyright 2013, Steffen Vogel"
|
||||
__copyright__ = "Copyright 2015, Steffen Vogel"
|
||||
__license__ = "GPLv3"
|
||||
__maintainer__ = "Steffen Vogel"
|
||||
__email__ = "post@steffenvogel.de"
|
||||
__status__ = "Prototype"
|
||||
|
||||
"""
|
||||
This file is part of transWhat
|
||||
|
@ -29,6 +28,7 @@ class Group():
|
|||
self.subject = subject
|
||||
self.subjectOwner = subjectOwner
|
||||
self.owner = owner
|
||||
self.joined = False
|
||||
|
||||
self.nick = "me"
|
||||
self.participants = { }
|
||||
self.participants = []
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
__author__ = "Steffen Vogel"
|
||||
__copyright__ = "Copyright 2013, Steffen Vogel"
|
||||
__copyright__ = "Copyright 2015, Steffen Vogel"
|
||||
__license__ = "GPLv3"
|
||||
__maintainer__ = "Steffen Vogel"
|
||||
__email__ = "post@steffenvogel.de"
|
||||
__status__ = "Prototype"
|
||||
|
||||
"""
|
||||
This file is part of transWhat
|
||||
|
|
271
session.py
271
session.py
|
@ -1,9 +1,8 @@
|
|||
__author__ = "Steffen Vogel"
|
||||
__copyright__ = "Copyright 2013, Steffen Vogel"
|
||||
__copyright__ = "Copyright 2015, Steffen Vogel"
|
||||
__license__ = "GPLv3"
|
||||
__maintainer__ = "Steffen Vogel"
|
||||
__email__ = "post@steffenvogel.de"
|
||||
__status__ = "Prototype"
|
||||
|
||||
"""
|
||||
This file is part of transWhat
|
||||
|
@ -28,7 +27,6 @@ import urllib
|
|||
import time
|
||||
|
||||
from PIL import Image
|
||||
import MySQLdb
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
@ -42,7 +40,6 @@ from buddy import BuddyList
|
|||
from threading import Timer
|
||||
from group import Group
|
||||
from bot import Bot
|
||||
from constants import *
|
||||
from yowsupwrapper import YowsupApp
|
||||
|
||||
|
||||
|
@ -57,14 +54,11 @@ class MsgIDs:
|
|||
|
||||
class Session(YowsupApp):
|
||||
|
||||
def __init__(self, backend, user, legacyName, extra, db):
|
||||
def __init__(self, backend, user, legacyName, extra):
|
||||
super(Session, self).__init__()
|
||||
self.logger = logging.getLogger(self.__class__.__name__)
|
||||
self.logger.info("Created: %s", legacyName)
|
||||
|
||||
#self.db = db
|
||||
self.db = MySQLdb.connect(DB_HOST, DB_USER, DB_PASS, DB_TABLE)
|
||||
|
||||
self.backend = backend
|
||||
self.user = user
|
||||
self.legacyName = legacyName
|
||||
|
@ -74,12 +68,14 @@ class Session(YowsupApp):
|
|||
|
||||
self.groups = {}
|
||||
self.gotGroupList = False
|
||||
# Functions to exectute when logged in via yowsup
|
||||
self.loginQueue = []
|
||||
self.joinRoomQueue = []
|
||||
self.presenceRequested = []
|
||||
self.offlineQueue = []
|
||||
self.msgIDs = { }
|
||||
self.groupOfflineQueue = { }
|
||||
self.shouldBeConnected = False
|
||||
self.loggedIn = False
|
||||
|
||||
self.timer = None
|
||||
self.password = None
|
||||
|
@ -87,7 +83,7 @@ class Session(YowsupApp):
|
|||
self.lastMsgId = None
|
||||
self.synced = False
|
||||
|
||||
self.buddies = BuddyList(self.legacyName, self.db)
|
||||
self.buddies = BuddyList(self.legacyName, self.backend, self.user, self)
|
||||
self.bot = Bot(self)
|
||||
|
||||
self.imgMsgId = None
|
||||
|
@ -102,6 +98,7 @@ class Session(YowsupApp):
|
|||
def logout(self):
|
||||
self.logger.info("%s logged out", self.user)
|
||||
super(Session, self).logout()
|
||||
self.loggedIn = False
|
||||
|
||||
def login(self, password):
|
||||
self.logger.info("%s attempting login", self.user)
|
||||
|
@ -132,39 +129,6 @@ class Session(YowsupApp):
|
|||
'\n'.join(text) + '\nIf you do not join them you will lose messages'
|
||||
#self.bot.send(message)
|
||||
|
||||
def updateRoster(self):
|
||||
self.logger.debug("Update roster")
|
||||
|
||||
old = self.buddies.keys()
|
||||
self.buddies.load()
|
||||
new = self.buddies.keys()
|
||||
contacts = new
|
||||
|
||||
if self.synced == False:
|
||||
self.sendSync(contacts, delta = False, interactive = True)
|
||||
self.synced = True
|
||||
|
||||
add = set(new) - set(old)
|
||||
remove = set(old) - set(new)
|
||||
|
||||
self.logger.debug("Roster remove: %s", str(list(remove)))
|
||||
self.logger.debug("Roster add: %s", str(list(add)))
|
||||
|
||||
for number in remove:
|
||||
self.backend.handleBuddyChanged(self.user, number, "", [],
|
||||
protocol_pb2.STATUS_NONE)
|
||||
self.backend.handleBuddyRemoved(self.user, number)
|
||||
self.unsubscribePresence(number)
|
||||
|
||||
for number in add:
|
||||
buddy = self.buddies[number]
|
||||
self.subscribePresence(number)
|
||||
self.backend.handleBuddyChanged(self.user, number, buddy.nick,
|
||||
buddy.groups, protocol_pb2.STATUS_NONE,
|
||||
iconHash = buddy.image_hash if buddy.image_hash is not None else "")
|
||||
|
||||
#self.requestLastSeen(number, self._lastSeen)
|
||||
|
||||
def _updateGroups(self, response, request):
|
||||
self.logger.debug('Received groups list %s', response)
|
||||
groups = response.getGroups()
|
||||
|
@ -223,9 +187,18 @@ class Session(YowsupApp):
|
|||
self.backend.handleRoomNicknameChanged(
|
||||
self.user, self._shortenGroupId(room), group.subject
|
||||
)
|
||||
group.joined = True
|
||||
else:
|
||||
self.logger.warn("Room doesn't exist: %s", room)
|
||||
|
||||
def leaveRoom(self, room):
|
||||
if room in self.groups:
|
||||
self.logger.info("Leaving room: %s room=%s", self.legacyName, room)
|
||||
group = self.groups[room]
|
||||
group.joined = False
|
||||
else:
|
||||
self.logger.warn("Room doesn't exist: %s. Unable to leave.", room)
|
||||
|
||||
def _refreshParticipants(self, room):
|
||||
group = self.groups[room]
|
||||
for jid in group.participants:
|
||||
|
@ -269,17 +242,19 @@ class Session(YowsupApp):
|
|||
#self.bot.call("welcome")
|
||||
self.initialized = True
|
||||
self.sendPresence(True)
|
||||
self.updateRoster()
|
||||
for func in self.loginQueue:
|
||||
func()
|
||||
|
||||
self.logger.debug('Requesting groups list')
|
||||
self.requestGroupsList(self._updateGroups)
|
||||
self.loggedIn = True
|
||||
|
||||
# Called by superclass
|
||||
def onAuthFailed(self, reason):
|
||||
self.logger.info("Auth failed: %s (%s)", self.user, reason)
|
||||
self.backend.handleDisconnected(self.user, 0, reason)
|
||||
self.password = None
|
||||
self.shouldBeConnected = False
|
||||
self.loggedIn = False
|
||||
|
||||
# Called by superclass
|
||||
def onDisconnect(self):
|
||||
|
@ -296,7 +271,7 @@ class Session(YowsupApp):
|
|||
buddy = self.buddies[_from.split('@')[0]]
|
||||
#self.backend.handleBuddyChanged(self.user, buddy.number.number,
|
||||
# buddy.nick, buddy.groups, protocol_pb2.STATUS_ONLINE)
|
||||
self.backend.handleMessageAck(self.user, buddy.number.number, self.msgIDs[_id].xmppId)
|
||||
self.backend.handleMessageAck(self.user, buddy.number, self.msgIDs[_id].xmppId)
|
||||
self.msgIDs[_id].cnt = self.msgIDs[_id].cnt +1
|
||||
if self.msgIDs[_id].cnt == 2:
|
||||
del self.msgIDs[_id]
|
||||
|
@ -475,12 +450,34 @@ class Session(YowsupApp):
|
|||
self.bot.send("You have been added to group: %s@%s (%s)"
|
||||
% (self._shortenGroupId(room), subject, self.backend.spectrum_jid))
|
||||
|
||||
# Called by superclass
|
||||
def onParticipantsAddedToGroup(self, group):
|
||||
self.logger.debug("Participants added to group: %s", group)
|
||||
room = group.getGroupId().split('@')[0]
|
||||
self.groups[room].participants.extend(group.getParticipants())
|
||||
self._refreshParticipants(room)
|
||||
|
||||
# Called by superclass
|
||||
def onParticipantsRemovedFromGroup(self, room, participants):
|
||||
self.logger.debug("Participants removed from group: %s, %s",
|
||||
room, participants)
|
||||
group = self.groups[room]
|
||||
for jid in participants:
|
||||
group.participants.remove(jid)
|
||||
buddy = jid.split("@")[0]
|
||||
try:
|
||||
nick = self.buddies[buddy].nick
|
||||
except KeyError:
|
||||
nick = buddy
|
||||
if nick == "":
|
||||
nick = buddy
|
||||
if buddy == self.legacyName:
|
||||
nick = group.nick
|
||||
flags = protocol_pb2.PARTICIPANT_FLAG_NONE
|
||||
self.backend.handleParticipantChanged(
|
||||
self.user, nick, self._shortenGroupId(room), flags,
|
||||
protocol_pb2.STATUS_NONE, buddy)
|
||||
|
||||
def onPresenceReceived(self, _type, name, jid, lastseen):
|
||||
self.logger.info("Presence received: %s %s %s %s", _type, name, jid, lastseen)
|
||||
buddy = jid.split("@")[0]
|
||||
|
@ -512,12 +509,12 @@ class Session(YowsupApp):
|
|||
|
||||
def onPresenceAvailable(self, buddy, statusmsg):
|
||||
self.logger.info("Is available: %s", buddy)
|
||||
self.backend.handleBuddyChanged(self.user, buddy.number.number,
|
||||
self.backend.handleBuddyChanged(self.user, buddy.number,
|
||||
buddy.nick, buddy.groups, protocol_pb2.STATUS_ONLINE, statusmsg, buddy.image_hash)
|
||||
|
||||
def onPresenceUnavailable(self, buddy, statusmsg):
|
||||
self.logger.info("Is unavailable: %s", buddy)
|
||||
self.backend.handleBuddyChanged(self.user, buddy.number.number,
|
||||
self.backend.handleBuddyChanged(self.user, buddy.number,
|
||||
buddy.nick, buddy.groups, protocol_pb2.STATUS_AWAY, statusmsg, buddy.image_hash)
|
||||
|
||||
# spectrum RequestMethods
|
||||
|
@ -540,6 +537,11 @@ class Session(YowsupApp):
|
|||
self.legacyName, sender, message)
|
||||
|
||||
message = message.encode("utf-8")
|
||||
# FIXME: Fragile, should pass this in to onDlerror
|
||||
self.dlerror_message = message
|
||||
self.dlerror_sender = sender
|
||||
self.dlerror_ID = ID
|
||||
# End Fragile
|
||||
|
||||
if sender == "bot":
|
||||
self.bot.parse(message)
|
||||
|
@ -555,9 +557,13 @@ class Session(YowsupApp):
|
|||
self.msgIDs[waId] = MsgIDs( ID, waId)
|
||||
else:
|
||||
room = sender
|
||||
if message[0] == '\\' and message[:1] != '\\\\':
|
||||
self.logger.debug("Executing command %s in %s", message, room)
|
||||
self.executeCommand(message, room)
|
||||
else:
|
||||
try:
|
||||
group = self.groups[self._lengthenGroupId(room)]
|
||||
self.logger.info("Group Message from %s to %s Groups: %s",
|
||||
self.logger.debug("Group Message from %s to %s Groups: %s",
|
||||
group.nick , group , self.groups)
|
||||
self.backend.handleMessage(
|
||||
self.user, room, message.decode('utf-8'), group.nick
|
||||
|
@ -573,6 +579,7 @@ class Session(YowsupApp):
|
|||
self.imgMsgId = ID
|
||||
self.imgBuddy = room + "@g.us"
|
||||
|
||||
|
||||
downloader = MediaDownloader(self.onDlsuccess, self.onDlerror)
|
||||
downloader.download(message)
|
||||
#self.imgMsgId = ID
|
||||
|
@ -621,6 +628,29 @@ class Session(YowsupApp):
|
|||
self.logger.info("WA Message send to %s with ID %s", buddy, waId)
|
||||
#self.sendTextMessage(sender + '@s.whatsapp.net', message)
|
||||
|
||||
def executeCommand(self, command, room):
|
||||
if command == '\\leave':
|
||||
self.logger.debug("Leaving room %s", room)
|
||||
# Leave group on whatsapp side
|
||||
self.leaveGroup(room)
|
||||
# Delete Room on spectrum side
|
||||
group = self.groups[room]
|
||||
for jid in group.participants:
|
||||
buddy = jid.split("@")[0]
|
||||
try:
|
||||
nick = self.buddies[buddy].nick
|
||||
except KeyError:
|
||||
nick = buddy
|
||||
if nick == "":
|
||||
nick = buddy
|
||||
if buddy == self.legacyName:
|
||||
nick = group.nick
|
||||
flags = protocol_pb2.PARTICIPANT_FLAG_ROOM_NOT_FOUND
|
||||
self.backend.handleParticipantChanged(
|
||||
self.user, nick, self._shortenGroupId(room), flags,
|
||||
protocol_pb2.STATUS_NONE, buddy)
|
||||
del self.groups[room]
|
||||
|
||||
def _requestLastSeen(self, buddy):
|
||||
|
||||
def onSuccess(buddy, lastseen):
|
||||
|
@ -681,9 +711,22 @@ class Session(YowsupApp):
|
|||
else:
|
||||
self.logger.debug("Group message sent from %s (%s) to %s: %s",
|
||||
buddy, nick, room, messageContent)
|
||||
try:
|
||||
group = self.groups[room]
|
||||
if group.joined:
|
||||
self.backend.handleMessage(self.user,room, messageContent,
|
||||
nick, "", timestamp)
|
||||
else:
|
||||
self.bot.send("You have received a message in group: %s@%s"
|
||||
% (room, self.backend.spectrum_jid))
|
||||
self.bot.send("Join the group in order to reply")
|
||||
self.bot.send("%s: %s" % (nick, messageContent))
|
||||
except KeyError:
|
||||
self.logger.warn("Group is not in group list")
|
||||
self.backend.handleMessage(self.user, self._shortenGroupId(room),
|
||||
messageContent, nick, "", timestamp)
|
||||
|
||||
|
||||
def changeStatus(self, status):
|
||||
if status != self.status:
|
||||
self.logger.info("Status changed: %s", status)
|
||||
|
@ -712,19 +755,19 @@ class Session(YowsupApp):
|
|||
msg = self.offlineQueue.pop(0)
|
||||
self.backend.handleMessage(self.user, msg[0], msg[1], "", "", msg[2])
|
||||
|
||||
# Called when user logs in to initialize the roster
|
||||
def loadBuddies(self, buddies):
|
||||
self.buddies.load(buddies)
|
||||
|
||||
# also for adding a new buddy
|
||||
def updateBuddy(self, buddy, nick, groups, image_hash = None):
|
||||
if buddy != "bot":
|
||||
self.buddies.update(buddy, nick, groups, image_hash)
|
||||
if self.initialized == True:
|
||||
self.updateRoster()
|
||||
|
||||
def removeBuddy(self, buddy):
|
||||
if buddy != "bot":
|
||||
self.logger.info("Buddy removed: %s", buddy)
|
||||
self.buddies.remove(buddy)
|
||||
self.updateRoster()
|
||||
|
||||
|
||||
def requestVCard(self, buddy, ID=None):
|
||||
def onSuccess(response, request):
|
||||
|
@ -740,6 +783,68 @@ class Session(YowsupApp):
|
|||
self.logger.debug('Requesting profile picture of %s', buddy)
|
||||
self.requestProfilePicture(buddy, onSuccess = onSuccess)
|
||||
|
||||
def onDlsuccess(self, path):
|
||||
self.logger.info("Success: Image downloaded to %s", path)
|
||||
os.rename(path, path+"."+self.imgType)
|
||||
if self.imgType != "jpg":
|
||||
im = Image.open(path+"."+self.imgType)
|
||||
im.save(path+".jpg")
|
||||
self.imgPath = path+".jpg"
|
||||
statinfo = os.stat(self.imgPath)
|
||||
name=os.path.basename(self.imgPath)
|
||||
self.logger.info("Buddy %s",self.imgBuddy)
|
||||
self.image_send(self.imgBuddy, self.imgPath)
|
||||
|
||||
#self.logger.info("Sending picture %s of size %s with name %s",self.imgPath, statinfo.st_size, name)
|
||||
#mtype = "image"
|
||||
|
||||
#sha1 = hashlib.sha256()
|
||||
#fp = open(self.imgPath, 'rb')
|
||||
#try:
|
||||
# sha1.update(fp.read())
|
||||
# hsh = base64.b64encode(sha1.digest())
|
||||
# self.call("media_requestUpload", (hsh, mtype, os.path.getsize(self.imgPath)))
|
||||
#finally:
|
||||
# fp.close()
|
||||
|
||||
|
||||
def onDlerror(self):
|
||||
self.logger.info("Download Error. Sending message as is.")
|
||||
waId = self.sendTextMessage(self.dlerror_sender + '@s.whatsapp.net', self.dlerror_message)
|
||||
self.msgIDs[waId] = MsgIDs(self.dlerror_ID, waId)
|
||||
|
||||
|
||||
def _doSendImage(self, filePath, url, to, ip = None, caption = None):
|
||||
waId = self.doSendImage(filePath, url, to, ip, caption)
|
||||
self.msgIDs[waId] = MsgIDs(self.imgMsgId, waId)
|
||||
|
||||
def _doSendAudio(self, filePath, url, to, ip = None, caption = None):
|
||||
waId = self.doSendAudio(filePath, url, to, ip, caption)
|
||||
self.msgIDs[waId] = MsgIDs(self.imgMsgId, waId)
|
||||
|
||||
|
||||
|
||||
|
||||
def createThumb(self, size=100, raw=False):
|
||||
img = Image.open(self.imgPath)
|
||||
width, height = img.size
|
||||
img_thumbnail = self.imgPath + '_thumbnail'
|
||||
|
||||
if width > height:
|
||||
nheight = float(height) / width * size
|
||||
nwidth = size
|
||||
else:
|
||||
nwidth = float(width) / height * size
|
||||
nheight = size
|
||||
|
||||
img.thumbnail((nwidth, nheight), Image.ANTIALIAS)
|
||||
img.save(img_thumbnail, 'JPEG')
|
||||
|
||||
with open(img_thumbnail, 'rb') as imageFile:
|
||||
raw = base64.b64encode(imageFile.read())
|
||||
|
||||
return raw
|
||||
|
||||
# Not used
|
||||
def onLocationReceived(self, messageId, jid, name, preview, latitude, longitude, receiptRequested, isBroadcast):
|
||||
buddy = jid.split("@")[0]
|
||||
|
@ -777,63 +882,3 @@ class Session(YowsupApp):
|
|||
|
||||
|
||||
|
||||
def onDlsuccess(self, path):
|
||||
self.logger.info("Success: Image downloaded to %s", path)
|
||||
os.rename(path, path+"."+self.imgType)
|
||||
if self.imgType != "jpg":
|
||||
im = Image.open(path+"."+self.imgType)
|
||||
im.save(path+".jpg")
|
||||
self.imgPath = path+".jpg"
|
||||
statinfo = os.stat(self.imgPath)
|
||||
name=os.path.basename(self.imgPath)
|
||||
self.logger.info("Buddy %s",self.imgBuddy)
|
||||
self.image_send(self.imgBuddy, self.imgPath)
|
||||
|
||||
#self.logger.info("Sending picture %s of size %s with name %s",self.imgPath, statinfo.st_size, name)
|
||||
#mtype = "image"
|
||||
|
||||
#sha1 = hashlib.sha256()
|
||||
#fp = open(self.imgPath, 'rb')
|
||||
#try:
|
||||
# sha1.update(fp.read())
|
||||
# hsh = base64.b64encode(sha1.digest())
|
||||
# self.call("media_requestUpload", (hsh, mtype, os.path.getsize(self.imgPath)))
|
||||
#finally:
|
||||
# fp.close()
|
||||
|
||||
|
||||
def onDlerror(self):
|
||||
self.logger.info("Download Error")
|
||||
|
||||
|
||||
def _doSendImage(self, filePath, url, to, ip = None, caption = None):
|
||||
waId = self.doSendImage(filePath, url, to, ip, caption)
|
||||
self.msgIDs[waId] = MsgIDs(self.imgMsgId, waId)
|
||||
|
||||
def _doSendAudio(self, filePath, url, to, ip = None, caption = None):
|
||||
waId = self.doSendAudio(filePath, url, to, ip, caption)
|
||||
self.msgIDs[waId] = MsgIDs(self.imgMsgId, waId)
|
||||
|
||||
|
||||
|
||||
|
||||
def createThumb(self, size=100, raw=False):
|
||||
img = Image.open(self.imgPath)
|
||||
width, height = img.size
|
||||
img_thumbnail = self.imgPath + '_thumbnail'
|
||||
|
||||
if width > height:
|
||||
nheight = float(height) / width * size
|
||||
nwidth = size
|
||||
else:
|
||||
nwidth = float(width) / height * size
|
||||
nheight = size
|
||||
|
||||
img.thumbnail((nwidth, nheight), Image.ANTIALIAS)
|
||||
img.save(img_thumbnail, 'JPEG')
|
||||
|
||||
with open(img_thumbnail, 'rb') as imageFile:
|
||||
raw = base64.b64encode(imageFile.read())
|
||||
|
||||
return raw
|
||||
|
||||
|
|
10
transwhat.py
10
transwhat.py
|
@ -1,11 +1,10 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
__author__ = "Steffen Vogel"
|
||||
__copyright__ = "Copyright 2013, Steffen Vogel"
|
||||
__copyright__ = "Copyright 2015, Steffen Vogel"
|
||||
__license__ = "GPLv3"
|
||||
__maintainer__ = "Steffen Vogel"
|
||||
__email__ = "post@steffenvogel.de"
|
||||
__status__ = "Prototype"
|
||||
|
||||
"""
|
||||
This file is part of transWhat
|
||||
|
@ -29,7 +28,6 @@ import traceback
|
|||
import logging
|
||||
import asyncore
|
||||
import sys, os
|
||||
import MySQLdb
|
||||
import e4u
|
||||
import threading
|
||||
import Queue
|
||||
|
@ -39,7 +37,6 @@ sys.path.insert(0, os.getcwd())
|
|||
from Spectrum2.iochannel import IOChannel
|
||||
|
||||
from whatsappbackend import WhatsAppBackend
|
||||
from constants import *
|
||||
from yowsup.common import YowConstants
|
||||
from yowsup.stacks import YowStack
|
||||
|
||||
|
@ -75,10 +72,11 @@ def connectionClosed():
|
|||
closed = True
|
||||
|
||||
# Main
|
||||
db = MySQLdb.connect(DB_HOST, DB_USER, DB_PASS, DB_TABLE)
|
||||
io = IOChannel(args.host, args.port, handleTransportData, connectionClosed)
|
||||
|
||||
plugin = WhatsAppBackend(io, db, args.j)
|
||||
plugin = WhatsAppBackend(io, args.j)
|
||||
|
||||
plugin.handleBackendConfig('features', 'send_buddies_on_login', 1)
|
||||
|
||||
while True:
|
||||
try:
|
||||
|
|
3
utils.py
3
utils.py
|
@ -1,9 +1,8 @@
|
|||
__author__ = "Steffen Vogel"
|
||||
__copyright__ = "Copyright 2013, Steffen Vogel"
|
||||
__copyright__ = "Copyright 2015, Steffen Vogel"
|
||||
__license__ = "GPLv3"
|
||||
__maintainer__ = "Steffen Vogel"
|
||||
__email__ = "post@steffenvogel.de"
|
||||
__status__ = "Prototype"
|
||||
|
||||
"""
|
||||
This file is part of transWhat
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
__author__ = "Steffen Vogel"
|
||||
__copyright__ = "Copyright 2013, Steffen Vogel"
|
||||
__copyright__ = "Copyright 2015, Steffen Vogel"
|
||||
__license__ = "GPLv3"
|
||||
__maintainer__ = "Steffen Vogel"
|
||||
__email__ = "post@steffenvogel.de"
|
||||
__status__ = "Prototype"
|
||||
|
||||
"""
|
||||
This file is part of transWhat
|
||||
|
@ -30,11 +29,10 @@ from session import Session
|
|||
import logging
|
||||
|
||||
class WhatsAppBackend(SpectrumBackend):
|
||||
def __init__(self, io, db, spectrum_jid):
|
||||
def __init__(self, io, spectrum_jid):
|
||||
SpectrumBackend.__init__(self)
|
||||
self.logger = logging.getLogger(self.__class__.__name__)
|
||||
self.io = io
|
||||
self.db = db
|
||||
self.sessions = { }
|
||||
self.spectrum_jid = spectrum_jid
|
||||
# Used to prevent duplicate messages
|
||||
|
@ -46,7 +44,7 @@ class WhatsAppBackend(SpectrumBackend):
|
|||
def handleLoginRequest(self, user, legacyName, password, extra):
|
||||
self.logger.debug("handleLoginRequest(user=%s, legacyName=%s)", user, legacyName)
|
||||
if user not in self.sessions:
|
||||
self.sessions[user] = Session(self, user, legacyName, extra, self.db)
|
||||
self.sessions[user] = Session(self, user, legacyName, extra)
|
||||
|
||||
if user not in self.lastMessage:
|
||||
self.lastMessage[user] = {}
|
||||
|
@ -78,11 +76,23 @@ class WhatsAppBackend(SpectrumBackend):
|
|||
self.logger.debug("handleJoinRoomRequest(user=%s, room=%s, nickname=%s)", user, room, nickname)
|
||||
self.sessions[user].joinRoom(room, nickname)
|
||||
|
||||
def handleLeaveRoomRequest(self, user, room):
|
||||
self.logger.debug("handleLeaveRoomRequest(user=%s, room=%s)", user, room)
|
||||
self.sessions[user].leaveRoom(room)
|
||||
|
||||
def handleStatusChangeRequest(self, user, status, statusMessage):
|
||||
self.logger.debug("handleStatusChangeRequest(user=%s, status=%d, statusMessage=%s)", user, status, statusMessage)
|
||||
self.sessions[user].changeStatusMessage(statusMessage)
|
||||
self.sessions[user].changeStatus(status)
|
||||
|
||||
def handleBuddies(self, buddies):
|
||||
"""Called when user logs in. Used to initialize roster."""
|
||||
self.logger.debug("handleBuddies(buddies=%s)", buddies)
|
||||
buddies = [b for b in buddies.buddy]
|
||||
if len(buddies) > 0:
|
||||
user = buddies[0].userName
|
||||
self.sessions[user].loadBuddies(buddies)
|
||||
|
||||
def handleBuddyUpdatedRequest(self, user, buddy, nick, groups):
|
||||
self.logger.debug("handleBuddyUpdatedRequest(user=%s, buddy=%s, nick=%s, groups=%s)", user, buddy, nick, str(groups))
|
||||
self.sessions[user].updateBuddy(buddy, nick, groups)
|
||||
|
@ -112,9 +122,6 @@ class WhatsAppBackend(SpectrumBackend):
|
|||
def handleBuddyBlockToggled(self, user, buddy, blocked):
|
||||
pass
|
||||
|
||||
def handleLeaveRoomRequest(self, user, room):
|
||||
pass
|
||||
|
||||
def handleVCardUpdatedRequest(self, user, photo, nickname):
|
||||
pass
|
||||
|
||||
|
@ -138,7 +145,7 @@ class WhatsAppBackend(SpectrumBackend):
|
|||
pass
|
||||
|
||||
def handleMessageAckRequest(self, user, legacyName, ID = 0):
|
||||
self.logger.info("Meassage ACK request for %s !!",leagcyName)
|
||||
self.logger.info("Meassage ACK request for %s !!",legacyName)
|
||||
|
||||
def sendData(self, data):
|
||||
self.io.sendData(data)
|
||||
|
|
|
@ -61,7 +61,6 @@ class YowsupApp(object):
|
|||
YowContactsIqProtocolLayer,
|
||||
YowChatstateProtocolLayer,
|
||||
YowCallsProtocolLayer,
|
||||
YowMediaProtocolLayer,
|
||||
YowPrivacyProtocolLayer,
|
||||
YowProfilesProtocolLayer,
|
||||
YowGroupsProtocolLayer,
|
||||
|
@ -217,6 +216,7 @@ class YowsupApp(object):
|
|||
- phone_number: (str) The cellphone number of the person to
|
||||
subscribe to
|
||||
"""
|
||||
self.logger.debug("Subscribing to Presence updates from %s", (phone_number))
|
||||
jid = phone_number + '@s.whatsapp.net'
|
||||
entity = SubscribePresenceProtocolEntity(jid)
|
||||
self.sendEntity(entity)
|
||||
|
@ -233,6 +233,16 @@ class YowsupApp(object):
|
|||
entity = UnsubscribePresenceProtocolEntity(jid)
|
||||
self.sendEntity(entity)
|
||||
|
||||
def leaveGroup(self, group):
|
||||
"""
|
||||
Permanently leave a WhatsApp group
|
||||
|
||||
Args:
|
||||
- group: (str) the group id (e.g. 27831788123-144024456)
|
||||
"""
|
||||
entity = LeaveGroupsIqProtocolEntity([group + '@g.us'])
|
||||
self.sendEntity(entity)
|
||||
|
||||
def setStatus(self, statusText):
|
||||
"""
|
||||
Send status to whatsapp
|
||||
|
@ -492,6 +502,15 @@ class YowsupApp(object):
|
|||
"""Called when participants have been added to a group"""
|
||||
pass
|
||||
|
||||
def onParticipantsRemovedFromGroup(self, group, participants):
|
||||
"""Called when participants have been removed from a group
|
||||
|
||||
Args:
|
||||
- group: (str) id of the group (e.g. 27831788123-144024456)
|
||||
- participants: (list) jids of participants that are removed
|
||||
"""
|
||||
pass
|
||||
|
||||
def sendEntity(self, entity):
|
||||
"""Sends an entity down the stack (as if YowsupAppLayer called toLower)"""
|
||||
self.stack.broadcastEvent(YowLayerEvent(YowsupAppLayer.TO_LOWER_EVENT,
|
||||
|
@ -587,15 +606,21 @@ class YowsupAppLayer(YowInterfaceLayer):
|
|||
"""
|
||||
Sends ack automatically
|
||||
"""
|
||||
self.logger.debug("Received notification: %s", entity)
|
||||
self.logger.debug("Received notification (%s): %s", type(entity), entity)
|
||||
self.toLower(entity.ack())
|
||||
if isinstance(entity, CreateGroupsNotificationProtocolEntity):
|
||||
self.caller.onAddedToGroup(entity)
|
||||
elif isinstance(entity, AddGroupsNotificationProtocolEntity):
|
||||
self.caller.onParticipantsAddedToGroup(entity)
|
||||
elif isinstance(entity, RemoveGroupsNotificationProtocolEntity):
|
||||
self.caller.onParticipantsRemovedFromGroup(
|
||||
entity.getGroupId().split('@')[0],
|
||||
entity.getParticipants().keys()
|
||||
)
|
||||
|
||||
@ProtocolEntityCallback('message')
|
||||
def onMessageReceived(self, entity):
|
||||
self.logger.debug("Received Message: %s", entity)
|
||||
if entity.getType() == MessageProtocolEntity.MESSAGE_TYPE_TEXT:
|
||||
self.caller.onTextMessage(
|
||||
entity._id,
|
||||
|
|
Loading…
Reference in a new issue